Calendar improvements

This commit is contained in:
Milan Paunovic
2025-02-02 22:28:40 +01:00
parent 0998dc29d0
commit 5cfec1544a
22 changed files with 5140 additions and 1188 deletions

View File

@ -0,0 +1,148 @@
diff --git a/node_modules/@howljs/calendar-kit/src/hooks/useSyncedList.tsx b/node_modules/@howljs/calendar-kit/src/hooks/useSyncedList.tsx
index 2c2d340..c27d395 100644
--- a/node_modules/@howljs/calendar-kit/src/hooks/useSyncedList.tsx
+++ b/node_modules/@howljs/calendar-kit/src/hooks/useSyncedList.tsx
@@ -40,12 +40,12 @@ const useSyncedList = ({ id }: { id: ScrollType }) => {
const _onMomentumEnd = () => {
if (
- isTriggerMomentum.current &&
- startDateUnix.current !== visibleDateUnix.current
+ isTriggerMomentum.current &&
+ startDateUnix.current !== visibleDateUnix.current
) {
triggerDateChanged.current = undefined;
onDateChanged?.(
- dateTimeToISOString(parseDateTime(visibleDateUnix.current))
+ dateTimeToISOString(parseDateTime(visibleDateUnix.current))
);
notifyDateChanged(visibleDateUnix.current);
isTriggerMomentum.current = false;
@@ -83,71 +83,70 @@ const useSyncedList = ({ id }: { id: ScrollType }) => {
});
const onVisibleColumnChanged = useCallback(
- (props: {
- index: number;
- column: number;
- columns: number;
- offset: number;
- extraScrollData: Record<string, any>;
- }) => {
- const { index: pageIndex, column, columns, extraScrollData } = props;
- const { visibleColumns, visibleDates } = extraScrollData;
+ (props: {
+ index: number;
+ column: number;
+ columns: number;
+ offset: number;
+ extraScrollData: Record<string, any>;
+ }) => {
+ const { index: pageIndex, column, columns, extraScrollData } = props;
+ const { visibleColumns, visibleDates } = extraScrollData;
- if (scrollType.current === id && visibleColumns && visibleDates) {
- const dayIndex = pageIndex * columns + column;
- const visibleStart = visibleDates[pageIndex * columns];
- const visibleEnd =
- visibleDates[pageIndex * columns + column + visibleColumns];
+ if (scrollType.current === id && visibleColumns && visibleDates) {
+ const dayIndex = pageIndex * columns + column;
+ const visibleStart = visibleDates[pageIndex * columns];
+ const visibleEnd =
+ visibleDates[pageIndex * columns + column + visibleColumns];
- if (visibleStart && visibleEnd) {
- const diffDays = Math.floor(
- (visibleEnd - visibleStart) / MILLISECONDS_IN_DAY
- );
- if (diffDays <= 7) {
- visibleWeeks.value = [visibleStart];
- } else {
- const nextWeekStart = visibleDates[pageIndex * columns + 7];
- if (nextWeekStart) {
- visibleWeeks.value = [visibleStart, nextWeekStart];
+ if (visibleStart && visibleEnd) {
+ const diffDays = Math.floor(
+ (visibleEnd - visibleStart) / MILLISECONDS_IN_DAY
+ );
+ if (diffDays <= 7) {
+ visibleWeeks.value = [visibleStart];
+ } else {
+ const nextWeekStart = visibleDates[pageIndex * columns + 7];
+ if (nextWeekStart) {
+ visibleWeeks.value = [visibleStart, nextWeekStart];
+ }
}
}
- }
-
- const currentDate = visibleDates[dayIndex];
- if (!currentDate) {
- triggerDateChanged.current = undefined;
- return;
- }
- if (visibleDateUnix.current !== currentDate) {
- const dateIsoStr = dateTimeToISOString(parseDateTime(currentDate));
- onChange?.(dateIsoStr);
- if (
- triggerDateChanged.current &&
- triggerDateChanged.current === currentDate
- ) {
+ const currentDate = visibleDates[dayIndex];
+ if (!currentDate) {
triggerDateChanged.current = undefined;
- onDateChanged?.(dateIsoStr);
- notifyDateChanged(currentDate);
+ return;
+ }
+
+ if (visibleDateUnix.current !== currentDate) {
+ const dateIsoStr = dateTimeToISOString(parseDateTime(currentDate));
+ onChange?.(dateIsoStr);
+ if (
+ triggerDateChanged?.current === currentDate
+ ) {
+ triggerDateChanged.current = undefined;
+ onDateChanged?.(dateIsoStr);
+ notifyDateChanged(currentDate);
+ }
+ visibleDateUnix.current = currentDate;
+ runOnUI(() => {
+ visibleDateUnixAnim.value = currentDate;
+ })();
}
- visibleDateUnix.current = currentDate;
- runOnUI(() => {
- visibleDateUnixAnim.value = currentDate;
- })();
}
- }
- },
- [
- scrollType,
- id,
- visibleDateUnix,
- visibleWeeks,
- triggerDateChanged,
- onChange,
- onDateChanged,
- notifyDateChanged,
- visibleDateUnixAnim,
- ]
+ },
+ [
+ scrollType,
+ id,
+ visibleDateUnix,
+ visibleWeeks,
+ triggerDateChanged,
+ onChange,
+ onDateChanged,
+ notifyDateChanged,
+ visibleDateUnixAnim,
+ ]
);
return { onScroll, onVisibleColumnChanged };

View File

@ -1,195 +0,0 @@
diff --git a/node_modules/react-native-big-calendar/build/index.js b/node_modules/react-native-big-calendar/build/index.js
index 848ceba..f326b8e 100644
--- a/node_modules/react-native-big-calendar/build/index.js
+++ b/node_modules/react-native-big-calendar/build/index.js
@@ -9,6 +9,17 @@ var isoWeek = require('dayjs/plugin/isoWeek');
var React = require('react');
var reactNative = require('react-native');
var calendarize = require('calendarize');
+var {
+ startOfDay,
+ endOfDay,
+ startOfWeek,
+ isAfter,
+ isBefore,
+ isSameDay,
+ differenceInDays,
+ add,
+ getTime
+} = require('date-fns');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
@@ -1000,87 +1011,91 @@ function _CalendarBodyForMonthView(_a) {
var start = _a.start, end = _a.end;
return day.isBetween(dayjs__default["default"](start).startOf('day'), dayjs__default["default"](end).endOf('day'), null, '[)');
});
- }
- else {
- /**
- * Better way to sort overlapping events that spans accross multiple days
- * For example, if you want following events
- * Event 1, start = 01/01 12:00, end = 02/01 12:00
- * Event 2, start = 02/01 12:00, end = 03/01 12:00
- * Event 3, start = 03/01 12:00, end = 04/01 12:00
- *
- * When drawing calendar in month view, event 3 should be placed at 3rd index for 03/01, because Event 2 are placed at 2nd index for 02/01 and 03/01
- *
- */
- var min_1 = day.startOf('day'), max_1 = day.endOf('day');
- //filter all events that starts from the current week until the current day, and sort them by reverse starting time
- var filteredEvents_1 = events
- .filter(function (_a) {
- var start = _a.start, end = _a.end;
- return dayjs__default["default"](end).isAfter(day.startOf('week')) && dayjs__default["default"](start).isBefore(max_1);
- })
- .sort(function (a, b) {
- if (dayjs__default["default"](a.start).isSame(b.start, 'day')) {
- var aDuration = dayjs__default["default"].duration(dayjs__default["default"](a.end).diff(dayjs__default["default"](a.start))).days();
- var bDuration = dayjs__default["default"].duration(dayjs__default["default"](b.end).diff(dayjs__default["default"](b.start))).days();
- return aDuration - bDuration;
- }
- return b.start.getTime() - a.start.getTime();
+ } else {
+ // Convert day once and cache all the commonly used dates/times
+ const jsDay = day?.toDate?.() || day;
+ const weekStart = startOfWeek(jsDay);
+ var min_1 = startOfDay(jsDay);
+ var max_1 = endOfDay(jsDay);
+ const max1Time = getTime(max_1);
+ const min1Time = getTime(min_1);
+
+ // Pre-process events with dates and cache timestamps
+ const processedEvents = events.map(event => {
+ const startDay = event.start?.toDate?.() || new Date(event.start);
+ const endDay = event.end?.toDate?.() || new Date(event.end);
+ return {
+ ...event,
+ startDay,
+ endDay,
+ startTime: getTime(startDay),
+ endTime: getTime(endDay),
+ startDayStart: startOfDay(startDay)
+ };
});
- /**
- * find the most relevant min date to filter the events
- * in the example:
- * 1. when rendering for 01/01, min date will be 01/01 (start of day for event 1)
- * 2. when rendering for 02/01, min date will be 01/01 (start of day for event 1)
- * 3. when rendering for 03/01, min date will be 01/01 (start of day for event 1)
- * 4. when rendering for 04/01, min date will be 01/01 (start of day for event 1)
- * 5. when rendering for 05/01, min date will be 05/01 (no event overlaps with 05/01)
- */
- filteredEvents_1.forEach(function (_a) {
- var start = _a.start, end = _a.end;
- if (dayjs__default["default"](end).isAfter(min_1) && dayjs__default["default"](start).isBefore(min_1)) {
- min_1 = dayjs__default["default"](start).startOf('day');
+
+ // Filter events within the weekly range and sort by reverse start time
+ let filteredEvents_1 = processedEvents
+ .filter(({ startTime, endTime }) =>
+ endTime > getTime(weekStart) && startTime < max1Time
+ )
+ .sort((a, b) => {
+ if (isSameDay(a.startDay, b.startDay)) {
+ // Pre-calculate durations since they're used in sorting
+ const aDuration = differenceInDays(a.endDay, a.startDay);
+ const bDuration = differenceInDays(b.endDay, b.startDay);
+ return bDuration - aDuration;
+ }
+ return b.startTime - a.startTime;
+ });
+
+ // Update min_1 to the earliest startDay for overlapping events
+ for (const event of filteredEvents_1) {
+ if (event.endTime > min1Time && event.startTime < min1Time) {
+ min_1 = event.startDayStart;
+ break; // We only need the first one due to the sort order
}
- });
+ }
+
+ // Filter to keep only events that overlap the min to max range, then reverse
+ const min1TimeUpdated = getTime(min_1);
filteredEvents_1 = filteredEvents_1
- .filter(function (_a) {
- var start = _a.start, end = _a.end;
- return dayjs__default["default"](end).endOf('day').isAfter(min_1) && dayjs__default["default"](start).isBefore(max_1);
- })
+ .filter(({ startTime, endDay }) =>
+ getTime(endOfDay(endDay)) > min1TimeUpdated && startTime < max1Time
+ )
.reverse();
- /**
- * We move eligible event to the top
- * For example, when rendering for 03/01, Event 3 should be moved to the top, since there is a gap left by Event 1
- */
- var finalEvents_1 = [];
- var tmpDay_1 = day.startOf('week');
- //re-sort events from the start of week until the calendar cell date
- //optimize sorting of event nodes and make sure that no empty gaps are left on top of calendar cell
- while (!tmpDay_1.isAfter(day)) {
- filteredEvents_1.forEach(function (event) {
- if (dayjs__default["default"](event.end).isBefore(tmpDay_1.startOf('day'))) {
- var eventToMoveUp = filteredEvents_1.find(function (e) {
- return dayjs__default["default"](e.start).startOf('day').isSame(tmpDay_1.startOf('day'));
- });
- if (eventToMoveUp != undefined) {
- //remove eventToMoveUp from finalEvents first
- if (finalEvents_1.indexOf(eventToMoveUp) > -1) {
- finalEvents_1.splice(finalEvents_1.indexOf(eventToMoveUp), 1);
- }
- if (finalEvents_1.indexOf(event) > -1) {
- finalEvents_1.splice(finalEvents_1.indexOf(event), 1, eventToMoveUp);
- }
- else {
+
+ // Move eligible events to the top, preventing duplicate entries
+ const finalEvents_1 = [];
+ const seenEvents = new Set(); // Use Set for faster lookups
+ let tmpDay_1 = weekStart;
+
+ while (!isAfter(tmpDay_1, jsDay)) {
+ const tmpDayTime = getTime(tmpDay_1);
+
+ for (const event of filteredEvents_1) {
+ const eventEndDayTime = getTime(startOfDay(event.endDay));
+
+ if (!seenEvents.has(event)) {
+ if (eventEndDayTime < tmpDayTime) {
+ // Find event starting on tmpDay
+ const eventToMoveUp = filteredEvents_1.find(e =>
+ isSameDay(e.startDayStart, tmpDay_1)
+ );
+ if (eventToMoveUp && !seenEvents.has(eventToMoveUp)) {
finalEvents_1.push(eventToMoveUp);
+ seenEvents.add(eventToMoveUp);
}
+ } else {
+ finalEvents_1.push(event);
+ seenEvents.add(event);
}
}
- else if (finalEvents_1.indexOf(event) == -1) {
- finalEvents_1.push(event);
- }
- });
- tmpDay_1 = tmpDay_1.add(1, 'day');
+ }
+ tmpDay_1 = add(tmpDay_1, { days: 1 });
}
+
+ console.log(finalEvents_1);
return finalEvents_1;
}
}, [events, sortedMonthView]);
@@ -1311,7 +1326,7 @@ function _CalendarHeader(_a) {
!stringHasContent(dayHeaderHighlightColor) &&
u['mt-6'],
] }, date.format('D')))),
- showAllDayEventCell ? (React__namespace.createElement(reactNative.View, { style: [
+ showAllDayEventCell ? (React__namespace.createElement(reactNative.ScrollView, { style: [
u['border-l'],
{ borderColor: theme.palette.gray['200'] },
{ height: cellHeight },