Files
gtd/app/src/components/TaskRow.tsx
Marcus Rehbock 0487bc7e4e
All checks were successful
Build & Release APK / build (push) Successful in 1m53s
Todoist-style: priorities P1-P4, estimates, FAB add form, Today view, natural quick add, drag-and-drop with haptics
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-07 19:46:11 -07:00

81 lines
2.3 KiB
TypeScript

import { useRouter } from "expo-router";
import { Pressable, StyleSheet, Text, View } from "react-native";
import Animated, { FadeIn } from "react-native-reanimated";
import { haptic } from "../lib/haptics";
import { formatEstimate, PRIORITY_COLOR } from "../lib/priority";
import { updateTask } from "../lib/store";
import { C } from "../lib/theme";
import type { Task, TaskStatus } from "../lib/types";
export default function TaskRow({
task,
uncheckTo = "next",
showStatus,
}: {
task: Task;
/** Status to revert to when un-checking a done task. */
uncheckTo?: TaskStatus;
showStatus?: boolean;
}) {
const router = useRouter();
const meta = [
showStatus ? task.status : null,
task.context,
task.waiting_for && `${task.waiting_for}`,
formatEstimate(task.estimate_min),
task.due_date && `due ${task.due_date}`,
]
.filter(Boolean)
.join(" · ");
const toggle = () => {
const done = task.status !== "done";
if (done) haptic.success();
else haptic.tap();
updateTask(task.id, { status: done ? "done" : uncheckTo });
};
return (
<Animated.View entering={FadeIn.duration(150)}>
<Pressable style={s.row} onPress={() => router.push(`/task/${task.id}`)}>
<Pressable
style={[s.checkbox, { borderColor: PRIORITY_COLOR[task.priority] }]}
hitSlop={10}
onPress={toggle}
>
{task.status === "done" && <View style={s.checkboxFill} />}
</Pressable>
<View style={{ flex: 1 }}>
<Text style={s.title} numberOfLines={2}>
{task.title}
</Text>
{!!meta && <Text style={s.meta}>{meta}</Text>}
</View>
</Pressable>
</Animated.View>
);
}
const s = StyleSheet.create({
row: {
flexDirection: "row",
alignItems: "center",
gap: 12,
paddingVertical: 14,
paddingHorizontal: 16,
borderBottomWidth: StyleSheet.hairlineWidth,
borderBottomColor: C.border,
},
checkbox: {
width: 22,
height: 22,
borderRadius: 11,
borderWidth: 2,
alignItems: "center",
justifyContent: "center",
},
checkboxFill: { width: 12, height: 12, borderRadius: 6, backgroundColor: C.done },
title: { color: C.text, fontSize: 16 },
meta: { color: C.muted, fontSize: 13, marginTop: 2 },
});