@blazeo.com/appointment-client 1.0.6 → 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/buildUnifiedCalendarView.d.ts +8 -0
- package/dist/calendar/buildUnifiedCalendarView.js +20 -5
- package/dist/calendar/fetchCalendarDetails.d.ts +8 -40
- package/dist/calendar/fetchCalendarDetails.js +116 -47
- package/dist/calendar/fetchCalendarWithOpeningHours.d.ts +1 -10
- package/dist/calendar/fetchCalendarWithOpeningHours.js +34 -15
- package/dist/calendar/getAllParticipantOpeningHours.d.ts +4 -1
- package/dist/calendar/getAllParticipantOpeningHours.js +6 -1
- package/dist/calendar/getOpeningHours.d.ts +4 -1
- package/dist/calendar/getOpeningHours.js +2 -2
- package/dist/calendar/getParticipantOpeningHours.js +9 -4
- package/dist/calendar/getParticipants.d.ts +4 -1
- package/dist/calendar/getParticipants.js +6 -1
- package/dist/calendar/mapToDesiredResponse.d.ts +70 -0
- package/dist/calendar/mapToDesiredResponse.js +99 -0
- package/dist/config/applyBlazeoDefaults.js +3 -2
- package/dist/config/blazeoClientDefaults.js +2 -2
- package/dist/config/ensureBlazeoHttpReady.d.ts +17 -0
- package/dist/config/ensureBlazeoHttpReady.js +31 -0
- package/dist/config/initializeAppointmentClient.d.ts +4 -0
- package/dist/config/initializeAppointmentClient.js +9 -3
- package/dist/config/syncBlazeoConnection.d.ts +6 -0
- package/dist/config/syncBlazeoConnection.js +18 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +3 -1
- package/package.json +1 -1
- package/sample/.env.example +5 -0
- package/sample/package-lock.json +1 -1
- package/sample/src/AllParticipantOpeningHoursTab.jsx +13 -4
- package/sample/src/App2.jsx +22 -2
- package/sample/src/AvailabilityTab.jsx +8 -3
- package/sample/src/BlazeoConnectionSettings.jsx +16 -15
- package/sample/src/CreateCalendarTab.jsx +23 -6
- package/sample/src/EventTab.jsx +31 -8
- package/sample/src/FetchCalendarTab.jsx +70 -44
- package/sample/src/OpeningHoursTab.jsx +13 -4
- package/sample/src/ParticipantInfoTab.jsx +8 -3
- package/sample/src/ParticipantOpeningHoursTab.jsx +17 -7
- 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/buildUnifiedCalendarView.ts +28 -5
- package/src/calendar/fetchCalendarDetails.ts +316 -226
- package/src/calendar/fetchCalendarWithOpeningHours.ts +130 -99
- package/src/calendar/getAllParticipantOpeningHours.ts +9 -1
- package/src/calendar/getOpeningHours.ts +2 -2
- package/src/calendar/getParticipantOpeningHours.ts +14 -5
- package/src/calendar/getParticipants.ts +9 -1
- package/src/calendar/mapToDesiredResponse.ts +104 -0
- package/src/config/applyBlazeoDefaults.ts +3 -2
- package/src/config/blazeoClientDefaults.ts +2 -2
- package/src/config/ensureBlazeoHttpReady.ts +41 -0
- package/src/config/initializeAppointmentClient.ts +9 -3
- package/src/config/syncBlazeoConnection.ts +19 -0
- package/src/index.ts +7 -1
- package/blazeo.com-appointment-client-1.0.6.tgz +0 -0
|
Binary file
|
|
@@ -6,18 +6,26 @@ export interface UnifiedCalendarMember {
|
|
|
6
6
|
status: number | null;
|
|
7
7
|
/** Full row from Participants/GetInfo (plain object). */
|
|
8
8
|
participantInfo?: Record<string, unknown> | null;
|
|
9
|
+
__typename?: string;
|
|
9
10
|
}
|
|
10
11
|
export interface UnifiedParticipantWithHours extends UnifiedCalendarMember {
|
|
11
12
|
openingHours: UnifiedOpeningHourRow[];
|
|
12
13
|
}
|
|
13
14
|
export interface UnifiedOpeningHourRow {
|
|
15
|
+
id?: number | string;
|
|
16
|
+
createdOn?: string;
|
|
17
|
+
modifiedOn?: string;
|
|
14
18
|
member: number | string;
|
|
19
|
+
openingHourId?: string;
|
|
20
|
+
calendarId?: string;
|
|
21
|
+
participantId?: string;
|
|
15
22
|
days: string[];
|
|
16
23
|
startHour: number;
|
|
17
24
|
startMinute: number;
|
|
18
25
|
endHour: number;
|
|
19
26
|
endMinute: number;
|
|
20
27
|
off: boolean;
|
|
28
|
+
__typename?: string;
|
|
21
29
|
}
|
|
22
30
|
export type UnifiedCalendarView = Record<string, unknown> & {
|
|
23
31
|
members: UnifiedCalendarMember[];
|
|
@@ -206,6 +206,7 @@ export function buildUnifiedCalendarView(calendarSnapshot, openingHoursRows, par
|
|
|
206
206
|
email: email ?? null,
|
|
207
207
|
status: deriveMemberStatus({}, inf),
|
|
208
208
|
participantInfo: participantInfoPlain,
|
|
209
|
+
__typename: "Member",
|
|
209
210
|
});
|
|
210
211
|
}
|
|
211
212
|
}
|
|
@@ -227,13 +228,20 @@ export function buildUnifiedCalendarView(calendarSnapshot, openingHoursRows, par
|
|
|
227
228
|
const endMinute = Number(pick(row, "endMinute", "EndMinute", "end_minute") ?? 0) || 0;
|
|
228
229
|
const off = Boolean(pick(row, "off", "Off"));
|
|
229
230
|
openingHours.push({
|
|
231
|
+
id: pick(row, "id", "Id") ?? 0,
|
|
232
|
+
createdOn: pick(row, "createdOn", "CreatedOn", "created_on") ?? "0001-01-01T00:00:00.000Z",
|
|
233
|
+
modifiedOn: pick(row, "modifiedOn", "ModifiedOn", "modified_on") ?? "0001-01-01T00:00:00.000Z",
|
|
230
234
|
member: memberId,
|
|
235
|
+
openingHourId: pick(row, "openingHourId", "OpeningHourId", "opening_hour_id") ?? "",
|
|
236
|
+
calendarId: pick(row, "calendarId", "CalendarId", "calendar_id") ?? "",
|
|
237
|
+
participantId: pick(row, "participantId", "ParticipantId", "participant_id") ?? "",
|
|
231
238
|
days,
|
|
232
239
|
startHour,
|
|
233
240
|
startMinute,
|
|
234
241
|
endHour,
|
|
235
242
|
endMinute,
|
|
236
243
|
off,
|
|
244
|
+
__typename: "OpeningHour",
|
|
237
245
|
});
|
|
238
246
|
}
|
|
239
247
|
mergeOpeningHoursBySlot(openingHours);
|
|
@@ -242,6 +250,7 @@ export function buildUnifiedCalendarView(calendarSnapshot, openingHoursRows, par
|
|
|
242
250
|
members,
|
|
243
251
|
openingHours,
|
|
244
252
|
participants: buildNestedParticipants(members, openingHours),
|
|
253
|
+
__typename: "Calendar",
|
|
245
254
|
};
|
|
246
255
|
return view;
|
|
247
256
|
}
|
|
@@ -249,17 +258,23 @@ export function buildUnifiedCalendarView(calendarSnapshot, openingHoursRows, par
|
|
|
249
258
|
* Groups opening hours into their respective participant objects.
|
|
250
259
|
*/
|
|
251
260
|
function buildNestedParticipants(members, openingHours) {
|
|
252
|
-
|
|
253
|
-
|
|
261
|
+
const nested = [];
|
|
262
|
+
members.forEach((m) => {
|
|
263
|
+
const hoursForThisMember = openingHours.filter((oh) => {
|
|
254
264
|
const mid = String(oh.member).trim().toLowerCase();
|
|
255
265
|
const pid = String(m.id).trim().toLowerCase();
|
|
256
266
|
return mid === pid;
|
|
257
267
|
});
|
|
258
268
|
// Remove the 'member' field from the nested opening hours as it's redundant.
|
|
259
|
-
const nestedHours =
|
|
260
|
-
|
|
269
|
+
const nestedHours = hoursForThisMember.map(({ member, ...rest }) => ({
|
|
270
|
+
...rest,
|
|
271
|
+
__typename: "OpeningHour"
|
|
272
|
+
}));
|
|
273
|
+
nested.push({
|
|
261
274
|
...m,
|
|
262
275
|
openingHours: nestedHours,
|
|
263
|
-
|
|
276
|
+
__typename: "Member",
|
|
277
|
+
});
|
|
264
278
|
});
|
|
279
|
+
return nested;
|
|
265
280
|
}
|
|
@@ -25,49 +25,17 @@ export declare function fetchCalendarDetails(calendarId: string, options?: {
|
|
|
25
25
|
includeUnifiedCalendarView?: boolean;
|
|
26
26
|
/** Prefer all-participant opening hours for **`calendarView`** when the API returns rows (default `true`). */
|
|
27
27
|
preferAllParticipantOpeningHours?: boolean;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
openingHours: any[];
|
|
33
|
-
participants: any[];
|
|
34
|
-
participantsInfo: any;
|
|
35
|
-
allParticipantOpeningHours: any[] | null;
|
|
36
|
-
embeddedFromGet: any[];
|
|
37
|
-
fromCalendarGet: boolean;
|
|
38
|
-
fromParticipantApi: boolean;
|
|
39
|
-
participantOpeningHoursResponse: any;
|
|
40
|
-
rawGet: any;
|
|
41
|
-
meta: {
|
|
42
|
-
ok: false;
|
|
43
|
-
reason: string;
|
|
44
|
-
};
|
|
45
|
-
} | {
|
|
46
|
-
calendar: any;
|
|
47
|
-
cal: any;
|
|
48
|
-
calendarView: UnifiedCalendarView | null;
|
|
49
|
-
openingHours: any[];
|
|
50
|
-
participants: any[];
|
|
51
|
-
participantsInfo: unknown;
|
|
52
|
-
allParticipantOpeningHours: any[] | null;
|
|
53
|
-
embeddedFromGet: any[];
|
|
54
|
-
fromCalendarGet: boolean;
|
|
55
|
-
fromParticipantApi: boolean;
|
|
56
|
-
participantOpeningHoursResponse: any;
|
|
57
|
-
meta: {
|
|
58
|
-
calendarViewMemberCount?: number | undefined;
|
|
59
|
-
calendarViewOpeningHourCount?: number | undefined;
|
|
60
|
-
ok: true;
|
|
61
|
-
/** `calendarView.openingHours` came from OpeningHours/All/Get */
|
|
62
|
-
calendarViewUsedAllParticipantOpeningHours: boolean;
|
|
63
|
-
reason?: undefined;
|
|
64
|
-
};
|
|
65
|
-
rawGet?: undefined;
|
|
66
|
-
}>;
|
|
28
|
+
/** Optional; applied with `resolveBlazeoConnection` so `CalendarModel.get` sees `baseUrl` without prior global `configure`. */
|
|
29
|
+
baseUrl?: string;
|
|
30
|
+
consumer?: string;
|
|
31
|
+
}): Promise<any>;
|
|
67
32
|
/**
|
|
68
33
|
* Single return value only: unified calendar **`calendarView`** —
|
|
69
34
|
* snapshot fields plus **`members`** (with **`participantInfo`**) plus **`openingHours`**
|
|
70
35
|
* (prefers all-participant opening hours when available). Same shape as `fetchCalendarDetails().calendarView`.
|
|
71
36
|
* Returns **`null`** if the calendar cannot be loaded (`CalendarModel.get`).
|
|
72
37
|
*/
|
|
73
|
-
export declare function fetchCalendarBundle(calendarId: string
|
|
38
|
+
export declare function fetchCalendarBundle(calendarId: string, connection?: {
|
|
39
|
+
baseUrl?: string;
|
|
40
|
+
consumer?: string;
|
|
41
|
+
}): Promise<UnifiedCalendarView | null>;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { CalendarModel } from "@blazeo.com/calendar-client";
|
|
2
|
-
import {
|
|
2
|
+
import { ensureBlazeoHttpReady } from "../config/ensureBlazeoHttpReady.js";
|
|
3
3
|
import { unwrapCalendarGetData, pickOpeningHoursArrayFromCalendarPayload, normalizeParticipantOpeningHoursResponse, } from "./fetchCalendarWithOpeningHours.js";
|
|
4
4
|
import { buildUnifiedCalendarView } from "./buildUnifiedCalendarView.js";
|
|
5
|
+
import { mapToDesiredCalendarResponse } from "./mapToDesiredResponse.js";
|
|
5
6
|
/**
|
|
6
7
|
* Normalizes the REST envelope from `calendar.getParticipantOpeningHours()`
|
|
7
8
|
* (`GET /Calendar/Participant/OpeningHours/Get`) into a plain row array.
|
|
@@ -83,21 +84,37 @@ function unwrapModelList(raw) {
|
|
|
83
84
|
* Server still performs multiple HTTP calls; on the client, **`calendarView`** is returned as **one object**.
|
|
84
85
|
*/
|
|
85
86
|
export async function fetchCalendarDetails(calendarId, options = {}) {
|
|
86
|
-
const { includeParticipantsInfo = false, includeUnifiedCalendarView = true, preferAllParticipantOpeningHours = true, } = options;
|
|
87
|
+
const { includeParticipantsInfo = false, includeUnifiedCalendarView = true, preferAllParticipantOpeningHours = true, baseUrl: optBaseUrl, consumer: optConsumer, } = options;
|
|
88
|
+
const conn = ensureBlazeoHttpReady({ baseUrl: optBaseUrl, consumer: optConsumer });
|
|
89
|
+
if (!conn.ok) {
|
|
90
|
+
return {
|
|
91
|
+
calendar: null,
|
|
92
|
+
cal: null,
|
|
93
|
+
calendarView: null,
|
|
94
|
+
openingHours: [],
|
|
95
|
+
participants: [],
|
|
96
|
+
participantsInfo: null,
|
|
97
|
+
allParticipantOpeningHours: null,
|
|
98
|
+
embeddedFromGet: [],
|
|
99
|
+
fromCalendarGet: false,
|
|
100
|
+
fromParticipantApi: false,
|
|
101
|
+
participantOpeningHoursResponse: null,
|
|
102
|
+
rawGet: null,
|
|
103
|
+
meta: { ok: false, reason: "missing_base_url", detail: conn.error },
|
|
104
|
+
};
|
|
105
|
+
}
|
|
87
106
|
const fetchParticipantsInfo = includeParticipantsInfo || includeUnifiedCalendarView;
|
|
88
107
|
const fetchAllHours = includeUnifiedCalendarView && preferAllParticipantOpeningHours;
|
|
89
|
-
// Calendar: `GET /Calendar/Get` is used
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
]);
|
|
94
|
-
if (cal == null) {
|
|
108
|
+
// Calendar: `GET /Calendar/Get` is used to get the raw data first.
|
|
109
|
+
const rawRes = await CalendarModel.getRaw(calendarId);
|
|
110
|
+
const payload = unwrapCalendarGetData(rawRes);
|
|
111
|
+
if (!payload) {
|
|
95
112
|
return {
|
|
96
113
|
calendar: null,
|
|
97
114
|
cal: null,
|
|
98
115
|
calendarView: null,
|
|
99
116
|
openingHours: [],
|
|
100
|
-
participants:
|
|
117
|
+
participants: null,
|
|
101
118
|
participantsInfo: null,
|
|
102
119
|
allParticipantOpeningHours: null,
|
|
103
120
|
embeddedFromGet: [],
|
|
@@ -108,7 +125,9 @@ export async function fetchCalendarDetails(calendarId, options = {}) {
|
|
|
108
125
|
meta: { ok: false, reason: "calendar_not_found" },
|
|
109
126
|
};
|
|
110
127
|
}
|
|
111
|
-
|
|
128
|
+
// Build the model instance manually to ensure the environment is correctly set.
|
|
129
|
+
// The static CalendarModel.get in calendar-client has a bug where it wraps env in { env: ... }.
|
|
130
|
+
const cal = CalendarModel.create({ ...payload, calendarId }, { baseUrl: conn.baseUrl, consumer: conn.consumer });
|
|
112
131
|
const embedded = pickOpeningHoursArrayFromCalendarPayload(payload) ?? [];
|
|
113
132
|
let participantOpeningHoursResponse = null;
|
|
114
133
|
let resolved = embedded.length > 0 ? embedded : null;
|
|
@@ -124,17 +143,69 @@ export async function fetchCalendarDetails(calendarId, options = {}) {
|
|
|
124
143
|
const participantsViaGetPromise = includeUnifiedCalendarView && typeof getCalPart === "function"
|
|
125
144
|
? getCalPart.call(CalendarModel, calendarId)
|
|
126
145
|
: Promise.resolve(null);
|
|
127
|
-
const [
|
|
128
|
-
|
|
146
|
+
const [participantsRaw, participantsViaGet, participantsInfoRaw, allHoursRaw] = await Promise.all([
|
|
147
|
+
cal.getParticipants(),
|
|
129
148
|
participantsViaGetPromise,
|
|
130
|
-
fetchParticipantsInfo ?
|
|
131
|
-
fetchAllHours ?
|
|
149
|
+
fetchParticipantsInfo ? cal.getParticipantsInfo() : Promise.resolve(null),
|
|
150
|
+
fetchAllHours ? cal.getAllParticipantOpeningHours() : Promise.resolve(null),
|
|
132
151
|
]);
|
|
133
|
-
const
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
const
|
|
137
|
-
const
|
|
152
|
+
const participantList = mergeParticipantSnapshots(unwrapModelList(participantsRaw), unwrapModelList(participantsViaGet));
|
|
153
|
+
const infoList = unwrapModelList(participantsInfoRaw);
|
|
154
|
+
// Merge participantList and infoList to ensure we have all members
|
|
155
|
+
const mergedParticipantsMap = new Map();
|
|
156
|
+
const getAnyId = (obj) => obj.id ?? obj.Id ?? obj.participantId ?? obj.ParticipantId ?? obj.participant_id;
|
|
157
|
+
// 1. Add from standard list
|
|
158
|
+
participantList.forEach((p) => {
|
|
159
|
+
const id = getAnyId(p);
|
|
160
|
+
if (id) {
|
|
161
|
+
mergedParticipantsMap.set(String(id).toLowerCase(), {
|
|
162
|
+
id: id,
|
|
163
|
+
name: p.name ?? p.Name ?? p.alias ?? p.Alias ?? "Member",
|
|
164
|
+
email: p.email ?? p.Email,
|
|
165
|
+
status: p.status ?? p.Status ?? 0,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
// 2. Add from info list (fallback/enrich)
|
|
170
|
+
infoList.forEach((i) => {
|
|
171
|
+
const id = getAnyId(i);
|
|
172
|
+
if (!id)
|
|
173
|
+
return;
|
|
174
|
+
const key = String(id).toLowerCase();
|
|
175
|
+
const existing = mergedParticipantsMap.get(key);
|
|
176
|
+
if (!existing) {
|
|
177
|
+
mergedParticipantsMap.set(key, {
|
|
178
|
+
id: id,
|
|
179
|
+
name: i.alias || i.Alias || i.name || i.Name || "Member",
|
|
180
|
+
email: i.email || i.Email,
|
|
181
|
+
status: i.status ?? i.Status ?? (i.isApproved ? 1 : 0),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
// Enrich existing with email/name if missing
|
|
186
|
+
if (!existing.email)
|
|
187
|
+
existing.email = i.email || i.Email;
|
|
188
|
+
if (!existing.name || existing.name === "Member") {
|
|
189
|
+
existing.name = i.alias || i.Alias || i.name || i.Name || existing.name;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
// 3. Synthetic Fallback: If openingHours reference a member we don't have, add them.
|
|
194
|
+
openingHours.forEach((oh) => {
|
|
195
|
+
const mid = oh.member ?? oh.Member ?? oh.participantId ?? oh.ParticipantId;
|
|
196
|
+
if (mid) {
|
|
197
|
+
const key = String(mid).toLowerCase();
|
|
198
|
+
if (!mergedParticipantsMap.has(key)) {
|
|
199
|
+
mergedParticipantsMap.set(key, {
|
|
200
|
+
id: mid,
|
|
201
|
+
name: "Member",
|
|
202
|
+
email: null,
|
|
203
|
+
status: 0,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
const finalParticipantList = Array.from(mergedParticipantsMap.values());
|
|
138
209
|
const allParticipantOpeningHours = fetchAllHours ? normalizeAllParticipantOpeningHoursResult(allHoursRaw) : null;
|
|
139
210
|
const openingHoursForUnifiedView = includeUnifiedCalendarView &&
|
|
140
211
|
preferAllParticipantOpeningHours &&
|
|
@@ -142,37 +213,34 @@ export async function fetchCalendarDetails(calendarId, options = {}) {
|
|
|
142
213
|
allParticipantOpeningHours.length > 0
|
|
143
214
|
? allParticipantOpeningHours
|
|
144
215
|
: openingHours;
|
|
145
|
-
const
|
|
146
|
-
? buildUnifiedCalendarView(
|
|
216
|
+
const calendarViewRaw = includeUnifiedCalendarView
|
|
217
|
+
? buildUnifiedCalendarView(payload, openingHoursForUnifiedView, finalParticipantList, infoList)
|
|
147
218
|
: null;
|
|
219
|
+
const calendarView = calendarViewRaw ? mapToDesiredCalendarResponse(calendarViewRaw, calendarViewRaw.openingHours, calendarViewRaw.members) : null;
|
|
148
220
|
const unifiedUsedAllEndpoint = includeUnifiedCalendarView &&
|
|
149
221
|
preferAllParticipantOpeningHours &&
|
|
150
222
|
allParticipantOpeningHours != null &&
|
|
151
223
|
allParticipantOpeningHours.length > 0;
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
? {
|
|
170
|
-
calendarViewMemberCount: calendarView.members.length,
|
|
171
|
-
calendarViewOpeningHourCount: calendarView.openingHours.length,
|
|
172
|
-
}
|
|
173
|
-
: {}),
|
|
224
|
+
if (!calendarView)
|
|
225
|
+
return null;
|
|
226
|
+
// Attach metadata as non-enumerable properties so they don't show up in JSON.stringify
|
|
227
|
+
// but are still accessible for debugging if needed.
|
|
228
|
+
Object.defineProperties(calendarView, {
|
|
229
|
+
_cal: { value: cal, enumerable: false },
|
|
230
|
+
_participants: { value: participantList, enumerable: false },
|
|
231
|
+
_openingHours: { value: openingHours, enumerable: false },
|
|
232
|
+
_rawGet: { value: rawRes, enumerable: false },
|
|
233
|
+
_meta: {
|
|
234
|
+
value: {
|
|
235
|
+
ok: true,
|
|
236
|
+
calendarViewUsedAllParticipantOpeningHours: unifiedUsedAllEndpoint,
|
|
237
|
+
calendarViewMemberCount: calendarView.members.length,
|
|
238
|
+
calendarViewOpeningHourCount: calendarView.openingHours.length,
|
|
239
|
+
},
|
|
240
|
+
enumerable: false
|
|
174
241
|
},
|
|
175
|
-
};
|
|
242
|
+
});
|
|
243
|
+
return calendarView;
|
|
176
244
|
}
|
|
177
245
|
/**
|
|
178
246
|
* Single return value only: unified calendar **`calendarView`** —
|
|
@@ -180,13 +248,14 @@ export async function fetchCalendarDetails(calendarId, options = {}) {
|
|
|
180
248
|
* (prefers all-participant opening hours when available). Same shape as `fetchCalendarDetails().calendarView`.
|
|
181
249
|
* Returns **`null`** if the calendar cannot be loaded (`CalendarModel.get`).
|
|
182
250
|
*/
|
|
183
|
-
export async function fetchCalendarBundle(calendarId) {
|
|
251
|
+
export async function fetchCalendarBundle(calendarId, connection) {
|
|
184
252
|
const d = await fetchCalendarDetails(calendarId, {
|
|
185
253
|
includeUnifiedCalendarView: true,
|
|
186
254
|
includeParticipantsInfo: true,
|
|
187
255
|
preferAllParticipantOpeningHours: true,
|
|
256
|
+
...connection,
|
|
188
257
|
});
|
|
189
|
-
if (!d
|
|
258
|
+
if (!d)
|
|
190
259
|
return null;
|
|
191
|
-
return d
|
|
260
|
+
return d;
|
|
192
261
|
}
|
|
@@ -22,13 +22,4 @@ export declare function normalizeParticipantOpeningHoursResponse(res: any): {
|
|
|
22
22
|
* 1. Prefer rows embedded on **GET /Calendar/Get** (`CalendarModel.getRaw` payload — `@blazeo.com/calendar-client` MST omits them).
|
|
23
23
|
* 2. If missing/empty, calls **`calendar.getParticipantOpeningHours()`** (`GET /Calendar/Participant/OpeningHours/Get`).
|
|
24
24
|
*/
|
|
25
|
-
export declare function fetchCalendarWithOpeningHours(calendarId: string, options?: any): Promise<
|
|
26
|
-
rawGet?: any;
|
|
27
|
-
calendar: any;
|
|
28
|
-
cal: any;
|
|
29
|
-
openingHours: any[];
|
|
30
|
-
embeddedFromGet: any[];
|
|
31
|
-
fromCalendarGet: boolean;
|
|
32
|
-
fromParticipantApi: boolean;
|
|
33
|
-
participantOpeningHoursResponse: any;
|
|
34
|
-
}>;
|
|
25
|
+
export declare function fetchCalendarWithOpeningHours(calendarId: string, options?: any): Promise<any>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CalendarModel } from "@blazeo.com/calendar-client";
|
|
2
|
-
import {
|
|
2
|
+
import { resolveBlazeoConnection } from "./createCalendar.js";
|
|
3
|
+
import { mapToDesiredCalendarResponse } from "./mapToDesiredResponse.js";
|
|
3
4
|
/**
|
|
4
5
|
* Unwrap nested REST shapes: `res.data`, `res.Data`, or `res.data.data`.
|
|
5
6
|
*/
|
|
@@ -65,10 +66,23 @@ export function normalizeParticipantOpeningHoursResponse(res) {
|
|
|
65
66
|
* 2. If missing/empty, calls **`calendar.getParticipantOpeningHours()`** (`GET /Calendar/Participant/OpeningHours/Get`).
|
|
66
67
|
*/
|
|
67
68
|
export async function fetchCalendarWithOpeningHours(calendarId, options = {}) {
|
|
68
|
-
const { includeRawGet = false } = options;
|
|
69
|
+
const { includeRawGet = false, baseUrl, consumer } = options;
|
|
70
|
+
const { baseUrl: resolvedBase, consumer: resolvedConsumer } = resolveBlazeoConnection({ baseUrl, consumer });
|
|
69
71
|
const rawRes = await CalendarModel.getRaw(calendarId);
|
|
70
|
-
const cal = await CalendarModel.get(calendarId);
|
|
71
72
|
const payload = unwrapCalendarGetData(rawRes);
|
|
73
|
+
let cal = null;
|
|
74
|
+
if (payload) {
|
|
75
|
+
// Manually create the model instance to fix a bug in calendar-client static get.
|
|
76
|
+
cal = CalendarModel.create({ ...payload, calendarId }, { baseUrl: resolvedBase, consumer: resolvedConsumer });
|
|
77
|
+
}
|
|
78
|
+
if (cal == null) {
|
|
79
|
+
return {
|
|
80
|
+
calendar: null,
|
|
81
|
+
openingHours: [],
|
|
82
|
+
raw: rawRes,
|
|
83
|
+
meta: { ok: false, reason: "calendar_not_found" },
|
|
84
|
+
};
|
|
85
|
+
}
|
|
72
86
|
const embedded = pickOpeningHoursArrayFromCalendarPayload(payload) ?? [];
|
|
73
87
|
let resolved = embedded.length > 0 ? embedded : null;
|
|
74
88
|
let participantRes = null;
|
|
@@ -80,16 +94,21 @@ export async function fetchCalendarWithOpeningHours(calendarId, options = {}) {
|
|
|
80
94
|
resolved = list;
|
|
81
95
|
}
|
|
82
96
|
const openingHours = Array.isArray(resolved) ? resolved : [];
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
97
|
+
const mappedOpeningHours = openingHours.map(oh => ({
|
|
98
|
+
...oh,
|
|
99
|
+
}));
|
|
100
|
+
const rawMembers = payload?.members ?? payload?.Members ?? payload?.participants ?? payload?.Participants;
|
|
101
|
+
const mappedMembers = Array.isArray(rawMembers)
|
|
102
|
+
? rawMembers.map((m) => ({ ...m }))
|
|
103
|
+
: [];
|
|
104
|
+
const calendar = mapToDesiredCalendarResponse(payload, openingHours, mappedMembers);
|
|
105
|
+
if (!calendar)
|
|
106
|
+
return null;
|
|
107
|
+
Object.defineProperties(calendar, {
|
|
108
|
+
_cal: { value: cal, enumerable: false },
|
|
109
|
+
_openingHours: { value: openingHours, enumerable: false },
|
|
110
|
+
_embeddedFromGet: { value: embedded, enumerable: false },
|
|
111
|
+
_rawGet: { value: rawRes, enumerable: false },
|
|
112
|
+
});
|
|
113
|
+
return calendar;
|
|
95
114
|
}
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
* Fetch all participant opening hours for a calendar.
|
|
3
3
|
* Uses `GET /Calendar/Participant/OpeningHours/All/Get`.
|
|
4
4
|
*/
|
|
5
|
-
export declare function getAllParticipantOpeningHours(calendarId: string
|
|
5
|
+
export declare function getAllParticipantOpeningHours(calendarId: string, options?: {
|
|
6
|
+
baseUrl?: string;
|
|
7
|
+
consumer?: string;
|
|
8
|
+
}): Promise<{
|
|
6
9
|
openingHours: any[];
|
|
7
10
|
raw: any[];
|
|
8
11
|
meta: {
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { CalendarModel } from "@blazeo.com/calendar-client";
|
|
2
|
+
import { ensureBlazeoHttpReady } from "../config/ensureBlazeoHttpReady.js";
|
|
2
3
|
import { normalizeParticipantOpeningHoursResponse } from "./fetchCalendarWithOpeningHours.js";
|
|
3
4
|
/**
|
|
4
5
|
* Fetch all participant opening hours for a calendar.
|
|
5
6
|
* Uses `GET /Calendar/Participant/OpeningHours/All/Get`.
|
|
6
7
|
*/
|
|
7
|
-
export async function getAllParticipantOpeningHours(calendarId) {
|
|
8
|
+
export async function getAllParticipantOpeningHours(calendarId, options = {}) {
|
|
9
|
+
const ready = ensureBlazeoHttpReady(options);
|
|
10
|
+
if (!ready.ok) {
|
|
11
|
+
throw new Error(ready.error);
|
|
12
|
+
}
|
|
8
13
|
const raw = await CalendarModel.getAllParticipantOpeningHours(calendarId);
|
|
9
14
|
// calendar-client static helper returns either `unknown[] | null` or an envelope depending on version/entrypoint.
|
|
10
15
|
if (Array.isArray(raw)) {
|
|
@@ -2,4 +2,7 @@
|
|
|
2
2
|
* Fetches opening hours for a calendar.
|
|
3
3
|
* Automatically handles embedded calendar-level hours and participant-level fallbacks.
|
|
4
4
|
*/
|
|
5
|
-
export declare function getOpeningHours(calendarId: string
|
|
5
|
+
export declare function getOpeningHours(calendarId: string, options?: {
|
|
6
|
+
baseUrl?: string;
|
|
7
|
+
consumer?: string;
|
|
8
|
+
}): Promise<any>;
|
|
@@ -3,7 +3,7 @@ import { fetchCalendarWithOpeningHours } from "./fetchCalendarWithOpeningHours.j
|
|
|
3
3
|
* Fetches opening hours for a calendar.
|
|
4
4
|
* Automatically handles embedded calendar-level hours and participant-level fallbacks.
|
|
5
5
|
*/
|
|
6
|
-
export async function getOpeningHours(calendarId) {
|
|
7
|
-
const result = await fetchCalendarWithOpeningHours(calendarId);
|
|
6
|
+
export async function getOpeningHours(calendarId, options = {}) {
|
|
7
|
+
const result = await fetchCalendarWithOpeningHours(calendarId, options);
|
|
8
8
|
return result.openingHours;
|
|
9
9
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CalendarModel } from "@blazeo.com/calendar-client";
|
|
2
|
-
import {
|
|
2
|
+
import { resolveBlazeoConnection } from "./createCalendar.js";
|
|
3
|
+
import { unwrapCalendarGetData, normalizeParticipantOpeningHoursResponse } from "./fetchCalendarWithOpeningHours.js";
|
|
3
4
|
/**
|
|
4
5
|
* Direct wrapper around `calendar.getParticipantOpeningHours()` for a calendar id.
|
|
5
6
|
*
|
|
@@ -8,15 +9,19 @@ import { normalizeParticipantOpeningHoursResponse } from "./fetchCalendarWithOpe
|
|
|
8
9
|
*/
|
|
9
10
|
export async function getParticipantOpeningHours(calendarId, options = {}) {
|
|
10
11
|
try {
|
|
11
|
-
const
|
|
12
|
-
|
|
12
|
+
const { baseUrl, consumer, ...passThrough } = options;
|
|
13
|
+
const { baseUrl: resolvedBase, consumer: resolvedConsumer } = resolveBlazeoConnection({ baseUrl, consumer });
|
|
14
|
+
const rawRes = await CalendarModel.getRaw(calendarId);
|
|
15
|
+
const payload = unwrapCalendarGetData(rawRes);
|
|
16
|
+
if (!payload) {
|
|
13
17
|
return {
|
|
14
18
|
openingHours: [],
|
|
15
19
|
raw: null,
|
|
16
20
|
meta: { ok: false, reason: "calendar_not_found" },
|
|
17
21
|
};
|
|
18
22
|
}
|
|
19
|
-
const
|
|
23
|
+
const cal = CalendarModel.create({ ...payload, calendarId }, { baseUrl: resolvedBase, consumer: resolvedConsumer });
|
|
24
|
+
const raw = await cal.getParticipantOpeningHours({ calendarId, ...(passThrough ?? {}) });
|
|
20
25
|
const { list } = normalizeParticipantOpeningHoursResponse(raw);
|
|
21
26
|
const openingHours = Array.isArray(list) ? list : [];
|
|
22
27
|
return {
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { CalendarModel } from "@blazeo.com/calendar-client";
|
|
2
|
+
import { ensureBlazeoHttpReady } from "../config/ensureBlazeoHttpReady.js";
|
|
2
3
|
/**
|
|
3
4
|
* Fetches participants for a calendar.
|
|
4
5
|
*/
|
|
5
|
-
export async function getParticipants(calendarId) {
|
|
6
|
+
export async function getParticipants(calendarId, options = {}) {
|
|
7
|
+
const ready = ensureBlazeoHttpReady(options);
|
|
8
|
+
if (!ready.ok) {
|
|
9
|
+
throw new Error(ready.error);
|
|
10
|
+
}
|
|
6
11
|
const participants = await CalendarModel.getParticipants(calendarId);
|
|
7
12
|
return Array.isArray(participants) ? participants : [];
|
|
8
13
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps a raw Blazeo API calendar payload (often PascalCase) to the specific camelCase
|
|
3
|
+
* shape requested by the user, including typenames and normalized fields.
|
|
4
|
+
*/
|
|
5
|
+
export declare function mapToDesiredCalendarResponse(payload: any, openingHours?: any[], members?: any[]): {
|
|
6
|
+
id: number | null;
|
|
7
|
+
durationUnit: number | null;
|
|
8
|
+
minimumBookingNotice: number | null;
|
|
9
|
+
minimumBookingNoticeUnit: number | null;
|
|
10
|
+
minimumCancelationNotice: number | null;
|
|
11
|
+
minimumCancelationNoticeUnit: number | null;
|
|
12
|
+
futureLimit: number | null;
|
|
13
|
+
futureLimitUnit: number | null;
|
|
14
|
+
bufferTime: number | null;
|
|
15
|
+
bufferTimeUnit: number | null;
|
|
16
|
+
calendarLink: any;
|
|
17
|
+
uuid: any;
|
|
18
|
+
location: any;
|
|
19
|
+
bookingPageTitle: any;
|
|
20
|
+
reminderChannelStatuses: {
|
|
21
|
+
id: any;
|
|
22
|
+
calendarId: any;
|
|
23
|
+
channelId: any;
|
|
24
|
+
status: boolean;
|
|
25
|
+
appointmentReminders: any;
|
|
26
|
+
__typename: string;
|
|
27
|
+
}[];
|
|
28
|
+
members: {
|
|
29
|
+
id: any;
|
|
30
|
+
name: any;
|
|
31
|
+
email: any;
|
|
32
|
+
status: any;
|
|
33
|
+
__typename: string;
|
|
34
|
+
}[];
|
|
35
|
+
createdOn: any;
|
|
36
|
+
modifiedOn: any;
|
|
37
|
+
name: any;
|
|
38
|
+
timeZoneId: any;
|
|
39
|
+
description: any;
|
|
40
|
+
assignmentType: number | null;
|
|
41
|
+
duration: number | null;
|
|
42
|
+
bookingLimit: number | null;
|
|
43
|
+
calendarJson: any;
|
|
44
|
+
isThirdPartySaved: boolean;
|
|
45
|
+
themeId: number | null;
|
|
46
|
+
theme: {
|
|
47
|
+
id: any;
|
|
48
|
+
color: any;
|
|
49
|
+
logoUrl: any;
|
|
50
|
+
__typename: string;
|
|
51
|
+
} | null;
|
|
52
|
+
openingHours: {
|
|
53
|
+
id: any;
|
|
54
|
+
createdOn: any;
|
|
55
|
+
modifiedOn: any;
|
|
56
|
+
member: any;
|
|
57
|
+
openingHourId: any;
|
|
58
|
+
calendarId: any;
|
|
59
|
+
participantId: any;
|
|
60
|
+
days: any;
|
|
61
|
+
startHour: any;
|
|
62
|
+
startMinute: any;
|
|
63
|
+
endHour: any;
|
|
64
|
+
endMinute: any;
|
|
65
|
+
off: boolean;
|
|
66
|
+
__typename: string;
|
|
67
|
+
}[];
|
|
68
|
+
appointmentUserDefinedFields: any;
|
|
69
|
+
__typename: string;
|
|
70
|
+
} | null;
|