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 efd85a1282..59981e9479 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/Calendar.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/Calendar.tsx @@ -4,10 +4,11 @@ import { format, getYear } from 'date-fns'; import { CalendarMonthCard } from '@/activities/calendar/components/CalendarMonthCard'; import { CalendarContext } from '@/activities/calendar/contexts/CalendarContext'; import { useCalendarEvents } from '@/activities/calendar/hooks/useCalendarEvents'; -import { sortCalendarEventsDesc } from '@/activities/calendar/utils/sortCalendarEvents'; +import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent'; +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { H3Title } from '@/ui/display/typography/components/H3Title'; import { Section } from '@/ui/layout/section/components/Section'; -import { mockedCalendarEvents } from '~/testing/mock-data/calendar'; const StyledContainer = styled.div` box-sizing: border-box; @@ -23,9 +24,11 @@ const StyledYear = styled.span` `; export const Calendar = () => { - const sortedCalendarEvents = [...mockedCalendarEvents].sort( - sortCalendarEventsDesc, - ); + const { records: calendarEvents } = useFindManyRecords({ + objectNameSingular: CoreObjectNameSingular.CalendarEvent, + orderBy: { startsAt: 'DescNullsLast', endsAt: 'DescNullsLast' }, + useRecordsWithoutConnection: true, + }); const { calendarEventsByDayTime, @@ -35,7 +38,13 @@ export const Calendar = () => { monthTimes, monthTimesByYear, updateCurrentCalendarEvent, - } = useCalendarEvents(sortedCalendarEvents); + } = useCalendarEvents( + calendarEvents.map((calendarEvent) => ({ + ...calendarEvent, + // TODO: retrieve CalendarChannel visibility from backend + visibility: 'SHARE_EVERYTHING', + })), + ); return ( { const theme = useTheme(); - const endOfDayDate = endOfDay(calendarEvents[0].startsAt); - const endsIn = differenceInSeconds(endOfDayDate, Date.now()); + const endOfDayDate = endOfDay(getCalendarEventStartDate(calendarEvents[0])); + const dayEndsIn = differenceInSeconds(endOfDayDate, Date.now()); const weekDayLabel = format(endOfDayDate, 'EE'); const monthDayLabel = format(endOfDayDate, 'dd'); @@ -71,7 +72,7 @@ export const CalendarDayCardContent = ({ animate="ended" variants={upcomingDayCardContentVariants} transition={{ - delay: Math.max(0, endsIn), + delay: Math.max(0, dayEndsIn), duration: theme.animation.duration.fast, }} > diff --git a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventDetails.tsx b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventDetails.tsx new file mode 100644 index 0000000000..ce919021fd --- /dev/null +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventDetails.tsx @@ -0,0 +1,146 @@ +import { css, useTheme } from '@emotion/react'; +import styled from '@emotion/styled'; + +import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent'; +import { useObjectMetadataItemOnly } from '@/object-metadata/hooks/useObjectMetadataItemOnly'; +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { formatFieldMetadataItemAsFieldDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsFieldDefinition'; +import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; +import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition'; +import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; +import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell'; +import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox'; +import { + Chip, + ChipAccent, + ChipSize, + ChipVariant, +} from '@/ui/display/chip/components/Chip'; +import { IconCalendarEvent } from '@/ui/display/icon'; +import { mapArrayToObject } from '~/utils/array/mapArrayToObject'; +import { beautifyPastDateRelativeToNow } from '~/utils/date-utils'; + +type CalendarEventDetailsProps = { + calendarEvent: CalendarEvent; +}; + +const StyledContainer = styled.div` + background: ${({ theme }) => theme.background.secondary}; + align-items: flex-start; + border-bottom: 1px solid ${({ theme }) => theme.border.color.medium}; + display: flex; + flex-direction: column; + gap: ${({ theme }) => theme.spacing(6)}; + padding: ${({ theme }) => theme.spacing(6)}; +`; + +const StyledEventChip = styled(Chip)` + gap: ${({ theme }) => theme.spacing(2)}; + padding-left: ${({ theme }) => theme.spacing(2)}; + padding-right: ${({ theme }) => theme.spacing(2)}; +`; + +const StyledHeader = styled.header``; + +const StyledTitle = styled.h2<{ canceled?: boolean }>` + color: ${({ theme }) => theme.font.color.primary}; + font-weight: ${({ theme }) => theme.font.weight.semiBold}; + margin: ${({ theme }) => theme.spacing(0, 0, 2)}; + + ${({ canceled }) => + canceled && + css` + text-decoration: line-through; + `} +`; + +const StyledCreatedAt = styled.div` + color: ${({ theme }) => theme.font.color.tertiary}; +`; + +const StyledFields = styled.div` + display: flex; + flex-direction: column; + gap: ${({ theme }) => theme.spacing(3)}; +`; + +const StyledPropertyBox = styled(PropertyBox)` + height: ${({ theme }) => theme.spacing(6)}; + padding: 0; +`; + +export const CalendarEventDetails = ({ + calendarEvent, +}: CalendarEventDetailsProps) => { + const theme = useTheme(); + const { objectMetadataItem } = useObjectMetadataItemOnly({ + objectNameSingular: CoreObjectNameSingular.CalendarEvent, + }); + + const fieldsToDisplay: Partial< + Record< + keyof CalendarEvent, + Partial, 'label'>> + > + > = { + startsAt: { label: 'Start Date' }, + endsAt: { label: 'End Date' }, + conferenceUri: { label: 'Meet link' }, + location: {}, + description: {}, + }; + const fieldsByName = mapArrayToObject( + objectMetadataItem.fields, + ({ name }) => name, + ); + + return ( + + } + label="Event" + /> + + + {calendarEvent.title} + + + Created{' '} + {beautifyPastDateRelativeToNow( + new Date(calendarEvent.externalCreatedAt), + )} + + + + {Object.entries(fieldsToDisplay).map(([fieldName, fieldOverride]) => ( + + [() => undefined, { loading: false }], + }} + > + + + + ))} + + + ); +}; 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 8523de0724..da0c22a72d 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx @@ -6,8 +6,10 @@ import { useRecoilValue } from 'recoil'; import { CalendarCurrentEventCursor } from '@/activities/calendar/components/CalendarCurrentEventCursor'; import { CalendarContext } from '@/activities/calendar/contexts/CalendarContext'; +import { useOpenCalendarEventRightDrawer } from '@/activities/calendar/right-drawer/hooks/useOpenCalendarEventRightDrawer'; import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent'; import { getCalendarEventEndDate } from '@/activities/calendar/utils/getCalendarEventEndDate'; +import { getCalendarEventStartDate } from '@/activities/calendar/utils/getCalendarEventStartDate'; import { hasCalendarEventEnded } from '@/activities/calendar/utils/hasCalendarEventEnded'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { IconArrowRight, IconLock } from '@/ui/display/icon'; @@ -22,12 +24,13 @@ type CalendarEventRowProps = { className?: string; }; -const StyledContainer = styled.div` +const StyledContainer = styled.div<{ showTitle?: boolean }>` align-items: center; display: inline-flex; gap: ${({ theme }) => theme.spacing(3)}; height: ${({ theme }) => theme.spacing(6)}; position: relative; + cursor: ${({ showTitle }) => (showTitle ? 'pointer' : 'not-allowed')}; `; const StyledAttendanceIndicator = styled.div<{ active?: boolean }>` @@ -101,21 +104,32 @@ export const CalendarEventRow = ({ const theme = useTheme(); const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState()); const { displayCurrentEventCursor = false } = useContext(CalendarContext); + const { openCalendarEventRightDrawer } = useOpenCalendarEventRightDrawer(); + const startsAt = getCalendarEventStartDate(calendarEvent); const endsAt = getCalendarEventEndDate(calendarEvent); const hasEnded = hasCalendarEventEnded(calendarEvent); const startTimeLabel = calendarEvent.isFullDay ? 'All day' - : format(calendarEvent.startsAt, 'HH:mm'); + : format(startsAt, 'HH:mm'); const endTimeLabel = calendarEvent.isFullDay ? '' : format(endsAt, 'HH:mm'); - const isCurrentWorkspaceMemberAttending = !!calendarEvent.attendees?.find( + const isCurrentWorkspaceMemberAttending = calendarEvent.attendees?.some( ({ workspaceMemberId }) => workspaceMemberId === currentWorkspaceMember?.id, ); + const showTitle = calendarEvent.visibility === 'SHARE_EVERYTHING'; return ( - + openCalendarEventRightDrawer(calendarEvent.id) + : undefined + } + > @@ -127,17 +141,17 @@ export const CalendarEventRow = ({ )} - {calendarEvent.visibility === 'METADATA' ? ( + {showTitle ? ( + + {calendarEvent.title} + + ) : ( Not shared - ) : ( - - {calendarEvent.title} - )} {!!calendarEvent.attendees?.length && ( 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 ff81adcf6d..4370ec88bc 100644 --- a/packages/twenty-front/src/modules/activities/calendar/contexts/CalendarContext.ts +++ b/packages/twenty-front/src/modules/activities/calendar/contexts/CalendarContext.ts @@ -4,7 +4,7 @@ import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent'; type CalendarContextValue = { calendarEventsByDayTime: Record; - currentCalendarEvent: CalendarEvent; + currentCalendarEvent?: CalendarEvent; displayCurrentEventCursor?: boolean; getNextCalendarEvent: ( calendarEvent: CalendarEvent, @@ -14,7 +14,6 @@ type CalendarContextValue = { export const CalendarContext = createContext({ calendarEventsByDayTime: {}, - currentCalendarEvent: {} as CalendarEvent, getNextCalendarEvent: () => undefined, updateCurrentCalendarEvent: () => {}, }); 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 3621c942e6..6552541bfb 100644 --- a/packages/twenty-front/src/modules/activities/calendar/hooks/useCalendarEvents.ts +++ b/packages/twenty-front/src/modules/activities/calendar/hooks/useCalendarEvents.ts @@ -3,6 +3,7 @@ import { getYear, isThisMonth, startOfDay, startOfMonth } from 'date-fns'; import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent'; import { findUpcomingCalendarEvent } from '@/activities/calendar/utils/findUpcomingCalendarEvent'; +import { getCalendarEventStartDate } from '@/activities/calendar/utils/getCalendarEventStartDate'; import { groupArrayItemsBy } from '~/utils/array/groupArrayItemsBy'; import { isDefined } from '~/utils/isDefined'; import { sortDesc } from '~/utils/sort'; @@ -10,7 +11,8 @@ import { sortDesc } from '~/utils/sort'; export const useCalendarEvents = (calendarEvents: CalendarEvent[]) => { const calendarEventsByDayTime = groupArrayItemsBy( calendarEvents, - ({ startsAt }) => startOfDay(startsAt).getTime(), + (calendarEvent) => + startOfDay(getCalendarEventStartDate(calendarEvent)).getTime(), ); const sortedDayTimes = Object.keys(calendarEventsByDayTime) @@ -45,17 +47,21 @@ export const useCalendarEvents = (calendarEvents: CalendarEvent[]) => { () => findUpcomingCalendarEvent(calendarEvents), [calendarEvents], ); - const lastEventInCalendar = calendarEvents[0]; + const lastEventInCalendar = calendarEvents.length + ? calendarEvents[0] + : undefined; const [currentCalendarEvent, setCurrentCalendarEvent] = useState( (initialUpcomingCalendarEvent && - (isThisMonth(initialUpcomingCalendarEvent.startsAt) + (isThisMonth(getCalendarEventStartDate(initialUpcomingCalendarEvent)) ? initialUpcomingCalendarEvent : getPreviousCalendarEvent(initialUpcomingCalendarEvent))) || lastEventInCalendar, ); const updateCurrentCalendarEvent = () => { + if (!currentCalendarEvent) return; + const nextCurrentCalendarEvent = getNextCalendarEvent(currentCalendarEvent); if (isDefined(nextCurrentCalendarEvent)) { diff --git a/packages/twenty-front/src/modules/activities/calendar/right-drawer/components/RightDrawerCalendarEvent.tsx b/packages/twenty-front/src/modules/activities/calendar/right-drawer/components/RightDrawerCalendarEvent.tsx new file mode 100644 index 0000000000..2a60859646 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/calendar/right-drawer/components/RightDrawerCalendarEvent.tsx @@ -0,0 +1,22 @@ +import { useRecoilValue } from 'recoil'; + +import { CalendarEventDetails } from '@/activities/calendar/components/CalendarEventDetails'; +import { viewableCalendarEventIdState } from '@/activities/calendar/states/viewableCalendarEventIdState'; +import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent'; +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord'; +import { useSetRecordInStore } from '@/object-record/record-store/hooks/useSetRecordInStore'; + +export const RightDrawerCalendarEvent = () => { + const { setRecords } = useSetRecordInStore(); + const calendarEventId = useRecoilValue(viewableCalendarEventIdState()); + const { record: calendarEvent } = useFindOneRecord({ + objectNameSingular: CoreObjectNameSingular.CalendarEvent, + objectRecordId: calendarEventId ?? '', + onCompleted: (record) => setRecords([record]), + }); + + if (!calendarEvent) return null; + + return ; +}; diff --git a/packages/twenty-front/src/modules/activities/calendar/right-drawer/hooks/useOpenCalendarEventRightDrawer.ts b/packages/twenty-front/src/modules/activities/calendar/right-drawer/hooks/useOpenCalendarEventRightDrawer.ts new file mode 100644 index 0000000000..ccf3e4fce5 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/calendar/right-drawer/hooks/useOpenCalendarEventRightDrawer.ts @@ -0,0 +1,23 @@ +import { useSetRecoilState } from 'recoil'; + +import { viewableCalendarEventIdState } from '@/activities/calendar/states/viewableCalendarEventIdState'; +import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer'; +import { RightDrawerHotkeyScope } from '@/ui/layout/right-drawer/types/RightDrawerHotkeyScope'; +import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages'; +import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; + +export const useOpenCalendarEventRightDrawer = () => { + const { openRightDrawer } = useRightDrawer(); + const setHotkeyScope = useSetHotkeyScope(); + const setViewableCalendarEventId = useSetRecoilState( + viewableCalendarEventIdState(), + ); + + const openCalendarEventRightDrawer = (calendarEventId: string) => { + setHotkeyScope(RightDrawerHotkeyScope.RightDrawer, { goto: false }); + openRightDrawer(RightDrawerPages.ViewCalendarEvent); + setViewableCalendarEventId(calendarEventId); + }; + + return { openCalendarEventRightDrawer }; +}; diff --git a/packages/twenty-front/src/modules/activities/calendar/states/viewableCalendarEventIdState.ts b/packages/twenty-front/src/modules/activities/calendar/states/viewableCalendarEventIdState.ts new file mode 100644 index 0000000000..8ecfe54f36 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/calendar/states/viewableCalendarEventIdState.ts @@ -0,0 +1,6 @@ +import { createState } from '@/ui/utilities/state/utils/createState'; + +export const viewableCalendarEventIdState = createState({ + key: 'viewableCalendarEventIdState', + defaultValue: null, +}); diff --git a/packages/twenty-front/src/modules/activities/calendar/types/CalendarEvent.ts b/packages/twenty-front/src/modules/activities/calendar/types/CalendarEvent.ts index c12c5f19fe..1e3cfb8506 100644 --- a/packages/twenty-front/src/modules/activities/calendar/types/CalendarEvent.ts +++ b/packages/twenty-front/src/modules/activities/calendar/types/CalendarEvent.ts @@ -1,10 +1,14 @@ // TODO: use backend CalendarEvent type when ready export type CalendarEvent = { - endsAt?: Date; + conferenceUri?: string; + description?: string; + endsAt?: string; + externalCreatedAt: string; id: string; - isFullDay: boolean; - startsAt: Date; isCanceled?: boolean; + isFullDay: boolean; + location?: string; + startsAt: string; title?: string; visibility: 'METADATA' | 'SHARE_EVERYTHING'; attendees?: { diff --git a/packages/twenty-front/src/modules/activities/calendar/utils/getCalendarEventEndDate.ts b/packages/twenty-front/src/modules/activities/calendar/utils/getCalendarEventEndDate.ts index 0d25a605bb..8463f2236f 100644 --- a/packages/twenty-front/src/modules/activities/calendar/utils/getCalendarEventEndDate.ts +++ b/packages/twenty-front/src/modules/activities/calendar/utils/getCalendarEventEndDate.ts @@ -1,7 +1,11 @@ import { endOfDay } from 'date-fns'; import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent'; +import { getCalendarEventStartDate } from '@/activities/calendar/utils/getCalendarEventStartDate'; export const getCalendarEventEndDate = ( calendarEvent: Pick, -) => calendarEvent.endsAt ?? endOfDay(calendarEvent.startsAt); +) => + calendarEvent.endsAt + ? new Date(calendarEvent.endsAt) + : endOfDay(getCalendarEventStartDate(calendarEvent)); diff --git a/packages/twenty-front/src/modules/activities/calendar/utils/getCalendarEventStartDate.ts b/packages/twenty-front/src/modules/activities/calendar/utils/getCalendarEventStartDate.ts new file mode 100644 index 0000000000..db7a08de3e --- /dev/null +++ b/packages/twenty-front/src/modules/activities/calendar/utils/getCalendarEventStartDate.ts @@ -0,0 +1,5 @@ +import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent'; + +export const getCalendarEventStartDate = ( + calendarEvent: Pick, +) => new Date(calendarEvent.startsAt); diff --git a/packages/twenty-front/src/modules/activities/calendar/utils/hasCalendarEventStarted.ts b/packages/twenty-front/src/modules/activities/calendar/utils/hasCalendarEventStarted.ts index ec7d7a2c5d..f351edc9d9 100644 --- a/packages/twenty-front/src/modules/activities/calendar/utils/hasCalendarEventStarted.ts +++ b/packages/twenty-front/src/modules/activities/calendar/utils/hasCalendarEventStarted.ts @@ -1,7 +1,8 @@ import { isPast } from 'date-fns'; import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent'; +import { getCalendarEventStartDate } from '@/activities/calendar/utils/getCalendarEventStartDate'; export const hasCalendarEventStarted = ( calendarEvent: Pick, -) => isPast(calendarEvent.startsAt); +) => isPast(getCalendarEventStartDate(calendarEvent)); diff --git a/packages/twenty-front/src/modules/activities/calendar/utils/sortCalendarEvents.ts b/packages/twenty-front/src/modules/activities/calendar/utils/sortCalendarEvents.ts index fc3b773538..8ea50406c3 100644 --- a/packages/twenty-front/src/modules/activities/calendar/utils/sortCalendarEvents.ts +++ b/packages/twenty-front/src/modules/activities/calendar/utils/sortCalendarEvents.ts @@ -1,5 +1,6 @@ import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent'; import { getCalendarEventEndDate } from '@/activities/calendar/utils/getCalendarEventEndDate'; +import { getCalendarEventStartDate } from '@/activities/calendar/utils/getCalendarEventStartDate'; import { sortAsc } from '~/utils/sort'; export const sortCalendarEventsAsc = ( @@ -7,18 +8,16 @@ export const sortCalendarEventsAsc = ( calendarEventB: Pick, ) => { const startsAtSort = sortAsc( - calendarEventA.startsAt.getTime(), - calendarEventB.startsAt.getTime(), + getCalendarEventStartDate(calendarEventA).getTime(), + getCalendarEventStartDate(calendarEventB).getTime(), ); - if (startsAtSort === 0) { - const endsAtA = getCalendarEventEndDate(calendarEventA); - const endsAtB = getCalendarEventEndDate(calendarEventB); + if (startsAtSort !== 0) return startsAtSort; - return sortAsc(endsAtA.getTime(), endsAtB.getTime()); - } - - return startsAtSort; + return sortAsc( + getCalendarEventEndDate(calendarEventA).getTime(), + getCalendarEventEndDate(calendarEventB).getTime(), + ); }; export const sortCalendarEventsDesc = ( diff --git a/packages/twenty-front/src/modules/activities/emails/right-drawer/components/RightDrawerEmailThreadTopBar.tsx b/packages/twenty-front/src/modules/activities/emails/right-drawer/components/RightDrawerEmailThreadTopBar.tsx deleted file mode 100644 index 29e71fe6e1..0000000000 --- a/packages/twenty-front/src/modules/activities/emails/right-drawer/components/RightDrawerEmailThreadTopBar.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import styled from '@emotion/styled'; - -import { StyledRightDrawerTopBar } from '@/ui/layout/right-drawer/components/StyledRightDrawerTopBar'; -import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; - -import { RightDrawerTopBarCloseButton } from '../../../../ui/layout/right-drawer/components/RightDrawerTopBarCloseButton'; -import { RightDrawerTopBarExpandButton } from '../../../../ui/layout/right-drawer/components/RightDrawerTopBarExpandButton'; - -const StyledTopBarWrapper = styled.div` - display: flex; -`; - -export const RightDrawerEmailThreadTopBar = () => { - const isMobile = useIsMobile(); - - return ( - - - - {!isMobile && } - - - ); -}; diff --git a/packages/twenty-front/src/modules/activities/emails/right-drawer/components/__stories__/RightDrawerEmailThreadTopBar.stories.tsx b/packages/twenty-front/src/modules/activities/emails/right-drawer/components/__stories__/RightDrawerEmailThreadTopBar.stories.tsx deleted file mode 100644 index ebbfc80dcb..0000000000 --- a/packages/twenty-front/src/modules/activities/emails/right-drawer/components/__stories__/RightDrawerEmailThreadTopBar.stories.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { Meta, StoryObj } from '@storybook/react'; - -import { RightDrawerEmailThreadTopBar } from '@/activities/emails/right-drawer/components/RightDrawerEmailThreadTopBar'; -import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator'; -import { graphqlMocks } from '~/testing/graphqlMocks'; - -const meta: Meta = { - title: 'Modules/Activities/Emails/RightDrawer/RightDrawerEmailThreadTopBar', - component: RightDrawerEmailThreadTopBar, - decorators: [ - (Story) => ( -
- -
- ), - ComponentDecorator, - ], - parameters: { - msw: graphqlMocks, - }, -}; - -export default meta; -type Story = StoryObj; - -export const Default: Story = {}; diff --git a/packages/twenty-front/src/modules/activities/right-drawer/components/RightDrawerActivityTopBar.tsx b/packages/twenty-front/src/modules/activities/right-drawer/components/RightDrawerActivityTopBar.tsx index 628fc3893d..2e3c35fe4c 100644 --- a/packages/twenty-front/src/modules/activities/right-drawer/components/RightDrawerActivityTopBar.tsx +++ b/packages/twenty-front/src/modules/activities/right-drawer/components/RightDrawerActivityTopBar.tsx @@ -1,17 +1,20 @@ import styled from '@emotion/styled'; import { ActivityActionBar } from '@/activities/right-drawer/components/ActivityActionBar'; +import { RightDrawerTopBarCloseButton } from '@/ui/layout/right-drawer/components/RightDrawerTopBarCloseButton'; +import { RightDrawerTopBarExpandButton } from '@/ui/layout/right-drawer/components/RightDrawerTopBarExpandButton'; import { StyledRightDrawerTopBar } from '@/ui/layout/right-drawer/components/StyledRightDrawerTopBar'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; -import { RightDrawerTopBarCloseButton } from '../../../ui/layout/right-drawer/components/RightDrawerTopBarCloseButton'; -import { RightDrawerTopBarExpandButton } from '../../../ui/layout/right-drawer/components/RightDrawerTopBarExpandButton'; +type RightDrawerActivityTopBarProps = { showActionBar?: boolean }; const StyledTopBarWrapper = styled.div` display: flex; `; -export const RightDrawerActivityTopBar = () => { +export const RightDrawerActivityTopBar = ({ + showActionBar = true, +}: RightDrawerActivityTopBarProps) => { const isMobile = useIsMobile(); return ( @@ -20,7 +23,7 @@ export const RightDrawerActivityTopBar = () => { {!isMobile && } - + {showActionBar && } ); }; diff --git a/packages/twenty-front/src/modules/object-metadata/types/CoreObjectNameSingular.ts b/packages/twenty-front/src/modules/object-metadata/types/CoreObjectNameSingular.ts index e148338d90..13591a07d0 100644 --- a/packages/twenty-front/src/modules/object-metadata/types/CoreObjectNameSingular.ts +++ b/packages/twenty-front/src/modules/object-metadata/types/CoreObjectNameSingular.ts @@ -4,6 +4,7 @@ export enum CoreObjectNameSingular { ApiKey = 'apiKey', Attachment = 'attachment', Blocklist = 'blocklist', + CalendarEvent = 'calendarEvent', Comment = 'comment', Company = 'company', ConnectedAccount = 'connectedAccount', diff --git a/packages/twenty-front/src/modules/object-record/record-field/hooks/useIsFieldInputOnly.ts b/packages/twenty-front/src/modules/object-record/record-field/hooks/useIsFieldInputOnly.ts index d1566823ce..750ea8b0b4 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/hooks/useIsFieldInputOnly.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/hooks/useIsFieldInputOnly.ts @@ -7,9 +7,5 @@ import { isFieldRating } from '../types/guards/isFieldRating'; export const useIsFieldInputOnly = () => { const { fieldDefinition } = useContext(FieldContext); - if (isFieldBoolean(fieldDefinition) || isFieldRating(fieldDefinition)) { - return true; - } - - return false; + return isFieldBoolean(fieldDefinition) || isFieldRating(fieldDefinition); }; diff --git a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx index fd677eecdc..bb2c8fc6bd 100644 --- a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx @@ -15,7 +15,11 @@ import { useInlineCell } from '../hooks/useInlineCell'; import { RecordInlineCellContainer } from './RecordInlineCellContainer'; -export const RecordInlineCell = () => { +type RecordInlineCellProps = { + readonly?: boolean; +}; + +export const RecordInlineCell = ({ readonly }: RecordInlineCellProps) => { const { fieldDefinition, entityId } = useContext(FieldContext); const buttonIcon = useGetButtonIcon(); @@ -63,6 +67,7 @@ export const RecordInlineCell = () => { return ( ` display: flex; gap: ${({ theme }) => theme.spacing(1)}; width: 100%; + + ${({ readonly }) => + !readonly && + css` + cursor: pointer; + `}; `; const StyledInlineCellBaseContainer = styled.div` @@ -83,6 +88,7 @@ const StyledTooltip = styled(Tooltip)` `; type RecordInlineCellContainerProps = { + readonly?: boolean; IconLabel?: IconComponent; label?: string; labelWidth?: number; @@ -98,6 +104,7 @@ type RecordInlineCellContainerProps = { }; export const RecordInlineCellContainer = ({ + readonly, IconLabel, label, labelWidth, @@ -115,17 +122,21 @@ export const RecordInlineCellContainer = ({ const [isHovered, setIsHovered] = useState(false); const handleContainerMouseEnter = () => { - setIsHovered(true); + if (!readonly) { + setIsHovered(true); + } }; const handleContainerMouseLeave = () => { - setIsHovered(false); + if (!readonly) { + setIsHovered(false); + } }; const { isInlineCellInEditMode, openInlineCell } = useInlineCell(); const handleDisplayModeClick = () => { - if (!editModeContentOnly) { + if (!readonly && !editModeContentOnly) { openInlineCell(customEditHotkeyScope); } }; @@ -167,10 +178,10 @@ export const RecordInlineCellContainer = ({ )} - {isInlineCellInEditMode ? ( + {!readonly && isInlineCellInEditMode ? ( {editModeContent} ) : editModeContentOnly ? ( - + ) : ( - + diff --git a/packages/twenty-front/src/modules/ui/display/chip/components/Chip.tsx b/packages/twenty-front/src/modules/ui/display/chip/components/Chip.tsx index 9e6f5843d5..cec0483d26 100644 --- a/packages/twenty-front/src/modules/ui/display/chip/components/Chip.tsx +++ b/packages/twenty-front/src/modules/ui/display/chip/components/Chip.tsx @@ -1,4 +1,5 @@ import { MouseEvent, ReactNode } from 'react'; +import { css } from '@emotion/react'; import styled from '@emotion/styled'; import { OverflowingTextWithTooltip } from '../../tooltip/OverflowingTextWithTooltip'; @@ -34,86 +35,108 @@ type ChipProps = { onClick?: (event: MouseEvent) => void; }; -const StyledContainer = styled.div>` +const StyledContainer = styled.div< + Pick< + ChipProps, + 'accent' | 'clickable' | 'disabled' | 'maxWidth' | 'size' | 'variant' + > +>` + --chip-horizontal-padding: ${({ theme }) => theme.spacing(1)}; + --chip-vertical-padding: ${({ theme }) => theme.spacing(1)}; + align-items: center; - - background-color: ${({ theme, variant }) => - variant === ChipVariant.Highlighted - ? theme.background.transparent.light - : variant === ChipVariant.Rounded - ? theme.background.transparent.lighter - : 'transparent'}; - border-color: ${({ theme, variant }) => - variant === ChipVariant.Rounded ? theme.border.color.medium : 'none'}; - border-radius: ${({ theme, variant }) => - variant === ChipVariant.Rounded ? '50px' : theme.border.radius.sm}; - border-style: ${({ variant }) => - variant === ChipVariant.Rounded ? 'solid' : 'none'}; - border-width: ${({ variant }) => - variant === ChipVariant.Rounded ? '1px' : '0px'}; - - color: ${({ theme, disabled, accent }) => - disabled - ? theme.font.color.light - : accent === ChipAccent.TextPrimary - ? theme.font.color.primary - : theme.font.color.secondary}; - cursor: ${({ clickable, disabled, variant }) => - disabled || variant === ChipVariant.Transparent - ? 'inherit' - : clickable - ? 'pointer' - : 'inherit'}; + border-radius: ${({ theme }) => theme.border.radius.sm}; + color: ${({ theme, disabled }) => + disabled ? theme.font.color.light : theme.font.color.secondary}; + cursor: ${({ clickable, disabled }) => + clickable ? 'pointer' : disabled ? 'not-allowed' : 'inherit'}; display: inline-flex; - font-weight: ${({ theme, accent }) => - accent === ChipAccent.TextSecondary ? theme.font.weight.medium : 'inherit'}; gap: ${({ theme }) => theme.spacing(1)}; - - height: ${({ size }) => (size === ChipSize.Large ? '16px' : '12px')}; - --chip-horizontal-padding: ${({ theme, variant }) => - variant === ChipVariant.Rounded ? theme.spacing(2) : theme.spacing(1)}; + height: ${({ theme }) => theme.spacing(3)}; max-width: ${({ maxWidth }) => maxWidth - ? `calc( ${maxWidth}px - 2*var(--chip-horizontal-padding))` + ? `calc(${maxWidth}px - 2 * var(--chip-horizontal-padding))` : '200px'}; - - --chip-vertical-padding: ${({ theme, variant }) => - variant === ChipVariant.Rounded ? '3px' : theme.spacing(1)}; - overflow: hidden; padding: var(--chip-vertical-padding) var(--chip-horizontal-padding); user-select: none; - :hover { - ${({ variant, theme, disabled }) => { - if (!disabled) { - return ( - 'background-color: ' + - (variant === ChipVariant.Highlighted - ? theme.background.transparent.medium - : variant === ChipVariant.Regular - ? theme.background.transparent.light - : 'transparent') + - ';' - ); - } - }} - } - :active { - ${({ variant, theme, disabled }) => { - if (!disabled) { - return ( - 'background-color: ' + - (variant === ChipVariant.Highlighted - ? theme.background.transparent.strong - : variant === ChipVariant.Regular - ? theme.background.transparent.medium - : 'transparent') + - ';' - ); - } - }} - } + // Accent style overrides + ${({ accent, disabled, theme }) => { + if (accent === ChipAccent.TextPrimary) { + return ( + !disabled && + css` + color: ${theme.font.color.primary}; + ` + ); + } + + if (accent === ChipAccent.TextSecondary) { + return css` + font-weight: ${theme.font.weight.medium}; + `; + } + }} + + // Size style overrides + ${({ theme, size }) => + size === ChipSize.Large && + css` + height: ${theme.spacing(4)}; + `} + + // Variant style overrides + ${({ disabled, theme, variant }) => { + if (variant === ChipVariant.Regular) { + return ( + !disabled && + css` + :hover { + background-color: ${theme.background.transparent.light}; + } + + :active { + background-color: ${theme.background.transparent.medium}; + } + ` + ); + } + + if (variant === ChipVariant.Highlighted) { + return css` + background-color: ${theme.background.transparent.light}; + + ${!disabled && + css` + :hover { + background-color: ${theme.background.transparent.medium}; + } + + :active { + background-color: ${theme.background.transparent.strong}; + } + `} + `; + } + + if (variant === ChipVariant.Rounded) { + return css` + --chip-horizontal-padding: ${theme.spacing(2)}; + --chip-vertical-padding: 3px; + + background-color: ${theme.background.transparent.lighter}; + border: 1px solid ${theme.border.color.medium}; + border-radius: 50px; + `; + } + + if (variant === ChipVariant.Transparent) { + return css` + cursor: inherit; + `; + } + }} `; const StyledLabel = styled.span` diff --git a/packages/twenty-front/src/modules/ui/display/icon/constants/index.ts b/packages/twenty-front/src/modules/ui/display/icon/constants/index.ts index becf2f91bb..cc521b61a0 100644 --- a/packages/twenty-front/src/modules/ui/display/icon/constants/index.ts +++ b/packages/twenty-front/src/modules/ui/display/icon/constants/index.ts @@ -950,6 +950,7 @@ import { IconCalendarBolt, IconCalendarCancel, IconCalendarCheck, + IconCalendarClock, IconCalendarCode, IconCalendarCog, IconCalendarDollar, @@ -4199,14 +4200,14 @@ import { } from '@tabler/icons-react'; export default { + Icon123, + Icon24Hours, Icon2fa, + Icon360, + Icon360View, Icon3dCubeSphere, Icon3dCubeSphereOff, Icon3dRotate, - Icon24Hours, - Icon123, - Icon360, - Icon360View, IconAB, IconAB2, IconAbacus, @@ -5149,6 +5150,7 @@ export default { IconCalendarBolt, IconCalendarCancel, IconCalendarCheck, + IconCalendarClock, IconCalendarCode, IconCalendarCog, IconCalendarDollar, @@ -5440,6 +5442,9 @@ export default { IconClockExclamation, IconClockHeart, IconClockHour1, + IconClockHour10, + IconClockHour11, + IconClockHour12, IconClockHour2, IconClockHour3, IconClockHour4, @@ -5448,9 +5453,6 @@ export default { IconClockHour7, IconClockHour8, IconClockHour9, - IconClockHour10, - IconClockHour11, - IconClockHour12, IconClockMinus, IconClockOff, IconClockPause, @@ -7117,10 +7119,10 @@ export default { IconMovieOff, IconMug, IconMugOff, - IconMultiplier1x, - IconMultiplier2x, IconMultiplier05x, IconMultiplier15x, + IconMultiplier1x, + IconMultiplier2x, IconMushroom, IconMushroomOff, IconMusic, @@ -7515,20 +7517,20 @@ export default { IconReservedLine, IconResize, IconRestore, - IconRewindBackward5, IconRewindBackward10, IconRewindBackward15, IconRewindBackward20, IconRewindBackward30, IconRewindBackward40, + IconRewindBackward5, IconRewindBackward50, IconRewindBackward60, - IconRewindForward5, IconRewindForward10, IconRewindForward15, IconRewindForward20, IconRewindForward30, IconRewindForward40, + IconRewindForward5, IconRewindForward50, IconRewindForward60, IconRibbonHealth, @@ -8080,11 +8082,11 @@ export default { IconTiltShift, IconTiltShiftOff, IconTimeDuration0, - IconTimeDuration5, IconTimeDuration10, IconTimeDuration15, IconTimeDuration30, IconTimeDuration45, + IconTimeDuration5, IconTimeDuration60, IconTimeDuration90, IconTimeDurationOff, diff --git a/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerRouter.tsx b/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerRouter.tsx index cb981739be..7eced58ff4 100644 --- a/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerRouter.tsx +++ b/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerRouter.tsx @@ -1,8 +1,8 @@ import styled from '@emotion/styled'; import { useRecoilState } from 'recoil'; +import { RightDrawerCalendarEvent } from '@/activities/calendar/right-drawer/components/RightDrawerCalendarEvent'; import { RightDrawerEmailThread } from '@/activities/emails/right-drawer/components/RightDrawerEmailThread'; -import { RightDrawerEmailThreadTopBar } from '@/activities/emails/right-drawer/components/RightDrawerEmailThreadTopBar'; import { RightDrawerCreateActivity } from '@/activities/right-drawer/components/create/RightDrawerCreateActivity'; import { RightDrawerEditActivity } from '@/activities/right-drawer/components/edit/RightDrawerEditActivity'; @@ -27,28 +27,31 @@ const StyledRightDrawerBody = styled.div` position: relative; `; +const RIGHT_DRAWER_PAGES_CONFIG = { + [RightDrawerPages.CreateActivity]: { + page: , + topBar: , + }, + [RightDrawerPages.EditActivity]: { + page: , + topBar: , + }, + [RightDrawerPages.ViewEmailThread]: { + page: , + topBar: , + }, + [RightDrawerPages.ViewCalendarEvent]: { + page: , + topBar: , + }, +}; + export const RightDrawerRouter = () => { const [rightDrawerPage] = useRecoilState(rightDrawerPageState()); - let page = <>; - let topBar = <>; - - switch (rightDrawerPage) { - case RightDrawerPages.CreateActivity: - page = ; - topBar = ; - break; - case RightDrawerPages.EditActivity: - page = ; - topBar = ; - break; - case RightDrawerPages.ViewEmailThread: - page = ; - topBar = ; - break; - default: - break; - } + const { topBar = null, page = null } = rightDrawerPage + ? RIGHT_DRAWER_PAGES_CONFIG[rightDrawerPage] + : {}; return ( diff --git a/packages/twenty-front/src/modules/ui/layout/right-drawer/types/RightDrawerPages.ts b/packages/twenty-front/src/modules/ui/layout/right-drawer/types/RightDrawerPages.ts index e0028a7c5e..df0cd28ca5 100644 --- a/packages/twenty-front/src/modules/ui/layout/right-drawer/types/RightDrawerPages.ts +++ b/packages/twenty-front/src/modules/ui/layout/right-drawer/types/RightDrawerPages.ts @@ -2,4 +2,5 @@ export enum RightDrawerPages { CreateActivity = 'create-activity', EditActivity = 'edit-activity', ViewEmailThread = 'view-email-thread', + ViewCalendarEvent = 'view-calendar-event', } diff --git a/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsCalendars.tsx b/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsCalendars.tsx index 9d4a537b8c..d4960b0731 100644 --- a/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsCalendars.tsx +++ b/packages/twenty-front/src/pages/settings/accounts/SettingsAccountsCalendars.tsx @@ -50,9 +50,10 @@ export const SettingsAccountsCalendars = () => { workspaceMemberId: currentWorkspaceMember?.id ?? '', }, ], - endsAt: exampleEndDate, + endsAt: exampleEndDate.toISOString(), + externalCreatedAt: new Date().toISOString(), isFullDay: false, - startsAt: exampleStartDate, + startsAt: exampleStartDate.toISOString(), title: 'Onboarding call', visibility: 'SHARE_EVERYTHING', }; diff --git a/packages/twenty-front/src/testing/mock-data/calendar.ts b/packages/twenty-front/src/testing/mock-data/calendar.ts index 1f1d8c7606..e0d671b6a4 100644 --- a/packages/twenty-front/src/testing/mock-data/calendar.ts +++ b/packages/twenty-front/src/testing/mock-data/calendar.ts @@ -1,13 +1,14 @@ -import { addDays, subMonths } from 'date-fns'; +import { addDays, subHours, subMonths } from 'date-fns'; import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent'; export const mockedCalendarEvents: CalendarEvent[] = [ { + externalCreatedAt: new Date().toISOString(), + endsAt: addDays(new Date().setHours(11, 30), 1).toISOString(), id: '9a6b35f1-6078-415b-9540-f62671bb81d0', - endsAt: addDays(new Date().setHours(11, 30), 1), isFullDay: false, - startsAt: addDays(new Date().setHours(10, 0), 1), + startsAt: addDays(new Date().setHours(10, 0), 1).toISOString(), visibility: 'METADATA', attendees: [ { displayName: 'John Doe', workspaceMemberId: 'john-doe' }, @@ -16,41 +17,46 @@ export const mockedCalendarEvents: CalendarEvent[] = [ ], }, { + externalCreatedAt: subHours(new Date(), 2).toISOString(), id: '19b32878-a950-4968-9e3b-ce5da514ea41', - endsAt: new Date(new Date().setHours(18, 40)), + endsAt: new Date(new Date().setHours(18, 40)).toISOString(), isCanceled: true, isFullDay: false, - startsAt: new Date(new Date().setHours(18, 0)), + startsAt: new Date(new Date().setHours(18, 0)).toISOString(), title: 'Bug solving', visibility: 'SHARE_EVERYTHING', }, { + externalCreatedAt: subHours(new Date(), 2).toISOString(), id: '6ad1cbcb-2ac4-409e-aff0-48165556fc0c', - endsAt: new Date(new Date().setHours(16, 30)), + endsAt: new Date(new Date().setHours(16, 30)).toISOString(), isFullDay: false, - startsAt: new Date(new Date().setHours(15, 15)), + startsAt: new Date(new Date().setHours(15, 15)).toISOString(), title: 'Onboarding Follow-Up Call', visibility: 'SHARE_EVERYTHING', }, { + externalCreatedAt: subHours(new Date(), 2).toISOString(), id: '52cc83e3-f3dc-4c25-8a7d-5ff857612142', - endsAt: new Date(new Date().setHours(10, 30)), + endsAt: new Date(new Date().setHours(10, 30)).toISOString(), isFullDay: false, - startsAt: new Date(new Date().setHours(10, 0)), + startsAt: new Date(new Date().setHours(10, 0)).toISOString(), title: 'Onboarding Call', visibility: 'SHARE_EVERYTHING', }, { + externalCreatedAt: subHours(new Date(), 2).toISOString(), id: '5a792d11-259a-4099-af51-59eb85e15d83', isFullDay: true, - startsAt: subMonths(new Date().setHours(8, 0), 1), + startsAt: subMonths(new Date().setHours(8, 0), 1).toISOString(), visibility: 'METADATA', }, { + externalCreatedAt: subHours(new Date(), 2).toISOString(), id: '89e2a1c7-3d3f-4e79-a492-aa5de3785fc5', - endsAt: subMonths(new Date().setHours(14, 30), 3), + endsAt: subMonths(new Date().setHours(14, 30), 3).toISOString(), isFullDay: false, - startsAt: subMonths(new Date().setHours(14, 0), 3), + startsAt: subMonths(new Date().setHours(14, 0), 3).toISOString(), title: 'Alan x Garry', visibility: 'SHARE_EVERYTHING', }, diff --git a/packages/twenty-server/src/database/commands/data-seed-dev-workspace.command.ts b/packages/twenty-server/src/database/commands/data-seed-dev-workspace.command.ts index 1bf8793d94..669177abb6 100644 --- a/packages/twenty-server/src/database/commands/data-seed-dev-workspace.command.ts +++ b/packages/twenty-server/src/database/commands/data-seed-dev-workspace.command.ts @@ -11,9 +11,10 @@ import { seedWorkspaceMember } from 'src/database/typeorm-seeds/workspace/worksp import { seedPeople } from 'src/database/typeorm-seeds/workspace/people'; import { seedCoreSchema } from 'src/database/typeorm-seeds/core'; import { EnvironmentService } from 'src/integrations/environment/environment.service'; -import { WorkspaceSyncMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.service'; -import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; +import { seedCalendarEvents } from 'src/database/typeorm-seeds/workspace/calendar-events'; import { ObjectMetadataService } from 'src/engine-metadata/object-metadata/object-metadata.service'; +import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; +import { WorkspaceSyncMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.service'; // TODO: implement dry-run @Command({ @@ -105,6 +106,7 @@ export class DataSeedWorkspaceCommand extends CommandRunner { await seedPeople(workspaceDataSource, dataSourceMetadata.schema); await seedPipelineStep(workspaceDataSource, dataSourceMetadata.schema); await seedOpportunity(workspaceDataSource, dataSourceMetadata.schema); + await seedCalendarEvents(workspaceDataSource, dataSourceMetadata.schema); await seedViews( workspaceDataSource, diff --git a/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-events.ts b/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-events.ts new file mode 100644 index 0000000000..8f2f23db0f --- /dev/null +++ b/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-events.ts @@ -0,0 +1,48 @@ +import { DataSource } from 'typeorm'; + +const tableName = 'calendarEvent'; + +export const seedCalendarEvents = async ( + workspaceDataSource: DataSource, + schemaName: string, +) => { + await workspaceDataSource + .createQueryBuilder() + .insert() + .into(`${schemaName}.${tableName}`, [ + 'id', + 'title', + 'isCanceled', + 'isFullDay', + 'startsAt', + 'endsAt', + 'externalCreatedAt', + 'externalUpdatedAt', + 'description', + 'location', + 'iCalUID', + 'conferenceSolution', + 'conferenceUri', + 'recurringEventExternalId', + ]) + .orIgnore() + .values([ + { + id: '86083141-1c0e-494c-a1b6-85b1c6fefaa5', + title: 'Meeting with Christoph', + isCanceled: false, + isFullDay: false, + startsAt: new Date(new Date().setHours(10, 0)).toISOString(), + endsAt: new Date(new Date().setHours(11, 0)).toISOString(), + externalCreatedAt: new Date().toISOString(), + externalUpdatedAt: new Date().toISOString(), + description: 'Discuss project progress', + location: 'Seattle', + iCalUID: 'event1@calendar.com', + conferenceSolution: 'Zoom', + conferenceUri: 'https://zoom.us/j/1234567890', + recurringEventExternalId: 'recurring1', + }, + ]) + .execute(); +};