1
1
import { default as Form } from "antd/es/form" ;
2
2
import { default as Input } from "antd/es/input" ;
3
3
import { default as ColorPicker } from "antd/es/color-picker" ;
4
+ import { default as Switch } from "antd/es/switch" ;
4
5
import { trans , getCalendarLocale } from "../../i18n/comps" ;
5
6
import { createRef , useContext , useRef , useState , useEffect , useCallback , useMemo , Suspense } from "react" ;
6
7
import dayjs from "dayjs" ;
@@ -19,6 +20,7 @@ import momentPlugin from "@fullcalendar/moment";
19
20
20
21
import ErrorBoundary from "./errorBoundary" ;
21
22
import { default as Tabs } from "antd/es/tabs" ;
23
+ import { differenceBy , differenceWith , isEqual , filter , includes } from "lodash" ;
22
24
23
25
import {
24
26
isValidColor ,
@@ -54,6 +56,8 @@ import {
54
56
migrateOldData ,
55
57
controlItem ,
56
58
depsConfig ,
59
+ stateComp ,
60
+ JSONObject ,
57
61
} from 'lowcoder-sdk' ;
58
62
59
63
import {
@@ -196,6 +200,10 @@ let childrenMap: any = {
196
200
currentPremiumView :dropdownControl ( DefaultWithPremiumViewOptions , "resourceTimelineDay" ) ,
197
201
animationStyle :styleControl ( AnimationStyle , 'animationStyle' ) ,
198
202
showVerticalScrollbar :withDefault ( BoolControl , false ) ,
203
+ initialData :stateComp < JSONObject > ( { } ) ,
204
+ updatedEvents :stateComp < JSONObject > ( { } ) ,
205
+ insertedEvents :stateComp < JSONObject > ( { } ) ,
206
+ deletedEvents :stateComp < JSONObject > ( { } ) ,
199
207
} ;
200
208
201
209
// this should ensure backwards compatibility with older versions of the SDK
@@ -233,8 +241,9 @@ let CalendarBasicComp = (function () {
233
241
currentFreeView ?:string ;
234
242
currentPremiumView ?:string ;
235
243
animationStyle ?:any ;
236
- modalStyle ?:any
237
- showVerticalScrollbar ?:boolean
244
+ modalStyle ?:any ;
245
+ showVerticalScrollbar ?:boolean ;
246
+ initialData :Array < EventType > ;
238
247
} , dispatch :any ) => {
239
248
const comp = useContext ( EditorContext ) ?. getUICompByName (
240
249
useContext ( CompNameContext )
@@ -243,11 +252,13 @@ let CalendarBasicComp = (function () {
243
252
const theme = useContext ( ThemeContext ) ;
244
253
const ref = createRef < HTMLDivElement > ( ) ;
245
254
const editEvent = useRef < EventType > ( ) ;
255
+ const initData = useRef < boolean > ( false ) ;
246
256
const [ form ] = Form . useForm ( ) ;
247
257
const [ left , setLeft ] = useState < number | undefined > ( undefined ) ;
248
258
const [ licensed , setLicensed ] = useState < boolean > ( props . licenseKey !== "" ) ;
249
259
const [ currentSlotLabelFormat , setCurrentSlotLabelFormat ] = useState ( slotLabelFormat ) ;
250
-
260
+ const [ initDataMap , setInitDataMap ] = useState < Record < string , number > > ( { } ) ;
261
+
251
262
useEffect ( ( ) => {
252
263
setLicensed ( props . licenseKey !== "" ) ;
253
264
} , [ props . licenseKey ] ) ;
@@ -290,27 +301,53 @@ let CalendarBasicComp = (function () {
290
301
start :dayjs ( item . start , DateParser ) . format ( ) ,
291
302
end :dayjs ( item . end , DateParser ) . format ( ) ,
292
303
allDay :item . allDay ,
293
- resourceId : item . resourceId ?item . resourceId : null ,
294
- groupId : item . groupId ?item . groupId : null ,
304
+ ... ( item . resourceId ?{ resourceId : item . resourceId } : { } ) ,
305
+ ... ( item . groupId ?{ groupId : item . groupId } : { } ) ,
295
306
backgroundColor :item . backgroundColor ,
296
- extendedProps :{
297
- color :isValidColor ( item . color || "" ) ?item . color :theme ?. theme ?. primary ,
298
- ... ( item . groupId ? { groupId :item . groupId } : { } ) , // Ensure color is in extendedProps
299
- detail : item . detail ,
300
- titleColor :item . titleColor ,
301
- detailColor :item . detailColor ,
302
- titleFontWeight :item . titleFontWeight ,
303
- titleFontStyle :item . titleFontStyle ,
304
- detailFontWeight :item . detailFontWeight ,
305
- detailFontStyle :item . detailFontStyle ,
306
- animation :item ?. animation ,
307
- animationDelay :item ?. animationDelay ,
308
- animationDuration :item ?. animationDuration ,
309
- animationIterationCount : item ?. animationIterationCount
310
- } }
307
+ extendedProps :{ // Ensure color is in extendedProps
308
+ color :isValidColor ( item . color || "" ) ?item . color :theme ?. theme ?. primary ,
309
+ detail :item . detail ,
310
+ titleColor : item . titleColor ,
311
+ detailColor :item . detailColor ,
312
+ titleFontWeight :item . titleFontWeight ,
313
+ titleFontStyle :item . titleFontStyle ,
314
+ detailFontWeight :item . detailFontWeight ,
315
+ detailFontStyle :item . detailFontStyle ,
316
+ animation :item ?. animation ,
317
+ animationDelay :item ?. animationDelay ,
318
+ animationDuration :item ?. animationDuration ,
319
+ animationIterationCount :item ?. animationIterationCount
320
+ }
321
+ }
311
322
} ) :[ currentEvents ] ;
312
323
} , [ currentEvents , theme ] )
313
324
325
+ useEffect ( ( ) => {
326
+ const mapData :Record < string , number > = { } ;
327
+ events ?. forEach ( ( item :any , index :number ) => {
328
+ mapData [ `${ item . id } ` ] = index ;
329
+ } )
330
+
331
+ if ( initData . current ) {
332
+ const difference = differenceWith ( events , props . initialData , isEqual ) ;
333
+ const inserted = differenceBy ( difference , Object . keys ( initDataMap ) ?. map ( id => ( { id} ) ) , 'id' )
334
+ const updated = filter ( difference , obj => includes ( Object . keys ( initDataMap ) , String ( obj . id ) ) ) ;
335
+ const deleted = differenceBy ( props . initialData , Object . keys ( mapData ) ?. map ( id => ( { id} ) ) , 'id' )
336
+
337
+ comp . children ?. comp . children ?. updatedEvents . dispatchChangeValueAction ( updated ) ;
338
+ comp . children ?. comp . children ?. insertedEvents . dispatchChangeValueAction ( inserted ) ;
339
+ comp . children ?. comp . children ?. deletedEvents . dispatchChangeValueAction ( deleted ) ;
340
+ }
341
+
342
+ if ( ! initData . current && events ?. length && comp ?. children ?. comp ?. children ?. initialData ) {
343
+ setInitDataMap ( mapData ) ;
344
+ comp ?. children ?. comp ?. children ?. initialData ?. dispatch ?.(
345
+ comp ?. children ?. comp ?. children ?. initialData ?. changeValueAction ?.( [ ...events ] )
346
+ ) ;
347
+ initData . current = true ;
348
+ }
349
+ } , [ JSON . stringify ( events ) , comp ?. children ?. comp ?. children ?. initialData ] ) ;
350
+
314
351
const resources = useMemo ( ( ) => props . resources . value , [ props . resources . value ] ) ;
315
352
316
353
// list all plugins for Fullcalendar
@@ -370,12 +407,12 @@ let CalendarBasicComp = (function () {
370
407
} , [ slotLabelFormat , slotLabelFormatWeek , slotLabelFormatMonth ] ) ;
371
408
372
409
const handleEventDataChange = useCallback ( ( data :Array < Record < string , any > > ) => {
373
- comp . children ?. comp . children . events . children . manual . children . manual . dispatch (
374
- comp . children ?. comp . children . events . children . manual . children . manual . setChildrensAction (
410
+ comp ? .children ?. comp . children . events . children . manual . children . manual . dispatch (
411
+ comp ? .children ?. comp . children . events . children . manual . children . manual . setChildrensAction (
375
412
data
376
413
)
377
414
) ;
378
- comp . children ?. comp . children . events . children . mapData . children . data . dispatchChangeValueAction (
415
+ comp ? .children ?. comp . children . events . children . mapData . children . data . dispatchChangeValueAction (
379
416
JSON . stringify ( data )
380
417
) ;
381
418
props . onEvent ( "change" ) ;
@@ -506,6 +543,24 @@ let CalendarBasicComp = (function () {
506
543
>
507
544
< Input />
508
545
</ Form . Item >
546
+ < Form . Item
547
+ label = { trans ( "calendar.eventStartTime" ) }
548
+ name = "start"
549
+ >
550
+ < Input />
551
+ </ Form . Item >
552
+ < Form . Item
553
+ label = { trans ( "calendar.eventEndTime" ) }
554
+ name = "end"
555
+ >
556
+ < Input />
557
+ </ Form . Item >
558
+ < Form . Item
559
+ label = { trans ( "calendar.eventAllDay" ) }
560
+ name = "allDay"
561
+ >
562
+ < Switch />
563
+ </ Form . Item >
509
564
</ FormWrapper >
510
565
</ Tabs . TabPane >
511
566
< Tabs . TabPane tab = { trans ( "calendar.colorStyles" ) } key = "2" >
@@ -768,12 +823,21 @@ let CalendarBasicComp = (function () {
768
823
showModal ( event , false ) ;
769
824
} , [ editEvent , showModal ] ) ;
770
825
771
- const handleDrop = useCallback ( ( ) => {
826
+ const handleDrop = useCallback ( ( eventInfo :EventType ) => {
827
+ let eventsList = [ ...props . events ] ;
828
+ const eventIdx = eventsList . findIndex (
829
+ ( item :EventType ) => item . id === eventInfo . id
830
+ ) ;
831
+ if ( eventIdx > - 1 ) {
832
+ eventsList [ eventIdx ] = eventInfo ;
833
+ handleEventDataChange ( eventsList ) ;
834
+ }
835
+
772
836
if ( typeof props . onDropEvent === 'function' ) {
773
837
props . onDropEvent ( "dropEvent" ) ;
774
838
}
775
839
} , [ props . onDropEvent ] ) ;
776
-
840
+
777
841
return (
778
842
< Wrapper
779
843
ref = { ref }
@@ -880,9 +944,13 @@ let CalendarBasicComp = (function () {
880
944
props . onEvent ( "change" ) ;
881
945
}
882
946
} }
883
- eventDragStop = { ( info ) => {
947
+ eventDrop = { ( info ) => {
948
+ const { extendedProps, ...event } = info . event . toJSON ( ) ;
884
949
if ( info . view ) {
885
- handleDrop ( ) ;
950
+ handleDrop ( {
951
+ ...event ,
952
+ ...extendedProps ,
953
+ } ) ;
886
954
}
887
955
} }
888
956
/>
@@ -1007,6 +1075,30 @@ const TmpCalendarComp = withExposingConfigs(CalendarBasicComp, [
1007
1075
return input . events . filter ( event => Boolean ( event . resourceId ) ) ;
1008
1076
} ,
1009
1077
} ) ,
1078
+ depsConfig ( {
1079
+ name :"toUpdatedEvents" ,
1080
+ desc :trans ( "calendar.updatedEvents" ) ,
1081
+ depKeys :[ "updatedEvents" ] ,
1082
+ func :( input :{ updatedEvents :any [ ] ; } ) => {
1083
+ return input . updatedEvents ;
1084
+ } ,
1085
+ } ) ,
1086
+ depsConfig ( {
1087
+ name :"toInsertedEvents" ,
1088
+ desc :trans ( "calendar.insertedEvents" ) ,
1089
+ depKeys :[ "insertedEvents" ] ,
1090
+ func :( input :{ insertedEvents :any [ ] ; } ) => {
1091
+ return input . insertedEvents ;
1092
+ } ,
1093
+ } ) ,
1094
+ depsConfig ( {
1095
+ name :"toDeletedEvents" ,
1096
+ desc :trans ( "calendar.deletedEvents" ) ,
1097
+ depKeys :[ "deletedEvents" ] ,
1098
+ func :( input :{ deletedEvents :any [ ] ; } ) => {
1099
+ return input . deletedEvents ;
1100
+ } ,
1101
+ } ) ,
1010
1102
] ) ;
1011
1103
1012
1104
let CalendarComp = withMethodExposing ( TmpCalendarComp , [
@@ -1124,7 +1216,43 @@ let CalendarComp = withMethodExposing(TmpCalendarComp, [
1124
1216
const viewKey = comp . children . licenseKey . getView ( ) === "" ?'defaultFreeView' :'defaultPremiumView' ;
1125
1217
comp . children [ "viewKey" ] . dispatchChangeValueAction ( "multiMonthYear" ) ;
1126
1218
}
1127
- }
1219
+ } ,
1220
+ {
1221
+ method :{
1222
+ name :"clearUpdatedEvents" ,
1223
+ detail :"Clear updated events list" ,
1224
+ params :[ ] ,
1225
+ } ,
1226
+ execute :( comp ) => {
1227
+ comp ?. children ?. updatedEvents . dispatch (
1228
+ comp ?. children ?. updatedEvents . changeValueAction ( [ ] )
1229
+ ) ;
1230
+ }
1231
+ } ,
1232
+ {
1233
+ method :{
1234
+ name :"clearInsertedEvents" ,
1235
+ detail :"Clear inserted events list" ,
1236
+ params :[ ] ,
1237
+ } ,
1238
+ execute :( comp ) => {
1239
+ comp ?. children ?. insertedEvents . dispatch (
1240
+ comp ?. children ?. insertedEvents . changeValueAction ( [ ] )
1241
+ ) ;
1242
+ }
1243
+ } ,
1244
+ {
1245
+ method :{
1246
+ name :"clearDeletedEvents" ,
1247
+ detail :"Clear deleted events list" ,
1248
+ params :[ ] ,
1249
+ } ,
1250
+ execute :( comp ) => {
1251
+ comp ?. children ?. deletedEvents . dispatch (
1252
+ comp ?. children ?. deletedEvents . changeValueAction ( [ ] )
1253
+ ) ;
1254
+ }
1255
+ } ,
1128
1256
] ) ;
1129
1257
1130
1258