11import { default as Form } from "antd/es/form" ;
22import { default as Input } from "antd/es/input" ;
33import { default as ColorPicker } from "antd/es/color-picker" ;
4+ import { default as Switch } from "antd/es/switch" ;
45import { trans , getCalendarLocale } from "../../i18n/comps" ;
56import { createRef , useContext , useRef , useState , useEffect , useCallback , useMemo , Suspense } from "react" ;
67import dayjs from "dayjs" ;
@@ -11,14 +12,15 @@ import adaptivePlugin from "@fullcalendar/adaptive";
1112import dayGridPlugin from "@fullcalendar/daygrid" ;
1213import multiMonthPlugin from '@fullcalendar/multimonth' ;
1314import timeGridPlugin from "@fullcalendar/timegrid" ;
14- import interactionPlugin from "@fullcalendar/interaction" ;
15+ import interactionPlugin , { EventResizeDoneArg } from "@fullcalendar/interaction" ;
1516import listPlugin from "@fullcalendar/list" ;
1617import allLocales from "@fullcalendar/core/locales-all" ;
17- import { EventContentArg , DateSelectArg } from "@fullcalendar/core" ;
18+ import { EventContentArg , DateSelectArg , EventDropArg } from "@fullcalendar/core" ;
1819import momentPlugin from "@fullcalendar/moment" ;
1920
2021import ErrorBoundary from "./errorBoundary" ;
2122import { default as Tabs } from "antd/es/tabs" ;
23+ import { differenceBy , differenceWith , isEqual , filter , includes } from "lodash" ;
2224
2325import {
2426 isValidColor ,
@@ -54,6 +56,8 @@ import {
5456 migrateOldData ,
5557 controlItem ,
5658 depsConfig ,
59+ stateComp ,
60+ JSONObject ,
5761} from 'lowcoder-sdk' ;
5862
5963import {
@@ -79,6 +83,7 @@ import {
7983 resourceTimeGridHeaderToolbar ,
8084} from "./calendarConstants" ;
8185import { EventOptionControl } from "./eventOptionsControl" ;
86+ import { EventImpl } from "@fullcalendar/core/internal" ;
8287
8388function fixOldData ( oldData : any ) {
8489 if ( ! Boolean ( oldData ) ) return ;
@@ -196,6 +201,10 @@ let childrenMap: any = {
196201 currentPremiumView : dropdownControl ( DefaultWithPremiumViewOptions , "resourceTimelineDay" ) ,
197202 animationStyle : styleControl ( AnimationStyle , 'animationStyle' ) ,
198203 showVerticalScrollbar : withDefault ( BoolControl , false ) ,
204+ initialData : stateComp < JSONObject > ( { } ) ,
205+ updatedEvents : stateComp < JSONObject > ( { } ) ,
206+ insertedEvents : stateComp < JSONObject > ( { } ) ,
207+ deletedEvents : stateComp < JSONObject > ( { } ) ,
199208} ;
200209
201210// this should ensure backwards compatibility with older versions of the SDK
@@ -233,8 +242,9 @@ let CalendarBasicComp = (function () {
233242 currentFreeView ?: string ;
234243 currentPremiumView ?: string ;
235244 animationStyle ?:any ;
236- modalStyle ?:any
237- showVerticalScrollbar ?:boolean
245+ modalStyle ?:any ;
246+ showVerticalScrollbar ?:boolean ;
247+ initialData : Array < EventType > ;
238248 } , dispatch : any ) => {
239249 const comp = useContext ( EditorContext ) ?. getUICompByName (
240250 useContext ( CompNameContext )
@@ -243,11 +253,13 @@ let CalendarBasicComp = (function () {
243253 const theme = useContext ( ThemeContext ) ;
244254 const ref = createRef < HTMLDivElement > ( ) ;
245255 const editEvent = useRef < EventType > ( ) ;
256+ const initData = useRef < boolean > ( false ) ;
246257 const [ form ] = Form . useForm ( ) ;
247258 const [ left , setLeft ] = useState < number | undefined > ( undefined ) ;
248259 const [ licensed , setLicensed ] = useState < boolean > ( props . licenseKey !== "" ) ;
249260 const [ currentSlotLabelFormat , setCurrentSlotLabelFormat ] = useState ( slotLabelFormat ) ;
250-
261+ const [ initDataMap , setInitDataMap ] = useState < Record < string , number > > ( { } ) ;
262+
251263 useEffect ( ( ) => {
252264 setLicensed ( props . licenseKey !== "" ) ;
253265 } , [ props . licenseKey ] ) ;
@@ -290,27 +302,53 @@ let CalendarBasicComp = (function () {
290302 start : dayjs ( item . start , DateParser ) . format ( ) ,
291303 end : dayjs ( item . end , DateParser ) . format ( ) ,
292304 allDay : item . allDay ,
293- resourceId : item . resourceId ? item . resourceId : null ,
294- groupId : item . groupId ? item . groupId : null ,
305+ ... ( item . resourceId ? { resourceId : item . resourceId } : { } ) ,
306+ ... ( item . groupId ? { groupId : item . groupId } : { } ) ,
295307 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- } }
308+ extendedProps : { // Ensure color is in extendedProps
309+ color : isValidColor ( item . color || "" ) ? item . color : theme ?. theme ?. primary ,
310+ detail : item . detail ,
311+ titleColor : item . titleColor ,
312+ detailColor :item . detailColor ,
313+ titleFontWeight :item . titleFontWeight ,
314+ titleFontStyle :item . titleFontStyle ,
315+ detailFontWeight :item . detailFontWeight ,
316+ detailFontStyle :item . detailFontStyle ,
317+ animation :item ?. animation ,
318+ animationDelay :item ?. animationDelay ,
319+ animationDuration :item ?. animationDuration ,
320+ animationIterationCount :item ?. animationIterationCount
321+ }
322+ }
311323 } ) : [ currentEvents ] ;
312324 } , [ currentEvents , theme ] )
313325
326+ useEffect ( ( ) => {
327+ const mapData : Record < string , number > = { } ;
328+ events ?. forEach ( ( item : any , index : number ) => {
329+ mapData [ `${ item . id } ` ] = index ;
330+ } )
331+
332+ if ( initData . current ) {
333+ const difference = differenceWith ( events , props . initialData , isEqual ) ;
334+ const inserted = differenceBy ( difference , Object . keys ( initDataMap ) ?. map ( id => ( { id } ) ) , 'id' )
335+ const updated = filter ( difference , obj => includes ( Object . keys ( initDataMap ) , String ( obj . id ) ) ) ;
336+ const deleted = differenceBy ( props . initialData , Object . keys ( mapData ) ?. map ( id => ( { id } ) ) , 'id' )
337+
338+ comp . children ?. comp . children ?. updatedEvents . dispatchChangeValueAction ( updated ) ;
339+ comp . children ?. comp . children ?. insertedEvents . dispatchChangeValueAction ( inserted ) ;
340+ comp . children ?. comp . children ?. deletedEvents . dispatchChangeValueAction ( deleted ) ;
341+ }
342+
343+ if ( ! initData . current && events ?. length && comp ?. children ?. comp ?. children ?. initialData ) {
344+ setInitDataMap ( mapData ) ;
345+ comp ?. children ?. comp ?. children ?. initialData ?. dispatch ?.(
346+ comp ?. children ?. comp ?. children ?. initialData ?. changeValueAction ?.( [ ...events ] )
347+ ) ;
348+ initData . current = true ;
349+ }
350+ } , [ JSON . stringify ( events ) , comp ?. children ?. comp ?. children ?. initialData ] ) ;
351+
314352 const resources = useMemo ( ( ) => props . resources . value , [ props . resources . value ] ) ;
315353
316354 // list all plugins for Fullcalendar
@@ -370,12 +408,12 @@ let CalendarBasicComp = (function () {
370408 } , [ slotLabelFormat , slotLabelFormatWeek , slotLabelFormatMonth ] ) ;
371409
372410 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 (
411+ comp ? .children ?. comp . children . events . children . manual . children . manual . dispatch (
412+ comp ? .children ?. comp . children . events . children . manual . children . manual . setChildrensAction (
375413 data
376414 )
377415 ) ;
378- comp . children ?. comp . children . events . children . mapData . children . data . dispatchChangeValueAction (
416+ comp ? .children ?. comp . children . events . children . mapData . children . data . dispatchChangeValueAction (
379417 JSON . stringify ( data )
380418 ) ;
381419 props . onEvent ( "change" ) ;
@@ -506,6 +544,24 @@ let CalendarBasicComp = (function () {
506544 >
507545 < Input />
508546 </ Form . Item >
547+ < Form . Item
548+ label = { trans ( "calendar.eventStartTime" ) }
549+ name = "start"
550+ >
551+ < Input />
552+ </ Form . Item >
553+ < Form . Item
554+ label = { trans ( "calendar.eventEndTime" ) }
555+ name = "end"
556+ >
557+ < Input />
558+ </ Form . Item >
559+ < Form . Item
560+ label = { trans ( "calendar.eventAllDay" ) }
561+ name = "allDay"
562+ >
563+ < Switch />
564+ </ Form . Item >
509565 </ FormWrapper >
510566 </ Tabs . TabPane >
511567 < Tabs . TabPane tab = { trans ( "calendar.colorStyles" ) } key = "2" >
@@ -768,12 +824,35 @@ let CalendarBasicComp = (function () {
768824 showModal ( event , false ) ;
769825 } , [ editEvent , showModal ] ) ;
770826
771- const handleDrop = useCallback ( ( ) => {
827+ const updateEventsOnDragOrResize = useCallback ( ( eventInfo : EventImpl ) => {
828+ const { extendedProps, title, ...event } = eventInfo . toJSON ( ) ;
829+
830+ let eventsList = [ ...props . events ] ;
831+ const eventIdx = eventsList . findIndex (
832+ ( item : EventType ) => item . id === event . id
833+ ) ;
834+ if ( eventIdx > - 1 ) {
835+ eventsList [ eventIdx ] = {
836+ label : title ,
837+ ...event ,
838+ ...extendedProps ,
839+ } ;
840+ handleEventDataChange ( eventsList ) ;
841+ }
842+ } , [ props . events , handleEventDataChange ] ) ;
843+
844+ const handleDrop = useCallback ( ( eventInfo : EventDropArg ) => {
845+ updateEventsOnDragOrResize ( eventInfo . event ) ;
846+
772847 if ( typeof props . onDropEvent === 'function' ) {
773- props . onDropEvent ( "dropEvent " ) ;
848+ props . onDropEvent ( "drop " ) ;
774849 }
775- } , [ props . onDropEvent ] ) ;
776-
850+ } , [ props . onDropEvent , updateEventsOnDragOrResize ] ) ;
851+
852+ const handleResize = useCallback ( ( eventInfo : EventResizeDoneArg ) => {
853+ updateEventsOnDragOrResize ( eventInfo . event ) ;
854+ } , [ props . onDropEvent , updateEventsOnDragOrResize ] ) ;
855+
777856 return (
778857 < Wrapper
779858 ref = { ref }
@@ -790,7 +869,7 @@ let CalendarBasicComp = (function () {
790869 slotEventOverlap = { false }
791870 events = { events }
792871 dayHeaders = { true }
793- dayHeaderFormat = { { weekday : 'short' , month : 'numeric' , day : 'numeric' , omitCommas : true } }
872+ // dayHeaderFormat={{ weekday: 'short', month: 'numeric', day: 'numeric', omitCommas: true }}
794873 expandRows = { true }
795874 multiMonthMinWidth = { 250 }
796875 nowIndicator = { true }
@@ -880,11 +959,13 @@ let CalendarBasicComp = (function () {
880959 props . onEvent ( "change" ) ;
881960 }
882961 } }
883- eventDragStop = { ( info ) => {
884- if ( info . view ) {
885- handleDrop ( ) ;
962+ eventDragStart = { ( ) => {
963+ if ( typeof props . onDropEvent === 'function' ) {
964+ props . onDropEvent ( "drag" ) ;
886965 }
887966 } }
967+ eventDrop = { handleDrop }
968+ eventResize = { handleResize }
888969 />
889970 </ ErrorBoundary >
890971 </ Wrapper >
@@ -1007,6 +1088,30 @@ const TmpCalendarComp = withExposingConfigs(CalendarBasicComp, [
10071088 return input . events . filter ( event => Boolean ( event . resourceId ) ) ;
10081089 } ,
10091090 } ) ,
1091+ depsConfig ( {
1092+ name : "toUpdatedEvents" ,
1093+ desc : trans ( "calendar.updatedEvents" ) ,
1094+ depKeys : [ "updatedEvents" ] ,
1095+ func : ( input : { updatedEvents : any [ ] ; } ) => {
1096+ return input . updatedEvents ;
1097+ } ,
1098+ } ) ,
1099+ depsConfig ( {
1100+ name : "toInsertedEvents" ,
1101+ desc : trans ( "calendar.insertedEvents" ) ,
1102+ depKeys : [ "insertedEvents" ] ,
1103+ func : ( input : { insertedEvents : any [ ] ; } ) => {
1104+ return input . insertedEvents ;
1105+ } ,
1106+ } ) ,
1107+ depsConfig ( {
1108+ name : "toDeletedEvents" ,
1109+ desc : trans ( "calendar.deletedEvents" ) ,
1110+ depKeys : [ "deletedEvents" ] ,
1111+ func : ( input : { deletedEvents : any [ ] ; } ) => {
1112+ return input . deletedEvents ;
1113+ } ,
1114+ } ) ,
10101115] ) ;
10111116
10121117let CalendarComp = withMethodExposing ( TmpCalendarComp , [
@@ -1124,7 +1229,43 @@ let CalendarComp = withMethodExposing(TmpCalendarComp, [
11241229 const viewKey = comp . children . licenseKey . getView ( ) === "" ? 'defaultFreeView' : 'defaultPremiumView' ;
11251230 comp . children [ "viewKey" ] . dispatchChangeValueAction ( "multiMonthYear" ) ;
11261231 }
1127- }
1232+ } ,
1233+ {
1234+ method : {
1235+ name : "clearUpdatedEvents" ,
1236+ detail : "Clear updated events list" ,
1237+ params : [ ] ,
1238+ } ,
1239+ execute : ( comp ) => {
1240+ comp ?. children ?. updatedEvents . dispatch (
1241+ comp ?. children ?. updatedEvents . changeValueAction ( [ ] )
1242+ ) ;
1243+ }
1244+ } ,
1245+ {
1246+ method : {
1247+ name : "clearInsertedEvents" ,
1248+ detail : "Clear inserted events list" ,
1249+ params : [ ] ,
1250+ } ,
1251+ execute : ( comp ) => {
1252+ comp ?. children ?. insertedEvents . dispatch (
1253+ comp ?. children ?. insertedEvents . changeValueAction ( [ ] )
1254+ ) ;
1255+ }
1256+ } ,
1257+ {
1258+ method : {
1259+ name : "clearDeletedEvents" ,
1260+ detail : "Clear deleted events list" ,
1261+ params : [ ] ,
1262+ } ,
1263+ execute : ( comp ) => {
1264+ comp ?. children ?. deletedEvents . dispatch (
1265+ comp ?. children ?. deletedEvents . changeValueAction ( [ ] )
1266+ ) ;
1267+ }
1268+ } ,
11281269 ] ) ;
11291270
11301271
0 commit comments