33import React , { FC , useEffect , useState } from "react" ;
44import { observer } from "mobx-react" ;
55import { Controller , useForm } from "react-hook-form" ;
6- import {
7- ArchiveIcon ,
8- ArchiveRestoreIcon ,
9- CalendarCheck2 ,
10- CalendarClock ,
11- ChevronRight ,
12- EllipsisIcon ,
13- LinkIcon ,
14- Trash2 ,
15- } from "lucide-react" ;
6+ import { ArchiveIcon , ArchiveRestoreIcon , ChevronRight , EllipsisIcon , LinkIcon , Trash2 } from "lucide-react" ;
167// types
178import { CYCLE_STATUS , CYCLE_UPDATED , EUserPermissions , EUserPermissionsLevel } from "@plane/constants" ;
189import { useTranslation } from "@plane/i18n" ;
1910import { ICycle } from "@plane/types" ;
2011// ui
2112import { CustomMenu , setToast , TOAST_TYPE } from "@plane/ui" ;
2213// components
23- import { DateDropdown } from "@/components/dropdowns" ;
14+ import { DateRangeDropdown } from "@/components/dropdowns" ;
2415// helpers
2516import { renderFormattedPayloadDate , getDate } from "@/helpers/date-time.helper" ;
2617import { copyUrlToClipboard } from "@/helpers/string.helper" ;
@@ -63,7 +54,7 @@ export const CycleSidebarHeader: FC<Props> = observer((props) => {
6354 const { t } = useTranslation ( ) ;
6455
6556 // form info
66- const { control, reset, getValues } = useForm ( {
57+ const { control, reset } = useForm ( {
6758 defaultValues,
6859 } ) ;
6960
@@ -110,10 +101,10 @@ export const CycleSidebarHeader: FC<Props> = observer((props) => {
110101 } ) ;
111102 } ;
112103
113- const submitChanges = ( data : Partial < ICycle > , changedProperty : string ) => {
104+ const submitChanges = async ( data : Partial < ICycle > , changedProperty : string ) => {
114105 if ( ! workspaceSlug || ! projectId || ! cycleDetails . id ) return ;
115106
116- updateCycleDetails ( workspaceSlug . toString ( ) , projectId . toString ( ) , cycleDetails . id . toString ( ) , data )
107+ await updateCycleDetails ( workspaceSlug . toString ( ) , projectId . toString ( ) , cycleDetails . id . toString ( ) , data )
117108 . then ( ( res ) => {
118109 captureCycleEvent ( {
119110 eventName : CYCLE_UPDATED ,
@@ -154,16 +145,22 @@ export const CycleSidebarHeader: FC<Props> = observer((props) => {
154145 }
155146 } ;
156147
157- const handleDateChange = async ( payload : { start_date ?: string | null ; end_date ?: string | null } ) => {
148+ const handleDateChange = async ( startDate : Date | undefined , endDate : Date | undefined ) => {
158149 let isDateValid = false ;
159150
160- if ( cycleDetails ?. start_date && cycleDetails ?. end_date )
151+ const payload = {
152+ start_date : renderFormattedPayloadDate ( startDate ) || null ,
153+ end_date : renderFormattedPayloadDate ( endDate ) || null ,
154+ } ;
155+
156+ if ( payload ?. start_date && payload . end_date ) {
161157 isDateValid = await dateChecker ( {
162158 ...payload ,
163- cycle_id : cycleDetails ? .id ,
159+ cycle_id : cycleDetails . id ,
164160 } ) ;
165- else isDateValid = await dateChecker ( payload ) ;
166-
161+ } else {
162+ isDateValid = true ;
163+ }
167164 if ( isDateValid ) {
168165 submitChanges ( payload , "date_range" ) ;
169166 setToast ( {
@@ -177,7 +174,6 @@ export const CycleSidebarHeader: FC<Props> = observer((props) => {
177174 title : t ( "project_cycles.action.update.failed.title" ) ,
178175 message : t ( "project_cycles.action.update.error.already_exists" ) ,
179176 } ) ;
180- reset ( { ...cycleDetails } ) ;
181177 }
182178 return isDateValid ;
183179 } ;
@@ -288,79 +284,41 @@ export const CycleSidebarHeader: FC<Props> = observer((props) => {
288284 </ span >
289285 ) }
290286 </ div >
291- < div className = "flex items-center gap-2" >
292- < Controller
293- name = "start_date"
294- control = { control }
295- rules = { { required : "Please select a date" } }
296- render = { ( { field : { value, onChange } } ) => (
297- < DateDropdown
298- value = { value ?? null }
299- onChange = { async ( val ) => {
300- let isDateValid ;
301- const valDate = val ? renderFormattedPayloadDate ( val ) : null ;
302- if ( getValues ( "end_date" ) ) {
303- isDateValid = await handleDateChange ( {
304- start_date : valDate ,
305- end_date : renderFormattedPayloadDate ( getValues ( "end_date" ) ) ,
306- } ) ;
307- } else {
308- isDateValid = await handleDateChange ( {
309- start_date : valDate ,
310- end_date : valDate ,
311- } ) ;
312- }
313- isDateValid && onChange ( renderFormattedPayloadDate ( val ) ) ;
314- } }
315- placeholder = { t ( "common.order_by.start_date" ) }
316- icon = { < CalendarClock className = "h-3 w-3 flex-shrink-0" /> }
317- buttonVariant = { value ? "border-with-text" : "border-without-text" }
318- buttonContainerClassName = { `h-6 w-full flex ${ ! isEditingAllowed || isArchived || isCompleted ? "cursor-not-allowed" : "cursor-pointer" } items-center gap-1.5 text-custom-text-300 rounded text-xs` }
319- optionsClassName = "z-10"
320- disabled = { ! isEditingAllowed || isArchived || isCompleted }
321- showTooltip
322- maxDate = { getDate ( getValues ( "end_date" ) ) }
323- isClearable = { false }
324- />
325- ) }
326- />
327287
328- < Controller
329- name = "end_date"
330- control = { control }
331- rules = { { required : "Please select a date" } }
332- render = { ( { field : { value, onChange } } ) => (
333- < DateDropdown
334- value = { getDate ( value ) ?? null }
335- onChange = { async ( val ) => {
336- let isDateValid ;
337- const valDate = val ? renderFormattedPayloadDate ( val ) : null ;
338- if ( getValues ( "start_date" ) ) {
339- isDateValid = await handleDateChange ( {
340- end_date : valDate ,
341- start_date : renderFormattedPayloadDate ( getValues ( "start_date" ) ) ,
342- } ) ;
343- } else {
344- isDateValid = await handleDateChange ( {
345- end_date : valDate ,
346- start_date : valDate ,
347- } ) ;
348- }
349- isDateValid && onChange ( renderFormattedPayloadDate ( val ) ) ;
350- } }
351- placeholder = { t ( "common.order_by.due_date" ) }
352- icon = { < CalendarCheck2 className = "h-3 w-3 flex-shrink-0" /> }
353- buttonVariant = { value ? "border-with-text" : "border-without-text" }
354- buttonContainerClassName = { `h-6 w-full flex ${ ! isEditingAllowed || isArchived || isCompleted ? "cursor-not-allowed" : "cursor-pointer" } items-center gap-1.5 text-custom-text-300 rounded text-xs` }
355- optionsClassName = "z-10"
356- disabled = { ! isEditingAllowed || isArchived || isCompleted }
357- showTooltip
358- minDate = { getDate ( getValues ( "start_date" ) ) }
359- isClearable = { false }
360- />
361- ) }
362- />
363- </ div >
288+ < Controller
289+ control = { control }
290+ name = "start_date"
291+ render = { ( { field : { value : startDateValue , onChange : onChangeStartDate } } ) => (
292+ < Controller
293+ control = { control }
294+ name = "end_date"
295+ render = { ( { field : { value : endDateValue , onChange : onChangeEndDate } } ) => (
296+ < DateRangeDropdown
297+ className = "h-7"
298+ buttonVariant = "border-with-text"
299+ minDate = { new Date ( ) }
300+ value = { {
301+ from : getDate ( startDateValue ) ,
302+ to : getDate ( endDateValue ) ,
303+ } }
304+ onSelect = { async ( val ) => {
305+ const isDateValid = await handleDateChange ( val ?. from , val ?. to ) ;
306+ if ( isDateValid ) {
307+ onChangeStartDate ( val ?. from ? renderFormattedPayloadDate ( val . from ) : null ) ;
308+ onChangeEndDate ( val ?. to ? renderFormattedPayloadDate ( val . to ) : null ) ;
309+ }
310+ } }
311+ placeholder = { {
312+ from : "Start date" ,
313+ to : "End date" ,
314+ } }
315+ required = { cycleDetails . status !== "draft" }
316+ disabled = { ! isEditingAllowed || isArchived || isCompleted }
317+ />
318+ ) }
319+ />
320+ ) }
321+ />
364322 </ div >
365323 </ >
366324 ) ;
0 commit comments