diff --git a/islands/calendar/MainCalendar.tsx b/islands/calendar/MainCalendar.tsx index b8bd2b4..9c79997 100644 --- a/islands/calendar/MainCalendar.tsx +++ b/islands/calendar/MainCalendar.tsx @@ -26,9 +26,19 @@ export default function MainCalendar({ initialCalendars, initialCalendarEvents, const isImportExportOptionsDropdownOpen = useSignal(false); const calendarEvents = useSignal(initialCalendarEvents); const searchTimeout = useSignal>(0); + const openEvent = useSignal(null); const dateFormat = new Intl.DateTimeFormat('en-GB', { year: 'numeric', month: 'long' }); const hourFormat = new Intl.DateTimeFormat('en-GB', { hour12: false, hour: '2-digit', minute: '2-digit' }); + const eventDateFormat = new Intl.DateTimeFormat('en-GB', { + year: 'numeric', + month: 'long', + day: 'numeric', + hour12: false, + hour: '2-digit', + minute: '2-digit', + }); + const allDayEventDateFormat = new Intl.DateTimeFormat('en-GB', { year: 'numeric', month: 'long', day: 'numeric' }); const today = new Date().toISOString().substring(0, 10); function onClickAddEvent() { @@ -111,6 +121,8 @@ export default function MainCalendar({ initialCalendars, initialCalendarEvents, // } isDeleting.value = false; + + openEvent.value = null; } } @@ -501,127 +513,147 @@ export default function MainCalendar({ initialCalendars, initialCalendarEvents,
-
-
-
-
- M - on -
-
- T - ue -
-
- W - ed -
-
- T - hu -
-
- F - ri -
-
- S - at -
-
- S - un -
+ {view === 'day' + ? ( +
+ TODO: Build day view
-
-
- {weeks.map((week, weekIndex) => - week.map((day, dayIndex) => { - const shortIsoDate = day.date.toISOString().substring(0, 10); + ) + : null} + {view === 'week' + ? ( +
+ TODO: Build week view +
+ ) + : null} + {view === 'month' + ? ( +
+
+
+
+ M + on +
+
+ T + ue +
+
+ W + ed +
+
+ T + hu +
+
+ F + ri +
+
+ S + at +
+
+ S + un +
+
+
+
+ {weeks.map((week, weekIndex) => + week.map((day, dayIndex) => { + const shortIsoDate = day.date.toISOString().substring(0, 10); - const startDayDate = new Date(shortIsoDate); - const endDayDate = new Date(shortIsoDate); - endDayDate.setHours(23); - endDayDate.setMinutes(59); - endDayDate.setSeconds(59); - endDayDate.setMilliseconds(999); + const startDayDate = new Date(shortIsoDate); + const endDayDate = new Date(shortIsoDate); + endDayDate.setHours(23); + endDayDate.setMinutes(59); + endDayDate.setSeconds(59); + endDayDate.setMilliseconds(999); - const isBottomLeftDay = weekIndex === weeks.length - 1 && dayIndex === 0; - const isBottomRightDay = weekIndex === weeks.length - 1 && dayIndex === week.length - 1; + const isBottomLeftDay = weekIndex === weeks.length - 1 && dayIndex === 0; + const isBottomRightDay = weekIndex === weeks.length - 1 && dayIndex === week.length - 1; - const isToday = today === shortIsoDate; + const isToday = today === shortIsoDate; - // TODO: Consider events that span multiple days - const dayEvents = calendarEvents.value.filter((calendarEvent) => - new Date(calendarEvent.start_date) >= startDayDate && - new Date(calendarEvent.end_date) <= endDayDate - ); + // TODO: Consider events that span multiple days + const dayEvents = calendarEvents.value.filter((calendarEvent) => + new Date(calendarEvent.start_date) >= startDayDate && + new Date(calendarEvent.end_date) <= endDayDate + ); - return ( -
- - {dayEvents.length > 0 - ? ( -
    - {[...dayEvents].slice(0, 2).map((dayEvent) => ( -
  1. - calendar.id === dayEvent.calendar_id) - ?.color || 'bg-gray-700' - }`} - > - -

    - {dayEvent.title} -

    -
    -
  2. - ))} - {dayEvents.length > 2 - ? ( -
  3. - -

    - ...{dayEvents.length - 2} more event{dayEvents.length - 2 === 1 ? '' : 's'} -

    -
    -
  4. - ) - : null} -
- ) - : null} -
- ); - }) - )} + return ( +
+ + {dayEvents.length > 0 + ? ( +
    + {[...dayEvents].slice(0, 2).map((dayEvent) => ( +
  1. + calendar.id === dayEvent.calendar_id) + ?.color || 'bg-gray-700' + }`} + onClick={() => openEvent.value = dayEvent} + > + +

    + {dayEvent.title} +

    +
    +
  2. + ))} + {dayEvents.length > 2 + ? ( +
  3. + +

    + ...{dayEvents.length - 2} more event{dayEvents.length - 2 === 1 ? '' : 's'} +

    +
    +
  4. + ) + : null} +
+ ) + : null} +
+ ); + }) + )} +
+
-
-
+ ) + : null} {baseUrl}/dav/principals/{' '} {baseUrl}/dav/calendars/
+ +
+
+ +
+

{openEvent.value?.title || ''}

+
+ + {openEvent.value?.start_date ? allDayEventDateFormat.format(new Date(openEvent.value.start_date)) : ''} + + {openEvent.value?.is_all_day ? All-day : ( + + {openEvent.value?.start_date ? hourFormat.format(new Date(openEvent.value.start_date)) : ''} -{' '} + {openEvent.value?.end_date ? hourFormat.format(new Date(openEvent.value.end_date)) : ''} + + )} +
+ {openEvent.value?.extra.description + ? ( +
+

{openEvent.value.extra.description}

+
+ ) + : null} +
+

TODO: location, calendar, recurrence, reminders

+
+
+ + + Edit + + +
+
); } diff --git a/lib/types.ts b/lib/types.ts index 33e1998..5df48cc 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -147,7 +147,6 @@ export interface Calendar { created_at: Date; } -// NOTE: I don't really invite people to events in my private calendars, so I don't think I'll need that complexity // TODO: Finish (more fields) export interface CalendarEvent { id: string; @@ -162,8 +161,17 @@ export interface CalendarEvent { extra: { description?: string; location?: string; + attendees?: CalendarEventAttendee[]; visibility: 'default' | 'public' | 'private'; + is_recurring?: boolean; + recurring_rrule?: string; }; updated_at: Date; created_at: Date; } + +export interface CalendarEventAttendee { + email: string; + status: 'accepted' | 'rejected' | 'invited'; + name?: string; +} diff --git a/routes/calendar.tsx b/routes/calendar.tsx index d47fe45..165c1e1 100644 --- a/routes/calendar.tsx +++ b/routes/calendar.tsx @@ -54,7 +54,7 @@ async function getCalendarEvents(userId: string, calendarIds: string[]): Promise { id: 'event-2', user_id: userId, - calendar_id: 'personal-1', + calendar_id: 'family-1', revision: 'fake-rev', title: 'Dermatologist', start_date: new Date('2024-03-17T16:30:00.000Z'), @@ -83,6 +83,22 @@ async function getCalendarEvents(userId: string, calendarIds: string[]): Promise updated_at: new Date(), created_at: new Date(), }, + { + id: 'event-4', + user_id: userId, + calendar_id: 'personal-1', + revision: 'fake-rev', + title: 'Schedule server updates', + start_date: new Date('2024-03-18T09:00:00.000Z'), + end_date: new Date('2024-03-18T21:00:00.000Z'), + is_all_day: true, + status: 'scheduled', + extra: { + visibility: 'default', + }, + updated_at: new Date(), + created_at: new Date(), + }, ]; } @@ -101,7 +117,7 @@ export const handler: Handlers = { const searchParams = new URL(request.url).searchParams; - const view = (searchParams.get('view') as Data['view']) || 'week'; + const view = (searchParams.get('view') as Data['view']) || 'month'; const startDate = searchParams.get('startDate') || new Date().toISOString().substring(0, 10); const userCalendars = await getCalendars(context.state.user.id);