@blackcode_sa/metaestetics-api 1.11.1 → 1.11.2

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 (36) hide show
  1. package/dist/admin/index.d.mts +324 -330
  2. package/dist/admin/index.d.ts +324 -330
  3. package/dist/backoffice/index.d.mts +67 -283
  4. package/dist/backoffice/index.d.ts +67 -283
  5. package/dist/backoffice/index.js +6 -114
  6. package/dist/backoffice/index.mjs +6 -112
  7. package/dist/index.d.mts +3037 -3100
  8. package/dist/index.d.ts +3037 -3100
  9. package/dist/index.js +129 -379
  10. package/dist/index.mjs +130 -379
  11. package/package.json +1 -1
  12. package/src/backoffice/expo-safe/index.ts +0 -2
  13. package/src/backoffice/services/__tests__/brand.service.test.ts +196 -0
  14. package/src/backoffice/services/__tests__/category.service.test.ts +201 -0
  15. package/src/backoffice/services/__tests__/product.service.test.ts +358 -0
  16. package/src/backoffice/services/__tests__/requirement.service.test.ts +226 -0
  17. package/src/backoffice/services/__tests__/subcategory.service.test.ts +181 -0
  18. package/src/backoffice/services/__tests__/technology.service.test.ts +1097 -0
  19. package/src/backoffice/services/technology.service.ts +10 -122
  20. package/src/backoffice/types/index.ts +0 -1
  21. package/src/backoffice/types/product.types.ts +1 -3
  22. package/src/backoffice/types/technology.types.ts +4 -4
  23. package/src/backoffice/validations/schemas.ts +9 -35
  24. package/src/services/appointment/appointment.service.ts +5 -0
  25. package/src/services/appointment/utils/appointment.utils.ts +113 -124
  26. package/src/services/procedure/procedure.service.ts +234 -434
  27. package/src/types/appointment/index.ts +37 -43
  28. package/src/types/clinic/index.ts +6 -1
  29. package/src/types/patient/medical-info.types.ts +3 -3
  30. package/src/types/procedure/index.ts +17 -20
  31. package/src/validations/appointment.schema.ts +118 -170
  32. package/src/validations/clinic.schema.ts +6 -1
  33. package/src/validations/patient/medical-info.schema.ts +2 -7
  34. package/src/backoffice/services/README.md +0 -40
  35. package/src/backoffice/services/constants.service.ts +0 -268
  36. package/src/backoffice/types/admin-constants.types.ts +0 -69
@@ -14,8 +14,8 @@ import {
14
14
  import { Technology, TECHNOLOGIES_COLLECTION } from "../types/technology.types";
15
15
  import { Requirement, RequirementType } from "../types/requirement.types";
16
16
  import { BlockingCondition } from "../types/static/blocking-condition.types";
17
- import { ContraindicationDynamic } from "../types/admin-constants.types";
18
- import { TreatmentBenefitDynamic } from "../types/admin-constants.types";
17
+ import { Contraindication } from "../types/static/contraindication.types";
18
+ import { TreatmentBenefit } from "../types/static/treatment-benefit.types";
19
19
  import {
20
20
  CertificationLevel,
21
21
  CertificationSpecialty,
@@ -346,21 +346,12 @@ export class TechnologyService extends BaseService {
346
346
  */
347
347
  async addContraindication(
348
348
  technologyId: string,
349
- contraindication: ContraindicationDynamic
349
+ contraindication: Contraindication
350
350
  ) {
351
351
  const docRef = doc(this.getTechnologiesRef(), technologyId);
352
- const technology = await this.getById(technologyId);
353
- if (!technology) {
354
- throw new Error(`Technology with id ${technologyId} not found`);
355
- }
356
-
357
- const existingContraindications = technology.contraindications || [];
358
- if (existingContraindications.some((c) => c.id === contraindication.id)) {
359
- return technology; // Already exists, do nothing
360
- }
361
352
 
362
353
  await updateDoc(docRef, {
363
- contraindications: [...existingContraindications, contraindication],
354
+ contraindications: arrayUnion(contraindication),
364
355
  updatedAt: new Date(),
365
356
  });
366
357
 
@@ -375,62 +366,12 @@ export class TechnologyService extends BaseService {
375
366
  */
376
367
  async removeContraindication(
377
368
  technologyId: string,
378
- contraindication: ContraindicationDynamic
369
+ contraindication: Contraindication
379
370
  ) {
380
371
  const docRef = doc(this.getTechnologiesRef(), technologyId);
381
- const technology = await this.getById(technologyId);
382
- if (!technology) {
383
- throw new Error(`Technology with id ${technologyId} not found`);
384
- }
385
-
386
- const updatedContraindications = (
387
- technology.contraindications || []
388
- ).filter((c) => c.id !== contraindication.id);
389
-
390
- await updateDoc(docRef, {
391
- contraindications: updatedContraindications,
392
- updatedAt: new Date(),
393
- });
394
-
395
- return this.getById(technologyId);
396
- }
397
-
398
- /**
399
- * Updates an existing contraindication in a technology's list.
400
- * If the contraindication does not exist, it will not be added.
401
- * @param technologyId - ID of the technology
402
- * @param contraindication - The updated contraindication object
403
- * @returns The updated technology
404
- */
405
- async updateContraindication(
406
- technologyId: string,
407
- contraindication: ContraindicationDynamic
408
- ) {
409
- const docRef = doc(this.getTechnologiesRef(), technologyId);
410
- const technology = await this.getById(technologyId);
411
- if (!technology) {
412
- throw new Error(`Technology with id ${technologyId} not found`);
413
- }
414
-
415
- const contraindications = technology.contraindications || [];
416
- const index = contraindications.findIndex(
417
- (c) => c.id === contraindication.id
418
- );
419
-
420
- if (index === -1) {
421
- // If contraindication doesn't exist, do not update
422
- // Consider throwing an error if this is an unexpected state
423
- console.warn(
424
- `Contraindication with id ${contraindication.id} not found for technology ${technologyId}. No update performed.`
425
- );
426
- return technology;
427
- }
428
-
429
- const updatedContraindications = [...contraindications];
430
- updatedContraindications[index] = contraindication;
431
372
 
432
373
  await updateDoc(docRef, {
433
- contraindications: updatedContraindications,
374
+ contraindications: arrayRemove(contraindication),
434
375
  updatedAt: new Date(),
435
376
  });
436
377
 
@@ -443,20 +384,11 @@ export class TechnologyService extends BaseService {
443
384
  * @param benefit - Benefit koji se dodaje
444
385
  * @returns Ažurirana tehnologija
445
386
  */
446
- async addBenefit(technologyId: string, benefit: TreatmentBenefitDynamic) {
387
+ async addBenefit(technologyId: string, benefit: TreatmentBenefit) {
447
388
  const docRef = doc(this.getTechnologiesRef(), technologyId);
448
- const technology = await this.getById(technologyId);
449
- if (!technology) {
450
- throw new Error(`Technology with id ${technologyId} not found`);
451
- }
452
-
453
- const existingBenefits = technology.benefits || [];
454
- if (existingBenefits.some((b) => b.id === benefit.id)) {
455
- return technology; // Already exists, do nothing
456
- }
457
389
 
458
390
  await updateDoc(docRef, {
459
- benefits: [...existingBenefits, benefit],
391
+ benefits: arrayUnion(benefit),
460
392
  updatedAt: new Date(),
461
393
  });
462
394
 
@@ -469,55 +401,11 @@ export class TechnologyService extends BaseService {
469
401
  * @param benefit - Benefit koji se uklanja
470
402
  * @returns Ažurirana tehnologija
471
403
  */
472
- async removeBenefit(technologyId: string, benefit: TreatmentBenefitDynamic) {
404
+ async removeBenefit(technologyId: string, benefit: TreatmentBenefit) {
473
405
  const docRef = doc(this.getTechnologiesRef(), technologyId);
474
- const technology = await this.getById(technologyId);
475
- if (!technology) {
476
- throw new Error(`Technology with id ${technologyId} not found`);
477
- }
478
-
479
- const updatedBenefits = (technology.benefits || []).filter(
480
- (b) => b.id !== benefit.id
481
- );
482
-
483
- await updateDoc(docRef, {
484
- benefits: updatedBenefits,
485
- updatedAt: new Date(),
486
- });
487
-
488
- return this.getById(technologyId);
489
- }
490
-
491
- /**
492
- * Updates an existing benefit in a technology's list.
493
- * If the benefit does not exist, it will not be added.
494
- * @param technologyId - ID of the technology
495
- * @param benefit - The updated benefit object
496
- * @returns The updated technology
497
- */
498
- async updateBenefit(technologyId: string, benefit: TreatmentBenefitDynamic) {
499
- const docRef = doc(this.getTechnologiesRef(), technologyId);
500
- const technology = await this.getById(technologyId);
501
- if (!technology) {
502
- throw new Error(`Technology with id ${technologyId} not found`);
503
- }
504
-
505
- const benefits = technology.benefits || [];
506
- const index = benefits.findIndex((b) => b.id === benefit.id);
507
-
508
- if (index === -1) {
509
- // If benefit doesn't exist, do not update
510
- console.warn(
511
- `Benefit with id ${benefit.id} not found for technology ${technologyId}. No update performed.`
512
- );
513
- return technology;
514
- }
515
-
516
- const updatedBenefits = [...benefits];
517
- updatedBenefits[index] = benefit;
518
406
 
519
407
  await updateDoc(docRef, {
520
- benefits: updatedBenefits,
408
+ benefits: arrayRemove(benefit),
521
409
  updatedAt: new Date(),
522
410
  });
523
411
 
@@ -6,4 +6,3 @@ export * from "./requirement.types";
6
6
  export * from "./subcategory.types";
7
7
  export * from "./technology.types";
8
8
  export * from "./static";
9
- export * from "./admin-constants.types";
@@ -1,5 +1,3 @@
1
- import type { ContraindicationDynamic } from "./admin-constants.types";
2
-
3
1
  /**
4
2
  * Product used in procedures
5
3
  * Can be consumables, equipment, or any other product needed for performing procedures
@@ -35,7 +33,7 @@ export interface Product {
35
33
  dosage?: string;
36
34
  composition?: string;
37
35
  indications?: string[];
38
- contraindications?: ContraindicationDynamic[];
36
+ contraindications?: string[];
39
37
  }
40
38
 
41
39
  /**
@@ -1,10 +1,10 @@
1
1
  import { Requirement } from "./requirement.types";
2
2
  import { BlockingCondition } from "./static/blocking-condition.types";
3
+ import { Contraindication } from "./static/contraindication.types";
4
+ import { TreatmentBenefit } from "./static/treatment-benefit.types";
3
5
  import { CertificationRequirement } from "./static/certification.types";
4
6
  import { DocumentTemplate } from "../../types/documentation-templates";
5
7
  import { ProcedureFamily } from "./static/procedure-family.types";
6
- import { ContraindicationDynamic } from "./admin-constants.types";
7
- import { TreatmentBenefitDynamic } from "./admin-constants.types";
8
8
 
9
9
  /**
10
10
  * Reference to a documentation template with metadata
@@ -65,8 +65,8 @@ export interface Technology {
65
65
  post: Requirement[];
66
66
  };
67
67
  blockingConditions: BlockingCondition[];
68
- contraindications: ContraindicationDynamic[];
69
- benefits: TreatmentBenefitDynamic[];
68
+ contraindications: Contraindication[];
69
+ benefits: TreatmentBenefit[];
70
70
  certificationRequirement: CertificationRequirement;
71
71
  documentationTemplates?: TechnologyDocumentationTemplate[];
72
72
  isActive: boolean;
@@ -1,53 +1,27 @@
1
1
  import { z } from "zod";
2
2
  import { ProcedureFamily } from "../types/static/procedure-family.types";
3
3
  import { BlockingCondition } from "../types/static/blocking-condition.types";
4
+ import { Contraindication } from "../types/static/contraindication.types";
5
+ import { TreatmentBenefit } from "../types/static/treatment-benefit.types";
4
6
  import { TimeUnit, RequirementType } from "../types/requirement.types";
5
7
  import {
6
8
  CertificationLevel,
7
9
  CertificationSpecialty,
8
10
  } from "../types/static/certification.types";
9
-
11
+ import {
12
+ DocumentElementType,
13
+ HeadingLevel,
14
+ ListType,
15
+ } from "../types/documentation-templates.types";
10
16
  import { documentTemplateSchema } from "../../validations/documentation-templates.schema";
11
17
 
12
- /**
13
- * Zod validation schema for a single dynamic contraindication.
14
- * @see ContraindicationDynamic in admin-constants.types.ts
15
- */
16
- export const contraindicationDynamicSchema = z.object({
17
- id: z
18
- .string()
19
- .min(1, "Contraindication ID is required")
20
- .regex(
21
- /^[a-z0-9_]+$/,
22
- "ID must be in snake_case (lowercase, numbers, and underscores only)"
23
- ),
24
- name: z.string().min(1, "Contraindication name is required"),
25
- description: z.string().optional(),
26
- });
27
-
28
- /**
29
- * Zod validation schema for a single dynamic treatment benefit.
30
- * @see TreatmentBenefitDynamic in admin-constants.types.ts
31
- */
32
- export const treatmentBenefitDynamicSchema = z.object({
33
- id: z
34
- .string()
35
- .min(1, "Benefit ID is required")
36
- .regex(
37
- /^[a-z0-9_]+$/,
38
- "ID must be in snake_case (lowercase, numbers, and underscores only)"
39
- ),
40
- name: z.string().min(1, "Benefit name is required"),
41
- description: z.string().optional(),
42
- });
43
-
44
18
  /**
45
19
  * Base validation schemas for enums
46
20
  */
47
21
  export const blockingConditionSchemaBackoffice =
48
22
  z.nativeEnum(BlockingCondition);
49
- export const contraindicationSchemaBackoffice = contraindicationDynamicSchema;
50
- export const treatmentBenefitSchemaBackoffice = treatmentBenefitDynamicSchema;
23
+ export const contraindicationSchemaBackoffice = z.nativeEnum(Contraindication);
24
+ export const treatmentBenefitSchemaBackoffice = z.nativeEnum(TreatmentBenefit);
51
25
  export const procedureFamilySchemaBackoffice = z.nativeEnum(ProcedureFamily);
52
26
  export const timeUnitSchemaBackoffice = z.nativeEnum(TimeUnit);
53
27
  export const requirementTypeSchema = z.nativeEnum(RequirementType);
@@ -21,15 +21,18 @@ import { BaseService } from "../base.service";
21
21
  import {
22
22
  Appointment,
23
23
  AppointmentStatus,
24
+ CreateAppointmentData,
24
25
  UpdateAppointmentData,
25
26
  SearchAppointmentsParams,
26
27
  PaymentStatus,
27
28
  AppointmentMediaItem,
28
29
  PatientReviewInfo,
30
+ LinkedFormInfo,
29
31
  type CreateAppointmentHttpData,
30
32
  APPOINTMENTS_COLLECTION,
31
33
  } from "../../types/appointment";
32
34
  import {
35
+ createAppointmentSchema,
33
36
  updateAppointmentSchema,
34
37
  searchAppointmentsSchema,
35
38
  rescheduleAppointmentSchema,
@@ -44,6 +47,8 @@ import { FilledDocumentService } from "../documentation-templates/filled-documen
44
47
 
45
48
  // Import utility functions
46
49
  import {
50
+ fetchAggregatedInfoUtil,
51
+ createAppointmentUtil,
47
52
  updateAppointmentUtil,
48
53
  getAppointmentByIdUtil,
49
54
  searchAppointmentsUtil,
@@ -33,6 +33,7 @@ import {
33
33
  PractitionerProfileInfo,
34
34
  } from "../../../types/profile";
35
35
  import { BlockingCondition } from "../../../backoffice/types/static/blocking-condition.types";
36
+ import { Contraindication } from "../../../backoffice/types/static/contraindication.types";
36
37
  import { Requirement } from "../../../backoffice/types/requirement.types";
37
38
  import { PRACTITIONERS_COLLECTION } from "../../../types/practitioner";
38
39
  import { CLINICS_COLLECTION } from "../../../types/clinic";
@@ -42,7 +43,6 @@ import {
42
43
  Technology,
43
44
  TECHNOLOGIES_COLLECTION,
44
45
  } from "../../../backoffice/types/technology.types";
45
- import type { ContraindicationDynamic } from "../../../backoffice";
46
46
 
47
47
  /**
48
48
  * Fetches all the necessary information for an appointment by IDs.
@@ -66,7 +66,7 @@ export async function fetchAggregatedInfoUtil(
66
66
  patientInfo: PatientProfileInfo;
67
67
  procedureInfo: ProcedureSummaryInfo;
68
68
  blockingConditions: BlockingCondition[];
69
- contraindications: ContraindicationDynamic[];
69
+ contraindications: Contraindication[];
70
70
  preProcedureRequirements: Requirement[];
71
71
  postProcedureRequirements: Requirement[];
72
72
  }> {
@@ -162,7 +162,7 @@ export async function fetchAggregatedInfoUtil(
162
162
  }
163
163
 
164
164
  let blockingConditions: BlockingCondition[] = [];
165
- let contraindications: ContraindicationDynamic[] = [];
165
+ let contraindications: Contraindication[] = [];
166
166
  let preProcedureRequirements: Requirement[] = [];
167
167
  let postProcedureRequirements: Requirement[] = [];
168
168
 
@@ -213,85 +213,85 @@ export async function fetchAggregatedInfoUtil(
213
213
  * @param generateId Function to generate a unique ID
214
214
  * @returns The created Appointment
215
215
  */
216
- // export async function createAppointmentUtil(
217
- // db: Firestore,
218
- // data: CreateAppointmentData,
219
- // aggregatedInfo: {
220
- // clinicInfo: ClinicInfo;
221
- // practitionerInfo: PractitionerProfileInfo;
222
- // patientInfo: PatientProfileInfo;
223
- // procedureInfo: ProcedureSummaryInfo;
224
- // blockingConditions: BlockingCondition[];
225
- // contraindications: ContraindicationDynamic[];
226
- // preProcedureRequirements: Requirement[];
227
- // postProcedureRequirements: Requirement[];
228
- // },
229
- // generateId: () => string
230
- // ): Promise<Appointment> {
231
- // try {
232
- // const appointmentId = generateId();
233
-
234
- // // Create appointment object
235
- // const appointment: Omit<Appointment, "createdAt" | "updatedAt"> & {
236
- // createdAt: any;
237
- // updatedAt: any;
238
- // } = {
239
- // id: appointmentId,
240
- // calendarEventId: data.calendarEventId,
241
- // clinicBranchId: data.clinicBranchId,
242
- // clinicInfo: aggregatedInfo.clinicInfo,
243
- // practitionerId: data.practitionerId,
244
- // practitionerInfo: aggregatedInfo.practitionerInfo,
245
- // patientId: data.patientId,
246
- // patientInfo: aggregatedInfo.patientInfo,
247
- // procedureId: data.procedureId,
248
- // procedureInfo: aggregatedInfo.procedureInfo,
249
- // status: data.initialStatus,
250
- // bookingTime: Timestamp.now(),
251
- // appointmentStartTime: data.appointmentStartTime,
252
- // appointmentEndTime: data.appointmentEndTime,
253
- // patientNotes: data.patientNotes || null,
254
- // cost: data.cost,
255
- // currency: data.currency,
256
- // paymentStatus: data.initialPaymentStatus || PaymentStatus.UNPAID,
257
- // blockingConditions: aggregatedInfo.blockingConditions,
258
- // contraindications: aggregatedInfo.contraindications,
259
- // preProcedureRequirements: aggregatedInfo.preProcedureRequirements,
260
- // postProcedureRequirements: aggregatedInfo.postProcedureRequirements,
261
- // completedPreRequirements: [],
262
- // completedPostRequirements: [],
263
- // createdAt: serverTimestamp(),
264
- // updatedAt: serverTimestamp(),
265
- // };
266
-
267
- // // Add additional fields for confirmation if appointment is already confirmed
268
- // if (data.initialStatus === AppointmentStatus.CONFIRMED) {
269
- // appointment.confirmationTime = Timestamp.now();
270
- // }
271
-
272
- // // Save to Firestore
273
- // await setDoc(doc(db, APPOINTMENTS_COLLECTION, appointmentId), appointment);
274
-
275
- // // Update the calendar event with the appointment ID
276
- // const calendarEventRef = doc(db, CALENDAR_COLLECTION, data.calendarEventId);
277
- // await updateDoc(calendarEventRef, {
278
- // appointmentId: appointmentId,
279
- // updatedAt: serverTimestamp(),
280
- // });
281
-
282
- // // Return the created appointment
283
- // // Convert serverTimestamp to regular Timestamp for immediate use
284
- // const now = Timestamp.now();
285
- // return {
286
- // ...appointment,
287
- // createdAt: now,
288
- // updatedAt: now,
289
- // } as Appointment;
290
- // } catch (error) {
291
- // console.error("Error creating appointment:", error);
292
- // throw error;
293
- // }
294
- // }
216
+ export async function createAppointmentUtil(
217
+ db: Firestore,
218
+ data: CreateAppointmentData,
219
+ aggregatedInfo: {
220
+ clinicInfo: ClinicInfo;
221
+ practitionerInfo: PractitionerProfileInfo;
222
+ patientInfo: PatientProfileInfo;
223
+ procedureInfo: ProcedureSummaryInfo;
224
+ blockingConditions: BlockingCondition[];
225
+ contraindications: Contraindication[];
226
+ preProcedureRequirements: Requirement[];
227
+ postProcedureRequirements: Requirement[];
228
+ },
229
+ generateId: () => string
230
+ ): Promise<Appointment> {
231
+ try {
232
+ const appointmentId = generateId();
233
+
234
+ // Create appointment object
235
+ const appointment: Omit<Appointment, "createdAt" | "updatedAt"> & {
236
+ createdAt: any;
237
+ updatedAt: any;
238
+ } = {
239
+ id: appointmentId,
240
+ calendarEventId: data.calendarEventId,
241
+ clinicBranchId: data.clinicBranchId,
242
+ clinicInfo: aggregatedInfo.clinicInfo,
243
+ practitionerId: data.practitionerId,
244
+ practitionerInfo: aggregatedInfo.practitionerInfo,
245
+ patientId: data.patientId,
246
+ patientInfo: aggregatedInfo.patientInfo,
247
+ procedureId: data.procedureId,
248
+ procedureInfo: aggregatedInfo.procedureInfo,
249
+ status: data.initialStatus,
250
+ bookingTime: Timestamp.now(),
251
+ appointmentStartTime: data.appointmentStartTime,
252
+ appointmentEndTime: data.appointmentEndTime,
253
+ patientNotes: data.patientNotes || null,
254
+ cost: data.cost,
255
+ currency: data.currency,
256
+ paymentStatus: data.initialPaymentStatus || PaymentStatus.UNPAID,
257
+ blockingConditions: aggregatedInfo.blockingConditions,
258
+ contraindications: aggregatedInfo.contraindications,
259
+ preProcedureRequirements: aggregatedInfo.preProcedureRequirements,
260
+ postProcedureRequirements: aggregatedInfo.postProcedureRequirements,
261
+ completedPreRequirements: [],
262
+ completedPostRequirements: [],
263
+ createdAt: serverTimestamp(),
264
+ updatedAt: serverTimestamp(),
265
+ };
266
+
267
+ // Add additional fields for confirmation if appointment is already confirmed
268
+ if (data.initialStatus === AppointmentStatus.CONFIRMED) {
269
+ appointment.confirmationTime = Timestamp.now();
270
+ }
271
+
272
+ // Save to Firestore
273
+ await setDoc(doc(db, APPOINTMENTS_COLLECTION, appointmentId), appointment);
274
+
275
+ // Update the calendar event with the appointment ID
276
+ const calendarEventRef = doc(db, CALENDAR_COLLECTION, data.calendarEventId);
277
+ await updateDoc(calendarEventRef, {
278
+ appointmentId: appointmentId,
279
+ updatedAt: serverTimestamp(),
280
+ });
281
+
282
+ // Return the created appointment
283
+ // Convert serverTimestamp to regular Timestamp for immediate use
284
+ const now = Timestamp.now();
285
+ return {
286
+ ...appointment,
287
+ createdAt: now,
288
+ updatedAt: now,
289
+ } as Appointment;
290
+ } catch (error) {
291
+ console.error("Error creating appointment:", error);
292
+ throw error;
293
+ }
294
+ }
295
295
 
296
296
  /**
297
297
  * Updates an existing appointment in Firestore.
@@ -327,27 +327,23 @@ export async function updateAppointmentUtil(
327
327
  const validPreReqIds = currentAppointment.preProcedureRequirements.map(
328
328
  (req) => req.id
329
329
  );
330
+ const invalidPreReqIds = data.completedPreRequirements.filter(
331
+ (id) => !validPreReqIds.includes(id)
332
+ );
330
333
 
331
- // Only perform validation and merging if the input is an array
332
- if (Array.isArray(data.completedPreRequirements)) {
333
- const invalidPreReqIds = data.completedPreRequirements.filter(
334
- (id) => !validPreReqIds.includes(id)
334
+ if (invalidPreReqIds.length > 0) {
335
+ throw new Error(
336
+ `Invalid pre-requirement IDs: ${invalidPreReqIds.join(", ")}`
335
337
  );
336
-
337
- if (invalidPreReqIds.length > 0) {
338
- throw new Error(
339
- `Invalid pre-requirement IDs: ${invalidPreReqIds.join(", ")}`
340
- );
341
- }
342
-
343
- // Update the completed pre-requirements
344
- completedPreRequirements = [
345
- ...new Set([
346
- ...completedPreRequirements,
347
- ...data.completedPreRequirements,
348
- ]),
349
- ];
350
338
  }
339
+
340
+ // Update the completed pre-requirements
341
+ completedPreRequirements = [
342
+ ...new Set([
343
+ ...completedPreRequirements,
344
+ ...data.completedPreRequirements,
345
+ ]),
346
+ ];
351
347
  }
352
348
 
353
349
  if (data.completedPostRequirements) {
@@ -355,37 +351,30 @@ export async function updateAppointmentUtil(
355
351
  const validPostReqIds = currentAppointment.postProcedureRequirements.map(
356
352
  (req) => req.id
357
353
  );
354
+ const invalidPostReqIds = data.completedPostRequirements.filter(
355
+ (id) => !validPostReqIds.includes(id)
356
+ );
358
357
 
359
- if (Array.isArray(data.completedPostRequirements)) {
360
- const invalidPostReqIds = data.completedPostRequirements.filter(
361
- (id) => !validPostReqIds.includes(id)
358
+ if (invalidPostReqIds.length > 0) {
359
+ throw new Error(
360
+ `Invalid post-requirement IDs: ${invalidPostReqIds.join(", ")}`
362
361
  );
363
-
364
- if (invalidPostReqIds.length > 0) {
365
- throw new Error(
366
- `Invalid post-requirement IDs: ${invalidPostReqIds.join(", ")}`
367
- );
368
- }
369
-
370
- // Update the completed post-requirements
371
- completedPostRequirements = [
372
- ...new Set([
373
- ...completedPostRequirements,
374
- ...data.completedPostRequirements,
375
- ]),
376
- ];
377
362
  }
363
+
364
+ // Update the completed post-requirements
365
+ completedPostRequirements = [
366
+ ...new Set([
367
+ ...completedPostRequirements,
368
+ ...data.completedPostRequirements,
369
+ ]),
370
+ ];
378
371
  }
379
372
 
380
373
  // Prepare update data
381
374
  const updateData: any = {
382
375
  ...data,
383
- completedPreRequirements: Array.isArray(data.completedPreRequirements)
384
- ? completedPreRequirements
385
- : data.completedPreRequirements,
386
- completedPostRequirements: Array.isArray(data.completedPostRequirements)
387
- ? completedPostRequirements
388
- : data.completedPostRequirements,
376
+ completedPreRequirements,
377
+ completedPostRequirements,
389
378
  updatedAt: serverTimestamp(),
390
379
  };
391
380
 
@@ -465,7 +454,7 @@ async function updateCalendarEventStatus(
465
454
  case AppointmentStatus.CANCELED_CLINIC:
466
455
  calendarStatus = "canceled";
467
456
  break;
468
- case AppointmentStatus.RESCHEDULED_BY_CLINIC:
457
+ case AppointmentStatus.RESCHEDULED:
469
458
  calendarStatus = "rescheduled";
470
459
  break;
471
460
  case AppointmentStatus.COMPLETED: