- Add tasks cache invalidation to etape create/update hooks - Fix timezone-unsafe overdue date comparison in TaskRow - Add due date picker to EtapeSheet (was missing from spec) - Use initialized ref to prevent form state overwrite on refetch - Remove unused deleteTask import from TaskList Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
120 lines
3.2 KiB
TypeScript
120 lines
3.2 KiB
TypeScript
import React from "react";
|
|
import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
|
|
import { Task, TASK_STATUSES } from "@/types/tasks.types";
|
|
import { useThemeColor } from "@/hooks/useThemeColor";
|
|
import { useColorScheme } from "@/hooks/useColorScheme";
|
|
import { Calendar } from "lucide-react-native";
|
|
|
|
type TaskRowProps = {
|
|
task: Task;
|
|
onPress: (task: Task) => void;
|
|
};
|
|
|
|
export default function TaskRow({ task, onPress }: TaskRowProps) {
|
|
const colorScheme = useColorScheme();
|
|
const isDark = colorScheme === "dark";
|
|
const textColor = useThemeColor({ light: "#1f2937", dark: "#f9fafb" }, "text");
|
|
const subtextColor = useThemeColor({ light: "#6b7280", dark: "#9ca3af" }, "text");
|
|
const borderColor = isDark ? "#374151" : "#e5e7eb";
|
|
|
|
const statusColor = TASK_STATUSES.find((s) => s.value === task.status)?.color ?? "#9ca3af";
|
|
const isOverdue = task.due_date && task.due_date < new Date().toISOString().slice(0, 10);
|
|
|
|
return (
|
|
<TouchableOpacity
|
|
style={[styles.container, { borderBottomColor: borderColor }]}
|
|
onPress={() => onPress(task)}
|
|
activeOpacity={0.7}
|
|
>
|
|
<View style={[styles.statusDot, { backgroundColor: statusColor }]} />
|
|
<View style={styles.content}>
|
|
<Text style={[styles.title, { color: textColor }]} numberOfLines={1}>
|
|
{task.title}
|
|
</Text>
|
|
<View style={styles.meta}>
|
|
{task.due_date && (
|
|
<View style={styles.dueDateBadge}>
|
|
<Calendar size={12} color={isOverdue ? "#ef4444" : subtextColor} />
|
|
<Text
|
|
style={[
|
|
styles.dueDate,
|
|
{ color: isOverdue ? "#ef4444" : subtextColor },
|
|
]}
|
|
>
|
|
{new Date(task.due_date).toLocaleDateString("fr-FR", {
|
|
day: "numeric",
|
|
month: "short",
|
|
})}
|
|
</Text>
|
|
</View>
|
|
)}
|
|
</View>
|
|
</View>
|
|
{task.assignee_name ? (
|
|
<View style={styles.avatar}>
|
|
<Text style={styles.avatarText}>
|
|
{task.assignee_name.charAt(0).toUpperCase()}
|
|
</Text>
|
|
</View>
|
|
) : (
|
|
<View style={[styles.avatar, styles.avatarEmpty]} />
|
|
)}
|
|
</TouchableOpacity>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
paddingVertical: 12,
|
|
paddingHorizontal: 16,
|
|
borderBottomWidth: StyleSheet.hairlineWidth,
|
|
gap: 12,
|
|
},
|
|
statusDot: {
|
|
width: 10,
|
|
height: 10,
|
|
borderRadius: 5,
|
|
},
|
|
content: {
|
|
flex: 1,
|
|
gap: 2,
|
|
},
|
|
title: {
|
|
fontSize: 15,
|
|
fontWeight: "500",
|
|
},
|
|
meta: {
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
gap: 8,
|
|
},
|
|
dueDateBadge: {
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
gap: 4,
|
|
},
|
|
dueDate: {
|
|
fontSize: 12,
|
|
},
|
|
avatar: {
|
|
width: 28,
|
|
height: 28,
|
|
borderRadius: 14,
|
|
backgroundColor: "#3b82f6",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
},
|
|
avatarEmpty: {
|
|
backgroundColor: "transparent",
|
|
borderWidth: 1.5,
|
|
borderColor: "#d1d5db",
|
|
borderStyle: "dashed",
|
|
},
|
|
avatarText: {
|
|
color: "#ffffff",
|
|
fontSize: 13,
|
|
fontWeight: "600",
|
|
},
|
|
});
|