@blackcode_sa/metaestetics-api 1.6.2 → 1.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/admin/index.d.mts +228 -25
  2. package/dist/admin/index.d.ts +228 -25
  3. package/dist/admin/index.js +35867 -2493
  4. package/dist/admin/index.mjs +35856 -2464
  5. package/dist/backoffice/index.d.mts +252 -1
  6. package/dist/backoffice/index.d.ts +252 -1
  7. package/dist/backoffice/index.js +86 -12
  8. package/dist/backoffice/index.mjs +86 -13
  9. package/dist/index.d.mts +1417 -554
  10. package/dist/index.d.ts +1417 -554
  11. package/dist/index.js +1393 -687
  12. package/dist/index.mjs +1423 -711
  13. package/package.json +1 -1
  14. package/src/admin/index.ts +15 -1
  15. package/src/admin/notifications/notifications.admin.ts +1 -1
  16. package/src/admin/requirements/README.md +128 -0
  17. package/src/admin/requirements/patient-requirements.admin.service.ts +482 -0
  18. package/src/index.ts +16 -1
  19. package/src/services/appointment/appointment.service.ts +315 -86
  20. package/src/services/clinic/clinic-admin.service.ts +3 -0
  21. package/src/services/clinic/clinic-group.service.ts +8 -0
  22. package/src/services/documentation-templates/documentation-template.service.ts +24 -16
  23. package/src/services/documentation-templates/filled-document.service.ts +253 -136
  24. package/src/services/patient/patient.service.ts +31 -1
  25. package/src/services/patient/patientRequirements.service.ts +285 -0
  26. package/src/services/patient/utils/practitioner.utils.ts +79 -1
  27. package/src/types/appointment/index.ts +134 -10
  28. package/src/types/documentation-templates/index.ts +34 -2
  29. package/src/types/notifications/README.md +77 -0
  30. package/src/types/notifications/index.ts +154 -27
  31. package/src/types/patient/index.ts +6 -0
  32. package/src/types/patient/patient-requirements.ts +81 -0
  33. package/src/validations/appointment.schema.ts +300 -62
  34. package/src/validations/documentation-templates/template.schema.ts +55 -0
  35. package/src/validations/documentation-templates.schema.ts +9 -14
  36. package/src/validations/notification.schema.ts +3 -3
  37. package/src/validations/patient/patient-requirements.schema.ts +75 -0
@@ -1,86 +1,277 @@
1
1
  import { z } from "zod";
2
- import { AppointmentStatus, PaymentStatus } from "../types/appointment";
2
+ import {
3
+ AppointmentStatus,
4
+ PaymentStatus,
5
+ MediaType,
6
+ } from "../types/appointment";
7
+ import { filledDocumentStatusSchema } from "./documentation-templates.schema";
3
8
 
4
- /**
5
- * Schema for validating appointment creation data
6
- */
7
- export const createAppointmentSchema = z.object({
8
- calendarEventId: z.string().min(1, "Calendar event ID is required"),
9
- clinicBranchId: z.string().min(1, "Clinic branch ID is required"),
10
- practitionerId: z.string().min(1, "Practitioner ID is required"),
11
- patientId: z.string().min(1, "Patient ID is required"),
12
- procedureId: z.string().min(1, "Procedure ID is required"),
13
- appointmentStartTime: z
9
+ // Define common constants locally if not available from common.schema.ts
10
+ const MIN_STRING_LENGTH = 1;
11
+ const MAX_STRING_LENGTH = 1024; // Example value
12
+ const MAX_STRING_LENGTH_LONG = 4096; // Example value for longer notes/comments
13
+ const MAX_ARRAY_LENGTH = 100; // Example value
14
+
15
+ // --- Enum Schemas ---
16
+ export const appointmentStatusSchema = z.nativeEnum(AppointmentStatus);
17
+ export const paymentStatusSchema = z.nativeEnum(PaymentStatus);
18
+ export const mediaTypeSchema = z.nativeEnum(MediaType);
19
+
20
+ // --- Schemas for Nested Objects from types/appointment/index.ts ---
21
+
22
+ export const appointmentMediaItemSchema = z.object({
23
+ id: z.string().min(MIN_STRING_LENGTH, "Media item ID is required"),
24
+ type: mediaTypeSchema,
25
+ url: z.string().url("Media URL must be a valid URL"),
26
+ fileName: z.string().optional(),
27
+ uploadedAt: z
14
28
  .any()
15
29
  .refine(
16
- (val) => val instanceof Date || val?._seconds !== undefined,
17
- "Appointment start time must be a valid timestamp"
30
+ (val) =>
31
+ val instanceof Date ||
32
+ val?._seconds !== undefined ||
33
+ typeof val === "number",
34
+ "uploadedAt must be a valid timestamp or Date object"
18
35
  ),
19
- appointmentEndTime: z
36
+ uploadedBy: z
37
+ .string()
38
+ .min(MIN_STRING_LENGTH, "Uploaded by user ID is required"),
39
+ description: z
40
+ .string()
41
+ .max(MAX_STRING_LENGTH, "Description too long")
42
+ .optional(),
43
+ });
44
+
45
+ export const procedureExtendedInfoSchema = z.object({
46
+ id: z.string().min(MIN_STRING_LENGTH),
47
+ name: z.string().min(MIN_STRING_LENGTH),
48
+ description: z.string(),
49
+ cost: z.number().min(0),
50
+ duration: z.number().min(0),
51
+ procedureFamily: z.any(),
52
+ procedureCategoryId: z.string(),
53
+ procedureCategoryName: z.string(),
54
+ procedureSubCategoryId: z.string(),
55
+ procedureSubCategoryName: z.string(),
56
+ procedureTechnologyId: z.string(),
57
+ procedureTechnologyName: z.string(),
58
+ procedureProductBrandId: z.string(),
59
+ procedureProductBrandName: z.string(),
60
+ procedureProductId: z.string(),
61
+ procedureProductName: z.string(),
62
+ });
63
+
64
+ export const linkedFormInfoSchema = z.object({
65
+ formId: z.string().min(MIN_STRING_LENGTH, "Form ID is required"),
66
+ templateId: z.string().min(MIN_STRING_LENGTH, "Template ID is required"),
67
+ templateVersion: z
68
+ .number()
69
+ .int()
70
+ .positive("Template version must be a positive integer"),
71
+ title: z.string().min(MIN_STRING_LENGTH, "Form title is required"),
72
+ isUserForm: z.boolean(),
73
+ status: filledDocumentStatusSchema,
74
+ path: z.string().min(MIN_STRING_LENGTH, "Form path is required"),
75
+ submittedAt: z
76
+ .any()
77
+ .refine(
78
+ (val) =>
79
+ val === undefined ||
80
+ val instanceof Date ||
81
+ val?._seconds !== undefined ||
82
+ typeof val === "number",
83
+ "submittedAt must be a valid timestamp or Date object"
84
+ )
85
+ .optional(),
86
+ completedAt: z
20
87
  .any()
21
88
  .refine(
22
- (val) => val instanceof Date || val?._seconds !== undefined,
23
- "Appointment end time must be a valid timestamp"
89
+ (val) =>
90
+ val === undefined ||
91
+ val instanceof Date ||
92
+ val?._seconds !== undefined ||
93
+ typeof val === "number",
94
+ "completedAt must be a valid timestamp or Date object"
95
+ )
96
+ .optional(),
97
+ });
98
+
99
+ export const patientReviewInfoSchema = z.object({
100
+ reviewId: z.string().min(MIN_STRING_LENGTH, "Review ID is required"),
101
+ rating: z.number().min(1).max(5, "Rating must be between 1 and 5"),
102
+ comment: z
103
+ .string()
104
+ .max(MAX_STRING_LENGTH_LONG, "Comment too long")
105
+ .optional(),
106
+ reviewedAt: z
107
+ .any()
108
+ .refine(
109
+ (val) =>
110
+ val instanceof Date ||
111
+ val?._seconds !== undefined ||
112
+ typeof val === "number",
113
+ "reviewedAt must be a valid timestamp or Date object"
24
114
  ),
25
- cost: z.number().min(0, "Cost must be a non-negative number"),
26
- currency: z.string().min(1, "Currency is required"),
27
- patientNotes: z.string().nullable().optional(),
28
- initialStatus: z.nativeEnum(AppointmentStatus, {
29
- errorMap: () => ({ message: "Invalid appointment status" }),
30
- }),
31
- initialPaymentStatus: z
32
- .nativeEnum(PaymentStatus, {
33
- errorMap: () => ({ message: "Invalid payment status" }),
34
- })
35
- .optional()
36
- .default(PaymentStatus.UNPAID),
37
115
  });
38
116
 
117
+ export const finalizedDetailsSchema = z.object({
118
+ by: z.string().min(MIN_STRING_LENGTH, "Finalized by user ID is required"),
119
+ at: z
120
+ .any()
121
+ .refine(
122
+ (val) =>
123
+ val instanceof Date ||
124
+ val?._seconds !== undefined ||
125
+ typeof val === "number",
126
+ "Finalized at must be a valid timestamp or Date object"
127
+ ),
128
+ notes: z
129
+ .string()
130
+ .max(MAX_STRING_LENGTH_LONG, "Finalization notes too long")
131
+ .optional(),
132
+ });
133
+
134
+ // --- Main Appointment Schemas ---
135
+
136
+ /**
137
+ * Schema for validating appointment creation data
138
+ */
139
+ export const createAppointmentSchema = z
140
+ .object({
141
+ calendarEventId: z
142
+ .string()
143
+ .min(MIN_STRING_LENGTH, "Calendar event ID is required"),
144
+ clinicBranchId: z
145
+ .string()
146
+ .min(MIN_STRING_LENGTH, "Clinic branch ID is required"),
147
+ practitionerId: z
148
+ .string()
149
+ .min(MIN_STRING_LENGTH, "Practitioner ID is required"),
150
+ patientId: z.string().min(MIN_STRING_LENGTH, "Patient ID is required"),
151
+ procedureId: z.string().min(MIN_STRING_LENGTH, "Procedure ID is required"),
152
+ appointmentStartTime: z
153
+ .any()
154
+ .refine(
155
+ (val) =>
156
+ val instanceof Date ||
157
+ val?._seconds !== undefined ||
158
+ typeof val === "number",
159
+ "Appointment start time must be a valid timestamp or Date object"
160
+ ),
161
+ appointmentEndTime: z
162
+ .any()
163
+ .refine(
164
+ (val) =>
165
+ val instanceof Date ||
166
+ val?._seconds !== undefined ||
167
+ typeof val === "number",
168
+ "Appointment end time must be a valid timestamp or Date object"
169
+ ),
170
+ cost: z.number().min(0, "Cost must be a non-negative number"),
171
+ currency: z.string().min(1, "Currency is required"),
172
+ patientNotes: z
173
+ .string()
174
+ .max(MAX_STRING_LENGTH, "Patient notes too long")
175
+ .nullable()
176
+ .optional(),
177
+ initialStatus: appointmentStatusSchema,
178
+ initialPaymentStatus: paymentStatusSchema
179
+ .optional()
180
+ .default(PaymentStatus.UNPAID),
181
+ })
182
+ .refine((data) => data.appointmentEndTime > data.appointmentStartTime, {
183
+ message: "Appointment end time must be after start time",
184
+ path: ["appointmentEndTime"],
185
+ });
186
+
39
187
  /**
40
188
  * Schema for validating appointment update data
41
189
  */
42
190
  export const updateAppointmentSchema = z
43
191
  .object({
44
- status: z
45
- .nativeEnum(AppointmentStatus, {
46
- errorMap: () => ({ message: "Invalid appointment status" }),
47
- })
192
+ status: appointmentStatusSchema.optional(),
193
+ confirmationTime: z.any().optional().nullable(),
194
+ cancellationTime: z.any().optional().nullable(),
195
+ rescheduleTime: z.any().optional().nullable(),
196
+ procedureActualStartTime: z.any().optional().nullable(),
197
+ actualDurationMinutes: z
198
+ .number()
199
+ .int()
200
+ .positive("Duration must be a positive integer")
201
+ .optional(),
202
+ cancellationReason: z
203
+ .string()
204
+ .max(MAX_STRING_LENGTH, "Cancellation reason too long")
205
+ .nullable()
206
+ .optional(),
207
+ canceledBy: z
208
+ .enum(["patient", "clinic", "practitioner", "system"])
209
+ .optional(),
210
+ internalNotes: z
211
+ .string()
212
+ .max(MAX_STRING_LENGTH_LONG, "Internal notes too long")
213
+ .nullable()
214
+ .optional(),
215
+ patientNotes: z.any().optional().nullable(),
216
+ paymentStatus: paymentStatusSchema.optional(),
217
+ paymentTransactionId: z.any().optional().nullable(),
218
+ completedPreRequirements: z
219
+ .union([z.array(z.string()), z.any()])
48
220
  .optional(),
49
- confirmationTime: z
221
+ completedPostRequirements: z
222
+ .union([z.array(z.string()), z.any()])
223
+ .optional(),
224
+ pendingUserFormsIds: z.union([z.array(z.string()), z.any()]).optional(),
225
+ appointmentStartTime: z
50
226
  .any()
51
227
  .refine(
52
228
  (val) =>
53
- val === null ||
54
229
  val === undefined ||
55
230
  val instanceof Date ||
56
- val?._seconds !== undefined,
57
- "Confirmation time must be a valid timestamp or null"
231
+ val?._seconds !== undefined ||
232
+ typeof val === "number",
233
+ "Appointment start time must be a valid timestamp or Date object"
58
234
  )
59
235
  .optional(),
60
- actualDurationMinutes: z
61
- .number()
62
- .positive("Duration must be positive")
236
+ appointmentEndTime: z
237
+ .any()
238
+ .refine(
239
+ (val) =>
240
+ val === undefined ||
241
+ val instanceof Date ||
242
+ val?._seconds !== undefined ||
243
+ typeof val === "number",
244
+ "Appointment end time must be a valid timestamp or Date object"
245
+ )
63
246
  .optional(),
64
- cancellationReason: z.string().nullable().optional(),
65
- canceledBy: z
66
- .enum(["patient", "clinic", "practitioner", "system"])
247
+ calendarEventId: z.string().min(MIN_STRING_LENGTH).optional(),
248
+ cost: z.number().min(0).optional(),
249
+ clinicBranchId: z.string().min(MIN_STRING_LENGTH).optional(),
250
+ practitionerId: z.string().min(MIN_STRING_LENGTH).optional(),
251
+ linkedForms: z
252
+ .union([z.array(linkedFormInfoSchema).max(MAX_ARRAY_LENGTH), z.any()])
67
253
  .optional(),
68
- internalNotes: z.string().nullable().optional(),
69
- paymentStatus: z
70
- .nativeEnum(PaymentStatus, {
71
- errorMap: () => ({ message: "Invalid payment status" }),
72
- })
254
+ media: z
255
+ .union([
256
+ z.array(appointmentMediaItemSchema).max(MAX_ARRAY_LENGTH),
257
+ z.any(),
258
+ ])
259
+ .optional(),
260
+ reviewInfo: z
261
+ .union([patientReviewInfoSchema.nullable(), z.any()])
262
+ .optional(),
263
+ finalizedDetails: z
264
+ .union([finalizedDetailsSchema.nullable(), z.any()])
73
265
  .optional(),
74
- paymentTransactionId: z.string().nullable().optional(),
75
- completedPreRequirements: z.array(z.string()).optional(),
76
- completedPostRequirements: z.array(z.string()).optional(),
266
+ isArchived: z.boolean().optional(),
267
+ updatedAt: z.any().optional(),
77
268
  })
78
269
  .refine(
79
270
  (data) => {
80
- // If status is being set to canceled, make sure reason and canceledBy are provided
81
271
  if (
82
272
  data.status === AppointmentStatus.CANCELED_CLINIC ||
83
- data.status === AppointmentStatus.CANCELED_PATIENT
273
+ data.status === AppointmentStatus.CANCELED_PATIENT ||
274
+ data.status === AppointmentStatus.CANCELED_PATIENT_RESCHEDULED
84
275
  ) {
85
276
  return !!data.cancellationReason && !!data.canceledBy;
86
277
  }
@@ -88,9 +279,22 @@ export const updateAppointmentSchema = z
88
279
  },
89
280
  {
90
281
  message:
91
- "Cancellation reason and canceled by must be provided when canceling an appointment",
282
+ "Cancellation reason and canceled by must be provided when canceling an appointment with patient or clinic origin.",
92
283
  path: ["status"],
93
284
  }
285
+ )
286
+ .refine(
287
+ (data) => {
288
+ if (data.appointmentStartTime && data.appointmentEndTime) {
289
+ return data.appointmentEndTime > data.appointmentStartTime;
290
+ }
291
+ return true;
292
+ },
293
+ {
294
+ message:
295
+ "Appointment end time must be after start time if both are provided",
296
+ path: ["appointmentEndTime"],
297
+ }
94
298
  );
95
299
 
96
300
  /**
@@ -101,25 +305,59 @@ export const searchAppointmentsSchema = z
101
305
  patientId: z.string().optional(),
102
306
  practitionerId: z.string().optional(),
103
307
  clinicBranchId: z.string().optional(),
104
- startDate: z.date().optional(),
105
- endDate: z.date().optional(),
308
+ startDate: z
309
+ .any()
310
+ .refine(
311
+ (val) =>
312
+ val === undefined ||
313
+ val instanceof Date ||
314
+ val?._seconds !== undefined ||
315
+ typeof val === "number",
316
+ "Start date must be a valid timestamp or Date object"
317
+ )
318
+ .optional(),
319
+ endDate: z
320
+ .any()
321
+ .refine(
322
+ (val) =>
323
+ val === undefined ||
324
+ val instanceof Date ||
325
+ val?._seconds !== undefined ||
326
+ typeof val === "number",
327
+ "End date must be a valid timestamp or Date object"
328
+ )
329
+ .optional(),
106
330
  status: z
107
331
  .union([
108
- z.nativeEnum(AppointmentStatus),
109
- z.array(z.nativeEnum(AppointmentStatus)),
332
+ appointmentStatusSchema,
333
+ z.array(appointmentStatusSchema).nonempty(),
110
334
  ])
111
335
  .optional(),
112
- limit: z.number().positive().optional(),
336
+ limit: z.number().positive().int().optional().default(20),
113
337
  startAfter: z.any().optional(),
114
338
  })
115
339
  .refine(
116
340
  (data) => {
117
- // Ensure at least one search parameter is provided
118
- return !!(data.patientId || data.practitionerId || data.clinicBranchId);
341
+ if (!data.startDate && !data.endDate && !data.status) {
342
+ return !!(data.patientId || data.practitionerId || data.clinicBranchId);
343
+ }
344
+ return true;
119
345
  },
120
346
  {
121
347
  message:
122
- "At least one of patientId, practitionerId, or clinicBranchId must be provided",
123
- path: ["searchCriteria"],
348
+ "At least one of patientId, practitionerId, or clinicBranchId must be provided if no date or status filters are set.",
349
+ path: ["patientId"],
350
+ }
351
+ )
352
+ .refine(
353
+ (data) => {
354
+ if (data.startDate && data.endDate) {
355
+ return data.endDate >= data.startDate;
356
+ }
357
+ return true;
358
+ },
359
+ {
360
+ message: "End date must be after or the same as start date",
361
+ path: ["endDate"],
124
362
  }
125
363
  );
@@ -3,6 +3,7 @@ import {
3
3
  DocumentElementType,
4
4
  HeadingLevel,
5
5
  ListType,
6
+ FilledDocumentStatus,
6
7
  } from "../../types/documentation-templates";
7
8
 
8
9
  // Base element schema
@@ -93,6 +94,12 @@ const signatureElementSchema = baseElementSchema.extend({
93
94
  label: z.string().min(1).max(200),
94
95
  });
95
96
 
97
+ // NEW: Digital signature element schema
98
+ const digitalSignatureElementSchema = baseElementSchema.extend({
99
+ type: z.literal(DocumentElementType.DITIGAL_SIGNATURE), // Matching your type enum
100
+ label: z.string().min(1).max(200),
101
+ });
102
+
96
103
  // File upload element schema
97
104
  const fileUploadElementSchema = baseElementSchema.extend({
98
105
  type: z.literal(DocumentElementType.FILE_UPLOAD),
@@ -114,6 +121,7 @@ export const documentElementSchema = z.discriminatedUnion("type", [
114
121
  textInputElementSchema,
115
122
  datePickerElementSchema,
116
123
  signatureElementSchema,
124
+ digitalSignatureElementSchema,
117
125
  fileUploadElementSchema,
118
126
  ]);
119
127
 
@@ -130,6 +138,7 @@ export const documentElementWithoutIdSchema = z.discriminatedUnion("type", [
130
138
  textInputElementSchema.omit({ id: true }),
131
139
  datePickerElementSchema.omit({ id: true }),
132
140
  signatureElementSchema.omit({ id: true }),
141
+ digitalSignatureElementSchema.omit({ id: true }),
133
142
  fileUploadElementSchema.omit({ id: true }),
134
143
  ]);
135
144
 
@@ -139,6 +148,9 @@ export const createDocumentTemplateSchema = z.object({
139
148
  description: z.string().max(1000).optional(),
140
149
  elements: z.array(documentElementWithoutIdSchema).min(1).max(100),
141
150
  tags: z.array(z.string().min(1).max(50)).max(20).optional(),
151
+ isUserForm: z.boolean().optional().default(false),
152
+ isRequired: z.boolean().optional().default(false),
153
+ sortingOrder: z.number().int().optional().default(0),
142
154
  });
143
155
 
144
156
  // Schema for updating a document template
@@ -148,6 +160,9 @@ export const updateDocumentTemplateSchema = z.object({
148
160
  elements: z.array(documentElementWithoutIdSchema).min(1).max(100).optional(),
149
161
  tags: z.array(z.string().min(1).max(50)).max(20).optional(),
150
162
  isActive: z.boolean().optional(),
163
+ isUserForm: z.boolean().optional(),
164
+ isRequired: z.boolean().optional(),
165
+ sortingOrder: z.number().int().optional(),
151
166
  });
152
167
 
153
168
  // Schema for a document template
@@ -162,4 +177,44 @@ export const documentTemplateSchema = z.object({
162
177
  tags: z.array(z.string().min(1).max(50)).max(20).optional(),
163
178
  version: z.number().int().positive(),
164
179
  isActive: z.boolean(),
180
+ isUserForm: z.boolean().optional().default(false),
181
+ isRequired: z.boolean().optional().default(false),
182
+ sortingOrder: z.number().int().optional().default(0),
183
+ });
184
+
185
+ // Filled Document Schemas
186
+ export const filledDocumentStatusSchema = z.nativeEnum(FilledDocumentStatus);
187
+
188
+ export const filledDocumentSchema = z.object({
189
+ id: z.string(),
190
+ templateId: z.string(),
191
+ templateVersion: z.number(),
192
+ isUserForm: z.boolean(),
193
+ procedureId: z.string(),
194
+ appointmentId: z.string(),
195
+ patientId: z.string(),
196
+ practitionerId: z.string(),
197
+ clinicId: z.string(),
198
+ createdAt: z.number(),
199
+ updatedAt: z.number(),
200
+ values: z.record(z.string(), z.any()),
201
+ status: filledDocumentStatusSchema,
202
+ });
203
+
204
+ export const createFilledDocumentDataSchema = z.object({
205
+ templateId: z.string(),
206
+ procedureId: z.string(),
207
+ appointmentId: z.string(),
208
+ patientId: z.string(),
209
+ practitionerId: z.string(),
210
+ clinicId: z.string(),
211
+ values: z.record(z.string(), z.any()).optional().default({}),
212
+ status: filledDocumentStatusSchema
213
+ .optional()
214
+ .default(FilledDocumentStatus.DRAFT),
215
+ });
216
+
217
+ export const updateFilledDocumentDataSchema = z.object({
218
+ values: z.record(z.string(), z.any()).optional(),
219
+ status: filledDocumentStatusSchema.optional(),
165
220
  });
@@ -1,15 +1,10 @@
1
- import {
2
- createDocumentTemplateSchema,
3
- updateDocumentTemplateSchema,
4
- documentTemplateSchema,
5
- documentElementSchema,
6
- documentElementWithoutIdSchema,
7
- } from "./documentation-templates/template.schema";
1
+ /**
2
+ * This file re-exports all schemas related to documentation templates and filled documents
3
+ * from their specific definition files.
4
+ */
8
5
 
9
- export {
10
- createDocumentTemplateSchema,
11
- updateDocumentTemplateSchema,
12
- documentTemplateSchema,
13
- documentElementSchema,
14
- documentElementWithoutIdSchema,
15
- };
6
+ // Assuming all relevant schemas, including filledDocumentStatusSchema,
7
+ // documentTemplateSchema, createDocumentTemplateSchema, updateDocumentTemplateSchema,
8
+ // filledDocumentSchema, createFilledDocumentDataSchema, updateFilledDocumentDataSchema etc.,
9
+ // are defined and exported from './documentation-templates/template.schema.ts'
10
+ export * from "./documentation-templates/template.schema";
@@ -24,7 +24,7 @@ export const baseNotificationSchema = z.object({
24
24
  * Validaciona šema za pre-requirement notifikaciju
25
25
  */
26
26
  export const preRequirementNotificationSchema = baseNotificationSchema.extend({
27
- notificationType: z.literal(NotificationType.PRE_REQUIREMENT),
27
+ notificationType: z.literal(NotificationType.REQUIREMENT_INSTRUCTION_DUE),
28
28
  treatmentId: z.string(),
29
29
  requirements: z.array(z.string()),
30
30
  deadline: z.any(), // Timestamp
@@ -34,7 +34,7 @@ export const preRequirementNotificationSchema = baseNotificationSchema.extend({
34
34
  * Validaciona šema za post-requirement notifikaciju
35
35
  */
36
36
  export const postRequirementNotificationSchema = baseNotificationSchema.extend({
37
- notificationType: z.literal(NotificationType.POST_REQUIREMENT),
37
+ notificationType: z.literal(NotificationType.REQUIREMENT_INSTRUCTION_DUE),
38
38
  treatmentId: z.string(),
39
39
  requirements: z.array(z.string()),
40
40
  deadline: z.any(), // Timestamp
@@ -56,7 +56,7 @@ export const appointmentReminderNotificationSchema =
56
56
  * Validaciona šema za appointment notifikaciju
57
57
  */
58
58
  export const appointmentNotificationSchema = baseNotificationSchema.extend({
59
- notificationType: z.literal(NotificationType.APPOINTMENT_NOTIFICATION),
59
+ notificationType: z.literal(NotificationType.APPOINTMENT_STATUS_CHANGE),
60
60
  appointmentId: z.string(),
61
61
  appointmentStatus: z.string(),
62
62
  previousStatus: z.string(),
@@ -0,0 +1,75 @@
1
+ import { z } from "zod";
2
+ import {
3
+ PatientInstructionStatus,
4
+ PatientRequirementOverallStatus,
5
+ } from "../../types/patient/patient-requirements";
6
+ import {
7
+ requirementTypeSchema,
8
+ timeUnitSchema, // Corrected import name to lowercase 'u'
9
+ } from "../../backoffice/validations/schemas";
10
+
11
+ /**
12
+ * Zod schema for `PatientInstructionStatus` enum.
13
+ */
14
+ export const patientInstructionStatusSchema = z.nativeEnum(
15
+ PatientInstructionStatus
16
+ );
17
+
18
+ /**
19
+ * Zod schema for `PatientRequirementInstruction` interface.
20
+ */
21
+ export const patientRequirementInstructionSchema = z.object({
22
+ instructionId: z.string().min(1, "Instruction ID is required."),
23
+ instructionText: z.string().min(1, "Instruction text is required."),
24
+ dueTime: z.any(), // Firestore Timestamp
25
+ actionableWindow: z.number().default(1),
26
+ status: patientInstructionStatusSchema,
27
+ originalNotifyAtValue: z.number(),
28
+ originalTimeframeUnit: timeUnitSchema, // Use the correctly imported timeUnitSchema
29
+ notificationId: z.string().optional(),
30
+ actionTakenAt: z.any().optional().nullable(), // Firestore Timestamp or null
31
+ updatedAt: z.any(), // Firestore Timestamp
32
+ });
33
+
34
+ /**
35
+ * Zod schema for `PatientRequirementOverallStatus` enum.
36
+ */
37
+ export const patientRequirementOverallStatusSchema = z.nativeEnum(
38
+ PatientRequirementOverallStatus
39
+ );
40
+
41
+ /**
42
+ * Define requirementImportanceSchema locally as it's not exported directly from backoffice.
43
+ */
44
+ export const requirementImportanceSchema = z.enum(["low", "medium", "high"]);
45
+
46
+ /**
47
+ * Zod schema for `PatientRequirementInstance` interface.
48
+ */
49
+ export const patientRequirementInstanceSchema = z.object({
50
+ id: z.string().min(1, "Instance ID is required."),
51
+ patientId: z.string().min(1, "Patient ID is required."),
52
+ appointmentId: z.string().min(1, "Appointment ID is required."),
53
+ originalRequirementId: z
54
+ .string()
55
+ .min(1, "Original Requirement ID is required."),
56
+ requirementType: requirementTypeSchema,
57
+ requirementName: z.string().min(1, "Requirement name is required."),
58
+ requirementDescription: z.string(),
59
+ requirementImportance: requirementImportanceSchema, // Use the locally defined schema
60
+ overallStatus: patientRequirementOverallStatusSchema,
61
+ instructions: z
62
+ .array(patientRequirementInstructionSchema)
63
+ .min(1, "At least one instruction is required."),
64
+ createdAt: z.any(), // Firestore Timestamp
65
+ updatedAt: z.any(), // Firestore Timestamp
66
+ });
67
+
68
+ /**
69
+ * Schema for updating a `PatientRequirementInstruction` status (subset of fields).
70
+ * Useful for when a patient marks an instruction as actioned.
71
+ */
72
+ export const updatePatientInstructionStatusSchema = z.object({
73
+ status: z.literal(PatientInstructionStatus.ACTION_TAKEN),
74
+ actionTakenAt: z.any(), // Should be a Timestamp from the server
75
+ });