Skip to content

Commit 62c5dec

Browse files
expose inserted,updated and deleted events + added startTime,endTime and allDay in edit modal + event dragging fixes
1 parent 5987c18 commit 62c5dec

File tree

3 files changed

+178
-28
lines changed

3 files changed

+178
-28
lines changed

client/packages/lowcoder-comps/src/comps/calendarComp/calendarComp.tsx

Lines changed: 156 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { default as Form } from "antd/es/form";
22
import { default as Input } from "antd/es/input";
33
import { default as ColorPicker } from "antd/es/color-picker";
4+
import { default as Switch } from "antd/es/switch";
45
import { trans, getCalendarLocale } from "../../i18n/comps";
56
import { createRef, useContext, useRef, useState, useEffect, useCallback, useMemo, Suspense } from "react";
67
import dayjs from "dayjs";
@@ -19,6 +20,7 @@ import momentPlugin from "@fullcalendar/moment";
1920

2021
import ErrorBoundary from "./errorBoundary";
2122
import { default as Tabs } from "antd/es/tabs";
23+
import { differenceBy, differenceWith, isEqual, filter, includes } from "lodash";
2224

2325
import {
2426
isValidColor,
@@ -54,6 +56,8 @@ import {
5456
migrateOldData,
5557
controlItem,
5658
depsConfig,
59+
stateComp,
60+
JSONObject,
5761
} from 'lowcoder-sdk';
5862

5963
import {
@@ -196,6 +200,10 @@ let childrenMap: any = {
196200
currentPremiumView: dropdownControl(DefaultWithPremiumViewOptions, "resourceTimelineDay"),
197201
animationStyle: styleControl(AnimationStyle, 'animationStyle'),
198202
showVerticalScrollbar: withDefault(BoolControl, false),
203+
initialData: stateComp<JSONObject>({}),
204+
updatedEvents: stateComp<JSONObject>({}),
205+
insertedEvents: stateComp<JSONObject>({}),
206+
deletedEvents: stateComp<JSONObject>({}),
199207
};
200208

201209
// this should ensure backwards compatibility with older versions of the SDK
@@ -233,8 +241,9 @@ let CalendarBasicComp = (function () {
233241
currentFreeView?: string;
234242
currentPremiumView?: string;
235243
animationStyle?:any;
236-
modalStyle?:any
237-
showVerticalScrollbar?:boolean
244+
modalStyle?:any;
245+
showVerticalScrollbar?:boolean;
246+
initialData: Array<EventType>;
238247
}, dispatch: any) => {
239248
const comp = useContext(EditorContext)?.getUICompByName(
240249
useContext(CompNameContext)
@@ -243,11 +252,13 @@ let CalendarBasicComp = (function () {
243252
const theme = useContext(ThemeContext);
244253
const ref = createRef<HTMLDivElement>();
245254
const editEvent = useRef<EventType>();
255+
const initData = useRef<boolean>(false);
246256
const [form] = Form.useForm();
247257
const [left, setLeft] = useState<number | undefined>(undefined);
248258
const [licensed, setLicensed] = useState<boolean>(props.licenseKey !== "");
249259
const [currentSlotLabelFormat, setCurrentSlotLabelFormat] = useState(slotLabelFormat);
250-
260+
const [initDataMap, setInitDataMap] = useState<Record<string, number>>({});
261+
251262
useEffect(() => {
252263
setLicensed(props.licenseKey !== "");
253264
}, [props.licenseKey]);
@@ -290,27 +301,53 @@ let CalendarBasicComp = (function () {
290301
start: dayjs(item.start, DateParser).format(),
291302
end: dayjs(item.end, DateParser).format(),
292303
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 } : {}),
295306
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+
}
311322
}) : [currentEvents];
312323
}, [currentEvents, theme])
313324

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+
314351
const resources = useMemo(() => props.resources.value, [props.resources.value]);
315352

316353
// list all plugins for Fullcalendar
@@ -370,12 +407,12 @@ let CalendarBasicComp = (function () {
370407
}, [slotLabelFormat, slotLabelFormatWeek, slotLabelFormatMonth]);
371408

372409
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(
375412
data
376413
)
377414
);
378-
comp.children?.comp.children.events.children.mapData.children.data.dispatchChangeValueAction(
415+
comp?.children?.comp.children.events.children.mapData.children.data.dispatchChangeValueAction(
379416
JSON.stringify(data)
380417
);
381418
props.onEvent("change");
@@ -506,6 +543,24 @@ let CalendarBasicComp = (function () {
506543
>
507544
<Input />
508545
</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>
509564
</FormWrapper>
510565
</Tabs.TabPane>
511566
<Tabs.TabPane tab={trans("calendar.colorStyles")} key="2">
@@ -768,12 +823,21 @@ let CalendarBasicComp = (function () {
768823
showModal(event, false);
769824
}, [editEvent, showModal]);
770825

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+
772836
if (typeof props.onDropEvent === 'function') {
773837
props.onDropEvent("dropEvent");
774838
}
775839
}, [props.onDropEvent]);
776-
840+
777841
return (
778842
<Wrapper
779843
ref={ref}
@@ -880,9 +944,13 @@ let CalendarBasicComp = (function () {
880944
props.onEvent("change");
881945
}
882946
}}
883-
eventDragStop={(info) => {
947+
eventDrop={(info) => {
948+
const {extendedProps, ...event} = info.event.toJSON();
884949
if (info.view) {
885-
handleDrop();
950+
handleDrop({
951+
...event,
952+
...extendedProps,
953+
});
886954
}
887955
}}
888956
/>
@@ -1007,6 +1075,30 @@ const TmpCalendarComp = withExposingConfigs(CalendarBasicComp, [
10071075
return input.events.filter(event => Boolean(event.resourceId));
10081076
},
10091077
}),
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+
}),
10101102
]);
10111103

10121104
let CalendarComp = withMethodExposing(TmpCalendarComp, [
@@ -1124,7 +1216,43 @@ let CalendarComp = withMethodExposing(TmpCalendarComp, [
11241216
const viewKey = comp.children.licenseKey.getView() === "" ? 'defaultFreeView' : 'defaultPremiumView';
11251217
comp.children["viewKey"].dispatchChangeValueAction("multiMonthYear");
11261218
}
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+
},
11281256
]);
11291257

11301258

client/packages/lowcoder-comps/src/comps/calendarComp/calendarConstants.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,25 @@ export const defaultEvents = [
988988
end: dayjs().hour(21).minute(30).second(0).format(DATE_TIME_FORMAT),
989989
color: "#079968",
990990
},
991+
{
992+
id: "6",
993+
label: "Coding",
994+
start: dayjs().hour(15).minute(0).second(0).format(DATE_TIME_FORMAT),
995+
end: dayjs().hour(17).minute(30).second(0).format(DATE_TIME_FORMAT),
996+
color: "#079968",
997+
backgroundColor:"#ffffff",
998+
detail: 'Discuss project milestones and deliverables.',
999+
titleColor:"#000000",
1000+
detailColor:"#000000",
1001+
titleFontWeight:"normal",
1002+
titleFontStyle:"italic",
1003+
detailFontWeight:"normal",
1004+
detailFontStyle:"italic",
1005+
animation:"none",
1006+
animationDelay:"0s",
1007+
animationDuration:"0s",
1008+
animationIterationCount:"0",
1009+
},
9911010
];
9921011
export const resourcesEventsDefaultData = [
9931012
{

client/packages/lowcoder-comps/src/i18n/comps/locales/en.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,9 @@ export const en = {
271271
resourcesDefault: "Rooms",
272272
resourcesName: "Resource Name",
273273
resourcesEvents : "Resources Events Data",
274+
deletedEvents : "List of deleted events",
275+
updatedEvents : "List of updated events",
276+
insertedEvents : "List of inserted events",
274277
editable: "Editable",
275278
license: "Licence Key",
276279
licenseTooltip: "Get your licence key from https://fullcalendar.io/purchase to enable premium views like Resource Timeline and Resource Grid.",

0 commit comments

Comments
 (0)