@blazeo.com/appointment-client 1.0.5 → 1.0.7
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.7.tgz +0 -0
- package/dist/calendar/blazeoCalendarRelationMethods.d.ts +4 -36
- package/dist/calendar/blazeoCalendarRelationMethods.js +0 -1
- package/dist/calendar/buildUnifiedCalendarView.d.ts +39 -0
- package/dist/calendar/buildUnifiedCalendarView.js +280 -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 +41 -18
- package/dist/calendar/fetchCalendarDetails.js +261 -51
- package/dist/calendar/fetchCalendarWithOpeningHours.d.ts +25 -21
- package/dist/calendar/fetchCalendarWithOpeningHours.js +114 -75
- package/dist/calendar/getAllParticipantOpeningHours.d.ts +22 -0
- package/dist/calendar/getAllParticipantOpeningHours.js +22 -0
- package/dist/calendar/getOpeningHours.d.ts +8 -0
- package/dist/calendar/getOpeningHours.js +9 -0
- package/dist/calendar/getParticipantOpeningHours.d.ts +37 -0
- package/dist/calendar/getParticipantOpeningHours.js +48 -0
- package/dist/calendar/getParticipants.d.ts +7 -0
- package/dist/calendar/getParticipants.js +13 -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/calendar/mapToDesiredResponse.d.ts +70 -0
- package/dist/calendar/mapToDesiredResponse.js +99 -0
- 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 +3 -3
- 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 +2 -3
- package/dist/config/ensureBlazeoHttpReady.d.ts +17 -0
- package/dist/config/ensureBlazeoHttpReady.js +31 -0
- package/dist/config/initializeAppointmentClient.d.ts +8 -28
- package/dist/config/initializeAppointmentClient.js +11 -24
- package/dist/config/syncBlazeoConnection.d.ts +6 -0
- package/dist/config/syncBlazeoConnection.js +18 -0
- 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 +26 -82
- package/dist/index.js +23 -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/.env.example +5 -0
- 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 +82 -0
- package/sample/src/App2.jsx +60 -3
- package/sample/src/AvailabilityTab.jsx +8 -3
- package/sample/src/BlazeoConnectionSettings.jsx +17 -16
- package/sample/src/CreateCalendarTab.jsx +23 -6
- package/sample/src/EventTab.jsx +31 -8
- package/sample/src/FetchCalendarTab.jsx +114 -38
- package/sample/src/OpeningHoursTab.jsx +87 -0
- package/sample/src/ParticipantInfoTab.jsx +77 -0
- package/sample/src/ParticipantOpeningHoursTab.jsx +98 -0
- package/sample/src/ParticipantTab.jsx +13 -4
- package/sample/src/blazeoBootstrap.js +30 -0
- package/sample/src/blazeoDemoError.js +14 -0
- package/sample/src/blazeoPushConnection.js +23 -0
- package/sample/src/main.jsx +3 -3
- package/sample/vite.config.js +19 -5
- package/src/calendar/blazeoCalendarRelationMethods.ts +19 -0
- package/src/calendar/buildUnifiedCalendarView.ts +345 -0
- package/src/calendar/calendarCreation.ts +179 -0
- package/src/calendar/createCalendar.ts +243 -0
- package/src/calendar/fetchCalendarDetails.ts +316 -0
- package/src/calendar/fetchCalendarWithOpeningHours.ts +130 -0
- package/src/calendar/getAllParticipantOpeningHours.ts +30 -0
- package/src/calendar/getOpeningHours.ts +10 -0
- package/src/calendar/getParticipantOpeningHours.ts +55 -0
- package/src/calendar/getParticipants.ts +17 -0
- package/src/calendar/mapCalendarToBlazeoSnapshot.ts +46 -0
- package/src/calendar/mapToDesiredResponse.ts +104 -0
- package/src/config/applyBlazeoDefaults.ts +14 -0
- package/src/config/blazeoClientDefaults.ts +11 -0
- package/src/config/ensureBlazeoHttpReady.ts +41 -0
- package/src/config/initializeAppointmentClient.ts +24 -0
- package/src/config/syncBlazeoConnection.ts +19 -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 +51 -0
- package/src/models/CalendarRootModel.ts +60 -0
- package/tsconfig.json +16 -0
- package/blazeo.com-appointment-client-1.0.5.tgz +0 -0
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
useMemo,
|
|
7
7
|
useState,
|
|
8
8
|
} from "react";
|
|
9
|
-
import { blazeoClientConfig
|
|
10
|
-
import {
|
|
9
|
+
import { blazeoClientConfig } from "appointment-client";
|
|
10
|
+
import { pushBlazeoConnection } from "./blazeoPushConnection.js";
|
|
11
11
|
|
|
12
12
|
const STORAGE_BASE = "appointment-client-sample:blazeoBaseUrl";
|
|
13
13
|
const STORAGE_CONSUMER = "appointment-client-sample:blazeoConsumer";
|
|
@@ -45,19 +45,11 @@ export function mergeBlazeoUiWithFile(uiBaseUrl, uiConsumer) {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
|
-
* Re-apply global Blazeo `configure` from the
|
|
49
|
-
*
|
|
50
|
-
* `getParticipantOpeningHours` (instance env) and static helpers always see the same
|
|
51
|
-
* `baseUrl`.
|
|
48
|
+
* Re-apply global Blazeo `configure` from the effective connection card state.
|
|
49
|
+
* Pushes into both calendar-client entrypoints ({@link pushBlazeoConnection}).
|
|
52
50
|
*/
|
|
53
51
|
export function configureBlazeoFromEffective(effective) {
|
|
54
|
-
|
|
55
|
-
if (!baseUrl) return;
|
|
56
|
-
const consumer = (effective?.consumer ?? "").trim() || undefined;
|
|
57
|
-
// Configure appointment-client (which configures its internal calendar-client instance)
|
|
58
|
-
initializeAppointmentClient({ baseUrl, ...(consumer ? { consumer } : {}) });
|
|
59
|
-
// Also configure the calendar-client instance that the sample (and Vite alias) may resolve.
|
|
60
|
-
configureCalendarClient({ baseUrl, ...(consumer ? { consumer } : {}) });
|
|
52
|
+
pushBlazeoConnection(effective);
|
|
61
53
|
}
|
|
62
54
|
|
|
63
55
|
const BlazeoConnectionContext = createContext(null);
|
|
@@ -71,6 +63,15 @@ export function BlazeoConnectionProvider({ children }) {
|
|
|
71
63
|
[baseUrlInput, consumerInput]
|
|
72
64
|
);
|
|
73
65
|
|
|
66
|
+
/** Pass into `fetchCalendarDetails`, `createCalendarAsync`, etc. (explicit `baseUrl` for `ensureBlazeoHttpReady`). */
|
|
67
|
+
const connectionOpts = useMemo(
|
|
68
|
+
() => ({
|
|
69
|
+
...(effective.baseUrl ? { baseUrl: effective.baseUrl } : {}),
|
|
70
|
+
...(effective.consumer ? { consumer: effective.consumer } : {}),
|
|
71
|
+
}),
|
|
72
|
+
[effective.baseUrl, effective.consumer]
|
|
73
|
+
);
|
|
74
|
+
|
|
74
75
|
useEffect(() => {
|
|
75
76
|
writeStored(STORAGE_BASE, baseUrlInput.trim());
|
|
76
77
|
}, [baseUrlInput]);
|
|
@@ -87,8 +88,7 @@ export function BlazeoConnectionProvider({ children }) {
|
|
|
87
88
|
useLayoutEffect(() => {
|
|
88
89
|
const { baseUrl, consumer } = mergeBlazeoUiWithFile(baseUrlInput, consumerInput);
|
|
89
90
|
if (!baseUrl) return;
|
|
90
|
-
|
|
91
|
-
configureCalendarClient({ baseUrl, ...(consumer ? { consumer } : {}) });
|
|
91
|
+
pushBlazeoConnection({ baseUrl, consumer });
|
|
92
92
|
}, [baseUrlInput, consumerInput]);
|
|
93
93
|
|
|
94
94
|
const value = useMemo(
|
|
@@ -98,8 +98,9 @@ export function BlazeoConnectionProvider({ children }) {
|
|
|
98
98
|
setBaseUrlInput,
|
|
99
99
|
setConsumerInput,
|
|
100
100
|
effective,
|
|
101
|
+
connectionOpts,
|
|
101
102
|
}),
|
|
102
|
-
[baseUrlInput, consumerInput, effective]
|
|
103
|
+
[baseUrlInput, consumerInput, effective, connectionOpts]
|
|
103
104
|
);
|
|
104
105
|
|
|
105
106
|
return (
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { useMemo, useState } from "react";
|
|
2
|
-
import { createCalendarAsync, createCalendarWithRelationsAsync } from "appointment-client";
|
|
2
|
+
import { createCalendarAsync, createCalendarWithRelationsAsync, ensureBlazeoHttpReady } from "appointment-client";
|
|
3
3
|
import { getSnapshot } from "mobx-state-tree";
|
|
4
4
|
import { configureBlazeoFromEffective, useBlazeoConnection } from "./BlazeoConnectionSettings.jsx";
|
|
5
|
+
import { mapBlazeoDemoError } from "./blazeoDemoError.js";
|
|
5
6
|
|
|
6
7
|
/** Demo payload aligned with `CalendarBOInput` / server `CalendarBO`. */
|
|
7
8
|
export function getExampleCalendarBOInput() {
|
|
@@ -38,7 +39,7 @@ export function getExampleCalendarBOInput() {
|
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
export function CreateCalendarTab() {
|
|
41
|
-
const { effective } = useBlazeoConnection();
|
|
42
|
+
const { effective, connectionOpts } = useBlazeoConnection();
|
|
42
43
|
const [localOnly, setLocalOnly] = useState(false);
|
|
43
44
|
const [saveRelations, setSaveRelations] = useState(true);
|
|
44
45
|
const [busy, setBusy] = useState(false);
|
|
@@ -70,7 +71,13 @@ export function CreateCalendarTab() {
|
|
|
70
71
|
setError("Set Base URL in the connection card above.");
|
|
71
72
|
return;
|
|
72
73
|
}
|
|
73
|
-
if (!localOnly)
|
|
74
|
+
if (!localOnly) {
|
|
75
|
+
configureBlazeoFromEffective(effective);
|
|
76
|
+
ensureBlazeoHttpReady({
|
|
77
|
+
baseUrl: effective.baseUrl,
|
|
78
|
+
...(effective.consumer ? { consumer: effective.consumer } : {}),
|
|
79
|
+
});
|
|
80
|
+
}
|
|
74
81
|
|
|
75
82
|
const hasRelations = (payload.members?.length ?? 0) > 0 || (payload.openingHours?.length ?? 0) > 0;
|
|
76
83
|
const useRelations = saveRelations && hasRelations && !localOnly;
|
|
@@ -78,10 +85,20 @@ export function CreateCalendarTab() {
|
|
|
78
85
|
setBusy(true);
|
|
79
86
|
try {
|
|
80
87
|
const result = useRelations
|
|
81
|
-
? await createCalendarWithRelationsAsync(payload, {
|
|
82
|
-
|
|
88
|
+
? await createCalendarWithRelationsAsync(payload, {
|
|
89
|
+
localOnly,
|
|
90
|
+
...connectionOpts,
|
|
91
|
+
baseUrl: effective.baseUrl,
|
|
92
|
+
...(effective.consumer ? { consumer: effective.consumer } : {}),
|
|
93
|
+
})
|
|
94
|
+
: await createCalendarAsync(payload, {
|
|
95
|
+
localOnly,
|
|
96
|
+
...connectionOpts,
|
|
97
|
+
baseUrl: effective.baseUrl,
|
|
98
|
+
...(effective.consumer ? { consumer: effective.consumer } : {}),
|
|
99
|
+
});
|
|
83
100
|
setOutput(JSON.stringify(result.ok ? getSnapshot(result.calendar) : result, null, 2));
|
|
84
|
-
if (!result.ok) setError(result.error);
|
|
101
|
+
if (!result.ok) setError(mapBlazeoDemoError(result.error));
|
|
85
102
|
} finally {
|
|
86
103
|
setBusy(false);
|
|
87
104
|
}
|
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
|
+
ensureBlazeoHttpReady,
|
|
5
6
|
EventModel,
|
|
6
7
|
rescheduleAppointmentEventAsync,
|
|
7
8
|
} from "appointment-client";
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
configureBlazeoFromEffective,
|
|
11
12
|
useBlazeoConnection,
|
|
12
13
|
} from "./BlazeoConnectionSettings.jsx";
|
|
14
|
+
import { mapBlazeoDemoError } from "./blazeoDemoError.js";
|
|
13
15
|
|
|
14
16
|
function getExampleCreatePayload() {
|
|
15
17
|
const start = new Date();
|
|
@@ -75,7 +77,7 @@ function safeJsonParse(text, fallback) {
|
|
|
75
77
|
}
|
|
76
78
|
|
|
77
79
|
export function EventTab() {
|
|
78
|
-
const { effective } = useBlazeoConnection();
|
|
80
|
+
const { effective, connectionOpts } = useBlazeoConnection();
|
|
79
81
|
const [offsetMinutes, setOffsetMinutes] = useState(-new Date().getTimezoneOffset());
|
|
80
82
|
const [createJson, setCreateJson] = useState(() =>
|
|
81
83
|
JSON.stringify(getExampleCreatePayload(), null, 2)
|
|
@@ -118,6 +120,7 @@ export function EventTab() {
|
|
|
118
120
|
const [output, setOutput] = useState("");
|
|
119
121
|
|
|
120
122
|
const opts = useMemo(() => ({ offsetMinutes: Number(offsetMinutes) || 0 }), [offsetMinutes]);
|
|
123
|
+
const eventOpts = useMemo(() => ({ ...opts, ...connectionOpts }), [opts, connectionOpts]);
|
|
121
124
|
|
|
122
125
|
function ensureBase() {
|
|
123
126
|
if (!effective.baseUrl) {
|
|
@@ -133,6 +136,10 @@ export function EventTab() {
|
|
|
133
136
|
setOutput("");
|
|
134
137
|
if (!ensureBase()) return;
|
|
135
138
|
configureBlazeoFromEffective(effective);
|
|
139
|
+
ensureBlazeoHttpReady({
|
|
140
|
+
baseUrl: effective.baseUrl,
|
|
141
|
+
...(effective.consumer ? { consumer: effective.consumer } : {}),
|
|
142
|
+
});
|
|
136
143
|
let payload;
|
|
137
144
|
try {
|
|
138
145
|
payload = JSON.parse(createJson);
|
|
@@ -142,9 +149,9 @@ export function EventTab() {
|
|
|
142
149
|
}
|
|
143
150
|
setBusy(true);
|
|
144
151
|
try {
|
|
145
|
-
const result = await createAppointmentEventAsync(payload,
|
|
152
|
+
const result = await createAppointmentEventAsync(payload, eventOpts);
|
|
146
153
|
setOutput(resultToJson(result));
|
|
147
|
-
if (!result.ok) setError(result.error);
|
|
154
|
+
if (!result.ok) setError(mapBlazeoDemoError(result.error));
|
|
148
155
|
} finally {
|
|
149
156
|
setBusy(false);
|
|
150
157
|
}
|
|
@@ -156,6 +163,10 @@ export function EventTab() {
|
|
|
156
163
|
setOutput("");
|
|
157
164
|
if (!ensureBase()) return;
|
|
158
165
|
configureBlazeoFromEffective(effective);
|
|
166
|
+
ensureBlazeoHttpReady({
|
|
167
|
+
baseUrl: effective.baseUrl,
|
|
168
|
+
...(effective.consumer ? { consumer: effective.consumer } : {}),
|
|
169
|
+
});
|
|
159
170
|
let payload;
|
|
160
171
|
try {
|
|
161
172
|
payload = JSON.parse(rescheduleJson);
|
|
@@ -165,9 +176,9 @@ export function EventTab() {
|
|
|
165
176
|
}
|
|
166
177
|
setBusy(true);
|
|
167
178
|
try {
|
|
168
|
-
const result = await rescheduleAppointmentEventAsync(payload,
|
|
179
|
+
const result = await rescheduleAppointmentEventAsync(payload, eventOpts);
|
|
169
180
|
setOutput(resultToJson(result));
|
|
170
|
-
if (!result.ok) setError(result.error);
|
|
181
|
+
if (!result.ok) setError(mapBlazeoDemoError(result.error));
|
|
171
182
|
} finally {
|
|
172
183
|
setBusy(false);
|
|
173
184
|
}
|
|
@@ -181,11 +192,19 @@ export function EventTab() {
|
|
|
181
192
|
if (!id) return setError("Enter Blazeo event id to cancel.");
|
|
182
193
|
if (!ensureBase()) return;
|
|
183
194
|
configureBlazeoFromEffective(effective);
|
|
195
|
+
ensureBlazeoHttpReady({
|
|
196
|
+
baseUrl: effective.baseUrl,
|
|
197
|
+
...(effective.consumer ? { consumer: effective.consumer } : {}),
|
|
198
|
+
});
|
|
184
199
|
setBusy(true);
|
|
185
200
|
try {
|
|
186
|
-
const result = await cancelAppointmentEventAsync(id, {
|
|
201
|
+
const result = await cancelAppointmentEventAsync(id, {
|
|
202
|
+
...connectionOpts,
|
|
203
|
+
baseUrl: effective.baseUrl,
|
|
204
|
+
...(effective.consumer ? { consumer: effective.consumer } : {}),
|
|
205
|
+
});
|
|
187
206
|
setOutput(JSON.stringify(result, null, 2));
|
|
188
|
-
if (!result.ok) setError(result.error);
|
|
207
|
+
if (!result.ok) setError(mapBlazeoDemoError(result.error));
|
|
189
208
|
} finally {
|
|
190
209
|
setBusy(false);
|
|
191
210
|
}
|
|
@@ -201,6 +220,10 @@ export function EventTab() {
|
|
|
201
220
|
if (!searchTo) return setError("Pick end date.");
|
|
202
221
|
if (!ensureBase()) return;
|
|
203
222
|
configureBlazeoFromEffective(effective);
|
|
223
|
+
ensureBlazeoHttpReady({
|
|
224
|
+
baseUrl: effective.baseUrl,
|
|
225
|
+
...(effective.consumer ? { consumer: effective.consumer } : {}),
|
|
226
|
+
});
|
|
204
227
|
|
|
205
228
|
const optsFromJson = safeJsonParse(searchFiltersJson, {});
|
|
206
229
|
const startDateFrom = new Date(`${searchFrom}T00:00:00.000Z`).toISOString();
|
|
@@ -221,7 +244,7 @@ export function EventTab() {
|
|
|
221
244
|
const totalCount = res?.totalCount ?? events.length;
|
|
222
245
|
setOutput(JSON.stringify({ totalCount, events }, null, 2));
|
|
223
246
|
} catch (err) {
|
|
224
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
247
|
+
setError(mapBlazeoDemoError(err instanceof Error ? err.message : String(err)));
|
|
225
248
|
} finally {
|
|
226
249
|
setBusy(false);
|
|
227
250
|
}
|
|
@@ -2,12 +2,16 @@ import { useMemo, useState } from "react";
|
|
|
2
2
|
import {
|
|
3
3
|
CalendarModel,
|
|
4
4
|
deleteCalendarAsync,
|
|
5
|
+
ensureBlazeoHttpReady,
|
|
5
6
|
fetchCalendarDetails,
|
|
6
|
-
fetchCalendarWithOpeningHours,
|
|
7
7
|
updateCalendarAsync,
|
|
8
8
|
} from "appointment-client";
|
|
9
9
|
import { getSnapshot, isStateTreeNode } from "mobx-state-tree";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
configureBlazeoFromEffective,
|
|
12
|
+
useBlazeoConnection,
|
|
13
|
+
} from "./BlazeoConnectionSettings.jsx";
|
|
14
|
+
import { mapBlazeoDemoError } from "./blazeoDemoError.js";
|
|
11
15
|
import { getExampleCalendarBOInput } from "./CreateCalendarTab.jsx";
|
|
12
16
|
|
|
13
17
|
function pick(row, ...keys) {
|
|
@@ -33,7 +37,7 @@ function explainFetchFailure(err, configuredBaseUrl) {
|
|
|
33
37
|
msg === "Failed to fetch" ||
|
|
34
38
|
msg === "Load failed" ||
|
|
35
39
|
(err instanceof TypeError && (/fetch/i.test(msg) || /network/i.test(msg)));
|
|
36
|
-
if (!isNetwork) return msg;
|
|
40
|
+
if (!isNetwork) return mapBlazeoDemoError(msg);
|
|
37
41
|
|
|
38
42
|
const isRemote =
|
|
39
43
|
configuredBaseUrl &&
|
|
@@ -53,8 +57,11 @@ function explainFetchFailure(err, configuredBaseUrl) {
|
|
|
53
57
|
return `${msg}\n\n${proxyHint}`;
|
|
54
58
|
}
|
|
55
59
|
|
|
56
|
-
/** Opening hours list from
|
|
60
|
+
/** Opening hours list from `calendarView`, embedded `calendar.openingHours`, or legacy `openingHours`. */
|
|
57
61
|
function pickOpeningHoursListFromBundle(parsed) {
|
|
62
|
+
if (Array.isArray(parsed?.openingHours)) return parsed.openingHours;
|
|
63
|
+
const fromView = parsed?.calendarView?.openingHours;
|
|
64
|
+
if (Array.isArray(fromView) && fromView.length > 0) return fromView;
|
|
58
65
|
const fromCal = parsed?.calendar?.openingHours;
|
|
59
66
|
if (Array.isArray(fromCal) && fromCal.length > 0) return fromCal;
|
|
60
67
|
const oh = parsed?.openingHours;
|
|
@@ -81,7 +88,7 @@ function OpeningHoursSummary({ outputJson }) {
|
|
|
81
88
|
return (
|
|
82
89
|
<p className="muted small" style={{ marginBottom: "0.75rem" }}>
|
|
83
90
|
No opening-hours rows parsed for the table. Check{" "}
|
|
84
|
-
<code>calendar.openingHours</code> or <code>openingHours</code> in the JSON below.
|
|
91
|
+
<code>calendar.openingHours</code>, <code>calendarView.openingHours</code>, or <code>openingHours</code> in the JSON below.
|
|
85
92
|
</p>
|
|
86
93
|
);
|
|
87
94
|
}
|
|
@@ -176,7 +183,7 @@ function calendarSnapshotToUpdatePayload(snap) {
|
|
|
176
183
|
}
|
|
177
184
|
|
|
178
185
|
export function FetchCalendarTab() {
|
|
179
|
-
const { effective } = useBlazeoConnection();
|
|
186
|
+
const { effective, connectionOpts } = useBlazeoConnection();
|
|
180
187
|
const [calendarId, setCalendarId] = useState("");
|
|
181
188
|
const [companyKey, setCompanyKey] = useState("");
|
|
182
189
|
const [busy, setBusy] = useState(false);
|
|
@@ -215,32 +222,48 @@ export function FetchCalendarTab() {
|
|
|
215
222
|
}
|
|
216
223
|
if (!ensureBaseConfigured()) return;
|
|
217
224
|
configureBlazeoFromEffective(effective);
|
|
225
|
+
ensureBlazeoHttpReady({
|
|
226
|
+
baseUrl: effective.baseUrl,
|
|
227
|
+
...(effective.consumer ? { consumer: effective.consumer } : {}),
|
|
228
|
+
});
|
|
218
229
|
|
|
219
230
|
setBusy(true);
|
|
220
231
|
try {
|
|
221
|
-
const details = await fetchCalendarDetails(id, {
|
|
232
|
+
const details = await fetchCalendarDetails(id, {
|
|
233
|
+
...connectionOpts,
|
|
234
|
+
baseUrl: effective.baseUrl,
|
|
235
|
+
...(effective.consumer ? { consumer: effective.consumer } : {}),
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
const meta = details?._meta ?? details?.meta;
|
|
239
|
+
if (meta && !meta.ok && meta.reason === "missing_base_url") {
|
|
240
|
+
setError(mapBlazeoDemoError(meta.detail ?? ""));
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
222
243
|
|
|
223
|
-
if (details
|
|
244
|
+
if (!details) {
|
|
245
|
+
ensureBlazeoHttpReady({
|
|
246
|
+
baseUrl: effective.baseUrl,
|
|
247
|
+
...(effective.consumer ? { consumer: effective.consumer } : {}),
|
|
248
|
+
});
|
|
224
249
|
const raw = await CalendarModel.getRaw(id);
|
|
225
250
|
setNote("CalendarModel.get returned null. Showing CalendarModel.getRaw only.");
|
|
226
251
|
setOutput(toDisplayJson(raw));
|
|
227
252
|
return;
|
|
228
253
|
}
|
|
229
254
|
|
|
230
|
-
const snap = getSnapshot(details.
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
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,
|
|
240
|
-
};
|
|
255
|
+
const snap = details._cal ? getSnapshot(details._cal) : null;
|
|
256
|
+
if (snap) {
|
|
257
|
+
setLastFetchUpdatePayload(JSON.stringify(calendarSnapshotToUpdatePayload(snap), null, 2));
|
|
258
|
+
}
|
|
241
259
|
|
|
242
|
-
|
|
243
|
-
|
|
260
|
+
// If it's the new flat response, just use it directly for output.
|
|
261
|
+
setOutput(toDisplayJson(details));
|
|
262
|
+
|
|
263
|
+
// We can still try to extract meta for the UI if needed
|
|
264
|
+
if (meta) {
|
|
265
|
+
setNote(`Source: ${meta.calendarViewUsedAllParticipantOpeningHours ? "AllParticipantOpeningHours" : "Embedded/ParticipantApi"}`);
|
|
266
|
+
}
|
|
244
267
|
} catch (err) {
|
|
245
268
|
setError(explainFetchFailure(err, effective.baseUrl));
|
|
246
269
|
} finally {
|
|
@@ -261,24 +284,41 @@ export function FetchCalendarTab() {
|
|
|
261
284
|
}
|
|
262
285
|
if (!ensureBaseConfigured()) return;
|
|
263
286
|
configureBlazeoFromEffective(effective);
|
|
287
|
+
ensureBlazeoHttpReady({
|
|
288
|
+
baseUrl: effective.baseUrl,
|
|
289
|
+
...(effective.consumer ? { consumer: effective.consumer } : {}),
|
|
290
|
+
});
|
|
264
291
|
|
|
265
292
|
setBusy(true);
|
|
266
293
|
try {
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
294
|
+
const byCompany = await CalendarModel.getByCompany(key);
|
|
295
|
+
const list = byCompany?.calendars ?? byCompany;
|
|
296
|
+
if (list == null || !Array.isArray(list) || list.length === 0) {
|
|
297
|
+
setNote(
|
|
298
|
+
"getByCompany returned null or an empty list. (calendar-client ≥1.0.17 returns { calendars, totalCount }.)"
|
|
299
|
+
);
|
|
300
|
+
setOutput(toDisplayJson(byCompany));
|
|
271
301
|
} else {
|
|
272
302
|
const enriched = await Promise.all(
|
|
273
303
|
list.map(async (c) => {
|
|
274
304
|
const id = c.calendarId ?? String(c.id ?? "");
|
|
275
305
|
if (!id) return { calendar: getSnapshot(c), openingHours: [], meta: { error: "no id" } };
|
|
276
306
|
try {
|
|
277
|
-
const b = await fetchCalendarDetails(id
|
|
307
|
+
const b = await fetchCalendarDetails(id, {
|
|
308
|
+
...connectionOpts,
|
|
309
|
+
baseUrl: effective.baseUrl,
|
|
310
|
+
...(effective.consumer ? { consumer: effective.consumer } : {}),
|
|
311
|
+
});
|
|
278
312
|
return {
|
|
313
|
+
calendarView: b.calendarView,
|
|
279
314
|
calendar: b.calendar ?? getSnapshot(c),
|
|
280
315
|
openingHours: b.openingHours,
|
|
281
|
-
participants: b.participants,
|
|
316
|
+
participants: (b.participants ?? []).map((p) => (isStateTreeNode(p) ? getSnapshot(p) : p)),
|
|
317
|
+
__openingHoursMeta: {
|
|
318
|
+
fromCalendarGet: b.fromCalendarGet,
|
|
319
|
+
fromParticipantApi: b.fromParticipantApi,
|
|
320
|
+
calendarViewUsedAllParticipantOpeningHours: b.meta?.calendarViewUsedAllParticipantOpeningHours,
|
|
321
|
+
},
|
|
282
322
|
meta: b.meta,
|
|
283
323
|
};
|
|
284
324
|
} catch (err) {
|
|
@@ -292,8 +332,9 @@ export function FetchCalendarTab() {
|
|
|
292
332
|
}
|
|
293
333
|
})
|
|
294
334
|
);
|
|
335
|
+
const total = byCompany?.totalCount ?? list.length;
|
|
295
336
|
setNote(
|
|
296
|
-
`Loaded ${list.length} calendar(s); opening hours + participants
|
|
337
|
+
`Loaded ${list.length} calendar(s) (totalCount=${total}); opening hours (embed → participant API) + participants per calendar.`
|
|
297
338
|
);
|
|
298
339
|
setOutput(toDisplayJson(enriched));
|
|
299
340
|
}
|
|
@@ -338,6 +379,10 @@ export function FetchCalendarTab() {
|
|
|
338
379
|
setMutateOutput("");
|
|
339
380
|
if (!ensureBaseConfigured()) return;
|
|
340
381
|
configureBlazeoFromEffective(effective);
|
|
382
|
+
ensureBlazeoHttpReady({
|
|
383
|
+
baseUrl: effective.baseUrl,
|
|
384
|
+
...(effective.consumer ? { consumer: effective.consumer } : {}),
|
|
385
|
+
});
|
|
341
386
|
let payload;
|
|
342
387
|
try {
|
|
343
388
|
payload = JSON.parse(updateJson);
|
|
@@ -347,7 +392,11 @@ export function FetchCalendarTab() {
|
|
|
347
392
|
}
|
|
348
393
|
setBusy(true);
|
|
349
394
|
try {
|
|
350
|
-
const result = await updateCalendarAsync(payload, {
|
|
395
|
+
const result = await updateCalendarAsync(payload, {
|
|
396
|
+
...connectionOpts,
|
|
397
|
+
baseUrl: effective.baseUrl,
|
|
398
|
+
...(effective.consumer ? { consumer: effective.consumer } : {}),
|
|
399
|
+
});
|
|
351
400
|
if (result.ok) {
|
|
352
401
|
setMutateNote("updateCalendarAsync → POST /Calendar/Event/Update");
|
|
353
402
|
setMutateOutput(
|
|
@@ -361,7 +410,7 @@ export function FetchCalendarTab() {
|
|
|
361
410
|
)
|
|
362
411
|
);
|
|
363
412
|
} else {
|
|
364
|
-
setError(result.error);
|
|
413
|
+
setError(mapBlazeoDemoError(result.error));
|
|
365
414
|
if (result.apiResponse != null) {
|
|
366
415
|
setMutateOutput(JSON.stringify(result.apiResponse, null, 2));
|
|
367
416
|
}
|
|
@@ -383,6 +432,10 @@ export function FetchCalendarTab() {
|
|
|
383
432
|
}
|
|
384
433
|
if (!ensureBaseConfigured()) return;
|
|
385
434
|
configureBlazeoFromEffective(effective);
|
|
435
|
+
ensureBlazeoHttpReady({
|
|
436
|
+
baseUrl: effective.baseUrl,
|
|
437
|
+
...(effective.consumer ? { consumer: effective.consumer } : {}),
|
|
438
|
+
});
|
|
386
439
|
if (
|
|
387
440
|
!window.confirm(
|
|
388
441
|
`Delete calendar "${id}"?\n\nThis calls GET /Calendar/Remove (cannot be undone on the server).`
|
|
@@ -392,12 +445,16 @@ export function FetchCalendarTab() {
|
|
|
392
445
|
}
|
|
393
446
|
setBusy(true);
|
|
394
447
|
try {
|
|
395
|
-
const result = await deleteCalendarAsync(id, {
|
|
448
|
+
const result = await deleteCalendarAsync(id, {
|
|
449
|
+
...connectionOpts,
|
|
450
|
+
baseUrl: effective.baseUrl,
|
|
451
|
+
...(effective.consumer ? { consumer: effective.consumer } : {}),
|
|
452
|
+
});
|
|
396
453
|
if (result.ok) {
|
|
397
454
|
setMutateNote("deleteCalendarAsync → GET /Calendar/Remove");
|
|
398
455
|
setMutateOutput(JSON.stringify({ calendarId: id, apiResponse: result.apiResponse ?? null }, null, 2));
|
|
399
456
|
} else {
|
|
400
|
-
setError(result.error);
|
|
457
|
+
setError(mapBlazeoDemoError(result.error));
|
|
401
458
|
if (result.apiResponse != null) {
|
|
402
459
|
setMutateOutput(JSON.stringify(result.apiResponse, null, 2));
|
|
403
460
|
}
|
|
@@ -410,13 +467,32 @@ export function FetchCalendarTab() {
|
|
|
410
467
|
return (
|
|
411
468
|
<>
|
|
412
469
|
<div className="card">
|
|
413
|
-
<h2>Fetch calendar</h2>
|
|
470
|
+
<h2>Fetch calendar · calendarView</h2>
|
|
471
|
+
<p className="muted small">
|
|
472
|
+
Runs <code>fetchCalendarDetails(calendarId)</code>. JSON field <code>calendarView</code> is first: one object with
|
|
473
|
+
calendar snapshot fields + <code>members</code> + <code>openingHours</code>, and a **new** <code>participants</code> array
|
|
474
|
+
where each participant has their own <code>openingHours</code> nested inside.
|
|
475
|
+
</p>
|
|
476
|
+
<p className="muted small">
|
|
477
|
+
Uses <code>fetchCalendarDetails</code>: legacy <code>openingHours</code> prefers embed on{" "}
|
|
478
|
+
<code>CalendarModel.getRaw</code>, else <code>getParticipantOpeningHours</code>.{" "}
|
|
479
|
+
<code>calendarView.openingHours</code> prefers <code>getAllParticipantOpeningHours</code> (
|
|
480
|
+
<code>GET /Calendar/Participant/OpeningHours/All/Get</code>) when the API returns rows. Members combine{" "}
|
|
481
|
+
<code>CalendarModel.getParticipants</code> + <code>CalendarModel.getParticipantsInfo</code> (each member may
|
|
482
|
+
include <code>participantInfo</code>).
|
|
483
|
+
</p>
|
|
484
|
+
<p className="muted small">
|
|
485
|
+
<strong>Single object in code:</strong> <code>fetchCalendarBundle(calendarId)</code> after{" "}
|
|
486
|
+
<code>initializeAppointmentClient({ baseUrl, consumer })</code> — same unified shape as{" "}
|
|
487
|
+
<code>calendarView</code> below. This tab runs <code>fetchCalendarDetails</code> so extra arrays stay visible.
|
|
488
|
+
</p>
|
|
414
489
|
<p className="muted small">
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
<code>
|
|
419
|
-
<code
|
|
490
|
+
<strong>DevTools Network:</strong> Each fetch fires <code>/Calendar/Get</code> <strong>twice</strong> (
|
|
491
|
+
<code>CalendarModel.get</code> + <code>getRaw</code>). Other calls use different URLs — filter by{" "}
|
|
492
|
+
<code>Participant</code>, <code>OpeningHours</code>, or <code>GetInfo</code>. Those power{" "}
|
|
493
|
+
<code>calendarView</code>. If you only see <code>Calendar/Get</code> yet the UI JSON has members/hours,
|
|
494
|
+
widen the Network filter ("All") or disable search; if <code>calendarView</code> is empty/missing fields,
|
|
495
|
+
check the <strong>Console</strong> for errors on the participant/opening-hours requests.
|
|
420
496
|
</p>
|
|
421
497
|
<p className="muted small">
|
|
422
498
|
Effective: <code>{effective.baseUrl || "(set connection or blazeoClientDefaults.ts)"}</code>
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { ensureBlazeoHttpReady, fetchCalendarWithOpeningHours } from "appointment-client";
|
|
3
|
+
import {
|
|
4
|
+
configureBlazeoFromEffective,
|
|
5
|
+
useBlazeoConnection,
|
|
6
|
+
} from "./BlazeoConnectionSettings.jsx";
|
|
7
|
+
import { mapBlazeoDemoError } from "./blazeoDemoError.js";
|
|
8
|
+
|
|
9
|
+
export function OpeningHoursTab() {
|
|
10
|
+
const { effective, connectionOpts } = useBlazeoConnection();
|
|
11
|
+
const [calendarId, setCalendarId] = useState("");
|
|
12
|
+
const [busy, setBusy] = useState(false);
|
|
13
|
+
const [error, setError] = useState("");
|
|
14
|
+
const [output, setOutput] = useState("");
|
|
15
|
+
|
|
16
|
+
async function handleFetch(e) {
|
|
17
|
+
e.preventDefault();
|
|
18
|
+
setError("");
|
|
19
|
+
setOutput("");
|
|
20
|
+
const id = calendarId.trim();
|
|
21
|
+
if (!id) {
|
|
22
|
+
setError("Enter a calendar id.");
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (!effective.baseUrl) {
|
|
26
|
+
setError("Set Base URL in the connection card above.");
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
configureBlazeoFromEffective(effective);
|
|
30
|
+
ensureBlazeoHttpReady({
|
|
31
|
+
baseUrl: effective.baseUrl,
|
|
32
|
+
...(effective.consumer ? { consumer: effective.consumer } : {}),
|
|
33
|
+
});
|
|
34
|
+
setBusy(true);
|
|
35
|
+
try {
|
|
36
|
+
const res = await fetchCalendarWithOpeningHours(id, {
|
|
37
|
+
...connectionOpts,
|
|
38
|
+
baseUrl: effective.baseUrl,
|
|
39
|
+
...(effective.consumer ? { consumer: effective.consumer } : {}),
|
|
40
|
+
});
|
|
41
|
+
setOutput(JSON.stringify(res, null, 2));
|
|
42
|
+
} catch (err) {
|
|
43
|
+
setError(mapBlazeoDemoError(err instanceof Error ? err.message : String(err)));
|
|
44
|
+
} finally {
|
|
45
|
+
setBusy(false);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<>
|
|
51
|
+
<div className="card">
|
|
52
|
+
<h2>Opening Hours (Detailed)</h2>
|
|
53
|
+
<p className="muted small">
|
|
54
|
+
Fetches business hours using <code>fetchCalendarWithOpeningHours</code>.
|
|
55
|
+
</p>
|
|
56
|
+
<form onSubmit={handleFetch} className="form">
|
|
57
|
+
<label className="form__label">
|
|
58
|
+
<span>Calendar id</span>
|
|
59
|
+
<input
|
|
60
|
+
type="text"
|
|
61
|
+
className="form__input"
|
|
62
|
+
value={calendarId}
|
|
63
|
+
onChange={(e) => setCalendarId(e.target.value)}
|
|
64
|
+
/>
|
|
65
|
+
</label>
|
|
66
|
+
<button type="submit" className="btn btn--primary" disabled={busy}>
|
|
67
|
+
{busy ? "Loading…" : "Fetch 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
|
+
}
|