@isma91/react-scheduler 4.0.3 → 4.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/.github/workflows/publish.yml +29 -0
  2. package/.github/workflows/tests.yml +35 -0
  3. package/.gitignore +32 -0
  4. package/.husky/pre-commit +2 -0
  5. package/.prettierignore +1 -0
  6. package/.prettierrc.json +7 -0
  7. package/.yarnrc.yml +1 -0
  8. package/README.md +1 -0
  9. package/dist/LICENSE +24 -0
  10. package/dist/README.md +174 -0
  11. package/{index.js → dist/index.js} +572 -558
  12. package/dist/package.json +65 -0
  13. package/{store → dist/store}/default.d.ts +2 -0
  14. package/{types.d.ts → dist/types.d.ts} +6 -0
  15. package/eslint.config.js +79 -0
  16. package/index.html +41 -0
  17. package/isma91-react-scheduler-4.0.5.tgz +0 -0
  18. package/jest.config.ts +194 -0
  19. package/package.json +76 -4
  20. package/public/favicon.ico +0 -0
  21. package/public/logo192.png +0 -0
  22. package/public/logo512.png +0 -0
  23. package/public/manifest.json +25 -0
  24. package/public/robots.txt +3 -0
  25. package/scripts/post-pack.js +34 -0
  26. package/src/App.tsx +25 -0
  27. package/src/Page1.tsx +67 -0
  28. package/src/events.tsx +227 -0
  29. package/src/index.tsx +21 -0
  30. package/src/lib/SchedulerComponent.tsx +78 -0
  31. package/src/lib/__tests__/index.test.tsx +24 -0
  32. package/src/lib/components/common/Cell.tsx +52 -0
  33. package/src/lib/components/common/LocaleArrow.tsx +38 -0
  34. package/src/lib/components/common/ResourceHeader.tsx +73 -0
  35. package/src/lib/components/common/Tabs.tsx +119 -0
  36. package/src/lib/components/common/TodayTypo.tsx +44 -0
  37. package/src/lib/components/common/WithResources.tsx +98 -0
  38. package/src/lib/components/events/Actions.tsx +65 -0
  39. package/src/lib/components/events/AgendaEventsList.tsx +126 -0
  40. package/src/lib/components/events/CurrentTimeBar.tsx +59 -0
  41. package/src/lib/components/events/EmptyAgenda.tsx +27 -0
  42. package/src/lib/components/events/EventItem.tsx +180 -0
  43. package/src/lib/components/events/EventItemPopover.tsx +179 -0
  44. package/src/lib/components/events/MonthEvents.tsx +141 -0
  45. package/src/lib/components/events/TodayEvents.tsx +99 -0
  46. package/src/lib/components/hoc/DateProvider.tsx +19 -0
  47. package/src/lib/components/inputs/DatePicker.tsx +95 -0
  48. package/src/lib/components/inputs/Input.tsx +113 -0
  49. package/src/lib/components/inputs/SelectInput.tsx +164 -0
  50. package/src/lib/components/month/MonthTable.tsx +207 -0
  51. package/src/lib/components/nav/DayDateBtn.tsx +77 -0
  52. package/src/lib/components/nav/MonthDateBtn.tsx +80 -0
  53. package/src/lib/components/nav/Navigation.tsx +201 -0
  54. package/src/lib/components/nav/WeekDateBtn.tsx +89 -0
  55. package/src/lib/components/week/WeekTable.tsx +229 -0
  56. package/src/lib/helpers/constants.ts +4 -0
  57. package/src/lib/helpers/generals.tsx +354 -0
  58. package/src/lib/hooks/useArrowDisable.ts +26 -0
  59. package/src/lib/hooks/useCellAttributes.ts +67 -0
  60. package/src/lib/hooks/useDragAttributes.ts +31 -0
  61. package/src/lib/hooks/useEventPermissions.ts +42 -0
  62. package/src/lib/hooks/useStore.ts +8 -0
  63. package/src/lib/hooks/useSyncScroll.ts +31 -0
  64. package/src/lib/hooks/useWindowResize.ts +37 -0
  65. package/src/lib/index.tsx +14 -0
  66. package/src/lib/positionManger/context.ts +14 -0
  67. package/src/lib/positionManger/provider.tsx +113 -0
  68. package/src/lib/positionManger/usePosition.ts +8 -0
  69. package/src/lib/store/context.ts +5 -0
  70. package/src/lib/store/default.ts +159 -0
  71. package/src/lib/store/provider.tsx +226 -0
  72. package/src/lib/store/types.ts +40 -0
  73. package/src/lib/styles/styles.ts +256 -0
  74. package/src/lib/types.ts +429 -0
  75. package/src/lib/views/Day.tsx +272 -0
  76. package/src/lib/views/DayAgenda.tsx +57 -0
  77. package/src/lib/views/Editor.tsx +258 -0
  78. package/src/lib/views/Month.tsx +82 -0
  79. package/src/lib/views/MonthAgenda.tsx +84 -0
  80. package/src/lib/views/Week.tsx +92 -0
  81. package/src/lib/views/WeekAgenda.tsx +81 -0
  82. package/src/vite-env.d.ts +3 -0
  83. package/tsconfig.build.json +5 -0
  84. package/tsconfig.json +27 -0
  85. package/vite.config.js +40 -0
  86. /package/{SchedulerComponent.d.ts → dist/SchedulerComponent.d.ts} +0 -0
  87. /package/{components → dist/components}/common/Cell.d.ts +0 -0
  88. /package/{components → dist/components}/common/LocaleArrow.d.ts +0 -0
  89. /package/{components → dist/components}/common/ResourceHeader.d.ts +0 -0
  90. /package/{components → dist/components}/common/Tabs.d.ts +0 -0
  91. /package/{components → dist/components}/common/TodayTypo.d.ts +0 -0
  92. /package/{components → dist/components}/common/WithResources.d.ts +0 -0
  93. /package/{components → dist/components}/events/Actions.d.ts +0 -0
  94. /package/{components → dist/components}/events/AgendaEventsList.d.ts +0 -0
  95. /package/{components → dist/components}/events/CurrentTimeBar.d.ts +0 -0
  96. /package/{components → dist/components}/events/EmptyAgenda.d.ts +0 -0
  97. /package/{components → dist/components}/events/EventItem.d.ts +0 -0
  98. /package/{components → dist/components}/events/EventItemPopover.d.ts +0 -0
  99. /package/{components → dist/components}/events/MonthEvents.d.ts +0 -0
  100. /package/{components → dist/components}/events/TodayEvents.d.ts +0 -0
  101. /package/{components → dist/components}/hoc/DateProvider.d.ts +0 -0
  102. /package/{components → dist/components}/inputs/DatePicker.d.ts +0 -0
  103. /package/{components → dist/components}/inputs/Input.d.ts +0 -0
  104. /package/{components → dist/components}/inputs/SelectInput.d.ts +0 -0
  105. /package/{components → dist/components}/month/MonthTable.d.ts +0 -0
  106. /package/{components → dist/components}/nav/DayDateBtn.d.ts +0 -0
  107. /package/{components → dist/components}/nav/MonthDateBtn.d.ts +0 -0
  108. /package/{components → dist/components}/nav/Navigation.d.ts +0 -0
  109. /package/{components → dist/components}/nav/WeekDateBtn.d.ts +0 -0
  110. /package/{components → dist/components}/week/WeekTable.d.ts +0 -0
  111. /package/{helpers → dist/helpers}/constants.d.ts +0 -0
  112. /package/{helpers → dist/helpers}/generals.d.ts +0 -0
  113. /package/{hooks → dist/hooks}/useArrowDisable.d.ts +0 -0
  114. /package/{hooks → dist/hooks}/useCellAttributes.d.ts +0 -0
  115. /package/{hooks → dist/hooks}/useDragAttributes.d.ts +0 -0
  116. /package/{hooks → dist/hooks}/useEventPermissions.d.ts +0 -0
  117. /package/{hooks → dist/hooks}/useStore.d.ts +0 -0
  118. /package/{hooks → dist/hooks}/useSyncScroll.d.ts +0 -0
  119. /package/{hooks → dist/hooks}/useWindowResize.d.ts +0 -0
  120. /package/{index.d.ts → dist/index.d.ts} +0 -0
  121. /package/{positionManger → dist/positionManger}/context.d.ts +0 -0
  122. /package/{positionManger → dist/positionManger}/provider.d.ts +0 -0
  123. /package/{positionManger → dist/positionManger}/usePosition.d.ts +0 -0
  124. /package/{store → dist/store}/context.d.ts +0 -0
  125. /package/{store → dist/store}/provider.d.ts +0 -0
  126. /package/{store → dist/store}/types.d.ts +0 -0
  127. /package/{styles → dist/styles}/styles.d.ts +0 -0
  128. /package/{views → dist/views}/Day.d.ts +0 -0
  129. /package/{views → dist/views}/DayAgenda.d.ts +0 -0
  130. /package/{views → dist/views}/Editor.d.ts +0 -0
  131. /package/{views → dist/views}/Month.d.ts +0 -0
  132. /package/{views → dist/views}/MonthAgenda.d.ts +0 -0
  133. /package/{views → dist/views}/Week.d.ts +0 -0
  134. /package/{views → dist/views}/WeekAgenda.d.ts +0 -0
@@ -0,0 +1,113 @@
1
+ import { useEffect, useState } from "react";
2
+ import { PositionManagerState, PositionContext } from "./context";
3
+ import useStore from "../hooks/useStore";
4
+ import { DefaultResource, FieldProps, ProcessedEvent, ResourceFields } from "../types";
5
+ import {
6
+ getResourcedEvents,
7
+ sortEventsByTheEarliest,
8
+ sortEventsByTheLengthest,
9
+ } from "../helpers/generals";
10
+ import { eachDayOfInterval, format } from "date-fns";
11
+ import { View } from "../components/nav/Navigation";
12
+
13
+ type Props = {
14
+ children: React.ReactNode;
15
+ };
16
+
17
+ const setEventPositions = (events: ProcessedEvent[]) => {
18
+ const slots: PositionManagerState["renderedSlots"][string] = {};
19
+ let position = 0;
20
+ for (let i = 0; i < events.length; i++) {
21
+ const event = events[i];
22
+ const eventLength = eachDayOfInterval({ start: event.start, end: event.end });
23
+ for (let i = 0; i < eventLength.length; i++) {
24
+ const day = format(eventLength[i], "yyyy-MM-dd");
25
+ if (slots[day]) {
26
+ const positions = Object.values(slots[day]);
27
+ while (positions.includes(position)) {
28
+ position += 1;
29
+ }
30
+ slots[day][event.event_id] = position;
31
+ } else {
32
+ slots[day] = { [event.event_id]: position };
33
+ }
34
+ }
35
+
36
+ // rest
37
+ position = 0;
38
+ }
39
+
40
+ return slots;
41
+ };
42
+
43
+ const setEventPositionsWithResources = (
44
+ events: ProcessedEvent[],
45
+ resources: DefaultResource[],
46
+ rFields: ResourceFields,
47
+ fields: FieldProps[],
48
+ view: View
49
+ ) => {
50
+ const sorted =
51
+ view === "month" ? sortEventsByTheLengthest(events) : sortEventsByTheEarliest(events);
52
+ const slots: PositionManagerState["renderedSlots"] = {};
53
+
54
+ if (resources.length) {
55
+ for (const resource of resources) {
56
+ const resourcedEvents = getResourcedEvents(sorted, resource, rFields, fields);
57
+ const positions = setEventPositions(resourcedEvents);
58
+ slots[resource[rFields.idField]] = positions;
59
+ }
60
+ } else {
61
+ slots.all = setEventPositions(sorted);
62
+ }
63
+ return slots;
64
+ };
65
+
66
+ export const PositionProvider = ({ children }: Props) => {
67
+ const { events, resources, resourceFields, fields, view } = useStore();
68
+ const [state, set] = useState<PositionManagerState>({
69
+ renderedSlots: setEventPositionsWithResources(events, resources, resourceFields, fields, view),
70
+ });
71
+
72
+ useEffect(() => {
73
+ set((prev) => ({
74
+ ...prev,
75
+ renderedSlots: setEventPositionsWithResources(
76
+ events,
77
+ resources,
78
+ resourceFields,
79
+ fields,
80
+ view
81
+ ),
82
+ }));
83
+ }, [events, fields, resourceFields, resources, view]);
84
+
85
+ const setRenderedSlot = (day: string, eventId: string, position: number, resourceId?: string) => {
86
+ set((prev) => ({
87
+ ...prev,
88
+ renderedSlots: {
89
+ ...prev.renderedSlots,
90
+ [resourceId || "all"]: {
91
+ ...prev.renderedSlots?.[resourceId || "all"],
92
+ [day]: prev.renderedSlots?.[resourceId || "all"]?.[day]
93
+ ? {
94
+ ...prev.renderedSlots?.[resourceId || "all"]?.[day],
95
+ [eventId]: position,
96
+ }
97
+ : { [eventId]: position },
98
+ },
99
+ },
100
+ }));
101
+ };
102
+
103
+ return (
104
+ <PositionContext.Provider
105
+ value={{
106
+ ...state,
107
+ setRenderedSlot,
108
+ }}
109
+ >
110
+ {children}
111
+ </PositionContext.Provider>
112
+ );
113
+ };
@@ -0,0 +1,8 @@
1
+ import { useContext } from "react";
2
+ import { PositionContext } from "./context";
3
+
4
+ const usePosition = () => {
5
+ return useContext(PositionContext);
6
+ };
7
+
8
+ export default usePosition;
@@ -0,0 +1,5 @@
1
+ import { createContext } from "react";
2
+ import { initialStore } from "./default";
3
+ import { Store } from "./types";
4
+
5
+ export const StoreContext = createContext<Store>(initialStore);
@@ -0,0 +1,159 @@
1
+ import { enUS } from "date-fns/locale";
2
+ import { SchedulerProps } from "../types";
3
+ import { getOneView, getTimeZonedDate } from "../helpers/generals";
4
+
5
+ const defaultMonth = {
6
+ weekDays: [0, 1, 2, 3, 4, 5, 6],
7
+ weekStartOn: 6,
8
+ startHour: 9,
9
+ endHour: 17,
10
+ navigation: true,
11
+ disableGoToDay: false,
12
+ };
13
+
14
+ const defaultWeek = {
15
+ weekDays: [0, 1, 2, 3, 4, 5, 6],
16
+ weekStartOn: 6,
17
+ startHour: 9,
18
+ endHour: 17,
19
+ step: 60,
20
+ navigation: true,
21
+ disableGoToDay: false,
22
+ };
23
+
24
+ const defaultDay = {
25
+ startHour: 9,
26
+ endHour: 17,
27
+ step: 60,
28
+ navigation: true,
29
+ };
30
+
31
+ const defaultResourceFields = {
32
+ idField: "assignee",
33
+ textField: "text",
34
+ subTextField: "subtext",
35
+ avatarField: "avatar",
36
+ colorField: "color",
37
+ };
38
+
39
+ const defaultTranslations = (trans: Partial<SchedulerProps["translations"]> = {}) => {
40
+ const { navigation, form, event, ...other } = trans;
41
+
42
+ return {
43
+ navigation: Object.assign(
44
+ {
45
+ month: "Month",
46
+ week: "Week",
47
+ day: "Day",
48
+ agenda: "Agenda",
49
+ today: "Today",
50
+ },
51
+ navigation
52
+ ),
53
+ form: Object.assign(
54
+ {
55
+ addTitle: "Add Event",
56
+ editTitle: "Edit Event",
57
+ confirm: "Confirm",
58
+ delete: "Delete",
59
+ cancel: "Cancel",
60
+ },
61
+ form
62
+ ),
63
+ event: Object.assign(
64
+ {
65
+ title: "Title",
66
+ start: "Start",
67
+ end: "End",
68
+ allDay: "All Day",
69
+ },
70
+ event
71
+ ),
72
+ ...Object.assign(
73
+ { moreEvents: "More...", loading: "Loading...", noDataToDisplay: "No data to display" },
74
+ other
75
+ ),
76
+ };
77
+ };
78
+
79
+ const defaultViews = (props: Partial<SchedulerProps>) => {
80
+ const { month, week, day } = props;
81
+ return {
82
+ month: month !== null ? Object.assign(defaultMonth, month) : null,
83
+ week: week !== null ? Object.assign(defaultWeek, week) : null,
84
+ day: day !== null ? Object.assign(defaultDay, day) : null,
85
+ };
86
+ };
87
+
88
+ export const defaultProps = (props: Partial<SchedulerProps>) => {
89
+ // We're pulling values out of props that we don't want to
90
+ // pass on, so there are 'unused' ones here.
91
+ const {
92
+ translations,
93
+ resourceFields,
94
+ view,
95
+ agenda,
96
+ selectedDate,
97
+ resourceViewMode,
98
+ direction,
99
+ dialogMaxWidth,
100
+ hourFormat,
101
+ ...otherProps
102
+ } = props;
103
+
104
+ const views = defaultViews(props);
105
+ const defaultView = view || "week";
106
+ const initialView = views[defaultView] ? defaultView : getOneView(views);
107
+ return {
108
+ ...views,
109
+ translations: defaultTranslations(translations),
110
+ resourceFields: Object.assign(defaultResourceFields, resourceFields),
111
+ view: initialView,
112
+ selectedDate: getTimeZonedDate(selectedDate || new Date(), props.timeZone),
113
+ height: 600,
114
+ navigation: true,
115
+ disableViewNavigator: false,
116
+ events: [],
117
+ fields: [],
118
+ loading: undefined,
119
+ customEditor: undefined,
120
+ onConfirm: undefined,
121
+ onDelete: undefined,
122
+ viewerExtraComponent: undefined,
123
+ resources: [],
124
+ resourceHeaderComponent: undefined,
125
+ resourceViewMode: resourceViewMode || "default",
126
+ direction: direction || "ltr",
127
+ dialogMaxWidth: dialogMaxWidth || "md",
128
+ locale: enUS,
129
+ deletable: true,
130
+ editable: true,
131
+ hourFormat: hourFormat || "12",
132
+ draggable: true,
133
+ agenda,
134
+ enableAgenda: typeof agenda === "undefined" || agenda,
135
+ showCurrentTimeBar: true,
136
+ forceInlineMultiDay: false,
137
+ ...otherProps,
138
+ };
139
+ };
140
+
141
+ export const initialStore = {
142
+ ...defaultProps({}),
143
+ setProps: () => {},
144
+ dialog: false,
145
+ selectedRange: undefined,
146
+ selectedEvent: undefined,
147
+ selectedResource: undefined,
148
+ handleState: () => {},
149
+ getViews: () => [],
150
+ toggleAgenda: () => {},
151
+ triggerDialog: () => {},
152
+ triggerLoading: () => {},
153
+ handleGotoDay: () => {},
154
+ confirmEvent: () => {},
155
+ setCurrentDragged: () => {},
156
+ onDrop: () => {},
157
+ _refetchToken: 0,
158
+ refetch: () => {},
159
+ };
@@ -0,0 +1,226 @@
1
+ import { DragEvent, useEffect, useState } from "react";
2
+ import { EventActions, ProcessedEvent, SchedulerProps } from "../types";
3
+ import { defaultProps, initialStore } from "./default";
4
+ import { StoreContext } from "./context";
5
+ import { SchedulerState, SelectedRange, Store } from "./types";
6
+ import { arraytizeFieldVal, getAvailableViews } from "../helpers/generals";
7
+ import { addMinutes, differenceInMinutes, isEqual } from "date-fns";
8
+ import { View } from "../components/nav/Navigation";
9
+
10
+ type Props = {
11
+ children: React.ReactNode;
12
+ initial: Partial<SchedulerProps>;
13
+ };
14
+
15
+ export const StoreProvider = ({ children, initial }: Props) => {
16
+ const [state, set] = useState<Store>({ ...initialStore, ...defaultProps(initial) });
17
+
18
+ useEffect(() => {
19
+ set((prev) => ({
20
+ ...prev,
21
+ onEventDrop: initial.onEventDrop,
22
+ customEditor: initial.customEditor,
23
+ customHeaderContent: initial.customHeaderContent,
24
+ // Only sync events if NOT using getRemoteEvents
25
+ // Otherwise, let the internal state manage events
26
+ ...(initial.getRemoteEvents ? {} : { events: initial.events || [] }),
27
+ }));
28
+ }, [
29
+ initial.onEventDrop,
30
+ initial.customEditor,
31
+ initial.events,
32
+ initial.customHeaderContent,
33
+ initial.getRemoteEvents,
34
+ ]);
35
+
36
+ useEffect(() => {
37
+ if ("undefined" !== typeof initial.loading) {
38
+ set((prev) => ({ ...prev, loading: initial.loading }));
39
+ }
40
+ }, [initial.loading]);
41
+
42
+ const handleState = (value: SchedulerState[keyof SchedulerState], name: keyof SchedulerState) => {
43
+ set((prev) => ({ ...prev, [name]: value }));
44
+ };
45
+
46
+ const getViews = () => {
47
+ return getAvailableViews(state);
48
+ };
49
+
50
+ const toggleAgenda = () => {
51
+ set((prev) => {
52
+ const newStatus = !prev.agenda;
53
+
54
+ if (state.onViewChange && typeof state.onViewChange === "function") {
55
+ state.onViewChange(state.view, newStatus);
56
+ }
57
+
58
+ return { ...prev, agenda: newStatus };
59
+ });
60
+ };
61
+
62
+ const triggerDialog = (status: boolean, selected?: SelectedRange | ProcessedEvent) => {
63
+ const isEvent = selected as ProcessedEvent;
64
+
65
+ set((prev) => ({
66
+ ...prev,
67
+ dialog: status,
68
+ selectedRange: isEvent?.event_id
69
+ ? undefined
70
+ : isEvent || {
71
+ start: new Date(),
72
+ end: new Date(Date.now() + 60 * 60 * 1000),
73
+ },
74
+ selectedEvent: isEvent?.event_id ? isEvent : undefined,
75
+ selectedResource: isEvent?.[state.resourceFields?.idField],
76
+ }));
77
+ };
78
+
79
+ const triggerLoading = (status: boolean) => {
80
+ // Trigger if not out-sourced by props
81
+ if (typeof initial.loading === "undefined") {
82
+ set((prev) => ({ ...prev, loading: status }));
83
+ }
84
+ };
85
+
86
+ const handleGotoDay = (day: Date) => {
87
+ const currentViews = getViews();
88
+ let view: View | undefined;
89
+ if (currentViews.includes("day")) {
90
+ view = "day";
91
+ set((prev) => ({ ...prev, view: "day", selectedDate: day }));
92
+ } else if (currentViews.includes("week")) {
93
+ view = "week";
94
+ set((prev) => ({ ...prev, view: "week", selectedDate: day }));
95
+ } else {
96
+ console.warn("No Day/Week views available");
97
+ }
98
+
99
+ if (!!view && state.onViewChange && typeof state.onViewChange === "function") {
100
+ state.onViewChange(view, state.agenda);
101
+ }
102
+
103
+ if (!!view && state.onSelectedDateChange && typeof state.onSelectedDateChange === "function") {
104
+ state.onSelectedDateChange(day);
105
+ }
106
+ };
107
+
108
+ const confirmEvent = (event: ProcessedEvent | ProcessedEvent[], action: EventActions) => {
109
+ let updatedEvents: ProcessedEvent[];
110
+ if (action === "edit") {
111
+ if (Array.isArray(event)) {
112
+ updatedEvents = state.events.map((e) => {
113
+ const exist = event.find((ex) => ex.event_id === e.event_id);
114
+ return exist ? { ...e, ...exist } : e;
115
+ });
116
+ } else {
117
+ updatedEvents = state.events.map((e) =>
118
+ e.event_id === event.event_id ? { ...e, ...event } : e
119
+ );
120
+ }
121
+ } else {
122
+ updatedEvents = state.events.concat(event);
123
+ }
124
+ set((prev) => ({ ...prev, events: updatedEvents }));
125
+ };
126
+
127
+ const setCurrentDragged = (event?: ProcessedEvent) => {
128
+ set((prev) => ({ ...prev, currentDragged: event }));
129
+ };
130
+
131
+ const onDrop = async (
132
+ event: DragEvent<HTMLButtonElement>,
133
+ eventId: string,
134
+ startTime: Date,
135
+ resKey?: string,
136
+ resVal?: string | number
137
+ ) => {
138
+ // Get dropped event
139
+ const droppedEvent = state.events.find((e) => {
140
+ if (typeof e.event_id === "number") {
141
+ return e.event_id === +eventId;
142
+ }
143
+ return e.event_id === eventId;
144
+ }) as ProcessedEvent;
145
+
146
+ // Check if has resource and if is multiple
147
+ const resField = state.fields.find((f) => f.name === resKey);
148
+ const isMultiple = !!resField?.config?.multiple;
149
+ let newResource = resVal as string | number | string[] | number[];
150
+ if (resField) {
151
+ const eResource = droppedEvent[resKey as string];
152
+ const currentRes = arraytizeFieldVal(resField, eResource, droppedEvent).value;
153
+ if (isMultiple) {
154
+ // if dropped on already owned resource
155
+ if (currentRes.includes(resVal)) {
156
+ // Omit if dropped on same time slot for multiple event
157
+ if (isEqual(droppedEvent.start, startTime)) {
158
+ return;
159
+ }
160
+ newResource = currentRes;
161
+ } else {
162
+ // if have multiple resource ? add other : move to other
163
+ newResource = currentRes.length > 1 ? [...currentRes, resVal] : [resVal];
164
+ }
165
+ }
166
+ }
167
+
168
+ // Omit if dropped on same time slot for non multiple events
169
+ if (isEqual(droppedEvent.start, startTime)) {
170
+ if (!newResource || (!isMultiple && newResource === droppedEvent[resKey as string])) {
171
+ return;
172
+ }
173
+ }
174
+
175
+ // Update event time according to original duration & update resources/owners
176
+ const diff = differenceInMinutes(droppedEvent.end, droppedEvent.start);
177
+ const updatedEvent: ProcessedEvent = {
178
+ ...droppedEvent,
179
+ start: startTime,
180
+ end: addMinutes(startTime, diff),
181
+ recurring: undefined,
182
+ [resKey as string]: newResource || "",
183
+ };
184
+
185
+ // Local
186
+ if (!state.onEventDrop || typeof state.onEventDrop !== "function") {
187
+ return confirmEvent(updatedEvent, "edit");
188
+ }
189
+ // Remote
190
+ try {
191
+ triggerLoading(true);
192
+ const _event = await state.onEventDrop(event, startTime, updatedEvent, droppedEvent);
193
+ if (_event) {
194
+ confirmEvent(_event, "edit");
195
+ }
196
+ } finally {
197
+ triggerLoading(false);
198
+ }
199
+ };
200
+
201
+ const refetch = () => {
202
+ if (initial.getRemoteEvents) {
203
+ set((prev) => ({ ...prev, _refetchToken: prev._refetchToken + 1 }));
204
+ }
205
+ };
206
+
207
+ return (
208
+ <StoreContext.Provider
209
+ value={{
210
+ ...state,
211
+ handleState,
212
+ getViews,
213
+ toggleAgenda,
214
+ triggerDialog,
215
+ triggerLoading,
216
+ handleGotoDay,
217
+ confirmEvent,
218
+ setCurrentDragged,
219
+ onDrop,
220
+ refetch,
221
+ }}
222
+ >
223
+ {children}
224
+ </StoreContext.Provider>
225
+ );
226
+ };
@@ -0,0 +1,40 @@
1
+ import { DragEvent } from "react";
2
+ import { View } from "../components/nav/Navigation";
3
+ import { DefaultResource, EventActions, ProcessedEvent, SchedulerProps } from "../types";
4
+
5
+ export type SelectedRange = { start: Date; end: Date };
6
+
7
+ export interface SchedulerState extends SchedulerProps {
8
+ dialog: boolean;
9
+ selectedRange?: SelectedRange;
10
+ selectedEvent?: ProcessedEvent;
11
+ selectedResource?: DefaultResource["assignee"] | DefaultResource["assignee"][];
12
+ selectedTab?: DefaultResource["assignee"];
13
+ currentDragged?: ProcessedEvent;
14
+ enableAgenda?: boolean;
15
+ /** @internal */
16
+ _refetchToken: number;
17
+ }
18
+
19
+ export interface Store extends SchedulerState {
20
+ handleState(value: SchedulerState[keyof SchedulerState], name: keyof SchedulerState): void;
21
+ getViews(): View[];
22
+ toggleAgenda: () => void;
23
+ triggerDialog(status: boolean, event?: SelectedRange | ProcessedEvent): void;
24
+ triggerLoading(status: boolean): void;
25
+ handleGotoDay(day: Date): void;
26
+ confirmEvent(event: ProcessedEvent | ProcessedEvent[], action: EventActions): void;
27
+ setCurrentDragged(event?: ProcessedEvent): void;
28
+ onDrop(
29
+ event: DragEvent<HTMLButtonElement>,
30
+ eventId: string,
31
+ droppedStartTime: Date,
32
+ resourceKey?: string,
33
+ resourceVal?: string | number
34
+ ): void;
35
+ /**
36
+ * Manually trigger a refetch of remote events.
37
+ * Only works when `getRemoteEvents` prop is provided.
38
+ */
39
+ refetch(): void;
40
+ }