@blackcode_sa/metaestetics-api 1.5.35 → 1.5.37
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 +2055 -1118
- package/dist/index.mjs +2071 -1123
- package/package.json +1 -1
- package/src/index.ts +26 -0
- package/src/services/appointment/appointment.service.ts +8 -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,856 @@ 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 currentUser = this.auth.currentUser;
|
|
11887
|
+
if (!currentUser) {
|
|
11888
|
+
throw new Error(
|
|
11889
|
+
"User must be authenticated to get available booking slots"
|
|
11890
|
+
);
|
|
11891
|
+
}
|
|
11892
|
+
const getAvailableBookingSlotsFunction = httpsCallable(
|
|
11893
|
+
this.functions,
|
|
11894
|
+
"getAvailableBookingSlots"
|
|
11895
|
+
);
|
|
11896
|
+
const result = await getAvailableBookingSlotsFunction({
|
|
11897
|
+
clinicId,
|
|
11898
|
+
practitionerId,
|
|
11899
|
+
procedureId,
|
|
11900
|
+
timeframe: {
|
|
11901
|
+
start: startDate.getTime(),
|
|
11902
|
+
// Convert to timestamp
|
|
11903
|
+
end: endDate.getTime()
|
|
11904
|
+
}
|
|
11905
|
+
});
|
|
11906
|
+
const response = result.data;
|
|
11907
|
+
if (!response.success) {
|
|
11908
|
+
throw new Error(
|
|
11909
|
+
response.error || "Failed to get available booking slots"
|
|
11910
|
+
);
|
|
11911
|
+
}
|
|
11912
|
+
const slots = response.availableSlots.map((slot) => ({
|
|
11913
|
+
start: new Date(slot.start)
|
|
11914
|
+
}));
|
|
11915
|
+
console.log(
|
|
11916
|
+
`[APPOINTMENT_SERVICE] Found ${slots.length} available booking slots`
|
|
11917
|
+
);
|
|
11918
|
+
return slots;
|
|
11919
|
+
} catch (error) {
|
|
11920
|
+
console.error(
|
|
11921
|
+
"[APPOINTMENT_SERVICE] Error getting available booking slots:",
|
|
11922
|
+
error
|
|
11923
|
+
);
|
|
11924
|
+
throw error;
|
|
11925
|
+
}
|
|
11926
|
+
}
|
|
11927
|
+
/**
|
|
11928
|
+
* Creates a new appointment.
|
|
11929
|
+
*
|
|
11930
|
+
* @param data Data needed to create the appointment
|
|
11931
|
+
* @returns The created appointment
|
|
11932
|
+
*/
|
|
11933
|
+
async createAppointment(data) {
|
|
11934
|
+
try {
|
|
11935
|
+
console.log("[APPOINTMENT_SERVICE] Creating appointment");
|
|
11936
|
+
const validatedData = await createAppointmentSchema.parseAsync(data);
|
|
11937
|
+
const aggregatedInfo = await fetchAggregatedInfoUtil(
|
|
11938
|
+
this.db,
|
|
11939
|
+
validatedData.clinicBranchId,
|
|
11940
|
+
validatedData.practitionerId,
|
|
11941
|
+
validatedData.patientId,
|
|
11942
|
+
validatedData.procedureId
|
|
11943
|
+
);
|
|
11944
|
+
const appointment = await createAppointmentUtil2(
|
|
11945
|
+
this.db,
|
|
11946
|
+
validatedData,
|
|
11947
|
+
aggregatedInfo,
|
|
11948
|
+
this.generateId.bind(this)
|
|
11949
|
+
);
|
|
11950
|
+
console.log(
|
|
11951
|
+
`[APPOINTMENT_SERVICE] Appointment created with ID: ${appointment.id}`
|
|
11952
|
+
);
|
|
11953
|
+
return appointment;
|
|
11954
|
+
} catch (error) {
|
|
11955
|
+
console.error("[APPOINTMENT_SERVICE] Error creating appointment:", error);
|
|
11956
|
+
throw error;
|
|
11957
|
+
}
|
|
11958
|
+
}
|
|
11959
|
+
/**
|
|
11960
|
+
* Gets an appointment by ID.
|
|
11961
|
+
*
|
|
11962
|
+
* @param appointmentId ID of the appointment to retrieve
|
|
11963
|
+
* @returns The appointment or null if not found
|
|
11964
|
+
*/
|
|
11965
|
+
async getAppointmentById(appointmentId) {
|
|
11966
|
+
try {
|
|
11967
|
+
console.log(
|
|
11968
|
+
`[APPOINTMENT_SERVICE] Getting appointment with ID: ${appointmentId}`
|
|
11969
|
+
);
|
|
11970
|
+
const appointment = await getAppointmentByIdUtil(this.db, appointmentId);
|
|
11971
|
+
console.log(
|
|
11972
|
+
`[APPOINTMENT_SERVICE] Appointment ${appointmentId} ${appointment ? "found" : "not found"}`
|
|
11973
|
+
);
|
|
11974
|
+
return appointment;
|
|
11975
|
+
} catch (error) {
|
|
11976
|
+
console.error(
|
|
11977
|
+
`[APPOINTMENT_SERVICE] Error getting appointment ${appointmentId}:`,
|
|
11978
|
+
error
|
|
11979
|
+
);
|
|
11980
|
+
throw error;
|
|
11981
|
+
}
|
|
11982
|
+
}
|
|
11983
|
+
/**
|
|
11984
|
+
* Updates an existing appointment.
|
|
11985
|
+
*
|
|
11986
|
+
* @param appointmentId ID of the appointment to update
|
|
11987
|
+
* @param data Update data for the appointment
|
|
11988
|
+
* @returns The updated appointment
|
|
11989
|
+
*/
|
|
11990
|
+
async updateAppointment(appointmentId, data) {
|
|
11991
|
+
try {
|
|
11992
|
+
console.log(
|
|
11993
|
+
`[APPOINTMENT_SERVICE] Updating appointment with ID: ${appointmentId}`
|
|
11994
|
+
);
|
|
11995
|
+
const validatedData = await updateAppointmentSchema.parseAsync(data);
|
|
11996
|
+
const updatedAppointment = await updateAppointmentUtil2(
|
|
11997
|
+
this.db,
|
|
11998
|
+
appointmentId,
|
|
11999
|
+
validatedData
|
|
12000
|
+
);
|
|
12001
|
+
console.log(
|
|
12002
|
+
`[APPOINTMENT_SERVICE] Appointment ${appointmentId} updated successfully`
|
|
12003
|
+
);
|
|
12004
|
+
return updatedAppointment;
|
|
12005
|
+
} catch (error) {
|
|
12006
|
+
console.error(
|
|
12007
|
+
`[APPOINTMENT_SERVICE] Error updating appointment ${appointmentId}:`,
|
|
12008
|
+
error
|
|
12009
|
+
);
|
|
12010
|
+
throw error;
|
|
12011
|
+
}
|
|
12012
|
+
}
|
|
12013
|
+
/**
|
|
12014
|
+
* Searches for appointments based on various criteria.
|
|
12015
|
+
*
|
|
12016
|
+
* @param params Search parameters
|
|
12017
|
+
* @returns Found appointments and the last document for pagination
|
|
12018
|
+
*/
|
|
12019
|
+
async searchAppointments(params) {
|
|
12020
|
+
try {
|
|
12021
|
+
console.log(
|
|
12022
|
+
"[APPOINTMENT_SERVICE] Searching appointments with params:",
|
|
12023
|
+
params
|
|
12024
|
+
);
|
|
12025
|
+
await searchAppointmentsSchema.parseAsync(params);
|
|
12026
|
+
const result = await searchAppointmentsUtil(this.db, params);
|
|
12027
|
+
console.log(
|
|
12028
|
+
`[APPOINTMENT_SERVICE] Found ${result.appointments.length} appointments`
|
|
12029
|
+
);
|
|
12030
|
+
return result;
|
|
12031
|
+
} catch (error) {
|
|
12032
|
+
console.error(
|
|
12033
|
+
"[APPOINTMENT_SERVICE] Error searching appointments:",
|
|
12034
|
+
error
|
|
12035
|
+
);
|
|
12036
|
+
throw error;
|
|
12037
|
+
}
|
|
12038
|
+
}
|
|
12039
|
+
/**
|
|
12040
|
+
* Gets appointments for a specific patient.
|
|
12041
|
+
*
|
|
12042
|
+
* @param patientId ID of the patient
|
|
12043
|
+
* @param options Optional parameters for filtering and pagination
|
|
12044
|
+
* @returns Found appointments and the last document for pagination
|
|
12045
|
+
*/
|
|
12046
|
+
async getPatientAppointments(patientId, options) {
|
|
12047
|
+
console.log(
|
|
12048
|
+
`[APPOINTMENT_SERVICE] Getting appointments for patient: ${patientId}`
|
|
12049
|
+
);
|
|
12050
|
+
const searchParams = {
|
|
12051
|
+
patientId,
|
|
12052
|
+
startDate: options == null ? void 0 : options.startDate,
|
|
12053
|
+
endDate: options == null ? void 0 : options.endDate,
|
|
12054
|
+
status: options == null ? void 0 : options.status,
|
|
12055
|
+
limit: options == null ? void 0 : options.limit,
|
|
12056
|
+
startAfter: options == null ? void 0 : options.startAfter
|
|
12057
|
+
};
|
|
12058
|
+
return this.searchAppointments(searchParams);
|
|
12059
|
+
}
|
|
12060
|
+
/**
|
|
12061
|
+
* Gets appointments for a specific practitioner.
|
|
12062
|
+
*
|
|
12063
|
+
* @param practitionerId ID of the practitioner
|
|
12064
|
+
* @param options Optional parameters for filtering and pagination
|
|
12065
|
+
* @returns Found appointments and the last document for pagination
|
|
12066
|
+
*/
|
|
12067
|
+
async getPractitionerAppointments(practitionerId, options) {
|
|
12068
|
+
console.log(
|
|
12069
|
+
`[APPOINTMENT_SERVICE] Getting appointments for practitioner: ${practitionerId}`
|
|
12070
|
+
);
|
|
12071
|
+
const searchParams = {
|
|
12072
|
+
practitionerId,
|
|
12073
|
+
startDate: options == null ? void 0 : options.startDate,
|
|
12074
|
+
endDate: options == null ? void 0 : options.endDate,
|
|
12075
|
+
status: options == null ? void 0 : options.status,
|
|
12076
|
+
limit: options == null ? void 0 : options.limit,
|
|
12077
|
+
startAfter: options == null ? void 0 : options.startAfter
|
|
12078
|
+
};
|
|
12079
|
+
return this.searchAppointments(searchParams);
|
|
12080
|
+
}
|
|
12081
|
+
/**
|
|
12082
|
+
* Gets appointments for a specific clinic.
|
|
12083
|
+
*
|
|
12084
|
+
* @param clinicBranchId ID of the clinic branch
|
|
12085
|
+
* @param options Optional parameters for filtering and pagination
|
|
12086
|
+
* @returns Found appointments and the last document for pagination
|
|
12087
|
+
*/
|
|
12088
|
+
async getClinicAppointments(clinicBranchId, options) {
|
|
12089
|
+
console.log(
|
|
12090
|
+
`[APPOINTMENT_SERVICE] Getting appointments for clinic: ${clinicBranchId}`
|
|
12091
|
+
);
|
|
12092
|
+
const searchParams = {
|
|
12093
|
+
clinicBranchId,
|
|
12094
|
+
practitionerId: options == null ? void 0 : options.practitionerId,
|
|
12095
|
+
startDate: options == null ? void 0 : options.startDate,
|
|
12096
|
+
endDate: options == null ? void 0 : options.endDate,
|
|
12097
|
+
status: options == null ? void 0 : options.status,
|
|
12098
|
+
limit: options == null ? void 0 : options.limit,
|
|
12099
|
+
startAfter: options == null ? void 0 : options.startAfter
|
|
12100
|
+
};
|
|
12101
|
+
return this.searchAppointments(searchParams);
|
|
12102
|
+
}
|
|
12103
|
+
/**
|
|
12104
|
+
* Updates the status of an appointment.
|
|
12105
|
+
*
|
|
12106
|
+
* @param appointmentId ID of the appointment
|
|
12107
|
+
* @param newStatus New status to set
|
|
12108
|
+
* @param cancellationReason Required if canceling the appointment
|
|
12109
|
+
* @param canceledBy Required if canceling the appointment
|
|
12110
|
+
* @returns The updated appointment
|
|
12111
|
+
*/
|
|
12112
|
+
async updateAppointmentStatus(appointmentId, newStatus, cancellationReason, canceledBy) {
|
|
12113
|
+
console.log(
|
|
12114
|
+
`[APPOINTMENT_SERVICE] Updating status of appointment ${appointmentId} to ${newStatus}`
|
|
12115
|
+
);
|
|
12116
|
+
const updateData = { status: newStatus };
|
|
12117
|
+
if (newStatus === "canceled_clinic" /* CANCELED_CLINIC */ || newStatus === "canceled_patient" /* CANCELED_PATIENT */) {
|
|
12118
|
+
if (!cancellationReason) {
|
|
12119
|
+
throw new Error(
|
|
12120
|
+
"Cancellation reason is required when canceling an appointment"
|
|
12121
|
+
);
|
|
12122
|
+
}
|
|
12123
|
+
if (!canceledBy) {
|
|
12124
|
+
throw new Error(
|
|
12125
|
+
"Canceled by is required when canceling an appointment"
|
|
12126
|
+
);
|
|
12127
|
+
}
|
|
12128
|
+
updateData.cancellationReason = cancellationReason;
|
|
12129
|
+
updateData.canceledBy = canceledBy;
|
|
12130
|
+
}
|
|
12131
|
+
if (newStatus === "confirmed" /* CONFIRMED */) {
|
|
12132
|
+
updateData.confirmationTime = Timestamp28.now();
|
|
12133
|
+
}
|
|
12134
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
12135
|
+
}
|
|
12136
|
+
/**
|
|
12137
|
+
* Confirms an appointment.
|
|
12138
|
+
*
|
|
12139
|
+
* @param appointmentId ID of the appointment to confirm
|
|
12140
|
+
* @returns The confirmed appointment
|
|
12141
|
+
*/
|
|
12142
|
+
async confirmAppointment(appointmentId) {
|
|
12143
|
+
console.log(
|
|
12144
|
+
`[APPOINTMENT_SERVICE] Confirming appointment: ${appointmentId}`
|
|
12145
|
+
);
|
|
12146
|
+
return this.updateAppointmentStatus(
|
|
12147
|
+
appointmentId,
|
|
12148
|
+
"confirmed" /* CONFIRMED */
|
|
12149
|
+
);
|
|
12150
|
+
}
|
|
12151
|
+
/**
|
|
12152
|
+
* Cancels an appointment from the clinic side.
|
|
12153
|
+
*
|
|
12154
|
+
* @param appointmentId ID of the appointment to cancel
|
|
12155
|
+
* @param reason Reason for cancellation
|
|
12156
|
+
* @returns The canceled appointment
|
|
12157
|
+
*/
|
|
12158
|
+
async cancelAppointmentByClinic(appointmentId, reason) {
|
|
12159
|
+
console.log(
|
|
12160
|
+
`[APPOINTMENT_SERVICE] Canceling appointment by clinic: ${appointmentId}`
|
|
12161
|
+
);
|
|
12162
|
+
return this.updateAppointmentStatus(
|
|
12163
|
+
appointmentId,
|
|
12164
|
+
"canceled_clinic" /* CANCELED_CLINIC */,
|
|
12165
|
+
reason,
|
|
12166
|
+
"clinic"
|
|
12167
|
+
);
|
|
12168
|
+
}
|
|
12169
|
+
/**
|
|
12170
|
+
* Cancels an appointment from the patient side.
|
|
12171
|
+
*
|
|
12172
|
+
* @param appointmentId ID of the appointment to cancel
|
|
12173
|
+
* @param reason Reason for cancellation
|
|
12174
|
+
* @returns The canceled appointment
|
|
12175
|
+
*/
|
|
12176
|
+
async cancelAppointmentByPatient(appointmentId, reason) {
|
|
12177
|
+
console.log(
|
|
12178
|
+
`[APPOINTMENT_SERVICE] Canceling appointment by patient: ${appointmentId}`
|
|
12179
|
+
);
|
|
12180
|
+
return this.updateAppointmentStatus(
|
|
12181
|
+
appointmentId,
|
|
12182
|
+
"canceled_patient" /* CANCELED_PATIENT */,
|
|
12183
|
+
reason,
|
|
12184
|
+
"patient"
|
|
12185
|
+
);
|
|
12186
|
+
}
|
|
12187
|
+
/**
|
|
12188
|
+
* Marks an appointment as checked in.
|
|
12189
|
+
*
|
|
12190
|
+
* @param appointmentId ID of the appointment
|
|
12191
|
+
* @returns The updated appointment
|
|
12192
|
+
*/
|
|
12193
|
+
async checkInAppointment(appointmentId) {
|
|
12194
|
+
console.log(
|
|
12195
|
+
`[APPOINTMENT_SERVICE] Checking in appointment: ${appointmentId}`
|
|
12196
|
+
);
|
|
12197
|
+
return this.updateAppointmentStatus(
|
|
12198
|
+
appointmentId,
|
|
12199
|
+
"checked_in" /* CHECKED_IN */
|
|
12200
|
+
);
|
|
12201
|
+
}
|
|
12202
|
+
/**
|
|
12203
|
+
* Marks an appointment as in progress.
|
|
12204
|
+
*
|
|
12205
|
+
* @param appointmentId ID of the appointment
|
|
12206
|
+
* @returns The updated appointment
|
|
12207
|
+
*/
|
|
12208
|
+
async startAppointment(appointmentId) {
|
|
12209
|
+
console.log(`[APPOINTMENT_SERVICE] Starting appointment: ${appointmentId}`);
|
|
12210
|
+
return this.updateAppointmentStatus(
|
|
12211
|
+
appointmentId,
|
|
12212
|
+
"in_progress" /* IN_PROGRESS */
|
|
12213
|
+
);
|
|
12214
|
+
}
|
|
12215
|
+
/**
|
|
12216
|
+
* Marks an appointment as completed.
|
|
12217
|
+
*
|
|
12218
|
+
* @param appointmentId ID of the appointment
|
|
12219
|
+
* @param actualDurationMinutes Actual duration of the appointment in minutes
|
|
12220
|
+
* @returns The updated appointment
|
|
12221
|
+
*/
|
|
12222
|
+
async completeAppointment(appointmentId, actualDurationMinutes) {
|
|
12223
|
+
console.log(
|
|
12224
|
+
`[APPOINTMENT_SERVICE] Completing appointment: ${appointmentId}`
|
|
12225
|
+
);
|
|
12226
|
+
const updateData = {
|
|
12227
|
+
status: "completed" /* COMPLETED */,
|
|
12228
|
+
actualDurationMinutes
|
|
12229
|
+
};
|
|
12230
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
12231
|
+
}
|
|
12232
|
+
/**
|
|
12233
|
+
* Marks an appointment as no-show.
|
|
12234
|
+
*
|
|
12235
|
+
* @param appointmentId ID of the appointment
|
|
12236
|
+
* @returns The updated appointment
|
|
12237
|
+
*/
|
|
12238
|
+
async markNoShow(appointmentId) {
|
|
12239
|
+
console.log(
|
|
12240
|
+
`[APPOINTMENT_SERVICE] Marking appointment as no-show: ${appointmentId}`
|
|
12241
|
+
);
|
|
12242
|
+
return this.updateAppointmentStatus(
|
|
12243
|
+
appointmentId,
|
|
12244
|
+
"no_show" /* NO_SHOW */
|
|
12245
|
+
);
|
|
12246
|
+
}
|
|
12247
|
+
/**
|
|
12248
|
+
* Updates the payment status of an appointment.
|
|
12249
|
+
*
|
|
12250
|
+
* @param appointmentId ID of the appointment
|
|
12251
|
+
* @param paymentStatus New payment status
|
|
12252
|
+
* @param paymentTransactionId Optional transaction ID for the payment
|
|
12253
|
+
* @returns The updated appointment
|
|
12254
|
+
*/
|
|
12255
|
+
async updatePaymentStatus(appointmentId, paymentStatus, paymentTransactionId) {
|
|
12256
|
+
console.log(
|
|
12257
|
+
`[APPOINTMENT_SERVICE] Updating payment status of appointment ${appointmentId} to ${paymentStatus}`
|
|
12258
|
+
);
|
|
12259
|
+
const updateData = {
|
|
12260
|
+
paymentStatus,
|
|
12261
|
+
paymentTransactionId: paymentTransactionId || null
|
|
12262
|
+
};
|
|
12263
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
12264
|
+
}
|
|
12265
|
+
/**
|
|
12266
|
+
* Marks pre-procedure requirements as completed.
|
|
12267
|
+
*
|
|
12268
|
+
* @param appointmentId ID of the appointment
|
|
12269
|
+
* @param requirementIds IDs of the requirements to mark as completed
|
|
12270
|
+
* @returns The updated appointment
|
|
12271
|
+
*/
|
|
12272
|
+
async completePreRequirements(appointmentId, requirementIds) {
|
|
12273
|
+
console.log(
|
|
12274
|
+
`[APPOINTMENT_SERVICE] Marking pre-requirements as completed for appointment: ${appointmentId}`
|
|
12275
|
+
);
|
|
12276
|
+
const updateData = {
|
|
12277
|
+
completedPreRequirements: requirementIds
|
|
12278
|
+
};
|
|
12279
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
12280
|
+
}
|
|
12281
|
+
/**
|
|
12282
|
+
* Marks post-procedure requirements as completed.
|
|
12283
|
+
*
|
|
12284
|
+
* @param appointmentId ID of the appointment
|
|
12285
|
+
* @param requirementIds IDs of the requirements to mark as completed
|
|
12286
|
+
* @returns The updated appointment
|
|
12287
|
+
*/
|
|
12288
|
+
async completePostRequirements(appointmentId, requirementIds) {
|
|
12289
|
+
console.log(
|
|
12290
|
+
`[APPOINTMENT_SERVICE] Marking post-requirements as completed for appointment: ${appointmentId}`
|
|
12291
|
+
);
|
|
12292
|
+
const updateData = {
|
|
12293
|
+
completedPostRequirements: requirementIds
|
|
12294
|
+
};
|
|
12295
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
12296
|
+
}
|
|
12297
|
+
/**
|
|
12298
|
+
* Updates the internal notes of an appointment.
|
|
12299
|
+
*
|
|
12300
|
+
* @param appointmentId ID of the appointment
|
|
12301
|
+
* @param notes Updated internal notes
|
|
12302
|
+
* @returns The updated appointment
|
|
12303
|
+
*/
|
|
12304
|
+
async updateInternalNotes(appointmentId, notes) {
|
|
12305
|
+
console.log(
|
|
12306
|
+
`[APPOINTMENT_SERVICE] Updating internal notes for appointment: ${appointmentId}`
|
|
12307
|
+
);
|
|
12308
|
+
const updateData = {
|
|
12309
|
+
internalNotes: notes
|
|
12310
|
+
};
|
|
12311
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
12312
|
+
}
|
|
12313
|
+
};
|
|
12314
|
+
|
|
12315
|
+
// src/backoffice/services/brand.service.ts
|
|
12316
|
+
import {
|
|
12317
|
+
addDoc as addDoc3,
|
|
12318
|
+
collection as collection24,
|
|
12319
|
+
doc as doc25,
|
|
11456
12320
|
getDoc as getDoc27,
|
|
11457
12321
|
getDocs as getDocs24,
|
|
11458
12322
|
query as query24,
|
|
@@ -11460,6 +12324,90 @@ import {
|
|
|
11460
12324
|
where as where24
|
|
11461
12325
|
} from "firebase/firestore";
|
|
11462
12326
|
|
|
12327
|
+
// src/backoffice/types/brand.types.ts
|
|
12328
|
+
var BRANDS_COLLECTION = "brands";
|
|
12329
|
+
|
|
12330
|
+
// src/backoffice/services/brand.service.ts
|
|
12331
|
+
var BrandService = class extends BaseService {
|
|
12332
|
+
/**
|
|
12333
|
+
* Gets reference to brands collection
|
|
12334
|
+
*/
|
|
12335
|
+
getBrandsRef() {
|
|
12336
|
+
return collection24(this.db, BRANDS_COLLECTION);
|
|
12337
|
+
}
|
|
12338
|
+
/**
|
|
12339
|
+
* Creates a new brand
|
|
12340
|
+
*/
|
|
12341
|
+
async create(brand) {
|
|
12342
|
+
const now = /* @__PURE__ */ new Date();
|
|
12343
|
+
const newBrand = {
|
|
12344
|
+
...brand,
|
|
12345
|
+
createdAt: now,
|
|
12346
|
+
updatedAt: now,
|
|
12347
|
+
isActive: true
|
|
12348
|
+
};
|
|
12349
|
+
const docRef = await addDoc3(this.getBrandsRef(), newBrand);
|
|
12350
|
+
return { id: docRef.id, ...newBrand };
|
|
12351
|
+
}
|
|
12352
|
+
/**
|
|
12353
|
+
* Gets all active brands
|
|
12354
|
+
*/
|
|
12355
|
+
async getAll() {
|
|
12356
|
+
const q = query24(this.getBrandsRef(), where24("isActive", "==", true));
|
|
12357
|
+
const snapshot = await getDocs24(q);
|
|
12358
|
+
return snapshot.docs.map(
|
|
12359
|
+
(doc30) => ({
|
|
12360
|
+
id: doc30.id,
|
|
12361
|
+
...doc30.data()
|
|
12362
|
+
})
|
|
12363
|
+
);
|
|
12364
|
+
}
|
|
12365
|
+
/**
|
|
12366
|
+
* Updates a brand
|
|
12367
|
+
*/
|
|
12368
|
+
async update(brandId, brand) {
|
|
12369
|
+
const updateData = {
|
|
12370
|
+
...brand,
|
|
12371
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
12372
|
+
};
|
|
12373
|
+
const docRef = doc25(this.getBrandsRef(), brandId);
|
|
12374
|
+
await updateDoc26(docRef, updateData);
|
|
12375
|
+
return this.getById(brandId);
|
|
12376
|
+
}
|
|
12377
|
+
/**
|
|
12378
|
+
* Soft deletes a brand
|
|
12379
|
+
*/
|
|
12380
|
+
async delete(brandId) {
|
|
12381
|
+
await this.update(brandId, {
|
|
12382
|
+
isActive: false
|
|
12383
|
+
});
|
|
12384
|
+
}
|
|
12385
|
+
/**
|
|
12386
|
+
* Gets a brand by ID
|
|
12387
|
+
*/
|
|
12388
|
+
async getById(brandId) {
|
|
12389
|
+
const docRef = doc25(this.getBrandsRef(), brandId);
|
|
12390
|
+
const docSnap = await getDoc27(docRef);
|
|
12391
|
+
if (!docSnap.exists()) return null;
|
|
12392
|
+
return {
|
|
12393
|
+
id: docSnap.id,
|
|
12394
|
+
...docSnap.data()
|
|
12395
|
+
};
|
|
12396
|
+
}
|
|
12397
|
+
};
|
|
12398
|
+
|
|
12399
|
+
// src/backoffice/services/category.service.ts
|
|
12400
|
+
import {
|
|
12401
|
+
addDoc as addDoc4,
|
|
12402
|
+
collection as collection25,
|
|
12403
|
+
doc as doc26,
|
|
12404
|
+
getDoc as getDoc28,
|
|
12405
|
+
getDocs as getDocs25,
|
|
12406
|
+
query as query25,
|
|
12407
|
+
updateDoc as updateDoc27,
|
|
12408
|
+
where as where25
|
|
12409
|
+
} from "firebase/firestore";
|
|
12410
|
+
|
|
11463
12411
|
// src/backoffice/types/category.types.ts
|
|
11464
12412
|
var CATEGORIES_COLLECTION = "backoffice_categories";
|
|
11465
12413
|
|
|
@@ -11469,7 +12417,7 @@ var CategoryService = class extends BaseService {
|
|
|
11469
12417
|
* Referenca na Firestore kolekciju kategorija
|
|
11470
12418
|
*/
|
|
11471
12419
|
get categoriesRef() {
|
|
11472
|
-
return
|
|
12420
|
+
return collection25(this.db, CATEGORIES_COLLECTION);
|
|
11473
12421
|
}
|
|
11474
12422
|
/**
|
|
11475
12423
|
* Kreira novu kategoriju u sistemu
|
|
@@ -11492,12 +12440,12 @@ var CategoryService = class extends BaseService {
|
|
|
11492
12440
|
* @returns Lista aktivnih kategorija
|
|
11493
12441
|
*/
|
|
11494
12442
|
async getAll() {
|
|
11495
|
-
const q =
|
|
11496
|
-
const snapshot = await
|
|
12443
|
+
const q = query25(this.categoriesRef, where25("isActive", "==", true));
|
|
12444
|
+
const snapshot = await getDocs25(q);
|
|
11497
12445
|
return snapshot.docs.map(
|
|
11498
|
-
(
|
|
11499
|
-
id:
|
|
11500
|
-
...
|
|
12446
|
+
(doc30) => ({
|
|
12447
|
+
id: doc30.id,
|
|
12448
|
+
...doc30.data()
|
|
11501
12449
|
})
|
|
11502
12450
|
);
|
|
11503
12451
|
}
|
|
@@ -11507,16 +12455,16 @@ var CategoryService = class extends BaseService {
|
|
|
11507
12455
|
* @returns Lista kategorija koje pripadaju traženoj familiji
|
|
11508
12456
|
*/
|
|
11509
12457
|
async getAllByFamily(family) {
|
|
11510
|
-
const q =
|
|
12458
|
+
const q = query25(
|
|
11511
12459
|
this.categoriesRef,
|
|
11512
|
-
|
|
11513
|
-
|
|
12460
|
+
where25("family", "==", family),
|
|
12461
|
+
where25("isActive", "==", true)
|
|
11514
12462
|
);
|
|
11515
|
-
const snapshot = await
|
|
12463
|
+
const snapshot = await getDocs25(q);
|
|
11516
12464
|
return snapshot.docs.map(
|
|
11517
|
-
(
|
|
11518
|
-
id:
|
|
11519
|
-
...
|
|
12465
|
+
(doc30) => ({
|
|
12466
|
+
id: doc30.id,
|
|
12467
|
+
...doc30.data()
|
|
11520
12468
|
})
|
|
11521
12469
|
);
|
|
11522
12470
|
}
|
|
@@ -11531,8 +12479,8 @@ var CategoryService = class extends BaseService {
|
|
|
11531
12479
|
...category,
|
|
11532
12480
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11533
12481
|
};
|
|
11534
|
-
const docRef =
|
|
11535
|
-
await
|
|
12482
|
+
const docRef = doc26(this.categoriesRef, id);
|
|
12483
|
+
await updateDoc27(docRef, updateData);
|
|
11536
12484
|
return this.getById(id);
|
|
11537
12485
|
}
|
|
11538
12486
|
/**
|
|
@@ -11548,8 +12496,8 @@ var CategoryService = class extends BaseService {
|
|
|
11548
12496
|
* @returns Kategorija ili null ako ne postoji
|
|
11549
12497
|
*/
|
|
11550
12498
|
async getById(id) {
|
|
11551
|
-
const docRef =
|
|
11552
|
-
const docSnap = await
|
|
12499
|
+
const docRef = doc26(this.categoriesRef, id);
|
|
12500
|
+
const docSnap = await getDoc28(docRef);
|
|
11553
12501
|
if (!docSnap.exists()) return null;
|
|
11554
12502
|
return {
|
|
11555
12503
|
id: docSnap.id,
|
|
@@ -11561,13 +12509,13 @@ var CategoryService = class extends BaseService {
|
|
|
11561
12509
|
// src/backoffice/services/subcategory.service.ts
|
|
11562
12510
|
import {
|
|
11563
12511
|
addDoc as addDoc5,
|
|
11564
|
-
collection as
|
|
11565
|
-
doc as
|
|
11566
|
-
getDoc as
|
|
11567
|
-
getDocs as
|
|
11568
|
-
query as
|
|
11569
|
-
updateDoc as
|
|
11570
|
-
where as
|
|
12512
|
+
collection as collection26,
|
|
12513
|
+
doc as doc27,
|
|
12514
|
+
getDoc as getDoc29,
|
|
12515
|
+
getDocs as getDocs26,
|
|
12516
|
+
query as query26,
|
|
12517
|
+
updateDoc as updateDoc28,
|
|
12518
|
+
where as where26
|
|
11571
12519
|
} from "firebase/firestore";
|
|
11572
12520
|
|
|
11573
12521
|
// src/backoffice/types/subcategory.types.ts
|
|
@@ -11580,7 +12528,7 @@ var SubcategoryService = class extends BaseService {
|
|
|
11580
12528
|
* @param categoryId - ID roditeljske kategorije
|
|
11581
12529
|
*/
|
|
11582
12530
|
getSubcategoriesRef(categoryId) {
|
|
11583
|
-
return
|
|
12531
|
+
return collection26(
|
|
11584
12532
|
this.db,
|
|
11585
12533
|
CATEGORIES_COLLECTION,
|
|
11586
12534
|
categoryId,
|
|
@@ -11614,15 +12562,15 @@ var SubcategoryService = class extends BaseService {
|
|
|
11614
12562
|
* @returns Lista aktivnih podkategorija
|
|
11615
12563
|
*/
|
|
11616
12564
|
async getAllByCategoryId(categoryId) {
|
|
11617
|
-
const q =
|
|
12565
|
+
const q = query26(
|
|
11618
12566
|
this.getSubcategoriesRef(categoryId),
|
|
11619
|
-
|
|
12567
|
+
where26("isActive", "==", true)
|
|
11620
12568
|
);
|
|
11621
|
-
const snapshot = await
|
|
12569
|
+
const snapshot = await getDocs26(q);
|
|
11622
12570
|
return snapshot.docs.map(
|
|
11623
|
-
(
|
|
11624
|
-
id:
|
|
11625
|
-
...
|
|
12571
|
+
(doc30) => ({
|
|
12572
|
+
id: doc30.id,
|
|
12573
|
+
...doc30.data()
|
|
11626
12574
|
})
|
|
11627
12575
|
);
|
|
11628
12576
|
}
|
|
@@ -11638,8 +12586,8 @@ var SubcategoryService = class extends BaseService {
|
|
|
11638
12586
|
...subcategory,
|
|
11639
12587
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11640
12588
|
};
|
|
11641
|
-
const docRef =
|
|
11642
|
-
await
|
|
12589
|
+
const docRef = doc27(this.getSubcategoriesRef(categoryId), subcategoryId);
|
|
12590
|
+
await updateDoc28(docRef, updateData);
|
|
11643
12591
|
return this.getById(categoryId, subcategoryId);
|
|
11644
12592
|
}
|
|
11645
12593
|
/**
|
|
@@ -11657,8 +12605,8 @@ var SubcategoryService = class extends BaseService {
|
|
|
11657
12605
|
* @returns Podkategorija ili null ako ne postoji
|
|
11658
12606
|
*/
|
|
11659
12607
|
async getById(categoryId, subcategoryId) {
|
|
11660
|
-
const docRef =
|
|
11661
|
-
const docSnap = await
|
|
12608
|
+
const docRef = doc27(this.getSubcategoriesRef(categoryId), subcategoryId);
|
|
12609
|
+
const docSnap = await getDoc29(docRef);
|
|
11662
12610
|
if (!docSnap.exists()) return null;
|
|
11663
12611
|
return {
|
|
11664
12612
|
id: docSnap.id,
|
|
@@ -11670,21 +12618,16 @@ var SubcategoryService = class extends BaseService {
|
|
|
11670
12618
|
// src/backoffice/services/technology.service.ts
|
|
11671
12619
|
import {
|
|
11672
12620
|
addDoc as addDoc6,
|
|
11673
|
-
collection as
|
|
11674
|
-
doc as
|
|
11675
|
-
getDoc as
|
|
11676
|
-
getDocs as
|
|
11677
|
-
query as
|
|
11678
|
-
updateDoc as
|
|
11679
|
-
where as
|
|
12621
|
+
collection as collection27,
|
|
12622
|
+
doc as doc28,
|
|
12623
|
+
getDoc as getDoc30,
|
|
12624
|
+
getDocs as getDocs27,
|
|
12625
|
+
query as query27,
|
|
12626
|
+
updateDoc as updateDoc29,
|
|
12627
|
+
where as where27,
|
|
11680
12628
|
arrayUnion as arrayUnion8,
|
|
11681
12629
|
arrayRemove as arrayRemove7
|
|
11682
12630
|
} 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
12631
|
var DEFAULT_CERTIFICATION_REQUIREMENT = {
|
|
11689
12632
|
minimumLevel: "aesthetician" /* AESTHETICIAN */,
|
|
11690
12633
|
requiredSpecialties: []
|
|
@@ -11694,7 +12637,7 @@ var TechnologyService = class extends BaseService {
|
|
|
11694
12637
|
* Vraća referencu na Firestore kolekciju tehnologija
|
|
11695
12638
|
*/
|
|
11696
12639
|
getTechnologiesRef() {
|
|
11697
|
-
return
|
|
12640
|
+
return collection27(this.db, TECHNOLOGIES_COLLECTION);
|
|
11698
12641
|
}
|
|
11699
12642
|
/**
|
|
11700
12643
|
* Kreira novu tehnologiju
|
|
@@ -11725,12 +12668,12 @@ var TechnologyService = class extends BaseService {
|
|
|
11725
12668
|
* @returns Lista aktivnih tehnologija
|
|
11726
12669
|
*/
|
|
11727
12670
|
async getAll() {
|
|
11728
|
-
const q =
|
|
11729
|
-
const snapshot = await
|
|
12671
|
+
const q = query27(this.getTechnologiesRef(), where27("isActive", "==", true));
|
|
12672
|
+
const snapshot = await getDocs27(q);
|
|
11730
12673
|
return snapshot.docs.map(
|
|
11731
|
-
(
|
|
11732
|
-
id:
|
|
11733
|
-
...
|
|
12674
|
+
(doc30) => ({
|
|
12675
|
+
id: doc30.id,
|
|
12676
|
+
...doc30.data()
|
|
11734
12677
|
})
|
|
11735
12678
|
);
|
|
11736
12679
|
}
|
|
@@ -11740,16 +12683,16 @@ var TechnologyService = class extends BaseService {
|
|
|
11740
12683
|
* @returns Lista aktivnih tehnologija
|
|
11741
12684
|
*/
|
|
11742
12685
|
async getAllByFamily(family) {
|
|
11743
|
-
const q =
|
|
12686
|
+
const q = query27(
|
|
11744
12687
|
this.getTechnologiesRef(),
|
|
11745
|
-
|
|
11746
|
-
|
|
12688
|
+
where27("isActive", "==", true),
|
|
12689
|
+
where27("family", "==", family)
|
|
11747
12690
|
);
|
|
11748
|
-
const snapshot = await
|
|
12691
|
+
const snapshot = await getDocs27(q);
|
|
11749
12692
|
return snapshot.docs.map(
|
|
11750
|
-
(
|
|
11751
|
-
id:
|
|
11752
|
-
...
|
|
12693
|
+
(doc30) => ({
|
|
12694
|
+
id: doc30.id,
|
|
12695
|
+
...doc30.data()
|
|
11753
12696
|
})
|
|
11754
12697
|
);
|
|
11755
12698
|
}
|
|
@@ -11759,16 +12702,16 @@ var TechnologyService = class extends BaseService {
|
|
|
11759
12702
|
* @returns Lista aktivnih tehnologija
|
|
11760
12703
|
*/
|
|
11761
12704
|
async getAllByCategoryId(categoryId) {
|
|
11762
|
-
const q =
|
|
12705
|
+
const q = query27(
|
|
11763
12706
|
this.getTechnologiesRef(),
|
|
11764
|
-
|
|
11765
|
-
|
|
12707
|
+
where27("isActive", "==", true),
|
|
12708
|
+
where27("categoryId", "==", categoryId)
|
|
11766
12709
|
);
|
|
11767
|
-
const snapshot = await
|
|
12710
|
+
const snapshot = await getDocs27(q);
|
|
11768
12711
|
return snapshot.docs.map(
|
|
11769
|
-
(
|
|
11770
|
-
id:
|
|
11771
|
-
...
|
|
12712
|
+
(doc30) => ({
|
|
12713
|
+
id: doc30.id,
|
|
12714
|
+
...doc30.data()
|
|
11772
12715
|
})
|
|
11773
12716
|
);
|
|
11774
12717
|
}
|
|
@@ -11778,16 +12721,16 @@ var TechnologyService = class extends BaseService {
|
|
|
11778
12721
|
* @returns Lista aktivnih tehnologija
|
|
11779
12722
|
*/
|
|
11780
12723
|
async getAllBySubcategoryId(subcategoryId) {
|
|
11781
|
-
const q =
|
|
12724
|
+
const q = query27(
|
|
11782
12725
|
this.getTechnologiesRef(),
|
|
11783
|
-
|
|
11784
|
-
|
|
12726
|
+
where27("isActive", "==", true),
|
|
12727
|
+
where27("subcategoryId", "==", subcategoryId)
|
|
11785
12728
|
);
|
|
11786
|
-
const snapshot = await
|
|
12729
|
+
const snapshot = await getDocs27(q);
|
|
11787
12730
|
return snapshot.docs.map(
|
|
11788
|
-
(
|
|
11789
|
-
id:
|
|
11790
|
-
...
|
|
12731
|
+
(doc30) => ({
|
|
12732
|
+
id: doc30.id,
|
|
12733
|
+
...doc30.data()
|
|
11791
12734
|
})
|
|
11792
12735
|
);
|
|
11793
12736
|
}
|
|
@@ -11802,8 +12745,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11802
12745
|
...technology,
|
|
11803
12746
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11804
12747
|
};
|
|
11805
|
-
const docRef =
|
|
11806
|
-
await
|
|
12748
|
+
const docRef = doc28(this.getTechnologiesRef(), technologyId);
|
|
12749
|
+
await updateDoc29(docRef, updateData);
|
|
11807
12750
|
return this.getById(technologyId);
|
|
11808
12751
|
}
|
|
11809
12752
|
/**
|
|
@@ -11821,8 +12764,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11821
12764
|
* @returns Tehnologija ili null ako ne postoji
|
|
11822
12765
|
*/
|
|
11823
12766
|
async getById(technologyId) {
|
|
11824
|
-
const docRef =
|
|
11825
|
-
const docSnap = await
|
|
12767
|
+
const docRef = doc28(this.getTechnologiesRef(), technologyId);
|
|
12768
|
+
const docSnap = await getDoc30(docRef);
|
|
11826
12769
|
if (!docSnap.exists()) return null;
|
|
11827
12770
|
return {
|
|
11828
12771
|
id: docSnap.id,
|
|
@@ -11836,9 +12779,9 @@ var TechnologyService = class extends BaseService {
|
|
|
11836
12779
|
* @returns Ažurirana tehnologija sa novim zahtevom
|
|
11837
12780
|
*/
|
|
11838
12781
|
async addRequirement(technologyId, requirement) {
|
|
11839
|
-
const docRef =
|
|
12782
|
+
const docRef = doc28(this.getTechnologiesRef(), technologyId);
|
|
11840
12783
|
const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
|
|
11841
|
-
await
|
|
12784
|
+
await updateDoc29(docRef, {
|
|
11842
12785
|
[requirementType]: arrayUnion8(requirement),
|
|
11843
12786
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11844
12787
|
});
|
|
@@ -11851,9 +12794,9 @@ var TechnologyService = class extends BaseService {
|
|
|
11851
12794
|
* @returns Ažurirana tehnologija bez uklonjenog zahteva
|
|
11852
12795
|
*/
|
|
11853
12796
|
async removeRequirement(technologyId, requirement) {
|
|
11854
|
-
const docRef =
|
|
12797
|
+
const docRef = doc28(this.getTechnologiesRef(), technologyId);
|
|
11855
12798
|
const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
|
|
11856
|
-
await
|
|
12799
|
+
await updateDoc29(docRef, {
|
|
11857
12800
|
[requirementType]: arrayRemove7(requirement),
|
|
11858
12801
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11859
12802
|
});
|
|
@@ -11891,8 +12834,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11891
12834
|
* @returns Ažurirana tehnologija
|
|
11892
12835
|
*/
|
|
11893
12836
|
async addBlockingCondition(technologyId, condition) {
|
|
11894
|
-
const docRef =
|
|
11895
|
-
await
|
|
12837
|
+
const docRef = doc28(this.getTechnologiesRef(), technologyId);
|
|
12838
|
+
await updateDoc29(docRef, {
|
|
11896
12839
|
blockingConditions: arrayUnion8(condition),
|
|
11897
12840
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11898
12841
|
});
|
|
@@ -11905,8 +12848,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11905
12848
|
* @returns Ažurirana tehnologija
|
|
11906
12849
|
*/
|
|
11907
12850
|
async removeBlockingCondition(technologyId, condition) {
|
|
11908
|
-
const docRef =
|
|
11909
|
-
await
|
|
12851
|
+
const docRef = doc28(this.getTechnologiesRef(), technologyId);
|
|
12852
|
+
await updateDoc29(docRef, {
|
|
11910
12853
|
blockingConditions: arrayRemove7(condition),
|
|
11911
12854
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11912
12855
|
});
|
|
@@ -11919,8 +12862,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11919
12862
|
* @returns Ažurirana tehnologija
|
|
11920
12863
|
*/
|
|
11921
12864
|
async addContraindication(technologyId, contraindication) {
|
|
11922
|
-
const docRef =
|
|
11923
|
-
await
|
|
12865
|
+
const docRef = doc28(this.getTechnologiesRef(), technologyId);
|
|
12866
|
+
await updateDoc29(docRef, {
|
|
11924
12867
|
contraindications: arrayUnion8(contraindication),
|
|
11925
12868
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11926
12869
|
});
|
|
@@ -11933,8 +12876,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11933
12876
|
* @returns Ažurirana tehnologija
|
|
11934
12877
|
*/
|
|
11935
12878
|
async removeContraindication(technologyId, contraindication) {
|
|
11936
|
-
const docRef =
|
|
11937
|
-
await
|
|
12879
|
+
const docRef = doc28(this.getTechnologiesRef(), technologyId);
|
|
12880
|
+
await updateDoc29(docRef, {
|
|
11938
12881
|
contraindications: arrayRemove7(contraindication),
|
|
11939
12882
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11940
12883
|
});
|
|
@@ -11947,8 +12890,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11947
12890
|
* @returns Ažurirana tehnologija
|
|
11948
12891
|
*/
|
|
11949
12892
|
async addBenefit(technologyId, benefit) {
|
|
11950
|
-
const docRef =
|
|
11951
|
-
await
|
|
12893
|
+
const docRef = doc28(this.getTechnologiesRef(), technologyId);
|
|
12894
|
+
await updateDoc29(docRef, {
|
|
11952
12895
|
benefits: arrayUnion8(benefit),
|
|
11953
12896
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11954
12897
|
});
|
|
@@ -11961,8 +12904,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11961
12904
|
* @returns Ažurirana tehnologija
|
|
11962
12905
|
*/
|
|
11963
12906
|
async removeBenefit(technologyId, benefit) {
|
|
11964
|
-
const docRef =
|
|
11965
|
-
await
|
|
12907
|
+
const docRef = doc28(this.getTechnologiesRef(), technologyId);
|
|
12908
|
+
await updateDoc29(docRef, {
|
|
11966
12909
|
benefits: arrayRemove7(benefit),
|
|
11967
12910
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11968
12911
|
});
|
|
@@ -12002,8 +12945,8 @@ var TechnologyService = class extends BaseService {
|
|
|
12002
12945
|
* @returns Ažurirana tehnologija
|
|
12003
12946
|
*/
|
|
12004
12947
|
async updateCertificationRequirement(technologyId, certificationRequirement) {
|
|
12005
|
-
const docRef =
|
|
12006
|
-
await
|
|
12948
|
+
const docRef = doc28(this.getTechnologiesRef(), technologyId);
|
|
12949
|
+
await updateDoc29(docRef, {
|
|
12007
12950
|
certificationRequirement,
|
|
12008
12951
|
updatedAt: /* @__PURE__ */ new Date()
|
|
12009
12952
|
});
|
|
@@ -12105,13 +13048,13 @@ var TechnologyService = class extends BaseService {
|
|
|
12105
13048
|
// src/backoffice/services/product.service.ts
|
|
12106
13049
|
import {
|
|
12107
13050
|
addDoc as addDoc7,
|
|
12108
|
-
collection as
|
|
12109
|
-
doc as
|
|
12110
|
-
getDoc as
|
|
12111
|
-
getDocs as
|
|
12112
|
-
query as
|
|
12113
|
-
updateDoc as
|
|
12114
|
-
where as
|
|
13051
|
+
collection as collection28,
|
|
13052
|
+
doc as doc29,
|
|
13053
|
+
getDoc as getDoc31,
|
|
13054
|
+
getDocs as getDocs28,
|
|
13055
|
+
query as query28,
|
|
13056
|
+
updateDoc as updateDoc30,
|
|
13057
|
+
where as where28
|
|
12115
13058
|
} from "firebase/firestore";
|
|
12116
13059
|
|
|
12117
13060
|
// src/backoffice/types/product.types.ts
|
|
@@ -12125,7 +13068,7 @@ var ProductService = class extends BaseService {
|
|
|
12125
13068
|
* @returns Firestore collection reference
|
|
12126
13069
|
*/
|
|
12127
13070
|
getProductsRef(technologyId) {
|
|
12128
|
-
return
|
|
13071
|
+
return collection28(
|
|
12129
13072
|
this.db,
|
|
12130
13073
|
TECHNOLOGIES_COLLECTION,
|
|
12131
13074
|
technologyId,
|
|
@@ -12155,15 +13098,15 @@ var ProductService = class extends BaseService {
|
|
|
12155
13098
|
* Gets all products for a technology
|
|
12156
13099
|
*/
|
|
12157
13100
|
async getAllByTechnology(technologyId) {
|
|
12158
|
-
const q =
|
|
13101
|
+
const q = query28(
|
|
12159
13102
|
this.getProductsRef(technologyId),
|
|
12160
|
-
|
|
13103
|
+
where28("isActive", "==", true)
|
|
12161
13104
|
);
|
|
12162
|
-
const snapshot = await
|
|
13105
|
+
const snapshot = await getDocs28(q);
|
|
12163
13106
|
return snapshot.docs.map(
|
|
12164
|
-
(
|
|
12165
|
-
id:
|
|
12166
|
-
...
|
|
13107
|
+
(doc30) => ({
|
|
13108
|
+
id: doc30.id,
|
|
13109
|
+
...doc30.data()
|
|
12167
13110
|
})
|
|
12168
13111
|
);
|
|
12169
13112
|
}
|
|
@@ -12171,21 +13114,21 @@ var ProductService = class extends BaseService {
|
|
|
12171
13114
|
* Gets all products for a brand by filtering through all technologies
|
|
12172
13115
|
*/
|
|
12173
13116
|
async getAllByBrand(brandId) {
|
|
12174
|
-
const allTechnologiesRef =
|
|
12175
|
-
const technologiesSnapshot = await
|
|
13117
|
+
const allTechnologiesRef = collection28(this.db, TECHNOLOGIES_COLLECTION);
|
|
13118
|
+
const technologiesSnapshot = await getDocs28(allTechnologiesRef);
|
|
12176
13119
|
const products = [];
|
|
12177
13120
|
for (const techDoc of technologiesSnapshot.docs) {
|
|
12178
|
-
const q =
|
|
13121
|
+
const q = query28(
|
|
12179
13122
|
this.getProductsRef(techDoc.id),
|
|
12180
|
-
|
|
12181
|
-
|
|
13123
|
+
where28("brandId", "==", brandId),
|
|
13124
|
+
where28("isActive", "==", true)
|
|
12182
13125
|
);
|
|
12183
|
-
const snapshot = await
|
|
13126
|
+
const snapshot = await getDocs28(q);
|
|
12184
13127
|
products.push(
|
|
12185
13128
|
...snapshot.docs.map(
|
|
12186
|
-
(
|
|
12187
|
-
id:
|
|
12188
|
-
...
|
|
13129
|
+
(doc30) => ({
|
|
13130
|
+
id: doc30.id,
|
|
13131
|
+
...doc30.data()
|
|
12189
13132
|
})
|
|
12190
13133
|
)
|
|
12191
13134
|
);
|
|
@@ -12200,8 +13143,8 @@ var ProductService = class extends BaseService {
|
|
|
12200
13143
|
...product,
|
|
12201
13144
|
updatedAt: /* @__PURE__ */ new Date()
|
|
12202
13145
|
};
|
|
12203
|
-
const docRef =
|
|
12204
|
-
await
|
|
13146
|
+
const docRef = doc29(this.getProductsRef(technologyId), productId);
|
|
13147
|
+
await updateDoc30(docRef, updateData);
|
|
12205
13148
|
return this.getById(technologyId, productId);
|
|
12206
13149
|
}
|
|
12207
13150
|
/**
|
|
@@ -12216,8 +13159,8 @@ var ProductService = class extends BaseService {
|
|
|
12216
13159
|
* Gets a product by ID
|
|
12217
13160
|
*/
|
|
12218
13161
|
async getById(technologyId, productId) {
|
|
12219
|
-
const docRef =
|
|
12220
|
-
const docSnap = await
|
|
13162
|
+
const docRef = doc29(this.getProductsRef(technologyId), productId);
|
|
13163
|
+
const docSnap = await getDoc31(docRef);
|
|
12221
13164
|
if (!docSnap.exists()) return null;
|
|
12222
13165
|
return {
|
|
12223
13166
|
id: docSnap.id,
|
|
@@ -12227,54 +13170,54 @@ var ProductService = class extends BaseService {
|
|
|
12227
13170
|
};
|
|
12228
13171
|
|
|
12229
13172
|
// src/validations/notification.schema.ts
|
|
12230
|
-
import { z as
|
|
12231
|
-
var baseNotificationSchema =
|
|
12232
|
-
id:
|
|
12233
|
-
userId:
|
|
12234
|
-
notificationTime:
|
|
13173
|
+
import { z as z23 } from "zod";
|
|
13174
|
+
var baseNotificationSchema = z23.object({
|
|
13175
|
+
id: z23.string().optional(),
|
|
13176
|
+
userId: z23.string(),
|
|
13177
|
+
notificationTime: z23.any(),
|
|
12235
13178
|
// Timestamp
|
|
12236
|
-
notificationType:
|
|
12237
|
-
notificationTokens:
|
|
12238
|
-
status:
|
|
12239
|
-
createdAt:
|
|
13179
|
+
notificationType: z23.nativeEnum(NotificationType),
|
|
13180
|
+
notificationTokens: z23.array(z23.string()),
|
|
13181
|
+
status: z23.nativeEnum(NotificationStatus),
|
|
13182
|
+
createdAt: z23.any().optional(),
|
|
12240
13183
|
// Timestamp
|
|
12241
|
-
updatedAt:
|
|
13184
|
+
updatedAt: z23.any().optional(),
|
|
12242
13185
|
// Timestamp
|
|
12243
|
-
title:
|
|
12244
|
-
body:
|
|
12245
|
-
isRead:
|
|
12246
|
-
userRole:
|
|
13186
|
+
title: z23.string(),
|
|
13187
|
+
body: z23.string(),
|
|
13188
|
+
isRead: z23.boolean(),
|
|
13189
|
+
userRole: z23.nativeEnum(UserRole)
|
|
12247
13190
|
});
|
|
12248
13191
|
var preRequirementNotificationSchema = baseNotificationSchema.extend({
|
|
12249
|
-
notificationType:
|
|
12250
|
-
treatmentId:
|
|
12251
|
-
requirements:
|
|
12252
|
-
deadline:
|
|
13192
|
+
notificationType: z23.literal("preRequirement" /* PRE_REQUIREMENT */),
|
|
13193
|
+
treatmentId: z23.string(),
|
|
13194
|
+
requirements: z23.array(z23.string()),
|
|
13195
|
+
deadline: z23.any()
|
|
12253
13196
|
// Timestamp
|
|
12254
13197
|
});
|
|
12255
13198
|
var postRequirementNotificationSchema = baseNotificationSchema.extend({
|
|
12256
|
-
notificationType:
|
|
12257
|
-
treatmentId:
|
|
12258
|
-
requirements:
|
|
12259
|
-
deadline:
|
|
13199
|
+
notificationType: z23.literal("postRequirement" /* POST_REQUIREMENT */),
|
|
13200
|
+
treatmentId: z23.string(),
|
|
13201
|
+
requirements: z23.array(z23.string()),
|
|
13202
|
+
deadline: z23.any()
|
|
12260
13203
|
// Timestamp
|
|
12261
13204
|
});
|
|
12262
13205
|
var appointmentReminderNotificationSchema = baseNotificationSchema.extend({
|
|
12263
|
-
notificationType:
|
|
12264
|
-
appointmentId:
|
|
12265
|
-
appointmentTime:
|
|
13206
|
+
notificationType: z23.literal("appointmentReminder" /* APPOINTMENT_REMINDER */),
|
|
13207
|
+
appointmentId: z23.string(),
|
|
13208
|
+
appointmentTime: z23.any(),
|
|
12266
13209
|
// Timestamp
|
|
12267
|
-
treatmentType:
|
|
12268
|
-
doctorName:
|
|
13210
|
+
treatmentType: z23.string(),
|
|
13211
|
+
doctorName: z23.string()
|
|
12269
13212
|
});
|
|
12270
13213
|
var appointmentNotificationSchema = baseNotificationSchema.extend({
|
|
12271
|
-
notificationType:
|
|
12272
|
-
appointmentId:
|
|
12273
|
-
appointmentStatus:
|
|
12274
|
-
previousStatus:
|
|
12275
|
-
reason:
|
|
13214
|
+
notificationType: z23.literal("appointmentNotification" /* APPOINTMENT_NOTIFICATION */),
|
|
13215
|
+
appointmentId: z23.string(),
|
|
13216
|
+
appointmentStatus: z23.string(),
|
|
13217
|
+
previousStatus: z23.string(),
|
|
13218
|
+
reason: z23.string().optional()
|
|
12276
13219
|
});
|
|
12277
|
-
var notificationSchema =
|
|
13220
|
+
var notificationSchema = z23.discriminatedUnion("notificationType", [
|
|
12278
13221
|
preRequirementNotificationSchema,
|
|
12279
13222
|
postRequirementNotificationSchema,
|
|
12280
13223
|
appointmentReminderNotificationSchema,
|
|
@@ -12313,9 +13256,12 @@ var RequirementType = /* @__PURE__ */ ((RequirementType2) => {
|
|
|
12313
13256
|
return RequirementType2;
|
|
12314
13257
|
})(RequirementType || {});
|
|
12315
13258
|
export {
|
|
13259
|
+
APPOINTMENTS_COLLECTION,
|
|
12316
13260
|
AUTH_ERRORS,
|
|
12317
13261
|
AdminTokenStatus,
|
|
12318
13262
|
AllergyType,
|
|
13263
|
+
AppointmentService,
|
|
13264
|
+
AppointmentStatus,
|
|
12319
13265
|
AuthService,
|
|
12320
13266
|
BlockingCondition,
|
|
12321
13267
|
BrandService,
|
|
@@ -12365,6 +13311,7 @@ export {
|
|
|
12365
13311
|
PRACTITIONERS_COLLECTION,
|
|
12366
13312
|
PROCEDURES_COLLECTION,
|
|
12367
13313
|
PatientService,
|
|
13314
|
+
PaymentStatus,
|
|
12368
13315
|
PracticeType,
|
|
12369
13316
|
PractitionerService,
|
|
12370
13317
|
PractitionerStatus,
|
|
@@ -12479,6 +13426,7 @@ export {
|
|
|
12479
13426
|
procedureSummaryInfoSchema,
|
|
12480
13427
|
requesterInfoSchema,
|
|
12481
13428
|
reviewSchema,
|
|
13429
|
+
searchAppointmentsSchema,
|
|
12482
13430
|
searchPatientsSchema,
|
|
12483
13431
|
syncedCalendarEventSchema,
|
|
12484
13432
|
timeSlotSchema2 as timeSlotSchema,
|