@blazeo.com/appointment-client 1.0.7 → 1.0.8
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/Appointment-Client/.gitattributes +2 -0
- package/blazeo.com-appointment-client-1.0.8.tgz +0 -0
- package/dist/calendar/buildUnifiedCalendarView.js +9 -3
- package/dist/calendar/fetchCalendarDetails.js +2 -1
- package/package.json +1 -1
- package/sample/package-lock.json +70 -1
- package/sample/package.json +1 -0
- package/sample/src/FetchCalendarTab.jsx +24 -26
- package/src/calendar/buildUnifiedCalendarView.ts +7 -2
- package/src/calendar/fetchCalendarDetails.ts +3 -1
- package/blazeo.com-appointment-client-1.0.7.tgz +0 -0
|
Binary file
|
|
@@ -40,9 +40,7 @@ function coerceMemberId(v) {
|
|
|
40
40
|
* Canonical member id used in both `members[].id` and `openingHours[].member`.
|
|
41
41
|
*/
|
|
42
42
|
function resolveParticipantMemberId(calPart) {
|
|
43
|
-
|
|
44
|
-
if (n != null && typeof n === "number" && !Number.isNaN(n))
|
|
45
|
-
return n;
|
|
43
|
+
// Prefer the participantId GUID when available — it is the stable cross-endpoint identifier.
|
|
46
44
|
const sid = pick(calPart, "participantId", "ParticipantId", "participant_id");
|
|
47
45
|
if (sid != null && String(sid).trim() !== "") {
|
|
48
46
|
const t = String(sid).trim();
|
|
@@ -50,6 +48,14 @@ function resolveParticipantMemberId(calPart) {
|
|
|
50
48
|
return Number(t);
|
|
51
49
|
return t;
|
|
52
50
|
}
|
|
51
|
+
// Fall back to id — accepts both numeric and string (e.g. a GUID stored as id).
|
|
52
|
+
const n = pick(calPart, "id", "Id");
|
|
53
|
+
if (n != null) {
|
|
54
|
+
if (typeof n === "number" && !Number.isNaN(n))
|
|
55
|
+
return n;
|
|
56
|
+
if (typeof n === "string" && n.trim() !== "")
|
|
57
|
+
return n.trim();
|
|
58
|
+
}
|
|
53
59
|
return "";
|
|
54
60
|
}
|
|
55
61
|
function dayOrderIndex(d) {
|
|
@@ -153,7 +153,8 @@ export async function fetchCalendarDetails(calendarId, options = {}) {
|
|
|
153
153
|
const infoList = unwrapModelList(participantsInfoRaw);
|
|
154
154
|
// Merge participantList and infoList to ensure we have all members
|
|
155
155
|
const mergedParticipantsMap = new Map();
|
|
156
|
-
|
|
156
|
+
// Prefer the participantId GUID; fall back to numeric id.
|
|
157
|
+
const getAnyId = (obj) => obj.participantId ?? obj.ParticipantId ?? obj.participant_id ?? obj.id ?? obj.Id;
|
|
157
158
|
// 1. Add from standard list
|
|
158
159
|
participantList.forEach((p) => {
|
|
159
160
|
const id = getAnyId(p);
|
package/package.json
CHANGED
package/sample/package-lock.json
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"": {
|
|
7
7
|
"name": "appointment-client-sample",
|
|
8
8
|
"dependencies": {
|
|
9
|
+
"@blazeo.com/appointment-client": "file:../blazeo.com-appointment-client-1.0.7.tgz",
|
|
9
10
|
"appointment-client": "file:..",
|
|
10
11
|
"react": "^19.0.0",
|
|
11
12
|
"react-dom": "^19.0.0"
|
|
@@ -17,7 +18,7 @@
|
|
|
17
18
|
},
|
|
18
19
|
"..": {
|
|
19
20
|
"name": "@blazeo.com/appointment-client",
|
|
20
|
-
"version": "1.0.
|
|
21
|
+
"version": "1.0.7",
|
|
21
22
|
"dependencies": {
|
|
22
23
|
"@blazeo.com/calendar-client": "^1.0.18",
|
|
23
24
|
"mobx": "^6.13.7",
|
|
@@ -319,6 +320,38 @@
|
|
|
319
320
|
"node": ">=6.9.0"
|
|
320
321
|
}
|
|
321
322
|
},
|
|
323
|
+
"node_modules/@blazeo.com/appointment-client": {
|
|
324
|
+
"version": "1.0.7",
|
|
325
|
+
"resolved": "file:../blazeo.com-appointment-client-1.0.7.tgz",
|
|
326
|
+
"integrity": "sha512-b2E5TIdxvNJLH3oEvCQngDhzQ08iwXNolPcok3emAlGipO0f8iGDij5hnVUntt68c2Lr3IPz3cvr/BcUY6MofQ==",
|
|
327
|
+
"dependencies": {
|
|
328
|
+
"@blazeo.com/calendar-client": "^1.0.18",
|
|
329
|
+
"mobx": "^6.13.7",
|
|
330
|
+
"mobx-state-tree": "^7.0.2"
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
"node_modules/@blazeo.com/calendar-client": {
|
|
334
|
+
"version": "1.0.18",
|
|
335
|
+
"resolved": "https://registry.npmjs.org/@blazeo.com/calendar-client/-/calendar-client-1.0.18.tgz",
|
|
336
|
+
"integrity": "sha512-wHqOZKUAH4JDgsdwaktEG68H5YfArOW3LEouCXznIza4YqNrlkfdJEyqiwNf6KjY2nELi+s2tFM22/1MKaWf5Q==",
|
|
337
|
+
"license": "UNLICENSED",
|
|
338
|
+
"dependencies": {
|
|
339
|
+
"mobx": "^6.10.0",
|
|
340
|
+
"mobx-state-tree": "^5.4.0"
|
|
341
|
+
},
|
|
342
|
+
"engines": {
|
|
343
|
+
"node": ">=18"
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
"node_modules/@blazeo.com/calendar-client/node_modules/mobx-state-tree": {
|
|
347
|
+
"version": "5.4.2",
|
|
348
|
+
"resolved": "https://registry.npmjs.org/mobx-state-tree/-/mobx-state-tree-5.4.2.tgz",
|
|
349
|
+
"integrity": "sha512-SGXAh2KCBQbWVcxeQbZEr5pchTgcfNZmGVRL2a2Me+pSMH98bZWXD6EOuuijbTGbc0hOoOsbab3JdwJyr+fW7Q==",
|
|
350
|
+
"license": "MIT",
|
|
351
|
+
"peerDependencies": {
|
|
352
|
+
"mobx": "^6.3.0"
|
|
353
|
+
}
|
|
354
|
+
},
|
|
322
355
|
"node_modules/@esbuild/aix-ppc64": {
|
|
323
356
|
"version": "0.25.12",
|
|
324
357
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
|
|
@@ -1425,6 +1458,28 @@
|
|
|
1425
1458
|
"yallist": "^3.0.2"
|
|
1426
1459
|
}
|
|
1427
1460
|
},
|
|
1461
|
+
"node_modules/mobx": {
|
|
1462
|
+
"version": "6.15.3",
|
|
1463
|
+
"resolved": "https://registry.npmjs.org/mobx/-/mobx-6.15.3.tgz",
|
|
1464
|
+
"integrity": "sha512-6+ZSYDs5zgH5CdGfEU2q2Lsa5PztVryL1ys7kAImTU25n2A9LAMj/yneVsQpd03MfwMLDQF+7kakJR9Z+cQxSw==",
|
|
1465
|
+
"license": "MIT",
|
|
1466
|
+
"funding": {
|
|
1467
|
+
"type": "opencollective",
|
|
1468
|
+
"url": "https://opencollective.com/mobx"
|
|
1469
|
+
}
|
|
1470
|
+
},
|
|
1471
|
+
"node_modules/mobx-state-tree": {
|
|
1472
|
+
"version": "7.2.0",
|
|
1473
|
+
"resolved": "https://registry.npmjs.org/mobx-state-tree/-/mobx-state-tree-7.2.0.tgz",
|
|
1474
|
+
"integrity": "sha512-o46IsMI/lHITYCmkbQgNOCDT8M9Hd2WAgOlHt42hCg+XUZP21obF5ui5Vv9epIsQV8Wpp/GWNHu1YFhTx6iq0g==",
|
|
1475
|
+
"license": "MIT",
|
|
1476
|
+
"dependencies": {
|
|
1477
|
+
"ts-essentials": "^9.4.1"
|
|
1478
|
+
},
|
|
1479
|
+
"peerDependencies": {
|
|
1480
|
+
"mobx": "^6.3.0"
|
|
1481
|
+
}
|
|
1482
|
+
},
|
|
1428
1483
|
"node_modules/ms": {
|
|
1429
1484
|
"version": "2.1.3",
|
|
1430
1485
|
"dev": true,
|
|
@@ -1598,6 +1653,20 @@
|
|
|
1598
1653
|
"url": "https://github.com/sponsors/SuperchupuDev"
|
|
1599
1654
|
}
|
|
1600
1655
|
},
|
|
1656
|
+
"node_modules/ts-essentials": {
|
|
1657
|
+
"version": "9.4.2",
|
|
1658
|
+
"resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-9.4.2.tgz",
|
|
1659
|
+
"integrity": "sha512-mB/cDhOvD7pg3YCLk2rOtejHjjdSi9in/IBYE13S+8WA5FBSraYf4V/ws55uvs0IvQ/l0wBOlXy5yBNZ9Bl8ZQ==",
|
|
1660
|
+
"license": "MIT",
|
|
1661
|
+
"peerDependencies": {
|
|
1662
|
+
"typescript": ">=4.1.0"
|
|
1663
|
+
},
|
|
1664
|
+
"peerDependenciesMeta": {
|
|
1665
|
+
"typescript": {
|
|
1666
|
+
"optional": true
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
},
|
|
1601
1670
|
"node_modules/update-browserslist-db": {
|
|
1602
1671
|
"version": "1.2.3",
|
|
1603
1672
|
"dev": true,
|
package/sample/package.json
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"participants:info": "node ./scripts/getInfoByCalendar.mjs"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
+
"@blazeo.com/appointment-client": "file:../blazeo.com-appointment-client-1.0.7.tgz",
|
|
13
14
|
"appointment-client": "file:..",
|
|
14
15
|
"react": "^19.0.0",
|
|
15
16
|
"react-dom": "^19.0.0"
|
|
@@ -304,23 +304,14 @@ export function FetchCalendarTab() {
|
|
|
304
304
|
const id = c.calendarId ?? String(c.id ?? "");
|
|
305
305
|
if (!id) return { calendar: getSnapshot(c), openingHours: [], meta: { error: "no id" } };
|
|
306
306
|
try {
|
|
307
|
+
// fetchCalendarDetails now returns the flat unified view directly
|
|
307
308
|
const b = await fetchCalendarDetails(id, {
|
|
308
309
|
...connectionOpts,
|
|
309
310
|
baseUrl: effective.baseUrl,
|
|
310
311
|
...(effective.consumer ? { consumer: effective.consumer } : {}),
|
|
311
312
|
});
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
calendar: b.calendar ?? getSnapshot(c),
|
|
315
|
-
openingHours: b.openingHours,
|
|
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
|
-
},
|
|
322
|
-
meta: b.meta,
|
|
323
|
-
};
|
|
313
|
+
// b IS the unified calendarView: members/openingHours/participants at top level
|
|
314
|
+
return b ?? { calendar: getSnapshot(c), openingHours: [], meta: { error: "null response" } };
|
|
324
315
|
} catch (err) {
|
|
325
316
|
return {
|
|
326
317
|
calendar: getSnapshot(c),
|
|
@@ -469,29 +460,29 @@ export function FetchCalendarTab() {
|
|
|
469
460
|
<div className="card">
|
|
470
461
|
<h2>Fetch calendar · calendarView</h2>
|
|
471
462
|
<p className="muted small">
|
|
472
|
-
Runs <code>fetchCalendarDetails(calendarId)</code>. JSON
|
|
473
|
-
calendar snapshot fields + <code>members</code> + <code>openingHours</code>,
|
|
474
|
-
where each participant
|
|
463
|
+
Runs <code>fetchCalendarDetails(calendarId)</code>. The JSON shown below <strong>is</strong> the unified calendar view:
|
|
464
|
+
one object with calendar snapshot fields + <code>members</code> + <code>openingHours</code>, plus a{" "}
|
|
465
|
+
<code>participants</code> array where each participant may include nested <code>openingHours</code>. (
|
|
466
|
+
<code>fetchCalendarBundle(calendarId)</code> returns the same shape.)
|
|
475
467
|
</p>
|
|
476
468
|
<p className="muted small">
|
|
477
469
|
Uses <code>fetchCalendarDetails</code>: legacy <code>openingHours</code> prefers embed on{" "}
|
|
478
470
|
<code>CalendarModel.getRaw</code>, else <code>getParticipantOpeningHours</code>.{" "}
|
|
479
|
-
<code>
|
|
471
|
+
Unified <code>openingHours</code> prefers <code>getAllParticipantOpeningHours</code> (
|
|
480
472
|
<code>GET /Calendar/Participant/OpeningHours/All/Get</code>) when the API returns rows. Members combine{" "}
|
|
481
473
|
<code>CalendarModel.getParticipants</code> + <code>CalendarModel.getParticipantsInfo</code> (each member may
|
|
482
474
|
include <code>participantInfo</code>).
|
|
483
475
|
</p>
|
|
484
476
|
<p className="muted small">
|
|
485
|
-
<strong>
|
|
486
|
-
<code>initializeAppointmentClient({ baseUrl, consumer })</code>
|
|
487
|
-
<code>
|
|
477
|
+
<strong>In code:</strong> <code>fetchCalendarBundle(calendarId)</code> (after{" "}
|
|
478
|
+
<code>initializeAppointmentClient({ baseUrl, consumer })</code>) is an alias for the same unified fetch;
|
|
479
|
+
use either alongside explicit <code>baseUrl</code> / <code>consumer</code> options when needed.
|
|
488
480
|
</p>
|
|
489
481
|
<p className="muted small">
|
|
490
482
|
<strong>DevTools Network:</strong> Each fetch fires <code>/Calendar/Get</code> <strong>twice</strong> (
|
|
491
483
|
<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
|
-
|
|
494
|
-
widen the Network filter ("All") or disable search; if <code>calendarView</code> is empty/missing fields,
|
|
484
|
+
<code>Participant</code>, <code>OpeningHours</code>, or <code>GetInfo</code>. Those power the unified view. If you only see <code>Calendar/Get</code> yet the UI JSON has members/hours,
|
|
485
|
+
widen the Network filter ("All") or disable search; if the unified object is empty/missing fields,
|
|
495
486
|
check the <strong>Console</strong> for errors on the participant/opening-hours requests.
|
|
496
487
|
</p>
|
|
497
488
|
<p className="muted small">
|
|
@@ -567,11 +558,18 @@ export function FetchCalendarTab() {
|
|
|
567
558
|
<div className="card">
|
|
568
559
|
<h2>Fetch calendars by company</h2>
|
|
569
560
|
<p className="muted small">
|
|
570
|
-
|
|
571
|
-
|
|
561
|
+
Step 1: <code>CalendarModel.getByCompany</code> → <code>GET /Calendar/All</code> (company key → calendar
|
|
562
|
+
list). Step 2: for each calendar id, this tab runs the same{" "}
|
|
563
|
+
<code>fetchCalendarDetails(calendarId)</code> pipeline as <strong>Fetch calendar · calendarView</strong>, so
|
|
564
|
+
the JSON below is an <strong>array</strong> of unified objects (members, openingHours, participants — same
|
|
565
|
+
shape as a single fetch). If an id is missing from the list row, that entry falls back to the raw snapshot
|
|
566
|
+
only.
|
|
567
|
+
</p>
|
|
568
|
+
<p className="muted small">
|
|
569
|
+
If the UI shows <strong>Failed to fetch</strong> while Base URL points at Azure/production, that is usually{" "}
|
|
572
570
|
<strong>CORS</strong>: enable proxy via <code>VITE_DEV_PROXY_TARGET</code> in{" "}
|
|
573
|
-
<code>sample/.env.development</code> and Base URL <code>http://localhost:5173/blazeo-api</code>
|
|
574
|
-
|
|
571
|
+
<code>sample/.env.development</code> and Base URL <code>http://localhost:5173/blazeo-api</code> (restart dev
|
|
572
|
+
server).
|
|
575
573
|
</p>
|
|
576
574
|
<form onSubmit={handleFetchByCompany} className="form">
|
|
577
575
|
<label className="form__label">
|
|
@@ -37,14 +37,19 @@ function coerceMemberId(v: unknown): number | string | null {
|
|
|
37
37
|
* Canonical member id used in both `members[].id` and `openingHours[].member`.
|
|
38
38
|
*/
|
|
39
39
|
function resolveParticipantMemberId(calPart: Record<string, any>): number | string {
|
|
40
|
-
|
|
41
|
-
if (n != null && typeof n === "number" && !Number.isNaN(n)) return n;
|
|
40
|
+
// Prefer the participantId GUID when available — it is the stable cross-endpoint identifier.
|
|
42
41
|
const sid = pick<string>(calPart, "participantId", "ParticipantId", "participant_id");
|
|
43
42
|
if (sid != null && String(sid).trim() !== "") {
|
|
44
43
|
const t = String(sid).trim();
|
|
45
44
|
if (/^\d+$/.test(t)) return Number(t);
|
|
46
45
|
return t;
|
|
47
46
|
}
|
|
47
|
+
// Fall back to id — accepts both numeric and string (e.g. a GUID stored as id).
|
|
48
|
+
const n = pick<number | string | null>(calPart, "id", "Id");
|
|
49
|
+
if (n != null) {
|
|
50
|
+
if (typeof n === "number" && !Number.isNaN(n)) return n;
|
|
51
|
+
if (typeof n === "string" && n.trim() !== "") return n.trim();
|
|
52
|
+
}
|
|
48
53
|
return "";
|
|
49
54
|
}
|
|
50
55
|
|
|
@@ -194,7 +194,9 @@ export async function fetchCalendarDetails(
|
|
|
194
194
|
// Merge participantList and infoList to ensure we have all members
|
|
195
195
|
const mergedParticipantsMap = new Map<string, any>();
|
|
196
196
|
|
|
197
|
-
|
|
197
|
+
// Prefer the participantId GUID; fall back to numeric id.
|
|
198
|
+
const getAnyId = (obj: any) =>
|
|
199
|
+
obj.participantId ?? obj.ParticipantId ?? obj.participant_id ?? obj.id ?? obj.Id;
|
|
198
200
|
|
|
199
201
|
// 1. Add from standard list
|
|
200
202
|
participantList.forEach((p: any) => {
|
|
Binary file
|