import { useRouter } from "expo-router";
import { Pressable, StyleSheet, Text, View } from "react-native";
import Animated, { FadeIn } from "react-native-reanimated";
import { dueMeta, friendlyDate, isDeferred } from "../lib/dates";
import { haptic } from "../lib/haptics";
import { formatEstimate, PRIORITY_COLOR } from "../lib/priority";
import { updateTask } from "../lib/store";
import { C, radius, space, type } from "../lib/theme";
import type { Task, TaskStatus } from "../lib/types";
export default function TaskRow({
task,
uncheckTo = "next",
showStatus,
onLongPress,
}: {
task: Task;
/** Status to revert to when un-checking a done task. */
uncheckTo?: TaskStatus;
showStatus?: boolean;
/** Drag handle for reorderable lists. */
onLongPress?: () => void;
}) {
const router = useRouter();
const done = task.status === "done";
// Due date is rendered separately so it can carry a tone color; the reader
// sees "due today" in amber, never does date math on an ISO string.
const due = task.due_date ? dueMeta(task.due_date) : null;
const dueColor = due?.tone === "overdue" ? C.danger : due?.tone === "today" ? C.warn : C.muted;
const base = [
showStatus ? task.status : null,
task.repeat && "↻",
task.context,
task.waiting_for && `→ ${task.waiting_for}`,
formatEstimate(task.estimate_min),
isDeferred(task.defer_date) && `⏸ until ${friendlyDate(task.defer_date!)}`,
]
.filter(Boolean)
.join(" · ");
const meta = base || due;
const flag = PRIORITY_COLOR[task.priority];
const toggle = () => {
const next = task.status !== "done";
if (next) haptic.success();
else haptic.tap();
updateTask(task.id, { status: next ? "done" : uncheckTo });
};
return (
[s.row, pressed && s.rowPressed]}
onPress={() => router.push(`/task/${task.id}`)}
onLongPress={onLongPress}
delayLongPress={200}
>
{/* Rounded square rather than a circle — the Things checkbox shape.
The border carries the priority colour, so priority is legible at a
glance without spending a whole column on a flag. */}
{done && ✓}
{task.title}
{!!meta && (
{base}
{!!base && !!due && " · "}
{due && {due.label}}
)}
);
}
const s = StyleSheet.create({
row: {
flexDirection: "row",
alignItems: "center",
gap: space.md,
paddingVertical: space.md + 2,
paddingHorizontal: space.lg,
backgroundColor: C.surface,
},
rowPressed: { backgroundColor: C.surface2 },
checkbox: {
width: 22,
height: 22,
borderRadius: 7,
borderWidth: 1.5,
alignItems: "center",
justifyContent: "center",
},
checkboxDone: { backgroundColor: C.done },
check: { color: C.onAccent, fontSize: 13, lineHeight: 16, fontWeight: "700" },
title: { ...type.row, color: C.text },
titleDone: { color: C.muted, textDecorationLine: "line-through" },
meta: { ...type.meta, color: C.muted, marginTop: 3 },
});
/** Inset hairline sized to line up under the task title, not the checkbox. */
export const TASK_ROW_INSET = space.lg + 22 + space.md;
export function TaskSeparator() {
return (
);
}