@weaver-apps/calendar 0.1.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"weaver-apps-calendar.mjs","names":[],"sources":["../../../../libs/calendar/src/lib/gateway/calendar-gateway.ts","../../../../libs/calendar/src/lib/plugin/calendar-host.ts","../../../../libs/calendar/src/lib/plugin/calendar-paths.ts","../../../../libs/calendar/src/lib/views/calendar-list-page.ts","../../../../libs/calendar/src/lib/views/calendar-list-page.html","../../../../libs/calendar/src/lib/week.ts","../../../../libs/calendar/src/lib/views/active-locale.ts","../../../../libs/calendar/src/lib/api/models/appointmentStatus.ts","../../../../libs/calendar/src/lib/views/appointment-dialog.ts","../../../../libs/calendar/src/lib/views/appointment-dialog.html","../../../../libs/calendar/src/lib/views/appointment-table.ts","../../../../libs/calendar/src/lib/views/appointment-table.html","../../../../libs/calendar/src/lib/views/calendar-page.ts","../../../../libs/calendar/src/lib/views/calendar-page.html","../../../../libs/calendar/src/lib/plugin/calendar-icons.ts","../../../../libs/calendar/src/lib/plugin/calendar.plugin.ts","../../../../libs/calendar/src/lib/api/endpoints.ts","../../../../libs/calendar/src/lib/gateway/http-calendar-gateway.ts"],"sourcesContent":["import { InjectionToken, Provider } from '@angular/core';\nimport type { AppointmentRequest, AppointmentResponse, AppointmentStatus, CalendarResponse } from '../api/models';\n\nexport interface CalendarRange {\n readonly from: Date;\n readonly until: Date;\n}\n\nexport interface ConflictingAppointment {\n readonly id: string;\n readonly start: string;\n readonly end: string;\n}\n\nexport type AppointmentOutcome =\n | { readonly kind: 'saved'; readonly appointment: AppointmentResponse }\n | { readonly kind: 'conflict'; readonly conflicts: readonly ConflictingAppointment[] }\n | { readonly kind: 'closed' }\n | { readonly kind: 'changed' }\n | { readonly kind: 'invalid' }\n | { readonly kind: 'missing' };\n\nexport interface CalendarGateway {\n calendars(): Promise<readonly CalendarResponse[]>;\n calendar(calendarId: string): Promise<CalendarResponse | null>;\n saveCalendar(calendarId: string, name: string): Promise<CalendarResponse>;\n appointments(calendarId: string, range: CalendarRange, contact?: string, signal?: AbortSignal): Promise<readonly AppointmentResponse[]>;\n book(calendarId: string, request: AppointmentRequest): Promise<AppointmentOutcome>;\n update(calendarId: string, appointmentId: string, request: AppointmentRequest): Promise<AppointmentOutcome>;\n cancel(calendarId: string, appointmentId: string, reason: string | null): Promise<AppointmentOutcome>;\n setStatus(calendarId: string, appointmentId: string, status: AppointmentStatus): Promise<AppointmentOutcome>;\n remove(calendarId: string, appointmentId: string): Promise<void>;\n}\n\nexport class CalendarGatewayError extends Error {\n constructor(readonly status: number) {\n super(`The calendar answered ${status}.`);\n }\n}\n\nexport const CALENDAR_GATEWAY = new InjectionToken<CalendarGateway>('weaver-apps.calendar.gateway');\n\nexport function provideCalendarGateway(gateway: CalendarGateway): Provider {\n return { provide: CALENDAR_GATEWAY, useValue: gateway };\n}\n","import type { PluginContext } from '@loomweaver/plugin-sdk';\n\ntype HostContext = Pick<PluginContext, 'ui' | 'navigateContent'>;\n\nclass CalendarHost {\n private ctx?: HostContext;\n\n bind(ctx: HostContext): void {\n this.ctx = ctx;\n }\n\n unbind(): void {\n this.ctx = undefined;\n }\n\n get ui(): HostContext['ui'] {\n if (!this.ctx) {\n throw new Error('The calendar plugin is not active.');\n }\n return this.ctx.ui;\n }\n\n navigate(path: string): void {\n this.ctx?.navigateContent(path);\n }\n}\n\nexport const calendarHost = new CalendarHost();\n","export const calendarListPath = 'calendar';\n\nexport function calendarPath(calendarId: string): string {\n return `${calendarListPath}/${calendarId}`;\n}\n","import { ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA, inject, resource } from '@angular/core';\nimport { TranslocoPipe } from '@jsverse/transloco';\nimport { CALENDAR_GATEWAY } from '../gateway/calendar-gateway';\nimport { calendarHost } from '../plugin/calendar-host';\nimport { calendarPath } from '../plugin/calendar-paths';\n\n@Component({\n selector: 'wa-calendar-list-page',\n imports: [TranslocoPipe],\n schemas: [CUSTOM_ELEMENTS_SCHEMA],\n templateUrl: './calendar-list-page.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CalendarListPage {\n private readonly gateway = inject(CALENDAR_GATEWAY);\n\n protected readonly calendars = resource({ loader: () => this.gateway.calendars() });\n\n protected open(calendarId: string): void {\n calendarHost.navigate(calendarPath(calendarId));\n }\n\n protected async create(): Promise<void> {\n const name = await calendarHost.ui.prompt({\n title: 'calendar.calendars.create',\n message: 'calendar.calendars.createMessage',\n confirmLabel: 'calendar.calendars.createConfirm',\n });\n if (!name?.trim()) {\n return;\n }\n try {\n const calendar = await this.gateway.saveCalendar(crypto.randomUUID(), name.trim());\n this.open(calendar.id);\n } catch {\n calendarHost.ui.toast({ message: 'calendar.errors.create', kind: 'error' });\n }\n }\n}\n","<div class=\"flex h-full flex-col gap-4 overflow-auto p-6\">\n <div class=\"flex items-center justify-between gap-4\">\n <h2 class=\"text-lg font-semibold text-content\">{{ 'calendar.calendars.title' | transloco }}</h2>\n <button type=\"button\" class=\"lw-btn lw-btn--primary\" (click)=\"create()\">{{ 'calendar.calendars.create' | transloco }}</button>\n </div>\n @if (calendars.error()) {\n <p class=\"text-sm text-negative\" role=\"alert\">{{ 'calendar.errors.load' | transloco }}</p>\n } @else if (calendars.hasValue()) {\n <ul role=\"list\" class=\"divide-y divide-border rounded-xl border border-border bg-surface\">\n @for (calendar of calendars.value(); track calendar.id) {\n <li>\n <button type=\"button\" class=\"flex w-full items-center gap-3 px-4 py-3 text-left text-sm text-content hover:bg-surface-overlay\" (click)=\"open(calendar.id)\">\n <lw-icon name=\"calendar\" size=\"1.25rem\"></lw-icon>\n <span>{{ calendar.name }}</span>\n </button>\n </li>\n } @empty {\n <li class=\"px-4 py-8 text-center text-sm text-content-faint\">{{ 'calendar.calendars.empty' | transloco }}</li>\n }\n </ul>\n }\n</div>\n","import type { CalendarRange } from './gateway/calendar-gateway';\n\nconst daysPerWeek = 7;\nconst sunday = 0;\nconst daysFromSundayToMonday = 6;\n\nexport function startOfWeek(date: Date): Date {\n const start = new Date(date.getFullYear(), date.getMonth(), date.getDate());\n const offset = start.getDay() === sunday ? daysFromSundayToMonday : start.getDay() - 1;\n start.setDate(start.getDate() - offset);\n return start;\n}\n\nexport function addWeeks(weekStart: Date, weeks: number): Date {\n const moved = new Date(weekStart);\n moved.setDate(moved.getDate() + weeks * daysPerWeek);\n return moved;\n}\n\nexport function weekRange(weekStart: Date): CalendarRange {\n return { from: weekStart, until: addWeeks(weekStart, 1) };\n}\n\nexport function localDate(value: Date): string {\n const pad = (part: number) => `${part}`.padStart(2, '0');\n return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}`;\n}\n\nexport function localTime(value: Date): string {\n const pad = (part: number) => `${part}`.padStart(2, '0');\n return `${pad(value.getHours())}:${pad(value.getMinutes())}`;\n}\n\nexport function combine(date: string, time: string): Date | null {\n const combined = new Date(`${date}T${time}`);\n return Number.isNaN(combined.getTime()) ? null : combined;\n}\n","import { inject, Signal } from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { TranslocoService } from '@jsverse/transloco';\n\nexport function activeLocale(): Signal<string> {\n const transloco = inject(TranslocoService);\n return toSignal(transloco.langChanges$, { initialValue: transloco.getActiveLang() });\n}\n","/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Weaver Apps\n * OpenAPI spec version: 1.0.0\n */\n\n/**\n * Where an appointment stands.\n */\nexport type AppointmentStatus = typeof AppointmentStatus[keyof typeof AppointmentStatus];\n\n\nexport const AppointmentStatus = {\n scheduled: 'scheduled',\n confirmed: 'confirmed',\n completed: 'completed',\n noShow: 'noShow',\n cancelled: 'cancelled',\n} as const;\n","import { ChangeDetectionStrategy, Component, computed, inject, signal } from '@angular/core';\nimport { DialogRef } from '@loomweaver/plugin-sdk';\nimport { TranslocoPipe } from '@jsverse/transloco';\nimport { AppointmentStatus, type AppointmentRequest, type AppointmentResponse } from '../api/models';\nimport { AppointmentOutcome, CALENDAR_GATEWAY, ConflictingAppointment } from '../gateway/calendar-gateway';\nimport { combine, localDate, localTime } from '../week';\nimport { activeLocale } from './active-locale';\n\nexport interface AppointmentDialogData {\n readonly calendarId: string;\n readonly appointment: AppointmentResponse | null;\n readonly day: Date;\n}\n\ntype Problem =\n | { readonly kind: 'none' }\n | { readonly kind: 'message'; readonly key: string }\n | { readonly kind: 'conflict'; readonly conflicts: readonly ConflictingAppointment[] };\n\nconst defaultStart = '09:00';\nconst defaultEnd = '10:00';\nconst settableStatuses: readonly AppointmentStatus[] = [\n AppointmentStatus.scheduled,\n AppointmentStatus.confirmed,\n AppointmentStatus.completed,\n AppointmentStatus.noShow,\n];\n\n@Component({\n selector: 'wa-appointment-dialog',\n imports: [TranslocoPipe],\n templateUrl: './appointment-dialog.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class AppointmentDialog {\n private readonly dialog = inject<DialogRef<boolean>>(DialogRef);\n private readonly gateway = inject(CALENDAR_GATEWAY);\n private readonly data = this.dialog.data as AppointmentDialogData;\n private existing = this.data.appointment;\n\n protected readonly locale = activeLocale();\n protected readonly editing = this.existing !== null;\n protected readonly statuses = settableStatuses;\n\n protected readonly title = signal(this.existing?.title ?? '');\n protected readonly date = signal(localDate(this.existing ? new Date(this.existing.start) : this.data.day));\n protected readonly start = signal(this.existing ? localTime(new Date(this.existing.start)) : defaultStart);\n protected readonly endDate = signal(localDate(this.existing ? new Date(this.existing.end) : this.data.day));\n protected readonly end = signal(this.existing ? localTime(new Date(this.existing.end)) : defaultEnd);\n protected readonly location = signal(this.existing?.location ?? '');\n protected readonly contactName = signal(this.existing?.contactName ?? '');\n protected readonly contactPhone = signal(this.existing?.contactPhone ?? '');\n protected readonly contactEmail = signal(this.existing?.contactEmail ?? '');\n protected readonly description = signal(this.existing?.description ?? '');\n protected readonly status = signal<AppointmentStatus>(this.existing?.status ?? AppointmentStatus.scheduled);\n protected readonly saving = signal(false);\n protected readonly problem = signal<Problem>({ kind: 'none' });\n private persisted = false;\n\n protected readonly problemKey = computed(() => {\n const problem = this.problem();\n return problem.kind === 'message' ? problem.key : '';\n });\n\n protected readonly conflictTimes = computed(() => {\n const problem = this.problem();\n if (problem.kind !== 'conflict') {\n return [];\n }\n const format = new Intl.DateTimeFormat(this.locale(), { dateStyle: 'short', timeStyle: 'short' });\n return problem.conflicts.map((conflict) => `${format.format(new Date(conflict.start))} – ${format.format(new Date(conflict.end))}`);\n });\n\n protected bind(target: { set(value: string): void }, event: Event): void {\n target.set((event.target as HTMLInputElement).value);\n }\n\n protected bindDate(event: Event): void {\n const value = (event.target as HTMLInputElement).value;\n if (this.endDate() === this.date()) {\n this.endDate.set(value);\n }\n this.date.set(value);\n }\n\n protected chooseStatus(event: Event): void {\n const chosen = settableStatuses.find((status) => status === (event.target as HTMLSelectElement).value);\n if (chosen) {\n this.status.set(chosen);\n }\n }\n\n protected close(): void {\n this.dialog.close(this.persisted);\n }\n\n protected async save(): Promise<void> {\n const request = this.request();\n if (!request) {\n return;\n }\n this.saving.set(true);\n try {\n const outcome = this.existing\n ? await this.gateway.update(this.data.calendarId, this.existing.id, request)\n : await this.gateway.book(this.data.calendarId, request);\n const final = await this.applyStatus(outcome);\n this.settle(final);\n } catch {\n this.problem.set({ kind: 'message', key: 'calendar.errors.save' });\n } finally {\n this.saving.set(false);\n }\n }\n\n private request(): AppointmentRequest | null {\n const startsAt = combine(this.date(), this.start());\n const endsAt = combine(this.endDate(), this.end());\n if (!this.title().trim()) {\n this.problem.set({ kind: 'message', key: 'calendar.dialog.titleRequired' });\n return null;\n }\n if (!startsAt || !endsAt || endsAt <= startsAt) {\n this.problem.set({ kind: 'message', key: 'calendar.dialog.periodInvalid' });\n return null;\n }\n return {\n title: this.title().trim(),\n start: startsAt.toISOString(),\n end: endsAt.toISOString(),\n description: this.optional(this.description()),\n location: this.optional(this.location()),\n contactName: this.optional(this.contactName()),\n contactPhone: this.optional(this.contactPhone()),\n contactEmail: this.optional(this.contactEmail()),\n };\n }\n\n private async applyStatus(outcome: AppointmentOutcome): Promise<AppointmentOutcome> {\n if (outcome.kind === 'saved') {\n this.existing = outcome.appointment;\n this.persisted = true;\n }\n if (outcome.kind !== 'saved' || outcome.appointment.status === this.status()) {\n return outcome;\n }\n return this.gateway.setStatus(this.data.calendarId, outcome.appointment.id, this.status());\n }\n\n private settle(outcome: AppointmentOutcome): void {\n switch (outcome.kind) {\n case 'saved':\n this.dialog.close(true);\n return;\n case 'conflict':\n this.problem.set({ kind: 'conflict', conflicts: outcome.conflicts });\n return;\n case 'closed':\n this.problem.set({ kind: 'message', key: 'calendar.dialog.closed' });\n return;\n case 'changed':\n this.problem.set({ kind: 'message', key: 'calendar.dialog.changed' });\n return;\n case 'invalid':\n this.problem.set({ kind: 'message', key: 'calendar.dialog.invalid' });\n return;\n default:\n this.problem.set({ kind: 'message', key: 'calendar.dialog.missing' });\n }\n }\n\n private optional(value: string): string | null {\n return value.trim() ? value.trim() : null;\n }\n}\n","<form class=\"flex flex-col gap-4\" (submit)=\"$event.preventDefault(); save()\">\n <label class=\"flex flex-col gap-1 text-sm text-content\">\n {{ 'calendar.fields.title' | transloco }}\n <input class=\"lw-field\" required [value]=\"title()\" (input)=\"bind(title, $event)\" />\n </label>\n\n <div class=\"grid grid-cols-2 gap-4 sm:grid-cols-4\">\n <label class=\"flex flex-col gap-1 text-sm text-content\">\n {{ 'calendar.fields.date' | transloco }}\n <input class=\"lw-field\" type=\"date\" required [value]=\"date()\" (input)=\"bindDate($event)\" />\n </label>\n <label class=\"flex flex-col gap-1 text-sm text-content\">\n {{ 'calendar.fields.start' | transloco }}\n <input class=\"lw-field\" type=\"time\" required [value]=\"start()\" (input)=\"bind(start, $event)\" />\n </label>\n <label class=\"flex flex-col gap-1 text-sm text-content\">\n {{ 'calendar.fields.endDate' | transloco }}\n <input class=\"lw-field\" type=\"date\" required [value]=\"endDate()\" (input)=\"bind(endDate, $event)\" />\n </label>\n <label class=\"flex flex-col gap-1 text-sm text-content\">\n {{ 'calendar.fields.end' | transloco }}\n <input class=\"lw-field\" type=\"time\" required [value]=\"end()\" (input)=\"bind(end, $event)\" />\n </label>\n </div>\n\n <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <label class=\"flex flex-col gap-1 text-sm text-content\">\n {{ 'calendar.fields.contactName' | transloco }}\n <input class=\"lw-field\" [value]=\"contactName()\" (input)=\"bind(contactName, $event)\" />\n </label>\n <label class=\"flex flex-col gap-1 text-sm text-content\">\n {{ 'calendar.fields.contactPhone' | transloco }}\n <input class=\"lw-field\" type=\"tel\" [value]=\"contactPhone()\" (input)=\"bind(contactPhone, $event)\" />\n </label>\n <label class=\"flex flex-col gap-1 text-sm text-content\">\n {{ 'calendar.fields.contactEmail' | transloco }}\n <input class=\"lw-field\" type=\"email\" [value]=\"contactEmail()\" (input)=\"bind(contactEmail, $event)\" />\n </label>\n </div>\n\n <label class=\"flex flex-col gap-1 text-sm text-content\">\n {{ 'calendar.fields.location' | transloco }}\n <input class=\"lw-field\" [value]=\"location()\" (input)=\"bind(location, $event)\" />\n </label>\n\n <label class=\"flex flex-col gap-1 text-sm text-content\">\n {{ 'calendar.fields.description' | transloco }}\n <textarea class=\"lw-field\" rows=\"3\" [value]=\"description()\" (input)=\"bind(description, $event)\"></textarea>\n </label>\n\n @if (editing) {\n <label class=\"flex flex-col gap-1 text-sm text-content\">\n {{ 'calendar.fields.status' | transloco }}\n <select class=\"lw-field\" [value]=\"status()\" (change)=\"chooseStatus($event)\">\n @for (choice of statuses; track choice) {\n <option [value]=\"choice\" [selected]=\"choice === status()\">{{ 'calendar.status.' + choice | transloco }}</option>\n }\n </select>\n </label>\n }\n\n @switch (problem().kind) {\n @case ('message') {\n <p class=\"text-sm text-negative\" role=\"alert\">{{ problemKey() | transloco }}</p>\n }\n @case ('conflict') {\n <div class=\"text-sm text-negative\" role=\"alert\">\n <p>{{ 'calendar.dialog.conflict' | transloco }}</p>\n <ul class=\"list-disc pl-5\">\n @for (time of conflictTimes(); track time) {\n <li>{{ time }}</li>\n }\n </ul>\n </div>\n }\n }\n\n <div class=\"flex justify-end gap-2\">\n <button type=\"button\" class=\"lw-btn lw-btn--default\" (click)=\"close()\">{{ 'calendar.dialog.cancel' | transloco }}</button>\n <button type=\"submit\" class=\"lw-btn lw-btn--primary\" [disabled]=\"saving()\">{{ 'calendar.dialog.save' | transloco }}</button>\n </div>\n</form>\n","import { ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA, computed, input, output } from '@angular/core';\nimport { TranslocoPipe } from '@jsverse/transloco';\nimport type { AppointmentResponse } from '../api/models';\n\ninterface AppointmentRow {\n readonly appointment: AppointmentResponse;\n readonly day: string;\n readonly hours: string;\n readonly cancelled: boolean;\n readonly statusKey: string;\n}\n\n@Component({\n selector: 'wa-appointment-table',\n imports: [TranslocoPipe],\n schemas: [CUSTOM_ELEMENTS_SCHEMA],\n templateUrl: './appointment-table.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class AppointmentTable {\n readonly appointments = input.required<readonly AppointmentResponse[]>();\n readonly locale = input.required<string>();\n\n readonly editAppointment = output<AppointmentResponse>();\n readonly cancelAppointment = output<AppointmentResponse>();\n readonly deleteAppointment = output<AppointmentResponse>();\n\n protected readonly rows = computed<readonly AppointmentRow[]>(() => {\n const day = new Intl.DateTimeFormat(this.locale(), { weekday: 'short', day: '2-digit', month: '2-digit', year: 'numeric' });\n const time = new Intl.DateTimeFormat(this.locale(), { hour: '2-digit', minute: '2-digit' });\n return this.appointments().map((appointment) => ({\n appointment,\n day: day.format(new Date(appointment.start)),\n hours: `${time.format(new Date(appointment.start))} – ${time.format(new Date(appointment.end))}`,\n cancelled: appointment.status === 'cancelled',\n statusKey: `calendar.status.${appointment.status}`,\n }));\n });\n}\n","<table class=\"w-full border-collapse text-sm\">\n <thead class=\"border-y border-border bg-surface-raised\">\n <tr>\n <th scope=\"col\" class=\"px-4 py-2 text-left text-xs font-medium uppercase tracking-wide text-content-faint\">{{ 'calendar.table.when' | transloco }}</th>\n <th scope=\"col\" class=\"px-4 py-2 text-left text-xs font-medium uppercase tracking-wide text-content-faint\">{{ 'calendar.table.title' | transloco }}</th>\n <th scope=\"col\" class=\"px-4 py-2 text-left text-xs font-medium uppercase tracking-wide text-content-faint\">{{ 'calendar.table.contact' | transloco }}</th>\n <th scope=\"col\" class=\"px-4 py-2 text-left text-xs font-medium uppercase tracking-wide text-content-faint\">{{ 'calendar.table.location' | transloco }}</th>\n <th scope=\"col\" class=\"px-4 py-2 text-left text-xs font-medium uppercase tracking-wide text-content-faint\">{{ 'calendar.table.status' | transloco }}</th>\n <th scope=\"col\" class=\"px-4 py-2\"><span class=\"sr-only\">{{ 'calendar.table.actions' | transloco }}</span></th>\n </tr>\n </thead>\n <tbody>\n @for (row of rows(); track row.appointment.id) {\n <tr class=\"border-b border-border\" [class.text-content-faint]=\"row.cancelled\" data-testid=\"appointment-row\">\n <td class=\"px-4 py-3 whitespace-nowrap\" [class.line-through]=\"row.cancelled\">\n <div class=\"font-medium text-content\">{{ row.day }}</div>\n <div class=\"text-content-faint\">{{ row.hours }}</div>\n </td>\n <td class=\"px-4 py-3 font-medium text-content\" [class.line-through]=\"row.cancelled\">{{ row.appointment.title }}</td>\n <td class=\"px-4 py-3\" [class.line-through]=\"row.cancelled\">\n <div class=\"text-content\">{{ row.appointment.contactName ?? '–' }}</div>\n @if (row.appointment.contactPhone) {\n <div class=\"text-content-faint\">{{ row.appointment.contactPhone }}</div>\n }\n </td>\n <td class=\"px-4 py-3 text-content-faint\" [class.line-through]=\"row.cancelled\">{{ row.appointment.location ?? '–' }}</td>\n <td class=\"px-4 py-3\">\n <span class=\"rounded-full border border-border px-2 py-0.5 text-xs text-content\" data-testid=\"appointment-status\">{{ row.statusKey | transloco }}</span>\n </td>\n <td class=\"px-4 py-3 text-right whitespace-nowrap\">\n <button type=\"button\" class=\"relative lw-btn lw-btn--ghost lw-btn--sm lw-btn--icon\" [attr.aria-label]=\"'calendar.actions.edit' | transloco\" (click)=\"editAppointment.emit(row.appointment)\">\n <lw-icon name=\"edit\" size=\"1rem\"></lw-icon>\n <lw-tooltip [attr.text]=\"'calendar.actions.edit' | transloco\" position=\"top\"></lw-tooltip>\n </button>\n @if (!row.cancelled) {\n <button type=\"button\" class=\"relative lw-btn lw-btn--ghost lw-btn--sm lw-btn--icon\" [attr.aria-label]=\"'calendar.actions.cancel' | transloco\" (click)=\"cancelAppointment.emit(row.appointment)\">\n <lw-icon name=\"calendarCancel\" size=\"1rem\"></lw-icon>\n <lw-tooltip [attr.text]=\"'calendar.actions.cancel' | transloco\" position=\"top\"></lw-tooltip>\n </button>\n }\n <button type=\"button\" class=\"relative lw-btn lw-btn--ghost lw-btn--sm lw-btn--icon\" [attr.aria-label]=\"'calendar.actions.delete' | transloco\" (click)=\"deleteAppointment.emit(row.appointment)\">\n <lw-icon name=\"trash\" size=\"1rem\"></lw-icon>\n <lw-tooltip [attr.text]=\"'calendar.actions.delete' | transloco\" position=\"top\"></lw-tooltip>\n </button>\n </td>\n </tr>\n } @empty {\n <tr>\n <td colspan=\"6\" class=\"px-4 py-8 text-center text-content-faint\">{{ 'calendar.table.empty' | transloco }}</td>\n </tr>\n }\n </tbody>\n</table>\n","import { ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA, computed, DestroyRef, inject, resource, signal } from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { ActivatedRoute } from '@angular/router';\nimport { TranslocoPipe } from '@jsverse/transloco';\nimport { map } from 'rxjs';\nimport type { AppointmentResponse } from '../api/models';\nimport { CALENDAR_GATEWAY } from '../gateway/calendar-gateway';\nimport { calendarHost } from '../plugin/calendar-host';\nimport { addWeeks, startOfWeek, weekRange } from '../week';\nimport { activeLocale } from './active-locale';\nimport { AppointmentDialog, AppointmentDialogData } from './appointment-dialog';\nimport { AppointmentTable } from './appointment-table';\n\nconst searchDelayMs = 300;\n\n@Component({\n selector: 'wa-calendar-page',\n imports: [TranslocoPipe, AppointmentTable],\n schemas: [CUSTOM_ELEMENTS_SCHEMA],\n templateUrl: './calendar-page.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CalendarPage {\n private readonly gateway = inject(CALENDAR_GATEWAY);\n private readonly route = inject(ActivatedRoute);\n private searchTimer?: ReturnType<typeof setTimeout>;\n\n protected readonly locale = activeLocale();\n protected readonly calendarId = toSignal(this.route.paramMap.pipe(map((params) => params.get('calendarId') ?? '')), {\n initialValue: this.route.snapshot.paramMap.get('calendarId') ?? '',\n });\n protected readonly weekStart = signal(startOfWeek(new Date()));\n protected readonly contact = signal('');\n\n protected readonly calendar = resource({\n params: () => this.calendarId(),\n loader: ({ params }) => this.gateway.calendar(params),\n });\n\n protected readonly appointments = resource({\n params: () => ({ calendarId: this.calendarId(), range: weekRange(this.weekStart()), contact: this.contact().trim() }),\n loader: ({ params, abortSignal }) =>\n this.gateway.appointments(params.calendarId, params.range, params.contact || undefined, abortSignal),\n });\n\n constructor() {\n inject(DestroyRef).onDestroy(() => clearTimeout(this.searchTimer));\n }\n\n protected readonly weekLabel = computed(() => {\n const range = weekRange(this.weekStart());\n const last = addWeeks(range.until, 0);\n last.setDate(last.getDate() - 1);\n const format = new Intl.DateTimeFormat(this.locale(), { day: '2-digit', month: '2-digit', year: 'numeric' });\n return `${format.format(range.from)} – ${format.format(last)}`;\n });\n\n protected previousWeek(): void {\n this.weekStart.update((start) => addWeeks(start, -1));\n }\n\n protected nextWeek(): void {\n this.weekStart.update((start) => addWeeks(start, 1));\n }\n\n protected thisWeek(): void {\n this.weekStart.set(startOfWeek(new Date()));\n }\n\n protected search(event: Event): void {\n const value = (event.target as HTMLInputElement).value;\n clearTimeout(this.searchTimer);\n this.searchTimer = setTimeout(() => this.contact.set(value), searchDelayMs);\n }\n\n protected add(): void {\n const today = new Date();\n const shown = weekRange(this.weekStart());\n const day = today >= shown.from && today < shown.until ? today : this.weekStart();\n this.openDialog({ calendarId: this.calendarId(), appointment: null, day }, 'calendar.dialog.addTitle');\n }\n\n protected edit(appointment: AppointmentResponse): void {\n this.openDialog({ calendarId: this.calendarId(), appointment, day: new Date(appointment.start) }, 'calendar.dialog.editTitle');\n }\n\n protected async cancel(appointment: AppointmentResponse): Promise<void> {\n const reason = await calendarHost.ui.prompt({\n title: 'calendar.cancel.title',\n message: 'calendar.cancel.message',\n confirmLabel: 'calendar.cancel.confirm',\n tone: 'warning',\n });\n if (reason === null) {\n return;\n }\n await this.attempt(async () => {\n const outcome = await this.gateway.cancel(this.calendarId(), appointment.id, reason.trim() || null);\n this.report(outcome.kind === 'saved' ? 'calendar.cancel.done' : 'calendar.errors.save', outcome.kind === 'saved');\n });\n }\n\n protected async remove(appointment: AppointmentResponse): Promise<void> {\n const confirmed = await calendarHost.ui.confirm({\n title: 'calendar.delete.title',\n message: 'calendar.delete.message',\n confirmLabel: 'calendar.delete.confirm',\n tone: 'danger',\n });\n if (!confirmed) {\n return;\n }\n await this.attempt(async () => {\n await this.gateway.remove(this.calendarId(), appointment.id);\n this.report('calendar.delete.done', true);\n });\n }\n\n private async attempt(work: () => Promise<void>): Promise<void> {\n try {\n await work();\n } catch {\n this.report('calendar.errors.save', false);\n }\n }\n\n private openDialog(data: AppointmentDialogData, title: string): void {\n const dialog = calendarHost.ui.open<boolean>(AppointmentDialog, { data, title, size: 'lg', dismiss: 'explicit' });\n void dialog.closed.then((saved) => {\n if (saved) {\n this.report('calendar.dialog.saved', true);\n }\n });\n }\n\n private report(message: string, success: boolean): void {\n calendarHost.ui.toast({ message, kind: success ? 'success' : 'error' });\n this.appointments.reload();\n }\n}\n","<div class=\"flex h-full flex-col gap-4 overflow-auto p-6\">\n <div class=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <h2 class=\"text-lg font-semibold text-content\">{{ calendar.value()?.name ?? ('calendar.title' | transloco) }}</h2>\n <div class=\"flex flex-wrap items-center gap-2\">\n <input\n type=\"search\"\n class=\"lw-field w-56\"\n [attr.aria-label]=\"'calendar.search.label' | transloco\"\n [attr.placeholder]=\"'calendar.search.placeholder' | transloco\"\n (input)=\"search($event)\"\n />\n <button type=\"button\" class=\"lw-btn lw-btn--primary\" (click)=\"add()\">\n <lw-icon name=\"add\" size=\"1rem\"></lw-icon>\n {{ 'calendar.actions.add' | transloco }}\n </button>\n </div>\n </div>\n\n <div class=\"flex items-center gap-2\">\n <button type=\"button\" class=\"relative lw-btn lw-btn--default lw-btn--sm lw-btn--icon\" [attr.aria-label]=\"'calendar.week.previous' | transloco\" (click)=\"previousWeek()\">\n <lw-icon name=\"calendarPrevious\" size=\"1rem\"></lw-icon>\n <lw-tooltip [attr.text]=\"'calendar.week.previous' | transloco\" position=\"bottom\"></lw-tooltip>\n </button>\n <button type=\"button\" class=\"lw-btn lw-btn--default lw-btn--sm\" (click)=\"thisWeek()\">{{ 'calendar.week.current' | transloco }}</button>\n <button type=\"button\" class=\"relative lw-btn lw-btn--default lw-btn--sm lw-btn--icon\" [attr.aria-label]=\"'calendar.week.next' | transloco\" (click)=\"nextWeek()\">\n <lw-icon name=\"calendarNext\" size=\"1rem\"></lw-icon>\n <lw-tooltip [attr.text]=\"'calendar.week.next' | transloco\" position=\"bottom\"></lw-tooltip>\n </button>\n <span class=\"text-sm font-medium text-content\" data-testid=\"week-label\">{{ weekLabel() }}</span>\n </div>\n\n @if (appointments.error()) {\n <p class=\"text-sm text-negative\" role=\"alert\">{{ 'calendar.errors.load' | transloco }}</p>\n } @else {\n <div class=\"overflow-hidden rounded-xl border border-border bg-surface\">\n <wa-appointment-table\n [appointments]=\"appointments.value() ?? []\"\n [locale]=\"locale()\"\n (editAppointment)=\"edit($event)\"\n (cancelAppointment)=\"cancel($event)\"\n (deleteAppointment)=\"remove($event)\"\n />\n </div>\n }\n</div>\n","const stroke = 'fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"';\n\nexport const calendarIcons: Readonly<Record<string, string>> = {\n calendar: `<svg viewBox=\"0 0 24 24\" ${stroke}><rect x=\"3.5\" y=\"5\" width=\"17\" height=\"15\" rx=\"2.5\"/><path d=\"M3.5 10h17M8 3v4M16 3v4\"/></svg>`,\n calendarPrevious: `<svg viewBox=\"0 0 24 24\" ${stroke}><path d=\"M15 5l-7 7 7 7\"/></svg>`,\n calendarNext: `<svg viewBox=\"0 0 24 24\" ${stroke}><path d=\"M9 5l7 7-7 7\"/></svg>`,\n calendarCancel: `<svg viewBox=\"0 0 24 24\" ${stroke}><circle cx=\"12\" cy=\"12\" r=\"8.5\"/><path d=\"M9 9l6 6M15 9l-6 6\"/></svg>`,\n};\n","import { Plugin } from '@loomweaver/plugin-sdk';\nimport { CalendarListPage } from '../views/calendar-list-page';\nimport { CalendarPage } from '../views/calendar-page';\nimport { calendarHost } from './calendar-host';\nimport { calendarIcons } from './calendar-icons';\nimport { calendarListPath } from './calendar-paths';\n\nexport interface CalendarPluginOptions {\n readonly railItem?: boolean;\n}\n\nexport function createCalendarPlugin(options: CalendarPluginOptions = {}): Plugin {\n return {\n manifest: {\n id: 'calendar',\n name: 'Calendar',\n capabilities: ['contributions', 'navigation', 'ui'],\n },\n activate(ctx) {\n calendarHost.bind(ctx);\n ctx.contributeIcons(calendarIcons);\n ctx.registerSurface({\n id: 'calendar.calendars',\n title: 'calendar.calendars.title',\n icon: 'calendar',\n routable: { path: calendarListPath },\n component: CalendarListPage,\n });\n ctx.registerSurface({\n id: 'calendar.calendar',\n title: 'calendar.title',\n icon: 'calendar',\n routable: { path: `${calendarListPath}/:calendarId` },\n component: CalendarPage,\n });\n if (options.railItem) {\n ctx.registerRailItem({\n id: 'calendar.rail',\n rail: 'primary',\n icon: 'calendar',\n title: 'calendar.calendars.title',\n run: () => ctx.navigateContent(calendarListPath),\n });\n }\n },\n deactivate() {\n calendarHost.unbind();\n },\n };\n}\n\nexport const calendarPlugin = createCalendarPlugin();\n","/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Weaver Apps\n * OpenAPI spec version: 1.0.0\n */\nimport type {\n AppointmentRequest,\n AppointmentResponse,\n BusyPeriod,\n CalendarAppointmentsListParams,\n CalendarCalendarsBusyParams,\n CalendarResponse,\n CancelAppointmentRequest,\n ChangeAppointmentStatusRequest,\n SaveCalendarRequest\n} from './models';\n\n\nexport type calendarCalendarsSaveResponse200 = {\n data: CalendarResponse\n status: 200\n}\n\nexport type calendarCalendarsSaveResponse201 = {\n data: CalendarResponse\n status: 201\n}\n\nexport type calendarCalendarsSaveResponseSuccess = (calendarCalendarsSaveResponse200 | calendarCalendarsSaveResponse201) & {\n headers: Headers;\n};\n;\n\nexport type calendarCalendarsSaveResponse = (calendarCalendarsSaveResponseSuccess)\n\nexport const getCalendarCalendarsSaveUrl = (calendarId: string,) => {\n\n\n\n\n return `/calendar/calendars/${calendarId}`\n}\n\nexport const calendarCalendarsSave = async (calendarId: string,\n saveCalendarRequest: SaveCalendarRequest, options?: RequestInit): Promise<calendarCalendarsSaveResponse> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nconst res = await fetch(getCalendarCalendarsSaveUrl(calendarId),\n {\n ...options,\n method: 'PUT',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(saveCalendarRequest)\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarCalendarsSaveResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as calendarCalendarsSaveResponse\n}\n\n\n\nexport type calendarCalendarsGetResponse200 = {\n data: CalendarResponse\n status: 200\n}\n\nexport type calendarCalendarsGetResponseSuccess = (calendarCalendarsGetResponse200) & {\n headers: Headers;\n};\n;\n\nexport type calendarCalendarsGetResponse = (calendarCalendarsGetResponseSuccess)\n\nexport const getCalendarCalendarsGetUrl = (calendarId: string,) => {\n\n\n\n\n return `/calendar/calendars/${calendarId}`\n}\n\nexport const calendarCalendarsGet = async (calendarId: string, options?: RequestInit): Promise<calendarCalendarsGetResponse> => {\n\n const res = await fetch(getCalendarCalendarsGetUrl(calendarId),\n {\n ...options,\n method: 'GET'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarCalendarsGetResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as calendarCalendarsGetResponse\n}\n\n\n\nexport type calendarCalendarsDeleteResponse204 = {\n data: void\n status: 204\n}\n\nexport type calendarCalendarsDeleteResponseSuccess = (calendarCalendarsDeleteResponse204) & {\n headers: Headers;\n};\n;\n\nexport type calendarCalendarsDeleteResponse = (calendarCalendarsDeleteResponseSuccess)\n\nexport const getCalendarCalendarsDeleteUrl = (calendarId: string,) => {\n\n\n\n\n return `/calendar/calendars/${calendarId}`\n}\n\nexport const calendarCalendarsDelete = async (calendarId: string, options?: RequestInit): Promise<calendarCalendarsDeleteResponse> => {\n\n const res = await fetch(getCalendarCalendarsDeleteUrl(calendarId),\n {\n ...options,\n method: 'DELETE'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarCalendarsDeleteResponse['data'] = body ? JSON.parse(body) : undefined\n return { data, status: res.status, headers: res.headers } as calendarCalendarsDeleteResponse\n}\n\n\n\nexport type calendarCalendarsListResponse200 = {\n data: CalendarResponse[]\n status: 200\n}\n\nexport type calendarCalendarsListResponseSuccess = (calendarCalendarsListResponse200) & {\n headers: Headers;\n};\n;\n\nexport type calendarCalendarsListResponse = (calendarCalendarsListResponseSuccess)\n\nexport const getCalendarCalendarsListUrl = () => {\n\n\n\n\n return `/calendar/calendars`\n}\n\nexport const calendarCalendarsList = async ( options?: RequestInit): Promise<calendarCalendarsListResponse> => {\n\n const res = await fetch(getCalendarCalendarsListUrl(),\n {\n ...options,\n method: 'GET'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarCalendarsListResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as calendarCalendarsListResponse\n}\n\n\n\nexport type calendarCalendarsBusyResponse200 = {\n data: BusyPeriod[]\n status: 200\n}\n\nexport type calendarCalendarsBusyResponseSuccess = (calendarCalendarsBusyResponse200) & {\n headers: Headers;\n};\n;\n\nexport type calendarCalendarsBusyResponse = (calendarCalendarsBusyResponseSuccess)\n\nexport const getCalendarCalendarsBusyUrl = (calendarId: string,\n params: CalendarCalendarsBusyParams,) => {\n const normalizedParams = new URLSearchParams();\n\n Object.entries(params || {}).forEach(([key, value]) => {\n\n if (value !== undefined) {\n normalizedParams.append(key, value === null ? 'null' : String(value))\n }\n });\n\n const stringifiedParams = normalizedParams.toString();\n\n return stringifiedParams.length > 0 ? `/calendar/calendars/${calendarId}/busy?${stringifiedParams}` : `/calendar/calendars/${calendarId}/busy`\n}\n\nexport const calendarCalendarsBusy = async (calendarId: string,\n params: CalendarCalendarsBusyParams, options?: RequestInit): Promise<calendarCalendarsBusyResponse> => {\n\n const res = await fetch(getCalendarCalendarsBusyUrl(calendarId,params),\n {\n ...options,\n method: 'GET'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarCalendarsBusyResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as calendarCalendarsBusyResponse\n}\n\n\n\nexport type calendarAppointmentsBookResponse201 = {\n data: AppointmentResponse\n status: 201\n}\n\nexport type calendarAppointmentsBookResponseSuccess = (calendarAppointmentsBookResponse201) & {\n headers: Headers;\n};\n;\n\nexport type calendarAppointmentsBookResponse = (calendarAppointmentsBookResponseSuccess)\n\nexport const getCalendarAppointmentsBookUrl = (calendarId: string,) => {\n\n\n\n\n return `/calendar/calendars/${calendarId}/appointments`\n}\n\nexport const calendarAppointmentsBook = async (calendarId: string,\n appointmentRequest: AppointmentRequest, options?: RequestInit): Promise<calendarAppointmentsBookResponse> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nconst res = await fetch(getCalendarAppointmentsBookUrl(calendarId),\n {\n ...options,\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(appointmentRequest)\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarAppointmentsBookResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as calendarAppointmentsBookResponse\n}\n\n\n\nexport type calendarAppointmentsListResponse200 = {\n data: AppointmentResponse[]\n status: 200\n}\n\nexport type calendarAppointmentsListResponseSuccess = (calendarAppointmentsListResponse200) & {\n headers: Headers;\n};\n;\n\nexport type calendarAppointmentsListResponse = (calendarAppointmentsListResponseSuccess)\n\nexport const getCalendarAppointmentsListUrl = (calendarId: string,\n params: CalendarAppointmentsListParams,) => {\n const normalizedParams = new URLSearchParams();\n\n Object.entries(params || {}).forEach(([key, value]) => {\n\n if (value !== undefined) {\n normalizedParams.append(key, value === null ? 'null' : String(value))\n }\n });\n\n const stringifiedParams = normalizedParams.toString();\n\n return stringifiedParams.length > 0 ? `/calendar/calendars/${calendarId}/appointments?${stringifiedParams}` : `/calendar/calendars/${calendarId}/appointments`\n}\n\nexport const calendarAppointmentsList = async (calendarId: string,\n params: CalendarAppointmentsListParams, options?: RequestInit): Promise<calendarAppointmentsListResponse> => {\n\n const res = await fetch(getCalendarAppointmentsListUrl(calendarId,params),\n {\n ...options,\n method: 'GET'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarAppointmentsListResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as calendarAppointmentsListResponse\n}\n\n\n\nexport type calendarAppointmentsGetResponse200 = {\n data: AppointmentResponse\n status: 200\n}\n\nexport type calendarAppointmentsGetResponseSuccess = (calendarAppointmentsGetResponse200) & {\n headers: Headers;\n};\n;\n\nexport type calendarAppointmentsGetResponse = (calendarAppointmentsGetResponseSuccess)\n\nexport const getCalendarAppointmentsGetUrl = (calendarId: string,\n appointmentId: string,) => {\n\n\n\n\n return `/calendar/calendars/${calendarId}/appointments/${appointmentId}`\n}\n\nexport const calendarAppointmentsGet = async (calendarId: string,\n appointmentId: string, options?: RequestInit): Promise<calendarAppointmentsGetResponse> => {\n\n const res = await fetch(getCalendarAppointmentsGetUrl(calendarId,appointmentId),\n {\n ...options,\n method: 'GET'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarAppointmentsGetResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as calendarAppointmentsGetResponse\n}\n\n\n\nexport type calendarAppointmentsUpdateResponse200 = {\n data: AppointmentResponse\n status: 200\n}\n\nexport type calendarAppointmentsUpdateResponseSuccess = (calendarAppointmentsUpdateResponse200) & {\n headers: Headers;\n};\n;\n\nexport type calendarAppointmentsUpdateResponse = (calendarAppointmentsUpdateResponseSuccess)\n\nexport const getCalendarAppointmentsUpdateUrl = (calendarId: string,\n appointmentId: string,) => {\n\n\n\n\n return `/calendar/calendars/${calendarId}/appointments/${appointmentId}`\n}\n\nexport const calendarAppointmentsUpdate = async (calendarId: string,\n appointmentId: string,\n appointmentRequest: AppointmentRequest, options?: RequestInit): Promise<calendarAppointmentsUpdateResponse> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nconst res = await fetch(getCalendarAppointmentsUpdateUrl(calendarId,appointmentId),\n {\n ...options,\n method: 'PUT',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(appointmentRequest)\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarAppointmentsUpdateResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as calendarAppointmentsUpdateResponse\n}\n\n\n\nexport type calendarAppointmentsDeleteResponse204 = {\n data: void\n status: 204\n}\n\nexport type calendarAppointmentsDeleteResponseSuccess = (calendarAppointmentsDeleteResponse204) & {\n headers: Headers;\n};\n;\n\nexport type calendarAppointmentsDeleteResponse = (calendarAppointmentsDeleteResponseSuccess)\n\nexport const getCalendarAppointmentsDeleteUrl = (calendarId: string,\n appointmentId: string,) => {\n\n\n\n\n return `/calendar/calendars/${calendarId}/appointments/${appointmentId}`\n}\n\nexport const calendarAppointmentsDelete = async (calendarId: string,\n appointmentId: string, options?: RequestInit): Promise<calendarAppointmentsDeleteResponse> => {\n\n const res = await fetch(getCalendarAppointmentsDeleteUrl(calendarId,appointmentId),\n {\n ...options,\n method: 'DELETE'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarAppointmentsDeleteResponse['data'] = body ? JSON.parse(body) : undefined\n return { data, status: res.status, headers: res.headers } as calendarAppointmentsDeleteResponse\n}\n\n\n\nexport type calendarAppointmentsCancelResponse200 = {\n data: AppointmentResponse\n status: 200\n}\n\nexport type calendarAppointmentsCancelResponseSuccess = (calendarAppointmentsCancelResponse200) & {\n headers: Headers;\n};\n;\n\nexport type calendarAppointmentsCancelResponse = (calendarAppointmentsCancelResponseSuccess)\n\nexport const getCalendarAppointmentsCancelUrl = (calendarId: string,\n appointmentId: string,) => {\n\n\n\n\n return `/calendar/calendars/${calendarId}/appointments/${appointmentId}/cancel`\n}\n\nexport const calendarAppointmentsCancel = async (calendarId: string,\n appointmentId: string,\n cancelAppointmentRequest: CancelAppointmentRequest, options?: RequestInit): Promise<calendarAppointmentsCancelResponse> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nconst res = await fetch(getCalendarAppointmentsCancelUrl(calendarId,appointmentId),\n {\n ...options,\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(cancelAppointmentRequest)\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarAppointmentsCancelResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as calendarAppointmentsCancelResponse\n}\n\n\n\nexport type calendarAppointmentsStatusResponse200 = {\n data: AppointmentResponse\n status: 200\n}\n\nexport type calendarAppointmentsStatusResponseSuccess = (calendarAppointmentsStatusResponse200) & {\n headers: Headers;\n};\n;\n\nexport type calendarAppointmentsStatusResponse = (calendarAppointmentsStatusResponseSuccess)\n\nexport const getCalendarAppointmentsStatusUrl = (calendarId: string,\n appointmentId: string,) => {\n\n\n\n\n return `/calendar/calendars/${calendarId}/appointments/${appointmentId}/status`\n}\n\nexport const calendarAppointmentsStatus = async (calendarId: string,\n appointmentId: string,\n changeAppointmentStatusRequest: ChangeAppointmentStatusRequest, options?: RequestInit): Promise<calendarAppointmentsStatusResponse> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nconst res = await fetch(getCalendarAppointmentsStatusUrl(calendarId,appointmentId),\n {\n ...options,\n method: 'PUT',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(changeAppointmentStatusRequest)\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarAppointmentsStatusResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as calendarAppointmentsStatusResponse\n}\n\n\n\n","import {\n getCalendarAppointmentsBookUrl,\n getCalendarAppointmentsCancelUrl,\n getCalendarAppointmentsDeleteUrl,\n getCalendarAppointmentsListUrl,\n getCalendarAppointmentsStatusUrl,\n getCalendarAppointmentsUpdateUrl,\n getCalendarCalendarsGetUrl,\n getCalendarCalendarsListUrl,\n getCalendarCalendarsSaveUrl,\n} from '../api/endpoints';\nimport type { AppointmentResponse, CalendarResponse } from '../api/models';\nimport { AppointmentOutcome, CalendarGateway, CalendarGatewayError, ConflictingAppointment } from './calendar-gateway';\n\nexport interface HttpCalendarGatewayOptions {\n readonly baseUrl: string;\n readonly headers?: Readonly<Record<string, string>>;\n readonly fetch?: typeof fetch;\n}\n\nconst notFound = 404;\nconst conflict = 409;\nconst badRequest = 400;\nconst conflictCode = 'appointment-conflict';\nconst closedCode = 'appointment-closed';\n\ninterface Problem {\n readonly code?: string;\n readonly conflicts?: readonly ConflictingAppointment[];\n}\n\nexport function createHttpCalendarGateway(options: HttpCalendarGatewayOptions): CalendarGateway {\n const base = options.baseUrl.replace(/\\/+$/, '');\n const run = options.fetch ?? ((input: RequestInfo | URL, init?: RequestInit) => fetch(input, init));\n\n const send = (path: string, method: string, body?: unknown, signal?: AbortSignal): Promise<Response> =>\n run(base + path, {\n method,\n signal,\n credentials: 'same-origin',\n headers: {\n Accept: 'application/json',\n ...(body === undefined ? {} : { 'Content-Type': 'application/json' }),\n ...options.headers,\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n });\n\n const read = async <T>(response: Response): Promise<T> => {\n if (!response.ok) {\n throw new CalendarGatewayError(response.status);\n }\n const value: T = await response.json();\n return value;\n };\n\n const outcome = async (response: Response): Promise<AppointmentOutcome> => {\n if (response.ok) {\n const appointment: AppointmentResponse = await response.json();\n return { kind: 'saved', appointment };\n }\n if (response.status === notFound) {\n return { kind: 'missing' };\n }\n if (response.status === badRequest) {\n return { kind: 'invalid' };\n }\n if (response.status !== conflict) {\n throw new CalendarGatewayError(response.status);\n }\n const problem: Problem = await response.json().catch(() => ({}));\n if (problem.code === conflictCode) {\n return { kind: 'conflict', conflicts: problem.conflicts ?? [] };\n }\n return problem.code === closedCode ? { kind: 'closed' } : { kind: 'changed' };\n };\n\n return {\n calendars: async () => read<CalendarResponse[]>(await send(getCalendarCalendarsListUrl(), 'GET')),\n calendar: async (calendarId) => {\n const response = await send(getCalendarCalendarsGetUrl(calendarId), 'GET');\n return response.status === notFound ? null : read<CalendarResponse>(response);\n },\n saveCalendar: async (calendarId, name) =>\n read<CalendarResponse>(await send(getCalendarCalendarsSaveUrl(calendarId), 'PUT', { name })),\n appointments: async (calendarId, range, contact, signal) => {\n const params = { from: range.from.toISOString(), until: range.until.toISOString(), ...(contact ? { contact } : {}) };\n return read<AppointmentResponse[]>(await send(getCalendarAppointmentsListUrl(calendarId, params), 'GET', undefined, signal));\n },\n book: async (calendarId, request) => outcome(await send(getCalendarAppointmentsBookUrl(calendarId), 'POST', request)),\n update: async (calendarId, appointmentId, request) =>\n outcome(await send(getCalendarAppointmentsUpdateUrl(calendarId, appointmentId), 'PUT', request)),\n cancel: async (calendarId, appointmentId, reason) =>\n outcome(await send(getCalendarAppointmentsCancelUrl(calendarId, appointmentId), 'POST', { reason })),\n setStatus: async (calendarId, appointmentId, status) =>\n outcome(await send(getCalendarAppointmentsStatusUrl(calendarId, appointmentId), 'PUT', { status })),\n remove: async (calendarId, appointmentId) => {\n const response = await send(getCalendarAppointmentsDeleteUrl(calendarId, appointmentId), 'DELETE');\n if (!response.ok && response.status !== notFound) {\n throw new CalendarGatewayError(response.status);\n }\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"weaver-apps-calendar.mjs","names":[],"sources":["../../../../libs/calendar/src/lib/plugin/calendar-icons.ts","../../../../libs/calendar/src/lib/plugin/calendar.plugin.ts","../../../../libs/calendar/src/lib/api/endpoints.ts","../../../../libs/calendar/src/lib/gateway/http-calendar-gateway.ts"],"sourcesContent":["import { calendarIconNames } from './calendar-ids';\n\nconst stroke = 'fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"';\n\nexport const calendarIcons: Readonly<Record<string, string>> = {\n [calendarIconNames.calendar]: `<svg viewBox=\"0 0 24 24\" ${stroke}><rect x=\"3.5\" y=\"5\" width=\"17\" height=\"15\" rx=\"2.5\"/><path d=\"M3.5 10h17M8 3v4M16 3v4\"/></svg>`,\n [calendarIconNames.previous]: `<svg viewBox=\"0 0 24 24\" ${stroke}><path d=\"M15 5l-7 7 7 7\"/></svg>`,\n [calendarIconNames.next]: `<svg viewBox=\"0 0 24 24\" ${stroke}><path d=\"M9 5l7 7-7 7\"/></svg>`,\n [calendarIconNames.cancel]: `<svg viewBox=\"0 0 24 24\" ${stroke}><circle cx=\"12\" cy=\"12\" r=\"8.5\"/><path d=\"M9 9l6 6M15 9l-6 6\"/></svg>`,\n};\n","import { Plugin } from '@loomweaver/plugin-sdk';\nimport { calendarHost } from './calendar-host';\nimport { calendarContributionIds, calendarIconNames, calendarPluginId } from './calendar-ids';\nimport { calendarIcons } from './calendar-icons';\nimport { calendarListPath } from './calendar-paths';\n\nexport interface CalendarPluginOptions {\n readonly railItem?: boolean;\n}\n\nexport function createCalendarPlugin(options: CalendarPluginOptions = {}): Plugin {\n return {\n manifest: {\n id: calendarPluginId,\n name: 'Calendar',\n capabilities: ['contributions', 'navigation', 'ui'],\n },\n activate(ctx) {\n calendarHost.bind(ctx);\n ctx.contributeIcons(calendarIcons);\n ctx.registerSurface({\n id: calendarContributionIds.calendars,\n title: 'weaver-apps-calendar.calendars.title',\n icon: calendarIconNames.calendar,\n routable: { path: calendarListPath },\n loadComponent: () => import('../views/calendar-list-page').then((module) => module.CalendarListPage),\n });\n ctx.registerSurface({\n id: calendarContributionIds.calendar,\n title: 'weaver-apps-calendar.title',\n icon: calendarIconNames.calendar,\n routable: { path: `${calendarListPath}/:calendarId` },\n loadComponent: () => import('../views/calendar-page').then((module) => module.CalendarPage),\n });\n if (options.railItem) {\n ctx.registerRailItem({\n id: calendarContributionIds.rail,\n rail: 'primary',\n icon: calendarIconNames.calendar,\n title: 'weaver-apps-calendar.calendars.title',\n run: () => ctx.navigateContent(calendarListPath),\n });\n }\n },\n deactivate() {\n calendarHost.unbind();\n },\n };\n}\n\nexport const calendarPlugin = createCalendarPlugin();\n","/**\n * Generated by orval 🍺\n * Do not edit manually.\n * Weaver Apps\n * OpenAPI spec version: 1.0.0\n */\nimport type {\n AppointmentRequest,\n AppointmentResponse,\n BusyPeriod,\n CalendarAppointmentsListParams,\n CalendarCalendarsBusyParams,\n CalendarResponse,\n CancelAppointmentRequest,\n ChangeAppointmentStatusRequest,\n SaveCalendarRequest\n} from './models';\n\n\nexport type calendarCalendarsSaveResponse200 = {\n data: CalendarResponse\n status: 200\n}\n\nexport type calendarCalendarsSaveResponse201 = {\n data: CalendarResponse\n status: 201\n}\n\nexport type calendarCalendarsSaveResponseSuccess = (calendarCalendarsSaveResponse200 | calendarCalendarsSaveResponse201) & {\n headers: Headers;\n};\n;\n\nexport type calendarCalendarsSaveResponse = (calendarCalendarsSaveResponseSuccess)\n\nexport const getCalendarCalendarsSaveUrl = (calendarId: string,) => {\n\n\n\n\n return `/calendar/calendars/${calendarId}`\n}\n\nexport const calendarCalendarsSave = async (calendarId: string,\n saveCalendarRequest: SaveCalendarRequest, options?: RequestInit): Promise<calendarCalendarsSaveResponse> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nconst res = await fetch(getCalendarCalendarsSaveUrl(calendarId),\n {\n ...options,\n method: 'PUT',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(saveCalendarRequest)\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarCalendarsSaveResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as calendarCalendarsSaveResponse\n}\n\n\n\nexport type calendarCalendarsGetResponse200 = {\n data: CalendarResponse\n status: 200\n}\n\nexport type calendarCalendarsGetResponseSuccess = (calendarCalendarsGetResponse200) & {\n headers: Headers;\n};\n;\n\nexport type calendarCalendarsGetResponse = (calendarCalendarsGetResponseSuccess)\n\nexport const getCalendarCalendarsGetUrl = (calendarId: string,) => {\n\n\n\n\n return `/calendar/calendars/${calendarId}`\n}\n\nexport const calendarCalendarsGet = async (calendarId: string, options?: RequestInit): Promise<calendarCalendarsGetResponse> => {\n\n const res = await fetch(getCalendarCalendarsGetUrl(calendarId),\n {\n ...options,\n method: 'GET'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarCalendarsGetResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as calendarCalendarsGetResponse\n}\n\n\n\nexport type calendarCalendarsDeleteResponse204 = {\n data: void\n status: 204\n}\n\nexport type calendarCalendarsDeleteResponseSuccess = (calendarCalendarsDeleteResponse204) & {\n headers: Headers;\n};\n;\n\nexport type calendarCalendarsDeleteResponse = (calendarCalendarsDeleteResponseSuccess)\n\nexport const getCalendarCalendarsDeleteUrl = (calendarId: string,) => {\n\n\n\n\n return `/calendar/calendars/${calendarId}`\n}\n\nexport const calendarCalendarsDelete = async (calendarId: string, options?: RequestInit): Promise<calendarCalendarsDeleteResponse> => {\n\n const res = await fetch(getCalendarCalendarsDeleteUrl(calendarId),\n {\n ...options,\n method: 'DELETE'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarCalendarsDeleteResponse['data'] = body ? JSON.parse(body) : undefined\n return { data, status: res.status, headers: res.headers } as calendarCalendarsDeleteResponse\n}\n\n\n\nexport type calendarCalendarsListResponse200 = {\n data: CalendarResponse[]\n status: 200\n}\n\nexport type calendarCalendarsListResponseSuccess = (calendarCalendarsListResponse200) & {\n headers: Headers;\n};\n;\n\nexport type calendarCalendarsListResponse = (calendarCalendarsListResponseSuccess)\n\nexport const getCalendarCalendarsListUrl = () => {\n\n\n\n\n return `/calendar/calendars`\n}\n\nexport const calendarCalendarsList = async ( options?: RequestInit): Promise<calendarCalendarsListResponse> => {\n\n const res = await fetch(getCalendarCalendarsListUrl(),\n {\n ...options,\n method: 'GET'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarCalendarsListResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as calendarCalendarsListResponse\n}\n\n\n\nexport type calendarCalendarsBusyResponse200 = {\n data: BusyPeriod[]\n status: 200\n}\n\nexport type calendarCalendarsBusyResponseSuccess = (calendarCalendarsBusyResponse200) & {\n headers: Headers;\n};\n;\n\nexport type calendarCalendarsBusyResponse = (calendarCalendarsBusyResponseSuccess)\n\nexport const getCalendarCalendarsBusyUrl = (calendarId: string,\n params: CalendarCalendarsBusyParams,) => {\n const normalizedParams = new URLSearchParams();\n\n Object.entries(params || {}).forEach(([key, value]) => {\n\n if (value !== undefined) {\n normalizedParams.append(key, value === null ? 'null' : String(value))\n }\n });\n\n const stringifiedParams = normalizedParams.toString();\n\n return stringifiedParams.length > 0 ? `/calendar/calendars/${calendarId}/busy?${stringifiedParams}` : `/calendar/calendars/${calendarId}/busy`\n}\n\nexport const calendarCalendarsBusy = async (calendarId: string,\n params: CalendarCalendarsBusyParams, options?: RequestInit): Promise<calendarCalendarsBusyResponse> => {\n\n const res = await fetch(getCalendarCalendarsBusyUrl(calendarId,params),\n {\n ...options,\n method: 'GET'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarCalendarsBusyResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as calendarCalendarsBusyResponse\n}\n\n\n\nexport type calendarAppointmentsBookResponse201 = {\n data: AppointmentResponse\n status: 201\n}\n\nexport type calendarAppointmentsBookResponseSuccess = (calendarAppointmentsBookResponse201) & {\n headers: Headers;\n};\n;\n\nexport type calendarAppointmentsBookResponse = (calendarAppointmentsBookResponseSuccess)\n\nexport const getCalendarAppointmentsBookUrl = (calendarId: string,) => {\n\n\n\n\n return `/calendar/calendars/${calendarId}/appointments`\n}\n\nexport const calendarAppointmentsBook = async (calendarId: string,\n appointmentRequest: AppointmentRequest, options?: RequestInit): Promise<calendarAppointmentsBookResponse> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nconst res = await fetch(getCalendarAppointmentsBookUrl(calendarId),\n {\n ...options,\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(appointmentRequest)\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarAppointmentsBookResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as calendarAppointmentsBookResponse\n}\n\n\n\nexport type calendarAppointmentsListResponse200 = {\n data: AppointmentResponse[]\n status: 200\n}\n\nexport type calendarAppointmentsListResponseSuccess = (calendarAppointmentsListResponse200) & {\n headers: Headers;\n};\n;\n\nexport type calendarAppointmentsListResponse = (calendarAppointmentsListResponseSuccess)\n\nexport const getCalendarAppointmentsListUrl = (calendarId: string,\n params: CalendarAppointmentsListParams,) => {\n const normalizedParams = new URLSearchParams();\n\n Object.entries(params || {}).forEach(([key, value]) => {\n\n if (value !== undefined) {\n normalizedParams.append(key, value === null ? 'null' : String(value))\n }\n });\n\n const stringifiedParams = normalizedParams.toString();\n\n return stringifiedParams.length > 0 ? `/calendar/calendars/${calendarId}/appointments?${stringifiedParams}` : `/calendar/calendars/${calendarId}/appointments`\n}\n\nexport const calendarAppointmentsList = async (calendarId: string,\n params: CalendarAppointmentsListParams, options?: RequestInit): Promise<calendarAppointmentsListResponse> => {\n\n const res = await fetch(getCalendarAppointmentsListUrl(calendarId,params),\n {\n ...options,\n method: 'GET'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarAppointmentsListResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as calendarAppointmentsListResponse\n}\n\n\n\nexport type calendarAppointmentsGetResponse200 = {\n data: AppointmentResponse\n status: 200\n}\n\nexport type calendarAppointmentsGetResponseSuccess = (calendarAppointmentsGetResponse200) & {\n headers: Headers;\n};\n;\n\nexport type calendarAppointmentsGetResponse = (calendarAppointmentsGetResponseSuccess)\n\nexport const getCalendarAppointmentsGetUrl = (calendarId: string,\n appointmentId: string,) => {\n\n\n\n\n return `/calendar/calendars/${calendarId}/appointments/${appointmentId}`\n}\n\nexport const calendarAppointmentsGet = async (calendarId: string,\n appointmentId: string, options?: RequestInit): Promise<calendarAppointmentsGetResponse> => {\n\n const res = await fetch(getCalendarAppointmentsGetUrl(calendarId,appointmentId),\n {\n ...options,\n method: 'GET'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarAppointmentsGetResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as calendarAppointmentsGetResponse\n}\n\n\n\nexport type calendarAppointmentsUpdateResponse200 = {\n data: AppointmentResponse\n status: 200\n}\n\nexport type calendarAppointmentsUpdateResponseSuccess = (calendarAppointmentsUpdateResponse200) & {\n headers: Headers;\n};\n;\n\nexport type calendarAppointmentsUpdateResponse = (calendarAppointmentsUpdateResponseSuccess)\n\nexport const getCalendarAppointmentsUpdateUrl = (calendarId: string,\n appointmentId: string,) => {\n\n\n\n\n return `/calendar/calendars/${calendarId}/appointments/${appointmentId}`\n}\n\nexport const calendarAppointmentsUpdate = async (calendarId: string,\n appointmentId: string,\n appointmentRequest: AppointmentRequest, options?: RequestInit): Promise<calendarAppointmentsUpdateResponse> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nconst res = await fetch(getCalendarAppointmentsUpdateUrl(calendarId,appointmentId),\n {\n ...options,\n method: 'PUT',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(appointmentRequest)\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarAppointmentsUpdateResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as calendarAppointmentsUpdateResponse\n}\n\n\n\nexport type calendarAppointmentsDeleteResponse204 = {\n data: void\n status: 204\n}\n\nexport type calendarAppointmentsDeleteResponseSuccess = (calendarAppointmentsDeleteResponse204) & {\n headers: Headers;\n};\n;\n\nexport type calendarAppointmentsDeleteResponse = (calendarAppointmentsDeleteResponseSuccess)\n\nexport const getCalendarAppointmentsDeleteUrl = (calendarId: string,\n appointmentId: string,) => {\n\n\n\n\n return `/calendar/calendars/${calendarId}/appointments/${appointmentId}`\n}\n\nexport const calendarAppointmentsDelete = async (calendarId: string,\n appointmentId: string, options?: RequestInit): Promise<calendarAppointmentsDeleteResponse> => {\n\n const res = await fetch(getCalendarAppointmentsDeleteUrl(calendarId,appointmentId),\n {\n ...options,\n method: 'DELETE'\n\n\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarAppointmentsDeleteResponse['data'] = body ? JSON.parse(body) : undefined\n return { data, status: res.status, headers: res.headers } as calendarAppointmentsDeleteResponse\n}\n\n\n\nexport type calendarAppointmentsCancelResponse200 = {\n data: AppointmentResponse\n status: 200\n}\n\nexport type calendarAppointmentsCancelResponseSuccess = (calendarAppointmentsCancelResponse200) & {\n headers: Headers;\n};\n;\n\nexport type calendarAppointmentsCancelResponse = (calendarAppointmentsCancelResponseSuccess)\n\nexport const getCalendarAppointmentsCancelUrl = (calendarId: string,\n appointmentId: string,) => {\n\n\n\n\n return `/calendar/calendars/${calendarId}/appointments/${appointmentId}/cancel`\n}\n\nexport const calendarAppointmentsCancel = async (calendarId: string,\n appointmentId: string,\n cancelAppointmentRequest: CancelAppointmentRequest, options?: RequestInit): Promise<calendarAppointmentsCancelResponse> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nconst res = await fetch(getCalendarAppointmentsCancelUrl(calendarId,appointmentId),\n {\n ...options,\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(cancelAppointmentRequest)\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarAppointmentsCancelResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as calendarAppointmentsCancelResponse\n}\n\n\n\nexport type calendarAppointmentsStatusResponse200 = {\n data: AppointmentResponse\n status: 200\n}\n\nexport type calendarAppointmentsStatusResponseSuccess = (calendarAppointmentsStatusResponse200) & {\n headers: Headers;\n};\n;\n\nexport type calendarAppointmentsStatusResponse = (calendarAppointmentsStatusResponseSuccess)\n\nexport const getCalendarAppointmentsStatusUrl = (calendarId: string,\n appointmentId: string,) => {\n\n\n\n\n return `/calendar/calendars/${calendarId}/appointments/${appointmentId}/status`\n}\n\nexport const calendarAppointmentsStatus = async (calendarId: string,\n appointmentId: string,\n changeAppointmentStatusRequest: ChangeAppointmentStatusRequest, options?: RequestInit): Promise<calendarAppointmentsStatusResponse> => {\n\n const getHeaders = (h?: NonNullable<RequestInit['headers']>): Record<string, string | readonly string[]> => {\n if (!h) return {};\n if (h instanceof Headers) return Object.fromEntries(h.entries());\n if (Symbol.iterator in h) {\n return Object.fromEntries(\n Array.from(h as Iterable<Iterable<string>>, (entry) => Array.from(entry) as [string, string]),\n );\n }\n const headers: Record<string, string | readonly string[]> = {};\n for (const [name, value] of Object.entries<string | readonly string[] | undefined>(h)) {\n if (value !== undefined) headers[name] = value;\n }\n return headers;\n };\nconst res = await fetch(getCalendarAppointmentsStatusUrl(calendarId,appointmentId),\n {\n ...options,\n method: 'PUT',\n headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) },\n body: JSON.stringify(changeAppointmentStatusRequest)\n }\n)\n\n\n const body = [204, 205, 304].includes(res.status) ? null : await res.text();\n\n const data: calendarAppointmentsStatusResponse['data'] = body ? JSON.parse(body) : {}\n return { data, status: res.status, headers: res.headers } as calendarAppointmentsStatusResponse\n}\n\n\n\n","import {\n getCalendarAppointmentsBookUrl,\n getCalendarAppointmentsCancelUrl,\n getCalendarAppointmentsDeleteUrl,\n getCalendarAppointmentsListUrl,\n getCalendarAppointmentsStatusUrl,\n getCalendarAppointmentsUpdateUrl,\n getCalendarCalendarsGetUrl,\n getCalendarCalendarsListUrl,\n getCalendarCalendarsSaveUrl,\n} from '../api/endpoints';\nimport type { AppointmentResponse, CalendarResponse } from '../api/models';\nimport { AppointmentOutcome, CalendarGateway, CalendarGatewayError, ConflictingAppointment } from './calendar-gateway';\n\nexport interface HttpCalendarGatewayOptions {\n readonly baseUrl: string;\n readonly headers?: Readonly<Record<string, string>>;\n readonly fetch?: typeof fetch;\n}\n\nconst notFound = 404;\nconst conflict = 409;\nconst badRequest = 400;\nconst conflictCode = 'appointment-conflict';\nconst closedCode = 'appointment-closed';\n\ninterface Problem {\n readonly code?: string;\n readonly conflicts?: readonly ConflictingAppointment[];\n}\n\nexport function createHttpCalendarGateway(options: HttpCalendarGatewayOptions): CalendarGateway {\n const base = options.baseUrl.replace(/\\/+$/, '');\n const run = options.fetch ?? ((input: RequestInfo | URL, init?: RequestInit) => fetch(input, init));\n\n const send = (path: string, method: string, body?: unknown, signal?: AbortSignal): Promise<Response> =>\n run(base + path, {\n method,\n signal,\n credentials: 'same-origin',\n headers: {\n Accept: 'application/json',\n ...(body === undefined ? {} : { 'Content-Type': 'application/json' }),\n ...options.headers,\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n });\n\n const read = async <T>(response: Response): Promise<T> => {\n if (!response.ok) {\n throw new CalendarGatewayError(response.status);\n }\n const value: T = await response.json();\n return value;\n };\n\n const outcome = async (response: Response): Promise<AppointmentOutcome> => {\n if (response.ok) {\n const appointment: AppointmentResponse = await response.json();\n return { kind: 'saved', appointment };\n }\n if (response.status === notFound) {\n return { kind: 'missing' };\n }\n if (response.status === badRequest) {\n return { kind: 'invalid' };\n }\n if (response.status !== conflict) {\n throw new CalendarGatewayError(response.status);\n }\n const problem: Problem = await response.json().catch(() => ({}));\n if (problem.code === conflictCode) {\n return { kind: 'conflict', conflicts: problem.conflicts ?? [] };\n }\n return problem.code === closedCode ? { kind: 'closed' } : { kind: 'changed' };\n };\n\n return {\n calendars: async () => read<CalendarResponse[]>(await send(getCalendarCalendarsListUrl(), 'GET')),\n calendar: async (calendarId) => {\n const response = await send(getCalendarCalendarsGetUrl(calendarId), 'GET');\n return response.status === notFound ? null : read<CalendarResponse>(response);\n },\n saveCalendar: async (calendarId, name) =>\n read<CalendarResponse>(await send(getCalendarCalendarsSaveUrl(calendarId), 'PUT', { name })),\n appointments: async (calendarId, range, contact, signal) => {\n const params = { from: range.from.toISOString(), until: range.until.toISOString(), ...(contact ? { contact } : {}) };\n return read<AppointmentResponse[]>(await send(getCalendarAppointmentsListUrl(calendarId, params), 'GET', undefined, signal));\n },\n book: async (calendarId, request) => outcome(await send(getCalendarAppointmentsBookUrl(calendarId), 'POST', request)),\n update: async (calendarId, appointmentId, request) =>\n outcome(await send(getCalendarAppointmentsUpdateUrl(calendarId, appointmentId), 'PUT', request)),\n cancel: async (calendarId, appointmentId, reason) =>\n outcome(await send(getCalendarAppointmentsCancelUrl(calendarId, appointmentId), 'POST', { reason })),\n setStatus: async (calendarId, appointmentId, status) =>\n outcome(await send(getCalendarAppointmentsStatusUrl(calendarId, appointmentId), 'PUT', { status })),\n remove: async (calendarId, appointmentId) => {\n const response = await send(getCalendarAppointmentsDeleteUrl(calendarId, appointmentId), 'DELETE');\n if (!response.ok && response.status !== notFound) {\n throw new CalendarGatewayError(response.status);\n }\n },\n };\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weaver-apps/calendar",
3
- "version": "0.1.3",
3
+ "version": "0.3.0",
4
4
  "description": "The calendar app's weaver for a LoomWeaver distribution: a calendar's appointments by week, booking, editing, cancelling and deleting, behind a gateway the host supplies.",
5
5
  "license": "Apache-2.0",
6
6
  "publishConfig": {
@@ -8,13 +8,20 @@
8
8
  "registry": "https://registry.npmjs.org/"
9
9
  },
10
10
  "peerDependencies": {
11
+ "@ag-grid-community/locale": "^36.2.0",
11
12
  "@angular/common": "^22.2.0",
12
13
  "@angular/core": "^22.2.0",
13
14
  "@angular/router": "^22.2.0",
14
15
  "@jsverse/transloco": "^8.4.0",
15
- "@loomweaver/plugin-sdk": ">=0.20.0 <1.0.0"
16
+ "@loomweaver/plugin-sdk": ">=0.20.0 <1.0.0",
17
+ "ag-grid-angular": "^36.2.0",
18
+ "ag-grid-community": "^36.2.0"
16
19
  },
17
20
  "sideEffects": false,
21
+ "dependencies": {
22
+ "@weaver-apps/data-grid": "0.3.0",
23
+ "tslib": "^2.3.0"
24
+ },
18
25
  "module": "fesm2022/weaver-apps-calendar.mjs",
19
26
  "typings": "types/weaver-apps-calendar.d.ts",
20
27
  "exports": {
@@ -26,8 +33,5 @@
26
33
  "default": "./fesm2022/weaver-apps-calendar.mjs"
27
34
  }
28
35
  },
29
- "type": "module",
30
- "dependencies": {
31
- "tslib": "^2.3.0"
32
- }
36
+ "type": "module"
33
37
  }
@@ -5,8 +5,14 @@ interface CalendarPluginOptions {
5
5
  }
6
6
  export declare function createCalendarPlugin(options?: CalendarPluginOptions): Plugin;
7
7
  export declare const calendarPlugin: Plugin;
8
- export declare const calendarListPath = "calendar";
8
+ export declare const calendarListPath = "weaver-apps-calendar";
9
9
  export declare function calendarPath(calendarId: string): string;
10
+ export declare const calendarPluginId = "weaver-apps-calendar";
11
+ export declare const calendarContributionIds: {
12
+ readonly calendars: "weaver-apps-calendar.calendars";
13
+ readonly calendar: "weaver-apps-calendar.calendar";
14
+ readonly rail: "weaver-apps-calendar.rail";
15
+ };
10
16
  /**
11
17
  * Generated by orval 🍺
12
18
  * Do not edit manually.
File without changes
File without changes