@weaver-apps/calendar 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/weaver-apps-calendar-calendar-gateway-DUo797bn.mjs +35 -0
- package/fesm2022/weaver-apps-calendar-calendar-gateway-DUo797bn.mjs.map +1 -0
- package/fesm2022/weaver-apps-calendar-calendar-list-page-dgF-nnQF.mjs +74 -0
- package/fesm2022/weaver-apps-calendar-calendar-list-page-dgF-nnQF.mjs.map +1 -0
- package/fesm2022/weaver-apps-calendar-calendar-page-DpdU_Vfy.mjs +722 -0
- package/fesm2022/weaver-apps-calendar-calendar-page-DpdU_Vfy.mjs.map +1 -0
- package/fesm2022/weaver-apps-calendar-calendar-paths-qzIR-lDU.mjs +19 -0
- package/fesm2022/weaver-apps-calendar-calendar-paths-qzIR-lDU.mjs.map +1 -0
- package/fesm2022/weaver-apps-calendar.mjs +4 -833
- package/fesm2022/weaver-apps-calendar.mjs.map +1 -1
- package/package.json +2 -2
|
@@ -1,834 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import { TranslocoPipe, TranslocoService, translateObjectSignal } from "@jsverse/transloco";
|
|
4
|
-
import { toSignal } from "@angular/core/rxjs-interop";
|
|
5
|
-
import { ActivatedRoute } from "@angular/router";
|
|
6
|
-
import { map } from "rxjs";
|
|
7
|
-
import { DialogRef } from "@loomweaver/plugin-sdk";
|
|
8
|
-
import { DataGrid, ListFilter } from "@weaver-apps/data-grid";
|
|
9
|
-
var CalendarGatewayError = class extends Error {
|
|
10
|
-
status;
|
|
11
|
-
constructor(status) {
|
|
12
|
-
super(`The calendar answered ${status}.`);
|
|
13
|
-
this.status = status;
|
|
14
|
-
}
|
|
15
|
-
};
|
|
16
|
-
const CALENDAR_GATEWAY = new InjectionToken("weaver-apps.calendar.gateway");
|
|
17
|
-
function provideCalendarGateway(gateway) {
|
|
18
|
-
return {
|
|
19
|
-
provide: CALENDAR_GATEWAY,
|
|
20
|
-
useValue: gateway
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
var CalendarHost = class {
|
|
24
|
-
ctx;
|
|
25
|
-
bind(ctx) {
|
|
26
|
-
this.ctx = ctx;
|
|
27
|
-
}
|
|
28
|
-
unbind() {
|
|
29
|
-
this.ctx = void 0;
|
|
30
|
-
}
|
|
31
|
-
get ui() {
|
|
32
|
-
if (!this.ctx) throw new Error("The calendar plugin is not active.");
|
|
33
|
-
return this.ctx.ui;
|
|
34
|
-
}
|
|
35
|
-
navigate(path) {
|
|
36
|
-
this.ctx?.navigateContent(path);
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
const calendarHost = new CalendarHost();
|
|
40
|
-
const calendarPluginId = "weaver-apps-calendar";
|
|
41
|
-
const calendarContributionIds = {
|
|
42
|
-
calendars: `${calendarPluginId}.calendars`,
|
|
43
|
-
calendar: `${calendarPluginId}.calendar`,
|
|
44
|
-
rail: `${calendarPluginId}.rail`
|
|
45
|
-
};
|
|
46
|
-
const calendarIconNames = {
|
|
47
|
-
calendar: `${calendarPluginId}.calendar`,
|
|
48
|
-
previous: `${calendarPluginId}.previous`,
|
|
49
|
-
next: `${calendarPluginId}.next`,
|
|
50
|
-
cancel: `${calendarPluginId}.cancel`
|
|
51
|
-
};
|
|
52
|
-
const calendarListPath = calendarPluginId;
|
|
53
|
-
function calendarPath(calendarId) {
|
|
54
|
-
return `${calendarListPath}/${calendarId}`;
|
|
55
|
-
}
|
|
56
|
-
var CalendarListPage = class CalendarListPage {
|
|
57
|
-
gateway = inject(CALENDAR_GATEWAY);
|
|
58
|
-
calendars = resource({
|
|
59
|
-
...ngDevMode ? { debugName: "calendars" } : /* istanbul ignore next */ {},
|
|
60
|
-
loader: () => this.gateway.calendars()
|
|
61
|
-
});
|
|
62
|
-
open(calendarId) {
|
|
63
|
-
calendarHost.navigate(calendarPath(calendarId));
|
|
64
|
-
}
|
|
65
|
-
async create() {
|
|
66
|
-
const name = await calendarHost.ui.prompt({
|
|
67
|
-
title: "weaver-apps-calendar.calendars.create",
|
|
68
|
-
message: "weaver-apps-calendar.calendars.createMessage",
|
|
69
|
-
confirmLabel: "weaver-apps-calendar.calendars.createConfirm"
|
|
70
|
-
});
|
|
71
|
-
if (!name?.trim()) return;
|
|
72
|
-
try {
|
|
73
|
-
const calendar = await this.gateway.saveCalendar(crypto.randomUUID(), name.trim());
|
|
74
|
-
this.open(calendar.id);
|
|
75
|
-
} catch {
|
|
76
|
-
calendarHost.ui.toast({
|
|
77
|
-
message: "weaver-apps-calendar.errors.create",
|
|
78
|
-
kind: "error"
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
83
|
-
minVersion: "12.0.0",
|
|
84
|
-
version: "22.2.3",
|
|
85
|
-
ngImport: i0,
|
|
86
|
-
type: CalendarListPage,
|
|
87
|
-
deps: [],
|
|
88
|
-
target: i0.ɵɵFactoryTarget.Component
|
|
89
|
-
});
|
|
90
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
91
|
-
minVersion: "17.0.0",
|
|
92
|
-
version: "22.2.3",
|
|
93
|
-
type: CalendarListPage,
|
|
94
|
-
isStandalone: true,
|
|
95
|
-
selector: "wa-calendar-list-page",
|
|
96
|
-
ngImport: i0,
|
|
97
|
-
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 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",
|
|
98
|
-
dependencies: [{
|
|
99
|
-
kind: "pipe",
|
|
100
|
-
type: TranslocoPipe,
|
|
101
|
-
name: "transloco"
|
|
102
|
-
}],
|
|
103
|
-
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
104
|
-
});
|
|
105
|
-
};
|
|
106
|
-
i0.ɵɵngDeclareClassMetadata({
|
|
107
|
-
minVersion: "12.0.0",
|
|
108
|
-
version: "22.2.3",
|
|
109
|
-
ngImport: i0,
|
|
110
|
-
type: CalendarListPage,
|
|
111
|
-
decorators: [{
|
|
112
|
-
type: Component,
|
|
113
|
-
args: [{
|
|
114
|
-
selector: "wa-calendar-list-page",
|
|
115
|
-
imports: [TranslocoPipe],
|
|
116
|
-
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
117
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
118
|
-
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 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"
|
|
119
|
-
}]
|
|
120
|
-
}]
|
|
121
|
-
});
|
|
122
|
-
const daysPerWeek = 7;
|
|
123
|
-
const sunday = 0;
|
|
124
|
-
const daysFromSundayToMonday = 6;
|
|
125
|
-
function startOfWeek(date) {
|
|
126
|
-
const start = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
127
|
-
const offset = start.getDay() === sunday ? daysFromSundayToMonday : start.getDay() - 1;
|
|
128
|
-
start.setDate(start.getDate() - offset);
|
|
129
|
-
return start;
|
|
130
|
-
}
|
|
131
|
-
function addWeeks(weekStart, weeks) {
|
|
132
|
-
const moved = new Date(weekStart);
|
|
133
|
-
moved.setDate(moved.getDate() + weeks * daysPerWeek);
|
|
134
|
-
return moved;
|
|
135
|
-
}
|
|
136
|
-
function weekRange(weekStart) {
|
|
137
|
-
return {
|
|
138
|
-
from: weekStart,
|
|
139
|
-
until: addWeeks(weekStart, 1)
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
function localDate(value) {
|
|
143
|
-
const pad = (part) => `${part}`.padStart(2, "0");
|
|
144
|
-
return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}`;
|
|
145
|
-
}
|
|
146
|
-
function localTime(value) {
|
|
147
|
-
const pad = (part) => `${part}`.padStart(2, "0");
|
|
148
|
-
return `${pad(value.getHours())}:${pad(value.getMinutes())}`;
|
|
149
|
-
}
|
|
150
|
-
function combine(date, time) {
|
|
151
|
-
const combined = /* @__PURE__ */ new Date(`${date}T${time}`);
|
|
152
|
-
return Number.isNaN(combined.getTime()) ? null : combined;
|
|
153
|
-
}
|
|
154
|
-
function activeLocale() {
|
|
155
|
-
const transloco = inject(TranslocoService);
|
|
156
|
-
return toSignal(transloco.langChanges$, { initialValue: transloco.getActiveLang() });
|
|
157
|
-
}
|
|
158
|
-
const AppointmentStatus = {
|
|
159
|
-
scheduled: "scheduled",
|
|
160
|
-
confirmed: "confirmed",
|
|
161
|
-
completed: "completed",
|
|
162
|
-
noShow: "noShow",
|
|
163
|
-
cancelled: "cancelled"
|
|
164
|
-
};
|
|
165
|
-
const defaultStart = "09:00";
|
|
166
|
-
const defaultEnd = "10:00";
|
|
167
|
-
const settableStatuses = [
|
|
168
|
-
AppointmentStatus.scheduled,
|
|
169
|
-
AppointmentStatus.confirmed,
|
|
170
|
-
AppointmentStatus.completed,
|
|
171
|
-
AppointmentStatus.noShow
|
|
172
|
-
];
|
|
173
|
-
var AppointmentDialog = class AppointmentDialog {
|
|
174
|
-
dialog = inject(DialogRef);
|
|
175
|
-
gateway = inject(CALENDAR_GATEWAY);
|
|
176
|
-
data = this.dialog.data;
|
|
177
|
-
existing = this.data.appointment;
|
|
178
|
-
locale = activeLocale();
|
|
179
|
-
editing = this.existing !== null;
|
|
180
|
-
statuses = settableStatuses;
|
|
181
|
-
title = signal(this.existing?.title ?? "", ...ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []);
|
|
182
|
-
date = signal(localDate(this.existing ? new Date(this.existing.start) : this.data.day), ...ngDevMode ? [{ debugName: "date" }] : /* istanbul ignore next */ []);
|
|
183
|
-
start = signal(this.existing ? localTime(new Date(this.existing.start)) : defaultStart, ...ngDevMode ? [{ debugName: "start" }] : /* istanbul ignore next */ []);
|
|
184
|
-
endDate = signal(localDate(this.existing ? new Date(this.existing.end) : this.data.day), ...ngDevMode ? [{ debugName: "endDate" }] : /* istanbul ignore next */ []);
|
|
185
|
-
end = signal(this.existing ? localTime(new Date(this.existing.end)) : defaultEnd, ...ngDevMode ? [{ debugName: "end" }] : /* istanbul ignore next */ []);
|
|
186
|
-
location = signal(this.existing?.location ?? "", ...ngDevMode ? [{ debugName: "location" }] : /* istanbul ignore next */ []);
|
|
187
|
-
contactName = signal(this.existing?.contactName ?? "", ...ngDevMode ? [{ debugName: "contactName" }] : /* istanbul ignore next */ []);
|
|
188
|
-
contactPhone = signal(this.existing?.contactPhone ?? "", ...ngDevMode ? [{ debugName: "contactPhone" }] : /* istanbul ignore next */ []);
|
|
189
|
-
contactEmail = signal(this.existing?.contactEmail ?? "", ...ngDevMode ? [{ debugName: "contactEmail" }] : /* istanbul ignore next */ []);
|
|
190
|
-
description = signal(this.existing?.description ?? "", ...ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []);
|
|
191
|
-
status = signal(this.existing?.status ?? AppointmentStatus.scheduled, ...ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []);
|
|
192
|
-
saving = signal(false, ...ngDevMode ? [{ debugName: "saving" }] : /* istanbul ignore next */ []);
|
|
193
|
-
problem = signal({ kind: "none" }, ...ngDevMode ? [{ debugName: "problem" }] : /* istanbul ignore next */ []);
|
|
194
|
-
persisted = false;
|
|
195
|
-
problemKey = computed(() => {
|
|
196
|
-
const problem = this.problem();
|
|
197
|
-
return problem.kind === "message" ? problem.key : "";
|
|
198
|
-
}, ...ngDevMode ? [{ debugName: "problemKey" }] : /* istanbul ignore next */ []);
|
|
199
|
-
conflictTimes = computed(() => {
|
|
200
|
-
const problem = this.problem();
|
|
201
|
-
if (problem.kind !== "conflict") return [];
|
|
202
|
-
const format = new Intl.DateTimeFormat(this.locale(), {
|
|
203
|
-
dateStyle: "short",
|
|
204
|
-
timeStyle: "short"
|
|
205
|
-
});
|
|
206
|
-
return problem.conflicts.map((conflict) => `${format.format(new Date(conflict.start))} – ${format.format(new Date(conflict.end))}`);
|
|
207
|
-
}, ...ngDevMode ? [{ debugName: "conflictTimes" }] : /* istanbul ignore next */ []);
|
|
208
|
-
bind(target, event) {
|
|
209
|
-
target.set(event.target.value);
|
|
210
|
-
}
|
|
211
|
-
bindDate(event) {
|
|
212
|
-
const value = event.target.value;
|
|
213
|
-
if (this.endDate() === this.date()) this.endDate.set(value);
|
|
214
|
-
this.date.set(value);
|
|
215
|
-
}
|
|
216
|
-
chooseStatus(event) {
|
|
217
|
-
const chosen = settableStatuses.find((status) => status === event.target.value);
|
|
218
|
-
if (chosen) this.status.set(chosen);
|
|
219
|
-
}
|
|
220
|
-
close() {
|
|
221
|
-
this.dialog.close(this.persisted);
|
|
222
|
-
}
|
|
223
|
-
async save() {
|
|
224
|
-
const request = this.request();
|
|
225
|
-
if (!request) return;
|
|
226
|
-
this.saving.set(true);
|
|
227
|
-
try {
|
|
228
|
-
const outcome = this.existing ? await this.gateway.update(this.data.calendarId, this.existing.id, request) : await this.gateway.book(this.data.calendarId, request);
|
|
229
|
-
const final = await this.applyStatus(outcome);
|
|
230
|
-
this.settle(final);
|
|
231
|
-
} catch {
|
|
232
|
-
this.problem.set({
|
|
233
|
-
kind: "message",
|
|
234
|
-
key: "weaver-apps-calendar.errors.save"
|
|
235
|
-
});
|
|
236
|
-
} finally {
|
|
237
|
-
this.saving.set(false);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
request() {
|
|
241
|
-
const startsAt = combine(this.date(), this.start());
|
|
242
|
-
const endsAt = combine(this.endDate(), this.end());
|
|
243
|
-
if (!this.title().trim()) {
|
|
244
|
-
this.problem.set({
|
|
245
|
-
kind: "message",
|
|
246
|
-
key: "weaver-apps-calendar.dialog.titleRequired"
|
|
247
|
-
});
|
|
248
|
-
return null;
|
|
249
|
-
}
|
|
250
|
-
if (!startsAt || !endsAt || endsAt <= startsAt) {
|
|
251
|
-
this.problem.set({
|
|
252
|
-
kind: "message",
|
|
253
|
-
key: "weaver-apps-calendar.dialog.periodInvalid"
|
|
254
|
-
});
|
|
255
|
-
return null;
|
|
256
|
-
}
|
|
257
|
-
return {
|
|
258
|
-
title: this.title().trim(),
|
|
259
|
-
start: startsAt.toISOString(),
|
|
260
|
-
end: endsAt.toISOString(),
|
|
261
|
-
description: this.optional(this.description()),
|
|
262
|
-
location: this.optional(this.location()),
|
|
263
|
-
contactName: this.optional(this.contactName()),
|
|
264
|
-
contactPhone: this.optional(this.contactPhone()),
|
|
265
|
-
contactEmail: this.optional(this.contactEmail())
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
|
-
async applyStatus(outcome) {
|
|
269
|
-
if (outcome.kind === "saved") {
|
|
270
|
-
this.existing = outcome.appointment;
|
|
271
|
-
this.persisted = true;
|
|
272
|
-
}
|
|
273
|
-
if (outcome.kind !== "saved" || outcome.appointment.status === this.status()) return outcome;
|
|
274
|
-
return this.gateway.setStatus(this.data.calendarId, outcome.appointment.id, this.status());
|
|
275
|
-
}
|
|
276
|
-
settle(outcome) {
|
|
277
|
-
switch (outcome.kind) {
|
|
278
|
-
case "saved":
|
|
279
|
-
this.dialog.close(true);
|
|
280
|
-
return;
|
|
281
|
-
case "conflict":
|
|
282
|
-
this.problem.set({
|
|
283
|
-
kind: "conflict",
|
|
284
|
-
conflicts: outcome.conflicts
|
|
285
|
-
});
|
|
286
|
-
return;
|
|
287
|
-
case "closed":
|
|
288
|
-
this.problem.set({
|
|
289
|
-
kind: "message",
|
|
290
|
-
key: "weaver-apps-calendar.dialog.closed"
|
|
291
|
-
});
|
|
292
|
-
return;
|
|
293
|
-
case "changed":
|
|
294
|
-
this.problem.set({
|
|
295
|
-
kind: "message",
|
|
296
|
-
key: "weaver-apps-calendar.dialog.changed"
|
|
297
|
-
});
|
|
298
|
-
return;
|
|
299
|
-
case "invalid":
|
|
300
|
-
this.problem.set({
|
|
301
|
-
kind: "message",
|
|
302
|
-
key: "weaver-apps-calendar.dialog.invalid"
|
|
303
|
-
});
|
|
304
|
-
return;
|
|
305
|
-
default: this.problem.set({
|
|
306
|
-
kind: "message",
|
|
307
|
-
key: "weaver-apps-calendar.dialog.missing"
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
optional(value) {
|
|
312
|
-
return value.trim() ? value.trim() : null;
|
|
313
|
-
}
|
|
314
|
-
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
315
|
-
minVersion: "12.0.0",
|
|
316
|
-
version: "22.2.3",
|
|
317
|
-
ngImport: i0,
|
|
318
|
-
type: AppointmentDialog,
|
|
319
|
-
deps: [],
|
|
320
|
-
target: i0.ɵɵFactoryTarget.Component
|
|
321
|
-
});
|
|
322
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
323
|
-
minVersion: "17.0.0",
|
|
324
|
-
version: "22.2.3",
|
|
325
|
-
type: AppointmentDialog,
|
|
326
|
-
isStandalone: true,
|
|
327
|
-
selector: "wa-appointment-dialog",
|
|
328
|
-
ngImport: i0,
|
|
329
|
-
template: "<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",
|
|
330
|
-
dependencies: [{
|
|
331
|
-
kind: "pipe",
|
|
332
|
-
type: TranslocoPipe,
|
|
333
|
-
name: "transloco"
|
|
334
|
-
}],
|
|
335
|
-
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
336
|
-
});
|
|
337
|
-
};
|
|
338
|
-
i0.ɵɵngDeclareClassMetadata({
|
|
339
|
-
minVersion: "12.0.0",
|
|
340
|
-
version: "22.2.3",
|
|
341
|
-
ngImport: i0,
|
|
342
|
-
type: AppointmentDialog,
|
|
343
|
-
decorators: [{
|
|
344
|
-
type: Component,
|
|
345
|
-
args: [{
|
|
346
|
-
selector: "wa-appointment-dialog",
|
|
347
|
-
imports: [TranslocoPipe],
|
|
348
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
349
|
-
template: "<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"
|
|
350
|
-
}]
|
|
351
|
-
}]
|
|
352
|
-
});
|
|
353
|
-
var AppointmentCell = class AppointmentCell {
|
|
354
|
-
params = null;
|
|
355
|
-
locale = signal("en", ...ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []);
|
|
356
|
-
kind = signal("title", ...ngDevMode ? [{ debugName: "kind" }] : /* istanbul ignore next */ []);
|
|
357
|
-
appointment = signal(null, ...ngDevMode ? [{ debugName: "appointment" }] : /* istanbul ignore next */ []);
|
|
358
|
-
cancelled = computed(() => this.appointment()?.status === "cancelled", ...ngDevMode ? [{ debugName: "cancelled" }] : /* istanbul ignore next */ []);
|
|
359
|
-
when = computed(() => {
|
|
360
|
-
const appointment = this.appointment();
|
|
361
|
-
if (!appointment) return {
|
|
362
|
-
day: "",
|
|
363
|
-
hours: ""
|
|
364
|
-
};
|
|
365
|
-
const day = new Intl.DateTimeFormat(this.locale(), {
|
|
366
|
-
weekday: "short",
|
|
367
|
-
day: "2-digit",
|
|
368
|
-
month: "2-digit",
|
|
369
|
-
year: "numeric"
|
|
370
|
-
});
|
|
371
|
-
const time = new Intl.DateTimeFormat(this.locale(), {
|
|
372
|
-
hour: "2-digit",
|
|
373
|
-
minute: "2-digit"
|
|
374
|
-
});
|
|
375
|
-
return {
|
|
376
|
-
day: day.format(new Date(appointment.start)),
|
|
377
|
-
hours: `${time.format(new Date(appointment.start))} – ${time.format(new Date(appointment.end))}`
|
|
378
|
-
};
|
|
379
|
-
}, ...ngDevMode ? [{ debugName: "when" }] : /* istanbul ignore next */ []);
|
|
380
|
-
agInit(params) {
|
|
381
|
-
this.params = params;
|
|
382
|
-
this.kind.set(params.kind);
|
|
383
|
-
this.appointment.set(params.data ?? null);
|
|
384
|
-
this.locale.set(params.locale());
|
|
385
|
-
}
|
|
386
|
-
refresh(params) {
|
|
387
|
-
this.agInit(params);
|
|
388
|
-
return true;
|
|
389
|
-
}
|
|
390
|
-
edit() {
|
|
391
|
-
this.hand(this.params?.edit);
|
|
392
|
-
}
|
|
393
|
-
cancel() {
|
|
394
|
-
this.hand(this.params?.cancel);
|
|
395
|
-
}
|
|
396
|
-
remove() {
|
|
397
|
-
this.hand(this.params?.remove);
|
|
398
|
-
}
|
|
399
|
-
hand(to) {
|
|
400
|
-
const appointment = this.appointment();
|
|
401
|
-
if (appointment) to?.(appointment);
|
|
402
|
-
}
|
|
403
|
-
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
404
|
-
minVersion: "12.0.0",
|
|
405
|
-
version: "22.2.3",
|
|
406
|
-
ngImport: i0,
|
|
407
|
-
type: AppointmentCell,
|
|
408
|
-
deps: [],
|
|
409
|
-
target: i0.ɵɵFactoryTarget.Component
|
|
410
|
-
});
|
|
411
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
412
|
-
minVersion: "17.0.0",
|
|
413
|
-
version: "22.2.3",
|
|
414
|
-
type: AppointmentCell,
|
|
415
|
-
isStandalone: true,
|
|
416
|
-
selector: "wa-appointment-cell",
|
|
417
|
-
ngImport: i0,
|
|
418
|
-
template: "@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 <span class=\"flex justify-end\">\n <button type=\"button\" class=\"relative lw-btn lw-btn--ghost lw-btn--sm lw-btn--icon\" [attr.aria-label]=\"'weaver-apps-calendar.actions.edit' | transloco\" (click)=\"edit()\">\n <lw-icon name=\"edit\" size=\"1rem\"></lw-icon>\n </button>\n @if (!cancelled()) {\n <button type=\"button\" class=\"relative lw-btn lw-btn--ghost lw-btn--sm lw-btn--icon\" [attr.aria-label]=\"'weaver-apps-calendar.actions.cancel' | transloco\" (click)=\"cancel()\">\n <lw-icon name=\"weaver-apps-calendar.cancel\" size=\"1rem\"></lw-icon>\n </button>\n }\n <button type=\"button\" class=\"relative lw-btn lw-btn--ghost lw-btn--sm lw-btn--icon\" [attr.aria-label]=\"'weaver-apps-calendar.actions.delete' | transloco\" (click)=\"remove()\">\n <lw-icon name=\"trash\" size=\"1rem\"></lw-icon>\n </button>\n </span>\n }\n }\n}\n",
|
|
419
|
-
dependencies: [{
|
|
420
|
-
kind: "pipe",
|
|
421
|
-
type: TranslocoPipe,
|
|
422
|
-
name: "transloco"
|
|
423
|
-
}],
|
|
424
|
-
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
425
|
-
});
|
|
426
|
-
};
|
|
427
|
-
i0.ɵɵngDeclareClassMetadata({
|
|
428
|
-
minVersion: "12.0.0",
|
|
429
|
-
version: "22.2.3",
|
|
430
|
-
ngImport: i0,
|
|
431
|
-
type: AppointmentCell,
|
|
432
|
-
decorators: [{
|
|
433
|
-
type: Component,
|
|
434
|
-
args: [{
|
|
435
|
-
selector: "wa-appointment-cell",
|
|
436
|
-
imports: [TranslocoPipe],
|
|
437
|
-
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
438
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
439
|
-
template: "@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 <span class=\"flex justify-end\">\n <button type=\"button\" class=\"relative lw-btn lw-btn--ghost lw-btn--sm lw-btn--icon\" [attr.aria-label]=\"'weaver-apps-calendar.actions.edit' | transloco\" (click)=\"edit()\">\n <lw-icon name=\"edit\" size=\"1rem\"></lw-icon>\n </button>\n @if (!cancelled()) {\n <button type=\"button\" class=\"relative lw-btn lw-btn--ghost lw-btn--sm lw-btn--icon\" [attr.aria-label]=\"'weaver-apps-calendar.actions.cancel' | transloco\" (click)=\"cancel()\">\n <lw-icon name=\"weaver-apps-calendar.cancel\" size=\"1rem\"></lw-icon>\n </button>\n }\n <button type=\"button\" class=\"relative lw-btn lw-btn--ghost lw-btn--sm lw-btn--icon\" [attr.aria-label]=\"'weaver-apps-calendar.actions.delete' | transloco\" (click)=\"remove()\">\n <lw-icon name=\"trash\" size=\"1rem\"></lw-icon>\n </button>\n </span>\n }\n }\n}\n"
|
|
440
|
-
}]
|
|
441
|
-
}]
|
|
442
|
-
});
|
|
443
|
-
const appointmentColumn = {
|
|
444
|
-
when: "start",
|
|
445
|
-
title: "title",
|
|
446
|
-
contact: "contact",
|
|
447
|
-
location: "location",
|
|
448
|
-
status: "status",
|
|
449
|
-
actions: "actions"
|
|
450
|
-
};
|
|
451
|
-
const actionsWidthPx = 136;
|
|
452
|
-
const whenMinWidthPx = 230;
|
|
453
|
-
const textMinWidthPx = 110;
|
|
454
|
-
const locationMinWidthPx = 90;
|
|
455
|
-
const statusMinWidthPx = 112;
|
|
456
|
-
function byStart(left, right) {
|
|
457
|
-
return Date.parse(left ?? "") - Date.parse(right ?? "");
|
|
458
|
-
}
|
|
459
|
-
function statusOf(appointment) {
|
|
460
|
-
return appointment.status;
|
|
461
|
-
}
|
|
462
|
-
var AppointmentTable = class AppointmentTable {
|
|
463
|
-
table = translateObjectSignal("weaver-apps-calendar.table");
|
|
464
|
-
statuses = translateObjectSignal("weaver-apps-calendar.status");
|
|
465
|
-
api = signal(null, ...ngDevMode ? [{ debugName: "api" }] : /* istanbul ignore next */ []);
|
|
466
|
-
appointments = input.required(...ngDevMode ? [{ debugName: "appointments" }] : /* istanbul ignore next */ []);
|
|
467
|
-
locale = input.required(...ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []);
|
|
468
|
-
editAppointment = output();
|
|
469
|
-
cancelAppointment = output();
|
|
470
|
-
deleteAppointment = output();
|
|
471
|
-
translated = computed(() => typeof this.table() === "object" && typeof this.table()["title"] === "string", ...ngDevMode ? [{ debugName: "translated" }] : /* istanbul ignore next */ []);
|
|
472
|
-
empty = computed(() => ({ noRowsToShow: this.table()["empty"] ?? "" }), ...ngDevMode ? [{ debugName: "empty" }] : /* istanbul ignore next */ []);
|
|
473
|
-
options = computed(() => ({
|
|
474
|
-
rowModelType: "clientSide",
|
|
475
|
-
columnDefs: this.columns(this.table()),
|
|
476
|
-
defaultColDef: {
|
|
477
|
-
sortable: false,
|
|
478
|
-
resizable: true,
|
|
479
|
-
suppressHeaderMenuButton: true
|
|
480
|
-
},
|
|
481
|
-
getRowId: (params) => params.data.id,
|
|
482
|
-
initialState: { sort: { sortModel: [{
|
|
483
|
-
colId: appointmentColumn.when,
|
|
484
|
-
sort: "asc"
|
|
485
|
-
}] } },
|
|
486
|
-
rowClassRules: { "text-content-faint": (params) => params.data?.status === AppointmentStatus.cancelled }
|
|
487
|
-
}), ...ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []);
|
|
488
|
-
constructor() {
|
|
489
|
-
effect(() => {
|
|
490
|
-
const api = this.api();
|
|
491
|
-
const appointments = this.appointments();
|
|
492
|
-
if (api && !api.isDestroyed()) api.setGridOption("rowData", [...appointments]);
|
|
493
|
-
});
|
|
494
|
-
}
|
|
495
|
-
ready(api) {
|
|
496
|
-
this.api.set(api);
|
|
497
|
-
}
|
|
498
|
-
columns(table) {
|
|
499
|
-
return [
|
|
500
|
-
{
|
|
501
|
-
...this.cell(appointmentColumn.when, "when", table["when"]),
|
|
502
|
-
field: "start",
|
|
503
|
-
sortable: true,
|
|
504
|
-
comparator: byStart,
|
|
505
|
-
flex: 2,
|
|
506
|
-
minWidth: whenMinWidthPx
|
|
507
|
-
},
|
|
508
|
-
{
|
|
509
|
-
...this.cell(appointmentColumn.title, "title", table["title"]),
|
|
510
|
-
field: "title",
|
|
511
|
-
sortable: true,
|
|
512
|
-
flex: 2,
|
|
513
|
-
minWidth: textMinWidthPx
|
|
514
|
-
},
|
|
515
|
-
{
|
|
516
|
-
...this.cell(appointmentColumn.contact, "contact", table["contact"]),
|
|
517
|
-
valueGetter: (params) => params.data?.contactName ?? "",
|
|
518
|
-
sortable: true,
|
|
519
|
-
flex: 2,
|
|
520
|
-
minWidth: textMinWidthPx
|
|
521
|
-
},
|
|
522
|
-
{
|
|
523
|
-
...this.cell(appointmentColumn.location, "location", table["location"]),
|
|
524
|
-
field: "location",
|
|
525
|
-
sortable: true,
|
|
526
|
-
flex: 1,
|
|
527
|
-
minWidth: locationMinWidthPx
|
|
528
|
-
},
|
|
529
|
-
{
|
|
530
|
-
...this.cell(appointmentColumn.status, "status", table["status"]),
|
|
531
|
-
field: "status",
|
|
532
|
-
sortable: true,
|
|
533
|
-
flex: 1,
|
|
534
|
-
minWidth: statusMinWidthPx,
|
|
535
|
-
filter: ListFilter,
|
|
536
|
-
filterParams: this.statusChoices()
|
|
537
|
-
},
|
|
538
|
-
{
|
|
539
|
-
...this.cell(appointmentColumn.actions, "actions", ""),
|
|
540
|
-
width: actionsWidthPx,
|
|
541
|
-
resizable: false
|
|
542
|
-
}
|
|
543
|
-
];
|
|
544
|
-
}
|
|
545
|
-
cell(colId, kind, headerName) {
|
|
546
|
-
return {
|
|
547
|
-
colId,
|
|
548
|
-
headerName: headerName ?? "",
|
|
549
|
-
cellRenderer: AppointmentCell,
|
|
550
|
-
cellRendererParams: {
|
|
551
|
-
kind,
|
|
552
|
-
locale: () => this.locale(),
|
|
553
|
-
edit: (appointment) => this.editAppointment.emit(appointment),
|
|
554
|
-
cancel: (appointment) => this.cancelAppointment.emit(appointment),
|
|
555
|
-
remove: (appointment) => this.deleteAppointment.emit(appointment)
|
|
556
|
-
}
|
|
557
|
-
};
|
|
558
|
-
}
|
|
559
|
-
statusChoices() {
|
|
560
|
-
const values = Object.values(AppointmentStatus);
|
|
561
|
-
return {
|
|
562
|
-
options: () => values.map((value) => ({
|
|
563
|
-
value,
|
|
564
|
-
label: this.statuses()[value] ?? value
|
|
565
|
-
})),
|
|
566
|
-
rowValue: statusOf
|
|
567
|
-
};
|
|
568
|
-
}
|
|
569
|
-
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
570
|
-
minVersion: "12.0.0",
|
|
571
|
-
version: "22.2.3",
|
|
572
|
-
ngImport: i0,
|
|
573
|
-
type: AppointmentTable,
|
|
574
|
-
deps: [],
|
|
575
|
-
target: i0.ɵɵFactoryTarget.Component
|
|
576
|
-
});
|
|
577
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
578
|
-
minVersion: "17.0.0",
|
|
579
|
-
version: "22.2.3",
|
|
580
|
-
type: AppointmentTable,
|
|
581
|
-
isStandalone: true,
|
|
582
|
-
selector: "wa-appointment-table",
|
|
583
|
-
inputs: {
|
|
584
|
-
appointments: {
|
|
585
|
-
classPropertyName: "appointments",
|
|
586
|
-
publicName: "appointments",
|
|
587
|
-
isSignal: true,
|
|
588
|
-
isRequired: true,
|
|
589
|
-
transformFunction: null
|
|
590
|
-
},
|
|
591
|
-
locale: {
|
|
592
|
-
classPropertyName: "locale",
|
|
593
|
-
publicName: "locale",
|
|
594
|
-
isSignal: true,
|
|
595
|
-
isRequired: true,
|
|
596
|
-
transformFunction: null
|
|
597
|
-
}
|
|
598
|
-
},
|
|
599
|
-
outputs: {
|
|
600
|
-
editAppointment: "editAppointment",
|
|
601
|
-
cancelAppointment: "cancelAppointment",
|
|
602
|
-
deleteAppointment: "deleteAppointment"
|
|
603
|
-
},
|
|
604
|
-
host: { classAttribute: "block h-full w-full" },
|
|
605
|
-
ngImport: i0,
|
|
606
|
-
template: "@if (translated()) {\n <wa-data-grid [options]=\"options()\" [localeOverrides]=\"empty()\" (ready)=\"ready($event)\" />\n}\n",
|
|
607
|
-
dependencies: [{
|
|
608
|
-
kind: "component",
|
|
609
|
-
type: DataGrid,
|
|
610
|
-
selector: "wa-data-grid",
|
|
611
|
-
inputs: ["options", "localeOverrides"],
|
|
612
|
-
outputs: ["ready"]
|
|
613
|
-
}],
|
|
614
|
-
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
615
|
-
});
|
|
616
|
-
};
|
|
617
|
-
i0.ɵɵngDeclareClassMetadata({
|
|
618
|
-
minVersion: "12.0.0",
|
|
619
|
-
version: "22.2.3",
|
|
620
|
-
ngImport: i0,
|
|
621
|
-
type: AppointmentTable,
|
|
622
|
-
decorators: [{
|
|
623
|
-
type: Component,
|
|
624
|
-
args: [{
|
|
625
|
-
selector: "wa-appointment-table",
|
|
626
|
-
imports: [DataGrid],
|
|
627
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
628
|
-
host: { class: "block h-full w-full" },
|
|
629
|
-
template: "@if (translated()) {\n <wa-data-grid [options]=\"options()\" [localeOverrides]=\"empty()\" (ready)=\"ready($event)\" />\n}\n"
|
|
630
|
-
}]
|
|
631
|
-
}],
|
|
632
|
-
ctorParameters: () => [],
|
|
633
|
-
propDecorators: {
|
|
634
|
-
appointments: [{
|
|
635
|
-
type: i0.Input,
|
|
636
|
-
args: [{
|
|
637
|
-
isSignal: true,
|
|
638
|
-
alias: "appointments",
|
|
639
|
-
required: true
|
|
640
|
-
}]
|
|
641
|
-
}],
|
|
642
|
-
locale: [{
|
|
643
|
-
type: i0.Input,
|
|
644
|
-
args: [{
|
|
645
|
-
isSignal: true,
|
|
646
|
-
alias: "locale",
|
|
647
|
-
required: true
|
|
648
|
-
}]
|
|
649
|
-
}],
|
|
650
|
-
editAppointment: [{
|
|
651
|
-
type: i0.Output,
|
|
652
|
-
args: ["editAppointment"]
|
|
653
|
-
}],
|
|
654
|
-
cancelAppointment: [{
|
|
655
|
-
type: i0.Output,
|
|
656
|
-
args: ["cancelAppointment"]
|
|
657
|
-
}],
|
|
658
|
-
deleteAppointment: [{
|
|
659
|
-
type: i0.Output,
|
|
660
|
-
args: ["deleteAppointment"]
|
|
661
|
-
}]
|
|
662
|
-
}
|
|
663
|
-
});
|
|
664
|
-
const searchDelayMs = 300;
|
|
665
|
-
var CalendarPage = class CalendarPage {
|
|
666
|
-
gateway = inject(CALENDAR_GATEWAY);
|
|
667
|
-
route = inject(ActivatedRoute);
|
|
668
|
-
searchTimer;
|
|
669
|
-
locale = activeLocale();
|
|
670
|
-
calendarId = toSignal(this.route.paramMap.pipe(map((params) => params.get("calendarId") ?? "")), { initialValue: this.route.snapshot.paramMap.get("calendarId") ?? "" });
|
|
671
|
-
weekStart = signal(startOfWeek(/* @__PURE__ */ new Date()), ...ngDevMode ? [{ debugName: "weekStart" }] : /* istanbul ignore next */ []);
|
|
672
|
-
contact = signal("", ...ngDevMode ? [{ debugName: "contact" }] : /* istanbul ignore next */ []);
|
|
673
|
-
calendar = resource({
|
|
674
|
-
...ngDevMode ? { debugName: "calendar" } : /* istanbul ignore next */ {},
|
|
675
|
-
params: () => this.calendarId(),
|
|
676
|
-
loader: ({ params }) => this.gateway.calendar(params)
|
|
677
|
-
});
|
|
678
|
-
appointments = resource({
|
|
679
|
-
...ngDevMode ? { debugName: "appointments" } : /* istanbul ignore next */ {},
|
|
680
|
-
params: () => ({
|
|
681
|
-
calendarId: this.calendarId(),
|
|
682
|
-
range: weekRange(this.weekStart()),
|
|
683
|
-
contact: this.contact().trim()
|
|
684
|
-
}),
|
|
685
|
-
loader: ({ params, abortSignal }) => this.gateway.appointments(params.calendarId, params.range, params.contact || void 0, abortSignal)
|
|
686
|
-
});
|
|
687
|
-
constructor() {
|
|
688
|
-
inject(DestroyRef).onDestroy(() => clearTimeout(this.searchTimer));
|
|
689
|
-
}
|
|
690
|
-
weekLabel = computed(() => {
|
|
691
|
-
const range = weekRange(this.weekStart());
|
|
692
|
-
const last = addWeeks(range.until, 0);
|
|
693
|
-
last.setDate(last.getDate() - 1);
|
|
694
|
-
const format = new Intl.DateTimeFormat(this.locale(), {
|
|
695
|
-
day: "2-digit",
|
|
696
|
-
month: "2-digit",
|
|
697
|
-
year: "numeric"
|
|
698
|
-
});
|
|
699
|
-
return `${format.format(range.from)} – ${format.format(last)}`;
|
|
700
|
-
}, ...ngDevMode ? [{ debugName: "weekLabel" }] : /* istanbul ignore next */ []);
|
|
701
|
-
previousWeek() {
|
|
702
|
-
this.weekStart.update((start) => addWeeks(start, -1));
|
|
703
|
-
}
|
|
704
|
-
nextWeek() {
|
|
705
|
-
this.weekStart.update((start) => addWeeks(start, 1));
|
|
706
|
-
}
|
|
707
|
-
thisWeek() {
|
|
708
|
-
this.weekStart.set(startOfWeek(/* @__PURE__ */ new Date()));
|
|
709
|
-
}
|
|
710
|
-
search(event) {
|
|
711
|
-
const value = event.target.value;
|
|
712
|
-
clearTimeout(this.searchTimer);
|
|
713
|
-
this.searchTimer = setTimeout(() => this.contact.set(value), searchDelayMs);
|
|
714
|
-
}
|
|
715
|
-
add() {
|
|
716
|
-
const today = /* @__PURE__ */ new Date();
|
|
717
|
-
const shown = weekRange(this.weekStart());
|
|
718
|
-
const day = today >= shown.from && today < shown.until ? today : this.weekStart();
|
|
719
|
-
this.openDialog({
|
|
720
|
-
calendarId: this.calendarId(),
|
|
721
|
-
appointment: null,
|
|
722
|
-
day
|
|
723
|
-
}, "weaver-apps-calendar.dialog.addTitle");
|
|
724
|
-
}
|
|
725
|
-
edit(appointment) {
|
|
726
|
-
this.openDialog({
|
|
727
|
-
calendarId: this.calendarId(),
|
|
728
|
-
appointment,
|
|
729
|
-
day: new Date(appointment.start)
|
|
730
|
-
}, "weaver-apps-calendar.dialog.editTitle");
|
|
731
|
-
}
|
|
732
|
-
async cancel(appointment) {
|
|
733
|
-
const reason = await calendarHost.ui.prompt({
|
|
734
|
-
title: "weaver-apps-calendar.cancel.title",
|
|
735
|
-
message: "weaver-apps-calendar.cancel.message",
|
|
736
|
-
confirmLabel: "weaver-apps-calendar.cancel.confirm",
|
|
737
|
-
tone: "warning"
|
|
738
|
-
});
|
|
739
|
-
if (reason === null) return;
|
|
740
|
-
await this.attempt(async () => {
|
|
741
|
-
const outcome = await this.gateway.cancel(this.calendarId(), appointment.id, reason.trim() || null);
|
|
742
|
-
this.report(outcome.kind === "saved" ? "weaver-apps-calendar.cancel.done" : "weaver-apps-calendar.errors.save", outcome.kind === "saved");
|
|
743
|
-
});
|
|
744
|
-
}
|
|
745
|
-
async remove(appointment) {
|
|
746
|
-
if (!await calendarHost.ui.confirm({
|
|
747
|
-
title: "weaver-apps-calendar.delete.title",
|
|
748
|
-
message: "weaver-apps-calendar.delete.message",
|
|
749
|
-
confirmLabel: "weaver-apps-calendar.delete.confirm",
|
|
750
|
-
tone: "danger"
|
|
751
|
-
})) return;
|
|
752
|
-
await this.attempt(async () => {
|
|
753
|
-
await this.gateway.remove(this.calendarId(), appointment.id);
|
|
754
|
-
this.report("weaver-apps-calendar.delete.done", true);
|
|
755
|
-
});
|
|
756
|
-
}
|
|
757
|
-
async attempt(work) {
|
|
758
|
-
try {
|
|
759
|
-
await work();
|
|
760
|
-
} catch {
|
|
761
|
-
this.report("weaver-apps-calendar.errors.save", false);
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
openDialog(data, title) {
|
|
765
|
-
calendarHost.ui.open(AppointmentDialog, {
|
|
766
|
-
data,
|
|
767
|
-
title,
|
|
768
|
-
size: "lg",
|
|
769
|
-
dismiss: "explicit"
|
|
770
|
-
}).closed.then((saved) => {
|
|
771
|
-
if (saved) this.report("weaver-apps-calendar.dialog.saved", true);
|
|
772
|
-
});
|
|
773
|
-
}
|
|
774
|
-
report(message, success) {
|
|
775
|
-
calendarHost.ui.toast({
|
|
776
|
-
message,
|
|
777
|
-
kind: success ? "success" : "error"
|
|
778
|
-
});
|
|
779
|
-
this.appointments.reload();
|
|
780
|
-
}
|
|
781
|
-
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
782
|
-
minVersion: "12.0.0",
|
|
783
|
-
version: "22.2.3",
|
|
784
|
-
ngImport: i0,
|
|
785
|
-
type: CalendarPage,
|
|
786
|
-
deps: [],
|
|
787
|
-
target: i0.ɵɵFactoryTarget.Component
|
|
788
|
-
});
|
|
789
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
790
|
-
minVersion: "17.0.0",
|
|
791
|
-
version: "22.2.3",
|
|
792
|
-
type: CalendarPage,
|
|
793
|
-
isStandalone: true,
|
|
794
|
-
selector: "wa-calendar-page",
|
|
795
|
-
ngImport: i0,
|
|
796
|
-
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\">{{ 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 (cancelAppointment)=\"cancel($event)\"\n (deleteAppointment)=\"remove($event)\"\n />\n </div>\n }\n</div>\n",
|
|
797
|
-
dependencies: [{
|
|
798
|
-
kind: "component",
|
|
799
|
-
type: AppointmentTable,
|
|
800
|
-
selector: "wa-appointment-table",
|
|
801
|
-
inputs: ["appointments", "locale"],
|
|
802
|
-
outputs: [
|
|
803
|
-
"editAppointment",
|
|
804
|
-
"cancelAppointment",
|
|
805
|
-
"deleteAppointment"
|
|
806
|
-
]
|
|
807
|
-
}, {
|
|
808
|
-
kind: "pipe",
|
|
809
|
-
type: TranslocoPipe,
|
|
810
|
-
name: "transloco"
|
|
811
|
-
}],
|
|
812
|
-
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
813
|
-
});
|
|
814
|
-
};
|
|
815
|
-
i0.ɵɵngDeclareClassMetadata({
|
|
816
|
-
minVersion: "12.0.0",
|
|
817
|
-
version: "22.2.3",
|
|
818
|
-
ngImport: i0,
|
|
819
|
-
type: CalendarPage,
|
|
820
|
-
decorators: [{
|
|
821
|
-
type: Component,
|
|
822
|
-
args: [{
|
|
823
|
-
selector: "wa-calendar-page",
|
|
824
|
-
imports: [TranslocoPipe, AppointmentTable],
|
|
825
|
-
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
826
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
827
|
-
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\">{{ 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 (cancelAppointment)=\"cancel($event)\"\n (deleteAppointment)=\"remove($event)\"\n />\n </div>\n }\n</div>\n"
|
|
828
|
-
}]
|
|
829
|
-
}],
|
|
830
|
-
ctorParameters: () => []
|
|
831
|
-
});
|
|
1
|
+
import { i as calendarHost, n as CalendarGatewayError, r as provideCalendarGateway, t as CALENDAR_GATEWAY } from "./weaver-apps-calendar-calendar-gateway-DUo797bn.mjs";
|
|
2
|
+
import { a as calendarPluginId, i as calendarIconNames, n as calendarPath, r as calendarContributionIds, t as calendarListPath } from "./weaver-apps-calendar-calendar-paths-qzIR-lDU.mjs";
|
|
832
3
|
const stroke = "fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"";
|
|
833
4
|
const calendarIcons = {
|
|
834
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>`,
|
|
@@ -855,14 +26,14 @@ function createCalendarPlugin(options = {}) {
|
|
|
855
26
|
title: "weaver-apps-calendar.calendars.title",
|
|
856
27
|
icon: calendarIconNames.calendar,
|
|
857
28
|
routable: { path: calendarListPath },
|
|
858
|
-
|
|
29
|
+
loadComponent: () => import("./weaver-apps-calendar-calendar-list-page-dgF-nnQF.mjs").then((module) => module.CalendarListPage)
|
|
859
30
|
});
|
|
860
31
|
ctx.registerSurface({
|
|
861
32
|
id: calendarContributionIds.calendar,
|
|
862
33
|
title: "weaver-apps-calendar.title",
|
|
863
34
|
icon: calendarIconNames.calendar,
|
|
864
35
|
routable: { path: `${calendarListPath}/:calendarId` },
|
|
865
|
-
|
|
36
|
+
loadComponent: () => import("./weaver-apps-calendar-calendar-page-DpdU_Vfy.mjs").then((module) => module.CalendarPage)
|
|
866
37
|
});
|
|
867
38
|
if (options.railItem) ctx.registerRailItem({
|
|
868
39
|
id: calendarContributionIds.rail,
|