1+ import React , { useState , useEffect } from 'react' ;
2+ import { useTranslation } from 'react-i18next' ;
3+ import { GenericModal } from "../ui/GenericModal" ;
4+ import { MenuItem , TextField , Typography , Box } from "@mui/material" ;
5+ import { Dropdown } from "../ui/DropdownMui" ;
6+ import Button from "@mui/material/Button" ;
7+ import { validMomentTimezones } from '../../constants/const' ;
8+ import { useGlobalInfoStore } from '../../context/globalInfo' ;
9+ import { getSchedule , deleteSchedule } from '../../api/storage' ;
10+
11+ interface ScheduleSettingsProps {
12+ isOpen : boolean ;
13+ handleStart : ( settings : ScheduleSettings ) => Promise < boolean > ;
14+ handleClose : ( ) => void ;
15+ initialSettings ?: ScheduleSettings | null ;
16+ }
17+
18+ export interface ScheduleSettings {
19+ runEvery : number ;
20+ runEveryUnit : string ;
21+ startFrom : string ;
22+ dayOfMonth ?: string ;
23+ atTimeStart ?: string ;
24+ atTimeEnd ?: string ;
25+ timezone : string ;
26+ }
27+
28+ export const ScheduleSettingsModal = ( { isOpen, handleStart, handleClose, initialSettings } : ScheduleSettingsProps ) => {
29+ const { t } = useTranslation ( ) ;
30+ const [ schedule , setSchedule ] = useState < ScheduleSettings | null > ( null ) ;
31+ const [ settings , setSettings ] = useState < ScheduleSettings > ( {
32+ runEvery : 1 ,
33+ runEveryUnit : 'HOURS' ,
34+ startFrom : 'MONDAY' ,
35+ dayOfMonth : '1' ,
36+ atTimeStart : '00:00' ,
37+ atTimeEnd : '01:00' ,
38+ timezone : 'UTC'
39+ } ) ;
40+
41+ useEffect ( ( ) => {
42+ if ( initialSettings ) {
43+ setSettings ( initialSettings ) ;
44+ }
45+ } , [ initialSettings ] ) ;
46+
47+ const handleChange = ( field : keyof ScheduleSettings , value : string | number | boolean ) => {
48+ setSettings ( prev => ( { ...prev , [ field ] : value } ) ) ;
49+ } ;
50+
51+ const textStyle = {
52+ width : '150px' ,
53+ height : '52px' ,
54+ marginRight : '10px' ,
55+ } ;
56+
57+ const dropDownStyle = {
58+ marginTop : '2px' ,
59+ width : '150px' ,
60+ height : '59px' ,
61+ marginRight : '10px' ,
62+ } ;
63+
64+ const units = [
65+ 'MINUTES' ,
66+ 'HOURS' ,
67+ 'DAYS' ,
68+ 'WEEKS' ,
69+ 'MONTHS'
70+ ] ;
71+
72+ const days = [
73+ 'MONDAY' ,
74+ 'TUESDAY' ,
75+ 'WEDNESDAY' ,
76+ 'THURSDAY' ,
77+ 'FRIDAY' ,
78+ 'SATURDAY' ,
79+ 'SUNDAY'
80+ ] ;
81+
82+ const { recordingId, notify } = useGlobalInfoStore ( ) ;
83+
84+ const deleteRobotSchedule = ( ) => {
85+ if ( recordingId ) {
86+ deleteSchedule ( recordingId ) ;
87+ setSchedule ( null ) ;
88+ notify ( 'success' , t ( 'Schedule deleted successfully' ) ) ;
89+ } else {
90+ console . error ( 'No recording id provided' ) ;
91+ }
92+
93+ setSettings ( {
94+ runEvery : 1 ,
95+ runEveryUnit : 'HOURS' ,
96+ startFrom : 'MONDAY' ,
97+ dayOfMonth : '' ,
98+ atTimeStart : '00:00' ,
99+ atTimeEnd : '01:00' ,
100+ timezone : 'UTC'
101+ } ) ;
102+ } ;
103+
104+ const getRobotSchedule = async ( ) => {
105+ if ( recordingId ) {
106+ const scheduleData = await getSchedule ( recordingId ) ;
107+ setSchedule ( scheduleData ) ;
108+ } else {
109+ console . error ( 'No recording id provided' ) ;
110+ }
111+ }
112+
113+ useEffect ( ( ) => {
114+ if ( isOpen ) {
115+ const fetchSchedule = async ( ) => {
116+ await getRobotSchedule ( ) ;
117+ } ;
118+ fetchSchedule ( ) ;
119+ }
120+ } , [ isOpen ] ) ;
121+
122+ const getDayOrdinal = ( day : string | undefined ) => {
123+ if ( ! day ) return '' ;
124+ const lastDigit = day . slice ( - 1 ) ;
125+ const lastTwoDigits = day . slice ( - 2 ) ;
126+
127+ // Special cases for 11, 12, 13
128+ if ( [ '11' , '12' , '13' ] . includes ( lastTwoDigits ) ) {
129+ return t ( 'schedule_settings.labels.on_day.th' ) ;
130+ }
131+
132+ // Other cases
133+ switch ( lastDigit ) {
134+ case '1' : return t ( 'schedule_settings.labels.on_day.st' ) ;
135+ case '2' : return t ( 'schedule_settings.labels.on_day.nd' ) ;
136+ case '3' : return t ( 'schedule_settings.labels.on_day.rd' ) ;
137+ default : return t ( 'schedule_settings.labels.on_day.th' ) ;
138+ }
139+ } ;
140+
141+ return (
142+ < GenericModal
143+ isOpen = { isOpen }
144+ onClose = { handleClose }
145+ modalStyle = { modalStyle }
146+ >
147+ < Box sx = { {
148+ display : 'flex' ,
149+ flexDirection : 'column' ,
150+ alignItems : 'flex-start' ,
151+ padding : '20px' ,
152+ '& > *' : { marginBottom : '20px' } ,
153+ } } >
154+ < Typography variant = "h6" sx = { { marginBottom : '20px' } } > { t ( 'schedule_settings.title' ) } </ Typography >
155+ < >
156+ { schedule !== null ? (
157+ < >
158+ < Typography > { t ( 'schedule_settings.run_every' ) } : { schedule . runEvery } { schedule . runEveryUnit . toLowerCase ( ) } </ Typography >
159+ < Typography > { [ 'MONTHS' , 'WEEKS' ] . includes ( settings . runEveryUnit ) ? t ( 'schedule_settings.start_from' ) : t ( 'schedule_settings.start_from' ) } : { schedule . startFrom . charAt ( 0 ) . toUpperCase ( ) + schedule . startFrom . slice ( 1 ) . toLowerCase ( ) } </ Typography >
160+ { schedule . runEveryUnit === 'MONTHS' && (
161+ < Typography > { t ( 'schedule_settings.on_day' ) } : { schedule . dayOfMonth } { getDayOrdinal ( schedule . dayOfMonth ) } of the month</ Typography >
162+ ) }
163+ < Typography > { t ( 'schedule_settings.at_around' ) } : { schedule . atTimeStart } , { schedule . timezone } { t ( 'schedule_settings.timezone' ) } </ Typography >
164+ < Box mt = { 2 } display = "flex" justifyContent = "space-between" >
165+ < Button
166+ onClick = { deleteRobotSchedule }
167+ variant = "outlined"
168+ color = "error"
169+ >
170+ { t ( 'schedule_settings.buttons.delete_schedule' ) }
171+ </ Button >
172+ </ Box >
173+ </ >
174+ ) : (
175+ < >
176+ < Box sx = { { display : 'flex' , alignItems : 'center' , width : '100%' } } >
177+ < Typography sx = { { marginRight : '10px' } } > { t ( 'schedule_settings.labels.run_once_every' ) } </ Typography >
178+ < TextField
179+ type = "number"
180+ value = { settings . runEvery }
181+ onChange = { ( e ) => handleChange ( 'runEvery' , parseInt ( e . target . value ) ) }
182+ sx = { textStyle }
183+ inputProps = { { min : 1 } }
184+ />
185+ < Dropdown
186+ label = ""
187+ id = "runEveryUnit"
188+ value = { settings . runEveryUnit }
189+ handleSelect = { ( e ) => handleChange ( 'runEveryUnit' , e . target . value ) }
190+ sx = { dropDownStyle }
191+ >
192+ { units . map ( ( unit ) => (
193+ < MenuItem key = { unit } value = { unit } > { unit . charAt ( 0 ) . toUpperCase ( ) + unit . slice ( 1 ) . toLowerCase ( ) } </ MenuItem >
194+ ) ) }
195+ </ Dropdown >
196+ </ Box >
197+
198+ < Box sx = { { display : 'flex' , alignItems : 'center' , width : '100%' } } >
199+ < Typography sx = { { marginBottom : '5px' , marginRight : '25px' } } >
200+ { [ 'MONTHS' , 'WEEKS' ] . includes ( settings . runEveryUnit ) ? t ( 'schedule_settings.labels.start_from_label' ) : t ( 'schedule_settings.labels.start_from_label' ) }
201+ </ Typography >
202+ < Dropdown
203+ label = ""
204+ id = "startFrom"
205+ value = { settings . startFrom }
206+ handleSelect = { ( e ) => handleChange ( 'startFrom' , e . target . value ) }
207+ sx = { dropDownStyle }
208+ >
209+ { days . map ( ( day ) => (
210+ < MenuItem key = { day } value = { day } >
211+ { day . charAt ( 0 ) . toUpperCase ( ) + day . slice ( 1 ) . toLowerCase ( ) }
212+ </ MenuItem >
213+ ) ) }
214+ </ Dropdown >
215+ </ Box >
216+
217+ { settings . runEveryUnit === 'MONTHS' && (
218+ < Box sx = { { display : 'flex' , alignItems : 'center' , width : '100%' } } >
219+ < Typography sx = { { marginBottom : '5px' , marginRight : '25px' } } > { t ( 'schedule_settings.labels.on_day_of_month' ) } </ Typography >
220+ < TextField
221+ type = "number"
222+ value = { settings . dayOfMonth }
223+ onChange = { ( e ) => handleChange ( 'dayOfMonth' , e . target . value ) }
224+ sx = { textStyle }
225+ inputProps = { { min : 1 , max : 31 } }
226+ />
227+ </ Box >
228+ ) }
229+
230+ { [ 'MINUTES' , 'HOURS' ] . includes ( settings . runEveryUnit ) ? (
231+ < Box sx = { { display : 'flex' , alignItems : 'center' , width : '100%' } } >
232+ < Box sx = { { marginRight : '20px' } } >
233+ < Typography sx = { { marginBottom : '5px' } } > { t ( 'schedule_settings.labels.in_between' ) } </ Typography >
234+ < TextField
235+ type = "time"
236+ value = { settings . atTimeStart }
237+ onChange = { ( e ) => handleChange ( 'atTimeStart' , e . target . value ) }
238+ sx = { textStyle }
239+ />
240+ < TextField
241+ type = "time"
242+ value = { settings . atTimeEnd }
243+ onChange = { ( e ) => handleChange ( 'atTimeEnd' , e . target . value ) }
244+ sx = { textStyle }
245+ />
246+ </ Box >
247+ </ Box >
248+ ) : (
249+ < Box sx = { { display : 'flex' , alignItems : 'center' , width : '100%' } } >
250+ < Typography sx = { { marginBottom : '5px' , marginRight : '10px' } } > { t ( 'schedule_settings.at_around' ) } </ Typography >
251+ < TextField
252+ type = "time"
253+ value = { settings . atTimeStart }
254+ onChange = { ( e ) => handleChange ( 'atTimeStart' , e . target . value ) }
255+ sx = { textStyle }
256+ />
257+ </ Box >
258+ ) }
259+
260+ < Box sx = { { display : 'flex' , alignItems : 'center' , width : '100%' } } >
261+ < Typography sx = { { marginRight : '10px' } } > { t ( 'schedule_settings.timezone' ) } </ Typography >
262+ < Dropdown
263+ label = ""
264+ id = "timezone"
265+ value = { settings . timezone }
266+ handleSelect = { ( e ) => handleChange ( 'timezone' , e . target . value ) }
267+ sx = { dropDownStyle }
268+ >
269+ { validMomentTimezones . map ( ( tz ) => (
270+ < MenuItem key = { tz } value = { tz } > { tz . charAt ( 0 ) . toUpperCase ( ) + tz . slice ( 1 ) . toLowerCase ( ) } </ MenuItem >
271+ ) ) }
272+ </ Dropdown >
273+ </ Box >
274+ < Box mt = { 2 } display = "flex" justifyContent = "flex-end" >
275+ < Button onClick = { async ( ) => {
276+ const success = await handleStart ( settings ) ;
277+ if ( success ) {
278+ await getRobotSchedule ( ) ;
279+ }
280+ } } variant = "contained" color = "primary" >
281+ { t ( 'schedule_settings.buttons.save_schedule' ) }
282+ </ Button >
283+ < Button
284+ onClick = { handleClose }
285+ color = "primary"
286+ variant = "outlined"
287+ style = { { marginLeft : '10px' } }
288+ sx = { {
289+ color : '#ff00c3 !important' ,
290+ borderColor : '#ff00c3 !important' ,
291+ backgroundColor : 'whitesmoke !important' ,
292+ } } >
293+ { t ( 'schedule_settings.buttons.cancel' ) }
294+ </ Button >
295+ </ Box >
296+ </ >
297+ ) }
298+ </ >
299+ </ Box >
300+ </ GenericModal >
301+ ) ;
302+ } ;
303+
304+ const modalStyle = {
305+ top : '50%' ,
306+ left : '50%' ,
307+ transform : 'translate(-50%, -50%)' ,
308+ width : '40%' ,
309+ backgroundColor : 'background.paper' ,
310+ p : 4 ,
311+ height : 'fit-content' ,
312+ display : 'block' ,
313+ padding : '20px' ,
314+ } ;
0 commit comments