@blackcode_sa/metaestetics-api 1.6.3 → 1.6.5
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/admin/index.d.mts +439 -25
- package/dist/admin/index.d.ts +439 -25
- package/dist/admin/index.js +36107 -2493
- package/dist/admin/index.mjs +36093 -2461
- package/dist/backoffice/index.d.mts +254 -1
- package/dist/backoffice/index.d.ts +254 -1
- package/dist/backoffice/index.js +86 -12
- package/dist/backoffice/index.mjs +86 -13
- package/dist/index.d.mts +1434 -621
- package/dist/index.d.ts +1434 -621
- package/dist/index.js +1381 -970
- package/dist/index.mjs +1433 -1016
- package/package.json +1 -1
- package/src/admin/aggregation/appointment/appointment.aggregation.service.ts +321 -0
- package/src/admin/booking/booking.admin.ts +376 -3
- package/src/admin/index.ts +15 -1
- package/src/admin/notifications/notifications.admin.ts +1 -1
- package/src/admin/requirements/README.md +128 -0
- package/src/admin/requirements/patient-requirements.admin.service.ts +482 -0
- package/src/backoffice/types/product.types.ts +2 -0
- package/src/index.ts +16 -1
- package/src/services/appointment/appointment.service.ts +386 -250
- package/src/services/clinic/clinic-admin.service.ts +3 -0
- package/src/services/clinic/clinic-group.service.ts +8 -0
- package/src/services/documentation-templates/documentation-template.service.ts +24 -16
- package/src/services/documentation-templates/filled-document.service.ts +253 -136
- package/src/services/patient/patientRequirements.service.ts +285 -0
- package/src/services/procedure/procedure.service.ts +1 -0
- package/src/types/appointment/index.ts +136 -11
- package/src/types/documentation-templates/index.ts +34 -2
- package/src/types/notifications/README.md +77 -0
- package/src/types/notifications/index.ts +154 -27
- package/src/types/patient/patient-requirements.ts +81 -0
- package/src/types/procedure/index.ts +7 -0
- package/src/validations/appointment.schema.ts +298 -62
- package/src/validations/documentation-templates/template.schema.ts +55 -0
- package/src/validations/documentation-templates.schema.ts +9 -14
- package/src/validations/notification.schema.ts +3 -3
- package/src/validations/patient/patient-requirements.schema.ts +75 -0
- package/src/validations/procedure.schema.ts +3 -0
package/dist/index.js
CHANGED
|
@@ -81,9 +81,13 @@ __export(index_exports, {
|
|
|
81
81
|
PATIENT_LOCATION_INFO_COLLECTION: () => PATIENT_LOCATION_INFO_COLLECTION,
|
|
82
82
|
PATIENT_MEDICAL_HISTORY_COLLECTION: () => PATIENT_MEDICAL_HISTORY_COLLECTION,
|
|
83
83
|
PATIENT_MEDICAL_INFO_COLLECTION: () => PATIENT_MEDICAL_INFO_COLLECTION,
|
|
84
|
+
PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME: () => PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME,
|
|
84
85
|
PATIENT_SENSITIVE_INFO_COLLECTION: () => PATIENT_SENSITIVE_INFO_COLLECTION,
|
|
85
86
|
PRACTITIONERS_COLLECTION: () => PRACTITIONERS_COLLECTION,
|
|
86
87
|
PROCEDURES_COLLECTION: () => PROCEDURES_COLLECTION,
|
|
88
|
+
PatientInstructionStatus: () => PatientInstructionStatus,
|
|
89
|
+
PatientRequirementOverallStatus: () => PatientRequirementOverallStatus,
|
|
90
|
+
PatientRequirementsService: () => PatientRequirementsService,
|
|
87
91
|
PatientService: () => PatientService,
|
|
88
92
|
PaymentStatus: () => PaymentStatus,
|
|
89
93
|
PracticeType: () => PracticeType,
|
|
@@ -148,6 +152,7 @@ __export(index_exports, {
|
|
|
148
152
|
createDefaultClinicGroupSchema: () => createDefaultClinicGroupSchema,
|
|
149
153
|
createDocumentTemplateSchema: () => createDocumentTemplateSchema,
|
|
150
154
|
createDraftPractitionerSchema: () => createDraftPractitionerSchema,
|
|
155
|
+
createFilledDocumentDataSchema: () => createFilledDocumentDataSchema,
|
|
151
156
|
createPatientLocationInfoSchema: () => createPatientLocationInfoSchema,
|
|
152
157
|
createPatientMedicalInfoSchema: () => createPatientMedicalInfoSchema,
|
|
153
158
|
createPatientProfileSchema: () => createPatientProfileSchema,
|
|
@@ -163,6 +168,8 @@ __export(index_exports, {
|
|
|
163
168
|
documentTemplateSchema: () => documentTemplateSchema,
|
|
164
169
|
emailSchema: () => emailSchema,
|
|
165
170
|
emergencyContactSchema: () => emergencyContactSchema,
|
|
171
|
+
filledDocumentSchema: () => filledDocumentSchema,
|
|
172
|
+
filledDocumentStatusSchema: () => filledDocumentStatusSchema,
|
|
166
173
|
gamificationSchema: () => gamificationSchema,
|
|
167
174
|
getFirebaseApp: () => getFirebaseApp,
|
|
168
175
|
getFirebaseAuth: () => getFirebaseAuth,
|
|
@@ -212,6 +219,7 @@ __export(index_exports, {
|
|
|
212
219
|
updateClinicSchema: () => updateClinicSchema,
|
|
213
220
|
updateContraindicationSchema: () => updateContraindicationSchema,
|
|
214
221
|
updateDocumentTemplateSchema: () => updateDocumentTemplateSchema,
|
|
222
|
+
updateFilledDocumentDataSchema: () => updateFilledDocumentDataSchema,
|
|
215
223
|
updateMedicationSchema: () => updateMedicationSchema,
|
|
216
224
|
updatePatientMedicalInfoSchema: () => updatePatientMedicalInfoSchema,
|
|
217
225
|
updateVitalStatsSchema: () => updateVitalStatsSchema,
|
|
@@ -224,19 +232,20 @@ __export(index_exports, {
|
|
|
224
232
|
module.exports = __toCommonJS(index_exports);
|
|
225
233
|
|
|
226
234
|
// src/validations/appointment.schema.ts
|
|
227
|
-
var
|
|
235
|
+
var import_zod2 = require("zod");
|
|
228
236
|
|
|
229
237
|
// src/types/appointment/index.ts
|
|
230
238
|
var AppointmentStatus = /* @__PURE__ */ ((AppointmentStatus2) => {
|
|
231
|
-
AppointmentStatus2["
|
|
239
|
+
AppointmentStatus2["PENDING"] = "pending";
|
|
232
240
|
AppointmentStatus2["CONFIRMED"] = "confirmed";
|
|
233
241
|
AppointmentStatus2["CHECKED_IN"] = "checked_in";
|
|
234
242
|
AppointmentStatus2["IN_PROGRESS"] = "in_progress";
|
|
235
243
|
AppointmentStatus2["COMPLETED"] = "completed";
|
|
236
244
|
AppointmentStatus2["CANCELED_PATIENT"] = "canceled_patient";
|
|
245
|
+
AppointmentStatus2["CANCELED_PATIENT_RESCHEDULED"] = "canceled_patient_rescheduled";
|
|
237
246
|
AppointmentStatus2["CANCELED_CLINIC"] = "canceled_clinic";
|
|
238
247
|
AppointmentStatus2["NO_SHOW"] = "no_show";
|
|
239
|
-
AppointmentStatus2["
|
|
248
|
+
AppointmentStatus2["RESCHEDULED_BY_CLINIC"] = "rescheduled_by_clinic";
|
|
240
249
|
return AppointmentStatus2;
|
|
241
250
|
})(AppointmentStatus || {});
|
|
242
251
|
var PaymentStatus = /* @__PURE__ */ ((PaymentStatus3) => {
|
|
@@ -247,82 +256,444 @@ var PaymentStatus = /* @__PURE__ */ ((PaymentStatus3) => {
|
|
|
247
256
|
PaymentStatus3["NOT_APPLICABLE"] = "not_applicable";
|
|
248
257
|
return PaymentStatus3;
|
|
249
258
|
})(PaymentStatus || {});
|
|
259
|
+
var MediaType = /* @__PURE__ */ ((MediaType2) => {
|
|
260
|
+
MediaType2["BEFORE_PHOTO"] = "before_photo";
|
|
261
|
+
MediaType2["AFTER_PHOTO"] = "after_photo";
|
|
262
|
+
MediaType2["CONSENT_SCAN"] = "consent_scan";
|
|
263
|
+
MediaType2["OTHER_DOCUMENT"] = "other_document";
|
|
264
|
+
return MediaType2;
|
|
265
|
+
})(MediaType || {});
|
|
250
266
|
var APPOINTMENTS_COLLECTION = "appointments";
|
|
251
267
|
|
|
268
|
+
// src/validations/documentation-templates/template.schema.ts
|
|
269
|
+
var import_zod = require("zod");
|
|
270
|
+
|
|
271
|
+
// src/types/documentation-templates/index.ts
|
|
272
|
+
var DOCUMENTATION_TEMPLATES_COLLECTION = "documentation-templates";
|
|
273
|
+
var FILLED_DOCUMENTS_COLLECTION = "filled-documents";
|
|
274
|
+
var USER_FORMS_SUBCOLLECTION = "user-forms";
|
|
275
|
+
var DOCTOR_FORMS_SUBCOLLECTION = "doctor-forms";
|
|
276
|
+
var DocumentElementType = /* @__PURE__ */ ((DocumentElementType2) => {
|
|
277
|
+
DocumentElementType2["HEADING"] = "heading";
|
|
278
|
+
DocumentElementType2["PARAGRAPH"] = "paragraph";
|
|
279
|
+
DocumentElementType2["LIST"] = "list";
|
|
280
|
+
DocumentElementType2["DYNAMIC_TEXT"] = "dynamic_text";
|
|
281
|
+
DocumentElementType2["BINARY_CHOICE"] = "binary_choice";
|
|
282
|
+
DocumentElementType2["MULTIPLE_CHOICE"] = "multiple_choice";
|
|
283
|
+
DocumentElementType2["SINGLE_CHOICE"] = "single_choice";
|
|
284
|
+
DocumentElementType2["RATING_SCALE"] = "rating_scale";
|
|
285
|
+
DocumentElementType2["TEXT_INPUT"] = "text_input";
|
|
286
|
+
DocumentElementType2["DATE_PICKER"] = "date_picker";
|
|
287
|
+
DocumentElementType2["SIGNATURE"] = "signature";
|
|
288
|
+
DocumentElementType2["DITIGAL_SIGNATURE"] = "digital_signature";
|
|
289
|
+
DocumentElementType2["FILE_UPLOAD"] = "file_upload";
|
|
290
|
+
return DocumentElementType2;
|
|
291
|
+
})(DocumentElementType || {});
|
|
292
|
+
var ListType = /* @__PURE__ */ ((ListType2) => {
|
|
293
|
+
ListType2["ORDERED"] = "ordered";
|
|
294
|
+
ListType2["UNORDERED"] = "unordered";
|
|
295
|
+
return ListType2;
|
|
296
|
+
})(ListType || {});
|
|
297
|
+
var HeadingLevel = /* @__PURE__ */ ((HeadingLevel2) => {
|
|
298
|
+
HeadingLevel2["H1"] = "h1";
|
|
299
|
+
HeadingLevel2["H2"] = "h2";
|
|
300
|
+
HeadingLevel2["H3"] = "h3";
|
|
301
|
+
HeadingLevel2["H4"] = "h4";
|
|
302
|
+
HeadingLevel2["H5"] = "h5";
|
|
303
|
+
HeadingLevel2["H6"] = "h6";
|
|
304
|
+
return HeadingLevel2;
|
|
305
|
+
})(HeadingLevel || {});
|
|
306
|
+
var DynamicVariable = /* @__PURE__ */ ((DynamicVariable2) => {
|
|
307
|
+
DynamicVariable2["PATIENT_NAME"] = "[PATIENT_NAME]";
|
|
308
|
+
DynamicVariable2["DOCTOR_NAME"] = "[DOCTOR_NAME]";
|
|
309
|
+
DynamicVariable2["CLINIC_NAME"] = "[CLINIC_NAME]";
|
|
310
|
+
DynamicVariable2["PATIENT_BIRTHDAY"] = "[PATIENT_BIRTHDAY]";
|
|
311
|
+
DynamicVariable2["APPOINTMENT_DATE"] = "[APPOINTMENT_DATE]";
|
|
312
|
+
DynamicVariable2["CURRENT_DATE"] = "[CURRENT_DATE]";
|
|
313
|
+
DynamicVariable2["PROCEDURE_NAME"] = "[PROCEDURE_NAME]";
|
|
314
|
+
DynamicVariable2["PROCEDURE_DESCRIPTION"] = "[PROCEDURE_DESCRIPTION]";
|
|
315
|
+
DynamicVariable2["PROCEDURE_COST"] = "[PROCEDURE_COST]";
|
|
316
|
+
DynamicVariable2["PROCEDURE_DURATION"] = "[PROCEDURE_DURATION]";
|
|
317
|
+
DynamicVariable2["PROCEDURE_RISK"] = "[PROCEDURE_RISK]";
|
|
318
|
+
return DynamicVariable2;
|
|
319
|
+
})(DynamicVariable || {});
|
|
320
|
+
var FilledDocumentStatus = /* @__PURE__ */ ((FilledDocumentStatus2) => {
|
|
321
|
+
FilledDocumentStatus2["DRAFT"] = "draft";
|
|
322
|
+
FilledDocumentStatus2["SKIPPED"] = "skipped";
|
|
323
|
+
FilledDocumentStatus2["PENDING"] = "pending";
|
|
324
|
+
FilledDocumentStatus2["COMPLETED"] = "completed";
|
|
325
|
+
FilledDocumentStatus2["SIGNED"] = "signed";
|
|
326
|
+
FilledDocumentStatus2["REJECTED"] = "rejected";
|
|
327
|
+
return FilledDocumentStatus2;
|
|
328
|
+
})(FilledDocumentStatus || {});
|
|
329
|
+
|
|
330
|
+
// src/validations/documentation-templates/template.schema.ts
|
|
331
|
+
var baseElementSchema = import_zod.z.object({
|
|
332
|
+
id: import_zod.z.string().optional(),
|
|
333
|
+
// Make id optional so we can omit it later
|
|
334
|
+
type: import_zod.z.nativeEnum(DocumentElementType),
|
|
335
|
+
required: import_zod.z.boolean().optional()
|
|
336
|
+
});
|
|
337
|
+
var headingElementSchema = baseElementSchema.extend({
|
|
338
|
+
type: import_zod.z.literal("heading" /* HEADING */),
|
|
339
|
+
text: import_zod.z.string().min(1).max(200),
|
|
340
|
+
level: import_zod.z.nativeEnum(HeadingLevel)
|
|
341
|
+
});
|
|
342
|
+
var paragraphElementSchema = baseElementSchema.extend({
|
|
343
|
+
type: import_zod.z.literal("paragraph" /* PARAGRAPH */),
|
|
344
|
+
text: import_zod.z.string().min(1).max(5e3)
|
|
345
|
+
});
|
|
346
|
+
var listElementSchema = baseElementSchema.extend({
|
|
347
|
+
type: import_zod.z.literal("list" /* LIST */),
|
|
348
|
+
items: import_zod.z.array(import_zod.z.string().min(1).max(500)).min(1).max(100),
|
|
349
|
+
listType: import_zod.z.nativeEnum(ListType)
|
|
350
|
+
});
|
|
351
|
+
var dynamicTextElementSchema = baseElementSchema.extend({
|
|
352
|
+
type: import_zod.z.literal("dynamic_text" /* DYNAMIC_TEXT */),
|
|
353
|
+
text: import_zod.z.string().min(1).max(5e3)
|
|
354
|
+
});
|
|
355
|
+
var binaryChoiceElementSchema = baseElementSchema.extend({
|
|
356
|
+
type: import_zod.z.literal("binary_choice" /* BINARY_CHOICE */),
|
|
357
|
+
question: import_zod.z.string().min(1).max(500),
|
|
358
|
+
defaultValue: import_zod.z.boolean().optional()
|
|
359
|
+
});
|
|
360
|
+
var multipleChoiceElementSchema = baseElementSchema.extend({
|
|
361
|
+
type: import_zod.z.literal("multiple_choice" /* MULTIPLE_CHOICE */),
|
|
362
|
+
question: import_zod.z.string().min(1).max(500),
|
|
363
|
+
options: import_zod.z.array(import_zod.z.string().min(1).max(200)).min(2).max(50),
|
|
364
|
+
defaultValues: import_zod.z.array(import_zod.z.string()).optional()
|
|
365
|
+
});
|
|
366
|
+
var singleChoiceElementSchema = baseElementSchema.extend({
|
|
367
|
+
type: import_zod.z.literal("single_choice" /* SINGLE_CHOICE */),
|
|
368
|
+
question: import_zod.z.string().min(1).max(500),
|
|
369
|
+
options: import_zod.z.array(import_zod.z.string().min(1).max(200)).min(2).max(50),
|
|
370
|
+
defaultValue: import_zod.z.string().optional()
|
|
371
|
+
});
|
|
372
|
+
var ratingScaleElementSchema = baseElementSchema.extend({
|
|
373
|
+
type: import_zod.z.literal("rating_scale" /* RATING_SCALE */),
|
|
374
|
+
question: import_zod.z.string().min(1).max(500),
|
|
375
|
+
min: import_zod.z.number().int().min(0).max(10),
|
|
376
|
+
max: import_zod.z.number().int().min(1).max(10),
|
|
377
|
+
labels: import_zod.z.record(import_zod.z.string()).optional(),
|
|
378
|
+
defaultValue: import_zod.z.number().int().optional()
|
|
379
|
+
});
|
|
380
|
+
var textInputElementSchema = baseElementSchema.extend({
|
|
381
|
+
type: import_zod.z.literal("text_input" /* TEXT_INPUT */),
|
|
382
|
+
label: import_zod.z.string().min(1).max(200),
|
|
383
|
+
placeholder: import_zod.z.string().max(200).optional(),
|
|
384
|
+
multiline: import_zod.z.boolean().optional(),
|
|
385
|
+
defaultValue: import_zod.z.string().optional()
|
|
386
|
+
});
|
|
387
|
+
var datePickerElementSchema = baseElementSchema.extend({
|
|
388
|
+
type: import_zod.z.literal("date_picker" /* DATE_PICKER */),
|
|
389
|
+
label: import_zod.z.string().min(1).max(200),
|
|
390
|
+
defaultValue: import_zod.z.string().optional()
|
|
391
|
+
// ISO date string
|
|
392
|
+
});
|
|
393
|
+
var signatureElementSchema = baseElementSchema.extend({
|
|
394
|
+
type: import_zod.z.literal("signature" /* SIGNATURE */),
|
|
395
|
+
label: import_zod.z.string().min(1).max(200)
|
|
396
|
+
});
|
|
397
|
+
var digitalSignatureElementSchema = baseElementSchema.extend({
|
|
398
|
+
type: import_zod.z.literal("digital_signature" /* DITIGAL_SIGNATURE */),
|
|
399
|
+
// Matching your type enum
|
|
400
|
+
label: import_zod.z.string().min(1).max(200)
|
|
401
|
+
});
|
|
402
|
+
var fileUploadElementSchema = baseElementSchema.extend({
|
|
403
|
+
type: import_zod.z.literal("file_upload" /* FILE_UPLOAD */),
|
|
404
|
+
label: import_zod.z.string().min(1).max(200),
|
|
405
|
+
allowedFileTypes: import_zod.z.array(import_zod.z.string()).optional(),
|
|
406
|
+
maxFileSizeMB: import_zod.z.number().positive().optional()
|
|
407
|
+
});
|
|
408
|
+
var documentElementSchema = import_zod.z.discriminatedUnion("type", [
|
|
409
|
+
headingElementSchema,
|
|
410
|
+
paragraphElementSchema,
|
|
411
|
+
listElementSchema,
|
|
412
|
+
dynamicTextElementSchema,
|
|
413
|
+
binaryChoiceElementSchema,
|
|
414
|
+
multipleChoiceElementSchema,
|
|
415
|
+
singleChoiceElementSchema,
|
|
416
|
+
ratingScaleElementSchema,
|
|
417
|
+
textInputElementSchema,
|
|
418
|
+
datePickerElementSchema,
|
|
419
|
+
signatureElementSchema,
|
|
420
|
+
digitalSignatureElementSchema,
|
|
421
|
+
fileUploadElementSchema
|
|
422
|
+
]);
|
|
423
|
+
var documentElementWithoutIdSchema = import_zod.z.discriminatedUnion("type", [
|
|
424
|
+
headingElementSchema.omit({ id: true }),
|
|
425
|
+
paragraphElementSchema.omit({ id: true }),
|
|
426
|
+
listElementSchema.omit({ id: true }),
|
|
427
|
+
dynamicTextElementSchema.omit({ id: true }),
|
|
428
|
+
binaryChoiceElementSchema.omit({ id: true }),
|
|
429
|
+
multipleChoiceElementSchema.omit({ id: true }),
|
|
430
|
+
singleChoiceElementSchema.omit({ id: true }),
|
|
431
|
+
ratingScaleElementSchema.omit({ id: true }),
|
|
432
|
+
textInputElementSchema.omit({ id: true }),
|
|
433
|
+
datePickerElementSchema.omit({ id: true }),
|
|
434
|
+
signatureElementSchema.omit({ id: true }),
|
|
435
|
+
digitalSignatureElementSchema.omit({ id: true }),
|
|
436
|
+
fileUploadElementSchema.omit({ id: true })
|
|
437
|
+
]);
|
|
438
|
+
var createDocumentTemplateSchema = import_zod.z.object({
|
|
439
|
+
title: import_zod.z.string().min(1).max(200),
|
|
440
|
+
description: import_zod.z.string().max(1e3).optional(),
|
|
441
|
+
elements: import_zod.z.array(documentElementWithoutIdSchema).min(1).max(100),
|
|
442
|
+
tags: import_zod.z.array(import_zod.z.string().min(1).max(50)).max(20).optional(),
|
|
443
|
+
isUserForm: import_zod.z.boolean().optional().default(false),
|
|
444
|
+
isRequired: import_zod.z.boolean().optional().default(false),
|
|
445
|
+
sortingOrder: import_zod.z.number().int().optional().default(0)
|
|
446
|
+
});
|
|
447
|
+
var updateDocumentTemplateSchema = import_zod.z.object({
|
|
448
|
+
title: import_zod.z.string().min(1).max(200).optional(),
|
|
449
|
+
description: import_zod.z.string().max(1e3).optional(),
|
|
450
|
+
elements: import_zod.z.array(documentElementWithoutIdSchema).min(1).max(100).optional(),
|
|
451
|
+
tags: import_zod.z.array(import_zod.z.string().min(1).max(50)).max(20).optional(),
|
|
452
|
+
isActive: import_zod.z.boolean().optional(),
|
|
453
|
+
isUserForm: import_zod.z.boolean().optional(),
|
|
454
|
+
isRequired: import_zod.z.boolean().optional(),
|
|
455
|
+
sortingOrder: import_zod.z.number().int().optional()
|
|
456
|
+
});
|
|
457
|
+
var documentTemplateSchema = import_zod.z.object({
|
|
458
|
+
id: import_zod.z.string(),
|
|
459
|
+
title: import_zod.z.string().min(1).max(200),
|
|
460
|
+
description: import_zod.z.string().max(1e3).optional(),
|
|
461
|
+
createdAt: import_zod.z.number(),
|
|
462
|
+
updatedAt: import_zod.z.number(),
|
|
463
|
+
createdBy: import_zod.z.string(),
|
|
464
|
+
elements: import_zod.z.array(documentElementSchema),
|
|
465
|
+
tags: import_zod.z.array(import_zod.z.string().min(1).max(50)).max(20).optional(),
|
|
466
|
+
version: import_zod.z.number().int().positive(),
|
|
467
|
+
isActive: import_zod.z.boolean(),
|
|
468
|
+
isUserForm: import_zod.z.boolean().optional().default(false),
|
|
469
|
+
isRequired: import_zod.z.boolean().optional().default(false),
|
|
470
|
+
sortingOrder: import_zod.z.number().int().optional().default(0)
|
|
471
|
+
});
|
|
472
|
+
var filledDocumentStatusSchema = import_zod.z.nativeEnum(FilledDocumentStatus);
|
|
473
|
+
var filledDocumentSchema = import_zod.z.object({
|
|
474
|
+
id: import_zod.z.string(),
|
|
475
|
+
templateId: import_zod.z.string(),
|
|
476
|
+
templateVersion: import_zod.z.number(),
|
|
477
|
+
isUserForm: import_zod.z.boolean(),
|
|
478
|
+
procedureId: import_zod.z.string(),
|
|
479
|
+
appointmentId: import_zod.z.string(),
|
|
480
|
+
patientId: import_zod.z.string(),
|
|
481
|
+
practitionerId: import_zod.z.string(),
|
|
482
|
+
clinicId: import_zod.z.string(),
|
|
483
|
+
createdAt: import_zod.z.number(),
|
|
484
|
+
updatedAt: import_zod.z.number(),
|
|
485
|
+
values: import_zod.z.record(import_zod.z.string(), import_zod.z.any()),
|
|
486
|
+
status: filledDocumentStatusSchema
|
|
487
|
+
});
|
|
488
|
+
var createFilledDocumentDataSchema = import_zod.z.object({
|
|
489
|
+
templateId: import_zod.z.string(),
|
|
490
|
+
procedureId: import_zod.z.string(),
|
|
491
|
+
appointmentId: import_zod.z.string(),
|
|
492
|
+
patientId: import_zod.z.string(),
|
|
493
|
+
practitionerId: import_zod.z.string(),
|
|
494
|
+
clinicId: import_zod.z.string(),
|
|
495
|
+
values: import_zod.z.record(import_zod.z.string(), import_zod.z.any()).optional().default({}),
|
|
496
|
+
status: filledDocumentStatusSchema.optional().default("draft" /* DRAFT */)
|
|
497
|
+
});
|
|
498
|
+
var updateFilledDocumentDataSchema = import_zod.z.object({
|
|
499
|
+
values: import_zod.z.record(import_zod.z.string(), import_zod.z.any()).optional(),
|
|
500
|
+
status: filledDocumentStatusSchema.optional()
|
|
501
|
+
});
|
|
502
|
+
|
|
252
503
|
// src/validations/appointment.schema.ts
|
|
253
|
-
var
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
504
|
+
var MIN_STRING_LENGTH = 1;
|
|
505
|
+
var MAX_STRING_LENGTH = 1024;
|
|
506
|
+
var MAX_STRING_LENGTH_LONG = 4096;
|
|
507
|
+
var MAX_ARRAY_LENGTH = 100;
|
|
508
|
+
var appointmentStatusSchema = import_zod2.z.nativeEnum(AppointmentStatus);
|
|
509
|
+
var paymentStatusSchema = import_zod2.z.nativeEnum(PaymentStatus);
|
|
510
|
+
var mediaTypeSchema = import_zod2.z.nativeEnum(MediaType);
|
|
511
|
+
var appointmentMediaItemSchema = import_zod2.z.object({
|
|
512
|
+
id: import_zod2.z.string().min(MIN_STRING_LENGTH, "Media item ID is required"),
|
|
513
|
+
type: mediaTypeSchema,
|
|
514
|
+
url: import_zod2.z.string().url("Media URL must be a valid URL"),
|
|
515
|
+
fileName: import_zod2.z.string().optional(),
|
|
516
|
+
uploadedAt: import_zod2.z.any().refine(
|
|
517
|
+
(val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
|
|
518
|
+
"uploadedAt must be a valid timestamp or Date object"
|
|
519
|
+
),
|
|
520
|
+
uploadedBy: import_zod2.z.string().min(MIN_STRING_LENGTH, "Uploaded by user ID is required"),
|
|
521
|
+
description: import_zod2.z.string().max(MAX_STRING_LENGTH, "Description too long").optional()
|
|
522
|
+
});
|
|
523
|
+
var procedureExtendedInfoSchema = import_zod2.z.object({
|
|
524
|
+
id: import_zod2.z.string().min(MIN_STRING_LENGTH),
|
|
525
|
+
name: import_zod2.z.string().min(MIN_STRING_LENGTH),
|
|
526
|
+
description: import_zod2.z.string(),
|
|
527
|
+
cost: import_zod2.z.number().min(0),
|
|
528
|
+
duration: import_zod2.z.number().min(0),
|
|
529
|
+
procedureFamily: import_zod2.z.any(),
|
|
530
|
+
procedureCategoryId: import_zod2.z.string(),
|
|
531
|
+
procedureCategoryName: import_zod2.z.string(),
|
|
532
|
+
procedureSubCategoryId: import_zod2.z.string(),
|
|
533
|
+
procedureSubCategoryName: import_zod2.z.string(),
|
|
534
|
+
procedureTechnologyId: import_zod2.z.string(),
|
|
535
|
+
procedureTechnologyName: import_zod2.z.string(),
|
|
536
|
+
procedureProductBrandId: import_zod2.z.string(),
|
|
537
|
+
procedureProductBrandName: import_zod2.z.string(),
|
|
538
|
+
procedureProductId: import_zod2.z.string(),
|
|
539
|
+
procedureProductName: import_zod2.z.string()
|
|
540
|
+
});
|
|
541
|
+
var linkedFormInfoSchema = import_zod2.z.object({
|
|
542
|
+
formId: import_zod2.z.string().min(MIN_STRING_LENGTH, "Form ID is required"),
|
|
543
|
+
templateId: import_zod2.z.string().min(MIN_STRING_LENGTH, "Template ID is required"),
|
|
544
|
+
templateVersion: import_zod2.z.number().int().positive("Template version must be a positive integer"),
|
|
545
|
+
title: import_zod2.z.string().min(MIN_STRING_LENGTH, "Form title is required"),
|
|
546
|
+
isUserForm: import_zod2.z.boolean(),
|
|
547
|
+
status: filledDocumentStatusSchema,
|
|
548
|
+
path: import_zod2.z.string().min(MIN_STRING_LENGTH, "Form path is required"),
|
|
549
|
+
submittedAt: import_zod2.z.any().refine(
|
|
550
|
+
(val) => val === void 0 || val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
|
|
551
|
+
"submittedAt must be a valid timestamp or Date object"
|
|
552
|
+
).optional(),
|
|
553
|
+
completedAt: import_zod2.z.any().refine(
|
|
554
|
+
(val) => val === void 0 || val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
|
|
555
|
+
"completedAt must be a valid timestamp or Date object"
|
|
556
|
+
).optional()
|
|
557
|
+
});
|
|
558
|
+
var patientReviewInfoSchema = import_zod2.z.object({
|
|
559
|
+
reviewId: import_zod2.z.string().min(MIN_STRING_LENGTH, "Review ID is required"),
|
|
560
|
+
rating: import_zod2.z.number().min(1).max(5, "Rating must be between 1 and 5"),
|
|
561
|
+
comment: import_zod2.z.string().max(MAX_STRING_LENGTH_LONG, "Comment too long").optional(),
|
|
562
|
+
reviewedAt: import_zod2.z.any().refine(
|
|
563
|
+
(val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
|
|
564
|
+
"reviewedAt must be a valid timestamp or Date object"
|
|
565
|
+
)
|
|
566
|
+
});
|
|
567
|
+
var finalizedDetailsSchema = import_zod2.z.object({
|
|
568
|
+
by: import_zod2.z.string().min(MIN_STRING_LENGTH, "Finalized by user ID is required"),
|
|
569
|
+
at: import_zod2.z.any().refine(
|
|
570
|
+
(val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
|
|
571
|
+
"Finalized at must be a valid timestamp or Date object"
|
|
572
|
+
),
|
|
573
|
+
notes: import_zod2.z.string().max(MAX_STRING_LENGTH_LONG, "Finalization notes too long").optional()
|
|
574
|
+
});
|
|
575
|
+
var createAppointmentSchema = import_zod2.z.object({
|
|
576
|
+
clinicBranchId: import_zod2.z.string().min(MIN_STRING_LENGTH, "Clinic branch ID is required"),
|
|
577
|
+
practitionerId: import_zod2.z.string().min(MIN_STRING_LENGTH, "Practitioner ID is required"),
|
|
578
|
+
patientId: import_zod2.z.string().min(MIN_STRING_LENGTH, "Patient ID is required"),
|
|
579
|
+
procedureId: import_zod2.z.string().min(MIN_STRING_LENGTH, "Procedure ID is required"),
|
|
580
|
+
appointmentStartTime: import_zod2.z.any().refine(
|
|
581
|
+
(val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
|
|
582
|
+
"Appointment start time must be a valid timestamp or Date object"
|
|
262
583
|
),
|
|
263
|
-
appointmentEndTime:
|
|
264
|
-
(val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0,
|
|
265
|
-
"Appointment end time must be a valid timestamp"
|
|
584
|
+
appointmentEndTime: import_zod2.z.any().refine(
|
|
585
|
+
(val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
|
|
586
|
+
"Appointment end time must be a valid timestamp or Date object"
|
|
266
587
|
),
|
|
267
|
-
cost:
|
|
268
|
-
currency:
|
|
269
|
-
patientNotes:
|
|
270
|
-
initialStatus:
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
}).optional().default("unpaid" /* UNPAID */)
|
|
588
|
+
cost: import_zod2.z.number().min(0, "Cost must be a non-negative number"),
|
|
589
|
+
currency: import_zod2.z.string().min(1, "Currency is required"),
|
|
590
|
+
patientNotes: import_zod2.z.string().max(MAX_STRING_LENGTH, "Patient notes too long").nullable().optional(),
|
|
591
|
+
initialStatus: appointmentStatusSchema,
|
|
592
|
+
initialPaymentStatus: paymentStatusSchema.optional().default("unpaid" /* UNPAID */)
|
|
593
|
+
}).refine((data) => data.appointmentEndTime > data.appointmentStartTime, {
|
|
594
|
+
message: "Appointment end time must be after start time",
|
|
595
|
+
path: ["appointmentEndTime"]
|
|
276
596
|
});
|
|
277
|
-
var updateAppointmentSchema =
|
|
278
|
-
status:
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
597
|
+
var updateAppointmentSchema = import_zod2.z.object({
|
|
598
|
+
status: appointmentStatusSchema.optional(),
|
|
599
|
+
confirmationTime: import_zod2.z.any().optional().nullable(),
|
|
600
|
+
cancellationTime: import_zod2.z.any().optional().nullable(),
|
|
601
|
+
rescheduleTime: import_zod2.z.any().optional().nullable(),
|
|
602
|
+
procedureActualStartTime: import_zod2.z.any().optional().nullable(),
|
|
603
|
+
actualDurationMinutes: import_zod2.z.number().int().positive("Duration must be a positive integer").optional(),
|
|
604
|
+
cancellationReason: import_zod2.z.string().max(MAX_STRING_LENGTH, "Cancellation reason too long").nullable().optional(),
|
|
605
|
+
canceledBy: import_zod2.z.enum(["patient", "clinic", "practitioner", "system"]).optional(),
|
|
606
|
+
internalNotes: import_zod2.z.string().max(MAX_STRING_LENGTH_LONG, "Internal notes too long").nullable().optional(),
|
|
607
|
+
patientNotes: import_zod2.z.any().optional().nullable(),
|
|
608
|
+
paymentStatus: paymentStatusSchema.optional(),
|
|
609
|
+
paymentTransactionId: import_zod2.z.any().optional().nullable(),
|
|
610
|
+
completedPreRequirements: import_zod2.z.union([import_zod2.z.array(import_zod2.z.string()), import_zod2.z.any()]).optional(),
|
|
611
|
+
completedPostRequirements: import_zod2.z.union([import_zod2.z.array(import_zod2.z.string()), import_zod2.z.any()]).optional(),
|
|
612
|
+
linkedFormIds: import_zod2.z.union([import_zod2.z.array(import_zod2.z.string()), import_zod2.z.any()]).optional(),
|
|
613
|
+
pendingUserFormsIds: import_zod2.z.union([import_zod2.z.array(import_zod2.z.string()), import_zod2.z.any()]).optional(),
|
|
614
|
+
appointmentStartTime: import_zod2.z.any().refine(
|
|
615
|
+
(val) => val === void 0 || val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
|
|
616
|
+
"Appointment start time must be a valid timestamp or Date object"
|
|
284
617
|
).optional(),
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
618
|
+
appointmentEndTime: import_zod2.z.any().refine(
|
|
619
|
+
(val) => val === void 0 || val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
|
|
620
|
+
"Appointment end time must be a valid timestamp or Date object"
|
|
621
|
+
).optional(),
|
|
622
|
+
calendarEventId: import_zod2.z.string().min(MIN_STRING_LENGTH).optional(),
|
|
623
|
+
cost: import_zod2.z.number().min(0).optional(),
|
|
624
|
+
clinicBranchId: import_zod2.z.string().min(MIN_STRING_LENGTH).optional(),
|
|
625
|
+
practitionerId: import_zod2.z.string().min(MIN_STRING_LENGTH).optional(),
|
|
626
|
+
linkedForms: import_zod2.z.union([import_zod2.z.array(linkedFormInfoSchema).max(MAX_ARRAY_LENGTH), import_zod2.z.any()]).optional(),
|
|
627
|
+
media: import_zod2.z.union([
|
|
628
|
+
import_zod2.z.array(appointmentMediaItemSchema).max(MAX_ARRAY_LENGTH),
|
|
629
|
+
import_zod2.z.any()
|
|
630
|
+
]).optional(),
|
|
631
|
+
reviewInfo: import_zod2.z.union([patientReviewInfoSchema.nullable(), import_zod2.z.any()]).optional(),
|
|
632
|
+
finalizedDetails: import_zod2.z.union([finalizedDetailsSchema.nullable(), import_zod2.z.any()]).optional(),
|
|
633
|
+
isArchived: import_zod2.z.boolean().optional(),
|
|
634
|
+
updatedAt: import_zod2.z.any().optional()
|
|
295
635
|
}).refine(
|
|
296
636
|
(data) => {
|
|
297
|
-
if (data.status === "canceled_clinic" /* CANCELED_CLINIC */ || data.status === "canceled_patient" /* CANCELED_PATIENT */) {
|
|
637
|
+
if (data.status === "canceled_clinic" /* CANCELED_CLINIC */ || data.status === "canceled_patient" /* CANCELED_PATIENT */ || data.status === "canceled_patient_rescheduled" /* CANCELED_PATIENT_RESCHEDULED */) {
|
|
298
638
|
return !!data.cancellationReason && !!data.canceledBy;
|
|
299
639
|
}
|
|
300
640
|
return true;
|
|
301
641
|
},
|
|
302
642
|
{
|
|
303
|
-
message: "Cancellation reason and canceled by must be provided when canceling an appointment",
|
|
643
|
+
message: "Cancellation reason and canceled by must be provided when canceling an appointment with patient or clinic origin.",
|
|
304
644
|
path: ["status"]
|
|
305
645
|
}
|
|
646
|
+
).refine(
|
|
647
|
+
(data) => {
|
|
648
|
+
if (data.appointmentStartTime && data.appointmentEndTime) {
|
|
649
|
+
return data.appointmentEndTime > data.appointmentStartTime;
|
|
650
|
+
}
|
|
651
|
+
return true;
|
|
652
|
+
},
|
|
653
|
+
{
|
|
654
|
+
message: "Appointment end time must be after start time if both are provided",
|
|
655
|
+
path: ["appointmentEndTime"]
|
|
656
|
+
}
|
|
306
657
|
);
|
|
307
|
-
var searchAppointmentsSchema =
|
|
308
|
-
patientId:
|
|
309
|
-
practitionerId:
|
|
310
|
-
clinicBranchId:
|
|
311
|
-
startDate:
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
658
|
+
var searchAppointmentsSchema = import_zod2.z.object({
|
|
659
|
+
patientId: import_zod2.z.string().optional(),
|
|
660
|
+
practitionerId: import_zod2.z.string().optional(),
|
|
661
|
+
clinicBranchId: import_zod2.z.string().optional(),
|
|
662
|
+
startDate: import_zod2.z.any().refine(
|
|
663
|
+
(val) => val === void 0 || val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
|
|
664
|
+
"Start date must be a valid timestamp or Date object"
|
|
665
|
+
).optional(),
|
|
666
|
+
endDate: import_zod2.z.any().refine(
|
|
667
|
+
(val) => val === void 0 || val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
|
|
668
|
+
"End date must be a valid timestamp or Date object"
|
|
669
|
+
).optional(),
|
|
670
|
+
status: import_zod2.z.union([
|
|
671
|
+
appointmentStatusSchema,
|
|
672
|
+
import_zod2.z.array(appointmentStatusSchema).nonempty()
|
|
316
673
|
]).optional(),
|
|
317
|
-
limit:
|
|
318
|
-
startAfter:
|
|
674
|
+
limit: import_zod2.z.number().positive().int().optional().default(20),
|
|
675
|
+
startAfter: import_zod2.z.any().optional()
|
|
319
676
|
}).refine(
|
|
320
677
|
(data) => {
|
|
321
|
-
|
|
678
|
+
if (!data.startDate && !data.endDate && !data.status) {
|
|
679
|
+
return !!(data.patientId || data.practitionerId || data.clinicBranchId);
|
|
680
|
+
}
|
|
681
|
+
return true;
|
|
682
|
+
},
|
|
683
|
+
{
|
|
684
|
+
message: "At least one of patientId, practitionerId, or clinicBranchId must be provided if no date or status filters are set.",
|
|
685
|
+
path: ["patientId"]
|
|
686
|
+
}
|
|
687
|
+
).refine(
|
|
688
|
+
(data) => {
|
|
689
|
+
if (data.startDate && data.endDate) {
|
|
690
|
+
return data.endDate >= data.startDate;
|
|
691
|
+
}
|
|
692
|
+
return true;
|
|
322
693
|
},
|
|
323
694
|
{
|
|
324
|
-
message: "
|
|
325
|
-
path: ["
|
|
695
|
+
message: "End date must be after or the same as start date",
|
|
696
|
+
path: ["endDate"]
|
|
326
697
|
}
|
|
327
698
|
);
|
|
328
699
|
|
|
@@ -371,54 +742,6 @@ var getFirebaseApp = async () => {
|
|
|
371
742
|
var import_auth5 = require("firebase/auth");
|
|
372
743
|
var import_firestore22 = require("firebase/firestore");
|
|
373
744
|
|
|
374
|
-
// src/types/documentation-templates/index.ts
|
|
375
|
-
var DOCUMENTATION_TEMPLATES_COLLECTION = "documentation-templates";
|
|
376
|
-
var FILLED_DOCUMENTS_COLLECTION = "filled-documents";
|
|
377
|
-
var DocumentElementType = /* @__PURE__ */ ((DocumentElementType2) => {
|
|
378
|
-
DocumentElementType2["HEADING"] = "heading";
|
|
379
|
-
DocumentElementType2["PARAGRAPH"] = "paragraph";
|
|
380
|
-
DocumentElementType2["LIST"] = "list";
|
|
381
|
-
DocumentElementType2["DYNAMIC_TEXT"] = "dynamic_text";
|
|
382
|
-
DocumentElementType2["BINARY_CHOICE"] = "binary_choice";
|
|
383
|
-
DocumentElementType2["MULTIPLE_CHOICE"] = "multiple_choice";
|
|
384
|
-
DocumentElementType2["SINGLE_CHOICE"] = "single_choice";
|
|
385
|
-
DocumentElementType2["RATING_SCALE"] = "rating_scale";
|
|
386
|
-
DocumentElementType2["TEXT_INPUT"] = "text_input";
|
|
387
|
-
DocumentElementType2["DATE_PICKER"] = "date_picker";
|
|
388
|
-
DocumentElementType2["SIGNATURE"] = "signature";
|
|
389
|
-
DocumentElementType2["FILE_UPLOAD"] = "file_upload";
|
|
390
|
-
return DocumentElementType2;
|
|
391
|
-
})(DocumentElementType || {});
|
|
392
|
-
var ListType = /* @__PURE__ */ ((ListType2) => {
|
|
393
|
-
ListType2["ORDERED"] = "ordered";
|
|
394
|
-
ListType2["UNORDERED"] = "unordered";
|
|
395
|
-
return ListType2;
|
|
396
|
-
})(ListType || {});
|
|
397
|
-
var HeadingLevel = /* @__PURE__ */ ((HeadingLevel2) => {
|
|
398
|
-
HeadingLevel2["H1"] = "h1";
|
|
399
|
-
HeadingLevel2["H2"] = "h2";
|
|
400
|
-
HeadingLevel2["H3"] = "h3";
|
|
401
|
-
HeadingLevel2["H4"] = "h4";
|
|
402
|
-
HeadingLevel2["H5"] = "h5";
|
|
403
|
-
HeadingLevel2["H6"] = "h6";
|
|
404
|
-
return HeadingLevel2;
|
|
405
|
-
})(HeadingLevel || {});
|
|
406
|
-
var DynamicVariable = /* @__PURE__ */ ((DynamicVariable2) => {
|
|
407
|
-
DynamicVariable2["PATIENT_NAME"] = "[PATIENT_NAME]";
|
|
408
|
-
DynamicVariable2["DOCTOR_NAME"] = "[DOCTOR_NAME]";
|
|
409
|
-
DynamicVariable2["CLINIC_NAME"] = "[CLINIC_NAME]";
|
|
410
|
-
DynamicVariable2["PATIENT_BIRTHDAY"] = "[PATIENT_BIRTHDAY]";
|
|
411
|
-
DynamicVariable2["APPOINTMENT_DATE"] = "[APPOINTMENT_DATE]";
|
|
412
|
-
DynamicVariable2["CURRENT_DATE"] = "[CURRENT_DATE]";
|
|
413
|
-
return DynamicVariable2;
|
|
414
|
-
})(DynamicVariable || {});
|
|
415
|
-
var FilledDocumentStatus = /* @__PURE__ */ ((FilledDocumentStatus2) => {
|
|
416
|
-
FilledDocumentStatus2["DRAFT"] = "draft";
|
|
417
|
-
FilledDocumentStatus2["COMPLETED"] = "completed";
|
|
418
|
-
FilledDocumentStatus2["SIGNED"] = "signed";
|
|
419
|
-
return FilledDocumentStatus2;
|
|
420
|
-
})(FilledDocumentStatus || {});
|
|
421
|
-
|
|
422
745
|
// src/types/calendar/index.ts
|
|
423
746
|
var CalendarEventStatus = /* @__PURE__ */ ((CalendarEventStatus4) => {
|
|
424
747
|
CalendarEventStatus4["PENDING"] = "pending";
|
|
@@ -465,136 +788,6 @@ var import_zod19 = require("zod");
|
|
|
465
788
|
|
|
466
789
|
// src/validations/schemas.ts
|
|
467
790
|
var import_zod3 = require("zod");
|
|
468
|
-
|
|
469
|
-
// src/validations/documentation-templates/template.schema.ts
|
|
470
|
-
var import_zod2 = require("zod");
|
|
471
|
-
var baseElementSchema = import_zod2.z.object({
|
|
472
|
-
id: import_zod2.z.string().optional(),
|
|
473
|
-
// Make id optional so we can omit it later
|
|
474
|
-
type: import_zod2.z.nativeEnum(DocumentElementType),
|
|
475
|
-
required: import_zod2.z.boolean().optional()
|
|
476
|
-
});
|
|
477
|
-
var headingElementSchema = baseElementSchema.extend({
|
|
478
|
-
type: import_zod2.z.literal("heading" /* HEADING */),
|
|
479
|
-
text: import_zod2.z.string().min(1).max(200),
|
|
480
|
-
level: import_zod2.z.nativeEnum(HeadingLevel)
|
|
481
|
-
});
|
|
482
|
-
var paragraphElementSchema = baseElementSchema.extend({
|
|
483
|
-
type: import_zod2.z.literal("paragraph" /* PARAGRAPH */),
|
|
484
|
-
text: import_zod2.z.string().min(1).max(5e3)
|
|
485
|
-
});
|
|
486
|
-
var listElementSchema = baseElementSchema.extend({
|
|
487
|
-
type: import_zod2.z.literal("list" /* LIST */),
|
|
488
|
-
items: import_zod2.z.array(import_zod2.z.string().min(1).max(500)).min(1).max(100),
|
|
489
|
-
listType: import_zod2.z.nativeEnum(ListType)
|
|
490
|
-
});
|
|
491
|
-
var dynamicTextElementSchema = baseElementSchema.extend({
|
|
492
|
-
type: import_zod2.z.literal("dynamic_text" /* DYNAMIC_TEXT */),
|
|
493
|
-
text: import_zod2.z.string().min(1).max(5e3)
|
|
494
|
-
});
|
|
495
|
-
var binaryChoiceElementSchema = baseElementSchema.extend({
|
|
496
|
-
type: import_zod2.z.literal("binary_choice" /* BINARY_CHOICE */),
|
|
497
|
-
question: import_zod2.z.string().min(1).max(500),
|
|
498
|
-
defaultValue: import_zod2.z.boolean().optional()
|
|
499
|
-
});
|
|
500
|
-
var multipleChoiceElementSchema = baseElementSchema.extend({
|
|
501
|
-
type: import_zod2.z.literal("multiple_choice" /* MULTIPLE_CHOICE */),
|
|
502
|
-
question: import_zod2.z.string().min(1).max(500),
|
|
503
|
-
options: import_zod2.z.array(import_zod2.z.string().min(1).max(200)).min(2).max(50),
|
|
504
|
-
defaultValues: import_zod2.z.array(import_zod2.z.string()).optional()
|
|
505
|
-
});
|
|
506
|
-
var singleChoiceElementSchema = baseElementSchema.extend({
|
|
507
|
-
type: import_zod2.z.literal("single_choice" /* SINGLE_CHOICE */),
|
|
508
|
-
question: import_zod2.z.string().min(1).max(500),
|
|
509
|
-
options: import_zod2.z.array(import_zod2.z.string().min(1).max(200)).min(2).max(50),
|
|
510
|
-
defaultValue: import_zod2.z.string().optional()
|
|
511
|
-
});
|
|
512
|
-
var ratingScaleElementSchema = baseElementSchema.extend({
|
|
513
|
-
type: import_zod2.z.literal("rating_scale" /* RATING_SCALE */),
|
|
514
|
-
question: import_zod2.z.string().min(1).max(500),
|
|
515
|
-
min: import_zod2.z.number().int().min(0).max(10),
|
|
516
|
-
max: import_zod2.z.number().int().min(1).max(10),
|
|
517
|
-
labels: import_zod2.z.record(import_zod2.z.string()).optional(),
|
|
518
|
-
defaultValue: import_zod2.z.number().int().optional()
|
|
519
|
-
});
|
|
520
|
-
var textInputElementSchema = baseElementSchema.extend({
|
|
521
|
-
type: import_zod2.z.literal("text_input" /* TEXT_INPUT */),
|
|
522
|
-
label: import_zod2.z.string().min(1).max(200),
|
|
523
|
-
placeholder: import_zod2.z.string().max(200).optional(),
|
|
524
|
-
multiline: import_zod2.z.boolean().optional(),
|
|
525
|
-
defaultValue: import_zod2.z.string().optional()
|
|
526
|
-
});
|
|
527
|
-
var datePickerElementSchema = baseElementSchema.extend({
|
|
528
|
-
type: import_zod2.z.literal("date_picker" /* DATE_PICKER */),
|
|
529
|
-
label: import_zod2.z.string().min(1).max(200),
|
|
530
|
-
defaultValue: import_zod2.z.string().optional()
|
|
531
|
-
// ISO date string
|
|
532
|
-
});
|
|
533
|
-
var signatureElementSchema = baseElementSchema.extend({
|
|
534
|
-
type: import_zod2.z.literal("signature" /* SIGNATURE */),
|
|
535
|
-
label: import_zod2.z.string().min(1).max(200)
|
|
536
|
-
});
|
|
537
|
-
var fileUploadElementSchema = baseElementSchema.extend({
|
|
538
|
-
type: import_zod2.z.literal("file_upload" /* FILE_UPLOAD */),
|
|
539
|
-
label: import_zod2.z.string().min(1).max(200),
|
|
540
|
-
allowedFileTypes: import_zod2.z.array(import_zod2.z.string()).optional(),
|
|
541
|
-
maxFileSizeMB: import_zod2.z.number().positive().optional()
|
|
542
|
-
});
|
|
543
|
-
var documentElementSchema = import_zod2.z.discriminatedUnion("type", [
|
|
544
|
-
headingElementSchema,
|
|
545
|
-
paragraphElementSchema,
|
|
546
|
-
listElementSchema,
|
|
547
|
-
dynamicTextElementSchema,
|
|
548
|
-
binaryChoiceElementSchema,
|
|
549
|
-
multipleChoiceElementSchema,
|
|
550
|
-
singleChoiceElementSchema,
|
|
551
|
-
ratingScaleElementSchema,
|
|
552
|
-
textInputElementSchema,
|
|
553
|
-
datePickerElementSchema,
|
|
554
|
-
signatureElementSchema,
|
|
555
|
-
fileUploadElementSchema
|
|
556
|
-
]);
|
|
557
|
-
var documentElementWithoutIdSchema = import_zod2.z.discriminatedUnion("type", [
|
|
558
|
-
headingElementSchema.omit({ id: true }),
|
|
559
|
-
paragraphElementSchema.omit({ id: true }),
|
|
560
|
-
listElementSchema.omit({ id: true }),
|
|
561
|
-
dynamicTextElementSchema.omit({ id: true }),
|
|
562
|
-
binaryChoiceElementSchema.omit({ id: true }),
|
|
563
|
-
multipleChoiceElementSchema.omit({ id: true }),
|
|
564
|
-
singleChoiceElementSchema.omit({ id: true }),
|
|
565
|
-
ratingScaleElementSchema.omit({ id: true }),
|
|
566
|
-
textInputElementSchema.omit({ id: true }),
|
|
567
|
-
datePickerElementSchema.omit({ id: true }),
|
|
568
|
-
signatureElementSchema.omit({ id: true }),
|
|
569
|
-
fileUploadElementSchema.omit({ id: true })
|
|
570
|
-
]);
|
|
571
|
-
var createDocumentTemplateSchema = import_zod2.z.object({
|
|
572
|
-
title: import_zod2.z.string().min(1).max(200),
|
|
573
|
-
description: import_zod2.z.string().max(1e3).optional(),
|
|
574
|
-
elements: import_zod2.z.array(documentElementWithoutIdSchema).min(1).max(100),
|
|
575
|
-
tags: import_zod2.z.array(import_zod2.z.string().min(1).max(50)).max(20).optional()
|
|
576
|
-
});
|
|
577
|
-
var updateDocumentTemplateSchema = import_zod2.z.object({
|
|
578
|
-
title: import_zod2.z.string().min(1).max(200).optional(),
|
|
579
|
-
description: import_zod2.z.string().max(1e3).optional(),
|
|
580
|
-
elements: import_zod2.z.array(documentElementWithoutIdSchema).min(1).max(100).optional(),
|
|
581
|
-
tags: import_zod2.z.array(import_zod2.z.string().min(1).max(50)).max(20).optional(),
|
|
582
|
-
isActive: import_zod2.z.boolean().optional()
|
|
583
|
-
});
|
|
584
|
-
var documentTemplateSchema = import_zod2.z.object({
|
|
585
|
-
id: import_zod2.z.string(),
|
|
586
|
-
title: import_zod2.z.string().min(1).max(200),
|
|
587
|
-
description: import_zod2.z.string().max(1e3).optional(),
|
|
588
|
-
createdAt: import_zod2.z.number(),
|
|
589
|
-
updatedAt: import_zod2.z.number(),
|
|
590
|
-
createdBy: import_zod2.z.string(),
|
|
591
|
-
elements: import_zod2.z.array(documentElementSchema),
|
|
592
|
-
tags: import_zod2.z.array(import_zod2.z.string().min(1).max(50)).max(20).optional(),
|
|
593
|
-
version: import_zod2.z.number().int().positive(),
|
|
594
|
-
isActive: import_zod2.z.boolean()
|
|
595
|
-
});
|
|
596
|
-
|
|
597
|
-
// src/validations/schemas.ts
|
|
598
791
|
var emailSchema = import_zod3.z.string().email("Invalid email format").min(5, "Email must be at least 5 characters").max(255, "Email must be less than 255 characters");
|
|
599
792
|
var passwordSchema = import_zod3.z.string().min(8, "Password must be at least 8 characters").max(100, "Password must be less than 100 characters").regex(
|
|
600
793
|
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d\w\W]{8,}$/,
|
|
@@ -1607,9 +1800,9 @@ var addAllergyUtil = async (db, patientId, data, userRef) => {
|
|
|
1607
1800
|
var updateAllergyUtil = async (db, patientId, data, userRef) => {
|
|
1608
1801
|
const validatedData = updateAllergySchema.parse(data);
|
|
1609
1802
|
const { allergyIndex, ...updateData } = validatedData;
|
|
1610
|
-
const
|
|
1611
|
-
if (!
|
|
1612
|
-
const medicalInfo =
|
|
1803
|
+
const doc33 = await (0, import_firestore5.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
1804
|
+
if (!doc33.exists()) throw new Error("Medical info not found");
|
|
1805
|
+
const medicalInfo = doc33.data();
|
|
1613
1806
|
if (allergyIndex >= medicalInfo.allergies.length) {
|
|
1614
1807
|
throw new Error("Invalid allergy index");
|
|
1615
1808
|
}
|
|
@@ -1625,9 +1818,9 @@ var updateAllergyUtil = async (db, patientId, data, userRef) => {
|
|
|
1625
1818
|
});
|
|
1626
1819
|
};
|
|
1627
1820
|
var removeAllergyUtil = async (db, patientId, allergyIndex, userRef) => {
|
|
1628
|
-
const
|
|
1629
|
-
if (!
|
|
1630
|
-
const medicalInfo =
|
|
1821
|
+
const doc33 = await (0, import_firestore5.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
1822
|
+
if (!doc33.exists()) throw new Error("Medical info not found");
|
|
1823
|
+
const medicalInfo = doc33.data();
|
|
1631
1824
|
if (allergyIndex >= medicalInfo.allergies.length) {
|
|
1632
1825
|
throw new Error("Invalid allergy index");
|
|
1633
1826
|
}
|
|
@@ -1652,9 +1845,9 @@ var addBlockingConditionUtil = async (db, patientId, data, userRef) => {
|
|
|
1652
1845
|
var updateBlockingConditionUtil = async (db, patientId, data, userRef) => {
|
|
1653
1846
|
const validatedData = updateBlockingConditionSchema.parse(data);
|
|
1654
1847
|
const { conditionIndex, ...updateData } = validatedData;
|
|
1655
|
-
const
|
|
1656
|
-
if (!
|
|
1657
|
-
const medicalInfo =
|
|
1848
|
+
const doc33 = await (0, import_firestore5.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
1849
|
+
if (!doc33.exists()) throw new Error("Medical info not found");
|
|
1850
|
+
const medicalInfo = doc33.data();
|
|
1658
1851
|
if (conditionIndex >= medicalInfo.blockingConditions.length) {
|
|
1659
1852
|
throw new Error("Invalid blocking condition index");
|
|
1660
1853
|
}
|
|
@@ -1670,9 +1863,9 @@ var updateBlockingConditionUtil = async (db, patientId, data, userRef) => {
|
|
|
1670
1863
|
});
|
|
1671
1864
|
};
|
|
1672
1865
|
var removeBlockingConditionUtil = async (db, patientId, conditionIndex, userRef) => {
|
|
1673
|
-
const
|
|
1674
|
-
if (!
|
|
1675
|
-
const medicalInfo =
|
|
1866
|
+
const doc33 = await (0, import_firestore5.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
1867
|
+
if (!doc33.exists()) throw new Error("Medical info not found");
|
|
1868
|
+
const medicalInfo = doc33.data();
|
|
1676
1869
|
if (conditionIndex >= medicalInfo.blockingConditions.length) {
|
|
1677
1870
|
throw new Error("Invalid blocking condition index");
|
|
1678
1871
|
}
|
|
@@ -1697,9 +1890,9 @@ var addContraindicationUtil = async (db, patientId, data, userRef) => {
|
|
|
1697
1890
|
var updateContraindicationUtil = async (db, patientId, data, userRef) => {
|
|
1698
1891
|
const validatedData = updateContraindicationSchema.parse(data);
|
|
1699
1892
|
const { contraindicationIndex, ...updateData } = validatedData;
|
|
1700
|
-
const
|
|
1701
|
-
if (!
|
|
1702
|
-
const medicalInfo =
|
|
1893
|
+
const doc33 = await (0, import_firestore5.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
1894
|
+
if (!doc33.exists()) throw new Error("Medical info not found");
|
|
1895
|
+
const medicalInfo = doc33.data();
|
|
1703
1896
|
if (contraindicationIndex >= medicalInfo.contraindications.length) {
|
|
1704
1897
|
throw new Error("Invalid contraindication index");
|
|
1705
1898
|
}
|
|
@@ -1715,9 +1908,9 @@ var updateContraindicationUtil = async (db, patientId, data, userRef) => {
|
|
|
1715
1908
|
});
|
|
1716
1909
|
};
|
|
1717
1910
|
var removeContraindicationUtil = async (db, patientId, contraindicationIndex, userRef) => {
|
|
1718
|
-
const
|
|
1719
|
-
if (!
|
|
1720
|
-
const medicalInfo =
|
|
1911
|
+
const doc33 = await (0, import_firestore5.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
1912
|
+
if (!doc33.exists()) throw new Error("Medical info not found");
|
|
1913
|
+
const medicalInfo = doc33.data();
|
|
1721
1914
|
if (contraindicationIndex >= medicalInfo.contraindications.length) {
|
|
1722
1915
|
throw new Error("Invalid contraindication index");
|
|
1723
1916
|
}
|
|
@@ -1742,9 +1935,9 @@ var addMedicationUtil = async (db, patientId, data, userRef) => {
|
|
|
1742
1935
|
var updateMedicationUtil = async (db, patientId, data, userRef) => {
|
|
1743
1936
|
const validatedData = updateMedicationSchema.parse(data);
|
|
1744
1937
|
const { medicationIndex, ...updateData } = validatedData;
|
|
1745
|
-
const
|
|
1746
|
-
if (!
|
|
1747
|
-
const medicalInfo =
|
|
1938
|
+
const doc33 = await (0, import_firestore5.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
1939
|
+
if (!doc33.exists()) throw new Error("Medical info not found");
|
|
1940
|
+
const medicalInfo = doc33.data();
|
|
1748
1941
|
if (medicationIndex >= medicalInfo.currentMedications.length) {
|
|
1749
1942
|
throw new Error("Invalid medication index");
|
|
1750
1943
|
}
|
|
@@ -1760,9 +1953,9 @@ var updateMedicationUtil = async (db, patientId, data, userRef) => {
|
|
|
1760
1953
|
});
|
|
1761
1954
|
};
|
|
1762
1955
|
var removeMedicationUtil = async (db, patientId, medicationIndex, userRef) => {
|
|
1763
|
-
const
|
|
1764
|
-
if (!
|
|
1765
|
-
const medicalInfo =
|
|
1956
|
+
const doc33 = await (0, import_firestore5.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
1957
|
+
if (!doc33.exists()) throw new Error("Medical info not found");
|
|
1958
|
+
const medicalInfo = doc33.data();
|
|
1766
1959
|
if (medicationIndex >= medicalInfo.currentMedications.length) {
|
|
1767
1960
|
throw new Error("Invalid medication index");
|
|
1768
1961
|
}
|
|
@@ -2040,7 +2233,7 @@ var searchPatientsUtil = async (db, params, requester) => {
|
|
|
2040
2233
|
try {
|
|
2041
2234
|
const finalQuery = (0, import_firestore6.query)(patientsCollectionRef, ...constraints);
|
|
2042
2235
|
const querySnapshot = await (0, import_firestore6.getDocs)(finalQuery);
|
|
2043
|
-
const patients = querySnapshot.docs.map((
|
|
2236
|
+
const patients = querySnapshot.docs.map((doc33) => doc33.data());
|
|
2044
2237
|
console.log(`[searchPatientsUtil] Found ${patients.length} patients matching criteria.`);
|
|
2045
2238
|
return patients;
|
|
2046
2239
|
} catch (error) {
|
|
@@ -2064,8 +2257,8 @@ var getAllPatientsUtil = async (db, options) => {
|
|
|
2064
2257
|
}
|
|
2065
2258
|
const patientsSnapshot = await (0, import_firestore6.getDocs)(q);
|
|
2066
2259
|
const patients = [];
|
|
2067
|
-
patientsSnapshot.forEach((
|
|
2068
|
-
patients.push(
|
|
2260
|
+
patientsSnapshot.forEach((doc33) => {
|
|
2261
|
+
patients.push(doc33.data());
|
|
2069
2262
|
});
|
|
2070
2263
|
console.log(`[getAllPatientsUtil] Found ${patients.length} patients`);
|
|
2071
2264
|
return patients;
|
|
@@ -2277,8 +2470,8 @@ var getPatientsByPractitionerUtil = async (db, practitionerId, options) => {
|
|
|
2277
2470
|
}
|
|
2278
2471
|
const patientsSnapshot = await (0, import_firestore9.getDocs)(q);
|
|
2279
2472
|
const patients = [];
|
|
2280
|
-
patientsSnapshot.forEach((
|
|
2281
|
-
patients.push(
|
|
2473
|
+
patientsSnapshot.forEach((doc33) => {
|
|
2474
|
+
patients.push(doc33.data());
|
|
2282
2475
|
});
|
|
2283
2476
|
console.log(
|
|
2284
2477
|
`[getPatientsByPractitionerUtil] Found ${patients.length} patients for practitioner ID: ${practitionerId}`
|
|
@@ -2366,8 +2559,8 @@ var getPatientsByClinicUtil = async (db, clinicId, options) => {
|
|
|
2366
2559
|
}
|
|
2367
2560
|
const patientsSnapshot = await (0, import_firestore10.getDocs)(q);
|
|
2368
2561
|
const patients = [];
|
|
2369
|
-
patientsSnapshot.forEach((
|
|
2370
|
-
patients.push(
|
|
2562
|
+
patientsSnapshot.forEach((doc33) => {
|
|
2563
|
+
patients.push(doc33.data());
|
|
2371
2564
|
});
|
|
2372
2565
|
console.log(
|
|
2373
2566
|
`[getPatientsByClinicUtil] Found ${patients.length} patients for clinic ID: ${clinicId}`
|
|
@@ -3480,7 +3673,7 @@ async function getClinicAdminsByGroup(db, clinicGroupId) {
|
|
|
3480
3673
|
(0, import_firestore13.where)("clinicGroupId", "==", clinicGroupId)
|
|
3481
3674
|
);
|
|
3482
3675
|
const querySnapshot = await (0, import_firestore13.getDocs)(q);
|
|
3483
|
-
return querySnapshot.docs.map((
|
|
3676
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
3484
3677
|
}
|
|
3485
3678
|
async function updateClinicAdmin(db, adminId, data) {
|
|
3486
3679
|
const admin = await getClinicAdmin(db, adminId);
|
|
@@ -3741,6 +3934,8 @@ var ClinicAdminService = class extends BaseService {
|
|
|
3741
3934
|
this.getClinicService()
|
|
3742
3935
|
);
|
|
3743
3936
|
}
|
|
3937
|
+
// TODO: Add more methods for clinic admins for managing permissions, editing profiles by the admin, or by the clinic group owner and so on
|
|
3938
|
+
// Generally refactor admin permissions and clinic group permissions and systems for admin management
|
|
3744
3939
|
};
|
|
3745
3940
|
|
|
3746
3941
|
// src/services/practitioner/practitioner.service.ts
|
|
@@ -4177,7 +4372,7 @@ var PractitionerService = class extends BaseService {
|
|
|
4177
4372
|
(0, import_firestore15.where)("expiresAt", ">", import_firestore15.Timestamp.now())
|
|
4178
4373
|
);
|
|
4179
4374
|
const querySnapshot = await (0, import_firestore15.getDocs)(q);
|
|
4180
|
-
return querySnapshot.docs.map((
|
|
4375
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
4181
4376
|
}
|
|
4182
4377
|
/**
|
|
4183
4378
|
* Gets a token by its string value and validates it
|
|
@@ -4260,7 +4455,7 @@ var PractitionerService = class extends BaseService {
|
|
|
4260
4455
|
(0, import_firestore15.where)("status", "==", "active" /* ACTIVE */)
|
|
4261
4456
|
);
|
|
4262
4457
|
const querySnapshot = await (0, import_firestore15.getDocs)(q);
|
|
4263
|
-
return querySnapshot.docs.map((
|
|
4458
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
4264
4459
|
}
|
|
4265
4460
|
/**
|
|
4266
4461
|
* Dohvata sve zdravstvene radnike za određenu kliniku
|
|
@@ -4272,7 +4467,7 @@ var PractitionerService = class extends BaseService {
|
|
|
4272
4467
|
(0, import_firestore15.where)("isActive", "==", true)
|
|
4273
4468
|
);
|
|
4274
4469
|
const querySnapshot = await (0, import_firestore15.getDocs)(q);
|
|
4275
|
-
return querySnapshot.docs.map((
|
|
4470
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
4276
4471
|
}
|
|
4277
4472
|
/**
|
|
4278
4473
|
* Dohvata sve draft zdravstvene radnike za određenu kliniku sa statusom DRAFT
|
|
@@ -4284,7 +4479,7 @@ var PractitionerService = class extends BaseService {
|
|
|
4284
4479
|
(0, import_firestore15.where)("status", "==", "draft" /* DRAFT */)
|
|
4285
4480
|
);
|
|
4286
4481
|
const querySnapshot = await (0, import_firestore15.getDocs)(q);
|
|
4287
|
-
return querySnapshot.docs.map((
|
|
4482
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
4288
4483
|
}
|
|
4289
4484
|
/**
|
|
4290
4485
|
* Updates a practitioner
|
|
@@ -4466,7 +4661,7 @@ var PractitionerService = class extends BaseService {
|
|
|
4466
4661
|
);
|
|
4467
4662
|
const querySnapshot = await (0, import_firestore15.getDocs)(q);
|
|
4468
4663
|
const practitioners = querySnapshot.docs.map(
|
|
4469
|
-
(
|
|
4664
|
+
(doc33) => doc33.data()
|
|
4470
4665
|
);
|
|
4471
4666
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
4472
4667
|
return {
|
|
@@ -4537,8 +4732,8 @@ var PractitionerService = class extends BaseService {
|
|
|
4537
4732
|
console.log(
|
|
4538
4733
|
`[PRACTITIONER_SERVICE] Found ${querySnapshot.docs.length} practitioners with base query`
|
|
4539
4734
|
);
|
|
4540
|
-
let practitioners = querySnapshot.docs.map((
|
|
4541
|
-
return { ...
|
|
4735
|
+
let practitioners = querySnapshot.docs.map((doc33) => {
|
|
4736
|
+
return { ...doc33.data(), id: doc33.id };
|
|
4542
4737
|
});
|
|
4543
4738
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
4544
4739
|
if (filters.nameSearch && filters.nameSearch.trim() !== "") {
|
|
@@ -4792,7 +4987,7 @@ var UserService = class extends BaseService {
|
|
|
4792
4987
|
];
|
|
4793
4988
|
const q = (0, import_firestore16.query)((0, import_firestore16.collection)(this.db, USERS_COLLECTION), ...constraints);
|
|
4794
4989
|
const querySnapshot = await (0, import_firestore16.getDocs)(q);
|
|
4795
|
-
const users = querySnapshot.docs.map((
|
|
4990
|
+
const users = querySnapshot.docs.map((doc33) => doc33.data());
|
|
4796
4991
|
return Promise.all(users.map((userData) => userSchema.parse(userData)));
|
|
4797
4992
|
}
|
|
4798
4993
|
/**
|
|
@@ -5156,7 +5351,7 @@ async function getAllActiveGroups(db) {
|
|
|
5156
5351
|
(0, import_firestore17.where)("isActive", "==", true)
|
|
5157
5352
|
);
|
|
5158
5353
|
const querySnapshot = await (0, import_firestore17.getDocs)(q);
|
|
5159
|
-
return querySnapshot.docs.map((
|
|
5354
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
5160
5355
|
}
|
|
5161
5356
|
async function updateClinicGroup(db, groupId, data, app) {
|
|
5162
5357
|
console.log("[CLINIC_GROUP] Updating clinic group", { groupId });
|
|
@@ -5528,6 +5723,11 @@ var ClinicGroupService = class extends BaseService {
|
|
|
5528
5723
|
this.app
|
|
5529
5724
|
);
|
|
5530
5725
|
}
|
|
5726
|
+
// TODO: Add a method to get all admin tokens for a clinic group (not just active ones)
|
|
5727
|
+
// TODO: Refactor admin token methods not to add tokens to the clinicGroup document,
|
|
5728
|
+
// but to add them to a subcollection called adminTokens that belongs to a specific clinicGroup document
|
|
5729
|
+
// TODO: Add granular control over admin permissions, e.g. only allow admins to manage certain clinics to tokens directly
|
|
5730
|
+
// TODO: Generally refactor admin tokens and invites, also create cloud function to send invites and send updates when sombody uses the token
|
|
5531
5731
|
};
|
|
5532
5732
|
|
|
5533
5733
|
// src/services/clinic/clinic.service.ts
|
|
@@ -5554,7 +5754,7 @@ async function getClinicsByGroup(db, groupId) {
|
|
|
5554
5754
|
(0, import_firestore18.where)("isActive", "==", true)
|
|
5555
5755
|
);
|
|
5556
5756
|
const querySnapshot = await (0, import_firestore18.getDocs)(q);
|
|
5557
|
-
return querySnapshot.docs.map((
|
|
5757
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
5558
5758
|
}
|
|
5559
5759
|
async function updateClinic(db, clinicId, data, adminId, clinicAdminService, app) {
|
|
5560
5760
|
console.log("[CLINIC] Starting clinic update", { clinicId, adminId });
|
|
@@ -5748,7 +5948,7 @@ async function getClinicsByAdmin(db, adminId, options = {}, clinicAdminService,
|
|
|
5748
5948
|
}
|
|
5749
5949
|
const q = (0, import_firestore18.query)((0, import_firestore18.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
5750
5950
|
const querySnapshot = await (0, import_firestore18.getDocs)(q);
|
|
5751
|
-
return querySnapshot.docs.map((
|
|
5951
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
5752
5952
|
}
|
|
5753
5953
|
async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGroupService) {
|
|
5754
5954
|
return getClinicsByAdmin(
|
|
@@ -5793,11 +5993,11 @@ async function getAllClinics(db, pagination, lastDoc) {
|
|
|
5793
5993
|
}
|
|
5794
5994
|
const clinicsSnapshot = await (0, import_firestore18.getDocs)(clinicsQuery);
|
|
5795
5995
|
const lastVisible = clinicsSnapshot.docs[clinicsSnapshot.docs.length - 1];
|
|
5796
|
-
const clinics = clinicsSnapshot.docs.map((
|
|
5797
|
-
const data =
|
|
5996
|
+
const clinics = clinicsSnapshot.docs.map((doc33) => {
|
|
5997
|
+
const data = doc33.data();
|
|
5798
5998
|
return {
|
|
5799
5999
|
...data,
|
|
5800
|
-
id:
|
|
6000
|
+
id: doc33.id
|
|
5801
6001
|
};
|
|
5802
6002
|
});
|
|
5803
6003
|
return {
|
|
@@ -5824,8 +6024,8 @@ async function getAllClinicsInRange(db, center, rangeInKm, pagination, lastDoc)
|
|
|
5824
6024
|
];
|
|
5825
6025
|
const q = (0, import_firestore18.query)((0, import_firestore18.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
5826
6026
|
const querySnapshot = await (0, import_firestore18.getDocs)(q);
|
|
5827
|
-
for (const
|
|
5828
|
-
const clinic =
|
|
6027
|
+
for (const doc33 of querySnapshot.docs) {
|
|
6028
|
+
const clinic = doc33.data();
|
|
5829
6029
|
const distance = (0, import_geofire_common4.distanceBetween)(
|
|
5830
6030
|
[center.latitude, center.longitude],
|
|
5831
6031
|
[clinic.location.latitude, clinic.location.longitude]
|
|
@@ -5942,8 +6142,8 @@ async function findClinicsInRadius(db, center, radiusInKm, filters) {
|
|
|
5942
6142
|
}
|
|
5943
6143
|
const q = (0, import_firestore19.query)((0, import_firestore19.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
5944
6144
|
const querySnapshot = await (0, import_firestore19.getDocs)(q);
|
|
5945
|
-
for (const
|
|
5946
|
-
const clinic =
|
|
6145
|
+
for (const doc33 of querySnapshot.docs) {
|
|
6146
|
+
const clinic = doc33.data();
|
|
5947
6147
|
const distance = (0, import_geofire_common5.distanceBetween)(
|
|
5948
6148
|
[center.latitude, center.longitude],
|
|
5949
6149
|
[clinic.location.latitude, clinic.location.longitude]
|
|
@@ -6031,8 +6231,8 @@ async function getClinicsByFilters(db, filters) {
|
|
|
6031
6231
|
console.log(
|
|
6032
6232
|
`[FILTER_UTILS] Found ${querySnapshot.docs.length} clinics in geo bound`
|
|
6033
6233
|
);
|
|
6034
|
-
for (const
|
|
6035
|
-
const clinic = { ...
|
|
6234
|
+
for (const doc33 of querySnapshot.docs) {
|
|
6235
|
+
const clinic = { ...doc33.data(), id: doc33.id };
|
|
6036
6236
|
const distance = (0, import_geofire_common6.distanceBetween)(
|
|
6037
6237
|
[center.latitude, center.longitude],
|
|
6038
6238
|
[clinic.location.latitude, clinic.location.longitude]
|
|
@@ -6088,8 +6288,8 @@ async function getClinicsByFilters(db, filters) {
|
|
|
6088
6288
|
console.log(
|
|
6089
6289
|
`[FILTER_UTILS] Found ${querySnapshot.docs.length} clinics with regular query`
|
|
6090
6290
|
);
|
|
6091
|
-
const clinics = querySnapshot.docs.map((
|
|
6092
|
-
return { ...
|
|
6291
|
+
const clinics = querySnapshot.docs.map((doc33) => {
|
|
6292
|
+
return { ...doc33.data(), id: doc33.id };
|
|
6093
6293
|
});
|
|
6094
6294
|
let filteredClinics = clinics;
|
|
6095
6295
|
if (filters.center) {
|
|
@@ -7301,17 +7501,28 @@ var import_firestore23 = require("firebase/firestore");
|
|
|
7301
7501
|
|
|
7302
7502
|
// src/types/notifications/index.ts
|
|
7303
7503
|
var NotificationType = /* @__PURE__ */ ((NotificationType3) => {
|
|
7304
|
-
NotificationType3["PRE_REQUIREMENT"] = "preRequirement";
|
|
7305
|
-
NotificationType3["POST_REQUIREMENT"] = "postRequirement";
|
|
7306
7504
|
NotificationType3["APPOINTMENT_REMINDER"] = "appointmentReminder";
|
|
7307
|
-
NotificationType3["
|
|
7505
|
+
NotificationType3["APPOINTMENT_STATUS_CHANGE"] = "appointmentStatusChange";
|
|
7506
|
+
NotificationType3["APPOINTMENT_RESCHEDULED_PROPOSAL"] = "appointmentRescheduledProposal";
|
|
7507
|
+
NotificationType3["APPOINTMENT_CANCELLED"] = "appointmentCancelled";
|
|
7508
|
+
NotificationType3["REQUIREMENT_INSTRUCTION_DUE"] = "requirementInstructionDue";
|
|
7509
|
+
NotificationType3["FORM_REMINDER"] = "formReminder";
|
|
7510
|
+
NotificationType3["FORM_SUBMISSION_CONFIRMATION"] = "formSubmissionConfirmation";
|
|
7511
|
+
NotificationType3["REVIEW_REQUEST"] = "reviewRequest";
|
|
7512
|
+
NotificationType3["PAYMENT_DUE"] = "paymentDue";
|
|
7513
|
+
NotificationType3["PAYMENT_CONFIRMATION"] = "paymentConfirmation";
|
|
7514
|
+
NotificationType3["PAYMENT_FAILED"] = "paymentFailed";
|
|
7515
|
+
NotificationType3["GENERAL_MESSAGE"] = "generalMessage";
|
|
7516
|
+
NotificationType3["ACCOUNT_NOTIFICATION"] = "accountNotification";
|
|
7308
7517
|
return NotificationType3;
|
|
7309
7518
|
})(NotificationType || {});
|
|
7310
7519
|
var NOTIFICATIONS_COLLECTION = "notifications";
|
|
7311
7520
|
var NotificationStatus = /* @__PURE__ */ ((NotificationStatus2) => {
|
|
7312
7521
|
NotificationStatus2["PENDING"] = "pending";
|
|
7522
|
+
NotificationStatus2["PROCESSING"] = "processing";
|
|
7313
7523
|
NotificationStatus2["SENT"] = "sent";
|
|
7314
7524
|
NotificationStatus2["FAILED"] = "failed";
|
|
7525
|
+
NotificationStatus2["DELIVERED"] = "delivered";
|
|
7315
7526
|
NotificationStatus2["CANCELLED"] = "cancelled";
|
|
7316
7527
|
NotificationStatus2["PARTIAL_SUCCESS"] = "partialSuccess";
|
|
7317
7528
|
return NotificationStatus2;
|
|
@@ -7367,9 +7578,9 @@ var NotificationService = class extends BaseService {
|
|
|
7367
7578
|
(0, import_firestore23.orderBy)("notificationTime", "desc")
|
|
7368
7579
|
);
|
|
7369
7580
|
const querySnapshot = await (0, import_firestore23.getDocs)(q);
|
|
7370
|
-
return querySnapshot.docs.map((
|
|
7371
|
-
id:
|
|
7372
|
-
...
|
|
7581
|
+
return querySnapshot.docs.map((doc33) => ({
|
|
7582
|
+
id: doc33.id,
|
|
7583
|
+
...doc33.data()
|
|
7373
7584
|
}));
|
|
7374
7585
|
}
|
|
7375
7586
|
/**
|
|
@@ -7383,9 +7594,9 @@ var NotificationService = class extends BaseService {
|
|
|
7383
7594
|
(0, import_firestore23.orderBy)("notificationTime", "desc")
|
|
7384
7595
|
);
|
|
7385
7596
|
const querySnapshot = await (0, import_firestore23.getDocs)(q);
|
|
7386
|
-
return querySnapshot.docs.map((
|
|
7387
|
-
id:
|
|
7388
|
-
...
|
|
7597
|
+
return querySnapshot.docs.map((doc33) => ({
|
|
7598
|
+
id: doc33.id,
|
|
7599
|
+
...doc33.data()
|
|
7389
7600
|
}));
|
|
7390
7601
|
}
|
|
7391
7602
|
/**
|
|
@@ -7457,9 +7668,9 @@ var NotificationService = class extends BaseService {
|
|
|
7457
7668
|
(0, import_firestore23.orderBy)("notificationTime", "desc")
|
|
7458
7669
|
);
|
|
7459
7670
|
const querySnapshot = await (0, import_firestore23.getDocs)(q);
|
|
7460
|
-
return querySnapshot.docs.map((
|
|
7461
|
-
id:
|
|
7462
|
-
...
|
|
7671
|
+
return querySnapshot.docs.map((doc33) => ({
|
|
7672
|
+
id: doc33.id,
|
|
7673
|
+
...doc33.data()
|
|
7463
7674
|
}));
|
|
7464
7675
|
}
|
|
7465
7676
|
/**
|
|
@@ -7472,9 +7683,9 @@ var NotificationService = class extends BaseService {
|
|
|
7472
7683
|
(0, import_firestore23.orderBy)("notificationTime", "desc")
|
|
7473
7684
|
);
|
|
7474
7685
|
const querySnapshot = await (0, import_firestore23.getDocs)(q);
|
|
7475
|
-
return querySnapshot.docs.map((
|
|
7476
|
-
id:
|
|
7477
|
-
...
|
|
7686
|
+
return querySnapshot.docs.map((doc33) => ({
|
|
7687
|
+
id: doc33.id,
|
|
7688
|
+
...doc33.data()
|
|
7478
7689
|
}));
|
|
7479
7690
|
}
|
|
7480
7691
|
};
|
|
@@ -7501,7 +7712,8 @@ var createProcedureSchema = import_zod20.z.object({
|
|
|
7501
7712
|
duration: import_zod20.z.number().min(1).max(480),
|
|
7502
7713
|
// Max 8 hours
|
|
7503
7714
|
practitionerId: import_zod20.z.string().min(1),
|
|
7504
|
-
clinicBranchId: import_zod20.z.string().min(1)
|
|
7715
|
+
clinicBranchId: import_zod20.z.string().min(1),
|
|
7716
|
+
photos: import_zod20.z.array(import_zod20.z.string()).optional()
|
|
7505
7717
|
});
|
|
7506
7718
|
var updateProcedureSchema = import_zod20.z.object({
|
|
7507
7719
|
name: import_zod20.z.string().min(3).max(100).optional(),
|
|
@@ -7516,7 +7728,8 @@ var updateProcedureSchema = import_zod20.z.object({
|
|
|
7516
7728
|
subcategoryId: import_zod20.z.string().optional(),
|
|
7517
7729
|
technologyId: import_zod20.z.string().optional(),
|
|
7518
7730
|
productId: import_zod20.z.string().optional(),
|
|
7519
|
-
clinicBranchId: import_zod20.z.string().optional()
|
|
7731
|
+
clinicBranchId: import_zod20.z.string().optional(),
|
|
7732
|
+
photos: import_zod20.z.array(import_zod20.z.string()).optional()
|
|
7520
7733
|
});
|
|
7521
7734
|
var procedureSchema = createProcedureSchema.extend({
|
|
7522
7735
|
id: import_zod20.z.string().min(1),
|
|
@@ -7530,6 +7743,8 @@ var procedureSchema = createProcedureSchema.extend({
|
|
|
7530
7743
|
// We'll validate the full product object separately
|
|
7531
7744
|
blockingConditions: import_zod20.z.array(import_zod20.z.any()),
|
|
7532
7745
|
// We'll validate blocking conditions separately
|
|
7746
|
+
contraindications: import_zod20.z.array(import_zod20.z.any()),
|
|
7747
|
+
// We'll validate contraindications separately
|
|
7533
7748
|
treatmentBenefits: import_zod20.z.array(import_zod20.z.any()),
|
|
7534
7749
|
// We'll validate treatment benefits separately
|
|
7535
7750
|
preRequirements: import_zod20.z.array(import_zod20.z.any()),
|
|
@@ -7634,6 +7849,7 @@ var ProcedureService = class extends BaseService {
|
|
|
7634
7849
|
technology,
|
|
7635
7850
|
product,
|
|
7636
7851
|
blockingConditions: technology.blockingConditions,
|
|
7852
|
+
contraindications: technology.contraindications || [],
|
|
7637
7853
|
treatmentBenefits: technology.benefits,
|
|
7638
7854
|
preRequirements: technology.requirements.pre,
|
|
7639
7855
|
postRequirements: technology.requirements.post,
|
|
@@ -7691,7 +7907,7 @@ var ProcedureService = class extends BaseService {
|
|
|
7691
7907
|
(0, import_firestore24.where)("isActive", "==", true)
|
|
7692
7908
|
);
|
|
7693
7909
|
const snapshot = await (0, import_firestore24.getDocs)(q);
|
|
7694
|
-
return snapshot.docs.map((
|
|
7910
|
+
return snapshot.docs.map((doc33) => doc33.data());
|
|
7695
7911
|
}
|
|
7696
7912
|
/**
|
|
7697
7913
|
* Gets all procedures for a practitioner
|
|
@@ -7705,7 +7921,7 @@ var ProcedureService = class extends BaseService {
|
|
|
7705
7921
|
(0, import_firestore24.where)("isActive", "==", true)
|
|
7706
7922
|
);
|
|
7707
7923
|
const snapshot = await (0, import_firestore24.getDocs)(q);
|
|
7708
|
-
return snapshot.docs.map((
|
|
7924
|
+
return snapshot.docs.map((doc33) => doc33.data());
|
|
7709
7925
|
}
|
|
7710
7926
|
/**
|
|
7711
7927
|
* Updates a procedure
|
|
@@ -7888,20 +8104,20 @@ var ProcedureService = class extends BaseService {
|
|
|
7888
8104
|
const proceduresCollection = (0, import_firestore24.collection)(this.db, PROCEDURES_COLLECTION);
|
|
7889
8105
|
let proceduresQuery = (0, import_firestore24.query)(proceduresCollection);
|
|
7890
8106
|
if (pagination && pagination > 0) {
|
|
7891
|
-
const { limit:
|
|
8107
|
+
const { limit: limit12, startAfter: startAfter12 } = await import("firebase/firestore");
|
|
7892
8108
|
if (lastDoc) {
|
|
7893
8109
|
proceduresQuery = (0, import_firestore24.query)(
|
|
7894
8110
|
proceduresCollection,
|
|
7895
8111
|
(0, import_firestore24.orderBy)("name"),
|
|
7896
8112
|
// Use imported orderBy
|
|
7897
|
-
|
|
7898
|
-
|
|
8113
|
+
startAfter12(lastDoc),
|
|
8114
|
+
limit12(pagination)
|
|
7899
8115
|
);
|
|
7900
8116
|
} else {
|
|
7901
8117
|
proceduresQuery = (0, import_firestore24.query)(
|
|
7902
8118
|
proceduresCollection,
|
|
7903
8119
|
(0, import_firestore24.orderBy)("name"),
|
|
7904
|
-
|
|
8120
|
+
limit12(pagination)
|
|
7905
8121
|
);
|
|
7906
8122
|
}
|
|
7907
8123
|
} else {
|
|
@@ -7909,11 +8125,11 @@ var ProcedureService = class extends BaseService {
|
|
|
7909
8125
|
}
|
|
7910
8126
|
const proceduresSnapshot = await (0, import_firestore24.getDocs)(proceduresQuery);
|
|
7911
8127
|
const lastVisible = proceduresSnapshot.docs[proceduresSnapshot.docs.length - 1];
|
|
7912
|
-
const procedures = proceduresSnapshot.docs.map((
|
|
7913
|
-
const data =
|
|
8128
|
+
const procedures = proceduresSnapshot.docs.map((doc33) => {
|
|
8129
|
+
const data = doc33.data();
|
|
7914
8130
|
return {
|
|
7915
8131
|
...data,
|
|
7916
|
-
id:
|
|
8132
|
+
id: doc33.id
|
|
7917
8133
|
// Ensure ID is present
|
|
7918
8134
|
};
|
|
7919
8135
|
});
|
|
@@ -7995,8 +8211,8 @@ var ProcedureService = class extends BaseService {
|
|
|
7995
8211
|
console.log(
|
|
7996
8212
|
`[PROCEDURE_SERVICE] Found ${querySnapshot.docs.length} procedures in geo bound`
|
|
7997
8213
|
);
|
|
7998
|
-
for (const
|
|
7999
|
-
const procedure = { ...
|
|
8214
|
+
for (const doc33 of querySnapshot.docs) {
|
|
8215
|
+
const procedure = { ...doc33.data(), id: doc33.id };
|
|
8000
8216
|
const distance = (0, import_geofire_common8.distanceBetween)(
|
|
8001
8217
|
[center.latitude, center.longitude],
|
|
8002
8218
|
[
|
|
@@ -8047,8 +8263,8 @@ var ProcedureService = class extends BaseService {
|
|
|
8047
8263
|
console.log(
|
|
8048
8264
|
`[PROCEDURE_SERVICE] Found ${querySnapshot.docs.length} procedures with regular query`
|
|
8049
8265
|
);
|
|
8050
|
-
const procedures = querySnapshot.docs.map((
|
|
8051
|
-
return { ...
|
|
8266
|
+
const procedures = querySnapshot.docs.map((doc33) => {
|
|
8267
|
+
return { ...doc33.data(), id: doc33.id };
|
|
8052
8268
|
});
|
|
8053
8269
|
if (filters.location) {
|
|
8054
8270
|
const center = filters.location;
|
|
@@ -8188,7 +8404,10 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
8188
8404
|
createdBy: userId,
|
|
8189
8405
|
version: 1,
|
|
8190
8406
|
isActive: true,
|
|
8191
|
-
tags: validatedData.tags || []
|
|
8407
|
+
tags: validatedData.tags || [],
|
|
8408
|
+
isUserForm: validatedData.isUserForm || false,
|
|
8409
|
+
isRequired: validatedData.isRequired || false,
|
|
8410
|
+
sortingOrder: validatedData.sortingOrder || 0
|
|
8192
8411
|
};
|
|
8193
8412
|
const docRef = (0, import_firestore25.doc)(this.collectionRef, templateId);
|
|
8194
8413
|
await (0, import_firestore25.setDoc)(docRef, template);
|
|
@@ -8223,21 +8442,31 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
8223
8442
|
if (validatedData.elements) {
|
|
8224
8443
|
updatedElements = validatedData.elements.map((element) => ({
|
|
8225
8444
|
...element,
|
|
8226
|
-
id: this.generateId()
|
|
8445
|
+
id: element.id || this.generateId()
|
|
8227
8446
|
}));
|
|
8228
8447
|
}
|
|
8229
|
-
const
|
|
8230
|
-
...validatedData,
|
|
8448
|
+
const updatePayload = {
|
|
8231
8449
|
elements: updatedElements,
|
|
8232
8450
|
updatedAt: Date.now(),
|
|
8233
8451
|
version: template.version + 1
|
|
8234
8452
|
};
|
|
8453
|
+
if (validatedData.title !== void 0)
|
|
8454
|
+
updatePayload.title = validatedData.title;
|
|
8455
|
+
if (validatedData.description !== void 0)
|
|
8456
|
+
updatePayload.description = validatedData.description;
|
|
8457
|
+
if (validatedData.isActive !== void 0)
|
|
8458
|
+
updatePayload.isActive = validatedData.isActive;
|
|
8459
|
+
if (validatedData.tags !== void 0)
|
|
8460
|
+
updatePayload.tags = validatedData.tags;
|
|
8461
|
+
if (validatedData.isUserForm !== void 0)
|
|
8462
|
+
updatePayload.isUserForm = validatedData.isUserForm;
|
|
8463
|
+
if (validatedData.isRequired !== void 0)
|
|
8464
|
+
updatePayload.isRequired = validatedData.isRequired;
|
|
8465
|
+
if (validatedData.sortingOrder !== void 0)
|
|
8466
|
+
updatePayload.sortingOrder = validatedData.sortingOrder;
|
|
8235
8467
|
const docRef = (0, import_firestore25.doc)(this.collectionRef, templateId);
|
|
8236
|
-
await (0, import_firestore25.updateDoc)(docRef,
|
|
8237
|
-
return {
|
|
8238
|
-
...template,
|
|
8239
|
-
...updateData
|
|
8240
|
-
};
|
|
8468
|
+
await (0, import_firestore25.updateDoc)(docRef, updatePayload);
|
|
8469
|
+
return { ...template, ...updatePayload };
|
|
8241
8470
|
}
|
|
8242
8471
|
/**
|
|
8243
8472
|
* Delete a document template
|
|
@@ -8266,9 +8495,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
8266
8495
|
const querySnapshot = await (0, import_firestore25.getDocs)(q);
|
|
8267
8496
|
const templates = [];
|
|
8268
8497
|
let lastVisible = null;
|
|
8269
|
-
querySnapshot.forEach((
|
|
8270
|
-
templates.push(
|
|
8271
|
-
lastVisible =
|
|
8498
|
+
querySnapshot.forEach((doc33) => {
|
|
8499
|
+
templates.push(doc33.data());
|
|
8500
|
+
lastVisible = doc33;
|
|
8272
8501
|
});
|
|
8273
8502
|
return {
|
|
8274
8503
|
templates,
|
|
@@ -8296,9 +8525,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
8296
8525
|
const querySnapshot = await (0, import_firestore25.getDocs)(q);
|
|
8297
8526
|
const templates = [];
|
|
8298
8527
|
let lastVisible = null;
|
|
8299
|
-
querySnapshot.forEach((
|
|
8300
|
-
templates.push(
|
|
8301
|
-
lastVisible =
|
|
8528
|
+
querySnapshot.forEach((doc33) => {
|
|
8529
|
+
templates.push(doc33.data());
|
|
8530
|
+
lastVisible = doc33;
|
|
8302
8531
|
});
|
|
8303
8532
|
return {
|
|
8304
8533
|
templates,
|
|
@@ -8325,9 +8554,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
8325
8554
|
const querySnapshot = await (0, import_firestore25.getDocs)(q);
|
|
8326
8555
|
const templates = [];
|
|
8327
8556
|
let lastVisible = null;
|
|
8328
|
-
querySnapshot.forEach((
|
|
8329
|
-
templates.push(
|
|
8330
|
-
lastVisible =
|
|
8557
|
+
querySnapshot.forEach((doc33) => {
|
|
8558
|
+
templates.push(doc33.data());
|
|
8559
|
+
lastVisible = doc33;
|
|
8331
8560
|
});
|
|
8332
8561
|
return {
|
|
8333
8562
|
templates,
|
|
@@ -8341,50 +8570,80 @@ var import_firestore26 = require("firebase/firestore");
|
|
|
8341
8570
|
var FilledDocumentService = class extends BaseService {
|
|
8342
8571
|
constructor(...args) {
|
|
8343
8572
|
super(...args);
|
|
8344
|
-
this.collectionRef = (0, import_firestore26.collection)(
|
|
8345
|
-
this.db,
|
|
8346
|
-
FILLED_DOCUMENTS_COLLECTION
|
|
8347
|
-
);
|
|
8348
8573
|
this.templateService = new DocumentationTemplateService(...args);
|
|
8349
8574
|
}
|
|
8575
|
+
getFormSubcollectionPath(isUserForm) {
|
|
8576
|
+
return isUserForm ? USER_FORMS_SUBCOLLECTION : DOCTOR_FORMS_SUBCOLLECTION;
|
|
8577
|
+
}
|
|
8350
8578
|
/**
|
|
8351
|
-
* Create a new filled document
|
|
8352
|
-
* @param templateId - ID of the template to use
|
|
8353
|
-
* @param
|
|
8354
|
-
* @param
|
|
8355
|
-
* @param
|
|
8356
|
-
* @
|
|
8579
|
+
* Create a new filled document within an appointment's subcollection.
|
|
8580
|
+
* @param templateId - ID of the template to use.
|
|
8581
|
+
* @param appointmentId - ID of the appointment this form belongs to.
|
|
8582
|
+
* @param procedureId - ID of the procedure associated with this form.
|
|
8583
|
+
* @param patientId - ID of the patient.
|
|
8584
|
+
* @param practitionerId - ID of the practitioner (can be system/generic if patient is filling).
|
|
8585
|
+
* @param clinicId - ID of the clinic.
|
|
8586
|
+
* @param initialValues - Optional initial values for the form elements.
|
|
8587
|
+
* @param initialStatus - Optional initial status for the form.
|
|
8588
|
+
* @returns The created filled document.
|
|
8357
8589
|
*/
|
|
8358
|
-
async
|
|
8590
|
+
async createFilledDocumentForAppointment(templateId, appointmentId, procedureId, patientId, practitionerId, clinicId, initialValues = {}, initialStatus = "draft" /* DRAFT */) {
|
|
8359
8591
|
const template = await this.templateService.getTemplateById(templateId);
|
|
8360
8592
|
if (!template) {
|
|
8361
8593
|
throw new Error(`Template with ID ${templateId} not found`);
|
|
8362
8594
|
}
|
|
8363
8595
|
const documentId3 = this.generateId();
|
|
8364
8596
|
const now = Date.now();
|
|
8597
|
+
const isUserForm = template.isUserForm || false;
|
|
8598
|
+
const formSubcollection = this.getFormSubcollectionPath(isUserForm);
|
|
8365
8599
|
const filledDocument = {
|
|
8366
8600
|
id: documentId3,
|
|
8367
8601
|
templateId,
|
|
8368
8602
|
templateVersion: template.version,
|
|
8603
|
+
isUserForm,
|
|
8604
|
+
// Set based on template
|
|
8605
|
+
isRequired: template.isRequired || false,
|
|
8606
|
+
// Inherit isRequired from the template
|
|
8607
|
+
appointmentId,
|
|
8608
|
+
// NEW
|
|
8609
|
+
procedureId,
|
|
8610
|
+
// NEW
|
|
8369
8611
|
patientId,
|
|
8370
8612
|
practitionerId,
|
|
8371
8613
|
clinicId,
|
|
8372
8614
|
createdAt: now,
|
|
8373
8615
|
updatedAt: now,
|
|
8374
|
-
values:
|
|
8375
|
-
status:
|
|
8616
|
+
values: initialValues,
|
|
8617
|
+
status: initialStatus
|
|
8376
8618
|
};
|
|
8377
|
-
const docRef = (0, import_firestore26.doc)(
|
|
8619
|
+
const docRef = (0, import_firestore26.doc)(
|
|
8620
|
+
this.db,
|
|
8621
|
+
APPOINTMENTS_COLLECTION,
|
|
8622
|
+
// Replaced "appointments"
|
|
8623
|
+
appointmentId,
|
|
8624
|
+
formSubcollection,
|
|
8625
|
+
documentId3
|
|
8626
|
+
);
|
|
8378
8627
|
await (0, import_firestore26.setDoc)(docRef, filledDocument);
|
|
8379
8628
|
return filledDocument;
|
|
8380
8629
|
}
|
|
8381
8630
|
/**
|
|
8382
|
-
* Get a filled document
|
|
8383
|
-
* @param
|
|
8384
|
-
* @
|
|
8631
|
+
* Get a specific filled document from an appointment's subcollection.
|
|
8632
|
+
* @param appointmentId - ID of the appointment.
|
|
8633
|
+
* @param formId - ID of the filled document.
|
|
8634
|
+
* @param isUserForm - Boolean indicating if it's a user form or doctor form.
|
|
8635
|
+
* @returns The filled document or null if not found.
|
|
8385
8636
|
*/
|
|
8386
|
-
async
|
|
8387
|
-
const
|
|
8637
|
+
async getFilledDocumentFromAppointmentById(appointmentId, formId, isUserForm) {
|
|
8638
|
+
const formSubcollection = this.getFormSubcollectionPath(isUserForm);
|
|
8639
|
+
const docRef = (0, import_firestore26.doc)(
|
|
8640
|
+
this.db,
|
|
8641
|
+
APPOINTMENTS_COLLECTION,
|
|
8642
|
+
// Replaced "appointments"
|
|
8643
|
+
appointmentId,
|
|
8644
|
+
formSubcollection,
|
|
8645
|
+
formId
|
|
8646
|
+
);
|
|
8388
8647
|
const docSnap = await (0, import_firestore26.getDoc)(docRef);
|
|
8389
8648
|
if (!docSnap.exists()) {
|
|
8390
8649
|
return null;
|
|
@@ -8392,178 +8651,183 @@ var FilledDocumentService = class extends BaseService {
|
|
|
8392
8651
|
return docSnap.data();
|
|
8393
8652
|
}
|
|
8394
8653
|
/**
|
|
8395
|
-
* Update values in a filled document
|
|
8396
|
-
* @param
|
|
8397
|
-
* @param
|
|
8398
|
-
* @param
|
|
8399
|
-
* @
|
|
8654
|
+
* Update values or status in a filled document within an appointment's subcollection.
|
|
8655
|
+
* @param appointmentId - ID of the appointment.
|
|
8656
|
+
* @param formId - ID of the filled document to update.
|
|
8657
|
+
* @param isUserForm - Boolean indicating if it's a user form or doctor form.
|
|
8658
|
+
* @param values - Updated values for elements.
|
|
8659
|
+
* @param status - Optional new status for the document.
|
|
8660
|
+
* @returns The updated filled document.
|
|
8400
8661
|
*/
|
|
8401
|
-
async
|
|
8402
|
-
const
|
|
8403
|
-
|
|
8404
|
-
|
|
8662
|
+
async updateFilledDocumentInAppointment(appointmentId, formId, isUserForm, values, status) {
|
|
8663
|
+
const formSubcollection = this.getFormSubcollectionPath(isUserForm);
|
|
8664
|
+
const docRef = (0, import_firestore26.doc)(
|
|
8665
|
+
this.db,
|
|
8666
|
+
APPOINTMENTS_COLLECTION,
|
|
8667
|
+
// Replaced "appointments"
|
|
8668
|
+
appointmentId,
|
|
8669
|
+
formSubcollection,
|
|
8670
|
+
formId
|
|
8671
|
+
);
|
|
8672
|
+
const existingDoc = await this.getFilledDocumentFromAppointmentById(
|
|
8673
|
+
appointmentId,
|
|
8674
|
+
formId,
|
|
8675
|
+
isUserForm
|
|
8676
|
+
);
|
|
8677
|
+
if (!existingDoc) {
|
|
8678
|
+
throw new Error(
|
|
8679
|
+
`Filled document with ID ${formId} not found in appointment ${appointmentId} ${formSubcollection}`
|
|
8680
|
+
);
|
|
8405
8681
|
}
|
|
8406
|
-
const
|
|
8407
|
-
values: {
|
|
8408
|
-
...filledDocument.values,
|
|
8409
|
-
...values
|
|
8410
|
-
},
|
|
8682
|
+
const updatePayload = {
|
|
8411
8683
|
updatedAt: Date.now()
|
|
8412
8684
|
};
|
|
8685
|
+
if (values) {
|
|
8686
|
+
updatePayload.values = {
|
|
8687
|
+
...existingDoc.values,
|
|
8688
|
+
...values
|
|
8689
|
+
};
|
|
8690
|
+
}
|
|
8413
8691
|
if (status) {
|
|
8414
|
-
|
|
8692
|
+
updatePayload.status = status;
|
|
8415
8693
|
}
|
|
8416
|
-
|
|
8417
|
-
|
|
8418
|
-
|
|
8419
|
-
|
|
8420
|
-
...updateData
|
|
8421
|
-
};
|
|
8694
|
+
if (Object.keys(updatePayload).length === 1 && "updatedAt" in updatePayload) {
|
|
8695
|
+
}
|
|
8696
|
+
await (0, import_firestore26.updateDoc)(docRef, updatePayload);
|
|
8697
|
+
return { ...existingDoc, ...updatePayload };
|
|
8422
8698
|
}
|
|
8423
8699
|
/**
|
|
8424
|
-
* Get filled
|
|
8425
|
-
* @param
|
|
8426
|
-
* @param pageSize
|
|
8427
|
-
* @param lastDoc
|
|
8428
|
-
* @returns Array of filled documents and the last document for pagination
|
|
8700
|
+
* Get all filled user forms for a specific appointment.
|
|
8701
|
+
* @param appointmentId ID of the appointment.
|
|
8702
|
+
* @param pageSize Number of documents to retrieve.
|
|
8703
|
+
* @param lastDoc Last document from previous page for pagination.
|
|
8429
8704
|
*/
|
|
8430
|
-
async
|
|
8705
|
+
async getFilledUserFormsForAppointment(appointmentId, pageSize = 20, lastDoc) {
|
|
8706
|
+
const subcollectionRef = (0, import_firestore26.collection)(
|
|
8707
|
+
this.db,
|
|
8708
|
+
APPOINTMENTS_COLLECTION,
|
|
8709
|
+
// Replaced "appointments"
|
|
8710
|
+
appointmentId,
|
|
8711
|
+
USER_FORMS_SUBCOLLECTION
|
|
8712
|
+
);
|
|
8431
8713
|
let q = (0, import_firestore26.query)(
|
|
8432
|
-
|
|
8433
|
-
(0, import_firestore26.where)("patientId", "==", patientId),
|
|
8714
|
+
subcollectionRef,
|
|
8434
8715
|
(0, import_firestore26.orderBy)("updatedAt", "desc"),
|
|
8435
8716
|
(0, import_firestore26.limit)(pageSize)
|
|
8436
8717
|
);
|
|
8437
8718
|
if (lastDoc) {
|
|
8438
8719
|
q = (0, import_firestore26.query)(q, (0, import_firestore26.startAfter)(lastDoc));
|
|
8439
8720
|
}
|
|
8440
|
-
|
|
8441
|
-
const documents = [];
|
|
8442
|
-
let lastVisible = null;
|
|
8443
|
-
querySnapshot.forEach((doc32) => {
|
|
8444
|
-
documents.push(doc32.data());
|
|
8445
|
-
lastVisible = doc32;
|
|
8446
|
-
});
|
|
8447
|
-
return {
|
|
8448
|
-
documents,
|
|
8449
|
-
lastDoc: lastVisible
|
|
8450
|
-
};
|
|
8721
|
+
return this.executeQuery(q);
|
|
8451
8722
|
}
|
|
8452
8723
|
/**
|
|
8453
|
-
* Get filled
|
|
8454
|
-
* @param
|
|
8455
|
-
* @param pageSize
|
|
8456
|
-
* @param lastDoc
|
|
8457
|
-
* @returns Array of filled documents and the last document for pagination
|
|
8724
|
+
* Get all filled doctor forms for a specific appointment.
|
|
8725
|
+
* @param appointmentId ID of the appointment.
|
|
8726
|
+
* @param pageSize Number of documents to retrieve.
|
|
8727
|
+
* @param lastDoc Last document from previous page for pagination.
|
|
8458
8728
|
*/
|
|
8459
|
-
async
|
|
8729
|
+
async getFilledDoctorFormsForAppointment(appointmentId, pageSize = 20, lastDoc) {
|
|
8730
|
+
const subcollectionRef = (0, import_firestore26.collection)(
|
|
8731
|
+
this.db,
|
|
8732
|
+
APPOINTMENTS_COLLECTION,
|
|
8733
|
+
// Replaced "appointments"
|
|
8734
|
+
appointmentId,
|
|
8735
|
+
DOCTOR_FORMS_SUBCOLLECTION
|
|
8736
|
+
);
|
|
8460
8737
|
let q = (0, import_firestore26.query)(
|
|
8461
|
-
|
|
8462
|
-
(0, import_firestore26.where)("practitionerId", "==", practitionerId),
|
|
8738
|
+
subcollectionRef,
|
|
8463
8739
|
(0, import_firestore26.orderBy)("updatedAt", "desc"),
|
|
8464
8740
|
(0, import_firestore26.limit)(pageSize)
|
|
8465
8741
|
);
|
|
8466
8742
|
if (lastDoc) {
|
|
8467
8743
|
q = (0, import_firestore26.query)(q, (0, import_firestore26.startAfter)(lastDoc));
|
|
8468
8744
|
}
|
|
8745
|
+
return this.executeQuery(q);
|
|
8746
|
+
}
|
|
8747
|
+
// Helper to execute query and return documents + lastDoc
|
|
8748
|
+
async executeQuery(q) {
|
|
8469
8749
|
const querySnapshot = await (0, import_firestore26.getDocs)(q);
|
|
8470
8750
|
const documents = [];
|
|
8471
8751
|
let lastVisible = null;
|
|
8472
|
-
querySnapshot.forEach((
|
|
8473
|
-
documents.push(
|
|
8474
|
-
lastVisible =
|
|
8752
|
+
querySnapshot.forEach((doc33) => {
|
|
8753
|
+
documents.push(doc33.data());
|
|
8754
|
+
lastVisible = doc33;
|
|
8475
8755
|
});
|
|
8476
8756
|
return {
|
|
8477
8757
|
documents,
|
|
8478
8758
|
lastDoc: lastVisible
|
|
8479
8759
|
};
|
|
8480
8760
|
}
|
|
8761
|
+
// IMPORTANT: The following methods that query across all patients/practitioners/clinics
|
|
8762
|
+
// (e.g., getFilledDocumentsByPatient, getFilledDocumentsByPractitioner)
|
|
8763
|
+
// will NOT work correctly if FILLED_DOCUMENTS_COLLECTION is no longer a top-level collection
|
|
8764
|
+
// and data is only in appointment subcollections. You would need to use
|
|
8765
|
+
// Firestore Collection Group Queries for that, which require an index and a different query approach.
|
|
8766
|
+
// These methods are left here for now but would need significant rework or removal.
|
|
8481
8767
|
/**
|
|
8482
|
-
* Get filled documents for a
|
|
8768
|
+
* Get filled documents for a patient (NEEDS REWORK for subcollections or Collection Group Query)
|
|
8769
|
+
* @param patientId - ID of the patient
|
|
8770
|
+
* @param pageSize - Number of documents to retrieve
|
|
8771
|
+
* @param lastDoc - Last document from previous page for pagination
|
|
8772
|
+
* @returns Array of filled documents and the last document for pagination
|
|
8773
|
+
*/
|
|
8774
|
+
async getFilledDocumentsByPatient(patientId, pageSize = 20, lastDoc) {
|
|
8775
|
+
console.warn(
|
|
8776
|
+
"getFilledDocumentsByPatient needs rework for subcollection model or Collection Group Queries."
|
|
8777
|
+
);
|
|
8778
|
+
return { documents: [], lastDoc: null };
|
|
8779
|
+
}
|
|
8780
|
+
/**
|
|
8781
|
+
* Get filled documents for a practitioner (NEEDS REWORK for subcollections or Collection Group Query)
|
|
8782
|
+
* @param practitionerId - ID of the practitioner
|
|
8783
|
+
* @param pageSize - Number of documents to retrieve
|
|
8784
|
+
* @param lastDoc - Last document from previous page for pagination
|
|
8785
|
+
* @returns Array of filled documents and the last document for pagination
|
|
8786
|
+
*/
|
|
8787
|
+
async getFilledDocumentsByPractitioner(practitionerId, pageSize = 20, lastDoc) {
|
|
8788
|
+
console.warn(
|
|
8789
|
+
"getFilledDocumentsByPractitioner needs rework for subcollection model or Collection Group Queries."
|
|
8790
|
+
);
|
|
8791
|
+
return { documents: [], lastDoc: null };
|
|
8792
|
+
}
|
|
8793
|
+
/**
|
|
8794
|
+
* Get filled documents for a clinic (NEEDS REWORK for subcollections or Collection Group Query)
|
|
8483
8795
|
* @param clinicId - ID of the clinic
|
|
8484
8796
|
* @param pageSize - Number of documents to retrieve
|
|
8485
8797
|
* @param lastDoc - Last document from previous page for pagination
|
|
8486
8798
|
* @returns Array of filled documents and the last document for pagination
|
|
8487
8799
|
*/
|
|
8488
8800
|
async getFilledDocumentsByClinic(clinicId, pageSize = 20, lastDoc) {
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
(0, import_firestore26.where)("clinicId", "==", clinicId),
|
|
8492
|
-
(0, import_firestore26.orderBy)("updatedAt", "desc"),
|
|
8493
|
-
(0, import_firestore26.limit)(pageSize)
|
|
8801
|
+
console.warn(
|
|
8802
|
+
"getFilledDocumentsByClinic needs rework for subcollection model or Collection Group Queries."
|
|
8494
8803
|
);
|
|
8495
|
-
|
|
8496
|
-
q = (0, import_firestore26.query)(q, (0, import_firestore26.startAfter)(lastDoc));
|
|
8497
|
-
}
|
|
8498
|
-
const querySnapshot = await (0, import_firestore26.getDocs)(q);
|
|
8499
|
-
const documents = [];
|
|
8500
|
-
let lastVisible = null;
|
|
8501
|
-
querySnapshot.forEach((doc32) => {
|
|
8502
|
-
documents.push(doc32.data());
|
|
8503
|
-
lastVisible = doc32;
|
|
8504
|
-
});
|
|
8505
|
-
return {
|
|
8506
|
-
documents,
|
|
8507
|
-
lastDoc: lastVisible
|
|
8508
|
-
};
|
|
8804
|
+
return { documents: [], lastDoc: null };
|
|
8509
8805
|
}
|
|
8510
8806
|
/**
|
|
8511
|
-
* Get filled documents by template
|
|
8807
|
+
* Get filled documents by template (NEEDS REWORK for subcollections or Collection Group Query)
|
|
8512
8808
|
* @param templateId - ID of the template
|
|
8513
8809
|
* @param pageSize - Number of documents to retrieve
|
|
8514
8810
|
* @param lastDoc - Last document from previous page for pagination
|
|
8515
8811
|
* @returns Array of filled documents and the last document for pagination
|
|
8516
8812
|
*/
|
|
8517
8813
|
async getFilledDocumentsByTemplate(templateId, pageSize = 20, lastDoc) {
|
|
8518
|
-
|
|
8519
|
-
|
|
8520
|
-
(0, import_firestore26.where)("templateId", "==", templateId),
|
|
8521
|
-
(0, import_firestore26.orderBy)("updatedAt", "desc"),
|
|
8522
|
-
(0, import_firestore26.limit)(pageSize)
|
|
8814
|
+
console.warn(
|
|
8815
|
+
"getFilledDocumentsByTemplate needs rework for subcollection model or Collection Group Queries."
|
|
8523
8816
|
);
|
|
8524
|
-
|
|
8525
|
-
q = (0, import_firestore26.query)(q, (0, import_firestore26.startAfter)(lastDoc));
|
|
8526
|
-
}
|
|
8527
|
-
const querySnapshot = await (0, import_firestore26.getDocs)(q);
|
|
8528
|
-
const documents = [];
|
|
8529
|
-
let lastVisible = null;
|
|
8530
|
-
querySnapshot.forEach((doc32) => {
|
|
8531
|
-
documents.push(doc32.data());
|
|
8532
|
-
lastVisible = doc32;
|
|
8533
|
-
});
|
|
8534
|
-
return {
|
|
8535
|
-
documents,
|
|
8536
|
-
lastDoc: lastVisible
|
|
8537
|
-
};
|
|
8817
|
+
return { documents: [], lastDoc: null };
|
|
8538
8818
|
}
|
|
8539
8819
|
/**
|
|
8540
|
-
* Get filled documents by status
|
|
8820
|
+
* Get filled documents by status (NEEDS REWORK for subcollections or Collection Group Query)
|
|
8541
8821
|
* @param status - Status to filter by
|
|
8542
8822
|
* @param pageSize - Number of documents to retrieve
|
|
8543
8823
|
* @param lastDoc - Last document from previous page for pagination
|
|
8544
8824
|
* @returns Array of filled documents and the last document for pagination
|
|
8545
8825
|
*/
|
|
8546
8826
|
async getFilledDocumentsByStatus(status, pageSize = 20, lastDoc) {
|
|
8547
|
-
|
|
8548
|
-
|
|
8549
|
-
(0, import_firestore26.where)("status", "==", status),
|
|
8550
|
-
(0, import_firestore26.orderBy)("updatedAt", "desc"),
|
|
8551
|
-
(0, import_firestore26.limit)(pageSize)
|
|
8827
|
+
console.warn(
|
|
8828
|
+
"getFilledDocumentsByStatus needs rework for subcollection model or Collection Group Queries."
|
|
8552
8829
|
);
|
|
8553
|
-
|
|
8554
|
-
q = (0, import_firestore26.query)(q, (0, import_firestore26.startAfter)(lastDoc));
|
|
8555
|
-
}
|
|
8556
|
-
const querySnapshot = await (0, import_firestore26.getDocs)(q);
|
|
8557
|
-
const documents = [];
|
|
8558
|
-
let lastVisible = null;
|
|
8559
|
-
querySnapshot.forEach((doc32) => {
|
|
8560
|
-
documents.push(doc32.data());
|
|
8561
|
-
lastVisible = doc32;
|
|
8562
|
-
});
|
|
8563
|
-
return {
|
|
8564
|
-
documents,
|
|
8565
|
-
lastDoc: lastVisible
|
|
8566
|
-
};
|
|
8830
|
+
return { documents: [], lastDoc: null };
|
|
8567
8831
|
}
|
|
8568
8832
|
};
|
|
8569
8833
|
|
|
@@ -9055,7 +9319,7 @@ async function searchCalendarEventsUtil(db, params) {
|
|
|
9055
9319
|
const finalQuery = (0, import_firestore33.query)(collectionRef, ...constraints);
|
|
9056
9320
|
const querySnapshot = await (0, import_firestore33.getDocs)(finalQuery);
|
|
9057
9321
|
const events = querySnapshot.docs.map(
|
|
9058
|
-
(
|
|
9322
|
+
(doc33) => ({ id: doc33.id, ...doc33.data() })
|
|
9059
9323
|
);
|
|
9060
9324
|
return events;
|
|
9061
9325
|
} catch (error) {
|
|
@@ -9137,7 +9401,7 @@ async function getPractitionerSyncedCalendarsUtil(db, practitionerId) {
|
|
|
9137
9401
|
);
|
|
9138
9402
|
const q = (0, import_firestore34.query)(calendarsRef, (0, import_firestore34.orderBy)("createdAt", "desc"));
|
|
9139
9403
|
const querySnapshot = await (0, import_firestore34.getDocs)(q);
|
|
9140
|
-
return querySnapshot.docs.map((
|
|
9404
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
9141
9405
|
}
|
|
9142
9406
|
async function getPatientSyncedCalendarUtil(db, patientId, calendarId) {
|
|
9143
9407
|
const calendarRef = getPatientSyncedCalendarDocRef(db, patientId, calendarId);
|
|
@@ -9154,7 +9418,7 @@ async function getPatientSyncedCalendarsUtil(db, patientId) {
|
|
|
9154
9418
|
);
|
|
9155
9419
|
const q = (0, import_firestore34.query)(calendarsRef, (0, import_firestore34.orderBy)("createdAt", "desc"));
|
|
9156
9420
|
const querySnapshot = await (0, import_firestore34.getDocs)(q);
|
|
9157
|
-
return querySnapshot.docs.map((
|
|
9421
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
9158
9422
|
}
|
|
9159
9423
|
async function getClinicSyncedCalendarUtil(db, clinicId, calendarId) {
|
|
9160
9424
|
const calendarRef = getClinicSyncedCalendarDocRef(db, clinicId, calendarId);
|
|
@@ -9171,7 +9435,7 @@ async function getClinicSyncedCalendarsUtil(db, clinicId) {
|
|
|
9171
9435
|
);
|
|
9172
9436
|
const q = (0, import_firestore34.query)(calendarsRef, (0, import_firestore34.orderBy)("createdAt", "desc"));
|
|
9173
9437
|
const querySnapshot = await (0, import_firestore34.getDocs)(q);
|
|
9174
|
-
return querySnapshot.docs.map((
|
|
9438
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
9175
9439
|
}
|
|
9176
9440
|
async function updatePractitionerSyncedCalendarUtil(db, practitionerId, calendarId, updateData) {
|
|
9177
9441
|
const calendarRef = getPractitionerSyncedCalendarDocRef(
|
|
@@ -10526,9 +10790,9 @@ var CalendarServiceV2 = class extends BaseService {
|
|
|
10526
10790
|
(0, import_firestore37.where)("eventTime.start", "<=", import_firestore36.Timestamp.fromDate(endDate))
|
|
10527
10791
|
);
|
|
10528
10792
|
const eventsSnapshot = await (0, import_firestore37.getDocs)(q);
|
|
10529
|
-
const events = eventsSnapshot.docs.map((
|
|
10530
|
-
id:
|
|
10531
|
-
...
|
|
10793
|
+
const events = eventsSnapshot.docs.map((doc33) => ({
|
|
10794
|
+
id: doc33.id,
|
|
10795
|
+
...doc33.data()
|
|
10532
10796
|
}));
|
|
10533
10797
|
const calendars = await this.syncedCalendarsService.getPractitionerSyncedCalendars(
|
|
10534
10798
|
doctorId
|
|
@@ -11160,7 +11424,7 @@ var CalendarServiceV2 = class extends BaseService {
|
|
|
11160
11424
|
])
|
|
11161
11425
|
);
|
|
11162
11426
|
const querySnapshot = await (0, import_firestore37.getDocs)(q);
|
|
11163
|
-
return querySnapshot.docs.map((
|
|
11427
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
11164
11428
|
}
|
|
11165
11429
|
/**
|
|
11166
11430
|
* Calculates available time slots based on working hours, schedule and existing appointments
|
|
@@ -11427,7 +11691,7 @@ var ReviewService = class extends BaseService {
|
|
|
11427
11691
|
(0, import_firestore38.where)("patientId", "==", patientId)
|
|
11428
11692
|
);
|
|
11429
11693
|
const snapshot = await (0, import_firestore38.getDocs)(q);
|
|
11430
|
-
return snapshot.docs.map((
|
|
11694
|
+
return snapshot.docs.map((doc33) => doc33.data());
|
|
11431
11695
|
}
|
|
11432
11696
|
/**
|
|
11433
11697
|
* Gets all reviews for a specific clinic
|
|
@@ -11440,7 +11704,7 @@ var ReviewService = class extends BaseService {
|
|
|
11440
11704
|
(0, import_firestore38.where)("clinicReview.clinicId", "==", clinicId)
|
|
11441
11705
|
);
|
|
11442
11706
|
const snapshot = await (0, import_firestore38.getDocs)(q);
|
|
11443
|
-
return snapshot.docs.map((
|
|
11707
|
+
return snapshot.docs.map((doc33) => doc33.data());
|
|
11444
11708
|
}
|
|
11445
11709
|
/**
|
|
11446
11710
|
* Gets all reviews for a specific practitioner
|
|
@@ -11453,7 +11717,7 @@ var ReviewService = class extends BaseService {
|
|
|
11453
11717
|
(0, import_firestore38.where)("practitionerReview.practitionerId", "==", practitionerId)
|
|
11454
11718
|
);
|
|
11455
11719
|
const snapshot = await (0, import_firestore38.getDocs)(q);
|
|
11456
|
-
return snapshot.docs.map((
|
|
11720
|
+
return snapshot.docs.map((doc33) => doc33.data());
|
|
11457
11721
|
}
|
|
11458
11722
|
/**
|
|
11459
11723
|
* Gets all reviews for a specific procedure
|
|
@@ -11466,7 +11730,7 @@ var ReviewService = class extends BaseService {
|
|
|
11466
11730
|
(0, import_firestore38.where)("procedureReview.procedureId", "==", procedureId)
|
|
11467
11731
|
);
|
|
11468
11732
|
const snapshot = await (0, import_firestore38.getDocs)(q);
|
|
11469
|
-
return snapshot.docs.map((
|
|
11733
|
+
return snapshot.docs.map((doc33) => doc33.data());
|
|
11470
11734
|
}
|
|
11471
11735
|
/**
|
|
11472
11736
|
* Gets all reviews for a specific appointment
|
|
@@ -11904,166 +12168,6 @@ var import_firestore39 = require("firebase/firestore");
|
|
|
11904
12168
|
var TECHNOLOGIES_COLLECTION = "technologies";
|
|
11905
12169
|
|
|
11906
12170
|
// src/services/appointment/utils/appointment.utils.ts
|
|
11907
|
-
async function fetchAggregatedInfoUtil(db, clinicId, practitionerId, patientId, procedureId) {
|
|
11908
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
|
|
11909
|
-
try {
|
|
11910
|
-
const [clinicDoc, practitionerDoc, patientDoc, procedureDoc] = await Promise.all([
|
|
11911
|
-
(0, import_firestore39.getDoc)((0, import_firestore39.doc)(db, CLINICS_COLLECTION, clinicId)),
|
|
11912
|
-
(0, import_firestore39.getDoc)((0, import_firestore39.doc)(db, PRACTITIONERS_COLLECTION, practitionerId)),
|
|
11913
|
-
(0, import_firestore39.getDoc)((0, import_firestore39.doc)(db, PATIENTS_COLLECTION, patientId)),
|
|
11914
|
-
(0, import_firestore39.getDoc)((0, import_firestore39.doc)(db, PROCEDURES_COLLECTION, procedureId))
|
|
11915
|
-
]);
|
|
11916
|
-
if (!clinicDoc.exists()) {
|
|
11917
|
-
throw new Error(`Clinic with ID ${clinicId} not found`);
|
|
11918
|
-
}
|
|
11919
|
-
if (!practitionerDoc.exists()) {
|
|
11920
|
-
throw new Error(`Practitioner with ID ${practitionerId} not found`);
|
|
11921
|
-
}
|
|
11922
|
-
if (!patientDoc.exists()) {
|
|
11923
|
-
throw new Error(`Patient with ID ${patientId} not found`);
|
|
11924
|
-
}
|
|
11925
|
-
if (!procedureDoc.exists()) {
|
|
11926
|
-
throw new Error(`Procedure with ID ${procedureId} not found`);
|
|
11927
|
-
}
|
|
11928
|
-
const clinicData = clinicDoc.data();
|
|
11929
|
-
const practitionerData = practitionerDoc.data();
|
|
11930
|
-
const patientData = patientDoc.data();
|
|
11931
|
-
const procedureData = procedureDoc.data();
|
|
11932
|
-
const clinicInfo = {
|
|
11933
|
-
id: clinicId,
|
|
11934
|
-
featuredPhoto: ((_a = clinicData.featuredPhotos) == null ? void 0 : _a[0]) || "",
|
|
11935
|
-
name: clinicData.name,
|
|
11936
|
-
description: clinicData.description || null,
|
|
11937
|
-
location: clinicData.location,
|
|
11938
|
-
contactInfo: clinicData.contactInfo
|
|
11939
|
-
};
|
|
11940
|
-
const practitionerInfo = {
|
|
11941
|
-
id: practitionerId,
|
|
11942
|
-
practitionerPhoto: ((_b = practitionerData.basicInfo) == null ? void 0 : _b.profileImageUrl) || null,
|
|
11943
|
-
name: `${((_c = practitionerData.basicInfo) == null ? void 0 : _c.firstName) || ""} ${((_d = practitionerData.basicInfo) == null ? void 0 : _d.lastName) || ""}`.trim(),
|
|
11944
|
-
email: ((_e = practitionerData.basicInfo) == null ? void 0 : _e.email) || "",
|
|
11945
|
-
phone: ((_f = practitionerData.basicInfo) == null ? void 0 : _f.phoneNumber) || null,
|
|
11946
|
-
certification: practitionerData.certification
|
|
11947
|
-
};
|
|
11948
|
-
const patientInfo = {
|
|
11949
|
-
id: patientId,
|
|
11950
|
-
fullName: patientData.displayName || "",
|
|
11951
|
-
email: patientData.email || "",
|
|
11952
|
-
phone: patientData.phoneNumber || null,
|
|
11953
|
-
dateOfBirth: patientData.dateOfBirth || import_firestore39.Timestamp.now(),
|
|
11954
|
-
gender: patientData.gender || "other"
|
|
11955
|
-
};
|
|
11956
|
-
const procedureInfo = {
|
|
11957
|
-
id: procedureId,
|
|
11958
|
-
name: procedureData.name,
|
|
11959
|
-
description: procedureData.description,
|
|
11960
|
-
photo: procedureData.photo || "",
|
|
11961
|
-
family: procedureData.family,
|
|
11962
|
-
categoryName: ((_g = procedureData.category) == null ? void 0 : _g.name) || "",
|
|
11963
|
-
subcategoryName: ((_h = procedureData.subcategory) == null ? void 0 : _h.name) || "",
|
|
11964
|
-
technologyName: ((_i = procedureData.technology) == null ? void 0 : _i.name) || "",
|
|
11965
|
-
brandName: ((_j = procedureData.product) == null ? void 0 : _j.brand) || "",
|
|
11966
|
-
productName: ((_k = procedureData.product) == null ? void 0 : _k.name) || "",
|
|
11967
|
-
price: procedureData.price || 0,
|
|
11968
|
-
pricingMeasure: procedureData.pricingMeasure,
|
|
11969
|
-
currency: procedureData.currency,
|
|
11970
|
-
duration: procedureData.duration || 0,
|
|
11971
|
-
clinicId,
|
|
11972
|
-
clinicName: clinicInfo.name,
|
|
11973
|
-
practitionerId,
|
|
11974
|
-
practitionerName: practitionerInfo.name
|
|
11975
|
-
};
|
|
11976
|
-
let technologyId = "";
|
|
11977
|
-
if ((_l = procedureData.technology) == null ? void 0 : _l.id) {
|
|
11978
|
-
technologyId = procedureData.technology.id;
|
|
11979
|
-
}
|
|
11980
|
-
let blockingConditions = [];
|
|
11981
|
-
let contraindications = [];
|
|
11982
|
-
let preProcedureRequirements = [];
|
|
11983
|
-
let postProcedureRequirements = [];
|
|
11984
|
-
if (technologyId) {
|
|
11985
|
-
const technologyDoc = await (0, import_firestore39.getDoc)(
|
|
11986
|
-
(0, import_firestore39.doc)(db, TECHNOLOGIES_COLLECTION, technologyId)
|
|
11987
|
-
);
|
|
11988
|
-
if (technologyDoc.exists()) {
|
|
11989
|
-
const technologyData = technologyDoc.data();
|
|
11990
|
-
blockingConditions = technologyData.blockingConditions || [];
|
|
11991
|
-
contraindications = technologyData.contraindications || [];
|
|
11992
|
-
preProcedureRequirements = ((_m = technologyData.requirements) == null ? void 0 : _m.pre) || [];
|
|
11993
|
-
postProcedureRequirements = ((_n = technologyData.requirements) == null ? void 0 : _n.post) || [];
|
|
11994
|
-
}
|
|
11995
|
-
} else {
|
|
11996
|
-
blockingConditions = procedureData.blockingConditions || [];
|
|
11997
|
-
contraindications = procedureData.contraindications || [];
|
|
11998
|
-
preProcedureRequirements = procedureData.preRequirements || [];
|
|
11999
|
-
postProcedureRequirements = procedureData.postRequirements || [];
|
|
12000
|
-
}
|
|
12001
|
-
return {
|
|
12002
|
-
clinicInfo,
|
|
12003
|
-
practitionerInfo,
|
|
12004
|
-
patientInfo,
|
|
12005
|
-
procedureInfo,
|
|
12006
|
-
blockingConditions,
|
|
12007
|
-
contraindications,
|
|
12008
|
-
preProcedureRequirements,
|
|
12009
|
-
postProcedureRequirements
|
|
12010
|
-
};
|
|
12011
|
-
} catch (error) {
|
|
12012
|
-
console.error("Error fetching aggregated info:", error);
|
|
12013
|
-
throw error;
|
|
12014
|
-
}
|
|
12015
|
-
}
|
|
12016
|
-
async function createAppointmentUtil2(db, data, aggregatedInfo, generateId2) {
|
|
12017
|
-
try {
|
|
12018
|
-
const appointmentId = generateId2();
|
|
12019
|
-
const appointment = {
|
|
12020
|
-
id: appointmentId,
|
|
12021
|
-
calendarEventId: data.calendarEventId,
|
|
12022
|
-
clinicBranchId: data.clinicBranchId,
|
|
12023
|
-
clinicInfo: aggregatedInfo.clinicInfo,
|
|
12024
|
-
practitionerId: data.practitionerId,
|
|
12025
|
-
practitionerInfo: aggregatedInfo.practitionerInfo,
|
|
12026
|
-
patientId: data.patientId,
|
|
12027
|
-
patientInfo: aggregatedInfo.patientInfo,
|
|
12028
|
-
procedureId: data.procedureId,
|
|
12029
|
-
procedureInfo: aggregatedInfo.procedureInfo,
|
|
12030
|
-
status: data.initialStatus,
|
|
12031
|
-
bookingTime: import_firestore39.Timestamp.now(),
|
|
12032
|
-
appointmentStartTime: data.appointmentStartTime,
|
|
12033
|
-
appointmentEndTime: data.appointmentEndTime,
|
|
12034
|
-
patientNotes: data.patientNotes || null,
|
|
12035
|
-
cost: data.cost,
|
|
12036
|
-
currency: data.currency,
|
|
12037
|
-
paymentStatus: data.initialPaymentStatus || "unpaid" /* UNPAID */,
|
|
12038
|
-
blockingConditions: aggregatedInfo.blockingConditions,
|
|
12039
|
-
contraindications: aggregatedInfo.contraindications,
|
|
12040
|
-
preProcedureRequirements: aggregatedInfo.preProcedureRequirements,
|
|
12041
|
-
postProcedureRequirements: aggregatedInfo.postProcedureRequirements,
|
|
12042
|
-
completedPreRequirements: [],
|
|
12043
|
-
completedPostRequirements: [],
|
|
12044
|
-
createdAt: (0, import_firestore39.serverTimestamp)(),
|
|
12045
|
-
updatedAt: (0, import_firestore39.serverTimestamp)()
|
|
12046
|
-
};
|
|
12047
|
-
if (data.initialStatus === "confirmed" /* CONFIRMED */) {
|
|
12048
|
-
appointment.confirmationTime = import_firestore39.Timestamp.now();
|
|
12049
|
-
}
|
|
12050
|
-
await (0, import_firestore39.setDoc)((0, import_firestore39.doc)(db, APPOINTMENTS_COLLECTION, appointmentId), appointment);
|
|
12051
|
-
const calendarEventRef = (0, import_firestore39.doc)(db, CALENDAR_COLLECTION, data.calendarEventId);
|
|
12052
|
-
await (0, import_firestore39.updateDoc)(calendarEventRef, {
|
|
12053
|
-
appointmentId,
|
|
12054
|
-
updatedAt: (0, import_firestore39.serverTimestamp)()
|
|
12055
|
-
});
|
|
12056
|
-
const now = import_firestore39.Timestamp.now();
|
|
12057
|
-
return {
|
|
12058
|
-
...appointment,
|
|
12059
|
-
createdAt: now,
|
|
12060
|
-
updatedAt: now
|
|
12061
|
-
};
|
|
12062
|
-
} catch (error) {
|
|
12063
|
-
console.error("Error creating appointment:", error);
|
|
12064
|
-
throw error;
|
|
12065
|
-
}
|
|
12066
|
-
}
|
|
12067
12171
|
async function updateAppointmentUtil2(db, appointmentId, data) {
|
|
12068
12172
|
try {
|
|
12069
12173
|
const appointmentRef = (0, import_firestore39.doc)(db, APPOINTMENTS_COLLECTION, appointmentId);
|
|
@@ -12165,7 +12269,7 @@ async function updateCalendarEventStatus(db, calendarEventId, appointmentStatus)
|
|
|
12165
12269
|
case "canceled_clinic" /* CANCELED_CLINIC */:
|
|
12166
12270
|
calendarStatus = "canceled";
|
|
12167
12271
|
break;
|
|
12168
|
-
case
|
|
12272
|
+
case AppointmentStatus.RESCHEDULED:
|
|
12169
12273
|
calendarStatus = "rescheduled";
|
|
12170
12274
|
break;
|
|
12171
12275
|
case "completed" /* COMPLETED */:
|
|
@@ -12239,7 +12343,7 @@ async function searchAppointmentsUtil(db, params) {
|
|
|
12239
12343
|
const q = (0, import_firestore39.query)((0, import_firestore39.collection)(db, APPOINTMENTS_COLLECTION), ...constraints);
|
|
12240
12344
|
const querySnapshot = await (0, import_firestore39.getDocs)(q);
|
|
12241
12345
|
const appointments = querySnapshot.docs.map(
|
|
12242
|
-
(
|
|
12346
|
+
(doc33) => doc33.data()
|
|
12243
12347
|
);
|
|
12244
12348
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
12245
12349
|
return { appointments, lastDoc };
|
|
@@ -12262,86 +12366,15 @@ var AppointmentService = class extends BaseService {
|
|
|
12262
12366
|
* @param practitionerService Practitioner service instance
|
|
12263
12367
|
* @param clinicService Clinic service instance
|
|
12264
12368
|
*/
|
|
12265
|
-
constructor(db, auth, app, calendarService, patientService, practitionerService, clinicService) {
|
|
12369
|
+
constructor(db, auth, app, calendarService, patientService, practitionerService, clinicService, filledDocumentService) {
|
|
12266
12370
|
super(db, auth, app);
|
|
12267
12371
|
this.calendarService = calendarService;
|
|
12268
12372
|
this.patientService = patientService;
|
|
12269
12373
|
this.practitionerService = practitionerService;
|
|
12270
12374
|
this.clinicService = clinicService;
|
|
12375
|
+
this.filledDocumentService = filledDocumentService;
|
|
12271
12376
|
this.functions = (0, import_functions.getFunctions)(app, "europe-west6");
|
|
12272
12377
|
}
|
|
12273
|
-
/**
|
|
12274
|
-
* Test method using the callable function version of getAvailableBookingSlots
|
|
12275
|
-
* For development and testing purposes only - not for production use
|
|
12276
|
-
*
|
|
12277
|
-
* @param clinicId ID of the clinic
|
|
12278
|
-
* @param practitionerId ID of the practitioner
|
|
12279
|
-
* @param procedureId ID of the procedure
|
|
12280
|
-
* @param startDate Start date of the time range to check
|
|
12281
|
-
* @param endDate End date of the time range to check
|
|
12282
|
-
* @returns Test result from the callable function
|
|
12283
|
-
*/
|
|
12284
|
-
async testGetAvailableBookingSlots(clinicId, practitionerId, procedureId, startDate, endDate) {
|
|
12285
|
-
try {
|
|
12286
|
-
console.log(
|
|
12287
|
-
`[APPOINTMENT_SERVICE] Testing callable function for clinic: ${clinicId}, practitioner: ${practitionerId}, procedure: ${procedureId}`
|
|
12288
|
-
);
|
|
12289
|
-
const getAvailableBookingSlotsCallable = (0, import_functions.httpsCallable)(
|
|
12290
|
-
this.functions,
|
|
12291
|
-
"getAvailableBookingSlots"
|
|
12292
|
-
);
|
|
12293
|
-
const result = await getAvailableBookingSlotsCallable({
|
|
12294
|
-
clinicId,
|
|
12295
|
-
practitionerId,
|
|
12296
|
-
procedureId,
|
|
12297
|
-
timeframe: {
|
|
12298
|
-
start: startDate.getTime(),
|
|
12299
|
-
end: endDate.getTime()
|
|
12300
|
-
}
|
|
12301
|
-
});
|
|
12302
|
-
console.log(
|
|
12303
|
-
"[APPOINTMENT_SERVICE] Callable function test result:",
|
|
12304
|
-
result.data
|
|
12305
|
-
);
|
|
12306
|
-
return result.data;
|
|
12307
|
-
} catch (error) {
|
|
12308
|
-
console.error(
|
|
12309
|
-
"[APPOINTMENT_SERVICE] Error testing callable function:",
|
|
12310
|
-
error
|
|
12311
|
-
);
|
|
12312
|
-
throw error;
|
|
12313
|
-
}
|
|
12314
|
-
}
|
|
12315
|
-
/**
|
|
12316
|
-
* Gets available booking slots for a specific clinic, practitioner, and procedure.
|
|
12317
|
-
*
|
|
12318
|
-
* @param clinicId ID of the clinic
|
|
12319
|
-
* @param practitionerId ID of the practitioner
|
|
12320
|
-
* @param procedureId ID of the procedure
|
|
12321
|
-
* @param startDate Start date of the time range to check
|
|
12322
|
-
* @param endDate End date of the time range to check
|
|
12323
|
-
* @returns Array of available booking slots
|
|
12324
|
-
*/
|
|
12325
|
-
async getAvailableBookingSlots(clinicId, practitionerId, procedureId, startDate, endDate) {
|
|
12326
|
-
try {
|
|
12327
|
-
console.log(
|
|
12328
|
-
`[APPOINTMENT_SERVICE] Getting available booking slots for clinic: ${clinicId}, practitioner: ${practitionerId}, procedure: ${procedureId}`
|
|
12329
|
-
);
|
|
12330
|
-
return this.getAvailableBookingSlotsHttp(
|
|
12331
|
-
clinicId,
|
|
12332
|
-
practitionerId,
|
|
12333
|
-
procedureId,
|
|
12334
|
-
startDate,
|
|
12335
|
-
endDate
|
|
12336
|
-
);
|
|
12337
|
-
} catch (error) {
|
|
12338
|
-
console.error(
|
|
12339
|
-
"[APPOINTMENT_SERVICE] Error getting available booking slots:",
|
|
12340
|
-
error
|
|
12341
|
-
);
|
|
12342
|
-
throw error;
|
|
12343
|
-
}
|
|
12344
|
-
}
|
|
12345
12378
|
/**
|
|
12346
12379
|
* Gets available booking slots for a specific clinic, practitioner, and procedure using HTTP request.
|
|
12347
12380
|
* This is an alternative implementation using direct HTTP request instead of callable function.
|
|
@@ -12443,34 +12476,81 @@ var AppointmentService = class extends BaseService {
|
|
|
12443
12476
|
}
|
|
12444
12477
|
}
|
|
12445
12478
|
/**
|
|
12446
|
-
* Creates
|
|
12479
|
+
* Creates an appointment via the Cloud Function orchestrateAppointmentCreation
|
|
12447
12480
|
*
|
|
12448
|
-
* @param data
|
|
12481
|
+
* @param data - CreateAppointmentData object
|
|
12449
12482
|
* @returns The created appointment
|
|
12450
12483
|
*/
|
|
12451
|
-
async
|
|
12484
|
+
async createAppointmentHttp(data) {
|
|
12452
12485
|
try {
|
|
12453
|
-
console.log(
|
|
12454
|
-
|
|
12455
|
-
const aggregatedInfo = await fetchAggregatedInfoUtil(
|
|
12456
|
-
this.db,
|
|
12457
|
-
validatedData.clinicBranchId,
|
|
12458
|
-
validatedData.practitionerId,
|
|
12459
|
-
validatedData.patientId,
|
|
12460
|
-
validatedData.procedureId
|
|
12486
|
+
console.log(
|
|
12487
|
+
"[APPOINTMENT_SERVICE] Creating appointment via cloud function"
|
|
12461
12488
|
);
|
|
12462
|
-
const
|
|
12463
|
-
|
|
12464
|
-
|
|
12465
|
-
|
|
12466
|
-
|
|
12489
|
+
const currentUser = this.auth.currentUser;
|
|
12490
|
+
if (!currentUser) {
|
|
12491
|
+
throw new Error("User must be authenticated to create an appointment");
|
|
12492
|
+
}
|
|
12493
|
+
const idToken = await currentUser.getIdToken();
|
|
12494
|
+
const functionUrl = `https://europe-west6-metaestetics.cloudfunctions.net/bookingApi/orchestrateAppointmentCreation`;
|
|
12495
|
+
const requestData = {
|
|
12496
|
+
patientId: data.patientId,
|
|
12497
|
+
procedureId: data.procedureId,
|
|
12498
|
+
appointmentStartTime: data.appointmentStartTime.toMillis ? data.appointmentStartTime.toMillis() : new Date(data.appointmentStartTime).getTime(),
|
|
12499
|
+
appointmentEndTime: data.appointmentEndTime.toMillis ? data.appointmentEndTime.toMillis() : new Date(data.appointmentEndTime).getTime(),
|
|
12500
|
+
patientNotes: data.patientNotes || null
|
|
12501
|
+
};
|
|
12502
|
+
console.log(
|
|
12503
|
+
`[APPOINTMENT_SERVICE] Making fetch request to ${functionUrl}`
|
|
12467
12504
|
);
|
|
12505
|
+
const response = await fetch(functionUrl, {
|
|
12506
|
+
method: "POST",
|
|
12507
|
+
mode: "cors",
|
|
12508
|
+
cache: "no-cache",
|
|
12509
|
+
credentials: "omit",
|
|
12510
|
+
headers: {
|
|
12511
|
+
"Content-Type": "application/json",
|
|
12512
|
+
Authorization: `Bearer ${idToken}`
|
|
12513
|
+
},
|
|
12514
|
+
redirect: "follow",
|
|
12515
|
+
referrerPolicy: "no-referrer",
|
|
12516
|
+
body: JSON.stringify(requestData)
|
|
12517
|
+
});
|
|
12468
12518
|
console.log(
|
|
12469
|
-
`[APPOINTMENT_SERVICE]
|
|
12519
|
+
`[APPOINTMENT_SERVICE] Received response ${response.status}: ${response.statusText}`
|
|
12470
12520
|
);
|
|
12471
|
-
|
|
12521
|
+
if (!response.ok) {
|
|
12522
|
+
const errorText = await response.text();
|
|
12523
|
+
console.error(
|
|
12524
|
+
`[APPOINTMENT_SERVICE] Error response details: ${errorText}`
|
|
12525
|
+
);
|
|
12526
|
+
throw new Error(
|
|
12527
|
+
`Failed to create appointment: ${response.status} ${response.statusText} - ${errorText}`
|
|
12528
|
+
);
|
|
12529
|
+
}
|
|
12530
|
+
const result = await response.json();
|
|
12531
|
+
if (!result.success) {
|
|
12532
|
+
throw new Error(result.error || "Failed to create appointment");
|
|
12533
|
+
}
|
|
12534
|
+
if (result.appointmentData) {
|
|
12535
|
+
console.log(
|
|
12536
|
+
`[APPOINTMENT_SERVICE] Appointment created with ID: ${result.appointmentId}`
|
|
12537
|
+
);
|
|
12538
|
+
return result.appointmentData;
|
|
12539
|
+
}
|
|
12540
|
+
const createdAppointment = await this.getAppointmentById(
|
|
12541
|
+
result.appointmentId
|
|
12542
|
+
);
|
|
12543
|
+
if (!createdAppointment) {
|
|
12544
|
+
throw new Error(
|
|
12545
|
+
`Failed to retrieve created appointment with ID: ${result.appointmentId}`
|
|
12546
|
+
);
|
|
12547
|
+
}
|
|
12548
|
+
return createdAppointment;
|
|
12472
12549
|
} catch (error) {
|
|
12473
|
-
console.error(
|
|
12550
|
+
console.error(
|
|
12551
|
+
"[APPOINTMENT_SERVICE] Error creating appointment via cloud function:",
|
|
12552
|
+
error
|
|
12553
|
+
);
|
|
12474
12554
|
throw error;
|
|
12475
12555
|
}
|
|
12476
12556
|
}
|
|
@@ -12623,192 +12703,340 @@ var AppointmentService = class extends BaseService {
|
|
|
12623
12703
|
*
|
|
12624
12704
|
* @param appointmentId ID of the appointment
|
|
12625
12705
|
* @param newStatus New status to set
|
|
12626
|
-
* @param
|
|
12627
|
-
* @param canceledBy Required if canceling the appointment
|
|
12706
|
+
* @param details Optional details for the status change
|
|
12628
12707
|
* @returns The updated appointment
|
|
12629
12708
|
*/
|
|
12630
|
-
async updateAppointmentStatus(appointmentId, newStatus,
|
|
12709
|
+
async updateAppointmentStatus(appointmentId, newStatus, details) {
|
|
12631
12710
|
console.log(
|
|
12632
12711
|
`[APPOINTMENT_SERVICE] Updating status of appointment ${appointmentId} to ${newStatus}`
|
|
12633
12712
|
);
|
|
12634
|
-
const updateData = {
|
|
12635
|
-
|
|
12636
|
-
|
|
12637
|
-
|
|
12638
|
-
|
|
12639
|
-
|
|
12713
|
+
const updateData = {
|
|
12714
|
+
status: newStatus,
|
|
12715
|
+
updatedAt: (0, import_firestore40.serverTimestamp)()
|
|
12716
|
+
};
|
|
12717
|
+
if (newStatus === "canceled_clinic" /* CANCELED_CLINIC */ || newStatus === "canceled_patient" /* CANCELED_PATIENT */ || newStatus === "canceled_patient_rescheduled" /* CANCELED_PATIENT_RESCHEDULED */) {
|
|
12718
|
+
if (!(details == null ? void 0 : details.cancellationReason)) {
|
|
12719
|
+
throw new Error("Cancellation reason is required when canceling.");
|
|
12640
12720
|
}
|
|
12641
|
-
if (!canceledBy) {
|
|
12642
|
-
throw new Error(
|
|
12643
|
-
"Canceled by is required when canceling an appointment"
|
|
12644
|
-
);
|
|
12721
|
+
if (!(details == null ? void 0 : details.canceledBy)) {
|
|
12722
|
+
throw new Error("Canceled by is required when canceling.");
|
|
12645
12723
|
}
|
|
12646
|
-
updateData.cancellationReason = cancellationReason;
|
|
12647
|
-
updateData.canceledBy = canceledBy;
|
|
12724
|
+
updateData.cancellationReason = details.cancellationReason;
|
|
12725
|
+
updateData.canceledBy = details.canceledBy;
|
|
12726
|
+
updateData.cancellationTime = import_firestore40.Timestamp.now();
|
|
12648
12727
|
}
|
|
12649
12728
|
if (newStatus === "confirmed" /* CONFIRMED */) {
|
|
12650
12729
|
updateData.confirmationTime = import_firestore40.Timestamp.now();
|
|
12651
12730
|
}
|
|
12731
|
+
if (newStatus === "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
|
|
12732
|
+
updateData.rescheduleTime = import_firestore40.Timestamp.now();
|
|
12733
|
+
}
|
|
12652
12734
|
return this.updateAppointment(appointmentId, updateData);
|
|
12653
12735
|
}
|
|
12654
12736
|
/**
|
|
12655
|
-
* Confirms an
|
|
12656
|
-
*
|
|
12657
|
-
* @param appointmentId ID of the appointment to confirm
|
|
12658
|
-
* @returns The confirmed appointment
|
|
12737
|
+
* Confirms a PENDING appointment by an Admin/Clinic.
|
|
12659
12738
|
*/
|
|
12660
|
-
async
|
|
12739
|
+
async confirmAppointmentAdmin(appointmentId) {
|
|
12661
12740
|
console.log(
|
|
12662
|
-
`[APPOINTMENT_SERVICE]
|
|
12741
|
+
`[APPOINTMENT_SERVICE] Admin confirming appointment: ${appointmentId}`
|
|
12663
12742
|
);
|
|
12743
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
12744
|
+
if (!appointment)
|
|
12745
|
+
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
12746
|
+
if (appointment.status !== "pending" /* PENDING */) {
|
|
12747
|
+
throw new Error(
|
|
12748
|
+
`Appointment ${appointmentId} is not in PENDING state to be confirmed.`
|
|
12749
|
+
);
|
|
12750
|
+
}
|
|
12664
12751
|
return this.updateAppointmentStatus(
|
|
12665
12752
|
appointmentId,
|
|
12666
12753
|
"confirmed" /* CONFIRMED */
|
|
12667
12754
|
);
|
|
12668
12755
|
}
|
|
12669
12756
|
/**
|
|
12670
|
-
* Cancels an appointment
|
|
12671
|
-
|
|
12672
|
-
|
|
12673
|
-
|
|
12674
|
-
|
|
12757
|
+
* Cancels an appointment by the User (Patient).
|
|
12758
|
+
*/
|
|
12759
|
+
async cancelAppointmentUser(appointmentId, reason) {
|
|
12760
|
+
console.log(
|
|
12761
|
+
`[APPOINTMENT_SERVICE] User canceling appointment: ${appointmentId}`
|
|
12762
|
+
);
|
|
12763
|
+
return this.updateAppointmentStatus(
|
|
12764
|
+
appointmentId,
|
|
12765
|
+
"canceled_patient" /* CANCELED_PATIENT */,
|
|
12766
|
+
{
|
|
12767
|
+
cancellationReason: reason,
|
|
12768
|
+
canceledBy: "patient"
|
|
12769
|
+
}
|
|
12770
|
+
);
|
|
12771
|
+
}
|
|
12772
|
+
/**
|
|
12773
|
+
* Cancels an appointment by an Admin/Clinic.
|
|
12675
12774
|
*/
|
|
12676
|
-
async
|
|
12775
|
+
async cancelAppointmentAdmin(appointmentId, reason) {
|
|
12677
12776
|
console.log(
|
|
12678
|
-
`[APPOINTMENT_SERVICE]
|
|
12777
|
+
`[APPOINTMENT_SERVICE] Admin canceling appointment: ${appointmentId}`
|
|
12679
12778
|
);
|
|
12680
12779
|
return this.updateAppointmentStatus(
|
|
12681
12780
|
appointmentId,
|
|
12682
12781
|
"canceled_clinic" /* CANCELED_CLINIC */,
|
|
12683
|
-
|
|
12684
|
-
|
|
12782
|
+
{
|
|
12783
|
+
cancellationReason: reason,
|
|
12784
|
+
canceledBy: "clinic"
|
|
12785
|
+
}
|
|
12685
12786
|
);
|
|
12686
12787
|
}
|
|
12687
12788
|
/**
|
|
12688
|
-
*
|
|
12689
|
-
*
|
|
12690
|
-
|
|
12691
|
-
|
|
12692
|
-
|
|
12789
|
+
* Admin proposes to reschedule an appointment.
|
|
12790
|
+
* Sets status to RESCHEDULED_BY_CLINIC and updates times.
|
|
12791
|
+
*/
|
|
12792
|
+
async rescheduleAppointmentAdmin(appointmentId, newStartTime, newEndTime) {
|
|
12793
|
+
console.log(
|
|
12794
|
+
`[APPOINTMENT_SERVICE] Admin rescheduling appointment: ${appointmentId}`
|
|
12795
|
+
);
|
|
12796
|
+
if (newEndTime.toMillis() <= newStartTime.toMillis()) {
|
|
12797
|
+
throw new Error("New end time must be after new start time.");
|
|
12798
|
+
}
|
|
12799
|
+
const updateData = {
|
|
12800
|
+
status: "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */,
|
|
12801
|
+
appointmentStartTime: newStartTime,
|
|
12802
|
+
appointmentEndTime: newEndTime,
|
|
12803
|
+
rescheduleTime: import_firestore40.Timestamp.now(),
|
|
12804
|
+
confirmationTime: null,
|
|
12805
|
+
updatedAt: (0, import_firestore40.serverTimestamp)()
|
|
12806
|
+
};
|
|
12807
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
12808
|
+
}
|
|
12809
|
+
/**
|
|
12810
|
+
* User confirms a reschedule proposed by the clinic.
|
|
12811
|
+
* Status changes from RESCHEDULED_BY_CLINIC to CONFIRMED.
|
|
12693
12812
|
*/
|
|
12694
|
-
async
|
|
12813
|
+
async rescheduleAppointmentConfirmUser(appointmentId) {
|
|
12695
12814
|
console.log(
|
|
12696
|
-
`[APPOINTMENT_SERVICE]
|
|
12815
|
+
`[APPOINTMENT_SERVICE] User confirming reschedule for: ${appointmentId}`
|
|
12697
12816
|
);
|
|
12817
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
12818
|
+
if (!appointment)
|
|
12819
|
+
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
12820
|
+
if (appointment.status !== "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
|
|
12821
|
+
throw new Error(
|
|
12822
|
+
`Appointment ${appointmentId} is not in RESCHEDULED_BY_CLINIC state.`
|
|
12823
|
+
);
|
|
12824
|
+
}
|
|
12698
12825
|
return this.updateAppointmentStatus(
|
|
12699
12826
|
appointmentId,
|
|
12700
|
-
"
|
|
12701
|
-
reason,
|
|
12702
|
-
"patient"
|
|
12827
|
+
"confirmed" /* CONFIRMED */
|
|
12703
12828
|
);
|
|
12704
12829
|
}
|
|
12705
12830
|
/**
|
|
12706
|
-
*
|
|
12707
|
-
*
|
|
12708
|
-
* @param appointmentId ID of the appointment
|
|
12709
|
-
* @returns The updated appointment
|
|
12831
|
+
* User rejects a reschedule proposed by the clinic.
|
|
12832
|
+
* Status changes from RESCHEDULED_BY_CLINIC to CANCELED_PATIENT_RESCHEDULED.
|
|
12710
12833
|
*/
|
|
12711
|
-
async
|
|
12834
|
+
async rescheduleAppointmentRejectUser(appointmentId, reason) {
|
|
12712
12835
|
console.log(
|
|
12713
|
-
`[APPOINTMENT_SERVICE]
|
|
12836
|
+
`[APPOINTMENT_SERVICE] User rejecting reschedule for: ${appointmentId}`
|
|
12714
12837
|
);
|
|
12838
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
12839
|
+
if (!appointment)
|
|
12840
|
+
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
12841
|
+
if (appointment.status !== "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
|
|
12842
|
+
throw new Error(
|
|
12843
|
+
`Appointment ${appointmentId} is not in RESCHEDULED_BY_CLINIC state.`
|
|
12844
|
+
);
|
|
12845
|
+
}
|
|
12715
12846
|
return this.updateAppointmentStatus(
|
|
12716
12847
|
appointmentId,
|
|
12717
|
-
"
|
|
12848
|
+
"canceled_patient_rescheduled" /* CANCELED_PATIENT_RESCHEDULED */,
|
|
12849
|
+
{
|
|
12850
|
+
cancellationReason: reason,
|
|
12851
|
+
canceledBy: "patient"
|
|
12852
|
+
}
|
|
12718
12853
|
);
|
|
12719
12854
|
}
|
|
12720
12855
|
/**
|
|
12721
|
-
*
|
|
12722
|
-
*
|
|
12723
|
-
* @param appointmentId ID of the appointment
|
|
12724
|
-
* @returns The updated appointment
|
|
12856
|
+
* Admin checks in a patient for their appointment.
|
|
12857
|
+
* Requires all pending user forms to be completed.
|
|
12725
12858
|
*/
|
|
12726
|
-
async
|
|
12727
|
-
console.log(
|
|
12859
|
+
async checkInPatientAdmin(appointmentId) {
|
|
12860
|
+
console.log(
|
|
12861
|
+
`[APPOINTMENT_SERVICE] Admin checking in patient for: ${appointmentId}`
|
|
12862
|
+
);
|
|
12863
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
12864
|
+
if (!appointment)
|
|
12865
|
+
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
12866
|
+
if (appointment.pendingUserFormsIds && appointment.pendingUserFormsIds.length > 0) {
|
|
12867
|
+
throw new Error(
|
|
12868
|
+
`Cannot check in: Patient has ${appointment.pendingUserFormsIds.length} pending required form(s). IDs: ${appointment.pendingUserFormsIds.join(
|
|
12869
|
+
", "
|
|
12870
|
+
)}`
|
|
12871
|
+
);
|
|
12872
|
+
}
|
|
12873
|
+
if (appointment.status !== "confirmed" /* CONFIRMED */ && appointment.status !== "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
|
|
12874
|
+
console.warn(
|
|
12875
|
+
`Checking in appointment ${appointmentId} with status ${appointment.status}. Ensure this is intended.`
|
|
12876
|
+
);
|
|
12877
|
+
}
|
|
12728
12878
|
return this.updateAppointmentStatus(
|
|
12729
12879
|
appointmentId,
|
|
12730
|
-
"
|
|
12880
|
+
"checked_in" /* CHECKED_IN */
|
|
12731
12881
|
);
|
|
12732
12882
|
}
|
|
12733
12883
|
/**
|
|
12734
|
-
*
|
|
12735
|
-
*
|
|
12736
|
-
* @param appointmentId ID of the appointment
|
|
12737
|
-
* @param actualDurationMinutes Actual duration of the appointment in minutes
|
|
12738
|
-
* @returns The updated appointment
|
|
12884
|
+
* Doctor starts the appointment procedure.
|
|
12739
12885
|
*/
|
|
12740
|
-
async
|
|
12886
|
+
async startAppointmentDoctor(appointmentId) {
|
|
12741
12887
|
console.log(
|
|
12742
|
-
`[APPOINTMENT_SERVICE]
|
|
12888
|
+
`[APPOINTMENT_SERVICE] Doctor starting appointment: ${appointmentId}`
|
|
12743
12889
|
);
|
|
12890
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
12891
|
+
if (!appointment)
|
|
12892
|
+
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
12893
|
+
if (appointment.status !== "checked_in" /* CHECKED_IN */) {
|
|
12894
|
+
throw new Error(
|
|
12895
|
+
`Appointment ${appointmentId} must be CHECKED_IN to start.`
|
|
12896
|
+
);
|
|
12897
|
+
}
|
|
12898
|
+
const updateData = {
|
|
12899
|
+
status: "in_progress" /* IN_PROGRESS */,
|
|
12900
|
+
procedureActualStartTime: import_firestore40.Timestamp.now(),
|
|
12901
|
+
// Set actual start time
|
|
12902
|
+
updatedAt: (0, import_firestore40.serverTimestamp)()
|
|
12903
|
+
};
|
|
12904
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
12905
|
+
}
|
|
12906
|
+
/**
|
|
12907
|
+
* Doctor completes and finalizes the appointment.
|
|
12908
|
+
*/
|
|
12909
|
+
async completeAppointmentDoctor(appointmentId, finalizationNotes, actualDurationMinutesInput) {
|
|
12910
|
+
console.log(
|
|
12911
|
+
`[APPOINTMENT_SERVICE] Doctor completing appointment: ${appointmentId}`
|
|
12912
|
+
);
|
|
12913
|
+
const currentUser = this.auth.currentUser;
|
|
12914
|
+
if (!currentUser)
|
|
12915
|
+
throw new Error("Authentication required to complete appointment.");
|
|
12916
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
12917
|
+
if (!appointment)
|
|
12918
|
+
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
12919
|
+
let calculatedDurationMinutes = actualDurationMinutesInput;
|
|
12920
|
+
const procedureCompletionTime = import_firestore40.Timestamp.now();
|
|
12921
|
+
if (calculatedDurationMinutes === void 0 && appointment.procedureActualStartTime) {
|
|
12922
|
+
const startTimeMillis = appointment.procedureActualStartTime.toMillis();
|
|
12923
|
+
const endTimeMillis = procedureCompletionTime.toMillis();
|
|
12924
|
+
if (endTimeMillis > startTimeMillis) {
|
|
12925
|
+
calculatedDurationMinutes = Math.round(
|
|
12926
|
+
(endTimeMillis - startTimeMillis) / 6e4
|
|
12927
|
+
);
|
|
12928
|
+
}
|
|
12929
|
+
}
|
|
12744
12930
|
const updateData = {
|
|
12745
12931
|
status: "completed" /* COMPLETED */,
|
|
12746
|
-
actualDurationMinutes
|
|
12932
|
+
actualDurationMinutes: calculatedDurationMinutes,
|
|
12933
|
+
// Use calculated or provided duration
|
|
12934
|
+
finalizedDetails: {
|
|
12935
|
+
by: currentUser.uid,
|
|
12936
|
+
// This is used ID, not practitioner's profile ID (just so we know who completed the appointment)
|
|
12937
|
+
at: procedureCompletionTime,
|
|
12938
|
+
// Use consistent completion timestamp
|
|
12939
|
+
notes: finalizationNotes
|
|
12940
|
+
},
|
|
12941
|
+
// Optionally update appointmentEndTime to the actual completion time
|
|
12942
|
+
// appointmentEndTime: procedureCompletionTime,
|
|
12943
|
+
updatedAt: (0, import_firestore40.serverTimestamp)()
|
|
12747
12944
|
};
|
|
12748
12945
|
return this.updateAppointment(appointmentId, updateData);
|
|
12749
12946
|
}
|
|
12750
12947
|
/**
|
|
12751
|
-
*
|
|
12752
|
-
*
|
|
12753
|
-
* @param appointmentId ID of the appointment
|
|
12754
|
-
* @returns The updated appointment
|
|
12948
|
+
* Admin marks an appointment as No-Show.
|
|
12755
12949
|
*/
|
|
12756
|
-
async
|
|
12950
|
+
async markNoShowAdmin(appointmentId) {
|
|
12757
12951
|
console.log(
|
|
12758
|
-
`[APPOINTMENT_SERVICE]
|
|
12952
|
+
`[APPOINTMENT_SERVICE] Admin marking no-show for: ${appointmentId}`
|
|
12759
12953
|
);
|
|
12954
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
12955
|
+
if (!appointment)
|
|
12956
|
+
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
12957
|
+
if (import_firestore40.Timestamp.now().toMillis() < appointment.appointmentStartTime.toMillis()) {
|
|
12958
|
+
throw new Error("Cannot mark no-show before appointment start time.");
|
|
12959
|
+
}
|
|
12760
12960
|
return this.updateAppointmentStatus(
|
|
12761
12961
|
appointmentId,
|
|
12762
|
-
"no_show" /* NO_SHOW
|
|
12962
|
+
"no_show" /* NO_SHOW */,
|
|
12963
|
+
{
|
|
12964
|
+
cancellationReason: "Patient did not show up for the appointment.",
|
|
12965
|
+
canceledBy: "clinic"
|
|
12966
|
+
}
|
|
12763
12967
|
);
|
|
12764
12968
|
}
|
|
12765
12969
|
/**
|
|
12766
|
-
*
|
|
12767
|
-
*
|
|
12768
|
-
* @param appointmentId ID of the appointment
|
|
12769
|
-
* @param paymentStatus New payment status
|
|
12770
|
-
* @param paymentTransactionId Optional transaction ID for the payment
|
|
12771
|
-
* @returns The updated appointment
|
|
12970
|
+
* Adds a media item to an appointment.
|
|
12772
12971
|
*/
|
|
12773
|
-
async
|
|
12972
|
+
async addMediaToAppointment(appointmentId, mediaItemData) {
|
|
12774
12973
|
console.log(
|
|
12775
|
-
`[APPOINTMENT_SERVICE]
|
|
12974
|
+
`[APPOINTMENT_SERVICE] Adding media to appointment ${appointmentId}`
|
|
12975
|
+
);
|
|
12976
|
+
const currentUser = this.auth.currentUser;
|
|
12977
|
+
if (!currentUser) throw new Error("Authentication required.");
|
|
12978
|
+
const newMediaItem = {
|
|
12979
|
+
...mediaItemData,
|
|
12980
|
+
id: this.generateId(),
|
|
12981
|
+
uploadedAt: import_firestore40.Timestamp.now(),
|
|
12982
|
+
uploadedBy: currentUser.uid
|
|
12983
|
+
};
|
|
12984
|
+
const updateData = {
|
|
12985
|
+
media: (0, import_firestore40.arrayUnion)(newMediaItem),
|
|
12986
|
+
updatedAt: (0, import_firestore40.serverTimestamp)()
|
|
12987
|
+
};
|
|
12988
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
12989
|
+
}
|
|
12990
|
+
/**
|
|
12991
|
+
* Removes a media item from an appointment.
|
|
12992
|
+
*/
|
|
12993
|
+
async removeMediaFromAppointment(appointmentId, mediaItemId) {
|
|
12994
|
+
console.log(
|
|
12995
|
+
`[APPOINTMENT_SERVICE] Removing media ${mediaItemId} from appointment ${appointmentId}`
|
|
12776
12996
|
);
|
|
12997
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
12998
|
+
if (!appointment || !appointment.media) {
|
|
12999
|
+
throw new Error("Appointment or media list not found.");
|
|
13000
|
+
}
|
|
13001
|
+
const mediaToRemove = appointment.media.find((m) => m.id === mediaItemId);
|
|
13002
|
+
if (!mediaToRemove) {
|
|
13003
|
+
throw new Error(`Media item ${mediaItemId} not found in appointment.`);
|
|
13004
|
+
}
|
|
12777
13005
|
const updateData = {
|
|
12778
|
-
|
|
12779
|
-
|
|
13006
|
+
media: (0, import_firestore40.arrayRemove)(mediaToRemove),
|
|
13007
|
+
updatedAt: (0, import_firestore40.serverTimestamp)()
|
|
12780
13008
|
};
|
|
12781
13009
|
return this.updateAppointment(appointmentId, updateData);
|
|
12782
13010
|
}
|
|
12783
13011
|
/**
|
|
12784
|
-
*
|
|
12785
|
-
*
|
|
12786
|
-
* @param appointmentId ID of the appointment
|
|
12787
|
-
* @param requirementIds IDs of the requirements to mark as completed
|
|
12788
|
-
* @returns The updated appointment
|
|
13012
|
+
* Adds or updates review information for an appointment.
|
|
12789
13013
|
*/
|
|
12790
|
-
async
|
|
13014
|
+
async addReviewToAppointment(appointmentId, reviewData) {
|
|
12791
13015
|
console.log(
|
|
12792
|
-
`[APPOINTMENT_SERVICE]
|
|
13016
|
+
`[APPOINTMENT_SERVICE] Adding review to appointment ${appointmentId}`
|
|
12793
13017
|
);
|
|
13018
|
+
const newReviewInfo = {
|
|
13019
|
+
...reviewData,
|
|
13020
|
+
reviewId: this.generateId(),
|
|
13021
|
+
reviewedAt: import_firestore40.Timestamp.now()
|
|
13022
|
+
};
|
|
12794
13023
|
const updateData = {
|
|
12795
|
-
|
|
13024
|
+
reviewInfo: newReviewInfo,
|
|
13025
|
+
updatedAt: (0, import_firestore40.serverTimestamp)()
|
|
12796
13026
|
};
|
|
12797
13027
|
return this.updateAppointment(appointmentId, updateData);
|
|
12798
13028
|
}
|
|
12799
13029
|
/**
|
|
12800
|
-
*
|
|
12801
|
-
*
|
|
12802
|
-
* @param appointmentId ID of the appointment
|
|
12803
|
-
* @param requirementIds IDs of the requirements to mark as completed
|
|
12804
|
-
* @returns The updated appointment
|
|
13030
|
+
* Updates the payment status of an appointment.
|
|
12805
13031
|
*/
|
|
12806
|
-
async
|
|
13032
|
+
async updatePaymentStatus(appointmentId, paymentStatus, paymentTransactionId) {
|
|
12807
13033
|
console.log(
|
|
12808
|
-
`[APPOINTMENT_SERVICE]
|
|
13034
|
+
`[APPOINTMENT_SERVICE] Updating payment status of appointment ${appointmentId} to ${paymentStatus}`
|
|
12809
13035
|
);
|
|
12810
13036
|
const updateData = {
|
|
12811
|
-
|
|
13037
|
+
paymentStatus,
|
|
13038
|
+
paymentTransactionId: paymentTransactionId || null,
|
|
13039
|
+
updatedAt: (0, import_firestore40.serverTimestamp)()
|
|
12812
13040
|
};
|
|
12813
13041
|
return this.updateAppointment(appointmentId, updateData);
|
|
12814
13042
|
}
|
|
@@ -12828,29 +13056,204 @@ var AppointmentService = class extends BaseService {
|
|
|
12828
13056
|
};
|
|
12829
13057
|
return this.updateAppointment(appointmentId, updateData);
|
|
12830
13058
|
}
|
|
13059
|
+
};
|
|
13060
|
+
|
|
13061
|
+
// src/services/patient/patientRequirements.service.ts
|
|
13062
|
+
var import_firestore41 = require("firebase/firestore");
|
|
13063
|
+
|
|
13064
|
+
// src/types/patient/patient-requirements.ts
|
|
13065
|
+
var PatientInstructionStatus = /* @__PURE__ */ ((PatientInstructionStatus2) => {
|
|
13066
|
+
PatientInstructionStatus2["PENDING_NOTIFICATION"] = "pendingNotification";
|
|
13067
|
+
PatientInstructionStatus2["ACTION_DUE"] = "actionDue";
|
|
13068
|
+
PatientInstructionStatus2["ACTION_TAKEN"] = "actionTaken";
|
|
13069
|
+
PatientInstructionStatus2["MISSED"] = "missed";
|
|
13070
|
+
PatientInstructionStatus2["CANCELLED"] = "cancelled";
|
|
13071
|
+
PatientInstructionStatus2["SKIPPED"] = "skipped";
|
|
13072
|
+
return PatientInstructionStatus2;
|
|
13073
|
+
})(PatientInstructionStatus || {});
|
|
13074
|
+
var PatientRequirementOverallStatus = /* @__PURE__ */ ((PatientRequirementOverallStatus2) => {
|
|
13075
|
+
PatientRequirementOverallStatus2["ACTIVE"] = "active";
|
|
13076
|
+
PatientRequirementOverallStatus2["ALL_INSTRUCTIONS_MET"] = "allInstructionsMet";
|
|
13077
|
+
PatientRequirementOverallStatus2["PARTIALLY_COMPLETED"] = "partiallyCompleted";
|
|
13078
|
+
PatientRequirementOverallStatus2["FAILED"] = "failed";
|
|
13079
|
+
PatientRequirementOverallStatus2["CANCELLED_APPOINTMENT"] = "cancelledAppointment";
|
|
13080
|
+
PatientRequirementOverallStatus2["SUPERSEDED_RESCHEDULE"] = "supersededReschedule";
|
|
13081
|
+
PatientRequirementOverallStatus2["FAILED_TO_PROCESS"] = "failedToProcess";
|
|
13082
|
+
return PatientRequirementOverallStatus2;
|
|
13083
|
+
})(PatientRequirementOverallStatus || {});
|
|
13084
|
+
var PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME = "patientRequirements";
|
|
13085
|
+
|
|
13086
|
+
// src/services/patient/patientRequirements.service.ts
|
|
13087
|
+
var PatientRequirementsService = class extends BaseService {
|
|
13088
|
+
constructor(db, auth, app) {
|
|
13089
|
+
super(db, auth, app);
|
|
13090
|
+
}
|
|
13091
|
+
getPatientRequirementsCollectionRef(patientId) {
|
|
13092
|
+
return (0, import_firestore41.collection)(
|
|
13093
|
+
this.db,
|
|
13094
|
+
`patients/${patientId}/${PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME}`
|
|
13095
|
+
);
|
|
13096
|
+
}
|
|
13097
|
+
getPatientRequirementDocRef(patientId, instanceId) {
|
|
13098
|
+
return (0, import_firestore41.doc)(
|
|
13099
|
+
this.getPatientRequirementsCollectionRef(patientId),
|
|
13100
|
+
instanceId
|
|
13101
|
+
);
|
|
13102
|
+
}
|
|
12831
13103
|
/**
|
|
12832
|
-
*
|
|
12833
|
-
*
|
|
13104
|
+
* Gets a specific patient requirement instance by its ID.
|
|
13105
|
+
* @param patientId - The ID of the patient.
|
|
13106
|
+
* @param instanceId - The ID of the requirement instance.
|
|
13107
|
+
* @returns The patient requirement instance or null if not found.
|
|
12834
13108
|
*/
|
|
12835
|
-
async
|
|
12836
|
-
|
|
12837
|
-
|
|
12838
|
-
|
|
12839
|
-
console.log("[APPOINTMENT_SERVICE] No user is signed in");
|
|
12840
|
-
return null;
|
|
12841
|
-
}
|
|
12842
|
-
const idToken = await currentUser.getIdToken();
|
|
12843
|
-
console.log("[APPOINTMENT_SERVICE] Debug token:", idToken);
|
|
12844
|
-
return idToken;
|
|
12845
|
-
} catch (error) {
|
|
12846
|
-
console.error("[APPOINTMENT_SERVICE] Error getting debug token:", error);
|
|
13109
|
+
async getPatientRequirementInstance(patientId, instanceId) {
|
|
13110
|
+
const docRef = this.getPatientRequirementDocRef(patientId, instanceId);
|
|
13111
|
+
const docSnap = await (0, import_firestore41.getDoc)(docRef);
|
|
13112
|
+
if (!docSnap.exists()) {
|
|
12847
13113
|
return null;
|
|
12848
13114
|
}
|
|
13115
|
+
const data = docSnap.data();
|
|
13116
|
+
return { id: docSnap.id, ...data };
|
|
13117
|
+
}
|
|
13118
|
+
/**
|
|
13119
|
+
* Retrieves patient requirement instances based on specified filters.
|
|
13120
|
+
* This is a flexible query method.
|
|
13121
|
+
*
|
|
13122
|
+
* @param patientId - The ID of the patient.
|
|
13123
|
+
* @param filters - Optional filters for appointmentId, overall statuses, instruction statuses, and due timeframes.
|
|
13124
|
+
* @param pageLimit - Optional limit for pagination.
|
|
13125
|
+
* @param lastVisible - Optional last document snapshot for pagination.
|
|
13126
|
+
* @returns A promise resolving to an array of matching patient requirement instances and the last document snapshot.
|
|
13127
|
+
*/
|
|
13128
|
+
async getAllPatientRequirementInstances(patientId, filters, pageLimit = 20, lastVisible) {
|
|
13129
|
+
const collRef = this.getPatientRequirementsCollectionRef(patientId);
|
|
13130
|
+
let q = (0, import_firestore41.query)(collRef, (0, import_firestore41.orderBy)("createdAt", "desc"));
|
|
13131
|
+
const queryConstraints = [];
|
|
13132
|
+
if ((filters == null ? void 0 : filters.appointmentId) && filters.appointmentId !== "all") {
|
|
13133
|
+
queryConstraints.push(
|
|
13134
|
+
(0, import_firestore41.where)("appointmentId", "==", filters.appointmentId)
|
|
13135
|
+
);
|
|
13136
|
+
}
|
|
13137
|
+
if ((filters == null ? void 0 : filters.statuses) && filters.statuses.length > 0) {
|
|
13138
|
+
queryConstraints.push((0, import_firestore41.where)("overallStatus", "in", filters.statuses));
|
|
13139
|
+
}
|
|
13140
|
+
if (lastVisible) {
|
|
13141
|
+
queryConstraints.push((0, import_firestore41.startAfter)(lastVisible));
|
|
13142
|
+
}
|
|
13143
|
+
queryConstraints.push((0, import_firestore41.limit)(pageLimit));
|
|
13144
|
+
q = (0, import_firestore41.query)(collRef, ...queryConstraints);
|
|
13145
|
+
const snapshot = await (0, import_firestore41.getDocs)(q);
|
|
13146
|
+
let requirements = snapshot.docs.map((docSnap) => {
|
|
13147
|
+
const data = docSnap.data();
|
|
13148
|
+
return { id: docSnap.id, ...data };
|
|
13149
|
+
});
|
|
13150
|
+
if ((filters == null ? void 0 : filters.instructionStatuses) && filters.instructionStatuses.length > 0) {
|
|
13151
|
+
requirements = requirements.filter(
|
|
13152
|
+
(req) => req.instructions.some(
|
|
13153
|
+
(instr) => filters.instructionStatuses.includes(instr.status)
|
|
13154
|
+
)
|
|
13155
|
+
);
|
|
13156
|
+
}
|
|
13157
|
+
if (filters == null ? void 0 : filters.dueBefore) {
|
|
13158
|
+
const dueBeforeMillis = filters.dueBefore.toMillis();
|
|
13159
|
+
requirements = requirements.filter(
|
|
13160
|
+
(req) => req.instructions.some(
|
|
13161
|
+
(instr) => instr.dueTime.toMillis() < dueBeforeMillis
|
|
13162
|
+
)
|
|
13163
|
+
);
|
|
13164
|
+
}
|
|
13165
|
+
if (filters == null ? void 0 : filters.dueAfter) {
|
|
13166
|
+
const dueAfterMillis = filters.dueAfter.toMillis();
|
|
13167
|
+
requirements = requirements.filter(
|
|
13168
|
+
(req) => req.instructions.some(
|
|
13169
|
+
(instr) => instr.dueTime.toMillis() > dueAfterMillis
|
|
13170
|
+
)
|
|
13171
|
+
);
|
|
13172
|
+
}
|
|
13173
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1] || null;
|
|
13174
|
+
return { requirements, lastDoc: newLastVisible };
|
|
13175
|
+
}
|
|
13176
|
+
/**
|
|
13177
|
+
* Marks a specific instruction within a PatientRequirementInstance as ACTION_TAKEN.
|
|
13178
|
+
* If all instructions are actioned, updates the overallStatus of the instance.
|
|
13179
|
+
*
|
|
13180
|
+
* @param patientId - The ID of the patient.
|
|
13181
|
+
* @param instanceId - The ID of the PatientRequirementInstance.
|
|
13182
|
+
* @param instructionId - The ID of the instruction to complete.
|
|
13183
|
+
* @returns The updated PatientRequirementInstance.
|
|
13184
|
+
* @throws Error if the instance or instruction is not found, or if the instruction is not in a completable state.
|
|
13185
|
+
*/
|
|
13186
|
+
async completeInstruction(patientId, instanceId, instructionId) {
|
|
13187
|
+
const instanceRef = this.getPatientRequirementDocRef(patientId, instanceId);
|
|
13188
|
+
const instanceSnap = await (0, import_firestore41.getDoc)(instanceRef);
|
|
13189
|
+
if (!instanceSnap.exists()) {
|
|
13190
|
+
throw new Error(
|
|
13191
|
+
`PatientRequirementInstance ${instanceId} not found for patient ${patientId}.`
|
|
13192
|
+
);
|
|
13193
|
+
}
|
|
13194
|
+
const instanceData = instanceSnap.data();
|
|
13195
|
+
const instance = { id: instanceSnap.id, ...instanceData };
|
|
13196
|
+
const instructionIndex = instance.instructions.findIndex(
|
|
13197
|
+
(instr) => instr.instructionId === instructionId
|
|
13198
|
+
);
|
|
13199
|
+
if (instructionIndex === -1) {
|
|
13200
|
+
throw new Error(
|
|
13201
|
+
`Instruction ${instructionId} not found in instance ${instanceId}.`
|
|
13202
|
+
);
|
|
13203
|
+
}
|
|
13204
|
+
const instructionToUpdate = instance.instructions[instructionIndex];
|
|
13205
|
+
if (instructionToUpdate.status !== "pendingNotification" /* PENDING_NOTIFICATION */ && instructionToUpdate.status !== "actionDue" /* ACTION_DUE */ && instructionToUpdate.status !== "missed" /* MISSED */) {
|
|
13206
|
+
if (instructionToUpdate.status === "actionTaken" /* ACTION_TAKEN */) {
|
|
13207
|
+
console.warn(
|
|
13208
|
+
`Instruction ${instructionId} is already marked as ACTION_TAKEN.`
|
|
13209
|
+
);
|
|
13210
|
+
return instance;
|
|
13211
|
+
}
|
|
13212
|
+
throw new Error(
|
|
13213
|
+
`Instruction ${instructionId} is in status ${instructionToUpdate.status} and cannot be marked as completed.`
|
|
13214
|
+
);
|
|
13215
|
+
}
|
|
13216
|
+
const now = import_firestore41.Timestamp.now();
|
|
13217
|
+
const updatedInstructions = [...instance.instructions];
|
|
13218
|
+
updatedInstructions[instructionIndex] = {
|
|
13219
|
+
...instructionToUpdate,
|
|
13220
|
+
status: "actionTaken" /* ACTION_TAKEN */,
|
|
13221
|
+
actionTakenAt: now,
|
|
13222
|
+
updatedAt: now
|
|
13223
|
+
};
|
|
13224
|
+
const allActionTaken = updatedInstructions.every(
|
|
13225
|
+
(instr) => instr.status === "actionTaken" /* ACTION_TAKEN */
|
|
13226
|
+
);
|
|
13227
|
+
let newOverallStatus = instance.overallStatus;
|
|
13228
|
+
if (allActionTaken) {
|
|
13229
|
+
newOverallStatus = "allInstructionsMet" /* ALL_INSTRUCTIONS_MET */;
|
|
13230
|
+
} else if (updatedInstructions.some(
|
|
13231
|
+
(instr) => instr.status === "actionTaken" /* ACTION_TAKEN */
|
|
13232
|
+
)) {
|
|
13233
|
+
newOverallStatus = "partiallyCompleted" /* PARTIALLY_COMPLETED */;
|
|
13234
|
+
}
|
|
13235
|
+
const updatePayload = {
|
|
13236
|
+
// Using a general type for updateDoc payload
|
|
13237
|
+
instructions: updatedInstructions,
|
|
13238
|
+
updatedAt: now
|
|
13239
|
+
};
|
|
13240
|
+
if (newOverallStatus !== instance.overallStatus) {
|
|
13241
|
+
updatePayload.overallStatus = newOverallStatus;
|
|
13242
|
+
}
|
|
13243
|
+
await (0, import_firestore41.updateDoc)(instanceRef, updatePayload);
|
|
13244
|
+
return {
|
|
13245
|
+
...instance,
|
|
13246
|
+
instructions: updatedInstructions,
|
|
13247
|
+
updatedAt: now,
|
|
13248
|
+
overallStatus: newOverallStatus
|
|
13249
|
+
};
|
|
12849
13250
|
}
|
|
13251
|
+
// Note: As per the request, full CRUD (create, direct update of instance, delete) is not part of this light service,
|
|
13252
|
+
// as those will be handled by Cloud Functions reacting to appointment lifecycle events.
|
|
12850
13253
|
};
|
|
12851
13254
|
|
|
12852
13255
|
// src/backoffice/services/brand.service.ts
|
|
12853
|
-
var
|
|
13256
|
+
var import_firestore42 = require("firebase/firestore");
|
|
12854
13257
|
|
|
12855
13258
|
// src/backoffice/types/brand.types.ts
|
|
12856
13259
|
var BRANDS_COLLECTION = "brands";
|
|
@@ -12861,7 +13264,7 @@ var BrandService = class extends BaseService {
|
|
|
12861
13264
|
* Gets reference to brands collection
|
|
12862
13265
|
*/
|
|
12863
13266
|
getBrandsRef() {
|
|
12864
|
-
return (0,
|
|
13267
|
+
return (0, import_firestore42.collection)(this.db, BRANDS_COLLECTION);
|
|
12865
13268
|
}
|
|
12866
13269
|
/**
|
|
12867
13270
|
* Creates a new brand
|
|
@@ -12874,19 +13277,19 @@ var BrandService = class extends BaseService {
|
|
|
12874
13277
|
updatedAt: now,
|
|
12875
13278
|
isActive: true
|
|
12876
13279
|
};
|
|
12877
|
-
const docRef = await (0,
|
|
13280
|
+
const docRef = await (0, import_firestore42.addDoc)(this.getBrandsRef(), newBrand);
|
|
12878
13281
|
return { id: docRef.id, ...newBrand };
|
|
12879
13282
|
}
|
|
12880
13283
|
/**
|
|
12881
13284
|
* Gets all active brands
|
|
12882
13285
|
*/
|
|
12883
13286
|
async getAll() {
|
|
12884
|
-
const q = (0,
|
|
12885
|
-
const snapshot = await (0,
|
|
13287
|
+
const q = (0, import_firestore42.query)(this.getBrandsRef(), (0, import_firestore42.where)("isActive", "==", true));
|
|
13288
|
+
const snapshot = await (0, import_firestore42.getDocs)(q);
|
|
12886
13289
|
return snapshot.docs.map(
|
|
12887
|
-
(
|
|
12888
|
-
id:
|
|
12889
|
-
...
|
|
13290
|
+
(doc33) => ({
|
|
13291
|
+
id: doc33.id,
|
|
13292
|
+
...doc33.data()
|
|
12890
13293
|
})
|
|
12891
13294
|
);
|
|
12892
13295
|
}
|
|
@@ -12898,8 +13301,8 @@ var BrandService = class extends BaseService {
|
|
|
12898
13301
|
...brand,
|
|
12899
13302
|
updatedAt: /* @__PURE__ */ new Date()
|
|
12900
13303
|
};
|
|
12901
|
-
const docRef = (0,
|
|
12902
|
-
await (0,
|
|
13304
|
+
const docRef = (0, import_firestore42.doc)(this.getBrandsRef(), brandId);
|
|
13305
|
+
await (0, import_firestore42.updateDoc)(docRef, updateData);
|
|
12903
13306
|
return this.getById(brandId);
|
|
12904
13307
|
}
|
|
12905
13308
|
/**
|
|
@@ -12914,8 +13317,8 @@ var BrandService = class extends BaseService {
|
|
|
12914
13317
|
* Gets a brand by ID
|
|
12915
13318
|
*/
|
|
12916
13319
|
async getById(brandId) {
|
|
12917
|
-
const docRef = (0,
|
|
12918
|
-
const docSnap = await (0,
|
|
13320
|
+
const docRef = (0, import_firestore42.doc)(this.getBrandsRef(), brandId);
|
|
13321
|
+
const docSnap = await (0, import_firestore42.getDoc)(docRef);
|
|
12919
13322
|
if (!docSnap.exists()) return null;
|
|
12920
13323
|
return {
|
|
12921
13324
|
id: docSnap.id,
|
|
@@ -12925,7 +13328,7 @@ var BrandService = class extends BaseService {
|
|
|
12925
13328
|
};
|
|
12926
13329
|
|
|
12927
13330
|
// src/backoffice/services/category.service.ts
|
|
12928
|
-
var
|
|
13331
|
+
var import_firestore43 = require("firebase/firestore");
|
|
12929
13332
|
|
|
12930
13333
|
// src/backoffice/types/category.types.ts
|
|
12931
13334
|
var CATEGORIES_COLLECTION = "backoffice_categories";
|
|
@@ -12936,7 +13339,7 @@ var CategoryService = class extends BaseService {
|
|
|
12936
13339
|
* Referenca na Firestore kolekciju kategorija
|
|
12937
13340
|
*/
|
|
12938
13341
|
get categoriesRef() {
|
|
12939
|
-
return (0,
|
|
13342
|
+
return (0, import_firestore43.collection)(this.db, CATEGORIES_COLLECTION);
|
|
12940
13343
|
}
|
|
12941
13344
|
/**
|
|
12942
13345
|
* Kreira novu kategoriju u sistemu
|
|
@@ -12951,7 +13354,7 @@ var CategoryService = class extends BaseService {
|
|
|
12951
13354
|
updatedAt: now,
|
|
12952
13355
|
isActive: true
|
|
12953
13356
|
};
|
|
12954
|
-
const docRef = await (0,
|
|
13357
|
+
const docRef = await (0, import_firestore43.addDoc)(this.categoriesRef, newCategory);
|
|
12955
13358
|
return { id: docRef.id, ...newCategory };
|
|
12956
13359
|
}
|
|
12957
13360
|
/**
|
|
@@ -12959,12 +13362,12 @@ var CategoryService = class extends BaseService {
|
|
|
12959
13362
|
* @returns Lista aktivnih kategorija
|
|
12960
13363
|
*/
|
|
12961
13364
|
async getAll() {
|
|
12962
|
-
const q = (0,
|
|
12963
|
-
const snapshot = await (0,
|
|
13365
|
+
const q = (0, import_firestore43.query)(this.categoriesRef, (0, import_firestore43.where)("isActive", "==", true));
|
|
13366
|
+
const snapshot = await (0, import_firestore43.getDocs)(q);
|
|
12964
13367
|
return snapshot.docs.map(
|
|
12965
|
-
(
|
|
12966
|
-
id:
|
|
12967
|
-
...
|
|
13368
|
+
(doc33) => ({
|
|
13369
|
+
id: doc33.id,
|
|
13370
|
+
...doc33.data()
|
|
12968
13371
|
})
|
|
12969
13372
|
);
|
|
12970
13373
|
}
|
|
@@ -12974,16 +13377,16 @@ var CategoryService = class extends BaseService {
|
|
|
12974
13377
|
* @returns Lista kategorija koje pripadaju traženoj familiji
|
|
12975
13378
|
*/
|
|
12976
13379
|
async getAllByFamily(family) {
|
|
12977
|
-
const q = (0,
|
|
13380
|
+
const q = (0, import_firestore43.query)(
|
|
12978
13381
|
this.categoriesRef,
|
|
12979
|
-
(0,
|
|
12980
|
-
(0,
|
|
13382
|
+
(0, import_firestore43.where)("family", "==", family),
|
|
13383
|
+
(0, import_firestore43.where)("isActive", "==", true)
|
|
12981
13384
|
);
|
|
12982
|
-
const snapshot = await (0,
|
|
13385
|
+
const snapshot = await (0, import_firestore43.getDocs)(q);
|
|
12983
13386
|
return snapshot.docs.map(
|
|
12984
|
-
(
|
|
12985
|
-
id:
|
|
12986
|
-
...
|
|
13387
|
+
(doc33) => ({
|
|
13388
|
+
id: doc33.id,
|
|
13389
|
+
...doc33.data()
|
|
12987
13390
|
})
|
|
12988
13391
|
);
|
|
12989
13392
|
}
|
|
@@ -12998,8 +13401,8 @@ var CategoryService = class extends BaseService {
|
|
|
12998
13401
|
...category,
|
|
12999
13402
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13000
13403
|
};
|
|
13001
|
-
const docRef = (0,
|
|
13002
|
-
await (0,
|
|
13404
|
+
const docRef = (0, import_firestore43.doc)(this.categoriesRef, id);
|
|
13405
|
+
await (0, import_firestore43.updateDoc)(docRef, updateData);
|
|
13003
13406
|
return this.getById(id);
|
|
13004
13407
|
}
|
|
13005
13408
|
/**
|
|
@@ -13015,8 +13418,8 @@ var CategoryService = class extends BaseService {
|
|
|
13015
13418
|
* @returns Kategorija ili null ako ne postoji
|
|
13016
13419
|
*/
|
|
13017
13420
|
async getById(id) {
|
|
13018
|
-
const docRef = (0,
|
|
13019
|
-
const docSnap = await (0,
|
|
13421
|
+
const docRef = (0, import_firestore43.doc)(this.categoriesRef, id);
|
|
13422
|
+
const docSnap = await (0, import_firestore43.getDoc)(docRef);
|
|
13020
13423
|
if (!docSnap.exists()) return null;
|
|
13021
13424
|
return {
|
|
13022
13425
|
id: docSnap.id,
|
|
@@ -13026,7 +13429,7 @@ var CategoryService = class extends BaseService {
|
|
|
13026
13429
|
};
|
|
13027
13430
|
|
|
13028
13431
|
// src/backoffice/services/subcategory.service.ts
|
|
13029
|
-
var
|
|
13432
|
+
var import_firestore44 = require("firebase/firestore");
|
|
13030
13433
|
|
|
13031
13434
|
// src/backoffice/types/subcategory.types.ts
|
|
13032
13435
|
var SUBCATEGORIES_COLLECTION = "subcategories";
|
|
@@ -13038,7 +13441,7 @@ var SubcategoryService = class extends BaseService {
|
|
|
13038
13441
|
* @param categoryId - ID roditeljske kategorije
|
|
13039
13442
|
*/
|
|
13040
13443
|
getSubcategoriesRef(categoryId) {
|
|
13041
|
-
return (0,
|
|
13444
|
+
return (0, import_firestore44.collection)(
|
|
13042
13445
|
this.db,
|
|
13043
13446
|
CATEGORIES_COLLECTION,
|
|
13044
13447
|
categoryId,
|
|
@@ -13060,7 +13463,7 @@ var SubcategoryService = class extends BaseService {
|
|
|
13060
13463
|
updatedAt: now,
|
|
13061
13464
|
isActive: true
|
|
13062
13465
|
};
|
|
13063
|
-
const docRef = await (0,
|
|
13466
|
+
const docRef = await (0, import_firestore44.addDoc)(
|
|
13064
13467
|
this.getSubcategoriesRef(categoryId),
|
|
13065
13468
|
newSubcategory
|
|
13066
13469
|
);
|
|
@@ -13072,15 +13475,15 @@ var SubcategoryService = class extends BaseService {
|
|
|
13072
13475
|
* @returns Lista aktivnih podkategorija
|
|
13073
13476
|
*/
|
|
13074
13477
|
async getAllByCategoryId(categoryId) {
|
|
13075
|
-
const q = (0,
|
|
13478
|
+
const q = (0, import_firestore44.query)(
|
|
13076
13479
|
this.getSubcategoriesRef(categoryId),
|
|
13077
|
-
(0,
|
|
13480
|
+
(0, import_firestore44.where)("isActive", "==", true)
|
|
13078
13481
|
);
|
|
13079
|
-
const snapshot = await (0,
|
|
13482
|
+
const snapshot = await (0, import_firestore44.getDocs)(q);
|
|
13080
13483
|
return snapshot.docs.map(
|
|
13081
|
-
(
|
|
13082
|
-
id:
|
|
13083
|
-
...
|
|
13484
|
+
(doc33) => ({
|
|
13485
|
+
id: doc33.id,
|
|
13486
|
+
...doc33.data()
|
|
13084
13487
|
})
|
|
13085
13488
|
);
|
|
13086
13489
|
}
|
|
@@ -13096,8 +13499,8 @@ var SubcategoryService = class extends BaseService {
|
|
|
13096
13499
|
...subcategory,
|
|
13097
13500
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13098
13501
|
};
|
|
13099
|
-
const docRef = (0,
|
|
13100
|
-
await (0,
|
|
13502
|
+
const docRef = (0, import_firestore44.doc)(this.getSubcategoriesRef(categoryId), subcategoryId);
|
|
13503
|
+
await (0, import_firestore44.updateDoc)(docRef, updateData);
|
|
13101
13504
|
return this.getById(categoryId, subcategoryId);
|
|
13102
13505
|
}
|
|
13103
13506
|
/**
|
|
@@ -13115,8 +13518,8 @@ var SubcategoryService = class extends BaseService {
|
|
|
13115
13518
|
* @returns Podkategorija ili null ako ne postoji
|
|
13116
13519
|
*/
|
|
13117
13520
|
async getById(categoryId, subcategoryId) {
|
|
13118
|
-
const docRef = (0,
|
|
13119
|
-
const docSnap = await (0,
|
|
13521
|
+
const docRef = (0, import_firestore44.doc)(this.getSubcategoriesRef(categoryId), subcategoryId);
|
|
13522
|
+
const docSnap = await (0, import_firestore44.getDoc)(docRef);
|
|
13120
13523
|
if (!docSnap.exists()) return null;
|
|
13121
13524
|
return {
|
|
13122
13525
|
id: docSnap.id,
|
|
@@ -13126,7 +13529,7 @@ var SubcategoryService = class extends BaseService {
|
|
|
13126
13529
|
};
|
|
13127
13530
|
|
|
13128
13531
|
// src/backoffice/services/technology.service.ts
|
|
13129
|
-
var
|
|
13532
|
+
var import_firestore45 = require("firebase/firestore");
|
|
13130
13533
|
var DEFAULT_CERTIFICATION_REQUIREMENT = {
|
|
13131
13534
|
minimumLevel: "aesthetician" /* AESTHETICIAN */,
|
|
13132
13535
|
requiredSpecialties: []
|
|
@@ -13136,7 +13539,7 @@ var TechnologyService = class extends BaseService {
|
|
|
13136
13539
|
* Vraća referencu na Firestore kolekciju tehnologija
|
|
13137
13540
|
*/
|
|
13138
13541
|
getTechnologiesRef() {
|
|
13139
|
-
return (0,
|
|
13542
|
+
return (0, import_firestore45.collection)(this.db, TECHNOLOGIES_COLLECTION);
|
|
13140
13543
|
}
|
|
13141
13544
|
/**
|
|
13142
13545
|
* Kreira novu tehnologiju
|
|
@@ -13159,7 +13562,7 @@ var TechnologyService = class extends BaseService {
|
|
|
13159
13562
|
benefits: technology.benefits || [],
|
|
13160
13563
|
certificationRequirement: technology.certificationRequirement || DEFAULT_CERTIFICATION_REQUIREMENT
|
|
13161
13564
|
};
|
|
13162
|
-
const docRef = await (0,
|
|
13565
|
+
const docRef = await (0, import_firestore45.addDoc)(this.getTechnologiesRef(), newTechnology);
|
|
13163
13566
|
return { id: docRef.id, ...newTechnology };
|
|
13164
13567
|
}
|
|
13165
13568
|
/**
|
|
@@ -13167,12 +13570,12 @@ var TechnologyService = class extends BaseService {
|
|
|
13167
13570
|
* @returns Lista aktivnih tehnologija
|
|
13168
13571
|
*/
|
|
13169
13572
|
async getAll() {
|
|
13170
|
-
const q = (0,
|
|
13171
|
-
const snapshot = await (0,
|
|
13573
|
+
const q = (0, import_firestore45.query)(this.getTechnologiesRef(), (0, import_firestore45.where)("isActive", "==", true));
|
|
13574
|
+
const snapshot = await (0, import_firestore45.getDocs)(q);
|
|
13172
13575
|
return snapshot.docs.map(
|
|
13173
|
-
(
|
|
13174
|
-
id:
|
|
13175
|
-
...
|
|
13576
|
+
(doc33) => ({
|
|
13577
|
+
id: doc33.id,
|
|
13578
|
+
...doc33.data()
|
|
13176
13579
|
})
|
|
13177
13580
|
);
|
|
13178
13581
|
}
|
|
@@ -13182,16 +13585,16 @@ var TechnologyService = class extends BaseService {
|
|
|
13182
13585
|
* @returns Lista aktivnih tehnologija
|
|
13183
13586
|
*/
|
|
13184
13587
|
async getAllByFamily(family) {
|
|
13185
|
-
const q = (0,
|
|
13588
|
+
const q = (0, import_firestore45.query)(
|
|
13186
13589
|
this.getTechnologiesRef(),
|
|
13187
|
-
(0,
|
|
13188
|
-
(0,
|
|
13590
|
+
(0, import_firestore45.where)("isActive", "==", true),
|
|
13591
|
+
(0, import_firestore45.where)("family", "==", family)
|
|
13189
13592
|
);
|
|
13190
|
-
const snapshot = await (0,
|
|
13593
|
+
const snapshot = await (0, import_firestore45.getDocs)(q);
|
|
13191
13594
|
return snapshot.docs.map(
|
|
13192
|
-
(
|
|
13193
|
-
id:
|
|
13194
|
-
...
|
|
13595
|
+
(doc33) => ({
|
|
13596
|
+
id: doc33.id,
|
|
13597
|
+
...doc33.data()
|
|
13195
13598
|
})
|
|
13196
13599
|
);
|
|
13197
13600
|
}
|
|
@@ -13201,16 +13604,16 @@ var TechnologyService = class extends BaseService {
|
|
|
13201
13604
|
* @returns Lista aktivnih tehnologija
|
|
13202
13605
|
*/
|
|
13203
13606
|
async getAllByCategoryId(categoryId) {
|
|
13204
|
-
const q = (0,
|
|
13607
|
+
const q = (0, import_firestore45.query)(
|
|
13205
13608
|
this.getTechnologiesRef(),
|
|
13206
|
-
(0,
|
|
13207
|
-
(0,
|
|
13609
|
+
(0, import_firestore45.where)("isActive", "==", true),
|
|
13610
|
+
(0, import_firestore45.where)("categoryId", "==", categoryId)
|
|
13208
13611
|
);
|
|
13209
|
-
const snapshot = await (0,
|
|
13612
|
+
const snapshot = await (0, import_firestore45.getDocs)(q);
|
|
13210
13613
|
return snapshot.docs.map(
|
|
13211
|
-
(
|
|
13212
|
-
id:
|
|
13213
|
-
...
|
|
13614
|
+
(doc33) => ({
|
|
13615
|
+
id: doc33.id,
|
|
13616
|
+
...doc33.data()
|
|
13214
13617
|
})
|
|
13215
13618
|
);
|
|
13216
13619
|
}
|
|
@@ -13220,16 +13623,16 @@ var TechnologyService = class extends BaseService {
|
|
|
13220
13623
|
* @returns Lista aktivnih tehnologija
|
|
13221
13624
|
*/
|
|
13222
13625
|
async getAllBySubcategoryId(subcategoryId) {
|
|
13223
|
-
const q = (0,
|
|
13626
|
+
const q = (0, import_firestore45.query)(
|
|
13224
13627
|
this.getTechnologiesRef(),
|
|
13225
|
-
(0,
|
|
13226
|
-
(0,
|
|
13628
|
+
(0, import_firestore45.where)("isActive", "==", true),
|
|
13629
|
+
(0, import_firestore45.where)("subcategoryId", "==", subcategoryId)
|
|
13227
13630
|
);
|
|
13228
|
-
const snapshot = await (0,
|
|
13631
|
+
const snapshot = await (0, import_firestore45.getDocs)(q);
|
|
13229
13632
|
return snapshot.docs.map(
|
|
13230
|
-
(
|
|
13231
|
-
id:
|
|
13232
|
-
...
|
|
13633
|
+
(doc33) => ({
|
|
13634
|
+
id: doc33.id,
|
|
13635
|
+
...doc33.data()
|
|
13233
13636
|
})
|
|
13234
13637
|
);
|
|
13235
13638
|
}
|
|
@@ -13244,8 +13647,8 @@ var TechnologyService = class extends BaseService {
|
|
|
13244
13647
|
...technology,
|
|
13245
13648
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13246
13649
|
};
|
|
13247
|
-
const docRef = (0,
|
|
13248
|
-
await (0,
|
|
13650
|
+
const docRef = (0, import_firestore45.doc)(this.getTechnologiesRef(), technologyId);
|
|
13651
|
+
await (0, import_firestore45.updateDoc)(docRef, updateData);
|
|
13249
13652
|
return this.getById(technologyId);
|
|
13250
13653
|
}
|
|
13251
13654
|
/**
|
|
@@ -13263,8 +13666,8 @@ var TechnologyService = class extends BaseService {
|
|
|
13263
13666
|
* @returns Tehnologija ili null ako ne postoji
|
|
13264
13667
|
*/
|
|
13265
13668
|
async getById(technologyId) {
|
|
13266
|
-
const docRef = (0,
|
|
13267
|
-
const docSnap = await (0,
|
|
13669
|
+
const docRef = (0, import_firestore45.doc)(this.getTechnologiesRef(), technologyId);
|
|
13670
|
+
const docSnap = await (0, import_firestore45.getDoc)(docRef);
|
|
13268
13671
|
if (!docSnap.exists()) return null;
|
|
13269
13672
|
return {
|
|
13270
13673
|
id: docSnap.id,
|
|
@@ -13278,10 +13681,10 @@ var TechnologyService = class extends BaseService {
|
|
|
13278
13681
|
* @returns Ažurirana tehnologija sa novim zahtevom
|
|
13279
13682
|
*/
|
|
13280
13683
|
async addRequirement(technologyId, requirement) {
|
|
13281
|
-
const docRef = (0,
|
|
13684
|
+
const docRef = (0, import_firestore45.doc)(this.getTechnologiesRef(), technologyId);
|
|
13282
13685
|
const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
|
|
13283
|
-
await (0,
|
|
13284
|
-
[requirementType]: (0,
|
|
13686
|
+
await (0, import_firestore45.updateDoc)(docRef, {
|
|
13687
|
+
[requirementType]: (0, import_firestore45.arrayUnion)(requirement),
|
|
13285
13688
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13286
13689
|
});
|
|
13287
13690
|
return this.getById(technologyId);
|
|
@@ -13293,10 +13696,10 @@ var TechnologyService = class extends BaseService {
|
|
|
13293
13696
|
* @returns Ažurirana tehnologija bez uklonjenog zahteva
|
|
13294
13697
|
*/
|
|
13295
13698
|
async removeRequirement(technologyId, requirement) {
|
|
13296
|
-
const docRef = (0,
|
|
13699
|
+
const docRef = (0, import_firestore45.doc)(this.getTechnologiesRef(), technologyId);
|
|
13297
13700
|
const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
|
|
13298
|
-
await (0,
|
|
13299
|
-
[requirementType]: (0,
|
|
13701
|
+
await (0, import_firestore45.updateDoc)(docRef, {
|
|
13702
|
+
[requirementType]: (0, import_firestore45.arrayRemove)(requirement),
|
|
13300
13703
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13301
13704
|
});
|
|
13302
13705
|
return this.getById(technologyId);
|
|
@@ -13333,9 +13736,9 @@ var TechnologyService = class extends BaseService {
|
|
|
13333
13736
|
* @returns Ažurirana tehnologija
|
|
13334
13737
|
*/
|
|
13335
13738
|
async addBlockingCondition(technologyId, condition) {
|
|
13336
|
-
const docRef = (0,
|
|
13337
|
-
await (0,
|
|
13338
|
-
blockingConditions: (0,
|
|
13739
|
+
const docRef = (0, import_firestore45.doc)(this.getTechnologiesRef(), technologyId);
|
|
13740
|
+
await (0, import_firestore45.updateDoc)(docRef, {
|
|
13741
|
+
blockingConditions: (0, import_firestore45.arrayUnion)(condition),
|
|
13339
13742
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13340
13743
|
});
|
|
13341
13744
|
return this.getById(technologyId);
|
|
@@ -13347,9 +13750,9 @@ var TechnologyService = class extends BaseService {
|
|
|
13347
13750
|
* @returns Ažurirana tehnologija
|
|
13348
13751
|
*/
|
|
13349
13752
|
async removeBlockingCondition(technologyId, condition) {
|
|
13350
|
-
const docRef = (0,
|
|
13351
|
-
await (0,
|
|
13352
|
-
blockingConditions: (0,
|
|
13753
|
+
const docRef = (0, import_firestore45.doc)(this.getTechnologiesRef(), technologyId);
|
|
13754
|
+
await (0, import_firestore45.updateDoc)(docRef, {
|
|
13755
|
+
blockingConditions: (0, import_firestore45.arrayRemove)(condition),
|
|
13353
13756
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13354
13757
|
});
|
|
13355
13758
|
return this.getById(technologyId);
|
|
@@ -13361,9 +13764,9 @@ var TechnologyService = class extends BaseService {
|
|
|
13361
13764
|
* @returns Ažurirana tehnologija
|
|
13362
13765
|
*/
|
|
13363
13766
|
async addContraindication(technologyId, contraindication) {
|
|
13364
|
-
const docRef = (0,
|
|
13365
|
-
await (0,
|
|
13366
|
-
contraindications: (0,
|
|
13767
|
+
const docRef = (0, import_firestore45.doc)(this.getTechnologiesRef(), technologyId);
|
|
13768
|
+
await (0, import_firestore45.updateDoc)(docRef, {
|
|
13769
|
+
contraindications: (0, import_firestore45.arrayUnion)(contraindication),
|
|
13367
13770
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13368
13771
|
});
|
|
13369
13772
|
return this.getById(technologyId);
|
|
@@ -13375,9 +13778,9 @@ var TechnologyService = class extends BaseService {
|
|
|
13375
13778
|
* @returns Ažurirana tehnologija
|
|
13376
13779
|
*/
|
|
13377
13780
|
async removeContraindication(technologyId, contraindication) {
|
|
13378
|
-
const docRef = (0,
|
|
13379
|
-
await (0,
|
|
13380
|
-
contraindications: (0,
|
|
13781
|
+
const docRef = (0, import_firestore45.doc)(this.getTechnologiesRef(), technologyId);
|
|
13782
|
+
await (0, import_firestore45.updateDoc)(docRef, {
|
|
13783
|
+
contraindications: (0, import_firestore45.arrayRemove)(contraindication),
|
|
13381
13784
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13382
13785
|
});
|
|
13383
13786
|
return this.getById(technologyId);
|
|
@@ -13389,9 +13792,9 @@ var TechnologyService = class extends BaseService {
|
|
|
13389
13792
|
* @returns Ažurirana tehnologija
|
|
13390
13793
|
*/
|
|
13391
13794
|
async addBenefit(technologyId, benefit) {
|
|
13392
|
-
const docRef = (0,
|
|
13393
|
-
await (0,
|
|
13394
|
-
benefits: (0,
|
|
13795
|
+
const docRef = (0, import_firestore45.doc)(this.getTechnologiesRef(), technologyId);
|
|
13796
|
+
await (0, import_firestore45.updateDoc)(docRef, {
|
|
13797
|
+
benefits: (0, import_firestore45.arrayUnion)(benefit),
|
|
13395
13798
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13396
13799
|
});
|
|
13397
13800
|
return this.getById(technologyId);
|
|
@@ -13403,9 +13806,9 @@ var TechnologyService = class extends BaseService {
|
|
|
13403
13806
|
* @returns Ažurirana tehnologija
|
|
13404
13807
|
*/
|
|
13405
13808
|
async removeBenefit(technologyId, benefit) {
|
|
13406
|
-
const docRef = (0,
|
|
13407
|
-
await (0,
|
|
13408
|
-
benefits: (0,
|
|
13809
|
+
const docRef = (0, import_firestore45.doc)(this.getTechnologiesRef(), technologyId);
|
|
13810
|
+
await (0, import_firestore45.updateDoc)(docRef, {
|
|
13811
|
+
benefits: (0, import_firestore45.arrayRemove)(benefit),
|
|
13409
13812
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13410
13813
|
});
|
|
13411
13814
|
return this.getById(technologyId);
|
|
@@ -13444,8 +13847,8 @@ var TechnologyService = class extends BaseService {
|
|
|
13444
13847
|
* @returns Ažurirana tehnologija
|
|
13445
13848
|
*/
|
|
13446
13849
|
async updateCertificationRequirement(technologyId, certificationRequirement) {
|
|
13447
|
-
const docRef = (0,
|
|
13448
|
-
await (0,
|
|
13850
|
+
const docRef = (0, import_firestore45.doc)(this.getTechnologiesRef(), technologyId);
|
|
13851
|
+
await (0, import_firestore45.updateDoc)(docRef, {
|
|
13449
13852
|
certificationRequirement,
|
|
13450
13853
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13451
13854
|
});
|
|
@@ -13545,7 +13948,7 @@ var TechnologyService = class extends BaseService {
|
|
|
13545
13948
|
};
|
|
13546
13949
|
|
|
13547
13950
|
// src/backoffice/services/product.service.ts
|
|
13548
|
-
var
|
|
13951
|
+
var import_firestore46 = require("firebase/firestore");
|
|
13549
13952
|
|
|
13550
13953
|
// src/backoffice/types/product.types.ts
|
|
13551
13954
|
var PRODUCTS_COLLECTION = "products";
|
|
@@ -13558,7 +13961,7 @@ var ProductService = class extends BaseService {
|
|
|
13558
13961
|
* @returns Firestore collection reference
|
|
13559
13962
|
*/
|
|
13560
13963
|
getProductsRef(technologyId) {
|
|
13561
|
-
return (0,
|
|
13964
|
+
return (0, import_firestore46.collection)(
|
|
13562
13965
|
this.db,
|
|
13563
13966
|
TECHNOLOGIES_COLLECTION,
|
|
13564
13967
|
technologyId,
|
|
@@ -13578,7 +13981,7 @@ var ProductService = class extends BaseService {
|
|
|
13578
13981
|
updatedAt: now,
|
|
13579
13982
|
isActive: true
|
|
13580
13983
|
};
|
|
13581
|
-
const productRef = await (0,
|
|
13984
|
+
const productRef = await (0, import_firestore46.addDoc)(
|
|
13582
13985
|
this.getProductsRef(technologyId),
|
|
13583
13986
|
newProduct
|
|
13584
13987
|
);
|
|
@@ -13588,15 +13991,15 @@ var ProductService = class extends BaseService {
|
|
|
13588
13991
|
* Gets all products for a technology
|
|
13589
13992
|
*/
|
|
13590
13993
|
async getAllByTechnology(technologyId) {
|
|
13591
|
-
const q = (0,
|
|
13994
|
+
const q = (0, import_firestore46.query)(
|
|
13592
13995
|
this.getProductsRef(technologyId),
|
|
13593
|
-
(0,
|
|
13996
|
+
(0, import_firestore46.where)("isActive", "==", true)
|
|
13594
13997
|
);
|
|
13595
|
-
const snapshot = await (0,
|
|
13998
|
+
const snapshot = await (0, import_firestore46.getDocs)(q);
|
|
13596
13999
|
return snapshot.docs.map(
|
|
13597
|
-
(
|
|
13598
|
-
id:
|
|
13599
|
-
...
|
|
14000
|
+
(doc33) => ({
|
|
14001
|
+
id: doc33.id,
|
|
14002
|
+
...doc33.data()
|
|
13600
14003
|
})
|
|
13601
14004
|
);
|
|
13602
14005
|
}
|
|
@@ -13604,21 +14007,21 @@ var ProductService = class extends BaseService {
|
|
|
13604
14007
|
* Gets all products for a brand by filtering through all technologies
|
|
13605
14008
|
*/
|
|
13606
14009
|
async getAllByBrand(brandId) {
|
|
13607
|
-
const allTechnologiesRef = (0,
|
|
13608
|
-
const technologiesSnapshot = await (0,
|
|
14010
|
+
const allTechnologiesRef = (0, import_firestore46.collection)(this.db, TECHNOLOGIES_COLLECTION);
|
|
14011
|
+
const technologiesSnapshot = await (0, import_firestore46.getDocs)(allTechnologiesRef);
|
|
13609
14012
|
const products = [];
|
|
13610
14013
|
for (const techDoc of technologiesSnapshot.docs) {
|
|
13611
|
-
const q = (0,
|
|
14014
|
+
const q = (0, import_firestore46.query)(
|
|
13612
14015
|
this.getProductsRef(techDoc.id),
|
|
13613
|
-
(0,
|
|
13614
|
-
(0,
|
|
14016
|
+
(0, import_firestore46.where)("brandId", "==", brandId),
|
|
14017
|
+
(0, import_firestore46.where)("isActive", "==", true)
|
|
13615
14018
|
);
|
|
13616
|
-
const snapshot = await (0,
|
|
14019
|
+
const snapshot = await (0, import_firestore46.getDocs)(q);
|
|
13617
14020
|
products.push(
|
|
13618
14021
|
...snapshot.docs.map(
|
|
13619
|
-
(
|
|
13620
|
-
id:
|
|
13621
|
-
...
|
|
14022
|
+
(doc33) => ({
|
|
14023
|
+
id: doc33.id,
|
|
14024
|
+
...doc33.data()
|
|
13622
14025
|
})
|
|
13623
14026
|
)
|
|
13624
14027
|
);
|
|
@@ -13633,8 +14036,8 @@ var ProductService = class extends BaseService {
|
|
|
13633
14036
|
...product,
|
|
13634
14037
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13635
14038
|
};
|
|
13636
|
-
const docRef = (0,
|
|
13637
|
-
await (0,
|
|
14039
|
+
const docRef = (0, import_firestore46.doc)(this.getProductsRef(technologyId), productId);
|
|
14040
|
+
await (0, import_firestore46.updateDoc)(docRef, updateData);
|
|
13638
14041
|
return this.getById(technologyId, productId);
|
|
13639
14042
|
}
|
|
13640
14043
|
/**
|
|
@@ -13649,8 +14052,8 @@ var ProductService = class extends BaseService {
|
|
|
13649
14052
|
* Gets a product by ID
|
|
13650
14053
|
*/
|
|
13651
14054
|
async getById(technologyId, productId) {
|
|
13652
|
-
const docRef = (0,
|
|
13653
|
-
const docSnap = await (0,
|
|
14055
|
+
const docRef = (0, import_firestore46.doc)(this.getProductsRef(technologyId), productId);
|
|
14056
|
+
const docSnap = await (0, import_firestore46.getDoc)(docRef);
|
|
13654
14057
|
if (!docSnap.exists()) return null;
|
|
13655
14058
|
return {
|
|
13656
14059
|
id: docSnap.id,
|
|
@@ -13679,14 +14082,14 @@ var baseNotificationSchema = import_zod24.z.object({
|
|
|
13679
14082
|
userRole: import_zod24.z.nativeEnum(UserRole)
|
|
13680
14083
|
});
|
|
13681
14084
|
var preRequirementNotificationSchema = baseNotificationSchema.extend({
|
|
13682
|
-
notificationType: import_zod24.z.literal("
|
|
14085
|
+
notificationType: import_zod24.z.literal("requirementInstructionDue" /* REQUIREMENT_INSTRUCTION_DUE */),
|
|
13683
14086
|
treatmentId: import_zod24.z.string(),
|
|
13684
14087
|
requirements: import_zod24.z.array(import_zod24.z.string()),
|
|
13685
14088
|
deadline: import_zod24.z.any()
|
|
13686
14089
|
// Timestamp
|
|
13687
14090
|
});
|
|
13688
14091
|
var postRequirementNotificationSchema = baseNotificationSchema.extend({
|
|
13689
|
-
notificationType: import_zod24.z.literal("
|
|
14092
|
+
notificationType: import_zod24.z.literal("requirementInstructionDue" /* REQUIREMENT_INSTRUCTION_DUE */),
|
|
13690
14093
|
treatmentId: import_zod24.z.string(),
|
|
13691
14094
|
requirements: import_zod24.z.array(import_zod24.z.string()),
|
|
13692
14095
|
deadline: import_zod24.z.any()
|
|
@@ -13701,7 +14104,7 @@ var appointmentReminderNotificationSchema = baseNotificationSchema.extend({
|
|
|
13701
14104
|
doctorName: import_zod24.z.string()
|
|
13702
14105
|
});
|
|
13703
14106
|
var appointmentNotificationSchema = baseNotificationSchema.extend({
|
|
13704
|
-
notificationType: import_zod24.z.literal("
|
|
14107
|
+
notificationType: import_zod24.z.literal("appointmentStatusChange" /* APPOINTMENT_STATUS_CHANGE */),
|
|
13705
14108
|
appointmentId: import_zod24.z.string(),
|
|
13706
14109
|
appointmentStatus: import_zod24.z.string(),
|
|
13707
14110
|
previousStatus: import_zod24.z.string(),
|
|
@@ -13798,9 +14201,13 @@ var RequirementType = /* @__PURE__ */ ((RequirementType2) => {
|
|
|
13798
14201
|
PATIENT_LOCATION_INFO_COLLECTION,
|
|
13799
14202
|
PATIENT_MEDICAL_HISTORY_COLLECTION,
|
|
13800
14203
|
PATIENT_MEDICAL_INFO_COLLECTION,
|
|
14204
|
+
PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME,
|
|
13801
14205
|
PATIENT_SENSITIVE_INFO_COLLECTION,
|
|
13802
14206
|
PRACTITIONERS_COLLECTION,
|
|
13803
14207
|
PROCEDURES_COLLECTION,
|
|
14208
|
+
PatientInstructionStatus,
|
|
14209
|
+
PatientRequirementOverallStatus,
|
|
14210
|
+
PatientRequirementsService,
|
|
13804
14211
|
PatientService,
|
|
13805
14212
|
PaymentStatus,
|
|
13806
14213
|
PracticeType,
|
|
@@ -13865,6 +14272,7 @@ var RequirementType = /* @__PURE__ */ ((RequirementType2) => {
|
|
|
13865
14272
|
createDefaultClinicGroupSchema,
|
|
13866
14273
|
createDocumentTemplateSchema,
|
|
13867
14274
|
createDraftPractitionerSchema,
|
|
14275
|
+
createFilledDocumentDataSchema,
|
|
13868
14276
|
createPatientLocationInfoSchema,
|
|
13869
14277
|
createPatientMedicalInfoSchema,
|
|
13870
14278
|
createPatientProfileSchema,
|
|
@@ -13880,6 +14288,8 @@ var RequirementType = /* @__PURE__ */ ((RequirementType2) => {
|
|
|
13880
14288
|
documentTemplateSchema,
|
|
13881
14289
|
emailSchema,
|
|
13882
14290
|
emergencyContactSchema,
|
|
14291
|
+
filledDocumentSchema,
|
|
14292
|
+
filledDocumentStatusSchema,
|
|
13883
14293
|
gamificationSchema,
|
|
13884
14294
|
getFirebaseApp,
|
|
13885
14295
|
getFirebaseAuth,
|
|
@@ -13929,6 +14339,7 @@ var RequirementType = /* @__PURE__ */ ((RequirementType2) => {
|
|
|
13929
14339
|
updateClinicSchema,
|
|
13930
14340
|
updateContraindicationSchema,
|
|
13931
14341
|
updateDocumentTemplateSchema,
|
|
14342
|
+
updateFilledDocumentDataSchema,
|
|
13932
14343
|
updateMedicationSchema,
|
|
13933
14344
|
updatePatientMedicalInfoSchema,
|
|
13934
14345
|
updateVitalStatsSchema,
|