@blazeo.com/appointment-client 1.0.5 → 1.0.6
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.6.tgz +0 -0
- package/dist/calendar/blazeoCalendarRelationMethods.d.ts +4 -36
- package/dist/calendar/blazeoCalendarRelationMethods.js +0 -1
- package/dist/calendar/buildUnifiedCalendarView.d.ts +31 -0
- package/dist/calendar/buildUnifiedCalendarView.js +265 -0
- package/dist/calendar/calendarCreation.d.ts +27 -0
- package/dist/calendar/calendarCreation.js +167 -0
- package/dist/calendar/calendarCreationFacade.d.ts +4 -13
- package/dist/calendar/calendarCreationFacade.js +3 -5
- package/dist/calendar/createCalendar.d.ts +67 -37
- package/dist/calendar/createCalendar.js +1 -3
- package/dist/calendar/fetchCalendarDetails.d.ts +73 -18
- package/dist/calendar/fetchCalendarDetails.js +192 -51
- package/dist/calendar/fetchCalendarWithOpeningHours.d.ts +34 -21
- package/dist/calendar/fetchCalendarWithOpeningHours.js +95 -75
- package/dist/calendar/getAllParticipantOpeningHours.d.ts +19 -0
- package/dist/calendar/getAllParticipantOpeningHours.js +17 -0
- package/dist/calendar/getOpeningHours.d.ts +5 -0
- package/dist/calendar/getOpeningHours.js +9 -0
- package/dist/calendar/getParticipantOpeningHours.d.ts +37 -0
- package/dist/calendar/getParticipantOpeningHours.js +43 -0
- package/dist/calendar/getParticipants.d.ts +4 -0
- package/dist/calendar/getParticipants.js +8 -0
- package/dist/calendar/mapCalendarBoToBlazeoSnapshot.d.ts +9 -9
- package/dist/calendar/mapCalendarBoToBlazeoSnapshot.js +43 -43
- package/dist/calendar/mapCalendarToBlazeoSnapshot.d.ts +22 -3
- package/dist/calendar/mapCalendarToBlazeoSnapshot.js +0 -1
- package/dist/config/applyBlazeoClientConfig.d.ts +2 -2
- package/dist/config/applyBlazeoClientConfig.js +13 -13
- package/dist/config/applyBlazeoDefaults.d.ts +0 -1
- package/dist/config/applyBlazeoDefaults.js +0 -1
- package/dist/config/blazeo.config.d.ts +10 -10
- package/dist/config/blazeo.config.js +10 -10
- package/dist/config/blazeoClientDefaults.d.ts +1 -2
- package/dist/config/blazeoClientDefaults.js +0 -1
- package/dist/config/initializeAppointmentClient.d.ts +4 -28
- package/dist/config/initializeAppointmentClient.js +5 -24
- package/dist/events/appointmentEventFacade.d.ts +55 -32
- package/dist/events/appointmentEventFacade.js +5 -10
- package/dist/events/mapAppointmentToEventSnapshot.d.ts +1 -4
- package/dist/events/mapAppointmentToEventSnapshot.js +0 -1
- package/dist/exampleData.d.ts +114 -10
- package/dist/exampleData.js +4 -5
- package/dist/facade/calendarCreationFacade.d.ts +39 -39
- package/dist/facade/calendarCreationFacade.js +95 -95
- package/dist/facade/mapCalendarBOToSnapshot.d.ts +9 -9
- package/dist/facade/mapCalendarBOToSnapshot.js +43 -43
- package/dist/facades/index.d.ts +11 -11
- package/dist/facades/index.js +11 -11
- package/dist/index.d.ts +23 -82
- package/dist/index.js +21 -33
- package/dist/models/CalendarRootModel.d.ts +36 -11
- package/dist/models/CalendarRootModel.js +22 -5
- package/dist/models/CalendarSlotModel.d.ts +8 -8
- package/dist/models/CalendarSlotModel.js +7 -7
- package/dist/models/EventModel.d.ts +10 -10
- package/dist/models/EventModel.js +9 -9
- package/dist/models/ParticipantModel.d.ts +8 -8
- package/dist/models/ParticipantModel.js +7 -7
- package/dist/models/index.d.ts +4 -4
- package/dist/models/index.js +4 -4
- package/dist/types/appointment.d.ts +27 -27
- package/dist/types/appointment.js +5 -5
- package/dist/types/calendar.d.ts +51 -51
- package/dist/types/calendar.js +5 -5
- package/dist/types/calendarBo.d.ts +61 -61
- package/dist/types/calendarBo.js +5 -5
- package/package.json +8 -2
- package/sample/build_error.txt +0 -0
- package/sample/demo.js +70 -0
- package/sample/package-lock.json +5 -2
- package/sample/package.json +3 -1
- package/sample/scripts/getInfoByCalendar.mjs +36 -0
- package/sample/scripts/getParticipantOpeningHours.mjs +48 -0
- package/sample/src/AllParticipantOpeningHoursTab.jsx +73 -0
- package/sample/src/App2.jsx +39 -2
- package/sample/src/BlazeoConnectionSettings.jsx +1 -1
- package/sample/src/FetchCalendarTab.jsx +70 -20
- package/sample/src/OpeningHoursTab.jsx +78 -0
- package/sample/src/ParticipantInfoTab.jsx +72 -0
- package/sample/src/ParticipantOpeningHoursTab.jsx +88 -0
- package/sample/src/ParticipantTab.jsx +2 -2
- package/src/calendar/blazeoCalendarRelationMethods.ts +19 -0
- package/src/calendar/buildUnifiedCalendarView.ts +322 -0
- package/src/calendar/calendarCreation.ts +179 -0
- package/src/calendar/createCalendar.ts +243 -0
- package/src/calendar/fetchCalendarDetails.ts +226 -0
- package/src/calendar/fetchCalendarWithOpeningHours.ts +99 -0
- package/src/calendar/getAllParticipantOpeningHours.ts +22 -0
- package/src/calendar/getOpeningHours.ts +10 -0
- package/src/calendar/getParticipantOpeningHours.ts +46 -0
- package/src/calendar/getParticipants.ts +9 -0
- package/src/calendar/mapCalendarToBlazeoSnapshot.ts +46 -0
- package/src/config/applyBlazeoDefaults.ts +13 -0
- package/src/config/blazeoClientDefaults.ts +11 -0
- package/src/config/initializeAppointmentClient.ts +18 -0
- package/src/events/appointmentEventFacade.ts +148 -0
- package/src/events/mapAppointmentToEventSnapshot.ts +65 -0
- package/src/exampleData.ts +79 -0
- package/src/index.ts +45 -0
- package/src/models/CalendarRootModel.ts +60 -0
- package/tsconfig.json +16 -0
- package/blazeo.com-appointment-client-1.0.5.tgz +0 -0
package/sample/src/App2.jsx
CHANGED
|
@@ -6,16 +6,25 @@ import {
|
|
|
6
6
|
import { CalendarTab } from "./CalendarTab.jsx";
|
|
7
7
|
import { EventTab } from "./EventTab.jsx";
|
|
8
8
|
import { ParticipantTab } from "./ParticipantTab.jsx";
|
|
9
|
+
import { ParticipantInfoTab } from "./ParticipantInfoTab.jsx";
|
|
10
|
+
import { ParticipantOpeningHoursTab } from "./ParticipantOpeningHoursTab.jsx";
|
|
11
|
+
import { AllParticipantOpeningHoursTab } from "./AllParticipantOpeningHoursTab.jsx";
|
|
9
12
|
import { AvailabilityTab } from "./AvailabilityTab.jsx";
|
|
10
13
|
import { CreateCalendarTab } from "./CreateCalendarTab.jsx";
|
|
11
14
|
import { FetchCalendarTab } from "./FetchCalendarTab.jsx";
|
|
15
|
+
import { OpeningHoursTab } from "./OpeningHoursTab.jsx";
|
|
12
16
|
|
|
13
17
|
const TABS = [
|
|
14
18
|
{ id: "calendar", label: "Calendar" },
|
|
15
|
-
|
|
19
|
+
/** `FetchCalendarTab` → `fetchCalendarDetails` + `calendarView` (unified object). */
|
|
20
|
+
{ id: "fetch", label: "Fetch · calendarView" },
|
|
16
21
|
{ id: "create", label: "Create calendar" },
|
|
17
22
|
{ id: "event", label: "Event" },
|
|
18
23
|
{ id: "participant", label: "Participant" },
|
|
24
|
+
{ id: "participant-info", label: "Participant info" },
|
|
25
|
+
{ id: "opening-hours", label: "Opening Hours" },
|
|
26
|
+
{ id: "participant-opening-hours", label: "Participant opening hours" },
|
|
27
|
+
{ id: "all-participant-opening-hours", label: "All participant opening hours" },
|
|
19
28
|
{ id: "availability", label: "Availability / booking" },
|
|
20
29
|
];
|
|
21
30
|
|
|
@@ -80,7 +89,7 @@ function AppShell() {
|
|
|
80
89
|
<main className="page">
|
|
81
90
|
<header className="header">
|
|
82
91
|
<h1>appointment-client</h1>
|
|
83
|
-
<p className="muted">Browser sample —
|
|
92
|
+
<p className="muted">Browser sample — use tab <strong>Fetch · calendarView</strong> for the unified <code>calendarView</code> object.</p>
|
|
84
93
|
</header>
|
|
85
94
|
|
|
86
95
|
<ConnectionSettingsCard />
|
|
@@ -128,6 +137,34 @@ function AppShell() {
|
|
|
128
137
|
<ParticipantTab />
|
|
129
138
|
</section>
|
|
130
139
|
)}
|
|
140
|
+
{activeId === "participant-info" && (
|
|
141
|
+
<section role="tabpanel" id="panel-participant-info" aria-labelledby="tab-participant-info">
|
|
142
|
+
<ParticipantInfoTab />
|
|
143
|
+
</section>
|
|
144
|
+
)}
|
|
145
|
+
{activeId === "opening-hours" && (
|
|
146
|
+
<section role="tabpanel" id="panel-opening-hours" aria-labelledby="tab-opening-hours">
|
|
147
|
+
<OpeningHoursTab />
|
|
148
|
+
</section>
|
|
149
|
+
)}
|
|
150
|
+
{activeId === "participant-opening-hours" && (
|
|
151
|
+
<section
|
|
152
|
+
role="tabpanel"
|
|
153
|
+
id="panel-participant-opening-hours"
|
|
154
|
+
aria-labelledby="tab-participant-opening-hours"
|
|
155
|
+
>
|
|
156
|
+
<ParticipantOpeningHoursTab />
|
|
157
|
+
</section>
|
|
158
|
+
)}
|
|
159
|
+
{activeId === "all-participant-opening-hours" && (
|
|
160
|
+
<section
|
|
161
|
+
role="tabpanel"
|
|
162
|
+
id="panel-all-participant-opening-hours"
|
|
163
|
+
aria-labelledby="tab-all-participant-opening-hours"
|
|
164
|
+
>
|
|
165
|
+
<AllParticipantOpeningHoursTab />
|
|
166
|
+
</section>
|
|
167
|
+
)}
|
|
131
168
|
{activeId === "availability" && (
|
|
132
169
|
<section role="tabpanel" id="panel-availability" aria-labelledby="tab-availability">
|
|
133
170
|
<AvailabilityTab />
|
|
@@ -45,7 +45,7 @@ export function mergeBlazeoUiWithFile(uiBaseUrl, uiConsumer) {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
|
-
* Re-apply global Blazeo `configure` from the
|
|
48
|
+
* Re-apply global Blazeo `configure` from the effective connection card state.
|
|
49
49
|
* Call at the start of any handler that uses `CalendarModel` / `EventModel` HTTP so
|
|
50
50
|
* `getParticipantOpeningHours` (instance env) and static helpers always see the same
|
|
51
51
|
* `baseUrl`.
|
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
CalendarModel,
|
|
4
4
|
deleteCalendarAsync,
|
|
5
5
|
fetchCalendarDetails,
|
|
6
|
-
fetchCalendarWithOpeningHours,
|
|
7
6
|
updateCalendarAsync,
|
|
8
7
|
} from "appointment-client";
|
|
9
8
|
import { getSnapshot, isStateTreeNode } from "mobx-state-tree";
|
|
@@ -53,8 +52,10 @@ function explainFetchFailure(err, configuredBaseUrl) {
|
|
|
53
52
|
return `${msg}\n\n${proxyHint}`;
|
|
54
53
|
}
|
|
55
54
|
|
|
56
|
-
/** Opening hours list from
|
|
55
|
+
/** Opening hours list from `calendarView`, embedded `calendar.openingHours`, or legacy `openingHours`. */
|
|
57
56
|
function pickOpeningHoursListFromBundle(parsed) {
|
|
57
|
+
const fromView = parsed?.calendarView?.openingHours;
|
|
58
|
+
if (Array.isArray(fromView) && fromView.length > 0) return fromView;
|
|
58
59
|
const fromCal = parsed?.calendar?.openingHours;
|
|
59
60
|
if (Array.isArray(fromCal) && fromCal.length > 0) return fromCal;
|
|
60
61
|
const oh = parsed?.openingHours;
|
|
@@ -81,7 +82,7 @@ function OpeningHoursSummary({ outputJson }) {
|
|
|
81
82
|
return (
|
|
82
83
|
<p className="muted small" style={{ marginBottom: "0.75rem" }}>
|
|
83
84
|
No opening-hours rows parsed for the table. Check{" "}
|
|
84
|
-
<code>calendar.openingHours</code> or <code>openingHours</code> in the JSON below.
|
|
85
|
+
<code>calendar.openingHours</code>, <code>calendarView.openingHours</code>, or <code>openingHours</code> in the JSON below.
|
|
85
86
|
</p>
|
|
86
87
|
);
|
|
87
88
|
}
|
|
@@ -218,7 +219,7 @@ export function FetchCalendarTab() {
|
|
|
218
219
|
|
|
219
220
|
setBusy(true);
|
|
220
221
|
try {
|
|
221
|
-
const details = await fetchCalendarDetails(id
|
|
222
|
+
const details = await fetchCalendarDetails(id);
|
|
222
223
|
|
|
223
224
|
if (details.cal == null) {
|
|
224
225
|
const raw = await CalendarModel.getRaw(id);
|
|
@@ -231,16 +232,36 @@ export function FetchCalendarTab() {
|
|
|
231
232
|
setLastFetchUpdatePayload(JSON.stringify(calendarSnapshotToUpdatePayload(snap), null, 2));
|
|
232
233
|
|
|
233
234
|
const payload = {
|
|
235
|
+
calendarView: details.calendarView,
|
|
234
236
|
calendar: details.calendar,
|
|
235
237
|
openingHours: details.openingHours,
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
238
|
+
allParticipantOpeningHours: details.allParticipantOpeningHours,
|
|
239
|
+
openingHoursApiResponse: details.participantOpeningHoursResponse ?? null,
|
|
240
|
+
participants: (details.participants ?? []).map((p) => (isStateTreeNode(p) ? getSnapshot(p) : p)),
|
|
241
|
+
participantsInfo: Array.isArray(details.participantsInfo)
|
|
242
|
+
? details.participantsInfo.map((p) => (isStateTreeNode(p) ? getSnapshot(p) : p))
|
|
243
|
+
: details.participantsInfo ?? null,
|
|
244
|
+
__openingHoursMeta: {
|
|
245
|
+
fromCalendarGet: details.fromCalendarGet,
|
|
246
|
+
fromParticipantApi: details.fromParticipantApi,
|
|
247
|
+
calendarViewUsedAllParticipantOpeningHours: details.meta?.calendarViewUsedAllParticipantOpeningHours,
|
|
248
|
+
embeddedCount: details.embeddedFromGet?.length ?? 0,
|
|
249
|
+
resolvedCount: details.openingHours?.length ?? 0,
|
|
250
|
+
},
|
|
239
251
|
meta: details.meta,
|
|
240
252
|
};
|
|
241
253
|
|
|
242
254
|
setOutput(toDisplayJson(payload));
|
|
243
|
-
setNote(
|
|
255
|
+
setNote(
|
|
256
|
+
(details.calendarView
|
|
257
|
+
? "Use `calendarView`: one object (calendar + nested participants with openingHours). "
|
|
258
|
+
: "") +
|
|
259
|
+
(details.fromCalendarGet
|
|
260
|
+
? "Opening hours: embedded on GET /Calendar/Get; participants from GET /Calendar/Participant/All. Single bundle in output."
|
|
261
|
+
: details.fromParticipantApi
|
|
262
|
+
? "Opening hours: GET /Calendar/Participant/OpeningHours/Get; participants from GET /Calendar/Participant/All. Single bundle in output."
|
|
263
|
+
: "Calendar loaded; opening hours empty from both embed + participant API; participants from GET /Calendar/Participant/All.")
|
|
264
|
+
);
|
|
244
265
|
} catch (err) {
|
|
245
266
|
setError(explainFetchFailure(err, effective.baseUrl));
|
|
246
267
|
} finally {
|
|
@@ -264,10 +285,13 @@ export function FetchCalendarTab() {
|
|
|
264
285
|
|
|
265
286
|
setBusy(true);
|
|
266
287
|
try {
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
288
|
+
const byCompany = await CalendarModel.getByCompany(key);
|
|
289
|
+
const list = byCompany?.calendars ?? byCompany;
|
|
290
|
+
if (list == null || !Array.isArray(list) || list.length === 0) {
|
|
291
|
+
setNote(
|
|
292
|
+
"getByCompany returned null or an empty list. (calendar-client ≥1.0.17 returns { calendars, totalCount }.)"
|
|
293
|
+
);
|
|
294
|
+
setOutput(toDisplayJson(byCompany));
|
|
271
295
|
} else {
|
|
272
296
|
const enriched = await Promise.all(
|
|
273
297
|
list.map(async (c) => {
|
|
@@ -276,9 +300,15 @@ export function FetchCalendarTab() {
|
|
|
276
300
|
try {
|
|
277
301
|
const b = await fetchCalendarDetails(id);
|
|
278
302
|
return {
|
|
303
|
+
calendarView: b.calendarView,
|
|
279
304
|
calendar: b.calendar ?? getSnapshot(c),
|
|
280
305
|
openingHours: b.openingHours,
|
|
281
|
-
participants: b.participants,
|
|
306
|
+
participants: (b.participants ?? []).map((p) => (isStateTreeNode(p) ? getSnapshot(p) : p)),
|
|
307
|
+
__openingHoursMeta: {
|
|
308
|
+
fromCalendarGet: b.fromCalendarGet,
|
|
309
|
+
fromParticipantApi: b.fromParticipantApi,
|
|
310
|
+
calendarViewUsedAllParticipantOpeningHours: b.meta?.calendarViewUsedAllParticipantOpeningHours,
|
|
311
|
+
},
|
|
282
312
|
meta: b.meta,
|
|
283
313
|
};
|
|
284
314
|
} catch (err) {
|
|
@@ -292,8 +322,9 @@ export function FetchCalendarTab() {
|
|
|
292
322
|
}
|
|
293
323
|
})
|
|
294
324
|
);
|
|
325
|
+
const total = byCompany?.totalCount ?? list.length;
|
|
295
326
|
setNote(
|
|
296
|
-
`Loaded ${list.length} calendar(s); opening hours + participants
|
|
327
|
+
`Loaded ${list.length} calendar(s) (totalCount=${total}); opening hours (embed → participant API) + participants per calendar.`
|
|
297
328
|
);
|
|
298
329
|
setOutput(toDisplayJson(enriched));
|
|
299
330
|
}
|
|
@@ -410,13 +441,32 @@ export function FetchCalendarTab() {
|
|
|
410
441
|
return (
|
|
411
442
|
<>
|
|
412
443
|
<div className="card">
|
|
413
|
-
<h2>Fetch calendar</h2>
|
|
444
|
+
<h2>Fetch calendar · calendarView</h2>
|
|
445
|
+
<p className="muted small">
|
|
446
|
+
Runs <code>fetchCalendarDetails(calendarId)</code>. JSON field <code>calendarView</code> is first: one object with
|
|
447
|
+
calendar snapshot fields + <code>members</code> + <code>openingHours</code>, and a **new** <code>participants</code> array
|
|
448
|
+
where each participant has their own <code>openingHours</code> nested inside.
|
|
449
|
+
</p>
|
|
450
|
+
<p className="muted small">
|
|
451
|
+
Uses <code>fetchCalendarDetails</code>: legacy <code>openingHours</code> prefers embed on{" "}
|
|
452
|
+
<code>CalendarModel.getRaw</code>, else <code>getParticipantOpeningHours</code>.{" "}
|
|
453
|
+
<code>calendarView.openingHours</code> prefers <code>getAllParticipantOpeningHours</code> (
|
|
454
|
+
<code>GET /Calendar/Participant/OpeningHours/All/Get</code>) when the API returns rows. Members combine{" "}
|
|
455
|
+
<code>CalendarModel.getParticipants</code> + <code>CalendarModel.getParticipantsInfo</code> (each member may
|
|
456
|
+
include <code>participantInfo</code>).
|
|
457
|
+
</p>
|
|
458
|
+
<p className="muted small">
|
|
459
|
+
<strong>Single object in code:</strong> <code>fetchCalendarBundle(calendarId)</code> after{" "}
|
|
460
|
+
<code>initializeAppointmentClient({ baseUrl, consumer })</code> — same unified shape as{" "}
|
|
461
|
+
<code>calendarView</code> below. This tab runs <code>fetchCalendarDetails</code> so extra arrays stay visible.
|
|
462
|
+
</p>
|
|
414
463
|
<p className="muted small">
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
<code>
|
|
419
|
-
<code
|
|
464
|
+
<strong>DevTools Network:</strong> Each fetch fires <code>/Calendar/Get</code> <strong>twice</strong> (
|
|
465
|
+
<code>CalendarModel.get</code> + <code>getRaw</code>). Other calls use different URLs — filter by{" "}
|
|
466
|
+
<code>Participant</code>, <code>OpeningHours</code>, or <code>GetInfo</code>. Those power{" "}
|
|
467
|
+
<code>calendarView</code>. If you only see <code>Calendar/Get</code> yet the UI JSON has members/hours,
|
|
468
|
+
widen the Network filter ("All") or disable search; if <code>calendarView</code> is empty/missing fields,
|
|
469
|
+
check the <strong>Console</strong> for errors on the participant/opening-hours requests.
|
|
420
470
|
</p>
|
|
421
471
|
<p className="muted small">
|
|
422
472
|
Effective: <code>{effective.baseUrl || "(set connection or blazeoClientDefaults.ts)"}</code>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { fetchCalendarWithOpeningHours } from "appointment-client";
|
|
3
|
+
import {
|
|
4
|
+
configureBlazeoFromEffective,
|
|
5
|
+
useBlazeoConnection,
|
|
6
|
+
} from "./BlazeoConnectionSettings.jsx";
|
|
7
|
+
|
|
8
|
+
export function OpeningHoursTab() {
|
|
9
|
+
const { effective } = useBlazeoConnection();
|
|
10
|
+
const [calendarId, setCalendarId] = useState("");
|
|
11
|
+
const [busy, setBusy] = useState(false);
|
|
12
|
+
const [error, setError] = useState("");
|
|
13
|
+
const [output, setOutput] = useState("");
|
|
14
|
+
|
|
15
|
+
async function handleFetch(e) {
|
|
16
|
+
e.preventDefault();
|
|
17
|
+
setError("");
|
|
18
|
+
setOutput("");
|
|
19
|
+
const id = calendarId.trim();
|
|
20
|
+
if (!id) {
|
|
21
|
+
setError("Enter a calendar id.");
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (!effective.baseUrl) {
|
|
25
|
+
setError("Set Base URL in the connection card above.");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
configureBlazeoFromEffective(effective);
|
|
29
|
+
setBusy(true);
|
|
30
|
+
try {
|
|
31
|
+
const res = await fetchCalendarWithOpeningHours(id);
|
|
32
|
+
setOutput(JSON.stringify(res, null, 2));
|
|
33
|
+
} catch (err) {
|
|
34
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
35
|
+
} finally {
|
|
36
|
+
setBusy(false);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<>
|
|
42
|
+
<div className="card">
|
|
43
|
+
<h2>Opening Hours (Detailed)</h2>
|
|
44
|
+
<p className="muted small">
|
|
45
|
+
Fetches business hours using <code>fetchCalendarWithOpeningHours</code>.
|
|
46
|
+
</p>
|
|
47
|
+
<form onSubmit={handleFetch} className="form">
|
|
48
|
+
<label className="form__label">
|
|
49
|
+
<span>Calendar id</span>
|
|
50
|
+
<input
|
|
51
|
+
type="text"
|
|
52
|
+
className="form__input"
|
|
53
|
+
value={calendarId}
|
|
54
|
+
onChange={(e) => setCalendarId(e.target.value)}
|
|
55
|
+
/>
|
|
56
|
+
</label>
|
|
57
|
+
<button type="submit" className="btn btn--primary" disabled={busy}>
|
|
58
|
+
{busy ? "Loading…" : "Fetch Opening Hours"}
|
|
59
|
+
</button>
|
|
60
|
+
</form>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
{error ? (
|
|
64
|
+
<div className="card card--error" role="alert">
|
|
65
|
+
<h2>Error</h2>
|
|
66
|
+
<pre className="pre-block">{error}</pre>
|
|
67
|
+
</div>
|
|
68
|
+
) : null}
|
|
69
|
+
|
|
70
|
+
{output ? (
|
|
71
|
+
<div className="card card--success">
|
|
72
|
+
<h2>Result</h2>
|
|
73
|
+
<pre className="pre-block">{output}</pre>
|
|
74
|
+
</div>
|
|
75
|
+
) : null}
|
|
76
|
+
</>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { CalendarParticipantModel } from "appointment-client";
|
|
3
|
+
import { configureBlazeoFromEffective, useBlazeoConnection } from "./BlazeoConnectionSettings.jsx";
|
|
4
|
+
|
|
5
|
+
export function ParticipantInfoTab() {
|
|
6
|
+
const { effective } = useBlazeoConnection();
|
|
7
|
+
const [calendarId, setCalendarId] = useState("");
|
|
8
|
+
const [busy, setBusy] = useState(false);
|
|
9
|
+
const [error, setError] = useState("");
|
|
10
|
+
const [output, setOutput] = useState("");
|
|
11
|
+
|
|
12
|
+
async function handleFetch(e) {
|
|
13
|
+
e.preventDefault();
|
|
14
|
+
setError("");
|
|
15
|
+
setOutput("");
|
|
16
|
+
const id = calendarId.trim();
|
|
17
|
+
if (!id) return setError("Enter a calendar id.");
|
|
18
|
+
if (!effective.baseUrl) return setError("Set Base URL in the connection card above.");
|
|
19
|
+
|
|
20
|
+
configureBlazeoFromEffective(effective);
|
|
21
|
+
setBusy(true);
|
|
22
|
+
try {
|
|
23
|
+
const info = await CalendarParticipantModel.getInfoByCalendar(id);
|
|
24
|
+
setOutput(JSON.stringify({ calendarId: id, count: Array.isArray(info) ? info.length : 0, info }, null, 2));
|
|
25
|
+
} catch (err) {
|
|
26
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
27
|
+
} finally {
|
|
28
|
+
setBusy(false);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<>
|
|
34
|
+
<div className="card">
|
|
35
|
+
<h2>Participant Info by Calendar</h2>
|
|
36
|
+
<p className="muted small">
|
|
37
|
+
Calls <code>CalendarParticipantModel.getInfoByCalendar(calendarId)</code>.
|
|
38
|
+
</p>
|
|
39
|
+
<form onSubmit={handleFetch} className="form">
|
|
40
|
+
<label className="form__label">
|
|
41
|
+
<span>Calendar id</span>
|
|
42
|
+
<input
|
|
43
|
+
type="text"
|
|
44
|
+
className="form__input"
|
|
45
|
+
value={calendarId}
|
|
46
|
+
onChange={(e) => setCalendarId(e.target.value)}
|
|
47
|
+
autoComplete="off"
|
|
48
|
+
/>
|
|
49
|
+
</label>
|
|
50
|
+
<button type="submit" className="btn btn--secondary" disabled={busy}>
|
|
51
|
+
{busy ? "Loading…" : "Fetch participant info"}
|
|
52
|
+
</button>
|
|
53
|
+
</form>
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
{error ? (
|
|
57
|
+
<div className="card card--error" role="alert">
|
|
58
|
+
<h2>Error</h2>
|
|
59
|
+
<pre className="pre-block">{error}</pre>
|
|
60
|
+
</div>
|
|
61
|
+
) : null}
|
|
62
|
+
|
|
63
|
+
{output ? (
|
|
64
|
+
<div className="card card--success">
|
|
65
|
+
<h2>Result</h2>
|
|
66
|
+
<pre className="pre-block">{output}</pre>
|
|
67
|
+
</div>
|
|
68
|
+
) : null}
|
|
69
|
+
</>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { getParticipantOpeningHours } from "appointment-client";
|
|
3
|
+
import { configureBlazeoFromEffective, useBlazeoConnection } from "./BlazeoConnectionSettings.jsx";
|
|
4
|
+
|
|
5
|
+
export function ParticipantOpeningHoursTab() {
|
|
6
|
+
const { effective } = useBlazeoConnection();
|
|
7
|
+
const [calendarId, setCalendarId] = useState("");
|
|
8
|
+
const [busy, setBusy] = useState(false);
|
|
9
|
+
const [error, setError] = useState("");
|
|
10
|
+
const [output, setOutput] = useState("");
|
|
11
|
+
|
|
12
|
+
async function handleFetch(e) {
|
|
13
|
+
e.preventDefault();
|
|
14
|
+
setError("");
|
|
15
|
+
setOutput("");
|
|
16
|
+
const id = calendarId.trim();
|
|
17
|
+
if (!id) return setError("Enter a calendar id.");
|
|
18
|
+
if (!effective.baseUrl) return setError("Set Base URL in the connection card above.");
|
|
19
|
+
|
|
20
|
+
configureBlazeoFromEffective(effective);
|
|
21
|
+
setBusy(true);
|
|
22
|
+
try {
|
|
23
|
+
debugger;
|
|
24
|
+
const result = await getParticipantOpeningHours(id);
|
|
25
|
+
|
|
26
|
+
if (!result.meta.ok) {
|
|
27
|
+
setError(result.meta.error || `Failed to fetch: ${result.meta.reason}`);
|
|
28
|
+
if (result.raw) setOutput(JSON.stringify(result.raw, null, 2));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
setOutput(JSON.stringify({
|
|
33
|
+
calendarId: id,
|
|
34
|
+
count: result.openingHours.length,
|
|
35
|
+
openingHours: result.openingHours,
|
|
36
|
+
raw: result.raw,
|
|
37
|
+
meta: result.meta
|
|
38
|
+
}, null, 2));
|
|
39
|
+
} catch (err) {
|
|
40
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
41
|
+
} finally {
|
|
42
|
+
setBusy(false);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<>
|
|
48
|
+
<div className="card">
|
|
49
|
+
<h2>Participant Opening Hours (Direct)</h2>
|
|
50
|
+
<p className="muted small">
|
|
51
|
+
Calls <code>CalendarModel.get(calendarId)</code> then{" "}
|
|
52
|
+
<code>calendar.getParticipantOpeningHours({})</code> (API:{" "}
|
|
53
|
+
<code>GET /Calendar/Participant/OpeningHours/Get</code>).
|
|
54
|
+
</p>
|
|
55
|
+
<form onSubmit={handleFetch} className="form">
|
|
56
|
+
<label className="form__label">
|
|
57
|
+
<span>Calendar id</span>
|
|
58
|
+
<input
|
|
59
|
+
type="text"
|
|
60
|
+
className="form__input"
|
|
61
|
+
value={calendarId}
|
|
62
|
+
onChange={(e) => setCalendarId(e.target.value)}
|
|
63
|
+
autoComplete="off"
|
|
64
|
+
/>
|
|
65
|
+
</label>
|
|
66
|
+
<button type="submit" className="btn btn--secondary" disabled={busy}>
|
|
67
|
+
{busy ? "Loading…" : "Fetch participant opening hours"}
|
|
68
|
+
</button>
|
|
69
|
+
</form>
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
{error ? (
|
|
73
|
+
<div className="card card--error" role="alert">
|
|
74
|
+
<h2>Error</h2>
|
|
75
|
+
<pre className="pre-block">{error}</pre>
|
|
76
|
+
</div>
|
|
77
|
+
) : null}
|
|
78
|
+
|
|
79
|
+
{output ? (
|
|
80
|
+
<div className="card card--success">
|
|
81
|
+
<h2>Result</h2>
|
|
82
|
+
<pre className="pre-block">{output}</pre>
|
|
83
|
+
</div>
|
|
84
|
+
) : null}
|
|
85
|
+
</>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useMemo, useState } from "react";
|
|
2
|
-
import { getExampleParticipants,
|
|
2
|
+
import { getExampleParticipants, getParticipants } from "appointment-client";
|
|
3
3
|
import { getSnapshot, isStateTreeNode } from "mobx-state-tree";
|
|
4
4
|
import {
|
|
5
5
|
configureBlazeoFromEffective,
|
|
@@ -43,7 +43,7 @@ export function ParticipantTab() {
|
|
|
43
43
|
configureBlazeoFromEffective(effective);
|
|
44
44
|
setBusy(true);
|
|
45
45
|
try {
|
|
46
|
-
const res = await
|
|
46
|
+
const res = await getParticipants(id);
|
|
47
47
|
setOutput(toDisplayJson(res));
|
|
48
48
|
} catch (err) {
|
|
49
49
|
setError(err instanceof Error ? err.message : String(err));
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** `GET /Calendar/Participant/Add` — attach `participantId` to this calendar. */
|
|
2
|
+
export function addParticipantToCalendar(calendar: any, participantId: string) {
|
|
3
|
+
return calendar.addParticipant(participantId);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
/** `GET /Calendar/Participant/Remove` */
|
|
7
|
+
export function removeParticipantFromCalendar(calendar: any, participantId: string) {
|
|
8
|
+
return calendar.removeParticipant(participantId);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** `POST /Calendar/Participant/Availability/OpeningHour/Save` — one day/slot. */
|
|
12
|
+
export function saveCalendarOpeningHour(calendar: any, payload: any) {
|
|
13
|
+
return calendar.saveOpeningHour(payload);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** `POST /Calendar/Participant/Availability/OpeningHours/Save` — batch body (API-specific shape). */
|
|
17
|
+
export function saveCalendarOpeningHoursBatch(calendar: any, payload: any) {
|
|
18
|
+
return calendar.saveOpeningHours(payload);
|
|
19
|
+
}
|