@@ -32,6 +32,26 @@ import { TruncatedText } from 'components/TruncatedText'
3232const ModuleIssueDetailsPage = ( ) => {
3333 const params = useParams ( ) as { programKey : string ; moduleKey : string ; issueId : string }
3434 const { programKey, moduleKey, issueId } = params
35+
36+ const formatDeadline = ( deadline : string | null ) => {
37+ if ( ! deadline ) return { text : 'No deadline set' , color : 'text-gray-600 dark:text-gray-300' }
38+
39+ const deadlineDate = new Date ( deadline )
40+ const today = new Date ( )
41+ const isOverdue = deadlineDate < today
42+ const daysLeft = Math . ceil ( ( deadlineDate . getTime ( ) - today . getTime ( ) ) / ( 1000 * 60 * 60 * 24 ) )
43+
44+ const statusText = isOverdue
45+ ? '(overdue)'
46+ : daysLeft === 0
47+ ? '(today)'
48+ : `(${ daysLeft } days left)`
49+
50+ return {
51+ text : `${ deadlineDate . toLocaleDateString ( ) } ${ statusText } ` ,
52+ color : 'text-[#DA3633]' ,
53+ }
54+ }
3555 const { data, loading, error } = useQuery ( GET_MODULE_ISSUE_VIEW , {
3656 variables : { programKey, moduleKey, number : Number ( issueId ) } ,
3757 skip : ! issueId ,
@@ -167,10 +187,14 @@ const ModuleIssueDetailsPage = () => {
167187 </ span >
168188 < span
169189 className = { `inline-flex items-center rounded-lg px-2 py-0.5 text-xs font-medium ${
170- issue . state === 'open' ? 'bg-[#2cbe4e] text-white' : 'bg-[#cb2431] text-white'
190+ issue . state === 'open'
191+ ? 'bg-[#238636] text-white'
192+ : issue . isMerged
193+ ? 'bg-[#8657E5] text-white'
194+ : 'bg-[#DA3633] text-white'
171195 } `}
172196 >
173- { issue . state === 'open' ? 'Open' : 'Closed' }
197+ { issue . state === 'open' ? 'Open' : issue . isMerged ? 'Merged' : 'Closed' }
174198 </ span >
175199 </ div >
176200 </ div >
@@ -195,23 +219,18 @@ const ModuleIssueDetailsPage = () => {
195219 </ div >
196220
197221 < div className = "flex flex-col gap-2" >
198- < div className = "flex flex-wrap items-center gap-2 " >
199- < span className = "font-medium" > Deadline:</ span >
222+ < div className = "flex flex-wrap items-center" >
223+ < span className = "font-medium" > Deadline: </ span >
200224 { isEditingDeadline && canEditDeadline ? (
201- < span className = "inline-flex items-center gap-2" >
202- < input
203- type = "date"
204- value = { deadlineInput }
205- onChange = { ( e ) => setDeadlineInput ( e . target . value ) }
206- min = { new Date ( ) . toISOString ( ) . slice ( 0 , 10 ) }
207- className = "h-8 rounded border border-gray-300 px-2 text-xs dark:border-gray-600"
208- />
209- < button
210- type = "button"
211- disabled = { ! deadlineInput || settingDeadline }
212- onClick = { async ( ) => {
213- if ( ! deadlineInput || settingDeadline || ! issueId ) return
214- const localDate = new Date ( deadlineInput + 'T23:59:59' )
225+ < input
226+ type = "date"
227+ value = { deadlineInput }
228+ onChange = { async ( e ) => {
229+ const newValue = e . target . value
230+ setDeadlineInput ( newValue )
231+
232+ if ( newValue && ! settingDeadline && issueId ) {
233+ const localDate = new Date ( newValue + 'T23:59:59' )
215234 const iso = localDate . toISOString ( )
216235 await setTaskDeadlineMutation ( {
217236 variables : {
@@ -221,64 +240,35 @@ const ModuleIssueDetailsPage = () => {
221240 deadlineAt : iso ,
222241 } ,
223242 } )
224- } }
225- className = "flex items-center justify-center rounded-md border border-[#1D7BD7] px-3 py-1 text-xs font-medium text-[#1D7BD7] transition-all hover:bg-[#1D7BD7] hover:text-white disabled:cursor-not-allowed disabled:opacity-50"
226- >
227- { settingDeadline ? 'Saving…' : 'Save' }
228- </ button >
229- < button
230- type = "button"
231- aria-label = "Cancel deadline edit"
232- title = "Cancel"
233- onClick = { ( ) => {
234- setDeadlineInput (
235- taskDeadline ? new Date ( taskDeadline ) . toISOString ( ) . slice ( 0 , 10 ) : ''
236- )
237243 setIsEditingDeadline ( false )
238- } }
239- className = "inline-flex h-7 w-7 items-center justify-center rounded-md text-gray-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-800"
240- >
241- < FontAwesomeIcon icon = { faXmark } className = "h-3.5 w-3.5" />
242- </ button >
243- </ span >
244+ }
245+ } }
246+ min = { new Date ( ) . toISOString ( ) . slice ( 0 , 10 ) }
247+ className = "h-8 rounded border border-gray-300 px-2 text-xs dark:border-gray-600"
248+ />
244249 ) : (
245- < span className = "inline-flex items-center gap-2" >
246- { ( ( ) => {
247- if ( ! taskDeadline ) {
248- return (
249- < span className = "text-xs font-medium text-gray-600 dark:text-gray-300" >
250- No deadline set
251- </ span >
250+ < button
251+ type = "button"
252+ disabled = { ! canEditDeadline }
253+ onClick = { ( ) => {
254+ if ( canEditDeadline ) {
255+ setDeadlineInput (
256+ taskDeadline ? new Date ( taskDeadline ) . toISOString ( ) . slice ( 0 , 10 ) : ''
252257 )
258+ setIsEditingDeadline ( true )
253259 }
254- const d = new Date ( taskDeadline )
255- const today = new Date ( )
256- const isPast = d . setHours ( 0 , 0 , 0 , 0 ) < today . setHours ( 0 , 0 , 0 , 0 )
257- const diffDays = Math . ceil (
258- ( d . getTime ( ) - today . getTime ( ) ) / ( 1000 * 60 * 60 * 24 )
259- )
260- const textClass = 'text-red-700 dark:text-red-300'
261- return (
262- < span className = { `text-xs font-medium ${ textClass } ` } >
263- { d . toLocaleDateString ( ) } { ' ' }
264- { isPast
265- ? '(overdue)'
266- : diffDays > 0
267- ? `(in ${ diffDays } days)`
268- : '(today)' }
269- </ span >
270- )
260+ } }
261+ className = { `inline-flex items-center gap-2 rounded px-2 py-1 text-left transition-colors ${
262+ canEditDeadline
263+ ? 'hover:bg-gray-100 dark:hover:bg-gray-800'
264+ : 'cursor-not-allowed'
265+ } `}
266+ >
267+ { ( ( ) => {
268+ const { text, color } = formatDeadline ( taskDeadline )
269+ return < span className = { `text-xs font-medium ${ color } ` } > { text } </ span >
271270 } ) ( ) }
272- { canEditDeadline && (
273- < button
274- type = "button"
275- className = "ml-2 text-xs text-blue-600 hover:underline dark:text-blue-400"
276- onClick = { ( ) => setIsEditingDeadline ( true ) }
277- >
278- Edit
279- </ button >
280- ) }
281- </ span >
271+ </ button >
282272 ) }
283273 </ div >
284274 </ div >
@@ -407,21 +397,21 @@ const ModuleIssueDetailsPage = () => {
407397 { pr . state === 'closed' && pr . mergedAt ? (
408398 < span
409399 className = "inline-flex items-center rounded-lg px-2 py-0.5 text-xs font-medium text-white"
410- style = { { backgroundColor : '#6f42c1 ' } }
400+ style = { { backgroundColor : '#8657E5 ' } }
411401 >
412402 Merged
413403 </ span >
414404 ) : pr . state === 'closed' ? (
415405 < span
416406 className = "inline-flex items-center rounded-lg px-2 py-0.5 text-xs font-medium text-white"
417- style = { { backgroundColor : '#cb2431 ' } }
407+ style = { { backgroundColor : '#DA3633 ' } }
418408 >
419409 Closed
420410 </ span >
421411 ) : (
422412 < span
423413 className = "inline-flex items-center rounded-lg px-2 py-0.5 text-xs font-medium text-white"
424- style = { { backgroundColor : '#2cbe4e ' } }
414+ style = { { backgroundColor : '#238636 ' } }
425415 >
426416 Open
427417 </ span >
0 commit comments