@blackcode_sa/metaestetics-api 1.6.3 → 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.
Files changed (34) hide show
  1. package/dist/admin/index.d.mts +228 -25
  2. package/dist/admin/index.d.ts +228 -25
  3. package/dist/admin/index.js +35867 -2493
  4. package/dist/admin/index.mjs +35856 -2464
  5. package/dist/backoffice/index.d.mts +252 -1
  6. package/dist/backoffice/index.d.ts +252 -1
  7. package/dist/backoffice/index.js +86 -12
  8. package/dist/backoffice/index.mjs +86 -13
  9. package/dist/index.d.mts +1400 -554
  10. package/dist/index.d.ts +1400 -554
  11. package/dist/index.js +1325 -683
  12. package/dist/index.mjs +1358 -710
  13. package/package.json +1 -1
  14. package/src/admin/index.ts +15 -1
  15. package/src/admin/notifications/notifications.admin.ts +1 -1
  16. package/src/admin/requirements/README.md +128 -0
  17. package/src/admin/requirements/patient-requirements.admin.service.ts +482 -0
  18. package/src/index.ts +16 -1
  19. package/src/services/appointment/appointment.service.ts +315 -86
  20. package/src/services/clinic/clinic-admin.service.ts +3 -0
  21. package/src/services/clinic/clinic-group.service.ts +8 -0
  22. package/src/services/documentation-templates/documentation-template.service.ts +24 -16
  23. package/src/services/documentation-templates/filled-document.service.ts +253 -136
  24. package/src/services/patient/patientRequirements.service.ts +285 -0
  25. package/src/types/appointment/index.ts +134 -10
  26. package/src/types/documentation-templates/index.ts +34 -2
  27. package/src/types/notifications/README.md +77 -0
  28. package/src/types/notifications/index.ts +154 -27
  29. package/src/types/patient/patient-requirements.ts +81 -0
  30. package/src/validations/appointment.schema.ts +300 -62
  31. package/src/validations/documentation-templates/template.schema.ts +55 -0
  32. package/src/validations/documentation-templates.schema.ts +9 -14
  33. package/src/validations/notification.schema.ts +3 -3
  34. package/src/validations/patient/patient-requirements.schema.ts +75 -0
package/dist/index.mjs CHANGED
@@ -1,17 +1,18 @@
1
1
  // src/validations/appointment.schema.ts
2
- import { z } from "zod";
2
+ import { z as z2 } from "zod";
3
3
 
4
4
  // src/types/appointment/index.ts
5
5
  var AppointmentStatus = /* @__PURE__ */ ((AppointmentStatus2) => {
6
- AppointmentStatus2["SCHEDULED"] = "scheduled";
6
+ AppointmentStatus2["PENDING"] = "pending";
7
7
  AppointmentStatus2["CONFIRMED"] = "confirmed";
8
8
  AppointmentStatus2["CHECKED_IN"] = "checked_in";
9
9
  AppointmentStatus2["IN_PROGRESS"] = "in_progress";
10
10
  AppointmentStatus2["COMPLETED"] = "completed";
11
11
  AppointmentStatus2["CANCELED_PATIENT"] = "canceled_patient";
12
+ AppointmentStatus2["CANCELED_PATIENT_RESCHEDULED"] = "canceled_patient_rescheduled";
12
13
  AppointmentStatus2["CANCELED_CLINIC"] = "canceled_clinic";
13
14
  AppointmentStatus2["NO_SHOW"] = "no_show";
14
- AppointmentStatus2["RESCHEDULED"] = "rescheduled";
15
+ AppointmentStatus2["RESCHEDULED_BY_CLINIC"] = "rescheduled_by_clinic";
15
16
  return AppointmentStatus2;
16
17
  })(AppointmentStatus || {});
17
18
  var PaymentStatus = /* @__PURE__ */ ((PaymentStatus3) => {
@@ -22,82 +23,444 @@ var PaymentStatus = /* @__PURE__ */ ((PaymentStatus3) => {
22
23
  PaymentStatus3["NOT_APPLICABLE"] = "not_applicable";
23
24
  return PaymentStatus3;
24
25
  })(PaymentStatus || {});
26
+ var MediaType = /* @__PURE__ */ ((MediaType2) => {
27
+ MediaType2["BEFORE_PHOTO"] = "before_photo";
28
+ MediaType2["AFTER_PHOTO"] = "after_photo";
29
+ MediaType2["CONSENT_SCAN"] = "consent_scan";
30
+ MediaType2["OTHER_DOCUMENT"] = "other_document";
31
+ return MediaType2;
32
+ })(MediaType || {});
25
33
  var APPOINTMENTS_COLLECTION = "appointments";
26
34
 
35
+ // src/validations/documentation-templates/template.schema.ts
36
+ import { z } from "zod";
37
+
38
+ // src/types/documentation-templates/index.ts
39
+ var DOCUMENTATION_TEMPLATES_COLLECTION = "documentation-templates";
40
+ var FILLED_DOCUMENTS_COLLECTION = "filled-documents";
41
+ var USER_FORMS_SUBCOLLECTION = "user-forms";
42
+ var DOCTOR_FORMS_SUBCOLLECTION = "doctor-forms";
43
+ var DocumentElementType = /* @__PURE__ */ ((DocumentElementType2) => {
44
+ DocumentElementType2["HEADING"] = "heading";
45
+ DocumentElementType2["PARAGRAPH"] = "paragraph";
46
+ DocumentElementType2["LIST"] = "list";
47
+ DocumentElementType2["DYNAMIC_TEXT"] = "dynamic_text";
48
+ DocumentElementType2["BINARY_CHOICE"] = "binary_choice";
49
+ DocumentElementType2["MULTIPLE_CHOICE"] = "multiple_choice";
50
+ DocumentElementType2["SINGLE_CHOICE"] = "single_choice";
51
+ DocumentElementType2["RATING_SCALE"] = "rating_scale";
52
+ DocumentElementType2["TEXT_INPUT"] = "text_input";
53
+ DocumentElementType2["DATE_PICKER"] = "date_picker";
54
+ DocumentElementType2["SIGNATURE"] = "signature";
55
+ DocumentElementType2["DITIGAL_SIGNATURE"] = "digital_signature";
56
+ DocumentElementType2["FILE_UPLOAD"] = "file_upload";
57
+ return DocumentElementType2;
58
+ })(DocumentElementType || {});
59
+ var ListType = /* @__PURE__ */ ((ListType2) => {
60
+ ListType2["ORDERED"] = "ordered";
61
+ ListType2["UNORDERED"] = "unordered";
62
+ return ListType2;
63
+ })(ListType || {});
64
+ var HeadingLevel = /* @__PURE__ */ ((HeadingLevel2) => {
65
+ HeadingLevel2["H1"] = "h1";
66
+ HeadingLevel2["H2"] = "h2";
67
+ HeadingLevel2["H3"] = "h3";
68
+ HeadingLevel2["H4"] = "h4";
69
+ HeadingLevel2["H5"] = "h5";
70
+ HeadingLevel2["H6"] = "h6";
71
+ return HeadingLevel2;
72
+ })(HeadingLevel || {});
73
+ var DynamicVariable = /* @__PURE__ */ ((DynamicVariable2) => {
74
+ DynamicVariable2["PATIENT_NAME"] = "[PATIENT_NAME]";
75
+ DynamicVariable2["DOCTOR_NAME"] = "[DOCTOR_NAME]";
76
+ DynamicVariable2["CLINIC_NAME"] = "[CLINIC_NAME]";
77
+ DynamicVariable2["PATIENT_BIRTHDAY"] = "[PATIENT_BIRTHDAY]";
78
+ DynamicVariable2["APPOINTMENT_DATE"] = "[APPOINTMENT_DATE]";
79
+ DynamicVariable2["CURRENT_DATE"] = "[CURRENT_DATE]";
80
+ DynamicVariable2["PROCEDURE_NAME"] = "[PROCEDURE_NAME]";
81
+ DynamicVariable2["PROCEDURE_DESCRIPTION"] = "[PROCEDURE_DESCRIPTION]";
82
+ DynamicVariable2["PROCEDURE_COST"] = "[PROCEDURE_COST]";
83
+ DynamicVariable2["PROCEDURE_DURATION"] = "[PROCEDURE_DURATION]";
84
+ DynamicVariable2["PROCEDURE_RISK"] = "[PROCEDURE_RISK]";
85
+ return DynamicVariable2;
86
+ })(DynamicVariable || {});
87
+ var FilledDocumentStatus = /* @__PURE__ */ ((FilledDocumentStatus2) => {
88
+ FilledDocumentStatus2["DRAFT"] = "draft";
89
+ FilledDocumentStatus2["SKIPPED"] = "skipped";
90
+ FilledDocumentStatus2["PENDING"] = "pending";
91
+ FilledDocumentStatus2["COMPLETED"] = "completed";
92
+ FilledDocumentStatus2["SIGNED"] = "signed";
93
+ FilledDocumentStatus2["REJECTED"] = "rejected";
94
+ return FilledDocumentStatus2;
95
+ })(FilledDocumentStatus || {});
96
+
97
+ // src/validations/documentation-templates/template.schema.ts
98
+ var baseElementSchema = z.object({
99
+ id: z.string().optional(),
100
+ // Make id optional so we can omit it later
101
+ type: z.nativeEnum(DocumentElementType),
102
+ required: z.boolean().optional()
103
+ });
104
+ var headingElementSchema = baseElementSchema.extend({
105
+ type: z.literal("heading" /* HEADING */),
106
+ text: z.string().min(1).max(200),
107
+ level: z.nativeEnum(HeadingLevel)
108
+ });
109
+ var paragraphElementSchema = baseElementSchema.extend({
110
+ type: z.literal("paragraph" /* PARAGRAPH */),
111
+ text: z.string().min(1).max(5e3)
112
+ });
113
+ var listElementSchema = baseElementSchema.extend({
114
+ type: z.literal("list" /* LIST */),
115
+ items: z.array(z.string().min(1).max(500)).min(1).max(100),
116
+ listType: z.nativeEnum(ListType)
117
+ });
118
+ var dynamicTextElementSchema = baseElementSchema.extend({
119
+ type: z.literal("dynamic_text" /* DYNAMIC_TEXT */),
120
+ text: z.string().min(1).max(5e3)
121
+ });
122
+ var binaryChoiceElementSchema = baseElementSchema.extend({
123
+ type: z.literal("binary_choice" /* BINARY_CHOICE */),
124
+ question: z.string().min(1).max(500),
125
+ defaultValue: z.boolean().optional()
126
+ });
127
+ var multipleChoiceElementSchema = baseElementSchema.extend({
128
+ type: z.literal("multiple_choice" /* MULTIPLE_CHOICE */),
129
+ question: z.string().min(1).max(500),
130
+ options: z.array(z.string().min(1).max(200)).min(2).max(50),
131
+ defaultValues: z.array(z.string()).optional()
132
+ });
133
+ var singleChoiceElementSchema = baseElementSchema.extend({
134
+ type: z.literal("single_choice" /* SINGLE_CHOICE */),
135
+ question: z.string().min(1).max(500),
136
+ options: z.array(z.string().min(1).max(200)).min(2).max(50),
137
+ defaultValue: z.string().optional()
138
+ });
139
+ var ratingScaleElementSchema = baseElementSchema.extend({
140
+ type: z.literal("rating_scale" /* RATING_SCALE */),
141
+ question: z.string().min(1).max(500),
142
+ min: z.number().int().min(0).max(10),
143
+ max: z.number().int().min(1).max(10),
144
+ labels: z.record(z.string()).optional(),
145
+ defaultValue: z.number().int().optional()
146
+ });
147
+ var textInputElementSchema = baseElementSchema.extend({
148
+ type: z.literal("text_input" /* TEXT_INPUT */),
149
+ label: z.string().min(1).max(200),
150
+ placeholder: z.string().max(200).optional(),
151
+ multiline: z.boolean().optional(),
152
+ defaultValue: z.string().optional()
153
+ });
154
+ var datePickerElementSchema = baseElementSchema.extend({
155
+ type: z.literal("date_picker" /* DATE_PICKER */),
156
+ label: z.string().min(1).max(200),
157
+ defaultValue: z.string().optional()
158
+ // ISO date string
159
+ });
160
+ var signatureElementSchema = baseElementSchema.extend({
161
+ type: z.literal("signature" /* SIGNATURE */),
162
+ label: z.string().min(1).max(200)
163
+ });
164
+ var digitalSignatureElementSchema = baseElementSchema.extend({
165
+ type: z.literal("digital_signature" /* DITIGAL_SIGNATURE */),
166
+ // Matching your type enum
167
+ label: z.string().min(1).max(200)
168
+ });
169
+ var fileUploadElementSchema = baseElementSchema.extend({
170
+ type: z.literal("file_upload" /* FILE_UPLOAD */),
171
+ label: z.string().min(1).max(200),
172
+ allowedFileTypes: z.array(z.string()).optional(),
173
+ maxFileSizeMB: z.number().positive().optional()
174
+ });
175
+ var documentElementSchema = z.discriminatedUnion("type", [
176
+ headingElementSchema,
177
+ paragraphElementSchema,
178
+ listElementSchema,
179
+ dynamicTextElementSchema,
180
+ binaryChoiceElementSchema,
181
+ multipleChoiceElementSchema,
182
+ singleChoiceElementSchema,
183
+ ratingScaleElementSchema,
184
+ textInputElementSchema,
185
+ datePickerElementSchema,
186
+ signatureElementSchema,
187
+ digitalSignatureElementSchema,
188
+ fileUploadElementSchema
189
+ ]);
190
+ var documentElementWithoutIdSchema = z.discriminatedUnion("type", [
191
+ headingElementSchema.omit({ id: true }),
192
+ paragraphElementSchema.omit({ id: true }),
193
+ listElementSchema.omit({ id: true }),
194
+ dynamicTextElementSchema.omit({ id: true }),
195
+ binaryChoiceElementSchema.omit({ id: true }),
196
+ multipleChoiceElementSchema.omit({ id: true }),
197
+ singleChoiceElementSchema.omit({ id: true }),
198
+ ratingScaleElementSchema.omit({ id: true }),
199
+ textInputElementSchema.omit({ id: true }),
200
+ datePickerElementSchema.omit({ id: true }),
201
+ signatureElementSchema.omit({ id: true }),
202
+ digitalSignatureElementSchema.omit({ id: true }),
203
+ fileUploadElementSchema.omit({ id: true })
204
+ ]);
205
+ var createDocumentTemplateSchema = z.object({
206
+ title: z.string().min(1).max(200),
207
+ description: z.string().max(1e3).optional(),
208
+ elements: z.array(documentElementWithoutIdSchema).min(1).max(100),
209
+ tags: z.array(z.string().min(1).max(50)).max(20).optional(),
210
+ isUserForm: z.boolean().optional().default(false),
211
+ isRequired: z.boolean().optional().default(false),
212
+ sortingOrder: z.number().int().optional().default(0)
213
+ });
214
+ var updateDocumentTemplateSchema = z.object({
215
+ title: z.string().min(1).max(200).optional(),
216
+ description: z.string().max(1e3).optional(),
217
+ elements: z.array(documentElementWithoutIdSchema).min(1).max(100).optional(),
218
+ tags: z.array(z.string().min(1).max(50)).max(20).optional(),
219
+ isActive: z.boolean().optional(),
220
+ isUserForm: z.boolean().optional(),
221
+ isRequired: z.boolean().optional(),
222
+ sortingOrder: z.number().int().optional()
223
+ });
224
+ var documentTemplateSchema = z.object({
225
+ id: z.string(),
226
+ title: z.string().min(1).max(200),
227
+ description: z.string().max(1e3).optional(),
228
+ createdAt: z.number(),
229
+ updatedAt: z.number(),
230
+ createdBy: z.string(),
231
+ elements: z.array(documentElementSchema),
232
+ tags: z.array(z.string().min(1).max(50)).max(20).optional(),
233
+ version: z.number().int().positive(),
234
+ isActive: z.boolean(),
235
+ isUserForm: z.boolean().optional().default(false),
236
+ isRequired: z.boolean().optional().default(false),
237
+ sortingOrder: z.number().int().optional().default(0)
238
+ });
239
+ var filledDocumentStatusSchema = z.nativeEnum(FilledDocumentStatus);
240
+ var filledDocumentSchema = z.object({
241
+ id: z.string(),
242
+ templateId: z.string(),
243
+ templateVersion: z.number(),
244
+ isUserForm: z.boolean(),
245
+ procedureId: z.string(),
246
+ appointmentId: z.string(),
247
+ patientId: z.string(),
248
+ practitionerId: z.string(),
249
+ clinicId: z.string(),
250
+ createdAt: z.number(),
251
+ updatedAt: z.number(),
252
+ values: z.record(z.string(), z.any()),
253
+ status: filledDocumentStatusSchema
254
+ });
255
+ var createFilledDocumentDataSchema = z.object({
256
+ templateId: z.string(),
257
+ procedureId: z.string(),
258
+ appointmentId: z.string(),
259
+ patientId: z.string(),
260
+ practitionerId: z.string(),
261
+ clinicId: z.string(),
262
+ values: z.record(z.string(), z.any()).optional().default({}),
263
+ status: filledDocumentStatusSchema.optional().default("draft" /* DRAFT */)
264
+ });
265
+ var updateFilledDocumentDataSchema = z.object({
266
+ values: z.record(z.string(), z.any()).optional(),
267
+ status: filledDocumentStatusSchema.optional()
268
+ });
269
+
27
270
  // src/validations/appointment.schema.ts
28
- var createAppointmentSchema = z.object({
29
- calendarEventId: z.string().min(1, "Calendar event ID is required"),
30
- clinicBranchId: z.string().min(1, "Clinic branch ID is required"),
31
- practitionerId: z.string().min(1, "Practitioner ID is required"),
32
- patientId: z.string().min(1, "Patient ID is required"),
33
- procedureId: z.string().min(1, "Procedure ID is required"),
34
- appointmentStartTime: z.any().refine(
35
- (val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0,
36
- "Appointment start time must be a valid timestamp"
271
+ var MIN_STRING_LENGTH = 1;
272
+ var MAX_STRING_LENGTH = 1024;
273
+ var MAX_STRING_LENGTH_LONG = 4096;
274
+ var MAX_ARRAY_LENGTH = 100;
275
+ var appointmentStatusSchema = z2.nativeEnum(AppointmentStatus);
276
+ var paymentStatusSchema = z2.nativeEnum(PaymentStatus);
277
+ var mediaTypeSchema = z2.nativeEnum(MediaType);
278
+ var appointmentMediaItemSchema = z2.object({
279
+ id: z2.string().min(MIN_STRING_LENGTH, "Media item ID is required"),
280
+ type: mediaTypeSchema,
281
+ url: z2.string().url("Media URL must be a valid URL"),
282
+ fileName: z2.string().optional(),
283
+ uploadedAt: z2.any().refine(
284
+ (val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
285
+ "uploadedAt must be a valid timestamp or Date object"
286
+ ),
287
+ uploadedBy: z2.string().min(MIN_STRING_LENGTH, "Uploaded by user ID is required"),
288
+ description: z2.string().max(MAX_STRING_LENGTH, "Description too long").optional()
289
+ });
290
+ var procedureExtendedInfoSchema = z2.object({
291
+ id: z2.string().min(MIN_STRING_LENGTH),
292
+ name: z2.string().min(MIN_STRING_LENGTH),
293
+ description: z2.string(),
294
+ cost: z2.number().min(0),
295
+ duration: z2.number().min(0),
296
+ procedureFamily: z2.any(),
297
+ procedureCategoryId: z2.string(),
298
+ procedureCategoryName: z2.string(),
299
+ procedureSubCategoryId: z2.string(),
300
+ procedureSubCategoryName: z2.string(),
301
+ procedureTechnologyId: z2.string(),
302
+ procedureTechnologyName: z2.string(),
303
+ procedureProductBrandId: z2.string(),
304
+ procedureProductBrandName: z2.string(),
305
+ procedureProductId: z2.string(),
306
+ procedureProductName: z2.string()
307
+ });
308
+ var linkedFormInfoSchema = z2.object({
309
+ formId: z2.string().min(MIN_STRING_LENGTH, "Form ID is required"),
310
+ templateId: z2.string().min(MIN_STRING_LENGTH, "Template ID is required"),
311
+ templateVersion: z2.number().int().positive("Template version must be a positive integer"),
312
+ title: z2.string().min(MIN_STRING_LENGTH, "Form title is required"),
313
+ isUserForm: z2.boolean(),
314
+ status: filledDocumentStatusSchema,
315
+ path: z2.string().min(MIN_STRING_LENGTH, "Form path is required"),
316
+ submittedAt: z2.any().refine(
317
+ (val) => val === void 0 || val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
318
+ "submittedAt must be a valid timestamp or Date object"
319
+ ).optional(),
320
+ completedAt: z2.any().refine(
321
+ (val) => val === void 0 || val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
322
+ "completedAt must be a valid timestamp or Date object"
323
+ ).optional()
324
+ });
325
+ var patientReviewInfoSchema = z2.object({
326
+ reviewId: z2.string().min(MIN_STRING_LENGTH, "Review ID is required"),
327
+ rating: z2.number().min(1).max(5, "Rating must be between 1 and 5"),
328
+ comment: z2.string().max(MAX_STRING_LENGTH_LONG, "Comment too long").optional(),
329
+ reviewedAt: z2.any().refine(
330
+ (val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
331
+ "reviewedAt must be a valid timestamp or Date object"
332
+ )
333
+ });
334
+ var finalizedDetailsSchema = z2.object({
335
+ by: z2.string().min(MIN_STRING_LENGTH, "Finalized by user ID is required"),
336
+ at: z2.any().refine(
337
+ (val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
338
+ "Finalized at must be a valid timestamp or Date object"
339
+ ),
340
+ notes: z2.string().max(MAX_STRING_LENGTH_LONG, "Finalization notes too long").optional()
341
+ });
342
+ var createAppointmentSchema = z2.object({
343
+ calendarEventId: z2.string().min(MIN_STRING_LENGTH, "Calendar event ID is required"),
344
+ clinicBranchId: z2.string().min(MIN_STRING_LENGTH, "Clinic branch ID is required"),
345
+ practitionerId: z2.string().min(MIN_STRING_LENGTH, "Practitioner ID is required"),
346
+ patientId: z2.string().min(MIN_STRING_LENGTH, "Patient ID is required"),
347
+ procedureId: z2.string().min(MIN_STRING_LENGTH, "Procedure ID is required"),
348
+ appointmentStartTime: z2.any().refine(
349
+ (val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
350
+ "Appointment start time must be a valid timestamp or Date object"
37
351
  ),
38
- appointmentEndTime: z.any().refine(
39
- (val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0,
40
- "Appointment end time must be a valid timestamp"
352
+ appointmentEndTime: z2.any().refine(
353
+ (val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
354
+ "Appointment end time must be a valid timestamp or Date object"
41
355
  ),
42
- cost: z.number().min(0, "Cost must be a non-negative number"),
43
- currency: z.string().min(1, "Currency is required"),
44
- patientNotes: z.string().nullable().optional(),
45
- initialStatus: z.nativeEnum(AppointmentStatus, {
46
- errorMap: () => ({ message: "Invalid appointment status" })
47
- }),
48
- initialPaymentStatus: z.nativeEnum(PaymentStatus, {
49
- errorMap: () => ({ message: "Invalid payment status" })
50
- }).optional().default("unpaid" /* UNPAID */)
356
+ cost: z2.number().min(0, "Cost must be a non-negative number"),
357
+ currency: z2.string().min(1, "Currency is required"),
358
+ patientNotes: z2.string().max(MAX_STRING_LENGTH, "Patient notes too long").nullable().optional(),
359
+ initialStatus: appointmentStatusSchema,
360
+ initialPaymentStatus: paymentStatusSchema.optional().default("unpaid" /* UNPAID */)
361
+ }).refine((data) => data.appointmentEndTime > data.appointmentStartTime, {
362
+ message: "Appointment end time must be after start time",
363
+ path: ["appointmentEndTime"]
51
364
  });
52
- var updateAppointmentSchema = z.object({
53
- status: z.nativeEnum(AppointmentStatus, {
54
- errorMap: () => ({ message: "Invalid appointment status" })
55
- }).optional(),
56
- confirmationTime: z.any().refine(
57
- (val) => val === null || val === void 0 || val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0,
58
- "Confirmation time must be a valid timestamp or null"
365
+ var updateAppointmentSchema = z2.object({
366
+ status: appointmentStatusSchema.optional(),
367
+ confirmationTime: z2.any().optional().nullable(),
368
+ cancellationTime: z2.any().optional().nullable(),
369
+ rescheduleTime: z2.any().optional().nullable(),
370
+ procedureActualStartTime: z2.any().optional().nullable(),
371
+ actualDurationMinutes: z2.number().int().positive("Duration must be a positive integer").optional(),
372
+ cancellationReason: z2.string().max(MAX_STRING_LENGTH, "Cancellation reason too long").nullable().optional(),
373
+ canceledBy: z2.enum(["patient", "clinic", "practitioner", "system"]).optional(),
374
+ internalNotes: z2.string().max(MAX_STRING_LENGTH_LONG, "Internal notes too long").nullable().optional(),
375
+ patientNotes: z2.any().optional().nullable(),
376
+ paymentStatus: paymentStatusSchema.optional(),
377
+ paymentTransactionId: z2.any().optional().nullable(),
378
+ completedPreRequirements: z2.union([z2.array(z2.string()), z2.any()]).optional(),
379
+ completedPostRequirements: z2.union([z2.array(z2.string()), z2.any()]).optional(),
380
+ pendingUserFormsIds: z2.union([z2.array(z2.string()), z2.any()]).optional(),
381
+ appointmentStartTime: z2.any().refine(
382
+ (val) => val === void 0 || val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
383
+ "Appointment start time must be a valid timestamp or Date object"
59
384
  ).optional(),
60
- actualDurationMinutes: z.number().positive("Duration must be positive").optional(),
61
- cancellationReason: z.string().nullable().optional(),
62
- canceledBy: z.enum(["patient", "clinic", "practitioner", "system"]).optional(),
63
- internalNotes: z.string().nullable().optional(),
64
- paymentStatus: z.nativeEnum(PaymentStatus, {
65
- errorMap: () => ({ message: "Invalid payment status" })
66
- }).optional(),
67
- paymentTransactionId: z.string().nullable().optional(),
68
- completedPreRequirements: z.array(z.string()).optional(),
69
- completedPostRequirements: z.array(z.string()).optional()
385
+ appointmentEndTime: z2.any().refine(
386
+ (val) => val === void 0 || val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
387
+ "Appointment end time must be a valid timestamp or Date object"
388
+ ).optional(),
389
+ calendarEventId: z2.string().min(MIN_STRING_LENGTH).optional(),
390
+ cost: z2.number().min(0).optional(),
391
+ clinicBranchId: z2.string().min(MIN_STRING_LENGTH).optional(),
392
+ practitionerId: z2.string().min(MIN_STRING_LENGTH).optional(),
393
+ linkedForms: z2.union([z2.array(linkedFormInfoSchema).max(MAX_ARRAY_LENGTH), z2.any()]).optional(),
394
+ media: z2.union([
395
+ z2.array(appointmentMediaItemSchema).max(MAX_ARRAY_LENGTH),
396
+ z2.any()
397
+ ]).optional(),
398
+ reviewInfo: z2.union([patientReviewInfoSchema.nullable(), z2.any()]).optional(),
399
+ finalizedDetails: z2.union([finalizedDetailsSchema.nullable(), z2.any()]).optional(),
400
+ isArchived: z2.boolean().optional(),
401
+ updatedAt: z2.any().optional()
70
402
  }).refine(
71
403
  (data) => {
72
- if (data.status === "canceled_clinic" /* CANCELED_CLINIC */ || data.status === "canceled_patient" /* CANCELED_PATIENT */) {
404
+ if (data.status === "canceled_clinic" /* CANCELED_CLINIC */ || data.status === "canceled_patient" /* CANCELED_PATIENT */ || data.status === "canceled_patient_rescheduled" /* CANCELED_PATIENT_RESCHEDULED */) {
73
405
  return !!data.cancellationReason && !!data.canceledBy;
74
406
  }
75
407
  return true;
76
408
  },
77
409
  {
78
- message: "Cancellation reason and canceled by must be provided when canceling an appointment",
410
+ message: "Cancellation reason and canceled by must be provided when canceling an appointment with patient or clinic origin.",
79
411
  path: ["status"]
80
412
  }
413
+ ).refine(
414
+ (data) => {
415
+ if (data.appointmentStartTime && data.appointmentEndTime) {
416
+ return data.appointmentEndTime > data.appointmentStartTime;
417
+ }
418
+ return true;
419
+ },
420
+ {
421
+ message: "Appointment end time must be after start time if both are provided",
422
+ path: ["appointmentEndTime"]
423
+ }
81
424
  );
82
- var searchAppointmentsSchema = z.object({
83
- patientId: z.string().optional(),
84
- practitionerId: z.string().optional(),
85
- clinicBranchId: z.string().optional(),
86
- startDate: z.date().optional(),
87
- endDate: z.date().optional(),
88
- status: z.union([
89
- z.nativeEnum(AppointmentStatus),
90
- z.array(z.nativeEnum(AppointmentStatus))
425
+ var searchAppointmentsSchema = z2.object({
426
+ patientId: z2.string().optional(),
427
+ practitionerId: z2.string().optional(),
428
+ clinicBranchId: z2.string().optional(),
429
+ startDate: z2.any().refine(
430
+ (val) => val === void 0 || val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
431
+ "Start date must be a valid timestamp or Date object"
432
+ ).optional(),
433
+ endDate: z2.any().refine(
434
+ (val) => val === void 0 || val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
435
+ "End date must be a valid timestamp or Date object"
436
+ ).optional(),
437
+ status: z2.union([
438
+ appointmentStatusSchema,
439
+ z2.array(appointmentStatusSchema).nonempty()
91
440
  ]).optional(),
92
- limit: z.number().positive().optional(),
93
- startAfter: z.any().optional()
441
+ limit: z2.number().positive().int().optional().default(20),
442
+ startAfter: z2.any().optional()
94
443
  }).refine(
95
444
  (data) => {
96
- return !!(data.patientId || data.practitionerId || data.clinicBranchId);
445
+ if (!data.startDate && !data.endDate && !data.status) {
446
+ return !!(data.patientId || data.practitionerId || data.clinicBranchId);
447
+ }
448
+ return true;
449
+ },
450
+ {
451
+ message: "At least one of patientId, practitionerId, or clinicBranchId must be provided if no date or status filters are set.",
452
+ path: ["patientId"]
453
+ }
454
+ ).refine(
455
+ (data) => {
456
+ if (data.startDate && data.endDate) {
457
+ return data.endDate >= data.startDate;
458
+ }
459
+ return true;
97
460
  },
98
461
  {
99
- message: "At least one of patientId, practitionerId, or clinicBranchId must be provided",
100
- path: ["searchCriteria"]
462
+ message: "End date must be after or the same as start date",
463
+ path: ["endDate"]
101
464
  }
102
465
  );
103
466
 
@@ -165,54 +528,6 @@ import {
165
528
  getDocs as getDocs13
166
529
  } from "firebase/firestore";
167
530
 
168
- // src/types/documentation-templates/index.ts
169
- var DOCUMENTATION_TEMPLATES_COLLECTION = "documentation-templates";
170
- var FILLED_DOCUMENTS_COLLECTION = "filled-documents";
171
- var DocumentElementType = /* @__PURE__ */ ((DocumentElementType2) => {
172
- DocumentElementType2["HEADING"] = "heading";
173
- DocumentElementType2["PARAGRAPH"] = "paragraph";
174
- DocumentElementType2["LIST"] = "list";
175
- DocumentElementType2["DYNAMIC_TEXT"] = "dynamic_text";
176
- DocumentElementType2["BINARY_CHOICE"] = "binary_choice";
177
- DocumentElementType2["MULTIPLE_CHOICE"] = "multiple_choice";
178
- DocumentElementType2["SINGLE_CHOICE"] = "single_choice";
179
- DocumentElementType2["RATING_SCALE"] = "rating_scale";
180
- DocumentElementType2["TEXT_INPUT"] = "text_input";
181
- DocumentElementType2["DATE_PICKER"] = "date_picker";
182
- DocumentElementType2["SIGNATURE"] = "signature";
183
- DocumentElementType2["FILE_UPLOAD"] = "file_upload";
184
- return DocumentElementType2;
185
- })(DocumentElementType || {});
186
- var ListType = /* @__PURE__ */ ((ListType2) => {
187
- ListType2["ORDERED"] = "ordered";
188
- ListType2["UNORDERED"] = "unordered";
189
- return ListType2;
190
- })(ListType || {});
191
- var HeadingLevel = /* @__PURE__ */ ((HeadingLevel2) => {
192
- HeadingLevel2["H1"] = "h1";
193
- HeadingLevel2["H2"] = "h2";
194
- HeadingLevel2["H3"] = "h3";
195
- HeadingLevel2["H4"] = "h4";
196
- HeadingLevel2["H5"] = "h5";
197
- HeadingLevel2["H6"] = "h6";
198
- return HeadingLevel2;
199
- })(HeadingLevel || {});
200
- var DynamicVariable = /* @__PURE__ */ ((DynamicVariable2) => {
201
- DynamicVariable2["PATIENT_NAME"] = "[PATIENT_NAME]";
202
- DynamicVariable2["DOCTOR_NAME"] = "[DOCTOR_NAME]";
203
- DynamicVariable2["CLINIC_NAME"] = "[CLINIC_NAME]";
204
- DynamicVariable2["PATIENT_BIRTHDAY"] = "[PATIENT_BIRTHDAY]";
205
- DynamicVariable2["APPOINTMENT_DATE"] = "[APPOINTMENT_DATE]";
206
- DynamicVariable2["CURRENT_DATE"] = "[CURRENT_DATE]";
207
- return DynamicVariable2;
208
- })(DynamicVariable || {});
209
- var FilledDocumentStatus = /* @__PURE__ */ ((FilledDocumentStatus2) => {
210
- FilledDocumentStatus2["DRAFT"] = "draft";
211
- FilledDocumentStatus2["COMPLETED"] = "completed";
212
- FilledDocumentStatus2["SIGNED"] = "signed";
213
- return FilledDocumentStatus2;
214
- })(FilledDocumentStatus || {});
215
-
216
531
  // src/types/calendar/index.ts
217
532
  var CalendarEventStatus = /* @__PURE__ */ ((CalendarEventStatus4) => {
218
533
  CalendarEventStatus4["PENDING"] = "pending";
@@ -259,136 +574,6 @@ import { z as z19 } from "zod";
259
574
 
260
575
  // src/validations/schemas.ts
261
576
  import { z as z3 } from "zod";
262
-
263
- // src/validations/documentation-templates/template.schema.ts
264
- import { z as z2 } from "zod";
265
- var baseElementSchema = z2.object({
266
- id: z2.string().optional(),
267
- // Make id optional so we can omit it later
268
- type: z2.nativeEnum(DocumentElementType),
269
- required: z2.boolean().optional()
270
- });
271
- var headingElementSchema = baseElementSchema.extend({
272
- type: z2.literal("heading" /* HEADING */),
273
- text: z2.string().min(1).max(200),
274
- level: z2.nativeEnum(HeadingLevel)
275
- });
276
- var paragraphElementSchema = baseElementSchema.extend({
277
- type: z2.literal("paragraph" /* PARAGRAPH */),
278
- text: z2.string().min(1).max(5e3)
279
- });
280
- var listElementSchema = baseElementSchema.extend({
281
- type: z2.literal("list" /* LIST */),
282
- items: z2.array(z2.string().min(1).max(500)).min(1).max(100),
283
- listType: z2.nativeEnum(ListType)
284
- });
285
- var dynamicTextElementSchema = baseElementSchema.extend({
286
- type: z2.literal("dynamic_text" /* DYNAMIC_TEXT */),
287
- text: z2.string().min(1).max(5e3)
288
- });
289
- var binaryChoiceElementSchema = baseElementSchema.extend({
290
- type: z2.literal("binary_choice" /* BINARY_CHOICE */),
291
- question: z2.string().min(1).max(500),
292
- defaultValue: z2.boolean().optional()
293
- });
294
- var multipleChoiceElementSchema = baseElementSchema.extend({
295
- type: z2.literal("multiple_choice" /* MULTIPLE_CHOICE */),
296
- question: z2.string().min(1).max(500),
297
- options: z2.array(z2.string().min(1).max(200)).min(2).max(50),
298
- defaultValues: z2.array(z2.string()).optional()
299
- });
300
- var singleChoiceElementSchema = baseElementSchema.extend({
301
- type: z2.literal("single_choice" /* SINGLE_CHOICE */),
302
- question: z2.string().min(1).max(500),
303
- options: z2.array(z2.string().min(1).max(200)).min(2).max(50),
304
- defaultValue: z2.string().optional()
305
- });
306
- var ratingScaleElementSchema = baseElementSchema.extend({
307
- type: z2.literal("rating_scale" /* RATING_SCALE */),
308
- question: z2.string().min(1).max(500),
309
- min: z2.number().int().min(0).max(10),
310
- max: z2.number().int().min(1).max(10),
311
- labels: z2.record(z2.string()).optional(),
312
- defaultValue: z2.number().int().optional()
313
- });
314
- var textInputElementSchema = baseElementSchema.extend({
315
- type: z2.literal("text_input" /* TEXT_INPUT */),
316
- label: z2.string().min(1).max(200),
317
- placeholder: z2.string().max(200).optional(),
318
- multiline: z2.boolean().optional(),
319
- defaultValue: z2.string().optional()
320
- });
321
- var datePickerElementSchema = baseElementSchema.extend({
322
- type: z2.literal("date_picker" /* DATE_PICKER */),
323
- label: z2.string().min(1).max(200),
324
- defaultValue: z2.string().optional()
325
- // ISO date string
326
- });
327
- var signatureElementSchema = baseElementSchema.extend({
328
- type: z2.literal("signature" /* SIGNATURE */),
329
- label: z2.string().min(1).max(200)
330
- });
331
- var fileUploadElementSchema = baseElementSchema.extend({
332
- type: z2.literal("file_upload" /* FILE_UPLOAD */),
333
- label: z2.string().min(1).max(200),
334
- allowedFileTypes: z2.array(z2.string()).optional(),
335
- maxFileSizeMB: z2.number().positive().optional()
336
- });
337
- var documentElementSchema = z2.discriminatedUnion("type", [
338
- headingElementSchema,
339
- paragraphElementSchema,
340
- listElementSchema,
341
- dynamicTextElementSchema,
342
- binaryChoiceElementSchema,
343
- multipleChoiceElementSchema,
344
- singleChoiceElementSchema,
345
- ratingScaleElementSchema,
346
- textInputElementSchema,
347
- datePickerElementSchema,
348
- signatureElementSchema,
349
- fileUploadElementSchema
350
- ]);
351
- var documentElementWithoutIdSchema = z2.discriminatedUnion("type", [
352
- headingElementSchema.omit({ id: true }),
353
- paragraphElementSchema.omit({ id: true }),
354
- listElementSchema.omit({ id: true }),
355
- dynamicTextElementSchema.omit({ id: true }),
356
- binaryChoiceElementSchema.omit({ id: true }),
357
- multipleChoiceElementSchema.omit({ id: true }),
358
- singleChoiceElementSchema.omit({ id: true }),
359
- ratingScaleElementSchema.omit({ id: true }),
360
- textInputElementSchema.omit({ id: true }),
361
- datePickerElementSchema.omit({ id: true }),
362
- signatureElementSchema.omit({ id: true }),
363
- fileUploadElementSchema.omit({ id: true })
364
- ]);
365
- var createDocumentTemplateSchema = z2.object({
366
- title: z2.string().min(1).max(200),
367
- description: z2.string().max(1e3).optional(),
368
- elements: z2.array(documentElementWithoutIdSchema).min(1).max(100),
369
- tags: z2.array(z2.string().min(1).max(50)).max(20).optional()
370
- });
371
- var updateDocumentTemplateSchema = z2.object({
372
- title: z2.string().min(1).max(200).optional(),
373
- description: z2.string().max(1e3).optional(),
374
- elements: z2.array(documentElementWithoutIdSchema).min(1).max(100).optional(),
375
- tags: z2.array(z2.string().min(1).max(50)).max(20).optional(),
376
- isActive: z2.boolean().optional()
377
- });
378
- var documentTemplateSchema = z2.object({
379
- id: z2.string(),
380
- title: z2.string().min(1).max(200),
381
- description: z2.string().max(1e3).optional(),
382
- createdAt: z2.number(),
383
- updatedAt: z2.number(),
384
- createdBy: z2.string(),
385
- elements: z2.array(documentElementSchema),
386
- tags: z2.array(z2.string().min(1).max(50)).max(20).optional(),
387
- version: z2.number().int().positive(),
388
- isActive: z2.boolean()
389
- });
390
-
391
- // src/validations/schemas.ts
392
577
  var emailSchema = z3.string().email("Invalid email format").min(5, "Email must be at least 5 characters").max(255, "Email must be less than 255 characters");
393
578
  var passwordSchema = z3.string().min(8, "Password must be at least 8 characters").max(100, "Password must be less than 100 characters").regex(
394
579
  /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d\w\W]{8,}$/,
@@ -1452,9 +1637,9 @@ var addAllergyUtil = async (db, patientId, data, userRef) => {
1452
1637
  var updateAllergyUtil = async (db, patientId, data, userRef) => {
1453
1638
  const validatedData = updateAllergySchema.parse(data);
1454
1639
  const { allergyIndex, ...updateData } = validatedData;
1455
- const doc32 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1456
- if (!doc32.exists()) throw new Error("Medical info not found");
1457
- const medicalInfo = doc32.data();
1640
+ const doc33 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1641
+ if (!doc33.exists()) throw new Error("Medical info not found");
1642
+ const medicalInfo = doc33.data();
1458
1643
  if (allergyIndex >= medicalInfo.allergies.length) {
1459
1644
  throw new Error("Invalid allergy index");
1460
1645
  }
@@ -1470,9 +1655,9 @@ var updateAllergyUtil = async (db, patientId, data, userRef) => {
1470
1655
  });
1471
1656
  };
1472
1657
  var removeAllergyUtil = async (db, patientId, allergyIndex, userRef) => {
1473
- const doc32 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1474
- if (!doc32.exists()) throw new Error("Medical info not found");
1475
- const medicalInfo = doc32.data();
1658
+ const doc33 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1659
+ if (!doc33.exists()) throw new Error("Medical info not found");
1660
+ const medicalInfo = doc33.data();
1476
1661
  if (allergyIndex >= medicalInfo.allergies.length) {
1477
1662
  throw new Error("Invalid allergy index");
1478
1663
  }
@@ -1497,9 +1682,9 @@ var addBlockingConditionUtil = async (db, patientId, data, userRef) => {
1497
1682
  var updateBlockingConditionUtil = async (db, patientId, data, userRef) => {
1498
1683
  const validatedData = updateBlockingConditionSchema.parse(data);
1499
1684
  const { conditionIndex, ...updateData } = validatedData;
1500
- const doc32 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1501
- if (!doc32.exists()) throw new Error("Medical info not found");
1502
- const medicalInfo = doc32.data();
1685
+ const doc33 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1686
+ if (!doc33.exists()) throw new Error("Medical info not found");
1687
+ const medicalInfo = doc33.data();
1503
1688
  if (conditionIndex >= medicalInfo.blockingConditions.length) {
1504
1689
  throw new Error("Invalid blocking condition index");
1505
1690
  }
@@ -1515,9 +1700,9 @@ var updateBlockingConditionUtil = async (db, patientId, data, userRef) => {
1515
1700
  });
1516
1701
  };
1517
1702
  var removeBlockingConditionUtil = async (db, patientId, conditionIndex, userRef) => {
1518
- const doc32 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1519
- if (!doc32.exists()) throw new Error("Medical info not found");
1520
- const medicalInfo = doc32.data();
1703
+ const doc33 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1704
+ if (!doc33.exists()) throw new Error("Medical info not found");
1705
+ const medicalInfo = doc33.data();
1521
1706
  if (conditionIndex >= medicalInfo.blockingConditions.length) {
1522
1707
  throw new Error("Invalid blocking condition index");
1523
1708
  }
@@ -1542,9 +1727,9 @@ var addContraindicationUtil = async (db, patientId, data, userRef) => {
1542
1727
  var updateContraindicationUtil = async (db, patientId, data, userRef) => {
1543
1728
  const validatedData = updateContraindicationSchema.parse(data);
1544
1729
  const { contraindicationIndex, ...updateData } = validatedData;
1545
- const doc32 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1546
- if (!doc32.exists()) throw new Error("Medical info not found");
1547
- const medicalInfo = doc32.data();
1730
+ const doc33 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1731
+ if (!doc33.exists()) throw new Error("Medical info not found");
1732
+ const medicalInfo = doc33.data();
1548
1733
  if (contraindicationIndex >= medicalInfo.contraindications.length) {
1549
1734
  throw new Error("Invalid contraindication index");
1550
1735
  }
@@ -1560,9 +1745,9 @@ var updateContraindicationUtil = async (db, patientId, data, userRef) => {
1560
1745
  });
1561
1746
  };
1562
1747
  var removeContraindicationUtil = async (db, patientId, contraindicationIndex, userRef) => {
1563
- const doc32 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1564
- if (!doc32.exists()) throw new Error("Medical info not found");
1565
- const medicalInfo = doc32.data();
1748
+ const doc33 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1749
+ if (!doc33.exists()) throw new Error("Medical info not found");
1750
+ const medicalInfo = doc33.data();
1566
1751
  if (contraindicationIndex >= medicalInfo.contraindications.length) {
1567
1752
  throw new Error("Invalid contraindication index");
1568
1753
  }
@@ -1587,9 +1772,9 @@ var addMedicationUtil = async (db, patientId, data, userRef) => {
1587
1772
  var updateMedicationUtil = async (db, patientId, data, userRef) => {
1588
1773
  const validatedData = updateMedicationSchema.parse(data);
1589
1774
  const { medicationIndex, ...updateData } = validatedData;
1590
- const doc32 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1591
- if (!doc32.exists()) throw new Error("Medical info not found");
1592
- const medicalInfo = doc32.data();
1775
+ const doc33 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1776
+ if (!doc33.exists()) throw new Error("Medical info not found");
1777
+ const medicalInfo = doc33.data();
1593
1778
  if (medicationIndex >= medicalInfo.currentMedications.length) {
1594
1779
  throw new Error("Invalid medication index");
1595
1780
  }
@@ -1605,9 +1790,9 @@ var updateMedicationUtil = async (db, patientId, data, userRef) => {
1605
1790
  });
1606
1791
  };
1607
1792
  var removeMedicationUtil = async (db, patientId, medicationIndex, userRef) => {
1608
- const doc32 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1609
- if (!doc32.exists()) throw new Error("Medical info not found");
1610
- const medicalInfo = doc32.data();
1793
+ const doc33 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1794
+ if (!doc33.exists()) throw new Error("Medical info not found");
1795
+ const medicalInfo = doc33.data();
1611
1796
  if (medicationIndex >= medicalInfo.currentMedications.length) {
1612
1797
  throw new Error("Invalid medication index");
1613
1798
  }
@@ -1885,7 +2070,7 @@ var searchPatientsUtil = async (db, params, requester) => {
1885
2070
  try {
1886
2071
  const finalQuery = query2(patientsCollectionRef, ...constraints);
1887
2072
  const querySnapshot = await getDocs2(finalQuery);
1888
- const patients = querySnapshot.docs.map((doc32) => doc32.data());
2073
+ const patients = querySnapshot.docs.map((doc33) => doc33.data());
1889
2074
  console.log(`[searchPatientsUtil] Found ${patients.length} patients matching criteria.`);
1890
2075
  return patients;
1891
2076
  } catch (error) {
@@ -1909,8 +2094,8 @@ var getAllPatientsUtil = async (db, options) => {
1909
2094
  }
1910
2095
  const patientsSnapshot = await getDocs2(q);
1911
2096
  const patients = [];
1912
- patientsSnapshot.forEach((doc32) => {
1913
- patients.push(doc32.data());
2097
+ patientsSnapshot.forEach((doc33) => {
2098
+ patients.push(doc33.data());
1914
2099
  });
1915
2100
  console.log(`[getAllPatientsUtil] Found ${patients.length} patients`);
1916
2101
  return patients;
@@ -2143,8 +2328,8 @@ var getPatientsByPractitionerUtil = async (db, practitionerId, options) => {
2143
2328
  }
2144
2329
  const patientsSnapshot = await getDocs3(q);
2145
2330
  const patients = [];
2146
- patientsSnapshot.forEach((doc32) => {
2147
- patients.push(doc32.data());
2331
+ patientsSnapshot.forEach((doc33) => {
2332
+ patients.push(doc33.data());
2148
2333
  });
2149
2334
  console.log(
2150
2335
  `[getPatientsByPractitionerUtil] Found ${patients.length} patients for practitioner ID: ${practitionerId}`
@@ -2241,8 +2426,8 @@ var getPatientsByClinicUtil = async (db, clinicId, options) => {
2241
2426
  }
2242
2427
  const patientsSnapshot = await getDocs4(q);
2243
2428
  const patients = [];
2244
- patientsSnapshot.forEach((doc32) => {
2245
- patients.push(doc32.data());
2429
+ patientsSnapshot.forEach((doc33) => {
2430
+ patients.push(doc33.data());
2246
2431
  });
2247
2432
  console.log(
2248
2433
  `[getPatientsByClinicUtil] Found ${patients.length} patients for clinic ID: ${clinicId}`
@@ -3367,7 +3552,7 @@ async function getClinicAdminsByGroup(db, clinicGroupId) {
3367
3552
  where5("clinicGroupId", "==", clinicGroupId)
3368
3553
  );
3369
3554
  const querySnapshot = await getDocs5(q);
3370
- return querySnapshot.docs.map((doc32) => doc32.data());
3555
+ return querySnapshot.docs.map((doc33) => doc33.data());
3371
3556
  }
3372
3557
  async function updateClinicAdmin(db, adminId, data) {
3373
3558
  const admin = await getClinicAdmin(db, adminId);
@@ -3628,6 +3813,8 @@ var ClinicAdminService = class extends BaseService {
3628
3813
  this.getClinicService()
3629
3814
  );
3630
3815
  }
3816
+ // TODO: Add more methods for clinic admins for managing permissions, editing profiles by the admin, or by the clinic group owner and so on
3817
+ // Generally refactor admin permissions and clinic group permissions and systems for admin management
3631
3818
  };
3632
3819
 
3633
3820
  // src/services/practitioner/practitioner.service.ts
@@ -4081,7 +4268,7 @@ var PractitionerService = class extends BaseService {
4081
4268
  where6("expiresAt", ">", Timestamp8.now())
4082
4269
  );
4083
4270
  const querySnapshot = await getDocs6(q);
4084
- return querySnapshot.docs.map((doc32) => doc32.data());
4271
+ return querySnapshot.docs.map((doc33) => doc33.data());
4085
4272
  }
4086
4273
  /**
4087
4274
  * Gets a token by its string value and validates it
@@ -4164,7 +4351,7 @@ var PractitionerService = class extends BaseService {
4164
4351
  where6("status", "==", "active" /* ACTIVE */)
4165
4352
  );
4166
4353
  const querySnapshot = await getDocs6(q);
4167
- return querySnapshot.docs.map((doc32) => doc32.data());
4354
+ return querySnapshot.docs.map((doc33) => doc33.data());
4168
4355
  }
4169
4356
  /**
4170
4357
  * Dohvata sve zdravstvene radnike za određenu kliniku
@@ -4176,7 +4363,7 @@ var PractitionerService = class extends BaseService {
4176
4363
  where6("isActive", "==", true)
4177
4364
  );
4178
4365
  const querySnapshot = await getDocs6(q);
4179
- return querySnapshot.docs.map((doc32) => doc32.data());
4366
+ return querySnapshot.docs.map((doc33) => doc33.data());
4180
4367
  }
4181
4368
  /**
4182
4369
  * Dohvata sve draft zdravstvene radnike za određenu kliniku sa statusom DRAFT
@@ -4188,7 +4375,7 @@ var PractitionerService = class extends BaseService {
4188
4375
  where6("status", "==", "draft" /* DRAFT */)
4189
4376
  );
4190
4377
  const querySnapshot = await getDocs6(q);
4191
- return querySnapshot.docs.map((doc32) => doc32.data());
4378
+ return querySnapshot.docs.map((doc33) => doc33.data());
4192
4379
  }
4193
4380
  /**
4194
4381
  * Updates a practitioner
@@ -4370,7 +4557,7 @@ var PractitionerService = class extends BaseService {
4370
4557
  );
4371
4558
  const querySnapshot = await getDocs6(q);
4372
4559
  const practitioners = querySnapshot.docs.map(
4373
- (doc32) => doc32.data()
4560
+ (doc33) => doc33.data()
4374
4561
  );
4375
4562
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
4376
4563
  return {
@@ -4441,8 +4628,8 @@ var PractitionerService = class extends BaseService {
4441
4628
  console.log(
4442
4629
  `[PRACTITIONER_SERVICE] Found ${querySnapshot.docs.length} practitioners with base query`
4443
4630
  );
4444
- let practitioners = querySnapshot.docs.map((doc32) => {
4445
- return { ...doc32.data(), id: doc32.id };
4631
+ let practitioners = querySnapshot.docs.map((doc33) => {
4632
+ return { ...doc33.data(), id: doc33.id };
4446
4633
  });
4447
4634
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
4448
4635
  if (filters.nameSearch && filters.nameSearch.trim() !== "") {
@@ -4696,7 +4883,7 @@ var UserService = class extends BaseService {
4696
4883
  ];
4697
4884
  const q = query7(collection7(this.db, USERS_COLLECTION), ...constraints);
4698
4885
  const querySnapshot = await getDocs7(q);
4699
- const users = querySnapshot.docs.map((doc32) => doc32.data());
4886
+ const users = querySnapshot.docs.map((doc33) => doc33.data());
4700
4887
  return Promise.all(users.map((userData) => userSchema.parse(userData)));
4701
4888
  }
4702
4889
  /**
@@ -5076,7 +5263,7 @@ async function getAllActiveGroups(db) {
5076
5263
  where8("isActive", "==", true)
5077
5264
  );
5078
5265
  const querySnapshot = await getDocs8(q);
5079
- return querySnapshot.docs.map((doc32) => doc32.data());
5266
+ return querySnapshot.docs.map((doc33) => doc33.data());
5080
5267
  }
5081
5268
  async function updateClinicGroup(db, groupId, data, app) {
5082
5269
  console.log("[CLINIC_GROUP] Updating clinic group", { groupId });
@@ -5448,6 +5635,11 @@ var ClinicGroupService = class extends BaseService {
5448
5635
  this.app
5449
5636
  );
5450
5637
  }
5638
+ // TODO: Add a method to get all admin tokens for a clinic group (not just active ones)
5639
+ // TODO: Refactor admin token methods not to add tokens to the clinicGroup document,
5640
+ // but to add them to a subcollection called adminTokens that belongs to a specific clinicGroup document
5641
+ // TODO: Add granular control over admin permissions, e.g. only allow admins to manage certain clinics to tokens directly
5642
+ // TODO: Generally refactor admin tokens and invites, also create cloud function to send invites and send updates when sombody uses the token
5451
5643
  };
5452
5644
 
5453
5645
  // src/services/clinic/clinic.service.ts
@@ -5500,7 +5692,7 @@ async function getClinicsByGroup(db, groupId) {
5500
5692
  where9("isActive", "==", true)
5501
5693
  );
5502
5694
  const querySnapshot = await getDocs9(q);
5503
- return querySnapshot.docs.map((doc32) => doc32.data());
5695
+ return querySnapshot.docs.map((doc33) => doc33.data());
5504
5696
  }
5505
5697
  async function updateClinic(db, clinicId, data, adminId, clinicAdminService, app) {
5506
5698
  console.log("[CLINIC] Starting clinic update", { clinicId, adminId });
@@ -5694,7 +5886,7 @@ async function getClinicsByAdmin(db, adminId, options = {}, clinicAdminService,
5694
5886
  }
5695
5887
  const q = query9(collection9(db, CLINICS_COLLECTION), ...constraints);
5696
5888
  const querySnapshot = await getDocs9(q);
5697
- return querySnapshot.docs.map((doc32) => doc32.data());
5889
+ return querySnapshot.docs.map((doc33) => doc33.data());
5698
5890
  }
5699
5891
  async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGroupService) {
5700
5892
  return getClinicsByAdmin(
@@ -5739,11 +5931,11 @@ async function getAllClinics(db, pagination, lastDoc) {
5739
5931
  }
5740
5932
  const clinicsSnapshot = await getDocs9(clinicsQuery);
5741
5933
  const lastVisible = clinicsSnapshot.docs[clinicsSnapshot.docs.length - 1];
5742
- const clinics = clinicsSnapshot.docs.map((doc32) => {
5743
- const data = doc32.data();
5934
+ const clinics = clinicsSnapshot.docs.map((doc33) => {
5935
+ const data = doc33.data();
5744
5936
  return {
5745
5937
  ...data,
5746
- id: doc32.id
5938
+ id: doc33.id
5747
5939
  };
5748
5940
  });
5749
5941
  return {
@@ -5770,8 +5962,8 @@ async function getAllClinicsInRange(db, center, rangeInKm, pagination, lastDoc)
5770
5962
  ];
5771
5963
  const q = query9(collection9(db, CLINICS_COLLECTION), ...constraints);
5772
5964
  const querySnapshot = await getDocs9(q);
5773
- for (const doc32 of querySnapshot.docs) {
5774
- const clinic = doc32.data();
5965
+ for (const doc33 of querySnapshot.docs) {
5966
+ const clinic = doc33.data();
5775
5967
  const distance = distanceBetween2(
5776
5968
  [center.latitude, center.longitude],
5777
5969
  [clinic.location.latitude, clinic.location.longitude]
@@ -5893,8 +6085,8 @@ async function findClinicsInRadius(db, center, radiusInKm, filters) {
5893
6085
  }
5894
6086
  const q = query10(collection10(db, CLINICS_COLLECTION), ...constraints);
5895
6087
  const querySnapshot = await getDocs10(q);
5896
- for (const doc32 of querySnapshot.docs) {
5897
- const clinic = doc32.data();
6088
+ for (const doc33 of querySnapshot.docs) {
6089
+ const clinic = doc33.data();
5898
6090
  const distance = distanceBetween3(
5899
6091
  [center.latitude, center.longitude],
5900
6092
  [clinic.location.latitude, clinic.location.longitude]
@@ -5990,8 +6182,8 @@ async function getClinicsByFilters(db, filters) {
5990
6182
  console.log(
5991
6183
  `[FILTER_UTILS] Found ${querySnapshot.docs.length} clinics in geo bound`
5992
6184
  );
5993
- for (const doc32 of querySnapshot.docs) {
5994
- const clinic = { ...doc32.data(), id: doc32.id };
6185
+ for (const doc33 of querySnapshot.docs) {
6186
+ const clinic = { ...doc33.data(), id: doc33.id };
5995
6187
  const distance = distanceBetween4(
5996
6188
  [center.latitude, center.longitude],
5997
6189
  [clinic.location.latitude, clinic.location.longitude]
@@ -6047,8 +6239,8 @@ async function getClinicsByFilters(db, filters) {
6047
6239
  console.log(
6048
6240
  `[FILTER_UTILS] Found ${querySnapshot.docs.length} clinics with regular query`
6049
6241
  );
6050
- const clinics = querySnapshot.docs.map((doc32) => {
6051
- return { ...doc32.data(), id: doc32.id };
6242
+ const clinics = querySnapshot.docs.map((doc33) => {
6243
+ return { ...doc33.data(), id: doc33.id };
6052
6244
  });
6053
6245
  let filteredClinics = clinics;
6054
6246
  if (filters.center) {
@@ -7273,17 +7465,28 @@ import {
7273
7465
 
7274
7466
  // src/types/notifications/index.ts
7275
7467
  var NotificationType = /* @__PURE__ */ ((NotificationType3) => {
7276
- NotificationType3["PRE_REQUIREMENT"] = "preRequirement";
7277
- NotificationType3["POST_REQUIREMENT"] = "postRequirement";
7278
7468
  NotificationType3["APPOINTMENT_REMINDER"] = "appointmentReminder";
7279
- NotificationType3["APPOINTMENT_NOTIFICATION"] = "appointmentNotification";
7469
+ NotificationType3["APPOINTMENT_STATUS_CHANGE"] = "appointmentStatusChange";
7470
+ NotificationType3["APPOINTMENT_RESCHEDULED_PROPOSAL"] = "appointmentRescheduledProposal";
7471
+ NotificationType3["APPOINTMENT_CANCELLED"] = "appointmentCancelled";
7472
+ NotificationType3["REQUIREMENT_INSTRUCTION_DUE"] = "requirementInstructionDue";
7473
+ NotificationType3["FORM_REMINDER"] = "formReminder";
7474
+ NotificationType3["FORM_SUBMISSION_CONFIRMATION"] = "formSubmissionConfirmation";
7475
+ NotificationType3["REVIEW_REQUEST"] = "reviewRequest";
7476
+ NotificationType3["PAYMENT_DUE"] = "paymentDue";
7477
+ NotificationType3["PAYMENT_CONFIRMATION"] = "paymentConfirmation";
7478
+ NotificationType3["PAYMENT_FAILED"] = "paymentFailed";
7479
+ NotificationType3["GENERAL_MESSAGE"] = "generalMessage";
7480
+ NotificationType3["ACCOUNT_NOTIFICATION"] = "accountNotification";
7280
7481
  return NotificationType3;
7281
7482
  })(NotificationType || {});
7282
7483
  var NOTIFICATIONS_COLLECTION = "notifications";
7283
7484
  var NotificationStatus = /* @__PURE__ */ ((NotificationStatus2) => {
7284
7485
  NotificationStatus2["PENDING"] = "pending";
7486
+ NotificationStatus2["PROCESSING"] = "processing";
7285
7487
  NotificationStatus2["SENT"] = "sent";
7286
7488
  NotificationStatus2["FAILED"] = "failed";
7489
+ NotificationStatus2["DELIVERED"] = "delivered";
7287
7490
  NotificationStatus2["CANCELLED"] = "cancelled";
7288
7491
  NotificationStatus2["PARTIAL_SUCCESS"] = "partialSuccess";
7289
7492
  return NotificationStatus2;
@@ -7339,9 +7542,9 @@ var NotificationService = class extends BaseService {
7339
7542
  orderBy3("notificationTime", "desc")
7340
7543
  );
7341
7544
  const querySnapshot = await getDocs14(q);
7342
- return querySnapshot.docs.map((doc32) => ({
7343
- id: doc32.id,
7344
- ...doc32.data()
7545
+ return querySnapshot.docs.map((doc33) => ({
7546
+ id: doc33.id,
7547
+ ...doc33.data()
7345
7548
  }));
7346
7549
  }
7347
7550
  /**
@@ -7355,9 +7558,9 @@ var NotificationService = class extends BaseService {
7355
7558
  orderBy3("notificationTime", "desc")
7356
7559
  );
7357
7560
  const querySnapshot = await getDocs14(q);
7358
- return querySnapshot.docs.map((doc32) => ({
7359
- id: doc32.id,
7360
- ...doc32.data()
7561
+ return querySnapshot.docs.map((doc33) => ({
7562
+ id: doc33.id,
7563
+ ...doc33.data()
7361
7564
  }));
7362
7565
  }
7363
7566
  /**
@@ -7429,9 +7632,9 @@ var NotificationService = class extends BaseService {
7429
7632
  orderBy3("notificationTime", "desc")
7430
7633
  );
7431
7634
  const querySnapshot = await getDocs14(q);
7432
- return querySnapshot.docs.map((doc32) => ({
7433
- id: doc32.id,
7434
- ...doc32.data()
7635
+ return querySnapshot.docs.map((doc33) => ({
7636
+ id: doc33.id,
7637
+ ...doc33.data()
7435
7638
  }));
7436
7639
  }
7437
7640
  /**
@@ -7444,9 +7647,9 @@ var NotificationService = class extends BaseService {
7444
7647
  orderBy3("notificationTime", "desc")
7445
7648
  );
7446
7649
  const querySnapshot = await getDocs14(q);
7447
- return querySnapshot.docs.map((doc32) => ({
7448
- id: doc32.id,
7449
- ...doc32.data()
7650
+ return querySnapshot.docs.map((doc33) => ({
7651
+ id: doc33.id,
7652
+ ...doc33.data()
7450
7653
  }));
7451
7654
  }
7452
7655
  };
@@ -7677,7 +7880,7 @@ var ProcedureService = class extends BaseService {
7677
7880
  where15("isActive", "==", true)
7678
7881
  );
7679
7882
  const snapshot = await getDocs15(q);
7680
- return snapshot.docs.map((doc32) => doc32.data());
7883
+ return snapshot.docs.map((doc33) => doc33.data());
7681
7884
  }
7682
7885
  /**
7683
7886
  * Gets all procedures for a practitioner
@@ -7691,7 +7894,7 @@ var ProcedureService = class extends BaseService {
7691
7894
  where15("isActive", "==", true)
7692
7895
  );
7693
7896
  const snapshot = await getDocs15(q);
7694
- return snapshot.docs.map((doc32) => doc32.data());
7897
+ return snapshot.docs.map((doc33) => doc33.data());
7695
7898
  }
7696
7899
  /**
7697
7900
  * Updates a procedure
@@ -7874,20 +8077,20 @@ var ProcedureService = class extends BaseService {
7874
8077
  const proceduresCollection = collection15(this.db, PROCEDURES_COLLECTION);
7875
8078
  let proceduresQuery = query15(proceduresCollection);
7876
8079
  if (pagination && pagination > 0) {
7877
- const { limit: limit11, startAfter: startAfter11 } = await import("firebase/firestore");
8080
+ const { limit: limit12, startAfter: startAfter12 } = await import("firebase/firestore");
7878
8081
  if (lastDoc) {
7879
8082
  proceduresQuery = query15(
7880
8083
  proceduresCollection,
7881
8084
  orderBy4("name"),
7882
8085
  // Use imported orderBy
7883
- startAfter11(lastDoc),
7884
- limit11(pagination)
8086
+ startAfter12(lastDoc),
8087
+ limit12(pagination)
7885
8088
  );
7886
8089
  } else {
7887
8090
  proceduresQuery = query15(
7888
8091
  proceduresCollection,
7889
8092
  orderBy4("name"),
7890
- limit11(pagination)
8093
+ limit12(pagination)
7891
8094
  );
7892
8095
  }
7893
8096
  } else {
@@ -7895,11 +8098,11 @@ var ProcedureService = class extends BaseService {
7895
8098
  }
7896
8099
  const proceduresSnapshot = await getDocs15(proceduresQuery);
7897
8100
  const lastVisible = proceduresSnapshot.docs[proceduresSnapshot.docs.length - 1];
7898
- const procedures = proceduresSnapshot.docs.map((doc32) => {
7899
- const data = doc32.data();
8101
+ const procedures = proceduresSnapshot.docs.map((doc33) => {
8102
+ const data = doc33.data();
7900
8103
  return {
7901
8104
  ...data,
7902
- id: doc32.id
8105
+ id: doc33.id
7903
8106
  // Ensure ID is present
7904
8107
  };
7905
8108
  });
@@ -7981,8 +8184,8 @@ var ProcedureService = class extends BaseService {
7981
8184
  console.log(
7982
8185
  `[PROCEDURE_SERVICE] Found ${querySnapshot.docs.length} procedures in geo bound`
7983
8186
  );
7984
- for (const doc32 of querySnapshot.docs) {
7985
- const procedure = { ...doc32.data(), id: doc32.id };
8187
+ for (const doc33 of querySnapshot.docs) {
8188
+ const procedure = { ...doc33.data(), id: doc33.id };
7986
8189
  const distance = distanceBetween6(
7987
8190
  [center.latitude, center.longitude],
7988
8191
  [
@@ -8033,8 +8236,8 @@ var ProcedureService = class extends BaseService {
8033
8236
  console.log(
8034
8237
  `[PROCEDURE_SERVICE] Found ${querySnapshot.docs.length} procedures with regular query`
8035
8238
  );
8036
- const procedures = querySnapshot.docs.map((doc32) => {
8037
- return { ...doc32.data(), id: doc32.id };
8239
+ const procedures = querySnapshot.docs.map((doc33) => {
8240
+ return { ...doc33.data(), id: doc33.id };
8038
8241
  });
8039
8242
  if (filters.location) {
8040
8243
  const center = filters.location;
@@ -8187,7 +8390,10 @@ var DocumentationTemplateService = class extends BaseService {
8187
8390
  createdBy: userId,
8188
8391
  version: 1,
8189
8392
  isActive: true,
8190
- tags: validatedData.tags || []
8393
+ tags: validatedData.tags || [],
8394
+ isUserForm: validatedData.isUserForm || false,
8395
+ isRequired: validatedData.isRequired || false,
8396
+ sortingOrder: validatedData.sortingOrder || 0
8191
8397
  };
8192
8398
  const docRef = doc16(this.collectionRef, templateId);
8193
8399
  await setDoc14(docRef, template);
@@ -8222,21 +8428,31 @@ var DocumentationTemplateService = class extends BaseService {
8222
8428
  if (validatedData.elements) {
8223
8429
  updatedElements = validatedData.elements.map((element) => ({
8224
8430
  ...element,
8225
- id: this.generateId()
8431
+ id: element.id || this.generateId()
8226
8432
  }));
8227
8433
  }
8228
- const updateData = {
8229
- ...validatedData,
8434
+ const updatePayload = {
8230
8435
  elements: updatedElements,
8231
8436
  updatedAt: Date.now(),
8232
8437
  version: template.version + 1
8233
8438
  };
8439
+ if (validatedData.title !== void 0)
8440
+ updatePayload.title = validatedData.title;
8441
+ if (validatedData.description !== void 0)
8442
+ updatePayload.description = validatedData.description;
8443
+ if (validatedData.isActive !== void 0)
8444
+ updatePayload.isActive = validatedData.isActive;
8445
+ if (validatedData.tags !== void 0)
8446
+ updatePayload.tags = validatedData.tags;
8447
+ if (validatedData.isUserForm !== void 0)
8448
+ updatePayload.isUserForm = validatedData.isUserForm;
8449
+ if (validatedData.isRequired !== void 0)
8450
+ updatePayload.isRequired = validatedData.isRequired;
8451
+ if (validatedData.sortingOrder !== void 0)
8452
+ updatePayload.sortingOrder = validatedData.sortingOrder;
8234
8453
  const docRef = doc16(this.collectionRef, templateId);
8235
- await updateDoc16(docRef, updateData);
8236
- return {
8237
- ...template,
8238
- ...updateData
8239
- };
8454
+ await updateDoc16(docRef, updatePayload);
8455
+ return { ...template, ...updatePayload };
8240
8456
  }
8241
8457
  /**
8242
8458
  * Delete a document template
@@ -8265,9 +8481,9 @@ var DocumentationTemplateService = class extends BaseService {
8265
8481
  const querySnapshot = await getDocs16(q);
8266
8482
  const templates = [];
8267
8483
  let lastVisible = null;
8268
- querySnapshot.forEach((doc32) => {
8269
- templates.push(doc32.data());
8270
- lastVisible = doc32;
8484
+ querySnapshot.forEach((doc33) => {
8485
+ templates.push(doc33.data());
8486
+ lastVisible = doc33;
8271
8487
  });
8272
8488
  return {
8273
8489
  templates,
@@ -8295,9 +8511,9 @@ var DocumentationTemplateService = class extends BaseService {
8295
8511
  const querySnapshot = await getDocs16(q);
8296
8512
  const templates = [];
8297
8513
  let lastVisible = null;
8298
- querySnapshot.forEach((doc32) => {
8299
- templates.push(doc32.data());
8300
- lastVisible = doc32;
8514
+ querySnapshot.forEach((doc33) => {
8515
+ templates.push(doc33.data());
8516
+ lastVisible = doc33;
8301
8517
  });
8302
8518
  return {
8303
8519
  templates,
@@ -8324,9 +8540,9 @@ var DocumentationTemplateService = class extends BaseService {
8324
8540
  const querySnapshot = await getDocs16(q);
8325
8541
  const templates = [];
8326
8542
  let lastVisible = null;
8327
- querySnapshot.forEach((doc32) => {
8328
- templates.push(doc32.data());
8329
- lastVisible = doc32;
8543
+ querySnapshot.forEach((doc33) => {
8544
+ templates.push(doc33.data());
8545
+ lastVisible = doc33;
8330
8546
  });
8331
8547
  return {
8332
8548
  templates,
@@ -8344,7 +8560,6 @@ import {
8344
8560
  setDoc as setDoc15,
8345
8561
  updateDoc as updateDoc17,
8346
8562
  query as query17,
8347
- where as where17,
8348
8563
  orderBy as orderBy6,
8349
8564
  limit as limit9,
8350
8565
  startAfter as startAfter9
@@ -8352,50 +8567,80 @@ import {
8352
8567
  var FilledDocumentService = class extends BaseService {
8353
8568
  constructor(...args) {
8354
8569
  super(...args);
8355
- this.collectionRef = collection17(
8356
- this.db,
8357
- FILLED_DOCUMENTS_COLLECTION
8358
- );
8359
8570
  this.templateService = new DocumentationTemplateService(...args);
8360
8571
  }
8572
+ getFormSubcollectionPath(isUserForm) {
8573
+ return isUserForm ? USER_FORMS_SUBCOLLECTION : DOCTOR_FORMS_SUBCOLLECTION;
8574
+ }
8361
8575
  /**
8362
- * Create a new filled document
8363
- * @param templateId - ID of the template to use
8364
- * @param patientId - ID of the patient
8365
- * @param practitionerId - ID of the practitioner
8366
- * @param clinicId - ID of the clinic
8367
- * @returns The created filled document
8576
+ * Create a new filled document within an appointment's subcollection.
8577
+ * @param templateId - ID of the template to use.
8578
+ * @param appointmentId - ID of the appointment this form belongs to.
8579
+ * @param procedureId - ID of the procedure associated with this form.
8580
+ * @param patientId - ID of the patient.
8581
+ * @param practitionerId - ID of the practitioner (can be system/generic if patient is filling).
8582
+ * @param clinicId - ID of the clinic.
8583
+ * @param initialValues - Optional initial values for the form elements.
8584
+ * @param initialStatus - Optional initial status for the form.
8585
+ * @returns The created filled document.
8368
8586
  */
8369
- async createFilledDocument(templateId, patientId, practitionerId, clinicId) {
8587
+ async createFilledDocumentForAppointment(templateId, appointmentId, procedureId, patientId, practitionerId, clinicId, initialValues = {}, initialStatus = "draft" /* DRAFT */) {
8370
8588
  const template = await this.templateService.getTemplateById(templateId);
8371
8589
  if (!template) {
8372
8590
  throw new Error(`Template with ID ${templateId} not found`);
8373
8591
  }
8374
8592
  const documentId3 = this.generateId();
8375
8593
  const now = Date.now();
8594
+ const isUserForm = template.isUserForm || false;
8595
+ const formSubcollection = this.getFormSubcollectionPath(isUserForm);
8376
8596
  const filledDocument = {
8377
8597
  id: documentId3,
8378
8598
  templateId,
8379
8599
  templateVersion: template.version,
8600
+ isUserForm,
8601
+ // Set based on template
8602
+ isRequired: template.isRequired || false,
8603
+ // Inherit isRequired from the template
8604
+ appointmentId,
8605
+ // NEW
8606
+ procedureId,
8607
+ // NEW
8380
8608
  patientId,
8381
8609
  practitionerId,
8382
8610
  clinicId,
8383
8611
  createdAt: now,
8384
8612
  updatedAt: now,
8385
- values: {},
8386
- status: "draft" /* DRAFT */
8613
+ values: initialValues,
8614
+ status: initialStatus
8387
8615
  };
8388
- const docRef = doc17(this.collectionRef, documentId3);
8616
+ const docRef = doc17(
8617
+ this.db,
8618
+ APPOINTMENTS_COLLECTION,
8619
+ // Replaced "appointments"
8620
+ appointmentId,
8621
+ formSubcollection,
8622
+ documentId3
8623
+ );
8389
8624
  await setDoc15(docRef, filledDocument);
8390
8625
  return filledDocument;
8391
8626
  }
8392
8627
  /**
8393
- * Get a filled document by ID
8394
- * @param documentId - ID of the filled document to retrieve
8395
- * @returns The filled document or null if not found
8628
+ * Get a specific filled document from an appointment's subcollection.
8629
+ * @param appointmentId - ID of the appointment.
8630
+ * @param formId - ID of the filled document.
8631
+ * @param isUserForm - Boolean indicating if it's a user form or doctor form.
8632
+ * @returns The filled document or null if not found.
8396
8633
  */
8397
- async getFilledDocumentById(documentId3) {
8398
- const docRef = doc17(this.collectionRef, documentId3);
8634
+ async getFilledDocumentFromAppointmentById(appointmentId, formId, isUserForm) {
8635
+ const formSubcollection = this.getFormSubcollectionPath(isUserForm);
8636
+ const docRef = doc17(
8637
+ this.db,
8638
+ APPOINTMENTS_COLLECTION,
8639
+ // Replaced "appointments"
8640
+ appointmentId,
8641
+ formSubcollection,
8642
+ formId
8643
+ );
8399
8644
  const docSnap = await getDoc20(docRef);
8400
8645
  if (!docSnap.exists()) {
8401
8646
  return null;
@@ -8403,178 +8648,183 @@ var FilledDocumentService = class extends BaseService {
8403
8648
  return docSnap.data();
8404
8649
  }
8405
8650
  /**
8406
- * Update values in a filled document
8407
- * @param documentId - ID of the filled document to update
8408
- * @param values - Updated values for elements
8409
- * @param status - Optional new status for the document
8410
- * @returns The updated filled document
8651
+ * Update values or status in a filled document within an appointment's subcollection.
8652
+ * @param appointmentId - ID of the appointment.
8653
+ * @param formId - ID of the filled document to update.
8654
+ * @param isUserForm - Boolean indicating if it's a user form or doctor form.
8655
+ * @param values - Updated values for elements.
8656
+ * @param status - Optional new status for the document.
8657
+ * @returns The updated filled document.
8411
8658
  */
8412
- async updateFilledDocument(documentId3, values, status) {
8413
- const filledDocument = await this.getFilledDocumentById(documentId3);
8414
- if (!filledDocument) {
8415
- throw new Error(`Filled document with ID ${documentId3} not found`);
8659
+ async updateFilledDocumentInAppointment(appointmentId, formId, isUserForm, values, status) {
8660
+ const formSubcollection = this.getFormSubcollectionPath(isUserForm);
8661
+ const docRef = doc17(
8662
+ this.db,
8663
+ APPOINTMENTS_COLLECTION,
8664
+ // Replaced "appointments"
8665
+ appointmentId,
8666
+ formSubcollection,
8667
+ formId
8668
+ );
8669
+ const existingDoc = await this.getFilledDocumentFromAppointmentById(
8670
+ appointmentId,
8671
+ formId,
8672
+ isUserForm
8673
+ );
8674
+ if (!existingDoc) {
8675
+ throw new Error(
8676
+ `Filled document with ID ${formId} not found in appointment ${appointmentId} ${formSubcollection}`
8677
+ );
8416
8678
  }
8417
- const updateData = {
8418
- values: {
8419
- ...filledDocument.values,
8420
- ...values
8421
- },
8679
+ const updatePayload = {
8422
8680
  updatedAt: Date.now()
8423
8681
  };
8682
+ if (values) {
8683
+ updatePayload.values = {
8684
+ ...existingDoc.values,
8685
+ ...values
8686
+ };
8687
+ }
8424
8688
  if (status) {
8425
- updateData.status = status;
8689
+ updatePayload.status = status;
8426
8690
  }
8427
- const docRef = doc17(this.collectionRef, documentId3);
8428
- await updateDoc17(docRef, updateData);
8429
- return {
8430
- ...filledDocument,
8431
- ...updateData
8432
- };
8691
+ if (Object.keys(updatePayload).length === 1 && "updatedAt" in updatePayload) {
8692
+ }
8693
+ await updateDoc17(docRef, updatePayload);
8694
+ return { ...existingDoc, ...updatePayload };
8433
8695
  }
8434
8696
  /**
8435
- * Get filled documents for a patient
8436
- * @param patientId - ID of the patient
8437
- * @param pageSize - Number of documents to retrieve
8438
- * @param lastDoc - Last document from previous page for pagination
8439
- * @returns Array of filled documents and the last document for pagination
8697
+ * Get all filled user forms for a specific appointment.
8698
+ * @param appointmentId ID of the appointment.
8699
+ * @param pageSize Number of documents to retrieve.
8700
+ * @param lastDoc Last document from previous page for pagination.
8440
8701
  */
8441
- async getFilledDocumentsByPatient(patientId, pageSize = 20, lastDoc) {
8702
+ async getFilledUserFormsForAppointment(appointmentId, pageSize = 20, lastDoc) {
8703
+ const subcollectionRef = collection17(
8704
+ this.db,
8705
+ APPOINTMENTS_COLLECTION,
8706
+ // Replaced "appointments"
8707
+ appointmentId,
8708
+ USER_FORMS_SUBCOLLECTION
8709
+ );
8442
8710
  let q = query17(
8443
- this.collectionRef,
8444
- where17("patientId", "==", patientId),
8711
+ subcollectionRef,
8445
8712
  orderBy6("updatedAt", "desc"),
8446
8713
  limit9(pageSize)
8447
8714
  );
8448
8715
  if (lastDoc) {
8449
8716
  q = query17(q, startAfter9(lastDoc));
8450
8717
  }
8451
- const querySnapshot = await getDocs17(q);
8452
- const documents = [];
8453
- let lastVisible = null;
8454
- querySnapshot.forEach((doc32) => {
8455
- documents.push(doc32.data());
8456
- lastVisible = doc32;
8457
- });
8458
- return {
8459
- documents,
8460
- lastDoc: lastVisible
8461
- };
8718
+ return this.executeQuery(q);
8462
8719
  }
8463
8720
  /**
8464
- * Get filled documents for a practitioner
8465
- * @param practitionerId - ID of the practitioner
8466
- * @param pageSize - Number of documents to retrieve
8467
- * @param lastDoc - Last document from previous page for pagination
8468
- * @returns Array of filled documents and the last document for pagination
8721
+ * Get all filled doctor forms for a specific appointment.
8722
+ * @param appointmentId ID of the appointment.
8723
+ * @param pageSize Number of documents to retrieve.
8724
+ * @param lastDoc Last document from previous page for pagination.
8469
8725
  */
8470
- async getFilledDocumentsByPractitioner(practitionerId, pageSize = 20, lastDoc) {
8726
+ async getFilledDoctorFormsForAppointment(appointmentId, pageSize = 20, lastDoc) {
8727
+ const subcollectionRef = collection17(
8728
+ this.db,
8729
+ APPOINTMENTS_COLLECTION,
8730
+ // Replaced "appointments"
8731
+ appointmentId,
8732
+ DOCTOR_FORMS_SUBCOLLECTION
8733
+ );
8471
8734
  let q = query17(
8472
- this.collectionRef,
8473
- where17("practitionerId", "==", practitionerId),
8735
+ subcollectionRef,
8474
8736
  orderBy6("updatedAt", "desc"),
8475
8737
  limit9(pageSize)
8476
8738
  );
8477
8739
  if (lastDoc) {
8478
8740
  q = query17(q, startAfter9(lastDoc));
8479
8741
  }
8742
+ return this.executeQuery(q);
8743
+ }
8744
+ // Helper to execute query and return documents + lastDoc
8745
+ async executeQuery(q) {
8480
8746
  const querySnapshot = await getDocs17(q);
8481
8747
  const documents = [];
8482
8748
  let lastVisible = null;
8483
- querySnapshot.forEach((doc32) => {
8484
- documents.push(doc32.data());
8485
- lastVisible = doc32;
8749
+ querySnapshot.forEach((doc33) => {
8750
+ documents.push(doc33.data());
8751
+ lastVisible = doc33;
8486
8752
  });
8487
8753
  return {
8488
8754
  documents,
8489
8755
  lastDoc: lastVisible
8490
8756
  };
8491
8757
  }
8758
+ // IMPORTANT: The following methods that query across all patients/practitioners/clinics
8759
+ // (e.g., getFilledDocumentsByPatient, getFilledDocumentsByPractitioner)
8760
+ // will NOT work correctly if FILLED_DOCUMENTS_COLLECTION is no longer a top-level collection
8761
+ // and data is only in appointment subcollections. You would need to use
8762
+ // Firestore Collection Group Queries for that, which require an index and a different query approach.
8763
+ // These methods are left here for now but would need significant rework or removal.
8764
+ /**
8765
+ * Get filled documents for a patient (NEEDS REWORK for subcollections or Collection Group Query)
8766
+ * @param patientId - ID of the patient
8767
+ * @param pageSize - Number of documents to retrieve
8768
+ * @param lastDoc - Last document from previous page for pagination
8769
+ * @returns Array of filled documents and the last document for pagination
8770
+ */
8771
+ async getFilledDocumentsByPatient(patientId, pageSize = 20, lastDoc) {
8772
+ console.warn(
8773
+ "getFilledDocumentsByPatient needs rework for subcollection model or Collection Group Queries."
8774
+ );
8775
+ return { documents: [], lastDoc: null };
8776
+ }
8777
+ /**
8778
+ * Get filled documents for a practitioner (NEEDS REWORK for subcollections or Collection Group Query)
8779
+ * @param practitionerId - ID of the practitioner
8780
+ * @param pageSize - Number of documents to retrieve
8781
+ * @param lastDoc - Last document from previous page for pagination
8782
+ * @returns Array of filled documents and the last document for pagination
8783
+ */
8784
+ async getFilledDocumentsByPractitioner(practitionerId, pageSize = 20, lastDoc) {
8785
+ console.warn(
8786
+ "getFilledDocumentsByPractitioner needs rework for subcollection model or Collection Group Queries."
8787
+ );
8788
+ return { documents: [], lastDoc: null };
8789
+ }
8492
8790
  /**
8493
- * Get filled documents for a clinic
8791
+ * Get filled documents for a clinic (NEEDS REWORK for subcollections or Collection Group Query)
8494
8792
  * @param clinicId - ID of the clinic
8495
8793
  * @param pageSize - Number of documents to retrieve
8496
8794
  * @param lastDoc - Last document from previous page for pagination
8497
8795
  * @returns Array of filled documents and the last document for pagination
8498
8796
  */
8499
8797
  async getFilledDocumentsByClinic(clinicId, pageSize = 20, lastDoc) {
8500
- let q = query17(
8501
- this.collectionRef,
8502
- where17("clinicId", "==", clinicId),
8503
- orderBy6("updatedAt", "desc"),
8504
- limit9(pageSize)
8798
+ console.warn(
8799
+ "getFilledDocumentsByClinic needs rework for subcollection model or Collection Group Queries."
8505
8800
  );
8506
- if (lastDoc) {
8507
- q = query17(q, startAfter9(lastDoc));
8508
- }
8509
- const querySnapshot = await getDocs17(q);
8510
- const documents = [];
8511
- let lastVisible = null;
8512
- querySnapshot.forEach((doc32) => {
8513
- documents.push(doc32.data());
8514
- lastVisible = doc32;
8515
- });
8516
- return {
8517
- documents,
8518
- lastDoc: lastVisible
8519
- };
8801
+ return { documents: [], lastDoc: null };
8520
8802
  }
8521
8803
  /**
8522
- * Get filled documents by template
8804
+ * Get filled documents by template (NEEDS REWORK for subcollections or Collection Group Query)
8523
8805
  * @param templateId - ID of the template
8524
8806
  * @param pageSize - Number of documents to retrieve
8525
8807
  * @param lastDoc - Last document from previous page for pagination
8526
8808
  * @returns Array of filled documents and the last document for pagination
8527
8809
  */
8528
8810
  async getFilledDocumentsByTemplate(templateId, pageSize = 20, lastDoc) {
8529
- let q = query17(
8530
- this.collectionRef,
8531
- where17("templateId", "==", templateId),
8532
- orderBy6("updatedAt", "desc"),
8533
- limit9(pageSize)
8811
+ console.warn(
8812
+ "getFilledDocumentsByTemplate needs rework for subcollection model or Collection Group Queries."
8534
8813
  );
8535
- if (lastDoc) {
8536
- q = query17(q, startAfter9(lastDoc));
8537
- }
8538
- const querySnapshot = await getDocs17(q);
8539
- const documents = [];
8540
- let lastVisible = null;
8541
- querySnapshot.forEach((doc32) => {
8542
- documents.push(doc32.data());
8543
- lastVisible = doc32;
8544
- });
8545
- return {
8546
- documents,
8547
- lastDoc: lastVisible
8548
- };
8814
+ return { documents: [], lastDoc: null };
8549
8815
  }
8550
8816
  /**
8551
- * Get filled documents by status
8817
+ * Get filled documents by status (NEEDS REWORK for subcollections or Collection Group Query)
8552
8818
  * @param status - Status to filter by
8553
8819
  * @param pageSize - Number of documents to retrieve
8554
8820
  * @param lastDoc - Last document from previous page for pagination
8555
8821
  * @returns Array of filled documents and the last document for pagination
8556
8822
  */
8557
8823
  async getFilledDocumentsByStatus(status, pageSize = 20, lastDoc) {
8558
- let q = query17(
8559
- this.collectionRef,
8560
- where17("status", "==", status),
8561
- orderBy6("updatedAt", "desc"),
8562
- limit9(pageSize)
8824
+ console.warn(
8825
+ "getFilledDocumentsByStatus needs rework for subcollection model or Collection Group Queries."
8563
8826
  );
8564
- if (lastDoc) {
8565
- q = query17(q, startAfter9(lastDoc));
8566
- }
8567
- const querySnapshot = await getDocs17(q);
8568
- const documents = [];
8569
- let lastVisible = null;
8570
- querySnapshot.forEach((doc32) => {
8571
- documents.push(doc32.data());
8572
- lastVisible = doc32;
8573
- });
8574
- return {
8575
- documents,
8576
- lastDoc: lastVisible
8577
- };
8827
+ return { documents: [], lastDoc: null };
8578
8828
  }
8579
8829
  };
8580
8830
 
@@ -9125,7 +9375,7 @@ async function searchCalendarEventsUtil(db, params) {
9125
9375
  const finalQuery = query21(collectionRef, ...constraints);
9126
9376
  const querySnapshot = await getDocs21(finalQuery);
9127
9377
  const events = querySnapshot.docs.map(
9128
- (doc32) => ({ id: doc32.id, ...doc32.data() })
9378
+ (doc33) => ({ id: doc33.id, ...doc33.data() })
9129
9379
  );
9130
9380
  return events;
9131
9381
  } catch (error) {
@@ -9218,7 +9468,7 @@ async function getPractitionerSyncedCalendarsUtil(db, practitionerId) {
9218
9468
  );
9219
9469
  const q = query22(calendarsRef, orderBy11("createdAt", "desc"));
9220
9470
  const querySnapshot = await getDocs22(q);
9221
- return querySnapshot.docs.map((doc32) => doc32.data());
9471
+ return querySnapshot.docs.map((doc33) => doc33.data());
9222
9472
  }
9223
9473
  async function getPatientSyncedCalendarUtil(db, patientId, calendarId) {
9224
9474
  const calendarRef = getPatientSyncedCalendarDocRef(db, patientId, calendarId);
@@ -9235,7 +9485,7 @@ async function getPatientSyncedCalendarsUtil(db, patientId) {
9235
9485
  );
9236
9486
  const q = query22(calendarsRef, orderBy11("createdAt", "desc"));
9237
9487
  const querySnapshot = await getDocs22(q);
9238
- return querySnapshot.docs.map((doc32) => doc32.data());
9488
+ return querySnapshot.docs.map((doc33) => doc33.data());
9239
9489
  }
9240
9490
  async function getClinicSyncedCalendarUtil(db, clinicId, calendarId) {
9241
9491
  const calendarRef = getClinicSyncedCalendarDocRef(db, clinicId, calendarId);
@@ -9252,7 +9502,7 @@ async function getClinicSyncedCalendarsUtil(db, clinicId) {
9252
9502
  );
9253
9503
  const q = query22(calendarsRef, orderBy11("createdAt", "desc"));
9254
9504
  const querySnapshot = await getDocs22(q);
9255
- return querySnapshot.docs.map((doc32) => doc32.data());
9505
+ return querySnapshot.docs.map((doc33) => doc33.data());
9256
9506
  }
9257
9507
  async function updatePractitionerSyncedCalendarUtil(db, practitionerId, calendarId, updateData) {
9258
9508
  const calendarRef = getPractitionerSyncedCalendarDocRef(
@@ -10607,9 +10857,9 @@ var CalendarServiceV2 = class extends BaseService {
10607
10857
  where23("eventTime.start", "<=", Timestamp25.fromDate(endDate))
10608
10858
  );
10609
10859
  const eventsSnapshot = await getDocs23(q);
10610
- const events = eventsSnapshot.docs.map((doc32) => ({
10611
- id: doc32.id,
10612
- ...doc32.data()
10860
+ const events = eventsSnapshot.docs.map((doc33) => ({
10861
+ id: doc33.id,
10862
+ ...doc33.data()
10613
10863
  }));
10614
10864
  const calendars = await this.syncedCalendarsService.getPractitionerSyncedCalendars(
10615
10865
  doctorId
@@ -11241,7 +11491,7 @@ var CalendarServiceV2 = class extends BaseService {
11241
11491
  ])
11242
11492
  );
11243
11493
  const querySnapshot = await getDocs23(q);
11244
- return querySnapshot.docs.map((doc32) => doc32.data());
11494
+ return querySnapshot.docs.map((doc33) => doc33.data());
11245
11495
  }
11246
11496
  /**
11247
11497
  * Calculates available time slots based on working hours, schedule and existing appointments
@@ -11520,7 +11770,7 @@ var ReviewService = class extends BaseService {
11520
11770
  where24("patientId", "==", patientId)
11521
11771
  );
11522
11772
  const snapshot = await getDocs24(q);
11523
- return snapshot.docs.map((doc32) => doc32.data());
11773
+ return snapshot.docs.map((doc33) => doc33.data());
11524
11774
  }
11525
11775
  /**
11526
11776
  * Gets all reviews for a specific clinic
@@ -11533,7 +11783,7 @@ var ReviewService = class extends BaseService {
11533
11783
  where24("clinicReview.clinicId", "==", clinicId)
11534
11784
  );
11535
11785
  const snapshot = await getDocs24(q);
11536
- return snapshot.docs.map((doc32) => doc32.data());
11786
+ return snapshot.docs.map((doc33) => doc33.data());
11537
11787
  }
11538
11788
  /**
11539
11789
  * Gets all reviews for a specific practitioner
@@ -11546,7 +11796,7 @@ var ReviewService = class extends BaseService {
11546
11796
  where24("practitionerReview.practitionerId", "==", practitionerId)
11547
11797
  );
11548
11798
  const snapshot = await getDocs24(q);
11549
- return snapshot.docs.map((doc32) => doc32.data());
11799
+ return snapshot.docs.map((doc33) => doc33.data());
11550
11800
  }
11551
11801
  /**
11552
11802
  * Gets all reviews for a specific procedure
@@ -11559,7 +11809,7 @@ var ReviewService = class extends BaseService {
11559
11809
  where24("procedureReview.procedureId", "==", procedureId)
11560
11810
  );
11561
11811
  const snapshot = await getDocs24(q);
11562
- return snapshot.docs.map((doc32) => doc32.data());
11812
+ return snapshot.docs.map((doc33) => doc33.data());
11563
11813
  }
11564
11814
  /**
11565
11815
  * Gets all reviews for a specific appointment
@@ -11988,7 +12238,10 @@ var ReviewService = class extends BaseService {
11988
12238
 
11989
12239
  // src/services/appointment/appointment.service.ts
11990
12240
  import {
11991
- Timestamp as Timestamp28
12241
+ Timestamp as Timestamp28,
12242
+ serverTimestamp as serverTimestamp24,
12243
+ arrayUnion as arrayUnion8,
12244
+ arrayRemove as arrayRemove7
11992
12245
  } from "firebase/firestore";
11993
12246
  import { getFunctions, httpsCallable } from "firebase/functions";
11994
12247
 
@@ -12274,7 +12527,7 @@ async function updateCalendarEventStatus(db, calendarEventId, appointmentStatus)
12274
12527
  case "canceled_clinic" /* CANCELED_CLINIC */:
12275
12528
  calendarStatus = "canceled";
12276
12529
  break;
12277
- case "rescheduled" /* RESCHEDULED */:
12530
+ case AppointmentStatus.RESCHEDULED:
12278
12531
  calendarStatus = "rescheduled";
12279
12532
  break;
12280
12533
  case "completed" /* COMPLETED */:
@@ -12348,7 +12601,7 @@ async function searchAppointmentsUtil(db, params) {
12348
12601
  const q = query25(collection25(db, APPOINTMENTS_COLLECTION), ...constraints);
12349
12602
  const querySnapshot = await getDocs25(q);
12350
12603
  const appointments = querySnapshot.docs.map(
12351
- (doc32) => doc32.data()
12604
+ (doc33) => doc33.data()
12352
12605
  );
12353
12606
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
12354
12607
  return { appointments, lastDoc };
@@ -12371,12 +12624,13 @@ var AppointmentService = class extends BaseService {
12371
12624
  * @param practitionerService Practitioner service instance
12372
12625
  * @param clinicService Clinic service instance
12373
12626
  */
12374
- constructor(db, auth, app, calendarService, patientService, practitionerService, clinicService) {
12627
+ constructor(db, auth, app, calendarService, patientService, practitionerService, clinicService, filledDocumentService) {
12375
12628
  super(db, auth, app);
12376
12629
  this.calendarService = calendarService;
12377
12630
  this.patientService = patientService;
12378
12631
  this.practitionerService = practitionerService;
12379
12632
  this.clinicService = clinicService;
12633
+ this.filledDocumentService = filledDocumentService;
12380
12634
  this.functions = getFunctions(app, "europe-west6");
12381
12635
  }
12382
12636
  /**
@@ -12732,152 +12986,331 @@ var AppointmentService = class extends BaseService {
12732
12986
  *
12733
12987
  * @param appointmentId ID of the appointment
12734
12988
  * @param newStatus New status to set
12735
- * @param cancellationReason Required if canceling the appointment
12736
- * @param canceledBy Required if canceling the appointment
12989
+ * @param details Optional details for the status change
12737
12990
  * @returns The updated appointment
12738
12991
  */
12739
- async updateAppointmentStatus(appointmentId, newStatus, cancellationReason, canceledBy) {
12992
+ async updateAppointmentStatus(appointmentId, newStatus, details) {
12740
12993
  console.log(
12741
12994
  `[APPOINTMENT_SERVICE] Updating status of appointment ${appointmentId} to ${newStatus}`
12742
12995
  );
12743
- const updateData = { status: newStatus };
12744
- if (newStatus === "canceled_clinic" /* CANCELED_CLINIC */ || newStatus === "canceled_patient" /* CANCELED_PATIENT */) {
12745
- if (!cancellationReason) {
12746
- throw new Error(
12747
- "Cancellation reason is required when canceling an appointment"
12748
- );
12996
+ const updateData = {
12997
+ status: newStatus,
12998
+ updatedAt: serverTimestamp24()
12999
+ };
13000
+ if (newStatus === "canceled_clinic" /* CANCELED_CLINIC */ || newStatus === "canceled_patient" /* CANCELED_PATIENT */ || newStatus === "canceled_patient_rescheduled" /* CANCELED_PATIENT_RESCHEDULED */) {
13001
+ if (!(details == null ? void 0 : details.cancellationReason)) {
13002
+ throw new Error("Cancellation reason is required when canceling.");
12749
13003
  }
12750
- if (!canceledBy) {
12751
- throw new Error(
12752
- "Canceled by is required when canceling an appointment"
12753
- );
13004
+ if (!(details == null ? void 0 : details.canceledBy)) {
13005
+ throw new Error("Canceled by is required when canceling.");
12754
13006
  }
12755
- updateData.cancellationReason = cancellationReason;
12756
- updateData.canceledBy = canceledBy;
13007
+ updateData.cancellationReason = details.cancellationReason;
13008
+ updateData.canceledBy = details.canceledBy;
13009
+ updateData.cancellationTime = Timestamp28.now();
12757
13010
  }
12758
13011
  if (newStatus === "confirmed" /* CONFIRMED */) {
12759
13012
  updateData.confirmationTime = Timestamp28.now();
12760
13013
  }
13014
+ if (newStatus === "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
13015
+ updateData.rescheduleTime = Timestamp28.now();
13016
+ }
12761
13017
  return this.updateAppointment(appointmentId, updateData);
12762
13018
  }
12763
13019
  /**
12764
- * Confirms an appointment.
12765
- *
12766
- * @param appointmentId ID of the appointment to confirm
12767
- * @returns The confirmed appointment
13020
+ * Confirms a PENDING appointment by an Admin/Clinic.
12768
13021
  */
12769
- async confirmAppointment(appointmentId) {
13022
+ async confirmAppointmentAdmin(appointmentId) {
12770
13023
  console.log(
12771
- `[APPOINTMENT_SERVICE] Confirming appointment: ${appointmentId}`
13024
+ `[APPOINTMENT_SERVICE] Admin confirming appointment: ${appointmentId}`
12772
13025
  );
13026
+ const appointment = await this.getAppointmentById(appointmentId);
13027
+ if (!appointment)
13028
+ throw new Error(`Appointment ${appointmentId} not found.`);
13029
+ if (appointment.status !== "pending" /* PENDING */) {
13030
+ throw new Error(
13031
+ `Appointment ${appointmentId} is not in PENDING state to be confirmed.`
13032
+ );
13033
+ }
12773
13034
  return this.updateAppointmentStatus(
12774
13035
  appointmentId,
12775
13036
  "confirmed" /* CONFIRMED */
12776
13037
  );
12777
13038
  }
12778
13039
  /**
12779
- * Cancels an appointment from the clinic side.
12780
- *
12781
- * @param appointmentId ID of the appointment to cancel
12782
- * @param reason Reason for cancellation
12783
- * @returns The canceled appointment
13040
+ * Cancels an appointment by the User (Patient).
12784
13041
  */
12785
- async cancelAppointmentByClinic(appointmentId, reason) {
13042
+ async cancelAppointmentUser(appointmentId, reason) {
12786
13043
  console.log(
12787
- `[APPOINTMENT_SERVICE] Canceling appointment by clinic: ${appointmentId}`
13044
+ `[APPOINTMENT_SERVICE] User canceling appointment: ${appointmentId}`
13045
+ );
13046
+ return this.updateAppointmentStatus(
13047
+ appointmentId,
13048
+ "canceled_patient" /* CANCELED_PATIENT */,
13049
+ {
13050
+ cancellationReason: reason,
13051
+ canceledBy: "patient"
13052
+ }
13053
+ );
13054
+ }
13055
+ /**
13056
+ * Cancels an appointment by an Admin/Clinic.
13057
+ */
13058
+ async cancelAppointmentAdmin(appointmentId, reason) {
13059
+ console.log(
13060
+ `[APPOINTMENT_SERVICE] Admin canceling appointment: ${appointmentId}`
12788
13061
  );
12789
13062
  return this.updateAppointmentStatus(
12790
13063
  appointmentId,
12791
13064
  "canceled_clinic" /* CANCELED_CLINIC */,
12792
- reason,
12793
- "clinic"
13065
+ {
13066
+ cancellationReason: reason,
13067
+ canceledBy: "clinic"
13068
+ }
12794
13069
  );
12795
13070
  }
12796
13071
  /**
12797
- * Cancels an appointment from the patient side.
12798
- *
12799
- * @param appointmentId ID of the appointment to cancel
12800
- * @param reason Reason for cancellation
12801
- * @returns The canceled appointment
13072
+ * Admin proposes to reschedule an appointment.
13073
+ * Sets status to RESCHEDULED_BY_CLINIC and updates times.
13074
+ */
13075
+ async rescheduleAppointmentAdmin(appointmentId, newStartTime, newEndTime) {
13076
+ console.log(
13077
+ `[APPOINTMENT_SERVICE] Admin rescheduling appointment: ${appointmentId}`
13078
+ );
13079
+ if (newEndTime.toMillis() <= newStartTime.toMillis()) {
13080
+ throw new Error("New end time must be after new start time.");
13081
+ }
13082
+ const updateData = {
13083
+ status: "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */,
13084
+ appointmentStartTime: newStartTime,
13085
+ appointmentEndTime: newEndTime,
13086
+ rescheduleTime: Timestamp28.now(),
13087
+ confirmationTime: null,
13088
+ updatedAt: serverTimestamp24()
13089
+ };
13090
+ return this.updateAppointment(appointmentId, updateData);
13091
+ }
13092
+ /**
13093
+ * User confirms a reschedule proposed by the clinic.
13094
+ * Status changes from RESCHEDULED_BY_CLINIC to CONFIRMED.
12802
13095
  */
12803
- async cancelAppointmentByPatient(appointmentId, reason) {
13096
+ async rescheduleAppointmentConfirmUser(appointmentId) {
12804
13097
  console.log(
12805
- `[APPOINTMENT_SERVICE] Canceling appointment by patient: ${appointmentId}`
13098
+ `[APPOINTMENT_SERVICE] User confirming reschedule for: ${appointmentId}`
12806
13099
  );
13100
+ const appointment = await this.getAppointmentById(appointmentId);
13101
+ if (!appointment)
13102
+ throw new Error(`Appointment ${appointmentId} not found.`);
13103
+ if (appointment.status !== "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
13104
+ throw new Error(
13105
+ `Appointment ${appointmentId} is not in RESCHEDULED_BY_CLINIC state.`
13106
+ );
13107
+ }
12807
13108
  return this.updateAppointmentStatus(
12808
13109
  appointmentId,
12809
- "canceled_patient" /* CANCELED_PATIENT */,
12810
- reason,
12811
- "patient"
13110
+ "confirmed" /* CONFIRMED */
12812
13111
  );
12813
13112
  }
12814
13113
  /**
12815
- * Marks an appointment as checked in.
12816
- *
12817
- * @param appointmentId ID of the appointment
12818
- * @returns The updated appointment
13114
+ * User rejects a reschedule proposed by the clinic.
13115
+ * Status changes from RESCHEDULED_BY_CLINIC to CANCELED_PATIENT_RESCHEDULED.
12819
13116
  */
12820
- async checkInAppointment(appointmentId) {
13117
+ async rescheduleAppointmentRejectUser(appointmentId, reason) {
12821
13118
  console.log(
12822
- `[APPOINTMENT_SERVICE] Checking in appointment: ${appointmentId}`
13119
+ `[APPOINTMENT_SERVICE] User rejecting reschedule for: ${appointmentId}`
12823
13120
  );
13121
+ const appointment = await this.getAppointmentById(appointmentId);
13122
+ if (!appointment)
13123
+ throw new Error(`Appointment ${appointmentId} not found.`);
13124
+ if (appointment.status !== "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
13125
+ throw new Error(
13126
+ `Appointment ${appointmentId} is not in RESCHEDULED_BY_CLINIC state.`
13127
+ );
13128
+ }
12824
13129
  return this.updateAppointmentStatus(
12825
13130
  appointmentId,
12826
- "checked_in" /* CHECKED_IN */
13131
+ "canceled_patient_rescheduled" /* CANCELED_PATIENT_RESCHEDULED */,
13132
+ {
13133
+ cancellationReason: reason,
13134
+ canceledBy: "patient"
13135
+ }
12827
13136
  );
12828
13137
  }
12829
13138
  /**
12830
- * Marks an appointment as in progress.
12831
- *
12832
- * @param appointmentId ID of the appointment
12833
- * @returns The updated appointment
13139
+ * Admin checks in a patient for their appointment.
13140
+ * Requires all pending user forms to be completed.
12834
13141
  */
12835
- async startAppointment(appointmentId) {
12836
- console.log(`[APPOINTMENT_SERVICE] Starting appointment: ${appointmentId}`);
13142
+ async checkInPatientAdmin(appointmentId) {
13143
+ console.log(
13144
+ `[APPOINTMENT_SERVICE] Admin checking in patient for: ${appointmentId}`
13145
+ );
13146
+ const appointment = await this.getAppointmentById(appointmentId);
13147
+ if (!appointment)
13148
+ throw new Error(`Appointment ${appointmentId} not found.`);
13149
+ if (appointment.pendingUserFormsIds && appointment.pendingUserFormsIds.length > 0) {
13150
+ throw new Error(
13151
+ `Cannot check in: Patient has ${appointment.pendingUserFormsIds.length} pending required form(s). IDs: ${appointment.pendingUserFormsIds.join(
13152
+ ", "
13153
+ )}`
13154
+ );
13155
+ }
13156
+ if (appointment.status !== "confirmed" /* CONFIRMED */ && appointment.status !== "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
13157
+ console.warn(
13158
+ `Checking in appointment ${appointmentId} with status ${appointment.status}. Ensure this is intended.`
13159
+ );
13160
+ }
12837
13161
  return this.updateAppointmentStatus(
12838
13162
  appointmentId,
12839
- "in_progress" /* IN_PROGRESS */
13163
+ "checked_in" /* CHECKED_IN */
12840
13164
  );
12841
13165
  }
12842
13166
  /**
12843
- * Marks an appointment as completed.
12844
- *
12845
- * @param appointmentId ID of the appointment
12846
- * @param actualDurationMinutes Actual duration of the appointment in minutes
12847
- * @returns The updated appointment
13167
+ * Doctor starts the appointment procedure.
12848
13168
  */
12849
- async completeAppointment(appointmentId, actualDurationMinutes) {
13169
+ async startAppointmentDoctor(appointmentId) {
12850
13170
  console.log(
12851
- `[APPOINTMENT_SERVICE] Completing appointment: ${appointmentId}`
13171
+ `[APPOINTMENT_SERVICE] Doctor starting appointment: ${appointmentId}`
12852
13172
  );
13173
+ const appointment = await this.getAppointmentById(appointmentId);
13174
+ if (!appointment)
13175
+ throw new Error(`Appointment ${appointmentId} not found.`);
13176
+ if (appointment.status !== "checked_in" /* CHECKED_IN */) {
13177
+ throw new Error(
13178
+ `Appointment ${appointmentId} must be CHECKED_IN to start.`
13179
+ );
13180
+ }
13181
+ const updateData = {
13182
+ status: "in_progress" /* IN_PROGRESS */,
13183
+ procedureActualStartTime: Timestamp28.now(),
13184
+ // Set actual start time
13185
+ updatedAt: serverTimestamp24()
13186
+ };
13187
+ return this.updateAppointment(appointmentId, updateData);
13188
+ }
13189
+ /**
13190
+ * Doctor completes and finalizes the appointment.
13191
+ */
13192
+ async completeAppointmentDoctor(appointmentId, finalizationNotes, actualDurationMinutesInput) {
13193
+ console.log(
13194
+ `[APPOINTMENT_SERVICE] Doctor completing appointment: ${appointmentId}`
13195
+ );
13196
+ const currentUser = this.auth.currentUser;
13197
+ if (!currentUser)
13198
+ throw new Error("Authentication required to complete appointment.");
13199
+ const appointment = await this.getAppointmentById(appointmentId);
13200
+ if (!appointment)
13201
+ throw new Error(`Appointment ${appointmentId} not found.`);
13202
+ let calculatedDurationMinutes = actualDurationMinutesInput;
13203
+ const procedureCompletionTime = Timestamp28.now();
13204
+ if (calculatedDurationMinutes === void 0 && appointment.procedureActualStartTime) {
13205
+ const startTimeMillis = appointment.procedureActualStartTime.toMillis();
13206
+ const endTimeMillis = procedureCompletionTime.toMillis();
13207
+ if (endTimeMillis > startTimeMillis) {
13208
+ calculatedDurationMinutes = Math.round(
13209
+ (endTimeMillis - startTimeMillis) / 6e4
13210
+ );
13211
+ }
13212
+ }
12853
13213
  const updateData = {
12854
13214
  status: "completed" /* COMPLETED */,
12855
- actualDurationMinutes
13215
+ actualDurationMinutes: calculatedDurationMinutes,
13216
+ // Use calculated or provided duration
13217
+ finalizedDetails: {
13218
+ by: currentUser.uid,
13219
+ // This is used ID, not practitioner's profile ID (just so we know who completed the appointment)
13220
+ at: procedureCompletionTime,
13221
+ // Use consistent completion timestamp
13222
+ notes: finalizationNotes
13223
+ },
13224
+ // Optionally update appointmentEndTime to the actual completion time
13225
+ // appointmentEndTime: procedureCompletionTime,
13226
+ updatedAt: serverTimestamp24()
12856
13227
  };
12857
13228
  return this.updateAppointment(appointmentId, updateData);
12858
13229
  }
12859
13230
  /**
12860
- * Marks an appointment as no-show.
12861
- *
12862
- * @param appointmentId ID of the appointment
12863
- * @returns The updated appointment
13231
+ * Admin marks an appointment as No-Show.
12864
13232
  */
12865
- async markNoShow(appointmentId) {
13233
+ async markNoShowAdmin(appointmentId) {
12866
13234
  console.log(
12867
- `[APPOINTMENT_SERVICE] Marking appointment as no-show: ${appointmentId}`
13235
+ `[APPOINTMENT_SERVICE] Admin marking no-show for: ${appointmentId}`
12868
13236
  );
13237
+ const appointment = await this.getAppointmentById(appointmentId);
13238
+ if (!appointment)
13239
+ throw new Error(`Appointment ${appointmentId} not found.`);
13240
+ if (Timestamp28.now().toMillis() < appointment.appointmentStartTime.toMillis()) {
13241
+ throw new Error("Cannot mark no-show before appointment start time.");
13242
+ }
12869
13243
  return this.updateAppointmentStatus(
12870
13244
  appointmentId,
12871
- "no_show" /* NO_SHOW */
13245
+ "no_show" /* NO_SHOW */,
13246
+ {
13247
+ cancellationReason: "Patient did not show up for the appointment.",
13248
+ canceledBy: "clinic"
13249
+ }
13250
+ );
13251
+ }
13252
+ /**
13253
+ * Adds a media item to an appointment.
13254
+ */
13255
+ async addMediaToAppointment(appointmentId, mediaItemData) {
13256
+ console.log(
13257
+ `[APPOINTMENT_SERVICE] Adding media to appointment ${appointmentId}`
13258
+ );
13259
+ const currentUser = this.auth.currentUser;
13260
+ if (!currentUser) throw new Error("Authentication required.");
13261
+ const newMediaItem = {
13262
+ ...mediaItemData,
13263
+ id: this.generateId(),
13264
+ uploadedAt: Timestamp28.now(),
13265
+ uploadedBy: currentUser.uid
13266
+ };
13267
+ const updateData = {
13268
+ media: arrayUnion8(newMediaItem),
13269
+ updatedAt: serverTimestamp24()
13270
+ };
13271
+ return this.updateAppointment(appointmentId, updateData);
13272
+ }
13273
+ /**
13274
+ * Removes a media item from an appointment.
13275
+ */
13276
+ async removeMediaFromAppointment(appointmentId, mediaItemId) {
13277
+ console.log(
13278
+ `[APPOINTMENT_SERVICE] Removing media ${mediaItemId} from appointment ${appointmentId}`
12872
13279
  );
13280
+ const appointment = await this.getAppointmentById(appointmentId);
13281
+ if (!appointment || !appointment.media) {
13282
+ throw new Error("Appointment or media list not found.");
13283
+ }
13284
+ const mediaToRemove = appointment.media.find((m) => m.id === mediaItemId);
13285
+ if (!mediaToRemove) {
13286
+ throw new Error(`Media item ${mediaItemId} not found in appointment.`);
13287
+ }
13288
+ const updateData = {
13289
+ media: arrayRemove7(mediaToRemove),
13290
+ updatedAt: serverTimestamp24()
13291
+ };
13292
+ return this.updateAppointment(appointmentId, updateData);
13293
+ }
13294
+ /**
13295
+ * Adds or updates review information for an appointment.
13296
+ */
13297
+ async addReviewToAppointment(appointmentId, reviewData) {
13298
+ console.log(
13299
+ `[APPOINTMENT_SERVICE] Adding review to appointment ${appointmentId}`
13300
+ );
13301
+ const newReviewInfo = {
13302
+ ...reviewData,
13303
+ reviewId: this.generateId(),
13304
+ reviewedAt: Timestamp28.now()
13305
+ };
13306
+ const updateData = {
13307
+ reviewInfo: newReviewInfo,
13308
+ updatedAt: serverTimestamp24()
13309
+ };
13310
+ return this.updateAppointment(appointmentId, updateData);
12873
13311
  }
12874
13312
  /**
12875
13313
  * Updates the payment status of an appointment.
12876
- *
12877
- * @param appointmentId ID of the appointment
12878
- * @param paymentStatus New payment status
12879
- * @param paymentTransactionId Optional transaction ID for the payment
12880
- * @returns The updated appointment
12881
13314
  */
12882
13315
  async updatePaymentStatus(appointmentId, paymentStatus, paymentTransactionId) {
12883
13316
  console.log(
@@ -12885,7 +13318,8 @@ var AppointmentService = class extends BaseService {
12885
13318
  );
12886
13319
  const updateData = {
12887
13320
  paymentStatus,
12888
- paymentTransactionId: paymentTransactionId || null
13321
+ paymentTransactionId: paymentTransactionId || null,
13322
+ updatedAt: serverTimestamp24()
12889
13323
  };
12890
13324
  return this.updateAppointment(appointmentId, updateData);
12891
13325
  }
@@ -12958,16 +13392,222 @@ var AppointmentService = class extends BaseService {
12958
13392
  }
12959
13393
  };
12960
13394
 
12961
- // src/backoffice/services/brand.service.ts
13395
+ // src/services/patient/patientRequirements.service.ts
12962
13396
  import {
12963
- addDoc as addDoc3,
12964
13397
  collection as collection26,
12965
- doc as doc27,
12966
- getDoc as getDoc29,
12967
13398
  getDocs as getDocs26,
12968
13399
  query as query26,
13400
+ where as where26,
13401
+ doc as doc27,
12969
13402
  updateDoc as updateDoc26,
12970
- where as where26
13403
+ Timestamp as Timestamp29,
13404
+ orderBy as orderBy13,
13405
+ limit as limit11,
13406
+ startAfter as startAfter11,
13407
+ getDoc as getDoc29
13408
+ } from "firebase/firestore";
13409
+
13410
+ // src/types/patient/patient-requirements.ts
13411
+ var PatientInstructionStatus = /* @__PURE__ */ ((PatientInstructionStatus2) => {
13412
+ PatientInstructionStatus2["PENDING_NOTIFICATION"] = "pendingNotification";
13413
+ PatientInstructionStatus2["ACTION_DUE"] = "actionDue";
13414
+ PatientInstructionStatus2["ACTION_TAKEN"] = "actionTaken";
13415
+ PatientInstructionStatus2["MISSED"] = "missed";
13416
+ PatientInstructionStatus2["CANCELLED"] = "cancelled";
13417
+ PatientInstructionStatus2["SKIPPED"] = "skipped";
13418
+ return PatientInstructionStatus2;
13419
+ })(PatientInstructionStatus || {});
13420
+ var PatientRequirementOverallStatus = /* @__PURE__ */ ((PatientRequirementOverallStatus2) => {
13421
+ PatientRequirementOverallStatus2["ACTIVE"] = "active";
13422
+ PatientRequirementOverallStatus2["ALL_INSTRUCTIONS_MET"] = "allInstructionsMet";
13423
+ PatientRequirementOverallStatus2["PARTIALLY_COMPLETED"] = "partiallyCompleted";
13424
+ PatientRequirementOverallStatus2["FAILED"] = "failed";
13425
+ PatientRequirementOverallStatus2["CANCELLED_APPOINTMENT"] = "cancelledAppointment";
13426
+ PatientRequirementOverallStatus2["SUPERSEDED_RESCHEDULE"] = "supersededReschedule";
13427
+ PatientRequirementOverallStatus2["FAILED_TO_PROCESS"] = "failedToProcess";
13428
+ return PatientRequirementOverallStatus2;
13429
+ })(PatientRequirementOverallStatus || {});
13430
+ var PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME = "patientRequirements";
13431
+
13432
+ // src/services/patient/patientRequirements.service.ts
13433
+ var PatientRequirementsService = class extends BaseService {
13434
+ constructor(db, auth, app) {
13435
+ super(db, auth, app);
13436
+ }
13437
+ getPatientRequirementsCollectionRef(patientId) {
13438
+ return collection26(
13439
+ this.db,
13440
+ `patients/${patientId}/${PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME}`
13441
+ );
13442
+ }
13443
+ getPatientRequirementDocRef(patientId, instanceId) {
13444
+ return doc27(
13445
+ this.getPatientRequirementsCollectionRef(patientId),
13446
+ instanceId
13447
+ );
13448
+ }
13449
+ /**
13450
+ * Gets a specific patient requirement instance by its ID.
13451
+ * @param patientId - The ID of the patient.
13452
+ * @param instanceId - The ID of the requirement instance.
13453
+ * @returns The patient requirement instance or null if not found.
13454
+ */
13455
+ async getPatientRequirementInstance(patientId, instanceId) {
13456
+ const docRef = this.getPatientRequirementDocRef(patientId, instanceId);
13457
+ const docSnap = await getDoc29(docRef);
13458
+ if (!docSnap.exists()) {
13459
+ return null;
13460
+ }
13461
+ const data = docSnap.data();
13462
+ return { id: docSnap.id, ...data };
13463
+ }
13464
+ /**
13465
+ * Retrieves patient requirement instances based on specified filters.
13466
+ * This is a flexible query method.
13467
+ *
13468
+ * @param patientId - The ID of the patient.
13469
+ * @param filters - Optional filters for appointmentId, overall statuses, instruction statuses, and due timeframes.
13470
+ * @param pageLimit - Optional limit for pagination.
13471
+ * @param lastVisible - Optional last document snapshot for pagination.
13472
+ * @returns A promise resolving to an array of matching patient requirement instances and the last document snapshot.
13473
+ */
13474
+ async getAllPatientRequirementInstances(patientId, filters, pageLimit = 20, lastVisible) {
13475
+ const collRef = this.getPatientRequirementsCollectionRef(patientId);
13476
+ let q = query26(collRef, orderBy13("createdAt", "desc"));
13477
+ const queryConstraints = [];
13478
+ if ((filters == null ? void 0 : filters.appointmentId) && filters.appointmentId !== "all") {
13479
+ queryConstraints.push(
13480
+ where26("appointmentId", "==", filters.appointmentId)
13481
+ );
13482
+ }
13483
+ if ((filters == null ? void 0 : filters.statuses) && filters.statuses.length > 0) {
13484
+ queryConstraints.push(where26("overallStatus", "in", filters.statuses));
13485
+ }
13486
+ if (lastVisible) {
13487
+ queryConstraints.push(startAfter11(lastVisible));
13488
+ }
13489
+ queryConstraints.push(limit11(pageLimit));
13490
+ q = query26(collRef, ...queryConstraints);
13491
+ const snapshot = await getDocs26(q);
13492
+ let requirements = snapshot.docs.map((docSnap) => {
13493
+ const data = docSnap.data();
13494
+ return { id: docSnap.id, ...data };
13495
+ });
13496
+ if ((filters == null ? void 0 : filters.instructionStatuses) && filters.instructionStatuses.length > 0) {
13497
+ requirements = requirements.filter(
13498
+ (req) => req.instructions.some(
13499
+ (instr) => filters.instructionStatuses.includes(instr.status)
13500
+ )
13501
+ );
13502
+ }
13503
+ if (filters == null ? void 0 : filters.dueBefore) {
13504
+ const dueBeforeMillis = filters.dueBefore.toMillis();
13505
+ requirements = requirements.filter(
13506
+ (req) => req.instructions.some(
13507
+ (instr) => instr.dueTime.toMillis() < dueBeforeMillis
13508
+ )
13509
+ );
13510
+ }
13511
+ if (filters == null ? void 0 : filters.dueAfter) {
13512
+ const dueAfterMillis = filters.dueAfter.toMillis();
13513
+ requirements = requirements.filter(
13514
+ (req) => req.instructions.some(
13515
+ (instr) => instr.dueTime.toMillis() > dueAfterMillis
13516
+ )
13517
+ );
13518
+ }
13519
+ const newLastVisible = snapshot.docs[snapshot.docs.length - 1] || null;
13520
+ return { requirements, lastDoc: newLastVisible };
13521
+ }
13522
+ /**
13523
+ * Marks a specific instruction within a PatientRequirementInstance as ACTION_TAKEN.
13524
+ * If all instructions are actioned, updates the overallStatus of the instance.
13525
+ *
13526
+ * @param patientId - The ID of the patient.
13527
+ * @param instanceId - The ID of the PatientRequirementInstance.
13528
+ * @param instructionId - The ID of the instruction to complete.
13529
+ * @returns The updated PatientRequirementInstance.
13530
+ * @throws Error if the instance or instruction is not found, or if the instruction is not in a completable state.
13531
+ */
13532
+ async completeInstruction(patientId, instanceId, instructionId) {
13533
+ const instanceRef = this.getPatientRequirementDocRef(patientId, instanceId);
13534
+ const instanceSnap = await getDoc29(instanceRef);
13535
+ if (!instanceSnap.exists()) {
13536
+ throw new Error(
13537
+ `PatientRequirementInstance ${instanceId} not found for patient ${patientId}.`
13538
+ );
13539
+ }
13540
+ const instanceData = instanceSnap.data();
13541
+ const instance = { id: instanceSnap.id, ...instanceData };
13542
+ const instructionIndex = instance.instructions.findIndex(
13543
+ (instr) => instr.instructionId === instructionId
13544
+ );
13545
+ if (instructionIndex === -1) {
13546
+ throw new Error(
13547
+ `Instruction ${instructionId} not found in instance ${instanceId}.`
13548
+ );
13549
+ }
13550
+ const instructionToUpdate = instance.instructions[instructionIndex];
13551
+ if (instructionToUpdate.status !== "pendingNotification" /* PENDING_NOTIFICATION */ && instructionToUpdate.status !== "actionDue" /* ACTION_DUE */ && instructionToUpdate.status !== "missed" /* MISSED */) {
13552
+ if (instructionToUpdate.status === "actionTaken" /* ACTION_TAKEN */) {
13553
+ console.warn(
13554
+ `Instruction ${instructionId} is already marked as ACTION_TAKEN.`
13555
+ );
13556
+ return instance;
13557
+ }
13558
+ throw new Error(
13559
+ `Instruction ${instructionId} is in status ${instructionToUpdate.status} and cannot be marked as completed.`
13560
+ );
13561
+ }
13562
+ const now = Timestamp29.now();
13563
+ const updatedInstructions = [...instance.instructions];
13564
+ updatedInstructions[instructionIndex] = {
13565
+ ...instructionToUpdate,
13566
+ status: "actionTaken" /* ACTION_TAKEN */,
13567
+ actionTakenAt: now,
13568
+ updatedAt: now
13569
+ };
13570
+ const allActionTaken = updatedInstructions.every(
13571
+ (instr) => instr.status === "actionTaken" /* ACTION_TAKEN */
13572
+ );
13573
+ let newOverallStatus = instance.overallStatus;
13574
+ if (allActionTaken) {
13575
+ newOverallStatus = "allInstructionsMet" /* ALL_INSTRUCTIONS_MET */;
13576
+ } else if (updatedInstructions.some(
13577
+ (instr) => instr.status === "actionTaken" /* ACTION_TAKEN */
13578
+ )) {
13579
+ newOverallStatus = "partiallyCompleted" /* PARTIALLY_COMPLETED */;
13580
+ }
13581
+ const updatePayload = {
13582
+ // Using a general type for updateDoc payload
13583
+ instructions: updatedInstructions,
13584
+ updatedAt: now
13585
+ };
13586
+ if (newOverallStatus !== instance.overallStatus) {
13587
+ updatePayload.overallStatus = newOverallStatus;
13588
+ }
13589
+ await updateDoc26(instanceRef, updatePayload);
13590
+ return {
13591
+ ...instance,
13592
+ instructions: updatedInstructions,
13593
+ updatedAt: now,
13594
+ overallStatus: newOverallStatus
13595
+ };
13596
+ }
13597
+ // Note: As per the request, full CRUD (create, direct update of instance, delete) is not part of this light service,
13598
+ // as those will be handled by Cloud Functions reacting to appointment lifecycle events.
13599
+ };
13600
+
13601
+ // src/backoffice/services/brand.service.ts
13602
+ import {
13603
+ addDoc as addDoc3,
13604
+ collection as collection27,
13605
+ doc as doc28,
13606
+ getDoc as getDoc30,
13607
+ getDocs as getDocs27,
13608
+ query as query27,
13609
+ updateDoc as updateDoc27,
13610
+ where as where27
12971
13611
  } from "firebase/firestore";
12972
13612
 
12973
13613
  // src/backoffice/types/brand.types.ts
@@ -12979,7 +13619,7 @@ var BrandService = class extends BaseService {
12979
13619
  * Gets reference to brands collection
12980
13620
  */
12981
13621
  getBrandsRef() {
12982
- return collection26(this.db, BRANDS_COLLECTION);
13622
+ return collection27(this.db, BRANDS_COLLECTION);
12983
13623
  }
12984
13624
  /**
12985
13625
  * Creates a new brand
@@ -12999,12 +13639,12 @@ var BrandService = class extends BaseService {
12999
13639
  * Gets all active brands
13000
13640
  */
13001
13641
  async getAll() {
13002
- const q = query26(this.getBrandsRef(), where26("isActive", "==", true));
13003
- const snapshot = await getDocs26(q);
13642
+ const q = query27(this.getBrandsRef(), where27("isActive", "==", true));
13643
+ const snapshot = await getDocs27(q);
13004
13644
  return snapshot.docs.map(
13005
- (doc32) => ({
13006
- id: doc32.id,
13007
- ...doc32.data()
13645
+ (doc33) => ({
13646
+ id: doc33.id,
13647
+ ...doc33.data()
13008
13648
  })
13009
13649
  );
13010
13650
  }
@@ -13016,8 +13656,8 @@ var BrandService = class extends BaseService {
13016
13656
  ...brand,
13017
13657
  updatedAt: /* @__PURE__ */ new Date()
13018
13658
  };
13019
- const docRef = doc27(this.getBrandsRef(), brandId);
13020
- await updateDoc26(docRef, updateData);
13659
+ const docRef = doc28(this.getBrandsRef(), brandId);
13660
+ await updateDoc27(docRef, updateData);
13021
13661
  return this.getById(brandId);
13022
13662
  }
13023
13663
  /**
@@ -13032,8 +13672,8 @@ var BrandService = class extends BaseService {
13032
13672
  * Gets a brand by ID
13033
13673
  */
13034
13674
  async getById(brandId) {
13035
- const docRef = doc27(this.getBrandsRef(), brandId);
13036
- const docSnap = await getDoc29(docRef);
13675
+ const docRef = doc28(this.getBrandsRef(), brandId);
13676
+ const docSnap = await getDoc30(docRef);
13037
13677
  if (!docSnap.exists()) return null;
13038
13678
  return {
13039
13679
  id: docSnap.id,
@@ -13045,13 +13685,13 @@ var BrandService = class extends BaseService {
13045
13685
  // src/backoffice/services/category.service.ts
13046
13686
  import {
13047
13687
  addDoc as addDoc4,
13048
- collection as collection27,
13049
- doc as doc28,
13050
- getDoc as getDoc30,
13051
- getDocs as getDocs27,
13052
- query as query27,
13053
- updateDoc as updateDoc27,
13054
- where as where27
13688
+ collection as collection28,
13689
+ doc as doc29,
13690
+ getDoc as getDoc31,
13691
+ getDocs as getDocs28,
13692
+ query as query28,
13693
+ updateDoc as updateDoc28,
13694
+ where as where28
13055
13695
  } from "firebase/firestore";
13056
13696
 
13057
13697
  // src/backoffice/types/category.types.ts
@@ -13063,7 +13703,7 @@ var CategoryService = class extends BaseService {
13063
13703
  * Referenca na Firestore kolekciju kategorija
13064
13704
  */
13065
13705
  get categoriesRef() {
13066
- return collection27(this.db, CATEGORIES_COLLECTION);
13706
+ return collection28(this.db, CATEGORIES_COLLECTION);
13067
13707
  }
13068
13708
  /**
13069
13709
  * Kreira novu kategoriju u sistemu
@@ -13086,12 +13726,12 @@ var CategoryService = class extends BaseService {
13086
13726
  * @returns Lista aktivnih kategorija
13087
13727
  */
13088
13728
  async getAll() {
13089
- const q = query27(this.categoriesRef, where27("isActive", "==", true));
13090
- const snapshot = await getDocs27(q);
13729
+ const q = query28(this.categoriesRef, where28("isActive", "==", true));
13730
+ const snapshot = await getDocs28(q);
13091
13731
  return snapshot.docs.map(
13092
- (doc32) => ({
13093
- id: doc32.id,
13094
- ...doc32.data()
13732
+ (doc33) => ({
13733
+ id: doc33.id,
13734
+ ...doc33.data()
13095
13735
  })
13096
13736
  );
13097
13737
  }
@@ -13101,16 +13741,16 @@ var CategoryService = class extends BaseService {
13101
13741
  * @returns Lista kategorija koje pripadaju traženoj familiji
13102
13742
  */
13103
13743
  async getAllByFamily(family) {
13104
- const q = query27(
13744
+ const q = query28(
13105
13745
  this.categoriesRef,
13106
- where27("family", "==", family),
13107
- where27("isActive", "==", true)
13746
+ where28("family", "==", family),
13747
+ where28("isActive", "==", true)
13108
13748
  );
13109
- const snapshot = await getDocs27(q);
13749
+ const snapshot = await getDocs28(q);
13110
13750
  return snapshot.docs.map(
13111
- (doc32) => ({
13112
- id: doc32.id,
13113
- ...doc32.data()
13751
+ (doc33) => ({
13752
+ id: doc33.id,
13753
+ ...doc33.data()
13114
13754
  })
13115
13755
  );
13116
13756
  }
@@ -13125,8 +13765,8 @@ var CategoryService = class extends BaseService {
13125
13765
  ...category,
13126
13766
  updatedAt: /* @__PURE__ */ new Date()
13127
13767
  };
13128
- const docRef = doc28(this.categoriesRef, id);
13129
- await updateDoc27(docRef, updateData);
13768
+ const docRef = doc29(this.categoriesRef, id);
13769
+ await updateDoc28(docRef, updateData);
13130
13770
  return this.getById(id);
13131
13771
  }
13132
13772
  /**
@@ -13142,8 +13782,8 @@ var CategoryService = class extends BaseService {
13142
13782
  * @returns Kategorija ili null ako ne postoji
13143
13783
  */
13144
13784
  async getById(id) {
13145
- const docRef = doc28(this.categoriesRef, id);
13146
- const docSnap = await getDoc30(docRef);
13785
+ const docRef = doc29(this.categoriesRef, id);
13786
+ const docSnap = await getDoc31(docRef);
13147
13787
  if (!docSnap.exists()) return null;
13148
13788
  return {
13149
13789
  id: docSnap.id,
@@ -13155,13 +13795,13 @@ var CategoryService = class extends BaseService {
13155
13795
  // src/backoffice/services/subcategory.service.ts
13156
13796
  import {
13157
13797
  addDoc as addDoc5,
13158
- collection as collection28,
13159
- doc as doc29,
13160
- getDoc as getDoc31,
13161
- getDocs as getDocs28,
13162
- query as query28,
13163
- updateDoc as updateDoc28,
13164
- where as where28
13798
+ collection as collection29,
13799
+ doc as doc30,
13800
+ getDoc as getDoc32,
13801
+ getDocs as getDocs29,
13802
+ query as query29,
13803
+ updateDoc as updateDoc29,
13804
+ where as where29
13165
13805
  } from "firebase/firestore";
13166
13806
 
13167
13807
  // src/backoffice/types/subcategory.types.ts
@@ -13174,7 +13814,7 @@ var SubcategoryService = class extends BaseService {
13174
13814
  * @param categoryId - ID roditeljske kategorije
13175
13815
  */
13176
13816
  getSubcategoriesRef(categoryId) {
13177
- return collection28(
13817
+ return collection29(
13178
13818
  this.db,
13179
13819
  CATEGORIES_COLLECTION,
13180
13820
  categoryId,
@@ -13208,15 +13848,15 @@ var SubcategoryService = class extends BaseService {
13208
13848
  * @returns Lista aktivnih podkategorija
13209
13849
  */
13210
13850
  async getAllByCategoryId(categoryId) {
13211
- const q = query28(
13851
+ const q = query29(
13212
13852
  this.getSubcategoriesRef(categoryId),
13213
- where28("isActive", "==", true)
13853
+ where29("isActive", "==", true)
13214
13854
  );
13215
- const snapshot = await getDocs28(q);
13855
+ const snapshot = await getDocs29(q);
13216
13856
  return snapshot.docs.map(
13217
- (doc32) => ({
13218
- id: doc32.id,
13219
- ...doc32.data()
13857
+ (doc33) => ({
13858
+ id: doc33.id,
13859
+ ...doc33.data()
13220
13860
  })
13221
13861
  );
13222
13862
  }
@@ -13232,8 +13872,8 @@ var SubcategoryService = class extends BaseService {
13232
13872
  ...subcategory,
13233
13873
  updatedAt: /* @__PURE__ */ new Date()
13234
13874
  };
13235
- const docRef = doc29(this.getSubcategoriesRef(categoryId), subcategoryId);
13236
- await updateDoc28(docRef, updateData);
13875
+ const docRef = doc30(this.getSubcategoriesRef(categoryId), subcategoryId);
13876
+ await updateDoc29(docRef, updateData);
13237
13877
  return this.getById(categoryId, subcategoryId);
13238
13878
  }
13239
13879
  /**
@@ -13251,8 +13891,8 @@ var SubcategoryService = class extends BaseService {
13251
13891
  * @returns Podkategorija ili null ako ne postoji
13252
13892
  */
13253
13893
  async getById(categoryId, subcategoryId) {
13254
- const docRef = doc29(this.getSubcategoriesRef(categoryId), subcategoryId);
13255
- const docSnap = await getDoc31(docRef);
13894
+ const docRef = doc30(this.getSubcategoriesRef(categoryId), subcategoryId);
13895
+ const docSnap = await getDoc32(docRef);
13256
13896
  if (!docSnap.exists()) return null;
13257
13897
  return {
13258
13898
  id: docSnap.id,
@@ -13264,15 +13904,15 @@ var SubcategoryService = class extends BaseService {
13264
13904
  // src/backoffice/services/technology.service.ts
13265
13905
  import {
13266
13906
  addDoc as addDoc6,
13267
- collection as collection29,
13268
- doc as doc30,
13269
- getDoc as getDoc32,
13270
- getDocs as getDocs29,
13271
- query as query29,
13272
- updateDoc as updateDoc29,
13273
- where as where29,
13274
- arrayUnion as arrayUnion8,
13275
- arrayRemove as arrayRemove7
13907
+ collection as collection30,
13908
+ doc as doc31,
13909
+ getDoc as getDoc33,
13910
+ getDocs as getDocs30,
13911
+ query as query30,
13912
+ updateDoc as updateDoc30,
13913
+ where as where30,
13914
+ arrayUnion as arrayUnion9,
13915
+ arrayRemove as arrayRemove8
13276
13916
  } from "firebase/firestore";
13277
13917
  var DEFAULT_CERTIFICATION_REQUIREMENT = {
13278
13918
  minimumLevel: "aesthetician" /* AESTHETICIAN */,
@@ -13283,7 +13923,7 @@ var TechnologyService = class extends BaseService {
13283
13923
  * Vraća referencu na Firestore kolekciju tehnologija
13284
13924
  */
13285
13925
  getTechnologiesRef() {
13286
- return collection29(this.db, TECHNOLOGIES_COLLECTION);
13926
+ return collection30(this.db, TECHNOLOGIES_COLLECTION);
13287
13927
  }
13288
13928
  /**
13289
13929
  * Kreira novu tehnologiju
@@ -13314,12 +13954,12 @@ var TechnologyService = class extends BaseService {
13314
13954
  * @returns Lista aktivnih tehnologija
13315
13955
  */
13316
13956
  async getAll() {
13317
- const q = query29(this.getTechnologiesRef(), where29("isActive", "==", true));
13318
- const snapshot = await getDocs29(q);
13957
+ const q = query30(this.getTechnologiesRef(), where30("isActive", "==", true));
13958
+ const snapshot = await getDocs30(q);
13319
13959
  return snapshot.docs.map(
13320
- (doc32) => ({
13321
- id: doc32.id,
13322
- ...doc32.data()
13960
+ (doc33) => ({
13961
+ id: doc33.id,
13962
+ ...doc33.data()
13323
13963
  })
13324
13964
  );
13325
13965
  }
@@ -13329,16 +13969,16 @@ var TechnologyService = class extends BaseService {
13329
13969
  * @returns Lista aktivnih tehnologija
13330
13970
  */
13331
13971
  async getAllByFamily(family) {
13332
- const q = query29(
13972
+ const q = query30(
13333
13973
  this.getTechnologiesRef(),
13334
- where29("isActive", "==", true),
13335
- where29("family", "==", family)
13974
+ where30("isActive", "==", true),
13975
+ where30("family", "==", family)
13336
13976
  );
13337
- const snapshot = await getDocs29(q);
13977
+ const snapshot = await getDocs30(q);
13338
13978
  return snapshot.docs.map(
13339
- (doc32) => ({
13340
- id: doc32.id,
13341
- ...doc32.data()
13979
+ (doc33) => ({
13980
+ id: doc33.id,
13981
+ ...doc33.data()
13342
13982
  })
13343
13983
  );
13344
13984
  }
@@ -13348,16 +13988,16 @@ var TechnologyService = class extends BaseService {
13348
13988
  * @returns Lista aktivnih tehnologija
13349
13989
  */
13350
13990
  async getAllByCategoryId(categoryId) {
13351
- const q = query29(
13991
+ const q = query30(
13352
13992
  this.getTechnologiesRef(),
13353
- where29("isActive", "==", true),
13354
- where29("categoryId", "==", categoryId)
13993
+ where30("isActive", "==", true),
13994
+ where30("categoryId", "==", categoryId)
13355
13995
  );
13356
- const snapshot = await getDocs29(q);
13996
+ const snapshot = await getDocs30(q);
13357
13997
  return snapshot.docs.map(
13358
- (doc32) => ({
13359
- id: doc32.id,
13360
- ...doc32.data()
13998
+ (doc33) => ({
13999
+ id: doc33.id,
14000
+ ...doc33.data()
13361
14001
  })
13362
14002
  );
13363
14003
  }
@@ -13367,16 +14007,16 @@ var TechnologyService = class extends BaseService {
13367
14007
  * @returns Lista aktivnih tehnologija
13368
14008
  */
13369
14009
  async getAllBySubcategoryId(subcategoryId) {
13370
- const q = query29(
14010
+ const q = query30(
13371
14011
  this.getTechnologiesRef(),
13372
- where29("isActive", "==", true),
13373
- where29("subcategoryId", "==", subcategoryId)
14012
+ where30("isActive", "==", true),
14013
+ where30("subcategoryId", "==", subcategoryId)
13374
14014
  );
13375
- const snapshot = await getDocs29(q);
14015
+ const snapshot = await getDocs30(q);
13376
14016
  return snapshot.docs.map(
13377
- (doc32) => ({
13378
- id: doc32.id,
13379
- ...doc32.data()
14017
+ (doc33) => ({
14018
+ id: doc33.id,
14019
+ ...doc33.data()
13380
14020
  })
13381
14021
  );
13382
14022
  }
@@ -13391,8 +14031,8 @@ var TechnologyService = class extends BaseService {
13391
14031
  ...technology,
13392
14032
  updatedAt: /* @__PURE__ */ new Date()
13393
14033
  };
13394
- const docRef = doc30(this.getTechnologiesRef(), technologyId);
13395
- await updateDoc29(docRef, updateData);
14034
+ const docRef = doc31(this.getTechnologiesRef(), technologyId);
14035
+ await updateDoc30(docRef, updateData);
13396
14036
  return this.getById(technologyId);
13397
14037
  }
13398
14038
  /**
@@ -13410,8 +14050,8 @@ var TechnologyService = class extends BaseService {
13410
14050
  * @returns Tehnologija ili null ako ne postoji
13411
14051
  */
13412
14052
  async getById(technologyId) {
13413
- const docRef = doc30(this.getTechnologiesRef(), technologyId);
13414
- const docSnap = await getDoc32(docRef);
14053
+ const docRef = doc31(this.getTechnologiesRef(), technologyId);
14054
+ const docSnap = await getDoc33(docRef);
13415
14055
  if (!docSnap.exists()) return null;
13416
14056
  return {
13417
14057
  id: docSnap.id,
@@ -13425,10 +14065,10 @@ var TechnologyService = class extends BaseService {
13425
14065
  * @returns Ažurirana tehnologija sa novim zahtevom
13426
14066
  */
13427
14067
  async addRequirement(technologyId, requirement) {
13428
- const docRef = doc30(this.getTechnologiesRef(), technologyId);
14068
+ const docRef = doc31(this.getTechnologiesRef(), technologyId);
13429
14069
  const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
13430
- await updateDoc29(docRef, {
13431
- [requirementType]: arrayUnion8(requirement),
14070
+ await updateDoc30(docRef, {
14071
+ [requirementType]: arrayUnion9(requirement),
13432
14072
  updatedAt: /* @__PURE__ */ new Date()
13433
14073
  });
13434
14074
  return this.getById(technologyId);
@@ -13440,10 +14080,10 @@ var TechnologyService = class extends BaseService {
13440
14080
  * @returns Ažurirana tehnologija bez uklonjenog zahteva
13441
14081
  */
13442
14082
  async removeRequirement(technologyId, requirement) {
13443
- const docRef = doc30(this.getTechnologiesRef(), technologyId);
14083
+ const docRef = doc31(this.getTechnologiesRef(), technologyId);
13444
14084
  const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
13445
- await updateDoc29(docRef, {
13446
- [requirementType]: arrayRemove7(requirement),
14085
+ await updateDoc30(docRef, {
14086
+ [requirementType]: arrayRemove8(requirement),
13447
14087
  updatedAt: /* @__PURE__ */ new Date()
13448
14088
  });
13449
14089
  return this.getById(technologyId);
@@ -13480,9 +14120,9 @@ var TechnologyService = class extends BaseService {
13480
14120
  * @returns Ažurirana tehnologija
13481
14121
  */
13482
14122
  async addBlockingCondition(technologyId, condition) {
13483
- const docRef = doc30(this.getTechnologiesRef(), technologyId);
13484
- await updateDoc29(docRef, {
13485
- blockingConditions: arrayUnion8(condition),
14123
+ const docRef = doc31(this.getTechnologiesRef(), technologyId);
14124
+ await updateDoc30(docRef, {
14125
+ blockingConditions: arrayUnion9(condition),
13486
14126
  updatedAt: /* @__PURE__ */ new Date()
13487
14127
  });
13488
14128
  return this.getById(technologyId);
@@ -13494,9 +14134,9 @@ var TechnologyService = class extends BaseService {
13494
14134
  * @returns Ažurirana tehnologija
13495
14135
  */
13496
14136
  async removeBlockingCondition(technologyId, condition) {
13497
- const docRef = doc30(this.getTechnologiesRef(), technologyId);
13498
- await updateDoc29(docRef, {
13499
- blockingConditions: arrayRemove7(condition),
14137
+ const docRef = doc31(this.getTechnologiesRef(), technologyId);
14138
+ await updateDoc30(docRef, {
14139
+ blockingConditions: arrayRemove8(condition),
13500
14140
  updatedAt: /* @__PURE__ */ new Date()
13501
14141
  });
13502
14142
  return this.getById(technologyId);
@@ -13508,9 +14148,9 @@ var TechnologyService = class extends BaseService {
13508
14148
  * @returns Ažurirana tehnologija
13509
14149
  */
13510
14150
  async addContraindication(technologyId, contraindication) {
13511
- const docRef = doc30(this.getTechnologiesRef(), technologyId);
13512
- await updateDoc29(docRef, {
13513
- contraindications: arrayUnion8(contraindication),
14151
+ const docRef = doc31(this.getTechnologiesRef(), technologyId);
14152
+ await updateDoc30(docRef, {
14153
+ contraindications: arrayUnion9(contraindication),
13514
14154
  updatedAt: /* @__PURE__ */ new Date()
13515
14155
  });
13516
14156
  return this.getById(technologyId);
@@ -13522,9 +14162,9 @@ var TechnologyService = class extends BaseService {
13522
14162
  * @returns Ažurirana tehnologija
13523
14163
  */
13524
14164
  async removeContraindication(technologyId, contraindication) {
13525
- const docRef = doc30(this.getTechnologiesRef(), technologyId);
13526
- await updateDoc29(docRef, {
13527
- contraindications: arrayRemove7(contraindication),
14165
+ const docRef = doc31(this.getTechnologiesRef(), technologyId);
14166
+ await updateDoc30(docRef, {
14167
+ contraindications: arrayRemove8(contraindication),
13528
14168
  updatedAt: /* @__PURE__ */ new Date()
13529
14169
  });
13530
14170
  return this.getById(technologyId);
@@ -13536,9 +14176,9 @@ var TechnologyService = class extends BaseService {
13536
14176
  * @returns Ažurirana tehnologija
13537
14177
  */
13538
14178
  async addBenefit(technologyId, benefit) {
13539
- const docRef = doc30(this.getTechnologiesRef(), technologyId);
13540
- await updateDoc29(docRef, {
13541
- benefits: arrayUnion8(benefit),
14179
+ const docRef = doc31(this.getTechnologiesRef(), technologyId);
14180
+ await updateDoc30(docRef, {
14181
+ benefits: arrayUnion9(benefit),
13542
14182
  updatedAt: /* @__PURE__ */ new Date()
13543
14183
  });
13544
14184
  return this.getById(technologyId);
@@ -13550,9 +14190,9 @@ var TechnologyService = class extends BaseService {
13550
14190
  * @returns Ažurirana tehnologija
13551
14191
  */
13552
14192
  async removeBenefit(technologyId, benefit) {
13553
- const docRef = doc30(this.getTechnologiesRef(), technologyId);
13554
- await updateDoc29(docRef, {
13555
- benefits: arrayRemove7(benefit),
14193
+ const docRef = doc31(this.getTechnologiesRef(), technologyId);
14194
+ await updateDoc30(docRef, {
14195
+ benefits: arrayRemove8(benefit),
13556
14196
  updatedAt: /* @__PURE__ */ new Date()
13557
14197
  });
13558
14198
  return this.getById(technologyId);
@@ -13591,8 +14231,8 @@ var TechnologyService = class extends BaseService {
13591
14231
  * @returns Ažurirana tehnologija
13592
14232
  */
13593
14233
  async updateCertificationRequirement(technologyId, certificationRequirement) {
13594
- const docRef = doc30(this.getTechnologiesRef(), technologyId);
13595
- await updateDoc29(docRef, {
14234
+ const docRef = doc31(this.getTechnologiesRef(), technologyId);
14235
+ await updateDoc30(docRef, {
13596
14236
  certificationRequirement,
13597
14237
  updatedAt: /* @__PURE__ */ new Date()
13598
14238
  });
@@ -13694,13 +14334,13 @@ var TechnologyService = class extends BaseService {
13694
14334
  // src/backoffice/services/product.service.ts
13695
14335
  import {
13696
14336
  addDoc as addDoc7,
13697
- collection as collection30,
13698
- doc as doc31,
13699
- getDoc as getDoc33,
13700
- getDocs as getDocs30,
13701
- query as query30,
13702
- updateDoc as updateDoc30,
13703
- where as where30
14337
+ collection as collection31,
14338
+ doc as doc32,
14339
+ getDoc as getDoc34,
14340
+ getDocs as getDocs31,
14341
+ query as query31,
14342
+ updateDoc as updateDoc31,
14343
+ where as where31
13704
14344
  } from "firebase/firestore";
13705
14345
 
13706
14346
  // src/backoffice/types/product.types.ts
@@ -13714,7 +14354,7 @@ var ProductService = class extends BaseService {
13714
14354
  * @returns Firestore collection reference
13715
14355
  */
13716
14356
  getProductsRef(technologyId) {
13717
- return collection30(
14357
+ return collection31(
13718
14358
  this.db,
13719
14359
  TECHNOLOGIES_COLLECTION,
13720
14360
  technologyId,
@@ -13744,15 +14384,15 @@ var ProductService = class extends BaseService {
13744
14384
  * Gets all products for a technology
13745
14385
  */
13746
14386
  async getAllByTechnology(technologyId) {
13747
- const q = query30(
14387
+ const q = query31(
13748
14388
  this.getProductsRef(technologyId),
13749
- where30("isActive", "==", true)
14389
+ where31("isActive", "==", true)
13750
14390
  );
13751
- const snapshot = await getDocs30(q);
14391
+ const snapshot = await getDocs31(q);
13752
14392
  return snapshot.docs.map(
13753
- (doc32) => ({
13754
- id: doc32.id,
13755
- ...doc32.data()
14393
+ (doc33) => ({
14394
+ id: doc33.id,
14395
+ ...doc33.data()
13756
14396
  })
13757
14397
  );
13758
14398
  }
@@ -13760,21 +14400,21 @@ var ProductService = class extends BaseService {
13760
14400
  * Gets all products for a brand by filtering through all technologies
13761
14401
  */
13762
14402
  async getAllByBrand(brandId) {
13763
- const allTechnologiesRef = collection30(this.db, TECHNOLOGIES_COLLECTION);
13764
- const technologiesSnapshot = await getDocs30(allTechnologiesRef);
14403
+ const allTechnologiesRef = collection31(this.db, TECHNOLOGIES_COLLECTION);
14404
+ const technologiesSnapshot = await getDocs31(allTechnologiesRef);
13765
14405
  const products = [];
13766
14406
  for (const techDoc of technologiesSnapshot.docs) {
13767
- const q = query30(
14407
+ const q = query31(
13768
14408
  this.getProductsRef(techDoc.id),
13769
- where30("brandId", "==", brandId),
13770
- where30("isActive", "==", true)
14409
+ where31("brandId", "==", brandId),
14410
+ where31("isActive", "==", true)
13771
14411
  );
13772
- const snapshot = await getDocs30(q);
14412
+ const snapshot = await getDocs31(q);
13773
14413
  products.push(
13774
14414
  ...snapshot.docs.map(
13775
- (doc32) => ({
13776
- id: doc32.id,
13777
- ...doc32.data()
14415
+ (doc33) => ({
14416
+ id: doc33.id,
14417
+ ...doc33.data()
13778
14418
  })
13779
14419
  )
13780
14420
  );
@@ -13789,8 +14429,8 @@ var ProductService = class extends BaseService {
13789
14429
  ...product,
13790
14430
  updatedAt: /* @__PURE__ */ new Date()
13791
14431
  };
13792
- const docRef = doc31(this.getProductsRef(technologyId), productId);
13793
- await updateDoc30(docRef, updateData);
14432
+ const docRef = doc32(this.getProductsRef(technologyId), productId);
14433
+ await updateDoc31(docRef, updateData);
13794
14434
  return this.getById(technologyId, productId);
13795
14435
  }
13796
14436
  /**
@@ -13805,8 +14445,8 @@ var ProductService = class extends BaseService {
13805
14445
  * Gets a product by ID
13806
14446
  */
13807
14447
  async getById(technologyId, productId) {
13808
- const docRef = doc31(this.getProductsRef(technologyId), productId);
13809
- const docSnap = await getDoc33(docRef);
14448
+ const docRef = doc32(this.getProductsRef(technologyId), productId);
14449
+ const docSnap = await getDoc34(docRef);
13810
14450
  if (!docSnap.exists()) return null;
13811
14451
  return {
13812
14452
  id: docSnap.id,
@@ -13835,14 +14475,14 @@ var baseNotificationSchema = z24.object({
13835
14475
  userRole: z24.nativeEnum(UserRole)
13836
14476
  });
13837
14477
  var preRequirementNotificationSchema = baseNotificationSchema.extend({
13838
- notificationType: z24.literal("preRequirement" /* PRE_REQUIREMENT */),
14478
+ notificationType: z24.literal("requirementInstructionDue" /* REQUIREMENT_INSTRUCTION_DUE */),
13839
14479
  treatmentId: z24.string(),
13840
14480
  requirements: z24.array(z24.string()),
13841
14481
  deadline: z24.any()
13842
14482
  // Timestamp
13843
14483
  });
13844
14484
  var postRequirementNotificationSchema = baseNotificationSchema.extend({
13845
- notificationType: z24.literal("postRequirement" /* POST_REQUIREMENT */),
14485
+ notificationType: z24.literal("requirementInstructionDue" /* REQUIREMENT_INSTRUCTION_DUE */),
13846
14486
  treatmentId: z24.string(),
13847
14487
  requirements: z24.array(z24.string()),
13848
14488
  deadline: z24.any()
@@ -13857,7 +14497,7 @@ var appointmentReminderNotificationSchema = baseNotificationSchema.extend({
13857
14497
  doctorName: z24.string()
13858
14498
  });
13859
14499
  var appointmentNotificationSchema = baseNotificationSchema.extend({
13860
- notificationType: z24.literal("appointmentNotification" /* APPOINTMENT_NOTIFICATION */),
14500
+ notificationType: z24.literal("appointmentStatusChange" /* APPOINTMENT_STATUS_CHANGE */),
13861
14501
  appointmentId: z24.string(),
13862
14502
  appointmentStatus: z24.string(),
13863
14503
  previousStatus: z24.string(),
@@ -13953,9 +14593,13 @@ export {
13953
14593
  PATIENT_LOCATION_INFO_COLLECTION,
13954
14594
  PATIENT_MEDICAL_HISTORY_COLLECTION,
13955
14595
  PATIENT_MEDICAL_INFO_COLLECTION,
14596
+ PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME,
13956
14597
  PATIENT_SENSITIVE_INFO_COLLECTION,
13957
14598
  PRACTITIONERS_COLLECTION,
13958
14599
  PROCEDURES_COLLECTION,
14600
+ PatientInstructionStatus,
14601
+ PatientRequirementOverallStatus,
14602
+ PatientRequirementsService,
13959
14603
  PatientService,
13960
14604
  PaymentStatus,
13961
14605
  PracticeType,
@@ -14020,6 +14664,7 @@ export {
14020
14664
  createDefaultClinicGroupSchema,
14021
14665
  createDocumentTemplateSchema,
14022
14666
  createDraftPractitionerSchema,
14667
+ createFilledDocumentDataSchema,
14023
14668
  createPatientLocationInfoSchema,
14024
14669
  createPatientMedicalInfoSchema,
14025
14670
  createPatientProfileSchema,
@@ -14035,6 +14680,8 @@ export {
14035
14680
  documentTemplateSchema,
14036
14681
  emailSchema,
14037
14682
  emergencyContactSchema,
14683
+ filledDocumentSchema,
14684
+ filledDocumentStatusSchema,
14038
14685
  gamificationSchema,
14039
14686
  getFirebaseApp,
14040
14687
  getFirebaseAuth,
@@ -14084,6 +14731,7 @@ export {
14084
14731
  updateClinicSchema,
14085
14732
  updateContraindicationSchema,
14086
14733
  updateDocumentTemplateSchema,
14734
+ updateFilledDocumentDataSchema,
14087
14735
  updateMedicationSchema,
14088
14736
  updatePatientMedicalInfoSchema,
14089
14737
  updateVitalStatsSchema,