@blazeo.com/appointment-client 1.0.3 → 1.0.4

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.
@@ -0,0 +1,244 @@
1
+ import { useMemo, useState } from "react";
2
+ import {
3
+ cancelAppointmentEventAsync,
4
+ createAppointmentEventAsync,
5
+ rescheduleAppointmentEventAsync,
6
+ } from "appointment-client";
7
+ import { getSnapshot, isStateTreeNode } from "mobx-state-tree";
8
+ import {
9
+ configureBlazeoFromEffective,
10
+ useBlazeoConnection,
11
+ } from "./BlazeoConnectionSettings.jsx";
12
+
13
+ function getExampleCreatePayload() {
14
+ const start = new Date();
15
+ start.setHours(10, 0, 0, 0);
16
+ const end = new Date(start);
17
+ end.setHours(10, 30, 0, 0);
18
+ return {
19
+ thirdPartyCalendarId: "your-calendar-id",
20
+ participantId: "00000000-0000-0000-0000-000000000000",
21
+ title: "Sample appointment",
22
+ description: "Created via appointment-client sample",
23
+ startDate: start.toISOString(),
24
+ endDate: end.toISOString(),
25
+ email: "visitor@example.com",
26
+ visitorName: "Visitor",
27
+ timeZone: "Pakistan Standard Time",
28
+ rescheduleUrl: "https://example.com/reschedule",
29
+ cancelUrl: "https://example.com/cancel",
30
+ };
31
+ }
32
+
33
+ function getExampleReschedulePayload() {
34
+ const start = new Date();
35
+ start.setDate(start.getDate() + 1);
36
+ start.setHours(14, 0, 0, 0);
37
+ const end = new Date(start);
38
+ end.setHours(14, 45, 0, 0);
39
+ return {
40
+ thirdPartyAppointmentId: "existing-blazeo-event-id",
41
+ thirdPartyCalendarId: "your-calendar-id",
42
+ participantId: "00000000-0000-0000-0000-000000000000",
43
+ title: "Rescheduled title",
44
+ notes: "Reschedule body",
45
+ startDate: start.toISOString(),
46
+ endDate: end.toISOString(),
47
+ email: "visitor@example.com",
48
+ timeZone: "Pakistan Standard Time",
49
+ };
50
+ }
51
+
52
+ function resultToJson(result) {
53
+ if (!result) return "";
54
+ if (result.ok && result.event && isStateTreeNode(result.event)) {
55
+ return JSON.stringify(
56
+ {
57
+ ok: true,
58
+ eventSnapshot: getSnapshot(result.event),
59
+ apiResponse: result.apiResponse ?? null,
60
+ },
61
+ null,
62
+ 2
63
+ );
64
+ }
65
+ return JSON.stringify(result, null, 2);
66
+ }
67
+
68
+ export function EventTab() {
69
+ const { effective } = useBlazeoConnection();
70
+ const [offsetMinutes, setOffsetMinutes] = useState(-new Date().getTimezoneOffset());
71
+ const [createJson, setCreateJson] = useState(() =>
72
+ JSON.stringify(getExampleCreatePayload(), null, 2)
73
+ );
74
+ const [rescheduleJson, setRescheduleJson] = useState(() =>
75
+ JSON.stringify(getExampleReschedulePayload(), null, 2)
76
+ );
77
+ const [cancelEventId, setCancelEventId] = useState("");
78
+ const [busy, setBusy] = useState(false);
79
+ const [error, setError] = useState("");
80
+ const [output, setOutput] = useState("");
81
+
82
+ const opts = useMemo(() => ({ offsetMinutes: Number(offsetMinutes) || 0 }), [offsetMinutes]);
83
+
84
+ function ensureBase() {
85
+ if (!effective.baseUrl) {
86
+ setError("Set Base URL in the connection card above.");
87
+ return false;
88
+ }
89
+ return true;
90
+ }
91
+
92
+ async function handleCreate(e) {
93
+ e.preventDefault();
94
+ setError("");
95
+ setOutput("");
96
+ if (!ensureBase()) return;
97
+ configureBlazeoFromEffective(effective);
98
+ let payload;
99
+ try {
100
+ payload = JSON.parse(createJson);
101
+ } catch (err) {
102
+ setError(`Create JSON: ${err instanceof Error ? err.message : String(err)}`);
103
+ return;
104
+ }
105
+ setBusy(true);
106
+ try {
107
+ const result = await createAppointmentEventAsync(payload, opts);
108
+ setOutput(resultToJson(result));
109
+ if (!result.ok) setError(result.error);
110
+ } finally {
111
+ setBusy(false);
112
+ }
113
+ }
114
+
115
+ async function handleReschedule(e) {
116
+ e.preventDefault();
117
+ setError("");
118
+ setOutput("");
119
+ if (!ensureBase()) return;
120
+ configureBlazeoFromEffective(effective);
121
+ let payload;
122
+ try {
123
+ payload = JSON.parse(rescheduleJson);
124
+ } catch (err) {
125
+ setError(`Reschedule JSON: ${err instanceof Error ? err.message : String(err)}`);
126
+ return;
127
+ }
128
+ setBusy(true);
129
+ try {
130
+ const result = await rescheduleAppointmentEventAsync(payload, opts);
131
+ setOutput(resultToJson(result));
132
+ if (!result.ok) setError(result.error);
133
+ } finally {
134
+ setBusy(false);
135
+ }
136
+ }
137
+
138
+ async function handleCancel(e) {
139
+ e.preventDefault();
140
+ setError("");
141
+ setOutput("");
142
+ const id = cancelEventId.trim();
143
+ if (!id) return setError("Enter Blazeo event id to cancel.");
144
+ if (!ensureBase()) return;
145
+ configureBlazeoFromEffective(effective);
146
+ setBusy(true);
147
+ try {
148
+ const result = await cancelAppointmentEventAsync(id, {});
149
+ setOutput(JSON.stringify(result, null, 2));
150
+ if (!result.ok) setError(result.error);
151
+ } finally {
152
+ setBusy(false);
153
+ }
154
+ }
155
+
156
+ return (
157
+ <>
158
+ <div className="card">
159
+ <h2>Appointment events</h2>
160
+ <p className="muted small">
161
+ Create/reschedule/cancel Blazeo events via <code>appointment-client</code>.
162
+ </p>
163
+ <label className="form__label">
164
+ <span>Offset minutes</span>
165
+ <input
166
+ type="number"
167
+ className="form__input"
168
+ value={offsetMinutes}
169
+ onChange={(e) => setOffsetMinutes(e.target.value)}
170
+ />
171
+ </label>
172
+ </div>
173
+
174
+ <div className="card">
175
+ <h2>Create event</h2>
176
+ <form onSubmit={handleCreate} className="form">
177
+ <label className="form__label">
178
+ <span>Payload (JSON)</span>
179
+ <textarea
180
+ className="form__textarea"
181
+ value={createJson}
182
+ onChange={(e) => setCreateJson(e.target.value)}
183
+ spellCheck={false}
184
+ rows={14}
185
+ />
186
+ </label>
187
+ <button type="submit" className="btn btn--primary" disabled={busy}>
188
+ {busy ? "Working…" : "Create"}
189
+ </button>
190
+ </form>
191
+ </div>
192
+
193
+ <div className="card">
194
+ <h2>Reschedule event</h2>
195
+ <form onSubmit={handleReschedule} className="form">
196
+ <label className="form__label">
197
+ <span>Payload (JSON)</span>
198
+ <textarea
199
+ className="form__textarea"
200
+ value={rescheduleJson}
201
+ onChange={(e) => setRescheduleJson(e.target.value)}
202
+ spellCheck={false}
203
+ rows={14}
204
+ />
205
+ </label>
206
+ <button type="submit" className="btn btn--primary" disabled={busy}>
207
+ {busy ? "Working…" : "Reschedule"}
208
+ </button>
209
+ </form>
210
+ </div>
211
+
212
+ <div className="card">
213
+ <h2>Cancel event</h2>
214
+ <form onSubmit={handleCancel} className="form">
215
+ <label className="form__label">
216
+ <span>Event id</span>
217
+ <input
218
+ className="form__input"
219
+ value={cancelEventId}
220
+ onChange={(e) => setCancelEventId(e.target.value)}
221
+ />
222
+ </label>
223
+ <button type="submit" className="btn btn--secondary" disabled={busy}>
224
+ {busy ? "Working…" : "Cancel"}
225
+ </button>
226
+ </form>
227
+ </div>
228
+
229
+ {error ? (
230
+ <div className="card card--error" role="alert">
231
+ <h2>Error</h2>
232
+ <pre className="pre-block">{error}</pre>
233
+ </div>
234
+ ) : null}
235
+
236
+ {output ? (
237
+ <div className="card card--success">
238
+ <h2>Result</h2>
239
+ <pre className="pre-block">{output}</pre>
240
+ </div>
241
+ ) : null}
242
+ </>
243
+ );
244
+ }