@blackcode_sa/metaestetics-api 1.5.34 → 1.5.36
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 +1829 -1514
- package/dist/index.d.ts +1829 -1514
- package/dist/index.js +2049 -1118
- package/dist/index.mjs +2065 -1123
- package/package.json +1 -1
- package/src/index.ts +26 -0
- package/src/services/appointment/appointment.service.ts +98 -0
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,106 @@
|
|
|
1
|
+
// src/validations/appointment.schema.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
// src/types/appointment/index.ts
|
|
5
|
+
var AppointmentStatus = /* @__PURE__ */ ((AppointmentStatus2) => {
|
|
6
|
+
AppointmentStatus2["SCHEDULED"] = "scheduled";
|
|
7
|
+
AppointmentStatus2["CONFIRMED"] = "confirmed";
|
|
8
|
+
AppointmentStatus2["CHECKED_IN"] = "checked_in";
|
|
9
|
+
AppointmentStatus2["IN_PROGRESS"] = "in_progress";
|
|
10
|
+
AppointmentStatus2["COMPLETED"] = "completed";
|
|
11
|
+
AppointmentStatus2["CANCELED_PATIENT"] = "canceled_patient";
|
|
12
|
+
AppointmentStatus2["CANCELED_CLINIC"] = "canceled_clinic";
|
|
13
|
+
AppointmentStatus2["NO_SHOW"] = "no_show";
|
|
14
|
+
AppointmentStatus2["RESCHEDULED"] = "rescheduled";
|
|
15
|
+
return AppointmentStatus2;
|
|
16
|
+
})(AppointmentStatus || {});
|
|
17
|
+
var PaymentStatus = /* @__PURE__ */ ((PaymentStatus3) => {
|
|
18
|
+
PaymentStatus3["UNPAID"] = "unpaid";
|
|
19
|
+
PaymentStatus3["PAID"] = "paid";
|
|
20
|
+
PaymentStatus3["PARTIALLY_PAID"] = "partially_paid";
|
|
21
|
+
PaymentStatus3["REFUNDED"] = "refunded";
|
|
22
|
+
PaymentStatus3["NOT_APPLICABLE"] = "not_applicable";
|
|
23
|
+
return PaymentStatus3;
|
|
24
|
+
})(PaymentStatus || {});
|
|
25
|
+
var APPOINTMENTS_COLLECTION = "appointments";
|
|
26
|
+
|
|
27
|
+
// src/validations/appointment.schema.ts
|
|
28
|
+
var createAppointmentSchema = z.object({
|
|
29
|
+
calendarEventId: z.string().min(1, "Calendar event ID is required"),
|
|
30
|
+
clinicBranchId: z.string().min(1, "Clinic branch ID is required"),
|
|
31
|
+
practitionerId: z.string().min(1, "Practitioner ID is required"),
|
|
32
|
+
patientId: z.string().min(1, "Patient ID is required"),
|
|
33
|
+
procedureId: z.string().min(1, "Procedure ID is required"),
|
|
34
|
+
appointmentStartTime: z.any().refine(
|
|
35
|
+
(val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0,
|
|
36
|
+
"Appointment start time must be a valid timestamp"
|
|
37
|
+
),
|
|
38
|
+
appointmentEndTime: z.any().refine(
|
|
39
|
+
(val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0,
|
|
40
|
+
"Appointment end time must be a valid timestamp"
|
|
41
|
+
),
|
|
42
|
+
cost: z.number().min(0, "Cost must be a non-negative number"),
|
|
43
|
+
currency: z.string().min(1, "Currency is required"),
|
|
44
|
+
patientNotes: z.string().nullable().optional(),
|
|
45
|
+
initialStatus: z.nativeEnum(AppointmentStatus, {
|
|
46
|
+
errorMap: () => ({ message: "Invalid appointment status" })
|
|
47
|
+
}),
|
|
48
|
+
initialPaymentStatus: z.nativeEnum(PaymentStatus, {
|
|
49
|
+
errorMap: () => ({ message: "Invalid payment status" })
|
|
50
|
+
}).optional().default("unpaid" /* UNPAID */)
|
|
51
|
+
});
|
|
52
|
+
var updateAppointmentSchema = z.object({
|
|
53
|
+
status: z.nativeEnum(AppointmentStatus, {
|
|
54
|
+
errorMap: () => ({ message: "Invalid appointment status" })
|
|
55
|
+
}).optional(),
|
|
56
|
+
confirmationTime: z.any().refine(
|
|
57
|
+
(val) => val === null || val === void 0 || val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0,
|
|
58
|
+
"Confirmation time must be a valid timestamp or null"
|
|
59
|
+
).optional(),
|
|
60
|
+
actualDurationMinutes: z.number().positive("Duration must be positive").optional(),
|
|
61
|
+
cancellationReason: z.string().nullable().optional(),
|
|
62
|
+
canceledBy: z.enum(["patient", "clinic", "practitioner", "system"]).optional(),
|
|
63
|
+
internalNotes: z.string().nullable().optional(),
|
|
64
|
+
paymentStatus: z.nativeEnum(PaymentStatus, {
|
|
65
|
+
errorMap: () => ({ message: "Invalid payment status" })
|
|
66
|
+
}).optional(),
|
|
67
|
+
paymentTransactionId: z.string().nullable().optional(),
|
|
68
|
+
completedPreRequirements: z.array(z.string()).optional(),
|
|
69
|
+
completedPostRequirements: z.array(z.string()).optional()
|
|
70
|
+
}).refine(
|
|
71
|
+
(data) => {
|
|
72
|
+
if (data.status === "canceled_clinic" /* CANCELED_CLINIC */ || data.status === "canceled_patient" /* CANCELED_PATIENT */) {
|
|
73
|
+
return !!data.cancellationReason && !!data.canceledBy;
|
|
74
|
+
}
|
|
75
|
+
return true;
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
message: "Cancellation reason and canceled by must be provided when canceling an appointment",
|
|
79
|
+
path: ["status"]
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
var searchAppointmentsSchema = z.object({
|
|
83
|
+
patientId: z.string().optional(),
|
|
84
|
+
practitionerId: z.string().optional(),
|
|
85
|
+
clinicBranchId: z.string().optional(),
|
|
86
|
+
startDate: z.date().optional(),
|
|
87
|
+
endDate: z.date().optional(),
|
|
88
|
+
status: z.union([
|
|
89
|
+
z.nativeEnum(AppointmentStatus),
|
|
90
|
+
z.array(z.nativeEnum(AppointmentStatus))
|
|
91
|
+
]).optional(),
|
|
92
|
+
limit: z.number().positive().optional(),
|
|
93
|
+
startAfter: z.any().optional()
|
|
94
|
+
}).refine(
|
|
95
|
+
(data) => {
|
|
96
|
+
return !!(data.patientId || data.practitionerId || data.clinicBranchId);
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
message: "At least one of patientId, practitionerId, or clinicBranchId must be provided",
|
|
100
|
+
path: ["searchCriteria"]
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
|
|
1
104
|
// src/config/firebase.ts
|
|
2
105
|
import { initializeApp } from "firebase/app";
|
|
3
106
|
import { getFirestore } from "firebase/firestore";
|
|
@@ -152,86 +255,86 @@ var UserRole = /* @__PURE__ */ ((UserRole2) => {
|
|
|
152
255
|
var USERS_COLLECTION = "users";
|
|
153
256
|
|
|
154
257
|
// src/services/auth.service.ts
|
|
155
|
-
import { z as
|
|
258
|
+
import { z as z18 } from "zod";
|
|
156
259
|
|
|
157
260
|
// src/validations/schemas.ts
|
|
158
|
-
import { z as
|
|
261
|
+
import { z as z3 } from "zod";
|
|
159
262
|
|
|
160
263
|
// src/validations/documentation-templates/template.schema.ts
|
|
161
|
-
import { z } from "zod";
|
|
162
|
-
var baseElementSchema =
|
|
163
|
-
id:
|
|
264
|
+
import { z as z2 } from "zod";
|
|
265
|
+
var baseElementSchema = z2.object({
|
|
266
|
+
id: z2.string().optional(),
|
|
164
267
|
// Make id optional so we can omit it later
|
|
165
|
-
type:
|
|
166
|
-
required:
|
|
268
|
+
type: z2.nativeEnum(DocumentElementType),
|
|
269
|
+
required: z2.boolean().optional()
|
|
167
270
|
});
|
|
168
271
|
var headingElementSchema = baseElementSchema.extend({
|
|
169
|
-
type:
|
|
170
|
-
text:
|
|
171
|
-
level:
|
|
272
|
+
type: z2.literal("heading" /* HEADING */),
|
|
273
|
+
text: z2.string().min(1).max(200),
|
|
274
|
+
level: z2.nativeEnum(HeadingLevel)
|
|
172
275
|
});
|
|
173
276
|
var paragraphElementSchema = baseElementSchema.extend({
|
|
174
|
-
type:
|
|
175
|
-
text:
|
|
277
|
+
type: z2.literal("paragraph" /* PARAGRAPH */),
|
|
278
|
+
text: z2.string().min(1).max(5e3)
|
|
176
279
|
});
|
|
177
280
|
var listElementSchema = baseElementSchema.extend({
|
|
178
|
-
type:
|
|
179
|
-
items:
|
|
180
|
-
listType:
|
|
281
|
+
type: z2.literal("list" /* LIST */),
|
|
282
|
+
items: z2.array(z2.string().min(1).max(500)).min(1).max(100),
|
|
283
|
+
listType: z2.nativeEnum(ListType)
|
|
181
284
|
});
|
|
182
285
|
var dynamicTextElementSchema = baseElementSchema.extend({
|
|
183
|
-
type:
|
|
184
|
-
text:
|
|
286
|
+
type: z2.literal("dynamic_text" /* DYNAMIC_TEXT */),
|
|
287
|
+
text: z2.string().min(1).max(5e3)
|
|
185
288
|
});
|
|
186
289
|
var binaryChoiceElementSchema = baseElementSchema.extend({
|
|
187
|
-
type:
|
|
188
|
-
question:
|
|
189
|
-
defaultValue:
|
|
290
|
+
type: z2.literal("binary_choice" /* BINARY_CHOICE */),
|
|
291
|
+
question: z2.string().min(1).max(500),
|
|
292
|
+
defaultValue: z2.boolean().optional()
|
|
190
293
|
});
|
|
191
294
|
var multipleChoiceElementSchema = baseElementSchema.extend({
|
|
192
|
-
type:
|
|
193
|
-
question:
|
|
194
|
-
options:
|
|
195
|
-
defaultValues:
|
|
295
|
+
type: z2.literal("multiple_choice" /* MULTIPLE_CHOICE */),
|
|
296
|
+
question: z2.string().min(1).max(500),
|
|
297
|
+
options: z2.array(z2.string().min(1).max(200)).min(2).max(50),
|
|
298
|
+
defaultValues: z2.array(z2.string()).optional()
|
|
196
299
|
});
|
|
197
300
|
var singleChoiceElementSchema = baseElementSchema.extend({
|
|
198
|
-
type:
|
|
199
|
-
question:
|
|
200
|
-
options:
|
|
201
|
-
defaultValue:
|
|
301
|
+
type: z2.literal("single_choice" /* SINGLE_CHOICE */),
|
|
302
|
+
question: z2.string().min(1).max(500),
|
|
303
|
+
options: z2.array(z2.string().min(1).max(200)).min(2).max(50),
|
|
304
|
+
defaultValue: z2.string().optional()
|
|
202
305
|
});
|
|
203
306
|
var ratingScaleElementSchema = baseElementSchema.extend({
|
|
204
|
-
type:
|
|
205
|
-
question:
|
|
206
|
-
min:
|
|
207
|
-
max:
|
|
208
|
-
labels:
|
|
209
|
-
defaultValue:
|
|
307
|
+
type: z2.literal("rating_scale" /* RATING_SCALE */),
|
|
308
|
+
question: z2.string().min(1).max(500),
|
|
309
|
+
min: z2.number().int().min(0).max(10),
|
|
310
|
+
max: z2.number().int().min(1).max(10),
|
|
311
|
+
labels: z2.record(z2.string()).optional(),
|
|
312
|
+
defaultValue: z2.number().int().optional()
|
|
210
313
|
});
|
|
211
314
|
var textInputElementSchema = baseElementSchema.extend({
|
|
212
|
-
type:
|
|
213
|
-
label:
|
|
214
|
-
placeholder:
|
|
215
|
-
multiline:
|
|
216
|
-
defaultValue:
|
|
315
|
+
type: z2.literal("text_input" /* TEXT_INPUT */),
|
|
316
|
+
label: z2.string().min(1).max(200),
|
|
317
|
+
placeholder: z2.string().max(200).optional(),
|
|
318
|
+
multiline: z2.boolean().optional(),
|
|
319
|
+
defaultValue: z2.string().optional()
|
|
217
320
|
});
|
|
218
321
|
var datePickerElementSchema = baseElementSchema.extend({
|
|
219
|
-
type:
|
|
220
|
-
label:
|
|
221
|
-
defaultValue:
|
|
322
|
+
type: z2.literal("date_picker" /* DATE_PICKER */),
|
|
323
|
+
label: z2.string().min(1).max(200),
|
|
324
|
+
defaultValue: z2.string().optional()
|
|
222
325
|
// ISO date string
|
|
223
326
|
});
|
|
224
327
|
var signatureElementSchema = baseElementSchema.extend({
|
|
225
|
-
type:
|
|
226
|
-
label:
|
|
328
|
+
type: z2.literal("signature" /* SIGNATURE */),
|
|
329
|
+
label: z2.string().min(1).max(200)
|
|
227
330
|
});
|
|
228
331
|
var fileUploadElementSchema = baseElementSchema.extend({
|
|
229
|
-
type:
|
|
230
|
-
label:
|
|
231
|
-
allowedFileTypes:
|
|
232
|
-
maxFileSizeMB:
|
|
332
|
+
type: z2.literal("file_upload" /* FILE_UPLOAD */),
|
|
333
|
+
label: z2.string().min(1).max(200),
|
|
334
|
+
allowedFileTypes: z2.array(z2.string()).optional(),
|
|
335
|
+
maxFileSizeMB: z2.number().positive().optional()
|
|
233
336
|
});
|
|
234
|
-
var documentElementSchema =
|
|
337
|
+
var documentElementSchema = z2.discriminatedUnion("type", [
|
|
235
338
|
headingElementSchema,
|
|
236
339
|
paragraphElementSchema,
|
|
237
340
|
listElementSchema,
|
|
@@ -245,7 +348,7 @@ var documentElementSchema = z.discriminatedUnion("type", [
|
|
|
245
348
|
signatureElementSchema,
|
|
246
349
|
fileUploadElementSchema
|
|
247
350
|
]);
|
|
248
|
-
var documentElementWithoutIdSchema =
|
|
351
|
+
var documentElementWithoutIdSchema = z2.discriminatedUnion("type", [
|
|
249
352
|
headingElementSchema.omit({ id: true }),
|
|
250
353
|
paragraphElementSchema.omit({ id: true }),
|
|
251
354
|
listElementSchema.omit({ id: true }),
|
|
@@ -259,50 +362,50 @@ var documentElementWithoutIdSchema = z.discriminatedUnion("type", [
|
|
|
259
362
|
signatureElementSchema.omit({ id: true }),
|
|
260
363
|
fileUploadElementSchema.omit({ id: true })
|
|
261
364
|
]);
|
|
262
|
-
var createDocumentTemplateSchema =
|
|
263
|
-
title:
|
|
264
|
-
description:
|
|
265
|
-
elements:
|
|
266
|
-
tags:
|
|
365
|
+
var createDocumentTemplateSchema = z2.object({
|
|
366
|
+
title: z2.string().min(1).max(200),
|
|
367
|
+
description: z2.string().max(1e3).optional(),
|
|
368
|
+
elements: z2.array(documentElementWithoutIdSchema).min(1).max(100),
|
|
369
|
+
tags: z2.array(z2.string().min(1).max(50)).max(20).optional()
|
|
267
370
|
});
|
|
268
|
-
var updateDocumentTemplateSchema =
|
|
269
|
-
title:
|
|
270
|
-
description:
|
|
271
|
-
elements:
|
|
272
|
-
tags:
|
|
273
|
-
isActive:
|
|
371
|
+
var updateDocumentTemplateSchema = z2.object({
|
|
372
|
+
title: z2.string().min(1).max(200).optional(),
|
|
373
|
+
description: z2.string().max(1e3).optional(),
|
|
374
|
+
elements: z2.array(documentElementWithoutIdSchema).min(1).max(100).optional(),
|
|
375
|
+
tags: z2.array(z2.string().min(1).max(50)).max(20).optional(),
|
|
376
|
+
isActive: z2.boolean().optional()
|
|
274
377
|
});
|
|
275
|
-
var documentTemplateSchema =
|
|
276
|
-
id:
|
|
277
|
-
title:
|
|
278
|
-
description:
|
|
279
|
-
createdAt:
|
|
280
|
-
updatedAt:
|
|
281
|
-
createdBy:
|
|
282
|
-
elements:
|
|
283
|
-
tags:
|
|
284
|
-
version:
|
|
285
|
-
isActive:
|
|
378
|
+
var documentTemplateSchema = z2.object({
|
|
379
|
+
id: z2.string(),
|
|
380
|
+
title: z2.string().min(1).max(200),
|
|
381
|
+
description: z2.string().max(1e3).optional(),
|
|
382
|
+
createdAt: z2.number(),
|
|
383
|
+
updatedAt: z2.number(),
|
|
384
|
+
createdBy: z2.string(),
|
|
385
|
+
elements: z2.array(documentElementSchema),
|
|
386
|
+
tags: z2.array(z2.string().min(1).max(50)).max(20).optional(),
|
|
387
|
+
version: z2.number().int().positive(),
|
|
388
|
+
isActive: z2.boolean()
|
|
286
389
|
});
|
|
287
390
|
|
|
288
391
|
// src/validations/schemas.ts
|
|
289
|
-
var emailSchema =
|
|
290
|
-
var passwordSchema =
|
|
392
|
+
var emailSchema = z3.string().email("Invalid email format").min(5, "Email must be at least 5 characters").max(255, "Email must be less than 255 characters");
|
|
393
|
+
var passwordSchema = z3.string().min(8, "Password must be at least 8 characters").max(100, "Password must be less than 100 characters").regex(
|
|
291
394
|
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d\w\W]{8,}$/,
|
|
292
395
|
"Password must contain at least one uppercase letter, one lowercase letter, and one number"
|
|
293
396
|
);
|
|
294
|
-
var userRoleSchema =
|
|
295
|
-
var userRolesSchema =
|
|
296
|
-
var timestampSchema =
|
|
397
|
+
var userRoleSchema = z3.nativeEnum(UserRole);
|
|
398
|
+
var userRolesSchema = z3.array(userRoleSchema).min(1, "User must have at least one role").max(3, "User cannot have more than 3 roles");
|
|
399
|
+
var timestampSchema = z3.custom((data) => {
|
|
297
400
|
if (data && typeof data === "object" && "isEqual" in data) {
|
|
298
401
|
return true;
|
|
299
402
|
}
|
|
300
403
|
return data && typeof data === "object" && "toDate" in data && "seconds" in data && "nanoseconds" in data;
|
|
301
404
|
}, "Must be a Timestamp object or serverTimestamp");
|
|
302
|
-
var clinicAdminOptionsSchema =
|
|
303
|
-
isGroupOwner:
|
|
304
|
-
groupToken:
|
|
305
|
-
groupId:
|
|
405
|
+
var clinicAdminOptionsSchema = z3.object({
|
|
406
|
+
isGroupOwner: z3.boolean(),
|
|
407
|
+
groupToken: z3.string().optional(),
|
|
408
|
+
groupId: z3.string().optional()
|
|
306
409
|
}).refine(
|
|
307
410
|
(data) => {
|
|
308
411
|
if (!data.isGroupOwner && (!data.groupToken || !data.groupId)) {
|
|
@@ -317,20 +420,20 @@ var clinicAdminOptionsSchema = z2.object({
|
|
|
317
420
|
message: "Invalid clinic admin options configuration"
|
|
318
421
|
}
|
|
319
422
|
);
|
|
320
|
-
var createUserOptionsSchema =
|
|
423
|
+
var createUserOptionsSchema = z3.object({
|
|
321
424
|
clinicAdminData: clinicAdminOptionsSchema.optional()
|
|
322
425
|
});
|
|
323
|
-
var userSchema =
|
|
324
|
-
uid:
|
|
325
|
-
email:
|
|
326
|
-
roles:
|
|
327
|
-
isAnonymous:
|
|
426
|
+
var userSchema = z3.object({
|
|
427
|
+
uid: z3.string(),
|
|
428
|
+
email: z3.string().email().nullable(),
|
|
429
|
+
roles: z3.array(userRoleSchema),
|
|
430
|
+
isAnonymous: z3.boolean(),
|
|
328
431
|
createdAt: timestampSchema,
|
|
329
432
|
updatedAt: timestampSchema,
|
|
330
433
|
lastLoginAt: timestampSchema,
|
|
331
|
-
patientProfile:
|
|
332
|
-
practitionerProfile:
|
|
333
|
-
adminProfile:
|
|
434
|
+
patientProfile: z3.string().optional(),
|
|
435
|
+
practitionerProfile: z3.string().optional(),
|
|
436
|
+
adminProfile: z3.string().optional()
|
|
334
437
|
});
|
|
335
438
|
|
|
336
439
|
// src/errors/auth.errors.ts
|
|
@@ -689,7 +792,7 @@ var USER_ERRORS = {
|
|
|
689
792
|
};
|
|
690
793
|
|
|
691
794
|
// src/services/user.service.ts
|
|
692
|
-
import { z as
|
|
795
|
+
import { z as z14 } from "zod";
|
|
693
796
|
|
|
694
797
|
// src/services/patient/patient.service.ts
|
|
695
798
|
import {
|
|
@@ -717,7 +820,7 @@ import {
|
|
|
717
820
|
doc as doc3
|
|
718
821
|
} from "firebase/firestore";
|
|
719
822
|
import { ref, uploadBytes, getDownloadURL, deleteObject } from "firebase/storage";
|
|
720
|
-
import { z as
|
|
823
|
+
import { z as z8 } from "zod";
|
|
721
824
|
|
|
722
825
|
// src/types/patient/medical-info.types.ts
|
|
723
826
|
var PATIENT_MEDICAL_INFO_COLLECTION = "medical_info";
|
|
@@ -746,11 +849,11 @@ var Gender = /* @__PURE__ */ ((Gender2) => {
|
|
|
746
849
|
})(Gender || {});
|
|
747
850
|
|
|
748
851
|
// src/validations/patient.schema.ts
|
|
749
|
-
import { z as
|
|
852
|
+
import { z as z6 } from "zod";
|
|
750
853
|
import { Timestamp } from "firebase/firestore";
|
|
751
854
|
|
|
752
855
|
// src/validations/patient/medical-info.schema.ts
|
|
753
|
-
import { z as
|
|
856
|
+
import { z as z5 } from "zod";
|
|
754
857
|
|
|
755
858
|
// src/types/patient/allergies.ts
|
|
756
859
|
var AllergyType = /* @__PURE__ */ ((AllergyType2) => {
|
|
@@ -839,71 +942,71 @@ var Contraindication = /* @__PURE__ */ ((Contraindication2) => {
|
|
|
839
942
|
})(Contraindication || {});
|
|
840
943
|
|
|
841
944
|
// src/validations/common.schema.ts
|
|
842
|
-
import { z as
|
|
843
|
-
var timestampSchema2 =
|
|
844
|
-
seconds:
|
|
845
|
-
nanoseconds:
|
|
945
|
+
import { z as z4 } from "zod";
|
|
946
|
+
var timestampSchema2 = z4.object({
|
|
947
|
+
seconds: z4.number(),
|
|
948
|
+
nanoseconds: z4.number()
|
|
846
949
|
});
|
|
847
950
|
|
|
848
951
|
// src/validations/patient/medical-info.schema.ts
|
|
849
|
-
var allergySubtypeSchema =
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
952
|
+
var allergySubtypeSchema = z5.union([
|
|
953
|
+
z5.nativeEnum(MedicationAllergySubtype),
|
|
954
|
+
z5.nativeEnum(FoodAllergySubtype),
|
|
955
|
+
z5.nativeEnum(EnvironmentalAllergySubtype),
|
|
956
|
+
z5.nativeEnum(CosmeticAllergySubtype),
|
|
957
|
+
z5.literal("other")
|
|
855
958
|
]);
|
|
856
|
-
var allergySchema =
|
|
857
|
-
type:
|
|
959
|
+
var allergySchema = z5.object({
|
|
960
|
+
type: z5.nativeEnum(AllergyType),
|
|
858
961
|
subtype: allergySubtypeSchema,
|
|
859
|
-
name:
|
|
860
|
-
severity:
|
|
861
|
-
reaction:
|
|
962
|
+
name: z5.string().optional(),
|
|
963
|
+
severity: z5.enum(["mild", "moderate", "severe"]).optional(),
|
|
964
|
+
reaction: z5.string().optional(),
|
|
862
965
|
diagnosed: timestampSchema2.optional(),
|
|
863
|
-
notes:
|
|
966
|
+
notes: z5.string().optional()
|
|
864
967
|
});
|
|
865
|
-
var vitalStatsSchema =
|
|
866
|
-
height:
|
|
867
|
-
weight:
|
|
868
|
-
bloodType:
|
|
869
|
-
bloodPressure:
|
|
870
|
-
systolic:
|
|
871
|
-
diastolic:
|
|
968
|
+
var vitalStatsSchema = z5.object({
|
|
969
|
+
height: z5.number().positive().optional(),
|
|
970
|
+
weight: z5.number().positive().optional(),
|
|
971
|
+
bloodType: z5.enum(["A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-"]).optional(),
|
|
972
|
+
bloodPressure: z5.object({
|
|
973
|
+
systolic: z5.number().min(70).max(200),
|
|
974
|
+
diastolic: z5.number().min(40).max(130),
|
|
872
975
|
lastMeasured: timestampSchema2
|
|
873
976
|
}).optional()
|
|
874
977
|
});
|
|
875
|
-
var blockingConditionSchema =
|
|
876
|
-
condition:
|
|
978
|
+
var blockingConditionSchema = z5.object({
|
|
979
|
+
condition: z5.nativeEnum(BlockingCondition),
|
|
877
980
|
diagnosedAt: timestampSchema2,
|
|
878
|
-
notes:
|
|
879
|
-
isActive:
|
|
981
|
+
notes: z5.string().optional(),
|
|
982
|
+
isActive: z5.boolean()
|
|
880
983
|
});
|
|
881
|
-
var contraindicationSchema =
|
|
882
|
-
condition:
|
|
984
|
+
var contraindicationSchema = z5.object({
|
|
985
|
+
condition: z5.nativeEnum(Contraindication),
|
|
883
986
|
lastOccurrence: timestampSchema2,
|
|
884
|
-
frequency:
|
|
885
|
-
notes:
|
|
886
|
-
isActive:
|
|
987
|
+
frequency: z5.enum(["rare", "occasional", "frequent"]),
|
|
988
|
+
notes: z5.string().optional(),
|
|
989
|
+
isActive: z5.boolean()
|
|
887
990
|
});
|
|
888
|
-
var medicationSchema =
|
|
889
|
-
name:
|
|
890
|
-
dosage:
|
|
891
|
-
frequency:
|
|
991
|
+
var medicationSchema = z5.object({
|
|
992
|
+
name: z5.string().min(1),
|
|
993
|
+
dosage: z5.string().min(1),
|
|
994
|
+
frequency: z5.string().min(1),
|
|
892
995
|
startDate: timestampSchema2,
|
|
893
996
|
endDate: timestampSchema2.optional(),
|
|
894
|
-
prescribedBy:
|
|
997
|
+
prescribedBy: z5.string().optional()
|
|
895
998
|
});
|
|
896
|
-
var patientMedicalInfoSchema =
|
|
897
|
-
patientId:
|
|
999
|
+
var patientMedicalInfoSchema = z5.object({
|
|
1000
|
+
patientId: z5.string(),
|
|
898
1001
|
vitalStats: vitalStatsSchema,
|
|
899
|
-
blockingConditions:
|
|
900
|
-
contraindications:
|
|
901
|
-
allergies:
|
|
902
|
-
currentMedications:
|
|
903
|
-
emergencyNotes:
|
|
1002
|
+
blockingConditions: z5.array(blockingConditionSchema),
|
|
1003
|
+
contraindications: z5.array(contraindicationSchema),
|
|
1004
|
+
allergies: z5.array(allergySchema),
|
|
1005
|
+
currentMedications: z5.array(medicationSchema),
|
|
1006
|
+
emergencyNotes: z5.string().optional(),
|
|
904
1007
|
lastUpdated: timestampSchema2,
|
|
905
|
-
updatedBy:
|
|
906
|
-
verifiedBy:
|
|
1008
|
+
updatedBy: z5.string(),
|
|
1009
|
+
verifiedBy: z5.string().optional(),
|
|
907
1010
|
verifiedAt: timestampSchema2.optional()
|
|
908
1011
|
});
|
|
909
1012
|
var createPatientMedicalInfoSchema = patientMedicalInfoSchema.omit({
|
|
@@ -917,141 +1020,141 @@ var updatePatientMedicalInfoSchema = createPatientMedicalInfoSchema.partial();
|
|
|
917
1020
|
var updateVitalStatsSchema = vitalStatsSchema;
|
|
918
1021
|
var addAllergySchema = allergySchema;
|
|
919
1022
|
var updateAllergySchema = allergySchema.partial().extend({
|
|
920
|
-
allergyIndex:
|
|
1023
|
+
allergyIndex: z5.number().min(0)
|
|
921
1024
|
});
|
|
922
1025
|
var addBlockingConditionSchema = blockingConditionSchema;
|
|
923
1026
|
var updateBlockingConditionSchema = blockingConditionSchema.partial().extend({
|
|
924
|
-
conditionIndex:
|
|
1027
|
+
conditionIndex: z5.number().min(0)
|
|
925
1028
|
});
|
|
926
1029
|
var addContraindicationSchema = contraindicationSchema;
|
|
927
1030
|
var updateContraindicationSchema = contraindicationSchema.partial().extend({
|
|
928
|
-
contraindicationIndex:
|
|
1031
|
+
contraindicationIndex: z5.number().min(0)
|
|
929
1032
|
});
|
|
930
1033
|
var addMedicationSchema = medicationSchema;
|
|
931
1034
|
var updateMedicationSchema = medicationSchema.partial().extend({
|
|
932
|
-
medicationIndex:
|
|
1035
|
+
medicationIndex: z5.number().min(0)
|
|
933
1036
|
});
|
|
934
1037
|
|
|
935
1038
|
// src/validations/patient.schema.ts
|
|
936
|
-
var locationDataSchema =
|
|
937
|
-
latitude:
|
|
938
|
-
longitude:
|
|
939
|
-
geohash:
|
|
1039
|
+
var locationDataSchema = z6.object({
|
|
1040
|
+
latitude: z6.number().min(-90).max(90),
|
|
1041
|
+
longitude: z6.number().min(-180).max(180),
|
|
1042
|
+
geohash: z6.string().optional()
|
|
940
1043
|
});
|
|
941
|
-
var addressDataSchema =
|
|
942
|
-
address:
|
|
943
|
-
city:
|
|
944
|
-
country:
|
|
945
|
-
postalCode:
|
|
1044
|
+
var addressDataSchema = z6.object({
|
|
1045
|
+
address: z6.string(),
|
|
1046
|
+
city: z6.string(),
|
|
1047
|
+
country: z6.string(),
|
|
1048
|
+
postalCode: z6.string()
|
|
946
1049
|
});
|
|
947
|
-
var emergencyContactSchema =
|
|
948
|
-
name:
|
|
949
|
-
relationship:
|
|
950
|
-
phoneNumber:
|
|
951
|
-
isNotifiable:
|
|
1050
|
+
var emergencyContactSchema = z6.object({
|
|
1051
|
+
name: z6.string(),
|
|
1052
|
+
relationship: z6.string(),
|
|
1053
|
+
phoneNumber: z6.string(),
|
|
1054
|
+
isNotifiable: z6.boolean()
|
|
952
1055
|
});
|
|
953
|
-
var gamificationSchema =
|
|
954
|
-
level:
|
|
955
|
-
points:
|
|
1056
|
+
var gamificationSchema = z6.object({
|
|
1057
|
+
level: z6.number(),
|
|
1058
|
+
points: z6.number()
|
|
956
1059
|
});
|
|
957
|
-
var patientLocationInfoSchema =
|
|
958
|
-
patientId:
|
|
959
|
-
userRef:
|
|
1060
|
+
var patientLocationInfoSchema = z6.object({
|
|
1061
|
+
patientId: z6.string(),
|
|
1062
|
+
userRef: z6.string(),
|
|
960
1063
|
locationData: locationDataSchema,
|
|
961
|
-
createdAt:
|
|
962
|
-
updatedAt:
|
|
1064
|
+
createdAt: z6.instanceof(Timestamp),
|
|
1065
|
+
updatedAt: z6.instanceof(Timestamp)
|
|
963
1066
|
});
|
|
964
|
-
var createPatientLocationInfoSchema =
|
|
965
|
-
patientId:
|
|
966
|
-
userRef:
|
|
1067
|
+
var createPatientLocationInfoSchema = z6.object({
|
|
1068
|
+
patientId: z6.string(),
|
|
1069
|
+
userRef: z6.string(),
|
|
967
1070
|
locationData: locationDataSchema
|
|
968
1071
|
});
|
|
969
|
-
var patientSensitiveInfoSchema =
|
|
970
|
-
patientId:
|
|
971
|
-
userRef:
|
|
972
|
-
photoUrl:
|
|
973
|
-
firstName:
|
|
974
|
-
lastName:
|
|
975
|
-
dateOfBirth:
|
|
976
|
-
gender:
|
|
977
|
-
email:
|
|
978
|
-
phoneNumber:
|
|
979
|
-
alternativePhoneNumber:
|
|
1072
|
+
var patientSensitiveInfoSchema = z6.object({
|
|
1073
|
+
patientId: z6.string(),
|
|
1074
|
+
userRef: z6.string(),
|
|
1075
|
+
photoUrl: z6.string().optional(),
|
|
1076
|
+
firstName: z6.string().min(2),
|
|
1077
|
+
lastName: z6.string().min(2),
|
|
1078
|
+
dateOfBirth: z6.instanceof(Timestamp).nullable(),
|
|
1079
|
+
gender: z6.nativeEnum(Gender),
|
|
1080
|
+
email: z6.string().email().optional(),
|
|
1081
|
+
phoneNumber: z6.string().optional(),
|
|
1082
|
+
alternativePhoneNumber: z6.string().optional(),
|
|
980
1083
|
addressData: addressDataSchema.optional(),
|
|
981
|
-
emergencyContacts:
|
|
982
|
-
createdAt:
|
|
983
|
-
updatedAt:
|
|
1084
|
+
emergencyContacts: z6.array(emergencyContactSchema).optional(),
|
|
1085
|
+
createdAt: z6.instanceof(Timestamp),
|
|
1086
|
+
updatedAt: z6.instanceof(Timestamp)
|
|
984
1087
|
});
|
|
985
|
-
var patientDoctorSchema =
|
|
986
|
-
userRef:
|
|
987
|
-
assignedAt:
|
|
988
|
-
assignedBy:
|
|
989
|
-
isActive:
|
|
990
|
-
notes:
|
|
1088
|
+
var patientDoctorSchema = z6.object({
|
|
1089
|
+
userRef: z6.string(),
|
|
1090
|
+
assignedAt: z6.instanceof(Timestamp),
|
|
1091
|
+
assignedBy: z6.string().optional(),
|
|
1092
|
+
isActive: z6.boolean(),
|
|
1093
|
+
notes: z6.string().optional()
|
|
991
1094
|
});
|
|
992
|
-
var patientClinicSchema =
|
|
993
|
-
clinicId:
|
|
994
|
-
assignedAt:
|
|
995
|
-
assignedBy:
|
|
996
|
-
isActive:
|
|
997
|
-
notes:
|
|
1095
|
+
var patientClinicSchema = z6.object({
|
|
1096
|
+
clinicId: z6.string(),
|
|
1097
|
+
assignedAt: z6.instanceof(Timestamp),
|
|
1098
|
+
assignedBy: z6.string().optional(),
|
|
1099
|
+
isActive: z6.boolean(),
|
|
1100
|
+
notes: z6.string().optional()
|
|
998
1101
|
});
|
|
999
|
-
var patientProfileSchema =
|
|
1000
|
-
id:
|
|
1001
|
-
userRef:
|
|
1002
|
-
displayName:
|
|
1003
|
-
profilePhoto:
|
|
1102
|
+
var patientProfileSchema = z6.object({
|
|
1103
|
+
id: z6.string(),
|
|
1104
|
+
userRef: z6.string(),
|
|
1105
|
+
displayName: z6.string(),
|
|
1106
|
+
profilePhoto: z6.string().url().nullable(),
|
|
1004
1107
|
gamification: gamificationSchema,
|
|
1005
|
-
expoTokens:
|
|
1006
|
-
isActive:
|
|
1007
|
-
isVerified:
|
|
1008
|
-
doctors:
|
|
1009
|
-
clinics:
|
|
1010
|
-
doctorIds:
|
|
1011
|
-
clinicIds:
|
|
1012
|
-
createdAt:
|
|
1013
|
-
updatedAt:
|
|
1108
|
+
expoTokens: z6.array(z6.string()),
|
|
1109
|
+
isActive: z6.boolean(),
|
|
1110
|
+
isVerified: z6.boolean(),
|
|
1111
|
+
doctors: z6.array(patientDoctorSchema),
|
|
1112
|
+
clinics: z6.array(patientClinicSchema),
|
|
1113
|
+
doctorIds: z6.array(z6.string()),
|
|
1114
|
+
clinicIds: z6.array(z6.string()),
|
|
1115
|
+
createdAt: z6.instanceof(Timestamp),
|
|
1116
|
+
updatedAt: z6.instanceof(Timestamp)
|
|
1014
1117
|
});
|
|
1015
|
-
var createPatientProfileSchema =
|
|
1016
|
-
userRef:
|
|
1017
|
-
displayName:
|
|
1018
|
-
profilePhoto:
|
|
1019
|
-
expoTokens:
|
|
1118
|
+
var createPatientProfileSchema = z6.object({
|
|
1119
|
+
userRef: z6.string(),
|
|
1120
|
+
displayName: z6.string(),
|
|
1121
|
+
profilePhoto: z6.string().url().nullable().optional(),
|
|
1122
|
+
expoTokens: z6.array(z6.string()),
|
|
1020
1123
|
gamification: gamificationSchema.optional(),
|
|
1021
|
-
isActive:
|
|
1022
|
-
isVerified:
|
|
1023
|
-
doctors:
|
|
1024
|
-
clinics:
|
|
1025
|
-
doctorIds:
|
|
1026
|
-
clinicIds:
|
|
1124
|
+
isActive: z6.boolean(),
|
|
1125
|
+
isVerified: z6.boolean(),
|
|
1126
|
+
doctors: z6.array(patientDoctorSchema).optional(),
|
|
1127
|
+
clinics: z6.array(patientClinicSchema).optional(),
|
|
1128
|
+
doctorIds: z6.array(z6.string()).optional(),
|
|
1129
|
+
clinicIds: z6.array(z6.string()).optional()
|
|
1027
1130
|
});
|
|
1028
|
-
var createPatientSensitiveInfoSchema =
|
|
1029
|
-
patientId:
|
|
1030
|
-
userRef:
|
|
1031
|
-
photoUrl:
|
|
1032
|
-
firstName:
|
|
1033
|
-
lastName:
|
|
1034
|
-
dateOfBirth:
|
|
1035
|
-
gender:
|
|
1036
|
-
email:
|
|
1037
|
-
phoneNumber:
|
|
1038
|
-
alternativePhoneNumber:
|
|
1131
|
+
var createPatientSensitiveInfoSchema = z6.object({
|
|
1132
|
+
patientId: z6.string(),
|
|
1133
|
+
userRef: z6.string(),
|
|
1134
|
+
photoUrl: z6.string().optional(),
|
|
1135
|
+
firstName: z6.string().min(2),
|
|
1136
|
+
lastName: z6.string().min(2),
|
|
1137
|
+
dateOfBirth: z6.instanceof(Timestamp).nullable(),
|
|
1138
|
+
gender: z6.nativeEnum(Gender),
|
|
1139
|
+
email: z6.string().email().optional(),
|
|
1140
|
+
phoneNumber: z6.string().optional(),
|
|
1141
|
+
alternativePhoneNumber: z6.string().optional(),
|
|
1039
1142
|
addressData: addressDataSchema.optional(),
|
|
1040
|
-
emergencyContacts:
|
|
1143
|
+
emergencyContacts: z6.array(emergencyContactSchema).optional()
|
|
1041
1144
|
});
|
|
1042
|
-
var searchPatientsSchema =
|
|
1043
|
-
clinicId:
|
|
1044
|
-
practitionerId:
|
|
1145
|
+
var searchPatientsSchema = z6.object({
|
|
1146
|
+
clinicId: z6.string().optional(),
|
|
1147
|
+
practitionerId: z6.string().optional()
|
|
1045
1148
|
}).refine((data) => data.clinicId || data.practitionerId, {
|
|
1046
1149
|
message: "At least one of clinicId or practitionerId must be provided",
|
|
1047
1150
|
path: []
|
|
1048
1151
|
// Optional: specify a path like ['clinicId'] or ['practitionerId']
|
|
1049
1152
|
});
|
|
1050
|
-
var requesterInfoSchema =
|
|
1051
|
-
id:
|
|
1052
|
-
role:
|
|
1053
|
-
associatedClinicId:
|
|
1054
|
-
associatedPractitionerId:
|
|
1153
|
+
var requesterInfoSchema = z6.object({
|
|
1154
|
+
id: z6.string(),
|
|
1155
|
+
role: z6.enum(["clinic_admin", "practitioner"]),
|
|
1156
|
+
associatedClinicId: z6.string().optional(),
|
|
1157
|
+
associatedPractitionerId: z6.string().optional()
|
|
1055
1158
|
}).refine(
|
|
1056
1159
|
(data) => {
|
|
1057
1160
|
if (data.role === "clinic_admin") {
|
|
@@ -1084,7 +1187,7 @@ import {
|
|
|
1084
1187
|
setDoc,
|
|
1085
1188
|
serverTimestamp
|
|
1086
1189
|
} from "firebase/firestore";
|
|
1087
|
-
import { z as
|
|
1190
|
+
import { z as z7 } from "zod";
|
|
1088
1191
|
var createSensitiveInfoUtil = async (db, data, requesterUserId) => {
|
|
1089
1192
|
try {
|
|
1090
1193
|
if (data.userRef !== requesterUserId) {
|
|
@@ -1109,7 +1212,7 @@ var createSensitiveInfoUtil = async (db, data, requesterUserId) => {
|
|
|
1109
1212
|
}
|
|
1110
1213
|
return createdDoc.data();
|
|
1111
1214
|
} catch (error) {
|
|
1112
|
-
if (error instanceof
|
|
1215
|
+
if (error instanceof z7.ZodError) {
|
|
1113
1216
|
throw new Error("Invalid sensitive info data: " + error.message);
|
|
1114
1217
|
}
|
|
1115
1218
|
throw error;
|
|
@@ -1349,9 +1452,9 @@ var addAllergyUtil = async (db, patientId, data, userRef) => {
|
|
|
1349
1452
|
var updateAllergyUtil = async (db, patientId, data, userRef) => {
|
|
1350
1453
|
const validatedData = updateAllergySchema.parse(data);
|
|
1351
1454
|
const { allergyIndex, ...updateData } = validatedData;
|
|
1352
|
-
const
|
|
1353
|
-
if (!
|
|
1354
|
-
const medicalInfo =
|
|
1455
|
+
const doc30 = await getDoc3(getMedicalInfoDocRef(db, patientId));
|
|
1456
|
+
if (!doc30.exists()) throw new Error("Medical info not found");
|
|
1457
|
+
const medicalInfo = doc30.data();
|
|
1355
1458
|
if (allergyIndex >= medicalInfo.allergies.length) {
|
|
1356
1459
|
throw new Error("Invalid allergy index");
|
|
1357
1460
|
}
|
|
@@ -1367,9 +1470,9 @@ var updateAllergyUtil = async (db, patientId, data, userRef) => {
|
|
|
1367
1470
|
});
|
|
1368
1471
|
};
|
|
1369
1472
|
var removeAllergyUtil = async (db, patientId, allergyIndex, userRef) => {
|
|
1370
|
-
const
|
|
1371
|
-
if (!
|
|
1372
|
-
const medicalInfo =
|
|
1473
|
+
const doc30 = await getDoc3(getMedicalInfoDocRef(db, patientId));
|
|
1474
|
+
if (!doc30.exists()) throw new Error("Medical info not found");
|
|
1475
|
+
const medicalInfo = doc30.data();
|
|
1373
1476
|
if (allergyIndex >= medicalInfo.allergies.length) {
|
|
1374
1477
|
throw new Error("Invalid allergy index");
|
|
1375
1478
|
}
|
|
@@ -1394,9 +1497,9 @@ var addBlockingConditionUtil = async (db, patientId, data, userRef) => {
|
|
|
1394
1497
|
var updateBlockingConditionUtil = async (db, patientId, data, userRef) => {
|
|
1395
1498
|
const validatedData = updateBlockingConditionSchema.parse(data);
|
|
1396
1499
|
const { conditionIndex, ...updateData } = validatedData;
|
|
1397
|
-
const
|
|
1398
|
-
if (!
|
|
1399
|
-
const medicalInfo =
|
|
1500
|
+
const doc30 = await getDoc3(getMedicalInfoDocRef(db, patientId));
|
|
1501
|
+
if (!doc30.exists()) throw new Error("Medical info not found");
|
|
1502
|
+
const medicalInfo = doc30.data();
|
|
1400
1503
|
if (conditionIndex >= medicalInfo.blockingConditions.length) {
|
|
1401
1504
|
throw new Error("Invalid blocking condition index");
|
|
1402
1505
|
}
|
|
@@ -1412,9 +1515,9 @@ var updateBlockingConditionUtil = async (db, patientId, data, userRef) => {
|
|
|
1412
1515
|
});
|
|
1413
1516
|
};
|
|
1414
1517
|
var removeBlockingConditionUtil = async (db, patientId, conditionIndex, userRef) => {
|
|
1415
|
-
const
|
|
1416
|
-
if (!
|
|
1417
|
-
const medicalInfo =
|
|
1518
|
+
const doc30 = await getDoc3(getMedicalInfoDocRef(db, patientId));
|
|
1519
|
+
if (!doc30.exists()) throw new Error("Medical info not found");
|
|
1520
|
+
const medicalInfo = doc30.data();
|
|
1418
1521
|
if (conditionIndex >= medicalInfo.blockingConditions.length) {
|
|
1419
1522
|
throw new Error("Invalid blocking condition index");
|
|
1420
1523
|
}
|
|
@@ -1439,9 +1542,9 @@ var addContraindicationUtil = async (db, patientId, data, userRef) => {
|
|
|
1439
1542
|
var updateContraindicationUtil = async (db, patientId, data, userRef) => {
|
|
1440
1543
|
const validatedData = updateContraindicationSchema.parse(data);
|
|
1441
1544
|
const { contraindicationIndex, ...updateData } = validatedData;
|
|
1442
|
-
const
|
|
1443
|
-
if (!
|
|
1444
|
-
const medicalInfo =
|
|
1545
|
+
const doc30 = await getDoc3(getMedicalInfoDocRef(db, patientId));
|
|
1546
|
+
if (!doc30.exists()) throw new Error("Medical info not found");
|
|
1547
|
+
const medicalInfo = doc30.data();
|
|
1445
1548
|
if (contraindicationIndex >= medicalInfo.contraindications.length) {
|
|
1446
1549
|
throw new Error("Invalid contraindication index");
|
|
1447
1550
|
}
|
|
@@ -1457,9 +1560,9 @@ var updateContraindicationUtil = async (db, patientId, data, userRef) => {
|
|
|
1457
1560
|
});
|
|
1458
1561
|
};
|
|
1459
1562
|
var removeContraindicationUtil = async (db, patientId, contraindicationIndex, userRef) => {
|
|
1460
|
-
const
|
|
1461
|
-
if (!
|
|
1462
|
-
const medicalInfo =
|
|
1563
|
+
const doc30 = await getDoc3(getMedicalInfoDocRef(db, patientId));
|
|
1564
|
+
if (!doc30.exists()) throw new Error("Medical info not found");
|
|
1565
|
+
const medicalInfo = doc30.data();
|
|
1463
1566
|
if (contraindicationIndex >= medicalInfo.contraindications.length) {
|
|
1464
1567
|
throw new Error("Invalid contraindication index");
|
|
1465
1568
|
}
|
|
@@ -1484,9 +1587,9 @@ var addMedicationUtil = async (db, patientId, data, userRef) => {
|
|
|
1484
1587
|
var updateMedicationUtil = async (db, patientId, data, userRef) => {
|
|
1485
1588
|
const validatedData = updateMedicationSchema.parse(data);
|
|
1486
1589
|
const { medicationIndex, ...updateData } = validatedData;
|
|
1487
|
-
const
|
|
1488
|
-
if (!
|
|
1489
|
-
const medicalInfo =
|
|
1590
|
+
const doc30 = await getDoc3(getMedicalInfoDocRef(db, patientId));
|
|
1591
|
+
if (!doc30.exists()) throw new Error("Medical info not found");
|
|
1592
|
+
const medicalInfo = doc30.data();
|
|
1490
1593
|
if (medicationIndex >= medicalInfo.currentMedications.length) {
|
|
1491
1594
|
throw new Error("Invalid medication index");
|
|
1492
1595
|
}
|
|
@@ -1502,9 +1605,9 @@ var updateMedicationUtil = async (db, patientId, data, userRef) => {
|
|
|
1502
1605
|
});
|
|
1503
1606
|
};
|
|
1504
1607
|
var removeMedicationUtil = async (db, patientId, medicationIndex, userRef) => {
|
|
1505
|
-
const
|
|
1506
|
-
if (!
|
|
1507
|
-
const medicalInfo =
|
|
1608
|
+
const doc30 = await getDoc3(getMedicalInfoDocRef(db, patientId));
|
|
1609
|
+
if (!doc30.exists()) throw new Error("Medical info not found");
|
|
1610
|
+
const medicalInfo = doc30.data();
|
|
1508
1611
|
if (medicationIndex >= medicalInfo.currentMedications.length) {
|
|
1509
1612
|
throw new Error("Invalid medication index");
|
|
1510
1613
|
}
|
|
@@ -1594,7 +1697,7 @@ var createPatientProfileUtil = async (db, data, generateId2) => {
|
|
|
1594
1697
|
return patientDoc.data();
|
|
1595
1698
|
} catch (error) {
|
|
1596
1699
|
console.error(`[createPatientProfileUtil] Error in patient profile creation:`, error);
|
|
1597
|
-
if (error instanceof
|
|
1700
|
+
if (error instanceof z8.ZodError) {
|
|
1598
1701
|
throw new Error("Invalid patient data: " + error.message);
|
|
1599
1702
|
}
|
|
1600
1703
|
throw error;
|
|
@@ -1782,7 +1885,7 @@ var searchPatientsUtil = async (db, params, requester) => {
|
|
|
1782
1885
|
try {
|
|
1783
1886
|
const finalQuery = query2(patientsCollectionRef, ...constraints);
|
|
1784
1887
|
const querySnapshot = await getDocs2(finalQuery);
|
|
1785
|
-
const patients = querySnapshot.docs.map((
|
|
1888
|
+
const patients = querySnapshot.docs.map((doc30) => doc30.data());
|
|
1786
1889
|
console.log(`[searchPatientsUtil] Found ${patients.length} patients matching criteria.`);
|
|
1787
1890
|
return patients;
|
|
1788
1891
|
} catch (error) {
|
|
@@ -1806,8 +1909,8 @@ var getAllPatientsUtil = async (db, options) => {
|
|
|
1806
1909
|
}
|
|
1807
1910
|
const patientsSnapshot = await getDocs2(q);
|
|
1808
1911
|
const patients = [];
|
|
1809
|
-
patientsSnapshot.forEach((
|
|
1810
|
-
patients.push(
|
|
1912
|
+
patientsSnapshot.forEach((doc30) => {
|
|
1913
|
+
patients.push(doc30.data());
|
|
1811
1914
|
});
|
|
1812
1915
|
console.log(`[getAllPatientsUtil] Found ${patients.length} patients`);
|
|
1813
1916
|
return patients;
|
|
@@ -1826,7 +1929,7 @@ import {
|
|
|
1826
1929
|
setDoc as setDoc5,
|
|
1827
1930
|
serverTimestamp as serverTimestamp5
|
|
1828
1931
|
} from "firebase/firestore";
|
|
1829
|
-
import { z as
|
|
1932
|
+
import { z as z9 } from "zod";
|
|
1830
1933
|
import { geohashForLocation } from "geofire-common";
|
|
1831
1934
|
var updatePatientLocationUtil = async (db, patientId, latitude, longitude) => {
|
|
1832
1935
|
const locationData = {
|
|
@@ -1865,7 +1968,7 @@ var createLocationInfoUtil = async (db, data, requesterId) => {
|
|
|
1865
1968
|
}
|
|
1866
1969
|
return locationDoc.data();
|
|
1867
1970
|
} catch (error) {
|
|
1868
|
-
if (error instanceof
|
|
1971
|
+
if (error instanceof z9.ZodError) {
|
|
1869
1972
|
throw new Error("Invalid location data: " + error.message);
|
|
1870
1973
|
}
|
|
1871
1974
|
throw error;
|
|
@@ -2378,11 +2481,11 @@ var SubscriptionModel = /* @__PURE__ */ ((SubscriptionModel2) => {
|
|
|
2378
2481
|
})(SubscriptionModel || {});
|
|
2379
2482
|
|
|
2380
2483
|
// src/validations/clinic.schema.ts
|
|
2381
|
-
import { z as
|
|
2484
|
+
import { z as z12 } from "zod";
|
|
2382
2485
|
import { Timestamp as Timestamp6 } from "firebase/firestore";
|
|
2383
2486
|
|
|
2384
2487
|
// src/validations/practitioner.schema.ts
|
|
2385
|
-
import { z as
|
|
2488
|
+
import { z as z11 } from "zod";
|
|
2386
2489
|
import { Timestamp as Timestamp5 } from "firebase/firestore";
|
|
2387
2490
|
|
|
2388
2491
|
// src/backoffice/types/static/certification.types.ts
|
|
@@ -2426,128 +2529,128 @@ var PractitionerTokenStatus = /* @__PURE__ */ ((PractitionerTokenStatus2) => {
|
|
|
2426
2529
|
})(PractitionerTokenStatus || {});
|
|
2427
2530
|
|
|
2428
2531
|
// src/validations/reviews.schema.ts
|
|
2429
|
-
import { z as
|
|
2430
|
-
var baseReviewSchema =
|
|
2431
|
-
id:
|
|
2432
|
-
patientId:
|
|
2433
|
-
fullReviewId:
|
|
2434
|
-
createdAt:
|
|
2435
|
-
updatedAt:
|
|
2436
|
-
comment:
|
|
2437
|
-
isVerified:
|
|
2438
|
-
isPublished:
|
|
2532
|
+
import { z as z10 } from "zod";
|
|
2533
|
+
var baseReviewSchema = z10.object({
|
|
2534
|
+
id: z10.string().min(1),
|
|
2535
|
+
patientId: z10.string().min(1),
|
|
2536
|
+
fullReviewId: z10.string().min(1),
|
|
2537
|
+
createdAt: z10.date(),
|
|
2538
|
+
updatedAt: z10.date(),
|
|
2539
|
+
comment: z10.string().min(1).max(2e3),
|
|
2540
|
+
isVerified: z10.boolean(),
|
|
2541
|
+
isPublished: z10.boolean()
|
|
2439
2542
|
});
|
|
2440
|
-
var baseReviewCreateSchema =
|
|
2441
|
-
patientId:
|
|
2442
|
-
comment:
|
|
2443
|
-
isVerified:
|
|
2444
|
-
isPublished:
|
|
2543
|
+
var baseReviewCreateSchema = z10.object({
|
|
2544
|
+
patientId: z10.string().min(1),
|
|
2545
|
+
comment: z10.string().min(1).max(2e3),
|
|
2546
|
+
isVerified: z10.boolean().default(false),
|
|
2547
|
+
isPublished: z10.boolean().default(true)
|
|
2445
2548
|
});
|
|
2446
2549
|
var clinicReviewSchema = baseReviewSchema.extend({
|
|
2447
|
-
clinicId:
|
|
2448
|
-
cleanliness:
|
|
2449
|
-
facilities:
|
|
2450
|
-
staffFriendliness:
|
|
2451
|
-
waitingTime:
|
|
2452
|
-
accessibility:
|
|
2453
|
-
overallRating:
|
|
2454
|
-
wouldRecommend:
|
|
2550
|
+
clinicId: z10.string().min(1),
|
|
2551
|
+
cleanliness: z10.number().min(1).max(5),
|
|
2552
|
+
facilities: z10.number().min(1).max(5),
|
|
2553
|
+
staffFriendliness: z10.number().min(1).max(5),
|
|
2554
|
+
waitingTime: z10.number().min(1).max(5),
|
|
2555
|
+
accessibility: z10.number().min(1).max(5),
|
|
2556
|
+
overallRating: z10.number().min(1).max(5),
|
|
2557
|
+
wouldRecommend: z10.boolean()
|
|
2455
2558
|
});
|
|
2456
2559
|
var createClinicReviewSchema = baseReviewCreateSchema.extend({
|
|
2457
|
-
clinicId:
|
|
2458
|
-
cleanliness:
|
|
2459
|
-
facilities:
|
|
2460
|
-
staffFriendliness:
|
|
2461
|
-
waitingTime:
|
|
2462
|
-
accessibility:
|
|
2463
|
-
wouldRecommend:
|
|
2560
|
+
clinicId: z10.string().min(1),
|
|
2561
|
+
cleanliness: z10.number().min(1).max(5),
|
|
2562
|
+
facilities: z10.number().min(1).max(5),
|
|
2563
|
+
staffFriendliness: z10.number().min(1).max(5),
|
|
2564
|
+
waitingTime: z10.number().min(1).max(5),
|
|
2565
|
+
accessibility: z10.number().min(1).max(5),
|
|
2566
|
+
wouldRecommend: z10.boolean()
|
|
2464
2567
|
});
|
|
2465
2568
|
var practitionerReviewSchema = baseReviewSchema.extend({
|
|
2466
|
-
practitionerId:
|
|
2467
|
-
knowledgeAndExpertise:
|
|
2468
|
-
communicationSkills:
|
|
2469
|
-
bedSideManner:
|
|
2470
|
-
thoroughness:
|
|
2471
|
-
trustworthiness:
|
|
2472
|
-
overallRating:
|
|
2473
|
-
wouldRecommend:
|
|
2569
|
+
practitionerId: z10.string().min(1),
|
|
2570
|
+
knowledgeAndExpertise: z10.number().min(1).max(5),
|
|
2571
|
+
communicationSkills: z10.number().min(1).max(5),
|
|
2572
|
+
bedSideManner: z10.number().min(1).max(5),
|
|
2573
|
+
thoroughness: z10.number().min(1).max(5),
|
|
2574
|
+
trustworthiness: z10.number().min(1).max(5),
|
|
2575
|
+
overallRating: z10.number().min(1).max(5),
|
|
2576
|
+
wouldRecommend: z10.boolean()
|
|
2474
2577
|
});
|
|
2475
2578
|
var createPractitionerReviewSchema = baseReviewCreateSchema.extend({
|
|
2476
|
-
practitionerId:
|
|
2477
|
-
knowledgeAndExpertise:
|
|
2478
|
-
communicationSkills:
|
|
2479
|
-
bedSideManner:
|
|
2480
|
-
thoroughness:
|
|
2481
|
-
trustworthiness:
|
|
2482
|
-
wouldRecommend:
|
|
2579
|
+
practitionerId: z10.string().min(1),
|
|
2580
|
+
knowledgeAndExpertise: z10.number().min(1).max(5),
|
|
2581
|
+
communicationSkills: z10.number().min(1).max(5),
|
|
2582
|
+
bedSideManner: z10.number().min(1).max(5),
|
|
2583
|
+
thoroughness: z10.number().min(1).max(5),
|
|
2584
|
+
trustworthiness: z10.number().min(1).max(5),
|
|
2585
|
+
wouldRecommend: z10.boolean()
|
|
2483
2586
|
});
|
|
2484
2587
|
var procedureReviewSchema = baseReviewSchema.extend({
|
|
2485
|
-
procedureId:
|
|
2486
|
-
effectivenessOfTreatment:
|
|
2487
|
-
outcomeExplanation:
|
|
2488
|
-
painManagement:
|
|
2489
|
-
followUpCare:
|
|
2490
|
-
valueForMoney:
|
|
2491
|
-
overallRating:
|
|
2492
|
-
wouldRecommend:
|
|
2588
|
+
procedureId: z10.string().min(1),
|
|
2589
|
+
effectivenessOfTreatment: z10.number().min(1).max(5),
|
|
2590
|
+
outcomeExplanation: z10.number().min(1).max(5),
|
|
2591
|
+
painManagement: z10.number().min(1).max(5),
|
|
2592
|
+
followUpCare: z10.number().min(1).max(5),
|
|
2593
|
+
valueForMoney: z10.number().min(1).max(5),
|
|
2594
|
+
overallRating: z10.number().min(1).max(5),
|
|
2595
|
+
wouldRecommend: z10.boolean()
|
|
2493
2596
|
});
|
|
2494
2597
|
var createProcedureReviewSchema = baseReviewCreateSchema.extend({
|
|
2495
|
-
procedureId:
|
|
2496
|
-
effectivenessOfTreatment:
|
|
2497
|
-
outcomeExplanation:
|
|
2498
|
-
painManagement:
|
|
2499
|
-
followUpCare:
|
|
2500
|
-
valueForMoney:
|
|
2501
|
-
wouldRecommend:
|
|
2598
|
+
procedureId: z10.string().min(1),
|
|
2599
|
+
effectivenessOfTreatment: z10.number().min(1).max(5),
|
|
2600
|
+
outcomeExplanation: z10.number().min(1).max(5),
|
|
2601
|
+
painManagement: z10.number().min(1).max(5),
|
|
2602
|
+
followUpCare: z10.number().min(1).max(5),
|
|
2603
|
+
valueForMoney: z10.number().min(1).max(5),
|
|
2604
|
+
wouldRecommend: z10.boolean()
|
|
2502
2605
|
});
|
|
2503
|
-
var clinicReviewInfoSchema =
|
|
2504
|
-
totalReviews:
|
|
2505
|
-
averageRating:
|
|
2506
|
-
cleanliness:
|
|
2507
|
-
facilities:
|
|
2508
|
-
staffFriendliness:
|
|
2509
|
-
waitingTime:
|
|
2510
|
-
accessibility:
|
|
2511
|
-
recommendationPercentage:
|
|
2606
|
+
var clinicReviewInfoSchema = z10.object({
|
|
2607
|
+
totalReviews: z10.number().min(0),
|
|
2608
|
+
averageRating: z10.number().min(0).max(5),
|
|
2609
|
+
cleanliness: z10.number().min(0).max(5),
|
|
2610
|
+
facilities: z10.number().min(0).max(5),
|
|
2611
|
+
staffFriendliness: z10.number().min(0).max(5),
|
|
2612
|
+
waitingTime: z10.number().min(0).max(5),
|
|
2613
|
+
accessibility: z10.number().min(0).max(5),
|
|
2614
|
+
recommendationPercentage: z10.number().min(0).max(100)
|
|
2512
2615
|
});
|
|
2513
|
-
var practitionerReviewInfoSchema =
|
|
2514
|
-
totalReviews:
|
|
2515
|
-
averageRating:
|
|
2516
|
-
knowledgeAndExpertise:
|
|
2517
|
-
communicationSkills:
|
|
2518
|
-
bedSideManner:
|
|
2519
|
-
thoroughness:
|
|
2520
|
-
trustworthiness:
|
|
2521
|
-
recommendationPercentage:
|
|
2616
|
+
var practitionerReviewInfoSchema = z10.object({
|
|
2617
|
+
totalReviews: z10.number().min(0),
|
|
2618
|
+
averageRating: z10.number().min(0).max(5),
|
|
2619
|
+
knowledgeAndExpertise: z10.number().min(0).max(5),
|
|
2620
|
+
communicationSkills: z10.number().min(0).max(5),
|
|
2621
|
+
bedSideManner: z10.number().min(0).max(5),
|
|
2622
|
+
thoroughness: z10.number().min(0).max(5),
|
|
2623
|
+
trustworthiness: z10.number().min(0).max(5),
|
|
2624
|
+
recommendationPercentage: z10.number().min(0).max(100)
|
|
2522
2625
|
});
|
|
2523
|
-
var procedureReviewInfoSchema =
|
|
2524
|
-
totalReviews:
|
|
2525
|
-
averageRating:
|
|
2526
|
-
effectivenessOfTreatment:
|
|
2527
|
-
outcomeExplanation:
|
|
2528
|
-
painManagement:
|
|
2529
|
-
followUpCare:
|
|
2530
|
-
valueForMoney:
|
|
2531
|
-
recommendationPercentage:
|
|
2626
|
+
var procedureReviewInfoSchema = z10.object({
|
|
2627
|
+
totalReviews: z10.number().min(0),
|
|
2628
|
+
averageRating: z10.number().min(0).max(5),
|
|
2629
|
+
effectivenessOfTreatment: z10.number().min(0).max(5),
|
|
2630
|
+
outcomeExplanation: z10.number().min(0).max(5),
|
|
2631
|
+
painManagement: z10.number().min(0).max(5),
|
|
2632
|
+
followUpCare: z10.number().min(0).max(5),
|
|
2633
|
+
valueForMoney: z10.number().min(0).max(5),
|
|
2634
|
+
recommendationPercentage: z10.number().min(0).max(100)
|
|
2532
2635
|
});
|
|
2533
|
-
var reviewSchema =
|
|
2534
|
-
id:
|
|
2535
|
-
appointmentId:
|
|
2536
|
-
patientId:
|
|
2537
|
-
createdAt:
|
|
2538
|
-
updatedAt:
|
|
2636
|
+
var reviewSchema = z10.object({
|
|
2637
|
+
id: z10.string().min(1),
|
|
2638
|
+
appointmentId: z10.string().min(1),
|
|
2639
|
+
patientId: z10.string().min(1),
|
|
2640
|
+
createdAt: z10.date(),
|
|
2641
|
+
updatedAt: z10.date(),
|
|
2539
2642
|
clinicReview: clinicReviewSchema.optional(),
|
|
2540
2643
|
practitionerReview: practitionerReviewSchema.optional(),
|
|
2541
2644
|
procedureReview: procedureReviewSchema.optional(),
|
|
2542
|
-
overallComment:
|
|
2543
|
-
overallRating:
|
|
2645
|
+
overallComment: z10.string().min(1).max(2e3),
|
|
2646
|
+
overallRating: z10.number().min(1).max(5)
|
|
2544
2647
|
});
|
|
2545
|
-
var createReviewSchema =
|
|
2546
|
-
patientId:
|
|
2648
|
+
var createReviewSchema = z10.object({
|
|
2649
|
+
patientId: z10.string().min(1),
|
|
2547
2650
|
clinicReview: createClinicReviewSchema.optional(),
|
|
2548
2651
|
practitionerReview: createPractitionerReviewSchema.optional(),
|
|
2549
2652
|
procedureReview: createProcedureReviewSchema.optional(),
|
|
2550
|
-
overallComment:
|
|
2653
|
+
overallComment: z10.string().min(1).max(2e3)
|
|
2551
2654
|
}).refine(
|
|
2552
2655
|
(data) => {
|
|
2553
2656
|
return data.clinicReview || data.practitionerReview || data.procedureReview;
|
|
@@ -2585,34 +2688,34 @@ var Currency = /* @__PURE__ */ ((Currency2) => {
|
|
|
2585
2688
|
})(Currency || {});
|
|
2586
2689
|
|
|
2587
2690
|
// src/validations/practitioner.schema.ts
|
|
2588
|
-
var practitionerBasicInfoSchema =
|
|
2589
|
-
firstName:
|
|
2590
|
-
lastName:
|
|
2591
|
-
title:
|
|
2592
|
-
email:
|
|
2593
|
-
phoneNumber:
|
|
2594
|
-
dateOfBirth:
|
|
2595
|
-
gender:
|
|
2596
|
-
profileImageUrl:
|
|
2597
|
-
bio:
|
|
2598
|
-
languages:
|
|
2691
|
+
var practitionerBasicInfoSchema = z11.object({
|
|
2692
|
+
firstName: z11.string().min(2).max(50),
|
|
2693
|
+
lastName: z11.string().min(2).max(50),
|
|
2694
|
+
title: z11.string().min(2).max(100),
|
|
2695
|
+
email: z11.string().email(),
|
|
2696
|
+
phoneNumber: z11.string().regex(/^\+?[1-9]\d{1,14}$/, "Invalid phone number"),
|
|
2697
|
+
dateOfBirth: z11.instanceof(Timestamp5).or(z11.date()),
|
|
2698
|
+
gender: z11.enum(["male", "female", "other"]),
|
|
2699
|
+
profileImageUrl: z11.string().url().optional(),
|
|
2700
|
+
bio: z11.string().max(1e3).optional(),
|
|
2701
|
+
languages: z11.array(z11.string()).min(1)
|
|
2599
2702
|
});
|
|
2600
|
-
var practitionerCertificationSchema =
|
|
2601
|
-
level:
|
|
2602
|
-
specialties:
|
|
2603
|
-
licenseNumber:
|
|
2604
|
-
issuingAuthority:
|
|
2605
|
-
issueDate:
|
|
2606
|
-
expiryDate:
|
|
2607
|
-
verificationStatus:
|
|
2703
|
+
var practitionerCertificationSchema = z11.object({
|
|
2704
|
+
level: z11.nativeEnum(CertificationLevel),
|
|
2705
|
+
specialties: z11.array(z11.nativeEnum(CertificationSpecialty)),
|
|
2706
|
+
licenseNumber: z11.string().min(3).max(50),
|
|
2707
|
+
issuingAuthority: z11.string().min(2).max(100),
|
|
2708
|
+
issueDate: z11.instanceof(Timestamp5).or(z11.date()),
|
|
2709
|
+
expiryDate: z11.instanceof(Timestamp5).or(z11.date()).optional(),
|
|
2710
|
+
verificationStatus: z11.enum(["pending", "verified", "rejected"])
|
|
2608
2711
|
});
|
|
2609
|
-
var timeSlotSchema =
|
|
2610
|
-
start:
|
|
2611
|
-
end:
|
|
2712
|
+
var timeSlotSchema = z11.object({
|
|
2713
|
+
start: z11.string().regex(/^([01]\d|2[0-3]):([0-5]\d)$/, "Invalid time format"),
|
|
2714
|
+
end: z11.string().regex(/^([01]\d|2[0-3]):([0-5]\d)$/, "Invalid time format")
|
|
2612
2715
|
}).nullable();
|
|
2613
|
-
var practitionerWorkingHoursSchema =
|
|
2614
|
-
practitionerId:
|
|
2615
|
-
clinicId:
|
|
2716
|
+
var practitionerWorkingHoursSchema = z11.object({
|
|
2717
|
+
practitionerId: z11.string().min(1),
|
|
2718
|
+
clinicId: z11.string().min(1),
|
|
2616
2719
|
monday: timeSlotSchema,
|
|
2617
2720
|
tuesday: timeSlotSchema,
|
|
2618
2721
|
wednesday: timeSlotSchema,
|
|
@@ -2620,12 +2723,12 @@ var practitionerWorkingHoursSchema = z10.object({
|
|
|
2620
2723
|
friday: timeSlotSchema,
|
|
2621
2724
|
saturday: timeSlotSchema,
|
|
2622
2725
|
sunday: timeSlotSchema,
|
|
2623
|
-
createdAt:
|
|
2624
|
-
updatedAt:
|
|
2726
|
+
createdAt: z11.instanceof(Timestamp5).or(z11.date()),
|
|
2727
|
+
updatedAt: z11.instanceof(Timestamp5).or(z11.date())
|
|
2625
2728
|
});
|
|
2626
|
-
var practitionerClinicWorkingHoursSchema =
|
|
2627
|
-
clinicId:
|
|
2628
|
-
workingHours:
|
|
2729
|
+
var practitionerClinicWorkingHoursSchema = z11.object({
|
|
2730
|
+
clinicId: z11.string().min(1),
|
|
2731
|
+
workingHours: z11.object({
|
|
2629
2732
|
monday: timeSlotSchema,
|
|
2630
2733
|
tuesday: timeSlotSchema,
|
|
2631
2734
|
wednesday: timeSlotSchema,
|
|
@@ -2634,114 +2737,114 @@ var practitionerClinicWorkingHoursSchema = z10.object({
|
|
|
2634
2737
|
saturday: timeSlotSchema,
|
|
2635
2738
|
sunday: timeSlotSchema
|
|
2636
2739
|
}),
|
|
2637
|
-
isActive:
|
|
2638
|
-
createdAt:
|
|
2639
|
-
updatedAt:
|
|
2740
|
+
isActive: z11.boolean(),
|
|
2741
|
+
createdAt: z11.instanceof(Timestamp5).or(z11.date()),
|
|
2742
|
+
updatedAt: z11.instanceof(Timestamp5).or(z11.date())
|
|
2640
2743
|
});
|
|
2641
|
-
var procedureSummaryInfoSchema =
|
|
2642
|
-
id:
|
|
2643
|
-
name:
|
|
2644
|
-
description:
|
|
2645
|
-
photo:
|
|
2646
|
-
family:
|
|
2647
|
-
categoryName:
|
|
2648
|
-
subcategoryName:
|
|
2649
|
-
technologyName:
|
|
2650
|
-
price:
|
|
2651
|
-
pricingMeasure:
|
|
2652
|
-
currency:
|
|
2653
|
-
duration:
|
|
2654
|
-
clinicId:
|
|
2655
|
-
clinicName:
|
|
2656
|
-
practitionerId:
|
|
2657
|
-
practitionerName:
|
|
2744
|
+
var procedureSummaryInfoSchema = z11.object({
|
|
2745
|
+
id: z11.string().min(1),
|
|
2746
|
+
name: z11.string().min(1),
|
|
2747
|
+
description: z11.string().optional(),
|
|
2748
|
+
photo: z11.string().optional(),
|
|
2749
|
+
family: z11.nativeEnum(ProcedureFamily),
|
|
2750
|
+
categoryName: z11.string(),
|
|
2751
|
+
subcategoryName: z11.string(),
|
|
2752
|
+
technologyName: z11.string(),
|
|
2753
|
+
price: z11.number().nonnegative(),
|
|
2754
|
+
pricingMeasure: z11.nativeEnum(PricingMeasure),
|
|
2755
|
+
currency: z11.nativeEnum(Currency),
|
|
2756
|
+
duration: z11.number().int().positive(),
|
|
2757
|
+
clinicId: z11.string().min(1),
|
|
2758
|
+
clinicName: z11.string().min(1),
|
|
2759
|
+
practitionerId: z11.string().min(1),
|
|
2760
|
+
practitionerName: z11.string().min(1)
|
|
2658
2761
|
});
|
|
2659
|
-
var practitionerSchema =
|
|
2660
|
-
id:
|
|
2661
|
-
userRef:
|
|
2762
|
+
var practitionerSchema = z11.object({
|
|
2763
|
+
id: z11.string().min(1),
|
|
2764
|
+
userRef: z11.string().min(1),
|
|
2662
2765
|
basicInfo: practitionerBasicInfoSchema,
|
|
2663
2766
|
certification: practitionerCertificationSchema,
|
|
2664
|
-
clinics:
|
|
2665
|
-
clinicWorkingHours:
|
|
2666
|
-
clinicsInfo:
|
|
2667
|
-
procedures:
|
|
2668
|
-
proceduresInfo:
|
|
2767
|
+
clinics: z11.array(z11.string()),
|
|
2768
|
+
clinicWorkingHours: z11.array(practitionerClinicWorkingHoursSchema),
|
|
2769
|
+
clinicsInfo: z11.array(clinicInfoSchema),
|
|
2770
|
+
procedures: z11.array(z11.string()),
|
|
2771
|
+
proceduresInfo: z11.array(procedureSummaryInfoSchema),
|
|
2669
2772
|
reviewInfo: practitionerReviewInfoSchema,
|
|
2670
|
-
isActive:
|
|
2671
|
-
isVerified:
|
|
2672
|
-
status:
|
|
2673
|
-
createdAt:
|
|
2674
|
-
updatedAt:
|
|
2773
|
+
isActive: z11.boolean(),
|
|
2774
|
+
isVerified: z11.boolean(),
|
|
2775
|
+
status: z11.nativeEnum(PractitionerStatus),
|
|
2776
|
+
createdAt: z11.instanceof(Timestamp5).or(z11.date()),
|
|
2777
|
+
updatedAt: z11.instanceof(Timestamp5).or(z11.date())
|
|
2675
2778
|
});
|
|
2676
|
-
var createPractitionerSchema =
|
|
2677
|
-
userRef:
|
|
2779
|
+
var createPractitionerSchema = z11.object({
|
|
2780
|
+
userRef: z11.string().min(1),
|
|
2678
2781
|
basicInfo: practitionerBasicInfoSchema,
|
|
2679
2782
|
certification: practitionerCertificationSchema,
|
|
2680
|
-
clinics:
|
|
2681
|
-
clinicWorkingHours:
|
|
2682
|
-
clinicsInfo:
|
|
2683
|
-
proceduresInfo:
|
|
2684
|
-
isActive:
|
|
2685
|
-
isVerified:
|
|
2686
|
-
status:
|
|
2783
|
+
clinics: z11.array(z11.string()).optional(),
|
|
2784
|
+
clinicWorkingHours: z11.array(practitionerClinicWorkingHoursSchema).optional(),
|
|
2785
|
+
clinicsInfo: z11.array(clinicInfoSchema).optional(),
|
|
2786
|
+
proceduresInfo: z11.array(procedureSummaryInfoSchema).optional(),
|
|
2787
|
+
isActive: z11.boolean(),
|
|
2788
|
+
isVerified: z11.boolean(),
|
|
2789
|
+
status: z11.nativeEnum(PractitionerStatus).optional()
|
|
2687
2790
|
});
|
|
2688
|
-
var createDraftPractitionerSchema =
|
|
2791
|
+
var createDraftPractitionerSchema = z11.object({
|
|
2689
2792
|
basicInfo: practitionerBasicInfoSchema,
|
|
2690
2793
|
certification: practitionerCertificationSchema,
|
|
2691
|
-
clinics:
|
|
2692
|
-
clinicWorkingHours:
|
|
2693
|
-
clinicsInfo:
|
|
2694
|
-
proceduresInfo:
|
|
2695
|
-
isActive:
|
|
2696
|
-
isVerified:
|
|
2794
|
+
clinics: z11.array(z11.string()).optional(),
|
|
2795
|
+
clinicWorkingHours: z11.array(practitionerClinicWorkingHoursSchema).optional(),
|
|
2796
|
+
clinicsInfo: z11.array(clinicInfoSchema).optional(),
|
|
2797
|
+
proceduresInfo: z11.array(procedureSummaryInfoSchema).optional(),
|
|
2798
|
+
isActive: z11.boolean().optional().default(false),
|
|
2799
|
+
isVerified: z11.boolean().optional().default(false)
|
|
2697
2800
|
});
|
|
2698
|
-
var practitionerTokenSchema =
|
|
2699
|
-
id:
|
|
2700
|
-
token:
|
|
2701
|
-
practitionerId:
|
|
2702
|
-
email:
|
|
2703
|
-
clinicId:
|
|
2704
|
-
status:
|
|
2705
|
-
createdBy:
|
|
2706
|
-
createdAt:
|
|
2707
|
-
expiresAt:
|
|
2708
|
-
usedBy:
|
|
2709
|
-
usedAt:
|
|
2801
|
+
var practitionerTokenSchema = z11.object({
|
|
2802
|
+
id: z11.string().min(1),
|
|
2803
|
+
token: z11.string().min(6),
|
|
2804
|
+
practitionerId: z11.string().min(1),
|
|
2805
|
+
email: z11.string().email(),
|
|
2806
|
+
clinicId: z11.string().min(1),
|
|
2807
|
+
status: z11.nativeEnum(PractitionerTokenStatus),
|
|
2808
|
+
createdBy: z11.string().min(1),
|
|
2809
|
+
createdAt: z11.instanceof(Timestamp5).or(z11.date()),
|
|
2810
|
+
expiresAt: z11.instanceof(Timestamp5).or(z11.date()),
|
|
2811
|
+
usedBy: z11.string().optional(),
|
|
2812
|
+
usedAt: z11.instanceof(Timestamp5).or(z11.date()).optional()
|
|
2710
2813
|
});
|
|
2711
|
-
var createPractitionerTokenSchema =
|
|
2712
|
-
practitionerId:
|
|
2713
|
-
email:
|
|
2714
|
-
clinicId:
|
|
2715
|
-
expiresAt:
|
|
2814
|
+
var createPractitionerTokenSchema = z11.object({
|
|
2815
|
+
practitionerId: z11.string().min(1),
|
|
2816
|
+
email: z11.string().email(),
|
|
2817
|
+
clinicId: z11.string().min(1),
|
|
2818
|
+
expiresAt: z11.date().optional()
|
|
2716
2819
|
});
|
|
2717
2820
|
|
|
2718
2821
|
// src/validations/clinic.schema.ts
|
|
2719
|
-
var clinicContactInfoSchema =
|
|
2720
|
-
email:
|
|
2721
|
-
phoneNumber:
|
|
2722
|
-
alternativePhoneNumber:
|
|
2723
|
-
website:
|
|
2822
|
+
var clinicContactInfoSchema = z12.object({
|
|
2823
|
+
email: z12.string().email(),
|
|
2824
|
+
phoneNumber: z12.string(),
|
|
2825
|
+
alternativePhoneNumber: z12.string().nullable().optional(),
|
|
2826
|
+
website: z12.string().nullable().optional()
|
|
2724
2827
|
});
|
|
2725
|
-
var clinicLocationSchema =
|
|
2726
|
-
address:
|
|
2727
|
-
city:
|
|
2728
|
-
country:
|
|
2729
|
-
postalCode:
|
|
2730
|
-
latitude:
|
|
2731
|
-
longitude:
|
|
2732
|
-
geohash:
|
|
2828
|
+
var clinicLocationSchema = z12.object({
|
|
2829
|
+
address: z12.string(),
|
|
2830
|
+
city: z12.string(),
|
|
2831
|
+
country: z12.string(),
|
|
2832
|
+
postalCode: z12.string(),
|
|
2833
|
+
latitude: z12.number().min(-90).max(90),
|
|
2834
|
+
longitude: z12.number().min(-180).max(180),
|
|
2835
|
+
geohash: z12.string().nullable().optional()
|
|
2733
2836
|
});
|
|
2734
|
-
var workingHoursTimeSchema =
|
|
2735
|
-
open:
|
|
2736
|
-
close:
|
|
2737
|
-
breaks:
|
|
2738
|
-
|
|
2739
|
-
start:
|
|
2740
|
-
end:
|
|
2837
|
+
var workingHoursTimeSchema = z12.object({
|
|
2838
|
+
open: z12.string(),
|
|
2839
|
+
close: z12.string(),
|
|
2840
|
+
breaks: z12.array(
|
|
2841
|
+
z12.object({
|
|
2842
|
+
start: z12.string(),
|
|
2843
|
+
end: z12.string()
|
|
2741
2844
|
})
|
|
2742
2845
|
).optional()
|
|
2743
2846
|
});
|
|
2744
|
-
var workingHoursSchema =
|
|
2847
|
+
var workingHoursSchema = z12.object({
|
|
2745
2848
|
monday: workingHoursTimeSchema.nullable(),
|
|
2746
2849
|
tuesday: workingHoursTimeSchema.nullable(),
|
|
2747
2850
|
wednesday: workingHoursTimeSchema.nullable(),
|
|
@@ -2750,235 +2853,235 @@ var workingHoursSchema = z11.object({
|
|
|
2750
2853
|
saturday: workingHoursTimeSchema.nullable(),
|
|
2751
2854
|
sunday: workingHoursTimeSchema.nullable()
|
|
2752
2855
|
});
|
|
2753
|
-
var clinicTagsSchema =
|
|
2754
|
-
tags:
|
|
2856
|
+
var clinicTagsSchema = z12.object({
|
|
2857
|
+
tags: z12.array(z12.nativeEnum(ClinicTag))
|
|
2755
2858
|
});
|
|
2756
|
-
var contactPersonSchema =
|
|
2757
|
-
firstName:
|
|
2758
|
-
lastName:
|
|
2759
|
-
title:
|
|
2760
|
-
email:
|
|
2761
|
-
phoneNumber:
|
|
2859
|
+
var contactPersonSchema = z12.object({
|
|
2860
|
+
firstName: z12.string(),
|
|
2861
|
+
lastName: z12.string(),
|
|
2862
|
+
title: z12.string().nullable().optional(),
|
|
2863
|
+
email: z12.string().email(),
|
|
2864
|
+
phoneNumber: z12.string().nullable().optional()
|
|
2762
2865
|
});
|
|
2763
|
-
var adminInfoSchema =
|
|
2764
|
-
id:
|
|
2765
|
-
name:
|
|
2766
|
-
email:
|
|
2866
|
+
var adminInfoSchema = z12.object({
|
|
2867
|
+
id: z12.string(),
|
|
2868
|
+
name: z12.string(),
|
|
2869
|
+
email: z12.string().email()
|
|
2767
2870
|
});
|
|
2768
|
-
var clinicInfoSchema =
|
|
2769
|
-
id:
|
|
2770
|
-
featuredPhoto:
|
|
2771
|
-
name:
|
|
2772
|
-
description:
|
|
2871
|
+
var clinicInfoSchema = z12.object({
|
|
2872
|
+
id: z12.string(),
|
|
2873
|
+
featuredPhoto: z12.string(),
|
|
2874
|
+
name: z12.string(),
|
|
2875
|
+
description: z12.string().nullable().optional(),
|
|
2773
2876
|
location: clinicLocationSchema,
|
|
2774
2877
|
contactInfo: clinicContactInfoSchema
|
|
2775
2878
|
});
|
|
2776
|
-
var doctorInfoSchema =
|
|
2777
|
-
id:
|
|
2778
|
-
name:
|
|
2779
|
-
description:
|
|
2780
|
-
photo:
|
|
2781
|
-
rating:
|
|
2782
|
-
services:
|
|
2879
|
+
var doctorInfoSchema = z12.object({
|
|
2880
|
+
id: z12.string(),
|
|
2881
|
+
name: z12.string(),
|
|
2882
|
+
description: z12.string().nullable().optional(),
|
|
2883
|
+
photo: z12.string(),
|
|
2884
|
+
rating: z12.number().min(0).max(5),
|
|
2885
|
+
services: z12.array(z12.string())
|
|
2783
2886
|
// List of procedure IDs practitioner offers
|
|
2784
2887
|
});
|
|
2785
|
-
var clinicAdminSchema =
|
|
2786
|
-
id:
|
|
2787
|
-
userRef:
|
|
2788
|
-
clinicGroupId:
|
|
2789
|
-
isGroupOwner:
|
|
2790
|
-
clinicsManaged:
|
|
2791
|
-
clinicsManagedInfo:
|
|
2888
|
+
var clinicAdminSchema = z12.object({
|
|
2889
|
+
id: z12.string(),
|
|
2890
|
+
userRef: z12.string(),
|
|
2891
|
+
clinicGroupId: z12.string(),
|
|
2892
|
+
isGroupOwner: z12.boolean(),
|
|
2893
|
+
clinicsManaged: z12.array(z12.string()),
|
|
2894
|
+
clinicsManagedInfo: z12.array(clinicInfoSchema),
|
|
2792
2895
|
contactInfo: contactPersonSchema,
|
|
2793
|
-
roleTitle:
|
|
2794
|
-
createdAt:
|
|
2795
|
-
updatedAt:
|
|
2796
|
-
isActive:
|
|
2896
|
+
roleTitle: z12.string(),
|
|
2897
|
+
createdAt: z12.instanceof(Date).or(z12.instanceof(Timestamp6)),
|
|
2898
|
+
updatedAt: z12.instanceof(Date).or(z12.instanceof(Timestamp6)),
|
|
2899
|
+
isActive: z12.boolean()
|
|
2797
2900
|
});
|
|
2798
|
-
var adminTokenSchema =
|
|
2799
|
-
id:
|
|
2800
|
-
token:
|
|
2801
|
-
email:
|
|
2802
|
-
status:
|
|
2803
|
-
usedByUserRef:
|
|
2804
|
-
createdAt:
|
|
2901
|
+
var adminTokenSchema = z12.object({
|
|
2902
|
+
id: z12.string(),
|
|
2903
|
+
token: z12.string(),
|
|
2904
|
+
email: z12.string().email().optional().nullable(),
|
|
2905
|
+
status: z12.nativeEnum(AdminTokenStatus),
|
|
2906
|
+
usedByUserRef: z12.string().optional(),
|
|
2907
|
+
createdAt: z12.instanceof(Date).or(z12.instanceof(Timestamp6)),
|
|
2805
2908
|
// Timestamp
|
|
2806
|
-
expiresAt:
|
|
2909
|
+
expiresAt: z12.instanceof(Date).or(z12.instanceof(Timestamp6))
|
|
2807
2910
|
// Timestamp
|
|
2808
2911
|
});
|
|
2809
|
-
var createAdminTokenSchema =
|
|
2810
|
-
expiresInDays:
|
|
2811
|
-
email:
|
|
2912
|
+
var createAdminTokenSchema = z12.object({
|
|
2913
|
+
expiresInDays: z12.number().min(1).max(30).optional(),
|
|
2914
|
+
email: z12.string().email().optional().nullable()
|
|
2812
2915
|
});
|
|
2813
|
-
var clinicGroupSchema =
|
|
2814
|
-
id:
|
|
2815
|
-
name:
|
|
2816
|
-
description:
|
|
2916
|
+
var clinicGroupSchema = z12.object({
|
|
2917
|
+
id: z12.string(),
|
|
2918
|
+
name: z12.string(),
|
|
2919
|
+
description: z12.string().nullable().optional(),
|
|
2817
2920
|
hqLocation: clinicLocationSchema,
|
|
2818
2921
|
contactInfo: clinicContactInfoSchema,
|
|
2819
2922
|
contactPerson: contactPersonSchema,
|
|
2820
|
-
clinics:
|
|
2821
|
-
clinicsInfo:
|
|
2822
|
-
admins:
|
|
2823
|
-
adminsInfo:
|
|
2824
|
-
adminTokens:
|
|
2825
|
-
ownerId:
|
|
2826
|
-
createdAt:
|
|
2923
|
+
clinics: z12.array(z12.string()),
|
|
2924
|
+
clinicsInfo: z12.array(clinicInfoSchema),
|
|
2925
|
+
admins: z12.array(z12.string()),
|
|
2926
|
+
adminsInfo: z12.array(adminInfoSchema),
|
|
2927
|
+
adminTokens: z12.array(adminTokenSchema),
|
|
2928
|
+
ownerId: z12.string().nullable(),
|
|
2929
|
+
createdAt: z12.instanceof(Date).or(z12.instanceof(Timestamp6)),
|
|
2827
2930
|
// Timestamp
|
|
2828
|
-
updatedAt:
|
|
2931
|
+
updatedAt: z12.instanceof(Date).or(z12.instanceof(Timestamp6)),
|
|
2829
2932
|
// Timestamp
|
|
2830
|
-
isActive:
|
|
2831
|
-
logo:
|
|
2832
|
-
practiceType:
|
|
2833
|
-
languages:
|
|
2834
|
-
subscriptionModel:
|
|
2835
|
-
calendarSyncEnabled:
|
|
2836
|
-
autoConfirmAppointments:
|
|
2837
|
-
businessIdentificationNumber:
|
|
2933
|
+
isActive: z12.boolean(),
|
|
2934
|
+
logo: z12.string().optional().nullable(),
|
|
2935
|
+
practiceType: z12.nativeEnum(PracticeType).optional(),
|
|
2936
|
+
languages: z12.array(z12.nativeEnum(Language)).optional(),
|
|
2937
|
+
subscriptionModel: z12.nativeEnum(SubscriptionModel),
|
|
2938
|
+
calendarSyncEnabled: z12.boolean().optional(),
|
|
2939
|
+
autoConfirmAppointments: z12.boolean().optional(),
|
|
2940
|
+
businessIdentificationNumber: z12.string().optional().nullable()
|
|
2838
2941
|
});
|
|
2839
|
-
var clinicSchema =
|
|
2840
|
-
id:
|
|
2841
|
-
clinicGroupId:
|
|
2842
|
-
name:
|
|
2843
|
-
description:
|
|
2942
|
+
var clinicSchema = z12.object({
|
|
2943
|
+
id: z12.string(),
|
|
2944
|
+
clinicGroupId: z12.string(),
|
|
2945
|
+
name: z12.string(),
|
|
2946
|
+
description: z12.string().nullable().optional(),
|
|
2844
2947
|
location: clinicLocationSchema,
|
|
2845
2948
|
contactInfo: clinicContactInfoSchema,
|
|
2846
2949
|
workingHours: workingHoursSchema,
|
|
2847
|
-
tags:
|
|
2848
|
-
featuredPhotos:
|
|
2849
|
-
coverPhoto:
|
|
2850
|
-
photosWithTags:
|
|
2851
|
-
|
|
2852
|
-
url:
|
|
2853
|
-
tag:
|
|
2950
|
+
tags: z12.array(z12.nativeEnum(ClinicTag)),
|
|
2951
|
+
featuredPhotos: z12.array(z12.string()),
|
|
2952
|
+
coverPhoto: z12.string().nullable(),
|
|
2953
|
+
photosWithTags: z12.array(
|
|
2954
|
+
z12.object({
|
|
2955
|
+
url: z12.string(),
|
|
2956
|
+
tag: z12.string()
|
|
2854
2957
|
})
|
|
2855
2958
|
).optional(),
|
|
2856
|
-
doctors:
|
|
2959
|
+
doctors: z12.array(z12.string()),
|
|
2857
2960
|
// List of practitioner IDs
|
|
2858
|
-
doctorsInfo:
|
|
2961
|
+
doctorsInfo: z12.array(doctorInfoSchema),
|
|
2859
2962
|
// Aggregated doctor info
|
|
2860
|
-
procedures:
|
|
2963
|
+
procedures: z12.array(z12.string()),
|
|
2861
2964
|
// List of procedure IDs offered by clinic
|
|
2862
|
-
proceduresInfo:
|
|
2965
|
+
proceduresInfo: z12.array(procedureSummaryInfoSchema),
|
|
2863
2966
|
// Use the correct schema for aggregated procedure info
|
|
2864
2967
|
// services: z.array(z.string()), // Likely deprecated, procedures covers this
|
|
2865
2968
|
// servicesInfo: z.array(serviceInfoSchema), // Deprecated, use proceduresInfo
|
|
2866
2969
|
reviewInfo: clinicReviewInfoSchema,
|
|
2867
|
-
admins:
|
|
2868
|
-
createdAt:
|
|
2970
|
+
admins: z12.array(z12.string()),
|
|
2971
|
+
createdAt: z12.instanceof(Date).or(z12.instanceof(Timestamp6)),
|
|
2869
2972
|
// Timestamp
|
|
2870
|
-
updatedAt:
|
|
2973
|
+
updatedAt: z12.instanceof(Date).or(z12.instanceof(Timestamp6)),
|
|
2871
2974
|
// Timestamp
|
|
2872
|
-
isActive:
|
|
2873
|
-
isVerified:
|
|
2874
|
-
logo:
|
|
2975
|
+
isActive: z12.boolean(),
|
|
2976
|
+
isVerified: z12.boolean(),
|
|
2977
|
+
logo: z12.string().optional()
|
|
2875
2978
|
});
|
|
2876
|
-
var createClinicAdminSchema =
|
|
2877
|
-
userRef:
|
|
2878
|
-
clinicGroupId:
|
|
2879
|
-
isGroupOwner:
|
|
2880
|
-
clinicsManaged:
|
|
2979
|
+
var createClinicAdminSchema = z12.object({
|
|
2980
|
+
userRef: z12.string(),
|
|
2981
|
+
clinicGroupId: z12.string().optional(),
|
|
2982
|
+
isGroupOwner: z12.boolean(),
|
|
2983
|
+
clinicsManaged: z12.array(z12.string()),
|
|
2881
2984
|
contactInfo: contactPersonSchema,
|
|
2882
|
-
roleTitle:
|
|
2883
|
-
isActive:
|
|
2985
|
+
roleTitle: z12.string(),
|
|
2986
|
+
isActive: z12.boolean()
|
|
2884
2987
|
// clinicsManagedInfo is aggregated, not provided on creation
|
|
2885
2988
|
});
|
|
2886
|
-
var createClinicGroupSchema =
|
|
2887
|
-
name:
|
|
2888
|
-
description:
|
|
2989
|
+
var createClinicGroupSchema = z12.object({
|
|
2990
|
+
name: z12.string(),
|
|
2991
|
+
description: z12.string().optional(),
|
|
2889
2992
|
hqLocation: clinicLocationSchema,
|
|
2890
2993
|
contactInfo: clinicContactInfoSchema,
|
|
2891
2994
|
contactPerson: contactPersonSchema,
|
|
2892
|
-
ownerId:
|
|
2893
|
-
isActive:
|
|
2894
|
-
logo:
|
|
2895
|
-
practiceType:
|
|
2896
|
-
languages:
|
|
2897
|
-
subscriptionModel:
|
|
2898
|
-
calendarSyncEnabled:
|
|
2899
|
-
autoConfirmAppointments:
|
|
2900
|
-
businessIdentificationNumber:
|
|
2995
|
+
ownerId: z12.string().nullable(),
|
|
2996
|
+
isActive: z12.boolean(),
|
|
2997
|
+
logo: z12.string().optional().nullable(),
|
|
2998
|
+
practiceType: z12.nativeEnum(PracticeType).optional(),
|
|
2999
|
+
languages: z12.array(z12.nativeEnum(Language)).optional(),
|
|
3000
|
+
subscriptionModel: z12.nativeEnum(SubscriptionModel).optional().default("no_subscription" /* NO_SUBSCRIPTION */),
|
|
3001
|
+
calendarSyncEnabled: z12.boolean().optional(),
|
|
3002
|
+
autoConfirmAppointments: z12.boolean().optional(),
|
|
3003
|
+
businessIdentificationNumber: z12.string().optional().nullable()
|
|
2901
3004
|
// clinics, clinicsInfo, admins, adminsInfo, adminTokens are managed internally
|
|
2902
3005
|
});
|
|
2903
|
-
var createClinicSchema =
|
|
2904
|
-
clinicGroupId:
|
|
2905
|
-
name:
|
|
2906
|
-
description:
|
|
3006
|
+
var createClinicSchema = z12.object({
|
|
3007
|
+
clinicGroupId: z12.string(),
|
|
3008
|
+
name: z12.string(),
|
|
3009
|
+
description: z12.string().optional(),
|
|
2907
3010
|
location: clinicLocationSchema,
|
|
2908
3011
|
contactInfo: clinicContactInfoSchema,
|
|
2909
3012
|
workingHours: workingHoursSchema,
|
|
2910
|
-
tags:
|
|
2911
|
-
coverPhoto:
|
|
2912
|
-
photosWithTags:
|
|
2913
|
-
|
|
2914
|
-
url:
|
|
2915
|
-
tag:
|
|
3013
|
+
tags: z12.array(z12.nativeEnum(ClinicTag)),
|
|
3014
|
+
coverPhoto: z12.string().nullable(),
|
|
3015
|
+
photosWithTags: z12.array(
|
|
3016
|
+
z12.object({
|
|
3017
|
+
url: z12.string(),
|
|
3018
|
+
tag: z12.string()
|
|
2916
3019
|
})
|
|
2917
3020
|
).optional(),
|
|
2918
3021
|
// doctors, doctorsInfo, procedures, proceduresInfo are managed internally/aggregated
|
|
2919
3022
|
// doctors: z.array(z.string()),
|
|
2920
3023
|
// services: z.array(z.string()), // Deprecated
|
|
2921
|
-
admins:
|
|
3024
|
+
admins: z12.array(z12.string()),
|
|
2922
3025
|
// Should likely just be creator ID initially
|
|
2923
|
-
isActive:
|
|
2924
|
-
isVerified:
|
|
2925
|
-
logo:
|
|
2926
|
-
featuredPhotos:
|
|
3026
|
+
isActive: z12.boolean(),
|
|
3027
|
+
isVerified: z12.boolean(),
|
|
3028
|
+
logo: z12.string().optional(),
|
|
3029
|
+
featuredPhotos: z12.array(z12.string()).optional()
|
|
2927
3030
|
});
|
|
2928
|
-
var createDefaultClinicGroupSchema =
|
|
2929
|
-
name:
|
|
2930
|
-
ownerId:
|
|
3031
|
+
var createDefaultClinicGroupSchema = z12.object({
|
|
3032
|
+
name: z12.string(),
|
|
3033
|
+
ownerId: z12.string().nullable(),
|
|
2931
3034
|
contactPerson: contactPersonSchema,
|
|
2932
3035
|
contactInfo: clinicContactInfoSchema,
|
|
2933
3036
|
hqLocation: clinicLocationSchema,
|
|
2934
|
-
isActive:
|
|
2935
|
-
logo:
|
|
2936
|
-
practiceType:
|
|
2937
|
-
languages:
|
|
2938
|
-
subscriptionModel:
|
|
3037
|
+
isActive: z12.boolean(),
|
|
3038
|
+
logo: z12.string().optional().nullable(),
|
|
3039
|
+
practiceType: z12.nativeEnum(PracticeType).optional(),
|
|
3040
|
+
languages: z12.array(z12.nativeEnum(Language)).optional(),
|
|
3041
|
+
subscriptionModel: z12.nativeEnum(SubscriptionModel).optional().default("no_subscription" /* NO_SUBSCRIPTION */)
|
|
2939
3042
|
});
|
|
2940
|
-
var clinicAdminSignupSchema =
|
|
2941
|
-
email:
|
|
2942
|
-
password:
|
|
2943
|
-
firstName:
|
|
2944
|
-
lastName:
|
|
2945
|
-
title:
|
|
2946
|
-
phoneNumber:
|
|
2947
|
-
isCreatingNewGroup:
|
|
2948
|
-
inviteToken:
|
|
2949
|
-
clinicGroupData:
|
|
2950
|
-
name:
|
|
3043
|
+
var clinicAdminSignupSchema = z12.object({
|
|
3044
|
+
email: z12.string().email(),
|
|
3045
|
+
password: z12.string().min(8),
|
|
3046
|
+
firstName: z12.string(),
|
|
3047
|
+
lastName: z12.string(),
|
|
3048
|
+
title: z12.string(),
|
|
3049
|
+
phoneNumber: z12.string(),
|
|
3050
|
+
isCreatingNewGroup: z12.boolean(),
|
|
3051
|
+
inviteToken: z12.string().optional(),
|
|
3052
|
+
clinicGroupData: z12.object({
|
|
3053
|
+
name: z12.string(),
|
|
2951
3054
|
hqLocation: clinicLocationSchema,
|
|
2952
|
-
logo:
|
|
3055
|
+
logo: z12.string().optional(),
|
|
2953
3056
|
contactInfo: clinicContactInfoSchema,
|
|
2954
|
-
subscriptionModel:
|
|
3057
|
+
subscriptionModel: z12.nativeEnum(SubscriptionModel).optional().default("no_subscription" /* NO_SUBSCRIPTION */)
|
|
2955
3058
|
}).optional()
|
|
2956
3059
|
});
|
|
2957
|
-
var clinicGroupSetupSchema =
|
|
2958
|
-
languages:
|
|
2959
|
-
practiceType:
|
|
2960
|
-
description:
|
|
2961
|
-
logo:
|
|
2962
|
-
calendarSyncEnabled:
|
|
2963
|
-
autoConfirmAppointments:
|
|
2964
|
-
businessIdentificationNumber:
|
|
3060
|
+
var clinicGroupSetupSchema = z12.object({
|
|
3061
|
+
languages: z12.array(z12.nativeEnum(Language)),
|
|
3062
|
+
practiceType: z12.nativeEnum(PracticeType),
|
|
3063
|
+
description: z12.string(),
|
|
3064
|
+
logo: z12.string(),
|
|
3065
|
+
calendarSyncEnabled: z12.boolean(),
|
|
3066
|
+
autoConfirmAppointments: z12.boolean(),
|
|
3067
|
+
businessIdentificationNumber: z12.string().optional().nullable()
|
|
2965
3068
|
});
|
|
2966
|
-
var clinicBranchSetupSchema =
|
|
2967
|
-
name:
|
|
3069
|
+
var clinicBranchSetupSchema = z12.object({
|
|
3070
|
+
name: z12.string(),
|
|
2968
3071
|
location: clinicLocationSchema,
|
|
2969
|
-
description:
|
|
3072
|
+
description: z12.string().optional(),
|
|
2970
3073
|
contactInfo: clinicContactInfoSchema,
|
|
2971
3074
|
workingHours: workingHoursSchema,
|
|
2972
|
-
tags:
|
|
2973
|
-
logo:
|
|
2974
|
-
coverPhoto:
|
|
2975
|
-
photosWithTags:
|
|
2976
|
-
|
|
2977
|
-
url:
|
|
2978
|
-
tag:
|
|
3075
|
+
tags: z12.array(z12.nativeEnum(ClinicTag)),
|
|
3076
|
+
logo: z12.string().optional(),
|
|
3077
|
+
coverPhoto: z12.string().nullable(),
|
|
3078
|
+
photosWithTags: z12.array(
|
|
3079
|
+
z12.object({
|
|
3080
|
+
url: z12.string(),
|
|
3081
|
+
tag: z12.string()
|
|
2979
3082
|
})
|
|
2980
3083
|
).optional(),
|
|
2981
|
-
featuredPhotos:
|
|
3084
|
+
featuredPhotos: z12.array(z12.string()).optional()
|
|
2982
3085
|
});
|
|
2983
3086
|
var updateClinicAdminSchema = createClinicAdminSchema.partial();
|
|
2984
3087
|
var updateClinicGroupSchema = createClinicGroupSchema.partial();
|
|
@@ -3165,7 +3268,7 @@ async function getClinicAdminsByGroup(db, clinicGroupId) {
|
|
|
3165
3268
|
where3("clinicGroupId", "==", clinicGroupId)
|
|
3166
3269
|
);
|
|
3167
3270
|
const querySnapshot = await getDocs3(q);
|
|
3168
|
-
return querySnapshot.docs.map((
|
|
3271
|
+
return querySnapshot.docs.map((doc30) => doc30.data());
|
|
3169
3272
|
}
|
|
3170
3273
|
async function updateClinicAdmin(db, adminId, data) {
|
|
3171
3274
|
const admin = await getClinicAdmin(db, adminId);
|
|
@@ -3447,7 +3550,7 @@ import {
|
|
|
3447
3550
|
arrayUnion as arrayUnion5,
|
|
3448
3551
|
arrayRemove as arrayRemove4
|
|
3449
3552
|
} from "firebase/firestore";
|
|
3450
|
-
import { z as
|
|
3553
|
+
import { z as z13 } from "zod";
|
|
3451
3554
|
import { distanceBetween } from "geofire-common";
|
|
3452
3555
|
var PractitionerService = class extends BaseService {
|
|
3453
3556
|
constructor(db, auth, app, clinicService) {
|
|
@@ -3516,7 +3619,7 @@ var PractitionerService = class extends BaseService {
|
|
|
3516
3619
|
}
|
|
3517
3620
|
return createdPractitioner;
|
|
3518
3621
|
} catch (error) {
|
|
3519
|
-
if (error instanceof
|
|
3622
|
+
if (error instanceof z13.ZodError) {
|
|
3520
3623
|
throw new Error(`Invalid practitioner data: ${error.message}`);
|
|
3521
3624
|
}
|
|
3522
3625
|
console.error("Error creating practitioner:", error);
|
|
@@ -3612,7 +3715,7 @@ var PractitionerService = class extends BaseService {
|
|
|
3612
3715
|
await setDoc7(doc6(this.db, tokenPath), token);
|
|
3613
3716
|
return { practitioner: savedPractitioner, token };
|
|
3614
3717
|
} catch (error) {
|
|
3615
|
-
if (error instanceof
|
|
3718
|
+
if (error instanceof z13.ZodError) {
|
|
3616
3719
|
throw new Error("Invalid practitioner data: " + error.message);
|
|
3617
3720
|
}
|
|
3618
3721
|
throw error;
|
|
@@ -3665,7 +3768,7 @@ var PractitionerService = class extends BaseService {
|
|
|
3665
3768
|
await setDoc7(doc6(this.db, tokenPath), token);
|
|
3666
3769
|
return token;
|
|
3667
3770
|
} catch (error) {
|
|
3668
|
-
if (error instanceof
|
|
3771
|
+
if (error instanceof z13.ZodError) {
|
|
3669
3772
|
throw new Error("Invalid token data: " + error.message);
|
|
3670
3773
|
}
|
|
3671
3774
|
throw error;
|
|
@@ -3687,7 +3790,7 @@ var PractitionerService = class extends BaseService {
|
|
|
3687
3790
|
where4("expiresAt", ">", Timestamp8.now())
|
|
3688
3791
|
);
|
|
3689
3792
|
const querySnapshot = await getDocs4(q);
|
|
3690
|
-
return querySnapshot.docs.map((
|
|
3793
|
+
return querySnapshot.docs.map((doc30) => doc30.data());
|
|
3691
3794
|
}
|
|
3692
3795
|
/**
|
|
3693
3796
|
* Gets a token by its string value and validates it
|
|
@@ -3770,7 +3873,7 @@ var PractitionerService = class extends BaseService {
|
|
|
3770
3873
|
where4("status", "==", "active" /* ACTIVE */)
|
|
3771
3874
|
);
|
|
3772
3875
|
const querySnapshot = await getDocs4(q);
|
|
3773
|
-
return querySnapshot.docs.map((
|
|
3876
|
+
return querySnapshot.docs.map((doc30) => doc30.data());
|
|
3774
3877
|
}
|
|
3775
3878
|
/**
|
|
3776
3879
|
* Dohvata sve zdravstvene radnike za određenu kliniku
|
|
@@ -3782,7 +3885,7 @@ var PractitionerService = class extends BaseService {
|
|
|
3782
3885
|
where4("isActive", "==", true)
|
|
3783
3886
|
);
|
|
3784
3887
|
const querySnapshot = await getDocs4(q);
|
|
3785
|
-
return querySnapshot.docs.map((
|
|
3888
|
+
return querySnapshot.docs.map((doc30) => doc30.data());
|
|
3786
3889
|
}
|
|
3787
3890
|
/**
|
|
3788
3891
|
* Dohvata sve draft zdravstvene radnike za određenu kliniku sa statusom DRAFT
|
|
@@ -3794,7 +3897,7 @@ var PractitionerService = class extends BaseService {
|
|
|
3794
3897
|
where4("status", "==", "draft" /* DRAFT */)
|
|
3795
3898
|
);
|
|
3796
3899
|
const querySnapshot = await getDocs4(q);
|
|
3797
|
-
return querySnapshot.docs.map((
|
|
3900
|
+
return querySnapshot.docs.map((doc30) => doc30.data());
|
|
3798
3901
|
}
|
|
3799
3902
|
/**
|
|
3800
3903
|
* Updates a practitioner
|
|
@@ -3825,7 +3928,7 @@ var PractitionerService = class extends BaseService {
|
|
|
3825
3928
|
}
|
|
3826
3929
|
return updatedPractitioner;
|
|
3827
3930
|
} catch (error) {
|
|
3828
|
-
if (error instanceof
|
|
3931
|
+
if (error instanceof z13.ZodError) {
|
|
3829
3932
|
throw new Error(`Invalid practitioner update data: ${error.message}`);
|
|
3830
3933
|
}
|
|
3831
3934
|
console.error(`Error updating practitioner ${practitionerId}:`, error);
|
|
@@ -3976,7 +4079,7 @@ var PractitionerService = class extends BaseService {
|
|
|
3976
4079
|
);
|
|
3977
4080
|
const querySnapshot = await getDocs4(q);
|
|
3978
4081
|
const practitioners = querySnapshot.docs.map(
|
|
3979
|
-
(
|
|
4082
|
+
(doc30) => doc30.data()
|
|
3980
4083
|
);
|
|
3981
4084
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
3982
4085
|
return {
|
|
@@ -4047,8 +4150,8 @@ var PractitionerService = class extends BaseService {
|
|
|
4047
4150
|
console.log(
|
|
4048
4151
|
`[PRACTITIONER_SERVICE] Found ${querySnapshot.docs.length} practitioners with base query`
|
|
4049
4152
|
);
|
|
4050
|
-
let practitioners = querySnapshot.docs.map((
|
|
4051
|
-
return { ...
|
|
4153
|
+
let practitioners = querySnapshot.docs.map((doc30) => {
|
|
4154
|
+
return { ...doc30.data(), id: doc30.id };
|
|
4052
4155
|
});
|
|
4053
4156
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
4054
4157
|
if (filters.nameSearch && filters.nameSearch.trim() !== "") {
|
|
@@ -4302,7 +4405,7 @@ var UserService = class extends BaseService {
|
|
|
4302
4405
|
];
|
|
4303
4406
|
const q = query5(collection5(this.db, USERS_COLLECTION), ...constraints);
|
|
4304
4407
|
const querySnapshot = await getDocs5(q);
|
|
4305
|
-
const users = querySnapshot.docs.map((
|
|
4408
|
+
const users = querySnapshot.docs.map((doc30) => doc30.data());
|
|
4306
4409
|
return Promise.all(users.map((userData) => userSchema.parse(userData)));
|
|
4307
4410
|
}
|
|
4308
4411
|
/**
|
|
@@ -4353,7 +4456,7 @@ var UserService = class extends BaseService {
|
|
|
4353
4456
|
});
|
|
4354
4457
|
return this.getUserById(uid);
|
|
4355
4458
|
} catch (error) {
|
|
4356
|
-
if (error instanceof
|
|
4459
|
+
if (error instanceof z14.ZodError) {
|
|
4357
4460
|
throw USER_ERRORS.VALIDATION_ERROR;
|
|
4358
4461
|
}
|
|
4359
4462
|
throw error;
|
|
@@ -4450,7 +4553,7 @@ import {
|
|
|
4450
4553
|
Timestamp as Timestamp10
|
|
4451
4554
|
} from "firebase/firestore";
|
|
4452
4555
|
import { geohashForLocation as geohashForLocation2 } from "geofire-common";
|
|
4453
|
-
import { z as
|
|
4556
|
+
import { z as z15 } from "zod";
|
|
4454
4557
|
|
|
4455
4558
|
// src/services/clinic/utils/photos.utils.ts
|
|
4456
4559
|
import {
|
|
@@ -4654,7 +4757,7 @@ async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdm
|
|
|
4654
4757
|
});
|
|
4655
4758
|
return groupData;
|
|
4656
4759
|
} catch (error) {
|
|
4657
|
-
if (error instanceof
|
|
4760
|
+
if (error instanceof z15.ZodError) {
|
|
4658
4761
|
console.error(
|
|
4659
4762
|
"[CLINIC_GROUP] Zod validation error:",
|
|
4660
4763
|
JSON.stringify(error.errors, null, 2)
|
|
@@ -4682,7 +4785,7 @@ async function getAllActiveGroups(db) {
|
|
|
4682
4785
|
where6("isActive", "==", true)
|
|
4683
4786
|
);
|
|
4684
4787
|
const querySnapshot = await getDocs6(q);
|
|
4685
|
-
return querySnapshot.docs.map((
|
|
4788
|
+
return querySnapshot.docs.map((doc30) => doc30.data());
|
|
4686
4789
|
}
|
|
4687
4790
|
async function updateClinicGroup(db, groupId, data, app) {
|
|
4688
4791
|
console.log("[CLINIC_GROUP] Updating clinic group", { groupId });
|
|
@@ -5069,7 +5172,7 @@ import {
|
|
|
5069
5172
|
import {
|
|
5070
5173
|
geohashForLocation as geohashForLocation4
|
|
5071
5174
|
} from "geofire-common";
|
|
5072
|
-
import { z as
|
|
5175
|
+
import { z as z17 } from "zod";
|
|
5073
5176
|
|
|
5074
5177
|
// src/services/clinic/utils/clinic.utils.ts
|
|
5075
5178
|
import {
|
|
@@ -5090,7 +5193,7 @@ import {
|
|
|
5090
5193
|
distanceBetween as distanceBetween2,
|
|
5091
5194
|
geohashQueryBounds
|
|
5092
5195
|
} from "geofire-common";
|
|
5093
|
-
import { z as
|
|
5196
|
+
import { z as z16 } from "zod";
|
|
5094
5197
|
async function getClinic(db, clinicId) {
|
|
5095
5198
|
const docRef = doc9(db, CLINICS_COLLECTION, clinicId);
|
|
5096
5199
|
const docSnap = await getDoc12(docRef);
|
|
@@ -5106,7 +5209,7 @@ async function getClinicsByGroup(db, groupId) {
|
|
|
5106
5209
|
where7("isActive", "==", true)
|
|
5107
5210
|
);
|
|
5108
5211
|
const querySnapshot = await getDocs7(q);
|
|
5109
|
-
return querySnapshot.docs.map((
|
|
5212
|
+
return querySnapshot.docs.map((doc30) => doc30.data());
|
|
5110
5213
|
}
|
|
5111
5214
|
async function updateClinic(db, clinicId, data, adminId, clinicAdminService, app) {
|
|
5112
5215
|
console.log("[CLINIC] Starting clinic update", { clinicId, adminId });
|
|
@@ -5300,7 +5403,7 @@ async function getClinicsByAdmin(db, adminId, options = {}, clinicAdminService,
|
|
|
5300
5403
|
}
|
|
5301
5404
|
const q = query7(collection7(db, CLINICS_COLLECTION), ...constraints);
|
|
5302
5405
|
const querySnapshot = await getDocs7(q);
|
|
5303
|
-
return querySnapshot.docs.map((
|
|
5406
|
+
return querySnapshot.docs.map((doc30) => doc30.data());
|
|
5304
5407
|
}
|
|
5305
5408
|
async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGroupService) {
|
|
5306
5409
|
return getClinicsByAdmin(
|
|
@@ -5345,11 +5448,11 @@ async function getAllClinics(db, pagination, lastDoc) {
|
|
|
5345
5448
|
}
|
|
5346
5449
|
const clinicsSnapshot = await getDocs7(clinicsQuery);
|
|
5347
5450
|
const lastVisible = clinicsSnapshot.docs[clinicsSnapshot.docs.length - 1];
|
|
5348
|
-
const clinics = clinicsSnapshot.docs.map((
|
|
5349
|
-
const data =
|
|
5451
|
+
const clinics = clinicsSnapshot.docs.map((doc30) => {
|
|
5452
|
+
const data = doc30.data();
|
|
5350
5453
|
return {
|
|
5351
5454
|
...data,
|
|
5352
|
-
id:
|
|
5455
|
+
id: doc30.id
|
|
5353
5456
|
};
|
|
5354
5457
|
});
|
|
5355
5458
|
return {
|
|
@@ -5376,8 +5479,8 @@ async function getAllClinicsInRange(db, center, rangeInKm, pagination, lastDoc)
|
|
|
5376
5479
|
];
|
|
5377
5480
|
const q = query7(collection7(db, CLINICS_COLLECTION), ...constraints);
|
|
5378
5481
|
const querySnapshot = await getDocs7(q);
|
|
5379
|
-
for (const
|
|
5380
|
-
const clinic =
|
|
5482
|
+
for (const doc30 of querySnapshot.docs) {
|
|
5483
|
+
const clinic = doc30.data();
|
|
5381
5484
|
const distance = distanceBetween2(
|
|
5382
5485
|
[center.latitude, center.longitude],
|
|
5383
5486
|
[clinic.location.latitude, clinic.location.longitude]
|
|
@@ -5499,8 +5602,8 @@ async function findClinicsInRadius(db, center, radiusInKm, filters) {
|
|
|
5499
5602
|
}
|
|
5500
5603
|
const q = query8(collection8(db, CLINICS_COLLECTION), ...constraints);
|
|
5501
5604
|
const querySnapshot = await getDocs8(q);
|
|
5502
|
-
for (const
|
|
5503
|
-
const clinic =
|
|
5605
|
+
for (const doc30 of querySnapshot.docs) {
|
|
5606
|
+
const clinic = doc30.data();
|
|
5504
5607
|
const distance = distanceBetween3(
|
|
5505
5608
|
[center.latitude, center.longitude],
|
|
5506
5609
|
[clinic.location.latitude, clinic.location.longitude]
|
|
@@ -5596,8 +5699,8 @@ async function getClinicsByFilters(db, filters) {
|
|
|
5596
5699
|
console.log(
|
|
5597
5700
|
`[FILTER_UTILS] Found ${querySnapshot.docs.length} clinics in geo bound`
|
|
5598
5701
|
);
|
|
5599
|
-
for (const
|
|
5600
|
-
const clinic = { ...
|
|
5702
|
+
for (const doc30 of querySnapshot.docs) {
|
|
5703
|
+
const clinic = { ...doc30.data(), id: doc30.id };
|
|
5601
5704
|
const distance = distanceBetween4(
|
|
5602
5705
|
[center.latitude, center.longitude],
|
|
5603
5706
|
[clinic.location.latitude, clinic.location.longitude]
|
|
@@ -5653,8 +5756,8 @@ async function getClinicsByFilters(db, filters) {
|
|
|
5653
5756
|
console.log(
|
|
5654
5757
|
`[FILTER_UTILS] Found ${querySnapshot.docs.length} clinics with regular query`
|
|
5655
5758
|
);
|
|
5656
|
-
const clinics = querySnapshot.docs.map((
|
|
5657
|
-
return { ...
|
|
5759
|
+
const clinics = querySnapshot.docs.map((doc30) => {
|
|
5760
|
+
return { ...doc30.data(), id: doc30.id };
|
|
5658
5761
|
});
|
|
5659
5762
|
let filteredClinics = clinics;
|
|
5660
5763
|
if (filters.center) {
|
|
@@ -5775,7 +5878,7 @@ var ClinicService = class extends BaseService {
|
|
|
5775
5878
|
if (!savedClinic) throw new Error("Failed to retrieve created clinic");
|
|
5776
5879
|
return savedClinic;
|
|
5777
5880
|
} catch (error) {
|
|
5778
|
-
if (error instanceof
|
|
5881
|
+
if (error instanceof z17.ZodError) {
|
|
5779
5882
|
throw new Error("Invalid clinic data: " + error.message);
|
|
5780
5883
|
}
|
|
5781
5884
|
console.error("Error creating clinic:", error);
|
|
@@ -5823,7 +5926,7 @@ var ClinicService = class extends BaseService {
|
|
|
5823
5926
|
if (!updatedClinic) throw new Error("Failed to retrieve updated clinic");
|
|
5824
5927
|
return updatedClinic;
|
|
5825
5928
|
} catch (error) {
|
|
5826
|
-
if (error instanceof
|
|
5929
|
+
if (error instanceof z17.ZodError) {
|
|
5827
5930
|
throw new Error(
|
|
5828
5931
|
"Invalid clinic update data: " + error.errors.map((e) => `${e.path.join(".")} - ${e.message}`).join(", ")
|
|
5829
5932
|
);
|
|
@@ -6282,7 +6385,7 @@ var AuthService = class extends BaseService {
|
|
|
6282
6385
|
clinicAdmin: adminProfile
|
|
6283
6386
|
};
|
|
6284
6387
|
} catch (error) {
|
|
6285
|
-
if (error instanceof
|
|
6388
|
+
if (error instanceof z18.ZodError) {
|
|
6286
6389
|
console.error(
|
|
6287
6390
|
"[AUTH] Zod validation error in signUpClinicAdmin:",
|
|
6288
6391
|
JSON.stringify(error.errors, null, 2)
|
|
@@ -6455,7 +6558,7 @@ var AuthService = class extends BaseService {
|
|
|
6455
6558
|
email
|
|
6456
6559
|
);
|
|
6457
6560
|
} catch (error) {
|
|
6458
|
-
if (error instanceof
|
|
6561
|
+
if (error instanceof z18.ZodError) {
|
|
6459
6562
|
throw AUTH_ERRORS.VALIDATION_ERROR;
|
|
6460
6563
|
}
|
|
6461
6564
|
const firebaseError = error;
|
|
@@ -6578,7 +6681,7 @@ var AuthService = class extends BaseService {
|
|
|
6578
6681
|
await emailSchema.parseAsync(email);
|
|
6579
6682
|
await sendPasswordResetEmail(this.auth, email);
|
|
6580
6683
|
} catch (error) {
|
|
6581
|
-
if (error instanceof
|
|
6684
|
+
if (error instanceof z18.ZodError) {
|
|
6582
6685
|
throw AUTH_ERRORS.VALIDATION_ERROR;
|
|
6583
6686
|
}
|
|
6584
6687
|
const firebaseError = error;
|
|
@@ -6617,7 +6720,7 @@ var AuthService = class extends BaseService {
|
|
|
6617
6720
|
await passwordSchema.parseAsync(newPassword);
|
|
6618
6721
|
await confirmPasswordReset(this.auth, oobCode, newPassword);
|
|
6619
6722
|
} catch (error) {
|
|
6620
|
-
if (error instanceof
|
|
6723
|
+
if (error instanceof z18.ZodError) {
|
|
6621
6724
|
throw AUTH_ERRORS.VALIDATION_ERROR;
|
|
6622
6725
|
}
|
|
6623
6726
|
const firebaseError = error;
|
|
@@ -6717,9 +6820,9 @@ var NotificationService = class extends BaseService {
|
|
|
6717
6820
|
orderBy3("notificationTime", "desc")
|
|
6718
6821
|
);
|
|
6719
6822
|
const querySnapshot = await getDocs12(q);
|
|
6720
|
-
return querySnapshot.docs.map((
|
|
6721
|
-
id:
|
|
6722
|
-
...
|
|
6823
|
+
return querySnapshot.docs.map((doc30) => ({
|
|
6824
|
+
id: doc30.id,
|
|
6825
|
+
...doc30.data()
|
|
6723
6826
|
}));
|
|
6724
6827
|
}
|
|
6725
6828
|
/**
|
|
@@ -6733,9 +6836,9 @@ var NotificationService = class extends BaseService {
|
|
|
6733
6836
|
orderBy3("notificationTime", "desc")
|
|
6734
6837
|
);
|
|
6735
6838
|
const querySnapshot = await getDocs12(q);
|
|
6736
|
-
return querySnapshot.docs.map((
|
|
6737
|
-
id:
|
|
6738
|
-
...
|
|
6839
|
+
return querySnapshot.docs.map((doc30) => ({
|
|
6840
|
+
id: doc30.id,
|
|
6841
|
+
...doc30.data()
|
|
6739
6842
|
}));
|
|
6740
6843
|
}
|
|
6741
6844
|
/**
|
|
@@ -6807,9 +6910,9 @@ var NotificationService = class extends BaseService {
|
|
|
6807
6910
|
orderBy3("notificationTime", "desc")
|
|
6808
6911
|
);
|
|
6809
6912
|
const querySnapshot = await getDocs12(q);
|
|
6810
|
-
return querySnapshot.docs.map((
|
|
6811
|
-
id:
|
|
6812
|
-
...
|
|
6913
|
+
return querySnapshot.docs.map((doc30) => ({
|
|
6914
|
+
id: doc30.id,
|
|
6915
|
+
...doc30.data()
|
|
6813
6916
|
}));
|
|
6814
6917
|
}
|
|
6815
6918
|
/**
|
|
@@ -6822,9 +6925,9 @@ var NotificationService = class extends BaseService {
|
|
|
6822
6925
|
orderBy3("notificationTime", "desc")
|
|
6823
6926
|
);
|
|
6824
6927
|
const querySnapshot = await getDocs12(q);
|
|
6825
|
-
return querySnapshot.docs.map((
|
|
6826
|
-
id:
|
|
6827
|
-
...
|
|
6928
|
+
return querySnapshot.docs.map((doc30) => ({
|
|
6929
|
+
id: doc30.id,
|
|
6930
|
+
...doc30.data()
|
|
6828
6931
|
}));
|
|
6829
6932
|
}
|
|
6830
6933
|
};
|
|
@@ -6850,59 +6953,59 @@ import {
|
|
|
6850
6953
|
var PROCEDURES_COLLECTION = "procedures";
|
|
6851
6954
|
|
|
6852
6955
|
// src/validations/procedure.schema.ts
|
|
6853
|
-
import { z as
|
|
6854
|
-
var createProcedureSchema =
|
|
6855
|
-
name:
|
|
6856
|
-
description:
|
|
6857
|
-
family:
|
|
6858
|
-
categoryId:
|
|
6859
|
-
subcategoryId:
|
|
6860
|
-
technologyId:
|
|
6861
|
-
productId:
|
|
6862
|
-
price:
|
|
6863
|
-
currency:
|
|
6864
|
-
pricingMeasure:
|
|
6865
|
-
duration:
|
|
6956
|
+
import { z as z19 } from "zod";
|
|
6957
|
+
var createProcedureSchema = z19.object({
|
|
6958
|
+
name: z19.string().min(1).max(200),
|
|
6959
|
+
description: z19.string().min(1).max(2e3),
|
|
6960
|
+
family: z19.nativeEnum(ProcedureFamily),
|
|
6961
|
+
categoryId: z19.string().min(1),
|
|
6962
|
+
subcategoryId: z19.string().min(1),
|
|
6963
|
+
technologyId: z19.string().min(1),
|
|
6964
|
+
productId: z19.string().min(1),
|
|
6965
|
+
price: z19.number().min(0),
|
|
6966
|
+
currency: z19.nativeEnum(Currency),
|
|
6967
|
+
pricingMeasure: z19.nativeEnum(PricingMeasure),
|
|
6968
|
+
duration: z19.number().min(1).max(480),
|
|
6866
6969
|
// Max 8 hours
|
|
6867
|
-
practitionerId:
|
|
6868
|
-
clinicBranchId:
|
|
6970
|
+
practitionerId: z19.string().min(1),
|
|
6971
|
+
clinicBranchId: z19.string().min(1)
|
|
6869
6972
|
});
|
|
6870
|
-
var updateProcedureSchema =
|
|
6871
|
-
name:
|
|
6872
|
-
description:
|
|
6873
|
-
price:
|
|
6874
|
-
currency:
|
|
6875
|
-
pricingMeasure:
|
|
6876
|
-
duration:
|
|
6877
|
-
isActive:
|
|
6878
|
-
practitionerId:
|
|
6879
|
-
categoryId:
|
|
6880
|
-
subcategoryId:
|
|
6881
|
-
technologyId:
|
|
6882
|
-
productId:
|
|
6883
|
-
clinicBranchId:
|
|
6973
|
+
var updateProcedureSchema = z19.object({
|
|
6974
|
+
name: z19.string().min(3).max(100).optional(),
|
|
6975
|
+
description: z19.string().min(3).max(1e3).optional(),
|
|
6976
|
+
price: z19.number().min(0).optional(),
|
|
6977
|
+
currency: z19.nativeEnum(Currency).optional(),
|
|
6978
|
+
pricingMeasure: z19.nativeEnum(PricingMeasure).optional(),
|
|
6979
|
+
duration: z19.number().min(0).optional(),
|
|
6980
|
+
isActive: z19.boolean().optional(),
|
|
6981
|
+
practitionerId: z19.string().optional(),
|
|
6982
|
+
categoryId: z19.string().optional(),
|
|
6983
|
+
subcategoryId: z19.string().optional(),
|
|
6984
|
+
technologyId: z19.string().optional(),
|
|
6985
|
+
productId: z19.string().optional(),
|
|
6986
|
+
clinicBranchId: z19.string().optional()
|
|
6884
6987
|
});
|
|
6885
6988
|
var procedureSchema = createProcedureSchema.extend({
|
|
6886
|
-
id:
|
|
6887
|
-
category:
|
|
6989
|
+
id: z19.string().min(1),
|
|
6990
|
+
category: z19.any(),
|
|
6888
6991
|
// We'll validate the full category object separately
|
|
6889
|
-
subcategory:
|
|
6992
|
+
subcategory: z19.any(),
|
|
6890
6993
|
// We'll validate the full subcategory object separately
|
|
6891
|
-
technology:
|
|
6994
|
+
technology: z19.any(),
|
|
6892
6995
|
// We'll validate the full technology object separately
|
|
6893
|
-
product:
|
|
6996
|
+
product: z19.any(),
|
|
6894
6997
|
// We'll validate the full product object separately
|
|
6895
|
-
blockingConditions:
|
|
6998
|
+
blockingConditions: z19.array(z19.any()),
|
|
6896
6999
|
// We'll validate blocking conditions separately
|
|
6897
|
-
treatmentBenefits:
|
|
7000
|
+
treatmentBenefits: z19.array(z19.any()),
|
|
6898
7001
|
// We'll validate treatment benefits separately
|
|
6899
|
-
preRequirements:
|
|
7002
|
+
preRequirements: z19.array(z19.any()),
|
|
6900
7003
|
// We'll validate requirements separately
|
|
6901
|
-
postRequirements:
|
|
7004
|
+
postRequirements: z19.array(z19.any()),
|
|
6902
7005
|
// We'll validate requirements separately
|
|
6903
|
-
certificationRequirement:
|
|
7006
|
+
certificationRequirement: z19.any(),
|
|
6904
7007
|
// We'll validate certification requirement separately
|
|
6905
|
-
documentationTemplates:
|
|
7008
|
+
documentationTemplates: z19.array(z19.any()),
|
|
6906
7009
|
// We'll validate documentation templates separately
|
|
6907
7010
|
clinicInfo: clinicInfoSchema,
|
|
6908
7011
|
// Clinic info validation
|
|
@@ -6910,9 +7013,9 @@ var procedureSchema = createProcedureSchema.extend({
|
|
|
6910
7013
|
// Doctor info validation
|
|
6911
7014
|
reviewInfo: procedureReviewInfoSchema,
|
|
6912
7015
|
// Procedure review info validation
|
|
6913
|
-
isActive:
|
|
6914
|
-
createdAt:
|
|
6915
|
-
updatedAt:
|
|
7016
|
+
isActive: z19.boolean(),
|
|
7017
|
+
createdAt: z19.date(),
|
|
7018
|
+
updatedAt: z19.date()
|
|
6916
7019
|
});
|
|
6917
7020
|
|
|
6918
7021
|
// src/services/procedure/procedure.service.ts
|
|
@@ -7055,7 +7158,7 @@ var ProcedureService = class extends BaseService {
|
|
|
7055
7158
|
where13("isActive", "==", true)
|
|
7056
7159
|
);
|
|
7057
7160
|
const snapshot = await getDocs13(q);
|
|
7058
|
-
return snapshot.docs.map((
|
|
7161
|
+
return snapshot.docs.map((doc30) => doc30.data());
|
|
7059
7162
|
}
|
|
7060
7163
|
/**
|
|
7061
7164
|
* Gets all procedures for a practitioner
|
|
@@ -7069,7 +7172,7 @@ var ProcedureService = class extends BaseService {
|
|
|
7069
7172
|
where13("isActive", "==", true)
|
|
7070
7173
|
);
|
|
7071
7174
|
const snapshot = await getDocs13(q);
|
|
7072
|
-
return snapshot.docs.map((
|
|
7175
|
+
return snapshot.docs.map((doc30) => doc30.data());
|
|
7073
7176
|
}
|
|
7074
7177
|
/**
|
|
7075
7178
|
* Updates a procedure
|
|
@@ -7252,20 +7355,20 @@ var ProcedureService = class extends BaseService {
|
|
|
7252
7355
|
const proceduresCollection = collection13(this.db, PROCEDURES_COLLECTION);
|
|
7253
7356
|
let proceduresQuery = query13(proceduresCollection);
|
|
7254
7357
|
if (pagination && pagination > 0) {
|
|
7255
|
-
const { limit:
|
|
7358
|
+
const { limit: limit9, startAfter: startAfter9 } = await import("firebase/firestore");
|
|
7256
7359
|
if (lastDoc) {
|
|
7257
7360
|
proceduresQuery = query13(
|
|
7258
7361
|
proceduresCollection,
|
|
7259
7362
|
orderBy4("name"),
|
|
7260
7363
|
// Use imported orderBy
|
|
7261
|
-
|
|
7262
|
-
|
|
7364
|
+
startAfter9(lastDoc),
|
|
7365
|
+
limit9(pagination)
|
|
7263
7366
|
);
|
|
7264
7367
|
} else {
|
|
7265
7368
|
proceduresQuery = query13(
|
|
7266
7369
|
proceduresCollection,
|
|
7267
7370
|
orderBy4("name"),
|
|
7268
|
-
|
|
7371
|
+
limit9(pagination)
|
|
7269
7372
|
);
|
|
7270
7373
|
}
|
|
7271
7374
|
} else {
|
|
@@ -7273,11 +7376,11 @@ var ProcedureService = class extends BaseService {
|
|
|
7273
7376
|
}
|
|
7274
7377
|
const proceduresSnapshot = await getDocs13(proceduresQuery);
|
|
7275
7378
|
const lastVisible = proceduresSnapshot.docs[proceduresSnapshot.docs.length - 1];
|
|
7276
|
-
const procedures = proceduresSnapshot.docs.map((
|
|
7277
|
-
const data =
|
|
7379
|
+
const procedures = proceduresSnapshot.docs.map((doc30) => {
|
|
7380
|
+
const data = doc30.data();
|
|
7278
7381
|
return {
|
|
7279
7382
|
...data,
|
|
7280
|
-
id:
|
|
7383
|
+
id: doc30.id
|
|
7281
7384
|
// Ensure ID is present
|
|
7282
7385
|
};
|
|
7283
7386
|
});
|
|
@@ -7359,8 +7462,8 @@ var ProcedureService = class extends BaseService {
|
|
|
7359
7462
|
console.log(
|
|
7360
7463
|
`[PROCEDURE_SERVICE] Found ${querySnapshot.docs.length} procedures in geo bound`
|
|
7361
7464
|
);
|
|
7362
|
-
for (const
|
|
7363
|
-
const procedure = { ...
|
|
7465
|
+
for (const doc30 of querySnapshot.docs) {
|
|
7466
|
+
const procedure = { ...doc30.data(), id: doc30.id };
|
|
7364
7467
|
const distance = distanceBetween6(
|
|
7365
7468
|
[center.latitude, center.longitude],
|
|
7366
7469
|
[
|
|
@@ -7411,8 +7514,8 @@ var ProcedureService = class extends BaseService {
|
|
|
7411
7514
|
console.log(
|
|
7412
7515
|
`[PROCEDURE_SERVICE] Found ${querySnapshot.docs.length} procedures with regular query`
|
|
7413
7516
|
);
|
|
7414
|
-
const procedures = querySnapshot.docs.map((
|
|
7415
|
-
return { ...
|
|
7517
|
+
const procedures = querySnapshot.docs.map((doc30) => {
|
|
7518
|
+
return { ...doc30.data(), id: doc30.id };
|
|
7416
7519
|
});
|
|
7417
7520
|
if (filters.location) {
|
|
7418
7521
|
const center = filters.location;
|
|
@@ -7643,9 +7746,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
7643
7746
|
const querySnapshot = await getDocs14(q);
|
|
7644
7747
|
const templates = [];
|
|
7645
7748
|
let lastVisible = null;
|
|
7646
|
-
querySnapshot.forEach((
|
|
7647
|
-
templates.push(
|
|
7648
|
-
lastVisible =
|
|
7749
|
+
querySnapshot.forEach((doc30) => {
|
|
7750
|
+
templates.push(doc30.data());
|
|
7751
|
+
lastVisible = doc30;
|
|
7649
7752
|
});
|
|
7650
7753
|
return {
|
|
7651
7754
|
templates,
|
|
@@ -7673,9 +7776,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
7673
7776
|
const querySnapshot = await getDocs14(q);
|
|
7674
7777
|
const templates = [];
|
|
7675
7778
|
let lastVisible = null;
|
|
7676
|
-
querySnapshot.forEach((
|
|
7677
|
-
templates.push(
|
|
7678
|
-
lastVisible =
|
|
7779
|
+
querySnapshot.forEach((doc30) => {
|
|
7780
|
+
templates.push(doc30.data());
|
|
7781
|
+
lastVisible = doc30;
|
|
7679
7782
|
});
|
|
7680
7783
|
return {
|
|
7681
7784
|
templates,
|
|
@@ -7702,9 +7805,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
7702
7805
|
const querySnapshot = await getDocs14(q);
|
|
7703
7806
|
const templates = [];
|
|
7704
7807
|
let lastVisible = null;
|
|
7705
|
-
querySnapshot.forEach((
|
|
7706
|
-
templates.push(
|
|
7707
|
-
lastVisible =
|
|
7808
|
+
querySnapshot.forEach((doc30) => {
|
|
7809
|
+
templates.push(doc30.data());
|
|
7810
|
+
lastVisible = doc30;
|
|
7708
7811
|
});
|
|
7709
7812
|
return {
|
|
7710
7813
|
templates,
|
|
@@ -7829,9 +7932,9 @@ var FilledDocumentService = class extends BaseService {
|
|
|
7829
7932
|
const querySnapshot = await getDocs15(q);
|
|
7830
7933
|
const documents = [];
|
|
7831
7934
|
let lastVisible = null;
|
|
7832
|
-
querySnapshot.forEach((
|
|
7833
|
-
documents.push(
|
|
7834
|
-
lastVisible =
|
|
7935
|
+
querySnapshot.forEach((doc30) => {
|
|
7936
|
+
documents.push(doc30.data());
|
|
7937
|
+
lastVisible = doc30;
|
|
7835
7938
|
});
|
|
7836
7939
|
return {
|
|
7837
7940
|
documents,
|
|
@@ -7858,9 +7961,9 @@ var FilledDocumentService = class extends BaseService {
|
|
|
7858
7961
|
const querySnapshot = await getDocs15(q);
|
|
7859
7962
|
const documents = [];
|
|
7860
7963
|
let lastVisible = null;
|
|
7861
|
-
querySnapshot.forEach((
|
|
7862
|
-
documents.push(
|
|
7863
|
-
lastVisible =
|
|
7964
|
+
querySnapshot.forEach((doc30) => {
|
|
7965
|
+
documents.push(doc30.data());
|
|
7966
|
+
lastVisible = doc30;
|
|
7864
7967
|
});
|
|
7865
7968
|
return {
|
|
7866
7969
|
documents,
|
|
@@ -7887,9 +7990,9 @@ var FilledDocumentService = class extends BaseService {
|
|
|
7887
7990
|
const querySnapshot = await getDocs15(q);
|
|
7888
7991
|
const documents = [];
|
|
7889
7992
|
let lastVisible = null;
|
|
7890
|
-
querySnapshot.forEach((
|
|
7891
|
-
documents.push(
|
|
7892
|
-
lastVisible =
|
|
7993
|
+
querySnapshot.forEach((doc30) => {
|
|
7994
|
+
documents.push(doc30.data());
|
|
7995
|
+
lastVisible = doc30;
|
|
7893
7996
|
});
|
|
7894
7997
|
return {
|
|
7895
7998
|
documents,
|
|
@@ -7916,9 +8019,9 @@ var FilledDocumentService = class extends BaseService {
|
|
|
7916
8019
|
const querySnapshot = await getDocs15(q);
|
|
7917
8020
|
const documents = [];
|
|
7918
8021
|
let lastVisible = null;
|
|
7919
|
-
querySnapshot.forEach((
|
|
7920
|
-
documents.push(
|
|
7921
|
-
lastVisible =
|
|
8022
|
+
querySnapshot.forEach((doc30) => {
|
|
8023
|
+
documents.push(doc30.data());
|
|
8024
|
+
lastVisible = doc30;
|
|
7922
8025
|
});
|
|
7923
8026
|
return {
|
|
7924
8027
|
documents,
|
|
@@ -7945,9 +8048,9 @@ var FilledDocumentService = class extends BaseService {
|
|
|
7945
8048
|
const querySnapshot = await getDocs15(q);
|
|
7946
8049
|
const documents = [];
|
|
7947
8050
|
let lastVisible = null;
|
|
7948
|
-
querySnapshot.forEach((
|
|
7949
|
-
documents.push(
|
|
7950
|
-
lastVisible =
|
|
8051
|
+
querySnapshot.forEach((doc30) => {
|
|
8052
|
+
documents.push(doc30.data());
|
|
8053
|
+
lastVisible = doc30;
|
|
7951
8054
|
});
|
|
7952
8055
|
return {
|
|
7953
8056
|
documents,
|
|
@@ -7981,42 +8084,42 @@ import {
|
|
|
7981
8084
|
} from "firebase/firestore";
|
|
7982
8085
|
|
|
7983
8086
|
// src/validations/calendar.schema.ts
|
|
7984
|
-
import { z as
|
|
8087
|
+
import { z as z21 } from "zod";
|
|
7985
8088
|
import { Timestamp as Timestamp18 } from "firebase/firestore";
|
|
7986
8089
|
|
|
7987
8090
|
// src/validations/profile-info.schema.ts
|
|
7988
|
-
import { z as
|
|
8091
|
+
import { z as z20 } from "zod";
|
|
7989
8092
|
import { Timestamp as Timestamp17 } from "firebase/firestore";
|
|
7990
|
-
var clinicInfoSchema2 =
|
|
7991
|
-
id:
|
|
7992
|
-
featuredPhoto:
|
|
7993
|
-
name:
|
|
7994
|
-
description:
|
|
8093
|
+
var clinicInfoSchema2 = z20.object({
|
|
8094
|
+
id: z20.string(),
|
|
8095
|
+
featuredPhoto: z20.string(),
|
|
8096
|
+
name: z20.string(),
|
|
8097
|
+
description: z20.string(),
|
|
7995
8098
|
location: clinicLocationSchema,
|
|
7996
8099
|
contactInfo: clinicContactInfoSchema
|
|
7997
8100
|
});
|
|
7998
|
-
var practitionerProfileInfoSchema =
|
|
7999
|
-
id:
|
|
8000
|
-
practitionerPhoto:
|
|
8001
|
-
name:
|
|
8002
|
-
email:
|
|
8003
|
-
phone:
|
|
8101
|
+
var practitionerProfileInfoSchema = z20.object({
|
|
8102
|
+
id: z20.string(),
|
|
8103
|
+
practitionerPhoto: z20.string().nullable(),
|
|
8104
|
+
name: z20.string(),
|
|
8105
|
+
email: z20.string().email(),
|
|
8106
|
+
phone: z20.string().nullable(),
|
|
8004
8107
|
certification: practitionerCertificationSchema
|
|
8005
8108
|
});
|
|
8006
|
-
var patientProfileInfoSchema =
|
|
8007
|
-
id:
|
|
8008
|
-
fullName:
|
|
8009
|
-
email:
|
|
8010
|
-
phone:
|
|
8011
|
-
dateOfBirth:
|
|
8012
|
-
gender:
|
|
8109
|
+
var patientProfileInfoSchema = z20.object({
|
|
8110
|
+
id: z20.string(),
|
|
8111
|
+
fullName: z20.string(),
|
|
8112
|
+
email: z20.string().email(),
|
|
8113
|
+
phone: z20.string().nullable(),
|
|
8114
|
+
dateOfBirth: z20.instanceof(Timestamp17),
|
|
8115
|
+
gender: z20.nativeEnum(Gender)
|
|
8013
8116
|
});
|
|
8014
8117
|
|
|
8015
8118
|
// src/validations/calendar.schema.ts
|
|
8016
8119
|
var MIN_APPOINTMENT_DURATION = 15;
|
|
8017
|
-
var calendarEventTimeSchema =
|
|
8018
|
-
start:
|
|
8019
|
-
end:
|
|
8120
|
+
var calendarEventTimeSchema = z21.object({
|
|
8121
|
+
start: z21.instanceof(Date).or(z21.instanceof(Timestamp18)),
|
|
8122
|
+
end: z21.instanceof(Date).or(z21.instanceof(Timestamp18))
|
|
8020
8123
|
}).refine(
|
|
8021
8124
|
(data) => {
|
|
8022
8125
|
const startDate = data.start instanceof Timestamp18 ? data.start.toDate() : data.start;
|
|
@@ -8037,46 +8140,46 @@ var calendarEventTimeSchema = z20.object({
|
|
|
8037
8140
|
path: ["start"]
|
|
8038
8141
|
}
|
|
8039
8142
|
);
|
|
8040
|
-
var timeSlotSchema2 =
|
|
8041
|
-
start:
|
|
8042
|
-
end:
|
|
8043
|
-
isAvailable:
|
|
8143
|
+
var timeSlotSchema2 = z21.object({
|
|
8144
|
+
start: z21.date(),
|
|
8145
|
+
end: z21.date(),
|
|
8146
|
+
isAvailable: z21.boolean()
|
|
8044
8147
|
}).refine((data) => data.start < data.end, {
|
|
8045
8148
|
message: "End time must be after start time",
|
|
8046
8149
|
path: ["end"]
|
|
8047
8150
|
});
|
|
8048
|
-
var syncedCalendarEventSchema =
|
|
8049
|
-
eventId:
|
|
8050
|
-
syncedCalendarProvider:
|
|
8051
|
-
syncedAt:
|
|
8151
|
+
var syncedCalendarEventSchema = z21.object({
|
|
8152
|
+
eventId: z21.string(),
|
|
8153
|
+
syncedCalendarProvider: z21.nativeEnum(SyncedCalendarProvider),
|
|
8154
|
+
syncedAt: z21.instanceof(Date).or(z21.instanceof(Timestamp18))
|
|
8052
8155
|
});
|
|
8053
|
-
var procedureInfoSchema =
|
|
8054
|
-
name:
|
|
8055
|
-
description:
|
|
8056
|
-
duration:
|
|
8057
|
-
price:
|
|
8058
|
-
currency:
|
|
8156
|
+
var procedureInfoSchema = z21.object({
|
|
8157
|
+
name: z21.string(),
|
|
8158
|
+
description: z21.string(),
|
|
8159
|
+
duration: z21.number().min(MIN_APPOINTMENT_DURATION),
|
|
8160
|
+
price: z21.number().min(0),
|
|
8161
|
+
currency: z21.nativeEnum(Currency)
|
|
8059
8162
|
});
|
|
8060
|
-
var procedureCategorizationSchema =
|
|
8061
|
-
procedureFamily:
|
|
8163
|
+
var procedureCategorizationSchema = z21.object({
|
|
8164
|
+
procedureFamily: z21.string(),
|
|
8062
8165
|
// Replace with proper enum when available
|
|
8063
|
-
procedureCategory:
|
|
8166
|
+
procedureCategory: z21.string(),
|
|
8064
8167
|
// Replace with proper enum when available
|
|
8065
|
-
procedureSubcategory:
|
|
8168
|
+
procedureSubcategory: z21.string(),
|
|
8066
8169
|
// Replace with proper enum when available
|
|
8067
|
-
procedureTechnology:
|
|
8170
|
+
procedureTechnology: z21.string(),
|
|
8068
8171
|
// Replace with proper enum when available
|
|
8069
|
-
procedureProduct:
|
|
8172
|
+
procedureProduct: z21.string()
|
|
8070
8173
|
// Replace with proper enum when available
|
|
8071
8174
|
});
|
|
8072
|
-
var
|
|
8073
|
-
clinicId:
|
|
8074
|
-
doctorId:
|
|
8075
|
-
patientId:
|
|
8076
|
-
procedureId:
|
|
8175
|
+
var createAppointmentSchema2 = z21.object({
|
|
8176
|
+
clinicId: z21.string().min(1, "Clinic ID is required"),
|
|
8177
|
+
doctorId: z21.string().min(1, "Doctor ID is required"),
|
|
8178
|
+
patientId: z21.string().min(1, "Patient ID is required"),
|
|
8179
|
+
procedureId: z21.string().min(1, "Procedure ID is required"),
|
|
8077
8180
|
eventLocation: clinicLocationSchema,
|
|
8078
8181
|
eventTime: calendarEventTimeSchema,
|
|
8079
|
-
description:
|
|
8182
|
+
description: z21.string().optional()
|
|
8080
8183
|
}).refine(
|
|
8081
8184
|
(data) => {
|
|
8082
8185
|
return true;
|
|
@@ -8085,73 +8188,73 @@ var createAppointmentSchema = z20.object({
|
|
|
8085
8188
|
message: "Invalid appointment parameters"
|
|
8086
8189
|
}
|
|
8087
8190
|
);
|
|
8088
|
-
var
|
|
8089
|
-
appointmentId:
|
|
8090
|
-
clinicId:
|
|
8091
|
-
doctorId:
|
|
8092
|
-
patientId:
|
|
8191
|
+
var updateAppointmentSchema2 = z21.object({
|
|
8192
|
+
appointmentId: z21.string().min(1, "Appointment ID is required"),
|
|
8193
|
+
clinicId: z21.string().min(1, "Clinic ID is required"),
|
|
8194
|
+
doctorId: z21.string().min(1, "Doctor ID is required"),
|
|
8195
|
+
patientId: z21.string().min(1, "Patient ID is required"),
|
|
8093
8196
|
eventTime: calendarEventTimeSchema.optional(),
|
|
8094
|
-
description:
|
|
8095
|
-
status:
|
|
8197
|
+
description: z21.string().optional(),
|
|
8198
|
+
status: z21.nativeEnum(CalendarEventStatus).optional()
|
|
8096
8199
|
});
|
|
8097
|
-
var createCalendarEventSchema =
|
|
8098
|
-
id:
|
|
8099
|
-
clinicBranchId:
|
|
8100
|
-
clinicBranchInfo:
|
|
8101
|
-
practitionerProfileId:
|
|
8200
|
+
var createCalendarEventSchema = z21.object({
|
|
8201
|
+
id: z21.string(),
|
|
8202
|
+
clinicBranchId: z21.string().nullable().optional(),
|
|
8203
|
+
clinicBranchInfo: z21.any().nullable().optional(),
|
|
8204
|
+
practitionerProfileId: z21.string().nullable().optional(),
|
|
8102
8205
|
practitionerProfileInfo: practitionerProfileInfoSchema.nullable().optional(),
|
|
8103
|
-
patientProfileId:
|
|
8206
|
+
patientProfileId: z21.string().nullable().optional(),
|
|
8104
8207
|
patientProfileInfo: patientProfileInfoSchema.nullable().optional(),
|
|
8105
|
-
procedureId:
|
|
8106
|
-
appointmentId:
|
|
8107
|
-
syncedCalendarEventId:
|
|
8108
|
-
eventName:
|
|
8208
|
+
procedureId: z21.string().nullable().optional(),
|
|
8209
|
+
appointmentId: z21.string().nullable().optional(),
|
|
8210
|
+
syncedCalendarEventId: z21.array(syncedCalendarEventSchema).nullable().optional(),
|
|
8211
|
+
eventName: z21.string().min(1, "Event name is required"),
|
|
8109
8212
|
eventLocation: clinicLocationSchema.optional(),
|
|
8110
8213
|
eventTime: calendarEventTimeSchema,
|
|
8111
|
-
description:
|
|
8112
|
-
status:
|
|
8113
|
-
syncStatus:
|
|
8114
|
-
eventType:
|
|
8115
|
-
createdAt:
|
|
8214
|
+
description: z21.string().optional(),
|
|
8215
|
+
status: z21.nativeEnum(CalendarEventStatus),
|
|
8216
|
+
syncStatus: z21.nativeEnum(CalendarSyncStatus),
|
|
8217
|
+
eventType: z21.nativeEnum(CalendarEventType),
|
|
8218
|
+
createdAt: z21.any(),
|
|
8116
8219
|
// FieldValue for server timestamp
|
|
8117
|
-
updatedAt:
|
|
8220
|
+
updatedAt: z21.any()
|
|
8118
8221
|
// FieldValue for server timestamp
|
|
8119
8222
|
});
|
|
8120
|
-
var updateCalendarEventSchema =
|
|
8121
|
-
syncedCalendarEventId:
|
|
8122
|
-
appointmentId:
|
|
8123
|
-
eventName:
|
|
8223
|
+
var updateCalendarEventSchema = z21.object({
|
|
8224
|
+
syncedCalendarEventId: z21.array(syncedCalendarEventSchema).nullable().optional(),
|
|
8225
|
+
appointmentId: z21.string().nullable().optional(),
|
|
8226
|
+
eventName: z21.string().optional(),
|
|
8124
8227
|
eventTime: calendarEventTimeSchema.optional(),
|
|
8125
|
-
description:
|
|
8126
|
-
status:
|
|
8127
|
-
syncStatus:
|
|
8128
|
-
eventType:
|
|
8129
|
-
updatedAt:
|
|
8228
|
+
description: z21.string().optional(),
|
|
8229
|
+
status: z21.nativeEnum(CalendarEventStatus).optional(),
|
|
8230
|
+
syncStatus: z21.nativeEnum(CalendarSyncStatus).optional(),
|
|
8231
|
+
eventType: z21.nativeEnum(CalendarEventType).optional(),
|
|
8232
|
+
updatedAt: z21.any()
|
|
8130
8233
|
// FieldValue for server timestamp
|
|
8131
8234
|
});
|
|
8132
|
-
var calendarEventSchema =
|
|
8133
|
-
id:
|
|
8134
|
-
clinicBranchId:
|
|
8135
|
-
clinicBranchInfo:
|
|
8235
|
+
var calendarEventSchema = z21.object({
|
|
8236
|
+
id: z21.string(),
|
|
8237
|
+
clinicBranchId: z21.string().nullable().optional(),
|
|
8238
|
+
clinicBranchInfo: z21.any().nullable().optional(),
|
|
8136
8239
|
// Will be replaced with proper clinic info schema
|
|
8137
|
-
practitionerProfileId:
|
|
8240
|
+
practitionerProfileId: z21.string().nullable().optional(),
|
|
8138
8241
|
practitionerProfileInfo: practitionerProfileInfoSchema.nullable().optional(),
|
|
8139
|
-
patientProfileId:
|
|
8242
|
+
patientProfileId: z21.string().nullable().optional(),
|
|
8140
8243
|
patientProfileInfo: patientProfileInfoSchema.nullable().optional(),
|
|
8141
|
-
procedureId:
|
|
8244
|
+
procedureId: z21.string().nullable().optional(),
|
|
8142
8245
|
procedureInfo: procedureInfoSchema.nullable().optional(),
|
|
8143
8246
|
procedureCategorization: procedureCategorizationSchema.nullable().optional(),
|
|
8144
|
-
appointmentId:
|
|
8145
|
-
syncedCalendarEventId:
|
|
8146
|
-
eventName:
|
|
8247
|
+
appointmentId: z21.string().nullable().optional(),
|
|
8248
|
+
syncedCalendarEventId: z21.array(syncedCalendarEventSchema).nullable().optional(),
|
|
8249
|
+
eventName: z21.string(),
|
|
8147
8250
|
eventLocation: clinicLocationSchema.optional(),
|
|
8148
8251
|
eventTime: calendarEventTimeSchema,
|
|
8149
|
-
description:
|
|
8150
|
-
status:
|
|
8151
|
-
syncStatus:
|
|
8152
|
-
eventType:
|
|
8153
|
-
createdAt:
|
|
8154
|
-
updatedAt:
|
|
8252
|
+
description: z21.string().optional(),
|
|
8253
|
+
status: z21.nativeEnum(CalendarEventStatus),
|
|
8254
|
+
syncStatus: z21.nativeEnum(CalendarSyncStatus),
|
|
8255
|
+
eventType: z21.nativeEnum(CalendarEventType),
|
|
8256
|
+
createdAt: z21.instanceof(Date).or(z21.instanceof(Timestamp18)),
|
|
8257
|
+
updatedAt: z21.instanceof(Date).or(z21.instanceof(Timestamp18))
|
|
8155
8258
|
});
|
|
8156
8259
|
|
|
8157
8260
|
// src/services/calendar/utils/clinic.utils.ts
|
|
@@ -8503,7 +8606,7 @@ async function searchCalendarEventsUtil(db, params) {
|
|
|
8503
8606
|
const finalQuery = query19(collectionRef, ...constraints);
|
|
8504
8607
|
const querySnapshot = await getDocs19(finalQuery);
|
|
8505
8608
|
const events = querySnapshot.docs.map(
|
|
8506
|
-
(
|
|
8609
|
+
(doc30) => ({ id: doc30.id, ...doc30.data() })
|
|
8507
8610
|
);
|
|
8508
8611
|
return events;
|
|
8509
8612
|
} catch (error) {
|
|
@@ -8596,7 +8699,7 @@ async function getPractitionerSyncedCalendarsUtil(db, practitionerId) {
|
|
|
8596
8699
|
);
|
|
8597
8700
|
const q = query20(calendarsRef, orderBy11("createdAt", "desc"));
|
|
8598
8701
|
const querySnapshot = await getDocs20(q);
|
|
8599
|
-
return querySnapshot.docs.map((
|
|
8702
|
+
return querySnapshot.docs.map((doc30) => doc30.data());
|
|
8600
8703
|
}
|
|
8601
8704
|
async function getPatientSyncedCalendarUtil(db, patientId, calendarId) {
|
|
8602
8705
|
const calendarRef = getPatientSyncedCalendarDocRef(db, patientId, calendarId);
|
|
@@ -8613,7 +8716,7 @@ async function getPatientSyncedCalendarsUtil(db, patientId) {
|
|
|
8613
8716
|
);
|
|
8614
8717
|
const q = query20(calendarsRef, orderBy11("createdAt", "desc"));
|
|
8615
8718
|
const querySnapshot = await getDocs20(q);
|
|
8616
|
-
return querySnapshot.docs.map((
|
|
8719
|
+
return querySnapshot.docs.map((doc30) => doc30.data());
|
|
8617
8720
|
}
|
|
8618
8721
|
async function getClinicSyncedCalendarUtil(db, clinicId, calendarId) {
|
|
8619
8722
|
const calendarRef = getClinicSyncedCalendarDocRef(db, clinicId, calendarId);
|
|
@@ -8630,7 +8733,7 @@ async function getClinicSyncedCalendarsUtil(db, clinicId) {
|
|
|
8630
8733
|
);
|
|
8631
8734
|
const q = query20(calendarsRef, orderBy11("createdAt", "desc"));
|
|
8632
8735
|
const querySnapshot = await getDocs20(q);
|
|
8633
|
-
return querySnapshot.docs.map((
|
|
8736
|
+
return querySnapshot.docs.map((doc30) => doc30.data());
|
|
8634
8737
|
}
|
|
8635
8738
|
async function updatePractitionerSyncedCalendarUtil(db, practitionerId, calendarId, updateData) {
|
|
8636
8739
|
const calendarRef = getPractitionerSyncedCalendarDocRef(
|
|
@@ -9985,9 +10088,9 @@ var CalendarServiceV2 = class extends BaseService {
|
|
|
9985
10088
|
where21("eventTime.start", "<=", Timestamp25.fromDate(endDate))
|
|
9986
10089
|
);
|
|
9987
10090
|
const eventsSnapshot = await getDocs21(q);
|
|
9988
|
-
const events = eventsSnapshot.docs.map((
|
|
9989
|
-
id:
|
|
9990
|
-
...
|
|
10091
|
+
const events = eventsSnapshot.docs.map((doc30) => ({
|
|
10092
|
+
id: doc30.id,
|
|
10093
|
+
...doc30.data()
|
|
9991
10094
|
}));
|
|
9992
10095
|
const calendars = await this.syncedCalendarsService.getPractitionerSyncedCalendars(
|
|
9993
10096
|
doctorId
|
|
@@ -10254,7 +10357,7 @@ var CalendarServiceV2 = class extends BaseService {
|
|
|
10254
10357
|
* @throws Error if validation fails
|
|
10255
10358
|
*/
|
|
10256
10359
|
async validateAppointmentParams(params) {
|
|
10257
|
-
await
|
|
10360
|
+
await createAppointmentSchema2.parseAsync(params);
|
|
10258
10361
|
}
|
|
10259
10362
|
/**
|
|
10260
10363
|
* Validates if the event time falls within clinic working hours
|
|
@@ -10536,7 +10639,7 @@ var CalendarServiceV2 = class extends BaseService {
|
|
|
10536
10639
|
* @param params - Update parameters to validate
|
|
10537
10640
|
*/
|
|
10538
10641
|
async validateUpdatePermissions(params) {
|
|
10539
|
-
await
|
|
10642
|
+
await updateAppointmentSchema2.parseAsync(params);
|
|
10540
10643
|
}
|
|
10541
10644
|
/**
|
|
10542
10645
|
* Gets clinic working hours for a specific date
|
|
@@ -10619,7 +10722,7 @@ var CalendarServiceV2 = class extends BaseService {
|
|
|
10619
10722
|
])
|
|
10620
10723
|
);
|
|
10621
10724
|
const querySnapshot = await getDocs21(q);
|
|
10622
|
-
return querySnapshot.docs.map((
|
|
10725
|
+
return querySnapshot.docs.map((doc30) => doc30.data());
|
|
10623
10726
|
}
|
|
10624
10727
|
/**
|
|
10625
10728
|
* Calculates available time slots based on working hours, schedule and existing appointments
|
|
@@ -10762,7 +10865,7 @@ import {
|
|
|
10762
10865
|
var REVIEWS_COLLECTION = "reviews";
|
|
10763
10866
|
|
|
10764
10867
|
// src/services/reviews/reviews.service.ts
|
|
10765
|
-
import { z as
|
|
10868
|
+
import { z as z22 } from "zod";
|
|
10766
10869
|
var ReviewService = class extends BaseService {
|
|
10767
10870
|
constructor(db, auth, app) {
|
|
10768
10871
|
super(db, auth, app);
|
|
@@ -10868,7 +10971,7 @@ var ReviewService = class extends BaseService {
|
|
|
10868
10971
|
await Promise.all(updatePromises);
|
|
10869
10972
|
return review;
|
|
10870
10973
|
} catch (error) {
|
|
10871
|
-
if (error instanceof
|
|
10974
|
+
if (error instanceof z22.ZodError) {
|
|
10872
10975
|
throw new Error(`Invalid review data: ${error.message}`);
|
|
10873
10976
|
}
|
|
10874
10977
|
throw error;
|
|
@@ -10898,7 +11001,7 @@ var ReviewService = class extends BaseService {
|
|
|
10898
11001
|
where22("patientId", "==", patientId)
|
|
10899
11002
|
);
|
|
10900
11003
|
const snapshot = await getDocs22(q);
|
|
10901
|
-
return snapshot.docs.map((
|
|
11004
|
+
return snapshot.docs.map((doc30) => doc30.data());
|
|
10902
11005
|
}
|
|
10903
11006
|
/**
|
|
10904
11007
|
* Gets all reviews for a specific clinic
|
|
@@ -10911,7 +11014,7 @@ var ReviewService = class extends BaseService {
|
|
|
10911
11014
|
where22("clinicReview.clinicId", "==", clinicId)
|
|
10912
11015
|
);
|
|
10913
11016
|
const snapshot = await getDocs22(q);
|
|
10914
|
-
return snapshot.docs.map((
|
|
11017
|
+
return snapshot.docs.map((doc30) => doc30.data());
|
|
10915
11018
|
}
|
|
10916
11019
|
/**
|
|
10917
11020
|
* Gets all reviews for a specific practitioner
|
|
@@ -10924,7 +11027,7 @@ var ReviewService = class extends BaseService {
|
|
|
10924
11027
|
where22("practitionerReview.practitionerId", "==", practitionerId)
|
|
10925
11028
|
);
|
|
10926
11029
|
const snapshot = await getDocs22(q);
|
|
10927
|
-
return snapshot.docs.map((
|
|
11030
|
+
return snapshot.docs.map((doc30) => doc30.data());
|
|
10928
11031
|
}
|
|
10929
11032
|
/**
|
|
10930
11033
|
* Gets all reviews for a specific procedure
|
|
@@ -10937,7 +11040,7 @@ var ReviewService = class extends BaseService {
|
|
|
10937
11040
|
where22("procedureReview.procedureId", "==", procedureId)
|
|
10938
11041
|
);
|
|
10939
11042
|
const snapshot = await getDocs22(q);
|
|
10940
|
-
return snapshot.docs.map((
|
|
11043
|
+
return snapshot.docs.map((doc30) => doc30.data());
|
|
10941
11044
|
}
|
|
10942
11045
|
/**
|
|
10943
11046
|
* Gets all reviews for a specific appointment
|
|
@@ -11364,95 +11467,850 @@ var ReviewService = class extends BaseService {
|
|
|
11364
11467
|
}
|
|
11365
11468
|
};
|
|
11366
11469
|
|
|
11367
|
-
// src/
|
|
11470
|
+
// src/services/appointment/appointment.service.ts
|
|
11471
|
+
import {
|
|
11472
|
+
Timestamp as Timestamp28
|
|
11473
|
+
} from "firebase/firestore";
|
|
11474
|
+
import { getFunctions, httpsCallable } from "firebase/functions";
|
|
11475
|
+
|
|
11476
|
+
// src/services/appointment/utils/appointment.utils.ts
|
|
11368
11477
|
import {
|
|
11369
|
-
addDoc as addDoc3,
|
|
11370
11478
|
collection as collection23,
|
|
11371
11479
|
doc as doc24,
|
|
11372
11480
|
getDoc as getDoc26,
|
|
11373
11481
|
getDocs as getDocs23,
|
|
11374
11482
|
query as query23,
|
|
11483
|
+
where as where23,
|
|
11484
|
+
setDoc as setDoc23,
|
|
11375
11485
|
updateDoc as updateDoc25,
|
|
11376
|
-
|
|
11486
|
+
serverTimestamp as serverTimestamp23,
|
|
11487
|
+
Timestamp as Timestamp27,
|
|
11488
|
+
orderBy as orderBy12,
|
|
11489
|
+
limit as limit8,
|
|
11490
|
+
startAfter as startAfter8
|
|
11377
11491
|
} from "firebase/firestore";
|
|
11378
11492
|
|
|
11379
|
-
// src/backoffice/types/
|
|
11380
|
-
var
|
|
11493
|
+
// src/backoffice/types/technology.types.ts
|
|
11494
|
+
var TECHNOLOGIES_COLLECTION = "technologies";
|
|
11381
11495
|
|
|
11382
|
-
// src/
|
|
11383
|
-
|
|
11384
|
-
|
|
11385
|
-
|
|
11386
|
-
|
|
11387
|
-
|
|
11388
|
-
|
|
11389
|
-
|
|
11390
|
-
|
|
11391
|
-
|
|
11392
|
-
|
|
11393
|
-
|
|
11394
|
-
|
|
11395
|
-
|
|
11396
|
-
|
|
11397
|
-
|
|
11398
|
-
|
|
11399
|
-
|
|
11496
|
+
// src/services/appointment/utils/appointment.utils.ts
|
|
11497
|
+
async function fetchAggregatedInfoUtil(db, clinicId, practitionerId, patientId, procedureId) {
|
|
11498
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
|
|
11499
|
+
try {
|
|
11500
|
+
const [clinicDoc, practitionerDoc, patientDoc, procedureDoc] = await Promise.all([
|
|
11501
|
+
getDoc26(doc24(db, CLINICS_COLLECTION, clinicId)),
|
|
11502
|
+
getDoc26(doc24(db, PRACTITIONERS_COLLECTION, practitionerId)),
|
|
11503
|
+
getDoc26(doc24(db, PATIENTS_COLLECTION, patientId)),
|
|
11504
|
+
getDoc26(doc24(db, PROCEDURES_COLLECTION, procedureId))
|
|
11505
|
+
]);
|
|
11506
|
+
if (!clinicDoc.exists()) {
|
|
11507
|
+
throw new Error(`Clinic with ID ${clinicId} not found`);
|
|
11508
|
+
}
|
|
11509
|
+
if (!practitionerDoc.exists()) {
|
|
11510
|
+
throw new Error(`Practitioner with ID ${practitionerId} not found`);
|
|
11511
|
+
}
|
|
11512
|
+
if (!patientDoc.exists()) {
|
|
11513
|
+
throw new Error(`Patient with ID ${patientId} not found`);
|
|
11514
|
+
}
|
|
11515
|
+
if (!procedureDoc.exists()) {
|
|
11516
|
+
throw new Error(`Procedure with ID ${procedureId} not found`);
|
|
11517
|
+
}
|
|
11518
|
+
const clinicData = clinicDoc.data();
|
|
11519
|
+
const practitionerData = practitionerDoc.data();
|
|
11520
|
+
const patientData = patientDoc.data();
|
|
11521
|
+
const procedureData = procedureDoc.data();
|
|
11522
|
+
const clinicInfo = {
|
|
11523
|
+
id: clinicId,
|
|
11524
|
+
featuredPhoto: ((_a = clinicData.featuredPhotos) == null ? void 0 : _a[0]) || "",
|
|
11525
|
+
name: clinicData.name,
|
|
11526
|
+
description: clinicData.description || null,
|
|
11527
|
+
location: clinicData.location,
|
|
11528
|
+
contactInfo: clinicData.contactInfo
|
|
11400
11529
|
};
|
|
11401
|
-
const
|
|
11402
|
-
|
|
11403
|
-
|
|
11404
|
-
|
|
11405
|
-
|
|
11406
|
-
|
|
11407
|
-
|
|
11408
|
-
const q = query23(this.getBrandsRef(), where23("isActive", "==", true));
|
|
11409
|
-
const snapshot = await getDocs23(q);
|
|
11410
|
-
return snapshot.docs.map(
|
|
11411
|
-
(doc29) => ({
|
|
11412
|
-
id: doc29.id,
|
|
11413
|
-
...doc29.data()
|
|
11414
|
-
})
|
|
11415
|
-
);
|
|
11416
|
-
}
|
|
11417
|
-
/**
|
|
11418
|
-
* Updates a brand
|
|
11419
|
-
*/
|
|
11420
|
-
async update(brandId, brand) {
|
|
11421
|
-
const updateData = {
|
|
11422
|
-
...brand,
|
|
11423
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
11530
|
+
const practitionerInfo = {
|
|
11531
|
+
id: practitionerId,
|
|
11532
|
+
practitionerPhoto: ((_b = practitionerData.basicInfo) == null ? void 0 : _b.profileImageUrl) || null,
|
|
11533
|
+
name: `${((_c = practitionerData.basicInfo) == null ? void 0 : _c.firstName) || ""} ${((_d = practitionerData.basicInfo) == null ? void 0 : _d.lastName) || ""}`.trim(),
|
|
11534
|
+
email: ((_e = practitionerData.basicInfo) == null ? void 0 : _e.email) || "",
|
|
11535
|
+
phone: ((_f = practitionerData.basicInfo) == null ? void 0 : _f.phoneNumber) || null,
|
|
11536
|
+
certification: practitionerData.certification
|
|
11424
11537
|
};
|
|
11425
|
-
const
|
|
11426
|
-
|
|
11427
|
-
|
|
11538
|
+
const patientInfo = {
|
|
11539
|
+
id: patientId,
|
|
11540
|
+
fullName: patientData.displayName || "",
|
|
11541
|
+
email: patientData.email || "",
|
|
11542
|
+
phone: patientData.phoneNumber || null,
|
|
11543
|
+
dateOfBirth: patientData.dateOfBirth || Timestamp27.now(),
|
|
11544
|
+
gender: patientData.gender || "other"
|
|
11545
|
+
};
|
|
11546
|
+
const procedureInfo = {
|
|
11547
|
+
id: procedureId,
|
|
11548
|
+
name: procedureData.name,
|
|
11549
|
+
description: procedureData.description,
|
|
11550
|
+
photo: procedureData.photo || "",
|
|
11551
|
+
family: procedureData.family,
|
|
11552
|
+
categoryName: ((_g = procedureData.category) == null ? void 0 : _g.name) || "",
|
|
11553
|
+
subcategoryName: ((_h = procedureData.subcategory) == null ? void 0 : _h.name) || "",
|
|
11554
|
+
technologyName: ((_i = procedureData.technology) == null ? void 0 : _i.name) || "",
|
|
11555
|
+
brandName: ((_j = procedureData.product) == null ? void 0 : _j.brand) || "",
|
|
11556
|
+
productName: ((_k = procedureData.product) == null ? void 0 : _k.name) || "",
|
|
11557
|
+
price: procedureData.price || 0,
|
|
11558
|
+
pricingMeasure: procedureData.pricingMeasure,
|
|
11559
|
+
currency: procedureData.currency,
|
|
11560
|
+
duration: procedureData.duration || 0,
|
|
11561
|
+
clinicId,
|
|
11562
|
+
clinicName: clinicInfo.name,
|
|
11563
|
+
practitionerId,
|
|
11564
|
+
practitionerName: practitionerInfo.name
|
|
11565
|
+
};
|
|
11566
|
+
let technologyId = "";
|
|
11567
|
+
if ((_l = procedureData.technology) == null ? void 0 : _l.id) {
|
|
11568
|
+
technologyId = procedureData.technology.id;
|
|
11569
|
+
}
|
|
11570
|
+
let blockingConditions = [];
|
|
11571
|
+
let contraindications = [];
|
|
11572
|
+
let preProcedureRequirements = [];
|
|
11573
|
+
let postProcedureRequirements = [];
|
|
11574
|
+
if (technologyId) {
|
|
11575
|
+
const technologyDoc = await getDoc26(
|
|
11576
|
+
doc24(db, TECHNOLOGIES_COLLECTION, technologyId)
|
|
11577
|
+
);
|
|
11578
|
+
if (technologyDoc.exists()) {
|
|
11579
|
+
const technologyData = technologyDoc.data();
|
|
11580
|
+
blockingConditions = technologyData.blockingConditions || [];
|
|
11581
|
+
contraindications = technologyData.contraindications || [];
|
|
11582
|
+
preProcedureRequirements = ((_m = technologyData.requirements) == null ? void 0 : _m.pre) || [];
|
|
11583
|
+
postProcedureRequirements = ((_n = technologyData.requirements) == null ? void 0 : _n.post) || [];
|
|
11584
|
+
}
|
|
11585
|
+
} else {
|
|
11586
|
+
blockingConditions = procedureData.blockingConditions || [];
|
|
11587
|
+
contraindications = procedureData.contraindications || [];
|
|
11588
|
+
preProcedureRequirements = procedureData.preRequirements || [];
|
|
11589
|
+
postProcedureRequirements = procedureData.postRequirements || [];
|
|
11590
|
+
}
|
|
11591
|
+
return {
|
|
11592
|
+
clinicInfo,
|
|
11593
|
+
practitionerInfo,
|
|
11594
|
+
patientInfo,
|
|
11595
|
+
procedureInfo,
|
|
11596
|
+
blockingConditions,
|
|
11597
|
+
contraindications,
|
|
11598
|
+
preProcedureRequirements,
|
|
11599
|
+
postProcedureRequirements
|
|
11600
|
+
};
|
|
11601
|
+
} catch (error) {
|
|
11602
|
+
console.error("Error fetching aggregated info:", error);
|
|
11603
|
+
throw error;
|
|
11428
11604
|
}
|
|
11429
|
-
|
|
11430
|
-
|
|
11431
|
-
|
|
11432
|
-
|
|
11433
|
-
|
|
11434
|
-
|
|
11605
|
+
}
|
|
11606
|
+
async function createAppointmentUtil2(db, data, aggregatedInfo, generateId2) {
|
|
11607
|
+
try {
|
|
11608
|
+
const appointmentId = generateId2();
|
|
11609
|
+
const appointment = {
|
|
11610
|
+
id: appointmentId,
|
|
11611
|
+
calendarEventId: data.calendarEventId,
|
|
11612
|
+
clinicBranchId: data.clinicBranchId,
|
|
11613
|
+
clinicInfo: aggregatedInfo.clinicInfo,
|
|
11614
|
+
practitionerId: data.practitionerId,
|
|
11615
|
+
practitionerInfo: aggregatedInfo.practitionerInfo,
|
|
11616
|
+
patientId: data.patientId,
|
|
11617
|
+
patientInfo: aggregatedInfo.patientInfo,
|
|
11618
|
+
procedureId: data.procedureId,
|
|
11619
|
+
procedureInfo: aggregatedInfo.procedureInfo,
|
|
11620
|
+
status: data.initialStatus,
|
|
11621
|
+
bookingTime: Timestamp27.now(),
|
|
11622
|
+
appointmentStartTime: data.appointmentStartTime,
|
|
11623
|
+
appointmentEndTime: data.appointmentEndTime,
|
|
11624
|
+
patientNotes: data.patientNotes || null,
|
|
11625
|
+
cost: data.cost,
|
|
11626
|
+
currency: data.currency,
|
|
11627
|
+
paymentStatus: data.initialPaymentStatus || "unpaid" /* UNPAID */,
|
|
11628
|
+
blockingConditions: aggregatedInfo.blockingConditions,
|
|
11629
|
+
contraindications: aggregatedInfo.contraindications,
|
|
11630
|
+
preProcedureRequirements: aggregatedInfo.preProcedureRequirements,
|
|
11631
|
+
postProcedureRequirements: aggregatedInfo.postProcedureRequirements,
|
|
11632
|
+
completedPreRequirements: [],
|
|
11633
|
+
completedPostRequirements: [],
|
|
11634
|
+
createdAt: serverTimestamp23(),
|
|
11635
|
+
updatedAt: serverTimestamp23()
|
|
11636
|
+
};
|
|
11637
|
+
if (data.initialStatus === "confirmed" /* CONFIRMED */) {
|
|
11638
|
+
appointment.confirmationTime = Timestamp27.now();
|
|
11639
|
+
}
|
|
11640
|
+
await setDoc23(doc24(db, APPOINTMENTS_COLLECTION, appointmentId), appointment);
|
|
11641
|
+
const calendarEventRef = doc24(db, CALENDAR_COLLECTION, data.calendarEventId);
|
|
11642
|
+
await updateDoc25(calendarEventRef, {
|
|
11643
|
+
appointmentId,
|
|
11644
|
+
updatedAt: serverTimestamp23()
|
|
11435
11645
|
});
|
|
11436
|
-
|
|
11437
|
-
/**
|
|
11438
|
-
* Gets a brand by ID
|
|
11439
|
-
*/
|
|
11440
|
-
async getById(brandId) {
|
|
11441
|
-
const docRef = doc24(this.getBrandsRef(), brandId);
|
|
11442
|
-
const docSnap = await getDoc26(docRef);
|
|
11443
|
-
if (!docSnap.exists()) return null;
|
|
11646
|
+
const now = Timestamp27.now();
|
|
11444
11647
|
return {
|
|
11445
|
-
|
|
11446
|
-
|
|
11648
|
+
...appointment,
|
|
11649
|
+
createdAt: now,
|
|
11650
|
+
updatedAt: now
|
|
11447
11651
|
};
|
|
11652
|
+
} catch (error) {
|
|
11653
|
+
console.error("Error creating appointment:", error);
|
|
11654
|
+
throw error;
|
|
11448
11655
|
}
|
|
11449
|
-
}
|
|
11450
|
-
|
|
11451
|
-
|
|
11452
|
-
|
|
11453
|
-
|
|
11454
|
-
|
|
11455
|
-
|
|
11656
|
+
}
|
|
11657
|
+
async function updateAppointmentUtil2(db, appointmentId, data) {
|
|
11658
|
+
try {
|
|
11659
|
+
const appointmentRef = doc24(db, APPOINTMENTS_COLLECTION, appointmentId);
|
|
11660
|
+
const appointmentDoc = await getDoc26(appointmentRef);
|
|
11661
|
+
if (!appointmentDoc.exists()) {
|
|
11662
|
+
throw new Error(`Appointment with ID ${appointmentId} not found`);
|
|
11663
|
+
}
|
|
11664
|
+
const currentAppointment = appointmentDoc.data();
|
|
11665
|
+
let completedPreRequirements = currentAppointment.completedPreRequirements || [];
|
|
11666
|
+
let completedPostRequirements = currentAppointment.completedPostRequirements || [];
|
|
11667
|
+
if (data.completedPreRequirements) {
|
|
11668
|
+
const validPreReqIds = currentAppointment.preProcedureRequirements.map(
|
|
11669
|
+
(req) => req.id
|
|
11670
|
+
);
|
|
11671
|
+
const invalidPreReqIds = data.completedPreRequirements.filter(
|
|
11672
|
+
(id) => !validPreReqIds.includes(id)
|
|
11673
|
+
);
|
|
11674
|
+
if (invalidPreReqIds.length > 0) {
|
|
11675
|
+
throw new Error(
|
|
11676
|
+
`Invalid pre-requirement IDs: ${invalidPreReqIds.join(", ")}`
|
|
11677
|
+
);
|
|
11678
|
+
}
|
|
11679
|
+
completedPreRequirements = [
|
|
11680
|
+
.../* @__PURE__ */ new Set([
|
|
11681
|
+
...completedPreRequirements,
|
|
11682
|
+
...data.completedPreRequirements
|
|
11683
|
+
])
|
|
11684
|
+
];
|
|
11685
|
+
}
|
|
11686
|
+
if (data.completedPostRequirements) {
|
|
11687
|
+
const validPostReqIds = currentAppointment.postProcedureRequirements.map(
|
|
11688
|
+
(req) => req.id
|
|
11689
|
+
);
|
|
11690
|
+
const invalidPostReqIds = data.completedPostRequirements.filter(
|
|
11691
|
+
(id) => !validPostReqIds.includes(id)
|
|
11692
|
+
);
|
|
11693
|
+
if (invalidPostReqIds.length > 0) {
|
|
11694
|
+
throw new Error(
|
|
11695
|
+
`Invalid post-requirement IDs: ${invalidPostReqIds.join(", ")}`
|
|
11696
|
+
);
|
|
11697
|
+
}
|
|
11698
|
+
completedPostRequirements = [
|
|
11699
|
+
.../* @__PURE__ */ new Set([
|
|
11700
|
+
...completedPostRequirements,
|
|
11701
|
+
...data.completedPostRequirements
|
|
11702
|
+
])
|
|
11703
|
+
];
|
|
11704
|
+
}
|
|
11705
|
+
const updateData = {
|
|
11706
|
+
...data,
|
|
11707
|
+
completedPreRequirements,
|
|
11708
|
+
completedPostRequirements,
|
|
11709
|
+
updatedAt: serverTimestamp23()
|
|
11710
|
+
};
|
|
11711
|
+
Object.keys(updateData).forEach((key) => {
|
|
11712
|
+
if (updateData[key] === void 0) {
|
|
11713
|
+
delete updateData[key];
|
|
11714
|
+
}
|
|
11715
|
+
});
|
|
11716
|
+
if (data.status && data.status !== currentAppointment.status) {
|
|
11717
|
+
if (data.status === "confirmed" /* CONFIRMED */ && !updateData.confirmationTime) {
|
|
11718
|
+
updateData.confirmationTime = Timestamp27.now();
|
|
11719
|
+
}
|
|
11720
|
+
if (currentAppointment.calendarEventId) {
|
|
11721
|
+
await updateCalendarEventStatus(
|
|
11722
|
+
db,
|
|
11723
|
+
currentAppointment.calendarEventId,
|
|
11724
|
+
data.status
|
|
11725
|
+
);
|
|
11726
|
+
}
|
|
11727
|
+
}
|
|
11728
|
+
await updateDoc25(appointmentRef, updateData);
|
|
11729
|
+
const updatedAppointmentDoc = await getDoc26(appointmentRef);
|
|
11730
|
+
if (!updatedAppointmentDoc.exists()) {
|
|
11731
|
+
throw new Error(
|
|
11732
|
+
`Failed to retrieve updated appointment ${appointmentId}`
|
|
11733
|
+
);
|
|
11734
|
+
}
|
|
11735
|
+
return updatedAppointmentDoc.data();
|
|
11736
|
+
} catch (error) {
|
|
11737
|
+
console.error(`Error updating appointment ${appointmentId}:`, error);
|
|
11738
|
+
throw error;
|
|
11739
|
+
}
|
|
11740
|
+
}
|
|
11741
|
+
async function updateCalendarEventStatus(db, calendarEventId, appointmentStatus) {
|
|
11742
|
+
try {
|
|
11743
|
+
const calendarEventRef = doc24(db, CALENDAR_COLLECTION, calendarEventId);
|
|
11744
|
+
const calendarEventDoc = await getDoc26(calendarEventRef);
|
|
11745
|
+
if (!calendarEventDoc.exists()) {
|
|
11746
|
+
console.warn(`Calendar event with ID ${calendarEventId} not found`);
|
|
11747
|
+
return;
|
|
11748
|
+
}
|
|
11749
|
+
let calendarStatus;
|
|
11750
|
+
switch (appointmentStatus) {
|
|
11751
|
+
case "confirmed" /* CONFIRMED */:
|
|
11752
|
+
calendarStatus = "confirmed";
|
|
11753
|
+
break;
|
|
11754
|
+
case "canceled_patient" /* CANCELED_PATIENT */:
|
|
11755
|
+
case "canceled_clinic" /* CANCELED_CLINIC */:
|
|
11756
|
+
calendarStatus = "canceled";
|
|
11757
|
+
break;
|
|
11758
|
+
case "rescheduled" /* RESCHEDULED */:
|
|
11759
|
+
calendarStatus = "rescheduled";
|
|
11760
|
+
break;
|
|
11761
|
+
case "completed" /* COMPLETED */:
|
|
11762
|
+
calendarStatus = "completed";
|
|
11763
|
+
break;
|
|
11764
|
+
default:
|
|
11765
|
+
return;
|
|
11766
|
+
}
|
|
11767
|
+
await updateDoc25(calendarEventRef, {
|
|
11768
|
+
status: calendarStatus,
|
|
11769
|
+
updatedAt: serverTimestamp23()
|
|
11770
|
+
});
|
|
11771
|
+
} catch (error) {
|
|
11772
|
+
console.error(`Error updating calendar event ${calendarEventId}:`, error);
|
|
11773
|
+
}
|
|
11774
|
+
}
|
|
11775
|
+
async function getAppointmentByIdUtil(db, appointmentId) {
|
|
11776
|
+
try {
|
|
11777
|
+
const appointmentDoc = await getDoc26(
|
|
11778
|
+
doc24(db, APPOINTMENTS_COLLECTION, appointmentId)
|
|
11779
|
+
);
|
|
11780
|
+
if (!appointmentDoc.exists()) {
|
|
11781
|
+
return null;
|
|
11782
|
+
}
|
|
11783
|
+
return appointmentDoc.data();
|
|
11784
|
+
} catch (error) {
|
|
11785
|
+
console.error(`Error getting appointment ${appointmentId}:`, error);
|
|
11786
|
+
throw error;
|
|
11787
|
+
}
|
|
11788
|
+
}
|
|
11789
|
+
async function searchAppointmentsUtil(db, params) {
|
|
11790
|
+
try {
|
|
11791
|
+
const constraints = [];
|
|
11792
|
+
if (params.patientId) {
|
|
11793
|
+
constraints.push(where23("patientId", "==", params.patientId));
|
|
11794
|
+
}
|
|
11795
|
+
if (params.practitionerId) {
|
|
11796
|
+
constraints.push(where23("practitionerId", "==", params.practitionerId));
|
|
11797
|
+
}
|
|
11798
|
+
if (params.clinicBranchId) {
|
|
11799
|
+
constraints.push(where23("clinicBranchId", "==", params.clinicBranchId));
|
|
11800
|
+
}
|
|
11801
|
+
if (params.startDate) {
|
|
11802
|
+
constraints.push(
|
|
11803
|
+
where23(
|
|
11804
|
+
"appointmentStartTime",
|
|
11805
|
+
">=",
|
|
11806
|
+
Timestamp27.fromDate(params.startDate)
|
|
11807
|
+
)
|
|
11808
|
+
);
|
|
11809
|
+
}
|
|
11810
|
+
if (params.endDate) {
|
|
11811
|
+
constraints.push(
|
|
11812
|
+
where23("appointmentStartTime", "<=", Timestamp27.fromDate(params.endDate))
|
|
11813
|
+
);
|
|
11814
|
+
}
|
|
11815
|
+
if (params.status) {
|
|
11816
|
+
if (Array.isArray(params.status)) {
|
|
11817
|
+
constraints.push(where23("status", "in", params.status));
|
|
11818
|
+
} else {
|
|
11819
|
+
constraints.push(where23("status", "==", params.status));
|
|
11820
|
+
}
|
|
11821
|
+
}
|
|
11822
|
+
constraints.push(orderBy12("appointmentStartTime", "asc"));
|
|
11823
|
+
if (params.limit) {
|
|
11824
|
+
constraints.push(limit8(params.limit));
|
|
11825
|
+
}
|
|
11826
|
+
if (params.startAfter) {
|
|
11827
|
+
constraints.push(startAfter8(params.startAfter));
|
|
11828
|
+
}
|
|
11829
|
+
const q = query23(collection23(db, APPOINTMENTS_COLLECTION), ...constraints);
|
|
11830
|
+
const querySnapshot = await getDocs23(q);
|
|
11831
|
+
const appointments = querySnapshot.docs.map(
|
|
11832
|
+
(doc30) => doc30.data()
|
|
11833
|
+
);
|
|
11834
|
+
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
11835
|
+
return { appointments, lastDoc };
|
|
11836
|
+
} catch (error) {
|
|
11837
|
+
console.error("Error searching appointments:", error);
|
|
11838
|
+
throw error;
|
|
11839
|
+
}
|
|
11840
|
+
}
|
|
11841
|
+
|
|
11842
|
+
// src/services/appointment/appointment.service.ts
|
|
11843
|
+
var AppointmentService = class extends BaseService {
|
|
11844
|
+
/**
|
|
11845
|
+
* Creates a new AppointmentService instance.
|
|
11846
|
+
*
|
|
11847
|
+
* @param db Firestore instance
|
|
11848
|
+
* @param auth Firebase Auth instance
|
|
11849
|
+
* @param app Firebase App instance
|
|
11850
|
+
* @param calendarService Calendar service instance
|
|
11851
|
+
* @param patientService Patient service instance
|
|
11852
|
+
* @param practitionerService Practitioner service instance
|
|
11853
|
+
* @param clinicService Clinic service instance
|
|
11854
|
+
*/
|
|
11855
|
+
constructor(db, auth, app, calendarService, patientService, practitionerService, clinicService) {
|
|
11856
|
+
super(db, auth, app);
|
|
11857
|
+
this.calendarService = calendarService;
|
|
11858
|
+
this.patientService = patientService;
|
|
11859
|
+
this.practitionerService = practitionerService;
|
|
11860
|
+
this.clinicService = clinicService;
|
|
11861
|
+
this.functions = getFunctions(app, "europe-west6");
|
|
11862
|
+
}
|
|
11863
|
+
/**
|
|
11864
|
+
* Gets available booking slots for a specific clinic, practitioner, and procedure.
|
|
11865
|
+
*
|
|
11866
|
+
* @param clinicId ID of the clinic
|
|
11867
|
+
* @param practitionerId ID of the practitioner
|
|
11868
|
+
* @param procedureId ID of the procedure
|
|
11869
|
+
* @param startDate Start date of the time range to check
|
|
11870
|
+
* @param endDate End date of the time range to check
|
|
11871
|
+
* @returns Array of available booking slots
|
|
11872
|
+
*/
|
|
11873
|
+
async getAvailableBookingSlots(clinicId, practitionerId, procedureId, startDate, endDate) {
|
|
11874
|
+
try {
|
|
11875
|
+
console.log(
|
|
11876
|
+
`[APPOINTMENT_SERVICE] Getting available booking slots for clinic: ${clinicId}, practitioner: ${practitionerId}, procedure: ${procedureId}`
|
|
11877
|
+
);
|
|
11878
|
+
if (!clinicId || !practitionerId || !procedureId || !startDate || !endDate) {
|
|
11879
|
+
throw new Error(
|
|
11880
|
+
"Missing required parameters for booking slots calculation"
|
|
11881
|
+
);
|
|
11882
|
+
}
|
|
11883
|
+
if (endDate <= startDate) {
|
|
11884
|
+
throw new Error("End date must be after start date");
|
|
11885
|
+
}
|
|
11886
|
+
const getAvailableBookingSlotsFunction = httpsCallable(
|
|
11887
|
+
this.functions,
|
|
11888
|
+
"getAvailableBookingSlots"
|
|
11889
|
+
);
|
|
11890
|
+
const result = await getAvailableBookingSlotsFunction({
|
|
11891
|
+
clinicId,
|
|
11892
|
+
practitionerId,
|
|
11893
|
+
procedureId,
|
|
11894
|
+
timeframe: {
|
|
11895
|
+
start: startDate.getTime(),
|
|
11896
|
+
// Convert to timestamp
|
|
11897
|
+
end: endDate.getTime()
|
|
11898
|
+
}
|
|
11899
|
+
});
|
|
11900
|
+
const response = result.data;
|
|
11901
|
+
if (!response.success) {
|
|
11902
|
+
throw new Error(
|
|
11903
|
+
response.error || "Failed to get available booking slots"
|
|
11904
|
+
);
|
|
11905
|
+
}
|
|
11906
|
+
const slots = response.availableSlots.map((slot) => ({
|
|
11907
|
+
start: new Date(slot.start)
|
|
11908
|
+
}));
|
|
11909
|
+
console.log(
|
|
11910
|
+
`[APPOINTMENT_SERVICE] Found ${slots.length} available booking slots`
|
|
11911
|
+
);
|
|
11912
|
+
return slots;
|
|
11913
|
+
} catch (error) {
|
|
11914
|
+
console.error(
|
|
11915
|
+
"[APPOINTMENT_SERVICE] Error getting available booking slots:",
|
|
11916
|
+
error
|
|
11917
|
+
);
|
|
11918
|
+
throw error;
|
|
11919
|
+
}
|
|
11920
|
+
}
|
|
11921
|
+
/**
|
|
11922
|
+
* Creates a new appointment.
|
|
11923
|
+
*
|
|
11924
|
+
* @param data Data needed to create the appointment
|
|
11925
|
+
* @returns The created appointment
|
|
11926
|
+
*/
|
|
11927
|
+
async createAppointment(data) {
|
|
11928
|
+
try {
|
|
11929
|
+
console.log("[APPOINTMENT_SERVICE] Creating appointment");
|
|
11930
|
+
const validatedData = await createAppointmentSchema.parseAsync(data);
|
|
11931
|
+
const aggregatedInfo = await fetchAggregatedInfoUtil(
|
|
11932
|
+
this.db,
|
|
11933
|
+
validatedData.clinicBranchId,
|
|
11934
|
+
validatedData.practitionerId,
|
|
11935
|
+
validatedData.patientId,
|
|
11936
|
+
validatedData.procedureId
|
|
11937
|
+
);
|
|
11938
|
+
const appointment = await createAppointmentUtil2(
|
|
11939
|
+
this.db,
|
|
11940
|
+
validatedData,
|
|
11941
|
+
aggregatedInfo,
|
|
11942
|
+
this.generateId.bind(this)
|
|
11943
|
+
);
|
|
11944
|
+
console.log(
|
|
11945
|
+
`[APPOINTMENT_SERVICE] Appointment created with ID: ${appointment.id}`
|
|
11946
|
+
);
|
|
11947
|
+
return appointment;
|
|
11948
|
+
} catch (error) {
|
|
11949
|
+
console.error("[APPOINTMENT_SERVICE] Error creating appointment:", error);
|
|
11950
|
+
throw error;
|
|
11951
|
+
}
|
|
11952
|
+
}
|
|
11953
|
+
/**
|
|
11954
|
+
* Gets an appointment by ID.
|
|
11955
|
+
*
|
|
11956
|
+
* @param appointmentId ID of the appointment to retrieve
|
|
11957
|
+
* @returns The appointment or null if not found
|
|
11958
|
+
*/
|
|
11959
|
+
async getAppointmentById(appointmentId) {
|
|
11960
|
+
try {
|
|
11961
|
+
console.log(
|
|
11962
|
+
`[APPOINTMENT_SERVICE] Getting appointment with ID: ${appointmentId}`
|
|
11963
|
+
);
|
|
11964
|
+
const appointment = await getAppointmentByIdUtil(this.db, appointmentId);
|
|
11965
|
+
console.log(
|
|
11966
|
+
`[APPOINTMENT_SERVICE] Appointment ${appointmentId} ${appointment ? "found" : "not found"}`
|
|
11967
|
+
);
|
|
11968
|
+
return appointment;
|
|
11969
|
+
} catch (error) {
|
|
11970
|
+
console.error(
|
|
11971
|
+
`[APPOINTMENT_SERVICE] Error getting appointment ${appointmentId}:`,
|
|
11972
|
+
error
|
|
11973
|
+
);
|
|
11974
|
+
throw error;
|
|
11975
|
+
}
|
|
11976
|
+
}
|
|
11977
|
+
/**
|
|
11978
|
+
* Updates an existing appointment.
|
|
11979
|
+
*
|
|
11980
|
+
* @param appointmentId ID of the appointment to update
|
|
11981
|
+
* @param data Update data for the appointment
|
|
11982
|
+
* @returns The updated appointment
|
|
11983
|
+
*/
|
|
11984
|
+
async updateAppointment(appointmentId, data) {
|
|
11985
|
+
try {
|
|
11986
|
+
console.log(
|
|
11987
|
+
`[APPOINTMENT_SERVICE] Updating appointment with ID: ${appointmentId}`
|
|
11988
|
+
);
|
|
11989
|
+
const validatedData = await updateAppointmentSchema.parseAsync(data);
|
|
11990
|
+
const updatedAppointment = await updateAppointmentUtil2(
|
|
11991
|
+
this.db,
|
|
11992
|
+
appointmentId,
|
|
11993
|
+
validatedData
|
|
11994
|
+
);
|
|
11995
|
+
console.log(
|
|
11996
|
+
`[APPOINTMENT_SERVICE] Appointment ${appointmentId} updated successfully`
|
|
11997
|
+
);
|
|
11998
|
+
return updatedAppointment;
|
|
11999
|
+
} catch (error) {
|
|
12000
|
+
console.error(
|
|
12001
|
+
`[APPOINTMENT_SERVICE] Error updating appointment ${appointmentId}:`,
|
|
12002
|
+
error
|
|
12003
|
+
);
|
|
12004
|
+
throw error;
|
|
12005
|
+
}
|
|
12006
|
+
}
|
|
12007
|
+
/**
|
|
12008
|
+
* Searches for appointments based on various criteria.
|
|
12009
|
+
*
|
|
12010
|
+
* @param params Search parameters
|
|
12011
|
+
* @returns Found appointments and the last document for pagination
|
|
12012
|
+
*/
|
|
12013
|
+
async searchAppointments(params) {
|
|
12014
|
+
try {
|
|
12015
|
+
console.log(
|
|
12016
|
+
"[APPOINTMENT_SERVICE] Searching appointments with params:",
|
|
12017
|
+
params
|
|
12018
|
+
);
|
|
12019
|
+
await searchAppointmentsSchema.parseAsync(params);
|
|
12020
|
+
const result = await searchAppointmentsUtil(this.db, params);
|
|
12021
|
+
console.log(
|
|
12022
|
+
`[APPOINTMENT_SERVICE] Found ${result.appointments.length} appointments`
|
|
12023
|
+
);
|
|
12024
|
+
return result;
|
|
12025
|
+
} catch (error) {
|
|
12026
|
+
console.error(
|
|
12027
|
+
"[APPOINTMENT_SERVICE] Error searching appointments:",
|
|
12028
|
+
error
|
|
12029
|
+
);
|
|
12030
|
+
throw error;
|
|
12031
|
+
}
|
|
12032
|
+
}
|
|
12033
|
+
/**
|
|
12034
|
+
* Gets appointments for a specific patient.
|
|
12035
|
+
*
|
|
12036
|
+
* @param patientId ID of the patient
|
|
12037
|
+
* @param options Optional parameters for filtering and pagination
|
|
12038
|
+
* @returns Found appointments and the last document for pagination
|
|
12039
|
+
*/
|
|
12040
|
+
async getPatientAppointments(patientId, options) {
|
|
12041
|
+
console.log(
|
|
12042
|
+
`[APPOINTMENT_SERVICE] Getting appointments for patient: ${patientId}`
|
|
12043
|
+
);
|
|
12044
|
+
const searchParams = {
|
|
12045
|
+
patientId,
|
|
12046
|
+
startDate: options == null ? void 0 : options.startDate,
|
|
12047
|
+
endDate: options == null ? void 0 : options.endDate,
|
|
12048
|
+
status: options == null ? void 0 : options.status,
|
|
12049
|
+
limit: options == null ? void 0 : options.limit,
|
|
12050
|
+
startAfter: options == null ? void 0 : options.startAfter
|
|
12051
|
+
};
|
|
12052
|
+
return this.searchAppointments(searchParams);
|
|
12053
|
+
}
|
|
12054
|
+
/**
|
|
12055
|
+
* Gets appointments for a specific practitioner.
|
|
12056
|
+
*
|
|
12057
|
+
* @param practitionerId ID of the practitioner
|
|
12058
|
+
* @param options Optional parameters for filtering and pagination
|
|
12059
|
+
* @returns Found appointments and the last document for pagination
|
|
12060
|
+
*/
|
|
12061
|
+
async getPractitionerAppointments(practitionerId, options) {
|
|
12062
|
+
console.log(
|
|
12063
|
+
`[APPOINTMENT_SERVICE] Getting appointments for practitioner: ${practitionerId}`
|
|
12064
|
+
);
|
|
12065
|
+
const searchParams = {
|
|
12066
|
+
practitionerId,
|
|
12067
|
+
startDate: options == null ? void 0 : options.startDate,
|
|
12068
|
+
endDate: options == null ? void 0 : options.endDate,
|
|
12069
|
+
status: options == null ? void 0 : options.status,
|
|
12070
|
+
limit: options == null ? void 0 : options.limit,
|
|
12071
|
+
startAfter: options == null ? void 0 : options.startAfter
|
|
12072
|
+
};
|
|
12073
|
+
return this.searchAppointments(searchParams);
|
|
12074
|
+
}
|
|
12075
|
+
/**
|
|
12076
|
+
* Gets appointments for a specific clinic.
|
|
12077
|
+
*
|
|
12078
|
+
* @param clinicBranchId ID of the clinic branch
|
|
12079
|
+
* @param options Optional parameters for filtering and pagination
|
|
12080
|
+
* @returns Found appointments and the last document for pagination
|
|
12081
|
+
*/
|
|
12082
|
+
async getClinicAppointments(clinicBranchId, options) {
|
|
12083
|
+
console.log(
|
|
12084
|
+
`[APPOINTMENT_SERVICE] Getting appointments for clinic: ${clinicBranchId}`
|
|
12085
|
+
);
|
|
12086
|
+
const searchParams = {
|
|
12087
|
+
clinicBranchId,
|
|
12088
|
+
practitionerId: options == null ? void 0 : options.practitionerId,
|
|
12089
|
+
startDate: options == null ? void 0 : options.startDate,
|
|
12090
|
+
endDate: options == null ? void 0 : options.endDate,
|
|
12091
|
+
status: options == null ? void 0 : options.status,
|
|
12092
|
+
limit: options == null ? void 0 : options.limit,
|
|
12093
|
+
startAfter: options == null ? void 0 : options.startAfter
|
|
12094
|
+
};
|
|
12095
|
+
return this.searchAppointments(searchParams);
|
|
12096
|
+
}
|
|
12097
|
+
/**
|
|
12098
|
+
* Updates the status of an appointment.
|
|
12099
|
+
*
|
|
12100
|
+
* @param appointmentId ID of the appointment
|
|
12101
|
+
* @param newStatus New status to set
|
|
12102
|
+
* @param cancellationReason Required if canceling the appointment
|
|
12103
|
+
* @param canceledBy Required if canceling the appointment
|
|
12104
|
+
* @returns The updated appointment
|
|
12105
|
+
*/
|
|
12106
|
+
async updateAppointmentStatus(appointmentId, newStatus, cancellationReason, canceledBy) {
|
|
12107
|
+
console.log(
|
|
12108
|
+
`[APPOINTMENT_SERVICE] Updating status of appointment ${appointmentId} to ${newStatus}`
|
|
12109
|
+
);
|
|
12110
|
+
const updateData = { status: newStatus };
|
|
12111
|
+
if (newStatus === "canceled_clinic" /* CANCELED_CLINIC */ || newStatus === "canceled_patient" /* CANCELED_PATIENT */) {
|
|
12112
|
+
if (!cancellationReason) {
|
|
12113
|
+
throw new Error(
|
|
12114
|
+
"Cancellation reason is required when canceling an appointment"
|
|
12115
|
+
);
|
|
12116
|
+
}
|
|
12117
|
+
if (!canceledBy) {
|
|
12118
|
+
throw new Error(
|
|
12119
|
+
"Canceled by is required when canceling an appointment"
|
|
12120
|
+
);
|
|
12121
|
+
}
|
|
12122
|
+
updateData.cancellationReason = cancellationReason;
|
|
12123
|
+
updateData.canceledBy = canceledBy;
|
|
12124
|
+
}
|
|
12125
|
+
if (newStatus === "confirmed" /* CONFIRMED */) {
|
|
12126
|
+
updateData.confirmationTime = Timestamp28.now();
|
|
12127
|
+
}
|
|
12128
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
12129
|
+
}
|
|
12130
|
+
/**
|
|
12131
|
+
* Confirms an appointment.
|
|
12132
|
+
*
|
|
12133
|
+
* @param appointmentId ID of the appointment to confirm
|
|
12134
|
+
* @returns The confirmed appointment
|
|
12135
|
+
*/
|
|
12136
|
+
async confirmAppointment(appointmentId) {
|
|
12137
|
+
console.log(
|
|
12138
|
+
`[APPOINTMENT_SERVICE] Confirming appointment: ${appointmentId}`
|
|
12139
|
+
);
|
|
12140
|
+
return this.updateAppointmentStatus(
|
|
12141
|
+
appointmentId,
|
|
12142
|
+
"confirmed" /* CONFIRMED */
|
|
12143
|
+
);
|
|
12144
|
+
}
|
|
12145
|
+
/**
|
|
12146
|
+
* Cancels an appointment from the clinic side.
|
|
12147
|
+
*
|
|
12148
|
+
* @param appointmentId ID of the appointment to cancel
|
|
12149
|
+
* @param reason Reason for cancellation
|
|
12150
|
+
* @returns The canceled appointment
|
|
12151
|
+
*/
|
|
12152
|
+
async cancelAppointmentByClinic(appointmentId, reason) {
|
|
12153
|
+
console.log(
|
|
12154
|
+
`[APPOINTMENT_SERVICE] Canceling appointment by clinic: ${appointmentId}`
|
|
12155
|
+
);
|
|
12156
|
+
return this.updateAppointmentStatus(
|
|
12157
|
+
appointmentId,
|
|
12158
|
+
"canceled_clinic" /* CANCELED_CLINIC */,
|
|
12159
|
+
reason,
|
|
12160
|
+
"clinic"
|
|
12161
|
+
);
|
|
12162
|
+
}
|
|
12163
|
+
/**
|
|
12164
|
+
* Cancels an appointment from the patient side.
|
|
12165
|
+
*
|
|
12166
|
+
* @param appointmentId ID of the appointment to cancel
|
|
12167
|
+
* @param reason Reason for cancellation
|
|
12168
|
+
* @returns The canceled appointment
|
|
12169
|
+
*/
|
|
12170
|
+
async cancelAppointmentByPatient(appointmentId, reason) {
|
|
12171
|
+
console.log(
|
|
12172
|
+
`[APPOINTMENT_SERVICE] Canceling appointment by patient: ${appointmentId}`
|
|
12173
|
+
);
|
|
12174
|
+
return this.updateAppointmentStatus(
|
|
12175
|
+
appointmentId,
|
|
12176
|
+
"canceled_patient" /* CANCELED_PATIENT */,
|
|
12177
|
+
reason,
|
|
12178
|
+
"patient"
|
|
12179
|
+
);
|
|
12180
|
+
}
|
|
12181
|
+
/**
|
|
12182
|
+
* Marks an appointment as checked in.
|
|
12183
|
+
*
|
|
12184
|
+
* @param appointmentId ID of the appointment
|
|
12185
|
+
* @returns The updated appointment
|
|
12186
|
+
*/
|
|
12187
|
+
async checkInAppointment(appointmentId) {
|
|
12188
|
+
console.log(
|
|
12189
|
+
`[APPOINTMENT_SERVICE] Checking in appointment: ${appointmentId}`
|
|
12190
|
+
);
|
|
12191
|
+
return this.updateAppointmentStatus(
|
|
12192
|
+
appointmentId,
|
|
12193
|
+
"checked_in" /* CHECKED_IN */
|
|
12194
|
+
);
|
|
12195
|
+
}
|
|
12196
|
+
/**
|
|
12197
|
+
* Marks an appointment as in progress.
|
|
12198
|
+
*
|
|
12199
|
+
* @param appointmentId ID of the appointment
|
|
12200
|
+
* @returns The updated appointment
|
|
12201
|
+
*/
|
|
12202
|
+
async startAppointment(appointmentId) {
|
|
12203
|
+
console.log(`[APPOINTMENT_SERVICE] Starting appointment: ${appointmentId}`);
|
|
12204
|
+
return this.updateAppointmentStatus(
|
|
12205
|
+
appointmentId,
|
|
12206
|
+
"in_progress" /* IN_PROGRESS */
|
|
12207
|
+
);
|
|
12208
|
+
}
|
|
12209
|
+
/**
|
|
12210
|
+
* Marks an appointment as completed.
|
|
12211
|
+
*
|
|
12212
|
+
* @param appointmentId ID of the appointment
|
|
12213
|
+
* @param actualDurationMinutes Actual duration of the appointment in minutes
|
|
12214
|
+
* @returns The updated appointment
|
|
12215
|
+
*/
|
|
12216
|
+
async completeAppointment(appointmentId, actualDurationMinutes) {
|
|
12217
|
+
console.log(
|
|
12218
|
+
`[APPOINTMENT_SERVICE] Completing appointment: ${appointmentId}`
|
|
12219
|
+
);
|
|
12220
|
+
const updateData = {
|
|
12221
|
+
status: "completed" /* COMPLETED */,
|
|
12222
|
+
actualDurationMinutes
|
|
12223
|
+
};
|
|
12224
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
12225
|
+
}
|
|
12226
|
+
/**
|
|
12227
|
+
* Marks an appointment as no-show.
|
|
12228
|
+
*
|
|
12229
|
+
* @param appointmentId ID of the appointment
|
|
12230
|
+
* @returns The updated appointment
|
|
12231
|
+
*/
|
|
12232
|
+
async markNoShow(appointmentId) {
|
|
12233
|
+
console.log(
|
|
12234
|
+
`[APPOINTMENT_SERVICE] Marking appointment as no-show: ${appointmentId}`
|
|
12235
|
+
);
|
|
12236
|
+
return this.updateAppointmentStatus(
|
|
12237
|
+
appointmentId,
|
|
12238
|
+
"no_show" /* NO_SHOW */
|
|
12239
|
+
);
|
|
12240
|
+
}
|
|
12241
|
+
/**
|
|
12242
|
+
* Updates the payment status of an appointment.
|
|
12243
|
+
*
|
|
12244
|
+
* @param appointmentId ID of the appointment
|
|
12245
|
+
* @param paymentStatus New payment status
|
|
12246
|
+
* @param paymentTransactionId Optional transaction ID for the payment
|
|
12247
|
+
* @returns The updated appointment
|
|
12248
|
+
*/
|
|
12249
|
+
async updatePaymentStatus(appointmentId, paymentStatus, paymentTransactionId) {
|
|
12250
|
+
console.log(
|
|
12251
|
+
`[APPOINTMENT_SERVICE] Updating payment status of appointment ${appointmentId} to ${paymentStatus}`
|
|
12252
|
+
);
|
|
12253
|
+
const updateData = {
|
|
12254
|
+
paymentStatus,
|
|
12255
|
+
paymentTransactionId: paymentTransactionId || null
|
|
12256
|
+
};
|
|
12257
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
12258
|
+
}
|
|
12259
|
+
/**
|
|
12260
|
+
* Marks pre-procedure requirements as completed.
|
|
12261
|
+
*
|
|
12262
|
+
* @param appointmentId ID of the appointment
|
|
12263
|
+
* @param requirementIds IDs of the requirements to mark as completed
|
|
12264
|
+
* @returns The updated appointment
|
|
12265
|
+
*/
|
|
12266
|
+
async completePreRequirements(appointmentId, requirementIds) {
|
|
12267
|
+
console.log(
|
|
12268
|
+
`[APPOINTMENT_SERVICE] Marking pre-requirements as completed for appointment: ${appointmentId}`
|
|
12269
|
+
);
|
|
12270
|
+
const updateData = {
|
|
12271
|
+
completedPreRequirements: requirementIds
|
|
12272
|
+
};
|
|
12273
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
12274
|
+
}
|
|
12275
|
+
/**
|
|
12276
|
+
* Marks post-procedure requirements as completed.
|
|
12277
|
+
*
|
|
12278
|
+
* @param appointmentId ID of the appointment
|
|
12279
|
+
* @param requirementIds IDs of the requirements to mark as completed
|
|
12280
|
+
* @returns The updated appointment
|
|
12281
|
+
*/
|
|
12282
|
+
async completePostRequirements(appointmentId, requirementIds) {
|
|
12283
|
+
console.log(
|
|
12284
|
+
`[APPOINTMENT_SERVICE] Marking post-requirements as completed for appointment: ${appointmentId}`
|
|
12285
|
+
);
|
|
12286
|
+
const updateData = {
|
|
12287
|
+
completedPostRequirements: requirementIds
|
|
12288
|
+
};
|
|
12289
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
12290
|
+
}
|
|
12291
|
+
/**
|
|
12292
|
+
* Updates the internal notes of an appointment.
|
|
12293
|
+
*
|
|
12294
|
+
* @param appointmentId ID of the appointment
|
|
12295
|
+
* @param notes Updated internal notes
|
|
12296
|
+
* @returns The updated appointment
|
|
12297
|
+
*/
|
|
12298
|
+
async updateInternalNotes(appointmentId, notes) {
|
|
12299
|
+
console.log(
|
|
12300
|
+
`[APPOINTMENT_SERVICE] Updating internal notes for appointment: ${appointmentId}`
|
|
12301
|
+
);
|
|
12302
|
+
const updateData = {
|
|
12303
|
+
internalNotes: notes
|
|
12304
|
+
};
|
|
12305
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
12306
|
+
}
|
|
12307
|
+
};
|
|
12308
|
+
|
|
12309
|
+
// src/backoffice/services/brand.service.ts
|
|
12310
|
+
import {
|
|
12311
|
+
addDoc as addDoc3,
|
|
12312
|
+
collection as collection24,
|
|
12313
|
+
doc as doc25,
|
|
11456
12314
|
getDoc as getDoc27,
|
|
11457
12315
|
getDocs as getDocs24,
|
|
11458
12316
|
query as query24,
|
|
@@ -11460,6 +12318,90 @@ import {
|
|
|
11460
12318
|
where as where24
|
|
11461
12319
|
} from "firebase/firestore";
|
|
11462
12320
|
|
|
12321
|
+
// src/backoffice/types/brand.types.ts
|
|
12322
|
+
var BRANDS_COLLECTION = "brands";
|
|
12323
|
+
|
|
12324
|
+
// src/backoffice/services/brand.service.ts
|
|
12325
|
+
var BrandService = class extends BaseService {
|
|
12326
|
+
/**
|
|
12327
|
+
* Gets reference to brands collection
|
|
12328
|
+
*/
|
|
12329
|
+
getBrandsRef() {
|
|
12330
|
+
return collection24(this.db, BRANDS_COLLECTION);
|
|
12331
|
+
}
|
|
12332
|
+
/**
|
|
12333
|
+
* Creates a new brand
|
|
12334
|
+
*/
|
|
12335
|
+
async create(brand) {
|
|
12336
|
+
const now = /* @__PURE__ */ new Date();
|
|
12337
|
+
const newBrand = {
|
|
12338
|
+
...brand,
|
|
12339
|
+
createdAt: now,
|
|
12340
|
+
updatedAt: now,
|
|
12341
|
+
isActive: true
|
|
12342
|
+
};
|
|
12343
|
+
const docRef = await addDoc3(this.getBrandsRef(), newBrand);
|
|
12344
|
+
return { id: docRef.id, ...newBrand };
|
|
12345
|
+
}
|
|
12346
|
+
/**
|
|
12347
|
+
* Gets all active brands
|
|
12348
|
+
*/
|
|
12349
|
+
async getAll() {
|
|
12350
|
+
const q = query24(this.getBrandsRef(), where24("isActive", "==", true));
|
|
12351
|
+
const snapshot = await getDocs24(q);
|
|
12352
|
+
return snapshot.docs.map(
|
|
12353
|
+
(doc30) => ({
|
|
12354
|
+
id: doc30.id,
|
|
12355
|
+
...doc30.data()
|
|
12356
|
+
})
|
|
12357
|
+
);
|
|
12358
|
+
}
|
|
12359
|
+
/**
|
|
12360
|
+
* Updates a brand
|
|
12361
|
+
*/
|
|
12362
|
+
async update(brandId, brand) {
|
|
12363
|
+
const updateData = {
|
|
12364
|
+
...brand,
|
|
12365
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
12366
|
+
};
|
|
12367
|
+
const docRef = doc25(this.getBrandsRef(), brandId);
|
|
12368
|
+
await updateDoc26(docRef, updateData);
|
|
12369
|
+
return this.getById(brandId);
|
|
12370
|
+
}
|
|
12371
|
+
/**
|
|
12372
|
+
* Soft deletes a brand
|
|
12373
|
+
*/
|
|
12374
|
+
async delete(brandId) {
|
|
12375
|
+
await this.update(brandId, {
|
|
12376
|
+
isActive: false
|
|
12377
|
+
});
|
|
12378
|
+
}
|
|
12379
|
+
/**
|
|
12380
|
+
* Gets a brand by ID
|
|
12381
|
+
*/
|
|
12382
|
+
async getById(brandId) {
|
|
12383
|
+
const docRef = doc25(this.getBrandsRef(), brandId);
|
|
12384
|
+
const docSnap = await getDoc27(docRef);
|
|
12385
|
+
if (!docSnap.exists()) return null;
|
|
12386
|
+
return {
|
|
12387
|
+
id: docSnap.id,
|
|
12388
|
+
...docSnap.data()
|
|
12389
|
+
};
|
|
12390
|
+
}
|
|
12391
|
+
};
|
|
12392
|
+
|
|
12393
|
+
// src/backoffice/services/category.service.ts
|
|
12394
|
+
import {
|
|
12395
|
+
addDoc as addDoc4,
|
|
12396
|
+
collection as collection25,
|
|
12397
|
+
doc as doc26,
|
|
12398
|
+
getDoc as getDoc28,
|
|
12399
|
+
getDocs as getDocs25,
|
|
12400
|
+
query as query25,
|
|
12401
|
+
updateDoc as updateDoc27,
|
|
12402
|
+
where as where25
|
|
12403
|
+
} from "firebase/firestore";
|
|
12404
|
+
|
|
11463
12405
|
// src/backoffice/types/category.types.ts
|
|
11464
12406
|
var CATEGORIES_COLLECTION = "backoffice_categories";
|
|
11465
12407
|
|
|
@@ -11469,7 +12411,7 @@ var CategoryService = class extends BaseService {
|
|
|
11469
12411
|
* Referenca na Firestore kolekciju kategorija
|
|
11470
12412
|
*/
|
|
11471
12413
|
get categoriesRef() {
|
|
11472
|
-
return
|
|
12414
|
+
return collection25(this.db, CATEGORIES_COLLECTION);
|
|
11473
12415
|
}
|
|
11474
12416
|
/**
|
|
11475
12417
|
* Kreira novu kategoriju u sistemu
|
|
@@ -11492,12 +12434,12 @@ var CategoryService = class extends BaseService {
|
|
|
11492
12434
|
* @returns Lista aktivnih kategorija
|
|
11493
12435
|
*/
|
|
11494
12436
|
async getAll() {
|
|
11495
|
-
const q =
|
|
11496
|
-
const snapshot = await
|
|
12437
|
+
const q = query25(this.categoriesRef, where25("isActive", "==", true));
|
|
12438
|
+
const snapshot = await getDocs25(q);
|
|
11497
12439
|
return snapshot.docs.map(
|
|
11498
|
-
(
|
|
11499
|
-
id:
|
|
11500
|
-
...
|
|
12440
|
+
(doc30) => ({
|
|
12441
|
+
id: doc30.id,
|
|
12442
|
+
...doc30.data()
|
|
11501
12443
|
})
|
|
11502
12444
|
);
|
|
11503
12445
|
}
|
|
@@ -11507,16 +12449,16 @@ var CategoryService = class extends BaseService {
|
|
|
11507
12449
|
* @returns Lista kategorija koje pripadaju traženoj familiji
|
|
11508
12450
|
*/
|
|
11509
12451
|
async getAllByFamily(family) {
|
|
11510
|
-
const q =
|
|
12452
|
+
const q = query25(
|
|
11511
12453
|
this.categoriesRef,
|
|
11512
|
-
|
|
11513
|
-
|
|
12454
|
+
where25("family", "==", family),
|
|
12455
|
+
where25("isActive", "==", true)
|
|
11514
12456
|
);
|
|
11515
|
-
const snapshot = await
|
|
12457
|
+
const snapshot = await getDocs25(q);
|
|
11516
12458
|
return snapshot.docs.map(
|
|
11517
|
-
(
|
|
11518
|
-
id:
|
|
11519
|
-
...
|
|
12459
|
+
(doc30) => ({
|
|
12460
|
+
id: doc30.id,
|
|
12461
|
+
...doc30.data()
|
|
11520
12462
|
})
|
|
11521
12463
|
);
|
|
11522
12464
|
}
|
|
@@ -11531,8 +12473,8 @@ var CategoryService = class extends BaseService {
|
|
|
11531
12473
|
...category,
|
|
11532
12474
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11533
12475
|
};
|
|
11534
|
-
const docRef =
|
|
11535
|
-
await
|
|
12476
|
+
const docRef = doc26(this.categoriesRef, id);
|
|
12477
|
+
await updateDoc27(docRef, updateData);
|
|
11536
12478
|
return this.getById(id);
|
|
11537
12479
|
}
|
|
11538
12480
|
/**
|
|
@@ -11548,8 +12490,8 @@ var CategoryService = class extends BaseService {
|
|
|
11548
12490
|
* @returns Kategorija ili null ako ne postoji
|
|
11549
12491
|
*/
|
|
11550
12492
|
async getById(id) {
|
|
11551
|
-
const docRef =
|
|
11552
|
-
const docSnap = await
|
|
12493
|
+
const docRef = doc26(this.categoriesRef, id);
|
|
12494
|
+
const docSnap = await getDoc28(docRef);
|
|
11553
12495
|
if (!docSnap.exists()) return null;
|
|
11554
12496
|
return {
|
|
11555
12497
|
id: docSnap.id,
|
|
@@ -11561,13 +12503,13 @@ var CategoryService = class extends BaseService {
|
|
|
11561
12503
|
// src/backoffice/services/subcategory.service.ts
|
|
11562
12504
|
import {
|
|
11563
12505
|
addDoc as addDoc5,
|
|
11564
|
-
collection as
|
|
11565
|
-
doc as
|
|
11566
|
-
getDoc as
|
|
11567
|
-
getDocs as
|
|
11568
|
-
query as
|
|
11569
|
-
updateDoc as
|
|
11570
|
-
where as
|
|
12506
|
+
collection as collection26,
|
|
12507
|
+
doc as doc27,
|
|
12508
|
+
getDoc as getDoc29,
|
|
12509
|
+
getDocs as getDocs26,
|
|
12510
|
+
query as query26,
|
|
12511
|
+
updateDoc as updateDoc28,
|
|
12512
|
+
where as where26
|
|
11571
12513
|
} from "firebase/firestore";
|
|
11572
12514
|
|
|
11573
12515
|
// src/backoffice/types/subcategory.types.ts
|
|
@@ -11580,7 +12522,7 @@ var SubcategoryService = class extends BaseService {
|
|
|
11580
12522
|
* @param categoryId - ID roditeljske kategorije
|
|
11581
12523
|
*/
|
|
11582
12524
|
getSubcategoriesRef(categoryId) {
|
|
11583
|
-
return
|
|
12525
|
+
return collection26(
|
|
11584
12526
|
this.db,
|
|
11585
12527
|
CATEGORIES_COLLECTION,
|
|
11586
12528
|
categoryId,
|
|
@@ -11614,15 +12556,15 @@ var SubcategoryService = class extends BaseService {
|
|
|
11614
12556
|
* @returns Lista aktivnih podkategorija
|
|
11615
12557
|
*/
|
|
11616
12558
|
async getAllByCategoryId(categoryId) {
|
|
11617
|
-
const q =
|
|
12559
|
+
const q = query26(
|
|
11618
12560
|
this.getSubcategoriesRef(categoryId),
|
|
11619
|
-
|
|
12561
|
+
where26("isActive", "==", true)
|
|
11620
12562
|
);
|
|
11621
|
-
const snapshot = await
|
|
12563
|
+
const snapshot = await getDocs26(q);
|
|
11622
12564
|
return snapshot.docs.map(
|
|
11623
|
-
(
|
|
11624
|
-
id:
|
|
11625
|
-
...
|
|
12565
|
+
(doc30) => ({
|
|
12566
|
+
id: doc30.id,
|
|
12567
|
+
...doc30.data()
|
|
11626
12568
|
})
|
|
11627
12569
|
);
|
|
11628
12570
|
}
|
|
@@ -11638,8 +12580,8 @@ var SubcategoryService = class extends BaseService {
|
|
|
11638
12580
|
...subcategory,
|
|
11639
12581
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11640
12582
|
};
|
|
11641
|
-
const docRef =
|
|
11642
|
-
await
|
|
12583
|
+
const docRef = doc27(this.getSubcategoriesRef(categoryId), subcategoryId);
|
|
12584
|
+
await updateDoc28(docRef, updateData);
|
|
11643
12585
|
return this.getById(categoryId, subcategoryId);
|
|
11644
12586
|
}
|
|
11645
12587
|
/**
|
|
@@ -11657,8 +12599,8 @@ var SubcategoryService = class extends BaseService {
|
|
|
11657
12599
|
* @returns Podkategorija ili null ako ne postoji
|
|
11658
12600
|
*/
|
|
11659
12601
|
async getById(categoryId, subcategoryId) {
|
|
11660
|
-
const docRef =
|
|
11661
|
-
const docSnap = await
|
|
12602
|
+
const docRef = doc27(this.getSubcategoriesRef(categoryId), subcategoryId);
|
|
12603
|
+
const docSnap = await getDoc29(docRef);
|
|
11662
12604
|
if (!docSnap.exists()) return null;
|
|
11663
12605
|
return {
|
|
11664
12606
|
id: docSnap.id,
|
|
@@ -11670,21 +12612,16 @@ var SubcategoryService = class extends BaseService {
|
|
|
11670
12612
|
// src/backoffice/services/technology.service.ts
|
|
11671
12613
|
import {
|
|
11672
12614
|
addDoc as addDoc6,
|
|
11673
|
-
collection as
|
|
11674
|
-
doc as
|
|
11675
|
-
getDoc as
|
|
11676
|
-
getDocs as
|
|
11677
|
-
query as
|
|
11678
|
-
updateDoc as
|
|
11679
|
-
where as
|
|
12615
|
+
collection as collection27,
|
|
12616
|
+
doc as doc28,
|
|
12617
|
+
getDoc as getDoc30,
|
|
12618
|
+
getDocs as getDocs27,
|
|
12619
|
+
query as query27,
|
|
12620
|
+
updateDoc as updateDoc29,
|
|
12621
|
+
where as where27,
|
|
11680
12622
|
arrayUnion as arrayUnion8,
|
|
11681
12623
|
arrayRemove as arrayRemove7
|
|
11682
12624
|
} from "firebase/firestore";
|
|
11683
|
-
|
|
11684
|
-
// src/backoffice/types/technology.types.ts
|
|
11685
|
-
var TECHNOLOGIES_COLLECTION = "technologies";
|
|
11686
|
-
|
|
11687
|
-
// src/backoffice/services/technology.service.ts
|
|
11688
12625
|
var DEFAULT_CERTIFICATION_REQUIREMENT = {
|
|
11689
12626
|
minimumLevel: "aesthetician" /* AESTHETICIAN */,
|
|
11690
12627
|
requiredSpecialties: []
|
|
@@ -11694,7 +12631,7 @@ var TechnologyService = class extends BaseService {
|
|
|
11694
12631
|
* Vraća referencu na Firestore kolekciju tehnologija
|
|
11695
12632
|
*/
|
|
11696
12633
|
getTechnologiesRef() {
|
|
11697
|
-
return
|
|
12634
|
+
return collection27(this.db, TECHNOLOGIES_COLLECTION);
|
|
11698
12635
|
}
|
|
11699
12636
|
/**
|
|
11700
12637
|
* Kreira novu tehnologiju
|
|
@@ -11725,12 +12662,12 @@ var TechnologyService = class extends BaseService {
|
|
|
11725
12662
|
* @returns Lista aktivnih tehnologija
|
|
11726
12663
|
*/
|
|
11727
12664
|
async getAll() {
|
|
11728
|
-
const q =
|
|
11729
|
-
const snapshot = await
|
|
12665
|
+
const q = query27(this.getTechnologiesRef(), where27("isActive", "==", true));
|
|
12666
|
+
const snapshot = await getDocs27(q);
|
|
11730
12667
|
return snapshot.docs.map(
|
|
11731
|
-
(
|
|
11732
|
-
id:
|
|
11733
|
-
...
|
|
12668
|
+
(doc30) => ({
|
|
12669
|
+
id: doc30.id,
|
|
12670
|
+
...doc30.data()
|
|
11734
12671
|
})
|
|
11735
12672
|
);
|
|
11736
12673
|
}
|
|
@@ -11740,16 +12677,16 @@ var TechnologyService = class extends BaseService {
|
|
|
11740
12677
|
* @returns Lista aktivnih tehnologija
|
|
11741
12678
|
*/
|
|
11742
12679
|
async getAllByFamily(family) {
|
|
11743
|
-
const q =
|
|
12680
|
+
const q = query27(
|
|
11744
12681
|
this.getTechnologiesRef(),
|
|
11745
|
-
|
|
11746
|
-
|
|
12682
|
+
where27("isActive", "==", true),
|
|
12683
|
+
where27("family", "==", family)
|
|
11747
12684
|
);
|
|
11748
|
-
const snapshot = await
|
|
12685
|
+
const snapshot = await getDocs27(q);
|
|
11749
12686
|
return snapshot.docs.map(
|
|
11750
|
-
(
|
|
11751
|
-
id:
|
|
11752
|
-
...
|
|
12687
|
+
(doc30) => ({
|
|
12688
|
+
id: doc30.id,
|
|
12689
|
+
...doc30.data()
|
|
11753
12690
|
})
|
|
11754
12691
|
);
|
|
11755
12692
|
}
|
|
@@ -11759,16 +12696,16 @@ var TechnologyService = class extends BaseService {
|
|
|
11759
12696
|
* @returns Lista aktivnih tehnologija
|
|
11760
12697
|
*/
|
|
11761
12698
|
async getAllByCategoryId(categoryId) {
|
|
11762
|
-
const q =
|
|
12699
|
+
const q = query27(
|
|
11763
12700
|
this.getTechnologiesRef(),
|
|
11764
|
-
|
|
11765
|
-
|
|
12701
|
+
where27("isActive", "==", true),
|
|
12702
|
+
where27("categoryId", "==", categoryId)
|
|
11766
12703
|
);
|
|
11767
|
-
const snapshot = await
|
|
12704
|
+
const snapshot = await getDocs27(q);
|
|
11768
12705
|
return snapshot.docs.map(
|
|
11769
|
-
(
|
|
11770
|
-
id:
|
|
11771
|
-
...
|
|
12706
|
+
(doc30) => ({
|
|
12707
|
+
id: doc30.id,
|
|
12708
|
+
...doc30.data()
|
|
11772
12709
|
})
|
|
11773
12710
|
);
|
|
11774
12711
|
}
|
|
@@ -11778,16 +12715,16 @@ var TechnologyService = class extends BaseService {
|
|
|
11778
12715
|
* @returns Lista aktivnih tehnologija
|
|
11779
12716
|
*/
|
|
11780
12717
|
async getAllBySubcategoryId(subcategoryId) {
|
|
11781
|
-
const q =
|
|
12718
|
+
const q = query27(
|
|
11782
12719
|
this.getTechnologiesRef(),
|
|
11783
|
-
|
|
11784
|
-
|
|
12720
|
+
where27("isActive", "==", true),
|
|
12721
|
+
where27("subcategoryId", "==", subcategoryId)
|
|
11785
12722
|
);
|
|
11786
|
-
const snapshot = await
|
|
12723
|
+
const snapshot = await getDocs27(q);
|
|
11787
12724
|
return snapshot.docs.map(
|
|
11788
|
-
(
|
|
11789
|
-
id:
|
|
11790
|
-
...
|
|
12725
|
+
(doc30) => ({
|
|
12726
|
+
id: doc30.id,
|
|
12727
|
+
...doc30.data()
|
|
11791
12728
|
})
|
|
11792
12729
|
);
|
|
11793
12730
|
}
|
|
@@ -11802,8 +12739,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11802
12739
|
...technology,
|
|
11803
12740
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11804
12741
|
};
|
|
11805
|
-
const docRef =
|
|
11806
|
-
await
|
|
12742
|
+
const docRef = doc28(this.getTechnologiesRef(), technologyId);
|
|
12743
|
+
await updateDoc29(docRef, updateData);
|
|
11807
12744
|
return this.getById(technologyId);
|
|
11808
12745
|
}
|
|
11809
12746
|
/**
|
|
@@ -11821,8 +12758,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11821
12758
|
* @returns Tehnologija ili null ako ne postoji
|
|
11822
12759
|
*/
|
|
11823
12760
|
async getById(technologyId) {
|
|
11824
|
-
const docRef =
|
|
11825
|
-
const docSnap = await
|
|
12761
|
+
const docRef = doc28(this.getTechnologiesRef(), technologyId);
|
|
12762
|
+
const docSnap = await getDoc30(docRef);
|
|
11826
12763
|
if (!docSnap.exists()) return null;
|
|
11827
12764
|
return {
|
|
11828
12765
|
id: docSnap.id,
|
|
@@ -11836,9 +12773,9 @@ var TechnologyService = class extends BaseService {
|
|
|
11836
12773
|
* @returns Ažurirana tehnologija sa novim zahtevom
|
|
11837
12774
|
*/
|
|
11838
12775
|
async addRequirement(technologyId, requirement) {
|
|
11839
|
-
const docRef =
|
|
12776
|
+
const docRef = doc28(this.getTechnologiesRef(), technologyId);
|
|
11840
12777
|
const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
|
|
11841
|
-
await
|
|
12778
|
+
await updateDoc29(docRef, {
|
|
11842
12779
|
[requirementType]: arrayUnion8(requirement),
|
|
11843
12780
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11844
12781
|
});
|
|
@@ -11851,9 +12788,9 @@ var TechnologyService = class extends BaseService {
|
|
|
11851
12788
|
* @returns Ažurirana tehnologija bez uklonjenog zahteva
|
|
11852
12789
|
*/
|
|
11853
12790
|
async removeRequirement(technologyId, requirement) {
|
|
11854
|
-
const docRef =
|
|
12791
|
+
const docRef = doc28(this.getTechnologiesRef(), technologyId);
|
|
11855
12792
|
const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
|
|
11856
|
-
await
|
|
12793
|
+
await updateDoc29(docRef, {
|
|
11857
12794
|
[requirementType]: arrayRemove7(requirement),
|
|
11858
12795
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11859
12796
|
});
|
|
@@ -11891,8 +12828,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11891
12828
|
* @returns Ažurirana tehnologija
|
|
11892
12829
|
*/
|
|
11893
12830
|
async addBlockingCondition(technologyId, condition) {
|
|
11894
|
-
const docRef =
|
|
11895
|
-
await
|
|
12831
|
+
const docRef = doc28(this.getTechnologiesRef(), technologyId);
|
|
12832
|
+
await updateDoc29(docRef, {
|
|
11896
12833
|
blockingConditions: arrayUnion8(condition),
|
|
11897
12834
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11898
12835
|
});
|
|
@@ -11905,8 +12842,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11905
12842
|
* @returns Ažurirana tehnologija
|
|
11906
12843
|
*/
|
|
11907
12844
|
async removeBlockingCondition(technologyId, condition) {
|
|
11908
|
-
const docRef =
|
|
11909
|
-
await
|
|
12845
|
+
const docRef = doc28(this.getTechnologiesRef(), technologyId);
|
|
12846
|
+
await updateDoc29(docRef, {
|
|
11910
12847
|
blockingConditions: arrayRemove7(condition),
|
|
11911
12848
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11912
12849
|
});
|
|
@@ -11919,8 +12856,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11919
12856
|
* @returns Ažurirana tehnologija
|
|
11920
12857
|
*/
|
|
11921
12858
|
async addContraindication(technologyId, contraindication) {
|
|
11922
|
-
const docRef =
|
|
11923
|
-
await
|
|
12859
|
+
const docRef = doc28(this.getTechnologiesRef(), technologyId);
|
|
12860
|
+
await updateDoc29(docRef, {
|
|
11924
12861
|
contraindications: arrayUnion8(contraindication),
|
|
11925
12862
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11926
12863
|
});
|
|
@@ -11933,8 +12870,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11933
12870
|
* @returns Ažurirana tehnologija
|
|
11934
12871
|
*/
|
|
11935
12872
|
async removeContraindication(technologyId, contraindication) {
|
|
11936
|
-
const docRef =
|
|
11937
|
-
await
|
|
12873
|
+
const docRef = doc28(this.getTechnologiesRef(), technologyId);
|
|
12874
|
+
await updateDoc29(docRef, {
|
|
11938
12875
|
contraindications: arrayRemove7(contraindication),
|
|
11939
12876
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11940
12877
|
});
|
|
@@ -11947,8 +12884,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11947
12884
|
* @returns Ažurirana tehnologija
|
|
11948
12885
|
*/
|
|
11949
12886
|
async addBenefit(technologyId, benefit) {
|
|
11950
|
-
const docRef =
|
|
11951
|
-
await
|
|
12887
|
+
const docRef = doc28(this.getTechnologiesRef(), technologyId);
|
|
12888
|
+
await updateDoc29(docRef, {
|
|
11952
12889
|
benefits: arrayUnion8(benefit),
|
|
11953
12890
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11954
12891
|
});
|
|
@@ -11961,8 +12898,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11961
12898
|
* @returns Ažurirana tehnologija
|
|
11962
12899
|
*/
|
|
11963
12900
|
async removeBenefit(technologyId, benefit) {
|
|
11964
|
-
const docRef =
|
|
11965
|
-
await
|
|
12901
|
+
const docRef = doc28(this.getTechnologiesRef(), technologyId);
|
|
12902
|
+
await updateDoc29(docRef, {
|
|
11966
12903
|
benefits: arrayRemove7(benefit),
|
|
11967
12904
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11968
12905
|
});
|
|
@@ -12002,8 +12939,8 @@ var TechnologyService = class extends BaseService {
|
|
|
12002
12939
|
* @returns Ažurirana tehnologija
|
|
12003
12940
|
*/
|
|
12004
12941
|
async updateCertificationRequirement(technologyId, certificationRequirement) {
|
|
12005
|
-
const docRef =
|
|
12006
|
-
await
|
|
12942
|
+
const docRef = doc28(this.getTechnologiesRef(), technologyId);
|
|
12943
|
+
await updateDoc29(docRef, {
|
|
12007
12944
|
certificationRequirement,
|
|
12008
12945
|
updatedAt: /* @__PURE__ */ new Date()
|
|
12009
12946
|
});
|
|
@@ -12105,13 +13042,13 @@ var TechnologyService = class extends BaseService {
|
|
|
12105
13042
|
// src/backoffice/services/product.service.ts
|
|
12106
13043
|
import {
|
|
12107
13044
|
addDoc as addDoc7,
|
|
12108
|
-
collection as
|
|
12109
|
-
doc as
|
|
12110
|
-
getDoc as
|
|
12111
|
-
getDocs as
|
|
12112
|
-
query as
|
|
12113
|
-
updateDoc as
|
|
12114
|
-
where as
|
|
13045
|
+
collection as collection28,
|
|
13046
|
+
doc as doc29,
|
|
13047
|
+
getDoc as getDoc31,
|
|
13048
|
+
getDocs as getDocs28,
|
|
13049
|
+
query as query28,
|
|
13050
|
+
updateDoc as updateDoc30,
|
|
13051
|
+
where as where28
|
|
12115
13052
|
} from "firebase/firestore";
|
|
12116
13053
|
|
|
12117
13054
|
// src/backoffice/types/product.types.ts
|
|
@@ -12125,7 +13062,7 @@ var ProductService = class extends BaseService {
|
|
|
12125
13062
|
* @returns Firestore collection reference
|
|
12126
13063
|
*/
|
|
12127
13064
|
getProductsRef(technologyId) {
|
|
12128
|
-
return
|
|
13065
|
+
return collection28(
|
|
12129
13066
|
this.db,
|
|
12130
13067
|
TECHNOLOGIES_COLLECTION,
|
|
12131
13068
|
technologyId,
|
|
@@ -12155,15 +13092,15 @@ var ProductService = class extends BaseService {
|
|
|
12155
13092
|
* Gets all products for a technology
|
|
12156
13093
|
*/
|
|
12157
13094
|
async getAllByTechnology(technologyId) {
|
|
12158
|
-
const q =
|
|
13095
|
+
const q = query28(
|
|
12159
13096
|
this.getProductsRef(technologyId),
|
|
12160
|
-
|
|
13097
|
+
where28("isActive", "==", true)
|
|
12161
13098
|
);
|
|
12162
|
-
const snapshot = await
|
|
13099
|
+
const snapshot = await getDocs28(q);
|
|
12163
13100
|
return snapshot.docs.map(
|
|
12164
|
-
(
|
|
12165
|
-
id:
|
|
12166
|
-
...
|
|
13101
|
+
(doc30) => ({
|
|
13102
|
+
id: doc30.id,
|
|
13103
|
+
...doc30.data()
|
|
12167
13104
|
})
|
|
12168
13105
|
);
|
|
12169
13106
|
}
|
|
@@ -12171,21 +13108,21 @@ var ProductService = class extends BaseService {
|
|
|
12171
13108
|
* Gets all products for a brand by filtering through all technologies
|
|
12172
13109
|
*/
|
|
12173
13110
|
async getAllByBrand(brandId) {
|
|
12174
|
-
const allTechnologiesRef =
|
|
12175
|
-
const technologiesSnapshot = await
|
|
13111
|
+
const allTechnologiesRef = collection28(this.db, TECHNOLOGIES_COLLECTION);
|
|
13112
|
+
const technologiesSnapshot = await getDocs28(allTechnologiesRef);
|
|
12176
13113
|
const products = [];
|
|
12177
13114
|
for (const techDoc of technologiesSnapshot.docs) {
|
|
12178
|
-
const q =
|
|
13115
|
+
const q = query28(
|
|
12179
13116
|
this.getProductsRef(techDoc.id),
|
|
12180
|
-
|
|
12181
|
-
|
|
13117
|
+
where28("brandId", "==", brandId),
|
|
13118
|
+
where28("isActive", "==", true)
|
|
12182
13119
|
);
|
|
12183
|
-
const snapshot = await
|
|
13120
|
+
const snapshot = await getDocs28(q);
|
|
12184
13121
|
products.push(
|
|
12185
13122
|
...snapshot.docs.map(
|
|
12186
|
-
(
|
|
12187
|
-
id:
|
|
12188
|
-
...
|
|
13123
|
+
(doc30) => ({
|
|
13124
|
+
id: doc30.id,
|
|
13125
|
+
...doc30.data()
|
|
12189
13126
|
})
|
|
12190
13127
|
)
|
|
12191
13128
|
);
|
|
@@ -12200,8 +13137,8 @@ var ProductService = class extends BaseService {
|
|
|
12200
13137
|
...product,
|
|
12201
13138
|
updatedAt: /* @__PURE__ */ new Date()
|
|
12202
13139
|
};
|
|
12203
|
-
const docRef =
|
|
12204
|
-
await
|
|
13140
|
+
const docRef = doc29(this.getProductsRef(technologyId), productId);
|
|
13141
|
+
await updateDoc30(docRef, updateData);
|
|
12205
13142
|
return this.getById(technologyId, productId);
|
|
12206
13143
|
}
|
|
12207
13144
|
/**
|
|
@@ -12216,8 +13153,8 @@ var ProductService = class extends BaseService {
|
|
|
12216
13153
|
* Gets a product by ID
|
|
12217
13154
|
*/
|
|
12218
13155
|
async getById(technologyId, productId) {
|
|
12219
|
-
const docRef =
|
|
12220
|
-
const docSnap = await
|
|
13156
|
+
const docRef = doc29(this.getProductsRef(technologyId), productId);
|
|
13157
|
+
const docSnap = await getDoc31(docRef);
|
|
12221
13158
|
if (!docSnap.exists()) return null;
|
|
12222
13159
|
return {
|
|
12223
13160
|
id: docSnap.id,
|
|
@@ -12227,54 +13164,54 @@ var ProductService = class extends BaseService {
|
|
|
12227
13164
|
};
|
|
12228
13165
|
|
|
12229
13166
|
// src/validations/notification.schema.ts
|
|
12230
|
-
import { z as
|
|
12231
|
-
var baseNotificationSchema =
|
|
12232
|
-
id:
|
|
12233
|
-
userId:
|
|
12234
|
-
notificationTime:
|
|
13167
|
+
import { z as z23 } from "zod";
|
|
13168
|
+
var baseNotificationSchema = z23.object({
|
|
13169
|
+
id: z23.string().optional(),
|
|
13170
|
+
userId: z23.string(),
|
|
13171
|
+
notificationTime: z23.any(),
|
|
12235
13172
|
// Timestamp
|
|
12236
|
-
notificationType:
|
|
12237
|
-
notificationTokens:
|
|
12238
|
-
status:
|
|
12239
|
-
createdAt:
|
|
13173
|
+
notificationType: z23.nativeEnum(NotificationType),
|
|
13174
|
+
notificationTokens: z23.array(z23.string()),
|
|
13175
|
+
status: z23.nativeEnum(NotificationStatus),
|
|
13176
|
+
createdAt: z23.any().optional(),
|
|
12240
13177
|
// Timestamp
|
|
12241
|
-
updatedAt:
|
|
13178
|
+
updatedAt: z23.any().optional(),
|
|
12242
13179
|
// Timestamp
|
|
12243
|
-
title:
|
|
12244
|
-
body:
|
|
12245
|
-
isRead:
|
|
12246
|
-
userRole:
|
|
13180
|
+
title: z23.string(),
|
|
13181
|
+
body: z23.string(),
|
|
13182
|
+
isRead: z23.boolean(),
|
|
13183
|
+
userRole: z23.nativeEnum(UserRole)
|
|
12247
13184
|
});
|
|
12248
13185
|
var preRequirementNotificationSchema = baseNotificationSchema.extend({
|
|
12249
|
-
notificationType:
|
|
12250
|
-
treatmentId:
|
|
12251
|
-
requirements:
|
|
12252
|
-
deadline:
|
|
13186
|
+
notificationType: z23.literal("preRequirement" /* PRE_REQUIREMENT */),
|
|
13187
|
+
treatmentId: z23.string(),
|
|
13188
|
+
requirements: z23.array(z23.string()),
|
|
13189
|
+
deadline: z23.any()
|
|
12253
13190
|
// Timestamp
|
|
12254
13191
|
});
|
|
12255
13192
|
var postRequirementNotificationSchema = baseNotificationSchema.extend({
|
|
12256
|
-
notificationType:
|
|
12257
|
-
treatmentId:
|
|
12258
|
-
requirements:
|
|
12259
|
-
deadline:
|
|
13193
|
+
notificationType: z23.literal("postRequirement" /* POST_REQUIREMENT */),
|
|
13194
|
+
treatmentId: z23.string(),
|
|
13195
|
+
requirements: z23.array(z23.string()),
|
|
13196
|
+
deadline: z23.any()
|
|
12260
13197
|
// Timestamp
|
|
12261
13198
|
});
|
|
12262
13199
|
var appointmentReminderNotificationSchema = baseNotificationSchema.extend({
|
|
12263
|
-
notificationType:
|
|
12264
|
-
appointmentId:
|
|
12265
|
-
appointmentTime:
|
|
13200
|
+
notificationType: z23.literal("appointmentReminder" /* APPOINTMENT_REMINDER */),
|
|
13201
|
+
appointmentId: z23.string(),
|
|
13202
|
+
appointmentTime: z23.any(),
|
|
12266
13203
|
// Timestamp
|
|
12267
|
-
treatmentType:
|
|
12268
|
-
doctorName:
|
|
13204
|
+
treatmentType: z23.string(),
|
|
13205
|
+
doctorName: z23.string()
|
|
12269
13206
|
});
|
|
12270
13207
|
var appointmentNotificationSchema = baseNotificationSchema.extend({
|
|
12271
|
-
notificationType:
|
|
12272
|
-
appointmentId:
|
|
12273
|
-
appointmentStatus:
|
|
12274
|
-
previousStatus:
|
|
12275
|
-
reason:
|
|
13208
|
+
notificationType: z23.literal("appointmentNotification" /* APPOINTMENT_NOTIFICATION */),
|
|
13209
|
+
appointmentId: z23.string(),
|
|
13210
|
+
appointmentStatus: z23.string(),
|
|
13211
|
+
previousStatus: z23.string(),
|
|
13212
|
+
reason: z23.string().optional()
|
|
12276
13213
|
});
|
|
12277
|
-
var notificationSchema =
|
|
13214
|
+
var notificationSchema = z23.discriminatedUnion("notificationType", [
|
|
12278
13215
|
preRequirementNotificationSchema,
|
|
12279
13216
|
postRequirementNotificationSchema,
|
|
12280
13217
|
appointmentReminderNotificationSchema,
|
|
@@ -12313,9 +13250,12 @@ var RequirementType = /* @__PURE__ */ ((RequirementType2) => {
|
|
|
12313
13250
|
return RequirementType2;
|
|
12314
13251
|
})(RequirementType || {});
|
|
12315
13252
|
export {
|
|
13253
|
+
APPOINTMENTS_COLLECTION,
|
|
12316
13254
|
AUTH_ERRORS,
|
|
12317
13255
|
AdminTokenStatus,
|
|
12318
13256
|
AllergyType,
|
|
13257
|
+
AppointmentService,
|
|
13258
|
+
AppointmentStatus,
|
|
12319
13259
|
AuthService,
|
|
12320
13260
|
BlockingCondition,
|
|
12321
13261
|
BrandService,
|
|
@@ -12365,6 +13305,7 @@ export {
|
|
|
12365
13305
|
PRACTITIONERS_COLLECTION,
|
|
12366
13306
|
PROCEDURES_COLLECTION,
|
|
12367
13307
|
PatientService,
|
|
13308
|
+
PaymentStatus,
|
|
12368
13309
|
PracticeType,
|
|
12369
13310
|
PractitionerService,
|
|
12370
13311
|
PractitionerStatus,
|
|
@@ -12479,6 +13420,7 @@ export {
|
|
|
12479
13420
|
procedureSummaryInfoSchema,
|
|
12480
13421
|
requesterInfoSchema,
|
|
12481
13422
|
reviewSchema,
|
|
13423
|
+
searchAppointmentsSchema,
|
|
12482
13424
|
searchPatientsSchema,
|
|
12483
13425
|
syncedCalendarEventSchema,
|
|
12484
13426
|
timeSlotSchema2 as timeSlotSchema,
|