@blackcode_sa/metaestetics-api 1.6.2 → 1.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/index.d.mts +228 -25
- package/dist/admin/index.d.ts +228 -25
- package/dist/admin/index.js +35867 -2493
- package/dist/admin/index.mjs +35856 -2464
- package/dist/backoffice/index.d.mts +252 -1
- package/dist/backoffice/index.d.ts +252 -1
- package/dist/backoffice/index.js +86 -12
- package/dist/backoffice/index.mjs +86 -13
- package/dist/index.d.mts +1417 -554
- package/dist/index.d.ts +1417 -554
- package/dist/index.js +1393 -687
- package/dist/index.mjs +1423 -711
- package/package.json +1 -1
- 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/index.ts +16 -1
- package/src/services/appointment/appointment.service.ts +315 -86
- 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/patient.service.ts +31 -1
- package/src/services/patient/patientRequirements.service.ts +285 -0
- package/src/services/patient/utils/practitioner.utils.ts +79 -1
- package/src/types/appointment/index.ts +134 -10
- 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/index.ts +6 -0
- package/src/types/patient/patient-requirements.ts +81 -0
- package/src/validations/appointment.schema.ts +300 -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/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"
|
|
262
572
|
),
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
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
|
+
calendarEventId: import_zod2.z.string().min(MIN_STRING_LENGTH, "Calendar event ID is required"),
|
|
577
|
+
clinicBranchId: import_zod2.z.string().min(MIN_STRING_LENGTH, "Clinic branch ID is required"),
|
|
578
|
+
practitionerId: import_zod2.z.string().min(MIN_STRING_LENGTH, "Practitioner ID is required"),
|
|
579
|
+
patientId: import_zod2.z.string().min(MIN_STRING_LENGTH, "Patient ID is required"),
|
|
580
|
+
procedureId: import_zod2.z.string().min(MIN_STRING_LENGTH, "Procedure ID is required"),
|
|
581
|
+
appointmentStartTime: import_zod2.z.any().refine(
|
|
582
|
+
(val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
|
|
583
|
+
"Appointment start time must be a valid timestamp or Date object"
|
|
266
584
|
),
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
585
|
+
appointmentEndTime: import_zod2.z.any().refine(
|
|
586
|
+
(val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
|
|
587
|
+
"Appointment end time must be a valid timestamp or Date object"
|
|
588
|
+
),
|
|
589
|
+
cost: import_zod2.z.number().min(0, "Cost must be a non-negative number"),
|
|
590
|
+
currency: import_zod2.z.string().min(1, "Currency is required"),
|
|
591
|
+
patientNotes: import_zod2.z.string().max(MAX_STRING_LENGTH, "Patient notes too long").nullable().optional(),
|
|
592
|
+
initialStatus: appointmentStatusSchema,
|
|
593
|
+
initialPaymentStatus: paymentStatusSchema.optional().default("unpaid" /* UNPAID */)
|
|
594
|
+
}).refine((data) => data.appointmentEndTime > data.appointmentStartTime, {
|
|
595
|
+
message: "Appointment end time must be after start time",
|
|
596
|
+
path: ["appointmentEndTime"]
|
|
276
597
|
});
|
|
277
|
-
var updateAppointmentSchema =
|
|
278
|
-
status:
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
598
|
+
var updateAppointmentSchema = import_zod2.z.object({
|
|
599
|
+
status: appointmentStatusSchema.optional(),
|
|
600
|
+
confirmationTime: import_zod2.z.any().optional().nullable(),
|
|
601
|
+
cancellationTime: import_zod2.z.any().optional().nullable(),
|
|
602
|
+
rescheduleTime: import_zod2.z.any().optional().nullable(),
|
|
603
|
+
procedureActualStartTime: import_zod2.z.any().optional().nullable(),
|
|
604
|
+
actualDurationMinutes: import_zod2.z.number().int().positive("Duration must be a positive integer").optional(),
|
|
605
|
+
cancellationReason: import_zod2.z.string().max(MAX_STRING_LENGTH, "Cancellation reason too long").nullable().optional(),
|
|
606
|
+
canceledBy: import_zod2.z.enum(["patient", "clinic", "practitioner", "system"]).optional(),
|
|
607
|
+
internalNotes: import_zod2.z.string().max(MAX_STRING_LENGTH_LONG, "Internal notes too long").nullable().optional(),
|
|
608
|
+
patientNotes: import_zod2.z.any().optional().nullable(),
|
|
609
|
+
paymentStatus: paymentStatusSchema.optional(),
|
|
610
|
+
paymentTransactionId: import_zod2.z.any().optional().nullable(),
|
|
611
|
+
completedPreRequirements: import_zod2.z.union([import_zod2.z.array(import_zod2.z.string()), import_zod2.z.any()]).optional(),
|
|
612
|
+
completedPostRequirements: 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;
|
|
322
682
|
},
|
|
323
683
|
{
|
|
324
|
-
message: "At least one of patientId, practitionerId, or clinicBranchId must be provided",
|
|
325
|
-
path: ["
|
|
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;
|
|
693
|
+
},
|
|
694
|
+
{
|
|
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}`
|
|
@@ -2294,6 +2487,51 @@ var getPatientsByPractitionerUtil = async (db, practitionerId, options) => {
|
|
|
2294
2487
|
);
|
|
2295
2488
|
}
|
|
2296
2489
|
};
|
|
2490
|
+
var getPatientsByPractitionerWithDetailsUtil = async (db, practitionerId, options) => {
|
|
2491
|
+
try {
|
|
2492
|
+
console.log(
|
|
2493
|
+
`[getPatientsByPractitionerWithDetailsUtil] Fetching detailed patient profiles for practitioner ID: ${practitionerId} with options:`,
|
|
2494
|
+
options
|
|
2495
|
+
);
|
|
2496
|
+
const patientProfiles = await getPatientsByPractitionerUtil(
|
|
2497
|
+
db,
|
|
2498
|
+
practitionerId,
|
|
2499
|
+
options
|
|
2500
|
+
);
|
|
2501
|
+
const patientProfilesWithDetails = await Promise.all(
|
|
2502
|
+
patientProfiles.map(async (profile) => {
|
|
2503
|
+
try {
|
|
2504
|
+
const sensitiveInfoDoc = await (0, import_firestore9.getDoc)(
|
|
2505
|
+
getSensitiveInfoDocRef(db, profile.id)
|
|
2506
|
+
);
|
|
2507
|
+
const sensitiveInfo = sensitiveInfoDoc.exists() ? sensitiveInfoDoc.data() : void 0;
|
|
2508
|
+
return {
|
|
2509
|
+
patientProfile: profile,
|
|
2510
|
+
patientSensitiveInfo: sensitiveInfo
|
|
2511
|
+
};
|
|
2512
|
+
} catch (error) {
|
|
2513
|
+
console.error(
|
|
2514
|
+
`[getPatientsByPractitionerWithDetailsUtil] Error fetching sensitive info for patient ${profile.id}:`,
|
|
2515
|
+
error
|
|
2516
|
+
);
|
|
2517
|
+
return { patientProfile: profile };
|
|
2518
|
+
}
|
|
2519
|
+
})
|
|
2520
|
+
);
|
|
2521
|
+
console.log(
|
|
2522
|
+
`[getPatientsByPractitionerWithDetailsUtil] Found ${patientProfilesWithDetails.length} detailed patient profiles for practitioner ID: ${practitionerId}`
|
|
2523
|
+
);
|
|
2524
|
+
return patientProfilesWithDetails;
|
|
2525
|
+
} catch (error) {
|
|
2526
|
+
console.error(
|
|
2527
|
+
`[getPatientsByPractitionerWithDetailsUtil] Error fetching detailed patient profiles:`,
|
|
2528
|
+
error
|
|
2529
|
+
);
|
|
2530
|
+
throw new Error(
|
|
2531
|
+
`Failed to retrieve detailed patient profiles: ${error instanceof Error ? error.message : String(error)}`
|
|
2532
|
+
);
|
|
2533
|
+
}
|
|
2534
|
+
};
|
|
2297
2535
|
|
|
2298
2536
|
// src/services/patient/utils/clinic.utils.ts
|
|
2299
2537
|
var import_firestore10 = require("firebase/firestore");
|
|
@@ -2321,8 +2559,8 @@ var getPatientsByClinicUtil = async (db, clinicId, options) => {
|
|
|
2321
2559
|
}
|
|
2322
2560
|
const patientsSnapshot = await (0, import_firestore10.getDocs)(q);
|
|
2323
2561
|
const patients = [];
|
|
2324
|
-
patientsSnapshot.forEach((
|
|
2325
|
-
patients.push(
|
|
2562
|
+
patientsSnapshot.forEach((doc33) => {
|
|
2563
|
+
patients.push(doc33.data());
|
|
2326
2564
|
});
|
|
2327
2565
|
console.log(
|
|
2328
2566
|
`[getPatientsByClinicUtil] Found ${patients.length} patients for clinic ID: ${clinicId}`
|
|
@@ -2622,6 +2860,25 @@ var PatientService = class extends BaseService {
|
|
|
2622
2860
|
);
|
|
2623
2861
|
return getPatientsByPractitionerUtil(this.db, practitionerId, options);
|
|
2624
2862
|
}
|
|
2863
|
+
/**
|
|
2864
|
+
* Gets all patients associated with a specific practitioner with their sensitive information.
|
|
2865
|
+
*
|
|
2866
|
+
* @param {string} practitionerId - ID of the practitioner whose patients to retrieve
|
|
2867
|
+
* @param {Object} options - Optional parameters for pagination
|
|
2868
|
+
* @param {number} options.limit - Maximum number of profiles to return
|
|
2869
|
+
* @param {string} options.startAfter - The ID of the document to start after (for pagination)
|
|
2870
|
+
* @returns {Promise<PatientProfileForDoctor[]>} A promise resolving to an array of patient profiles with sensitive info
|
|
2871
|
+
*/
|
|
2872
|
+
async getPatientsByPractitionerWithDetails(practitionerId, options) {
|
|
2873
|
+
console.log(
|
|
2874
|
+
`[PatientService.getPatientsByPractitionerWithDetails] Fetching detailed patient profiles for practitioner: ${practitionerId}`
|
|
2875
|
+
);
|
|
2876
|
+
return getPatientsByPractitionerWithDetailsUtil(
|
|
2877
|
+
this.db,
|
|
2878
|
+
practitionerId,
|
|
2879
|
+
options
|
|
2880
|
+
);
|
|
2881
|
+
}
|
|
2625
2882
|
/**
|
|
2626
2883
|
* Gets all patients associated with a specific clinic.
|
|
2627
2884
|
*
|
|
@@ -3416,7 +3673,7 @@ async function getClinicAdminsByGroup(db, clinicGroupId) {
|
|
|
3416
3673
|
(0, import_firestore13.where)("clinicGroupId", "==", clinicGroupId)
|
|
3417
3674
|
);
|
|
3418
3675
|
const querySnapshot = await (0, import_firestore13.getDocs)(q);
|
|
3419
|
-
return querySnapshot.docs.map((
|
|
3676
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
3420
3677
|
}
|
|
3421
3678
|
async function updateClinicAdmin(db, adminId, data) {
|
|
3422
3679
|
const admin = await getClinicAdmin(db, adminId);
|
|
@@ -3677,6 +3934,8 @@ var ClinicAdminService = class extends BaseService {
|
|
|
3677
3934
|
this.getClinicService()
|
|
3678
3935
|
);
|
|
3679
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
|
|
3680
3939
|
};
|
|
3681
3940
|
|
|
3682
3941
|
// src/services/practitioner/practitioner.service.ts
|
|
@@ -4113,7 +4372,7 @@ var PractitionerService = class extends BaseService {
|
|
|
4113
4372
|
(0, import_firestore15.where)("expiresAt", ">", import_firestore15.Timestamp.now())
|
|
4114
4373
|
);
|
|
4115
4374
|
const querySnapshot = await (0, import_firestore15.getDocs)(q);
|
|
4116
|
-
return querySnapshot.docs.map((
|
|
4375
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
4117
4376
|
}
|
|
4118
4377
|
/**
|
|
4119
4378
|
* Gets a token by its string value and validates it
|
|
@@ -4196,7 +4455,7 @@ var PractitionerService = class extends BaseService {
|
|
|
4196
4455
|
(0, import_firestore15.where)("status", "==", "active" /* ACTIVE */)
|
|
4197
4456
|
);
|
|
4198
4457
|
const querySnapshot = await (0, import_firestore15.getDocs)(q);
|
|
4199
|
-
return querySnapshot.docs.map((
|
|
4458
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
4200
4459
|
}
|
|
4201
4460
|
/**
|
|
4202
4461
|
* Dohvata sve zdravstvene radnike za određenu kliniku
|
|
@@ -4208,7 +4467,7 @@ var PractitionerService = class extends BaseService {
|
|
|
4208
4467
|
(0, import_firestore15.where)("isActive", "==", true)
|
|
4209
4468
|
);
|
|
4210
4469
|
const querySnapshot = await (0, import_firestore15.getDocs)(q);
|
|
4211
|
-
return querySnapshot.docs.map((
|
|
4470
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
4212
4471
|
}
|
|
4213
4472
|
/**
|
|
4214
4473
|
* Dohvata sve draft zdravstvene radnike za određenu kliniku sa statusom DRAFT
|
|
@@ -4220,7 +4479,7 @@ var PractitionerService = class extends BaseService {
|
|
|
4220
4479
|
(0, import_firestore15.where)("status", "==", "draft" /* DRAFT */)
|
|
4221
4480
|
);
|
|
4222
4481
|
const querySnapshot = await (0, import_firestore15.getDocs)(q);
|
|
4223
|
-
return querySnapshot.docs.map((
|
|
4482
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
4224
4483
|
}
|
|
4225
4484
|
/**
|
|
4226
4485
|
* Updates a practitioner
|
|
@@ -4402,7 +4661,7 @@ var PractitionerService = class extends BaseService {
|
|
|
4402
4661
|
);
|
|
4403
4662
|
const querySnapshot = await (0, import_firestore15.getDocs)(q);
|
|
4404
4663
|
const practitioners = querySnapshot.docs.map(
|
|
4405
|
-
(
|
|
4664
|
+
(doc33) => doc33.data()
|
|
4406
4665
|
);
|
|
4407
4666
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
4408
4667
|
return {
|
|
@@ -4473,8 +4732,8 @@ var PractitionerService = class extends BaseService {
|
|
|
4473
4732
|
console.log(
|
|
4474
4733
|
`[PRACTITIONER_SERVICE] Found ${querySnapshot.docs.length} practitioners with base query`
|
|
4475
4734
|
);
|
|
4476
|
-
let practitioners = querySnapshot.docs.map((
|
|
4477
|
-
return { ...
|
|
4735
|
+
let practitioners = querySnapshot.docs.map((doc33) => {
|
|
4736
|
+
return { ...doc33.data(), id: doc33.id };
|
|
4478
4737
|
});
|
|
4479
4738
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
4480
4739
|
if (filters.nameSearch && filters.nameSearch.trim() !== "") {
|
|
@@ -4728,7 +4987,7 @@ var UserService = class extends BaseService {
|
|
|
4728
4987
|
];
|
|
4729
4988
|
const q = (0, import_firestore16.query)((0, import_firestore16.collection)(this.db, USERS_COLLECTION), ...constraints);
|
|
4730
4989
|
const querySnapshot = await (0, import_firestore16.getDocs)(q);
|
|
4731
|
-
const users = querySnapshot.docs.map((
|
|
4990
|
+
const users = querySnapshot.docs.map((doc33) => doc33.data());
|
|
4732
4991
|
return Promise.all(users.map((userData) => userSchema.parse(userData)));
|
|
4733
4992
|
}
|
|
4734
4993
|
/**
|
|
@@ -5092,7 +5351,7 @@ async function getAllActiveGroups(db) {
|
|
|
5092
5351
|
(0, import_firestore17.where)("isActive", "==", true)
|
|
5093
5352
|
);
|
|
5094
5353
|
const querySnapshot = await (0, import_firestore17.getDocs)(q);
|
|
5095
|
-
return querySnapshot.docs.map((
|
|
5354
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
5096
5355
|
}
|
|
5097
5356
|
async function updateClinicGroup(db, groupId, data, app) {
|
|
5098
5357
|
console.log("[CLINIC_GROUP] Updating clinic group", { groupId });
|
|
@@ -5464,6 +5723,11 @@ var ClinicGroupService = class extends BaseService {
|
|
|
5464
5723
|
this.app
|
|
5465
5724
|
);
|
|
5466
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
|
|
5467
5731
|
};
|
|
5468
5732
|
|
|
5469
5733
|
// src/services/clinic/clinic.service.ts
|
|
@@ -5490,7 +5754,7 @@ async function getClinicsByGroup(db, groupId) {
|
|
|
5490
5754
|
(0, import_firestore18.where)("isActive", "==", true)
|
|
5491
5755
|
);
|
|
5492
5756
|
const querySnapshot = await (0, import_firestore18.getDocs)(q);
|
|
5493
|
-
return querySnapshot.docs.map((
|
|
5757
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
5494
5758
|
}
|
|
5495
5759
|
async function updateClinic(db, clinicId, data, adminId, clinicAdminService, app) {
|
|
5496
5760
|
console.log("[CLINIC] Starting clinic update", { clinicId, adminId });
|
|
@@ -5684,7 +5948,7 @@ async function getClinicsByAdmin(db, adminId, options = {}, clinicAdminService,
|
|
|
5684
5948
|
}
|
|
5685
5949
|
const q = (0, import_firestore18.query)((0, import_firestore18.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
5686
5950
|
const querySnapshot = await (0, import_firestore18.getDocs)(q);
|
|
5687
|
-
return querySnapshot.docs.map((
|
|
5951
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
5688
5952
|
}
|
|
5689
5953
|
async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGroupService) {
|
|
5690
5954
|
return getClinicsByAdmin(
|
|
@@ -5729,11 +5993,11 @@ async function getAllClinics(db, pagination, lastDoc) {
|
|
|
5729
5993
|
}
|
|
5730
5994
|
const clinicsSnapshot = await (0, import_firestore18.getDocs)(clinicsQuery);
|
|
5731
5995
|
const lastVisible = clinicsSnapshot.docs[clinicsSnapshot.docs.length - 1];
|
|
5732
|
-
const clinics = clinicsSnapshot.docs.map((
|
|
5733
|
-
const data =
|
|
5996
|
+
const clinics = clinicsSnapshot.docs.map((doc33) => {
|
|
5997
|
+
const data = doc33.data();
|
|
5734
5998
|
return {
|
|
5735
5999
|
...data,
|
|
5736
|
-
id:
|
|
6000
|
+
id: doc33.id
|
|
5737
6001
|
};
|
|
5738
6002
|
});
|
|
5739
6003
|
return {
|
|
@@ -5760,8 +6024,8 @@ async function getAllClinicsInRange(db, center, rangeInKm, pagination, lastDoc)
|
|
|
5760
6024
|
];
|
|
5761
6025
|
const q = (0, import_firestore18.query)((0, import_firestore18.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
5762
6026
|
const querySnapshot = await (0, import_firestore18.getDocs)(q);
|
|
5763
|
-
for (const
|
|
5764
|
-
const clinic =
|
|
6027
|
+
for (const doc33 of querySnapshot.docs) {
|
|
6028
|
+
const clinic = doc33.data();
|
|
5765
6029
|
const distance = (0, import_geofire_common4.distanceBetween)(
|
|
5766
6030
|
[center.latitude, center.longitude],
|
|
5767
6031
|
[clinic.location.latitude, clinic.location.longitude]
|
|
@@ -5878,8 +6142,8 @@ async function findClinicsInRadius(db, center, radiusInKm, filters) {
|
|
|
5878
6142
|
}
|
|
5879
6143
|
const q = (0, import_firestore19.query)((0, import_firestore19.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
5880
6144
|
const querySnapshot = await (0, import_firestore19.getDocs)(q);
|
|
5881
|
-
for (const
|
|
5882
|
-
const clinic =
|
|
6145
|
+
for (const doc33 of querySnapshot.docs) {
|
|
6146
|
+
const clinic = doc33.data();
|
|
5883
6147
|
const distance = (0, import_geofire_common5.distanceBetween)(
|
|
5884
6148
|
[center.latitude, center.longitude],
|
|
5885
6149
|
[clinic.location.latitude, clinic.location.longitude]
|
|
@@ -5967,8 +6231,8 @@ async function getClinicsByFilters(db, filters) {
|
|
|
5967
6231
|
console.log(
|
|
5968
6232
|
`[FILTER_UTILS] Found ${querySnapshot.docs.length} clinics in geo bound`
|
|
5969
6233
|
);
|
|
5970
|
-
for (const
|
|
5971
|
-
const clinic = { ...
|
|
6234
|
+
for (const doc33 of querySnapshot.docs) {
|
|
6235
|
+
const clinic = { ...doc33.data(), id: doc33.id };
|
|
5972
6236
|
const distance = (0, import_geofire_common6.distanceBetween)(
|
|
5973
6237
|
[center.latitude, center.longitude],
|
|
5974
6238
|
[clinic.location.latitude, clinic.location.longitude]
|
|
@@ -6024,8 +6288,8 @@ async function getClinicsByFilters(db, filters) {
|
|
|
6024
6288
|
console.log(
|
|
6025
6289
|
`[FILTER_UTILS] Found ${querySnapshot.docs.length} clinics with regular query`
|
|
6026
6290
|
);
|
|
6027
|
-
const clinics = querySnapshot.docs.map((
|
|
6028
|
-
return { ...
|
|
6291
|
+
const clinics = querySnapshot.docs.map((doc33) => {
|
|
6292
|
+
return { ...doc33.data(), id: doc33.id };
|
|
6029
6293
|
});
|
|
6030
6294
|
let filteredClinics = clinics;
|
|
6031
6295
|
if (filters.center) {
|
|
@@ -7237,17 +7501,28 @@ var import_firestore23 = require("firebase/firestore");
|
|
|
7237
7501
|
|
|
7238
7502
|
// src/types/notifications/index.ts
|
|
7239
7503
|
var NotificationType = /* @__PURE__ */ ((NotificationType3) => {
|
|
7240
|
-
NotificationType3["PRE_REQUIREMENT"] = "preRequirement";
|
|
7241
|
-
NotificationType3["POST_REQUIREMENT"] = "postRequirement";
|
|
7242
7504
|
NotificationType3["APPOINTMENT_REMINDER"] = "appointmentReminder";
|
|
7243
|
-
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";
|
|
7244
7517
|
return NotificationType3;
|
|
7245
7518
|
})(NotificationType || {});
|
|
7246
7519
|
var NOTIFICATIONS_COLLECTION = "notifications";
|
|
7247
7520
|
var NotificationStatus = /* @__PURE__ */ ((NotificationStatus2) => {
|
|
7248
7521
|
NotificationStatus2["PENDING"] = "pending";
|
|
7522
|
+
NotificationStatus2["PROCESSING"] = "processing";
|
|
7249
7523
|
NotificationStatus2["SENT"] = "sent";
|
|
7250
7524
|
NotificationStatus2["FAILED"] = "failed";
|
|
7525
|
+
NotificationStatus2["DELIVERED"] = "delivered";
|
|
7251
7526
|
NotificationStatus2["CANCELLED"] = "cancelled";
|
|
7252
7527
|
NotificationStatus2["PARTIAL_SUCCESS"] = "partialSuccess";
|
|
7253
7528
|
return NotificationStatus2;
|
|
@@ -7303,9 +7578,9 @@ var NotificationService = class extends BaseService {
|
|
|
7303
7578
|
(0, import_firestore23.orderBy)("notificationTime", "desc")
|
|
7304
7579
|
);
|
|
7305
7580
|
const querySnapshot = await (0, import_firestore23.getDocs)(q);
|
|
7306
|
-
return querySnapshot.docs.map((
|
|
7307
|
-
id:
|
|
7308
|
-
...
|
|
7581
|
+
return querySnapshot.docs.map((doc33) => ({
|
|
7582
|
+
id: doc33.id,
|
|
7583
|
+
...doc33.data()
|
|
7309
7584
|
}));
|
|
7310
7585
|
}
|
|
7311
7586
|
/**
|
|
@@ -7319,9 +7594,9 @@ var NotificationService = class extends BaseService {
|
|
|
7319
7594
|
(0, import_firestore23.orderBy)("notificationTime", "desc")
|
|
7320
7595
|
);
|
|
7321
7596
|
const querySnapshot = await (0, import_firestore23.getDocs)(q);
|
|
7322
|
-
return querySnapshot.docs.map((
|
|
7323
|
-
id:
|
|
7324
|
-
...
|
|
7597
|
+
return querySnapshot.docs.map((doc33) => ({
|
|
7598
|
+
id: doc33.id,
|
|
7599
|
+
...doc33.data()
|
|
7325
7600
|
}));
|
|
7326
7601
|
}
|
|
7327
7602
|
/**
|
|
@@ -7393,9 +7668,9 @@ var NotificationService = class extends BaseService {
|
|
|
7393
7668
|
(0, import_firestore23.orderBy)("notificationTime", "desc")
|
|
7394
7669
|
);
|
|
7395
7670
|
const querySnapshot = await (0, import_firestore23.getDocs)(q);
|
|
7396
|
-
return querySnapshot.docs.map((
|
|
7397
|
-
id:
|
|
7398
|
-
...
|
|
7671
|
+
return querySnapshot.docs.map((doc33) => ({
|
|
7672
|
+
id: doc33.id,
|
|
7673
|
+
...doc33.data()
|
|
7399
7674
|
}));
|
|
7400
7675
|
}
|
|
7401
7676
|
/**
|
|
@@ -7408,9 +7683,9 @@ var NotificationService = class extends BaseService {
|
|
|
7408
7683
|
(0, import_firestore23.orderBy)("notificationTime", "desc")
|
|
7409
7684
|
);
|
|
7410
7685
|
const querySnapshot = await (0, import_firestore23.getDocs)(q);
|
|
7411
|
-
return querySnapshot.docs.map((
|
|
7412
|
-
id:
|
|
7413
|
-
...
|
|
7686
|
+
return querySnapshot.docs.map((doc33) => ({
|
|
7687
|
+
id: doc33.id,
|
|
7688
|
+
...doc33.data()
|
|
7414
7689
|
}));
|
|
7415
7690
|
}
|
|
7416
7691
|
};
|
|
@@ -7627,7 +7902,7 @@ var ProcedureService = class extends BaseService {
|
|
|
7627
7902
|
(0, import_firestore24.where)("isActive", "==", true)
|
|
7628
7903
|
);
|
|
7629
7904
|
const snapshot = await (0, import_firestore24.getDocs)(q);
|
|
7630
|
-
return snapshot.docs.map((
|
|
7905
|
+
return snapshot.docs.map((doc33) => doc33.data());
|
|
7631
7906
|
}
|
|
7632
7907
|
/**
|
|
7633
7908
|
* Gets all procedures for a practitioner
|
|
@@ -7641,7 +7916,7 @@ var ProcedureService = class extends BaseService {
|
|
|
7641
7916
|
(0, import_firestore24.where)("isActive", "==", true)
|
|
7642
7917
|
);
|
|
7643
7918
|
const snapshot = await (0, import_firestore24.getDocs)(q);
|
|
7644
|
-
return snapshot.docs.map((
|
|
7919
|
+
return snapshot.docs.map((doc33) => doc33.data());
|
|
7645
7920
|
}
|
|
7646
7921
|
/**
|
|
7647
7922
|
* Updates a procedure
|
|
@@ -7824,20 +8099,20 @@ var ProcedureService = class extends BaseService {
|
|
|
7824
8099
|
const proceduresCollection = (0, import_firestore24.collection)(this.db, PROCEDURES_COLLECTION);
|
|
7825
8100
|
let proceduresQuery = (0, import_firestore24.query)(proceduresCollection);
|
|
7826
8101
|
if (pagination && pagination > 0) {
|
|
7827
|
-
const { limit:
|
|
8102
|
+
const { limit: limit12, startAfter: startAfter12 } = await import("firebase/firestore");
|
|
7828
8103
|
if (lastDoc) {
|
|
7829
8104
|
proceduresQuery = (0, import_firestore24.query)(
|
|
7830
8105
|
proceduresCollection,
|
|
7831
8106
|
(0, import_firestore24.orderBy)("name"),
|
|
7832
8107
|
// Use imported orderBy
|
|
7833
|
-
|
|
7834
|
-
|
|
8108
|
+
startAfter12(lastDoc),
|
|
8109
|
+
limit12(pagination)
|
|
7835
8110
|
);
|
|
7836
8111
|
} else {
|
|
7837
8112
|
proceduresQuery = (0, import_firestore24.query)(
|
|
7838
8113
|
proceduresCollection,
|
|
7839
8114
|
(0, import_firestore24.orderBy)("name"),
|
|
7840
|
-
|
|
8115
|
+
limit12(pagination)
|
|
7841
8116
|
);
|
|
7842
8117
|
}
|
|
7843
8118
|
} else {
|
|
@@ -7845,11 +8120,11 @@ var ProcedureService = class extends BaseService {
|
|
|
7845
8120
|
}
|
|
7846
8121
|
const proceduresSnapshot = await (0, import_firestore24.getDocs)(proceduresQuery);
|
|
7847
8122
|
const lastVisible = proceduresSnapshot.docs[proceduresSnapshot.docs.length - 1];
|
|
7848
|
-
const procedures = proceduresSnapshot.docs.map((
|
|
7849
|
-
const data =
|
|
8123
|
+
const procedures = proceduresSnapshot.docs.map((doc33) => {
|
|
8124
|
+
const data = doc33.data();
|
|
7850
8125
|
return {
|
|
7851
8126
|
...data,
|
|
7852
|
-
id:
|
|
8127
|
+
id: doc33.id
|
|
7853
8128
|
// Ensure ID is present
|
|
7854
8129
|
};
|
|
7855
8130
|
});
|
|
@@ -7931,8 +8206,8 @@ var ProcedureService = class extends BaseService {
|
|
|
7931
8206
|
console.log(
|
|
7932
8207
|
`[PROCEDURE_SERVICE] Found ${querySnapshot.docs.length} procedures in geo bound`
|
|
7933
8208
|
);
|
|
7934
|
-
for (const
|
|
7935
|
-
const procedure = { ...
|
|
8209
|
+
for (const doc33 of querySnapshot.docs) {
|
|
8210
|
+
const procedure = { ...doc33.data(), id: doc33.id };
|
|
7936
8211
|
const distance = (0, import_geofire_common8.distanceBetween)(
|
|
7937
8212
|
[center.latitude, center.longitude],
|
|
7938
8213
|
[
|
|
@@ -7983,8 +8258,8 @@ var ProcedureService = class extends BaseService {
|
|
|
7983
8258
|
console.log(
|
|
7984
8259
|
`[PROCEDURE_SERVICE] Found ${querySnapshot.docs.length} procedures with regular query`
|
|
7985
8260
|
);
|
|
7986
|
-
const procedures = querySnapshot.docs.map((
|
|
7987
|
-
return { ...
|
|
8261
|
+
const procedures = querySnapshot.docs.map((doc33) => {
|
|
8262
|
+
return { ...doc33.data(), id: doc33.id };
|
|
7988
8263
|
});
|
|
7989
8264
|
if (filters.location) {
|
|
7990
8265
|
const center = filters.location;
|
|
@@ -8124,7 +8399,10 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
8124
8399
|
createdBy: userId,
|
|
8125
8400
|
version: 1,
|
|
8126
8401
|
isActive: true,
|
|
8127
|
-
tags: validatedData.tags || []
|
|
8402
|
+
tags: validatedData.tags || [],
|
|
8403
|
+
isUserForm: validatedData.isUserForm || false,
|
|
8404
|
+
isRequired: validatedData.isRequired || false,
|
|
8405
|
+
sortingOrder: validatedData.sortingOrder || 0
|
|
8128
8406
|
};
|
|
8129
8407
|
const docRef = (0, import_firestore25.doc)(this.collectionRef, templateId);
|
|
8130
8408
|
await (0, import_firestore25.setDoc)(docRef, template);
|
|
@@ -8159,21 +8437,31 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
8159
8437
|
if (validatedData.elements) {
|
|
8160
8438
|
updatedElements = validatedData.elements.map((element) => ({
|
|
8161
8439
|
...element,
|
|
8162
|
-
id: this.generateId()
|
|
8440
|
+
id: element.id || this.generateId()
|
|
8163
8441
|
}));
|
|
8164
8442
|
}
|
|
8165
|
-
const
|
|
8166
|
-
...validatedData,
|
|
8443
|
+
const updatePayload = {
|
|
8167
8444
|
elements: updatedElements,
|
|
8168
8445
|
updatedAt: Date.now(),
|
|
8169
8446
|
version: template.version + 1
|
|
8170
8447
|
};
|
|
8448
|
+
if (validatedData.title !== void 0)
|
|
8449
|
+
updatePayload.title = validatedData.title;
|
|
8450
|
+
if (validatedData.description !== void 0)
|
|
8451
|
+
updatePayload.description = validatedData.description;
|
|
8452
|
+
if (validatedData.isActive !== void 0)
|
|
8453
|
+
updatePayload.isActive = validatedData.isActive;
|
|
8454
|
+
if (validatedData.tags !== void 0)
|
|
8455
|
+
updatePayload.tags = validatedData.tags;
|
|
8456
|
+
if (validatedData.isUserForm !== void 0)
|
|
8457
|
+
updatePayload.isUserForm = validatedData.isUserForm;
|
|
8458
|
+
if (validatedData.isRequired !== void 0)
|
|
8459
|
+
updatePayload.isRequired = validatedData.isRequired;
|
|
8460
|
+
if (validatedData.sortingOrder !== void 0)
|
|
8461
|
+
updatePayload.sortingOrder = validatedData.sortingOrder;
|
|
8171
8462
|
const docRef = (0, import_firestore25.doc)(this.collectionRef, templateId);
|
|
8172
|
-
await (0, import_firestore25.updateDoc)(docRef,
|
|
8173
|
-
return {
|
|
8174
|
-
...template,
|
|
8175
|
-
...updateData
|
|
8176
|
-
};
|
|
8463
|
+
await (0, import_firestore25.updateDoc)(docRef, updatePayload);
|
|
8464
|
+
return { ...template, ...updatePayload };
|
|
8177
8465
|
}
|
|
8178
8466
|
/**
|
|
8179
8467
|
* Delete a document template
|
|
@@ -8202,9 +8490,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
8202
8490
|
const querySnapshot = await (0, import_firestore25.getDocs)(q);
|
|
8203
8491
|
const templates = [];
|
|
8204
8492
|
let lastVisible = null;
|
|
8205
|
-
querySnapshot.forEach((
|
|
8206
|
-
templates.push(
|
|
8207
|
-
lastVisible =
|
|
8493
|
+
querySnapshot.forEach((doc33) => {
|
|
8494
|
+
templates.push(doc33.data());
|
|
8495
|
+
lastVisible = doc33;
|
|
8208
8496
|
});
|
|
8209
8497
|
return {
|
|
8210
8498
|
templates,
|
|
@@ -8232,9 +8520,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
8232
8520
|
const querySnapshot = await (0, import_firestore25.getDocs)(q);
|
|
8233
8521
|
const templates = [];
|
|
8234
8522
|
let lastVisible = null;
|
|
8235
|
-
querySnapshot.forEach((
|
|
8236
|
-
templates.push(
|
|
8237
|
-
lastVisible =
|
|
8523
|
+
querySnapshot.forEach((doc33) => {
|
|
8524
|
+
templates.push(doc33.data());
|
|
8525
|
+
lastVisible = doc33;
|
|
8238
8526
|
});
|
|
8239
8527
|
return {
|
|
8240
8528
|
templates,
|
|
@@ -8261,9 +8549,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
8261
8549
|
const querySnapshot = await (0, import_firestore25.getDocs)(q);
|
|
8262
8550
|
const templates = [];
|
|
8263
8551
|
let lastVisible = null;
|
|
8264
|
-
querySnapshot.forEach((
|
|
8265
|
-
templates.push(
|
|
8266
|
-
lastVisible =
|
|
8552
|
+
querySnapshot.forEach((doc33) => {
|
|
8553
|
+
templates.push(doc33.data());
|
|
8554
|
+
lastVisible = doc33;
|
|
8267
8555
|
});
|
|
8268
8556
|
return {
|
|
8269
8557
|
templates,
|
|
@@ -8277,50 +8565,80 @@ var import_firestore26 = require("firebase/firestore");
|
|
|
8277
8565
|
var FilledDocumentService = class extends BaseService {
|
|
8278
8566
|
constructor(...args) {
|
|
8279
8567
|
super(...args);
|
|
8280
|
-
this.collectionRef = (0, import_firestore26.collection)(
|
|
8281
|
-
this.db,
|
|
8282
|
-
FILLED_DOCUMENTS_COLLECTION
|
|
8283
|
-
);
|
|
8284
8568
|
this.templateService = new DocumentationTemplateService(...args);
|
|
8285
8569
|
}
|
|
8570
|
+
getFormSubcollectionPath(isUserForm) {
|
|
8571
|
+
return isUserForm ? USER_FORMS_SUBCOLLECTION : DOCTOR_FORMS_SUBCOLLECTION;
|
|
8572
|
+
}
|
|
8286
8573
|
/**
|
|
8287
|
-
* Create a new filled document
|
|
8288
|
-
* @param templateId - ID of the template to use
|
|
8289
|
-
* @param
|
|
8290
|
-
* @param
|
|
8291
|
-
* @param
|
|
8292
|
-
* @
|
|
8574
|
+
* Create a new filled document within an appointment's subcollection.
|
|
8575
|
+
* @param templateId - ID of the template to use.
|
|
8576
|
+
* @param appointmentId - ID of the appointment this form belongs to.
|
|
8577
|
+
* @param procedureId - ID of the procedure associated with this form.
|
|
8578
|
+
* @param patientId - ID of the patient.
|
|
8579
|
+
* @param practitionerId - ID of the practitioner (can be system/generic if patient is filling).
|
|
8580
|
+
* @param clinicId - ID of the clinic.
|
|
8581
|
+
* @param initialValues - Optional initial values for the form elements.
|
|
8582
|
+
* @param initialStatus - Optional initial status for the form.
|
|
8583
|
+
* @returns The created filled document.
|
|
8293
8584
|
*/
|
|
8294
|
-
async
|
|
8585
|
+
async createFilledDocumentForAppointment(templateId, appointmentId, procedureId, patientId, practitionerId, clinicId, initialValues = {}, initialStatus = "draft" /* DRAFT */) {
|
|
8295
8586
|
const template = await this.templateService.getTemplateById(templateId);
|
|
8296
8587
|
if (!template) {
|
|
8297
8588
|
throw new Error(`Template with ID ${templateId} not found`);
|
|
8298
8589
|
}
|
|
8299
8590
|
const documentId3 = this.generateId();
|
|
8300
8591
|
const now = Date.now();
|
|
8592
|
+
const isUserForm = template.isUserForm || false;
|
|
8593
|
+
const formSubcollection = this.getFormSubcollectionPath(isUserForm);
|
|
8301
8594
|
const filledDocument = {
|
|
8302
8595
|
id: documentId3,
|
|
8303
8596
|
templateId,
|
|
8304
8597
|
templateVersion: template.version,
|
|
8598
|
+
isUserForm,
|
|
8599
|
+
// Set based on template
|
|
8600
|
+
isRequired: template.isRequired || false,
|
|
8601
|
+
// Inherit isRequired from the template
|
|
8602
|
+
appointmentId,
|
|
8603
|
+
// NEW
|
|
8604
|
+
procedureId,
|
|
8605
|
+
// NEW
|
|
8305
8606
|
patientId,
|
|
8306
8607
|
practitionerId,
|
|
8307
8608
|
clinicId,
|
|
8308
8609
|
createdAt: now,
|
|
8309
8610
|
updatedAt: now,
|
|
8310
|
-
values:
|
|
8311
|
-
status:
|
|
8611
|
+
values: initialValues,
|
|
8612
|
+
status: initialStatus
|
|
8312
8613
|
};
|
|
8313
|
-
const docRef = (0, import_firestore26.doc)(
|
|
8614
|
+
const docRef = (0, import_firestore26.doc)(
|
|
8615
|
+
this.db,
|
|
8616
|
+
APPOINTMENTS_COLLECTION,
|
|
8617
|
+
// Replaced "appointments"
|
|
8618
|
+
appointmentId,
|
|
8619
|
+
formSubcollection,
|
|
8620
|
+
documentId3
|
|
8621
|
+
);
|
|
8314
8622
|
await (0, import_firestore26.setDoc)(docRef, filledDocument);
|
|
8315
8623
|
return filledDocument;
|
|
8316
8624
|
}
|
|
8317
8625
|
/**
|
|
8318
|
-
* Get a filled document
|
|
8319
|
-
* @param
|
|
8320
|
-
* @
|
|
8626
|
+
* Get a specific filled document from an appointment's subcollection.
|
|
8627
|
+
* @param appointmentId - ID of the appointment.
|
|
8628
|
+
* @param formId - ID of the filled document.
|
|
8629
|
+
* @param isUserForm - Boolean indicating if it's a user form or doctor form.
|
|
8630
|
+
* @returns The filled document or null if not found.
|
|
8321
8631
|
*/
|
|
8322
|
-
async
|
|
8323
|
-
const
|
|
8632
|
+
async getFilledDocumentFromAppointmentById(appointmentId, formId, isUserForm) {
|
|
8633
|
+
const formSubcollection = this.getFormSubcollectionPath(isUserForm);
|
|
8634
|
+
const docRef = (0, import_firestore26.doc)(
|
|
8635
|
+
this.db,
|
|
8636
|
+
APPOINTMENTS_COLLECTION,
|
|
8637
|
+
// Replaced "appointments"
|
|
8638
|
+
appointmentId,
|
|
8639
|
+
formSubcollection,
|
|
8640
|
+
formId
|
|
8641
|
+
);
|
|
8324
8642
|
const docSnap = await (0, import_firestore26.getDoc)(docRef);
|
|
8325
8643
|
if (!docSnap.exists()) {
|
|
8326
8644
|
return null;
|
|
@@ -8328,178 +8646,183 @@ var FilledDocumentService = class extends BaseService {
|
|
|
8328
8646
|
return docSnap.data();
|
|
8329
8647
|
}
|
|
8330
8648
|
/**
|
|
8331
|
-
* Update values in a filled document
|
|
8332
|
-
* @param
|
|
8333
|
-
* @param
|
|
8334
|
-
* @param
|
|
8335
|
-
* @
|
|
8649
|
+
* Update values or status in a filled document within an appointment's subcollection.
|
|
8650
|
+
* @param appointmentId - ID of the appointment.
|
|
8651
|
+
* @param formId - ID of the filled document to update.
|
|
8652
|
+
* @param isUserForm - Boolean indicating if it's a user form or doctor form.
|
|
8653
|
+
* @param values - Updated values for elements.
|
|
8654
|
+
* @param status - Optional new status for the document.
|
|
8655
|
+
* @returns The updated filled document.
|
|
8336
8656
|
*/
|
|
8337
|
-
async
|
|
8338
|
-
const
|
|
8339
|
-
|
|
8340
|
-
|
|
8657
|
+
async updateFilledDocumentInAppointment(appointmentId, formId, isUserForm, values, status) {
|
|
8658
|
+
const formSubcollection = this.getFormSubcollectionPath(isUserForm);
|
|
8659
|
+
const docRef = (0, import_firestore26.doc)(
|
|
8660
|
+
this.db,
|
|
8661
|
+
APPOINTMENTS_COLLECTION,
|
|
8662
|
+
// Replaced "appointments"
|
|
8663
|
+
appointmentId,
|
|
8664
|
+
formSubcollection,
|
|
8665
|
+
formId
|
|
8666
|
+
);
|
|
8667
|
+
const existingDoc = await this.getFilledDocumentFromAppointmentById(
|
|
8668
|
+
appointmentId,
|
|
8669
|
+
formId,
|
|
8670
|
+
isUserForm
|
|
8671
|
+
);
|
|
8672
|
+
if (!existingDoc) {
|
|
8673
|
+
throw new Error(
|
|
8674
|
+
`Filled document with ID ${formId} not found in appointment ${appointmentId} ${formSubcollection}`
|
|
8675
|
+
);
|
|
8341
8676
|
}
|
|
8342
|
-
const
|
|
8343
|
-
values: {
|
|
8344
|
-
...filledDocument.values,
|
|
8345
|
-
...values
|
|
8346
|
-
},
|
|
8677
|
+
const updatePayload = {
|
|
8347
8678
|
updatedAt: Date.now()
|
|
8348
8679
|
};
|
|
8680
|
+
if (values) {
|
|
8681
|
+
updatePayload.values = {
|
|
8682
|
+
...existingDoc.values,
|
|
8683
|
+
...values
|
|
8684
|
+
};
|
|
8685
|
+
}
|
|
8349
8686
|
if (status) {
|
|
8350
|
-
|
|
8687
|
+
updatePayload.status = status;
|
|
8351
8688
|
}
|
|
8352
|
-
|
|
8353
|
-
|
|
8354
|
-
|
|
8355
|
-
|
|
8356
|
-
...updateData
|
|
8357
|
-
};
|
|
8689
|
+
if (Object.keys(updatePayload).length === 1 && "updatedAt" in updatePayload) {
|
|
8690
|
+
}
|
|
8691
|
+
await (0, import_firestore26.updateDoc)(docRef, updatePayload);
|
|
8692
|
+
return { ...existingDoc, ...updatePayload };
|
|
8358
8693
|
}
|
|
8359
8694
|
/**
|
|
8360
|
-
* Get filled
|
|
8361
|
-
* @param
|
|
8362
|
-
* @param pageSize
|
|
8363
|
-
* @param lastDoc
|
|
8364
|
-
* @returns Array of filled documents and the last document for pagination
|
|
8695
|
+
* Get all filled user forms for a specific appointment.
|
|
8696
|
+
* @param appointmentId ID of the appointment.
|
|
8697
|
+
* @param pageSize Number of documents to retrieve.
|
|
8698
|
+
* @param lastDoc Last document from previous page for pagination.
|
|
8365
8699
|
*/
|
|
8366
|
-
async
|
|
8700
|
+
async getFilledUserFormsForAppointment(appointmentId, pageSize = 20, lastDoc) {
|
|
8701
|
+
const subcollectionRef = (0, import_firestore26.collection)(
|
|
8702
|
+
this.db,
|
|
8703
|
+
APPOINTMENTS_COLLECTION,
|
|
8704
|
+
// Replaced "appointments"
|
|
8705
|
+
appointmentId,
|
|
8706
|
+
USER_FORMS_SUBCOLLECTION
|
|
8707
|
+
);
|
|
8367
8708
|
let q = (0, import_firestore26.query)(
|
|
8368
|
-
|
|
8369
|
-
(0, import_firestore26.where)("patientId", "==", patientId),
|
|
8709
|
+
subcollectionRef,
|
|
8370
8710
|
(0, import_firestore26.orderBy)("updatedAt", "desc"),
|
|
8371
8711
|
(0, import_firestore26.limit)(pageSize)
|
|
8372
8712
|
);
|
|
8373
8713
|
if (lastDoc) {
|
|
8374
8714
|
q = (0, import_firestore26.query)(q, (0, import_firestore26.startAfter)(lastDoc));
|
|
8375
8715
|
}
|
|
8376
|
-
|
|
8377
|
-
const documents = [];
|
|
8378
|
-
let lastVisible = null;
|
|
8379
|
-
querySnapshot.forEach((doc32) => {
|
|
8380
|
-
documents.push(doc32.data());
|
|
8381
|
-
lastVisible = doc32;
|
|
8382
|
-
});
|
|
8383
|
-
return {
|
|
8384
|
-
documents,
|
|
8385
|
-
lastDoc: lastVisible
|
|
8386
|
-
};
|
|
8716
|
+
return this.executeQuery(q);
|
|
8387
8717
|
}
|
|
8388
8718
|
/**
|
|
8389
|
-
* Get filled
|
|
8390
|
-
* @param
|
|
8391
|
-
* @param pageSize
|
|
8392
|
-
* @param lastDoc
|
|
8393
|
-
* @returns Array of filled documents and the last document for pagination
|
|
8719
|
+
* Get all filled doctor forms for a specific appointment.
|
|
8720
|
+
* @param appointmentId ID of the appointment.
|
|
8721
|
+
* @param pageSize Number of documents to retrieve.
|
|
8722
|
+
* @param lastDoc Last document from previous page for pagination.
|
|
8394
8723
|
*/
|
|
8395
|
-
async
|
|
8724
|
+
async getFilledDoctorFormsForAppointment(appointmentId, pageSize = 20, lastDoc) {
|
|
8725
|
+
const subcollectionRef = (0, import_firestore26.collection)(
|
|
8726
|
+
this.db,
|
|
8727
|
+
APPOINTMENTS_COLLECTION,
|
|
8728
|
+
// Replaced "appointments"
|
|
8729
|
+
appointmentId,
|
|
8730
|
+
DOCTOR_FORMS_SUBCOLLECTION
|
|
8731
|
+
);
|
|
8396
8732
|
let q = (0, import_firestore26.query)(
|
|
8397
|
-
|
|
8398
|
-
(0, import_firestore26.where)("practitionerId", "==", practitionerId),
|
|
8733
|
+
subcollectionRef,
|
|
8399
8734
|
(0, import_firestore26.orderBy)("updatedAt", "desc"),
|
|
8400
8735
|
(0, import_firestore26.limit)(pageSize)
|
|
8401
8736
|
);
|
|
8402
8737
|
if (lastDoc) {
|
|
8403
8738
|
q = (0, import_firestore26.query)(q, (0, import_firestore26.startAfter)(lastDoc));
|
|
8404
8739
|
}
|
|
8740
|
+
return this.executeQuery(q);
|
|
8741
|
+
}
|
|
8742
|
+
// Helper to execute query and return documents + lastDoc
|
|
8743
|
+
async executeQuery(q) {
|
|
8405
8744
|
const querySnapshot = await (0, import_firestore26.getDocs)(q);
|
|
8406
8745
|
const documents = [];
|
|
8407
8746
|
let lastVisible = null;
|
|
8408
|
-
querySnapshot.forEach((
|
|
8409
|
-
documents.push(
|
|
8410
|
-
lastVisible =
|
|
8747
|
+
querySnapshot.forEach((doc33) => {
|
|
8748
|
+
documents.push(doc33.data());
|
|
8749
|
+
lastVisible = doc33;
|
|
8411
8750
|
});
|
|
8412
8751
|
return {
|
|
8413
8752
|
documents,
|
|
8414
8753
|
lastDoc: lastVisible
|
|
8415
8754
|
};
|
|
8416
8755
|
}
|
|
8756
|
+
// IMPORTANT: The following methods that query across all patients/practitioners/clinics
|
|
8757
|
+
// (e.g., getFilledDocumentsByPatient, getFilledDocumentsByPractitioner)
|
|
8758
|
+
// will NOT work correctly if FILLED_DOCUMENTS_COLLECTION is no longer a top-level collection
|
|
8759
|
+
// and data is only in appointment subcollections. You would need to use
|
|
8760
|
+
// Firestore Collection Group Queries for that, which require an index and a different query approach.
|
|
8761
|
+
// These methods are left here for now but would need significant rework or removal.
|
|
8417
8762
|
/**
|
|
8418
|
-
* Get filled documents for a
|
|
8419
|
-
* @param
|
|
8763
|
+
* Get filled documents for a patient (NEEDS REWORK for subcollections or Collection Group Query)
|
|
8764
|
+
* @param patientId - ID of the patient
|
|
8420
8765
|
* @param pageSize - Number of documents to retrieve
|
|
8421
8766
|
* @param lastDoc - Last document from previous page for pagination
|
|
8422
8767
|
* @returns Array of filled documents and the last document for pagination
|
|
8423
8768
|
*/
|
|
8424
|
-
async
|
|
8425
|
-
|
|
8426
|
-
|
|
8427
|
-
(0, import_firestore26.where)("clinicId", "==", clinicId),
|
|
8428
|
-
(0, import_firestore26.orderBy)("updatedAt", "desc"),
|
|
8429
|
-
(0, import_firestore26.limit)(pageSize)
|
|
8769
|
+
async getFilledDocumentsByPatient(patientId, pageSize = 20, lastDoc) {
|
|
8770
|
+
console.warn(
|
|
8771
|
+
"getFilledDocumentsByPatient needs rework for subcollection model or Collection Group Queries."
|
|
8430
8772
|
);
|
|
8431
|
-
|
|
8432
|
-
q = (0, import_firestore26.query)(q, (0, import_firestore26.startAfter)(lastDoc));
|
|
8433
|
-
}
|
|
8434
|
-
const querySnapshot = await (0, import_firestore26.getDocs)(q);
|
|
8435
|
-
const documents = [];
|
|
8436
|
-
let lastVisible = null;
|
|
8437
|
-
querySnapshot.forEach((doc32) => {
|
|
8438
|
-
documents.push(doc32.data());
|
|
8439
|
-
lastVisible = doc32;
|
|
8440
|
-
});
|
|
8441
|
-
return {
|
|
8442
|
-
documents,
|
|
8443
|
-
lastDoc: lastVisible
|
|
8444
|
-
};
|
|
8773
|
+
return { documents: [], lastDoc: null };
|
|
8445
8774
|
}
|
|
8446
8775
|
/**
|
|
8447
|
-
* Get filled documents
|
|
8448
|
-
* @param
|
|
8776
|
+
* Get filled documents for a practitioner (NEEDS REWORK for subcollections or Collection Group Query)
|
|
8777
|
+
* @param practitionerId - ID of the practitioner
|
|
8449
8778
|
* @param pageSize - Number of documents to retrieve
|
|
8450
8779
|
* @param lastDoc - Last document from previous page for pagination
|
|
8451
8780
|
* @returns Array of filled documents and the last document for pagination
|
|
8452
8781
|
*/
|
|
8453
|
-
async
|
|
8454
|
-
|
|
8455
|
-
|
|
8456
|
-
(0, import_firestore26.where)("templateId", "==", templateId),
|
|
8457
|
-
(0, import_firestore26.orderBy)("updatedAt", "desc"),
|
|
8458
|
-
(0, import_firestore26.limit)(pageSize)
|
|
8782
|
+
async getFilledDocumentsByPractitioner(practitionerId, pageSize = 20, lastDoc) {
|
|
8783
|
+
console.warn(
|
|
8784
|
+
"getFilledDocumentsByPractitioner needs rework for subcollection model or Collection Group Queries."
|
|
8459
8785
|
);
|
|
8460
|
-
|
|
8461
|
-
|
|
8462
|
-
|
|
8463
|
-
|
|
8464
|
-
|
|
8465
|
-
|
|
8466
|
-
|
|
8467
|
-
|
|
8468
|
-
|
|
8469
|
-
|
|
8470
|
-
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
};
|
|
8786
|
+
return { documents: [], lastDoc: null };
|
|
8787
|
+
}
|
|
8788
|
+
/**
|
|
8789
|
+
* Get filled documents for a clinic (NEEDS REWORK for subcollections or Collection Group Query)
|
|
8790
|
+
* @param clinicId - ID of the clinic
|
|
8791
|
+
* @param pageSize - Number of documents to retrieve
|
|
8792
|
+
* @param lastDoc - Last document from previous page for pagination
|
|
8793
|
+
* @returns Array of filled documents and the last document for pagination
|
|
8794
|
+
*/
|
|
8795
|
+
async getFilledDocumentsByClinic(clinicId, pageSize = 20, lastDoc) {
|
|
8796
|
+
console.warn(
|
|
8797
|
+
"getFilledDocumentsByClinic needs rework for subcollection model or Collection Group Queries."
|
|
8798
|
+
);
|
|
8799
|
+
return { documents: [], lastDoc: null };
|
|
8474
8800
|
}
|
|
8475
8801
|
/**
|
|
8476
|
-
* Get filled documents by
|
|
8802
|
+
* Get filled documents by template (NEEDS REWORK for subcollections or Collection Group Query)
|
|
8803
|
+
* @param templateId - ID of the template
|
|
8804
|
+
* @param pageSize - Number of documents to retrieve
|
|
8805
|
+
* @param lastDoc - Last document from previous page for pagination
|
|
8806
|
+
* @returns Array of filled documents and the last document for pagination
|
|
8807
|
+
*/
|
|
8808
|
+
async getFilledDocumentsByTemplate(templateId, pageSize = 20, lastDoc) {
|
|
8809
|
+
console.warn(
|
|
8810
|
+
"getFilledDocumentsByTemplate needs rework for subcollection model or Collection Group Queries."
|
|
8811
|
+
);
|
|
8812
|
+
return { documents: [], lastDoc: null };
|
|
8813
|
+
}
|
|
8814
|
+
/**
|
|
8815
|
+
* Get filled documents by status (NEEDS REWORK for subcollections or Collection Group Query)
|
|
8477
8816
|
* @param status - Status to filter by
|
|
8478
8817
|
* @param pageSize - Number of documents to retrieve
|
|
8479
8818
|
* @param lastDoc - Last document from previous page for pagination
|
|
8480
8819
|
* @returns Array of filled documents and the last document for pagination
|
|
8481
8820
|
*/
|
|
8482
8821
|
async getFilledDocumentsByStatus(status, pageSize = 20, lastDoc) {
|
|
8483
|
-
|
|
8484
|
-
|
|
8485
|
-
(0, import_firestore26.where)("status", "==", status),
|
|
8486
|
-
(0, import_firestore26.orderBy)("updatedAt", "desc"),
|
|
8487
|
-
(0, import_firestore26.limit)(pageSize)
|
|
8822
|
+
console.warn(
|
|
8823
|
+
"getFilledDocumentsByStatus needs rework for subcollection model or Collection Group Queries."
|
|
8488
8824
|
);
|
|
8489
|
-
|
|
8490
|
-
q = (0, import_firestore26.query)(q, (0, import_firestore26.startAfter)(lastDoc));
|
|
8491
|
-
}
|
|
8492
|
-
const querySnapshot = await (0, import_firestore26.getDocs)(q);
|
|
8493
|
-
const documents = [];
|
|
8494
|
-
let lastVisible = null;
|
|
8495
|
-
querySnapshot.forEach((doc32) => {
|
|
8496
|
-
documents.push(doc32.data());
|
|
8497
|
-
lastVisible = doc32;
|
|
8498
|
-
});
|
|
8499
|
-
return {
|
|
8500
|
-
documents,
|
|
8501
|
-
lastDoc: lastVisible
|
|
8502
|
-
};
|
|
8825
|
+
return { documents: [], lastDoc: null };
|
|
8503
8826
|
}
|
|
8504
8827
|
};
|
|
8505
8828
|
|
|
@@ -8991,7 +9314,7 @@ async function searchCalendarEventsUtil(db, params) {
|
|
|
8991
9314
|
const finalQuery = (0, import_firestore33.query)(collectionRef, ...constraints);
|
|
8992
9315
|
const querySnapshot = await (0, import_firestore33.getDocs)(finalQuery);
|
|
8993
9316
|
const events = querySnapshot.docs.map(
|
|
8994
|
-
(
|
|
9317
|
+
(doc33) => ({ id: doc33.id, ...doc33.data() })
|
|
8995
9318
|
);
|
|
8996
9319
|
return events;
|
|
8997
9320
|
} catch (error) {
|
|
@@ -9073,7 +9396,7 @@ async function getPractitionerSyncedCalendarsUtil(db, practitionerId) {
|
|
|
9073
9396
|
);
|
|
9074
9397
|
const q = (0, import_firestore34.query)(calendarsRef, (0, import_firestore34.orderBy)("createdAt", "desc"));
|
|
9075
9398
|
const querySnapshot = await (0, import_firestore34.getDocs)(q);
|
|
9076
|
-
return querySnapshot.docs.map((
|
|
9399
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
9077
9400
|
}
|
|
9078
9401
|
async function getPatientSyncedCalendarUtil(db, patientId, calendarId) {
|
|
9079
9402
|
const calendarRef = getPatientSyncedCalendarDocRef(db, patientId, calendarId);
|
|
@@ -9090,7 +9413,7 @@ async function getPatientSyncedCalendarsUtil(db, patientId) {
|
|
|
9090
9413
|
);
|
|
9091
9414
|
const q = (0, import_firestore34.query)(calendarsRef, (0, import_firestore34.orderBy)("createdAt", "desc"));
|
|
9092
9415
|
const querySnapshot = await (0, import_firestore34.getDocs)(q);
|
|
9093
|
-
return querySnapshot.docs.map((
|
|
9416
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
9094
9417
|
}
|
|
9095
9418
|
async function getClinicSyncedCalendarUtil(db, clinicId, calendarId) {
|
|
9096
9419
|
const calendarRef = getClinicSyncedCalendarDocRef(db, clinicId, calendarId);
|
|
@@ -9107,7 +9430,7 @@ async function getClinicSyncedCalendarsUtil(db, clinicId) {
|
|
|
9107
9430
|
);
|
|
9108
9431
|
const q = (0, import_firestore34.query)(calendarsRef, (0, import_firestore34.orderBy)("createdAt", "desc"));
|
|
9109
9432
|
const querySnapshot = await (0, import_firestore34.getDocs)(q);
|
|
9110
|
-
return querySnapshot.docs.map((
|
|
9433
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
9111
9434
|
}
|
|
9112
9435
|
async function updatePractitionerSyncedCalendarUtil(db, practitionerId, calendarId, updateData) {
|
|
9113
9436
|
const calendarRef = getPractitionerSyncedCalendarDocRef(
|
|
@@ -10462,9 +10785,9 @@ var CalendarServiceV2 = class extends BaseService {
|
|
|
10462
10785
|
(0, import_firestore37.where)("eventTime.start", "<=", import_firestore36.Timestamp.fromDate(endDate))
|
|
10463
10786
|
);
|
|
10464
10787
|
const eventsSnapshot = await (0, import_firestore37.getDocs)(q);
|
|
10465
|
-
const events = eventsSnapshot.docs.map((
|
|
10466
|
-
id:
|
|
10467
|
-
...
|
|
10788
|
+
const events = eventsSnapshot.docs.map((doc33) => ({
|
|
10789
|
+
id: doc33.id,
|
|
10790
|
+
...doc33.data()
|
|
10468
10791
|
}));
|
|
10469
10792
|
const calendars = await this.syncedCalendarsService.getPractitionerSyncedCalendars(
|
|
10470
10793
|
doctorId
|
|
@@ -11096,7 +11419,7 @@ var CalendarServiceV2 = class extends BaseService {
|
|
|
11096
11419
|
])
|
|
11097
11420
|
);
|
|
11098
11421
|
const querySnapshot = await (0, import_firestore37.getDocs)(q);
|
|
11099
|
-
return querySnapshot.docs.map((
|
|
11422
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
11100
11423
|
}
|
|
11101
11424
|
/**
|
|
11102
11425
|
* Calculates available time slots based on working hours, schedule and existing appointments
|
|
@@ -11363,7 +11686,7 @@ var ReviewService = class extends BaseService {
|
|
|
11363
11686
|
(0, import_firestore38.where)("patientId", "==", patientId)
|
|
11364
11687
|
);
|
|
11365
11688
|
const snapshot = await (0, import_firestore38.getDocs)(q);
|
|
11366
|
-
return snapshot.docs.map((
|
|
11689
|
+
return snapshot.docs.map((doc33) => doc33.data());
|
|
11367
11690
|
}
|
|
11368
11691
|
/**
|
|
11369
11692
|
* Gets all reviews for a specific clinic
|
|
@@ -11376,7 +11699,7 @@ var ReviewService = class extends BaseService {
|
|
|
11376
11699
|
(0, import_firestore38.where)("clinicReview.clinicId", "==", clinicId)
|
|
11377
11700
|
);
|
|
11378
11701
|
const snapshot = await (0, import_firestore38.getDocs)(q);
|
|
11379
|
-
return snapshot.docs.map((
|
|
11702
|
+
return snapshot.docs.map((doc33) => doc33.data());
|
|
11380
11703
|
}
|
|
11381
11704
|
/**
|
|
11382
11705
|
* Gets all reviews for a specific practitioner
|
|
@@ -11389,7 +11712,7 @@ var ReviewService = class extends BaseService {
|
|
|
11389
11712
|
(0, import_firestore38.where)("practitionerReview.practitionerId", "==", practitionerId)
|
|
11390
11713
|
);
|
|
11391
11714
|
const snapshot = await (0, import_firestore38.getDocs)(q);
|
|
11392
|
-
return snapshot.docs.map((
|
|
11715
|
+
return snapshot.docs.map((doc33) => doc33.data());
|
|
11393
11716
|
}
|
|
11394
11717
|
/**
|
|
11395
11718
|
* Gets all reviews for a specific procedure
|
|
@@ -11402,7 +11725,7 @@ var ReviewService = class extends BaseService {
|
|
|
11402
11725
|
(0, import_firestore38.where)("procedureReview.procedureId", "==", procedureId)
|
|
11403
11726
|
);
|
|
11404
11727
|
const snapshot = await (0, import_firestore38.getDocs)(q);
|
|
11405
|
-
return snapshot.docs.map((
|
|
11728
|
+
return snapshot.docs.map((doc33) => doc33.data());
|
|
11406
11729
|
}
|
|
11407
11730
|
/**
|
|
11408
11731
|
* Gets all reviews for a specific appointment
|
|
@@ -12101,7 +12424,7 @@ async function updateCalendarEventStatus(db, calendarEventId, appointmentStatus)
|
|
|
12101
12424
|
case "canceled_clinic" /* CANCELED_CLINIC */:
|
|
12102
12425
|
calendarStatus = "canceled";
|
|
12103
12426
|
break;
|
|
12104
|
-
case
|
|
12427
|
+
case AppointmentStatus.RESCHEDULED:
|
|
12105
12428
|
calendarStatus = "rescheduled";
|
|
12106
12429
|
break;
|
|
12107
12430
|
case "completed" /* COMPLETED */:
|
|
@@ -12175,7 +12498,7 @@ async function searchAppointmentsUtil(db, params) {
|
|
|
12175
12498
|
const q = (0, import_firestore39.query)((0, import_firestore39.collection)(db, APPOINTMENTS_COLLECTION), ...constraints);
|
|
12176
12499
|
const querySnapshot = await (0, import_firestore39.getDocs)(q);
|
|
12177
12500
|
const appointments = querySnapshot.docs.map(
|
|
12178
|
-
(
|
|
12501
|
+
(doc33) => doc33.data()
|
|
12179
12502
|
);
|
|
12180
12503
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
12181
12504
|
return { appointments, lastDoc };
|
|
@@ -12198,12 +12521,13 @@ var AppointmentService = class extends BaseService {
|
|
|
12198
12521
|
* @param practitionerService Practitioner service instance
|
|
12199
12522
|
* @param clinicService Clinic service instance
|
|
12200
12523
|
*/
|
|
12201
|
-
constructor(db, auth, app, calendarService, patientService, practitionerService, clinicService) {
|
|
12524
|
+
constructor(db, auth, app, calendarService, patientService, practitionerService, clinicService, filledDocumentService) {
|
|
12202
12525
|
super(db, auth, app);
|
|
12203
12526
|
this.calendarService = calendarService;
|
|
12204
12527
|
this.patientService = patientService;
|
|
12205
12528
|
this.practitionerService = practitionerService;
|
|
12206
12529
|
this.clinicService = clinicService;
|
|
12530
|
+
this.filledDocumentService = filledDocumentService;
|
|
12207
12531
|
this.functions = (0, import_functions.getFunctions)(app, "europe-west6");
|
|
12208
12532
|
}
|
|
12209
12533
|
/**
|
|
@@ -12559,152 +12883,331 @@ var AppointmentService = class extends BaseService {
|
|
|
12559
12883
|
*
|
|
12560
12884
|
* @param appointmentId ID of the appointment
|
|
12561
12885
|
* @param newStatus New status to set
|
|
12562
|
-
* @param
|
|
12563
|
-
* @param canceledBy Required if canceling the appointment
|
|
12886
|
+
* @param details Optional details for the status change
|
|
12564
12887
|
* @returns The updated appointment
|
|
12565
12888
|
*/
|
|
12566
|
-
async updateAppointmentStatus(appointmentId, newStatus,
|
|
12889
|
+
async updateAppointmentStatus(appointmentId, newStatus, details) {
|
|
12567
12890
|
console.log(
|
|
12568
12891
|
`[APPOINTMENT_SERVICE] Updating status of appointment ${appointmentId} to ${newStatus}`
|
|
12569
12892
|
);
|
|
12570
|
-
const updateData = {
|
|
12571
|
-
|
|
12572
|
-
|
|
12573
|
-
|
|
12574
|
-
|
|
12575
|
-
|
|
12893
|
+
const updateData = {
|
|
12894
|
+
status: newStatus,
|
|
12895
|
+
updatedAt: (0, import_firestore40.serverTimestamp)()
|
|
12896
|
+
};
|
|
12897
|
+
if (newStatus === "canceled_clinic" /* CANCELED_CLINIC */ || newStatus === "canceled_patient" /* CANCELED_PATIENT */ || newStatus === "canceled_patient_rescheduled" /* CANCELED_PATIENT_RESCHEDULED */) {
|
|
12898
|
+
if (!(details == null ? void 0 : details.cancellationReason)) {
|
|
12899
|
+
throw new Error("Cancellation reason is required when canceling.");
|
|
12576
12900
|
}
|
|
12577
|
-
if (!canceledBy) {
|
|
12578
|
-
throw new Error(
|
|
12579
|
-
"Canceled by is required when canceling an appointment"
|
|
12580
|
-
);
|
|
12901
|
+
if (!(details == null ? void 0 : details.canceledBy)) {
|
|
12902
|
+
throw new Error("Canceled by is required when canceling.");
|
|
12581
12903
|
}
|
|
12582
|
-
updateData.cancellationReason = cancellationReason;
|
|
12583
|
-
updateData.canceledBy = canceledBy;
|
|
12904
|
+
updateData.cancellationReason = details.cancellationReason;
|
|
12905
|
+
updateData.canceledBy = details.canceledBy;
|
|
12906
|
+
updateData.cancellationTime = import_firestore40.Timestamp.now();
|
|
12584
12907
|
}
|
|
12585
12908
|
if (newStatus === "confirmed" /* CONFIRMED */) {
|
|
12586
12909
|
updateData.confirmationTime = import_firestore40.Timestamp.now();
|
|
12587
12910
|
}
|
|
12911
|
+
if (newStatus === "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
|
|
12912
|
+
updateData.rescheduleTime = import_firestore40.Timestamp.now();
|
|
12913
|
+
}
|
|
12588
12914
|
return this.updateAppointment(appointmentId, updateData);
|
|
12589
12915
|
}
|
|
12590
12916
|
/**
|
|
12591
|
-
* Confirms an
|
|
12592
|
-
*
|
|
12593
|
-
* @param appointmentId ID of the appointment to confirm
|
|
12594
|
-
* @returns The confirmed appointment
|
|
12917
|
+
* Confirms a PENDING appointment by an Admin/Clinic.
|
|
12595
12918
|
*/
|
|
12596
|
-
async
|
|
12919
|
+
async confirmAppointmentAdmin(appointmentId) {
|
|
12597
12920
|
console.log(
|
|
12598
|
-
`[APPOINTMENT_SERVICE]
|
|
12921
|
+
`[APPOINTMENT_SERVICE] Admin confirming appointment: ${appointmentId}`
|
|
12599
12922
|
);
|
|
12923
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
12924
|
+
if (!appointment)
|
|
12925
|
+
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
12926
|
+
if (appointment.status !== "pending" /* PENDING */) {
|
|
12927
|
+
throw new Error(
|
|
12928
|
+
`Appointment ${appointmentId} is not in PENDING state to be confirmed.`
|
|
12929
|
+
);
|
|
12930
|
+
}
|
|
12600
12931
|
return this.updateAppointmentStatus(
|
|
12601
12932
|
appointmentId,
|
|
12602
12933
|
"confirmed" /* CONFIRMED */
|
|
12603
12934
|
);
|
|
12604
12935
|
}
|
|
12605
12936
|
/**
|
|
12606
|
-
* Cancels an appointment
|
|
12607
|
-
|
|
12608
|
-
|
|
12609
|
-
|
|
12610
|
-
|
|
12937
|
+
* Cancels an appointment by the User (Patient).
|
|
12938
|
+
*/
|
|
12939
|
+
async cancelAppointmentUser(appointmentId, reason) {
|
|
12940
|
+
console.log(
|
|
12941
|
+
`[APPOINTMENT_SERVICE] User canceling appointment: ${appointmentId}`
|
|
12942
|
+
);
|
|
12943
|
+
return this.updateAppointmentStatus(
|
|
12944
|
+
appointmentId,
|
|
12945
|
+
"canceled_patient" /* CANCELED_PATIENT */,
|
|
12946
|
+
{
|
|
12947
|
+
cancellationReason: reason,
|
|
12948
|
+
canceledBy: "patient"
|
|
12949
|
+
}
|
|
12950
|
+
);
|
|
12951
|
+
}
|
|
12952
|
+
/**
|
|
12953
|
+
* Cancels an appointment by an Admin/Clinic.
|
|
12611
12954
|
*/
|
|
12612
|
-
async
|
|
12955
|
+
async cancelAppointmentAdmin(appointmentId, reason) {
|
|
12613
12956
|
console.log(
|
|
12614
|
-
`[APPOINTMENT_SERVICE]
|
|
12957
|
+
`[APPOINTMENT_SERVICE] Admin canceling appointment: ${appointmentId}`
|
|
12615
12958
|
);
|
|
12616
12959
|
return this.updateAppointmentStatus(
|
|
12617
12960
|
appointmentId,
|
|
12618
12961
|
"canceled_clinic" /* CANCELED_CLINIC */,
|
|
12619
|
-
|
|
12620
|
-
|
|
12962
|
+
{
|
|
12963
|
+
cancellationReason: reason,
|
|
12964
|
+
canceledBy: "clinic"
|
|
12965
|
+
}
|
|
12621
12966
|
);
|
|
12622
12967
|
}
|
|
12623
12968
|
/**
|
|
12624
|
-
*
|
|
12625
|
-
*
|
|
12626
|
-
|
|
12627
|
-
|
|
12628
|
-
|
|
12969
|
+
* Admin proposes to reschedule an appointment.
|
|
12970
|
+
* Sets status to RESCHEDULED_BY_CLINIC and updates times.
|
|
12971
|
+
*/
|
|
12972
|
+
async rescheduleAppointmentAdmin(appointmentId, newStartTime, newEndTime) {
|
|
12973
|
+
console.log(
|
|
12974
|
+
`[APPOINTMENT_SERVICE] Admin rescheduling appointment: ${appointmentId}`
|
|
12975
|
+
);
|
|
12976
|
+
if (newEndTime.toMillis() <= newStartTime.toMillis()) {
|
|
12977
|
+
throw new Error("New end time must be after new start time.");
|
|
12978
|
+
}
|
|
12979
|
+
const updateData = {
|
|
12980
|
+
status: "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */,
|
|
12981
|
+
appointmentStartTime: newStartTime,
|
|
12982
|
+
appointmentEndTime: newEndTime,
|
|
12983
|
+
rescheduleTime: import_firestore40.Timestamp.now(),
|
|
12984
|
+
confirmationTime: null,
|
|
12985
|
+
updatedAt: (0, import_firestore40.serverTimestamp)()
|
|
12986
|
+
};
|
|
12987
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
12988
|
+
}
|
|
12989
|
+
/**
|
|
12990
|
+
* User confirms a reschedule proposed by the clinic.
|
|
12991
|
+
* Status changes from RESCHEDULED_BY_CLINIC to CONFIRMED.
|
|
12629
12992
|
*/
|
|
12630
|
-
async
|
|
12993
|
+
async rescheduleAppointmentConfirmUser(appointmentId) {
|
|
12631
12994
|
console.log(
|
|
12632
|
-
`[APPOINTMENT_SERVICE]
|
|
12995
|
+
`[APPOINTMENT_SERVICE] User confirming reschedule for: ${appointmentId}`
|
|
12633
12996
|
);
|
|
12997
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
12998
|
+
if (!appointment)
|
|
12999
|
+
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
13000
|
+
if (appointment.status !== "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
|
|
13001
|
+
throw new Error(
|
|
13002
|
+
`Appointment ${appointmentId} is not in RESCHEDULED_BY_CLINIC state.`
|
|
13003
|
+
);
|
|
13004
|
+
}
|
|
12634
13005
|
return this.updateAppointmentStatus(
|
|
12635
13006
|
appointmentId,
|
|
12636
|
-
"
|
|
12637
|
-
reason,
|
|
12638
|
-
"patient"
|
|
13007
|
+
"confirmed" /* CONFIRMED */
|
|
12639
13008
|
);
|
|
12640
13009
|
}
|
|
12641
13010
|
/**
|
|
12642
|
-
*
|
|
12643
|
-
*
|
|
12644
|
-
* @param appointmentId ID of the appointment
|
|
12645
|
-
* @returns The updated appointment
|
|
13011
|
+
* User rejects a reschedule proposed by the clinic.
|
|
13012
|
+
* Status changes from RESCHEDULED_BY_CLINIC to CANCELED_PATIENT_RESCHEDULED.
|
|
12646
13013
|
*/
|
|
12647
|
-
async
|
|
13014
|
+
async rescheduleAppointmentRejectUser(appointmentId, reason) {
|
|
12648
13015
|
console.log(
|
|
12649
|
-
`[APPOINTMENT_SERVICE]
|
|
13016
|
+
`[APPOINTMENT_SERVICE] User rejecting reschedule for: ${appointmentId}`
|
|
12650
13017
|
);
|
|
13018
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
13019
|
+
if (!appointment)
|
|
13020
|
+
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
13021
|
+
if (appointment.status !== "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
|
|
13022
|
+
throw new Error(
|
|
13023
|
+
`Appointment ${appointmentId} is not in RESCHEDULED_BY_CLINIC state.`
|
|
13024
|
+
);
|
|
13025
|
+
}
|
|
12651
13026
|
return this.updateAppointmentStatus(
|
|
12652
13027
|
appointmentId,
|
|
12653
|
-
"
|
|
13028
|
+
"canceled_patient_rescheduled" /* CANCELED_PATIENT_RESCHEDULED */,
|
|
13029
|
+
{
|
|
13030
|
+
cancellationReason: reason,
|
|
13031
|
+
canceledBy: "patient"
|
|
13032
|
+
}
|
|
12654
13033
|
);
|
|
12655
13034
|
}
|
|
12656
13035
|
/**
|
|
12657
|
-
*
|
|
12658
|
-
*
|
|
12659
|
-
* @param appointmentId ID of the appointment
|
|
12660
|
-
* @returns The updated appointment
|
|
13036
|
+
* Admin checks in a patient for their appointment.
|
|
13037
|
+
* Requires all pending user forms to be completed.
|
|
12661
13038
|
*/
|
|
12662
|
-
async
|
|
12663
|
-
console.log(
|
|
13039
|
+
async checkInPatientAdmin(appointmentId) {
|
|
13040
|
+
console.log(
|
|
13041
|
+
`[APPOINTMENT_SERVICE] Admin checking in patient for: ${appointmentId}`
|
|
13042
|
+
);
|
|
13043
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
13044
|
+
if (!appointment)
|
|
13045
|
+
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
13046
|
+
if (appointment.pendingUserFormsIds && appointment.pendingUserFormsIds.length > 0) {
|
|
13047
|
+
throw new Error(
|
|
13048
|
+
`Cannot check in: Patient has ${appointment.pendingUserFormsIds.length} pending required form(s). IDs: ${appointment.pendingUserFormsIds.join(
|
|
13049
|
+
", "
|
|
13050
|
+
)}`
|
|
13051
|
+
);
|
|
13052
|
+
}
|
|
13053
|
+
if (appointment.status !== "confirmed" /* CONFIRMED */ && appointment.status !== "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
|
|
13054
|
+
console.warn(
|
|
13055
|
+
`Checking in appointment ${appointmentId} with status ${appointment.status}. Ensure this is intended.`
|
|
13056
|
+
);
|
|
13057
|
+
}
|
|
12664
13058
|
return this.updateAppointmentStatus(
|
|
12665
13059
|
appointmentId,
|
|
12666
|
-
"
|
|
13060
|
+
"checked_in" /* CHECKED_IN */
|
|
12667
13061
|
);
|
|
12668
13062
|
}
|
|
12669
13063
|
/**
|
|
12670
|
-
*
|
|
12671
|
-
*
|
|
12672
|
-
* @param appointmentId ID of the appointment
|
|
12673
|
-
* @param actualDurationMinutes Actual duration of the appointment in minutes
|
|
12674
|
-
* @returns The updated appointment
|
|
13064
|
+
* Doctor starts the appointment procedure.
|
|
12675
13065
|
*/
|
|
12676
|
-
async
|
|
13066
|
+
async startAppointmentDoctor(appointmentId) {
|
|
12677
13067
|
console.log(
|
|
12678
|
-
`[APPOINTMENT_SERVICE]
|
|
13068
|
+
`[APPOINTMENT_SERVICE] Doctor starting appointment: ${appointmentId}`
|
|
12679
13069
|
);
|
|
13070
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
13071
|
+
if (!appointment)
|
|
13072
|
+
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
13073
|
+
if (appointment.status !== "checked_in" /* CHECKED_IN */) {
|
|
13074
|
+
throw new Error(
|
|
13075
|
+
`Appointment ${appointmentId} must be CHECKED_IN to start.`
|
|
13076
|
+
);
|
|
13077
|
+
}
|
|
13078
|
+
const updateData = {
|
|
13079
|
+
status: "in_progress" /* IN_PROGRESS */,
|
|
13080
|
+
procedureActualStartTime: import_firestore40.Timestamp.now(),
|
|
13081
|
+
// Set actual start time
|
|
13082
|
+
updatedAt: (0, import_firestore40.serverTimestamp)()
|
|
13083
|
+
};
|
|
13084
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
13085
|
+
}
|
|
13086
|
+
/**
|
|
13087
|
+
* Doctor completes and finalizes the appointment.
|
|
13088
|
+
*/
|
|
13089
|
+
async completeAppointmentDoctor(appointmentId, finalizationNotes, actualDurationMinutesInput) {
|
|
13090
|
+
console.log(
|
|
13091
|
+
`[APPOINTMENT_SERVICE] Doctor completing appointment: ${appointmentId}`
|
|
13092
|
+
);
|
|
13093
|
+
const currentUser = this.auth.currentUser;
|
|
13094
|
+
if (!currentUser)
|
|
13095
|
+
throw new Error("Authentication required to complete appointment.");
|
|
13096
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
13097
|
+
if (!appointment)
|
|
13098
|
+
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
13099
|
+
let calculatedDurationMinutes = actualDurationMinutesInput;
|
|
13100
|
+
const procedureCompletionTime = import_firestore40.Timestamp.now();
|
|
13101
|
+
if (calculatedDurationMinutes === void 0 && appointment.procedureActualStartTime) {
|
|
13102
|
+
const startTimeMillis = appointment.procedureActualStartTime.toMillis();
|
|
13103
|
+
const endTimeMillis = procedureCompletionTime.toMillis();
|
|
13104
|
+
if (endTimeMillis > startTimeMillis) {
|
|
13105
|
+
calculatedDurationMinutes = Math.round(
|
|
13106
|
+
(endTimeMillis - startTimeMillis) / 6e4
|
|
13107
|
+
);
|
|
13108
|
+
}
|
|
13109
|
+
}
|
|
12680
13110
|
const updateData = {
|
|
12681
13111
|
status: "completed" /* COMPLETED */,
|
|
12682
|
-
actualDurationMinutes
|
|
13112
|
+
actualDurationMinutes: calculatedDurationMinutes,
|
|
13113
|
+
// Use calculated or provided duration
|
|
13114
|
+
finalizedDetails: {
|
|
13115
|
+
by: currentUser.uid,
|
|
13116
|
+
// This is used ID, not practitioner's profile ID (just so we know who completed the appointment)
|
|
13117
|
+
at: procedureCompletionTime,
|
|
13118
|
+
// Use consistent completion timestamp
|
|
13119
|
+
notes: finalizationNotes
|
|
13120
|
+
},
|
|
13121
|
+
// Optionally update appointmentEndTime to the actual completion time
|
|
13122
|
+
// appointmentEndTime: procedureCompletionTime,
|
|
13123
|
+
updatedAt: (0, import_firestore40.serverTimestamp)()
|
|
12683
13124
|
};
|
|
12684
13125
|
return this.updateAppointment(appointmentId, updateData);
|
|
12685
13126
|
}
|
|
12686
13127
|
/**
|
|
12687
|
-
*
|
|
12688
|
-
*
|
|
12689
|
-
* @param appointmentId ID of the appointment
|
|
12690
|
-
* @returns The updated appointment
|
|
13128
|
+
* Admin marks an appointment as No-Show.
|
|
12691
13129
|
*/
|
|
12692
|
-
async
|
|
13130
|
+
async markNoShowAdmin(appointmentId) {
|
|
12693
13131
|
console.log(
|
|
12694
|
-
`[APPOINTMENT_SERVICE]
|
|
13132
|
+
`[APPOINTMENT_SERVICE] Admin marking no-show for: ${appointmentId}`
|
|
12695
13133
|
);
|
|
13134
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
13135
|
+
if (!appointment)
|
|
13136
|
+
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
13137
|
+
if (import_firestore40.Timestamp.now().toMillis() < appointment.appointmentStartTime.toMillis()) {
|
|
13138
|
+
throw new Error("Cannot mark no-show before appointment start time.");
|
|
13139
|
+
}
|
|
12696
13140
|
return this.updateAppointmentStatus(
|
|
12697
13141
|
appointmentId,
|
|
12698
|
-
"no_show" /* NO_SHOW
|
|
13142
|
+
"no_show" /* NO_SHOW */,
|
|
13143
|
+
{
|
|
13144
|
+
cancellationReason: "Patient did not show up for the appointment.",
|
|
13145
|
+
canceledBy: "clinic"
|
|
13146
|
+
}
|
|
13147
|
+
);
|
|
13148
|
+
}
|
|
13149
|
+
/**
|
|
13150
|
+
* Adds a media item to an appointment.
|
|
13151
|
+
*/
|
|
13152
|
+
async addMediaToAppointment(appointmentId, mediaItemData) {
|
|
13153
|
+
console.log(
|
|
13154
|
+
`[APPOINTMENT_SERVICE] Adding media to appointment ${appointmentId}`
|
|
13155
|
+
);
|
|
13156
|
+
const currentUser = this.auth.currentUser;
|
|
13157
|
+
if (!currentUser) throw new Error("Authentication required.");
|
|
13158
|
+
const newMediaItem = {
|
|
13159
|
+
...mediaItemData,
|
|
13160
|
+
id: this.generateId(),
|
|
13161
|
+
uploadedAt: import_firestore40.Timestamp.now(),
|
|
13162
|
+
uploadedBy: currentUser.uid
|
|
13163
|
+
};
|
|
13164
|
+
const updateData = {
|
|
13165
|
+
media: (0, import_firestore40.arrayUnion)(newMediaItem),
|
|
13166
|
+
updatedAt: (0, import_firestore40.serverTimestamp)()
|
|
13167
|
+
};
|
|
13168
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
13169
|
+
}
|
|
13170
|
+
/**
|
|
13171
|
+
* Removes a media item from an appointment.
|
|
13172
|
+
*/
|
|
13173
|
+
async removeMediaFromAppointment(appointmentId, mediaItemId) {
|
|
13174
|
+
console.log(
|
|
13175
|
+
`[APPOINTMENT_SERVICE] Removing media ${mediaItemId} from appointment ${appointmentId}`
|
|
13176
|
+
);
|
|
13177
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
13178
|
+
if (!appointment || !appointment.media) {
|
|
13179
|
+
throw new Error("Appointment or media list not found.");
|
|
13180
|
+
}
|
|
13181
|
+
const mediaToRemove = appointment.media.find((m) => m.id === mediaItemId);
|
|
13182
|
+
if (!mediaToRemove) {
|
|
13183
|
+
throw new Error(`Media item ${mediaItemId} not found in appointment.`);
|
|
13184
|
+
}
|
|
13185
|
+
const updateData = {
|
|
13186
|
+
media: (0, import_firestore40.arrayRemove)(mediaToRemove),
|
|
13187
|
+
updatedAt: (0, import_firestore40.serverTimestamp)()
|
|
13188
|
+
};
|
|
13189
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
13190
|
+
}
|
|
13191
|
+
/**
|
|
13192
|
+
* Adds or updates review information for an appointment.
|
|
13193
|
+
*/
|
|
13194
|
+
async addReviewToAppointment(appointmentId, reviewData) {
|
|
13195
|
+
console.log(
|
|
13196
|
+
`[APPOINTMENT_SERVICE] Adding review to appointment ${appointmentId}`
|
|
12699
13197
|
);
|
|
13198
|
+
const newReviewInfo = {
|
|
13199
|
+
...reviewData,
|
|
13200
|
+
reviewId: this.generateId(),
|
|
13201
|
+
reviewedAt: import_firestore40.Timestamp.now()
|
|
13202
|
+
};
|
|
13203
|
+
const updateData = {
|
|
13204
|
+
reviewInfo: newReviewInfo,
|
|
13205
|
+
updatedAt: (0, import_firestore40.serverTimestamp)()
|
|
13206
|
+
};
|
|
13207
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
12700
13208
|
}
|
|
12701
13209
|
/**
|
|
12702
13210
|
* Updates the payment status of an appointment.
|
|
12703
|
-
*
|
|
12704
|
-
* @param appointmentId ID of the appointment
|
|
12705
|
-
* @param paymentStatus New payment status
|
|
12706
|
-
* @param paymentTransactionId Optional transaction ID for the payment
|
|
12707
|
-
* @returns The updated appointment
|
|
12708
13211
|
*/
|
|
12709
13212
|
async updatePaymentStatus(appointmentId, paymentStatus, paymentTransactionId) {
|
|
12710
13213
|
console.log(
|
|
@@ -12712,7 +13215,8 @@ var AppointmentService = class extends BaseService {
|
|
|
12712
13215
|
);
|
|
12713
13216
|
const updateData = {
|
|
12714
13217
|
paymentStatus,
|
|
12715
|
-
paymentTransactionId: paymentTransactionId || null
|
|
13218
|
+
paymentTransactionId: paymentTransactionId || null,
|
|
13219
|
+
updatedAt: (0, import_firestore40.serverTimestamp)()
|
|
12716
13220
|
};
|
|
12717
13221
|
return this.updateAppointment(appointmentId, updateData);
|
|
12718
13222
|
}
|
|
@@ -12785,9 +13289,203 @@ var AppointmentService = class extends BaseService {
|
|
|
12785
13289
|
}
|
|
12786
13290
|
};
|
|
12787
13291
|
|
|
12788
|
-
// src/
|
|
13292
|
+
// src/services/patient/patientRequirements.service.ts
|
|
12789
13293
|
var import_firestore41 = require("firebase/firestore");
|
|
12790
13294
|
|
|
13295
|
+
// src/types/patient/patient-requirements.ts
|
|
13296
|
+
var PatientInstructionStatus = /* @__PURE__ */ ((PatientInstructionStatus2) => {
|
|
13297
|
+
PatientInstructionStatus2["PENDING_NOTIFICATION"] = "pendingNotification";
|
|
13298
|
+
PatientInstructionStatus2["ACTION_DUE"] = "actionDue";
|
|
13299
|
+
PatientInstructionStatus2["ACTION_TAKEN"] = "actionTaken";
|
|
13300
|
+
PatientInstructionStatus2["MISSED"] = "missed";
|
|
13301
|
+
PatientInstructionStatus2["CANCELLED"] = "cancelled";
|
|
13302
|
+
PatientInstructionStatus2["SKIPPED"] = "skipped";
|
|
13303
|
+
return PatientInstructionStatus2;
|
|
13304
|
+
})(PatientInstructionStatus || {});
|
|
13305
|
+
var PatientRequirementOverallStatus = /* @__PURE__ */ ((PatientRequirementOverallStatus2) => {
|
|
13306
|
+
PatientRequirementOverallStatus2["ACTIVE"] = "active";
|
|
13307
|
+
PatientRequirementOverallStatus2["ALL_INSTRUCTIONS_MET"] = "allInstructionsMet";
|
|
13308
|
+
PatientRequirementOverallStatus2["PARTIALLY_COMPLETED"] = "partiallyCompleted";
|
|
13309
|
+
PatientRequirementOverallStatus2["FAILED"] = "failed";
|
|
13310
|
+
PatientRequirementOverallStatus2["CANCELLED_APPOINTMENT"] = "cancelledAppointment";
|
|
13311
|
+
PatientRequirementOverallStatus2["SUPERSEDED_RESCHEDULE"] = "supersededReschedule";
|
|
13312
|
+
PatientRequirementOverallStatus2["FAILED_TO_PROCESS"] = "failedToProcess";
|
|
13313
|
+
return PatientRequirementOverallStatus2;
|
|
13314
|
+
})(PatientRequirementOverallStatus || {});
|
|
13315
|
+
var PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME = "patientRequirements";
|
|
13316
|
+
|
|
13317
|
+
// src/services/patient/patientRequirements.service.ts
|
|
13318
|
+
var PatientRequirementsService = class extends BaseService {
|
|
13319
|
+
constructor(db, auth, app) {
|
|
13320
|
+
super(db, auth, app);
|
|
13321
|
+
}
|
|
13322
|
+
getPatientRequirementsCollectionRef(patientId) {
|
|
13323
|
+
return (0, import_firestore41.collection)(
|
|
13324
|
+
this.db,
|
|
13325
|
+
`patients/${patientId}/${PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME}`
|
|
13326
|
+
);
|
|
13327
|
+
}
|
|
13328
|
+
getPatientRequirementDocRef(patientId, instanceId) {
|
|
13329
|
+
return (0, import_firestore41.doc)(
|
|
13330
|
+
this.getPatientRequirementsCollectionRef(patientId),
|
|
13331
|
+
instanceId
|
|
13332
|
+
);
|
|
13333
|
+
}
|
|
13334
|
+
/**
|
|
13335
|
+
* Gets a specific patient requirement instance by its ID.
|
|
13336
|
+
* @param patientId - The ID of the patient.
|
|
13337
|
+
* @param instanceId - The ID of the requirement instance.
|
|
13338
|
+
* @returns The patient requirement instance or null if not found.
|
|
13339
|
+
*/
|
|
13340
|
+
async getPatientRequirementInstance(patientId, instanceId) {
|
|
13341
|
+
const docRef = this.getPatientRequirementDocRef(patientId, instanceId);
|
|
13342
|
+
const docSnap = await (0, import_firestore41.getDoc)(docRef);
|
|
13343
|
+
if (!docSnap.exists()) {
|
|
13344
|
+
return null;
|
|
13345
|
+
}
|
|
13346
|
+
const data = docSnap.data();
|
|
13347
|
+
return { id: docSnap.id, ...data };
|
|
13348
|
+
}
|
|
13349
|
+
/**
|
|
13350
|
+
* Retrieves patient requirement instances based on specified filters.
|
|
13351
|
+
* This is a flexible query method.
|
|
13352
|
+
*
|
|
13353
|
+
* @param patientId - The ID of the patient.
|
|
13354
|
+
* @param filters - Optional filters for appointmentId, overall statuses, instruction statuses, and due timeframes.
|
|
13355
|
+
* @param pageLimit - Optional limit for pagination.
|
|
13356
|
+
* @param lastVisible - Optional last document snapshot for pagination.
|
|
13357
|
+
* @returns A promise resolving to an array of matching patient requirement instances and the last document snapshot.
|
|
13358
|
+
*/
|
|
13359
|
+
async getAllPatientRequirementInstances(patientId, filters, pageLimit = 20, lastVisible) {
|
|
13360
|
+
const collRef = this.getPatientRequirementsCollectionRef(patientId);
|
|
13361
|
+
let q = (0, import_firestore41.query)(collRef, (0, import_firestore41.orderBy)("createdAt", "desc"));
|
|
13362
|
+
const queryConstraints = [];
|
|
13363
|
+
if ((filters == null ? void 0 : filters.appointmentId) && filters.appointmentId !== "all") {
|
|
13364
|
+
queryConstraints.push(
|
|
13365
|
+
(0, import_firestore41.where)("appointmentId", "==", filters.appointmentId)
|
|
13366
|
+
);
|
|
13367
|
+
}
|
|
13368
|
+
if ((filters == null ? void 0 : filters.statuses) && filters.statuses.length > 0) {
|
|
13369
|
+
queryConstraints.push((0, import_firestore41.where)("overallStatus", "in", filters.statuses));
|
|
13370
|
+
}
|
|
13371
|
+
if (lastVisible) {
|
|
13372
|
+
queryConstraints.push((0, import_firestore41.startAfter)(lastVisible));
|
|
13373
|
+
}
|
|
13374
|
+
queryConstraints.push((0, import_firestore41.limit)(pageLimit));
|
|
13375
|
+
q = (0, import_firestore41.query)(collRef, ...queryConstraints);
|
|
13376
|
+
const snapshot = await (0, import_firestore41.getDocs)(q);
|
|
13377
|
+
let requirements = snapshot.docs.map((docSnap) => {
|
|
13378
|
+
const data = docSnap.data();
|
|
13379
|
+
return { id: docSnap.id, ...data };
|
|
13380
|
+
});
|
|
13381
|
+
if ((filters == null ? void 0 : filters.instructionStatuses) && filters.instructionStatuses.length > 0) {
|
|
13382
|
+
requirements = requirements.filter(
|
|
13383
|
+
(req) => req.instructions.some(
|
|
13384
|
+
(instr) => filters.instructionStatuses.includes(instr.status)
|
|
13385
|
+
)
|
|
13386
|
+
);
|
|
13387
|
+
}
|
|
13388
|
+
if (filters == null ? void 0 : filters.dueBefore) {
|
|
13389
|
+
const dueBeforeMillis = filters.dueBefore.toMillis();
|
|
13390
|
+
requirements = requirements.filter(
|
|
13391
|
+
(req) => req.instructions.some(
|
|
13392
|
+
(instr) => instr.dueTime.toMillis() < dueBeforeMillis
|
|
13393
|
+
)
|
|
13394
|
+
);
|
|
13395
|
+
}
|
|
13396
|
+
if (filters == null ? void 0 : filters.dueAfter) {
|
|
13397
|
+
const dueAfterMillis = filters.dueAfter.toMillis();
|
|
13398
|
+
requirements = requirements.filter(
|
|
13399
|
+
(req) => req.instructions.some(
|
|
13400
|
+
(instr) => instr.dueTime.toMillis() > dueAfterMillis
|
|
13401
|
+
)
|
|
13402
|
+
);
|
|
13403
|
+
}
|
|
13404
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1] || null;
|
|
13405
|
+
return { requirements, lastDoc: newLastVisible };
|
|
13406
|
+
}
|
|
13407
|
+
/**
|
|
13408
|
+
* Marks a specific instruction within a PatientRequirementInstance as ACTION_TAKEN.
|
|
13409
|
+
* If all instructions are actioned, updates the overallStatus of the instance.
|
|
13410
|
+
*
|
|
13411
|
+
* @param patientId - The ID of the patient.
|
|
13412
|
+
* @param instanceId - The ID of the PatientRequirementInstance.
|
|
13413
|
+
* @param instructionId - The ID of the instruction to complete.
|
|
13414
|
+
* @returns The updated PatientRequirementInstance.
|
|
13415
|
+
* @throws Error if the instance or instruction is not found, or if the instruction is not in a completable state.
|
|
13416
|
+
*/
|
|
13417
|
+
async completeInstruction(patientId, instanceId, instructionId) {
|
|
13418
|
+
const instanceRef = this.getPatientRequirementDocRef(patientId, instanceId);
|
|
13419
|
+
const instanceSnap = await (0, import_firestore41.getDoc)(instanceRef);
|
|
13420
|
+
if (!instanceSnap.exists()) {
|
|
13421
|
+
throw new Error(
|
|
13422
|
+
`PatientRequirementInstance ${instanceId} not found for patient ${patientId}.`
|
|
13423
|
+
);
|
|
13424
|
+
}
|
|
13425
|
+
const instanceData = instanceSnap.data();
|
|
13426
|
+
const instance = { id: instanceSnap.id, ...instanceData };
|
|
13427
|
+
const instructionIndex = instance.instructions.findIndex(
|
|
13428
|
+
(instr) => instr.instructionId === instructionId
|
|
13429
|
+
);
|
|
13430
|
+
if (instructionIndex === -1) {
|
|
13431
|
+
throw new Error(
|
|
13432
|
+
`Instruction ${instructionId} not found in instance ${instanceId}.`
|
|
13433
|
+
);
|
|
13434
|
+
}
|
|
13435
|
+
const instructionToUpdate = instance.instructions[instructionIndex];
|
|
13436
|
+
if (instructionToUpdate.status !== "pendingNotification" /* PENDING_NOTIFICATION */ && instructionToUpdate.status !== "actionDue" /* ACTION_DUE */ && instructionToUpdate.status !== "missed" /* MISSED */) {
|
|
13437
|
+
if (instructionToUpdate.status === "actionTaken" /* ACTION_TAKEN */) {
|
|
13438
|
+
console.warn(
|
|
13439
|
+
`Instruction ${instructionId} is already marked as ACTION_TAKEN.`
|
|
13440
|
+
);
|
|
13441
|
+
return instance;
|
|
13442
|
+
}
|
|
13443
|
+
throw new Error(
|
|
13444
|
+
`Instruction ${instructionId} is in status ${instructionToUpdate.status} and cannot be marked as completed.`
|
|
13445
|
+
);
|
|
13446
|
+
}
|
|
13447
|
+
const now = import_firestore41.Timestamp.now();
|
|
13448
|
+
const updatedInstructions = [...instance.instructions];
|
|
13449
|
+
updatedInstructions[instructionIndex] = {
|
|
13450
|
+
...instructionToUpdate,
|
|
13451
|
+
status: "actionTaken" /* ACTION_TAKEN */,
|
|
13452
|
+
actionTakenAt: now,
|
|
13453
|
+
updatedAt: now
|
|
13454
|
+
};
|
|
13455
|
+
const allActionTaken = updatedInstructions.every(
|
|
13456
|
+
(instr) => instr.status === "actionTaken" /* ACTION_TAKEN */
|
|
13457
|
+
);
|
|
13458
|
+
let newOverallStatus = instance.overallStatus;
|
|
13459
|
+
if (allActionTaken) {
|
|
13460
|
+
newOverallStatus = "allInstructionsMet" /* ALL_INSTRUCTIONS_MET */;
|
|
13461
|
+
} else if (updatedInstructions.some(
|
|
13462
|
+
(instr) => instr.status === "actionTaken" /* ACTION_TAKEN */
|
|
13463
|
+
)) {
|
|
13464
|
+
newOverallStatus = "partiallyCompleted" /* PARTIALLY_COMPLETED */;
|
|
13465
|
+
}
|
|
13466
|
+
const updatePayload = {
|
|
13467
|
+
// Using a general type for updateDoc payload
|
|
13468
|
+
instructions: updatedInstructions,
|
|
13469
|
+
updatedAt: now
|
|
13470
|
+
};
|
|
13471
|
+
if (newOverallStatus !== instance.overallStatus) {
|
|
13472
|
+
updatePayload.overallStatus = newOverallStatus;
|
|
13473
|
+
}
|
|
13474
|
+
await (0, import_firestore41.updateDoc)(instanceRef, updatePayload);
|
|
13475
|
+
return {
|
|
13476
|
+
...instance,
|
|
13477
|
+
instructions: updatedInstructions,
|
|
13478
|
+
updatedAt: now,
|
|
13479
|
+
overallStatus: newOverallStatus
|
|
13480
|
+
};
|
|
13481
|
+
}
|
|
13482
|
+
// Note: As per the request, full CRUD (create, direct update of instance, delete) is not part of this light service,
|
|
13483
|
+
// as those will be handled by Cloud Functions reacting to appointment lifecycle events.
|
|
13484
|
+
};
|
|
13485
|
+
|
|
13486
|
+
// src/backoffice/services/brand.service.ts
|
|
13487
|
+
var import_firestore42 = require("firebase/firestore");
|
|
13488
|
+
|
|
12791
13489
|
// src/backoffice/types/brand.types.ts
|
|
12792
13490
|
var BRANDS_COLLECTION = "brands";
|
|
12793
13491
|
|
|
@@ -12797,7 +13495,7 @@ var BrandService = class extends BaseService {
|
|
|
12797
13495
|
* Gets reference to brands collection
|
|
12798
13496
|
*/
|
|
12799
13497
|
getBrandsRef() {
|
|
12800
|
-
return (0,
|
|
13498
|
+
return (0, import_firestore42.collection)(this.db, BRANDS_COLLECTION);
|
|
12801
13499
|
}
|
|
12802
13500
|
/**
|
|
12803
13501
|
* Creates a new brand
|
|
@@ -12810,19 +13508,19 @@ var BrandService = class extends BaseService {
|
|
|
12810
13508
|
updatedAt: now,
|
|
12811
13509
|
isActive: true
|
|
12812
13510
|
};
|
|
12813
|
-
const docRef = await (0,
|
|
13511
|
+
const docRef = await (0, import_firestore42.addDoc)(this.getBrandsRef(), newBrand);
|
|
12814
13512
|
return { id: docRef.id, ...newBrand };
|
|
12815
13513
|
}
|
|
12816
13514
|
/**
|
|
12817
13515
|
* Gets all active brands
|
|
12818
13516
|
*/
|
|
12819
13517
|
async getAll() {
|
|
12820
|
-
const q = (0,
|
|
12821
|
-
const snapshot = await (0,
|
|
13518
|
+
const q = (0, import_firestore42.query)(this.getBrandsRef(), (0, import_firestore42.where)("isActive", "==", true));
|
|
13519
|
+
const snapshot = await (0, import_firestore42.getDocs)(q);
|
|
12822
13520
|
return snapshot.docs.map(
|
|
12823
|
-
(
|
|
12824
|
-
id:
|
|
12825
|
-
...
|
|
13521
|
+
(doc33) => ({
|
|
13522
|
+
id: doc33.id,
|
|
13523
|
+
...doc33.data()
|
|
12826
13524
|
})
|
|
12827
13525
|
);
|
|
12828
13526
|
}
|
|
@@ -12834,8 +13532,8 @@ var BrandService = class extends BaseService {
|
|
|
12834
13532
|
...brand,
|
|
12835
13533
|
updatedAt: /* @__PURE__ */ new Date()
|
|
12836
13534
|
};
|
|
12837
|
-
const docRef = (0,
|
|
12838
|
-
await (0,
|
|
13535
|
+
const docRef = (0, import_firestore42.doc)(this.getBrandsRef(), brandId);
|
|
13536
|
+
await (0, import_firestore42.updateDoc)(docRef, updateData);
|
|
12839
13537
|
return this.getById(brandId);
|
|
12840
13538
|
}
|
|
12841
13539
|
/**
|
|
@@ -12850,8 +13548,8 @@ var BrandService = class extends BaseService {
|
|
|
12850
13548
|
* Gets a brand by ID
|
|
12851
13549
|
*/
|
|
12852
13550
|
async getById(brandId) {
|
|
12853
|
-
const docRef = (0,
|
|
12854
|
-
const docSnap = await (0,
|
|
13551
|
+
const docRef = (0, import_firestore42.doc)(this.getBrandsRef(), brandId);
|
|
13552
|
+
const docSnap = await (0, import_firestore42.getDoc)(docRef);
|
|
12855
13553
|
if (!docSnap.exists()) return null;
|
|
12856
13554
|
return {
|
|
12857
13555
|
id: docSnap.id,
|
|
@@ -12861,7 +13559,7 @@ var BrandService = class extends BaseService {
|
|
|
12861
13559
|
};
|
|
12862
13560
|
|
|
12863
13561
|
// src/backoffice/services/category.service.ts
|
|
12864
|
-
var
|
|
13562
|
+
var import_firestore43 = require("firebase/firestore");
|
|
12865
13563
|
|
|
12866
13564
|
// src/backoffice/types/category.types.ts
|
|
12867
13565
|
var CATEGORIES_COLLECTION = "backoffice_categories";
|
|
@@ -12872,7 +13570,7 @@ var CategoryService = class extends BaseService {
|
|
|
12872
13570
|
* Referenca na Firestore kolekciju kategorija
|
|
12873
13571
|
*/
|
|
12874
13572
|
get categoriesRef() {
|
|
12875
|
-
return (0,
|
|
13573
|
+
return (0, import_firestore43.collection)(this.db, CATEGORIES_COLLECTION);
|
|
12876
13574
|
}
|
|
12877
13575
|
/**
|
|
12878
13576
|
* Kreira novu kategoriju u sistemu
|
|
@@ -12887,7 +13585,7 @@ var CategoryService = class extends BaseService {
|
|
|
12887
13585
|
updatedAt: now,
|
|
12888
13586
|
isActive: true
|
|
12889
13587
|
};
|
|
12890
|
-
const docRef = await (0,
|
|
13588
|
+
const docRef = await (0, import_firestore43.addDoc)(this.categoriesRef, newCategory);
|
|
12891
13589
|
return { id: docRef.id, ...newCategory };
|
|
12892
13590
|
}
|
|
12893
13591
|
/**
|
|
@@ -12895,12 +13593,12 @@ var CategoryService = class extends BaseService {
|
|
|
12895
13593
|
* @returns Lista aktivnih kategorija
|
|
12896
13594
|
*/
|
|
12897
13595
|
async getAll() {
|
|
12898
|
-
const q = (0,
|
|
12899
|
-
const snapshot = await (0,
|
|
13596
|
+
const q = (0, import_firestore43.query)(this.categoriesRef, (0, import_firestore43.where)("isActive", "==", true));
|
|
13597
|
+
const snapshot = await (0, import_firestore43.getDocs)(q);
|
|
12900
13598
|
return snapshot.docs.map(
|
|
12901
|
-
(
|
|
12902
|
-
id:
|
|
12903
|
-
...
|
|
13599
|
+
(doc33) => ({
|
|
13600
|
+
id: doc33.id,
|
|
13601
|
+
...doc33.data()
|
|
12904
13602
|
})
|
|
12905
13603
|
);
|
|
12906
13604
|
}
|
|
@@ -12910,16 +13608,16 @@ var CategoryService = class extends BaseService {
|
|
|
12910
13608
|
* @returns Lista kategorija koje pripadaju traženoj familiji
|
|
12911
13609
|
*/
|
|
12912
13610
|
async getAllByFamily(family) {
|
|
12913
|
-
const q = (0,
|
|
13611
|
+
const q = (0, import_firestore43.query)(
|
|
12914
13612
|
this.categoriesRef,
|
|
12915
|
-
(0,
|
|
12916
|
-
(0,
|
|
13613
|
+
(0, import_firestore43.where)("family", "==", family),
|
|
13614
|
+
(0, import_firestore43.where)("isActive", "==", true)
|
|
12917
13615
|
);
|
|
12918
|
-
const snapshot = await (0,
|
|
13616
|
+
const snapshot = await (0, import_firestore43.getDocs)(q);
|
|
12919
13617
|
return snapshot.docs.map(
|
|
12920
|
-
(
|
|
12921
|
-
id:
|
|
12922
|
-
...
|
|
13618
|
+
(doc33) => ({
|
|
13619
|
+
id: doc33.id,
|
|
13620
|
+
...doc33.data()
|
|
12923
13621
|
})
|
|
12924
13622
|
);
|
|
12925
13623
|
}
|
|
@@ -12934,8 +13632,8 @@ var CategoryService = class extends BaseService {
|
|
|
12934
13632
|
...category,
|
|
12935
13633
|
updatedAt: /* @__PURE__ */ new Date()
|
|
12936
13634
|
};
|
|
12937
|
-
const docRef = (0,
|
|
12938
|
-
await (0,
|
|
13635
|
+
const docRef = (0, import_firestore43.doc)(this.categoriesRef, id);
|
|
13636
|
+
await (0, import_firestore43.updateDoc)(docRef, updateData);
|
|
12939
13637
|
return this.getById(id);
|
|
12940
13638
|
}
|
|
12941
13639
|
/**
|
|
@@ -12951,8 +13649,8 @@ var CategoryService = class extends BaseService {
|
|
|
12951
13649
|
* @returns Kategorija ili null ako ne postoji
|
|
12952
13650
|
*/
|
|
12953
13651
|
async getById(id) {
|
|
12954
|
-
const docRef = (0,
|
|
12955
|
-
const docSnap = await (0,
|
|
13652
|
+
const docRef = (0, import_firestore43.doc)(this.categoriesRef, id);
|
|
13653
|
+
const docSnap = await (0, import_firestore43.getDoc)(docRef);
|
|
12956
13654
|
if (!docSnap.exists()) return null;
|
|
12957
13655
|
return {
|
|
12958
13656
|
id: docSnap.id,
|
|
@@ -12962,7 +13660,7 @@ var CategoryService = class extends BaseService {
|
|
|
12962
13660
|
};
|
|
12963
13661
|
|
|
12964
13662
|
// src/backoffice/services/subcategory.service.ts
|
|
12965
|
-
var
|
|
13663
|
+
var import_firestore44 = require("firebase/firestore");
|
|
12966
13664
|
|
|
12967
13665
|
// src/backoffice/types/subcategory.types.ts
|
|
12968
13666
|
var SUBCATEGORIES_COLLECTION = "subcategories";
|
|
@@ -12974,7 +13672,7 @@ var SubcategoryService = class extends BaseService {
|
|
|
12974
13672
|
* @param categoryId - ID roditeljske kategorije
|
|
12975
13673
|
*/
|
|
12976
13674
|
getSubcategoriesRef(categoryId) {
|
|
12977
|
-
return (0,
|
|
13675
|
+
return (0, import_firestore44.collection)(
|
|
12978
13676
|
this.db,
|
|
12979
13677
|
CATEGORIES_COLLECTION,
|
|
12980
13678
|
categoryId,
|
|
@@ -12996,7 +13694,7 @@ var SubcategoryService = class extends BaseService {
|
|
|
12996
13694
|
updatedAt: now,
|
|
12997
13695
|
isActive: true
|
|
12998
13696
|
};
|
|
12999
|
-
const docRef = await (0,
|
|
13697
|
+
const docRef = await (0, import_firestore44.addDoc)(
|
|
13000
13698
|
this.getSubcategoriesRef(categoryId),
|
|
13001
13699
|
newSubcategory
|
|
13002
13700
|
);
|
|
@@ -13008,15 +13706,15 @@ var SubcategoryService = class extends BaseService {
|
|
|
13008
13706
|
* @returns Lista aktivnih podkategorija
|
|
13009
13707
|
*/
|
|
13010
13708
|
async getAllByCategoryId(categoryId) {
|
|
13011
|
-
const q = (0,
|
|
13709
|
+
const q = (0, import_firestore44.query)(
|
|
13012
13710
|
this.getSubcategoriesRef(categoryId),
|
|
13013
|
-
(0,
|
|
13711
|
+
(0, import_firestore44.where)("isActive", "==", true)
|
|
13014
13712
|
);
|
|
13015
|
-
const snapshot = await (0,
|
|
13713
|
+
const snapshot = await (0, import_firestore44.getDocs)(q);
|
|
13016
13714
|
return snapshot.docs.map(
|
|
13017
|
-
(
|
|
13018
|
-
id:
|
|
13019
|
-
...
|
|
13715
|
+
(doc33) => ({
|
|
13716
|
+
id: doc33.id,
|
|
13717
|
+
...doc33.data()
|
|
13020
13718
|
})
|
|
13021
13719
|
);
|
|
13022
13720
|
}
|
|
@@ -13032,8 +13730,8 @@ var SubcategoryService = class extends BaseService {
|
|
|
13032
13730
|
...subcategory,
|
|
13033
13731
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13034
13732
|
};
|
|
13035
|
-
const docRef = (0,
|
|
13036
|
-
await (0,
|
|
13733
|
+
const docRef = (0, import_firestore44.doc)(this.getSubcategoriesRef(categoryId), subcategoryId);
|
|
13734
|
+
await (0, import_firestore44.updateDoc)(docRef, updateData);
|
|
13037
13735
|
return this.getById(categoryId, subcategoryId);
|
|
13038
13736
|
}
|
|
13039
13737
|
/**
|
|
@@ -13051,8 +13749,8 @@ var SubcategoryService = class extends BaseService {
|
|
|
13051
13749
|
* @returns Podkategorija ili null ako ne postoji
|
|
13052
13750
|
*/
|
|
13053
13751
|
async getById(categoryId, subcategoryId) {
|
|
13054
|
-
const docRef = (0,
|
|
13055
|
-
const docSnap = await (0,
|
|
13752
|
+
const docRef = (0, import_firestore44.doc)(this.getSubcategoriesRef(categoryId), subcategoryId);
|
|
13753
|
+
const docSnap = await (0, import_firestore44.getDoc)(docRef);
|
|
13056
13754
|
if (!docSnap.exists()) return null;
|
|
13057
13755
|
return {
|
|
13058
13756
|
id: docSnap.id,
|
|
@@ -13062,7 +13760,7 @@ var SubcategoryService = class extends BaseService {
|
|
|
13062
13760
|
};
|
|
13063
13761
|
|
|
13064
13762
|
// src/backoffice/services/technology.service.ts
|
|
13065
|
-
var
|
|
13763
|
+
var import_firestore45 = require("firebase/firestore");
|
|
13066
13764
|
var DEFAULT_CERTIFICATION_REQUIREMENT = {
|
|
13067
13765
|
minimumLevel: "aesthetician" /* AESTHETICIAN */,
|
|
13068
13766
|
requiredSpecialties: []
|
|
@@ -13072,7 +13770,7 @@ var TechnologyService = class extends BaseService {
|
|
|
13072
13770
|
* Vraća referencu na Firestore kolekciju tehnologija
|
|
13073
13771
|
*/
|
|
13074
13772
|
getTechnologiesRef() {
|
|
13075
|
-
return (0,
|
|
13773
|
+
return (0, import_firestore45.collection)(this.db, TECHNOLOGIES_COLLECTION);
|
|
13076
13774
|
}
|
|
13077
13775
|
/**
|
|
13078
13776
|
* Kreira novu tehnologiju
|
|
@@ -13095,7 +13793,7 @@ var TechnologyService = class extends BaseService {
|
|
|
13095
13793
|
benefits: technology.benefits || [],
|
|
13096
13794
|
certificationRequirement: technology.certificationRequirement || DEFAULT_CERTIFICATION_REQUIREMENT
|
|
13097
13795
|
};
|
|
13098
|
-
const docRef = await (0,
|
|
13796
|
+
const docRef = await (0, import_firestore45.addDoc)(this.getTechnologiesRef(), newTechnology);
|
|
13099
13797
|
return { id: docRef.id, ...newTechnology };
|
|
13100
13798
|
}
|
|
13101
13799
|
/**
|
|
@@ -13103,12 +13801,12 @@ var TechnologyService = class extends BaseService {
|
|
|
13103
13801
|
* @returns Lista aktivnih tehnologija
|
|
13104
13802
|
*/
|
|
13105
13803
|
async getAll() {
|
|
13106
|
-
const q = (0,
|
|
13107
|
-
const snapshot = await (0,
|
|
13804
|
+
const q = (0, import_firestore45.query)(this.getTechnologiesRef(), (0, import_firestore45.where)("isActive", "==", true));
|
|
13805
|
+
const snapshot = await (0, import_firestore45.getDocs)(q);
|
|
13108
13806
|
return snapshot.docs.map(
|
|
13109
|
-
(
|
|
13110
|
-
id:
|
|
13111
|
-
...
|
|
13807
|
+
(doc33) => ({
|
|
13808
|
+
id: doc33.id,
|
|
13809
|
+
...doc33.data()
|
|
13112
13810
|
})
|
|
13113
13811
|
);
|
|
13114
13812
|
}
|
|
@@ -13118,16 +13816,16 @@ var TechnologyService = class extends BaseService {
|
|
|
13118
13816
|
* @returns Lista aktivnih tehnologija
|
|
13119
13817
|
*/
|
|
13120
13818
|
async getAllByFamily(family) {
|
|
13121
|
-
const q = (0,
|
|
13819
|
+
const q = (0, import_firestore45.query)(
|
|
13122
13820
|
this.getTechnologiesRef(),
|
|
13123
|
-
(0,
|
|
13124
|
-
(0,
|
|
13821
|
+
(0, import_firestore45.where)("isActive", "==", true),
|
|
13822
|
+
(0, import_firestore45.where)("family", "==", family)
|
|
13125
13823
|
);
|
|
13126
|
-
const snapshot = await (0,
|
|
13824
|
+
const snapshot = await (0, import_firestore45.getDocs)(q);
|
|
13127
13825
|
return snapshot.docs.map(
|
|
13128
|
-
(
|
|
13129
|
-
id:
|
|
13130
|
-
...
|
|
13826
|
+
(doc33) => ({
|
|
13827
|
+
id: doc33.id,
|
|
13828
|
+
...doc33.data()
|
|
13131
13829
|
})
|
|
13132
13830
|
);
|
|
13133
13831
|
}
|
|
@@ -13137,16 +13835,16 @@ var TechnologyService = class extends BaseService {
|
|
|
13137
13835
|
* @returns Lista aktivnih tehnologija
|
|
13138
13836
|
*/
|
|
13139
13837
|
async getAllByCategoryId(categoryId) {
|
|
13140
|
-
const q = (0,
|
|
13838
|
+
const q = (0, import_firestore45.query)(
|
|
13141
13839
|
this.getTechnologiesRef(),
|
|
13142
|
-
(0,
|
|
13143
|
-
(0,
|
|
13840
|
+
(0, import_firestore45.where)("isActive", "==", true),
|
|
13841
|
+
(0, import_firestore45.where)("categoryId", "==", categoryId)
|
|
13144
13842
|
);
|
|
13145
|
-
const snapshot = await (0,
|
|
13843
|
+
const snapshot = await (0, import_firestore45.getDocs)(q);
|
|
13146
13844
|
return snapshot.docs.map(
|
|
13147
|
-
(
|
|
13148
|
-
id:
|
|
13149
|
-
...
|
|
13845
|
+
(doc33) => ({
|
|
13846
|
+
id: doc33.id,
|
|
13847
|
+
...doc33.data()
|
|
13150
13848
|
})
|
|
13151
13849
|
);
|
|
13152
13850
|
}
|
|
@@ -13156,16 +13854,16 @@ var TechnologyService = class extends BaseService {
|
|
|
13156
13854
|
* @returns Lista aktivnih tehnologija
|
|
13157
13855
|
*/
|
|
13158
13856
|
async getAllBySubcategoryId(subcategoryId) {
|
|
13159
|
-
const q = (0,
|
|
13857
|
+
const q = (0, import_firestore45.query)(
|
|
13160
13858
|
this.getTechnologiesRef(),
|
|
13161
|
-
(0,
|
|
13162
|
-
(0,
|
|
13859
|
+
(0, import_firestore45.where)("isActive", "==", true),
|
|
13860
|
+
(0, import_firestore45.where)("subcategoryId", "==", subcategoryId)
|
|
13163
13861
|
);
|
|
13164
|
-
const snapshot = await (0,
|
|
13862
|
+
const snapshot = await (0, import_firestore45.getDocs)(q);
|
|
13165
13863
|
return snapshot.docs.map(
|
|
13166
|
-
(
|
|
13167
|
-
id:
|
|
13168
|
-
...
|
|
13864
|
+
(doc33) => ({
|
|
13865
|
+
id: doc33.id,
|
|
13866
|
+
...doc33.data()
|
|
13169
13867
|
})
|
|
13170
13868
|
);
|
|
13171
13869
|
}
|
|
@@ -13180,8 +13878,8 @@ var TechnologyService = class extends BaseService {
|
|
|
13180
13878
|
...technology,
|
|
13181
13879
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13182
13880
|
};
|
|
13183
|
-
const docRef = (0,
|
|
13184
|
-
await (0,
|
|
13881
|
+
const docRef = (0, import_firestore45.doc)(this.getTechnologiesRef(), technologyId);
|
|
13882
|
+
await (0, import_firestore45.updateDoc)(docRef, updateData);
|
|
13185
13883
|
return this.getById(technologyId);
|
|
13186
13884
|
}
|
|
13187
13885
|
/**
|
|
@@ -13199,8 +13897,8 @@ var TechnologyService = class extends BaseService {
|
|
|
13199
13897
|
* @returns Tehnologija ili null ako ne postoji
|
|
13200
13898
|
*/
|
|
13201
13899
|
async getById(technologyId) {
|
|
13202
|
-
const docRef = (0,
|
|
13203
|
-
const docSnap = await (0,
|
|
13900
|
+
const docRef = (0, import_firestore45.doc)(this.getTechnologiesRef(), technologyId);
|
|
13901
|
+
const docSnap = await (0, import_firestore45.getDoc)(docRef);
|
|
13204
13902
|
if (!docSnap.exists()) return null;
|
|
13205
13903
|
return {
|
|
13206
13904
|
id: docSnap.id,
|
|
@@ -13214,10 +13912,10 @@ var TechnologyService = class extends BaseService {
|
|
|
13214
13912
|
* @returns Ažurirana tehnologija sa novim zahtevom
|
|
13215
13913
|
*/
|
|
13216
13914
|
async addRequirement(technologyId, requirement) {
|
|
13217
|
-
const docRef = (0,
|
|
13915
|
+
const docRef = (0, import_firestore45.doc)(this.getTechnologiesRef(), technologyId);
|
|
13218
13916
|
const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
|
|
13219
|
-
await (0,
|
|
13220
|
-
[requirementType]: (0,
|
|
13917
|
+
await (0, import_firestore45.updateDoc)(docRef, {
|
|
13918
|
+
[requirementType]: (0, import_firestore45.arrayUnion)(requirement),
|
|
13221
13919
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13222
13920
|
});
|
|
13223
13921
|
return this.getById(technologyId);
|
|
@@ -13229,10 +13927,10 @@ var TechnologyService = class extends BaseService {
|
|
|
13229
13927
|
* @returns Ažurirana tehnologija bez uklonjenog zahteva
|
|
13230
13928
|
*/
|
|
13231
13929
|
async removeRequirement(technologyId, requirement) {
|
|
13232
|
-
const docRef = (0,
|
|
13930
|
+
const docRef = (0, import_firestore45.doc)(this.getTechnologiesRef(), technologyId);
|
|
13233
13931
|
const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
|
|
13234
|
-
await (0,
|
|
13235
|
-
[requirementType]: (0,
|
|
13932
|
+
await (0, import_firestore45.updateDoc)(docRef, {
|
|
13933
|
+
[requirementType]: (0, import_firestore45.arrayRemove)(requirement),
|
|
13236
13934
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13237
13935
|
});
|
|
13238
13936
|
return this.getById(technologyId);
|
|
@@ -13269,9 +13967,9 @@ var TechnologyService = class extends BaseService {
|
|
|
13269
13967
|
* @returns Ažurirana tehnologija
|
|
13270
13968
|
*/
|
|
13271
13969
|
async addBlockingCondition(technologyId, condition) {
|
|
13272
|
-
const docRef = (0,
|
|
13273
|
-
await (0,
|
|
13274
|
-
blockingConditions: (0,
|
|
13970
|
+
const docRef = (0, import_firestore45.doc)(this.getTechnologiesRef(), technologyId);
|
|
13971
|
+
await (0, import_firestore45.updateDoc)(docRef, {
|
|
13972
|
+
blockingConditions: (0, import_firestore45.arrayUnion)(condition),
|
|
13275
13973
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13276
13974
|
});
|
|
13277
13975
|
return this.getById(technologyId);
|
|
@@ -13283,9 +13981,9 @@ var TechnologyService = class extends BaseService {
|
|
|
13283
13981
|
* @returns Ažurirana tehnologija
|
|
13284
13982
|
*/
|
|
13285
13983
|
async removeBlockingCondition(technologyId, condition) {
|
|
13286
|
-
const docRef = (0,
|
|
13287
|
-
await (0,
|
|
13288
|
-
blockingConditions: (0,
|
|
13984
|
+
const docRef = (0, import_firestore45.doc)(this.getTechnologiesRef(), technologyId);
|
|
13985
|
+
await (0, import_firestore45.updateDoc)(docRef, {
|
|
13986
|
+
blockingConditions: (0, import_firestore45.arrayRemove)(condition),
|
|
13289
13987
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13290
13988
|
});
|
|
13291
13989
|
return this.getById(technologyId);
|
|
@@ -13297,9 +13995,9 @@ var TechnologyService = class extends BaseService {
|
|
|
13297
13995
|
* @returns Ažurirana tehnologija
|
|
13298
13996
|
*/
|
|
13299
13997
|
async addContraindication(technologyId, contraindication) {
|
|
13300
|
-
const docRef = (0,
|
|
13301
|
-
await (0,
|
|
13302
|
-
contraindications: (0,
|
|
13998
|
+
const docRef = (0, import_firestore45.doc)(this.getTechnologiesRef(), technologyId);
|
|
13999
|
+
await (0, import_firestore45.updateDoc)(docRef, {
|
|
14000
|
+
contraindications: (0, import_firestore45.arrayUnion)(contraindication),
|
|
13303
14001
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13304
14002
|
});
|
|
13305
14003
|
return this.getById(technologyId);
|
|
@@ -13311,9 +14009,9 @@ var TechnologyService = class extends BaseService {
|
|
|
13311
14009
|
* @returns Ažurirana tehnologija
|
|
13312
14010
|
*/
|
|
13313
14011
|
async removeContraindication(technologyId, contraindication) {
|
|
13314
|
-
const docRef = (0,
|
|
13315
|
-
await (0,
|
|
13316
|
-
contraindications: (0,
|
|
14012
|
+
const docRef = (0, import_firestore45.doc)(this.getTechnologiesRef(), technologyId);
|
|
14013
|
+
await (0, import_firestore45.updateDoc)(docRef, {
|
|
14014
|
+
contraindications: (0, import_firestore45.arrayRemove)(contraindication),
|
|
13317
14015
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13318
14016
|
});
|
|
13319
14017
|
return this.getById(technologyId);
|
|
@@ -13325,9 +14023,9 @@ var TechnologyService = class extends BaseService {
|
|
|
13325
14023
|
* @returns Ažurirana tehnologija
|
|
13326
14024
|
*/
|
|
13327
14025
|
async addBenefit(technologyId, benefit) {
|
|
13328
|
-
const docRef = (0,
|
|
13329
|
-
await (0,
|
|
13330
|
-
benefits: (0,
|
|
14026
|
+
const docRef = (0, import_firestore45.doc)(this.getTechnologiesRef(), technologyId);
|
|
14027
|
+
await (0, import_firestore45.updateDoc)(docRef, {
|
|
14028
|
+
benefits: (0, import_firestore45.arrayUnion)(benefit),
|
|
13331
14029
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13332
14030
|
});
|
|
13333
14031
|
return this.getById(technologyId);
|
|
@@ -13339,9 +14037,9 @@ var TechnologyService = class extends BaseService {
|
|
|
13339
14037
|
* @returns Ažurirana tehnologija
|
|
13340
14038
|
*/
|
|
13341
14039
|
async removeBenefit(technologyId, benefit) {
|
|
13342
|
-
const docRef = (0,
|
|
13343
|
-
await (0,
|
|
13344
|
-
benefits: (0,
|
|
14040
|
+
const docRef = (0, import_firestore45.doc)(this.getTechnologiesRef(), technologyId);
|
|
14041
|
+
await (0, import_firestore45.updateDoc)(docRef, {
|
|
14042
|
+
benefits: (0, import_firestore45.arrayRemove)(benefit),
|
|
13345
14043
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13346
14044
|
});
|
|
13347
14045
|
return this.getById(technologyId);
|
|
@@ -13380,8 +14078,8 @@ var TechnologyService = class extends BaseService {
|
|
|
13380
14078
|
* @returns Ažurirana tehnologija
|
|
13381
14079
|
*/
|
|
13382
14080
|
async updateCertificationRequirement(technologyId, certificationRequirement) {
|
|
13383
|
-
const docRef = (0,
|
|
13384
|
-
await (0,
|
|
14081
|
+
const docRef = (0, import_firestore45.doc)(this.getTechnologiesRef(), technologyId);
|
|
14082
|
+
await (0, import_firestore45.updateDoc)(docRef, {
|
|
13385
14083
|
certificationRequirement,
|
|
13386
14084
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13387
14085
|
});
|
|
@@ -13481,7 +14179,7 @@ var TechnologyService = class extends BaseService {
|
|
|
13481
14179
|
};
|
|
13482
14180
|
|
|
13483
14181
|
// src/backoffice/services/product.service.ts
|
|
13484
|
-
var
|
|
14182
|
+
var import_firestore46 = require("firebase/firestore");
|
|
13485
14183
|
|
|
13486
14184
|
// src/backoffice/types/product.types.ts
|
|
13487
14185
|
var PRODUCTS_COLLECTION = "products";
|
|
@@ -13494,7 +14192,7 @@ var ProductService = class extends BaseService {
|
|
|
13494
14192
|
* @returns Firestore collection reference
|
|
13495
14193
|
*/
|
|
13496
14194
|
getProductsRef(technologyId) {
|
|
13497
|
-
return (0,
|
|
14195
|
+
return (0, import_firestore46.collection)(
|
|
13498
14196
|
this.db,
|
|
13499
14197
|
TECHNOLOGIES_COLLECTION,
|
|
13500
14198
|
technologyId,
|
|
@@ -13514,7 +14212,7 @@ var ProductService = class extends BaseService {
|
|
|
13514
14212
|
updatedAt: now,
|
|
13515
14213
|
isActive: true
|
|
13516
14214
|
};
|
|
13517
|
-
const productRef = await (0,
|
|
14215
|
+
const productRef = await (0, import_firestore46.addDoc)(
|
|
13518
14216
|
this.getProductsRef(technologyId),
|
|
13519
14217
|
newProduct
|
|
13520
14218
|
);
|
|
@@ -13524,15 +14222,15 @@ var ProductService = class extends BaseService {
|
|
|
13524
14222
|
* Gets all products for a technology
|
|
13525
14223
|
*/
|
|
13526
14224
|
async getAllByTechnology(technologyId) {
|
|
13527
|
-
const q = (0,
|
|
14225
|
+
const q = (0, import_firestore46.query)(
|
|
13528
14226
|
this.getProductsRef(technologyId),
|
|
13529
|
-
(0,
|
|
14227
|
+
(0, import_firestore46.where)("isActive", "==", true)
|
|
13530
14228
|
);
|
|
13531
|
-
const snapshot = await (0,
|
|
14229
|
+
const snapshot = await (0, import_firestore46.getDocs)(q);
|
|
13532
14230
|
return snapshot.docs.map(
|
|
13533
|
-
(
|
|
13534
|
-
id:
|
|
13535
|
-
...
|
|
14231
|
+
(doc33) => ({
|
|
14232
|
+
id: doc33.id,
|
|
14233
|
+
...doc33.data()
|
|
13536
14234
|
})
|
|
13537
14235
|
);
|
|
13538
14236
|
}
|
|
@@ -13540,21 +14238,21 @@ var ProductService = class extends BaseService {
|
|
|
13540
14238
|
* Gets all products for a brand by filtering through all technologies
|
|
13541
14239
|
*/
|
|
13542
14240
|
async getAllByBrand(brandId) {
|
|
13543
|
-
const allTechnologiesRef = (0,
|
|
13544
|
-
const technologiesSnapshot = await (0,
|
|
14241
|
+
const allTechnologiesRef = (0, import_firestore46.collection)(this.db, TECHNOLOGIES_COLLECTION);
|
|
14242
|
+
const technologiesSnapshot = await (0, import_firestore46.getDocs)(allTechnologiesRef);
|
|
13545
14243
|
const products = [];
|
|
13546
14244
|
for (const techDoc of technologiesSnapshot.docs) {
|
|
13547
|
-
const q = (0,
|
|
14245
|
+
const q = (0, import_firestore46.query)(
|
|
13548
14246
|
this.getProductsRef(techDoc.id),
|
|
13549
|
-
(0,
|
|
13550
|
-
(0,
|
|
14247
|
+
(0, import_firestore46.where)("brandId", "==", brandId),
|
|
14248
|
+
(0, import_firestore46.where)("isActive", "==", true)
|
|
13551
14249
|
);
|
|
13552
|
-
const snapshot = await (0,
|
|
14250
|
+
const snapshot = await (0, import_firestore46.getDocs)(q);
|
|
13553
14251
|
products.push(
|
|
13554
14252
|
...snapshot.docs.map(
|
|
13555
|
-
(
|
|
13556
|
-
id:
|
|
13557
|
-
...
|
|
14253
|
+
(doc33) => ({
|
|
14254
|
+
id: doc33.id,
|
|
14255
|
+
...doc33.data()
|
|
13558
14256
|
})
|
|
13559
14257
|
)
|
|
13560
14258
|
);
|
|
@@ -13569,8 +14267,8 @@ var ProductService = class extends BaseService {
|
|
|
13569
14267
|
...product,
|
|
13570
14268
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13571
14269
|
};
|
|
13572
|
-
const docRef = (0,
|
|
13573
|
-
await (0,
|
|
14270
|
+
const docRef = (0, import_firestore46.doc)(this.getProductsRef(technologyId), productId);
|
|
14271
|
+
await (0, import_firestore46.updateDoc)(docRef, updateData);
|
|
13574
14272
|
return this.getById(technologyId, productId);
|
|
13575
14273
|
}
|
|
13576
14274
|
/**
|
|
@@ -13585,8 +14283,8 @@ var ProductService = class extends BaseService {
|
|
|
13585
14283
|
* Gets a product by ID
|
|
13586
14284
|
*/
|
|
13587
14285
|
async getById(technologyId, productId) {
|
|
13588
|
-
const docRef = (0,
|
|
13589
|
-
const docSnap = await (0,
|
|
14286
|
+
const docRef = (0, import_firestore46.doc)(this.getProductsRef(technologyId), productId);
|
|
14287
|
+
const docSnap = await (0, import_firestore46.getDoc)(docRef);
|
|
13590
14288
|
if (!docSnap.exists()) return null;
|
|
13591
14289
|
return {
|
|
13592
14290
|
id: docSnap.id,
|
|
@@ -13615,14 +14313,14 @@ var baseNotificationSchema = import_zod24.z.object({
|
|
|
13615
14313
|
userRole: import_zod24.z.nativeEnum(UserRole)
|
|
13616
14314
|
});
|
|
13617
14315
|
var preRequirementNotificationSchema = baseNotificationSchema.extend({
|
|
13618
|
-
notificationType: import_zod24.z.literal("
|
|
14316
|
+
notificationType: import_zod24.z.literal("requirementInstructionDue" /* REQUIREMENT_INSTRUCTION_DUE */),
|
|
13619
14317
|
treatmentId: import_zod24.z.string(),
|
|
13620
14318
|
requirements: import_zod24.z.array(import_zod24.z.string()),
|
|
13621
14319
|
deadline: import_zod24.z.any()
|
|
13622
14320
|
// Timestamp
|
|
13623
14321
|
});
|
|
13624
14322
|
var postRequirementNotificationSchema = baseNotificationSchema.extend({
|
|
13625
|
-
notificationType: import_zod24.z.literal("
|
|
14323
|
+
notificationType: import_zod24.z.literal("requirementInstructionDue" /* REQUIREMENT_INSTRUCTION_DUE */),
|
|
13626
14324
|
treatmentId: import_zod24.z.string(),
|
|
13627
14325
|
requirements: import_zod24.z.array(import_zod24.z.string()),
|
|
13628
14326
|
deadline: import_zod24.z.any()
|
|
@@ -13637,7 +14335,7 @@ var appointmentReminderNotificationSchema = baseNotificationSchema.extend({
|
|
|
13637
14335
|
doctorName: import_zod24.z.string()
|
|
13638
14336
|
});
|
|
13639
14337
|
var appointmentNotificationSchema = baseNotificationSchema.extend({
|
|
13640
|
-
notificationType: import_zod24.z.literal("
|
|
14338
|
+
notificationType: import_zod24.z.literal("appointmentStatusChange" /* APPOINTMENT_STATUS_CHANGE */),
|
|
13641
14339
|
appointmentId: import_zod24.z.string(),
|
|
13642
14340
|
appointmentStatus: import_zod24.z.string(),
|
|
13643
14341
|
previousStatus: import_zod24.z.string(),
|
|
@@ -13734,9 +14432,13 @@ var RequirementType = /* @__PURE__ */ ((RequirementType2) => {
|
|
|
13734
14432
|
PATIENT_LOCATION_INFO_COLLECTION,
|
|
13735
14433
|
PATIENT_MEDICAL_HISTORY_COLLECTION,
|
|
13736
14434
|
PATIENT_MEDICAL_INFO_COLLECTION,
|
|
14435
|
+
PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME,
|
|
13737
14436
|
PATIENT_SENSITIVE_INFO_COLLECTION,
|
|
13738
14437
|
PRACTITIONERS_COLLECTION,
|
|
13739
14438
|
PROCEDURES_COLLECTION,
|
|
14439
|
+
PatientInstructionStatus,
|
|
14440
|
+
PatientRequirementOverallStatus,
|
|
14441
|
+
PatientRequirementsService,
|
|
13740
14442
|
PatientService,
|
|
13741
14443
|
PaymentStatus,
|
|
13742
14444
|
PracticeType,
|
|
@@ -13801,6 +14503,7 @@ var RequirementType = /* @__PURE__ */ ((RequirementType2) => {
|
|
|
13801
14503
|
createDefaultClinicGroupSchema,
|
|
13802
14504
|
createDocumentTemplateSchema,
|
|
13803
14505
|
createDraftPractitionerSchema,
|
|
14506
|
+
createFilledDocumentDataSchema,
|
|
13804
14507
|
createPatientLocationInfoSchema,
|
|
13805
14508
|
createPatientMedicalInfoSchema,
|
|
13806
14509
|
createPatientProfileSchema,
|
|
@@ -13816,6 +14519,8 @@ var RequirementType = /* @__PURE__ */ ((RequirementType2) => {
|
|
|
13816
14519
|
documentTemplateSchema,
|
|
13817
14520
|
emailSchema,
|
|
13818
14521
|
emergencyContactSchema,
|
|
14522
|
+
filledDocumentSchema,
|
|
14523
|
+
filledDocumentStatusSchema,
|
|
13819
14524
|
gamificationSchema,
|
|
13820
14525
|
getFirebaseApp,
|
|
13821
14526
|
getFirebaseAuth,
|
|
@@ -13865,6 +14570,7 @@ var RequirementType = /* @__PURE__ */ ((RequirementType2) => {
|
|
|
13865
14570
|
updateClinicSchema,
|
|
13866
14571
|
updateContraindicationSchema,
|
|
13867
14572
|
updateDocumentTemplateSchema,
|
|
14573
|
+
updateFilledDocumentDataSchema,
|
|
13868
14574
|
updateMedicationSchema,
|
|
13869
14575
|
updatePatientMedicalInfoSchema,
|
|
13870
14576
|
updateVitalStatsSchema,
|