@weaver-apps/calendar 0.3.1 → 0.4.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.
- package/README.md +23 -0
- package/fesm2022/{weaver-apps-calendar-calendar-list-page-CF8odTAv.mjs → weaver-apps-calendar-calendar-list-page-hzMBlQ5b.mjs} +11 -6
- package/fesm2022/weaver-apps-calendar-calendar-list-page-hzMBlQ5b.mjs.map +1 -0
- package/fesm2022/{weaver-apps-calendar-calendar-page-BjJzPlTa.mjs → weaver-apps-calendar-calendar-page-DbWMaf4n.mjs} +8 -5
- package/fesm2022/weaver-apps-calendar-calendar-page-DbWMaf4n.mjs.map +1 -0
- package/fesm2022/{weaver-apps-calendar-calendar-paths-AFikgbRs.mjs → weaver-apps-calendar-calendar-paths-Di_vI0IJ.mjs} +2 -2
- package/fesm2022/{weaver-apps-calendar-calendar-paths-AFikgbRs.mjs.map → weaver-apps-calendar-calendar-paths-Di_vI0IJ.mjs.map} +1 -1
- package/fesm2022/{weaver-apps-calendar-calendar-gateway-DqiL9VbI.mjs → weaver-apps-calendar-calendar-titles-nFkww5mx.mjs} +12 -2
- package/fesm2022/weaver-apps-calendar-calendar-titles-nFkww5mx.mjs.map +1 -0
- package/fesm2022/weaver-apps-calendar.mjs +5 -5
- package/package.json +2 -2
- package/types/weaver-apps-calendar.d.ts +3 -1
- package/fesm2022/weaver-apps-calendar-calendar-gateway-DqiL9VbI.mjs.map +0 -1
- package/fesm2022/weaver-apps-calendar-calendar-list-page-CF8odTAv.mjs.map +0 -1
- package/fesm2022/weaver-apps-calendar-calendar-page-BjJzPlTa.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -30,6 +30,29 @@ provideCalendarGateway(createHttpCalendarGateway({ baseUrl: '/weaver-apps' })),
|
|
|
30
30
|
dependency; the host composes nothing for it.
|
|
31
31
|
- If the host compiles the shell's theme with Tailwind, add the package and `@weaver-apps/data-grid` as an `@source`.
|
|
32
32
|
|
|
33
|
+
## Titles from the host
|
|
34
|
+
|
|
35
|
+
By default a calendar is headed and listed by the name stored with it. A host that names calendars itself, say in
|
|
36
|
+
the reader's language, hands those titles to the weaver:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import { provideCalendarTitles } from '@weaver-apps/calendar';
|
|
40
|
+
|
|
41
|
+
provideCalendarTitles(() => {
|
|
42
|
+
const names = inject(MyCalendarNames);
|
|
43
|
+
return (calendarId) => names.titleOf(calendarId);
|
|
44
|
+
}),
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- The factory runs in the host's injection context, so it may `inject` what it needs.
|
|
48
|
+
- The returned function answers a calendar id with a title, or `null` (or a blank string) when the host has none.
|
|
49
|
+
The calendar page's heading and the list then show the host's title, otherwise the stored name, and while
|
|
50
|
+
neither is known the weaver's own translated title.
|
|
51
|
+
- The weaver calls the function inside a `computed`. Every signal it reads, such as the host's active language, is
|
|
52
|
+
tracked, so a changed title re-titles the open page. A host with an observable turns it into a signal with
|
|
53
|
+
`toSignal` first.
|
|
54
|
+
- The function runs for every listed calendar whenever a signal it reads changes; keep it a lookup.
|
|
55
|
+
|
|
33
56
|
## Names in the host
|
|
34
57
|
|
|
35
58
|
The plugin id is `weaver-apps-calendar` (`calendarPluginId`). Every id the plugin registers and every icon
|
|
@@ -1,14 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as calendarPath } from "./weaver-apps-calendar-calendar-paths-
|
|
1
|
+
import { i as CALENDAR_GATEWAY, n as calendarTitle, t as CALENDAR_TITLES, u as calendarHost } from "./weaver-apps-calendar-calendar-titles-nFkww5mx.mjs";
|
|
2
|
+
import { n as calendarPath } from "./weaver-apps-calendar-calendar-paths-Di_vI0IJ.mjs";
|
|
3
3
|
import * as i0 from "@angular/core";
|
|
4
|
-
import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component, inject, resource } from "@angular/core";
|
|
4
|
+
import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component, computed, inject, resource } from "@angular/core";
|
|
5
5
|
import { TranslocoPipe } from "@jsverse/transloco";
|
|
6
6
|
var CalendarListPage = class CalendarListPage {
|
|
7
7
|
gateway = inject(CALENDAR_GATEWAY);
|
|
8
|
+
titles = inject(CALENDAR_TITLES, { optional: true });
|
|
8
9
|
calendars = resource({
|
|
9
10
|
...ngDevMode ? { debugName: "calendars" } : /* istanbul ignore next */ {},
|
|
10
11
|
loader: () => this.gateway.calendars()
|
|
11
12
|
});
|
|
13
|
+
entries = computed(() => this.calendars.hasValue() ? this.calendars.value().map((calendar) => ({
|
|
14
|
+
id: calendar.id,
|
|
15
|
+
title: calendarTitle(this.titles, calendar.id, calendar.name)
|
|
16
|
+
})) : [], ...ngDevMode ? [{ debugName: "entries" }] : /* istanbul ignore next */ []);
|
|
12
17
|
open(calendarId) {
|
|
13
18
|
calendarHost.navigate(calendarPath(calendarId));
|
|
14
19
|
}
|
|
@@ -44,7 +49,7 @@ var CalendarListPage = class CalendarListPage {
|
|
|
44
49
|
isStandalone: true,
|
|
45
50
|
selector: "wa-calendar-list-page",
|
|
46
51
|
ngImport: i0,
|
|
47
|
-
template: "<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\">{{ 'weaver-apps-calendar.calendars.title' | transloco }}</h2>\n <button type=\"button\" class=\"lw-btn lw-btn--primary\" (click)=\"create()\">{{ 'weaver-apps-calendar.calendars.create' | transloco }}</button>\n </div>\n @if (calendars.error()) {\n <p class=\"text-sm text-negative\" role=\"alert\">{{ 'weaver-apps-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
|
|
52
|
+
template: "<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\">{{ 'weaver-apps-calendar.calendars.title' | transloco }}</h2>\n <button type=\"button\" class=\"lw-btn lw-btn--primary\" (click)=\"create()\">{{ 'weaver-apps-calendar.calendars.create' | transloco }}</button>\n </div>\n @if (calendars.error()) {\n <p class=\"text-sm text-negative\" role=\"alert\">{{ 'weaver-apps-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 entries(); 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=\"weaver-apps-calendar.calendar\" size=\"1.25rem\"></lw-icon>\n <span>{{ calendar.title }}</span>\n </button>\n </li>\n } @empty {\n <li class=\"px-4 py-8 text-center text-sm text-content-faint\">{{ 'weaver-apps-calendar.calendars.empty' | transloco }}</li>\n }\n </ul>\n }\n</div>\n",
|
|
48
53
|
dependencies: [{
|
|
49
54
|
kind: "pipe",
|
|
50
55
|
type: TranslocoPipe,
|
|
@@ -65,10 +70,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
65
70
|
imports: [TranslocoPipe],
|
|
66
71
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
67
72
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
68
|
-
template: "<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\">{{ 'weaver-apps-calendar.calendars.title' | transloco }}</h2>\n <button type=\"button\" class=\"lw-btn lw-btn--primary\" (click)=\"create()\">{{ 'weaver-apps-calendar.calendars.create' | transloco }}</button>\n </div>\n @if (calendars.error()) {\n <p class=\"text-sm text-negative\" role=\"alert\">{{ 'weaver-apps-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
|
|
73
|
+
template: "<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\">{{ 'weaver-apps-calendar.calendars.title' | transloco }}</h2>\n <button type=\"button\" class=\"lw-btn lw-btn--primary\" (click)=\"create()\">{{ 'weaver-apps-calendar.calendars.create' | transloco }}</button>\n </div>\n @if (calendars.error()) {\n <p class=\"text-sm text-negative\" role=\"alert\">{{ 'weaver-apps-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 entries(); 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=\"weaver-apps-calendar.calendar\" size=\"1.25rem\"></lw-icon>\n <span>{{ calendar.title }}</span>\n </button>\n </li>\n } @empty {\n <li class=\"px-4 py-8 text-center text-sm text-content-faint\">{{ 'weaver-apps-calendar.calendars.empty' | transloco }}</li>\n }\n </ul>\n }\n</div>\n"
|
|
69
74
|
}]
|
|
70
75
|
}]
|
|
71
76
|
});
|
|
72
77
|
export { CalendarListPage };
|
|
73
78
|
|
|
74
|
-
//# sourceMappingURL=weaver-apps-calendar-calendar-list-page-
|
|
79
|
+
//# sourceMappingURL=weaver-apps-calendar-calendar-list-page-hzMBlQ5b.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"weaver-apps-calendar-calendar-list-page-hzMBlQ5b.mjs","names":[],"sources":["../../../../libs/calendar/src/lib/views/calendar-list-page.ts","../../../../libs/calendar/src/lib/views/calendar-list-page.html"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, CUSTOM_ELEMENTS_SCHEMA, inject, resource } from '@angular/core';\nimport { TranslocoPipe } from '@jsverse/transloco';\nimport { CALENDAR_GATEWAY } from '../gateway/calendar-gateway';\nimport { CALENDAR_TITLES, calendarTitle } from '../gateway/calendar-titles';\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 private readonly titles = inject(CALENDAR_TITLES, { optional: true });\n\n protected readonly calendars = resource({ loader: () => this.gateway.calendars() });\n\n protected readonly entries = computed(() =>\n this.calendars.hasValue() ? this.calendars.value().map((calendar) => ({ id: calendar.id, title: calendarTitle(this.titles, calendar.id, calendar.name) })) : [],\n );\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: 'weaver-apps-calendar.calendars.create',\n message: 'weaver-apps-calendar.calendars.createMessage',\n confirmLabel: 'weaver-apps-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: 'weaver-apps-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\">{{ 'weaver-apps-calendar.calendars.title' | transloco }}</h2>\n <button type=\"button\" class=\"lw-btn lw-btn--primary\" (click)=\"create()\">{{ 'weaver-apps-calendar.calendars.create' | transloco }}</button>\n </div>\n @if (calendars.error()) {\n <p class=\"text-sm text-negative\" role=\"alert\">{{ 'weaver-apps-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 entries(); 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=\"weaver-apps-calendar.calendar\" size=\"1.25rem\"></lw-icon>\n <span>{{ calendar.title }}</span>\n </button>\n </li>\n } @empty {\n <li class=\"px-4 py-8 text-center text-sm text-content-faint\">{{ 'weaver-apps-calendar.calendars.empty' | transloco }}</li>\n }\n </ul>\n }\n</div>\n"],"mappings":";;;;;AAcA,IAAa,mBAAb,MAAa,iBAAgB;CACV,UAAU,OAAO,gBAAgB;CACjC,SAAS,OAAO,iBAAiB,EAAE,UAAU,KAAI,CAAE;CAEjD,YAAY,SAAQ;EAAA,GAAA,YAAA,EAAA,WAAA,YAAA,+BAAA,CAAA;EAAG,cAAc,KAAK,QAAQ,UAAS;CAAE,CAAA;CAE7D,UAAU,eAC3B,KAAK,UAAU,SAAQ,IAAK,KAAK,UAAU,MAAK,CAAE,CAAC,KAAK,cAAc;EAAE,IAAI,SAAS;EAAI,OAAO,cAAc,KAAK,QAAQ,SAAS,IAAI,SAAS,IAAI;CAAC,EAAG,IAAI,CAAA,GAC9J,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CAES,KAAK,YAAkB;EAC/B,aAAa,SAAS,aAAa,UAAU,CAAC;CAChD;CAEU,MAAM,SAAM;EACpB,MAAM,OAAO,MAAM,aAAa,GAAG,OAAO;GACxC,OAAO;GACP,SAAS;GACT,cAAc;EACf,CAAA;EACD,IAAI,CAAC,MAAM,KAAI,GACb;EAEF,IAAI;GACF,MAAM,WAAW,MAAM,KAAK,QAAQ,aAAa,OAAO,WAAU,GAAI,KAAK,KAAI,CAAE;GACjF,KAAK,KAAK,SAAS,EAAE;EACvB,QAAQ;GACN,aAAa,GAAG,MAAM;IAAE,SAAS;IAAsC,MAAM;GAAO,CAAE;EACxF;CACF;CA7BW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAgB,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAhB,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAgB,cAAA;EAAA,UAAA;EAAA,UAAA;EAAA,UCd7B;EAsBA,cAAA,CAAA;GAAA,MAAA;GAAA,MDbY;GAAa,MAAA;EAAA,CAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AAKZ,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAgB,YAAA,CAAA;EAP5B,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAuB,SACxB,CAAC,aAAa;GAAC,SACf,CAAC,sBAAsB;GAAC,iBAEhB,wBAAwB;GAAM,UAAA;EAAA,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { c as calendarIconNames, i as CALENDAR_GATEWAY, n as calendarTitle, t as CALENDAR_TITLES, u as calendarHost } from "./weaver-apps-calendar-calendar-titles-nFkww5mx.mjs";
|
|
2
2
|
import * as i0 from "@angular/core";
|
|
3
3
|
import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component, DestroyRef, computed, effect, inject, input, output, resource, signal } from "@angular/core";
|
|
4
4
|
import { TranslocoPipe, TranslocoService, translateObjectSignal } from "@jsverse/transloco";
|
|
@@ -451,7 +451,8 @@ var AppointmentTable = class AppointmentTable {
|
|
|
451
451
|
{
|
|
452
452
|
...this.cell(appointmentColumn.actions, "actions", ""),
|
|
453
453
|
width: actionsWidthPx,
|
|
454
|
-
resizable: false
|
|
454
|
+
resizable: false,
|
|
455
|
+
pinned: "right"
|
|
455
456
|
}
|
|
456
457
|
];
|
|
457
458
|
}
|
|
@@ -570,6 +571,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
570
571
|
const searchDelayMs = 300;
|
|
571
572
|
var CalendarPage = class CalendarPage {
|
|
572
573
|
gateway = inject(CALENDAR_GATEWAY);
|
|
574
|
+
titles = inject(CALENDAR_TITLES, { optional: true });
|
|
573
575
|
route = inject(ActivatedRoute);
|
|
574
576
|
searchTimer;
|
|
575
577
|
locale = activeLocale();
|
|
@@ -581,6 +583,7 @@ var CalendarPage = class CalendarPage {
|
|
|
581
583
|
params: () => this.calendarId(),
|
|
582
584
|
loader: ({ params }) => this.gateway.calendar(params)
|
|
583
585
|
});
|
|
586
|
+
title = computed(() => calendarTitle(this.titles, this.calendarId(), this.calendar.hasValue() ? this.calendar.value()?.name ?? null : null), ...ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []);
|
|
584
587
|
appointments = resource({
|
|
585
588
|
...ngDevMode ? { debugName: "appointments" } : /* istanbul ignore next */ {},
|
|
586
589
|
params: () => ({
|
|
@@ -709,7 +712,7 @@ var CalendarPage = class CalendarPage {
|
|
|
709
712
|
isStandalone: true,
|
|
710
713
|
selector: "wa-calendar-page",
|
|
711
714
|
ngImport: i0,
|
|
712
|
-
template: "<div class=\"flex h-full flex-col gap-4 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\">{{
|
|
715
|
+
template: "<div class=\"flex h-full flex-col gap-4 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\">{{ title() ?? ('weaver-apps-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]=\"'weaver-apps-calendar.search.label' | transloco\"\n [attr.placeholder]=\"'weaver-apps-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 {{ 'weaver-apps-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]=\"'weaver-apps-calendar.week.previous' | transloco\" (click)=\"previousWeek()\">\n <lw-icon name=\"weaver-apps-calendar.previous\" size=\"1rem\"></lw-icon>\n <lw-tooltip [attr.text]=\"'weaver-apps-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()\">{{ 'weaver-apps-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]=\"'weaver-apps-calendar.week.next' | transloco\" (click)=\"nextWeek()\">\n <lw-icon name=\"weaver-apps-calendar.next\" size=\"1rem\"></lw-icon>\n <lw-tooltip [attr.text]=\"'weaver-apps-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\">{{ 'weaver-apps-calendar.errors.load' | transloco }}</p>\n } @else {\n <div class=\"min-h-80 flex-1\">\n <wa-appointment-table\n [appointments]=\"appointments.value() ?? []\"\n [locale]=\"locale()\"\n (editAppointment)=\"edit($event)\"\n (appointmentActions)=\"actions($event)\"\n />\n </div>\n }\n</div>\n",
|
|
713
716
|
dependencies: [{
|
|
714
717
|
kind: "component",
|
|
715
718
|
type: AppointmentTable,
|
|
@@ -736,11 +739,11 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
736
739
|
imports: [TranslocoPipe, AppointmentTable],
|
|
737
740
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
738
741
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
739
|
-
template: "<div class=\"flex h-full flex-col gap-4 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\">{{
|
|
742
|
+
template: "<div class=\"flex h-full flex-col gap-4 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\">{{ title() ?? ('weaver-apps-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]=\"'weaver-apps-calendar.search.label' | transloco\"\n [attr.placeholder]=\"'weaver-apps-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 {{ 'weaver-apps-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]=\"'weaver-apps-calendar.week.previous' | transloco\" (click)=\"previousWeek()\">\n <lw-icon name=\"weaver-apps-calendar.previous\" size=\"1rem\"></lw-icon>\n <lw-tooltip [attr.text]=\"'weaver-apps-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()\">{{ 'weaver-apps-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]=\"'weaver-apps-calendar.week.next' | transloco\" (click)=\"nextWeek()\">\n <lw-icon name=\"weaver-apps-calendar.next\" size=\"1rem\"></lw-icon>\n <lw-tooltip [attr.text]=\"'weaver-apps-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\">{{ 'weaver-apps-calendar.errors.load' | transloco }}</p>\n } @else {\n <div class=\"min-h-80 flex-1\">\n <wa-appointment-table\n [appointments]=\"appointments.value() ?? []\"\n [locale]=\"locale()\"\n (editAppointment)=\"edit($event)\"\n (appointmentActions)=\"actions($event)\"\n />\n </div>\n }\n</div>\n"
|
|
740
743
|
}]
|
|
741
744
|
}],
|
|
742
745
|
ctorParameters: () => []
|
|
743
746
|
});
|
|
744
747
|
export { CalendarPage };
|
|
745
748
|
|
|
746
|
-
//# sourceMappingURL=weaver-apps-calendar-calendar-page-
|
|
749
|
+
//# sourceMappingURL=weaver-apps-calendar-calendar-page-DbWMaf4n.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"weaver-apps-calendar-calendar-page-DbWMaf4n.mjs","names":[],"sources":["../../../../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-menu.ts","../../../../libs/calendar/src/lib/views/appointment-cell.ts","../../../../libs/calendar/src/lib/views/appointment-cell.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"],"sourcesContent":["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: 'weaver-apps-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: 'weaver-apps-calendar.dialog.titleRequired' });\n return null;\n }\n if (!startsAt || !endsAt || endsAt <= startsAt) {\n this.problem.set({ kind: 'message', key: 'weaver-apps-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: 'weaver-apps-calendar.dialog.closed' });\n return;\n case 'changed':\n this.problem.set({ kind: 'message', key: 'weaver-apps-calendar.dialog.changed' });\n return;\n case 'invalid':\n this.problem.set({ kind: 'message', key: 'weaver-apps-calendar.dialog.invalid' });\n return;\n default:\n this.problem.set({ kind: 'message', key: 'weaver-apps-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 {{ 'weaver-apps-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 {{ 'weaver-apps-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 {{ 'weaver-apps-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 {{ 'weaver-apps-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 {{ 'weaver-apps-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 {{ 'weaver-apps-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 {{ 'weaver-apps-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 {{ 'weaver-apps-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 {{ 'weaver-apps-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 {{ 'weaver-apps-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 {{ 'weaver-apps-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()\">{{ 'weaver-apps-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>{{ 'weaver-apps-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()\">{{ 'weaver-apps-calendar.dialog.cancel' | transloco }}</button>\n <button type=\"submit\" class=\"lw-btn lw-btn--primary\" [disabled]=\"saving()\">{{ 'weaver-apps-calendar.dialog.save' | transloco }}</button>\n </div>\n</form>\n","import type { UiMenuAction } from '@loomweaver/plugin-sdk';\nimport { AppointmentStatus, type AppointmentResponse } from '../api/models';\nimport { calendarIconNames } from '../plugin/calendar-ids';\n\nexport interface AppointmentMenuRuns {\n readonly edit: () => void;\n readonly cancel: () => void;\n readonly remove: () => void;\n}\n\nexport function appointmentMenu(appointment: AppointmentResponse, runs: AppointmentMenuRuns): UiMenuAction[] {\n const cancellable = appointment.status !== AppointmentStatus.cancelled;\n return [\n { label: 'weaver-apps-calendar.actions.edit', icon: 'edit', run: runs.edit },\n ...(cancellable ? [{ label: 'weaver-apps-calendar.actions.cancel', icon: calendarIconNames.cancel, run: runs.cancel }] : []),\n { label: 'weaver-apps-calendar.actions.delete', icon: 'trash', run: runs.remove },\n ];\n}\n","import { ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA, computed, signal } from '@angular/core';\nimport { TranslocoPipe } from '@jsverse/transloco';\nimport type { ICellRendererAngularComp } from 'ag-grid-angular';\nimport type { ICellRendererParams } from 'ag-grid-community';\nimport type { AppointmentResponse } from '../api/models';\n\nexport interface AppointmentActions {\n readonly appointment: AppointmentResponse;\n readonly x: number;\n readonly y: number;\n}\n\nexport type AppointmentCellKind = 'when' | 'title' | 'contact' | 'location' | 'status' | 'actions';\n\nexport interface AppointmentCellParams {\n readonly kind: AppointmentCellKind;\n readonly locale: () => string;\n readonly actions: (actions: AppointmentActions) => void;\n}\n\ntype Params = ICellRendererParams<AppointmentResponse> & AppointmentCellParams;\n\n@Component({\n selector: 'wa-appointment-cell',\n imports: [TranslocoPipe],\n schemas: [CUSTOM_ELEMENTS_SCHEMA],\n templateUrl: './appointment-cell.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class AppointmentCell implements ICellRendererAngularComp {\n private params: Params | null = null;\n private readonly locale = signal('en');\n\n protected readonly kind = signal<AppointmentCellKind>('title');\n protected readonly appointment = signal<AppointmentResponse | null>(null);\n protected readonly cancelled = computed(() => this.appointment()?.status === 'cancelled');\n protected readonly when = computed(() => {\n const appointment = this.appointment();\n if (!appointment) {\n return { day: '', hours: '' };\n }\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 {\n day: day.format(new Date(appointment.start)),\n hours: `${time.format(new Date(appointment.start))} – ${time.format(new Date(appointment.end))}`,\n };\n });\n\n agInit(params: Params): void {\n this.params = params;\n this.kind.set(params.kind);\n this.appointment.set(params.data ?? null);\n this.locale.set(params.locale());\n }\n\n refresh(params: Params): boolean {\n this.agInit(params);\n return true;\n }\n\n protected openActions(event: MouseEvent): void {\n const appointment = this.appointment();\n if (appointment) {\n this.params?.actions({ appointment, ...menuAnchor(event) });\n }\n }\n}\n\nfunction menuAnchor(event: MouseEvent): { readonly x: number; readonly y: number } {\n if (event.detail > 0) {\n return { x: event.clientX, y: event.clientY };\n }\n const bounds = (event.currentTarget as HTMLElement).getBoundingClientRect();\n return { x: bounds.left, y: bounds.bottom };\n}\n","@if (appointment(); as appointment) {\n @switch (kind()) {\n @case ('when') {\n <span class=\"font-medium\" [class.text-content]=\"!cancelled()\" [class.line-through]=\"cancelled()\">{{ when().day }}</span>\n <span class=\"ml-2 text-content-faint\" [class.line-through]=\"cancelled()\">{{ when().hours }}</span>\n }\n @case ('title') {\n <span class=\"font-medium\" [class.text-content]=\"!cancelled()\" [class.line-through]=\"cancelled()\">{{ appointment.title }}</span>\n }\n @case ('contact') {\n <span [class.line-through]=\"cancelled()\">{{ appointment.contactName ?? '–' }}</span>\n @if (appointment.contactPhone) {\n <span class=\"ml-2 text-content-faint\" [class.line-through]=\"cancelled()\">{{ appointment.contactPhone }}</span>\n }\n }\n @case ('location') {\n <span class=\"text-content-faint\" [class.line-through]=\"cancelled()\">{{ appointment.location ?? '–' }}</span>\n }\n @case ('status') {\n <span class=\"rounded-full border border-border px-2 py-0.5 text-xs text-content\" data-testid=\"appointment-status\">{{ 'weaver-apps-calendar.status.' + appointment.status | transloco }}</span>\n }\n @case ('actions') {\n <button type=\"button\" class=\"relative lw-btn lw-btn--ghost lw-btn--sm lw-btn--icon\" [attr.aria-label]=\"'weaver-apps-calendar.actions.more' | transloco\" (click)=\"openActions($event)\">\n <lw-icon name=\"more\" size=\"1rem\"></lw-icon>\n </button>\n }\n }\n}\n","import { ChangeDetectionStrategy, Component, computed, effect, input, output, signal, type Signal } from '@angular/core';\nimport { translateObjectSignal } from '@jsverse/transloco';\nimport { DataGrid, ListFilter, type ListFilterParams, openOnRow } from '@weaver-apps/data-grid';\nimport type { ColDef, GridApi, GridOptions } from 'ag-grid-community';\nimport { AppointmentStatus, type AppointmentResponse } from '../api/models';\nimport { AppointmentCell, type AppointmentActions, type AppointmentCellKind, type AppointmentCellParams } from './appointment-cell';\n\ntype Texts = Readonly<Record<string, string>>;\n\nexport const appointmentColumn = {\n when: 'start',\n title: 'title',\n contact: 'contact',\n location: 'location',\n status: 'status',\n actions: 'actions',\n} as const;\n\nconst actionsWidthPx = 72;\nconst whenMinWidthPx = 230;\nconst textMinWidthPx = 110;\nconst locationMinWidthPx = 90;\nconst statusMinWidthPx = 112;\n\nexport function byStart(left: string | undefined, right: string | undefined): number {\n return Date.parse(left ?? '') - Date.parse(right ?? '');\n}\n\nexport function statusOf(appointment: AppointmentResponse): string {\n return appointment.status;\n}\n\n@Component({\n selector: 'wa-appointment-table',\n imports: [DataGrid],\n templateUrl: './appointment-table.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'block h-full w-full' },\n})\nexport class AppointmentTable {\n private readonly table = translateObjectSignal('weaver-apps-calendar.table') as Signal<Texts>;\n private readonly statuses = translateObjectSignal('weaver-apps-calendar.status') as Signal<Texts>;\n private readonly api = signal<GridApi<AppointmentResponse> | null>(null);\n\n readonly appointments = input.required<readonly AppointmentResponse[]>();\n readonly locale = input.required<string>();\n\n readonly editAppointment = output<AppointmentResponse>();\n readonly appointmentActions = output<AppointmentActions>();\n\n protected readonly translated = computed(() => typeof this.table() === 'object' && typeof this.table()['title'] === 'string');\n\n protected readonly empty = computed(() => ({ noRowsToShow: this.table()['empty'] ?? '' }));\n\n protected readonly options = computed<GridOptions<AppointmentResponse>>(() => ({\n rowModelType: 'clientSide',\n columnDefs: this.columns(this.table()),\n defaultColDef: { sortable: false, resizable: true, suppressHeaderMenuButton: true },\n getRowId: (params) => params.data.id,\n initialState: { sort: { sortModel: [{ colId: appointmentColumn.when, sort: 'asc' }] } },\n rowClassRules: { 'text-content-faint': (params) => params.data?.status === AppointmentStatus.cancelled },\n ...openOnRow<AppointmentResponse>((appointment) => this.editAppointment.emit(appointment), { except: [appointmentColumn.actions] }),\n }));\n\n constructor() {\n effect(() => {\n const api = this.api();\n const appointments = this.appointments();\n if (api && !api.isDestroyed()) {\n api.setGridOption('rowData', [...appointments]);\n }\n });\n }\n\n protected ready(api: GridApi<AppointmentResponse>): void {\n this.api.set(api);\n }\n\n private columns(table: Texts): ColDef<AppointmentResponse>[] {\n return [\n { ...this.cell(appointmentColumn.when, 'when', table['when']), field: 'start', sortable: true, comparator: byStart, flex: 2, minWidth: whenMinWidthPx },\n { ...this.cell(appointmentColumn.title, 'title', table['title']), field: 'title', sortable: true, flex: 2, minWidth: textMinWidthPx },\n {\n ...this.cell(appointmentColumn.contact, 'contact', table['contact']),\n valueGetter: (params) => params.data?.contactName ?? '',\n sortable: true,\n flex: 2,\n minWidth: textMinWidthPx,\n },\n { ...this.cell(appointmentColumn.location, 'location', table['location']), field: 'location', sortable: true, flex: 1, minWidth: locationMinWidthPx },\n {\n ...this.cell(appointmentColumn.status, 'status', table['status']),\n field: 'status',\n sortable: true,\n flex: 1,\n minWidth: statusMinWidthPx,\n filter: ListFilter,\n filterParams: this.statusChoices(),\n },\n { ...this.cell(appointmentColumn.actions, 'actions', ''), width: actionsWidthPx, resizable: false, pinned: 'right' },\n ];\n }\n\n private cell(colId: string, kind: AppointmentCellKind, headerName: string | undefined): ColDef<AppointmentResponse> {\n const params: AppointmentCellParams = {\n kind,\n locale: () => this.locale(),\n actions: (actions) => this.appointmentActions.emit(actions),\n };\n return { colId, headerName: headerName ?? '', cellRenderer: AppointmentCell, cellRendererParams: params };\n }\n\n private statusChoices(): ListFilterParams {\n const values = Object.values(AppointmentStatus);\n return {\n options: () => values.map((value) => ({ value, label: this.statuses()[value] ?? value })),\n rowValue: statusOf,\n };\n }\n}\n","@if (translated()) {\n <wa-data-grid [options]=\"options()\" [localeOverrides]=\"empty()\" (ready)=\"ready($event)\" />\n}\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 { CALENDAR_TITLES, calendarTitle } from '../gateway/calendar-titles';\nimport { calendarHost } from '../plugin/calendar-host';\nimport { addWeeks, startOfWeek, weekRange } from '../week';\nimport { activeLocale } from './active-locale';\nimport type { AppointmentActions } from './appointment-cell';\nimport { AppointmentDialog, AppointmentDialogData } from './appointment-dialog';\nimport { appointmentMenu } from './appointment-menu';\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 titles = inject(CALENDAR_TITLES, { optional: true });\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 title = computed(() =>\n calendarTitle(this.titles, this.calendarId(), this.calendar.hasValue() ? (this.calendar.value()?.name ?? null) : null),\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 }, 'weaver-apps-calendar.dialog.addTitle');\n }\n\n protected edit(appointment: AppointmentResponse): void {\n this.openDialog({ calendarId: this.calendarId(), appointment, day: new Date(appointment.start) }, 'weaver-apps-calendar.dialog.editTitle');\n }\n\n protected actions({ appointment, x, y }: AppointmentActions): void {\n const runs = { edit: () => this.edit(appointment), cancel: () => void this.cancel(appointment), remove: () => void this.remove(appointment) };\n calendarHost.ui.openMenu(appointmentMenu(appointment, runs), { x, y });\n }\n\n protected async cancel(appointment: AppointmentResponse): Promise<void> {\n const reason = await calendarHost.ui.prompt({\n title: 'weaver-apps-calendar.cancel.title',\n message: 'weaver-apps-calendar.cancel.message',\n confirmLabel: 'weaver-apps-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' ? 'weaver-apps-calendar.cancel.done' : 'weaver-apps-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: 'weaver-apps-calendar.delete.title',\n message: 'weaver-apps-calendar.delete.message',\n confirmLabel: 'weaver-apps-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('weaver-apps-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('weaver-apps-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('weaver-apps-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 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\">{{ title() ?? ('weaver-apps-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]=\"'weaver-apps-calendar.search.label' | transloco\"\n [attr.placeholder]=\"'weaver-apps-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 {{ 'weaver-apps-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]=\"'weaver-apps-calendar.week.previous' | transloco\" (click)=\"previousWeek()\">\n <lw-icon name=\"weaver-apps-calendar.previous\" size=\"1rem\"></lw-icon>\n <lw-tooltip [attr.text]=\"'weaver-apps-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()\">{{ 'weaver-apps-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]=\"'weaver-apps-calendar.week.next' | transloco\" (click)=\"nextWeek()\">\n <lw-icon name=\"weaver-apps-calendar.next\" size=\"1rem\"></lw-icon>\n <lw-tooltip [attr.text]=\"'weaver-apps-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\">{{ 'weaver-apps-calendar.errors.load' | transloco }}</p>\n } @else {\n <div class=\"min-h-80 flex-1\">\n <wa-appointment-table\n [appointments]=\"appointments.value() ?? []\"\n [locale]=\"locale()\"\n (editAppointment)=\"edit($event)\"\n (appointmentActions)=\"actions($event)\"\n />\n </div>\n }\n</div>\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { l as calendarPluginId } from "./weaver-apps-calendar-calendar-titles-nFkww5mx.mjs";
|
|
2
2
|
const calendarListPath = calendarPluginId;
|
|
3
3
|
function calendarPath(calendarId) {
|
|
4
4
|
return `${calendarListPath}/${calendarId}`;
|
|
5
5
|
}
|
|
6
6
|
export { calendarPath as n, calendarListPath as t };
|
|
7
7
|
|
|
8
|
-
//# sourceMappingURL=weaver-apps-calendar-calendar-paths-
|
|
8
|
+
//# sourceMappingURL=weaver-apps-calendar-calendar-paths-Di_vI0IJ.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"weaver-apps-calendar-calendar-paths-
|
|
1
|
+
{"version":3,"file":"weaver-apps-calendar-calendar-paths-Di_vI0IJ.mjs","names":[],"sources":["../../../../libs/calendar/src/lib/plugin/calendar-paths.ts"],"sourcesContent":["import { calendarPluginId } from './calendar-ids';\n\nexport const calendarListPath = calendarPluginId;\n\nexport function calendarPath(calendarId: string): string {\n return `${calendarListPath}/${calendarId}`;\n}\n"],"mappings":";AAEA,MAAa,mBAAmB;AAEhC,SAAgB,aAAa,YAAkB;CAC7C,OAAO,GAAG,iBAAgB,GAAI;AAChC"}
|
|
@@ -42,6 +42,16 @@ function provideCalendarGateway(gateway) {
|
|
|
42
42
|
useValue: gateway
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
|
-
|
|
45
|
+
const CALENDAR_TITLES = new InjectionToken("weaver-apps.calendar.titles");
|
|
46
|
+
function provideCalendarTitles(factory) {
|
|
47
|
+
return {
|
|
48
|
+
provide: CALENDAR_TITLES,
|
|
49
|
+
useFactory: factory
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function calendarTitle(titles, calendarId, storedName) {
|
|
53
|
+
return titles?.(calendarId)?.trim() || storedName;
|
|
54
|
+
}
|
|
55
|
+
export { CalendarGatewayError as a, calendarIconNames as c, CALENDAR_GATEWAY as i, calendarPluginId as l, calendarTitle as n, provideCalendarGateway as o, provideCalendarTitles as r, calendarContributionIds as s, CALENDAR_TITLES as t, calendarHost as u };
|
|
46
56
|
|
|
47
|
-
//# sourceMappingURL=weaver-apps-calendar-calendar-
|
|
57
|
+
//# sourceMappingURL=weaver-apps-calendar-calendar-titles-nFkww5mx.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"weaver-apps-calendar-calendar-titles-nFkww5mx.mjs","names":[],"sources":["../../../../libs/calendar/src/lib/plugin/calendar-host.ts","../../../../libs/calendar/src/lib/plugin/calendar-ids.ts","../../../../libs/calendar/src/lib/gateway/calendar-gateway.ts","../../../../libs/calendar/src/lib/gateway/calendar-titles.ts"],"sourcesContent":["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 calendarPluginId = 'weaver-apps-calendar';\n\nexport const calendarContributionIds = {\n calendars: `${calendarPluginId}.calendars`,\n calendar: `${calendarPluginId}.calendar`,\n rail: `${calendarPluginId}.rail`,\n} as const;\n\nexport const calendarIconNames = {\n calendar: `${calendarPluginId}.calendar`,\n previous: `${calendarPluginId}.previous`,\n next: `${calendarPluginId}.next`,\n cancel: `${calendarPluginId}.cancel`,\n} as const;\n","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 { InjectionToken, Provider } from '@angular/core';\n\nexport type CalendarTitles = (calendarId: string) => string | null;\n\nexport const CALENDAR_TITLES = new InjectionToken<CalendarTitles>('weaver-apps.calendar.titles');\n\nexport function provideCalendarTitles(factory: () => CalendarTitles): Provider {\n return { provide: CALENDAR_TITLES, useFactory: factory };\n}\n\nexport function calendarTitle(titles: CalendarTitles | null, calendarId: string, storedName: string | null): string | null {\n return titles?.(calendarId)?.trim() || storedName;\n}\n"],"mappings":";AAIA,IAAM,eAAN,MAAkB;CACR;CAER,KAAK,KAAgB;EACnB,KAAK,MAAM;CACb;CAEA,SAAM;EACJ,KAAK,MAAM;CACb;CAEA,IAAI,KAAE;EACJ,IAAI,CAAC,KAAK,KACR,MAAM,IAAI,MAAM,oCAAoC;EAEtD,OAAO,KAAK,IAAI;CAClB;CAEA,SAAS,MAAY;EACnB,KAAK,KAAK,gBAAgB,IAAI;CAChC;AACD;AAED,MAAa,eAAe,IAAI,aAAY;AC3B5C,MAAa,mBAAmB;AAEhC,MAAa,0BAA0B;CACrC,WAAW,GAAG,iBAAgB;CAC9B,UAAU,GAAG,iBAAgB;CAC7B,MAAM,GAAG,iBAAgB;AACjB;AAEV,MAAa,oBAAoB;CAC/B,UAAU,GAAG,iBAAgB;CAC7B,UAAU,GAAG,iBAAgB;CAC7B,MAAM,GAAG,iBAAgB;CACzB,QAAQ,GAAG,iBAAgB;AACnB;ACqBV,IAAa,uBAAb,cAA0C,MAAK;CACxB;CAArB,YAAqB,QAAc;EACjC,MAAM,yBAAyB,OAAM,EAAG;EADrB,KAAA,SAAA;CAErB;AACD;AAED,MAAa,mBAAmB,IAAI,eAAgC,8BAA8B;AAElG,SAAgB,uBAAuB,SAAwB;CAC7D,OAAO;EAAE,SAAS;EAAkB,UAAU;CAAO;AACvD;ACxCA,MAAa,kBAAkB,IAAI,eAA+B,6BAA6B;AAE/F,SAAgB,sBAAsB,SAA6B;CACjE,OAAO;EAAE,SAAS;EAAiB,YAAY;CAAO;AACxD;AAEA,SAAgB,cAAc,QAA+B,YAAoB,YAAyB;CACxG,OAAO,SAAS,UAAU,CAAC,EAAE,KAAI,KAAM;AACzC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as calendarIconNames, i as
|
|
2
|
-
import { n as calendarPath, t as calendarListPath } from "./weaver-apps-calendar-calendar-paths-
|
|
1
|
+
import { a as CalendarGatewayError, c as calendarIconNames, i as CALENDAR_GATEWAY, l as calendarPluginId, o as provideCalendarGateway, r as provideCalendarTitles, s as calendarContributionIds, u as calendarHost } from "./weaver-apps-calendar-calendar-titles-nFkww5mx.mjs";
|
|
2
|
+
import { n as calendarPath, t as calendarListPath } from "./weaver-apps-calendar-calendar-paths-Di_vI0IJ.mjs";
|
|
3
3
|
const stroke = "fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"";
|
|
4
4
|
const calendarIcons = {
|
|
5
5
|
[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>`,
|
|
@@ -26,14 +26,14 @@ function createCalendarPlugin(options = {}) {
|
|
|
26
26
|
title: "weaver-apps-calendar.calendars.title",
|
|
27
27
|
icon: calendarIconNames.calendar,
|
|
28
28
|
routable: { path: calendarListPath },
|
|
29
|
-
loadComponent: () => import("./weaver-apps-calendar-calendar-list-page-
|
|
29
|
+
loadComponent: () => import("./weaver-apps-calendar-calendar-list-page-hzMBlQ5b.mjs").then((module) => module.CalendarListPage)
|
|
30
30
|
});
|
|
31
31
|
ctx.registerSurface({
|
|
32
32
|
id: calendarContributionIds.calendar,
|
|
33
33
|
title: "weaver-apps-calendar.title",
|
|
34
34
|
icon: calendarIconNames.calendar,
|
|
35
35
|
routable: { path: `${calendarListPath}/:calendarId` },
|
|
36
|
-
loadComponent: () => import("./weaver-apps-calendar-calendar-page-
|
|
36
|
+
loadComponent: () => import("./weaver-apps-calendar-calendar-page-DbWMaf4n.mjs").then((module) => module.CalendarPage)
|
|
37
37
|
});
|
|
38
38
|
if (options.railItem) ctx.registerRailItem({
|
|
39
39
|
id: calendarContributionIds.rail,
|
|
@@ -144,6 +144,6 @@ function createHttpCalendarGateway(options) {
|
|
|
144
144
|
}
|
|
145
145
|
};
|
|
146
146
|
}
|
|
147
|
-
export { CALENDAR_GATEWAY, CalendarGatewayError, calendarContributionIds, calendarListPath, calendarPath, calendarPlugin, calendarPluginId, createCalendarPlugin, createHttpCalendarGateway, provideCalendarGateway };
|
|
147
|
+
export { CALENDAR_GATEWAY, CalendarGatewayError, calendarContributionIds, calendarListPath, calendarPath, calendarPlugin, calendarPluginId, createCalendarPlugin, createHttpCalendarGateway, provideCalendarGateway, provideCalendarTitles };
|
|
148
148
|
|
|
149
149
|
//# sourceMappingURL=weaver-apps-calendar.mjs.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weaver-apps/calendar",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.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": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
},
|
|
20
20
|
"sideEffects": false,
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@weaver-apps/data-grid": "0.
|
|
22
|
+
"@weaver-apps/data-grid": "0.4.0",
|
|
23
23
|
"tslib": "^2.3.0"
|
|
24
24
|
},
|
|
25
25
|
"module": "fesm2022/weaver-apps-calendar.mjs",
|
|
@@ -198,10 +198,12 @@ export declare class CalendarGatewayError extends Error {
|
|
|
198
198
|
}
|
|
199
199
|
export declare const CALENDAR_GATEWAY: InjectionToken<CalendarGateway>;
|
|
200
200
|
export declare function provideCalendarGateway(gateway: CalendarGateway): Provider;
|
|
201
|
+
type CalendarTitles = (calendarId: string) => string | null;
|
|
202
|
+
export declare function provideCalendarTitles(factory: () => CalendarTitles): Provider;
|
|
201
203
|
interface HttpCalendarGatewayOptions {
|
|
202
204
|
readonly baseUrl: string;
|
|
203
205
|
readonly headers?: Readonly<Record<string, string>>;
|
|
204
206
|
readonly fetch?: typeof fetch;
|
|
205
207
|
}
|
|
206
208
|
export declare function createHttpCalendarGateway(options: HttpCalendarGatewayOptions): CalendarGateway;
|
|
207
|
-
export type { AppointmentOutcome, AppointmentRequest, AppointmentResponse, AppointmentStatus, CalendarGateway, CalendarPluginOptions, CalendarRange, CalendarResponse, ConflictingAppointment, HttpCalendarGatewayOptions };
|
|
209
|
+
export type { AppointmentOutcome, AppointmentRequest, AppointmentResponse, AppointmentStatus, CalendarGateway, CalendarPluginOptions, CalendarRange, CalendarResponse, CalendarTitles, ConflictingAppointment, HttpCalendarGatewayOptions };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"weaver-apps-calendar-calendar-gateway-DqiL9VbI.mjs","names":[],"sources":["../../../../libs/calendar/src/lib/plugin/calendar-host.ts","../../../../libs/calendar/src/lib/plugin/calendar-ids.ts","../../../../libs/calendar/src/lib/gateway/calendar-gateway.ts"],"sourcesContent":["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 calendarPluginId = 'weaver-apps-calendar';\n\nexport const calendarContributionIds = {\n calendars: `${calendarPluginId}.calendars`,\n calendar: `${calendarPluginId}.calendar`,\n rail: `${calendarPluginId}.rail`,\n} as const;\n\nexport const calendarIconNames = {\n calendar: `${calendarPluginId}.calendar`,\n previous: `${calendarPluginId}.previous`,\n next: `${calendarPluginId}.next`,\n cancel: `${calendarPluginId}.cancel`,\n} as const;\n","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"],"mappings":";AAIA,IAAM,eAAN,MAAkB;CACR;CAER,KAAK,KAAgB;EACnB,KAAK,MAAM;CACb;CAEA,SAAM;EACJ,KAAK,MAAM;CACb;CAEA,IAAI,KAAE;EACJ,IAAI,CAAC,KAAK,KACR,MAAM,IAAI,MAAM,oCAAoC;EAEtD,OAAO,KAAK,IAAI;CAClB;CAEA,SAAS,MAAY;EACnB,KAAK,KAAK,gBAAgB,IAAI;CAChC;AACD;AAED,MAAa,eAAe,IAAI,aAAY;AC3B5C,MAAa,mBAAmB;AAEhC,MAAa,0BAA0B;CACrC,WAAW,GAAG,iBAAgB;CAC9B,UAAU,GAAG,iBAAgB;CAC7B,MAAM,GAAG,iBAAgB;AACjB;AAEV,MAAa,oBAAoB;CAC/B,UAAU,GAAG,iBAAgB;CAC7B,UAAU,GAAG,iBAAgB;CAC7B,MAAM,GAAG,iBAAgB;CACzB,QAAQ,GAAG,iBAAgB;AACnB;ACqBV,IAAa,uBAAb,cAA0C,MAAK;CACxB;CAArB,YAAqB,QAAc;EACjC,MAAM,yBAAyB,OAAM,EAAG;EADrB,KAAA,SAAA;CAErB;AACD;AAED,MAAa,mBAAmB,IAAI,eAAgC,8BAA8B;AAElG,SAAgB,uBAAuB,SAAwB;CAC7D,OAAO;EAAE,SAAS;EAAkB,UAAU;CAAO;AACvD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"weaver-apps-calendar-calendar-list-page-CF8odTAv.mjs","names":[],"sources":["../../../../libs/calendar/src/lib/views/calendar-list-page.ts","../../../../libs/calendar/src/lib/views/calendar-list-page.html"],"sourcesContent":["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: 'weaver-apps-calendar.calendars.create',\n message: 'weaver-apps-calendar.calendars.createMessage',\n confirmLabel: 'weaver-apps-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: 'weaver-apps-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\">{{ 'weaver-apps-calendar.calendars.title' | transloco }}</h2>\n <button type=\"button\" class=\"lw-btn lw-btn--primary\" (click)=\"create()\">{{ 'weaver-apps-calendar.calendars.create' | transloco }}</button>\n </div>\n @if (calendars.error()) {\n <p class=\"text-sm text-negative\" role=\"alert\">{{ 'weaver-apps-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=\"weaver-apps-calendar.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\">{{ 'weaver-apps-calendar.calendars.empty' | transloco }}</li>\n }\n </ul>\n }\n</div>\n"],"mappings":";;;;;AAaA,IAAa,mBAAb,MAAa,iBAAgB;CACV,UAAU,OAAO,gBAAgB;CAE/B,YAAY,SAAQ;EAAA,GAAA,YAAA,EAAA,WAAA,YAAA,+BAAA,CAAA;EAAG,cAAc,KAAK,QAAQ,UAAS;CAAE,CAAA;CAEtE,KAAK,YAAkB;EAC/B,aAAa,SAAS,aAAa,UAAU,CAAC;CAChD;CAEU,MAAM,SAAM;EACpB,MAAM,OAAO,MAAM,aAAa,GAAG,OAAO;GACxC,OAAO;GACP,SAAS;GACT,cAAc;EACf,CAAA;EACD,IAAI,CAAC,MAAM,KAAI,GACb;EAEF,IAAI;GACF,MAAM,WAAW,MAAM,KAAK,QAAQ,aAAa,OAAO,WAAU,GAAI,KAAK,KAAI,CAAE;GACjF,KAAK,KAAK,SAAS,EAAE;EACvB,QAAQ;GACN,aAAa,GAAG,MAAM;IAAE,SAAS;IAAsC,MAAM;GAAO,CAAE;EACxF;CACF;CAxBW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAgB,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAhB,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAgB,cAAA;EAAA,UAAA;EAAA,UAAA;EAAA,UCb7B;EAsBA,cAAA,CAAA;GAAA,MAAA;GAAA,MDdY;GAAa,MAAA;EAAA,CAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AAKZ,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAgB,YAAA,CAAA;EAP5B,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAuB,SACxB,CAAC,aAAa;GAAC,SACf,CAAC,sBAAsB;GAAC,iBAEhB,wBAAwB;GAAM,UAAA;EAAA,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"weaver-apps-calendar-calendar-page-BjJzPlTa.mjs","names":[],"sources":["../../../../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-menu.ts","../../../../libs/calendar/src/lib/views/appointment-cell.ts","../../../../libs/calendar/src/lib/views/appointment-cell.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"],"sourcesContent":["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: 'weaver-apps-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: 'weaver-apps-calendar.dialog.titleRequired' });\n return null;\n }\n if (!startsAt || !endsAt || endsAt <= startsAt) {\n this.problem.set({ kind: 'message', key: 'weaver-apps-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: 'weaver-apps-calendar.dialog.closed' });\n return;\n case 'changed':\n this.problem.set({ kind: 'message', key: 'weaver-apps-calendar.dialog.changed' });\n return;\n case 'invalid':\n this.problem.set({ kind: 'message', key: 'weaver-apps-calendar.dialog.invalid' });\n return;\n default:\n this.problem.set({ kind: 'message', key: 'weaver-apps-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 {{ 'weaver-apps-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 {{ 'weaver-apps-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 {{ 'weaver-apps-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 {{ 'weaver-apps-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 {{ 'weaver-apps-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 {{ 'weaver-apps-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 {{ 'weaver-apps-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 {{ 'weaver-apps-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 {{ 'weaver-apps-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 {{ 'weaver-apps-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 {{ 'weaver-apps-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()\">{{ 'weaver-apps-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>{{ 'weaver-apps-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()\">{{ 'weaver-apps-calendar.dialog.cancel' | transloco }}</button>\n <button type=\"submit\" class=\"lw-btn lw-btn--primary\" [disabled]=\"saving()\">{{ 'weaver-apps-calendar.dialog.save' | transloco }}</button>\n </div>\n</form>\n","import type { UiMenuAction } from '@loomweaver/plugin-sdk';\nimport { AppointmentStatus, type AppointmentResponse } from '../api/models';\nimport { calendarIconNames } from '../plugin/calendar-ids';\n\nexport interface AppointmentMenuRuns {\n readonly edit: () => void;\n readonly cancel: () => void;\n readonly remove: () => void;\n}\n\nexport function appointmentMenu(appointment: AppointmentResponse, runs: AppointmentMenuRuns): UiMenuAction[] {\n const cancellable = appointment.status !== AppointmentStatus.cancelled;\n return [\n { label: 'weaver-apps-calendar.actions.edit', icon: 'edit', run: runs.edit },\n ...(cancellable ? [{ label: 'weaver-apps-calendar.actions.cancel', icon: calendarIconNames.cancel, run: runs.cancel }] : []),\n { label: 'weaver-apps-calendar.actions.delete', icon: 'trash', run: runs.remove },\n ];\n}\n","import { ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA, computed, signal } from '@angular/core';\nimport { TranslocoPipe } from '@jsverse/transloco';\nimport type { ICellRendererAngularComp } from 'ag-grid-angular';\nimport type { ICellRendererParams } from 'ag-grid-community';\nimport type { AppointmentResponse } from '../api/models';\n\nexport interface AppointmentActions {\n readonly appointment: AppointmentResponse;\n readonly x: number;\n readonly y: number;\n}\n\nexport type AppointmentCellKind = 'when' | 'title' | 'contact' | 'location' | 'status' | 'actions';\n\nexport interface AppointmentCellParams {\n readonly kind: AppointmentCellKind;\n readonly locale: () => string;\n readonly actions: (actions: AppointmentActions) => void;\n}\n\ntype Params = ICellRendererParams<AppointmentResponse> & AppointmentCellParams;\n\n@Component({\n selector: 'wa-appointment-cell',\n imports: [TranslocoPipe],\n schemas: [CUSTOM_ELEMENTS_SCHEMA],\n templateUrl: './appointment-cell.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class AppointmentCell implements ICellRendererAngularComp {\n private params: Params | null = null;\n private readonly locale = signal('en');\n\n protected readonly kind = signal<AppointmentCellKind>('title');\n protected readonly appointment = signal<AppointmentResponse | null>(null);\n protected readonly cancelled = computed(() => this.appointment()?.status === 'cancelled');\n protected readonly when = computed(() => {\n const appointment = this.appointment();\n if (!appointment) {\n return { day: '', hours: '' };\n }\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 {\n day: day.format(new Date(appointment.start)),\n hours: `${time.format(new Date(appointment.start))} – ${time.format(new Date(appointment.end))}`,\n };\n });\n\n agInit(params: Params): void {\n this.params = params;\n this.kind.set(params.kind);\n this.appointment.set(params.data ?? null);\n this.locale.set(params.locale());\n }\n\n refresh(params: Params): boolean {\n this.agInit(params);\n return true;\n }\n\n protected openActions(event: MouseEvent): void {\n const appointment = this.appointment();\n if (appointment) {\n this.params?.actions({ appointment, ...menuAnchor(event) });\n }\n }\n}\n\nfunction menuAnchor(event: MouseEvent): { readonly x: number; readonly y: number } {\n if (event.detail > 0) {\n return { x: event.clientX, y: event.clientY };\n }\n const bounds = (event.currentTarget as HTMLElement).getBoundingClientRect();\n return { x: bounds.left, y: bounds.bottom };\n}\n","@if (appointment(); as appointment) {\n @switch (kind()) {\n @case ('when') {\n <span class=\"font-medium\" [class.text-content]=\"!cancelled()\" [class.line-through]=\"cancelled()\">{{ when().day }}</span>\n <span class=\"ml-2 text-content-faint\" [class.line-through]=\"cancelled()\">{{ when().hours }}</span>\n }\n @case ('title') {\n <span class=\"font-medium\" [class.text-content]=\"!cancelled()\" [class.line-through]=\"cancelled()\">{{ appointment.title }}</span>\n }\n @case ('contact') {\n <span [class.line-through]=\"cancelled()\">{{ appointment.contactName ?? '–' }}</span>\n @if (appointment.contactPhone) {\n <span class=\"ml-2 text-content-faint\" [class.line-through]=\"cancelled()\">{{ appointment.contactPhone }}</span>\n }\n }\n @case ('location') {\n <span class=\"text-content-faint\" [class.line-through]=\"cancelled()\">{{ appointment.location ?? '–' }}</span>\n }\n @case ('status') {\n <span class=\"rounded-full border border-border px-2 py-0.5 text-xs text-content\" data-testid=\"appointment-status\">{{ 'weaver-apps-calendar.status.' + appointment.status | transloco }}</span>\n }\n @case ('actions') {\n <button type=\"button\" class=\"relative lw-btn lw-btn--ghost lw-btn--sm lw-btn--icon\" [attr.aria-label]=\"'weaver-apps-calendar.actions.more' | transloco\" (click)=\"openActions($event)\">\n <lw-icon name=\"more\" size=\"1rem\"></lw-icon>\n </button>\n }\n }\n}\n","import { ChangeDetectionStrategy, Component, computed, effect, input, output, signal, type Signal } from '@angular/core';\nimport { translateObjectSignal } from '@jsverse/transloco';\nimport { DataGrid, ListFilter, type ListFilterParams, openOnRow } from '@weaver-apps/data-grid';\nimport type { ColDef, GridApi, GridOptions } from 'ag-grid-community';\nimport { AppointmentStatus, type AppointmentResponse } from '../api/models';\nimport { AppointmentCell, type AppointmentActions, type AppointmentCellKind, type AppointmentCellParams } from './appointment-cell';\n\ntype Texts = Readonly<Record<string, string>>;\n\nexport const appointmentColumn = {\n when: 'start',\n title: 'title',\n contact: 'contact',\n location: 'location',\n status: 'status',\n actions: 'actions',\n} as const;\n\nconst actionsWidthPx = 72;\nconst whenMinWidthPx = 230;\nconst textMinWidthPx = 110;\nconst locationMinWidthPx = 90;\nconst statusMinWidthPx = 112;\n\nexport function byStart(left: string | undefined, right: string | undefined): number {\n return Date.parse(left ?? '') - Date.parse(right ?? '');\n}\n\nexport function statusOf(appointment: AppointmentResponse): string {\n return appointment.status;\n}\n\n@Component({\n selector: 'wa-appointment-table',\n imports: [DataGrid],\n templateUrl: './appointment-table.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'block h-full w-full' },\n})\nexport class AppointmentTable {\n private readonly table = translateObjectSignal('weaver-apps-calendar.table') as Signal<Texts>;\n private readonly statuses = translateObjectSignal('weaver-apps-calendar.status') as Signal<Texts>;\n private readonly api = signal<GridApi<AppointmentResponse> | null>(null);\n\n readonly appointments = input.required<readonly AppointmentResponse[]>();\n readonly locale = input.required<string>();\n\n readonly editAppointment = output<AppointmentResponse>();\n readonly appointmentActions = output<AppointmentActions>();\n\n protected readonly translated = computed(() => typeof this.table() === 'object' && typeof this.table()['title'] === 'string');\n\n protected readonly empty = computed(() => ({ noRowsToShow: this.table()['empty'] ?? '' }));\n\n protected readonly options = computed<GridOptions<AppointmentResponse>>(() => ({\n rowModelType: 'clientSide',\n columnDefs: this.columns(this.table()),\n defaultColDef: { sortable: false, resizable: true, suppressHeaderMenuButton: true },\n getRowId: (params) => params.data.id,\n initialState: { sort: { sortModel: [{ colId: appointmentColumn.when, sort: 'asc' }] } },\n rowClassRules: { 'text-content-faint': (params) => params.data?.status === AppointmentStatus.cancelled },\n ...openOnRow<AppointmentResponse>((appointment) => this.editAppointment.emit(appointment), { except: [appointmentColumn.actions] }),\n }));\n\n constructor() {\n effect(() => {\n const api = this.api();\n const appointments = this.appointments();\n if (api && !api.isDestroyed()) {\n api.setGridOption('rowData', [...appointments]);\n }\n });\n }\n\n protected ready(api: GridApi<AppointmentResponse>): void {\n this.api.set(api);\n }\n\n private columns(table: Texts): ColDef<AppointmentResponse>[] {\n return [\n { ...this.cell(appointmentColumn.when, 'when', table['when']), field: 'start', sortable: true, comparator: byStart, flex: 2, minWidth: whenMinWidthPx },\n { ...this.cell(appointmentColumn.title, 'title', table['title']), field: 'title', sortable: true, flex: 2, minWidth: textMinWidthPx },\n {\n ...this.cell(appointmentColumn.contact, 'contact', table['contact']),\n valueGetter: (params) => params.data?.contactName ?? '',\n sortable: true,\n flex: 2,\n minWidth: textMinWidthPx,\n },\n { ...this.cell(appointmentColumn.location, 'location', table['location']), field: 'location', sortable: true, flex: 1, minWidth: locationMinWidthPx },\n {\n ...this.cell(appointmentColumn.status, 'status', table['status']),\n field: 'status',\n sortable: true,\n flex: 1,\n minWidth: statusMinWidthPx,\n filter: ListFilter,\n filterParams: this.statusChoices(),\n },\n { ...this.cell(appointmentColumn.actions, 'actions', ''), width: actionsWidthPx, resizable: false },\n ];\n }\n\n private cell(colId: string, kind: AppointmentCellKind, headerName: string | undefined): ColDef<AppointmentResponse> {\n const params: AppointmentCellParams = {\n kind,\n locale: () => this.locale(),\n actions: (actions) => this.appointmentActions.emit(actions),\n };\n return { colId, headerName: headerName ?? '', cellRenderer: AppointmentCell, cellRendererParams: params };\n }\n\n private statusChoices(): ListFilterParams {\n const values = Object.values(AppointmentStatus);\n return {\n options: () => values.map((value) => ({ value, label: this.statuses()[value] ?? value })),\n rowValue: statusOf,\n };\n }\n}\n","@if (translated()) {\n <wa-data-grid [options]=\"options()\" [localeOverrides]=\"empty()\" (ready)=\"ready($event)\" />\n}\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 type { AppointmentActions } from './appointment-cell';\nimport { AppointmentDialog, AppointmentDialogData } from './appointment-dialog';\nimport { appointmentMenu } from './appointment-menu';\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 }, 'weaver-apps-calendar.dialog.addTitle');\n }\n\n protected edit(appointment: AppointmentResponse): void {\n this.openDialog({ calendarId: this.calendarId(), appointment, day: new Date(appointment.start) }, 'weaver-apps-calendar.dialog.editTitle');\n }\n\n protected actions({ appointment, x, y }: AppointmentActions): void {\n const runs = { edit: () => this.edit(appointment), cancel: () => void this.cancel(appointment), remove: () => void this.remove(appointment) };\n calendarHost.ui.openMenu(appointmentMenu(appointment, runs), { x, y });\n }\n\n protected async cancel(appointment: AppointmentResponse): Promise<void> {\n const reason = await calendarHost.ui.prompt({\n title: 'weaver-apps-calendar.cancel.title',\n message: 'weaver-apps-calendar.cancel.message',\n confirmLabel: 'weaver-apps-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' ? 'weaver-apps-calendar.cancel.done' : 'weaver-apps-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: 'weaver-apps-calendar.delete.title',\n message: 'weaver-apps-calendar.delete.message',\n confirmLabel: 'weaver-apps-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('weaver-apps-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('weaver-apps-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('weaver-apps-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 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 ?? ('weaver-apps-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]=\"'weaver-apps-calendar.search.label' | transloco\"\n [attr.placeholder]=\"'weaver-apps-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 {{ 'weaver-apps-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]=\"'weaver-apps-calendar.week.previous' | transloco\" (click)=\"previousWeek()\">\n <lw-icon name=\"weaver-apps-calendar.previous\" size=\"1rem\"></lw-icon>\n <lw-tooltip [attr.text]=\"'weaver-apps-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()\">{{ 'weaver-apps-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]=\"'weaver-apps-calendar.week.next' | transloco\" (click)=\"nextWeek()\">\n <lw-icon name=\"weaver-apps-calendar.next\" size=\"1rem\"></lw-icon>\n <lw-tooltip [attr.text]=\"'weaver-apps-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\">{{ 'weaver-apps-calendar.errors.load' | transloco }}</p>\n } @else {\n <div class=\"min-h-80 flex-1\">\n <wa-appointment-table\n [appointments]=\"appointments.value() ?? []\"\n [locale]=\"locale()\"\n (editAppointment)=\"edit($event)\"\n (appointmentActions)=\"actions($event)\"\n />\n </div>\n }\n</div>\n"],"mappings":"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"}
|