@sneat/extension-eventus-shared 0.0.1
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/sneat-extension-eventus-shared-bring-along-page.component-DHi-E8P1.mjs +153 -0
- package/fesm2022/sneat-extension-eventus-shared-bring-along-page.component-DHi-E8P1.mjs.map +1 -0
- package/fesm2022/sneat-extension-eventus-shared-create-event-page.component-Da39fu36.mjs +90 -0
- package/fesm2022/sneat-extension-eventus-shared-create-event-page.component-Da39fu36.mjs.map +1 -0
- package/fesm2022/sneat-extension-eventus-shared-edit-event-page.component-lhOpcqld.mjs +103 -0
- package/fesm2022/sneat-extension-eventus-shared-edit-event-page.component-lhOpcqld.mjs.map +1 -0
- package/fesm2022/sneat-extension-eventus-shared-event-page.component-CuOA0EU9.mjs +143 -0
- package/fesm2022/sneat-extension-eventus-shared-event-page.component-CuOA0EU9.mjs.map +1 -0
- package/fesm2022/sneat-extension-eventus-shared-events-list-page.component-DELSoZ2W.mjs +72 -0
- package/fesm2022/sneat-extension-eventus-shared-events-list-page.component-DELSoZ2W.mjs.map +1 -0
- package/fesm2022/sneat-extension-eventus-shared-invitees-page.component-DGG1LDd7.mjs +94 -0
- package/fesm2022/sneat-extension-eventus-shared-invitees-page.component-DGG1LDd7.mjs.map +1 -0
- package/fesm2022/sneat-extension-eventus-shared-responses-page.component-L9ayYgBN.mjs +78 -0
- package/fesm2022/sneat-extension-eventus-shared-responses-page.component-L9ayYgBN.mjs.map +1 -0
- package/fesm2022/sneat-extension-eventus-shared-share-links-page.component-BzZ6tFBc.mjs +92 -0
- package/fesm2022/sneat-extension-eventus-shared-share-links-page.component-BzZ6tFBc.mjs.map +1 -0
- package/fesm2022/sneat-extension-eventus-shared.mjs +270 -0
- package/fesm2022/sneat-extension-eventus-shared.mjs.map +1 -0
- package/package.json +43 -0
- package/types/sneat-extension-eventus-shared.d.ts +60 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, input, signal, computed, Component } from '@angular/core';
|
|
3
|
+
import * as i1 from '@angular/forms';
|
|
4
|
+
import { FormsModule } from '@angular/forms';
|
|
5
|
+
import { IonHeader, IonToolbar, IonTitle, IonButtons, IonBackButton, IonButton, IonContent, IonList, IonListHeader, IonItem, IonLabel, IonInput, IonNote, IonText, IonSpinner } from '@ionic/angular/standalone';
|
|
6
|
+
import { BRING_ALONG_SERVICE, EVENTUS_CURRENT_CLAIMANT, extractErrorMessage } from '@sneat/extension-eventus-contract';
|
|
7
|
+
|
|
8
|
+
// Bring-along screen for an event: the host defines slots (label + optional
|
|
9
|
+
// note); each slot shows as OPEN (with Claim) or CLAIMED ("{label} — {claimant}",
|
|
10
|
+
// with Release when the current claimant owns it). A 409 on claim shows a
|
|
11
|
+
// friendly message and refreshes the list.
|
|
12
|
+
// (AC: host-defines-slots, claim-prevents-duplicates)
|
|
13
|
+
class BringAlongPageComponent {
|
|
14
|
+
bringAlongService = inject(BRING_ALONG_SERVICE);
|
|
15
|
+
claimant = inject(EVENTUS_CURRENT_CLAIMANT);
|
|
16
|
+
spaceID = input.required(...(ngDevMode ? [{ debugName: "spaceID" }] : /* istanbul ignore next */ []));
|
|
17
|
+
eventID = input.required(...(ngDevMode ? [{ debugName: "eventID" }] : /* istanbul ignore next */ []));
|
|
18
|
+
slots = signal([], ...(ngDevMode ? [{ debugName: "slots" }] : /* istanbul ignore next */ []));
|
|
19
|
+
loading = signal(true, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
20
|
+
submitting = signal(false, ...(ngDevMode ? [{ debugName: "submitting" }] : /* istanbul ignore next */ []));
|
|
21
|
+
error = signal(undefined, ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
|
|
22
|
+
newLabel = '';
|
|
23
|
+
newNote = '';
|
|
24
|
+
/** The identity used for claim/release, shown in the header for clarity. */
|
|
25
|
+
claimantLabel = computed(() => this.claimant.label, ...(ngDevMode ? [{ debugName: "claimantLabel" }] : /* istanbul ignore next */ []));
|
|
26
|
+
ngOnInit() {
|
|
27
|
+
this.loadSlots();
|
|
28
|
+
}
|
|
29
|
+
loadSlots() {
|
|
30
|
+
this.loading.set(true);
|
|
31
|
+
this.bringAlongService.listSlots(this.spaceID(), this.eventID()).subscribe({
|
|
32
|
+
next: (slots) => {
|
|
33
|
+
this.slots.set(slots);
|
|
34
|
+
this.loading.set(false);
|
|
35
|
+
},
|
|
36
|
+
error: (err) => {
|
|
37
|
+
this.loading.set(false);
|
|
38
|
+
this.error.set(extractErrorMessage(err, 'Failed to load slots.'));
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/** Whether the current claimant owns this slot (so they may release it). */
|
|
43
|
+
claimedByMe(slot) {
|
|
44
|
+
return slot.claimedBy?.ref === this.claimant.ref;
|
|
45
|
+
}
|
|
46
|
+
/** Host defines a new slot. (AC: host-defines-slots) */
|
|
47
|
+
addSlot() {
|
|
48
|
+
const label = this.newLabel.trim();
|
|
49
|
+
if (!label || this.submitting()) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const note = this.newNote.trim();
|
|
53
|
+
this.submitting.set(true);
|
|
54
|
+
this.error.set(undefined);
|
|
55
|
+
this.bringAlongService
|
|
56
|
+
.defineSlot(this.spaceID(), this.eventID(), {
|
|
57
|
+
label,
|
|
58
|
+
...(note ? { note } : {}),
|
|
59
|
+
})
|
|
60
|
+
.subscribe({
|
|
61
|
+
next: (slot) => {
|
|
62
|
+
this.slots.update((list) => [...list, slot]);
|
|
63
|
+
this.newLabel = '';
|
|
64
|
+
this.newNote = '';
|
|
65
|
+
this.submitting.set(false);
|
|
66
|
+
},
|
|
67
|
+
error: (err) => {
|
|
68
|
+
this.submitting.set(false);
|
|
69
|
+
this.error.set(extractErrorMessage(err, 'Failed to add slot.'));
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/** Claim an open slot. On 409 show a friendly message and refresh. */
|
|
74
|
+
claim(slot) {
|
|
75
|
+
if (this.submitting()) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
this.submitting.set(true);
|
|
79
|
+
this.error.set(undefined);
|
|
80
|
+
this.bringAlongService
|
|
81
|
+
.claimSlot(this.spaceID(), this.eventID(), slot.id, {
|
|
82
|
+
ref: this.claimant.ref,
|
|
83
|
+
label: this.claimant.label,
|
|
84
|
+
})
|
|
85
|
+
.subscribe({
|
|
86
|
+
next: (updated) => {
|
|
87
|
+
this.replaceSlot(updated);
|
|
88
|
+
this.submitting.set(false);
|
|
89
|
+
},
|
|
90
|
+
error: (err) => {
|
|
91
|
+
this.submitting.set(false);
|
|
92
|
+
if (err?.status === 409) {
|
|
93
|
+
this.error.set('Already claimed by someone else.');
|
|
94
|
+
this.loadSlots();
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
this.error.set(extractErrorMessage(err, 'Failed to claim slot.'));
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
/** Release a slot the current claimant owns, returning it to open. */
|
|
103
|
+
release(slot) {
|
|
104
|
+
if (this.submitting()) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
this.submitting.set(true);
|
|
108
|
+
this.error.set(undefined);
|
|
109
|
+
this.bringAlongService
|
|
110
|
+
.releaseSlot(this.spaceID(), this.eventID(), slot.id, {
|
|
111
|
+
ref: this.claimant.ref,
|
|
112
|
+
})
|
|
113
|
+
.subscribe({
|
|
114
|
+
next: (updated) => {
|
|
115
|
+
this.replaceSlot(updated);
|
|
116
|
+
this.submitting.set(false);
|
|
117
|
+
},
|
|
118
|
+
error: (err) => {
|
|
119
|
+
this.submitting.set(false);
|
|
120
|
+
this.error.set(extractErrorMessage(err, 'Failed to release slot.'));
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
replaceSlot(updated) {
|
|
125
|
+
this.slots.update((list) => list.map((s) => (s.id === updated.id ? updated : s)));
|
|
126
|
+
}
|
|
127
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: BringAlongPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
128
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: BringAlongPageComponent, isStandalone: true, selector: "eventus-bring-along-page", inputs: { spaceID: { classPropertyName: "spaceID", publicName: "spaceID", isSignal: true, isRequired: true, transformFunction: null }, eventID: { classPropertyName: "eventID", publicName: "eventID", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"start\">\n <ion-back-button defaultHref=\"/\"></ion-back-button>\n </ion-buttons>\n <ion-title>Bring along</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n @if (error()) {\n <ion-text color=\"danger\">{{ error() }}</ion-text>\n }\n\n <ion-list>\n <ion-list-header>Add a slot</ion-list-header>\n <ion-item>\n <ion-input\n label=\"What's needed\"\n labelPlacement=\"floating\"\n placeholder=\"e.g. Drinks\"\n [(ngModel)]=\"newLabel\"\n ></ion-input>\n </ion-item>\n <ion-item>\n <ion-input\n label=\"Note (optional)\"\n labelPlacement=\"floating\"\n placeholder=\"e.g. 2 bottles\"\n [(ngModel)]=\"newNote\"\n ></ion-input>\n </ion-item>\n <ion-button\n expand=\"block\"\n class=\"ion-margin-top\"\n [disabled]=\"submitting() || !newLabel.trim()\"\n (click)=\"addSlot()\"\n >\n Add slot\n </ion-button>\n </ion-list>\n\n <ion-list>\n <ion-list-header>Slots</ion-list-header>\n @if (loading()) {\n <ion-item>\n <ion-spinner aria-label=\"Loading slots\"></ion-spinner>\n </ion-item>\n } @else {\n @for (slot of slots(); track slot.id) {\n <ion-item>\n <ion-label class=\"ion-text-wrap\">\n @if (slot.claimedBy; as claimant) {\n <h3>{{ slot.label }} \u2014 {{ claimant.label }}</h3>\n } @else {\n <h3>{{ slot.label }}</h3>\n <ion-note color=\"success\">Open</ion-note>\n }\n @if (slot.note) {\n <p>{{ slot.note }}</p>\n }\n </ion-label>\n @if (!slot.claimedBy) {\n <ion-button\n slot=\"end\"\n [disabled]=\"submitting()\"\n (click)=\"claim(slot)\"\n >\n Claim\n </ion-button>\n } @else if (claimedByMe(slot)) {\n <ion-button\n slot=\"end\"\n fill=\"outline\"\n [disabled]=\"submitting()\"\n (click)=\"release(slot)\"\n >\n Release\n </ion-button>\n }\n </ion-item>\n } @empty {\n <ion-item>\n <ion-note>No slots yet.</ion-note>\n </ion-item>\n }\n }\n </ion-list>\n</ion-content>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonBackButton, selector: "ion-back-button" }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonListHeader, selector: "ion-list-header", inputs: ["color", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }] });
|
|
129
|
+
}
|
|
130
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: BringAlongPageComponent, decorators: [{
|
|
131
|
+
type: Component,
|
|
132
|
+
args: [{ selector: 'eventus-bring-along-page', imports: [
|
|
133
|
+
FormsModule,
|
|
134
|
+
IonHeader,
|
|
135
|
+
IonToolbar,
|
|
136
|
+
IonTitle,
|
|
137
|
+
IonButtons,
|
|
138
|
+
IonBackButton,
|
|
139
|
+
IonButton,
|
|
140
|
+
IonContent,
|
|
141
|
+
IonList,
|
|
142
|
+
IonListHeader,
|
|
143
|
+
IonItem,
|
|
144
|
+
IonLabel,
|
|
145
|
+
IonInput,
|
|
146
|
+
IonNote,
|
|
147
|
+
IonText,
|
|
148
|
+
IonSpinner,
|
|
149
|
+
], template: "<ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"start\">\n <ion-back-button defaultHref=\"/\"></ion-back-button>\n </ion-buttons>\n <ion-title>Bring along</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n @if (error()) {\n <ion-text color=\"danger\">{{ error() }}</ion-text>\n }\n\n <ion-list>\n <ion-list-header>Add a slot</ion-list-header>\n <ion-item>\n <ion-input\n label=\"What's needed\"\n labelPlacement=\"floating\"\n placeholder=\"e.g. Drinks\"\n [(ngModel)]=\"newLabel\"\n ></ion-input>\n </ion-item>\n <ion-item>\n <ion-input\n label=\"Note (optional)\"\n labelPlacement=\"floating\"\n placeholder=\"e.g. 2 bottles\"\n [(ngModel)]=\"newNote\"\n ></ion-input>\n </ion-item>\n <ion-button\n expand=\"block\"\n class=\"ion-margin-top\"\n [disabled]=\"submitting() || !newLabel.trim()\"\n (click)=\"addSlot()\"\n >\n Add slot\n </ion-button>\n </ion-list>\n\n <ion-list>\n <ion-list-header>Slots</ion-list-header>\n @if (loading()) {\n <ion-item>\n <ion-spinner aria-label=\"Loading slots\"></ion-spinner>\n </ion-item>\n } @else {\n @for (slot of slots(); track slot.id) {\n <ion-item>\n <ion-label class=\"ion-text-wrap\">\n @if (slot.claimedBy; as claimant) {\n <h3>{{ slot.label }} \u2014 {{ claimant.label }}</h3>\n } @else {\n <h3>{{ slot.label }}</h3>\n <ion-note color=\"success\">Open</ion-note>\n }\n @if (slot.note) {\n <p>{{ slot.note }}</p>\n }\n </ion-label>\n @if (!slot.claimedBy) {\n <ion-button\n slot=\"end\"\n [disabled]=\"submitting()\"\n (click)=\"claim(slot)\"\n >\n Claim\n </ion-button>\n } @else if (claimedByMe(slot)) {\n <ion-button\n slot=\"end\"\n fill=\"outline\"\n [disabled]=\"submitting()\"\n (click)=\"release(slot)\"\n >\n Release\n </ion-button>\n }\n </ion-item>\n } @empty {\n <ion-item>\n <ion-note>No slots yet.</ion-note>\n </ion-item>\n }\n }\n </ion-list>\n</ion-content>\n" }]
|
|
150
|
+
}], propDecorators: { spaceID: [{ type: i0.Input, args: [{ isSignal: true, alias: "spaceID", required: true }] }], eventID: [{ type: i0.Input, args: [{ isSignal: true, alias: "eventID", required: true }] }] } });
|
|
151
|
+
|
|
152
|
+
export { BringAlongPageComponent };
|
|
153
|
+
//# sourceMappingURL=sneat-extension-eventus-shared-bring-along-page.component-DHi-E8P1.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sneat-extension-eventus-shared-bring-along-page.component-DHi-E8P1.mjs","sources":["../../../../../../libs/extensions/eventus/shared/src/lib/pages/bring-along/bring-along-page.component.ts","../../../../../../libs/extensions/eventus/shared/src/lib/pages/bring-along/bring-along-page.component.html"],"sourcesContent":["import { Component, OnInit, computed, inject, input, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport {\n IonBackButton,\n IonButton,\n IonButtons,\n IonContent,\n IonHeader,\n IonInput,\n IonItem,\n IonLabel,\n IonList,\n IonListHeader,\n IonNote,\n IonSpinner,\n IonText,\n IonTitle,\n IonToolbar,\n} from '@ionic/angular/standalone';\nimport {\n BRING_ALONG_SERVICE,\n EVENTUS_CURRENT_CLAIMANT,\n extractErrorMessage,\n IBringAlongSlot,\n} from '@sneat/extension-eventus-contract';\n\n// Bring-along screen for an event: the host defines slots (label + optional\n// note); each slot shows as OPEN (with Claim) or CLAIMED (\"{label} — {claimant}\",\n// with Release when the current claimant owns it). A 409 on claim shows a\n// friendly message and refreshes the list.\n// (AC: host-defines-slots, claim-prevents-duplicates)\n@Component({\n selector: 'eventus-bring-along-page',\n templateUrl: './bring-along-page.component.html',\n imports: [\n FormsModule,\n IonHeader,\n IonToolbar,\n IonTitle,\n IonButtons,\n IonBackButton,\n IonButton,\n IonContent,\n IonList,\n IonListHeader,\n IonItem,\n IonLabel,\n IonInput,\n IonNote,\n IonText,\n IonSpinner,\n ],\n})\nexport class BringAlongPageComponent implements OnInit {\n private readonly bringAlongService = inject(BRING_ALONG_SERVICE);\n private readonly claimant = inject(EVENTUS_CURRENT_CLAIMANT);\n\n readonly spaceID = input.required<string>();\n readonly eventID = input.required<string>();\n\n protected readonly slots = signal<IBringAlongSlot[]>([]);\n protected readonly loading = signal(true);\n protected readonly submitting = signal(false);\n protected readonly error = signal<string | undefined>(undefined);\n\n protected newLabel = '';\n protected newNote = '';\n\n /** The identity used for claim/release, shown in the header for clarity. */\n protected readonly claimantLabel = computed(() => this.claimant.label);\n\n ngOnInit(): void {\n this.loadSlots();\n }\n\n private loadSlots(): void {\n this.loading.set(true);\n this.bringAlongService.listSlots(this.spaceID(), this.eventID()).subscribe({\n next: (slots) => {\n this.slots.set(slots);\n this.loading.set(false);\n },\n error: (err: unknown) => {\n this.loading.set(false);\n this.error.set(extractErrorMessage(err, 'Failed to load slots.'));\n },\n });\n }\n\n /** Whether the current claimant owns this slot (so they may release it). */\n protected claimedByMe(slot: IBringAlongSlot): boolean {\n return slot.claimedBy?.ref === this.claimant.ref;\n }\n\n /** Host defines a new slot. (AC: host-defines-slots) */\n protected addSlot(): void {\n const label = this.newLabel.trim();\n if (!label || this.submitting()) {\n return;\n }\n const note = this.newNote.trim();\n this.submitting.set(true);\n this.error.set(undefined);\n this.bringAlongService\n .defineSlot(this.spaceID(), this.eventID(), {\n label,\n ...(note ? { note } : {}),\n })\n .subscribe({\n next: (slot) => {\n this.slots.update((list) => [...list, slot]);\n this.newLabel = '';\n this.newNote = '';\n this.submitting.set(false);\n },\n error: (err: unknown) => {\n this.submitting.set(false);\n this.error.set(extractErrorMessage(err, 'Failed to add slot.'));\n },\n });\n }\n\n /** Claim an open slot. On 409 show a friendly message and refresh. */\n protected claim(slot: IBringAlongSlot): void {\n if (this.submitting()) {\n return;\n }\n this.submitting.set(true);\n this.error.set(undefined);\n this.bringAlongService\n .claimSlot(this.spaceID(), this.eventID(), slot.id, {\n ref: this.claimant.ref,\n label: this.claimant.label,\n })\n .subscribe({\n next: (updated) => {\n this.replaceSlot(updated);\n this.submitting.set(false);\n },\n error: (err: { status?: number }) => {\n this.submitting.set(false);\n if (err?.status === 409) {\n this.error.set('Already claimed by someone else.');\n this.loadSlots();\n } else {\n this.error.set(extractErrorMessage(err, 'Failed to claim slot.'));\n }\n },\n });\n }\n\n /** Release a slot the current claimant owns, returning it to open. */\n protected release(slot: IBringAlongSlot): void {\n if (this.submitting()) {\n return;\n }\n this.submitting.set(true);\n this.error.set(undefined);\n this.bringAlongService\n .releaseSlot(this.spaceID(), this.eventID(), slot.id, {\n ref: this.claimant.ref,\n })\n .subscribe({\n next: (updated) => {\n this.replaceSlot(updated);\n this.submitting.set(false);\n },\n error: (err: unknown) => {\n this.submitting.set(false);\n this.error.set(extractErrorMessage(err, 'Failed to release slot.'));\n },\n });\n }\n\n private replaceSlot(updated: IBringAlongSlot): void {\n this.slots.update((list) =>\n list.map((s) => (s.id === updated.id ? updated : s)),\n );\n }\n}\n","<ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"start\">\n <ion-back-button defaultHref=\"/\"></ion-back-button>\n </ion-buttons>\n <ion-title>Bring along</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n @if (error()) {\n <ion-text color=\"danger\">{{ error() }}</ion-text>\n }\n\n <ion-list>\n <ion-list-header>Add a slot</ion-list-header>\n <ion-item>\n <ion-input\n label=\"What's needed\"\n labelPlacement=\"floating\"\n placeholder=\"e.g. Drinks\"\n [(ngModel)]=\"newLabel\"\n ></ion-input>\n </ion-item>\n <ion-item>\n <ion-input\n label=\"Note (optional)\"\n labelPlacement=\"floating\"\n placeholder=\"e.g. 2 bottles\"\n [(ngModel)]=\"newNote\"\n ></ion-input>\n </ion-item>\n <ion-button\n expand=\"block\"\n class=\"ion-margin-top\"\n [disabled]=\"submitting() || !newLabel.trim()\"\n (click)=\"addSlot()\"\n >\n Add slot\n </ion-button>\n </ion-list>\n\n <ion-list>\n <ion-list-header>Slots</ion-list-header>\n @if (loading()) {\n <ion-item>\n <ion-spinner aria-label=\"Loading slots\"></ion-spinner>\n </ion-item>\n } @else {\n @for (slot of slots(); track slot.id) {\n <ion-item>\n <ion-label class=\"ion-text-wrap\">\n @if (slot.claimedBy; as claimant) {\n <h3>{{ slot.label }} — {{ claimant.label }}</h3>\n } @else {\n <h3>{{ slot.label }}</h3>\n <ion-note color=\"success\">Open</ion-note>\n }\n @if (slot.note) {\n <p>{{ slot.note }}</p>\n }\n </ion-label>\n @if (!slot.claimedBy) {\n <ion-button\n slot=\"end\"\n [disabled]=\"submitting()\"\n (click)=\"claim(slot)\"\n >\n Claim\n </ion-button>\n } @else if (claimedByMe(slot)) {\n <ion-button\n slot=\"end\"\n fill=\"outline\"\n [disabled]=\"submitting()\"\n (click)=\"release(slot)\"\n >\n Release\n </ion-button>\n }\n </ion-item>\n } @empty {\n <ion-item>\n <ion-note>No slots yet.</ion-note>\n </ion-item>\n }\n }\n </ion-list>\n</ion-content>\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, input, signal, Component } from '@angular/core';
|
|
3
|
+
import * as i1 from '@angular/forms';
|
|
4
|
+
import { FormsModule } from '@angular/forms';
|
|
5
|
+
import { Router } from '@angular/router';
|
|
6
|
+
import { IonHeader, IonToolbar, IonTitle, IonButtons, IonBackButton, IonContent, IonList, IonItem, IonInput, IonDatetime, IonTextarea, IonNote, IonButton } from '@ionic/angular/standalone';
|
|
7
|
+
import { EVENTUS_EVENT_SERVICE, extractErrorMessage } from '@sneat/extension-eventus-contract';
|
|
8
|
+
|
|
9
|
+
// Host screen to create an event (title, date/time, location, description).
|
|
10
|
+
// On success it navigates to the created event's view page.
|
|
11
|
+
// (AC: host-creates-event)
|
|
12
|
+
class CreateEventPageComponent {
|
|
13
|
+
eventService = inject(EVENTUS_EVENT_SERVICE);
|
|
14
|
+
router = inject(Router);
|
|
15
|
+
/** Host space the event is created in (from the route). */
|
|
16
|
+
spaceType = input.required(...(ngDevMode ? [{ debugName: "spaceType" }] : /* istanbul ignore next */ []));
|
|
17
|
+
spaceID = input.required(...(ngDevMode ? [{ debugName: "spaceID" }] : /* istanbul ignore next */ []));
|
|
18
|
+
title = '';
|
|
19
|
+
start = '';
|
|
20
|
+
location = '';
|
|
21
|
+
description = '';
|
|
22
|
+
/** Event length in minutes (default 60); reuses Calendarius's duration model. */
|
|
23
|
+
durationMinutes = 60;
|
|
24
|
+
submitting = signal(false, ...(ngDevMode ? [{ debugName: "submitting" }] : /* istanbul ignore next */ []));
|
|
25
|
+
error = signal(undefined, ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
|
|
26
|
+
get canSubmit() {
|
|
27
|
+
return (!this.submitting() &&
|
|
28
|
+
this.title.trim().length > 0 &&
|
|
29
|
+
this.start.trim().length > 0 &&
|
|
30
|
+
this.location.trim().length > 0);
|
|
31
|
+
}
|
|
32
|
+
submit() {
|
|
33
|
+
if (!this.canSubmit) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const request = {
|
|
37
|
+
title: this.title.trim(),
|
|
38
|
+
start: this.start,
|
|
39
|
+
location: this.location.trim(),
|
|
40
|
+
};
|
|
41
|
+
const description = this.description.trim();
|
|
42
|
+
if (description) {
|
|
43
|
+
request.description = description;
|
|
44
|
+
}
|
|
45
|
+
if (this.durationMinutes > 0) {
|
|
46
|
+
request.durationMinutes = this.durationMinutes;
|
|
47
|
+
}
|
|
48
|
+
this.submitting.set(true);
|
|
49
|
+
this.error.set(undefined);
|
|
50
|
+
this.eventService.createEvent(this.spaceID(), request).subscribe({
|
|
51
|
+
next: (created) => {
|
|
52
|
+
void this.router.navigate([
|
|
53
|
+
'/space',
|
|
54
|
+
this.spaceType(),
|
|
55
|
+
this.spaceID(),
|
|
56
|
+
'events',
|
|
57
|
+
created.id,
|
|
58
|
+
]);
|
|
59
|
+
},
|
|
60
|
+
error: (err) => {
|
|
61
|
+
this.submitting.set(false);
|
|
62
|
+
this.error.set(extractErrorMessage(err, 'Failed to create event.'));
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: CreateEventPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
67
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: CreateEventPageComponent, isStandalone: true, selector: "eventus-create-event-page", inputs: { spaceType: { classPropertyName: "spaceType", publicName: "spaceType", isSignal: true, isRequired: true, transformFunction: null }, spaceID: { classPropertyName: "spaceID", publicName: "spaceID", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"start\">\n <ion-back-button defaultHref=\"/\"></ion-back-button>\n </ion-buttons>\n <ion-title>New event</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n <ion-list>\n <ion-item>\n <ion-input\n label=\"Title\"\n labelPlacement=\"stacked\"\n placeholder=\"Sophie's 10th Birthday\"\n [(ngModel)]=\"title\"\n required\n ></ion-input>\n </ion-item>\n\n <ion-item>\n <ion-input\n label=\"Location\"\n labelPlacement=\"stacked\"\n placeholder=\"123 Main St\"\n [(ngModel)]=\"location\"\n required\n ></ion-input>\n </ion-item>\n\n <ion-item>\n <ion-textarea\n label=\"Description\"\n labelPlacement=\"stacked\"\n placeholder=\"Optional details\"\n [(ngModel)]=\"description\"\n [autoGrow]=\"true\"\n ></ion-textarea>\n </ion-item>\n </ion-list>\n\n <ion-list>\n <ion-item lines=\"none\">\n <ion-note>Date & time</ion-note>\n </ion-item>\n <ion-datetime\n aria-label=\"Event date and time\"\n [(ngModel)]=\"start\"\n presentation=\"date-time\"\n ></ion-datetime>\n <ion-item>\n <ion-input\n label=\"Duration (minutes)\"\n labelPlacement=\"stacked\"\n type=\"number\"\n min=\"1\"\n [(ngModel)]=\"durationMinutes\"\n ></ion-input>\n </ion-item>\n </ion-list>\n\n @if (error()) {\n <ion-note color=\"danger\" class=\"ion-padding-start\">{{ error() }}</ion-note>\n }\n\n <ion-button\n expand=\"block\"\n class=\"ion-margin-top\"\n [disabled]=\"!canSubmit\"\n (click)=\"submit()\"\n >\n Create event\n </ion-button>\n</ion-content>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonBackButton, selector: "ion-back-button" }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: IonDatetime, selector: "ion-datetime", inputs: ["cancelText", "clearText", "color", "dayValues", "disabled", "doneText", "firstDayOfWeek", "formatOptions", "highlightedDates", "hourCycle", "hourValues", "isDateEnabled", "locale", "max", "min", "minuteValues", "mode", "monthValues", "multiple", "name", "preferWheel", "presentation", "readonly", "showAdjacentDays", "showClearButton", "showDefaultButtons", "showDefaultTimeLabel", "showDefaultTitle", "size", "titleSelectedDatesFormatter", "value", "yearValues"] }, { kind: "component", type: IonTextarea, selector: "ion-textarea", inputs: ["autoGrow", "autocapitalize", "autofocus", "clearOnEdit", "color", "cols", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "maxlength", "minlength", "mode", "name", "placeholder", "readonly", "required", "rows", "shape", "spellcheck", "value", "wrap"] }, { kind: "component", type: IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }] });
|
|
68
|
+
}
|
|
69
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: CreateEventPageComponent, decorators: [{
|
|
70
|
+
type: Component,
|
|
71
|
+
args: [{ selector: 'eventus-create-event-page', imports: [
|
|
72
|
+
FormsModule,
|
|
73
|
+
IonHeader,
|
|
74
|
+
IonToolbar,
|
|
75
|
+
IonTitle,
|
|
76
|
+
IonButtons,
|
|
77
|
+
IonBackButton,
|
|
78
|
+
IonContent,
|
|
79
|
+
IonList,
|
|
80
|
+
IonItem,
|
|
81
|
+
IonInput,
|
|
82
|
+
IonDatetime,
|
|
83
|
+
IonTextarea,
|
|
84
|
+
IonNote,
|
|
85
|
+
IonButton,
|
|
86
|
+
], template: "<ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"start\">\n <ion-back-button defaultHref=\"/\"></ion-back-button>\n </ion-buttons>\n <ion-title>New event</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n <ion-list>\n <ion-item>\n <ion-input\n label=\"Title\"\n labelPlacement=\"stacked\"\n placeholder=\"Sophie's 10th Birthday\"\n [(ngModel)]=\"title\"\n required\n ></ion-input>\n </ion-item>\n\n <ion-item>\n <ion-input\n label=\"Location\"\n labelPlacement=\"stacked\"\n placeholder=\"123 Main St\"\n [(ngModel)]=\"location\"\n required\n ></ion-input>\n </ion-item>\n\n <ion-item>\n <ion-textarea\n label=\"Description\"\n labelPlacement=\"stacked\"\n placeholder=\"Optional details\"\n [(ngModel)]=\"description\"\n [autoGrow]=\"true\"\n ></ion-textarea>\n </ion-item>\n </ion-list>\n\n <ion-list>\n <ion-item lines=\"none\">\n <ion-note>Date & time</ion-note>\n </ion-item>\n <ion-datetime\n aria-label=\"Event date and time\"\n [(ngModel)]=\"start\"\n presentation=\"date-time\"\n ></ion-datetime>\n <ion-item>\n <ion-input\n label=\"Duration (minutes)\"\n labelPlacement=\"stacked\"\n type=\"number\"\n min=\"1\"\n [(ngModel)]=\"durationMinutes\"\n ></ion-input>\n </ion-item>\n </ion-list>\n\n @if (error()) {\n <ion-note color=\"danger\" class=\"ion-padding-start\">{{ error() }}</ion-note>\n }\n\n <ion-button\n expand=\"block\"\n class=\"ion-margin-top\"\n [disabled]=\"!canSubmit\"\n (click)=\"submit()\"\n >\n Create event\n </ion-button>\n</ion-content>\n" }]
|
|
87
|
+
}], propDecorators: { spaceType: [{ type: i0.Input, args: [{ isSignal: true, alias: "spaceType", required: true }] }], spaceID: [{ type: i0.Input, args: [{ isSignal: true, alias: "spaceID", required: true }] }] } });
|
|
88
|
+
|
|
89
|
+
export { CreateEventPageComponent };
|
|
90
|
+
//# sourceMappingURL=sneat-extension-eventus-shared-create-event-page.component-Da39fu36.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sneat-extension-eventus-shared-create-event-page.component-Da39fu36.mjs","sources":["../../../../../../libs/extensions/eventus/shared/src/lib/pages/create-event/create-event-page.component.ts","../../../../../../libs/extensions/eventus/shared/src/lib/pages/create-event/create-event-page.component.html"],"sourcesContent":["import { Component, inject, input, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { Router } from '@angular/router';\nimport {\n IonButton,\n IonButtons,\n IonBackButton,\n IonContent,\n IonHeader,\n IonInput,\n IonItem,\n IonList,\n IonDatetime,\n IonNote,\n IonTextarea,\n IonTitle,\n IonToolbar,\n} from '@ionic/angular/standalone';\nimport {\n EVENTUS_EVENT_SERVICE,\n extractErrorMessage,\n ICreateEventRequest,\n} from '@sneat/extension-eventus-contract';\n\n// Host screen to create an event (title, date/time, location, description).\n// On success it navigates to the created event's view page.\n// (AC: host-creates-event)\n@Component({\n selector: 'eventus-create-event-page',\n templateUrl: './create-event-page.component.html',\n imports: [\n FormsModule,\n IonHeader,\n IonToolbar,\n IonTitle,\n IonButtons,\n IonBackButton,\n IonContent,\n IonList,\n IonItem,\n IonInput,\n IonDatetime,\n IonTextarea,\n IonNote,\n IonButton,\n ],\n})\nexport class CreateEventPageComponent {\n private readonly eventService = inject(EVENTUS_EVENT_SERVICE);\n private readonly router = inject(Router);\n\n /** Host space the event is created in (from the route). */\n readonly spaceType = input.required<string>();\n readonly spaceID = input.required<string>();\n\n protected title = '';\n protected start = '';\n protected location = '';\n protected description = '';\n /** Event length in minutes (default 60); reuses Calendarius's duration model. */\n protected durationMinutes = 60;\n\n protected readonly submitting = signal(false);\n protected readonly error = signal<string | undefined>(undefined);\n\n protected get canSubmit(): boolean {\n return (\n !this.submitting() &&\n this.title.trim().length > 0 &&\n this.start.trim().length > 0 &&\n this.location.trim().length > 0\n );\n }\n\n protected submit(): void {\n if (!this.canSubmit) {\n return;\n }\n const request: ICreateEventRequest = {\n title: this.title.trim(),\n start: this.start,\n location: this.location.trim(),\n };\n const description = this.description.trim();\n if (description) {\n request.description = description;\n }\n if (this.durationMinutes > 0) {\n request.durationMinutes = this.durationMinutes;\n }\n\n this.submitting.set(true);\n this.error.set(undefined);\n this.eventService.createEvent(this.spaceID(), request).subscribe({\n next: (created) => {\n void this.router.navigate([\n '/space',\n this.spaceType(),\n this.spaceID(),\n 'events',\n created.id,\n ]);\n },\n error: (err: unknown) => {\n this.submitting.set(false);\n this.error.set(extractErrorMessage(err, 'Failed to create event.'));\n },\n });\n }\n}\n","<ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"start\">\n <ion-back-button defaultHref=\"/\"></ion-back-button>\n </ion-buttons>\n <ion-title>New event</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n <ion-list>\n <ion-item>\n <ion-input\n label=\"Title\"\n labelPlacement=\"stacked\"\n placeholder=\"Sophie's 10th Birthday\"\n [(ngModel)]=\"title\"\n required\n ></ion-input>\n </ion-item>\n\n <ion-item>\n <ion-input\n label=\"Location\"\n labelPlacement=\"stacked\"\n placeholder=\"123 Main St\"\n [(ngModel)]=\"location\"\n required\n ></ion-input>\n </ion-item>\n\n <ion-item>\n <ion-textarea\n label=\"Description\"\n labelPlacement=\"stacked\"\n placeholder=\"Optional details\"\n [(ngModel)]=\"description\"\n [autoGrow]=\"true\"\n ></ion-textarea>\n </ion-item>\n </ion-list>\n\n <ion-list>\n <ion-item lines=\"none\">\n <ion-note>Date & time</ion-note>\n </ion-item>\n <ion-datetime\n aria-label=\"Event date and time\"\n [(ngModel)]=\"start\"\n presentation=\"date-time\"\n ></ion-datetime>\n <ion-item>\n <ion-input\n label=\"Duration (minutes)\"\n labelPlacement=\"stacked\"\n type=\"number\"\n min=\"1\"\n [(ngModel)]=\"durationMinutes\"\n ></ion-input>\n </ion-item>\n </ion-list>\n\n @if (error()) {\n <ion-note color=\"danger\" class=\"ion-padding-start\">{{ error() }}</ion-note>\n }\n\n <ion-button\n expand=\"block\"\n class=\"ion-margin-top\"\n [disabled]=\"!canSubmit\"\n (click)=\"submit()\"\n >\n Create event\n </ion-button>\n</ion-content>\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, input, signal, Component } from '@angular/core';
|
|
3
|
+
import * as i1 from '@angular/forms';
|
|
4
|
+
import { FormsModule } from '@angular/forms';
|
|
5
|
+
import { Router } from '@angular/router';
|
|
6
|
+
import { IonHeader, IonToolbar, IonTitle, IonButtons, IonBackButton, IonContent, IonList, IonItem, IonInput, IonDatetime, IonTextarea, IonNote, IonText, IonSpinner, IonButton } from '@ionic/angular/standalone';
|
|
7
|
+
import { EVENT_SERVICE, extractErrorMessage } from '@sneat/extension-eventus-contract';
|
|
8
|
+
|
|
9
|
+
// Host screen to edit an event's title/date-time/location/description (PUT).
|
|
10
|
+
// Loads the current event to prefill the form. (AC: only-host-edits)
|
|
11
|
+
class EditEventPageComponent {
|
|
12
|
+
eventService = inject(EVENT_SERVICE);
|
|
13
|
+
router = inject(Router);
|
|
14
|
+
spaceType = input.required(...(ngDevMode ? [{ debugName: "spaceType" }] : /* istanbul ignore next */ []));
|
|
15
|
+
spaceID = input.required(...(ngDevMode ? [{ debugName: "spaceID" }] : /* istanbul ignore next */ []));
|
|
16
|
+
eventID = input.required(...(ngDevMode ? [{ debugName: "eventID" }] : /* istanbul ignore next */ []));
|
|
17
|
+
title = '';
|
|
18
|
+
start = '';
|
|
19
|
+
location = '';
|
|
20
|
+
description = '';
|
|
21
|
+
loading = signal(true, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
22
|
+
loadFailed = signal(false, ...(ngDevMode ? [{ debugName: "loadFailed" }] : /* istanbul ignore next */ []));
|
|
23
|
+
saving = signal(false, ...(ngDevMode ? [{ debugName: "saving" }] : /* istanbul ignore next */ []));
|
|
24
|
+
error = signal(undefined, ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
|
|
25
|
+
ngOnInit() {
|
|
26
|
+
this.eventService.getEvent(this.spaceID(), this.eventID()).subscribe({
|
|
27
|
+
next: (event) => {
|
|
28
|
+
this.title = event.title;
|
|
29
|
+
this.start = event.start;
|
|
30
|
+
this.location = event.location;
|
|
31
|
+
this.description = event.description ?? '';
|
|
32
|
+
this.loading.set(false);
|
|
33
|
+
},
|
|
34
|
+
error: (err) => {
|
|
35
|
+
this.loading.set(false);
|
|
36
|
+
this.loadFailed.set(true);
|
|
37
|
+
this.error.set(extractErrorMessage(err, 'Failed to load event.'));
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
get canSave() {
|
|
42
|
+
return (!this.saving() &&
|
|
43
|
+
this.title.trim().length > 0 &&
|
|
44
|
+
this.start.trim().length > 0 &&
|
|
45
|
+
this.location.trim().length > 0);
|
|
46
|
+
}
|
|
47
|
+
save() {
|
|
48
|
+
if (!this.canSave) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const request = {
|
|
52
|
+
title: this.title.trim(),
|
|
53
|
+
start: this.start,
|
|
54
|
+
location: this.location.trim(),
|
|
55
|
+
description: this.description.trim(),
|
|
56
|
+
};
|
|
57
|
+
this.saving.set(true);
|
|
58
|
+
this.error.set(undefined);
|
|
59
|
+
this.eventService
|
|
60
|
+
.updateEvent(this.spaceID(), this.eventID(), request)
|
|
61
|
+
.subscribe({
|
|
62
|
+
next: (event) => {
|
|
63
|
+
void this.router.navigate([
|
|
64
|
+
'/space',
|
|
65
|
+
this.spaceType(),
|
|
66
|
+
this.spaceID(),
|
|
67
|
+
'events',
|
|
68
|
+
event.id,
|
|
69
|
+
]);
|
|
70
|
+
},
|
|
71
|
+
error: (err) => {
|
|
72
|
+
this.saving.set(false);
|
|
73
|
+
this.error.set(extractErrorMessage(err, 'Failed to save event.'));
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: EditEventPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
78
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: EditEventPageComponent, isStandalone: true, selector: "eventus-edit-event-page", inputs: { spaceType: { classPropertyName: "spaceType", publicName: "spaceType", isSignal: true, isRequired: true, transformFunction: null }, spaceID: { classPropertyName: "spaceID", publicName: "spaceID", isSignal: true, isRequired: true, transformFunction: null }, eventID: { classPropertyName: "eventID", publicName: "eventID", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"start\">\n <ion-back-button defaultHref=\"/\"></ion-back-button>\n </ion-buttons>\n <ion-title>Edit event</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n @if (loading()) {\n <ion-spinner aria-label=\"Loading event\"></ion-spinner>\n } @else if (loadFailed()) {\n <ion-text color=\"danger\">{{ error() }}</ion-text>\n } @else {\n <ion-list>\n <ion-item>\n <ion-input\n label=\"Title\"\n labelPlacement=\"stacked\"\n [(ngModel)]=\"title\"\n required\n ></ion-input>\n </ion-item>\n\n <ion-item>\n <ion-input\n label=\"Location\"\n labelPlacement=\"stacked\"\n [(ngModel)]=\"location\"\n required\n ></ion-input>\n </ion-item>\n\n <ion-item>\n <ion-textarea\n label=\"Description\"\n labelPlacement=\"stacked\"\n placeholder=\"Optional details\"\n [(ngModel)]=\"description\"\n [autoGrow]=\"true\"\n ></ion-textarea>\n </ion-item>\n </ion-list>\n\n <ion-list>\n <ion-item lines=\"none\">\n <ion-note>Date & time</ion-note>\n </ion-item>\n <ion-datetime\n aria-label=\"Event date and time\"\n [(ngModel)]=\"start\"\n presentation=\"date-time\"\n ></ion-datetime>\n </ion-list>\n\n @if (error()) {\n <ion-text color=\"danger\">{{ error() }}</ion-text>\n }\n\n <ion-button\n expand=\"block\"\n class=\"ion-margin-top\"\n [disabled]=\"!canSave\"\n (click)=\"save()\"\n >\n Save changes\n </ion-button>\n }\n</ion-content>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonBackButton, selector: "ion-back-button" }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: IonDatetime, selector: "ion-datetime", inputs: ["cancelText", "clearText", "color", "dayValues", "disabled", "doneText", "firstDayOfWeek", "formatOptions", "highlightedDates", "hourCycle", "hourValues", "isDateEnabled", "locale", "max", "min", "minuteValues", "mode", "monthValues", "multiple", "name", "preferWheel", "presentation", "readonly", "showAdjacentDays", "showClearButton", "showDefaultButtons", "showDefaultTimeLabel", "showDefaultTitle", "size", "titleSelectedDatesFormatter", "value", "yearValues"] }, { kind: "component", type: IonTextarea, selector: "ion-textarea", inputs: ["autoGrow", "autocapitalize", "autofocus", "clearOnEdit", "color", "cols", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "maxlength", "minlength", "mode", "name", "placeholder", "readonly", "required", "rows", "shape", "spellcheck", "value", "wrap"] }, { kind: "component", type: IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }] });
|
|
79
|
+
}
|
|
80
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: EditEventPageComponent, decorators: [{
|
|
81
|
+
type: Component,
|
|
82
|
+
args: [{ selector: 'eventus-edit-event-page', imports: [
|
|
83
|
+
FormsModule,
|
|
84
|
+
IonHeader,
|
|
85
|
+
IonToolbar,
|
|
86
|
+
IonTitle,
|
|
87
|
+
IonButtons,
|
|
88
|
+
IonBackButton,
|
|
89
|
+
IonContent,
|
|
90
|
+
IonList,
|
|
91
|
+
IonItem,
|
|
92
|
+
IonInput,
|
|
93
|
+
IonDatetime,
|
|
94
|
+
IonTextarea,
|
|
95
|
+
IonNote,
|
|
96
|
+
IonText,
|
|
97
|
+
IonSpinner,
|
|
98
|
+
IonButton,
|
|
99
|
+
], template: "<ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"start\">\n <ion-back-button defaultHref=\"/\"></ion-back-button>\n </ion-buttons>\n <ion-title>Edit event</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n @if (loading()) {\n <ion-spinner aria-label=\"Loading event\"></ion-spinner>\n } @else if (loadFailed()) {\n <ion-text color=\"danger\">{{ error() }}</ion-text>\n } @else {\n <ion-list>\n <ion-item>\n <ion-input\n label=\"Title\"\n labelPlacement=\"stacked\"\n [(ngModel)]=\"title\"\n required\n ></ion-input>\n </ion-item>\n\n <ion-item>\n <ion-input\n label=\"Location\"\n labelPlacement=\"stacked\"\n [(ngModel)]=\"location\"\n required\n ></ion-input>\n </ion-item>\n\n <ion-item>\n <ion-textarea\n label=\"Description\"\n labelPlacement=\"stacked\"\n placeholder=\"Optional details\"\n [(ngModel)]=\"description\"\n [autoGrow]=\"true\"\n ></ion-textarea>\n </ion-item>\n </ion-list>\n\n <ion-list>\n <ion-item lines=\"none\">\n <ion-note>Date & time</ion-note>\n </ion-item>\n <ion-datetime\n aria-label=\"Event date and time\"\n [(ngModel)]=\"start\"\n presentation=\"date-time\"\n ></ion-datetime>\n </ion-list>\n\n @if (error()) {\n <ion-text color=\"danger\">{{ error() }}</ion-text>\n }\n\n <ion-button\n expand=\"block\"\n class=\"ion-margin-top\"\n [disabled]=\"!canSave\"\n (click)=\"save()\"\n >\n Save changes\n </ion-button>\n }\n</ion-content>\n" }]
|
|
100
|
+
}], propDecorators: { spaceType: [{ type: i0.Input, args: [{ isSignal: true, alias: "spaceType", required: true }] }], spaceID: [{ type: i0.Input, args: [{ isSignal: true, alias: "spaceID", required: true }] }], eventID: [{ type: i0.Input, args: [{ isSignal: true, alias: "eventID", required: true }] }] } });
|
|
101
|
+
|
|
102
|
+
export { EditEventPageComponent };
|
|
103
|
+
//# sourceMappingURL=sneat-extension-eventus-shared-edit-event-page.component-lhOpcqld.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sneat-extension-eventus-shared-edit-event-page.component-lhOpcqld.mjs","sources":["../../../../../../libs/extensions/eventus/shared/src/lib/pages/edit-event/edit-event-page.component.ts","../../../../../../libs/extensions/eventus/shared/src/lib/pages/edit-event/edit-event-page.component.html"],"sourcesContent":["import { Component, OnInit, inject, input, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { Router } from '@angular/router';\nimport {\n IonBackButton,\n IonButton,\n IonButtons,\n IonContent,\n IonDatetime,\n IonHeader,\n IonInput,\n IonItem,\n IonList,\n IonNote,\n IonSpinner,\n IonTextarea,\n IonText,\n IonTitle,\n IonToolbar,\n} from '@ionic/angular/standalone';\nimport {\n EVENT_SERVICE,\n extractErrorMessage,\n IUpdateEventRequest,\n} from '@sneat/extension-eventus-contract';\n\n// Host screen to edit an event's title/date-time/location/description (PUT).\n// Loads the current event to prefill the form. (AC: only-host-edits)\n@Component({\n selector: 'eventus-edit-event-page',\n templateUrl: './edit-event-page.component.html',\n imports: [\n FormsModule,\n IonHeader,\n IonToolbar,\n IonTitle,\n IonButtons,\n IonBackButton,\n IonContent,\n IonList,\n IonItem,\n IonInput,\n IonDatetime,\n IonTextarea,\n IonNote,\n IonText,\n IonSpinner,\n IonButton,\n ],\n})\nexport class EditEventPageComponent implements OnInit {\n private readonly eventService = inject(EVENT_SERVICE);\n private readonly router = inject(Router);\n\n readonly spaceType = input.required<string>();\n readonly spaceID = input.required<string>();\n readonly eventID = input.required<string>();\n\n protected title = '';\n protected start = '';\n protected location = '';\n protected description = '';\n\n protected readonly loading = signal(true);\n protected readonly loadFailed = signal(false);\n protected readonly saving = signal(false);\n protected readonly error = signal<string | undefined>(undefined);\n\n ngOnInit(): void {\n this.eventService.getEvent(this.spaceID(), this.eventID()).subscribe({\n next: (event) => {\n this.title = event.title;\n this.start = event.start;\n this.location = event.location;\n this.description = event.description ?? '';\n this.loading.set(false);\n },\n error: (err: unknown) => {\n this.loading.set(false);\n this.loadFailed.set(true);\n this.error.set(extractErrorMessage(err, 'Failed to load event.'));\n },\n });\n }\n\n protected get canSave(): boolean {\n return (\n !this.saving() &&\n this.title.trim().length > 0 &&\n this.start.trim().length > 0 &&\n this.location.trim().length > 0\n );\n }\n\n protected save(): void {\n if (!this.canSave) {\n return;\n }\n const request: IUpdateEventRequest = {\n title: this.title.trim(),\n start: this.start,\n location: this.location.trim(),\n description: this.description.trim(),\n };\n\n this.saving.set(true);\n this.error.set(undefined);\n this.eventService\n .updateEvent(this.spaceID(), this.eventID(), request)\n .subscribe({\n next: (event) => {\n void this.router.navigate([\n '/space',\n this.spaceType(),\n this.spaceID(),\n 'events',\n event.id,\n ]);\n },\n error: (err: unknown) => {\n this.saving.set(false);\n this.error.set(extractErrorMessage(err, 'Failed to save event.'));\n },\n });\n }\n}\n","<ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"start\">\n <ion-back-button defaultHref=\"/\"></ion-back-button>\n </ion-buttons>\n <ion-title>Edit event</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n @if (loading()) {\n <ion-spinner aria-label=\"Loading event\"></ion-spinner>\n } @else if (loadFailed()) {\n <ion-text color=\"danger\">{{ error() }}</ion-text>\n } @else {\n <ion-list>\n <ion-item>\n <ion-input\n label=\"Title\"\n labelPlacement=\"stacked\"\n [(ngModel)]=\"title\"\n required\n ></ion-input>\n </ion-item>\n\n <ion-item>\n <ion-input\n label=\"Location\"\n labelPlacement=\"stacked\"\n [(ngModel)]=\"location\"\n required\n ></ion-input>\n </ion-item>\n\n <ion-item>\n <ion-textarea\n label=\"Description\"\n labelPlacement=\"stacked\"\n placeholder=\"Optional details\"\n [(ngModel)]=\"description\"\n [autoGrow]=\"true\"\n ></ion-textarea>\n </ion-item>\n </ion-list>\n\n <ion-list>\n <ion-item lines=\"none\">\n <ion-note>Date & time</ion-note>\n </ion-item>\n <ion-datetime\n aria-label=\"Event date and time\"\n [(ngModel)]=\"start\"\n presentation=\"date-time\"\n ></ion-datetime>\n </ion-list>\n\n @if (error()) {\n <ion-text color=\"danger\">{{ error() }}</ion-text>\n }\n\n <ion-button\n expand=\"block\"\n class=\"ion-margin-top\"\n [disabled]=\"!canSave\"\n (click)=\"save()\"\n >\n Save changes\n </ion-button>\n }\n</ion-content>\n"],"names":[],"mappings":"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"}
|