@blackcode_sa/metaestetics-api 1.7.37 → 1.7.39

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/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/validations/appointment.schema.ts
2
- import { z as z2 } from "zod";
2
+ import { z as z3 } from "zod";
3
3
 
4
4
  // src/types/appointment/index.ts
5
5
  var AppointmentStatus = /* @__PURE__ */ ((AppointmentStatus2) => {
@@ -267,139 +267,187 @@ var updateFilledDocumentDataSchema = z.object({
267
267
  status: filledDocumentStatusSchema.optional()
268
268
  });
269
269
 
270
+ // src/backoffice/types/static/pricing.types.ts
271
+ var PricingMeasure = /* @__PURE__ */ ((PricingMeasure3) => {
272
+ PricingMeasure3["PER_ML"] = "per_ml";
273
+ PricingMeasure3["PER_ZONE"] = "per_zone";
274
+ PricingMeasure3["PER_AREA"] = "per_area";
275
+ PricingMeasure3["PER_SESSION"] = "per_session";
276
+ PricingMeasure3["PER_TREATMENT"] = "per_treatment";
277
+ PricingMeasure3["PER_PACKAGE"] = "per_package";
278
+ return PricingMeasure3;
279
+ })(PricingMeasure || {});
280
+ var Currency = /* @__PURE__ */ ((Currency2) => {
281
+ Currency2["EUR"] = "EUR";
282
+ Currency2["USD"] = "USD";
283
+ Currency2["GBP"] = "GBP";
284
+ Currency2["CHF"] = "CHF";
285
+ Currency2["AUD"] = "AUD";
286
+ return Currency2;
287
+ })(Currency || {});
288
+
289
+ // src/validations/media.schema.ts
290
+ import { z as z2 } from "zod";
291
+ var mediaResourceSchema = z2.union([
292
+ z2.string().url(),
293
+ z2.instanceof(File),
294
+ z2.instanceof(Blob)
295
+ ]);
296
+
270
297
  // src/validations/appointment.schema.ts
271
298
  var MIN_STRING_LENGTH = 1;
272
299
  var MAX_STRING_LENGTH = 1024;
273
300
  var MAX_STRING_LENGTH_LONG = 4096;
274
301
  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"),
302
+ var appointmentStatusSchema = z3.nativeEnum(AppointmentStatus);
303
+ var paymentStatusSchema = z3.nativeEnum(PaymentStatus);
304
+ var mediaTypeSchema = z3.nativeEnum(MediaType);
305
+ var appointmentMediaItemSchema = z3.object({
306
+ id: z3.string().min(MIN_STRING_LENGTH, "Media item ID is required"),
280
307
  type: mediaTypeSchema,
281
- url: z2.string().url("Media URL must be a valid URL"),
282
- fileName: z2.string().optional(),
283
- uploadedAt: z2.any().refine(
308
+ url: z3.string().url("Media URL must be a valid URL"),
309
+ fileName: z3.string().optional(),
310
+ uploadedAt: z3.any().refine(
284
311
  (val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || (val == null ? void 0 : val.seconds) !== void 0 || typeof val === "number" || typeof val === "string" || val && typeof val.toMillis === "function",
285
312
  "uploadedAt must be a valid timestamp or Date object"
286
313
  ),
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()
314
+ uploadedBy: z3.string().min(MIN_STRING_LENGTH, "Uploaded by user ID is required"),
315
+ description: z3.string().max(MAX_STRING_LENGTH, "Description too long").optional()
289
316
  });
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()
317
+ var procedureExtendedInfoSchema = z3.object({
318
+ id: z3.string().min(MIN_STRING_LENGTH),
319
+ name: z3.string().min(MIN_STRING_LENGTH),
320
+ description: z3.string(),
321
+ cost: z3.number().min(0),
322
+ duration: z3.number().min(0),
323
+ procedureFamily: z3.any(),
324
+ procedureCategoryId: z3.string(),
325
+ procedureCategoryName: z3.string(),
326
+ procedureSubCategoryId: z3.string(),
327
+ procedureSubCategoryName: z3.string(),
328
+ procedureTechnologyId: z3.string(),
329
+ procedureTechnologyName: z3.string(),
330
+ procedureProductBrandId: z3.string(),
331
+ procedureProductBrandName: z3.string(),
332
+ procedureProductId: z3.string(),
333
+ procedureProductName: z3.string()
307
334
  });
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
- isRequired: z2.boolean().optional(),
335
+ var linkedFormInfoSchema = z3.object({
336
+ formId: z3.string().min(MIN_STRING_LENGTH, "Form ID is required"),
337
+ templateId: z3.string().min(MIN_STRING_LENGTH, "Template ID is required"),
338
+ templateVersion: z3.number().int().positive("Template version must be a positive integer"),
339
+ title: z3.string().min(MIN_STRING_LENGTH, "Form title is required"),
340
+ isUserForm: z3.boolean(),
341
+ isRequired: z3.boolean().optional(),
315
342
  status: filledDocumentStatusSchema,
316
- path: z2.string().min(MIN_STRING_LENGTH, "Form path is required"),
317
- submittedAt: z2.any().refine(
343
+ path: z3.string().min(MIN_STRING_LENGTH, "Form path is required"),
344
+ submittedAt: z3.any().refine(
318
345
  (val) => val === void 0 || val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || (val == null ? void 0 : val.seconds) !== void 0 || typeof val === "number" || typeof val === "string" || val && typeof val.toMillis === "function",
319
346
  "submittedAt must be a valid timestamp or Date object"
320
347
  ).optional(),
321
- completedAt: z2.any().refine(
348
+ completedAt: z3.any().refine(
322
349
  (val) => val === void 0 || val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || (val == null ? void 0 : val.seconds) !== void 0 || typeof val === "number" || typeof val === "string" || val && typeof val.toMillis === "function",
323
350
  "completedAt must be a valid timestamp or Date object"
324
351
  ).optional()
325
352
  });
326
- var patientReviewInfoSchema = z2.object({
327
- reviewId: z2.string().min(MIN_STRING_LENGTH, "Review ID is required"),
328
- rating: z2.number().min(1).max(5, "Rating must be between 1 and 5"),
329
- comment: z2.string().max(MAX_STRING_LENGTH_LONG, "Comment too long").optional(),
330
- reviewedAt: z2.any().refine(
353
+ var patientReviewInfoSchema = z3.object({
354
+ reviewId: z3.string().min(MIN_STRING_LENGTH, "Review ID is required"),
355
+ rating: z3.number().min(1).max(5, "Rating must be between 1 and 5"),
356
+ comment: z3.string().max(MAX_STRING_LENGTH_LONG, "Comment too long").optional(),
357
+ reviewedAt: z3.any().refine(
331
358
  (val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || (val == null ? void 0 : val.seconds) !== void 0 || typeof val === "number" || typeof val === "string" || val && typeof val.toMillis === "function",
332
359
  "reviewedAt must be a valid timestamp or Date object"
333
360
  )
334
361
  });
335
- var finalizedDetailsSchema = z2.object({
336
- by: z2.string().min(MIN_STRING_LENGTH, "Finalized by user ID is required"),
337
- at: z2.any().refine(
362
+ var finalizedDetailsSchema = z3.object({
363
+ by: z3.string().min(MIN_STRING_LENGTH, "Finalized by user ID is required"),
364
+ at: z3.any().refine(
338
365
  (val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || (val == null ? void 0 : val.seconds) !== void 0 || typeof val === "number" || typeof val === "string" || val && typeof val.toMillis === "function",
339
366
  "Finalized at must be a valid timestamp or Date object"
340
367
  ),
341
- notes: z2.string().max(MAX_STRING_LENGTH_LONG, "Finalization notes too long").optional()
368
+ notes: z3.string().max(MAX_STRING_LENGTH_LONG, "Finalization notes too long").optional()
369
+ });
370
+ var beforeAfterPerZoneSchema = z3.object({
371
+ before: mediaResourceSchema.nullable(),
372
+ after: mediaResourceSchema.nullable(),
373
+ note: z3.string().nullable()
374
+ });
375
+ var billingPerZoneSchema = z3.object({
376
+ Product: z3.string().min(MIN_STRING_LENGTH, "Product name is required"),
377
+ ProductId: z3.string().nullable(),
378
+ Quantity: z3.number().min(0, "Quantity must be non-negative"),
379
+ UnitOfMeasurement: z3.nativeEnum(PricingMeasure),
380
+ UnitPrice: z3.number().min(0, "Unit price must be non-negative"),
381
+ UnitCurency: z3.nativeEnum(Currency),
382
+ Subtotal: z3.number().min(0, "Subtotal must be non-negative"),
383
+ Note: z3.string().nullable()
342
384
  });
343
- var createAppointmentSchema = z2.object({
344
- clinicBranchId: z2.string().min(MIN_STRING_LENGTH, "Clinic branch ID is required"),
345
- practitionerId: z2.string().min(MIN_STRING_LENGTH, "Practitioner ID is required"),
346
- patientId: z2.string().min(MIN_STRING_LENGTH, "Patient ID is required"),
347
- procedureId: z2.string().min(MIN_STRING_LENGTH, "Procedure ID is required"),
348
- appointmentStartTime: z2.any().refine(
385
+ var appointmentMetadataSchema = z3.object({
386
+ selectedZones: z3.array(z3.string()).nullable(),
387
+ zonePhotos: z3.record(z3.string(), beforeAfterPerZoneSchema).nullable(),
388
+ zoneBilling: z3.record(z3.string(), billingPerZoneSchema).nullable()
389
+ });
390
+ var createAppointmentSchema = z3.object({
391
+ clinicBranchId: z3.string().min(MIN_STRING_LENGTH, "Clinic branch ID is required"),
392
+ practitionerId: z3.string().min(MIN_STRING_LENGTH, "Practitioner ID is required"),
393
+ patientId: z3.string().min(MIN_STRING_LENGTH, "Patient ID is required"),
394
+ procedureId: z3.string().min(MIN_STRING_LENGTH, "Procedure ID is required"),
395
+ appointmentStartTime: z3.any().refine(
349
396
  (val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || (val == null ? void 0 : val.seconds) !== void 0 || typeof val === "number" || typeof val === "string" || val && typeof val.toMillis === "function",
350
397
  "Appointment start time must be a valid timestamp or Date object"
351
398
  ),
352
- appointmentEndTime: z2.any().refine(
399
+ appointmentEndTime: z3.any().refine(
353
400
  (val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || (val == null ? void 0 : val.seconds) !== void 0 || typeof val === "number" || typeof val === "string" || val && typeof val.toMillis === "function",
354
401
  "Appointment end time must be a valid timestamp or Date object"
355
402
  ),
356
- cost: z2.number().min(0, "Cost must be a non-negative number"),
357
- currency: z2.string().min(1, "Currency is required"),
358
- patientNotes: z2.string().max(MAX_STRING_LENGTH, "Patient notes too long").nullable().optional(),
403
+ cost: z3.number().min(0, "Cost must be a non-negative number"),
404
+ currency: z3.string().min(1, "Currency is required"),
405
+ patientNotes: z3.string().max(MAX_STRING_LENGTH, "Patient notes too long").nullable().optional(),
359
406
  initialStatus: appointmentStatusSchema,
360
407
  initialPaymentStatus: paymentStatusSchema.optional().default("unpaid" /* UNPAID */)
361
408
  }).refine((data) => data.appointmentEndTime > data.appointmentStartTime, {
362
409
  message: "Appointment end time must be after start time",
363
410
  path: ["appointmentEndTime"]
364
411
  });
365
- var updateAppointmentSchema = z2.object({
412
+ var updateAppointmentSchema = z3.object({
366
413
  status: appointmentStatusSchema.optional(),
367
- confirmationTime: z2.any().optional().nullable(),
368
- cancellationTime: z2.any().optional().nullable(),
369
- rescheduleTime: z2.any().optional().nullable(),
370
- procedureActualStartTime: z2.any().optional().nullable(),
371
- actualDurationMinutes: z2.number().int().positive("Duration must be a positive integer").optional(),
372
- cancellationReason: z2.string().max(MAX_STRING_LENGTH, "Cancellation reason too long").nullable().optional(),
373
- canceledBy: z2.enum(["patient", "clinic", "practitioner", "system"]).optional(),
374
- internalNotes: z2.string().max(MAX_STRING_LENGTH_LONG, "Internal notes too long").nullable().optional(),
375
- patientNotes: z2.any().optional().nullable(),
414
+ confirmationTime: z3.any().optional().nullable(),
415
+ cancellationTime: z3.any().optional().nullable(),
416
+ rescheduleTime: z3.any().optional().nullable(),
417
+ procedureActualStartTime: z3.any().optional().nullable(),
418
+ actualDurationMinutes: z3.number().int().positive("Duration must be a positive integer").optional(),
419
+ cancellationReason: z3.string().max(MAX_STRING_LENGTH, "Cancellation reason too long").nullable().optional(),
420
+ canceledBy: z3.enum(["patient", "clinic", "practitioner", "system"]).optional(),
421
+ internalNotes: z3.string().max(MAX_STRING_LENGTH_LONG, "Internal notes too long").nullable().optional(),
422
+ patientNotes: z3.any().optional().nullable(),
376
423
  paymentStatus: paymentStatusSchema.optional(),
377
- paymentTransactionId: z2.any().optional().nullable(),
378
- completedPreRequirements: z2.union([z2.array(z2.string()), z2.any()]).optional(),
379
- completedPostRequirements: z2.union([z2.array(z2.string()), z2.any()]).optional(),
380
- linkedFormIds: z2.union([z2.array(z2.string()), z2.any()]).optional(),
381
- pendingUserFormsIds: z2.union([z2.array(z2.string()), z2.any()]).optional(),
382
- appointmentStartTime: z2.any().refine(
424
+ paymentTransactionId: z3.any().optional().nullable(),
425
+ completedPreRequirements: z3.union([z3.array(z3.string()), z3.any()]).optional(),
426
+ completedPostRequirements: z3.union([z3.array(z3.string()), z3.any()]).optional(),
427
+ linkedFormIds: z3.union([z3.array(z3.string()), z3.any()]).optional(),
428
+ pendingUserFormsIds: z3.union([z3.array(z3.string()), z3.any()]).optional(),
429
+ appointmentStartTime: z3.any().refine(
383
430
  (val) => val === void 0 || val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || (val == null ? void 0 : val.seconds) !== void 0 || typeof val === "number" || typeof val === "string" || val && typeof val.toMillis === "function",
384
431
  "Appointment start time must be a valid timestamp or Date object"
385
432
  ).optional(),
386
- appointmentEndTime: z2.any().refine(
433
+ appointmentEndTime: z3.any().refine(
387
434
  (val) => val === void 0 || val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || (val == null ? void 0 : val.seconds) !== void 0 || typeof val === "number" || typeof val === "string" || val && typeof val.toMillis === "function",
388
435
  "Appointment end time must be a valid timestamp or Date object"
389
436
  ).optional(),
390
- calendarEventId: z2.string().min(MIN_STRING_LENGTH).optional(),
391
- cost: z2.number().min(0).optional(),
392
- clinicBranchId: z2.string().min(MIN_STRING_LENGTH).optional(),
393
- practitionerId: z2.string().min(MIN_STRING_LENGTH).optional(),
394
- linkedForms: z2.union([z2.array(linkedFormInfoSchema).max(MAX_ARRAY_LENGTH), z2.any()]).optional(),
395
- media: z2.union([
396
- z2.array(appointmentMediaItemSchema).max(MAX_ARRAY_LENGTH),
397
- z2.any()
437
+ calendarEventId: z3.string().min(MIN_STRING_LENGTH).optional(),
438
+ cost: z3.number().min(0).optional(),
439
+ clinicBranchId: z3.string().min(MIN_STRING_LENGTH).optional(),
440
+ practitionerId: z3.string().min(MIN_STRING_LENGTH).optional(),
441
+ linkedForms: z3.union([z3.array(linkedFormInfoSchema).max(MAX_ARRAY_LENGTH), z3.any()]).optional(),
442
+ media: z3.union([
443
+ z3.array(appointmentMediaItemSchema).max(MAX_ARRAY_LENGTH),
444
+ z3.any()
398
445
  ]).optional(),
399
- reviewInfo: z2.union([patientReviewInfoSchema.nullable(), z2.any()]).optional(),
400
- finalizedDetails: z2.union([finalizedDetailsSchema.nullable(), z2.any()]).optional(),
401
- isArchived: z2.boolean().optional(),
402
- updatedAt: z2.any().optional()
446
+ reviewInfo: z3.union([patientReviewInfoSchema.nullable(), z3.any()]).optional(),
447
+ finalizedDetails: z3.union([finalizedDetailsSchema.nullable(), z3.any()]).optional(),
448
+ isArchived: z3.boolean().optional(),
449
+ updatedAt: z3.any().optional(),
450
+ metadata: appointmentMetadataSchema.optional()
403
451
  }).refine(
404
452
  (data) => {
405
453
  if (data.status === "canceled_clinic" /* CANCELED_CLINIC */ || data.status === "canceled_patient" /* CANCELED_PATIENT */ || data.status === "canceled_patient_rescheduled" /* CANCELED_PATIENT_RESCHEDULED */) {
@@ -423,24 +471,24 @@ var updateAppointmentSchema = z2.object({
423
471
  path: ["appointmentEndTime"]
424
472
  }
425
473
  );
426
- var searchAppointmentsSchema = z2.object({
427
- patientId: z2.string().optional(),
428
- practitionerId: z2.string().optional(),
429
- clinicBranchId: z2.string().optional(),
430
- startDate: z2.any().refine(
474
+ var searchAppointmentsSchema = z3.object({
475
+ patientId: z3.string().optional(),
476
+ practitionerId: z3.string().optional(),
477
+ clinicBranchId: z3.string().optional(),
478
+ startDate: z3.any().refine(
431
479
  (val) => val === void 0 || val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || (val == null ? void 0 : val.seconds) !== void 0 || typeof val === "number" || typeof val === "string" || val && typeof val.toMillis === "function",
432
480
  "Start date must be a valid timestamp or Date object"
433
481
  ).optional(),
434
- endDate: z2.any().refine(
482
+ endDate: z3.any().refine(
435
483
  (val) => val === void 0 || val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || (val == null ? void 0 : val.seconds) !== void 0 || typeof val === "number" || typeof val === "string" || val && typeof val.toMillis === "function",
436
484
  "End date must be a valid timestamp or Date object"
437
485
  ).optional(),
438
- status: z2.union([
486
+ status: z3.union([
439
487
  appointmentStatusSchema,
440
- z2.array(appointmentStatusSchema).nonempty()
488
+ z3.array(appointmentStatusSchema).nonempty()
441
489
  ]).optional(),
442
- limit: z2.number().positive().int().optional().default(20),
443
- startAfter: z2.any().optional()
490
+ limit: z3.number().positive().int().optional().default(20),
491
+ startAfter: z3.any().optional()
444
492
  }).refine(
445
493
  (data) => {
446
494
  if (!data.startDate && !data.endDate && !data.status) {
@@ -464,13 +512,13 @@ var searchAppointmentsSchema = z2.object({
464
512
  path: ["endDate"]
465
513
  }
466
514
  );
467
- var rescheduleAppointmentSchema = z2.object({
468
- appointmentId: z2.string().min(MIN_STRING_LENGTH, "Appointment ID is required"),
469
- newStartTime: z2.any().refine(
515
+ var rescheduleAppointmentSchema = z3.object({
516
+ appointmentId: z3.string().min(MIN_STRING_LENGTH, "Appointment ID is required"),
517
+ newStartTime: z3.any().refine(
470
518
  (val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || (val == null ? void 0 : val.seconds) !== void 0 || typeof val === "number" || typeof val === "string" || val && typeof val.toMillis === "function",
471
519
  "New start time must be a valid timestamp, Date object, number, or string"
472
520
  ),
473
- newEndTime: z2.any().refine(
521
+ newEndTime: z3.any().refine(
474
522
  (val) => val instanceof Date || (val == null ? void 0 : val._seconds) !== void 0 || (val == null ? void 0 : val.seconds) !== void 0 || typeof val === "number" || typeof val === "string" || val && typeof val.toMillis === "function",
475
523
  "New end time must be a valid timestamp, Date object, number, or string"
476
524
  )
@@ -590,24 +638,24 @@ var USERS_COLLECTION = "users";
590
638
  import { z as z20 } from "zod";
591
639
 
592
640
  // src/validations/schemas.ts
593
- import { z as z3 } from "zod";
594
- 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");
595
- var passwordSchema = z3.string().min(8, "Password must be at least 8 characters").max(100, "Password must be less than 100 characters").regex(
641
+ import { z as z4 } from "zod";
642
+ var emailSchema = z4.string().email("Invalid email format").min(5, "Email must be at least 5 characters").max(255, "Email must be less than 255 characters");
643
+ var passwordSchema = z4.string().min(8, "Password must be at least 8 characters").max(100, "Password must be less than 100 characters").regex(
596
644
  /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d\w\W]{8,}$/,
597
645
  "Password must contain at least one uppercase letter, one lowercase letter, and one number"
598
646
  );
599
- var userRoleSchema = z3.nativeEnum(UserRole);
600
- var userRolesSchema = z3.array(userRoleSchema).min(1, "User must have at least one role").max(3, "User cannot have more than 3 roles");
601
- var timestampSchema = z3.custom((data) => {
647
+ var userRoleSchema = z4.nativeEnum(UserRole);
648
+ var userRolesSchema = z4.array(userRoleSchema).min(1, "User must have at least one role").max(3, "User cannot have more than 3 roles");
649
+ var timestampSchema = z4.custom((data) => {
602
650
  if (data && typeof data === "object" && "isEqual" in data) {
603
651
  return true;
604
652
  }
605
653
  return data && typeof data === "object" && "toDate" in data && "seconds" in data && "nanoseconds" in data;
606
654
  }, "Must be a Timestamp object or serverTimestamp");
607
- var clinicAdminOptionsSchema = z3.object({
608
- isGroupOwner: z3.boolean(),
609
- groupToken: z3.string().optional(),
610
- groupId: z3.string().optional()
655
+ var clinicAdminOptionsSchema = z4.object({
656
+ isGroupOwner: z4.boolean(),
657
+ groupToken: z4.string().optional(),
658
+ groupId: z4.string().optional()
611
659
  }).refine(
612
660
  (data) => {
613
661
  if (!data.isGroupOwner && (!data.groupToken || !data.groupId)) {
@@ -622,20 +670,20 @@ var clinicAdminOptionsSchema = z3.object({
622
670
  message: "Invalid clinic admin options configuration"
623
671
  }
624
672
  );
625
- var createUserOptionsSchema = z3.object({
673
+ var createUserOptionsSchema = z4.object({
626
674
  clinicAdminData: clinicAdminOptionsSchema.optional()
627
675
  });
628
- var userSchema = z3.object({
629
- uid: z3.string(),
630
- email: z3.string().email().nullable(),
631
- roles: z3.array(userRoleSchema),
632
- isAnonymous: z3.boolean(),
676
+ var userSchema = z4.object({
677
+ uid: z4.string(),
678
+ email: z4.string().email().nullable(),
679
+ roles: z4.array(userRoleSchema),
680
+ isAnonymous: z4.boolean(),
633
681
  createdAt: timestampSchema,
634
682
  updatedAt: timestampSchema,
635
683
  lastLoginAt: timestampSchema,
636
- patientProfile: z3.string().optional(),
637
- practitionerProfile: z3.string().optional(),
638
- adminProfile: z3.string().optional()
684
+ patientProfile: z4.string().optional(),
685
+ practitionerProfile: z4.string().optional(),
686
+ adminProfile: z4.string().optional()
639
687
  });
640
688
 
641
689
  // src/errors/auth.errors.ts
@@ -1371,14 +1419,6 @@ var Gender = /* @__PURE__ */ ((Gender2) => {
1371
1419
  import { z as z7 } from "zod";
1372
1420
  import { Timestamp as Timestamp3 } from "firebase/firestore";
1373
1421
 
1374
- // src/validations/media.schema.ts
1375
- import { z as z4 } from "zod";
1376
- var mediaResourceSchema = z4.union([
1377
- z4.string().url(),
1378
- z4.instanceof(File),
1379
- z4.instanceof(Blob)
1380
- ]);
1381
-
1382
1422
  // src/validations/patient/medical-info.schema.ts
1383
1423
  import { z as z6 } from "zod";
1384
1424
 
@@ -3633,25 +3673,6 @@ var ProcedureFamily = /* @__PURE__ */ ((ProcedureFamily2) => {
3633
3673
  return ProcedureFamily2;
3634
3674
  })(ProcedureFamily || {});
3635
3675
 
3636
- // src/backoffice/types/static/pricing.types.ts
3637
- var PricingMeasure = /* @__PURE__ */ ((PricingMeasure3) => {
3638
- PricingMeasure3["PER_ML"] = "per_ml";
3639
- PricingMeasure3["PER_ZONE"] = "per_zone";
3640
- PricingMeasure3["PER_AREA"] = "per_area";
3641
- PricingMeasure3["PER_SESSION"] = "per_session";
3642
- PricingMeasure3["PER_TREATMENT"] = "per_treatment";
3643
- PricingMeasure3["PER_PACKAGE"] = "per_package";
3644
- return PricingMeasure3;
3645
- })(PricingMeasure || {});
3646
- var Currency = /* @__PURE__ */ ((Currency2) => {
3647
- Currency2["EUR"] = "EUR";
3648
- Currency2["USD"] = "USD";
3649
- Currency2["GBP"] = "GBP";
3650
- Currency2["CHF"] = "CHF";
3651
- Currency2["AUD"] = "AUD";
3652
- return Currency2;
3653
- })(Currency || {});
3654
-
3655
3676
  // src/validations/shared.schema.ts
3656
3677
  var sharedClinicContactInfoSchema = z12.object({
3657
3678
  email: z12.string().email(),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@blackcode_sa/metaestetics-api",
3
3
  "private": false,
4
- "version": "1.7.37",
4
+ "version": "1.7.39",
5
5
  "description": "Firebase authentication service with anonymous upgrade support",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.mjs",
package/src/index.ts CHANGED
@@ -134,6 +134,9 @@ export type {
134
134
  CreateAppointmentHttpData,
135
135
  UpdateAppointmentData,
136
136
  SearchAppointmentsParams,
137
+ AppointmentMetadata,
138
+ BeforeAfterPerZone,
139
+ BillingPerZone,
137
140
  } from "./types/appointment";
138
141
  export {
139
142
  AppointmentStatus,
@@ -5,12 +5,16 @@ import {
5
5
  PatientProfileInfo,
6
6
  } from "../profile";
7
7
  import { ProcedureSummaryInfo } from "../procedure";
8
- import { Currency } from "../../backoffice/types/static/pricing.types";
8
+ import {
9
+ Currency,
10
+ type PricingMeasure,
11
+ } from "../../backoffice/types/static/pricing.types";
9
12
  import { BlockingCondition } from "../../backoffice/types/static/blocking-condition.types";
10
13
  import { Contraindication } from "../../backoffice/types/static/contraindication.types";
11
14
  import { Requirement } from "../../backoffice/types/requirement.types";
12
15
  import { FilledDocumentStatus } from "../documentation-templates";
13
16
  import type { ProcedureFamily } from "../../backoffice";
17
+ import type { MediaResource } from "../../services/media/media.service";
14
18
 
15
19
  /**
16
20
  * Enum defining the possible statuses of an appointment.
@@ -111,6 +115,52 @@ export interface PatientReviewInfo {
111
115
  reviewedAt: Timestamp;
112
116
  }
113
117
 
118
+ /**
119
+ * Interface for before/after photos and notes per zone
120
+ */
121
+ export interface BeforeAfterPerZone {
122
+ /** URL for before photo or null if not available */
123
+ before: MediaResource | null;
124
+ /** URL for after photo or null if not available */
125
+ after: MediaResource | null;
126
+ /** Optional note for the zone */
127
+ note: string | null;
128
+ }
129
+
130
+ /**
131
+ * Interface for billing information per zone
132
+ */
133
+ export interface BillingPerZone {
134
+ /** Product name/description */
135
+ Product: string;
136
+ /** Product ID */
137
+ ProductId: string | null;
138
+ /** Quantity used (can be decimal) */
139
+ Quantity: number;
140
+ /** Unit of measurement */
141
+ UnitOfMeasurement: PricingMeasure;
142
+ /** Unit price for the product */
143
+ UnitPrice: number;
144
+ /** Currency for the unit price */
145
+ UnitCurency: Currency;
146
+ /** Calculated subtotal */
147
+ Subtotal: number;
148
+ /** Optional billing note */
149
+ Note: string | null;
150
+ }
151
+
152
+ /**
153
+ * Interface for appointment metadata containing zone-specific information
154
+ */
155
+ export interface AppointmentMetadata {
156
+ /** Array of selected zones for the appointment */
157
+ selectedZones: string[] | null;
158
+ /** Map of zone photos with before/after images and notes */
159
+ zonePhotos: Record<string, BeforeAfterPerZone> | null;
160
+ /** Map of billing information per zone */
161
+ zoneBilling: Record<string, BillingPerZone> | null;
162
+ }
163
+
114
164
  /**
115
165
  * Represents a booked appointment, aggregating key information and relevant procedure rules.
116
166
  */
@@ -207,6 +257,9 @@ export interface Appointment {
207
257
 
208
258
  /** NEW: Flag for soft deletion or archiving */
209
259
  isArchived?: boolean;
260
+
261
+ /** NEW: Metadata for the appointment - used for area selection and photos */
262
+ metadata?: AppointmentMetadata;
210
263
  }
211
264
 
212
265
  /**
@@ -279,6 +332,9 @@ export interface UpdateAppointmentData {
279
332
  isArchived?: boolean;
280
333
 
281
334
  updatedAt?: FieldValue; // To set server timestamp
335
+
336
+ /** NEW: For updating metadata */
337
+ metadata?: AppointmentMetadata;
282
338
  }
283
339
 
284
340
  /**
@@ -5,6 +5,11 @@ import {
5
5
  MediaType,
6
6
  } from "../types/appointment";
7
7
  import { filledDocumentStatusSchema } from "./documentation-templates.schema";
8
+ import {
9
+ Currency,
10
+ PricingMeasure,
11
+ } from "../backoffice/types/static/pricing.types";
12
+ import { mediaResourceSchema } from "./media.schema";
8
13
 
9
14
  // Define common constants locally if not available from common.schema.ts
10
15
  const MIN_STRING_LENGTH = 1;
@@ -147,6 +152,38 @@ export const finalizedDetailsSchema = z.object({
147
152
  .optional(),
148
153
  });
149
154
 
155
+ /**
156
+ * Schema for before/after photos and notes per zone
157
+ */
158
+ export const beforeAfterPerZoneSchema = z.object({
159
+ before: mediaResourceSchema.nullable(),
160
+ after: mediaResourceSchema.nullable(),
161
+ note: z.string().nullable(),
162
+ });
163
+
164
+ /**
165
+ * Schema for billing information per zone
166
+ */
167
+ export const billingPerZoneSchema = z.object({
168
+ Product: z.string().min(MIN_STRING_LENGTH, "Product name is required"),
169
+ ProductId: z.string().nullable(),
170
+ Quantity: z.number().min(0, "Quantity must be non-negative"),
171
+ UnitOfMeasurement: z.nativeEnum(PricingMeasure),
172
+ UnitPrice: z.number().min(0, "Unit price must be non-negative"),
173
+ UnitCurency: z.nativeEnum(Currency),
174
+ Subtotal: z.number().min(0, "Subtotal must be non-negative"),
175
+ Note: z.string().nullable(),
176
+ });
177
+
178
+ /**
179
+ * Schema for appointment metadata containing zone-specific information
180
+ */
181
+ export const appointmentMetadataSchema = z.object({
182
+ selectedZones: z.array(z.string()).nullable(),
183
+ zonePhotos: z.record(z.string(), beforeAfterPerZoneSchema).nullable(),
184
+ zoneBilling: z.record(z.string(), billingPerZoneSchema).nullable(),
185
+ });
186
+
150
187
  // --- Main Appointment Schemas ---
151
188
 
152
189
  /**
@@ -291,6 +328,7 @@ export const updateAppointmentSchema = z
291
328
  .optional(),
292
329
  isArchived: z.boolean().optional(),
293
330
  updatedAt: z.any().optional(),
331
+ metadata: appointmentMetadataSchema.optional(),
294
332
  })
295
333
  .refine(
296
334
  (data) => {