Skip to content

Commit 894c857

Browse files
feat: src/useSubtasks.ts (#20)
1 parent 9545a37 commit 894c857

1 file changed

Lines changed: 68 additions & 0 deletions

File tree

src/useSubtasks.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { useState, useCallback, useEffect } from "react";
2+
3+
interface Subtask {
4+
id: string;
5+
text: string;
6+
done: boolean;
7+
}
8+
9+
type SubtaskMap = Record<string, Subtask[]>;
10+
11+
/**
12+
* Manage subtasks for todo items.
13+
* Each todo can have unlimited subtasks with independent completion state.
14+
*/
15+
export function useSubtasks() {
16+
const [subtasks, setSubtasks] = useState<SubtaskMap>(() => {
17+
const saved = localStorage.getItem("subtasks");
18+
return saved ? JSON.parse(saved) : {};
19+
});
20+
21+
useEffect(() => {
22+
localStorage.setItem("subtasks", JSON.stringify(subtasks));
23+
}, [subtasks]);
24+
25+
const addSubtask = useCallback((todoId: string, text: string) => {
26+
setSubtasks(prev => ({
27+
...prev,
28+
[todoId]: [...(prev[todoId] || []), { id: crypto.randomUUID(), text, done: false }],
29+
}));
30+
}, []);
31+
32+
const toggleSubtask = useCallback((todoId: string, subtaskId: string) => {
33+
setSubtasks(prev => ({
34+
...prev,
35+
[todoId]: (prev[todoId] || []).map(s =>
36+
s.id === subtaskId ? { ...s, done: !s.done } : s
37+
),
38+
}));
39+
}, []);
40+
41+
const deleteSubtask = useCallback((todoId: string, subtaskId: string) => {
42+
setSubtasks(prev => ({
43+
...prev,
44+
[todoId]: (prev[todoId] || []).filter(s => s.id !== subtaskId),
45+
}));
46+
}, []);
47+
48+
const getSubtasks = useCallback((todoId: string): Subtask[] => {
49+
return subtasks[todoId] || [];
50+
}, [subtasks]);
51+
52+
const getProgress = useCallback((todoId: string): { done: number; total: number; percentage: number } => {
53+
const subs = subtasks[todoId] || [];
54+
const done = subs.filter(s => s.done).length;
55+
const total = subs.length;
56+
return { done, total, percentage: total > 0 ? Math.round((done / total) * 100) : 0 };
57+
}, [subtasks]);
58+
59+
const clearSubtasks = useCallback((todoId: string) => {
60+
setSubtasks(prev => {
61+
const copy = { ...prev };
62+
delete copy[todoId];
63+
return copy;
64+
});
65+
}, []);
66+
67+
return { addSubtask, toggleSubtask, deleteSubtask, getSubtasks, getProgress, clearSubtasks };
68+
}

0 commit comments

Comments
 (0)