diff --git a/packages/twenty-front/src/modules/activities/calendar/components/Calendar.tsx b/packages/twenty-front/src/modules/activities/calendar/components/Calendar.tsx index 2c89215d5..ae35cb7a5 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/Calendar.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/Calendar.tsx @@ -12,7 +12,7 @@ import { SkeletonLoader } from '@/activities/components/SkeletonLoader'; import { useCustomResolver } from '@/activities/hooks/useCustomResolver'; import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { TimelineCalendarEventsWithTotal } from '~/generated/graphql'; +import { H3Title } from 'twenty-ui/display'; import { AnimatedPlaceholder, AnimatedPlaceholderEmptyContainer, @@ -22,7 +22,7 @@ import { EMPTY_PLACEHOLDER_TRANSITION_PROPS, Section, } from 'twenty-ui/layout'; -import { H3Title } from 'twenty-ui/display'; +import { TimelineCalendarEventsWithTotal } from '~/generated/graphql'; const StyledContainer = styled.div` box-sizing: border-box; @@ -82,12 +82,9 @@ export const Calendar = ({ const { calendarEventsByDayTime, - currentCalendarEvent, daysByMonthTime, - getNextCalendarEvent, monthTimes, monthTimesByYear, - updateCurrentCalendarEvent, } = useCalendarEvents(timelineCalendarEvents || []); if (firstQueryLoading) { @@ -119,10 +116,6 @@ export const Calendar = ({ diff --git a/packages/twenty-front/src/modules/activities/calendar/components/CalendarCurrentEventCursor.tsx b/packages/twenty-front/src/modules/activities/calendar/components/CalendarCurrentEventCursor.tsx deleted file mode 100644 index 3284431e9..000000000 --- a/packages/twenty-front/src/modules/activities/calendar/components/CalendarCurrentEventCursor.tsx +++ /dev/null @@ -1,180 +0,0 @@ -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { - differenceInSeconds, - isThisMonth, - startOfDay, - startOfMonth, -} from 'date-fns'; -import { AnimatePresence, motion } from 'framer-motion'; -import { useContext, useMemo, useState } from 'react'; - -import { CalendarContext } from '@/activities/calendar/contexts/CalendarContext'; -import { getCalendarEventEndDate } from '@/activities/calendar/utils/getCalendarEventEndDate'; -import { getCalendarEventStartDate } from '@/activities/calendar/utils/getCalendarEventStartDate'; -import { hasCalendarEventEnded } from '@/activities/calendar/utils/hasCalendarEventEnded'; -import { hasCalendarEventStarted } from '@/activities/calendar/utils/hasCalendarEventStarted'; -import { TimelineCalendarEvent } from '~/generated/graphql'; - -type CalendarCurrentEventCursorProps = { - calendarEvent: TimelineCalendarEvent; -}; - -const StyledDot = styled(motion.div)` - background-color: ${({ theme }) => theme.font.color.danger}; - border-radius: 1px; - height: ${({ theme }) => theme.spacing(1)}; - width: ${({ theme }) => theme.spacing(1)}; -`; - -const StyledCurrentEventCursor = styled(motion.div)` - align-items: center; - background-color: ${({ theme }) => theme.font.color.danger}; - display: inline-flex; - height: 1.5px; - left: 0; - position: absolute; - right: 0; - border-radius: ${({ theme }) => theme.border.radius.sm}; - transform: translateY(-50%); -`; - -export const CalendarCurrentEventCursor = ({ - calendarEvent, -}: CalendarCurrentEventCursorProps) => { - const theme = useTheme(); - const { - calendarEventsByDayTime, - currentCalendarEvent, - getNextCalendarEvent, - updateCurrentCalendarEvent, - } = useContext(CalendarContext); - - const nextCalendarEvent = getNextCalendarEvent(calendarEvent); - const nextCalendarEventStartsAt = nextCalendarEvent - ? getCalendarEventStartDate(nextCalendarEvent) - : undefined; - const isNextEventThisMonth = - !!nextCalendarEventStartsAt && isThisMonth(nextCalendarEventStartsAt); - - const calendarEventStartsAt = getCalendarEventStartDate(calendarEvent); - const calendarEventEndsAt = getCalendarEventEndDate(calendarEvent); - - const isCurrent = currentCalendarEvent?.id === calendarEvent.id; - const [hasStarted, setHasStarted] = useState( - hasCalendarEventStarted(calendarEvent), - ); - const [hasEnded, setHasEnded] = useState( - hasCalendarEventEnded(calendarEvent), - ); - const [isWaiting, setIsWaiting] = useState(hasEnded && !isNextEventThisMonth); - - const dayTime = startOfDay(calendarEventStartsAt).getTime(); - const dayEvents = calendarEventsByDayTime[dayTime]; - const isFirstEventOfDay = dayEvents?.slice(-1)[0] === calendarEvent; - const isLastEventOfDay = dayEvents?.[0] === calendarEvent; - - const topOffset = isLastEventOfDay ? 9 : 6; - const bottomOffset = isFirstEventOfDay ? 9 : 6; - - const currentEventCursorVariants = { - beforeEvent: { top: `calc(100% + ${bottomOffset}px)` }, - eventStart: { - top: 'calc(100% + 3px)', - transition: { - delay: Math.max( - 0, - differenceInSeconds(calendarEventStartsAt, new Date()), - ), - }, - }, - eventEnd: { - top: `-${topOffset}px`, - transition: { - delay: Math.max( - 0, - differenceInSeconds(calendarEventEndsAt, new Date()) + 1, - ), - }, - }, - fadeAway: { - opacity: 0, - top: `-${topOffset}px`, - transition: { - delay: - isWaiting && nextCalendarEventStartsAt - ? differenceInSeconds( - startOfMonth(nextCalendarEventStartsAt), - new Date(), - ) - : 0, - }, - }, - }; - - const animationSequence = useMemo(() => { - if (!hasStarted) return { initial: 'beforeEvent', animate: 'eventStart' }; - - if (!hasEnded) { - return { initial: 'eventStart', animate: 'eventEnd' }; - } - - if (!isWaiting) { - return { initial: undefined, animate: 'eventEnd' }; - } - - return { initial: 'eventEnd', animate: 'fadeAway' }; - }, [hasEnded, hasStarted, isWaiting]); - - return ( - - {isCurrent && ( - { - if (stage === 'eventStart') { - setHasStarted(true); - } - - if (stage === 'eventEnd') { - setHasEnded(true); - - if (isNextEventThisMonth) { - updateCurrentCalendarEvent(); - } - // If the next event is not the same month as the current event, - // we don't want the cursor to jump to the next month until the next month starts. - // => Wait for the upcoming event's month to start before moving the cursor. - // Example: we're in March. The previous event is February 15th, and the next event is April 10th. - // We want the cursor to stay in February until April starts. - else { - setIsWaiting(true); - } - } - - if (isWaiting && stage === 'fadeAway') { - setIsWaiting(false); - updateCurrentCalendarEvent(); - } - }} - transition={{ duration: theme.animation.duration.normal }} - > - - - - - )} - - ); -}; diff --git a/packages/twenty-front/src/modules/activities/calendar/components/CalendarDayCardContent.tsx b/packages/twenty-front/src/modules/activities/calendar/components/CalendarDayCardContent.tsx index 48839ed8b..0f46422f1 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/CalendarDayCardContent.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarDayCardContent.tsx @@ -4,8 +4,8 @@ import { differenceInSeconds, endOfDay, format } from 'date-fns'; import { CalendarEventRow } from '@/activities/calendar/components/CalendarEventRow'; import { getCalendarEventStartDate } from '@/activities/calendar/utils/getCalendarEventStartDate'; -import { TimelineCalendarEvent } from '~/generated/graphql'; import { CardContent } from 'twenty-ui/layout'; +import { TimelineCalendarEvent } from '~/generated/graphql'; type CalendarDayCardContentProps = { calendarEvents: TimelineCalendarEvent[]; diff --git a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx index e0a484dae..e8ce9f753 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx @@ -1,13 +1,10 @@ import { css, useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { format } from 'date-fns'; -import { useContext } from 'react'; import { useRecoilValue } from 'recoil'; -import { CalendarCurrentEventCursor } from '@/activities/calendar/components/CalendarCurrentEventCursor'; import { CalendarEventNotSharedContent } from '@/activities/calendar/components/CalendarEventNotSharedContent'; import { CalendarEventParticipantsAvatarGroup } from '@/activities/calendar/components/CalendarEventParticipantsAvatarGroup'; -import { CalendarContext } from '@/activities/calendar/contexts/CalendarContext'; import { getCalendarEventEndDate } from '@/activities/calendar/utils/getCalendarEventEndDate'; import { getCalendarEventStartDate } from '@/activities/calendar/utils/getCalendarEventStartDate'; import { hasCalendarEventEnded } from '@/activities/calendar/utils/hasCalendarEventEnded'; @@ -88,7 +85,6 @@ export const CalendarEventRow = ({ }: CalendarEventRowProps) => { const theme = useTheme(); const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); - const { displayCurrentEventCursor = false } = useContext(CalendarContext); const { openCalendarEventInCommandMenu } = useOpenCalendarEventInCommandMenu(); @@ -143,9 +139,6 @@ export const CalendarEventRow = ({ participants={calendarEvent.participants} /> )} - {displayCurrentEventCursor && ( - - )} ); }; diff --git a/packages/twenty-front/src/modules/activities/calendar/contexts/CalendarContext.ts b/packages/twenty-front/src/modules/activities/calendar/contexts/CalendarContext.ts index e012d90f2..38b23229c 100644 --- a/packages/twenty-front/src/modules/activities/calendar/contexts/CalendarContext.ts +++ b/packages/twenty-front/src/modules/activities/calendar/contexts/CalendarContext.ts @@ -4,16 +4,8 @@ import { TimelineCalendarEvent } from '~/generated/graphql'; type CalendarContextValue = { calendarEventsByDayTime: Record; - currentCalendarEvent?: TimelineCalendarEvent; - displayCurrentEventCursor?: boolean; - getNextCalendarEvent: ( - calendarEvent: TimelineCalendarEvent, - ) => TimelineCalendarEvent | undefined; - updateCurrentCalendarEvent: () => void; }; export const CalendarContext = createContext({ calendarEventsByDayTime: {}, - getNextCalendarEvent: () => undefined, - updateCurrentCalendarEvent: () => {}, }); diff --git a/packages/twenty-front/src/modules/activities/calendar/hooks/__tests__/useCalendarEvents.test.tsx b/packages/twenty-front/src/modules/activities/calendar/hooks/__tests__/useCalendarEvents.test.tsx index 1c62ae6fe..2d4f58640 100644 --- a/packages/twenty-front/src/modules/activities/calendar/hooks/__tests__/useCalendarEvents.test.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/hooks/__tests__/useCalendarEvents.test.tsx @@ -1,4 +1,4 @@ -import { act, renderHook } from '@testing-library/react'; +import { renderHook } from '@testing-library/react'; import { useCalendarEvents } from '@/activities/calendar/hooks/useCalendarEvents'; import { @@ -85,20 +85,13 @@ const calendarEvents: TimelineCalendarEvent[] = [ }, ]; -describe('useCalendar', () => { - it('returns calendar events', () => { +describe('useCalendarEvents', () => { + it('returns calendar events grouped by day time', () => { const { result } = renderHook(() => useCalendarEvents(calendarEvents)); - expect(result.current.currentCalendarEvent).toBe(calendarEvents[0]); - - expect(result.current.getNextCalendarEvent(calendarEvents[1])).toBe( - calendarEvents[0], - ); - - act(() => { - result.current.updateCurrentCalendarEvent(); - }); - - expect(result.current.currentCalendarEvent).toBe(calendarEvents[0]); + expect(result.current.calendarEventsByDayTime).toBeDefined(); + expect(result.current.daysByMonthTime).toBeDefined(); + expect(result.current.monthTimes).toBeDefined(); + expect(result.current.monthTimesByYear).toBeDefined(); }); }); diff --git a/packages/twenty-front/src/modules/activities/calendar/hooks/useCalendarEvents.ts b/packages/twenty-front/src/modules/activities/calendar/hooks/useCalendarEvents.ts index 329bda154..8283633fc 100644 --- a/packages/twenty-front/src/modules/activities/calendar/hooks/useCalendarEvents.ts +++ b/packages/twenty-front/src/modules/activities/calendar/hooks/useCalendarEvents.ts @@ -1,12 +1,9 @@ -import { getYear, isThisMonth, startOfDay, startOfMonth } from 'date-fns'; -import { useMemo, useState } from 'react'; +import { getYear, startOfDay, startOfMonth } from 'date-fns'; -import { findUpcomingCalendarEvent } from '@/activities/calendar/utils/findUpcomingCalendarEvent'; import { getCalendarEventStartDate } from '@/activities/calendar/utils/getCalendarEventStartDate'; import { TimelineCalendarEvent } from '~/generated/graphql'; import { groupArrayItemsBy } from '~/utils/array/groupArrayItemsBy'; import { sortDesc } from '~/utils/sort'; -import { isDefined } from 'twenty-shared/utils'; export const useCalendarEvents = (calendarEvents: TimelineCalendarEvent[]) => { const calendarEventsByDayTime = groupArrayItemsBy( @@ -29,53 +26,10 @@ export const useCalendarEvents = (calendarEvents: TimelineCalendarEvent[]) => { const monthTimesByYear = groupArrayItemsBy(sortedMonthTimes, getYear); - const getPreviousCalendarEvent = (calendarEvent: TimelineCalendarEvent) => { - const calendarEventIndex = calendarEvents.indexOf(calendarEvent); - return calendarEventIndex < calendarEvents.length - 1 - ? calendarEvents[calendarEventIndex + 1] - : undefined; - }; - - const getNextCalendarEvent = (calendarEvent: TimelineCalendarEvent) => { - const calendarEventIndex = calendarEvents.indexOf(calendarEvent); - return calendarEventIndex > 0 - ? calendarEvents[calendarEventIndex - 1] - : undefined; - }; - - const initialUpcomingCalendarEvent = useMemo( - () => findUpcomingCalendarEvent(calendarEvents), - [calendarEvents], - ); - const lastEventInCalendar = calendarEvents.length - ? calendarEvents[0] - : undefined; - - const [currentCalendarEvent, setCurrentCalendarEvent] = useState( - (initialUpcomingCalendarEvent && - (isThisMonth(getCalendarEventStartDate(initialUpcomingCalendarEvent)) - ? initialUpcomingCalendarEvent - : getPreviousCalendarEvent(initialUpcomingCalendarEvent))) || - lastEventInCalendar, - ); - - const updateCurrentCalendarEvent = () => { - if (!currentCalendarEvent) return; - - const nextCurrentCalendarEvent = getNextCalendarEvent(currentCalendarEvent); - - if (isDefined(nextCurrentCalendarEvent)) { - setCurrentCalendarEvent(nextCurrentCalendarEvent); - } - }; - return { calendarEventsByDayTime, - currentCalendarEvent, daysByMonthTime, - getNextCalendarEvent, monthTimes: sortedMonthTimes, monthTimesByYear, - updateCurrentCalendarEvent, }; }; diff --git a/packages/twenty-front/src/modules/activities/calendar/utils/__tests__/findUpcomingCalendarEvent.test.ts b/packages/twenty-front/src/modules/activities/calendar/utils/__tests__/findUpcomingCalendarEvent.test.ts deleted file mode 100644 index dce86cc71..000000000 --- a/packages/twenty-front/src/modules/activities/calendar/utils/__tests__/findUpcomingCalendarEvent.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { addDays, addHours, startOfDay, subDays, subHours } from 'date-fns'; - -import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent'; - -import { findUpcomingCalendarEvent } from '../findUpcomingCalendarEvent'; - -const pastEvent: Pick = { - startsAt: subHours(new Date(), 2).toISOString(), - endsAt: subHours(new Date(), 1).toISOString(), - isFullDay: false, -}; -const fullDayPastEvent: Pick = { - startsAt: subDays(new Date(), 1).toISOString(), - isFullDay: true, -}; - -const currentEvent: Pick = { - startsAt: addHours(new Date(), 1).toISOString(), - endsAt: addHours(new Date(), 2).toISOString(), - isFullDay: false, -}; -const currentFullDayEvent: Pick = { - startsAt: startOfDay(new Date()).toISOString(), - isFullDay: true, -}; - -const futureEvent: Pick = { - startsAt: addDays(new Date(), 1).toISOString(), - endsAt: addDays(new Date(), 2).toISOString(), - isFullDay: false, -}; -const fullDayFutureEvent: Pick = { - startsAt: addDays(new Date(), 2).toISOString(), - isFullDay: false, -}; - -describe('findUpcomingCalendarEvent', () => { - it('returns the first current event by chronological order', () => { - // Given - const calendarEvents = [ - futureEvent, - currentFullDayEvent, - pastEvent, - currentEvent, - ]; - - // When - const result = findUpcomingCalendarEvent(calendarEvents); - - // Then - expect(result).toEqual(currentFullDayEvent); - }); - - it('returns the next future event by chronological order', () => { - // Given - const calendarEvents = [ - fullDayPastEvent, - fullDayFutureEvent, - futureEvent, - pastEvent, - ]; - - // When - const result = findUpcomingCalendarEvent(calendarEvents); - - // Then - expect(result).toEqual(futureEvent); - }); - - it('returns undefined if all events are in the past', () => { - // Given - const calendarEvents = [pastEvent, fullDayPastEvent]; - - // When - const result = findUpcomingCalendarEvent(calendarEvents); - - // Then - expect(result).toBeUndefined(); - }); -}); diff --git a/packages/twenty-front/src/modules/activities/calendar/utils/findUpcomingCalendarEvent.ts b/packages/twenty-front/src/modules/activities/calendar/utils/findUpcomingCalendarEvent.ts deleted file mode 100644 index 250a45112..000000000 --- a/packages/twenty-front/src/modules/activities/calendar/utils/findUpcomingCalendarEvent.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent'; -import { hasCalendarEventEnded } from '@/activities/calendar/utils/hasCalendarEventEnded'; -import { sortCalendarEventsAsc } from '@/activities/calendar/utils/sortCalendarEvents'; - -export const findUpcomingCalendarEvent = < - T extends Pick, ->( - calendarEvents: T[], -) => - [...calendarEvents] - .sort(sortCalendarEventsAsc) - .find((calendarEvent) => !hasCalendarEventEnded(calendarEvent)); diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelsGeneral.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelsGeneral.tsx index 14898148c..4ab66f3fb 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelsGeneral.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelsGeneral.tsx @@ -3,15 +3,15 @@ import { CalendarContext } from '@/activities/calendar/contexts/CalendarContext' import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { SettingsAccountsCalendarDisplaySettings } from '@/settings/accounts/components/SettingsAccountsCalendarDisplaySettings'; import styled from '@emotion/styled'; +import { t } from '@lingui/core/macro'; import { Section } from '@react-email/components'; import { addMinutes, endOfDay, min, startOfDay } from 'date-fns'; import { useRecoilValue } from 'recoil'; +import { H2Title } from 'twenty-ui/display'; import { CalendarChannelVisibility, TimelineCalendarEvent, } from '~/generated/graphql'; -import { t } from '@lingui/core/macro'; -import { H2Title } from 'twenty-ui/display'; const StyledGeneralContainer = styled.div` display: flex; @@ -78,12 +78,9 @@ export const SettingsAccountsCalendarChannelsGeneral = () => { /> undefined, - updateCurrentCalendarEvent: () => {}, }} >