@blackcode_sa/metaestetics-api 1.4.18 → 1.5.0
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/dist/index.d.mts +7405 -4795
- package/dist/index.d.ts +7405 -4795
- package/dist/index.js +2736 -109
- package/dist/index.mjs +2772 -109
- package/package.json +4 -3
- package/src/index.ts +48 -1
- package/src/services/calendar/calendar-refactored.service.ts +1531 -0
- package/src/services/calendar/calendar.service.ts +1077 -0
- package/src/services/calendar/synced-calendars.service.ts +743 -0
- package/src/services/calendar/utils/appointment.utils.ts +314 -0
- package/src/services/calendar/utils/calendar-event.utils.ts +510 -0
- package/src/services/calendar/utils/clinic.utils.ts +237 -0
- package/src/services/calendar/utils/docs.utils.ts +157 -0
- package/src/services/calendar/utils/google-calendar.utils.ts +697 -0
- package/src/services/calendar/utils/index.ts +8 -0
- package/src/services/calendar/utils/patient.utils.ts +198 -0
- package/src/services/calendar/utils/practitioner.utils.ts +221 -0
- package/src/services/calendar/utils/synced-calendar.utils.ts +472 -0
- package/src/services/practitioner/practitioner.service.ts +1 -0
- package/src/types/calendar/index.ts +187 -0
- package/src/types/calendar/synced-calendar.types.ts +66 -0
- package/src/types/clinic/index.ts +1 -12
- package/src/types/index.ts +4 -0
- package/src/types/practitioner/index.ts +21 -0
- package/src/types/profile/index.ts +39 -0
- package/src/validations/calendar.schema.ts +223 -0
- package/src/validations/practitioner.schema.ts +21 -0
- package/src/validations/profile-info.schema.ts +41 -0
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Firestore,
|
|
3
|
+
collection,
|
|
4
|
+
doc,
|
|
5
|
+
getDoc,
|
|
6
|
+
getDocs,
|
|
7
|
+
setDoc,
|
|
8
|
+
updateDoc,
|
|
9
|
+
deleteDoc,
|
|
10
|
+
query,
|
|
11
|
+
where,
|
|
12
|
+
orderBy,
|
|
13
|
+
Timestamp,
|
|
14
|
+
serverTimestamp,
|
|
15
|
+
} from "firebase/firestore";
|
|
16
|
+
import {
|
|
17
|
+
SyncedCalendar,
|
|
18
|
+
SyncedCalendarProvider,
|
|
19
|
+
CreateSyncedCalendarData,
|
|
20
|
+
UpdateSyncedCalendarData,
|
|
21
|
+
SYNCED_CALENDARS_COLLECTION,
|
|
22
|
+
} from "../../../types/calendar/synced-calendar.types";
|
|
23
|
+
import {
|
|
24
|
+
getPractitionerSyncedCalendarDocRef,
|
|
25
|
+
getPatientSyncedCalendarDocRef,
|
|
26
|
+
getClinicSyncedCalendarDocRef,
|
|
27
|
+
} from "./docs.utils";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Creates a synced calendar for a practitioner
|
|
31
|
+
* @param db - Firestore instance
|
|
32
|
+
* @param practitionerId - ID of the practitioner
|
|
33
|
+
* @param calendarData - Synced calendar data
|
|
34
|
+
* @param generateId - Function to generate a unique ID
|
|
35
|
+
* @returns Created synced calendar
|
|
36
|
+
*/
|
|
37
|
+
export async function createPractitionerSyncedCalendarUtil(
|
|
38
|
+
db: Firestore,
|
|
39
|
+
practitionerId: string,
|
|
40
|
+
calendarData: Omit<
|
|
41
|
+
CreateSyncedCalendarData,
|
|
42
|
+
"id" | "createdAt" | "updatedAt"
|
|
43
|
+
>,
|
|
44
|
+
generateId: () => string
|
|
45
|
+
): Promise<SyncedCalendar> {
|
|
46
|
+
const calendarId = generateId();
|
|
47
|
+
const calendarRef = getPractitionerSyncedCalendarDocRef(
|
|
48
|
+
db,
|
|
49
|
+
practitionerId,
|
|
50
|
+
calendarId
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const newCalendar: CreateSyncedCalendarData = {
|
|
54
|
+
id: calendarId,
|
|
55
|
+
...calendarData,
|
|
56
|
+
createdAt: serverTimestamp(),
|
|
57
|
+
updatedAt: serverTimestamp(),
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
await setDoc(calendarRef, newCalendar);
|
|
61
|
+
|
|
62
|
+
// Convert server timestamp to Timestamp for return value
|
|
63
|
+
return {
|
|
64
|
+
...newCalendar,
|
|
65
|
+
createdAt: Timestamp.now(),
|
|
66
|
+
updatedAt: Timestamp.now(),
|
|
67
|
+
} as SyncedCalendar;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Creates a synced calendar for a patient
|
|
72
|
+
* @param db - Firestore instance
|
|
73
|
+
* @param patientId - ID of the patient
|
|
74
|
+
* @param calendarData - Synced calendar data
|
|
75
|
+
* @param generateId - Function to generate a unique ID
|
|
76
|
+
* @returns Created synced calendar
|
|
77
|
+
*/
|
|
78
|
+
export async function createPatientSyncedCalendarUtil(
|
|
79
|
+
db: Firestore,
|
|
80
|
+
patientId: string,
|
|
81
|
+
calendarData: Omit<
|
|
82
|
+
CreateSyncedCalendarData,
|
|
83
|
+
"id" | "createdAt" | "updatedAt"
|
|
84
|
+
>,
|
|
85
|
+
generateId: () => string
|
|
86
|
+
): Promise<SyncedCalendar> {
|
|
87
|
+
const calendarId = generateId();
|
|
88
|
+
const calendarRef = getPatientSyncedCalendarDocRef(db, patientId, calendarId);
|
|
89
|
+
|
|
90
|
+
const newCalendar: CreateSyncedCalendarData = {
|
|
91
|
+
id: calendarId,
|
|
92
|
+
...calendarData,
|
|
93
|
+
createdAt: serverTimestamp(),
|
|
94
|
+
updatedAt: serverTimestamp(),
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
await setDoc(calendarRef, newCalendar);
|
|
98
|
+
|
|
99
|
+
// Convert server timestamp to Timestamp for return value
|
|
100
|
+
return {
|
|
101
|
+
...newCalendar,
|
|
102
|
+
createdAt: Timestamp.now(),
|
|
103
|
+
updatedAt: Timestamp.now(),
|
|
104
|
+
} as SyncedCalendar;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Creates a synced calendar for a clinic
|
|
109
|
+
* @param db - Firestore instance
|
|
110
|
+
* @param clinicId - ID of the clinic
|
|
111
|
+
* @param calendarData - Synced calendar data
|
|
112
|
+
* @param generateId - Function to generate a unique ID
|
|
113
|
+
* @returns Created synced calendar
|
|
114
|
+
*/
|
|
115
|
+
export async function createClinicSyncedCalendarUtil(
|
|
116
|
+
db: Firestore,
|
|
117
|
+
clinicId: string,
|
|
118
|
+
calendarData: Omit<
|
|
119
|
+
CreateSyncedCalendarData,
|
|
120
|
+
"id" | "createdAt" | "updatedAt"
|
|
121
|
+
>,
|
|
122
|
+
generateId: () => string
|
|
123
|
+
): Promise<SyncedCalendar> {
|
|
124
|
+
const calendarId = generateId();
|
|
125
|
+
const calendarRef = getClinicSyncedCalendarDocRef(db, clinicId, calendarId);
|
|
126
|
+
|
|
127
|
+
const newCalendar: CreateSyncedCalendarData = {
|
|
128
|
+
id: calendarId,
|
|
129
|
+
...calendarData,
|
|
130
|
+
createdAt: serverTimestamp(),
|
|
131
|
+
updatedAt: serverTimestamp(),
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
await setDoc(calendarRef, newCalendar);
|
|
135
|
+
|
|
136
|
+
// Convert server timestamp to Timestamp for return value
|
|
137
|
+
return {
|
|
138
|
+
...newCalendar,
|
|
139
|
+
createdAt: Timestamp.now(),
|
|
140
|
+
updatedAt: Timestamp.now(),
|
|
141
|
+
} as SyncedCalendar;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Gets a synced calendar for a practitioner
|
|
146
|
+
* @param db - Firestore instance
|
|
147
|
+
* @param practitionerId - ID of the practitioner
|
|
148
|
+
* @param calendarId - ID of the synced calendar
|
|
149
|
+
* @returns Synced calendar or null if not found
|
|
150
|
+
*/
|
|
151
|
+
export async function getPractitionerSyncedCalendarUtil(
|
|
152
|
+
db: Firestore,
|
|
153
|
+
practitionerId: string,
|
|
154
|
+
calendarId: string
|
|
155
|
+
): Promise<SyncedCalendar | null> {
|
|
156
|
+
const calendarRef = getPractitionerSyncedCalendarDocRef(
|
|
157
|
+
db,
|
|
158
|
+
practitionerId,
|
|
159
|
+
calendarId
|
|
160
|
+
);
|
|
161
|
+
const calendarDoc = await getDoc(calendarRef);
|
|
162
|
+
|
|
163
|
+
if (!calendarDoc.exists()) {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return calendarDoc.data() as SyncedCalendar;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Gets all synced calendars for a practitioner
|
|
172
|
+
* @param db - Firestore instance
|
|
173
|
+
* @param practitionerId - ID of the practitioner
|
|
174
|
+
* @returns Array of synced calendars
|
|
175
|
+
*/
|
|
176
|
+
export async function getPractitionerSyncedCalendarsUtil(
|
|
177
|
+
db: Firestore,
|
|
178
|
+
practitionerId: string
|
|
179
|
+
): Promise<SyncedCalendar[]> {
|
|
180
|
+
const calendarsRef = collection(
|
|
181
|
+
db,
|
|
182
|
+
`practitioners/${practitionerId}/${SYNCED_CALENDARS_COLLECTION}`
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
const q = query(calendarsRef, orderBy("createdAt", "desc"));
|
|
186
|
+
const querySnapshot = await getDocs(q);
|
|
187
|
+
|
|
188
|
+
return querySnapshot.docs.map((doc) => doc.data() as SyncedCalendar);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Gets a synced calendar for a patient
|
|
193
|
+
* @param db - Firestore instance
|
|
194
|
+
* @param patientId - ID of the patient
|
|
195
|
+
* @param calendarId - ID of the synced calendar
|
|
196
|
+
* @returns Synced calendar or null if not found
|
|
197
|
+
*/
|
|
198
|
+
export async function getPatientSyncedCalendarUtil(
|
|
199
|
+
db: Firestore,
|
|
200
|
+
patientId: string,
|
|
201
|
+
calendarId: string
|
|
202
|
+
): Promise<SyncedCalendar | null> {
|
|
203
|
+
const calendarRef = getPatientSyncedCalendarDocRef(db, patientId, calendarId);
|
|
204
|
+
const calendarDoc = await getDoc(calendarRef);
|
|
205
|
+
|
|
206
|
+
if (!calendarDoc.exists()) {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return calendarDoc.data() as SyncedCalendar;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Gets all synced calendars for a patient
|
|
215
|
+
* @param db - Firestore instance
|
|
216
|
+
* @param patientId - ID of the patient
|
|
217
|
+
* @returns Array of synced calendars
|
|
218
|
+
*/
|
|
219
|
+
export async function getPatientSyncedCalendarsUtil(
|
|
220
|
+
db: Firestore,
|
|
221
|
+
patientId: string
|
|
222
|
+
): Promise<SyncedCalendar[]> {
|
|
223
|
+
const calendarsRef = collection(
|
|
224
|
+
db,
|
|
225
|
+
`patients/${patientId}/${SYNCED_CALENDARS_COLLECTION}`
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
const q = query(calendarsRef, orderBy("createdAt", "desc"));
|
|
229
|
+
const querySnapshot = await getDocs(q);
|
|
230
|
+
|
|
231
|
+
return querySnapshot.docs.map((doc) => doc.data() as SyncedCalendar);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Gets a synced calendar for a clinic
|
|
236
|
+
* @param db - Firestore instance
|
|
237
|
+
* @param clinicId - ID of the clinic
|
|
238
|
+
* @param calendarId - ID of the synced calendar
|
|
239
|
+
* @returns Synced calendar or null if not found
|
|
240
|
+
*/
|
|
241
|
+
export async function getClinicSyncedCalendarUtil(
|
|
242
|
+
db: Firestore,
|
|
243
|
+
clinicId: string,
|
|
244
|
+
calendarId: string
|
|
245
|
+
): Promise<SyncedCalendar | null> {
|
|
246
|
+
const calendarRef = getClinicSyncedCalendarDocRef(db, clinicId, calendarId);
|
|
247
|
+
const calendarDoc = await getDoc(calendarRef);
|
|
248
|
+
|
|
249
|
+
if (!calendarDoc.exists()) {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return calendarDoc.data() as SyncedCalendar;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Gets all synced calendars for a clinic
|
|
258
|
+
* @param db - Firestore instance
|
|
259
|
+
* @param clinicId - ID of the clinic
|
|
260
|
+
* @returns Array of synced calendars
|
|
261
|
+
*/
|
|
262
|
+
export async function getClinicSyncedCalendarsUtil(
|
|
263
|
+
db: Firestore,
|
|
264
|
+
clinicId: string
|
|
265
|
+
): Promise<SyncedCalendar[]> {
|
|
266
|
+
const calendarsRef = collection(
|
|
267
|
+
db,
|
|
268
|
+
`clinics/${clinicId}/${SYNCED_CALENDARS_COLLECTION}`
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
const q = query(calendarsRef, orderBy("createdAt", "desc"));
|
|
272
|
+
const querySnapshot = await getDocs(q);
|
|
273
|
+
|
|
274
|
+
return querySnapshot.docs.map((doc) => doc.data() as SyncedCalendar);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Updates a synced calendar for a practitioner
|
|
279
|
+
* @param db - Firestore instance
|
|
280
|
+
* @param practitionerId - ID of the practitioner
|
|
281
|
+
* @param calendarId - ID of the synced calendar
|
|
282
|
+
* @param updateData - Data to update
|
|
283
|
+
* @returns Updated synced calendar
|
|
284
|
+
*/
|
|
285
|
+
export async function updatePractitionerSyncedCalendarUtil(
|
|
286
|
+
db: Firestore,
|
|
287
|
+
practitionerId: string,
|
|
288
|
+
calendarId: string,
|
|
289
|
+
updateData: Omit<UpdateSyncedCalendarData, "updatedAt">
|
|
290
|
+
): Promise<SyncedCalendar> {
|
|
291
|
+
const calendarRef = getPractitionerSyncedCalendarDocRef(
|
|
292
|
+
db,
|
|
293
|
+
practitionerId,
|
|
294
|
+
calendarId
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
const updates: UpdateSyncedCalendarData = {
|
|
298
|
+
...updateData,
|
|
299
|
+
updatedAt: serverTimestamp(),
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
await updateDoc(calendarRef, updates as any);
|
|
303
|
+
|
|
304
|
+
// Get the updated document
|
|
305
|
+
const updatedDoc = await getDoc(calendarRef);
|
|
306
|
+
|
|
307
|
+
if (!updatedDoc.exists()) {
|
|
308
|
+
throw new Error("Synced calendar not found after update");
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return updatedDoc.data() as SyncedCalendar;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Updates a synced calendar for a patient
|
|
316
|
+
* @param db - Firestore instance
|
|
317
|
+
* @param patientId - ID of the patient
|
|
318
|
+
* @param calendarId - ID of the synced calendar
|
|
319
|
+
* @param updateData - Data to update
|
|
320
|
+
* @returns Updated synced calendar
|
|
321
|
+
*/
|
|
322
|
+
export async function updatePatientSyncedCalendarUtil(
|
|
323
|
+
db: Firestore,
|
|
324
|
+
patientId: string,
|
|
325
|
+
calendarId: string,
|
|
326
|
+
updateData: Omit<UpdateSyncedCalendarData, "updatedAt">
|
|
327
|
+
): Promise<SyncedCalendar> {
|
|
328
|
+
const calendarRef = getPatientSyncedCalendarDocRef(db, patientId, calendarId);
|
|
329
|
+
|
|
330
|
+
const updates: UpdateSyncedCalendarData = {
|
|
331
|
+
...updateData,
|
|
332
|
+
updatedAt: serverTimestamp(),
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
await updateDoc(calendarRef, updates as any);
|
|
336
|
+
|
|
337
|
+
// Get the updated document
|
|
338
|
+
const updatedDoc = await getDoc(calendarRef);
|
|
339
|
+
|
|
340
|
+
if (!updatedDoc.exists()) {
|
|
341
|
+
throw new Error("Synced calendar not found after update");
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return updatedDoc.data() as SyncedCalendar;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Updates a synced calendar for a clinic
|
|
349
|
+
* @param db - Firestore instance
|
|
350
|
+
* @param clinicId - ID of the clinic
|
|
351
|
+
* @param calendarId - ID of the synced calendar
|
|
352
|
+
* @param updateData - Data to update
|
|
353
|
+
* @returns Updated synced calendar
|
|
354
|
+
*/
|
|
355
|
+
export async function updateClinicSyncedCalendarUtil(
|
|
356
|
+
db: Firestore,
|
|
357
|
+
clinicId: string,
|
|
358
|
+
calendarId: string,
|
|
359
|
+
updateData: Omit<UpdateSyncedCalendarData, "updatedAt">
|
|
360
|
+
): Promise<SyncedCalendar> {
|
|
361
|
+
const calendarRef = getClinicSyncedCalendarDocRef(db, clinicId, calendarId);
|
|
362
|
+
|
|
363
|
+
const updates: UpdateSyncedCalendarData = {
|
|
364
|
+
...updateData,
|
|
365
|
+
updatedAt: serverTimestamp(),
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
await updateDoc(calendarRef, updates as any);
|
|
369
|
+
|
|
370
|
+
// Get the updated document
|
|
371
|
+
const updatedDoc = await getDoc(calendarRef);
|
|
372
|
+
|
|
373
|
+
if (!updatedDoc.exists()) {
|
|
374
|
+
throw new Error("Synced calendar not found after update");
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return updatedDoc.data() as SyncedCalendar;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Deletes a synced calendar for a practitioner
|
|
382
|
+
* @param db - Firestore instance
|
|
383
|
+
* @param practitionerId - ID of the practitioner
|
|
384
|
+
* @param calendarId - ID of the synced calendar
|
|
385
|
+
*/
|
|
386
|
+
export async function deletePractitionerSyncedCalendarUtil(
|
|
387
|
+
db: Firestore,
|
|
388
|
+
practitionerId: string,
|
|
389
|
+
calendarId: string
|
|
390
|
+
): Promise<void> {
|
|
391
|
+
const calendarRef = getPractitionerSyncedCalendarDocRef(
|
|
392
|
+
db,
|
|
393
|
+
practitionerId,
|
|
394
|
+
calendarId
|
|
395
|
+
);
|
|
396
|
+
await deleteDoc(calendarRef);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Deletes a synced calendar for a patient
|
|
401
|
+
* @param db - Firestore instance
|
|
402
|
+
* @param patientId - ID of the patient
|
|
403
|
+
* @param calendarId - ID of the synced calendar
|
|
404
|
+
*/
|
|
405
|
+
export async function deletePatientSyncedCalendarUtil(
|
|
406
|
+
db: Firestore,
|
|
407
|
+
patientId: string,
|
|
408
|
+
calendarId: string
|
|
409
|
+
): Promise<void> {
|
|
410
|
+
const calendarRef = getPatientSyncedCalendarDocRef(db, patientId, calendarId);
|
|
411
|
+
await deleteDoc(calendarRef);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Deletes a synced calendar for a clinic
|
|
416
|
+
* @param db - Firestore instance
|
|
417
|
+
* @param clinicId - ID of the clinic
|
|
418
|
+
* @param calendarId - ID of the synced calendar
|
|
419
|
+
*/
|
|
420
|
+
export async function deleteClinicSyncedCalendarUtil(
|
|
421
|
+
db: Firestore,
|
|
422
|
+
clinicId: string,
|
|
423
|
+
calendarId: string
|
|
424
|
+
): Promise<void> {
|
|
425
|
+
const calendarRef = getClinicSyncedCalendarDocRef(db, clinicId, calendarId);
|
|
426
|
+
await deleteDoc(calendarRef);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Updates the last synced timestamp for a synced calendar
|
|
431
|
+
* @param db - Firestore instance
|
|
432
|
+
* @param entityType - Type of entity (practitioner, patient, clinic)
|
|
433
|
+
* @param entityId - ID of the entity
|
|
434
|
+
* @param calendarId - ID of the synced calendar
|
|
435
|
+
* @returns Updated synced calendar
|
|
436
|
+
*/
|
|
437
|
+
export async function updateLastSyncedTimestampUtil(
|
|
438
|
+
db: Firestore,
|
|
439
|
+
entityType: "practitioner" | "patient" | "clinic",
|
|
440
|
+
entityId: string,
|
|
441
|
+
calendarId: string
|
|
442
|
+
): Promise<SyncedCalendar> {
|
|
443
|
+
const updateData: Omit<UpdateSyncedCalendarData, "updatedAt"> = {
|
|
444
|
+
lastSyncedAt: Timestamp.now(),
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
switch (entityType) {
|
|
448
|
+
case "practitioner":
|
|
449
|
+
return updatePractitionerSyncedCalendarUtil(
|
|
450
|
+
db,
|
|
451
|
+
entityId,
|
|
452
|
+
calendarId,
|
|
453
|
+
updateData
|
|
454
|
+
);
|
|
455
|
+
case "patient":
|
|
456
|
+
return updatePatientSyncedCalendarUtil(
|
|
457
|
+
db,
|
|
458
|
+
entityId,
|
|
459
|
+
calendarId,
|
|
460
|
+
updateData
|
|
461
|
+
);
|
|
462
|
+
case "clinic":
|
|
463
|
+
return updateClinicSyncedCalendarUtil(
|
|
464
|
+
db,
|
|
465
|
+
entityId,
|
|
466
|
+
calendarId,
|
|
467
|
+
updateData
|
|
468
|
+
);
|
|
469
|
+
default:
|
|
470
|
+
throw new Error(`Invalid entity type: ${entityType}`);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
@@ -92,6 +92,7 @@ export class PractitionerService extends BaseService {
|
|
|
92
92
|
basicInfo: validatedData.basicInfo,
|
|
93
93
|
certification: validatedData.certification,
|
|
94
94
|
clinics: validatedData.clinics || [],
|
|
95
|
+
clinicWorkingHours: validatedData.clinicWorkingHours || [],
|
|
95
96
|
isActive: validatedData.isActive,
|
|
96
97
|
isVerified: validatedData.isVerified,
|
|
97
98
|
createdAt: serverTimestamp(),
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { Timestamp, FieldValue } from "firebase/firestore";
|
|
2
|
+
import type { ClinicLocation } from "../clinic";
|
|
3
|
+
import type {
|
|
4
|
+
Category,
|
|
5
|
+
ProcedureFamily,
|
|
6
|
+
Product,
|
|
7
|
+
Subcategory,
|
|
8
|
+
Technology,
|
|
9
|
+
} from "../../backoffice";
|
|
10
|
+
import type { SyncedCalendarProvider } from "./synced-calendar.types";
|
|
11
|
+
import type { Gender } from "../patient";
|
|
12
|
+
import type { PractitionerCertification } from "../practitioner";
|
|
13
|
+
import type { Currency } from "../../backoffice/types/static/pricing.types";
|
|
14
|
+
import type {
|
|
15
|
+
ClinicInfo,
|
|
16
|
+
PractitionerProfileInfo,
|
|
17
|
+
PatientProfileInfo,
|
|
18
|
+
} from "../profile";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Enum for calendar event status
|
|
22
|
+
*/
|
|
23
|
+
export enum CalendarEventStatus {
|
|
24
|
+
PENDING = "pending", // When event is created, but not confirmed
|
|
25
|
+
CONFIRMED = "confirmed", // When event is confirmed and ready to be used
|
|
26
|
+
REJECTED = "rejected", // When event is rejected by the clinic administrator or patient
|
|
27
|
+
CANCELED = "canceled", // When event is canceled by the patient
|
|
28
|
+
RESCHEDULED = "rescheduled", // When event is rescheduled by the clinic administrator
|
|
29
|
+
COMPLETED = "completed", // When event is completed
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Enum for calendar event sync status
|
|
34
|
+
*/
|
|
35
|
+
export enum CalendarSyncStatus {
|
|
36
|
+
INTERNAL = "internal",
|
|
37
|
+
EXTERNAL = "external",
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Enum for calendar event types
|
|
42
|
+
*/
|
|
43
|
+
export enum CalendarEventType {
|
|
44
|
+
APPOINTMENT = "appointment",
|
|
45
|
+
BLOCKING = "blocking",
|
|
46
|
+
BREAK = "break",
|
|
47
|
+
FREE_DAY = "free_day",
|
|
48
|
+
OTHER = "other",
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Interface for calendar event time
|
|
53
|
+
*/
|
|
54
|
+
export interface CalendarEventTime {
|
|
55
|
+
start: Timestamp;
|
|
56
|
+
end: Timestamp;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface ProcedureInfo {
|
|
60
|
+
// TO-DO: Create detailed procedure info when procedures are integrated
|
|
61
|
+
name: string;
|
|
62
|
+
description: string;
|
|
63
|
+
duration: number;
|
|
64
|
+
price: number;
|
|
65
|
+
currency: Currency;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface ProcedureCategorization {
|
|
69
|
+
procedureFamily: ProcedureFamily;
|
|
70
|
+
procedureCategory: Category;
|
|
71
|
+
procedureSubcategory: Subcategory;
|
|
72
|
+
procedureTechnology: Technology;
|
|
73
|
+
procedureProduct: Product;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface SyncedCalendarEvent {
|
|
77
|
+
eventId: string;
|
|
78
|
+
syncedCalendarProvider: SyncedCalendarProvider;
|
|
79
|
+
syncedAt: Timestamp; // Timestamp when the event was last synced with the external calendar
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Interface for calendar event
|
|
84
|
+
*/
|
|
85
|
+
export interface CalendarEvent {
|
|
86
|
+
id: string;
|
|
87
|
+
clinicBranchId?: string | null;
|
|
88
|
+
clinicBranchInfo?: ClinicInfo | null;
|
|
89
|
+
practitionerProfileId?: string | null;
|
|
90
|
+
practitionerProfileInfo?: PractitionerProfileInfo | null;
|
|
91
|
+
patientProfileId?: string | null;
|
|
92
|
+
patientProfileInfo?: PatientProfileInfo | null;
|
|
93
|
+
procedureId?: string | null;
|
|
94
|
+
procedureInfo?: ProcedureInfo | null;
|
|
95
|
+
procedureCategorization?: ProcedureCategorization | null;
|
|
96
|
+
appointmentId?: string | null; // Created when calendar event is confirmed and it's type is APPOINTMENT
|
|
97
|
+
syncedCalendarEventId?: SyncedCalendarEvent[] | null;
|
|
98
|
+
eventName: string;
|
|
99
|
+
eventLocation?: ClinicLocation;
|
|
100
|
+
eventTime: CalendarEventTime;
|
|
101
|
+
description?: string;
|
|
102
|
+
status: CalendarEventStatus;
|
|
103
|
+
syncStatus: CalendarSyncStatus;
|
|
104
|
+
eventType: CalendarEventType;
|
|
105
|
+
createdAt: Timestamp;
|
|
106
|
+
updatedAt: Timestamp;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Interface for creating a calendar event
|
|
111
|
+
*/
|
|
112
|
+
export interface CreateCalendarEventData {
|
|
113
|
+
id: string;
|
|
114
|
+
clinicBranchId?: string | null;
|
|
115
|
+
clinicBranchInfo?: ClinicInfo | null;
|
|
116
|
+
practitionerProfileId?: string | null;
|
|
117
|
+
practitionerProfileInfo?: PractitionerProfileInfo | null;
|
|
118
|
+
patientProfileId?: string | null;
|
|
119
|
+
patientProfileInfo?: PatientProfileInfo | null;
|
|
120
|
+
procedureId?: string | null;
|
|
121
|
+
appointmentId?: string | null; // Not needed if event type is not APPOINTMENT, or if there is no automatic appointment confirmation
|
|
122
|
+
syncedCalendarEventId?: SyncedCalendarEvent[] | null;
|
|
123
|
+
eventName: string;
|
|
124
|
+
eventLocation?: ClinicLocation;
|
|
125
|
+
eventTime: CalendarEventTime;
|
|
126
|
+
description?: string;
|
|
127
|
+
status: CalendarEventStatus;
|
|
128
|
+
syncStatus: CalendarSyncStatus;
|
|
129
|
+
eventType: CalendarEventType;
|
|
130
|
+
createdAt: FieldValue;
|
|
131
|
+
updatedAt: FieldValue;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Interface for updating a calendar event
|
|
136
|
+
*/
|
|
137
|
+
export interface UpdateCalendarEventData {
|
|
138
|
+
syncedCalendarEventId?: SyncedCalendarEvent[] | null;
|
|
139
|
+
appointmentId?: string | null; // Updated when calendar event is confirmed and it's type is APPOINTMENT, plus Appointment is created
|
|
140
|
+
eventName?: string;
|
|
141
|
+
eventTime?: CalendarEventTime;
|
|
142
|
+
description?: string;
|
|
143
|
+
status?: CalendarEventStatus;
|
|
144
|
+
syncStatus?: CalendarSyncStatus;
|
|
145
|
+
eventType?: CalendarEventType;
|
|
146
|
+
updatedAt: FieldValue;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Interface for available time slot
|
|
151
|
+
*/
|
|
152
|
+
export interface TimeSlot {
|
|
153
|
+
start: Date;
|
|
154
|
+
end: Date;
|
|
155
|
+
isAvailable: boolean;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Interface for appointment creation parameters
|
|
160
|
+
*/
|
|
161
|
+
export interface CreateAppointmentParams {
|
|
162
|
+
clinicId: string;
|
|
163
|
+
doctorId: string;
|
|
164
|
+
patientId: string;
|
|
165
|
+
procedureId: string;
|
|
166
|
+
eventLocation: ClinicLocation;
|
|
167
|
+
eventTime: CalendarEventTime;
|
|
168
|
+
description?: string;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Interface for appointment update parameters
|
|
173
|
+
*/
|
|
174
|
+
export interface UpdateAppointmentParams {
|
|
175
|
+
appointmentId: string;
|
|
176
|
+
clinicId: string;
|
|
177
|
+
doctorId: string;
|
|
178
|
+
patientId: string;
|
|
179
|
+
eventTime?: CalendarEventTime;
|
|
180
|
+
description?: string;
|
|
181
|
+
status?: CalendarEventStatus;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Collection names for calendar
|
|
186
|
+
*/
|
|
187
|
+
export const CALENDAR_COLLECTION = "calendar";
|