@blazeo.com/appointment-client 1.0.4 → 1.0.5
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/blazeo.com-appointment-client-1.0.5.tgz +0 -0
- package/dist/calendar/fetchCalendarDetails.d.ts +18 -0
- package/dist/calendar/fetchCalendarDetails.js +51 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +3 -4
- package/sample/package-lock.json +50 -2
- package/sample/src/EventTab.jsx +128 -0
- package/sample/src/FetchCalendarTab.jsx +17 -38
- package/blazeo.com-appointment-client-1.0.4.tgz +0 -0
|
Binary file
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare function fetchCalendarDetails(calendarId: string, options?: {
|
|
2
|
+
includeParticipantsInfo?: boolean;
|
|
3
|
+
}): Promise<{
|
|
4
|
+
calendar: (Record<string, unknown> & {
|
|
5
|
+
openingHours: unknown[];
|
|
6
|
+
}) | null;
|
|
7
|
+
/** Live MST calendar node (same as `CalendarModel.get`) — use for instance calls. */
|
|
8
|
+
cal: unknown;
|
|
9
|
+
openingHours: unknown[];
|
|
10
|
+
participants: unknown[];
|
|
11
|
+
participantsInfo: unknown;
|
|
12
|
+
openingHoursApiResponse: unknown;
|
|
13
|
+
meta: {
|
|
14
|
+
ok: boolean;
|
|
15
|
+
reason?: string;
|
|
16
|
+
};
|
|
17
|
+
}>;
|
|
18
|
+
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { CalendarModel } from "@blazeo.com/calendar-client";
|
|
2
|
+
import { getSnapshot } from "mobx-state-tree";
|
|
3
|
+
import { normalizeParticipantOpeningHoursResponse } from "./fetchCalendarWithOpeningHours.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Loads calendar + opening hours + participants and returns a single bundle.
|
|
7
|
+
*
|
|
8
|
+
* Network calls (when calendar exists):
|
|
9
|
+
* - GET /Calendar/Get
|
|
10
|
+
* - GET /Calendar/Participant/OpeningHours/Get
|
|
11
|
+
* - GET /Calendar/Participant/All
|
|
12
|
+
*/
|
|
13
|
+
export async function fetchCalendarDetails(calendarId, options = {}) {
|
|
14
|
+
const { includeParticipantsInfo = false } = options;
|
|
15
|
+
|
|
16
|
+
const cal = await CalendarModel.get(calendarId);
|
|
17
|
+
if (cal == null) {
|
|
18
|
+
return {
|
|
19
|
+
calendar: null,
|
|
20
|
+
cal: null,
|
|
21
|
+
openingHours: [],
|
|
22
|
+
participants: [],
|
|
23
|
+
participantsInfo: null,
|
|
24
|
+
openingHoursApiResponse: null,
|
|
25
|
+
meta: { ok: false, reason: "calendar_not_found" }
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const [openingHoursRes, participants, participantsInfo] = await Promise.all([
|
|
30
|
+
cal.getParticipantOpeningHours({}),
|
|
31
|
+
cal.getParticipants(),
|
|
32
|
+
includeParticipantsInfo ? cal.getParticipantsInfo() : Promise.resolve(null)
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
const { list: openingHoursList } = normalizeParticipantOpeningHoursResponse(openingHoursRes);
|
|
36
|
+
const openingHours = Array.isArray(openingHoursList) ? openingHoursList : [];
|
|
37
|
+
|
|
38
|
+
const snap = getSnapshot(cal);
|
|
39
|
+
const calendar = { ...snap, openingHours };
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
calendar,
|
|
43
|
+
cal,
|
|
44
|
+
openingHours,
|
|
45
|
+
participants: Array.isArray(participants) ? participants : [],
|
|
46
|
+
participantsInfo,
|
|
47
|
+
openingHoursApiResponse: openingHoursRes,
|
|
48
|
+
meta: { ok: true }
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
package/dist/index.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export { mapCalendarBOToSnapshot } from "./calendar/mapCalendarToBlazeoSnapshot.
|
|
|
18
18
|
export type { CalendarInput as CalendarBOInput, MemberBOInput, OpeningHourBOInput, } from "./types/calendar.js";
|
|
19
19
|
export type { ApexAppointmentInput } from "./types/appointment.js";
|
|
20
20
|
export { fetchCalendarWithOpeningHours, normalizeParticipantOpeningHoursResponse, pickOpeningHoursArrayFromCalendarPayload, unwrapCalendarGetData, } from "./calendar/fetchCalendarWithOpeningHours.js";
|
|
21
|
+
export { fetchCalendarDetails } from "./calendar/fetchCalendarDetails.js";
|
|
21
22
|
export { CalendarModel, EventModel, ParticipantModel, OpeningHourModel, } from "@blazeo.com/calendar-client";
|
|
22
23
|
export { configure, getConfig } from "@blazeo.com/calendar-client";
|
|
23
24
|
export { getExampleCalendarRoot, getExampleCalendarRootSnapshot, getExampleEvents, getExampleParticipants, getExampleSlots, } from "./exampleData.js";
|
package/dist/index.js
CHANGED
|
@@ -17,6 +17,7 @@ export * from "./facades/index.js";
|
|
|
17
17
|
export * from "./models/index.js";
|
|
18
18
|
export { mapCalendarBOToSnapshot } from "./calendar/mapCalendarToBlazeoSnapshot.js";
|
|
19
19
|
export { fetchCalendarWithOpeningHours, normalizeParticipantOpeningHoursResponse, pickOpeningHoursArrayFromCalendarPayload, unwrapCalendarGetData, } from "./calendar/fetchCalendarWithOpeningHours.js";
|
|
20
|
+
export { fetchCalendarDetails } from "./calendar/fetchCalendarDetails.js";
|
|
20
21
|
export { CalendarModel, EventModel, ParticipantModel, OpeningHourModel, } from "@blazeo.com/calendar-client";
|
|
21
22
|
export { configure, getConfig } from "@blazeo.com/calendar-client";
|
|
22
23
|
export { getExampleCalendarRoot, getExampleCalendarRootSnapshot, getExampleEvents, getExampleParticipants, getExampleSlots, } from "./exampleData.js";
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blazeo.com/appointment-client",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
|
-
},
|
|
6
|
+
},
|
|
7
7
|
"author": "Blazeo",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"main": "./dist/index.js",
|
|
@@ -15,9 +15,8 @@
|
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@blazeo.com/calendar-client": "^1.0.
|
|
18
|
+
"@blazeo.com/calendar-client": "^1.0.17",
|
|
19
19
|
"mobx": "^6.13.7",
|
|
20
20
|
"mobx-state-tree": "^7.0.2"
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
-
|
package/sample/package-lock.json
CHANGED
|
@@ -17,13 +17,61 @@
|
|
|
17
17
|
},
|
|
18
18
|
"..": {
|
|
19
19
|
"name": "@blazeo.com/appointment-client",
|
|
20
|
-
"version": "1.0.
|
|
20
|
+
"version": "1.0.4",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@blazeo.com/calendar-client": "^1.0.
|
|
22
|
+
"@blazeo.com/calendar-client": "^1.0.17",
|
|
23
23
|
"mobx": "^6.13.7",
|
|
24
24
|
"mobx-state-tree": "^7.0.2"
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
|
+
"../node_modules/@blazeo.com/calendar-client": {
|
|
28
|
+
"version": "1.0.17",
|
|
29
|
+
"license": "UNLICENSED",
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"mobx": "^6.10.0",
|
|
32
|
+
"mobx-state-tree": "^5.4.0"
|
|
33
|
+
},
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=18"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"../node_modules/@blazeo.com/calendar-client/node_modules/mobx-state-tree": {
|
|
39
|
+
"version": "5.4.2",
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"mobx": "^6.3.0"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"../node_modules/mobx": {
|
|
46
|
+
"version": "6.15.0",
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"funding": {
|
|
49
|
+
"type": "opencollective",
|
|
50
|
+
"url": "https://opencollective.com/mobx"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"../node_modules/mobx-state-tree": {
|
|
54
|
+
"version": "7.2.0",
|
|
55
|
+
"license": "MIT",
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"ts-essentials": "^9.4.1"
|
|
58
|
+
},
|
|
59
|
+
"peerDependencies": {
|
|
60
|
+
"mobx": "^6.3.0"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"../node_modules/ts-essentials": {
|
|
64
|
+
"version": "9.4.2",
|
|
65
|
+
"license": "MIT",
|
|
66
|
+
"peerDependencies": {
|
|
67
|
+
"typescript": ">=4.1.0"
|
|
68
|
+
},
|
|
69
|
+
"peerDependenciesMeta": {
|
|
70
|
+
"typescript": {
|
|
71
|
+
"optional": true
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
},
|
|
27
75
|
"node_modules/@babel/code-frame": {
|
|
28
76
|
"version": "7.29.0",
|
|
29
77
|
"dev": true,
|
package/sample/src/EventTab.jsx
CHANGED
|
@@ -2,6 +2,7 @@ import { useMemo, useState } from "react";
|
|
|
2
2
|
import {
|
|
3
3
|
cancelAppointmentEventAsync,
|
|
4
4
|
createAppointmentEventAsync,
|
|
5
|
+
EventModel,
|
|
5
6
|
rescheduleAppointmentEventAsync,
|
|
6
7
|
} from "appointment-client";
|
|
7
8
|
import { getSnapshot, isStateTreeNode } from "mobx-state-tree";
|
|
@@ -65,6 +66,14 @@ function resultToJson(result) {
|
|
|
65
66
|
return JSON.stringify(result, null, 2);
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
function safeJsonParse(text, fallback) {
|
|
70
|
+
try {
|
|
71
|
+
return JSON.parse(text);
|
|
72
|
+
} catch {
|
|
73
|
+
return fallback;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
68
77
|
export function EventTab() {
|
|
69
78
|
const { effective } = useBlazeoConnection();
|
|
70
79
|
const [offsetMinutes, setOffsetMinutes] = useState(-new Date().getTimezoneOffset());
|
|
@@ -74,6 +83,35 @@ export function EventTab() {
|
|
|
74
83
|
const [rescheduleJson, setRescheduleJson] = useState(() =>
|
|
75
84
|
JSON.stringify(getExampleReschedulePayload(), null, 2)
|
|
76
85
|
);
|
|
86
|
+
const [searchCompanyKey, setSearchCompanyKey] = useState("");
|
|
87
|
+
const [searchFrom, setSearchFrom] = useState(() => new Date().toISOString().slice(0, 10));
|
|
88
|
+
const [searchTo, setSearchTo] = useState(() => {
|
|
89
|
+
const d = new Date();
|
|
90
|
+
d.setDate(d.getDate() + 7);
|
|
91
|
+
return d.toISOString().slice(0, 10);
|
|
92
|
+
});
|
|
93
|
+
const [searchFiltersJson, setSearchFiltersJson] = useState(() =>
|
|
94
|
+
JSON.stringify(
|
|
95
|
+
{
|
|
96
|
+
calendarId: "",
|
|
97
|
+
participantId: "",
|
|
98
|
+
leadId: "",
|
|
99
|
+
visitorName: "",
|
|
100
|
+
visitorEmail: "",
|
|
101
|
+
visitorPhone: "",
|
|
102
|
+
title: "",
|
|
103
|
+
search: "",
|
|
104
|
+
attendeeStatus: "",
|
|
105
|
+
eventSource: "",
|
|
106
|
+
sort: "",
|
|
107
|
+
sortOrder: "desc",
|
|
108
|
+
page: 1,
|
|
109
|
+
page_size: 25,
|
|
110
|
+
},
|
|
111
|
+
null,
|
|
112
|
+
2
|
|
113
|
+
)
|
|
114
|
+
);
|
|
77
115
|
const [cancelEventId, setCancelEventId] = useState("");
|
|
78
116
|
const [busy, setBusy] = useState(false);
|
|
79
117
|
const [error, setError] = useState("");
|
|
@@ -153,6 +191,42 @@ export function EventTab() {
|
|
|
153
191
|
}
|
|
154
192
|
}
|
|
155
193
|
|
|
194
|
+
async function handleSearchByDateRange(e) {
|
|
195
|
+
e.preventDefault();
|
|
196
|
+
setError("");
|
|
197
|
+
setOutput("");
|
|
198
|
+
const companyKey = searchCompanyKey.trim();
|
|
199
|
+
if (!companyKey) return setError("Enter company key.");
|
|
200
|
+
if (!searchFrom) return setError("Pick start date.");
|
|
201
|
+
if (!searchTo) return setError("Pick end date.");
|
|
202
|
+
if (!ensureBase()) return;
|
|
203
|
+
configureBlazeoFromEffective(effective);
|
|
204
|
+
|
|
205
|
+
const optsFromJson = safeJsonParse(searchFiltersJson, {});
|
|
206
|
+
const startDateFrom = new Date(`${searchFrom}T00:00:00.000Z`).toISOString();
|
|
207
|
+
const startDateTo = new Date(`${searchTo}T23:59:59.999Z`).toISOString();
|
|
208
|
+
|
|
209
|
+
setBusy(true);
|
|
210
|
+
try {
|
|
211
|
+
const res = await EventModel.getByDateRangeWithFilters(
|
|
212
|
+
companyKey,
|
|
213
|
+
startDateFrom,
|
|
214
|
+
startDateTo,
|
|
215
|
+
optsFromJson
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
const events = (res?.events ?? []).map((e) =>
|
|
219
|
+
isStateTreeNode(e) ? getSnapshot(e) : (e?.toJSON?.() ?? e)
|
|
220
|
+
);
|
|
221
|
+
const totalCount = res?.totalCount ?? events.length;
|
|
222
|
+
setOutput(JSON.stringify({ totalCount, events }, null, 2));
|
|
223
|
+
} catch (err) {
|
|
224
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
225
|
+
} finally {
|
|
226
|
+
setBusy(false);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
156
230
|
return (
|
|
157
231
|
<>
|
|
158
232
|
<div className="card">
|
|
@@ -171,6 +245,60 @@ export function EventTab() {
|
|
|
171
245
|
</label>
|
|
172
246
|
</div>
|
|
173
247
|
|
|
248
|
+
<div className="card">
|
|
249
|
+
<h2>Search events (date range + filters)</h2>
|
|
250
|
+
<p className="muted small">
|
|
251
|
+
Calls <code>EventModel.getByDateRangeWithFilters</code> →
|
|
252
|
+
<code> GET /event/search/daterange/get</code> (company scope). Offset header comes from the{" "}
|
|
253
|
+
<code>offset</code> field above.
|
|
254
|
+
</p>
|
|
255
|
+
<form onSubmit={handleSearchByDateRange} className="form">
|
|
256
|
+
<label className="form__label">
|
|
257
|
+
<span>Company key</span>
|
|
258
|
+
<input
|
|
259
|
+
className="form__input"
|
|
260
|
+
value={searchCompanyKey}
|
|
261
|
+
onChange={(e) => setSearchCompanyKey(e.target.value)}
|
|
262
|
+
placeholder="company_key"
|
|
263
|
+
autoComplete="off"
|
|
264
|
+
/>
|
|
265
|
+
</label>
|
|
266
|
+
<div className="connection-card__row">
|
|
267
|
+
<label className="form__label">
|
|
268
|
+
<span>Start date (from)</span>
|
|
269
|
+
<input
|
|
270
|
+
type="date"
|
|
271
|
+
className="form__input"
|
|
272
|
+
value={searchFrom}
|
|
273
|
+
onChange={(e) => setSearchFrom(e.target.value)}
|
|
274
|
+
/>
|
|
275
|
+
</label>
|
|
276
|
+
<label className="form__label">
|
|
277
|
+
<span>Start date (to)</span>
|
|
278
|
+
<input
|
|
279
|
+
type="date"
|
|
280
|
+
className="form__input"
|
|
281
|
+
value={searchTo}
|
|
282
|
+
onChange={(e) => setSearchTo(e.target.value)}
|
|
283
|
+
/>
|
|
284
|
+
</label>
|
|
285
|
+
</div>
|
|
286
|
+
<label className="form__label">
|
|
287
|
+
<span>Filters (JSON)</span>
|
|
288
|
+
<textarea
|
|
289
|
+
className="form__textarea"
|
|
290
|
+
value={searchFiltersJson}
|
|
291
|
+
onChange={(e) => setSearchFiltersJson(e.target.value)}
|
|
292
|
+
spellCheck={false}
|
|
293
|
+
rows={10}
|
|
294
|
+
/>
|
|
295
|
+
</label>
|
|
296
|
+
<button type="submit" className="btn btn--secondary" disabled={busy}>
|
|
297
|
+
{busy ? "Loading…" : "Search"}
|
|
298
|
+
</button>
|
|
299
|
+
</form>
|
|
300
|
+
</div>
|
|
301
|
+
|
|
174
302
|
<div className="card">
|
|
175
303
|
<h2>Create event</h2>
|
|
176
304
|
<form onSubmit={handleCreate} className="form">
|
|
@@ -2,6 +2,7 @@ import { useMemo, useState } from "react";
|
|
|
2
2
|
import {
|
|
3
3
|
CalendarModel,
|
|
4
4
|
deleteCalendarAsync,
|
|
5
|
+
fetchCalendarDetails,
|
|
5
6
|
fetchCalendarWithOpeningHours,
|
|
6
7
|
updateCalendarAsync,
|
|
7
8
|
} from "appointment-client";
|
|
@@ -217,49 +218,29 @@ export function FetchCalendarTab() {
|
|
|
217
218
|
|
|
218
219
|
setBusy(true);
|
|
219
220
|
try {
|
|
220
|
-
const
|
|
221
|
+
const details = await fetchCalendarDetails(id, { includeParticipantsInfo: true });
|
|
221
222
|
|
|
222
|
-
if (
|
|
223
|
+
if (details.cal == null) {
|
|
223
224
|
const raw = await CalendarModel.getRaw(id);
|
|
224
|
-
setNote(
|
|
225
|
-
"CalendarModel.get returned null. Showing CalendarModel.getRaw only (opening hours merge skipped)."
|
|
226
|
-
);
|
|
225
|
+
setNote("CalendarModel.get returned null. Showing CalendarModel.getRaw only.");
|
|
227
226
|
setOutput(toDisplayJson(raw));
|
|
228
227
|
return;
|
|
229
228
|
}
|
|
230
229
|
|
|
231
|
-
const snap = getSnapshot(
|
|
230
|
+
const snap = getSnapshot(details.cal);
|
|
232
231
|
setLastFetchUpdatePayload(JSON.stringify(calendarSnapshotToUpdatePayload(snap), null, 2));
|
|
233
232
|
|
|
234
|
-
const [participants, participantsInfo] = await Promise.all([
|
|
235
|
-
bundle.cal.getParticipants(),
|
|
236
|
-
bundle.cal.getParticipantsInfo(),
|
|
237
|
-
]);
|
|
238
|
-
|
|
239
233
|
const payload = {
|
|
240
|
-
calendar:
|
|
241
|
-
openingHours:
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
participantsInfo,
|
|
247
|
-
__openingHoursMeta: {
|
|
248
|
-
fromCalendarGet: bundle.fromCalendarGet,
|
|
249
|
-
fromParticipantApi: bundle.fromParticipantApi,
|
|
250
|
-
embeddedCount: bundle.embeddedFromGet?.length ?? 0,
|
|
251
|
-
resolvedCount: bundle.openingHours?.length ?? 0,
|
|
252
|
-
},
|
|
234
|
+
calendar: details.calendar,
|
|
235
|
+
openingHours: details.openingHours,
|
|
236
|
+
openingHoursApiResponse: details.openingHoursApiResponse ?? null,
|
|
237
|
+
participants: details.participants,
|
|
238
|
+
participantsInfo: details.participantsInfo ?? null,
|
|
239
|
+
meta: details.meta,
|
|
253
240
|
};
|
|
254
241
|
|
|
255
242
|
setOutput(toDisplayJson(payload));
|
|
256
|
-
setNote(
|
|
257
|
-
bundle.fromCalendarGet
|
|
258
|
-
? "Opening hours: embedded on GET /Calendar/Get (`appointment-client` fetchCalendarWithOpeningHours)."
|
|
259
|
-
: bundle.fromParticipantApi
|
|
260
|
-
? "Opening hours: from GET /Calendar/Participant/OpeningHours/Get (calendar GET had none)."
|
|
261
|
-
: "Opening hours: none returned."
|
|
262
|
-
);
|
|
243
|
+
setNote("Loaded calendar + opening hours + participants (3 calls) → single response object.");
|
|
263
244
|
} catch (err) {
|
|
264
245
|
setError(explainFetchFailure(err, effective.baseUrl));
|
|
265
246
|
} finally {
|
|
@@ -293,20 +274,18 @@ export function FetchCalendarTab() {
|
|
|
293
274
|
const id = c.calendarId ?? String(c.id ?? "");
|
|
294
275
|
if (!id) return { calendar: getSnapshot(c), openingHours: [], meta: { error: "no id" } };
|
|
295
276
|
try {
|
|
296
|
-
const b = await
|
|
277
|
+
const b = await fetchCalendarDetails(id);
|
|
297
278
|
return {
|
|
298
279
|
calendar: b.calendar ?? getSnapshot(c),
|
|
299
280
|
openingHours: b.openingHours,
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
fromParticipantApi: b.fromParticipantApi,
|
|
303
|
-
},
|
|
281
|
+
participants: b.participants,
|
|
282
|
+
meta: b.meta,
|
|
304
283
|
};
|
|
305
284
|
} catch (err) {
|
|
306
285
|
return {
|
|
307
286
|
calendar: getSnapshot(c),
|
|
308
287
|
openingHours: [],
|
|
309
|
-
|
|
288
|
+
meta: {
|
|
310
289
|
error: err instanceof Error ? err.message : String(err),
|
|
311
290
|
},
|
|
312
291
|
};
|
|
@@ -314,7 +293,7 @@ export function FetchCalendarTab() {
|
|
|
314
293
|
})
|
|
315
294
|
);
|
|
316
295
|
setNote(
|
|
317
|
-
`Loaded ${list.length} calendar(s); opening hours
|
|
296
|
+
`Loaded ${list.length} calendar(s); opening hours + participants loaded per calendar (single details bundle).`
|
|
318
297
|
);
|
|
319
298
|
setOutput(toDisplayJson(enriched));
|
|
320
299
|
}
|
|
Binary file
|