@blazeo.com/appointment-client 1.0.11 → 1.0.14

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.
Files changed (138) hide show
  1. package/blazeo.com-appointment-client-1.0.14.tgz +0 -0
  2. package/package.json +3 -2
  3. package/sample/src/EventTab.jsx +435 -395
  4. package/sample/src/FetchCalendarTab.jsx +19 -33
  5. package/sample/src/LeadTab.jsx +335 -0
  6. package/src/calendar/calendarCreation.ts +62 -15
  7. package/src/calendar/fetchCalendarDetails.ts +10 -2
  8. package/src/calendar/getCalendarsByCompany.ts +17 -64
  9. package/src/calendar/mapToDesiredResponse.ts +31 -17
  10. package/src/events/getAppointmentsByFilter.ts +98 -0
  11. package/src/index.ts +23 -14
  12. package/src/lead/fetchLeadDetails.ts +106 -0
  13. package/blazeo.com-appointment-client-1.0.11.tgz +0 -0
  14. package/dist/calendar/blazeoCalendarRelationMethods.d.ts +0 -8
  15. package/dist/calendar/blazeoCalendarRelationMethods.d.ts.map +0 -1
  16. package/dist/calendar/blazeoCalendarRelationMethods.js +0 -16
  17. package/dist/calendar/blazeoCalendarRelationMethods.js.map +0 -1
  18. package/dist/calendar/buildUnifiedCalendarView.d.ts +0 -39
  19. package/dist/calendar/buildUnifiedCalendarView.js +0 -301
  20. package/dist/calendar/calendarCreation.d.ts +0 -27
  21. package/dist/calendar/calendarCreation.js +0 -191
  22. package/dist/calendar/calendarCreationFacade.d.ts +0 -27
  23. package/dist/calendar/calendarCreationFacade.d.ts.map +0 -1
  24. package/dist/calendar/calendarCreationFacade.js +0 -167
  25. package/dist/calendar/calendarCreationFacade.js.map +0 -1
  26. package/dist/calendar/createCalendar.d.ts +0 -81
  27. package/dist/calendar/createCalendar.d.ts.map +0 -1
  28. package/dist/calendar/createCalendar.js +0 -206
  29. package/dist/calendar/createCalendar.js.map +0 -1
  30. package/dist/calendar/fetchCalendarDetails.d.ts +0 -41
  31. package/dist/calendar/fetchCalendarDetails.js +0 -262
  32. package/dist/calendar/fetchCalendarWithOpeningHours.d.ts +0 -25
  33. package/dist/calendar/fetchCalendarWithOpeningHours.js +0 -114
  34. package/dist/calendar/getAllParticipantOpeningHours.d.ts +0 -22
  35. package/dist/calendar/getAllParticipantOpeningHours.js +0 -22
  36. package/dist/calendar/getCalendarsByCompany.d.ts +0 -9
  37. package/dist/calendar/getCalendarsByCompany.js +0 -107
  38. package/dist/calendar/getOpeningHours.d.ts +0 -8
  39. package/dist/calendar/getOpeningHours.js +0 -9
  40. package/dist/calendar/getParticipantOpeningHours.d.ts +0 -37
  41. package/dist/calendar/getParticipantOpeningHours.js +0 -48
  42. package/dist/calendar/getParticipants.d.ts +0 -7
  43. package/dist/calendar/getParticipants.js +0 -13
  44. package/dist/calendar/mapCalendarBoToBlazeoSnapshot.d.ts +0 -10
  45. package/dist/calendar/mapCalendarBoToBlazeoSnapshot.d.ts.map +0 -1
  46. package/dist/calendar/mapCalendarBoToBlazeoSnapshot.js +0 -44
  47. package/dist/calendar/mapCalendarBoToBlazeoSnapshot.js.map +0 -1
  48. package/dist/calendar/mapCalendarToBlazeoSnapshot.d.ts +0 -29
  49. package/dist/calendar/mapCalendarToBlazeoSnapshot.d.ts.map +0 -1
  50. package/dist/calendar/mapCalendarToBlazeoSnapshot.js +0 -44
  51. package/dist/calendar/mapCalendarToBlazeoSnapshot.js.map +0 -1
  52. package/dist/calendar/mapToDesiredResponse.d.ts +0 -70
  53. package/dist/calendar/mapToDesiredResponse.js +0 -99
  54. package/dist/config/applyBlazeoClientConfig.d.ts +0 -3
  55. package/dist/config/applyBlazeoClientConfig.d.ts.map +0 -1
  56. package/dist/config/applyBlazeoClientConfig.js +0 -14
  57. package/dist/config/applyBlazeoClientConfig.js.map +0 -1
  58. package/dist/config/applyBlazeoDefaults.d.ts +0 -2
  59. package/dist/config/applyBlazeoDefaults.d.ts.map +0 -1
  60. package/dist/config/applyBlazeoDefaults.js +0 -14
  61. package/dist/config/applyBlazeoDefaults.js.map +0 -1
  62. package/dist/config/blazeo.config.d.ts +0 -11
  63. package/dist/config/blazeo.config.d.ts.map +0 -1
  64. package/dist/config/blazeo.config.js +0 -11
  65. package/dist/config/blazeo.config.js.map +0 -1
  66. package/dist/config/blazeoClientDefaults.d.ts +0 -11
  67. package/dist/config/blazeoClientDefaults.d.ts.map +0 -1
  68. package/dist/config/blazeoClientDefaults.js +0 -11
  69. package/dist/config/blazeoClientDefaults.js.map +0 -1
  70. package/dist/config/ensureBlazeoHttpReady.d.ts +0 -17
  71. package/dist/config/ensureBlazeoHttpReady.js +0 -31
  72. package/dist/config/initializeAppointmentClient.d.ts +0 -11
  73. package/dist/config/initializeAppointmentClient.d.ts.map +0 -1
  74. package/dist/config/initializeAppointmentClient.js +0 -15
  75. package/dist/config/initializeAppointmentClient.js.map +0 -1
  76. package/dist/config/syncBlazeoConnection.d.ts +0 -6
  77. package/dist/config/syncBlazeoConnection.js +0 -18
  78. package/dist/events/appointmentEventFacade.d.ts +0 -67
  79. package/dist/events/appointmentEventFacade.d.ts.map +0 -1
  80. package/dist/events/appointmentEventFacade.js +0 -124
  81. package/dist/events/appointmentEventFacade.js.map +0 -1
  82. package/dist/events/mapAppointmentToEventSnapshot.d.ts +0 -5
  83. package/dist/events/mapAppointmentToEventSnapshot.d.ts.map +0 -1
  84. package/dist/events/mapAppointmentToEventSnapshot.js +0 -57
  85. package/dist/events/mapAppointmentToEventSnapshot.js.map +0 -1
  86. package/dist/exampleData.d.ts +0 -119
  87. package/dist/exampleData.d.ts.map +0 -1
  88. package/dist/exampleData.js +0 -71
  89. package/dist/exampleData.js.map +0 -1
  90. package/dist/facade/calendarCreationFacade.d.ts +0 -40
  91. package/dist/facade/calendarCreationFacade.d.ts.map +0 -1
  92. package/dist/facade/calendarCreationFacade.js +0 -96
  93. package/dist/facade/calendarCreationFacade.js.map +0 -1
  94. package/dist/facade/mapCalendarBOToSnapshot.d.ts +0 -10
  95. package/dist/facade/mapCalendarBOToSnapshot.d.ts.map +0 -1
  96. package/dist/facade/mapCalendarBOToSnapshot.js +0 -44
  97. package/dist/facade/mapCalendarBOToSnapshot.js.map +0 -1
  98. package/dist/facades/index.d.ts +0 -12
  99. package/dist/facades/index.d.ts.map +0 -1
  100. package/dist/facades/index.js +0 -12
  101. package/dist/facades/index.js.map +0 -1
  102. package/dist/index.d.ts +0 -40
  103. package/dist/index.d.ts.map +0 -1
  104. package/dist/index.js +0 -39
  105. package/dist/index.js.map +0 -1
  106. package/dist/models/CalendarRootModel.d.ts +0 -56
  107. package/dist/models/CalendarRootModel.d.ts.map +0 -1
  108. package/dist/models/CalendarRootModel.js +0 -54
  109. package/dist/models/CalendarRootModel.js.map +0 -1
  110. package/dist/models/CalendarSlotModel.d.ts +0 -9
  111. package/dist/models/CalendarSlotModel.d.ts.map +0 -1
  112. package/dist/models/CalendarSlotModel.js +0 -8
  113. package/dist/models/CalendarSlotModel.js.map +0 -1
  114. package/dist/models/EventModel.d.ts +0 -11
  115. package/dist/models/EventModel.d.ts.map +0 -1
  116. package/dist/models/EventModel.js +0 -10
  117. package/dist/models/EventModel.js.map +0 -1
  118. package/dist/models/ParticipantModel.d.ts +0 -9
  119. package/dist/models/ParticipantModel.d.ts.map +0 -1
  120. package/dist/models/ParticipantModel.js +0 -8
  121. package/dist/models/ParticipantModel.js.map +0 -1
  122. package/dist/models/index.d.ts +0 -5
  123. package/dist/models/index.d.ts.map +0 -1
  124. package/dist/models/index.js +0 -5
  125. package/dist/models/index.js.map +0 -1
  126. package/dist/types/appointment.d.ts +0 -28
  127. package/dist/types/appointment.d.ts.map +0 -1
  128. package/dist/types/appointment.js +0 -6
  129. package/dist/types/appointment.js.map +0 -1
  130. package/dist/types/calendar.d.ts +0 -52
  131. package/dist/types/calendar.d.ts.map +0 -1
  132. package/dist/types/calendar.js +0 -6
  133. package/dist/types/calendar.js.map +0 -1
  134. package/dist/types/calendarBo.d.ts +0 -62
  135. package/dist/types/calendarBo.d.ts.map +0 -1
  136. package/dist/types/calendarBo.js +0 -6
  137. package/dist/types/calendarBo.js.map +0 -1
  138. package/sample/package-lock.json +0 -1778
@@ -1,395 +1,435 @@
1
- import { useMemo, useState } from "react";
2
- import {
3
- cancelAppointmentEventAsync,
4
- createAppointmentEventAsync,
5
- ensureBlazeoHttpReady,
6
- EventModel,
7
- rescheduleAppointmentEventAsync,
8
- } from "appointment-client";
9
- import { getSnapshot, isStateTreeNode } from "mobx-state-tree";
10
- import {
11
- configureBlazeoFromEffective,
12
- useBlazeoConnection,
13
- } from "./BlazeoConnectionSettings.jsx";
14
- import { mapBlazeoDemoError } from "./blazeoDemoError.js";
15
-
16
- function getExampleCreatePayload() {
17
- const start = new Date();
18
- start.setHours(10, 0, 0, 0);
19
- const end = new Date(start);
20
- end.setHours(10, 30, 0, 0);
21
- return {
22
- thirdPartyCalendarId: "your-calendar-id",
23
- participantId: "00000000-0000-0000-0000-000000000000",
24
- title: "Sample appointment",
25
- description: "Created via appointment-client sample",
26
- startDate: start.toISOString(),
27
- endDate: end.toISOString(),
28
- email: "visitor@example.com",
29
- visitorName: "Visitor",
30
- timeZone: "Pakistan Standard Time",
31
- rescheduleUrl: "https://example.com/reschedule",
32
- cancelUrl: "https://example.com/cancel",
33
- };
34
- }
35
-
36
- function getExampleReschedulePayload() {
37
- const start = new Date();
38
- start.setDate(start.getDate() + 1);
39
- start.setHours(14, 0, 0, 0);
40
- const end = new Date(start);
41
- end.setHours(14, 45, 0, 0);
42
- return {
43
- thirdPartyAppointmentId: "existing-blazeo-event-id",
44
- thirdPartyCalendarId: "your-calendar-id",
45
- participantId: "00000000-0000-0000-0000-000000000000",
46
- title: "Rescheduled title",
47
- notes: "Reschedule body",
48
- startDate: start.toISOString(),
49
- endDate: end.toISOString(),
50
- email: "visitor@example.com",
51
- timeZone: "Pakistan Standard Time",
52
- };
53
- }
54
-
55
- function resultToJson(result) {
56
- if (!result) return "";
57
- if (result.ok && result.event && isStateTreeNode(result.event)) {
58
- return JSON.stringify(
59
- {
60
- ok: true,
61
- eventSnapshot: getSnapshot(result.event),
62
- apiResponse: result.apiResponse ?? null,
63
- },
64
- null,
65
- 2
66
- );
67
- }
68
- return JSON.stringify(result, null, 2);
69
- }
70
-
71
- function safeJsonParse(text, fallback) {
72
- try {
73
- return JSON.parse(text);
74
- } catch {
75
- return fallback;
76
- }
77
- }
78
-
79
- export function EventTab() {
80
- const { effective, connectionOpts } = useBlazeoConnection();
81
- const [offsetMinutes, setOffsetMinutes] = useState(-new Date().getTimezoneOffset());
82
- const [createJson, setCreateJson] = useState(() =>
83
- JSON.stringify(getExampleCreatePayload(), null, 2)
84
- );
85
- const [rescheduleJson, setRescheduleJson] = useState(() =>
86
- JSON.stringify(getExampleReschedulePayload(), null, 2)
87
- );
88
- const [searchCompanyKey, setSearchCompanyKey] = useState("");
89
- const [searchFrom, setSearchFrom] = useState(() => new Date().toISOString().slice(0, 10));
90
- const [searchTo, setSearchTo] = useState(() => {
91
- const d = new Date();
92
- d.setDate(d.getDate() + 7);
93
- return d.toISOString().slice(0, 10);
94
- });
95
- const [searchFiltersJson, setSearchFiltersJson] = useState(() =>
96
- JSON.stringify(
97
- {
98
- calendarId: "",
99
- participantId: "",
100
- leadId: "",
101
- visitorName: "",
102
- visitorEmail: "",
103
- visitorPhone: "",
104
- title: "",
105
- search: "",
106
- attendeeStatus: "",
107
- eventSource: "",
108
- sort: "",
109
- sortOrder: "desc",
110
- page: 1,
111
- page_size: 25,
112
- },
113
- null,
114
- 2
115
- )
116
- );
117
- const [cancelEventId, setCancelEventId] = useState("");
118
- const [busy, setBusy] = useState(false);
119
- const [error, setError] = useState("");
120
- const [output, setOutput] = useState("");
121
-
122
- const opts = useMemo(() => ({ offsetMinutes: Number(offsetMinutes) || 0 }), [offsetMinutes]);
123
- const eventOpts = useMemo(() => ({ ...opts, ...connectionOpts }), [opts, connectionOpts]);
124
-
125
- function ensureBase() {
126
- if (!effective.baseUrl) {
127
- setError("Set Base URL in the connection card above.");
128
- return false;
129
- }
130
- return true;
131
- }
132
-
133
- async function handleCreate(e) {
134
- e.preventDefault();
135
- setError("");
136
- setOutput("");
137
- if (!ensureBase()) return;
138
- configureBlazeoFromEffective(effective);
139
- ensureBlazeoHttpReady({
140
- baseUrl: effective.baseUrl,
141
- ...(effective.consumer ? { consumer: effective.consumer } : {}),
142
- });
143
- let payload;
144
- try {
145
- payload = JSON.parse(createJson);
146
- } catch (err) {
147
- setError(`Create JSON: ${err instanceof Error ? err.message : String(err)}`);
148
- return;
149
- }
150
- setBusy(true);
151
- try {
152
- const result = await createAppointmentEventAsync(payload, eventOpts);
153
- setOutput(resultToJson(result));
154
- if (!result.ok) setError(mapBlazeoDemoError(result.error));
155
- } finally {
156
- setBusy(false);
157
- }
158
- }
159
-
160
- async function handleReschedule(e) {
161
- e.preventDefault();
162
- setError("");
163
- setOutput("");
164
- if (!ensureBase()) return;
165
- configureBlazeoFromEffective(effective);
166
- ensureBlazeoHttpReady({
167
- baseUrl: effective.baseUrl,
168
- ...(effective.consumer ? { consumer: effective.consumer } : {}),
169
- });
170
- let payload;
171
- try {
172
- payload = JSON.parse(rescheduleJson);
173
- } catch (err) {
174
- setError(`Reschedule JSON: ${err instanceof Error ? err.message : String(err)}`);
175
- return;
176
- }
177
- setBusy(true);
178
- try {
179
- const result = await rescheduleAppointmentEventAsync(payload, eventOpts);
180
- setOutput(resultToJson(result));
181
- if (!result.ok) setError(mapBlazeoDemoError(result.error));
182
- } finally {
183
- setBusy(false);
184
- }
185
- }
186
-
187
- async function handleCancel(e) {
188
- e.preventDefault();
189
- setError("");
190
- setOutput("");
191
- const id = cancelEventId.trim();
192
- if (!id) return setError("Enter Blazeo event id to cancel.");
193
- if (!ensureBase()) return;
194
- configureBlazeoFromEffective(effective);
195
- ensureBlazeoHttpReady({
196
- baseUrl: effective.baseUrl,
197
- ...(effective.consumer ? { consumer: effective.consumer } : {}),
198
- });
199
- setBusy(true);
200
- try {
201
- const result = await cancelAppointmentEventAsync(id, {
202
- ...connectionOpts,
203
- baseUrl: effective.baseUrl,
204
- ...(effective.consumer ? { consumer: effective.consumer } : {}),
205
- });
206
- setOutput(JSON.stringify(result, null, 2));
207
- if (!result.ok) setError(mapBlazeoDemoError(result.error));
208
- } finally {
209
- setBusy(false);
210
- }
211
- }
212
-
213
- async function handleSearchByDateRange(e) {
214
- e.preventDefault();
215
- setError("");
216
- setOutput("");
217
- const companyKey = searchCompanyKey.trim();
218
- if (!companyKey) return setError("Enter company key.");
219
- if (!searchFrom) return setError("Pick start date.");
220
- if (!searchTo) return setError("Pick end date.");
221
- if (!ensureBase()) return;
222
- configureBlazeoFromEffective(effective);
223
- ensureBlazeoHttpReady({
224
- baseUrl: effective.baseUrl,
225
- ...(effective.consumer ? { consumer: effective.consumer } : {}),
226
- });
227
-
228
- const optsFromJson = safeJsonParse(searchFiltersJson, {});
229
- const startDateFrom = new Date(`${searchFrom}T00:00:00.000Z`).toISOString();
230
- const startDateTo = new Date(`${searchTo}T23:59:59.999Z`).toISOString();
231
-
232
- setBusy(true);
233
- try {
234
- const res = await EventModel.getByDateRangeWithFilters(
235
- companyKey,
236
- startDateFrom,
237
- startDateTo,
238
- optsFromJson
239
- );
240
-
241
- const events = (res?.events ?? []).map((e) =>
242
- isStateTreeNode(e) ? getSnapshot(e) : (e?.toJSON?.() ?? e)
243
- );
244
- const totalCount = res?.totalCount ?? events.length;
245
- setOutput(JSON.stringify({ totalCount, events }, null, 2));
246
- } catch (err) {
247
- setError(mapBlazeoDemoError(err instanceof Error ? err.message : String(err)));
248
- } finally {
249
- setBusy(false);
250
- }
251
- }
252
-
253
- return (
254
- <>
255
- <div className="card">
256
- <h2>Appointment events</h2>
257
- <p className="muted small">
258
- Create/reschedule/cancel Blazeo events via <code>appointment-client</code>.
259
- </p>
260
- <label className="form__label">
261
- <span>Offset minutes</span>
262
- <input
263
- type="number"
264
- className="form__input"
265
- value={offsetMinutes}
266
- onChange={(e) => setOffsetMinutes(e.target.value)}
267
- />
268
- </label>
269
- </div>
270
-
271
- <div className="card">
272
- <h2>Search events (date range + filters)</h2>
273
- <p className="muted small">
274
- Calls <code>EventModel.getByDateRangeWithFilters</code> →
275
- <code> GET /event/search/daterange/get</code> (company scope). Offset header comes from the{" "}
276
- <code>offset</code> field above.
277
- </p>
278
- <form onSubmit={handleSearchByDateRange} className="form">
279
- <label className="form__label">
280
- <span>Company key</span>
281
- <input
282
- className="form__input"
283
- value={searchCompanyKey}
284
- onChange={(e) => setSearchCompanyKey(e.target.value)}
285
- placeholder="company_key"
286
- autoComplete="off"
287
- />
288
- </label>
289
- <div className="connection-card__row">
290
- <label className="form__label">
291
- <span>Start date (from)</span>
292
- <input
293
- type="date"
294
- className="form__input"
295
- value={searchFrom}
296
- onChange={(e) => setSearchFrom(e.target.value)}
297
- />
298
- </label>
299
- <label className="form__label">
300
- <span>Start date (to)</span>
301
- <input
302
- type="date"
303
- className="form__input"
304
- value={searchTo}
305
- onChange={(e) => setSearchTo(e.target.value)}
306
- />
307
- </label>
308
- </div>
309
- <label className="form__label">
310
- <span>Filters (JSON)</span>
311
- <textarea
312
- className="form__textarea"
313
- value={searchFiltersJson}
314
- onChange={(e) => setSearchFiltersJson(e.target.value)}
315
- spellCheck={false}
316
- rows={10}
317
- />
318
- </label>
319
- <button type="submit" className="btn btn--secondary" disabled={busy}>
320
- {busy ? "Loading…" : "Search"}
321
- </button>
322
- </form>
323
- </div>
324
-
325
- <div className="card">
326
- <h2>Create event</h2>
327
- <form onSubmit={handleCreate} className="form">
328
- <label className="form__label">
329
- <span>Payload (JSON)</span>
330
- <textarea
331
- className="form__textarea"
332
- value={createJson}
333
- onChange={(e) => setCreateJson(e.target.value)}
334
- spellCheck={false}
335
- rows={14}
336
- />
337
- </label>
338
- <button type="submit" className="btn btn--primary" disabled={busy}>
339
- {busy ? "Working…" : "Create"}
340
- </button>
341
- </form>
342
- </div>
343
-
344
- <div className="card">
345
- <h2>Reschedule event</h2>
346
- <form onSubmit={handleReschedule} className="form">
347
- <label className="form__label">
348
- <span>Payload (JSON)</span>
349
- <textarea
350
- className="form__textarea"
351
- value={rescheduleJson}
352
- onChange={(e) => setRescheduleJson(e.target.value)}
353
- spellCheck={false}
354
- rows={14}
355
- />
356
- </label>
357
- <button type="submit" className="btn btn--primary" disabled={busy}>
358
- {busy ? "Working…" : "Reschedule"}
359
- </button>
360
- </form>
361
- </div>
362
-
363
- <div className="card">
364
- <h2>Cancel event</h2>
365
- <form onSubmit={handleCancel} className="form">
366
- <label className="form__label">
367
- <span>Event id</span>
368
- <input
369
- className="form__input"
370
- value={cancelEventId}
371
- onChange={(e) => setCancelEventId(e.target.value)}
372
- />
373
- </label>
374
- <button type="submit" className="btn btn--secondary" disabled={busy}>
375
- {busy ? "Working…" : "Cancel"}
376
- </button>
377
- </form>
378
- </div>
379
-
380
- {error ? (
381
- <div className="card card--error" role="alert">
382
- <h2>Error</h2>
383
- <pre className="pre-block">{error}</pre>
384
- </div>
385
- ) : null}
386
-
387
- {output ? (
388
- <div className="card card--success">
389
- <h2>Result</h2>
390
- <pre className="pre-block">{output}</pre>
391
- </div>
392
- ) : null}
393
- </>
394
- );
395
- }
1
+ import { useMemo, useState } from "react";
2
+ import {
3
+ cancelAppointmentEventAsync,
4
+ createAppointmentEventAsync,
5
+ ensureBlazeoHttpReady,
6
+ EventModel,
7
+ getAppointmentsByFilter,
8
+ rescheduleAppointmentEventAsync,
9
+ } from "appointment-client";
10
+ import { getSnapshot, isStateTreeNode } from "mobx-state-tree";
11
+ import {
12
+ configureBlazeoFromEffective,
13
+ useBlazeoConnection,
14
+ } from "./BlazeoConnectionSettings.jsx";
15
+ import { mapBlazeoDemoError } from "./blazeoDemoError.js";
16
+
17
+ function getExampleCreatePayload() {
18
+ const start = new Date();
19
+ start.setHours(10, 0, 0, 0);
20
+ const end = new Date(start);
21
+ end.setHours(10, 30, 0, 0);
22
+ return {
23
+ thirdPartyCalendarId: "your-calendar-id",
24
+ participantId: "00000000-0000-0000-0000-000000000000",
25
+ title: "Sample appointment",
26
+ description: "Created via appointment-client sample",
27
+ startDate: start.toISOString(),
28
+ endDate: end.toISOString(),
29
+ email: "visitor@example.com",
30
+ visitorName: "Visitor",
31
+ timeZone: "Pakistan Standard Time",
32
+ rescheduleUrl: "https://example.com/reschedule",
33
+ cancelUrl: "https://example.com/cancel",
34
+ };
35
+ }
36
+
37
+ function getExampleReschedulePayload() {
38
+ const start = new Date();
39
+ start.setDate(start.getDate() + 1);
40
+ start.setHours(14, 0, 0, 0);
41
+ const end = new Date(start);
42
+ end.setHours(14, 45, 0, 0);
43
+ return {
44
+ thirdPartyAppointmentId: "existing-blazeo-event-id",
45
+ thirdPartyCalendarId: "your-calendar-id",
46
+ participantId: "00000000-0000-0000-0000-000000000000",
47
+ title: "Rescheduled title",
48
+ notes: "Reschedule body",
49
+ startDate: start.toISOString(),
50
+ endDate: end.toISOString(),
51
+ email: "visitor@example.com",
52
+ timeZone: "Pakistan Standard Time",
53
+ };
54
+ }
55
+
56
+ function resultToJson(result) {
57
+ if (!result) return "";
58
+ if (result.ok && result.event && isStateTreeNode(result.event)) {
59
+ return JSON.stringify(
60
+ {
61
+ ok: true,
62
+ eventSnapshot: getSnapshot(result.event),
63
+ apiResponse: result.apiResponse ?? null,
64
+ },
65
+ null,
66
+ 2
67
+ );
68
+ }
69
+ return JSON.stringify(result, null, 2);
70
+ }
71
+
72
+ function safeJsonParse(text, fallback) {
73
+ try {
74
+ return JSON.parse(text);
75
+ } catch {
76
+ return fallback;
77
+ }
78
+ }
79
+
80
+ export function EventTab() {
81
+ const { effective, connectionOpts } = useBlazeoConnection();
82
+ const [offsetMinutes, setOffsetMinutes] = useState(-new Date().getTimezoneOffset());
83
+ const [createJson, setCreateJson] = useState(() =>
84
+ JSON.stringify(getExampleCreatePayload(), null, 2)
85
+ );
86
+ const [rescheduleJson, setRescheduleJson] = useState(() =>
87
+ JSON.stringify(getExampleReschedulePayload(), null, 2)
88
+ );
89
+ const [searchCompanyKey, setSearchCompanyKey] = useState("");
90
+ const [searchFrom, setSearchFrom] = useState(() => new Date().toISOString().slice(0, 10));
91
+ const [searchTo, setSearchTo] = useState(() => {
92
+ const d = new Date();
93
+ d.setDate(d.getDate() + 7);
94
+ return d.toISOString().slice(0, 10);
95
+ });
96
+ const [searchFiltersJson, setSearchFiltersJson] = useState(() =>
97
+ JSON.stringify(
98
+ {
99
+ calendarId: "",
100
+ participantId: "",
101
+ leadId: "",
102
+ visitorName: "",
103
+ visitorEmail: "",
104
+ visitorPhone: "",
105
+ title: "",
106
+ search: "",
107
+ attendeeStatus: "",
108
+ eventSource: "",
109
+ sort: "",
110
+ sortOrder: "desc",
111
+ page: 1,
112
+ page_size: 25,
113
+ },
114
+ null,
115
+ 2
116
+ )
117
+ );
118
+ const [cancelEventId, setCancelEventId] = useState("");
119
+ const [busy, setBusy] = useState(false);
120
+ const [error, setError] = useState("");
121
+ const [output, setOutput] = useState("");
122
+
123
+ const opts = useMemo(() => ({ offsetMinutes: Number(offsetMinutes) || 0 }), [offsetMinutes]);
124
+ const eventOpts = useMemo(() => ({ ...opts, ...connectionOpts }), [opts, connectionOpts]);
125
+
126
+ function ensureBase() {
127
+ if (!effective.baseUrl) {
128
+ setError("Set Base URL in the connection card above.");
129
+ return false;
130
+ }
131
+ return true;
132
+ }
133
+
134
+ async function handleCreate(e) {
135
+ e.preventDefault();
136
+ setError("");
137
+ setOutput("");
138
+ if (!ensureBase()) return;
139
+ configureBlazeoFromEffective(effective);
140
+ ensureBlazeoHttpReady({
141
+ baseUrl: effective.baseUrl,
142
+ ...(effective.consumer ? { consumer: effective.consumer } : {}),
143
+ });
144
+ let payload;
145
+ try {
146
+ payload = JSON.parse(createJson);
147
+ } catch (err) {
148
+ setError(`Create JSON: ${err instanceof Error ? err.message : String(err)}`);
149
+ return;
150
+ }
151
+ setBusy(true);
152
+ try {
153
+ const result = await createAppointmentEventAsync(payload, eventOpts);
154
+ setOutput(resultToJson(result));
155
+ if (!result.ok) setError(mapBlazeoDemoError(result.error));
156
+ } finally {
157
+ setBusy(false);
158
+ }
159
+ }
160
+
161
+ async function handleReschedule(e) {
162
+ e.preventDefault();
163
+ setError("");
164
+ setOutput("");
165
+ if (!ensureBase()) return;
166
+ configureBlazeoFromEffective(effective);
167
+ ensureBlazeoHttpReady({
168
+ baseUrl: effective.baseUrl,
169
+ ...(effective.consumer ? { consumer: effective.consumer } : {}),
170
+ });
171
+ let payload;
172
+ try {
173
+ payload = JSON.parse(rescheduleJson);
174
+ } catch (err) {
175
+ setError(`Reschedule JSON: ${err instanceof Error ? err.message : String(err)}`);
176
+ return;
177
+ }
178
+ setBusy(true);
179
+ try {
180
+ const result = await rescheduleAppointmentEventAsync(payload, eventOpts);
181
+ setOutput(resultToJson(result));
182
+ if (!result.ok) setError(mapBlazeoDemoError(result.error));
183
+ } finally {
184
+ setBusy(false);
185
+ }
186
+ }
187
+
188
+ async function handleCancel(e) {
189
+ e.preventDefault();
190
+ setError("");
191
+ setOutput("");
192
+ const id = cancelEventId.trim();
193
+ if (!id) return setError("Enter Blazeo event id to cancel.");
194
+ if (!ensureBase()) return;
195
+ configureBlazeoFromEffective(effective);
196
+ ensureBlazeoHttpReady({
197
+ baseUrl: effective.baseUrl,
198
+ ...(effective.consumer ? { consumer: effective.consumer } : {}),
199
+ });
200
+ setBusy(true);
201
+ try {
202
+ const result = await cancelAppointmentEventAsync(id, {
203
+ ...connectionOpts,
204
+ baseUrl: effective.baseUrl,
205
+ ...(effective.consumer ? { consumer: effective.consumer } : {}),
206
+ });
207
+ setOutput(JSON.stringify(result, null, 2));
208
+ if (!result.ok) setError(mapBlazeoDemoError(result.error));
209
+ } finally {
210
+ setBusy(false);
211
+ }
212
+ }
213
+
214
+ async function handleSearchByDateRange(e) {
215
+ e.preventDefault();
216
+ setError("");
217
+ setOutput("");
218
+ const companyKey = searchCompanyKey.trim();
219
+ if (!companyKey) return setError("Enter company key.");
220
+ if (!searchFrom) return setError("Pick start date.");
221
+ if (!searchTo) return setError("Pick end date.");
222
+ if (!ensureBase()) return;
223
+ configureBlazeoFromEffective(effective);
224
+ ensureBlazeoHttpReady({
225
+ baseUrl: effective.baseUrl,
226
+ ...(effective.consumer ? { consumer: effective.consumer } : {}),
227
+ });
228
+
229
+ const optsFromJson = safeJsonParse(searchFiltersJson, {});
230
+ const startDateFrom = new Date(`${searchFrom}T00:00:00.000Z`).toISOString();
231
+ const startDateTo = new Date(`${searchTo}T23:59:59.999Z`).toISOString();
232
+
233
+ setBusy(true);
234
+ try {
235
+ const res = await EventModel.getByDateRangeWithFilters(
236
+ companyKey,
237
+ startDateFrom,
238
+ startDateTo,
239
+ optsFromJson
240
+ );
241
+
242
+ const events = (res?.events ?? []).map((e) =>
243
+ isStateTreeNode(e) ? getSnapshot(e) : (e?.toJSON?.() ?? e)
244
+ );
245
+ const totalCount = res?.totalCount ?? events.length;
246
+ setOutput(JSON.stringify({ totalCount, events }, null, 2));
247
+ } finally {
248
+ setBusy(false);
249
+ }
250
+ }
251
+
252
+ async function handleEnrichedSearch(e) {
253
+ e.preventDefault();
254
+ setError("");
255
+ setOutput("");
256
+ const companyKey = searchCompanyKey.trim();
257
+ if (!companyKey) return setError("Enter company key.");
258
+ if (!searchFrom) return setError("Pick start date.");
259
+ if (!searchTo) return setError("Pick end date.");
260
+ if (!ensureBase()) return;
261
+ configureBlazeoFromEffective(effective);
262
+ ensureBlazeoHttpReady({
263
+ baseUrl: effective.baseUrl,
264
+ ...(effective.consumer ? { consumer: effective.consumer } : {}),
265
+ });
266
+
267
+ const optsFromJson = safeJsonParse(searchFiltersJson, {});
268
+ const startDateFrom = new Date(`${searchFrom}T00:00:00.000Z`).toISOString();
269
+ const startDateTo = new Date(`${searchTo}T23:59:59.999Z`).toISOString();
270
+
271
+ setBusy(true);
272
+ try {
273
+ const res = await getAppointmentsByFilter(
274
+ companyKey,
275
+ startDateFrom,
276
+ startDateTo,
277
+ optsFromJson
278
+ );
279
+
280
+ setOutput(JSON.stringify(res, null, 2));
281
+ } catch (err) {
282
+ setError(mapBlazeoDemoError(err instanceof Error ? err.message : String(err)));
283
+ } finally {
284
+ setBusy(false);
285
+ }
286
+ }
287
+
288
+ return (
289
+ <>
290
+ <div className="card">
291
+ <h2>Appointment events</h2>
292
+ <p className="muted small">
293
+ Create/reschedule/cancel Blazeo events via <code>appointment-client</code>.
294
+ </p>
295
+ <label className="form__label">
296
+ <span>Offset minutes</span>
297
+ <input
298
+ type="number"
299
+ className="form__input"
300
+ value={offsetMinutes}
301
+ onChange={(e) => setOffsetMinutes(e.target.value)}
302
+ />
303
+ </label>
304
+ </div>
305
+
306
+ <div className="card">
307
+ <h2>Search events (date range + filters)</h2>
308
+ <p className="muted small">
309
+ Calls <code>EventModel.getByDateRangeWithFilters</code>
310
+ <code> GET /event/search/daterange/get</code> (company scope). Offset header comes from the{" "}
311
+ <code>offset</code> field above.
312
+ </p>
313
+ <form onSubmit={handleSearchByDateRange} className="form">
314
+ <label className="form__label">
315
+ <span>Company key</span>
316
+ <input
317
+ className="form__input"
318
+ value={searchCompanyKey}
319
+ onChange={(e) => setSearchCompanyKey(e.target.value)}
320
+ placeholder="company_key"
321
+ autoComplete="off"
322
+ />
323
+ </label>
324
+ <div className="connection-card__row">
325
+ <label className="form__label">
326
+ <span>Start date (from)</span>
327
+ <input
328
+ type="date"
329
+ className="form__input"
330
+ value={searchFrom}
331
+ onChange={(e) => setSearchFrom(e.target.value)}
332
+ />
333
+ </label>
334
+ <label className="form__label">
335
+ <span>Start date (to)</span>
336
+ <input
337
+ type="date"
338
+ className="form__input"
339
+ value={searchTo}
340
+ onChange={(e) => setSearchTo(e.target.value)}
341
+ />
342
+ </label>
343
+ </div>
344
+ <label className="form__label">
345
+ <span>Filters (JSON)</span>
346
+ <textarea
347
+ className="form__textarea"
348
+ value={searchFiltersJson}
349
+ onChange={(e) => setSearchFiltersJson(e.target.value)}
350
+ spellCheck={false}
351
+ rows={10}
352
+ />
353
+ </label>
354
+ <div className="connection-card__row">
355
+ <button type="button" className="btn btn--secondary" onClick={handleSearchByDateRange} disabled={busy}>
356
+ {busy ? "Loading…" : "Raw Search"}
357
+ </button>
358
+ <button type="button" className="btn btn--primary" onClick={handleEnrichedSearch} disabled={busy}>
359
+ {busy ? "Loading…" : "Enriched Search (New)"}
360
+ </button>
361
+ </div>
362
+ </form>
363
+ </div>
364
+
365
+ <div className="card">
366
+ <h2>Create event</h2>
367
+ <form onSubmit={handleCreate} className="form">
368
+ <label className="form__label">
369
+ <span>Payload (JSON)</span>
370
+ <textarea
371
+ className="form__textarea"
372
+ value={createJson}
373
+ onChange={(e) => setCreateJson(e.target.value)}
374
+ spellCheck={false}
375
+ rows={14}
376
+ />
377
+ </label>
378
+ <button type="submit" className="btn btn--primary" disabled={busy}>
379
+ {busy ? "Working…" : "Create"}
380
+ </button>
381
+ </form>
382
+ </div>
383
+
384
+ <div className="card">
385
+ <h2>Reschedule event</h2>
386
+ <form onSubmit={handleReschedule} className="form">
387
+ <label className="form__label">
388
+ <span>Payload (JSON)</span>
389
+ <textarea
390
+ className="form__textarea"
391
+ value={rescheduleJson}
392
+ onChange={(e) => setRescheduleJson(e.target.value)}
393
+ spellCheck={false}
394
+ rows={14}
395
+ />
396
+ </label>
397
+ <button type="submit" className="btn btn--primary" disabled={busy}>
398
+ {busy ? "Working…" : "Reschedule"}
399
+ </button>
400
+ </form>
401
+ </div>
402
+
403
+ <div className="card">
404
+ <h2>Cancel event</h2>
405
+ <form onSubmit={handleCancel} className="form">
406
+ <label className="form__label">
407
+ <span>Event id</span>
408
+ <input
409
+ className="form__input"
410
+ value={cancelEventId}
411
+ onChange={(e) => setCancelEventId(e.target.value)}
412
+ />
413
+ </label>
414
+ <button type="submit" className="btn btn--secondary" disabled={busy}>
415
+ {busy ? "Working…" : "Cancel"}
416
+ </button>
417
+ </form>
418
+ </div>
419
+
420
+ {error ? (
421
+ <div className="card card--error" role="alert">
422
+ <h2>Error</h2>
423
+ <pre className="pre-block">{error}</pre>
424
+ </div>
425
+ ) : null}
426
+
427
+ {output ? (
428
+ <div className="card card--success">
429
+ <h2>Result</h2>
430
+ <pre className="pre-block">{output}</pre>
431
+ </div>
432
+ ) : null}
433
+ </>
434
+ );
435
+ }