@isma91/react-scheduler 4.0.0

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/LICENSE +24 -0
  9. package/README.md +172 -0
  10. package/dist/LICENSE +24 -0
  11. package/dist/README.md +172 -0
  12. package/dist/SchedulerComponent.d.ts +3 -0
  13. package/dist/components/common/Cell.d.ts +13 -0
  14. package/dist/components/common/LocaleArrow.d.ts +8 -0
  15. package/dist/components/common/ResourceHeader.d.ts +6 -0
  16. package/dist/components/common/Tabs.d.ts +16 -0
  17. package/dist/components/common/TodayTypo.d.ts +8 -0
  18. package/dist/components/common/WithResources.d.ts +6 -0
  19. package/dist/components/events/Actions.d.ts +8 -0
  20. package/dist/components/events/AgendaEventsList.d.ts +7 -0
  21. package/dist/components/events/CurrentTimeBar.d.ts +11 -0
  22. package/dist/components/events/EmptyAgenda.d.ts +2 -0
  23. package/dist/components/events/EventItem.d.ts +10 -0
  24. package/dist/components/events/EventItemPopover.d.ts +9 -0
  25. package/dist/components/events/MonthEvents.d.ts +13 -0
  26. package/dist/components/events/TodayEvents.d.ts +16 -0
  27. package/dist/components/hoc/DateProvider.d.ts +5 -0
  28. package/dist/components/inputs/DatePicker.d.ts +14 -0
  29. package/dist/components/inputs/Input.d.ts +19 -0
  30. package/dist/components/inputs/SelectInput.d.ts +22 -0
  31. package/dist/components/month/MonthTable.d.ts +8 -0
  32. package/dist/components/nav/DayDateBtn.d.ts +6 -0
  33. package/dist/components/nav/MonthDateBtn.d.ts +6 -0
  34. package/dist/components/nav/Navigation.d.ts +3 -0
  35. package/dist/components/nav/WeekDateBtn.d.ts +8 -0
  36. package/dist/components/week/WeekTable.d.ts +11 -0
  37. package/dist/helpers/constants.d.ts +4 -0
  38. package/dist/helpers/generals.d.ts +78 -0
  39. package/dist/hooks/useArrowDisable.d.ts +5 -0
  40. package/dist/hooks/useCellAttributes.d.ts +18 -0
  41. package/dist/hooks/useDragAttributes.d.ts +10 -0
  42. package/dist/hooks/useEventPermissions.d.ts +7 -0
  43. package/dist/hooks/useStore.d.ts +2 -0
  44. package/dist/hooks/useSyncScroll.d.ts +8 -0
  45. package/dist/hooks/useWindowResize.d.ts +4 -0
  46. package/dist/index.d.ts +3 -0
  47. package/dist/index.js +2853 -0
  48. package/dist/package.json +65 -0
  49. package/dist/positionManger/context.d.ts +14 -0
  50. package/dist/positionManger/provider.d.ts +5 -0
  51. package/dist/positionManger/usePosition.d.ts +4 -0
  52. package/dist/store/context.d.ts +2 -0
  53. package/dist/store/default.d.ts +245 -0
  54. package/dist/store/provider.d.ts +7 -0
  55. package/dist/store/types.d.ts +27 -0
  56. package/dist/styles/styles.d.ts +30 -0
  57. package/dist/types.d.ts +372 -0
  58. package/dist/views/Day.d.ts +2 -0
  59. package/dist/views/DayAgenda.d.ts +7 -0
  60. package/dist/views/Editor.d.ts +11 -0
  61. package/dist/views/Month.d.ts +2 -0
  62. package/dist/views/MonthAgenda.d.ts +7 -0
  63. package/dist/views/Week.d.ts +2 -0
  64. package/dist/views/WeekAgenda.d.ts +8 -0
  65. package/eslint.config.js +79 -0
  66. package/index.html +41 -0
  67. package/jest.config.ts +194 -0
  68. package/package.json +137 -0
  69. package/public/favicon.ico +0 -0
  70. package/public/logo192.png +0 -0
  71. package/public/logo512.png +0 -0
  72. package/public/manifest.json +25 -0
  73. package/public/robots.txt +3 -0
  74. package/scripts/post-pack.js +34 -0
  75. package/src/App.tsx +25 -0
  76. package/src/Page1.tsx +67 -0
  77. package/src/events.tsx +227 -0
  78. package/src/index.tsx +21 -0
  79. package/src/lib/SchedulerComponent.tsx +78 -0
  80. package/src/lib/__tests__/index.test.tsx +24 -0
  81. package/src/lib/components/common/Cell.tsx +52 -0
  82. package/src/lib/components/common/LocaleArrow.tsx +38 -0
  83. package/src/lib/components/common/ResourceHeader.tsx +73 -0
  84. package/src/lib/components/common/Tabs.tsx +119 -0
  85. package/src/lib/components/common/TodayTypo.tsx +44 -0
  86. package/src/lib/components/common/WithResources.tsx +98 -0
  87. package/src/lib/components/events/Actions.tsx +65 -0
  88. package/src/lib/components/events/AgendaEventsList.tsx +115 -0
  89. package/src/lib/components/events/CurrentTimeBar.tsx +59 -0
  90. package/src/lib/components/events/EmptyAgenda.tsx +27 -0
  91. package/src/lib/components/events/EventItem.tsx +180 -0
  92. package/src/lib/components/events/EventItemPopover.tsx +179 -0
  93. package/src/lib/components/events/MonthEvents.tsx +141 -0
  94. package/src/lib/components/events/TodayEvents.tsx +99 -0
  95. package/src/lib/components/hoc/DateProvider.tsx +19 -0
  96. package/src/lib/components/inputs/DatePicker.tsx +95 -0
  97. package/src/lib/components/inputs/Input.tsx +113 -0
  98. package/src/lib/components/inputs/SelectInput.tsx +164 -0
  99. package/src/lib/components/month/MonthTable.tsx +207 -0
  100. package/src/lib/components/nav/DayDateBtn.tsx +77 -0
  101. package/src/lib/components/nav/MonthDateBtn.tsx +80 -0
  102. package/src/lib/components/nav/Navigation.tsx +201 -0
  103. package/src/lib/components/nav/WeekDateBtn.tsx +89 -0
  104. package/src/lib/components/week/WeekTable.tsx +229 -0
  105. package/src/lib/helpers/constants.ts +4 -0
  106. package/src/lib/helpers/generals.tsx +354 -0
  107. package/src/lib/hooks/useArrowDisable.ts +26 -0
  108. package/src/lib/hooks/useCellAttributes.ts +67 -0
  109. package/src/lib/hooks/useDragAttributes.ts +31 -0
  110. package/src/lib/hooks/useEventPermissions.ts +42 -0
  111. package/src/lib/hooks/useStore.ts +8 -0
  112. package/src/lib/hooks/useSyncScroll.ts +31 -0
  113. package/src/lib/hooks/useWindowResize.ts +37 -0
  114. package/src/lib/index.tsx +14 -0
  115. package/src/lib/positionManger/context.ts +14 -0
  116. package/src/lib/positionManger/provider.tsx +113 -0
  117. package/src/lib/positionManger/usePosition.ts +8 -0
  118. package/src/lib/store/context.ts +5 -0
  119. package/src/lib/store/default.ts +157 -0
  120. package/src/lib/store/provider.tsx +211 -0
  121. package/src/lib/store/types.ts +33 -0
  122. package/src/lib/styles/styles.ts +256 -0
  123. package/src/lib/types.ts +423 -0
  124. package/src/lib/views/Day.tsx +265 -0
  125. package/src/lib/views/DayAgenda.tsx +57 -0
  126. package/src/lib/views/Editor.tsx +258 -0
  127. package/src/lib/views/Month.tsx +82 -0
  128. package/src/lib/views/MonthAgenda.tsx +84 -0
  129. package/src/lib/views/Week.tsx +92 -0
  130. package/src/lib/views/WeekAgenda.tsx +81 -0
  131. package/src/vite-env.d.ts +3 -0
  132. package/tsconfig.build.json +5 -0
  133. package/tsconfig.json +27 -0
  134. package/vite.config.js +40 -0
@@ -0,0 +1,98 @@
1
+ import { useMemo } from "react";
2
+ import { DefaultResource } from "../../types";
3
+ import { ResourceHeader } from "./ResourceHeader";
4
+ import { ButtonTabProps, ButtonTabs } from "./Tabs";
5
+ import useStore from "../../hooks/useStore";
6
+ import { Box, useTheme } from "@mui/material";
7
+
8
+ interface WithResourcesProps {
9
+ renderChildren(resource: DefaultResource): React.ReactNode;
10
+ }
11
+ const WithResources = ({ renderChildren }: WithResourcesProps) => {
12
+ const { resources, resourceFields, resourceViewMode } = useStore();
13
+ const theme = useTheme();
14
+
15
+ if (resourceViewMode === "tabs") {
16
+ return <ResourcesTabTables renderChildren={renderChildren} />;
17
+ } else if (resourceViewMode === "vertical") {
18
+ return (
19
+ <>
20
+ {resources.map((res: DefaultResource, i: number) => (
21
+ <Box key={`${res[resourceFields.idField]}_${i}`} sx={{ display: "flex" }}>
22
+ <Box
23
+ sx={{
24
+ borderColor: theme.palette.grey[300],
25
+ borderStyle: "solid",
26
+ borderWidth: "1px 1px 0 1px",
27
+ paddingTop: 1,
28
+ flexBasis: 140,
29
+ }}
30
+ >
31
+ <ResourceHeader resource={res} />
32
+ </Box>
33
+ <Box
34
+ //
35
+ sx={{ width: "100%", overflowX: "auto" }}
36
+ >
37
+ {renderChildren(res)}
38
+ </Box>
39
+ </Box>
40
+ ))}
41
+ </>
42
+ );
43
+ } else {
44
+ return (
45
+ <>
46
+ {resources.map((res: DefaultResource, i: number) => (
47
+ <div key={`${res[resourceFields.idField]}_${i}`}>
48
+ <ResourceHeader resource={res} />
49
+ {renderChildren(res)}
50
+ </div>
51
+ ))}
52
+ </>
53
+ );
54
+ }
55
+ };
56
+
57
+ const ResourcesTabTables = ({ renderChildren }: WithResourcesProps) => {
58
+ const { resources, resourceFields, selectedTab, handleState, onResourceChange } = useStore();
59
+
60
+ const tabs: ButtonTabProps[] = resources.map((res) => {
61
+ return {
62
+ id: res[resourceFields.idField],
63
+ label: <ResourceHeader resource={res} />,
64
+ component: <>{renderChildren(res)}</>,
65
+ };
66
+ });
67
+
68
+ const setTab = (tab: DefaultResource["assignee"]) => {
69
+ handleState(tab, "selectedTab");
70
+ if (typeof onResourceChange === "function") {
71
+ const selected = resources.find((re) => re[resourceFields.idField] === tab);
72
+ if (selected) {
73
+ onResourceChange(selected);
74
+ }
75
+ }
76
+ };
77
+
78
+ const currentTabSafeId = useMemo(() => {
79
+ const firstId = resources[0][resourceFields.idField];
80
+ if (!selectedTab) {
81
+ return firstId;
82
+ }
83
+
84
+ // Make sure current selected id is within the resources array
85
+ const idx = resources.findIndex((re) => re[resourceFields.idField] === selectedTab);
86
+ if (idx < 0) {
87
+ return firstId;
88
+ }
89
+
90
+ return selectedTab;
91
+ }, [resources, resourceFields.idField, selectedTab]);
92
+
93
+ return (
94
+ <ButtonTabs tabs={tabs} tab={currentTabSafeId} setTab={setTab} style={{ display: "grid" }} />
95
+ );
96
+ };
97
+
98
+ export { WithResources };
@@ -0,0 +1,65 @@
1
+ import DeleteRounded from "@mui/icons-material/DeleteRounded";
2
+ import EditRounded from "@mui/icons-material/EditRounded";
3
+ import { Button, Grow, IconButton, Slide } from "@mui/material";
4
+ import { useState } from "react";
5
+ import { EventActions as Actions } from "../../styles/styles";
6
+ import { ProcessedEvent } from "../../types";
7
+ import useStore from "../../hooks/useStore";
8
+ import useEventPermissions from "../../hooks/useEventPermissions";
9
+
10
+ interface Props {
11
+ event: ProcessedEvent;
12
+ onDelete(): void;
13
+ onEdit(): void;
14
+ }
15
+
16
+ const EventActions = ({ event, onDelete, onEdit }: Props) => {
17
+ const { translations, direction } = useStore();
18
+ const [deleteConfirm, setDeleteConfirm] = useState(false);
19
+
20
+ const handleDelete = () => {
21
+ if (!deleteConfirm) {
22
+ return setDeleteConfirm(true);
23
+ }
24
+ onDelete();
25
+ };
26
+
27
+ const { canEdit, canDelete } = useEventPermissions(event);
28
+
29
+ return (
30
+ <Actions>
31
+ <Grow in={!deleteConfirm} exit={false} timeout={400} unmountOnExit>
32
+ <div>
33
+ {canEdit && (
34
+ <IconButton size="small" onClick={onEdit}>
35
+ <EditRounded />
36
+ </IconButton>
37
+ )}
38
+ {canDelete && (
39
+ <IconButton size="small" onClick={handleDelete}>
40
+ <DeleteRounded />
41
+ </IconButton>
42
+ )}
43
+ </div>
44
+ </Grow>
45
+ <Slide
46
+ in={deleteConfirm}
47
+ direction={direction === "rtl" ? "right" : "left"}
48
+ unmountOnExit
49
+ timeout={400}
50
+ exit={false}
51
+ >
52
+ <div>
53
+ <Button className="delete" size="small" onClick={handleDelete}>
54
+ {translations.form.delete.toUpperCase()}
55
+ </Button>
56
+ <Button className="cancel" size="small" onClick={() => setDeleteConfirm(false)}>
57
+ {translations.form.cancel.toUpperCase()}
58
+ </Button>
59
+ </div>
60
+ </Slide>
61
+ </Actions>
62
+ );
63
+ };
64
+
65
+ export default EventActions;
@@ -0,0 +1,115 @@
1
+ import { Fragment, MouseEvent, useState } from "react";
2
+ import {
3
+ useTheme,
4
+ List,
5
+ ListItemButton,
6
+ ListItemAvatar,
7
+ Avatar,
8
+ ListItemText,
9
+ } from "@mui/material";
10
+ import { format } from "date-fns";
11
+ import { ProcessedEvent } from "../../types";
12
+ import { getHourFormat, isTimeZonedToday } from "../../helpers/generals";
13
+ import useStore from "../../hooks/useStore";
14
+ import EventItemPopover from "./EventItemPopover";
15
+
16
+ interface AgendaEventsListProps {
17
+ day: Date;
18
+ events: ProcessedEvent[];
19
+ }
20
+
21
+ const AgendaEventsList = ({ day, events }: AgendaEventsListProps) => {
22
+ const [anchorEl, setAnchorEl] = useState<Element | null>(null);
23
+ const [selectedEvent, setSelectedEvent] = useState<ProcessedEvent>();
24
+ const [deleteConfirm, setDeleteConfirm] = useState(false);
25
+ const { locale, hourFormat, eventRenderer, onEventClick, timeZone, disableViewer } = useStore();
26
+ const theme = useTheme();
27
+ const hFormat = getHourFormat(hourFormat);
28
+
29
+ const triggerViewer = (el?: MouseEvent<Element>) => {
30
+ if (!el?.currentTarget && deleteConfirm) {
31
+ setDeleteConfirm(false);
32
+ }
33
+ setAnchorEl(el?.currentTarget || null);
34
+ };
35
+
36
+ return (
37
+ <Fragment>
38
+ <List>
39
+ {events.map((event) => {
40
+ const startIsToday = isTimeZonedToday({
41
+ dateLeft: event.start,
42
+ dateRight: day,
43
+ timeZone,
44
+ });
45
+ const startFormat = startIsToday ? hFormat : `MMM d, ${hFormat}`;
46
+ const startDate = format(event.start, startFormat, {
47
+ locale,
48
+ });
49
+ const endIsToday = isTimeZonedToday({ dateLeft: event.end, dateRight: day, timeZone });
50
+
51
+ const endFormat = endIsToday ? hFormat : `MMM d, ${hFormat}`;
52
+ const endDate = format(event.end, endFormat, {
53
+ locale,
54
+ });
55
+
56
+ if (typeof eventRenderer === "function") {
57
+ return eventRenderer({
58
+ event,
59
+ onClick: (e) => {
60
+ setSelectedEvent(event);
61
+ triggerViewer(e);
62
+ },
63
+ });
64
+ }
65
+
66
+ return (
67
+ <ListItemButton
68
+ key={`${event.start.getTime()}_${event.end.getTime()}_${event.event_id}`}
69
+ focusRipple
70
+ disableRipple={disableViewer}
71
+ tabIndex={disableViewer ? -1 : 0}
72
+ disabled={event.disabled}
73
+ onClick={(e) => {
74
+ e.preventDefault();
75
+ e.stopPropagation();
76
+ if (!disableViewer) {
77
+ triggerViewer(e);
78
+ }
79
+ setSelectedEvent(event);
80
+ if (typeof onEventClick === "function") {
81
+ onEventClick(event);
82
+ }
83
+ }}
84
+ >
85
+ <ListItemAvatar>
86
+ <Avatar
87
+ sx={{
88
+ bgcolor: event.disabled ? "#d0d0d0" : event.color || theme.palette.primary.main,
89
+ color: event.disabled
90
+ ? "#808080"
91
+ : event.textColor || theme.palette.primary.contrastText,
92
+ }}
93
+ >
94
+ {event.agendaAvatar || " "}
95
+ </Avatar>
96
+ </ListItemAvatar>
97
+ <ListItemText primary={event.title} secondary={`${startDate} - ${endDate}`} />
98
+ </ListItemButton>
99
+ );
100
+ })}
101
+ </List>
102
+
103
+ {/* Viewer */}
104
+ {selectedEvent && (
105
+ <EventItemPopover
106
+ anchorEl={anchorEl}
107
+ event={selectedEvent}
108
+ onTriggerViewer={triggerViewer}
109
+ />
110
+ )}
111
+ </Fragment>
112
+ );
113
+ };
114
+
115
+ export default AgendaEventsList;
@@ -0,0 +1,59 @@
1
+ import { useEffect, useState } from "react";
2
+ import { differenceInMinutes, set } from "date-fns";
3
+ import { BORDER_HEIGHT } from "../../helpers/constants";
4
+ import { getTimeZonedDate } from "../../helpers/generals";
5
+ import { TimeIndicatorBar } from "../../styles/styles";
6
+
7
+ interface CurrentTimeBarProps {
8
+ startHour: number;
9
+ step: number;
10
+ minuteHeight: number;
11
+ timeZone?: string;
12
+ zIndex?: number;
13
+ currentTime?: Date;
14
+ color?: string;
15
+ }
16
+
17
+ function calculateTop({
18
+ startHour,
19
+ step,
20
+ minuteHeight,
21
+ timeZone,
22
+ currentTime,
23
+ }: CurrentTimeBarProps): number {
24
+ const now = currentTime
25
+ ? getTimeZonedDate(currentTime, timeZone)
26
+ : getTimeZonedDate(new Date(), timeZone);
27
+
28
+ const minutesFromTop = differenceInMinutes(now, set(now, { hours: startHour, minutes: 0 }));
29
+ const topSpace = minutesFromTop * minuteHeight;
30
+ const slotsFromTop = minutesFromTop / step;
31
+ const borderFactor = slotsFromTop + BORDER_HEIGHT;
32
+ const top = topSpace + borderFactor;
33
+
34
+ return top;
35
+ }
36
+
37
+ const CurrentTimeBar = (props: CurrentTimeBarProps) => {
38
+ const [top, setTop] = useState(calculateTop(props));
39
+ const { startHour, step, minuteHeight, timeZone, currentTime, color } = props;
40
+
41
+ useEffect(() => {
42
+ const calcProps = { startHour, step, minuteHeight, timeZone, currentTime };
43
+ setTop(calculateTop(calcProps));
44
+ const interval = setInterval(() => setTop(calculateTop(calcProps)), 60 * 1000);
45
+ return () => clearInterval(interval);
46
+ }, [startHour, step, minuteHeight, timeZone, currentTime]);
47
+
48
+ // Prevent showing bar on top of days/header
49
+ if (top < 0) return null;
50
+
51
+ return (
52
+ <TimeIndicatorBar style={{ top, zIndex: props.zIndex }} color={color}>
53
+ <div />
54
+ <div />
55
+ </TimeIndicatorBar>
56
+ );
57
+ };
58
+
59
+ export default CurrentTimeBar;
@@ -0,0 +1,27 @@
1
+ import { AgendaDiv } from "../../styles/styles";
2
+ import { Typography } from "@mui/material";
3
+ import useStore from "../../hooks/useStore";
4
+
5
+ const EmptyAgenda = () => {
6
+ const { height, translations, stickyNavigationOffset, stickyNavigationHeight } = useStore();
7
+ return (
8
+ <AgendaDiv
9
+ stickyOffset={stickyNavigationOffset}
10
+ stickyHeight={stickyNavigationHeight}
11
+ sx={{
12
+ borderWidth: 1,
13
+ padding: 1,
14
+ height: height / 2,
15
+ display: "flex",
16
+ alignItems: "center",
17
+ justifyContent: "center",
18
+ }}
19
+ >
20
+ <div className="rs__cell rs__agenda_items">
21
+ <Typography>{translations.noDataToDisplay}</Typography>
22
+ </div>
23
+ </AgendaDiv>
24
+ );
25
+ };
26
+
27
+ export default EmptyAgenda;
@@ -0,0 +1,180 @@
1
+ import { Fragment, MouseEvent, useCallback, useMemo, useState } from "react";
2
+ import { Typography, ButtonBase, useTheme } from "@mui/material";
3
+ import { format } from "date-fns";
4
+ import { ProcessedEvent } from "../../types";
5
+ import ArrowRightRoundedIcon from "@mui/icons-material/ArrowRightRounded";
6
+ import ArrowLeftRoundedIcon from "@mui/icons-material/ArrowLeftRounded";
7
+ import { EventItemPaper } from "../../styles/styles";
8
+ import { differenceInDaysOmitTime, getHourFormat } from "../../helpers/generals";
9
+ import useStore from "../../hooks/useStore";
10
+ import useDragAttributes from "../../hooks/useDragAttributes";
11
+ import EventItemPopover from "./EventItemPopover";
12
+ import useEventPermissions from "../../hooks/useEventPermissions";
13
+
14
+ interface EventItemProps {
15
+ event: ProcessedEvent;
16
+ multiday?: boolean;
17
+ hasPrev?: boolean;
18
+ hasNext?: boolean;
19
+ showdate?: boolean;
20
+ }
21
+
22
+ const EventItem = ({ event, multiday, hasPrev, hasNext, showdate = true }: EventItemProps) => {
23
+ const { direction, locale, hourFormat, eventRenderer, onEventClick, view, disableViewer } =
24
+ useStore();
25
+ const dragProps = useDragAttributes(event);
26
+ const [anchorEl, setAnchorEl] = useState<Element | null>(null);
27
+ const [deleteConfirm, setDeleteConfirm] = useState(false);
28
+ const theme = useTheme();
29
+ const hFormat = getHourFormat(hourFormat);
30
+
31
+ const NextArrow = direction === "rtl" ? ArrowLeftRoundedIcon : ArrowRightRoundedIcon;
32
+ const PrevArrow = direction === "rtl" ? ArrowRightRoundedIcon : ArrowLeftRoundedIcon;
33
+ const hideDates = differenceInDaysOmitTime(event.start, event.end) <= 0 && event.allDay;
34
+
35
+ const { canDrag } = useEventPermissions(event);
36
+
37
+ const triggerViewer = useCallback(
38
+ (el?: MouseEvent<Element>) => {
39
+ if (!el?.currentTarget && deleteConfirm) {
40
+ setDeleteConfirm(false);
41
+ }
42
+ setAnchorEl(el?.currentTarget || null);
43
+ },
44
+ [deleteConfirm]
45
+ );
46
+
47
+ const renderEvent = useMemo(() => {
48
+ // Check if has custom render event method
49
+ // only applicable to non-multiday events and not in month-view
50
+ if (typeof eventRenderer === "function" && !multiday && view !== "month") {
51
+ const custom = eventRenderer({ event, onClick: triggerViewer, ...dragProps });
52
+ if (custom) {
53
+ return (
54
+ <EventItemPaper key={`${event.start.getTime()}_${event.end.getTime()}_${event.event_id}`}>
55
+ {custom}
56
+ </EventItemPaper>
57
+ );
58
+ }
59
+ }
60
+
61
+ let item = (
62
+ <div style={{ padding: "2px 6px" }}>
63
+ <Typography variant="subtitle2" style={{ fontSize: 12 }} noWrap>
64
+ {event.title}
65
+ </Typography>
66
+ {event.subtitle && (
67
+ <Typography variant="body2" style={{ fontSize: 11 }} noWrap>
68
+ {event.subtitle}
69
+ </Typography>
70
+ )}
71
+ {showdate && (
72
+ <Typography style={{ fontSize: 11 }} noWrap>
73
+ {`${format(event.start, hFormat, {
74
+ locale,
75
+ })} - ${format(event.end, hFormat, { locale })}`}
76
+ </Typography>
77
+ )}
78
+ </div>
79
+ );
80
+ if (multiday) {
81
+ item = (
82
+ <div
83
+ style={{
84
+ padding: 2,
85
+ display: "flex",
86
+ alignItems: "center",
87
+ justifyContent: "space-between",
88
+ }}
89
+ >
90
+ <Typography sx={{ fontSize: 11 }} noWrap>
91
+ {hasPrev ? (
92
+ <PrevArrow fontSize="small" sx={{ display: "flex" }} />
93
+ ) : (
94
+ showdate && !hideDates && format(event.start, hFormat, { locale })
95
+ )}
96
+ </Typography>
97
+ <Typography variant="subtitle2" align="center" sx={{ fontSize: 12 }} noWrap>
98
+ {event.title}
99
+ </Typography>
100
+ <Typography sx={{ fontSize: 11 }} noWrap>
101
+ {hasNext ? (
102
+ <NextArrow fontSize="small" sx={{ display: "flex" }} />
103
+ ) : (
104
+ showdate && !hideDates && format(event.end, hFormat, { locale })
105
+ )}
106
+ </Typography>
107
+ </div>
108
+ );
109
+ }
110
+ return (
111
+ <EventItemPaper
112
+ key={`${event.start.getTime()}_${event.end.getTime()}_${event.event_id}`}
113
+ disabled={event.disabled}
114
+ sx={{
115
+ bgcolor: event.disabled ? "#d0d0d0" : event.color || theme.palette.primary.main,
116
+ color: event.disabled ? "#808080" : event.textColor || theme.palette.primary.contrastText,
117
+ borderTop: event._hasPrev
118
+ ? `3px dashed ${event.textColor || theme.palette.primary.contrastText}`
119
+ : undefined,
120
+ borderBottom: event._hasNext
121
+ ? `3px dashed ${event.textColor || theme.palette.primary.contrastText}`
122
+ : undefined,
123
+ ...(event.sx || {}),
124
+ }}
125
+ >
126
+ <ButtonBase
127
+ onClick={(e) => {
128
+ e.preventDefault();
129
+ e.stopPropagation();
130
+ if (!disableViewer) {
131
+ triggerViewer(e);
132
+ }
133
+ if (typeof onEventClick === "function") {
134
+ onEventClick(event);
135
+ }
136
+ }}
137
+ focusRipple
138
+ tabIndex={disableViewer ? -1 : 0}
139
+ disableRipple={disableViewer}
140
+ disabled={event.disabled}
141
+ >
142
+ <div {...dragProps} draggable={canDrag}>
143
+ {item}
144
+ </div>
145
+ </ButtonBase>
146
+ </EventItemPaper>
147
+ );
148
+ }, [
149
+ eventRenderer,
150
+ multiday,
151
+ view,
152
+ event,
153
+ showdate,
154
+ hFormat,
155
+ locale,
156
+ theme.palette.primary.main,
157
+ theme.palette.primary.contrastText,
158
+ disableViewer,
159
+ dragProps,
160
+ canDrag,
161
+ triggerViewer,
162
+ hasPrev,
163
+ PrevArrow,
164
+ hideDates,
165
+ hasNext,
166
+ NextArrow,
167
+ onEventClick,
168
+ ]);
169
+
170
+ return (
171
+ <Fragment>
172
+ {renderEvent}
173
+
174
+ {/* Viewer */}
175
+ <EventItemPopover anchorEl={anchorEl} event={event} onTriggerViewer={triggerViewer} />
176
+ </Fragment>
177
+ );
178
+ };
179
+
180
+ export default EventItem;