@blackcode_sa/metaestetics-api 1.6.3 → 1.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/index.d.mts +439 -25
- package/dist/admin/index.d.ts +439 -25
- package/dist/admin/index.js +36107 -2493
- package/dist/admin/index.mjs +36093 -2461
- package/dist/backoffice/index.d.mts +254 -1
- package/dist/backoffice/index.d.ts +254 -1
- package/dist/backoffice/index.js +86 -12
- package/dist/backoffice/index.mjs +86 -13
- package/dist/index.d.mts +1434 -621
- package/dist/index.d.ts +1434 -621
- package/dist/index.js +1381 -970
- package/dist/index.mjs +1433 -1016
- package/package.json +1 -1
- package/src/admin/aggregation/appointment/appointment.aggregation.service.ts +321 -0
- package/src/admin/booking/booking.admin.ts +376 -3
- package/src/admin/index.ts +15 -1
- package/src/admin/notifications/notifications.admin.ts +1 -1
- package/src/admin/requirements/README.md +128 -0
- package/src/admin/requirements/patient-requirements.admin.service.ts +482 -0
- package/src/backoffice/types/product.types.ts +2 -0
- package/src/index.ts +16 -1
- package/src/services/appointment/appointment.service.ts +386 -250
- package/src/services/clinic/clinic-admin.service.ts +3 -0
- package/src/services/clinic/clinic-group.service.ts +8 -0
- package/src/services/documentation-templates/documentation-template.service.ts +24 -16
- package/src/services/documentation-templates/filled-document.service.ts +253 -136
- package/src/services/patient/patientRequirements.service.ts +285 -0
- package/src/services/procedure/procedure.service.ts +1 -0
- package/src/types/appointment/index.ts +136 -11
- package/src/types/documentation-templates/index.ts +34 -2
- package/src/types/notifications/README.md +77 -0
- package/src/types/notifications/index.ts +154 -27
- package/src/types/patient/patient-requirements.ts +81 -0
- package/src/types/procedure/index.ts +7 -0
- package/src/validations/appointment.schema.ts +298 -62
- package/src/validations/documentation-templates/template.schema.ts +55 -0
- package/src/validations/documentation-templates.schema.ts +9 -14
- package/src/validations/notification.schema.ts +3 -3
- package/src/validations/patient/patient-requirements.schema.ts +75 -0
- package/src/validations/procedure.schema.ts +3 -0
package/dist/index.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["
|
|
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["
|
|
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
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
+
clinicBranchId: z2.string().min(MIN_STRING_LENGTH, "Clinic branch ID is required"),
|
|
344
|
+
practitionerId: z2.string().min(MIN_STRING_LENGTH, "Practitioner ID is required"),
|
|
345
|
+
patientId: z2.string().min(MIN_STRING_LENGTH, "Patient ID is required"),
|
|
346
|
+
procedureId: z2.string().min(MIN_STRING_LENGTH, "Procedure ID is required"),
|
|
347
|
+
appointmentStartTime: z2.any().refine(
|
|
348
|
+
(val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
|
|
349
|
+
"Appointment start time must be a valid timestamp or Date object"
|
|
37
350
|
),
|
|
38
|
-
appointmentEndTime:
|
|
39
|
-
(val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0,
|
|
40
|
-
"Appointment end time must be a valid timestamp"
|
|
351
|
+
appointmentEndTime: z2.any().refine(
|
|
352
|
+
(val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || typeof val === "number",
|
|
353
|
+
"Appointment end time must be a valid timestamp or Date object"
|
|
41
354
|
),
|
|
42
|
-
cost:
|
|
43
|
-
currency:
|
|
44
|
-
patientNotes:
|
|
45
|
-
initialStatus:
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}).optional().default("unpaid" /* UNPAID */)
|
|
355
|
+
cost: z2.number().min(0, "Cost must be a non-negative number"),
|
|
356
|
+
currency: z2.string().min(1, "Currency is required"),
|
|
357
|
+
patientNotes: z2.string().max(MAX_STRING_LENGTH, "Patient notes too long").nullable().optional(),
|
|
358
|
+
initialStatus: appointmentStatusSchema,
|
|
359
|
+
initialPaymentStatus: paymentStatusSchema.optional().default("unpaid" /* UNPAID */)
|
|
360
|
+
}).refine((data) => data.appointmentEndTime > data.appointmentStartTime, {
|
|
361
|
+
message: "Appointment end time must be after start time",
|
|
362
|
+
path: ["appointmentEndTime"]
|
|
51
363
|
});
|
|
52
|
-
var updateAppointmentSchema =
|
|
53
|
-
status:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
364
|
+
var updateAppointmentSchema = z2.object({
|
|
365
|
+
status: appointmentStatusSchema.optional(),
|
|
366
|
+
confirmationTime: z2.any().optional().nullable(),
|
|
367
|
+
cancellationTime: z2.any().optional().nullable(),
|
|
368
|
+
rescheduleTime: z2.any().optional().nullable(),
|
|
369
|
+
procedureActualStartTime: z2.any().optional().nullable(),
|
|
370
|
+
actualDurationMinutes: z2.number().int().positive("Duration must be a positive integer").optional(),
|
|
371
|
+
cancellationReason: z2.string().max(MAX_STRING_LENGTH, "Cancellation reason too long").nullable().optional(),
|
|
372
|
+
canceledBy: z2.enum(["patient", "clinic", "practitioner", "system"]).optional(),
|
|
373
|
+
internalNotes: z2.string().max(MAX_STRING_LENGTH_LONG, "Internal notes too long").nullable().optional(),
|
|
374
|
+
patientNotes: z2.any().optional().nullable(),
|
|
375
|
+
paymentStatus: paymentStatusSchema.optional(),
|
|
376
|
+
paymentTransactionId: z2.any().optional().nullable(),
|
|
377
|
+
completedPreRequirements: z2.union([z2.array(z2.string()), z2.any()]).optional(),
|
|
378
|
+
completedPostRequirements: z2.union([z2.array(z2.string()), z2.any()]).optional(),
|
|
379
|
+
linkedFormIds: 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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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 =
|
|
83
|
-
patientId:
|
|
84
|
-
practitionerId:
|
|
85
|
-
clinicBranchId:
|
|
86
|
-
startDate:
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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:
|
|
93
|
-
startAfter:
|
|
441
|
+
limit: z2.number().positive().int().optional().default(20),
|
|
442
|
+
startAfter: z2.any().optional()
|
|
94
443
|
}).refine(
|
|
95
444
|
(data) => {
|
|
96
|
-
|
|
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: "
|
|
100
|
-
path: ["
|
|
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
|
|
1456
|
-
if (!
|
|
1457
|
-
const medicalInfo =
|
|
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
|
|
1474
|
-
if (!
|
|
1475
|
-
const medicalInfo =
|
|
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
|
|
1501
|
-
if (!
|
|
1502
|
-
const medicalInfo =
|
|
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
|
|
1519
|
-
if (!
|
|
1520
|
-
const medicalInfo =
|
|
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
|
|
1546
|
-
if (!
|
|
1547
|
-
const medicalInfo =
|
|
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
|
|
1564
|
-
if (!
|
|
1565
|
-
const medicalInfo =
|
|
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
|
|
1591
|
-
if (!
|
|
1592
|
-
const medicalInfo =
|
|
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
|
|
1609
|
-
if (!
|
|
1610
|
-
const medicalInfo =
|
|
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((
|
|
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((
|
|
1913
|
-
patients.push(
|
|
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((
|
|
2147
|
-
patients.push(
|
|
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((
|
|
2245
|
-
patients.push(
|
|
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((
|
|
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((
|
|
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((
|
|
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((
|
|
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((
|
|
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
|
-
(
|
|
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((
|
|
4445
|
-
return { ...
|
|
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((
|
|
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((
|
|
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((
|
|
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((
|
|
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((
|
|
5743
|
-
const data =
|
|
5934
|
+
const clinics = clinicsSnapshot.docs.map((doc33) => {
|
|
5935
|
+
const data = doc33.data();
|
|
5744
5936
|
return {
|
|
5745
5937
|
...data,
|
|
5746
|
-
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
|
|
5774
|
-
const clinic =
|
|
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
|
|
5897
|
-
const clinic =
|
|
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
|
|
5994
|
-
const clinic = { ...
|
|
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((
|
|
6051
|
-
return { ...
|
|
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["
|
|
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((
|
|
7343
|
-
id:
|
|
7344
|
-
...
|
|
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((
|
|
7359
|
-
id:
|
|
7360
|
-
...
|
|
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((
|
|
7433
|
-
id:
|
|
7434
|
-
...
|
|
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((
|
|
7448
|
-
id:
|
|
7449
|
-
...
|
|
7650
|
+
return querySnapshot.docs.map((doc33) => ({
|
|
7651
|
+
id: doc33.id,
|
|
7652
|
+
...doc33.data()
|
|
7450
7653
|
}));
|
|
7451
7654
|
}
|
|
7452
7655
|
};
|
|
@@ -7487,7 +7690,8 @@ var createProcedureSchema = z20.object({
|
|
|
7487
7690
|
duration: z20.number().min(1).max(480),
|
|
7488
7691
|
// Max 8 hours
|
|
7489
7692
|
practitionerId: z20.string().min(1),
|
|
7490
|
-
clinicBranchId: z20.string().min(1)
|
|
7693
|
+
clinicBranchId: z20.string().min(1),
|
|
7694
|
+
photos: z20.array(z20.string()).optional()
|
|
7491
7695
|
});
|
|
7492
7696
|
var updateProcedureSchema = z20.object({
|
|
7493
7697
|
name: z20.string().min(3).max(100).optional(),
|
|
@@ -7502,7 +7706,8 @@ var updateProcedureSchema = z20.object({
|
|
|
7502
7706
|
subcategoryId: z20.string().optional(),
|
|
7503
7707
|
technologyId: z20.string().optional(),
|
|
7504
7708
|
productId: z20.string().optional(),
|
|
7505
|
-
clinicBranchId: z20.string().optional()
|
|
7709
|
+
clinicBranchId: z20.string().optional(),
|
|
7710
|
+
photos: z20.array(z20.string()).optional()
|
|
7506
7711
|
});
|
|
7507
7712
|
var procedureSchema = createProcedureSchema.extend({
|
|
7508
7713
|
id: z20.string().min(1),
|
|
@@ -7516,6 +7721,8 @@ var procedureSchema = createProcedureSchema.extend({
|
|
|
7516
7721
|
// We'll validate the full product object separately
|
|
7517
7722
|
blockingConditions: z20.array(z20.any()),
|
|
7518
7723
|
// We'll validate blocking conditions separately
|
|
7724
|
+
contraindications: z20.array(z20.any()),
|
|
7725
|
+
// We'll validate contraindications separately
|
|
7519
7726
|
treatmentBenefits: z20.array(z20.any()),
|
|
7520
7727
|
// We'll validate treatment benefits separately
|
|
7521
7728
|
preRequirements: z20.array(z20.any()),
|
|
@@ -7620,6 +7827,7 @@ var ProcedureService = class extends BaseService {
|
|
|
7620
7827
|
technology,
|
|
7621
7828
|
product,
|
|
7622
7829
|
blockingConditions: technology.blockingConditions,
|
|
7830
|
+
contraindications: technology.contraindications || [],
|
|
7623
7831
|
treatmentBenefits: technology.benefits,
|
|
7624
7832
|
preRequirements: technology.requirements.pre,
|
|
7625
7833
|
postRequirements: technology.requirements.post,
|
|
@@ -7677,7 +7885,7 @@ var ProcedureService = class extends BaseService {
|
|
|
7677
7885
|
where15("isActive", "==", true)
|
|
7678
7886
|
);
|
|
7679
7887
|
const snapshot = await getDocs15(q);
|
|
7680
|
-
return snapshot.docs.map((
|
|
7888
|
+
return snapshot.docs.map((doc33) => doc33.data());
|
|
7681
7889
|
}
|
|
7682
7890
|
/**
|
|
7683
7891
|
* Gets all procedures for a practitioner
|
|
@@ -7691,7 +7899,7 @@ var ProcedureService = class extends BaseService {
|
|
|
7691
7899
|
where15("isActive", "==", true)
|
|
7692
7900
|
);
|
|
7693
7901
|
const snapshot = await getDocs15(q);
|
|
7694
|
-
return snapshot.docs.map((
|
|
7902
|
+
return snapshot.docs.map((doc33) => doc33.data());
|
|
7695
7903
|
}
|
|
7696
7904
|
/**
|
|
7697
7905
|
* Updates a procedure
|
|
@@ -7874,20 +8082,20 @@ var ProcedureService = class extends BaseService {
|
|
|
7874
8082
|
const proceduresCollection = collection15(this.db, PROCEDURES_COLLECTION);
|
|
7875
8083
|
let proceduresQuery = query15(proceduresCollection);
|
|
7876
8084
|
if (pagination && pagination > 0) {
|
|
7877
|
-
const { limit:
|
|
8085
|
+
const { limit: limit12, startAfter: startAfter12 } = await import("firebase/firestore");
|
|
7878
8086
|
if (lastDoc) {
|
|
7879
8087
|
proceduresQuery = query15(
|
|
7880
8088
|
proceduresCollection,
|
|
7881
8089
|
orderBy4("name"),
|
|
7882
8090
|
// Use imported orderBy
|
|
7883
|
-
|
|
7884
|
-
|
|
8091
|
+
startAfter12(lastDoc),
|
|
8092
|
+
limit12(pagination)
|
|
7885
8093
|
);
|
|
7886
8094
|
} else {
|
|
7887
8095
|
proceduresQuery = query15(
|
|
7888
8096
|
proceduresCollection,
|
|
7889
8097
|
orderBy4("name"),
|
|
7890
|
-
|
|
8098
|
+
limit12(pagination)
|
|
7891
8099
|
);
|
|
7892
8100
|
}
|
|
7893
8101
|
} else {
|
|
@@ -7895,11 +8103,11 @@ var ProcedureService = class extends BaseService {
|
|
|
7895
8103
|
}
|
|
7896
8104
|
const proceduresSnapshot = await getDocs15(proceduresQuery);
|
|
7897
8105
|
const lastVisible = proceduresSnapshot.docs[proceduresSnapshot.docs.length - 1];
|
|
7898
|
-
const procedures = proceduresSnapshot.docs.map((
|
|
7899
|
-
const data =
|
|
8106
|
+
const procedures = proceduresSnapshot.docs.map((doc33) => {
|
|
8107
|
+
const data = doc33.data();
|
|
7900
8108
|
return {
|
|
7901
8109
|
...data,
|
|
7902
|
-
id:
|
|
8110
|
+
id: doc33.id
|
|
7903
8111
|
// Ensure ID is present
|
|
7904
8112
|
};
|
|
7905
8113
|
});
|
|
@@ -7981,8 +8189,8 @@ var ProcedureService = class extends BaseService {
|
|
|
7981
8189
|
console.log(
|
|
7982
8190
|
`[PROCEDURE_SERVICE] Found ${querySnapshot.docs.length} procedures in geo bound`
|
|
7983
8191
|
);
|
|
7984
|
-
for (const
|
|
7985
|
-
const procedure = { ...
|
|
8192
|
+
for (const doc33 of querySnapshot.docs) {
|
|
8193
|
+
const procedure = { ...doc33.data(), id: doc33.id };
|
|
7986
8194
|
const distance = distanceBetween6(
|
|
7987
8195
|
[center.latitude, center.longitude],
|
|
7988
8196
|
[
|
|
@@ -8033,8 +8241,8 @@ var ProcedureService = class extends BaseService {
|
|
|
8033
8241
|
console.log(
|
|
8034
8242
|
`[PROCEDURE_SERVICE] Found ${querySnapshot.docs.length} procedures with regular query`
|
|
8035
8243
|
);
|
|
8036
|
-
const procedures = querySnapshot.docs.map((
|
|
8037
|
-
return { ...
|
|
8244
|
+
const procedures = querySnapshot.docs.map((doc33) => {
|
|
8245
|
+
return { ...doc33.data(), id: doc33.id };
|
|
8038
8246
|
});
|
|
8039
8247
|
if (filters.location) {
|
|
8040
8248
|
const center = filters.location;
|
|
@@ -8187,7 +8395,10 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
8187
8395
|
createdBy: userId,
|
|
8188
8396
|
version: 1,
|
|
8189
8397
|
isActive: true,
|
|
8190
|
-
tags: validatedData.tags || []
|
|
8398
|
+
tags: validatedData.tags || [],
|
|
8399
|
+
isUserForm: validatedData.isUserForm || false,
|
|
8400
|
+
isRequired: validatedData.isRequired || false,
|
|
8401
|
+
sortingOrder: validatedData.sortingOrder || 0
|
|
8191
8402
|
};
|
|
8192
8403
|
const docRef = doc16(this.collectionRef, templateId);
|
|
8193
8404
|
await setDoc14(docRef, template);
|
|
@@ -8222,21 +8433,31 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
8222
8433
|
if (validatedData.elements) {
|
|
8223
8434
|
updatedElements = validatedData.elements.map((element) => ({
|
|
8224
8435
|
...element,
|
|
8225
|
-
id: this.generateId()
|
|
8436
|
+
id: element.id || this.generateId()
|
|
8226
8437
|
}));
|
|
8227
8438
|
}
|
|
8228
|
-
const
|
|
8229
|
-
...validatedData,
|
|
8439
|
+
const updatePayload = {
|
|
8230
8440
|
elements: updatedElements,
|
|
8231
8441
|
updatedAt: Date.now(),
|
|
8232
8442
|
version: template.version + 1
|
|
8233
8443
|
};
|
|
8444
|
+
if (validatedData.title !== void 0)
|
|
8445
|
+
updatePayload.title = validatedData.title;
|
|
8446
|
+
if (validatedData.description !== void 0)
|
|
8447
|
+
updatePayload.description = validatedData.description;
|
|
8448
|
+
if (validatedData.isActive !== void 0)
|
|
8449
|
+
updatePayload.isActive = validatedData.isActive;
|
|
8450
|
+
if (validatedData.tags !== void 0)
|
|
8451
|
+
updatePayload.tags = validatedData.tags;
|
|
8452
|
+
if (validatedData.isUserForm !== void 0)
|
|
8453
|
+
updatePayload.isUserForm = validatedData.isUserForm;
|
|
8454
|
+
if (validatedData.isRequired !== void 0)
|
|
8455
|
+
updatePayload.isRequired = validatedData.isRequired;
|
|
8456
|
+
if (validatedData.sortingOrder !== void 0)
|
|
8457
|
+
updatePayload.sortingOrder = validatedData.sortingOrder;
|
|
8234
8458
|
const docRef = doc16(this.collectionRef, templateId);
|
|
8235
|
-
await updateDoc16(docRef,
|
|
8236
|
-
return {
|
|
8237
|
-
...template,
|
|
8238
|
-
...updateData
|
|
8239
|
-
};
|
|
8459
|
+
await updateDoc16(docRef, updatePayload);
|
|
8460
|
+
return { ...template, ...updatePayload };
|
|
8240
8461
|
}
|
|
8241
8462
|
/**
|
|
8242
8463
|
* Delete a document template
|
|
@@ -8265,9 +8486,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
8265
8486
|
const querySnapshot = await getDocs16(q);
|
|
8266
8487
|
const templates = [];
|
|
8267
8488
|
let lastVisible = null;
|
|
8268
|
-
querySnapshot.forEach((
|
|
8269
|
-
templates.push(
|
|
8270
|
-
lastVisible =
|
|
8489
|
+
querySnapshot.forEach((doc33) => {
|
|
8490
|
+
templates.push(doc33.data());
|
|
8491
|
+
lastVisible = doc33;
|
|
8271
8492
|
});
|
|
8272
8493
|
return {
|
|
8273
8494
|
templates,
|
|
@@ -8295,9 +8516,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
8295
8516
|
const querySnapshot = await getDocs16(q);
|
|
8296
8517
|
const templates = [];
|
|
8297
8518
|
let lastVisible = null;
|
|
8298
|
-
querySnapshot.forEach((
|
|
8299
|
-
templates.push(
|
|
8300
|
-
lastVisible =
|
|
8519
|
+
querySnapshot.forEach((doc33) => {
|
|
8520
|
+
templates.push(doc33.data());
|
|
8521
|
+
lastVisible = doc33;
|
|
8301
8522
|
});
|
|
8302
8523
|
return {
|
|
8303
8524
|
templates,
|
|
@@ -8324,9 +8545,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
8324
8545
|
const querySnapshot = await getDocs16(q);
|
|
8325
8546
|
const templates = [];
|
|
8326
8547
|
let lastVisible = null;
|
|
8327
|
-
querySnapshot.forEach((
|
|
8328
|
-
templates.push(
|
|
8329
|
-
lastVisible =
|
|
8548
|
+
querySnapshot.forEach((doc33) => {
|
|
8549
|
+
templates.push(doc33.data());
|
|
8550
|
+
lastVisible = doc33;
|
|
8330
8551
|
});
|
|
8331
8552
|
return {
|
|
8332
8553
|
templates,
|
|
@@ -8344,7 +8565,6 @@ import {
|
|
|
8344
8565
|
setDoc as setDoc15,
|
|
8345
8566
|
updateDoc as updateDoc17,
|
|
8346
8567
|
query as query17,
|
|
8347
|
-
where as where17,
|
|
8348
8568
|
orderBy as orderBy6,
|
|
8349
8569
|
limit as limit9,
|
|
8350
8570
|
startAfter as startAfter9
|
|
@@ -8352,50 +8572,80 @@ import {
|
|
|
8352
8572
|
var FilledDocumentService = class extends BaseService {
|
|
8353
8573
|
constructor(...args) {
|
|
8354
8574
|
super(...args);
|
|
8355
|
-
this.collectionRef = collection17(
|
|
8356
|
-
this.db,
|
|
8357
|
-
FILLED_DOCUMENTS_COLLECTION
|
|
8358
|
-
);
|
|
8359
8575
|
this.templateService = new DocumentationTemplateService(...args);
|
|
8360
8576
|
}
|
|
8577
|
+
getFormSubcollectionPath(isUserForm) {
|
|
8578
|
+
return isUserForm ? USER_FORMS_SUBCOLLECTION : DOCTOR_FORMS_SUBCOLLECTION;
|
|
8579
|
+
}
|
|
8361
8580
|
/**
|
|
8362
|
-
* Create a new filled document
|
|
8363
|
-
* @param templateId - ID of the template to use
|
|
8364
|
-
* @param
|
|
8365
|
-
* @param
|
|
8366
|
-
* @param
|
|
8367
|
-
* @
|
|
8581
|
+
* Create a new filled document within an appointment's subcollection.
|
|
8582
|
+
* @param templateId - ID of the template to use.
|
|
8583
|
+
* @param appointmentId - ID of the appointment this form belongs to.
|
|
8584
|
+
* @param procedureId - ID of the procedure associated with this form.
|
|
8585
|
+
* @param patientId - ID of the patient.
|
|
8586
|
+
* @param practitionerId - ID of the practitioner (can be system/generic if patient is filling).
|
|
8587
|
+
* @param clinicId - ID of the clinic.
|
|
8588
|
+
* @param initialValues - Optional initial values for the form elements.
|
|
8589
|
+
* @param initialStatus - Optional initial status for the form.
|
|
8590
|
+
* @returns The created filled document.
|
|
8368
8591
|
*/
|
|
8369
|
-
async
|
|
8592
|
+
async createFilledDocumentForAppointment(templateId, appointmentId, procedureId, patientId, practitionerId, clinicId, initialValues = {}, initialStatus = "draft" /* DRAFT */) {
|
|
8370
8593
|
const template = await this.templateService.getTemplateById(templateId);
|
|
8371
8594
|
if (!template) {
|
|
8372
8595
|
throw new Error(`Template with ID ${templateId} not found`);
|
|
8373
8596
|
}
|
|
8374
8597
|
const documentId3 = this.generateId();
|
|
8375
8598
|
const now = Date.now();
|
|
8599
|
+
const isUserForm = template.isUserForm || false;
|
|
8600
|
+
const formSubcollection = this.getFormSubcollectionPath(isUserForm);
|
|
8376
8601
|
const filledDocument = {
|
|
8377
8602
|
id: documentId3,
|
|
8378
8603
|
templateId,
|
|
8379
8604
|
templateVersion: template.version,
|
|
8605
|
+
isUserForm,
|
|
8606
|
+
// Set based on template
|
|
8607
|
+
isRequired: template.isRequired || false,
|
|
8608
|
+
// Inherit isRequired from the template
|
|
8609
|
+
appointmentId,
|
|
8610
|
+
// NEW
|
|
8611
|
+
procedureId,
|
|
8612
|
+
// NEW
|
|
8380
8613
|
patientId,
|
|
8381
8614
|
practitionerId,
|
|
8382
8615
|
clinicId,
|
|
8383
8616
|
createdAt: now,
|
|
8384
8617
|
updatedAt: now,
|
|
8385
|
-
values:
|
|
8386
|
-
status:
|
|
8618
|
+
values: initialValues,
|
|
8619
|
+
status: initialStatus
|
|
8387
8620
|
};
|
|
8388
|
-
const docRef = doc17(
|
|
8621
|
+
const docRef = doc17(
|
|
8622
|
+
this.db,
|
|
8623
|
+
APPOINTMENTS_COLLECTION,
|
|
8624
|
+
// Replaced "appointments"
|
|
8625
|
+
appointmentId,
|
|
8626
|
+
formSubcollection,
|
|
8627
|
+
documentId3
|
|
8628
|
+
);
|
|
8389
8629
|
await setDoc15(docRef, filledDocument);
|
|
8390
8630
|
return filledDocument;
|
|
8391
8631
|
}
|
|
8392
8632
|
/**
|
|
8393
|
-
* Get a filled document
|
|
8394
|
-
* @param
|
|
8395
|
-
* @
|
|
8633
|
+
* Get a specific filled document from an appointment's subcollection.
|
|
8634
|
+
* @param appointmentId - ID of the appointment.
|
|
8635
|
+
* @param formId - ID of the filled document.
|
|
8636
|
+
* @param isUserForm - Boolean indicating if it's a user form or doctor form.
|
|
8637
|
+
* @returns The filled document or null if not found.
|
|
8396
8638
|
*/
|
|
8397
|
-
async
|
|
8398
|
-
const
|
|
8639
|
+
async getFilledDocumentFromAppointmentById(appointmentId, formId, isUserForm) {
|
|
8640
|
+
const formSubcollection = this.getFormSubcollectionPath(isUserForm);
|
|
8641
|
+
const docRef = doc17(
|
|
8642
|
+
this.db,
|
|
8643
|
+
APPOINTMENTS_COLLECTION,
|
|
8644
|
+
// Replaced "appointments"
|
|
8645
|
+
appointmentId,
|
|
8646
|
+
formSubcollection,
|
|
8647
|
+
formId
|
|
8648
|
+
);
|
|
8399
8649
|
const docSnap = await getDoc20(docRef);
|
|
8400
8650
|
if (!docSnap.exists()) {
|
|
8401
8651
|
return null;
|
|
@@ -8403,178 +8653,183 @@ var FilledDocumentService = class extends BaseService {
|
|
|
8403
8653
|
return docSnap.data();
|
|
8404
8654
|
}
|
|
8405
8655
|
/**
|
|
8406
|
-
* Update values in a filled document
|
|
8407
|
-
* @param
|
|
8408
|
-
* @param
|
|
8409
|
-
* @param
|
|
8410
|
-
* @
|
|
8656
|
+
* Update values or status in a filled document within an appointment's subcollection.
|
|
8657
|
+
* @param appointmentId - ID of the appointment.
|
|
8658
|
+
* @param formId - ID of the filled document to update.
|
|
8659
|
+
* @param isUserForm - Boolean indicating if it's a user form or doctor form.
|
|
8660
|
+
* @param values - Updated values for elements.
|
|
8661
|
+
* @param status - Optional new status for the document.
|
|
8662
|
+
* @returns The updated filled document.
|
|
8411
8663
|
*/
|
|
8412
|
-
async
|
|
8413
|
-
const
|
|
8414
|
-
|
|
8415
|
-
|
|
8664
|
+
async updateFilledDocumentInAppointment(appointmentId, formId, isUserForm, values, status) {
|
|
8665
|
+
const formSubcollection = this.getFormSubcollectionPath(isUserForm);
|
|
8666
|
+
const docRef = doc17(
|
|
8667
|
+
this.db,
|
|
8668
|
+
APPOINTMENTS_COLLECTION,
|
|
8669
|
+
// Replaced "appointments"
|
|
8670
|
+
appointmentId,
|
|
8671
|
+
formSubcollection,
|
|
8672
|
+
formId
|
|
8673
|
+
);
|
|
8674
|
+
const existingDoc = await this.getFilledDocumentFromAppointmentById(
|
|
8675
|
+
appointmentId,
|
|
8676
|
+
formId,
|
|
8677
|
+
isUserForm
|
|
8678
|
+
);
|
|
8679
|
+
if (!existingDoc) {
|
|
8680
|
+
throw new Error(
|
|
8681
|
+
`Filled document with ID ${formId} not found in appointment ${appointmentId} ${formSubcollection}`
|
|
8682
|
+
);
|
|
8416
8683
|
}
|
|
8417
|
-
const
|
|
8418
|
-
values: {
|
|
8419
|
-
...filledDocument.values,
|
|
8420
|
-
...values
|
|
8421
|
-
},
|
|
8684
|
+
const updatePayload = {
|
|
8422
8685
|
updatedAt: Date.now()
|
|
8423
8686
|
};
|
|
8687
|
+
if (values) {
|
|
8688
|
+
updatePayload.values = {
|
|
8689
|
+
...existingDoc.values,
|
|
8690
|
+
...values
|
|
8691
|
+
};
|
|
8692
|
+
}
|
|
8424
8693
|
if (status) {
|
|
8425
|
-
|
|
8694
|
+
updatePayload.status = status;
|
|
8426
8695
|
}
|
|
8427
|
-
|
|
8428
|
-
|
|
8429
|
-
|
|
8430
|
-
|
|
8431
|
-
...updateData
|
|
8432
|
-
};
|
|
8696
|
+
if (Object.keys(updatePayload).length === 1 && "updatedAt" in updatePayload) {
|
|
8697
|
+
}
|
|
8698
|
+
await updateDoc17(docRef, updatePayload);
|
|
8699
|
+
return { ...existingDoc, ...updatePayload };
|
|
8433
8700
|
}
|
|
8434
8701
|
/**
|
|
8435
|
-
* Get filled
|
|
8436
|
-
* @param
|
|
8437
|
-
* @param pageSize
|
|
8438
|
-
* @param lastDoc
|
|
8439
|
-
* @returns Array of filled documents and the last document for pagination
|
|
8702
|
+
* Get all filled user forms for a specific appointment.
|
|
8703
|
+
* @param appointmentId ID of the appointment.
|
|
8704
|
+
* @param pageSize Number of documents to retrieve.
|
|
8705
|
+
* @param lastDoc Last document from previous page for pagination.
|
|
8440
8706
|
*/
|
|
8441
|
-
async
|
|
8707
|
+
async getFilledUserFormsForAppointment(appointmentId, pageSize = 20, lastDoc) {
|
|
8708
|
+
const subcollectionRef = collection17(
|
|
8709
|
+
this.db,
|
|
8710
|
+
APPOINTMENTS_COLLECTION,
|
|
8711
|
+
// Replaced "appointments"
|
|
8712
|
+
appointmentId,
|
|
8713
|
+
USER_FORMS_SUBCOLLECTION
|
|
8714
|
+
);
|
|
8442
8715
|
let q = query17(
|
|
8443
|
-
|
|
8444
|
-
where17("patientId", "==", patientId),
|
|
8716
|
+
subcollectionRef,
|
|
8445
8717
|
orderBy6("updatedAt", "desc"),
|
|
8446
8718
|
limit9(pageSize)
|
|
8447
8719
|
);
|
|
8448
8720
|
if (lastDoc) {
|
|
8449
8721
|
q = query17(q, startAfter9(lastDoc));
|
|
8450
8722
|
}
|
|
8451
|
-
|
|
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
|
-
};
|
|
8723
|
+
return this.executeQuery(q);
|
|
8462
8724
|
}
|
|
8463
8725
|
/**
|
|
8464
|
-
* Get filled
|
|
8465
|
-
* @param
|
|
8466
|
-
* @param pageSize
|
|
8467
|
-
* @param lastDoc
|
|
8468
|
-
* @returns Array of filled documents and the last document for pagination
|
|
8726
|
+
* Get all filled doctor forms for a specific appointment.
|
|
8727
|
+
* @param appointmentId ID of the appointment.
|
|
8728
|
+
* @param pageSize Number of documents to retrieve.
|
|
8729
|
+
* @param lastDoc Last document from previous page for pagination.
|
|
8469
8730
|
*/
|
|
8470
|
-
async
|
|
8731
|
+
async getFilledDoctorFormsForAppointment(appointmentId, pageSize = 20, lastDoc) {
|
|
8732
|
+
const subcollectionRef = collection17(
|
|
8733
|
+
this.db,
|
|
8734
|
+
APPOINTMENTS_COLLECTION,
|
|
8735
|
+
// Replaced "appointments"
|
|
8736
|
+
appointmentId,
|
|
8737
|
+
DOCTOR_FORMS_SUBCOLLECTION
|
|
8738
|
+
);
|
|
8471
8739
|
let q = query17(
|
|
8472
|
-
|
|
8473
|
-
where17("practitionerId", "==", practitionerId),
|
|
8740
|
+
subcollectionRef,
|
|
8474
8741
|
orderBy6("updatedAt", "desc"),
|
|
8475
8742
|
limit9(pageSize)
|
|
8476
8743
|
);
|
|
8477
8744
|
if (lastDoc) {
|
|
8478
8745
|
q = query17(q, startAfter9(lastDoc));
|
|
8479
8746
|
}
|
|
8747
|
+
return this.executeQuery(q);
|
|
8748
|
+
}
|
|
8749
|
+
// Helper to execute query and return documents + lastDoc
|
|
8750
|
+
async executeQuery(q) {
|
|
8480
8751
|
const querySnapshot = await getDocs17(q);
|
|
8481
8752
|
const documents = [];
|
|
8482
8753
|
let lastVisible = null;
|
|
8483
|
-
querySnapshot.forEach((
|
|
8484
|
-
documents.push(
|
|
8485
|
-
lastVisible =
|
|
8754
|
+
querySnapshot.forEach((doc33) => {
|
|
8755
|
+
documents.push(doc33.data());
|
|
8756
|
+
lastVisible = doc33;
|
|
8486
8757
|
});
|
|
8487
8758
|
return {
|
|
8488
8759
|
documents,
|
|
8489
8760
|
lastDoc: lastVisible
|
|
8490
8761
|
};
|
|
8491
8762
|
}
|
|
8763
|
+
// IMPORTANT: The following methods that query across all patients/practitioners/clinics
|
|
8764
|
+
// (e.g., getFilledDocumentsByPatient, getFilledDocumentsByPractitioner)
|
|
8765
|
+
// will NOT work correctly if FILLED_DOCUMENTS_COLLECTION is no longer a top-level collection
|
|
8766
|
+
// and data is only in appointment subcollections. You would need to use
|
|
8767
|
+
// Firestore Collection Group Queries for that, which require an index and a different query approach.
|
|
8768
|
+
// These methods are left here for now but would need significant rework or removal.
|
|
8769
|
+
/**
|
|
8770
|
+
* Get filled documents for a patient (NEEDS REWORK for subcollections or Collection Group Query)
|
|
8771
|
+
* @param patientId - ID of the patient
|
|
8772
|
+
* @param pageSize - Number of documents to retrieve
|
|
8773
|
+
* @param lastDoc - Last document from previous page for pagination
|
|
8774
|
+
* @returns Array of filled documents and the last document for pagination
|
|
8775
|
+
*/
|
|
8776
|
+
async getFilledDocumentsByPatient(patientId, pageSize = 20, lastDoc) {
|
|
8777
|
+
console.warn(
|
|
8778
|
+
"getFilledDocumentsByPatient needs rework for subcollection model or Collection Group Queries."
|
|
8779
|
+
);
|
|
8780
|
+
return { documents: [], lastDoc: null };
|
|
8781
|
+
}
|
|
8782
|
+
/**
|
|
8783
|
+
* Get filled documents for a practitioner (NEEDS REWORK for subcollections or Collection Group Query)
|
|
8784
|
+
* @param practitionerId - ID of the practitioner
|
|
8785
|
+
* @param pageSize - Number of documents to retrieve
|
|
8786
|
+
* @param lastDoc - Last document from previous page for pagination
|
|
8787
|
+
* @returns Array of filled documents and the last document for pagination
|
|
8788
|
+
*/
|
|
8789
|
+
async getFilledDocumentsByPractitioner(practitionerId, pageSize = 20, lastDoc) {
|
|
8790
|
+
console.warn(
|
|
8791
|
+
"getFilledDocumentsByPractitioner needs rework for subcollection model or Collection Group Queries."
|
|
8792
|
+
);
|
|
8793
|
+
return { documents: [], lastDoc: null };
|
|
8794
|
+
}
|
|
8492
8795
|
/**
|
|
8493
|
-
* Get filled documents for a clinic
|
|
8796
|
+
* Get filled documents for a clinic (NEEDS REWORK for subcollections or Collection Group Query)
|
|
8494
8797
|
* @param clinicId - ID of the clinic
|
|
8495
8798
|
* @param pageSize - Number of documents to retrieve
|
|
8496
8799
|
* @param lastDoc - Last document from previous page for pagination
|
|
8497
8800
|
* @returns Array of filled documents and the last document for pagination
|
|
8498
8801
|
*/
|
|
8499
8802
|
async getFilledDocumentsByClinic(clinicId, pageSize = 20, lastDoc) {
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
where17("clinicId", "==", clinicId),
|
|
8503
|
-
orderBy6("updatedAt", "desc"),
|
|
8504
|
-
limit9(pageSize)
|
|
8803
|
+
console.warn(
|
|
8804
|
+
"getFilledDocumentsByClinic needs rework for subcollection model or Collection Group Queries."
|
|
8505
8805
|
);
|
|
8506
|
-
|
|
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
|
-
};
|
|
8806
|
+
return { documents: [], lastDoc: null };
|
|
8520
8807
|
}
|
|
8521
8808
|
/**
|
|
8522
|
-
* Get filled documents by template
|
|
8809
|
+
* Get filled documents by template (NEEDS REWORK for subcollections or Collection Group Query)
|
|
8523
8810
|
* @param templateId - ID of the template
|
|
8524
8811
|
* @param pageSize - Number of documents to retrieve
|
|
8525
8812
|
* @param lastDoc - Last document from previous page for pagination
|
|
8526
8813
|
* @returns Array of filled documents and the last document for pagination
|
|
8527
8814
|
*/
|
|
8528
8815
|
async getFilledDocumentsByTemplate(templateId, pageSize = 20, lastDoc) {
|
|
8529
|
-
|
|
8530
|
-
|
|
8531
|
-
where17("templateId", "==", templateId),
|
|
8532
|
-
orderBy6("updatedAt", "desc"),
|
|
8533
|
-
limit9(pageSize)
|
|
8816
|
+
console.warn(
|
|
8817
|
+
"getFilledDocumentsByTemplate needs rework for subcollection model or Collection Group Queries."
|
|
8534
8818
|
);
|
|
8535
|
-
|
|
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
|
-
};
|
|
8819
|
+
return { documents: [], lastDoc: null };
|
|
8549
8820
|
}
|
|
8550
8821
|
/**
|
|
8551
|
-
* Get filled documents by status
|
|
8822
|
+
* Get filled documents by status (NEEDS REWORK for subcollections or Collection Group Query)
|
|
8552
8823
|
* @param status - Status to filter by
|
|
8553
8824
|
* @param pageSize - Number of documents to retrieve
|
|
8554
8825
|
* @param lastDoc - Last document from previous page for pagination
|
|
8555
8826
|
* @returns Array of filled documents and the last document for pagination
|
|
8556
8827
|
*/
|
|
8557
8828
|
async getFilledDocumentsByStatus(status, pageSize = 20, lastDoc) {
|
|
8558
|
-
|
|
8559
|
-
|
|
8560
|
-
where17("status", "==", status),
|
|
8561
|
-
orderBy6("updatedAt", "desc"),
|
|
8562
|
-
limit9(pageSize)
|
|
8829
|
+
console.warn(
|
|
8830
|
+
"getFilledDocumentsByStatus needs rework for subcollection model or Collection Group Queries."
|
|
8563
8831
|
);
|
|
8564
|
-
|
|
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
|
-
};
|
|
8832
|
+
return { documents: [], lastDoc: null };
|
|
8578
8833
|
}
|
|
8579
8834
|
};
|
|
8580
8835
|
|
|
@@ -9125,7 +9380,7 @@ async function searchCalendarEventsUtil(db, params) {
|
|
|
9125
9380
|
const finalQuery = query21(collectionRef, ...constraints);
|
|
9126
9381
|
const querySnapshot = await getDocs21(finalQuery);
|
|
9127
9382
|
const events = querySnapshot.docs.map(
|
|
9128
|
-
(
|
|
9383
|
+
(doc33) => ({ id: doc33.id, ...doc33.data() })
|
|
9129
9384
|
);
|
|
9130
9385
|
return events;
|
|
9131
9386
|
} catch (error) {
|
|
@@ -9218,7 +9473,7 @@ async function getPractitionerSyncedCalendarsUtil(db, practitionerId) {
|
|
|
9218
9473
|
);
|
|
9219
9474
|
const q = query22(calendarsRef, orderBy11("createdAt", "desc"));
|
|
9220
9475
|
const querySnapshot = await getDocs22(q);
|
|
9221
|
-
return querySnapshot.docs.map((
|
|
9476
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
9222
9477
|
}
|
|
9223
9478
|
async function getPatientSyncedCalendarUtil(db, patientId, calendarId) {
|
|
9224
9479
|
const calendarRef = getPatientSyncedCalendarDocRef(db, patientId, calendarId);
|
|
@@ -9235,7 +9490,7 @@ async function getPatientSyncedCalendarsUtil(db, patientId) {
|
|
|
9235
9490
|
);
|
|
9236
9491
|
const q = query22(calendarsRef, orderBy11("createdAt", "desc"));
|
|
9237
9492
|
const querySnapshot = await getDocs22(q);
|
|
9238
|
-
return querySnapshot.docs.map((
|
|
9493
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
9239
9494
|
}
|
|
9240
9495
|
async function getClinicSyncedCalendarUtil(db, clinicId, calendarId) {
|
|
9241
9496
|
const calendarRef = getClinicSyncedCalendarDocRef(db, clinicId, calendarId);
|
|
@@ -9252,7 +9507,7 @@ async function getClinicSyncedCalendarsUtil(db, clinicId) {
|
|
|
9252
9507
|
);
|
|
9253
9508
|
const q = query22(calendarsRef, orderBy11("createdAt", "desc"));
|
|
9254
9509
|
const querySnapshot = await getDocs22(q);
|
|
9255
|
-
return querySnapshot.docs.map((
|
|
9510
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
9256
9511
|
}
|
|
9257
9512
|
async function updatePractitionerSyncedCalendarUtil(db, practitionerId, calendarId, updateData) {
|
|
9258
9513
|
const calendarRef = getPractitionerSyncedCalendarDocRef(
|
|
@@ -10607,9 +10862,9 @@ var CalendarServiceV2 = class extends BaseService {
|
|
|
10607
10862
|
where23("eventTime.start", "<=", Timestamp25.fromDate(endDate))
|
|
10608
10863
|
);
|
|
10609
10864
|
const eventsSnapshot = await getDocs23(q);
|
|
10610
|
-
const events = eventsSnapshot.docs.map((
|
|
10611
|
-
id:
|
|
10612
|
-
...
|
|
10865
|
+
const events = eventsSnapshot.docs.map((doc33) => ({
|
|
10866
|
+
id: doc33.id,
|
|
10867
|
+
...doc33.data()
|
|
10613
10868
|
}));
|
|
10614
10869
|
const calendars = await this.syncedCalendarsService.getPractitionerSyncedCalendars(
|
|
10615
10870
|
doctorId
|
|
@@ -11241,7 +11496,7 @@ var CalendarServiceV2 = class extends BaseService {
|
|
|
11241
11496
|
])
|
|
11242
11497
|
);
|
|
11243
11498
|
const querySnapshot = await getDocs23(q);
|
|
11244
|
-
return querySnapshot.docs.map((
|
|
11499
|
+
return querySnapshot.docs.map((doc33) => doc33.data());
|
|
11245
11500
|
}
|
|
11246
11501
|
/**
|
|
11247
11502
|
* Calculates available time slots based on working hours, schedule and existing appointments
|
|
@@ -11520,7 +11775,7 @@ var ReviewService = class extends BaseService {
|
|
|
11520
11775
|
where24("patientId", "==", patientId)
|
|
11521
11776
|
);
|
|
11522
11777
|
const snapshot = await getDocs24(q);
|
|
11523
|
-
return snapshot.docs.map((
|
|
11778
|
+
return snapshot.docs.map((doc33) => doc33.data());
|
|
11524
11779
|
}
|
|
11525
11780
|
/**
|
|
11526
11781
|
* Gets all reviews for a specific clinic
|
|
@@ -11533,7 +11788,7 @@ var ReviewService = class extends BaseService {
|
|
|
11533
11788
|
where24("clinicReview.clinicId", "==", clinicId)
|
|
11534
11789
|
);
|
|
11535
11790
|
const snapshot = await getDocs24(q);
|
|
11536
|
-
return snapshot.docs.map((
|
|
11791
|
+
return snapshot.docs.map((doc33) => doc33.data());
|
|
11537
11792
|
}
|
|
11538
11793
|
/**
|
|
11539
11794
|
* Gets all reviews for a specific practitioner
|
|
@@ -11546,7 +11801,7 @@ var ReviewService = class extends BaseService {
|
|
|
11546
11801
|
where24("practitionerReview.practitionerId", "==", practitionerId)
|
|
11547
11802
|
);
|
|
11548
11803
|
const snapshot = await getDocs24(q);
|
|
11549
|
-
return snapshot.docs.map((
|
|
11804
|
+
return snapshot.docs.map((doc33) => doc33.data());
|
|
11550
11805
|
}
|
|
11551
11806
|
/**
|
|
11552
11807
|
* Gets all reviews for a specific procedure
|
|
@@ -11559,7 +11814,7 @@ var ReviewService = class extends BaseService {
|
|
|
11559
11814
|
where24("procedureReview.procedureId", "==", procedureId)
|
|
11560
11815
|
);
|
|
11561
11816
|
const snapshot = await getDocs24(q);
|
|
11562
|
-
return snapshot.docs.map((
|
|
11817
|
+
return snapshot.docs.map((doc33) => doc33.data());
|
|
11563
11818
|
}
|
|
11564
11819
|
/**
|
|
11565
11820
|
* Gets all reviews for a specific appointment
|
|
@@ -11988,9 +12243,12 @@ var ReviewService = class extends BaseService {
|
|
|
11988
12243
|
|
|
11989
12244
|
// src/services/appointment/appointment.service.ts
|
|
11990
12245
|
import {
|
|
11991
|
-
Timestamp as Timestamp28
|
|
12246
|
+
Timestamp as Timestamp28,
|
|
12247
|
+
serverTimestamp as serverTimestamp24,
|
|
12248
|
+
arrayUnion as arrayUnion8,
|
|
12249
|
+
arrayRemove as arrayRemove7
|
|
11992
12250
|
} from "firebase/firestore";
|
|
11993
|
-
import { getFunctions
|
|
12251
|
+
import { getFunctions } from "firebase/functions";
|
|
11994
12252
|
|
|
11995
12253
|
// src/services/appointment/utils/appointment.utils.ts
|
|
11996
12254
|
import {
|
|
@@ -12013,166 +12271,6 @@ import {
|
|
|
12013
12271
|
var TECHNOLOGIES_COLLECTION = "technologies";
|
|
12014
12272
|
|
|
12015
12273
|
// src/services/appointment/utils/appointment.utils.ts
|
|
12016
|
-
async function fetchAggregatedInfoUtil(db, clinicId, practitionerId, patientId, procedureId) {
|
|
12017
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
|
|
12018
|
-
try {
|
|
12019
|
-
const [clinicDoc, practitionerDoc, patientDoc, procedureDoc] = await Promise.all([
|
|
12020
|
-
getDoc28(doc26(db, CLINICS_COLLECTION, clinicId)),
|
|
12021
|
-
getDoc28(doc26(db, PRACTITIONERS_COLLECTION, practitionerId)),
|
|
12022
|
-
getDoc28(doc26(db, PATIENTS_COLLECTION, patientId)),
|
|
12023
|
-
getDoc28(doc26(db, PROCEDURES_COLLECTION, procedureId))
|
|
12024
|
-
]);
|
|
12025
|
-
if (!clinicDoc.exists()) {
|
|
12026
|
-
throw new Error(`Clinic with ID ${clinicId} not found`);
|
|
12027
|
-
}
|
|
12028
|
-
if (!practitionerDoc.exists()) {
|
|
12029
|
-
throw new Error(`Practitioner with ID ${practitionerId} not found`);
|
|
12030
|
-
}
|
|
12031
|
-
if (!patientDoc.exists()) {
|
|
12032
|
-
throw new Error(`Patient with ID ${patientId} not found`);
|
|
12033
|
-
}
|
|
12034
|
-
if (!procedureDoc.exists()) {
|
|
12035
|
-
throw new Error(`Procedure with ID ${procedureId} not found`);
|
|
12036
|
-
}
|
|
12037
|
-
const clinicData = clinicDoc.data();
|
|
12038
|
-
const practitionerData = practitionerDoc.data();
|
|
12039
|
-
const patientData = patientDoc.data();
|
|
12040
|
-
const procedureData = procedureDoc.data();
|
|
12041
|
-
const clinicInfo = {
|
|
12042
|
-
id: clinicId,
|
|
12043
|
-
featuredPhoto: ((_a = clinicData.featuredPhotos) == null ? void 0 : _a[0]) || "",
|
|
12044
|
-
name: clinicData.name,
|
|
12045
|
-
description: clinicData.description || null,
|
|
12046
|
-
location: clinicData.location,
|
|
12047
|
-
contactInfo: clinicData.contactInfo
|
|
12048
|
-
};
|
|
12049
|
-
const practitionerInfo = {
|
|
12050
|
-
id: practitionerId,
|
|
12051
|
-
practitionerPhoto: ((_b = practitionerData.basicInfo) == null ? void 0 : _b.profileImageUrl) || null,
|
|
12052
|
-
name: `${((_c = practitionerData.basicInfo) == null ? void 0 : _c.firstName) || ""} ${((_d = practitionerData.basicInfo) == null ? void 0 : _d.lastName) || ""}`.trim(),
|
|
12053
|
-
email: ((_e = practitionerData.basicInfo) == null ? void 0 : _e.email) || "",
|
|
12054
|
-
phone: ((_f = practitionerData.basicInfo) == null ? void 0 : _f.phoneNumber) || null,
|
|
12055
|
-
certification: practitionerData.certification
|
|
12056
|
-
};
|
|
12057
|
-
const patientInfo = {
|
|
12058
|
-
id: patientId,
|
|
12059
|
-
fullName: patientData.displayName || "",
|
|
12060
|
-
email: patientData.email || "",
|
|
12061
|
-
phone: patientData.phoneNumber || null,
|
|
12062
|
-
dateOfBirth: patientData.dateOfBirth || Timestamp27.now(),
|
|
12063
|
-
gender: patientData.gender || "other"
|
|
12064
|
-
};
|
|
12065
|
-
const procedureInfo = {
|
|
12066
|
-
id: procedureId,
|
|
12067
|
-
name: procedureData.name,
|
|
12068
|
-
description: procedureData.description,
|
|
12069
|
-
photo: procedureData.photo || "",
|
|
12070
|
-
family: procedureData.family,
|
|
12071
|
-
categoryName: ((_g = procedureData.category) == null ? void 0 : _g.name) || "",
|
|
12072
|
-
subcategoryName: ((_h = procedureData.subcategory) == null ? void 0 : _h.name) || "",
|
|
12073
|
-
technologyName: ((_i = procedureData.technology) == null ? void 0 : _i.name) || "",
|
|
12074
|
-
brandName: ((_j = procedureData.product) == null ? void 0 : _j.brand) || "",
|
|
12075
|
-
productName: ((_k = procedureData.product) == null ? void 0 : _k.name) || "",
|
|
12076
|
-
price: procedureData.price || 0,
|
|
12077
|
-
pricingMeasure: procedureData.pricingMeasure,
|
|
12078
|
-
currency: procedureData.currency,
|
|
12079
|
-
duration: procedureData.duration || 0,
|
|
12080
|
-
clinicId,
|
|
12081
|
-
clinicName: clinicInfo.name,
|
|
12082
|
-
practitionerId,
|
|
12083
|
-
practitionerName: practitionerInfo.name
|
|
12084
|
-
};
|
|
12085
|
-
let technologyId = "";
|
|
12086
|
-
if ((_l = procedureData.technology) == null ? void 0 : _l.id) {
|
|
12087
|
-
technologyId = procedureData.technology.id;
|
|
12088
|
-
}
|
|
12089
|
-
let blockingConditions = [];
|
|
12090
|
-
let contraindications = [];
|
|
12091
|
-
let preProcedureRequirements = [];
|
|
12092
|
-
let postProcedureRequirements = [];
|
|
12093
|
-
if (technologyId) {
|
|
12094
|
-
const technologyDoc = await getDoc28(
|
|
12095
|
-
doc26(db, TECHNOLOGIES_COLLECTION, technologyId)
|
|
12096
|
-
);
|
|
12097
|
-
if (technologyDoc.exists()) {
|
|
12098
|
-
const technologyData = technologyDoc.data();
|
|
12099
|
-
blockingConditions = technologyData.blockingConditions || [];
|
|
12100
|
-
contraindications = technologyData.contraindications || [];
|
|
12101
|
-
preProcedureRequirements = ((_m = technologyData.requirements) == null ? void 0 : _m.pre) || [];
|
|
12102
|
-
postProcedureRequirements = ((_n = technologyData.requirements) == null ? void 0 : _n.post) || [];
|
|
12103
|
-
}
|
|
12104
|
-
} else {
|
|
12105
|
-
blockingConditions = procedureData.blockingConditions || [];
|
|
12106
|
-
contraindications = procedureData.contraindications || [];
|
|
12107
|
-
preProcedureRequirements = procedureData.preRequirements || [];
|
|
12108
|
-
postProcedureRequirements = procedureData.postRequirements || [];
|
|
12109
|
-
}
|
|
12110
|
-
return {
|
|
12111
|
-
clinicInfo,
|
|
12112
|
-
practitionerInfo,
|
|
12113
|
-
patientInfo,
|
|
12114
|
-
procedureInfo,
|
|
12115
|
-
blockingConditions,
|
|
12116
|
-
contraindications,
|
|
12117
|
-
preProcedureRequirements,
|
|
12118
|
-
postProcedureRequirements
|
|
12119
|
-
};
|
|
12120
|
-
} catch (error) {
|
|
12121
|
-
console.error("Error fetching aggregated info:", error);
|
|
12122
|
-
throw error;
|
|
12123
|
-
}
|
|
12124
|
-
}
|
|
12125
|
-
async function createAppointmentUtil2(db, data, aggregatedInfo, generateId2) {
|
|
12126
|
-
try {
|
|
12127
|
-
const appointmentId = generateId2();
|
|
12128
|
-
const appointment = {
|
|
12129
|
-
id: appointmentId,
|
|
12130
|
-
calendarEventId: data.calendarEventId,
|
|
12131
|
-
clinicBranchId: data.clinicBranchId,
|
|
12132
|
-
clinicInfo: aggregatedInfo.clinicInfo,
|
|
12133
|
-
practitionerId: data.practitionerId,
|
|
12134
|
-
practitionerInfo: aggregatedInfo.practitionerInfo,
|
|
12135
|
-
patientId: data.patientId,
|
|
12136
|
-
patientInfo: aggregatedInfo.patientInfo,
|
|
12137
|
-
procedureId: data.procedureId,
|
|
12138
|
-
procedureInfo: aggregatedInfo.procedureInfo,
|
|
12139
|
-
status: data.initialStatus,
|
|
12140
|
-
bookingTime: Timestamp27.now(),
|
|
12141
|
-
appointmentStartTime: data.appointmentStartTime,
|
|
12142
|
-
appointmentEndTime: data.appointmentEndTime,
|
|
12143
|
-
patientNotes: data.patientNotes || null,
|
|
12144
|
-
cost: data.cost,
|
|
12145
|
-
currency: data.currency,
|
|
12146
|
-
paymentStatus: data.initialPaymentStatus || "unpaid" /* UNPAID */,
|
|
12147
|
-
blockingConditions: aggregatedInfo.blockingConditions,
|
|
12148
|
-
contraindications: aggregatedInfo.contraindications,
|
|
12149
|
-
preProcedureRequirements: aggregatedInfo.preProcedureRequirements,
|
|
12150
|
-
postProcedureRequirements: aggregatedInfo.postProcedureRequirements,
|
|
12151
|
-
completedPreRequirements: [],
|
|
12152
|
-
completedPostRequirements: [],
|
|
12153
|
-
createdAt: serverTimestamp23(),
|
|
12154
|
-
updatedAt: serverTimestamp23()
|
|
12155
|
-
};
|
|
12156
|
-
if (data.initialStatus === "confirmed" /* CONFIRMED */) {
|
|
12157
|
-
appointment.confirmationTime = Timestamp27.now();
|
|
12158
|
-
}
|
|
12159
|
-
await setDoc23(doc26(db, APPOINTMENTS_COLLECTION, appointmentId), appointment);
|
|
12160
|
-
const calendarEventRef = doc26(db, CALENDAR_COLLECTION, data.calendarEventId);
|
|
12161
|
-
await updateDoc25(calendarEventRef, {
|
|
12162
|
-
appointmentId,
|
|
12163
|
-
updatedAt: serverTimestamp23()
|
|
12164
|
-
});
|
|
12165
|
-
const now = Timestamp27.now();
|
|
12166
|
-
return {
|
|
12167
|
-
...appointment,
|
|
12168
|
-
createdAt: now,
|
|
12169
|
-
updatedAt: now
|
|
12170
|
-
};
|
|
12171
|
-
} catch (error) {
|
|
12172
|
-
console.error("Error creating appointment:", error);
|
|
12173
|
-
throw error;
|
|
12174
|
-
}
|
|
12175
|
-
}
|
|
12176
12274
|
async function updateAppointmentUtil2(db, appointmentId, data) {
|
|
12177
12275
|
try {
|
|
12178
12276
|
const appointmentRef = doc26(db, APPOINTMENTS_COLLECTION, appointmentId);
|
|
@@ -12274,7 +12372,7 @@ async function updateCalendarEventStatus(db, calendarEventId, appointmentStatus)
|
|
|
12274
12372
|
case "canceled_clinic" /* CANCELED_CLINIC */:
|
|
12275
12373
|
calendarStatus = "canceled";
|
|
12276
12374
|
break;
|
|
12277
|
-
case
|
|
12375
|
+
case AppointmentStatus.RESCHEDULED:
|
|
12278
12376
|
calendarStatus = "rescheduled";
|
|
12279
12377
|
break;
|
|
12280
12378
|
case "completed" /* COMPLETED */:
|
|
@@ -12348,7 +12446,7 @@ async function searchAppointmentsUtil(db, params) {
|
|
|
12348
12446
|
const q = query25(collection25(db, APPOINTMENTS_COLLECTION), ...constraints);
|
|
12349
12447
|
const querySnapshot = await getDocs25(q);
|
|
12350
12448
|
const appointments = querySnapshot.docs.map(
|
|
12351
|
-
(
|
|
12449
|
+
(doc33) => doc33.data()
|
|
12352
12450
|
);
|
|
12353
12451
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
12354
12452
|
return { appointments, lastDoc };
|
|
@@ -12371,86 +12469,15 @@ var AppointmentService = class extends BaseService {
|
|
|
12371
12469
|
* @param practitionerService Practitioner service instance
|
|
12372
12470
|
* @param clinicService Clinic service instance
|
|
12373
12471
|
*/
|
|
12374
|
-
constructor(db, auth, app, calendarService, patientService, practitionerService, clinicService) {
|
|
12472
|
+
constructor(db, auth, app, calendarService, patientService, practitionerService, clinicService, filledDocumentService) {
|
|
12375
12473
|
super(db, auth, app);
|
|
12376
12474
|
this.calendarService = calendarService;
|
|
12377
12475
|
this.patientService = patientService;
|
|
12378
12476
|
this.practitionerService = practitionerService;
|
|
12379
12477
|
this.clinicService = clinicService;
|
|
12478
|
+
this.filledDocumentService = filledDocumentService;
|
|
12380
12479
|
this.functions = getFunctions(app, "europe-west6");
|
|
12381
12480
|
}
|
|
12382
|
-
/**
|
|
12383
|
-
* Test method using the callable function version of getAvailableBookingSlots
|
|
12384
|
-
* For development and testing purposes only - not for production use
|
|
12385
|
-
*
|
|
12386
|
-
* @param clinicId ID of the clinic
|
|
12387
|
-
* @param practitionerId ID of the practitioner
|
|
12388
|
-
* @param procedureId ID of the procedure
|
|
12389
|
-
* @param startDate Start date of the time range to check
|
|
12390
|
-
* @param endDate End date of the time range to check
|
|
12391
|
-
* @returns Test result from the callable function
|
|
12392
|
-
*/
|
|
12393
|
-
async testGetAvailableBookingSlots(clinicId, practitionerId, procedureId, startDate, endDate) {
|
|
12394
|
-
try {
|
|
12395
|
-
console.log(
|
|
12396
|
-
`[APPOINTMENT_SERVICE] Testing callable function for clinic: ${clinicId}, practitioner: ${practitionerId}, procedure: ${procedureId}`
|
|
12397
|
-
);
|
|
12398
|
-
const getAvailableBookingSlotsCallable = httpsCallable(
|
|
12399
|
-
this.functions,
|
|
12400
|
-
"getAvailableBookingSlots"
|
|
12401
|
-
);
|
|
12402
|
-
const result = await getAvailableBookingSlotsCallable({
|
|
12403
|
-
clinicId,
|
|
12404
|
-
practitionerId,
|
|
12405
|
-
procedureId,
|
|
12406
|
-
timeframe: {
|
|
12407
|
-
start: startDate.getTime(),
|
|
12408
|
-
end: endDate.getTime()
|
|
12409
|
-
}
|
|
12410
|
-
});
|
|
12411
|
-
console.log(
|
|
12412
|
-
"[APPOINTMENT_SERVICE] Callable function test result:",
|
|
12413
|
-
result.data
|
|
12414
|
-
);
|
|
12415
|
-
return result.data;
|
|
12416
|
-
} catch (error) {
|
|
12417
|
-
console.error(
|
|
12418
|
-
"[APPOINTMENT_SERVICE] Error testing callable function:",
|
|
12419
|
-
error
|
|
12420
|
-
);
|
|
12421
|
-
throw error;
|
|
12422
|
-
}
|
|
12423
|
-
}
|
|
12424
|
-
/**
|
|
12425
|
-
* Gets available booking slots for a specific clinic, practitioner, and procedure.
|
|
12426
|
-
*
|
|
12427
|
-
* @param clinicId ID of the clinic
|
|
12428
|
-
* @param practitionerId ID of the practitioner
|
|
12429
|
-
* @param procedureId ID of the procedure
|
|
12430
|
-
* @param startDate Start date of the time range to check
|
|
12431
|
-
* @param endDate End date of the time range to check
|
|
12432
|
-
* @returns Array of available booking slots
|
|
12433
|
-
*/
|
|
12434
|
-
async getAvailableBookingSlots(clinicId, practitionerId, procedureId, startDate, endDate) {
|
|
12435
|
-
try {
|
|
12436
|
-
console.log(
|
|
12437
|
-
`[APPOINTMENT_SERVICE] Getting available booking slots for clinic: ${clinicId}, practitioner: ${practitionerId}, procedure: ${procedureId}`
|
|
12438
|
-
);
|
|
12439
|
-
return this.getAvailableBookingSlotsHttp(
|
|
12440
|
-
clinicId,
|
|
12441
|
-
practitionerId,
|
|
12442
|
-
procedureId,
|
|
12443
|
-
startDate,
|
|
12444
|
-
endDate
|
|
12445
|
-
);
|
|
12446
|
-
} catch (error) {
|
|
12447
|
-
console.error(
|
|
12448
|
-
"[APPOINTMENT_SERVICE] Error getting available booking slots:",
|
|
12449
|
-
error
|
|
12450
|
-
);
|
|
12451
|
-
throw error;
|
|
12452
|
-
}
|
|
12453
|
-
}
|
|
12454
12481
|
/**
|
|
12455
12482
|
* Gets available booking slots for a specific clinic, practitioner, and procedure using HTTP request.
|
|
12456
12483
|
* This is an alternative implementation using direct HTTP request instead of callable function.
|
|
@@ -12552,49 +12579,96 @@ var AppointmentService = class extends BaseService {
|
|
|
12552
12579
|
}
|
|
12553
12580
|
}
|
|
12554
12581
|
/**
|
|
12555
|
-
* Creates
|
|
12582
|
+
* Creates an appointment via the Cloud Function orchestrateAppointmentCreation
|
|
12556
12583
|
*
|
|
12557
|
-
* @param data
|
|
12584
|
+
* @param data - CreateAppointmentData object
|
|
12558
12585
|
* @returns The created appointment
|
|
12559
12586
|
*/
|
|
12560
|
-
async
|
|
12587
|
+
async createAppointmentHttp(data) {
|
|
12561
12588
|
try {
|
|
12562
|
-
console.log("[APPOINTMENT_SERVICE] Creating appointment");
|
|
12563
|
-
const validatedData = await createAppointmentSchema.parseAsync(data);
|
|
12564
|
-
const aggregatedInfo = await fetchAggregatedInfoUtil(
|
|
12565
|
-
this.db,
|
|
12566
|
-
validatedData.clinicBranchId,
|
|
12567
|
-
validatedData.practitionerId,
|
|
12568
|
-
validatedData.patientId,
|
|
12569
|
-
validatedData.procedureId
|
|
12570
|
-
);
|
|
12571
|
-
const appointment = await createAppointmentUtil2(
|
|
12572
|
-
this.db,
|
|
12573
|
-
validatedData,
|
|
12574
|
-
aggregatedInfo,
|
|
12575
|
-
this.generateId.bind(this)
|
|
12576
|
-
);
|
|
12577
12589
|
console.log(
|
|
12578
|
-
|
|
12590
|
+
"[APPOINTMENT_SERVICE] Creating appointment via cloud function"
|
|
12579
12591
|
);
|
|
12580
|
-
|
|
12581
|
-
|
|
12582
|
-
|
|
12583
|
-
|
|
12584
|
-
|
|
12585
|
-
|
|
12586
|
-
|
|
12587
|
-
|
|
12588
|
-
|
|
12589
|
-
|
|
12590
|
-
|
|
12591
|
-
|
|
12592
|
-
|
|
12593
|
-
try {
|
|
12592
|
+
const currentUser = this.auth.currentUser;
|
|
12593
|
+
if (!currentUser) {
|
|
12594
|
+
throw new Error("User must be authenticated to create an appointment");
|
|
12595
|
+
}
|
|
12596
|
+
const idToken = await currentUser.getIdToken();
|
|
12597
|
+
const functionUrl = `https://europe-west6-metaestetics.cloudfunctions.net/bookingApi/orchestrateAppointmentCreation`;
|
|
12598
|
+
const requestData = {
|
|
12599
|
+
patientId: data.patientId,
|
|
12600
|
+
procedureId: data.procedureId,
|
|
12601
|
+
appointmentStartTime: data.appointmentStartTime.toMillis ? data.appointmentStartTime.toMillis() : new Date(data.appointmentStartTime).getTime(),
|
|
12602
|
+
appointmentEndTime: data.appointmentEndTime.toMillis ? data.appointmentEndTime.toMillis() : new Date(data.appointmentEndTime).getTime(),
|
|
12603
|
+
patientNotes: data.patientNotes || null
|
|
12604
|
+
};
|
|
12594
12605
|
console.log(
|
|
12595
|
-
`[APPOINTMENT_SERVICE]
|
|
12606
|
+
`[APPOINTMENT_SERVICE] Making fetch request to ${functionUrl}`
|
|
12596
12607
|
);
|
|
12597
|
-
const
|
|
12608
|
+
const response = await fetch(functionUrl, {
|
|
12609
|
+
method: "POST",
|
|
12610
|
+
mode: "cors",
|
|
12611
|
+
cache: "no-cache",
|
|
12612
|
+
credentials: "omit",
|
|
12613
|
+
headers: {
|
|
12614
|
+
"Content-Type": "application/json",
|
|
12615
|
+
Authorization: `Bearer ${idToken}`
|
|
12616
|
+
},
|
|
12617
|
+
redirect: "follow",
|
|
12618
|
+
referrerPolicy: "no-referrer",
|
|
12619
|
+
body: JSON.stringify(requestData)
|
|
12620
|
+
});
|
|
12621
|
+
console.log(
|
|
12622
|
+
`[APPOINTMENT_SERVICE] Received response ${response.status}: ${response.statusText}`
|
|
12623
|
+
);
|
|
12624
|
+
if (!response.ok) {
|
|
12625
|
+
const errorText = await response.text();
|
|
12626
|
+
console.error(
|
|
12627
|
+
`[APPOINTMENT_SERVICE] Error response details: ${errorText}`
|
|
12628
|
+
);
|
|
12629
|
+
throw new Error(
|
|
12630
|
+
`Failed to create appointment: ${response.status} ${response.statusText} - ${errorText}`
|
|
12631
|
+
);
|
|
12632
|
+
}
|
|
12633
|
+
const result = await response.json();
|
|
12634
|
+
if (!result.success) {
|
|
12635
|
+
throw new Error(result.error || "Failed to create appointment");
|
|
12636
|
+
}
|
|
12637
|
+
if (result.appointmentData) {
|
|
12638
|
+
console.log(
|
|
12639
|
+
`[APPOINTMENT_SERVICE] Appointment created with ID: ${result.appointmentId}`
|
|
12640
|
+
);
|
|
12641
|
+
return result.appointmentData;
|
|
12642
|
+
}
|
|
12643
|
+
const createdAppointment = await this.getAppointmentById(
|
|
12644
|
+
result.appointmentId
|
|
12645
|
+
);
|
|
12646
|
+
if (!createdAppointment) {
|
|
12647
|
+
throw new Error(
|
|
12648
|
+
`Failed to retrieve created appointment with ID: ${result.appointmentId}`
|
|
12649
|
+
);
|
|
12650
|
+
}
|
|
12651
|
+
return createdAppointment;
|
|
12652
|
+
} catch (error) {
|
|
12653
|
+
console.error(
|
|
12654
|
+
"[APPOINTMENT_SERVICE] Error creating appointment via cloud function:",
|
|
12655
|
+
error
|
|
12656
|
+
);
|
|
12657
|
+
throw error;
|
|
12658
|
+
}
|
|
12659
|
+
}
|
|
12660
|
+
/**
|
|
12661
|
+
* Gets an appointment by ID.
|
|
12662
|
+
*
|
|
12663
|
+
* @param appointmentId ID of the appointment to retrieve
|
|
12664
|
+
* @returns The appointment or null if not found
|
|
12665
|
+
*/
|
|
12666
|
+
async getAppointmentById(appointmentId) {
|
|
12667
|
+
try {
|
|
12668
|
+
console.log(
|
|
12669
|
+
`[APPOINTMENT_SERVICE] Getting appointment with ID: ${appointmentId}`
|
|
12670
|
+
);
|
|
12671
|
+
const appointment = await getAppointmentByIdUtil(this.db, appointmentId);
|
|
12598
12672
|
console.log(
|
|
12599
12673
|
`[APPOINTMENT_SERVICE] Appointment ${appointmentId} ${appointment ? "found" : "not found"}`
|
|
12600
12674
|
);
|
|
@@ -12732,192 +12806,340 @@ var AppointmentService = class extends BaseService {
|
|
|
12732
12806
|
*
|
|
12733
12807
|
* @param appointmentId ID of the appointment
|
|
12734
12808
|
* @param newStatus New status to set
|
|
12735
|
-
* @param
|
|
12736
|
-
* @param canceledBy Required if canceling the appointment
|
|
12809
|
+
* @param details Optional details for the status change
|
|
12737
12810
|
* @returns The updated appointment
|
|
12738
12811
|
*/
|
|
12739
|
-
async updateAppointmentStatus(appointmentId, newStatus,
|
|
12812
|
+
async updateAppointmentStatus(appointmentId, newStatus, details) {
|
|
12740
12813
|
console.log(
|
|
12741
12814
|
`[APPOINTMENT_SERVICE] Updating status of appointment ${appointmentId} to ${newStatus}`
|
|
12742
12815
|
);
|
|
12743
|
-
const updateData = {
|
|
12744
|
-
|
|
12745
|
-
|
|
12746
|
-
|
|
12747
|
-
|
|
12748
|
-
|
|
12816
|
+
const updateData = {
|
|
12817
|
+
status: newStatus,
|
|
12818
|
+
updatedAt: serverTimestamp24()
|
|
12819
|
+
};
|
|
12820
|
+
if (newStatus === "canceled_clinic" /* CANCELED_CLINIC */ || newStatus === "canceled_patient" /* CANCELED_PATIENT */ || newStatus === "canceled_patient_rescheduled" /* CANCELED_PATIENT_RESCHEDULED */) {
|
|
12821
|
+
if (!(details == null ? void 0 : details.cancellationReason)) {
|
|
12822
|
+
throw new Error("Cancellation reason is required when canceling.");
|
|
12749
12823
|
}
|
|
12750
|
-
if (!canceledBy) {
|
|
12751
|
-
throw new Error(
|
|
12752
|
-
"Canceled by is required when canceling an appointment"
|
|
12753
|
-
);
|
|
12824
|
+
if (!(details == null ? void 0 : details.canceledBy)) {
|
|
12825
|
+
throw new Error("Canceled by is required when canceling.");
|
|
12754
12826
|
}
|
|
12755
|
-
updateData.cancellationReason = cancellationReason;
|
|
12756
|
-
updateData.canceledBy = canceledBy;
|
|
12827
|
+
updateData.cancellationReason = details.cancellationReason;
|
|
12828
|
+
updateData.canceledBy = details.canceledBy;
|
|
12829
|
+
updateData.cancellationTime = Timestamp28.now();
|
|
12757
12830
|
}
|
|
12758
12831
|
if (newStatus === "confirmed" /* CONFIRMED */) {
|
|
12759
12832
|
updateData.confirmationTime = Timestamp28.now();
|
|
12760
12833
|
}
|
|
12834
|
+
if (newStatus === "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
|
|
12835
|
+
updateData.rescheduleTime = Timestamp28.now();
|
|
12836
|
+
}
|
|
12761
12837
|
return this.updateAppointment(appointmentId, updateData);
|
|
12762
12838
|
}
|
|
12763
12839
|
/**
|
|
12764
|
-
* Confirms an
|
|
12765
|
-
*
|
|
12766
|
-
* @param appointmentId ID of the appointment to confirm
|
|
12767
|
-
* @returns The confirmed appointment
|
|
12840
|
+
* Confirms a PENDING appointment by an Admin/Clinic.
|
|
12768
12841
|
*/
|
|
12769
|
-
async
|
|
12842
|
+
async confirmAppointmentAdmin(appointmentId) {
|
|
12770
12843
|
console.log(
|
|
12771
|
-
`[APPOINTMENT_SERVICE]
|
|
12844
|
+
`[APPOINTMENT_SERVICE] Admin confirming appointment: ${appointmentId}`
|
|
12772
12845
|
);
|
|
12846
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
12847
|
+
if (!appointment)
|
|
12848
|
+
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
12849
|
+
if (appointment.status !== "pending" /* PENDING */) {
|
|
12850
|
+
throw new Error(
|
|
12851
|
+
`Appointment ${appointmentId} is not in PENDING state to be confirmed.`
|
|
12852
|
+
);
|
|
12853
|
+
}
|
|
12773
12854
|
return this.updateAppointmentStatus(
|
|
12774
12855
|
appointmentId,
|
|
12775
12856
|
"confirmed" /* CONFIRMED */
|
|
12776
12857
|
);
|
|
12777
12858
|
}
|
|
12778
12859
|
/**
|
|
12779
|
-
* Cancels an appointment
|
|
12780
|
-
*
|
|
12781
|
-
* @param appointmentId ID of the appointment to cancel
|
|
12782
|
-
* @param reason Reason for cancellation
|
|
12783
|
-
* @returns The canceled appointment
|
|
12860
|
+
* Cancels an appointment by the User (Patient).
|
|
12784
12861
|
*/
|
|
12785
|
-
async
|
|
12862
|
+
async cancelAppointmentUser(appointmentId, reason) {
|
|
12786
12863
|
console.log(
|
|
12787
|
-
`[APPOINTMENT_SERVICE]
|
|
12864
|
+
`[APPOINTMENT_SERVICE] User canceling appointment: ${appointmentId}`
|
|
12865
|
+
);
|
|
12866
|
+
return this.updateAppointmentStatus(
|
|
12867
|
+
appointmentId,
|
|
12868
|
+
"canceled_patient" /* CANCELED_PATIENT */,
|
|
12869
|
+
{
|
|
12870
|
+
cancellationReason: reason,
|
|
12871
|
+
canceledBy: "patient"
|
|
12872
|
+
}
|
|
12873
|
+
);
|
|
12874
|
+
}
|
|
12875
|
+
/**
|
|
12876
|
+
* Cancels an appointment by an Admin/Clinic.
|
|
12877
|
+
*/
|
|
12878
|
+
async cancelAppointmentAdmin(appointmentId, reason) {
|
|
12879
|
+
console.log(
|
|
12880
|
+
`[APPOINTMENT_SERVICE] Admin canceling appointment: ${appointmentId}`
|
|
12788
12881
|
);
|
|
12789
12882
|
return this.updateAppointmentStatus(
|
|
12790
12883
|
appointmentId,
|
|
12791
12884
|
"canceled_clinic" /* CANCELED_CLINIC */,
|
|
12792
|
-
|
|
12793
|
-
|
|
12885
|
+
{
|
|
12886
|
+
cancellationReason: reason,
|
|
12887
|
+
canceledBy: "clinic"
|
|
12888
|
+
}
|
|
12794
12889
|
);
|
|
12795
12890
|
}
|
|
12796
12891
|
/**
|
|
12797
|
-
*
|
|
12798
|
-
*
|
|
12799
|
-
* @param appointmentId ID of the appointment to cancel
|
|
12800
|
-
* @param reason Reason for cancellation
|
|
12801
|
-
* @returns The canceled appointment
|
|
12892
|
+
* Admin proposes to reschedule an appointment.
|
|
12893
|
+
* Sets status to RESCHEDULED_BY_CLINIC and updates times.
|
|
12802
12894
|
*/
|
|
12803
|
-
async
|
|
12895
|
+
async rescheduleAppointmentAdmin(appointmentId, newStartTime, newEndTime) {
|
|
12804
12896
|
console.log(
|
|
12805
|
-
`[APPOINTMENT_SERVICE]
|
|
12897
|
+
`[APPOINTMENT_SERVICE] Admin rescheduling appointment: ${appointmentId}`
|
|
12806
12898
|
);
|
|
12899
|
+
if (newEndTime.toMillis() <= newStartTime.toMillis()) {
|
|
12900
|
+
throw new Error("New end time must be after new start time.");
|
|
12901
|
+
}
|
|
12902
|
+
const updateData = {
|
|
12903
|
+
status: "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */,
|
|
12904
|
+
appointmentStartTime: newStartTime,
|
|
12905
|
+
appointmentEndTime: newEndTime,
|
|
12906
|
+
rescheduleTime: Timestamp28.now(),
|
|
12907
|
+
confirmationTime: null,
|
|
12908
|
+
updatedAt: serverTimestamp24()
|
|
12909
|
+
};
|
|
12910
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
12911
|
+
}
|
|
12912
|
+
/**
|
|
12913
|
+
* User confirms a reschedule proposed by the clinic.
|
|
12914
|
+
* Status changes from RESCHEDULED_BY_CLINIC to CONFIRMED.
|
|
12915
|
+
*/
|
|
12916
|
+
async rescheduleAppointmentConfirmUser(appointmentId) {
|
|
12917
|
+
console.log(
|
|
12918
|
+
`[APPOINTMENT_SERVICE] User confirming reschedule for: ${appointmentId}`
|
|
12919
|
+
);
|
|
12920
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
12921
|
+
if (!appointment)
|
|
12922
|
+
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
12923
|
+
if (appointment.status !== "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
|
|
12924
|
+
throw new Error(
|
|
12925
|
+
`Appointment ${appointmentId} is not in RESCHEDULED_BY_CLINIC state.`
|
|
12926
|
+
);
|
|
12927
|
+
}
|
|
12807
12928
|
return this.updateAppointmentStatus(
|
|
12808
12929
|
appointmentId,
|
|
12809
|
-
"
|
|
12810
|
-
reason,
|
|
12811
|
-
"patient"
|
|
12930
|
+
"confirmed" /* CONFIRMED */
|
|
12812
12931
|
);
|
|
12813
12932
|
}
|
|
12814
12933
|
/**
|
|
12815
|
-
*
|
|
12816
|
-
*
|
|
12817
|
-
* @param appointmentId ID of the appointment
|
|
12818
|
-
* @returns The updated appointment
|
|
12934
|
+
* User rejects a reschedule proposed by the clinic.
|
|
12935
|
+
* Status changes from RESCHEDULED_BY_CLINIC to CANCELED_PATIENT_RESCHEDULED.
|
|
12819
12936
|
*/
|
|
12820
|
-
async
|
|
12937
|
+
async rescheduleAppointmentRejectUser(appointmentId, reason) {
|
|
12821
12938
|
console.log(
|
|
12822
|
-
`[APPOINTMENT_SERVICE]
|
|
12939
|
+
`[APPOINTMENT_SERVICE] User rejecting reschedule for: ${appointmentId}`
|
|
12823
12940
|
);
|
|
12941
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
12942
|
+
if (!appointment)
|
|
12943
|
+
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
12944
|
+
if (appointment.status !== "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
|
|
12945
|
+
throw new Error(
|
|
12946
|
+
`Appointment ${appointmentId} is not in RESCHEDULED_BY_CLINIC state.`
|
|
12947
|
+
);
|
|
12948
|
+
}
|
|
12824
12949
|
return this.updateAppointmentStatus(
|
|
12825
12950
|
appointmentId,
|
|
12826
|
-
"
|
|
12951
|
+
"canceled_patient_rescheduled" /* CANCELED_PATIENT_RESCHEDULED */,
|
|
12952
|
+
{
|
|
12953
|
+
cancellationReason: reason,
|
|
12954
|
+
canceledBy: "patient"
|
|
12955
|
+
}
|
|
12827
12956
|
);
|
|
12828
12957
|
}
|
|
12829
12958
|
/**
|
|
12830
|
-
*
|
|
12831
|
-
*
|
|
12832
|
-
* @param appointmentId ID of the appointment
|
|
12833
|
-
* @returns The updated appointment
|
|
12959
|
+
* Admin checks in a patient for their appointment.
|
|
12960
|
+
* Requires all pending user forms to be completed.
|
|
12834
12961
|
*/
|
|
12835
|
-
async
|
|
12836
|
-
console.log(
|
|
12962
|
+
async checkInPatientAdmin(appointmentId) {
|
|
12963
|
+
console.log(
|
|
12964
|
+
`[APPOINTMENT_SERVICE] Admin checking in patient for: ${appointmentId}`
|
|
12965
|
+
);
|
|
12966
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
12967
|
+
if (!appointment)
|
|
12968
|
+
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
12969
|
+
if (appointment.pendingUserFormsIds && appointment.pendingUserFormsIds.length > 0) {
|
|
12970
|
+
throw new Error(
|
|
12971
|
+
`Cannot check in: Patient has ${appointment.pendingUserFormsIds.length} pending required form(s). IDs: ${appointment.pendingUserFormsIds.join(
|
|
12972
|
+
", "
|
|
12973
|
+
)}`
|
|
12974
|
+
);
|
|
12975
|
+
}
|
|
12976
|
+
if (appointment.status !== "confirmed" /* CONFIRMED */ && appointment.status !== "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
|
|
12977
|
+
console.warn(
|
|
12978
|
+
`Checking in appointment ${appointmentId} with status ${appointment.status}. Ensure this is intended.`
|
|
12979
|
+
);
|
|
12980
|
+
}
|
|
12837
12981
|
return this.updateAppointmentStatus(
|
|
12838
12982
|
appointmentId,
|
|
12839
|
-
"
|
|
12983
|
+
"checked_in" /* CHECKED_IN */
|
|
12840
12984
|
);
|
|
12841
12985
|
}
|
|
12842
12986
|
/**
|
|
12843
|
-
*
|
|
12844
|
-
*
|
|
12845
|
-
* @param appointmentId ID of the appointment
|
|
12846
|
-
* @param actualDurationMinutes Actual duration of the appointment in minutes
|
|
12847
|
-
* @returns The updated appointment
|
|
12987
|
+
* Doctor starts the appointment procedure.
|
|
12848
12988
|
*/
|
|
12849
|
-
async
|
|
12989
|
+
async startAppointmentDoctor(appointmentId) {
|
|
12850
12990
|
console.log(
|
|
12851
|
-
`[APPOINTMENT_SERVICE]
|
|
12991
|
+
`[APPOINTMENT_SERVICE] Doctor starting appointment: ${appointmentId}`
|
|
12852
12992
|
);
|
|
12993
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
12994
|
+
if (!appointment)
|
|
12995
|
+
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
12996
|
+
if (appointment.status !== "checked_in" /* CHECKED_IN */) {
|
|
12997
|
+
throw new Error(
|
|
12998
|
+
`Appointment ${appointmentId} must be CHECKED_IN to start.`
|
|
12999
|
+
);
|
|
13000
|
+
}
|
|
13001
|
+
const updateData = {
|
|
13002
|
+
status: "in_progress" /* IN_PROGRESS */,
|
|
13003
|
+
procedureActualStartTime: Timestamp28.now(),
|
|
13004
|
+
// Set actual start time
|
|
13005
|
+
updatedAt: serverTimestamp24()
|
|
13006
|
+
};
|
|
13007
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
13008
|
+
}
|
|
13009
|
+
/**
|
|
13010
|
+
* Doctor completes and finalizes the appointment.
|
|
13011
|
+
*/
|
|
13012
|
+
async completeAppointmentDoctor(appointmentId, finalizationNotes, actualDurationMinutesInput) {
|
|
13013
|
+
console.log(
|
|
13014
|
+
`[APPOINTMENT_SERVICE] Doctor completing appointment: ${appointmentId}`
|
|
13015
|
+
);
|
|
13016
|
+
const currentUser = this.auth.currentUser;
|
|
13017
|
+
if (!currentUser)
|
|
13018
|
+
throw new Error("Authentication required to complete appointment.");
|
|
13019
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
13020
|
+
if (!appointment)
|
|
13021
|
+
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
13022
|
+
let calculatedDurationMinutes = actualDurationMinutesInput;
|
|
13023
|
+
const procedureCompletionTime = Timestamp28.now();
|
|
13024
|
+
if (calculatedDurationMinutes === void 0 && appointment.procedureActualStartTime) {
|
|
13025
|
+
const startTimeMillis = appointment.procedureActualStartTime.toMillis();
|
|
13026
|
+
const endTimeMillis = procedureCompletionTime.toMillis();
|
|
13027
|
+
if (endTimeMillis > startTimeMillis) {
|
|
13028
|
+
calculatedDurationMinutes = Math.round(
|
|
13029
|
+
(endTimeMillis - startTimeMillis) / 6e4
|
|
13030
|
+
);
|
|
13031
|
+
}
|
|
13032
|
+
}
|
|
12853
13033
|
const updateData = {
|
|
12854
13034
|
status: "completed" /* COMPLETED */,
|
|
12855
|
-
actualDurationMinutes
|
|
13035
|
+
actualDurationMinutes: calculatedDurationMinutes,
|
|
13036
|
+
// Use calculated or provided duration
|
|
13037
|
+
finalizedDetails: {
|
|
13038
|
+
by: currentUser.uid,
|
|
13039
|
+
// This is used ID, not practitioner's profile ID (just so we know who completed the appointment)
|
|
13040
|
+
at: procedureCompletionTime,
|
|
13041
|
+
// Use consistent completion timestamp
|
|
13042
|
+
notes: finalizationNotes
|
|
13043
|
+
},
|
|
13044
|
+
// Optionally update appointmentEndTime to the actual completion time
|
|
13045
|
+
// appointmentEndTime: procedureCompletionTime,
|
|
13046
|
+
updatedAt: serverTimestamp24()
|
|
12856
13047
|
};
|
|
12857
13048
|
return this.updateAppointment(appointmentId, updateData);
|
|
12858
13049
|
}
|
|
12859
13050
|
/**
|
|
12860
|
-
*
|
|
12861
|
-
*
|
|
12862
|
-
* @param appointmentId ID of the appointment
|
|
12863
|
-
* @returns The updated appointment
|
|
13051
|
+
* Admin marks an appointment as No-Show.
|
|
12864
13052
|
*/
|
|
12865
|
-
async
|
|
13053
|
+
async markNoShowAdmin(appointmentId) {
|
|
12866
13054
|
console.log(
|
|
12867
|
-
`[APPOINTMENT_SERVICE]
|
|
13055
|
+
`[APPOINTMENT_SERVICE] Admin marking no-show for: ${appointmentId}`
|
|
12868
13056
|
);
|
|
13057
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
13058
|
+
if (!appointment)
|
|
13059
|
+
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
13060
|
+
if (Timestamp28.now().toMillis() < appointment.appointmentStartTime.toMillis()) {
|
|
13061
|
+
throw new Error("Cannot mark no-show before appointment start time.");
|
|
13062
|
+
}
|
|
12869
13063
|
return this.updateAppointmentStatus(
|
|
12870
13064
|
appointmentId,
|
|
12871
|
-
"no_show" /* NO_SHOW
|
|
13065
|
+
"no_show" /* NO_SHOW */,
|
|
13066
|
+
{
|
|
13067
|
+
cancellationReason: "Patient did not show up for the appointment.",
|
|
13068
|
+
canceledBy: "clinic"
|
|
13069
|
+
}
|
|
12872
13070
|
);
|
|
12873
13071
|
}
|
|
12874
13072
|
/**
|
|
12875
|
-
*
|
|
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
|
|
13073
|
+
* Adds a media item to an appointment.
|
|
12881
13074
|
*/
|
|
12882
|
-
async
|
|
13075
|
+
async addMediaToAppointment(appointmentId, mediaItemData) {
|
|
12883
13076
|
console.log(
|
|
12884
|
-
`[APPOINTMENT_SERVICE]
|
|
13077
|
+
`[APPOINTMENT_SERVICE] Adding media to appointment ${appointmentId}`
|
|
13078
|
+
);
|
|
13079
|
+
const currentUser = this.auth.currentUser;
|
|
13080
|
+
if (!currentUser) throw new Error("Authentication required.");
|
|
13081
|
+
const newMediaItem = {
|
|
13082
|
+
...mediaItemData,
|
|
13083
|
+
id: this.generateId(),
|
|
13084
|
+
uploadedAt: Timestamp28.now(),
|
|
13085
|
+
uploadedBy: currentUser.uid
|
|
13086
|
+
};
|
|
13087
|
+
const updateData = {
|
|
13088
|
+
media: arrayUnion8(newMediaItem),
|
|
13089
|
+
updatedAt: serverTimestamp24()
|
|
13090
|
+
};
|
|
13091
|
+
return this.updateAppointment(appointmentId, updateData);
|
|
13092
|
+
}
|
|
13093
|
+
/**
|
|
13094
|
+
* Removes a media item from an appointment.
|
|
13095
|
+
*/
|
|
13096
|
+
async removeMediaFromAppointment(appointmentId, mediaItemId) {
|
|
13097
|
+
console.log(
|
|
13098
|
+
`[APPOINTMENT_SERVICE] Removing media ${mediaItemId} from appointment ${appointmentId}`
|
|
12885
13099
|
);
|
|
13100
|
+
const appointment = await this.getAppointmentById(appointmentId);
|
|
13101
|
+
if (!appointment || !appointment.media) {
|
|
13102
|
+
throw new Error("Appointment or media list not found.");
|
|
13103
|
+
}
|
|
13104
|
+
const mediaToRemove = appointment.media.find((m) => m.id === mediaItemId);
|
|
13105
|
+
if (!mediaToRemove) {
|
|
13106
|
+
throw new Error(`Media item ${mediaItemId} not found in appointment.`);
|
|
13107
|
+
}
|
|
12886
13108
|
const updateData = {
|
|
12887
|
-
|
|
12888
|
-
|
|
13109
|
+
media: arrayRemove7(mediaToRemove),
|
|
13110
|
+
updatedAt: serverTimestamp24()
|
|
12889
13111
|
};
|
|
12890
13112
|
return this.updateAppointment(appointmentId, updateData);
|
|
12891
13113
|
}
|
|
12892
13114
|
/**
|
|
12893
|
-
*
|
|
12894
|
-
*
|
|
12895
|
-
* @param appointmentId ID of the appointment
|
|
12896
|
-
* @param requirementIds IDs of the requirements to mark as completed
|
|
12897
|
-
* @returns The updated appointment
|
|
13115
|
+
* Adds or updates review information for an appointment.
|
|
12898
13116
|
*/
|
|
12899
|
-
async
|
|
13117
|
+
async addReviewToAppointment(appointmentId, reviewData) {
|
|
12900
13118
|
console.log(
|
|
12901
|
-
`[APPOINTMENT_SERVICE]
|
|
13119
|
+
`[APPOINTMENT_SERVICE] Adding review to appointment ${appointmentId}`
|
|
12902
13120
|
);
|
|
13121
|
+
const newReviewInfo = {
|
|
13122
|
+
...reviewData,
|
|
13123
|
+
reviewId: this.generateId(),
|
|
13124
|
+
reviewedAt: Timestamp28.now()
|
|
13125
|
+
};
|
|
12903
13126
|
const updateData = {
|
|
12904
|
-
|
|
13127
|
+
reviewInfo: newReviewInfo,
|
|
13128
|
+
updatedAt: serverTimestamp24()
|
|
12905
13129
|
};
|
|
12906
13130
|
return this.updateAppointment(appointmentId, updateData);
|
|
12907
13131
|
}
|
|
12908
13132
|
/**
|
|
12909
|
-
*
|
|
12910
|
-
*
|
|
12911
|
-
* @param appointmentId ID of the appointment
|
|
12912
|
-
* @param requirementIds IDs of the requirements to mark as completed
|
|
12913
|
-
* @returns The updated appointment
|
|
13133
|
+
* Updates the payment status of an appointment.
|
|
12914
13134
|
*/
|
|
12915
|
-
async
|
|
13135
|
+
async updatePaymentStatus(appointmentId, paymentStatus, paymentTransactionId) {
|
|
12916
13136
|
console.log(
|
|
12917
|
-
`[APPOINTMENT_SERVICE]
|
|
13137
|
+
`[APPOINTMENT_SERVICE] Updating payment status of appointment ${appointmentId} to ${paymentStatus}`
|
|
12918
13138
|
);
|
|
12919
13139
|
const updateData = {
|
|
12920
|
-
|
|
13140
|
+
paymentStatus,
|
|
13141
|
+
paymentTransactionId: paymentTransactionId || null,
|
|
13142
|
+
updatedAt: serverTimestamp24()
|
|
12921
13143
|
};
|
|
12922
13144
|
return this.updateAppointment(appointmentId, updateData);
|
|
12923
13145
|
}
|
|
@@ -12937,37 +13159,224 @@ var AppointmentService = class extends BaseService {
|
|
|
12937
13159
|
};
|
|
12938
13160
|
return this.updateAppointment(appointmentId, updateData);
|
|
12939
13161
|
}
|
|
13162
|
+
};
|
|
13163
|
+
|
|
13164
|
+
// src/services/patient/patientRequirements.service.ts
|
|
13165
|
+
import {
|
|
13166
|
+
collection as collection26,
|
|
13167
|
+
getDocs as getDocs26,
|
|
13168
|
+
query as query26,
|
|
13169
|
+
where as where26,
|
|
13170
|
+
doc as doc27,
|
|
13171
|
+
updateDoc as updateDoc26,
|
|
13172
|
+
Timestamp as Timestamp29,
|
|
13173
|
+
orderBy as orderBy13,
|
|
13174
|
+
limit as limit11,
|
|
13175
|
+
startAfter as startAfter11,
|
|
13176
|
+
getDoc as getDoc29
|
|
13177
|
+
} from "firebase/firestore";
|
|
13178
|
+
|
|
13179
|
+
// src/types/patient/patient-requirements.ts
|
|
13180
|
+
var PatientInstructionStatus = /* @__PURE__ */ ((PatientInstructionStatus2) => {
|
|
13181
|
+
PatientInstructionStatus2["PENDING_NOTIFICATION"] = "pendingNotification";
|
|
13182
|
+
PatientInstructionStatus2["ACTION_DUE"] = "actionDue";
|
|
13183
|
+
PatientInstructionStatus2["ACTION_TAKEN"] = "actionTaken";
|
|
13184
|
+
PatientInstructionStatus2["MISSED"] = "missed";
|
|
13185
|
+
PatientInstructionStatus2["CANCELLED"] = "cancelled";
|
|
13186
|
+
PatientInstructionStatus2["SKIPPED"] = "skipped";
|
|
13187
|
+
return PatientInstructionStatus2;
|
|
13188
|
+
})(PatientInstructionStatus || {});
|
|
13189
|
+
var PatientRequirementOverallStatus = /* @__PURE__ */ ((PatientRequirementOverallStatus2) => {
|
|
13190
|
+
PatientRequirementOverallStatus2["ACTIVE"] = "active";
|
|
13191
|
+
PatientRequirementOverallStatus2["ALL_INSTRUCTIONS_MET"] = "allInstructionsMet";
|
|
13192
|
+
PatientRequirementOverallStatus2["PARTIALLY_COMPLETED"] = "partiallyCompleted";
|
|
13193
|
+
PatientRequirementOverallStatus2["FAILED"] = "failed";
|
|
13194
|
+
PatientRequirementOverallStatus2["CANCELLED_APPOINTMENT"] = "cancelledAppointment";
|
|
13195
|
+
PatientRequirementOverallStatus2["SUPERSEDED_RESCHEDULE"] = "supersededReschedule";
|
|
13196
|
+
PatientRequirementOverallStatus2["FAILED_TO_PROCESS"] = "failedToProcess";
|
|
13197
|
+
return PatientRequirementOverallStatus2;
|
|
13198
|
+
})(PatientRequirementOverallStatus || {});
|
|
13199
|
+
var PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME = "patientRequirements";
|
|
13200
|
+
|
|
13201
|
+
// src/services/patient/patientRequirements.service.ts
|
|
13202
|
+
var PatientRequirementsService = class extends BaseService {
|
|
13203
|
+
constructor(db, auth, app) {
|
|
13204
|
+
super(db, auth, app);
|
|
13205
|
+
}
|
|
13206
|
+
getPatientRequirementsCollectionRef(patientId) {
|
|
13207
|
+
return collection26(
|
|
13208
|
+
this.db,
|
|
13209
|
+
`patients/${patientId}/${PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME}`
|
|
13210
|
+
);
|
|
13211
|
+
}
|
|
13212
|
+
getPatientRequirementDocRef(patientId, instanceId) {
|
|
13213
|
+
return doc27(
|
|
13214
|
+
this.getPatientRequirementsCollectionRef(patientId),
|
|
13215
|
+
instanceId
|
|
13216
|
+
);
|
|
13217
|
+
}
|
|
12940
13218
|
/**
|
|
12941
|
-
*
|
|
12942
|
-
*
|
|
13219
|
+
* Gets a specific patient requirement instance by its ID.
|
|
13220
|
+
* @param patientId - The ID of the patient.
|
|
13221
|
+
* @param instanceId - The ID of the requirement instance.
|
|
13222
|
+
* @returns The patient requirement instance or null if not found.
|
|
12943
13223
|
*/
|
|
12944
|
-
async
|
|
12945
|
-
|
|
12946
|
-
|
|
12947
|
-
|
|
12948
|
-
console.log("[APPOINTMENT_SERVICE] No user is signed in");
|
|
12949
|
-
return null;
|
|
12950
|
-
}
|
|
12951
|
-
const idToken = await currentUser.getIdToken();
|
|
12952
|
-
console.log("[APPOINTMENT_SERVICE] Debug token:", idToken);
|
|
12953
|
-
return idToken;
|
|
12954
|
-
} catch (error) {
|
|
12955
|
-
console.error("[APPOINTMENT_SERVICE] Error getting debug token:", error);
|
|
13224
|
+
async getPatientRequirementInstance(patientId, instanceId) {
|
|
13225
|
+
const docRef = this.getPatientRequirementDocRef(patientId, instanceId);
|
|
13226
|
+
const docSnap = await getDoc29(docRef);
|
|
13227
|
+
if (!docSnap.exists()) {
|
|
12956
13228
|
return null;
|
|
12957
13229
|
}
|
|
13230
|
+
const data = docSnap.data();
|
|
13231
|
+
return { id: docSnap.id, ...data };
|
|
12958
13232
|
}
|
|
13233
|
+
/**
|
|
13234
|
+
* Retrieves patient requirement instances based on specified filters.
|
|
13235
|
+
* This is a flexible query method.
|
|
13236
|
+
*
|
|
13237
|
+
* @param patientId - The ID of the patient.
|
|
13238
|
+
* @param filters - Optional filters for appointmentId, overall statuses, instruction statuses, and due timeframes.
|
|
13239
|
+
* @param pageLimit - Optional limit for pagination.
|
|
13240
|
+
* @param lastVisible - Optional last document snapshot for pagination.
|
|
13241
|
+
* @returns A promise resolving to an array of matching patient requirement instances and the last document snapshot.
|
|
13242
|
+
*/
|
|
13243
|
+
async getAllPatientRequirementInstances(patientId, filters, pageLimit = 20, lastVisible) {
|
|
13244
|
+
const collRef = this.getPatientRequirementsCollectionRef(patientId);
|
|
13245
|
+
let q = query26(collRef, orderBy13("createdAt", "desc"));
|
|
13246
|
+
const queryConstraints = [];
|
|
13247
|
+
if ((filters == null ? void 0 : filters.appointmentId) && filters.appointmentId !== "all") {
|
|
13248
|
+
queryConstraints.push(
|
|
13249
|
+
where26("appointmentId", "==", filters.appointmentId)
|
|
13250
|
+
);
|
|
13251
|
+
}
|
|
13252
|
+
if ((filters == null ? void 0 : filters.statuses) && filters.statuses.length > 0) {
|
|
13253
|
+
queryConstraints.push(where26("overallStatus", "in", filters.statuses));
|
|
13254
|
+
}
|
|
13255
|
+
if (lastVisible) {
|
|
13256
|
+
queryConstraints.push(startAfter11(lastVisible));
|
|
13257
|
+
}
|
|
13258
|
+
queryConstraints.push(limit11(pageLimit));
|
|
13259
|
+
q = query26(collRef, ...queryConstraints);
|
|
13260
|
+
const snapshot = await getDocs26(q);
|
|
13261
|
+
let requirements = snapshot.docs.map((docSnap) => {
|
|
13262
|
+
const data = docSnap.data();
|
|
13263
|
+
return { id: docSnap.id, ...data };
|
|
13264
|
+
});
|
|
13265
|
+
if ((filters == null ? void 0 : filters.instructionStatuses) && filters.instructionStatuses.length > 0) {
|
|
13266
|
+
requirements = requirements.filter(
|
|
13267
|
+
(req) => req.instructions.some(
|
|
13268
|
+
(instr) => filters.instructionStatuses.includes(instr.status)
|
|
13269
|
+
)
|
|
13270
|
+
);
|
|
13271
|
+
}
|
|
13272
|
+
if (filters == null ? void 0 : filters.dueBefore) {
|
|
13273
|
+
const dueBeforeMillis = filters.dueBefore.toMillis();
|
|
13274
|
+
requirements = requirements.filter(
|
|
13275
|
+
(req) => req.instructions.some(
|
|
13276
|
+
(instr) => instr.dueTime.toMillis() < dueBeforeMillis
|
|
13277
|
+
)
|
|
13278
|
+
);
|
|
13279
|
+
}
|
|
13280
|
+
if (filters == null ? void 0 : filters.dueAfter) {
|
|
13281
|
+
const dueAfterMillis = filters.dueAfter.toMillis();
|
|
13282
|
+
requirements = requirements.filter(
|
|
13283
|
+
(req) => req.instructions.some(
|
|
13284
|
+
(instr) => instr.dueTime.toMillis() > dueAfterMillis
|
|
13285
|
+
)
|
|
13286
|
+
);
|
|
13287
|
+
}
|
|
13288
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1] || null;
|
|
13289
|
+
return { requirements, lastDoc: newLastVisible };
|
|
13290
|
+
}
|
|
13291
|
+
/**
|
|
13292
|
+
* Marks a specific instruction within a PatientRequirementInstance as ACTION_TAKEN.
|
|
13293
|
+
* If all instructions are actioned, updates the overallStatus of the instance.
|
|
13294
|
+
*
|
|
13295
|
+
* @param patientId - The ID of the patient.
|
|
13296
|
+
* @param instanceId - The ID of the PatientRequirementInstance.
|
|
13297
|
+
* @param instructionId - The ID of the instruction to complete.
|
|
13298
|
+
* @returns The updated PatientRequirementInstance.
|
|
13299
|
+
* @throws Error if the instance or instruction is not found, or if the instruction is not in a completable state.
|
|
13300
|
+
*/
|
|
13301
|
+
async completeInstruction(patientId, instanceId, instructionId) {
|
|
13302
|
+
const instanceRef = this.getPatientRequirementDocRef(patientId, instanceId);
|
|
13303
|
+
const instanceSnap = await getDoc29(instanceRef);
|
|
13304
|
+
if (!instanceSnap.exists()) {
|
|
13305
|
+
throw new Error(
|
|
13306
|
+
`PatientRequirementInstance ${instanceId} not found for patient ${patientId}.`
|
|
13307
|
+
);
|
|
13308
|
+
}
|
|
13309
|
+
const instanceData = instanceSnap.data();
|
|
13310
|
+
const instance = { id: instanceSnap.id, ...instanceData };
|
|
13311
|
+
const instructionIndex = instance.instructions.findIndex(
|
|
13312
|
+
(instr) => instr.instructionId === instructionId
|
|
13313
|
+
);
|
|
13314
|
+
if (instructionIndex === -1) {
|
|
13315
|
+
throw new Error(
|
|
13316
|
+
`Instruction ${instructionId} not found in instance ${instanceId}.`
|
|
13317
|
+
);
|
|
13318
|
+
}
|
|
13319
|
+
const instructionToUpdate = instance.instructions[instructionIndex];
|
|
13320
|
+
if (instructionToUpdate.status !== "pendingNotification" /* PENDING_NOTIFICATION */ && instructionToUpdate.status !== "actionDue" /* ACTION_DUE */ && instructionToUpdate.status !== "missed" /* MISSED */) {
|
|
13321
|
+
if (instructionToUpdate.status === "actionTaken" /* ACTION_TAKEN */) {
|
|
13322
|
+
console.warn(
|
|
13323
|
+
`Instruction ${instructionId} is already marked as ACTION_TAKEN.`
|
|
13324
|
+
);
|
|
13325
|
+
return instance;
|
|
13326
|
+
}
|
|
13327
|
+
throw new Error(
|
|
13328
|
+
`Instruction ${instructionId} is in status ${instructionToUpdate.status} and cannot be marked as completed.`
|
|
13329
|
+
);
|
|
13330
|
+
}
|
|
13331
|
+
const now = Timestamp29.now();
|
|
13332
|
+
const updatedInstructions = [...instance.instructions];
|
|
13333
|
+
updatedInstructions[instructionIndex] = {
|
|
13334
|
+
...instructionToUpdate,
|
|
13335
|
+
status: "actionTaken" /* ACTION_TAKEN */,
|
|
13336
|
+
actionTakenAt: now,
|
|
13337
|
+
updatedAt: now
|
|
13338
|
+
};
|
|
13339
|
+
const allActionTaken = updatedInstructions.every(
|
|
13340
|
+
(instr) => instr.status === "actionTaken" /* ACTION_TAKEN */
|
|
13341
|
+
);
|
|
13342
|
+
let newOverallStatus = instance.overallStatus;
|
|
13343
|
+
if (allActionTaken) {
|
|
13344
|
+
newOverallStatus = "allInstructionsMet" /* ALL_INSTRUCTIONS_MET */;
|
|
13345
|
+
} else if (updatedInstructions.some(
|
|
13346
|
+
(instr) => instr.status === "actionTaken" /* ACTION_TAKEN */
|
|
13347
|
+
)) {
|
|
13348
|
+
newOverallStatus = "partiallyCompleted" /* PARTIALLY_COMPLETED */;
|
|
13349
|
+
}
|
|
13350
|
+
const updatePayload = {
|
|
13351
|
+
// Using a general type for updateDoc payload
|
|
13352
|
+
instructions: updatedInstructions,
|
|
13353
|
+
updatedAt: now
|
|
13354
|
+
};
|
|
13355
|
+
if (newOverallStatus !== instance.overallStatus) {
|
|
13356
|
+
updatePayload.overallStatus = newOverallStatus;
|
|
13357
|
+
}
|
|
13358
|
+
await updateDoc26(instanceRef, updatePayload);
|
|
13359
|
+
return {
|
|
13360
|
+
...instance,
|
|
13361
|
+
instructions: updatedInstructions,
|
|
13362
|
+
updatedAt: now,
|
|
13363
|
+
overallStatus: newOverallStatus
|
|
13364
|
+
};
|
|
13365
|
+
}
|
|
13366
|
+
// Note: As per the request, full CRUD (create, direct update of instance, delete) is not part of this light service,
|
|
13367
|
+
// as those will be handled by Cloud Functions reacting to appointment lifecycle events.
|
|
12959
13368
|
};
|
|
12960
13369
|
|
|
12961
13370
|
// src/backoffice/services/brand.service.ts
|
|
12962
13371
|
import {
|
|
12963
13372
|
addDoc as addDoc3,
|
|
12964
|
-
collection as
|
|
12965
|
-
doc as
|
|
12966
|
-
getDoc as
|
|
12967
|
-
getDocs as
|
|
12968
|
-
query as
|
|
12969
|
-
updateDoc as
|
|
12970
|
-
where as
|
|
13373
|
+
collection as collection27,
|
|
13374
|
+
doc as doc28,
|
|
13375
|
+
getDoc as getDoc30,
|
|
13376
|
+
getDocs as getDocs27,
|
|
13377
|
+
query as query27,
|
|
13378
|
+
updateDoc as updateDoc27,
|
|
13379
|
+
where as where27
|
|
12971
13380
|
} from "firebase/firestore";
|
|
12972
13381
|
|
|
12973
13382
|
// src/backoffice/types/brand.types.ts
|
|
@@ -12979,7 +13388,7 @@ var BrandService = class extends BaseService {
|
|
|
12979
13388
|
* Gets reference to brands collection
|
|
12980
13389
|
*/
|
|
12981
13390
|
getBrandsRef() {
|
|
12982
|
-
return
|
|
13391
|
+
return collection27(this.db, BRANDS_COLLECTION);
|
|
12983
13392
|
}
|
|
12984
13393
|
/**
|
|
12985
13394
|
* Creates a new brand
|
|
@@ -12999,12 +13408,12 @@ var BrandService = class extends BaseService {
|
|
|
12999
13408
|
* Gets all active brands
|
|
13000
13409
|
*/
|
|
13001
13410
|
async getAll() {
|
|
13002
|
-
const q =
|
|
13003
|
-
const snapshot = await
|
|
13411
|
+
const q = query27(this.getBrandsRef(), where27("isActive", "==", true));
|
|
13412
|
+
const snapshot = await getDocs27(q);
|
|
13004
13413
|
return snapshot.docs.map(
|
|
13005
|
-
(
|
|
13006
|
-
id:
|
|
13007
|
-
...
|
|
13414
|
+
(doc33) => ({
|
|
13415
|
+
id: doc33.id,
|
|
13416
|
+
...doc33.data()
|
|
13008
13417
|
})
|
|
13009
13418
|
);
|
|
13010
13419
|
}
|
|
@@ -13016,8 +13425,8 @@ var BrandService = class extends BaseService {
|
|
|
13016
13425
|
...brand,
|
|
13017
13426
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13018
13427
|
};
|
|
13019
|
-
const docRef =
|
|
13020
|
-
await
|
|
13428
|
+
const docRef = doc28(this.getBrandsRef(), brandId);
|
|
13429
|
+
await updateDoc27(docRef, updateData);
|
|
13021
13430
|
return this.getById(brandId);
|
|
13022
13431
|
}
|
|
13023
13432
|
/**
|
|
@@ -13032,8 +13441,8 @@ var BrandService = class extends BaseService {
|
|
|
13032
13441
|
* Gets a brand by ID
|
|
13033
13442
|
*/
|
|
13034
13443
|
async getById(brandId) {
|
|
13035
|
-
const docRef =
|
|
13036
|
-
const docSnap = await
|
|
13444
|
+
const docRef = doc28(this.getBrandsRef(), brandId);
|
|
13445
|
+
const docSnap = await getDoc30(docRef);
|
|
13037
13446
|
if (!docSnap.exists()) return null;
|
|
13038
13447
|
return {
|
|
13039
13448
|
id: docSnap.id,
|
|
@@ -13045,13 +13454,13 @@ var BrandService = class extends BaseService {
|
|
|
13045
13454
|
// src/backoffice/services/category.service.ts
|
|
13046
13455
|
import {
|
|
13047
13456
|
addDoc as addDoc4,
|
|
13048
|
-
collection as
|
|
13049
|
-
doc as
|
|
13050
|
-
getDoc as
|
|
13051
|
-
getDocs as
|
|
13052
|
-
query as
|
|
13053
|
-
updateDoc as
|
|
13054
|
-
where as
|
|
13457
|
+
collection as collection28,
|
|
13458
|
+
doc as doc29,
|
|
13459
|
+
getDoc as getDoc31,
|
|
13460
|
+
getDocs as getDocs28,
|
|
13461
|
+
query as query28,
|
|
13462
|
+
updateDoc as updateDoc28,
|
|
13463
|
+
where as where28
|
|
13055
13464
|
} from "firebase/firestore";
|
|
13056
13465
|
|
|
13057
13466
|
// src/backoffice/types/category.types.ts
|
|
@@ -13063,7 +13472,7 @@ var CategoryService = class extends BaseService {
|
|
|
13063
13472
|
* Referenca na Firestore kolekciju kategorija
|
|
13064
13473
|
*/
|
|
13065
13474
|
get categoriesRef() {
|
|
13066
|
-
return
|
|
13475
|
+
return collection28(this.db, CATEGORIES_COLLECTION);
|
|
13067
13476
|
}
|
|
13068
13477
|
/**
|
|
13069
13478
|
* Kreira novu kategoriju u sistemu
|
|
@@ -13086,12 +13495,12 @@ var CategoryService = class extends BaseService {
|
|
|
13086
13495
|
* @returns Lista aktivnih kategorija
|
|
13087
13496
|
*/
|
|
13088
13497
|
async getAll() {
|
|
13089
|
-
const q =
|
|
13090
|
-
const snapshot = await
|
|
13498
|
+
const q = query28(this.categoriesRef, where28("isActive", "==", true));
|
|
13499
|
+
const snapshot = await getDocs28(q);
|
|
13091
13500
|
return snapshot.docs.map(
|
|
13092
|
-
(
|
|
13093
|
-
id:
|
|
13094
|
-
...
|
|
13501
|
+
(doc33) => ({
|
|
13502
|
+
id: doc33.id,
|
|
13503
|
+
...doc33.data()
|
|
13095
13504
|
})
|
|
13096
13505
|
);
|
|
13097
13506
|
}
|
|
@@ -13101,16 +13510,16 @@ var CategoryService = class extends BaseService {
|
|
|
13101
13510
|
* @returns Lista kategorija koje pripadaju traženoj familiji
|
|
13102
13511
|
*/
|
|
13103
13512
|
async getAllByFamily(family) {
|
|
13104
|
-
const q =
|
|
13513
|
+
const q = query28(
|
|
13105
13514
|
this.categoriesRef,
|
|
13106
|
-
|
|
13107
|
-
|
|
13515
|
+
where28("family", "==", family),
|
|
13516
|
+
where28("isActive", "==", true)
|
|
13108
13517
|
);
|
|
13109
|
-
const snapshot = await
|
|
13518
|
+
const snapshot = await getDocs28(q);
|
|
13110
13519
|
return snapshot.docs.map(
|
|
13111
|
-
(
|
|
13112
|
-
id:
|
|
13113
|
-
...
|
|
13520
|
+
(doc33) => ({
|
|
13521
|
+
id: doc33.id,
|
|
13522
|
+
...doc33.data()
|
|
13114
13523
|
})
|
|
13115
13524
|
);
|
|
13116
13525
|
}
|
|
@@ -13125,8 +13534,8 @@ var CategoryService = class extends BaseService {
|
|
|
13125
13534
|
...category,
|
|
13126
13535
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13127
13536
|
};
|
|
13128
|
-
const docRef =
|
|
13129
|
-
await
|
|
13537
|
+
const docRef = doc29(this.categoriesRef, id);
|
|
13538
|
+
await updateDoc28(docRef, updateData);
|
|
13130
13539
|
return this.getById(id);
|
|
13131
13540
|
}
|
|
13132
13541
|
/**
|
|
@@ -13142,8 +13551,8 @@ var CategoryService = class extends BaseService {
|
|
|
13142
13551
|
* @returns Kategorija ili null ako ne postoji
|
|
13143
13552
|
*/
|
|
13144
13553
|
async getById(id) {
|
|
13145
|
-
const docRef =
|
|
13146
|
-
const docSnap = await
|
|
13554
|
+
const docRef = doc29(this.categoriesRef, id);
|
|
13555
|
+
const docSnap = await getDoc31(docRef);
|
|
13147
13556
|
if (!docSnap.exists()) return null;
|
|
13148
13557
|
return {
|
|
13149
13558
|
id: docSnap.id,
|
|
@@ -13155,13 +13564,13 @@ var CategoryService = class extends BaseService {
|
|
|
13155
13564
|
// src/backoffice/services/subcategory.service.ts
|
|
13156
13565
|
import {
|
|
13157
13566
|
addDoc as addDoc5,
|
|
13158
|
-
collection as
|
|
13159
|
-
doc as
|
|
13160
|
-
getDoc as
|
|
13161
|
-
getDocs as
|
|
13162
|
-
query as
|
|
13163
|
-
updateDoc as
|
|
13164
|
-
where as
|
|
13567
|
+
collection as collection29,
|
|
13568
|
+
doc as doc30,
|
|
13569
|
+
getDoc as getDoc32,
|
|
13570
|
+
getDocs as getDocs29,
|
|
13571
|
+
query as query29,
|
|
13572
|
+
updateDoc as updateDoc29,
|
|
13573
|
+
where as where29
|
|
13165
13574
|
} from "firebase/firestore";
|
|
13166
13575
|
|
|
13167
13576
|
// src/backoffice/types/subcategory.types.ts
|
|
@@ -13174,7 +13583,7 @@ var SubcategoryService = class extends BaseService {
|
|
|
13174
13583
|
* @param categoryId - ID roditeljske kategorije
|
|
13175
13584
|
*/
|
|
13176
13585
|
getSubcategoriesRef(categoryId) {
|
|
13177
|
-
return
|
|
13586
|
+
return collection29(
|
|
13178
13587
|
this.db,
|
|
13179
13588
|
CATEGORIES_COLLECTION,
|
|
13180
13589
|
categoryId,
|
|
@@ -13208,15 +13617,15 @@ var SubcategoryService = class extends BaseService {
|
|
|
13208
13617
|
* @returns Lista aktivnih podkategorija
|
|
13209
13618
|
*/
|
|
13210
13619
|
async getAllByCategoryId(categoryId) {
|
|
13211
|
-
const q =
|
|
13620
|
+
const q = query29(
|
|
13212
13621
|
this.getSubcategoriesRef(categoryId),
|
|
13213
|
-
|
|
13622
|
+
where29("isActive", "==", true)
|
|
13214
13623
|
);
|
|
13215
|
-
const snapshot = await
|
|
13624
|
+
const snapshot = await getDocs29(q);
|
|
13216
13625
|
return snapshot.docs.map(
|
|
13217
|
-
(
|
|
13218
|
-
id:
|
|
13219
|
-
...
|
|
13626
|
+
(doc33) => ({
|
|
13627
|
+
id: doc33.id,
|
|
13628
|
+
...doc33.data()
|
|
13220
13629
|
})
|
|
13221
13630
|
);
|
|
13222
13631
|
}
|
|
@@ -13232,8 +13641,8 @@ var SubcategoryService = class extends BaseService {
|
|
|
13232
13641
|
...subcategory,
|
|
13233
13642
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13234
13643
|
};
|
|
13235
|
-
const docRef =
|
|
13236
|
-
await
|
|
13644
|
+
const docRef = doc30(this.getSubcategoriesRef(categoryId), subcategoryId);
|
|
13645
|
+
await updateDoc29(docRef, updateData);
|
|
13237
13646
|
return this.getById(categoryId, subcategoryId);
|
|
13238
13647
|
}
|
|
13239
13648
|
/**
|
|
@@ -13251,8 +13660,8 @@ var SubcategoryService = class extends BaseService {
|
|
|
13251
13660
|
* @returns Podkategorija ili null ako ne postoji
|
|
13252
13661
|
*/
|
|
13253
13662
|
async getById(categoryId, subcategoryId) {
|
|
13254
|
-
const docRef =
|
|
13255
|
-
const docSnap = await
|
|
13663
|
+
const docRef = doc30(this.getSubcategoriesRef(categoryId), subcategoryId);
|
|
13664
|
+
const docSnap = await getDoc32(docRef);
|
|
13256
13665
|
if (!docSnap.exists()) return null;
|
|
13257
13666
|
return {
|
|
13258
13667
|
id: docSnap.id,
|
|
@@ -13264,15 +13673,15 @@ var SubcategoryService = class extends BaseService {
|
|
|
13264
13673
|
// src/backoffice/services/technology.service.ts
|
|
13265
13674
|
import {
|
|
13266
13675
|
addDoc as addDoc6,
|
|
13267
|
-
collection as
|
|
13268
|
-
doc as
|
|
13269
|
-
getDoc as
|
|
13270
|
-
getDocs as
|
|
13271
|
-
query as
|
|
13272
|
-
updateDoc as
|
|
13273
|
-
where as
|
|
13274
|
-
arrayUnion as
|
|
13275
|
-
arrayRemove as
|
|
13676
|
+
collection as collection30,
|
|
13677
|
+
doc as doc31,
|
|
13678
|
+
getDoc as getDoc33,
|
|
13679
|
+
getDocs as getDocs30,
|
|
13680
|
+
query as query30,
|
|
13681
|
+
updateDoc as updateDoc30,
|
|
13682
|
+
where as where30,
|
|
13683
|
+
arrayUnion as arrayUnion9,
|
|
13684
|
+
arrayRemove as arrayRemove8
|
|
13276
13685
|
} from "firebase/firestore";
|
|
13277
13686
|
var DEFAULT_CERTIFICATION_REQUIREMENT = {
|
|
13278
13687
|
minimumLevel: "aesthetician" /* AESTHETICIAN */,
|
|
@@ -13283,7 +13692,7 @@ var TechnologyService = class extends BaseService {
|
|
|
13283
13692
|
* Vraća referencu na Firestore kolekciju tehnologija
|
|
13284
13693
|
*/
|
|
13285
13694
|
getTechnologiesRef() {
|
|
13286
|
-
return
|
|
13695
|
+
return collection30(this.db, TECHNOLOGIES_COLLECTION);
|
|
13287
13696
|
}
|
|
13288
13697
|
/**
|
|
13289
13698
|
* Kreira novu tehnologiju
|
|
@@ -13314,12 +13723,12 @@ var TechnologyService = class extends BaseService {
|
|
|
13314
13723
|
* @returns Lista aktivnih tehnologija
|
|
13315
13724
|
*/
|
|
13316
13725
|
async getAll() {
|
|
13317
|
-
const q =
|
|
13318
|
-
const snapshot = await
|
|
13726
|
+
const q = query30(this.getTechnologiesRef(), where30("isActive", "==", true));
|
|
13727
|
+
const snapshot = await getDocs30(q);
|
|
13319
13728
|
return snapshot.docs.map(
|
|
13320
|
-
(
|
|
13321
|
-
id:
|
|
13322
|
-
...
|
|
13729
|
+
(doc33) => ({
|
|
13730
|
+
id: doc33.id,
|
|
13731
|
+
...doc33.data()
|
|
13323
13732
|
})
|
|
13324
13733
|
);
|
|
13325
13734
|
}
|
|
@@ -13329,16 +13738,16 @@ var TechnologyService = class extends BaseService {
|
|
|
13329
13738
|
* @returns Lista aktivnih tehnologija
|
|
13330
13739
|
*/
|
|
13331
13740
|
async getAllByFamily(family) {
|
|
13332
|
-
const q =
|
|
13741
|
+
const q = query30(
|
|
13333
13742
|
this.getTechnologiesRef(),
|
|
13334
|
-
|
|
13335
|
-
|
|
13743
|
+
where30("isActive", "==", true),
|
|
13744
|
+
where30("family", "==", family)
|
|
13336
13745
|
);
|
|
13337
|
-
const snapshot = await
|
|
13746
|
+
const snapshot = await getDocs30(q);
|
|
13338
13747
|
return snapshot.docs.map(
|
|
13339
|
-
(
|
|
13340
|
-
id:
|
|
13341
|
-
...
|
|
13748
|
+
(doc33) => ({
|
|
13749
|
+
id: doc33.id,
|
|
13750
|
+
...doc33.data()
|
|
13342
13751
|
})
|
|
13343
13752
|
);
|
|
13344
13753
|
}
|
|
@@ -13348,16 +13757,16 @@ var TechnologyService = class extends BaseService {
|
|
|
13348
13757
|
* @returns Lista aktivnih tehnologija
|
|
13349
13758
|
*/
|
|
13350
13759
|
async getAllByCategoryId(categoryId) {
|
|
13351
|
-
const q =
|
|
13760
|
+
const q = query30(
|
|
13352
13761
|
this.getTechnologiesRef(),
|
|
13353
|
-
|
|
13354
|
-
|
|
13762
|
+
where30("isActive", "==", true),
|
|
13763
|
+
where30("categoryId", "==", categoryId)
|
|
13355
13764
|
);
|
|
13356
|
-
const snapshot = await
|
|
13765
|
+
const snapshot = await getDocs30(q);
|
|
13357
13766
|
return snapshot.docs.map(
|
|
13358
|
-
(
|
|
13359
|
-
id:
|
|
13360
|
-
...
|
|
13767
|
+
(doc33) => ({
|
|
13768
|
+
id: doc33.id,
|
|
13769
|
+
...doc33.data()
|
|
13361
13770
|
})
|
|
13362
13771
|
);
|
|
13363
13772
|
}
|
|
@@ -13367,16 +13776,16 @@ var TechnologyService = class extends BaseService {
|
|
|
13367
13776
|
* @returns Lista aktivnih tehnologija
|
|
13368
13777
|
*/
|
|
13369
13778
|
async getAllBySubcategoryId(subcategoryId) {
|
|
13370
|
-
const q =
|
|
13779
|
+
const q = query30(
|
|
13371
13780
|
this.getTechnologiesRef(),
|
|
13372
|
-
|
|
13373
|
-
|
|
13781
|
+
where30("isActive", "==", true),
|
|
13782
|
+
where30("subcategoryId", "==", subcategoryId)
|
|
13374
13783
|
);
|
|
13375
|
-
const snapshot = await
|
|
13784
|
+
const snapshot = await getDocs30(q);
|
|
13376
13785
|
return snapshot.docs.map(
|
|
13377
|
-
(
|
|
13378
|
-
id:
|
|
13379
|
-
...
|
|
13786
|
+
(doc33) => ({
|
|
13787
|
+
id: doc33.id,
|
|
13788
|
+
...doc33.data()
|
|
13380
13789
|
})
|
|
13381
13790
|
);
|
|
13382
13791
|
}
|
|
@@ -13391,8 +13800,8 @@ var TechnologyService = class extends BaseService {
|
|
|
13391
13800
|
...technology,
|
|
13392
13801
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13393
13802
|
};
|
|
13394
|
-
const docRef =
|
|
13395
|
-
await
|
|
13803
|
+
const docRef = doc31(this.getTechnologiesRef(), technologyId);
|
|
13804
|
+
await updateDoc30(docRef, updateData);
|
|
13396
13805
|
return this.getById(technologyId);
|
|
13397
13806
|
}
|
|
13398
13807
|
/**
|
|
@@ -13410,8 +13819,8 @@ var TechnologyService = class extends BaseService {
|
|
|
13410
13819
|
* @returns Tehnologija ili null ako ne postoji
|
|
13411
13820
|
*/
|
|
13412
13821
|
async getById(technologyId) {
|
|
13413
|
-
const docRef =
|
|
13414
|
-
const docSnap = await
|
|
13822
|
+
const docRef = doc31(this.getTechnologiesRef(), technologyId);
|
|
13823
|
+
const docSnap = await getDoc33(docRef);
|
|
13415
13824
|
if (!docSnap.exists()) return null;
|
|
13416
13825
|
return {
|
|
13417
13826
|
id: docSnap.id,
|
|
@@ -13425,10 +13834,10 @@ var TechnologyService = class extends BaseService {
|
|
|
13425
13834
|
* @returns Ažurirana tehnologija sa novim zahtevom
|
|
13426
13835
|
*/
|
|
13427
13836
|
async addRequirement(technologyId, requirement) {
|
|
13428
|
-
const docRef =
|
|
13837
|
+
const docRef = doc31(this.getTechnologiesRef(), technologyId);
|
|
13429
13838
|
const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
|
|
13430
|
-
await
|
|
13431
|
-
[requirementType]:
|
|
13839
|
+
await updateDoc30(docRef, {
|
|
13840
|
+
[requirementType]: arrayUnion9(requirement),
|
|
13432
13841
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13433
13842
|
});
|
|
13434
13843
|
return this.getById(technologyId);
|
|
@@ -13440,10 +13849,10 @@ var TechnologyService = class extends BaseService {
|
|
|
13440
13849
|
* @returns Ažurirana tehnologija bez uklonjenog zahteva
|
|
13441
13850
|
*/
|
|
13442
13851
|
async removeRequirement(technologyId, requirement) {
|
|
13443
|
-
const docRef =
|
|
13852
|
+
const docRef = doc31(this.getTechnologiesRef(), technologyId);
|
|
13444
13853
|
const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
|
|
13445
|
-
await
|
|
13446
|
-
[requirementType]:
|
|
13854
|
+
await updateDoc30(docRef, {
|
|
13855
|
+
[requirementType]: arrayRemove8(requirement),
|
|
13447
13856
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13448
13857
|
});
|
|
13449
13858
|
return this.getById(technologyId);
|
|
@@ -13480,9 +13889,9 @@ var TechnologyService = class extends BaseService {
|
|
|
13480
13889
|
* @returns Ažurirana tehnologija
|
|
13481
13890
|
*/
|
|
13482
13891
|
async addBlockingCondition(technologyId, condition) {
|
|
13483
|
-
const docRef =
|
|
13484
|
-
await
|
|
13485
|
-
blockingConditions:
|
|
13892
|
+
const docRef = doc31(this.getTechnologiesRef(), technologyId);
|
|
13893
|
+
await updateDoc30(docRef, {
|
|
13894
|
+
blockingConditions: arrayUnion9(condition),
|
|
13486
13895
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13487
13896
|
});
|
|
13488
13897
|
return this.getById(technologyId);
|
|
@@ -13494,9 +13903,9 @@ var TechnologyService = class extends BaseService {
|
|
|
13494
13903
|
* @returns Ažurirana tehnologija
|
|
13495
13904
|
*/
|
|
13496
13905
|
async removeBlockingCondition(technologyId, condition) {
|
|
13497
|
-
const docRef =
|
|
13498
|
-
await
|
|
13499
|
-
blockingConditions:
|
|
13906
|
+
const docRef = doc31(this.getTechnologiesRef(), technologyId);
|
|
13907
|
+
await updateDoc30(docRef, {
|
|
13908
|
+
blockingConditions: arrayRemove8(condition),
|
|
13500
13909
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13501
13910
|
});
|
|
13502
13911
|
return this.getById(technologyId);
|
|
@@ -13508,9 +13917,9 @@ var TechnologyService = class extends BaseService {
|
|
|
13508
13917
|
* @returns Ažurirana tehnologija
|
|
13509
13918
|
*/
|
|
13510
13919
|
async addContraindication(technologyId, contraindication) {
|
|
13511
|
-
const docRef =
|
|
13512
|
-
await
|
|
13513
|
-
contraindications:
|
|
13920
|
+
const docRef = doc31(this.getTechnologiesRef(), technologyId);
|
|
13921
|
+
await updateDoc30(docRef, {
|
|
13922
|
+
contraindications: arrayUnion9(contraindication),
|
|
13514
13923
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13515
13924
|
});
|
|
13516
13925
|
return this.getById(technologyId);
|
|
@@ -13522,9 +13931,9 @@ var TechnologyService = class extends BaseService {
|
|
|
13522
13931
|
* @returns Ažurirana tehnologija
|
|
13523
13932
|
*/
|
|
13524
13933
|
async removeContraindication(technologyId, contraindication) {
|
|
13525
|
-
const docRef =
|
|
13526
|
-
await
|
|
13527
|
-
contraindications:
|
|
13934
|
+
const docRef = doc31(this.getTechnologiesRef(), technologyId);
|
|
13935
|
+
await updateDoc30(docRef, {
|
|
13936
|
+
contraindications: arrayRemove8(contraindication),
|
|
13528
13937
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13529
13938
|
});
|
|
13530
13939
|
return this.getById(technologyId);
|
|
@@ -13536,9 +13945,9 @@ var TechnologyService = class extends BaseService {
|
|
|
13536
13945
|
* @returns Ažurirana tehnologija
|
|
13537
13946
|
*/
|
|
13538
13947
|
async addBenefit(technologyId, benefit) {
|
|
13539
|
-
const docRef =
|
|
13540
|
-
await
|
|
13541
|
-
benefits:
|
|
13948
|
+
const docRef = doc31(this.getTechnologiesRef(), technologyId);
|
|
13949
|
+
await updateDoc30(docRef, {
|
|
13950
|
+
benefits: arrayUnion9(benefit),
|
|
13542
13951
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13543
13952
|
});
|
|
13544
13953
|
return this.getById(technologyId);
|
|
@@ -13550,9 +13959,9 @@ var TechnologyService = class extends BaseService {
|
|
|
13550
13959
|
* @returns Ažurirana tehnologija
|
|
13551
13960
|
*/
|
|
13552
13961
|
async removeBenefit(technologyId, benefit) {
|
|
13553
|
-
const docRef =
|
|
13554
|
-
await
|
|
13555
|
-
benefits:
|
|
13962
|
+
const docRef = doc31(this.getTechnologiesRef(), technologyId);
|
|
13963
|
+
await updateDoc30(docRef, {
|
|
13964
|
+
benefits: arrayRemove8(benefit),
|
|
13556
13965
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13557
13966
|
});
|
|
13558
13967
|
return this.getById(technologyId);
|
|
@@ -13591,8 +14000,8 @@ var TechnologyService = class extends BaseService {
|
|
|
13591
14000
|
* @returns Ažurirana tehnologija
|
|
13592
14001
|
*/
|
|
13593
14002
|
async updateCertificationRequirement(technologyId, certificationRequirement) {
|
|
13594
|
-
const docRef =
|
|
13595
|
-
await
|
|
14003
|
+
const docRef = doc31(this.getTechnologiesRef(), technologyId);
|
|
14004
|
+
await updateDoc30(docRef, {
|
|
13596
14005
|
certificationRequirement,
|
|
13597
14006
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13598
14007
|
});
|
|
@@ -13694,13 +14103,13 @@ var TechnologyService = class extends BaseService {
|
|
|
13694
14103
|
// src/backoffice/services/product.service.ts
|
|
13695
14104
|
import {
|
|
13696
14105
|
addDoc as addDoc7,
|
|
13697
|
-
collection as
|
|
13698
|
-
doc as
|
|
13699
|
-
getDoc as
|
|
13700
|
-
getDocs as
|
|
13701
|
-
query as
|
|
13702
|
-
updateDoc as
|
|
13703
|
-
where as
|
|
14106
|
+
collection as collection31,
|
|
14107
|
+
doc as doc32,
|
|
14108
|
+
getDoc as getDoc34,
|
|
14109
|
+
getDocs as getDocs31,
|
|
14110
|
+
query as query31,
|
|
14111
|
+
updateDoc as updateDoc31,
|
|
14112
|
+
where as where31
|
|
13704
14113
|
} from "firebase/firestore";
|
|
13705
14114
|
|
|
13706
14115
|
// src/backoffice/types/product.types.ts
|
|
@@ -13714,7 +14123,7 @@ var ProductService = class extends BaseService {
|
|
|
13714
14123
|
* @returns Firestore collection reference
|
|
13715
14124
|
*/
|
|
13716
14125
|
getProductsRef(technologyId) {
|
|
13717
|
-
return
|
|
14126
|
+
return collection31(
|
|
13718
14127
|
this.db,
|
|
13719
14128
|
TECHNOLOGIES_COLLECTION,
|
|
13720
14129
|
technologyId,
|
|
@@ -13744,15 +14153,15 @@ var ProductService = class extends BaseService {
|
|
|
13744
14153
|
* Gets all products for a technology
|
|
13745
14154
|
*/
|
|
13746
14155
|
async getAllByTechnology(technologyId) {
|
|
13747
|
-
const q =
|
|
14156
|
+
const q = query31(
|
|
13748
14157
|
this.getProductsRef(technologyId),
|
|
13749
|
-
|
|
14158
|
+
where31("isActive", "==", true)
|
|
13750
14159
|
);
|
|
13751
|
-
const snapshot = await
|
|
14160
|
+
const snapshot = await getDocs31(q);
|
|
13752
14161
|
return snapshot.docs.map(
|
|
13753
|
-
(
|
|
13754
|
-
id:
|
|
13755
|
-
...
|
|
14162
|
+
(doc33) => ({
|
|
14163
|
+
id: doc33.id,
|
|
14164
|
+
...doc33.data()
|
|
13756
14165
|
})
|
|
13757
14166
|
);
|
|
13758
14167
|
}
|
|
@@ -13760,21 +14169,21 @@ var ProductService = class extends BaseService {
|
|
|
13760
14169
|
* Gets all products for a brand by filtering through all technologies
|
|
13761
14170
|
*/
|
|
13762
14171
|
async getAllByBrand(brandId) {
|
|
13763
|
-
const allTechnologiesRef =
|
|
13764
|
-
const technologiesSnapshot = await
|
|
14172
|
+
const allTechnologiesRef = collection31(this.db, TECHNOLOGIES_COLLECTION);
|
|
14173
|
+
const technologiesSnapshot = await getDocs31(allTechnologiesRef);
|
|
13765
14174
|
const products = [];
|
|
13766
14175
|
for (const techDoc of technologiesSnapshot.docs) {
|
|
13767
|
-
const q =
|
|
14176
|
+
const q = query31(
|
|
13768
14177
|
this.getProductsRef(techDoc.id),
|
|
13769
|
-
|
|
13770
|
-
|
|
14178
|
+
where31("brandId", "==", brandId),
|
|
14179
|
+
where31("isActive", "==", true)
|
|
13771
14180
|
);
|
|
13772
|
-
const snapshot = await
|
|
14181
|
+
const snapshot = await getDocs31(q);
|
|
13773
14182
|
products.push(
|
|
13774
14183
|
...snapshot.docs.map(
|
|
13775
|
-
(
|
|
13776
|
-
id:
|
|
13777
|
-
...
|
|
14184
|
+
(doc33) => ({
|
|
14185
|
+
id: doc33.id,
|
|
14186
|
+
...doc33.data()
|
|
13778
14187
|
})
|
|
13779
14188
|
)
|
|
13780
14189
|
);
|
|
@@ -13789,8 +14198,8 @@ var ProductService = class extends BaseService {
|
|
|
13789
14198
|
...product,
|
|
13790
14199
|
updatedAt: /* @__PURE__ */ new Date()
|
|
13791
14200
|
};
|
|
13792
|
-
const docRef =
|
|
13793
|
-
await
|
|
14201
|
+
const docRef = doc32(this.getProductsRef(technologyId), productId);
|
|
14202
|
+
await updateDoc31(docRef, updateData);
|
|
13794
14203
|
return this.getById(technologyId, productId);
|
|
13795
14204
|
}
|
|
13796
14205
|
/**
|
|
@@ -13805,8 +14214,8 @@ var ProductService = class extends BaseService {
|
|
|
13805
14214
|
* Gets a product by ID
|
|
13806
14215
|
*/
|
|
13807
14216
|
async getById(technologyId, productId) {
|
|
13808
|
-
const docRef =
|
|
13809
|
-
const docSnap = await
|
|
14217
|
+
const docRef = doc32(this.getProductsRef(technologyId), productId);
|
|
14218
|
+
const docSnap = await getDoc34(docRef);
|
|
13810
14219
|
if (!docSnap.exists()) return null;
|
|
13811
14220
|
return {
|
|
13812
14221
|
id: docSnap.id,
|
|
@@ -13835,14 +14244,14 @@ var baseNotificationSchema = z24.object({
|
|
|
13835
14244
|
userRole: z24.nativeEnum(UserRole)
|
|
13836
14245
|
});
|
|
13837
14246
|
var preRequirementNotificationSchema = baseNotificationSchema.extend({
|
|
13838
|
-
notificationType: z24.literal("
|
|
14247
|
+
notificationType: z24.literal("requirementInstructionDue" /* REQUIREMENT_INSTRUCTION_DUE */),
|
|
13839
14248
|
treatmentId: z24.string(),
|
|
13840
14249
|
requirements: z24.array(z24.string()),
|
|
13841
14250
|
deadline: z24.any()
|
|
13842
14251
|
// Timestamp
|
|
13843
14252
|
});
|
|
13844
14253
|
var postRequirementNotificationSchema = baseNotificationSchema.extend({
|
|
13845
|
-
notificationType: z24.literal("
|
|
14254
|
+
notificationType: z24.literal("requirementInstructionDue" /* REQUIREMENT_INSTRUCTION_DUE */),
|
|
13846
14255
|
treatmentId: z24.string(),
|
|
13847
14256
|
requirements: z24.array(z24.string()),
|
|
13848
14257
|
deadline: z24.any()
|
|
@@ -13857,7 +14266,7 @@ var appointmentReminderNotificationSchema = baseNotificationSchema.extend({
|
|
|
13857
14266
|
doctorName: z24.string()
|
|
13858
14267
|
});
|
|
13859
14268
|
var appointmentNotificationSchema = baseNotificationSchema.extend({
|
|
13860
|
-
notificationType: z24.literal("
|
|
14269
|
+
notificationType: z24.literal("appointmentStatusChange" /* APPOINTMENT_STATUS_CHANGE */),
|
|
13861
14270
|
appointmentId: z24.string(),
|
|
13862
14271
|
appointmentStatus: z24.string(),
|
|
13863
14272
|
previousStatus: z24.string(),
|
|
@@ -13953,9 +14362,13 @@ export {
|
|
|
13953
14362
|
PATIENT_LOCATION_INFO_COLLECTION,
|
|
13954
14363
|
PATIENT_MEDICAL_HISTORY_COLLECTION,
|
|
13955
14364
|
PATIENT_MEDICAL_INFO_COLLECTION,
|
|
14365
|
+
PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME,
|
|
13956
14366
|
PATIENT_SENSITIVE_INFO_COLLECTION,
|
|
13957
14367
|
PRACTITIONERS_COLLECTION,
|
|
13958
14368
|
PROCEDURES_COLLECTION,
|
|
14369
|
+
PatientInstructionStatus,
|
|
14370
|
+
PatientRequirementOverallStatus,
|
|
14371
|
+
PatientRequirementsService,
|
|
13959
14372
|
PatientService,
|
|
13960
14373
|
PaymentStatus,
|
|
13961
14374
|
PracticeType,
|
|
@@ -14020,6 +14433,7 @@ export {
|
|
|
14020
14433
|
createDefaultClinicGroupSchema,
|
|
14021
14434
|
createDocumentTemplateSchema,
|
|
14022
14435
|
createDraftPractitionerSchema,
|
|
14436
|
+
createFilledDocumentDataSchema,
|
|
14023
14437
|
createPatientLocationInfoSchema,
|
|
14024
14438
|
createPatientMedicalInfoSchema,
|
|
14025
14439
|
createPatientProfileSchema,
|
|
@@ -14035,6 +14449,8 @@ export {
|
|
|
14035
14449
|
documentTemplateSchema,
|
|
14036
14450
|
emailSchema,
|
|
14037
14451
|
emergencyContactSchema,
|
|
14452
|
+
filledDocumentSchema,
|
|
14453
|
+
filledDocumentStatusSchema,
|
|
14038
14454
|
gamificationSchema,
|
|
14039
14455
|
getFirebaseApp,
|
|
14040
14456
|
getFirebaseAuth,
|
|
@@ -14084,6 +14500,7 @@ export {
|
|
|
14084
14500
|
updateClinicSchema,
|
|
14085
14501
|
updateContraindicationSchema,
|
|
14086
14502
|
updateDocumentTemplateSchema,
|
|
14503
|
+
updateFilledDocumentDataSchema,
|
|
14087
14504
|
updateMedicationSchema,
|
|
14088
14505
|
updatePatientMedicalInfoSchema,
|
|
14089
14506
|
updateVitalStatsSchema,
|