import { useSignal } from '@preact/signals'; import { Calendar, CalendarEvent } from '/lib/models/calendar.ts'; import { capitalizeWord, convertObjectToFormData } from '/lib/utils/misc.ts'; import { FormField, generateFieldHtml } from '/lib/form-utils.tsx'; import { RequestBody as DeleteRequestBody, ResponseBody as DeleteResponseBody, } from '/routes/api/calendar/delete-event.tsx'; interface ViewCalendarEventProps { initialCalendarEvent: CalendarEvent; calendars: Calendar[]; formData: Record; error?: string; notice?: string; } export function formFields(calendarEvent: CalendarEvent, calendars: Calendar[], updateType: 'raw' | 'ui') { const fields: FormField[] = [ { name: 'update-type', label: 'Update type', type: 'hidden', value: updateType, readOnly: true, }, ]; if (updateType === 'ui') { fields.push({ name: 'title', label: 'Title', type: 'text', placeholder: 'Dentis', value: calendarEvent.title, required: true, }, { name: 'calendarId', label: 'Calendar', type: 'select', value: calendarEvent.calendarId, options: calendars.map((calendar) => ({ label: calendar.displayName!, value: calendar.uid! })), required: true, description: 'Cannot be changed after the event has been created.', }, { name: 'startDate', label: 'Start date', type: 'datetime-local', value: new Date(calendarEvent.startDate).toISOString().substring(0, 16), required: true, description: 'Dates are set in the default calendar timezone, controlled by Radicale.', }, { name: 'endDate', label: 'End date', type: 'datetime-local', value: new Date(calendarEvent.endDate).toISOString().substring(0, 16), required: true, description: 'Dates are set in the default calendar timezone, controlled by Radicale.', }, { name: 'isAllDay', label: 'All-day?', type: 'checkbox', placeholder: 'YYYYMMDD', value: 'true', required: false, checked: calendarEvent.isAllDay, }, { name: 'status', label: 'Status', type: 'select', value: calendarEvent.status, options: (['scheduled', 'pending', 'canceled'] as CalendarEvent['status'][]).map((status) => ({ label: capitalizeWord(status), value: status, })), required: true, }, { name: 'description', label: 'Description', type: 'textarea', placeholder: 'Just a regular check-up.', value: calendarEvent.description, required: false, }, { name: 'eventUrl', label: 'URL', type: 'url', placeholder: 'https://example.com', value: calendarEvent.eventUrl, required: false, }, { name: 'location', label: 'Location', type: 'text', placeholder: 'Birmingham, UK', value: calendarEvent.location, required: false, }, { name: 'transparency', label: 'Transparency', type: 'select', value: calendarEvent.transparency, options: (['opaque', 'transparent'] as CalendarEvent['transparency'][]).map(( transparency, ) => ({ label: capitalizeWord(transparency), value: transparency, })), required: true, }); } else if (updateType === 'raw') { fields.push({ name: 'ics', label: 'Raw ICS', type: 'textarea', placeholder: 'Raw ICS...', value: calendarEvent.data, description: 'This is the raw ICS for this event. Use this to manually update the event _if_ you know what you are doing.', rows: '10', }); } return fields; } export default function ViewCalendarEvent( { initialCalendarEvent, calendars, formData: formDataObject, error, notice }: ViewCalendarEventProps, ) { const isDeleting = useSignal(false); const calendarEvent = useSignal(initialCalendarEvent); const formData = convertObjectToFormData(formDataObject); async function onClickDeleteEvent() { const message = calendarEvent.peek().isRecurring ? 'Are you sure you want to delete _all_ instances of this recurring event?' : 'Are you sure you want to delete this event?'; if (confirm(message)) { if (isDeleting.value) { return; } isDeleting.value = true; try { const requestBody: DeleteRequestBody = { calendarIds: calendars.map((calendar) => calendar.uid!), calendarView: 'day', calendarStartDate: new Date().toISOString().substring(0, 10), calendarEventId: calendarEvent.value.uid!, calendarId: calendarEvent.value.calendarId, }; const response = await fetch(`/api/calendar/delete-event`, { method: 'POST', body: JSON.stringify(requestBody), }); const result = await response.json() as DeleteResponseBody; if (!result.success) { throw new Error('Failed to delete event!'); } window.location.href = '/calendar'; } catch (error) { console.error(error); } isDeleting.value = false; } } return ( <>
View calendar
{error ? (

Failed to update!

{error}

) : null} {notice ? (

Success!

{notice}

) : null}
{formFields(calendarEvent.peek(), calendars, 'ui').map((field) => generateFieldHtml(field, formData))}
{calendarEvent.peek().isRecurring ? (

Note that you'll update all instances of this recurring event.

) : null}

Edit Raw ICS{' '} Expand
{formFields(calendarEvent.peek(), calendars, 'raw').map((field) => generateFieldHtml(field, formData))}
{isDeleting.value ? ( <> Deleting... ) : null} {!isDeleting.value ? <>  : null}
); }