Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

in month view, multiple days events with other events are overlapped sometime. #1137

Open
relay955 opened this issue Feb 11, 2025 · 1 comment

Comments

@relay955
Copy link

relay955 commented Feb 11, 2025

reproducible storybook code

import { storiesOf } from '@storybook/react'
import React, { useCallback } from 'react'
import { Button } from 'react-native'

import { Calendar } from '../src'
import dayjs from "dayjs";

const MOBILE_HEIGHT = 736

storiesOf('reproduction-issue', module)
  .add('month mode', () => <CalendarContainer swipeEnabled={true} />)

interface CalendarContainerProps {
  swipeEnabled: boolean
}

const events = [
  {
    title: 'event1',
    start: dayjs("2025-02-11").toDate(),
    end: dayjs("2025-02-12").toDate(),
  },
  {
    title: 'event2',
    start: dayjs("2025-02-12").toDate(),
    end: dayjs("2025-02-13").toDate(),
  },
  {
    title: 'event3',
    start: dayjs("2025-02-13").toDate(),
    end: dayjs("2025-02-13").toDate(),
  },
]

const CalendarContainer: React.FC<CalendarContainerProps> = ({ swipeEnabled }) => {
  return (
    <>
      <Calendar
        events={events}
        swipeEnabled={swipeEnabled}
        date={new Date("2025-02-01")}
        height={MOBILE_HEIGHT}
        mode="month"
      />
    </>
  )
}

result

Image

when clicked event 2, we can see event 3 behind event 2.

Image

currently I fixed this by replacing the event sorting algorithm.

However, this code changes some of the sort order, and can't use option 'sortedMonthView=false'.

If someone needs to fix the bug now, use the code below temporarily.

CalendarBodyForMonthView.tsx, line 119

  const eventsByDate = React.useMemo(() => {
    let multipleDayEventsOrder:Map<T, number> = new Map();
    let eventDict: { [date: string]: T[] } = {};
    let dateToCompare = dayjs(targetDate).startOf('month').startOf('week').startOf('day');
    let startDateOfWeek = dateToCompare.startOf('week');
    let lastDateOfWeek = dateToCompare.endOf('week');
    let lastDateOfMonth = dayjs(targetDate).endOf('month').endOf('week').endOf('day').add(1, 'day');

    while(dateToCompare.isBefore(lastDateOfMonth, 'day')) {
      //Update the relevant variables to the next week when the date you're currently trying to index is past the last date of the current week
      //Initialize the order index for multi-date events, as the order of multi-date events changes every week.
      if (dateToCompare.isAfter(lastDateOfWeek)) {
        multipleDayEventsOrder.clear();
        startDateOfWeek = dayjs(dateToCompare).startOf('week');
        lastDateOfWeek = dayjs(dateToCompare).endOf('week');
      }

      //Get all the vevents that start today and sort them.
      let todayStartsEvents = events
        .filter((event) => dateToCompare.isSame(dayjs(event.start).startOf('day'),'day') ||
          (dateToCompare.isSame(startDateOfWeek,'day') &&
            dateToCompare.isBetween(dayjs(event.start).startOf('day'),dayjs(event.end).startOf('day'),'day','[]')))
        .sort((a, b) => {
          if (dayjs(a.start).startOf('day').isBefore(dayjs(a.end).startOf('day'),'day') ||
            dayjs(a.start).startOf('day').isBefore(dayjs(b.end).startOf('day'),'day')) {
            const aDuration = dayjs.duration(dayjs(a.end).diff(dayjs(a.start))).days()
            const bDuration = dayjs.duration(dayjs(b.end).diff(dayjs(b.start))).days()
            return bDuration - aDuration
          }
          return b.start.getTime() - a.start.getTime()
        });

      let todayStartsEventsSet = new Set(todayStartsEvents);
      let finalEvents = [...todayStartsEvents];

      // Import and sort events that don't start today, but are included today.
      let todayIncludedEvents = events.filter((event) =>
        dateToCompare.isBetween(dayjs(event.start).startOf('day'),dayjs(event.end).startOf('day'),'day','[]')
        && !todayStartsEventsSet.has(event)
      ).sort((a, b) => (multipleDayEventsOrder.get(a) ?? 0) - (multipleDayEventsOrder.get(b) ?? 0));

      // Inserts an existing multi-day event into today's schedule,
      // preserving the order of the existing multi-day event.
      todayIncludedEvents.forEach((event) => {
        if (!multipleDayEventsOrder.has(event)) return;
        let order = multipleDayEventsOrder.get(event);
        if (order === undefined) return;
        finalEvents.splice(order, 0, event);
      });

      eventDict[dateToCompare.format(SIMPLE_DATE_FORMAT)] = finalEvents;

      //Pre-indexes locations in a multi-date event starting with the current date
      //for use in the next date index.
      finalEvents.forEach((event) => {
        if (dayjs(event.end).diff(dayjs(event.start), 'day') > 0) {
          multipleDayEventsOrder.set(event, finalEvents.indexOf(event));
        }
      });

      dateToCompare = dateToCompare.add(1, 'day');
    }
    return eventDict;
  }, [events,sortedMonthView]);

add this, and remove sortedEvents.

CalendarBodyForMonthView.tsx, line 333
before

                    sortedEvents(date).reduce(

after

                  (eventsByDate[date.format("YYYY-MM-DD")] ?? []).reduce(
@acro5piano
Copy link
Owner

Hmm this must be a complicated issue... If you send a pull request, I'm happy merge it though.
Please don't forget to update the storybook format if you do so. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants