11import { useState } from "react" ;
22
3+ import { TopicInput } from "@/components/topic_input" ;
4+
35interface Time {
46 id : number ;
57 day : number ;
@@ -27,35 +29,71 @@ type ItemProps = {
2729 item : Item ;
2830 onToggle ?: ( id : number ) => void ;
2931 onUpdate : ( item : Item ) => void ;
32+ availableTopics : Topic [ ] ;
3033} ;
3134
32- export function TaskItem ( { item, onToggle, onUpdate } : ItemProps ) {
35+ type TopicSelection =
36+ | { type : "existing" ; id : number }
37+ | { type : "new" ; name : string ; color_hex : number } ;
38+
39+ export function TaskItem ( {
40+ item,
41+ onToggle,
42+ onUpdate,
43+ availableTopics,
44+ } : ItemProps ) {
45+ {
46+ /* Editing Functionality */
47+ }
3348 const [ isEditing , setIsEditing ] = useState ( false ) ;
3449 const [ draftName , setDraftName ] = useState ( item . name ) ;
50+ const [ draftDescription , setDraftDescription ] = useState ( item . description ) ;
51+ const [ draftTopics , setDraftTopics ] = useState < TopicSelection [ ] > ( [ ] ) ;
3552 const [ saving , setSaving ] = useState ( false ) ;
3653
3754 function startEdit ( ) {
3855 setDraftName ( item . name ) ;
56+ setDraftDescription ( item . description ) ;
57+ setDraftTopics (
58+ item . topics . map ( ( t ) => ( {
59+ type : "existing" ,
60+ id : t . id ,
61+ } ) ) ,
62+ ) ;
3963 setIsEditing ( true ) ;
4064 }
4165
4266 function cancelEdit ( ) {
43- setIsEditing ( false ) ;
4467 setDraftName ( item . name ) ;
68+ setDraftDescription ( item . description ) ;
69+ setDraftTopics ( item . topics . map ( ( t ) => ( { type : "existing" , id : t . id } ) ) ) ;
70+ setIsEditing ( false ) ;
4571 }
4672
4773 async function saveEdit ( ) {
4874 setSaving ( true ) ;
4975 try {
76+ const existing_topic_ids = draftTopics
77+ . filter ( ( t ) => t . type === "existing" )
78+ . map ( ( t ) => t . id ) ;
79+
80+ const new_topics = draftTopics
81+ . filter ( ( t ) => t . type === "new" )
82+ . map ( ( t ) => ( {
83+ name : t . name ,
84+ color_hex : t . color_hex ,
85+ } ) ) ;
5086 const response = await fetch (
5187 `http://localhost:8000/api/planner/tasks/${ item . id } /` ,
5288 {
5389 method : "PUT" ,
5490 headers : { "Content-Type" : "application/json" } ,
5591 body : JSON . stringify ( {
5692 name : draftName ,
57- description : item . description ,
93+ description : draftDescription ,
5894 completed : item . completed ,
95+ existing_topic_ids : existing_topic_ids ,
96+ new_topics : new_topics ,
5997 } ) ,
6098 } ,
6199 ) ;
@@ -72,9 +110,13 @@ export function TaskItem({ item, onToggle, onUpdate }: ItemProps) {
72110 }
73111 }
74112
113+ {
114+ /* Item Display */
115+ }
75116 return (
76- < label className = "m-1 flex w-96 flex-col rounded-md border-2 border-zinc-200 bg-zinc-700 p-2" >
117+ < div className = "m-1 flex w-96 flex-col rounded-md border-2 border-zinc-200 bg-zinc-700 p-2" >
77118 < div className = "flex items-center justify-between" >
119+ { /* Task Name and Completion */ }
78120 < div className = "flex items-center space-x-2" >
79121 < input
80122 type = "checkbox"
@@ -98,6 +140,8 @@ export function TaskItem({ item, onToggle, onUpdate }: ItemProps) {
98140 </ span >
99141 ) }
100142 </ div >
143+
144+ { /* Task Times */ }
101145 < div className = "flex flex-col items-end text-sm text-zinc-300" >
102146 { item . times ?. length > 0
103147 ? item . times . map ( ( t ) => (
@@ -110,26 +154,45 @@ export function TaskItem({ item, onToggle, onUpdate }: ItemProps) {
110154 </ div >
111155 </ div >
112156
157+ { /* Task Topics */ }
113158 < div className = "flex flex-wrap gap-1 text-sm text-zinc-300" >
114- { item . topics ?. length > 0
115- ? item . topics . map ( ( topic ) => (
159+ { isEditing ? (
160+ < TopicInput
161+ availableTopics = { availableTopics }
162+ topics = { draftTopics }
163+ setTopics = { setDraftTopics }
164+ />
165+ ) : item . topics . length > 0 ? (
166+ item . topics . map ( ( topic ) => (
167+ < span
168+ key = { topic . id }
169+ className = "flex items-center gap-1 rounded-lg border-2 border-zinc-500 px-2 py-0.5 text-zinc-100"
170+ >
116171 < span
117- key = { topic . id }
118- className = "flex items-center gap-1 rounded-lg border-2 border-zinc-500 px-2 py-0.5 text-zinc-100"
119- >
120- < span
121- className = "h-2 w-2 rounded-full"
122- style = { {
123- backgroundColor : `# ${ topic . color_hex . toString ( 16 ) . padStart ( 6 , "0" ) } ` ,
124- } }
125- / >
126- { topic . name }
127- </ span >
128- ) )
129- : "No topics" }
172+ className = "h-2 w-2 rounded-full"
173+ style = { {
174+ backgroundColor : `# ${ topic . color_hex
175+ . toString ( 16 )
176+ . padStart ( 6 , "0" ) } ` ,
177+ } }
178+ />
179+ { topic . name }
180+ </ span >
181+ ) )
182+ ) : (
183+ "No topics"
184+ ) }
130185 </ div >
186+
187+ { /* Task Description */ }
131188 < div >
132- { item . description ? (
189+ { isEditing ? (
190+ < textarea
191+ value = { draftDescription }
192+ onChange = { ( e ) => setDraftDescription ( e . target . value ) }
193+ className = "mt-2 w-full rounded border-2 bg-zinc-600 p-1 text-zinc-200"
194+ />
195+ ) : item . description ? (
133196 < span className = "mt-2 block text-zinc-300" > { item . description } </ span >
134197 ) : (
135198 < span className = "mt-2 block italic text-zinc-500" >
@@ -149,7 +212,7 @@ export function TaskItem({ item, onToggle, onUpdate }: ItemProps) {
149212 < button onClick = { startEdit } > Edit</ button >
150213 ) }
151214 </ div >
152- </ label >
215+ </ div >
153216 ) ;
154217}
155218
0 commit comments