@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
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { CalendarModel } from "@blazeo.com/calendar-client";
|
|
2
|
+
import { ensureBlazeoHttpReady } from "../config/ensureBlazeoHttpReady.js";
|
|
3
|
+
import { normalizeParticipantOpeningHoursResponse } from "./fetchCalendarWithOpeningHours.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Fetch all participant opening hours for a calendar.
|
|
7
|
+
* Uses `GET /Calendar/Participant/OpeningHours/All/Get`.
|
|
8
|
+
*/
|
|
9
|
+
export async function getAllParticipantOpeningHours(
|
|
10
|
+
calendarId: string,
|
|
11
|
+
options: { baseUrl?: string; consumer?: string } = {}
|
|
12
|
+
) {
|
|
13
|
+
const ready = ensureBlazeoHttpReady(options);
|
|
14
|
+
if (!ready.ok) {
|
|
15
|
+
throw new Error(ready.error);
|
|
16
|
+
}
|
|
17
|
+
const raw: any = await (CalendarModel as any).getAllParticipantOpeningHours(calendarId);
|
|
18
|
+
|
|
19
|
+
// calendar-client static helper returns either `unknown[] | null` or an envelope depending on version/entrypoint.
|
|
20
|
+
if (Array.isArray(raw)) {
|
|
21
|
+
return { openingHours: raw, raw, meta: { ok: true as const, shape: "array" as const } };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const { list } = normalizeParticipantOpeningHoursResponse(raw);
|
|
25
|
+
const openingHours = Array.isArray(list) ? list : [];
|
|
26
|
+
const ok = Array.isArray(list) ? true : raw?.status === "success";
|
|
27
|
+
|
|
28
|
+
return { openingHours, raw, meta: { ok: !!ok as boolean } };
|
|
29
|
+
}
|
|
30
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { fetchCalendarWithOpeningHours } from "./fetchCalendarWithOpeningHours.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Fetches opening hours for a calendar.
|
|
5
|
+
* Automatically handles embedded calendar-level hours and participant-level fallbacks.
|
|
6
|
+
*/
|
|
7
|
+
export async function getOpeningHours(calendarId: string, options: { baseUrl?: string; consumer?: string } = {}) {
|
|
8
|
+
const result = await fetchCalendarWithOpeningHours(calendarId, options);
|
|
9
|
+
return result.openingHours;
|
|
10
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { CalendarModel } from "@blazeo.com/calendar-client";
|
|
2
|
+
import { resolveBlazeoConnection } from "./createCalendar.js";
|
|
3
|
+
import { unwrapCalendarGetData, normalizeParticipantOpeningHoursResponse } from "./fetchCalendarWithOpeningHours.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Direct wrapper around `calendar.getParticipantOpeningHours()` for a calendar id.
|
|
7
|
+
*
|
|
8
|
+
* This hits `GET /Calendar/Participant/OpeningHours/Get` (server-side shape may vary),
|
|
9
|
+
* so we also return a normalized list alongside the raw response.
|
|
10
|
+
*/
|
|
11
|
+
export async function getParticipantOpeningHours(calendarId: string, options: any = {}) {
|
|
12
|
+
try {
|
|
13
|
+
const { baseUrl, consumer, ...passThrough } = options;
|
|
14
|
+
const { baseUrl: resolvedBase, consumer: resolvedConsumer } = resolveBlazeoConnection({ baseUrl, consumer });
|
|
15
|
+
const rawRes = await (CalendarModel as any).getRaw(calendarId);
|
|
16
|
+
const payload = unwrapCalendarGetData(rawRes);
|
|
17
|
+
|
|
18
|
+
if (!payload) {
|
|
19
|
+
return {
|
|
20
|
+
openingHours: [] as any[],
|
|
21
|
+
raw: null as any,
|
|
22
|
+
meta: { ok: false as const, reason: "calendar_not_found" },
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const cal = (CalendarModel as any).create(
|
|
27
|
+
{ ...payload, calendarId },
|
|
28
|
+
{ baseUrl: resolvedBase, consumer: resolvedConsumer }
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const raw = await cal.getParticipantOpeningHours({ calendarId, ...(passThrough ?? {}) });
|
|
32
|
+
const { list } = normalizeParticipantOpeningHoursResponse(raw);
|
|
33
|
+
const openingHours = Array.isArray(list) ? list : [];
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
openingHours,
|
|
37
|
+
raw,
|
|
38
|
+
meta: {
|
|
39
|
+
ok: true as const,
|
|
40
|
+
count: openingHours.length,
|
|
41
|
+
status: raw?.status ?? (raw?.Status || "unknown"),
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
} catch (err) {
|
|
45
|
+
return {
|
|
46
|
+
openingHours: [] as any[],
|
|
47
|
+
raw: null as any,
|
|
48
|
+
meta: {
|
|
49
|
+
ok: false as const,
|
|
50
|
+
reason: "exception",
|
|
51
|
+
error: err instanceof Error ? err.message : String(err),
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { CalendarModel } from "@blazeo.com/calendar-client";
|
|
2
|
+
import { ensureBlazeoHttpReady } from "../config/ensureBlazeoHttpReady.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Fetches participants for a calendar.
|
|
6
|
+
*/
|
|
7
|
+
export async function getParticipants(
|
|
8
|
+
calendarId: string,
|
|
9
|
+
options: { baseUrl?: string; consumer?: string } = {}
|
|
10
|
+
) {
|
|
11
|
+
const ready = ensureBlazeoHttpReady(options);
|
|
12
|
+
if (!ready.ok) {
|
|
13
|
+
throw new Error(ready.error);
|
|
14
|
+
}
|
|
15
|
+
const participants = await CalendarModel.getParticipants(calendarId);
|
|
16
|
+
return Array.isArray(participants) ? participants : [];
|
|
17
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Default enum values aligned with ApexFlows / Blazeo (`AssignmentMethod`, `Unit`). */
|
|
2
|
+
const DEFAULT_ASSIGNMENT_METHOD = 1;
|
|
3
|
+
const DEFAULT_UNIT_MINUTES = 1;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* For Blazeo `Calendar` MST: `types.optional(types.number)` accepts `undefined` (uses default)
|
|
7
|
+
* but not `null`. Coerce null/absent to `undefined`.
|
|
8
|
+
*/
|
|
9
|
+
function optionalNumber(v: any) {
|
|
10
|
+
return v == null ? undefined : v;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Maps Apex `CalendarBO`-shaped input to a snapshot for
|
|
15
|
+
* {@link CalendarModel.create} from `@blazeo.com/calendar-client`.
|
|
16
|
+
*
|
|
17
|
+
* Only fields that exist on Blazeo's `Calendar` model are included so MST does not receive
|
|
18
|
+
* unknown keys or invalid `null`s on optional numbers.
|
|
19
|
+
*/
|
|
20
|
+
export function mapCalendarBOToSnapshot(bo: any) {
|
|
21
|
+
const c = globalThis.crypto;
|
|
22
|
+
const generatedId = c?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
23
|
+
const calendarId = bo.calendarId ?? generatedId;
|
|
24
|
+
return {
|
|
25
|
+
companyKey: bo.companyKey ?? null,
|
|
26
|
+
calendarId,
|
|
27
|
+
name: bo.name ?? null,
|
|
28
|
+
timeZoneId: bo.timeZoneId ?? null,
|
|
29
|
+
purpose: bo.purpose ?? bo.bookingPageTitle ?? "",
|
|
30
|
+
description: bo.description ?? null,
|
|
31
|
+
assignmentMethod: bo.assignmentMethod ?? bo.assignmentType ?? DEFAULT_ASSIGNMENT_METHOD,
|
|
32
|
+
duration: optionalNumber(bo.duration) ?? 30,
|
|
33
|
+
durationUnit: optionalNumber(bo.durationUnit) ?? DEFAULT_UNIT_MINUTES,
|
|
34
|
+
minimumBookingNotice: optionalNumber(bo.minimumBookingNotice) ?? 0,
|
|
35
|
+
minimumBookingNoticeUnit: optionalNumber(bo.minimumBookingNoticeUnit) ?? DEFAULT_UNIT_MINUTES,
|
|
36
|
+
minimumCancelationNotice: optionalNumber(bo.minimumCancelationNotice) ?? 0,
|
|
37
|
+
minimumCancelationNoticeUnit: optionalNumber(bo.minimumCancelationNoticeUnit) ?? DEFAULT_UNIT_MINUTES,
|
|
38
|
+
futureLimit: optionalNumber(bo.futureLimit) ?? 0,
|
|
39
|
+
futureLimitUnit: optionalNumber(bo.futureLimitUnit) ?? 3,
|
|
40
|
+
bufferTime: optionalNumber(bo.bufferTime),
|
|
41
|
+
bufferTimeUnit: optionalNumber(bo.bufferTimeUnit) ?? DEFAULT_UNIT_MINUTES,
|
|
42
|
+
bookingLimit: optionalNumber(bo.bookingLimit),
|
|
43
|
+
createdOn: bo.createdOn ?? null,
|
|
44
|
+
modifiedOn: bo.modifiedOn ?? null,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
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 function mapToDesiredCalendarResponse(payload: any, openingHours: any[] = [], members: any[] = []) {
|
|
6
|
+
if (!payload) return null;
|
|
7
|
+
|
|
8
|
+
const pick = (obj: any, ...keys: string[]) => {
|
|
9
|
+
for (const k of keys) {
|
|
10
|
+
if (obj[k] !== undefined && obj[k] !== null) return obj[k];
|
|
11
|
+
}
|
|
12
|
+
return undefined;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const n = (v: any) => (v != null && v !== "" ? Number(v) : null);
|
|
16
|
+
|
|
17
|
+
// Map members with typename
|
|
18
|
+
const mappedMembers = members.map(m => ({
|
|
19
|
+
id: m.id ?? pick(m, "id", "Id"),
|
|
20
|
+
name: m.name ?? pick(m, "name", "Name", "alias", "Alias"),
|
|
21
|
+
email: m.email ?? pick(m, "email", "Email") ?? null,
|
|
22
|
+
status: m.status ?? pick(m, "status", "Status") ?? 0,
|
|
23
|
+
__typename: "Member"
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
// Map opening hours with typename and raw fields
|
|
27
|
+
const mappedOpeningHours = openingHours.map(oh => ({
|
|
28
|
+
id: pick(oh, "id", "Id") ?? 0,
|
|
29
|
+
createdOn: pick(oh, "createdOn", "CreatedOn", "created_on") ?? "0001-01-01T00:00:00.000Z",
|
|
30
|
+
modifiedOn: pick(oh, "modifiedOn", "ModifiedOn", "modified_on") ?? "0001-01-01T00:00:00.000Z",
|
|
31
|
+
member: pick(oh, "member", "Member"),
|
|
32
|
+
openingHourId: pick(oh, "openingHourId", "OpeningHourId", "opening_hour_id") ?? "",
|
|
33
|
+
calendarId: pick(oh, "calendarId", "CalendarId", "calendar_id") ?? "",
|
|
34
|
+
participantId: pick(oh, "participantId", "ParticipantId", "participant_id") ?? "",
|
|
35
|
+
days: oh.days ?? [],
|
|
36
|
+
startHour: oh.startHour ?? pick(oh, "startHour", "StartHour") ?? 0,
|
|
37
|
+
startMinute: oh.startMinute ?? pick(oh, "startMinute", "StartMinute") ?? 0,
|
|
38
|
+
endHour: oh.endHour ?? pick(oh, "endHour", "EndHour") ?? 0,
|
|
39
|
+
endMinute: oh.endMinute ?? pick(oh, "endMinute", "EndMinute") ?? 0,
|
|
40
|
+
off: !!(oh.off ?? pick(oh, "off", "Off")),
|
|
41
|
+
__typename: "OpeningHour"
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
// Map theme
|
|
45
|
+
const rawTheme = pick(payload, "theme", "Theme");
|
|
46
|
+
const theme = rawTheme ? {
|
|
47
|
+
id: pick(rawTheme, "id", "Id"),
|
|
48
|
+
color: pick(rawTheme, "color", "Color"),
|
|
49
|
+
logoUrl: pick(rawTheme, "logoUrl", "LogoUrl") ?? null,
|
|
50
|
+
__typename: "Theme"
|
|
51
|
+
} : null;
|
|
52
|
+
|
|
53
|
+
// Map reminders
|
|
54
|
+
const rawReminders = pick(payload, "reminderChannelStatuses", "ReminderChannelStatuses") ?? [];
|
|
55
|
+
const reminderChannelStatuses = Array.isArray(rawReminders) ? rawReminders.map((r: any) => ({
|
|
56
|
+
id: pick(r, "id", "Id"),
|
|
57
|
+
calendarId: pick(r, "calendarId", "CalendarId"),
|
|
58
|
+
channelId: pick(r, "channelId", "ChannelId"),
|
|
59
|
+
status: !!pick(r, "status", "Status"),
|
|
60
|
+
appointmentReminders: (pick(r, "appointmentReminders", "AppointmentReminders") ?? []).map((ar: any) => ({
|
|
61
|
+
id: pick(ar, "id", "Id"),
|
|
62
|
+
reminderChannelStatusId: pick(ar, "reminderChannelStatusId", "ReminderChannelStatusId"),
|
|
63
|
+
recipientType: pick(ar, "recipientType", "RecipientType"),
|
|
64
|
+
beforeEventTime: pick(ar, "beforeEventTime", "BeforeEventTime"),
|
|
65
|
+
unit: pick(ar, "unit", "Unit"),
|
|
66
|
+
__typename: "AppointmentReminder"
|
|
67
|
+
})),
|
|
68
|
+
__typename: "ReminderChannelStatus"
|
|
69
|
+
})) : [];
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
id: n(pick(payload, "id", "Id")),
|
|
73
|
+
durationUnit: n(pick(payload, "durationUnit", "DurationUnit")),
|
|
74
|
+
minimumBookingNotice: n(pick(payload, "minimumBookingNotice", "MinimumBookingNotice")),
|
|
75
|
+
minimumBookingNoticeUnit: n(pick(payload, "minimumBookingNoticeUnit", "MinimumBookingNoticeUnit")),
|
|
76
|
+
minimumCancelationNotice: n(pick(payload, "minimumCancelationNotice", "MinimumCancelationNotice")),
|
|
77
|
+
minimumCancelationNoticeUnit: n(pick(payload, "minimumCancelationNoticeUnit", "MinimumCancelationNoticeUnit")),
|
|
78
|
+
futureLimit: n(pick(payload, "futureLimit", "FutureLimit")),
|
|
79
|
+
futureLimitUnit: n(pick(payload, "futureLimitUnit", "FutureLimitUnit")),
|
|
80
|
+
bufferTime: n(pick(payload, "bufferTime", "BufferTime")),
|
|
81
|
+
bufferTimeUnit: n(pick(payload, "bufferTimeUnit", "BufferTimeUnit")),
|
|
82
|
+
calendarLink: pick(payload, "calendarLink", "CalendarLink"),
|
|
83
|
+
uuid: pick(payload, "uuid", "Uuid", "calendarId", "CalendarId"),
|
|
84
|
+
location: pick(payload, "location", "Location") ?? "",
|
|
85
|
+
bookingPageTitle: pick(payload, "bookingPageTitle", "BookingPageTitle") ?? null,
|
|
86
|
+
reminderChannelStatuses,
|
|
87
|
+
members: mappedMembers,
|
|
88
|
+
createdOn: pick(payload, "createdOn", "CreatedOn") ?? "0001-01-01T00:00:00.000Z",
|
|
89
|
+
modifiedOn: pick(payload, "modifiedOn", "ModifiedOn") ?? "0001-01-01T00:00:00.000Z",
|
|
90
|
+
name: pick(payload, "name", "Name"),
|
|
91
|
+
timeZoneId: pick(payload, "timeZoneId", "TimeZoneId"),
|
|
92
|
+
description: pick(payload, "description", "Description") ?? "",
|
|
93
|
+
assignmentType: n(pick(payload, "assignmentType", "AssignmentType", "assignmentMethod", "AssignmentMethod")),
|
|
94
|
+
duration: n(pick(payload, "duration", "Duration")),
|
|
95
|
+
bookingLimit: n(pick(payload, "bookingLimit", "BookingLimit")),
|
|
96
|
+
calendarJson: pick(payload, "calendarJson", "CalendarJson") ?? null,
|
|
97
|
+
isThirdPartySaved: !!pick(payload, "isThirdPartySaved", "IsThirdPartySaved"),
|
|
98
|
+
themeId: n(pick(payload, "themeId", "ThemeId")),
|
|
99
|
+
theme,
|
|
100
|
+
openingHours: mappedOpeningHours,
|
|
101
|
+
appointmentUserDefinedFields: pick(payload, "appointmentUserDefinedFields", "AppointmentUserDefinedFields") ?? [],
|
|
102
|
+
__typename: "Calendar"
|
|
103
|
+
};
|
|
104
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { blazeoClientConfig } from "./blazeoClientDefaults.js";
|
|
2
|
+
import { syncBlazeoConnection } from "./syncBlazeoConnection.js";
|
|
3
|
+
|
|
4
|
+
/** Push {@link blazeoClientConfig} into `@blazeo.com/calendar-client` (global store). Call explicitly if you use file defaults; otherwise use {@link initializeAppointmentClient}. */
|
|
5
|
+
export function applyBlazeoClientConfig() {
|
|
6
|
+
debugger;
|
|
7
|
+
const baseUrl = blazeoClientConfig.baseUrl?.trim().replace(/\/+$/, "");
|
|
8
|
+
if (!baseUrl) return;
|
|
9
|
+
const consumer = blazeoClientConfig.consumer?.trim();
|
|
10
|
+
syncBlazeoConnection({
|
|
11
|
+
baseUrl,
|
|
12
|
+
...(consumer ? { consumer } : {}),
|
|
13
|
+
});
|
|
14
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional file-based defaults for local development or publishing a fork.
|
|
3
|
+
* Host apps should prefer {@link initializeAppointmentClient} with env-driven `baseUrl` / `consumer`.
|
|
4
|
+
* To apply these values, call {@link applyBlazeoClientConfig} during bootstrap (not automatic on import).
|
|
5
|
+
*
|
|
6
|
+
* @example baseUrl: "https://apptscheduling.azurewebsites.net"
|
|
7
|
+
*/
|
|
8
|
+
export const blazeoClientConfig = {
|
|
9
|
+
baseUrl: "https://apptscheduling.azurewebsites.net",
|
|
10
|
+
consumer: "smarthub",
|
|
11
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { configure } from "@blazeo.com/calendar-client";
|
|
2
|
+
import { resolveBlazeoConnection } from "../calendar/createCalendar.js";
|
|
3
|
+
|
|
4
|
+
export type EnsureBlazeoHttpOptions = {
|
|
5
|
+
baseUrl?: string;
|
|
6
|
+
consumer?: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Ensures global Blazeo `configure({ baseUrl })` runs before any `CalendarModel` / `EventModel` HTTP.
|
|
11
|
+
* Uses the same resolution as {@link resolveBlazeoConnection}: explicit args, existing `getConfig()`,
|
|
12
|
+
* then `blazeoClientDefaults` — so file defaults apply even if the host never called `configure`.
|
|
13
|
+
*/
|
|
14
|
+
export function ensureBlazeoHttpReady(options: EnsureBlazeoHttpOptions = {}):
|
|
15
|
+
| { ok: true; baseUrl: string; consumer?: string }
|
|
16
|
+
| { ok: false; error: string } {
|
|
17
|
+
// Hard-prefer explicit args (call-site can bypass any module-resolution mismatch).
|
|
18
|
+
const explicitBase = options.baseUrl?.trim().replace(/\/+$/, "");
|
|
19
|
+
const explicitConsumer = options.consumer?.trim() || undefined;
|
|
20
|
+
if (explicitBase) {
|
|
21
|
+
configure({
|
|
22
|
+
baseUrl: explicitBase,
|
|
23
|
+
...(explicitConsumer ? { consumer: explicitConsumer } : {}),
|
|
24
|
+
});
|
|
25
|
+
return { ok: true, baseUrl: explicitBase, ...(explicitConsumer ? { consumer: explicitConsumer } : {}) };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const { baseUrl, consumer } = resolveBlazeoConnection(options);
|
|
29
|
+
if (!baseUrl) {
|
|
30
|
+
return {
|
|
31
|
+
ok: false,
|
|
32
|
+
error:
|
|
33
|
+
"Blazeo base URL is not set. Call initializeAppointmentClient({ baseUrl }) or configure({ baseUrl }) at app startup, set blazeoClientConfig.baseUrl, or pass baseUrl when calling fetch APIs.",
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
configure({
|
|
37
|
+
baseUrl,
|
|
38
|
+
...(consumer ? { consumer } : {}),
|
|
39
|
+
});
|
|
40
|
+
return { ok: true, baseUrl, ...(consumer ? { consumer } : {}) };
|
|
41
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { getConfig } from "@blazeo.com/calendar-client";
|
|
2
|
+
import { syncBlazeoConnection } from "./syncBlazeoConnection.js";
|
|
3
|
+
|
|
4
|
+
export interface AppointmentClientConfig {
|
|
5
|
+
baseUrl: string;
|
|
6
|
+
consumer?: string;
|
|
7
|
+
fetch?: typeof fetch;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let isConfigured = false;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Applies Blazeo connection (same as {@link syncBlazeoConnection}) and marks the client as configured
|
|
14
|
+
* when a non-empty `baseUrl` was written to `@blazeo.com/calendar-client`.
|
|
15
|
+
*/
|
|
16
|
+
export function initializeAppointmentClient(config: AppointmentClientConfig) {
|
|
17
|
+
if (syncBlazeoConnection(config)) {
|
|
18
|
+
isConfigured = true;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function isAppointmentClientConfigured() {
|
|
23
|
+
return isConfigured || getConfig() !== null;
|
|
24
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { configure } from "@blazeo.com/calendar-client";
|
|
2
|
+
import type { AppointmentClientConfig } from "./initializeAppointmentClient.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Writes `baseUrl` / `consumer` into the global `@blazeo.com/calendar-client` `configure()` store.
|
|
6
|
+
* Returns whether anything was applied (skipped when `baseUrl` is empty after trim).
|
|
7
|
+
*/
|
|
8
|
+
export function syncBlazeoConnection(config: AppointmentClientConfig): boolean {
|
|
9
|
+
const baseUrl = config.baseUrl?.trim().replace(/\/+$/, "");
|
|
10
|
+
if (!baseUrl) return false;
|
|
11
|
+
configure({
|
|
12
|
+
baseUrl,
|
|
13
|
+
...(config.consumer != null && String(config.consumer).trim() !== ""
|
|
14
|
+
? { consumer: String(config.consumer).trim() }
|
|
15
|
+
: {}),
|
|
16
|
+
...(config.fetch ? { fetch: config.fetch } : {}),
|
|
17
|
+
});
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { EventModel, configure } from "@blazeo.com/calendar-client";
|
|
2
|
+
import { buildModelEnv, resolveBlazeoConnection } from "../calendar/createCalendar.js";
|
|
3
|
+
import { mapAppointmentToEventSnapshot } from "./mapAppointmentToEventSnapshot.js";
|
|
4
|
+
|
|
5
|
+
function isFailureStatus(res: any) {
|
|
6
|
+
return res.status !== "success" && res.status !== "Success";
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function ensureConfigure(resolvedBase: string | undefined, resolvedConsumer: string | undefined) {
|
|
10
|
+
if (resolvedBase) {
|
|
11
|
+
configure({
|
|
12
|
+
baseUrl: resolvedBase,
|
|
13
|
+
...(resolvedConsumer ? { consumer: resolvedConsumer } : {}),
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function runEventMutation(input: any, mode: "create" | "reschedule", options: any) {
|
|
19
|
+
const { baseUrl: resolvedBase, consumer: resolvedConsumer } = resolveBlazeoConnection(options);
|
|
20
|
+
ensureConfigure(resolvedBase, resolvedConsumer);
|
|
21
|
+
|
|
22
|
+
const baseUrl = resolvedBase;
|
|
23
|
+
const consumer = resolvedConsumer;
|
|
24
|
+
|
|
25
|
+
if (!options.localOnly && !baseUrl) {
|
|
26
|
+
return {
|
|
27
|
+
ok: false,
|
|
28
|
+
error:
|
|
29
|
+
"baseUrl is missing. Set `blazeoClientConfig.baseUrl` in `appointment-client/src/config/blazeoClientDefaults.ts` or call `configure({ baseUrl })`.",
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const snapshot = mapAppointmentToEventSnapshot(input, mode);
|
|
34
|
+
const eventIdForApi = snapshot.eventId;
|
|
35
|
+
|
|
36
|
+
if (mode === "reschedule" && (!eventIdForApi || eventIdForApi === "new")) {
|
|
37
|
+
return {
|
|
38
|
+
ok: false,
|
|
39
|
+
error: "thirdPartyAppointmentId is required for reschedule (existing Blazeo event id).",
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const env = buildModelEnv(baseUrl, consumer, Boolean(options.localOnly));
|
|
44
|
+
if (!options.localOnly && env.baseUrl == null) {
|
|
45
|
+
return {
|
|
46
|
+
ok: false,
|
|
47
|
+
error: "Model env requires baseUrl. Set `blazeoClientConfig` or pass `baseUrl` in options.",
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const eventNode: any = EventModel.create(snapshot, env);
|
|
52
|
+
|
|
53
|
+
if (options.localOnly) {
|
|
54
|
+
return { ok: true, event: eventNode };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const offset = options.offsetMinutes;
|
|
58
|
+
const apiRes: any =
|
|
59
|
+
mode === "create" ? await eventNode.create(offset) : await eventNode.reschedule(offset);
|
|
60
|
+
|
|
61
|
+
if (isFailureStatus(apiRes)) {
|
|
62
|
+
const msg =
|
|
63
|
+
apiRes.message ??
|
|
64
|
+
(typeof apiRes.data === "string" ? apiRes.data : undefined) ??
|
|
65
|
+
JSON.stringify(apiRes);
|
|
66
|
+
return {
|
|
67
|
+
ok: false,
|
|
68
|
+
error:
|
|
69
|
+
mode === "create" ? msg || "Event create failed" : msg || "Event reschedule failed",
|
|
70
|
+
apiResponse: apiRes,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return { ok: true, event: eventNode, apiResponse: apiRes };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Creates an appointment event — `Event.create()` → `POST /event/create`
|
|
79
|
+
* (aligned with `AppointmentAPIAdapter.Create`).
|
|
80
|
+
*/
|
|
81
|
+
export async function createAppointmentEventAsync(input: any, options: any = {}) {
|
|
82
|
+
try {
|
|
83
|
+
return await runEventMutation(input, "create", options);
|
|
84
|
+
} catch (err) {
|
|
85
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
86
|
+
return { ok: false, error: message };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Reschedules an appointment — `Event.reschedule()` → `POST /event/reschedule`
|
|
92
|
+
* (aligned with `AppointmentAPIAdapter.Reschedule`).
|
|
93
|
+
*/
|
|
94
|
+
export async function rescheduleAppointmentEventAsync(input: any, options: any = {}) {
|
|
95
|
+
try {
|
|
96
|
+
return await runEventMutation(input, "reschedule", options);
|
|
97
|
+
} catch (err) {
|
|
98
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
99
|
+
return { ok: false, error: message };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Cancels an appointment — `EventModel.cancel` → `GET /event/cancel`
|
|
105
|
+
* (aligned with `AppointmentAPIAdapter.Cancel`).
|
|
106
|
+
*/
|
|
107
|
+
export async function cancelAppointmentEventAsync(appointmentEventId: string, options: any = {}) {
|
|
108
|
+
try {
|
|
109
|
+
const id = appointmentEventId.trim();
|
|
110
|
+
if (!id) {
|
|
111
|
+
return { ok: false, error: "appointmentEventId is required for cancel." };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const { baseUrl: resolvedBase, consumer: resolvedConsumer } = resolveBlazeoConnection(options);
|
|
115
|
+
ensureConfigure(resolvedBase, resolvedConsumer);
|
|
116
|
+
|
|
117
|
+
const baseUrl = resolvedBase;
|
|
118
|
+
if (!options.localOnly && !baseUrl) {
|
|
119
|
+
return {
|
|
120
|
+
ok: false,
|
|
121
|
+
error:
|
|
122
|
+
"baseUrl is missing. Set `blazeoClientConfig.baseUrl` in `appointment-client/src/config/blazeoClientDefaults.ts` or call `configure({ baseUrl })`.",
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (options.localOnly) {
|
|
127
|
+
return { ok: true, apiResponse: undefined };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const apiRes: any = await (EventModel as any).cancel(id);
|
|
131
|
+
if (isFailureStatus(apiRes)) {
|
|
132
|
+
const msg =
|
|
133
|
+
apiRes.message ??
|
|
134
|
+
(typeof apiRes.data === "string" ? apiRes.data : undefined) ??
|
|
135
|
+
JSON.stringify(apiRes);
|
|
136
|
+
return {
|
|
137
|
+
ok: false,
|
|
138
|
+
error: msg || "Event cancel failed",
|
|
139
|
+
apiResponse: apiRes,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return { ok: true, apiResponse: apiRes };
|
|
144
|
+
} catch (err) {
|
|
145
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
146
|
+
return { ok: false, error: message };
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
function parseDate(value: any) {
|
|
2
|
+
const d = value instanceof Date ? value : new Date(value);
|
|
3
|
+
if (Number.isNaN(d.getTime())) {
|
|
4
|
+
throw new Error("Invalid startDate or endDate");
|
|
5
|
+
}
|
|
6
|
+
return d;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function formatYmd(d: Date) {
|
|
10
|
+
const y = d.getFullYear();
|
|
11
|
+
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
12
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
13
|
+
return `${y}-${m}-${day}`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function normalizeParticipantId(id: string) {
|
|
17
|
+
return id.trim().replace(/^\{|\}$/g, "");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Maps Apex appointment input to a Blazeo `Event` MST snapshot for
|
|
22
|
+
* {@link EventModel.create} from `@blazeo.com/calendar-client`.
|
|
23
|
+
*/
|
|
24
|
+
export function mapAppointmentToEventSnapshot(input: any, mode: "create" | "reschedule") {
|
|
25
|
+
const start = parseDate(input.startDate);
|
|
26
|
+
const end = parseDate(input.endDate);
|
|
27
|
+
const description =
|
|
28
|
+
mode === "create"
|
|
29
|
+
? (input.description ?? null)
|
|
30
|
+
: (input.description ?? input.notes ?? null);
|
|
31
|
+
|
|
32
|
+
const eventIdRaw = input.thirdPartyAppointmentId?.trim();
|
|
33
|
+
const eventId = eventIdRaw && eventIdRaw !== "new" ? eventIdRaw : "new";
|
|
34
|
+
const email = input.email ?? input.visitorEmail ?? null;
|
|
35
|
+
const phone = input.phone ?? input.visitorPhone ?? null;
|
|
36
|
+
const visitorName = input.visitorName?.trim() || null;
|
|
37
|
+
|
|
38
|
+
const snap: any = {
|
|
39
|
+
eventId,
|
|
40
|
+
calendarId: input.thirdPartyCalendarId?.trim() ?? "",
|
|
41
|
+
participantId: normalizeParticipantId(input.participantId),
|
|
42
|
+
title: input.title ?? null,
|
|
43
|
+
description,
|
|
44
|
+
startDate: formatYmd(start),
|
|
45
|
+
endDate: formatYmd(end),
|
|
46
|
+
startHour: start.getHours(),
|
|
47
|
+
startMinute: start.getMinutes(),
|
|
48
|
+
endHour: end.getHours(),
|
|
49
|
+
endMinute: end.getMinutes(),
|
|
50
|
+
visitorName,
|
|
51
|
+
visitorEmail: email,
|
|
52
|
+
visitorPhone: phone,
|
|
53
|
+
rescheduleLink: input.rescheduleUrl ?? null,
|
|
54
|
+
cancelLink: input.cancelUrl ?? null,
|
|
55
|
+
timeZone: input.timeZone ?? null,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
if (mode === "create") {
|
|
59
|
+
const now = new Date().toISOString();
|
|
60
|
+
snap.createdOn = now;
|
|
61
|
+
snap.modifiedOn = now;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return snap;
|
|
65
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { CalendarSlotModel } from "./models/CalendarRootModel.js";
|
|
2
|
+
import { CalendarRootModel } from "./models/CalendarRootModel.js";
|
|
3
|
+
import { EventModel } from "./models/CalendarRootModel.js";
|
|
4
|
+
import { ParticipantModel } from "./models/CalendarRootModel.js";
|
|
5
|
+
|
|
6
|
+
const EXAMPLE_SLOT_SNAPSHOTS = [
|
|
7
|
+
{
|
|
8
|
+
id: "slot-1",
|
|
9
|
+
title: "Team standup",
|
|
10
|
+
start: "09:00",
|
|
11
|
+
end: "09:15",
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
id: "slot-2",
|
|
15
|
+
title: "Focus block",
|
|
16
|
+
start: "10:00",
|
|
17
|
+
end: "12:00",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: "slot-3",
|
|
21
|
+
title: "1:1 with design",
|
|
22
|
+
start: "14:00",
|
|
23
|
+
end: "14:30",
|
|
24
|
+
},
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
const EXAMPLE_EVENT_SNAPSHOTS = [
|
|
28
|
+
{
|
|
29
|
+
id: "ev-1",
|
|
30
|
+
title: "Product roadmap review",
|
|
31
|
+
calendarId: "cal-eng",
|
|
32
|
+
startsAt: "2026-04-02T15:00:00.000Z",
|
|
33
|
+
endsAt: "2026-04-02T16:00:00.000Z",
|
|
34
|
+
participantIds: ["p-1", "p-2"],
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: "ev-2",
|
|
38
|
+
title: "Customer onboarding call",
|
|
39
|
+
calendarId: "cal-sales",
|
|
40
|
+
startsAt: "2026-04-03T10:30:00.000Z",
|
|
41
|
+
endsAt: "2026-04-03T11:00:00.000Z",
|
|
42
|
+
participantIds: ["p-3"],
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const EXAMPLE_PARTICIPANT_SNAPSHOTS = [
|
|
47
|
+
{ id: "p-1", name: "Alex Morgan", email: "alex@example.com", role: "Organizer" },
|
|
48
|
+
{ id: "p-2", name: "Jordan Lee", email: "jordan@example.com", role: "Required" },
|
|
49
|
+
{ id: "p-3", name: "Sam Rivera", email: "sam@example.com", role: "Optional" },
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
/** Example slot nodes (MST instances). */
|
|
53
|
+
export function getExampleSlots() {
|
|
54
|
+
return EXAMPLE_SLOT_SNAPSHOTS.map((s) => CalendarSlotModel.create(s as any));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Example event nodes. */
|
|
58
|
+
export function getExampleEvents() {
|
|
59
|
+
return EXAMPLE_EVENT_SNAPSHOTS.map((s) => EventModel.create(s as any));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Example participant nodes. */
|
|
63
|
+
export function getExampleParticipants() {
|
|
64
|
+
return EXAMPLE_PARTICIPANT_SNAPSHOTS.map((s) => ParticipantModel.create(s as any));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Full root store snapshot suitable for `createCalendarRoot(snapshot)`. */
|
|
68
|
+
export function getExampleCalendarRootSnapshot() {
|
|
69
|
+
return {
|
|
70
|
+
slots: EXAMPLE_SLOT_SNAPSHOTS,
|
|
71
|
+
events: EXAMPLE_EVENT_SNAPSHOTS,
|
|
72
|
+
participants: EXAMPLE_PARTICIPANT_SNAPSHOTS,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Root store with example slots, events, and participants. */
|
|
77
|
+
export function getExampleCalendarRoot() {
|
|
78
|
+
return CalendarRootModel.create(getExampleCalendarRootSnapshot() as any);
|
|
79
|
+
}
|