@blackcode_sa/metaestetics-api 1.7.12 → 1.7.14

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.d.ts CHANGED
@@ -507,6 +507,102 @@ declare enum Currency {
507
507
  AUD = "AUD"
508
508
  }
509
509
 
510
+ declare class BaseService {
511
+ protected db: Firestore;
512
+ protected auth: Auth;
513
+ protected app: FirebaseApp;
514
+ protected storage: FirebaseStorage;
515
+ constructor(db: Firestore, auth: Auth, app: FirebaseApp);
516
+ /**
517
+ * Generiše jedinstveni ID za dokumente
518
+ * Format: xxxxxxxxxxxx-timestamp
519
+ * Gde je x random karakter (broj ili slovo)
520
+ */
521
+ protected generateId(): string;
522
+ }
523
+
524
+ /**
525
+ * Enum for media access levels
526
+ */
527
+ declare enum MediaAccessLevel {
528
+ PUBLIC = "public",
529
+ PRIVATE = "private",
530
+ CONFIDENTIAL = "confidential"
531
+ }
532
+ /**
533
+ * Type that allows a field to be either a URL string or a File object
534
+ */
535
+ type MediaResource = string | File | Blob;
536
+ /**
537
+ * Media file metadata interface
538
+ */
539
+ interface MediaMetadata {
540
+ id: string;
541
+ name: string;
542
+ url: string;
543
+ contentType: string;
544
+ size: number;
545
+ createdAt: Timestamp;
546
+ accessLevel: MediaAccessLevel;
547
+ ownerId: string;
548
+ collectionName: string;
549
+ path: string;
550
+ updatedAt?: Timestamp;
551
+ }
552
+ declare const MEDIA_METADATA_COLLECTION = "media_metadata";
553
+ declare class MediaService extends BaseService {
554
+ constructor(db: Firestore, auth: Auth, app: FirebaseApp);
555
+ /**
556
+ * Upload a media file, store its metadata, and return the metadata including the URL.
557
+ * @param file - The file to upload.
558
+ * @param ownerId - ID of the owner (user, patient, clinic, etc.).
559
+ * @param accessLevel - Access level (public, private, confidential).
560
+ * @param collectionName - The logical collection name this media belongs to (e.g., 'patient_profile_pictures', 'clinic_logos').
561
+ * @param originalFileName - Optional: the original name of the file, if not using file.name.
562
+ * @returns Promise with the media metadata.
563
+ */
564
+ uploadMedia(file: File | Blob, ownerId: string, accessLevel: MediaAccessLevel, collectionName: string, originalFileName?: string): Promise<MediaMetadata>;
565
+ /**
566
+ * Get media metadata from Firestore by its ID.
567
+ * @param mediaId - ID of the media.
568
+ * @returns Promise with the media metadata or null if not found.
569
+ */
570
+ getMediaMetadata(mediaId: string): Promise<MediaMetadata | null>;
571
+ /**
572
+ * Get media metadata from Firestore by its public URL.
573
+ * @param url - The public URL of the media file.
574
+ * @returns Promise with the media metadata or null if not found.
575
+ */
576
+ getMediaMetadataByUrl(url: string): Promise<MediaMetadata | null>;
577
+ /**
578
+ * Delete media from storage and remove metadata from Firestore.
579
+ * @param mediaId - ID of the media to delete.
580
+ */
581
+ deleteMedia(mediaId: string): Promise<void>;
582
+ /**
583
+ * Update media access level. This involves moving the file in Firebase Storage
584
+ * to a new path reflecting the new access level, and updating its metadata.
585
+ * @param mediaId - ID of the media to update.
586
+ * @param newAccessLevel - New access level.
587
+ * @returns Promise with the updated media metadata, or null if metadata not found.
588
+ */
589
+ updateMediaAccessLevel(mediaId: string, newAccessLevel: MediaAccessLevel): Promise<MediaMetadata | null>;
590
+ /**
591
+ * List all media for an owner, optionally filtered by collection and access level.
592
+ * @param ownerId - ID of the owner.
593
+ * @param collectionName - Optional: Filter by collection name.
594
+ * @param accessLevel - Optional: Filter by access level.
595
+ * @param count - Optional: Number of items to fetch.
596
+ * @param startAfterId - Optional: ID of the document to start after (for pagination).
597
+ */
598
+ listMedia(ownerId: string, collectionName?: string, accessLevel?: MediaAccessLevel, count?: number, startAfterId?: string): Promise<MediaMetadata[]>;
599
+ /**
600
+ * Get download URL for media. (Convenience, as URL is in metadata)
601
+ * @param mediaId - ID of the media.
602
+ */
603
+ getMediaDownloadUrl(mediaId: string): Promise<string | null>;
604
+ }
605
+
510
606
  /**
511
607
  * Procedure represents a specific medical procedure that can be performed by a practitioner in a clinic
512
608
  * It inherits properties from technology and adds clinic/practitioner specific details
@@ -517,7 +613,7 @@ interface Procedure {
517
613
  /** Name of the procedure */
518
614
  name: string;
519
615
  /** Photos of the procedure */
520
- photos?: string[];
616
+ photos?: MediaResource[];
521
617
  /** Detailed description of the procedure */
522
618
  description: string;
523
619
  /** Family of procedures this belongs to (aesthetics/surgery) */
@@ -586,7 +682,7 @@ interface CreateProcedureData {
586
682
  duration: number;
587
683
  practitionerId: string;
588
684
  clinicBranchId: string;
589
- photos?: string[];
685
+ photos?: MediaResource[];
590
686
  }
591
687
  /**
592
688
  * Data that can be updated for an existing procedure
@@ -605,7 +701,7 @@ interface UpdateProcedureData {
605
701
  technologyId?: string;
606
702
  productId?: string;
607
703
  clinicBranchId?: string;
608
- photos?: string[];
704
+ photos?: MediaResource[];
609
705
  }
610
706
  /**
611
707
  * Collection name for procedures in Firestore
@@ -749,102 +845,6 @@ declare enum ClinicPhotoTag {
749
845
  OTHER = "other"
750
846
  }
751
847
 
752
- declare class BaseService {
753
- protected db: Firestore;
754
- protected auth: Auth;
755
- protected app: FirebaseApp;
756
- protected storage: FirebaseStorage;
757
- constructor(db: Firestore, auth: Auth, app: FirebaseApp);
758
- /**
759
- * Generiše jedinstveni ID za dokumente
760
- * Format: xxxxxxxxxxxx-timestamp
761
- * Gde je x random karakter (broj ili slovo)
762
- */
763
- protected generateId(): string;
764
- }
765
-
766
- /**
767
- * Enum for media access levels
768
- */
769
- declare enum MediaAccessLevel {
770
- PUBLIC = "public",
771
- PRIVATE = "private",
772
- CONFIDENTIAL = "confidential"
773
- }
774
- /**
775
- * Type that allows a field to be either a URL string or a File object
776
- */
777
- type MediaResource = string | File | Blob;
778
- /**
779
- * Media file metadata interface
780
- */
781
- interface MediaMetadata {
782
- id: string;
783
- name: string;
784
- url: string;
785
- contentType: string;
786
- size: number;
787
- createdAt: Timestamp;
788
- accessLevel: MediaAccessLevel;
789
- ownerId: string;
790
- collectionName: string;
791
- path: string;
792
- updatedAt?: Timestamp;
793
- }
794
- declare const MEDIA_METADATA_COLLECTION = "media_metadata";
795
- declare class MediaService extends BaseService {
796
- constructor(db: Firestore, auth: Auth, app: FirebaseApp);
797
- /**
798
- * Upload a media file, store its metadata, and return the metadata including the URL.
799
- * @param file - The file to upload.
800
- * @param ownerId - ID of the owner (user, patient, clinic, etc.).
801
- * @param accessLevel - Access level (public, private, confidential).
802
- * @param collectionName - The logical collection name this media belongs to (e.g., 'patient_profile_pictures', 'clinic_logos').
803
- * @param originalFileName - Optional: the original name of the file, if not using file.name.
804
- * @returns Promise with the media metadata.
805
- */
806
- uploadMedia(file: File | Blob, ownerId: string, accessLevel: MediaAccessLevel, collectionName: string, originalFileName?: string): Promise<MediaMetadata>;
807
- /**
808
- * Get media metadata from Firestore by its ID.
809
- * @param mediaId - ID of the media.
810
- * @returns Promise with the media metadata or null if not found.
811
- */
812
- getMediaMetadata(mediaId: string): Promise<MediaMetadata | null>;
813
- /**
814
- * Get media metadata from Firestore by its public URL.
815
- * @param url - The public URL of the media file.
816
- * @returns Promise with the media metadata or null if not found.
817
- */
818
- getMediaMetadataByUrl(url: string): Promise<MediaMetadata | null>;
819
- /**
820
- * Delete media from storage and remove metadata from Firestore.
821
- * @param mediaId - ID of the media to delete.
822
- */
823
- deleteMedia(mediaId: string): Promise<void>;
824
- /**
825
- * Update media access level. This involves moving the file in Firebase Storage
826
- * to a new path reflecting the new access level, and updating its metadata.
827
- * @param mediaId - ID of the media to update.
828
- * @param newAccessLevel - New access level.
829
- * @returns Promise with the updated media metadata, or null if metadata not found.
830
- */
831
- updateMediaAccessLevel(mediaId: string, newAccessLevel: MediaAccessLevel): Promise<MediaMetadata | null>;
832
- /**
833
- * List all media for an owner, optionally filtered by collection and access level.
834
- * @param ownerId - ID of the owner.
835
- * @param collectionName - Optional: Filter by collection name.
836
- * @param accessLevel - Optional: Filter by access level.
837
- * @param count - Optional: Number of items to fetch.
838
- * @param startAfterId - Optional: ID of the document to start after (for pagination).
839
- */
840
- listMedia(ownerId: string, collectionName?: string, accessLevel?: MediaAccessLevel, count?: number, startAfterId?: string): Promise<MediaMetadata[]>;
841
- /**
842
- * Get download URL for media. (Convenience, as URL is in metadata)
843
- * @param mediaId - ID of the media.
844
- */
845
- getMediaDownloadUrl(mediaId: string): Promise<string | null>;
846
- }
847
-
848
848
  declare const CLINIC_GROUPS_COLLECTION = "clinic_groups";
849
849
  declare const CLINIC_ADMINS_COLLECTION = "clinic_admins";
850
850
  declare const CLINICS_COLLECTION = "clinics";
@@ -4836,8 +4836,8 @@ declare const updateAppointmentSchema: z.ZodEffects<z.ZodEffects<z.ZodObject<{
4836
4836
  submittedAt: z.ZodOptional<z.ZodEffects<z.ZodAny, any, any>>;
4837
4837
  completedAt: z.ZodOptional<z.ZodEffects<z.ZodAny, any, any>>;
4838
4838
  }, "strip", z.ZodTypeAny, {
4839
- status: FilledDocumentStatus;
4840
4839
  path: string;
4840
+ status: FilledDocumentStatus;
4841
4841
  title: string;
4842
4842
  isUserForm: boolean;
4843
4843
  templateId: string;
@@ -4847,8 +4847,8 @@ declare const updateAppointmentSchema: z.ZodEffects<z.ZodEffects<z.ZodObject<{
4847
4847
  submittedAt?: any;
4848
4848
  completedAt?: any;
4849
4849
  }, {
4850
- status: FilledDocumentStatus;
4851
4850
  path: string;
4851
+ status: FilledDocumentStatus;
4852
4852
  title: string;
4853
4853
  isUserForm: boolean;
4854
4854
  templateId: string;
@@ -5103,56 +5103,56 @@ declare const searchAppointmentsSchema: z.ZodEffects<z.ZodEffects<z.ZodObject<{
5103
5103
  startAfter: z.ZodOptional<z.ZodAny>;
5104
5104
  }, "strip", z.ZodTypeAny, {
5105
5105
  limit: number;
5106
+ startAfter?: any;
5106
5107
  status?: AppointmentStatus | [AppointmentStatus, ...AppointmentStatus[]] | undefined;
5107
5108
  patientId?: string | undefined;
5108
5109
  startDate?: any;
5109
5110
  endDate?: any;
5110
- startAfter?: any;
5111
5111
  practitionerId?: string | undefined;
5112
5112
  clinicBranchId?: string | undefined;
5113
5113
  }, {
5114
+ limit?: number | undefined;
5115
+ startAfter?: any;
5114
5116
  status?: AppointmentStatus | [AppointmentStatus, ...AppointmentStatus[]] | undefined;
5115
5117
  patientId?: string | undefined;
5116
5118
  startDate?: any;
5117
5119
  endDate?: any;
5118
- limit?: number | undefined;
5119
- startAfter?: any;
5120
5120
  practitionerId?: string | undefined;
5121
5121
  clinicBranchId?: string | undefined;
5122
5122
  }>, {
5123
5123
  limit: number;
5124
+ startAfter?: any;
5124
5125
  status?: AppointmentStatus | [AppointmentStatus, ...AppointmentStatus[]] | undefined;
5125
5126
  patientId?: string | undefined;
5126
5127
  startDate?: any;
5127
5128
  endDate?: any;
5128
- startAfter?: any;
5129
5129
  practitionerId?: string | undefined;
5130
5130
  clinicBranchId?: string | undefined;
5131
5131
  }, {
5132
+ limit?: number | undefined;
5133
+ startAfter?: any;
5132
5134
  status?: AppointmentStatus | [AppointmentStatus, ...AppointmentStatus[]] | undefined;
5133
5135
  patientId?: string | undefined;
5134
5136
  startDate?: any;
5135
5137
  endDate?: any;
5136
- limit?: number | undefined;
5137
- startAfter?: any;
5138
5138
  practitionerId?: string | undefined;
5139
5139
  clinicBranchId?: string | undefined;
5140
5140
  }>, {
5141
5141
  limit: number;
5142
+ startAfter?: any;
5142
5143
  status?: AppointmentStatus | [AppointmentStatus, ...AppointmentStatus[]] | undefined;
5143
5144
  patientId?: string | undefined;
5144
5145
  startDate?: any;
5145
5146
  endDate?: any;
5146
- startAfter?: any;
5147
5147
  practitionerId?: string | undefined;
5148
5148
  clinicBranchId?: string | undefined;
5149
5149
  }, {
5150
+ limit?: number | undefined;
5151
+ startAfter?: any;
5150
5152
  status?: AppointmentStatus | [AppointmentStatus, ...AppointmentStatus[]] | undefined;
5151
5153
  patientId?: string | undefined;
5152
5154
  startDate?: any;
5153
5155
  endDate?: any;
5154
- limit?: number | undefined;
5155
- startAfter?: any;
5156
5156
  practitionerId?: string | undefined;
5157
5157
  clinicBranchId?: string | undefined;
5158
5158
  }>;
@@ -6444,7 +6444,24 @@ declare class ProcedureService extends BaseService {
6444
6444
  private subcategoryService;
6445
6445
  private technologyService;
6446
6446
  private productService;
6447
- constructor(db: Firestore, auth: Auth, app: FirebaseApp, categoryService: CategoryService, subcategoryService: SubcategoryService, technologyService: TechnologyService, productService: ProductService);
6447
+ private mediaService;
6448
+ constructor(db: Firestore, auth: Auth, app: FirebaseApp, categoryService: CategoryService, subcategoryService: SubcategoryService, technologyService: TechnologyService, productService: ProductService, mediaService: MediaService);
6449
+ /**
6450
+ * Process media resource (string URL or File object)
6451
+ * @param media String URL or File object
6452
+ * @param ownerId Owner ID for the media (usually procedureId)
6453
+ * @param collectionName Collection name for organizing files
6454
+ * @returns URL string after processing
6455
+ */
6456
+ private processMedia;
6457
+ /**
6458
+ * Process array of media resources (strings or Files)
6459
+ * @param mediaArray Array of string URLs or File objects
6460
+ * @param ownerId Owner ID for the media
6461
+ * @param collectionName Collection name for organizing files
6462
+ * @returns Array of URL strings after processing
6463
+ */
6464
+ private processMediaArray;
6448
6465
  /**
6449
6466
  * Creates a new procedure
6450
6467
  * @param data - The data for creating a new procedure
@@ -14079,6 +14096,7 @@ declare const clinicGroupSchema: z.ZodObject<{
14079
14096
  updatedAt: Date | Timestamp;
14080
14097
  name: string;
14081
14098
  isActive: boolean;
14099
+ ownerId: string | null;
14082
14100
  clinics: string[];
14083
14101
  clinicsInfo: {
14084
14102
  id: string;
@@ -14101,7 +14119,6 @@ declare const clinicGroupSchema: z.ZodObject<{
14101
14119
  featuredPhoto: string;
14102
14120
  description?: string | null | undefined;
14103
14121
  }[];
14104
- ownerId: string | null;
14105
14122
  contactInfo: {
14106
14123
  email: string;
14107
14124
  phoneNumber: string;
@@ -14157,6 +14174,7 @@ declare const clinicGroupSchema: z.ZodObject<{
14157
14174
  updatedAt: Date | Timestamp;
14158
14175
  name: string;
14159
14176
  isActive: boolean;
14177
+ ownerId: string | null;
14160
14178
  clinics: string[];
14161
14179
  clinicsInfo: {
14162
14180
  id: string;
@@ -14179,7 +14197,6 @@ declare const clinicGroupSchema: z.ZodObject<{
14179
14197
  featuredPhoto: string;
14180
14198
  description?: string | null | undefined;
14181
14199
  }[];
14182
- ownerId: string | null;
14183
14200
  contactInfo: {
14184
14201
  email: string;
14185
14202
  phoneNumber: string;
package/dist/index.js CHANGED
@@ -8353,7 +8353,7 @@ var createProcedureSchema = import_zod21.z.object({
8353
8353
  // Max 8 hours
8354
8354
  practitionerId: import_zod21.z.string().min(1),
8355
8355
  clinicBranchId: import_zod21.z.string().min(1),
8356
- photos: import_zod21.z.array(import_zod21.z.string()).optional()
8356
+ photos: import_zod21.z.array(mediaResourceSchema).optional()
8357
8357
  });
8358
8358
  var updateProcedureSchema = import_zod21.z.object({
8359
8359
  name: import_zod21.z.string().min(3).max(100).optional(),
@@ -8369,7 +8369,7 @@ var updateProcedureSchema = import_zod21.z.object({
8369
8369
  technologyId: import_zod21.z.string().optional(),
8370
8370
  productId: import_zod21.z.string().optional(),
8371
8371
  clinicBranchId: import_zod21.z.string().optional(),
8372
- photos: import_zod21.z.array(import_zod21.z.string()).optional()
8372
+ photos: import_zod21.z.array(mediaResourceSchema).optional()
8373
8373
  });
8374
8374
  var procedureSchema = createProcedureSchema.extend({
8375
8375
  id: import_zod21.z.string().min(1),
@@ -8409,12 +8409,61 @@ var procedureSchema = createProcedureSchema.extend({
8409
8409
  // src/services/procedure/procedure.service.ts
8410
8410
  var import_geofire_common8 = require("geofire-common");
8411
8411
  var ProcedureService = class extends BaseService {
8412
- constructor(db, auth, app, categoryService, subcategoryService, technologyService, productService) {
8412
+ constructor(db, auth, app, categoryService, subcategoryService, technologyService, productService, mediaService) {
8413
8413
  super(db, auth, app);
8414
8414
  this.categoryService = categoryService;
8415
8415
  this.subcategoryService = subcategoryService;
8416
8416
  this.technologyService = technologyService;
8417
8417
  this.productService = productService;
8418
+ this.mediaService = mediaService;
8419
+ }
8420
+ /**
8421
+ * Process media resource (string URL or File object)
8422
+ * @param media String URL or File object
8423
+ * @param ownerId Owner ID for the media (usually procedureId)
8424
+ * @param collectionName Collection name for organizing files
8425
+ * @returns URL string after processing
8426
+ */
8427
+ async processMedia(media, ownerId, collectionName) {
8428
+ if (!media) return null;
8429
+ if (typeof media === "string") {
8430
+ return media;
8431
+ }
8432
+ if (media instanceof File || media instanceof Blob) {
8433
+ console.log(
8434
+ `[ProcedureService] Uploading ${collectionName} media for ${ownerId}`
8435
+ );
8436
+ const metadata = await this.mediaService.uploadMedia(
8437
+ media,
8438
+ ownerId,
8439
+ "public" /* PUBLIC */,
8440
+ collectionName
8441
+ );
8442
+ return metadata.url;
8443
+ }
8444
+ return null;
8445
+ }
8446
+ /**
8447
+ * Process array of media resources (strings or Files)
8448
+ * @param mediaArray Array of string URLs or File objects
8449
+ * @param ownerId Owner ID for the media
8450
+ * @param collectionName Collection name for organizing files
8451
+ * @returns Array of URL strings after processing
8452
+ */
8453
+ async processMediaArray(mediaArray, ownerId, collectionName) {
8454
+ if (!mediaArray || mediaArray.length === 0) return [];
8455
+ const result = [];
8456
+ for (const media of mediaArray) {
8457
+ const processedUrl = await this.processMedia(
8458
+ media,
8459
+ ownerId,
8460
+ collectionName
8461
+ );
8462
+ if (processedUrl) {
8463
+ result.push(processedUrl);
8464
+ }
8465
+ }
8466
+ return result;
8418
8467
  }
8419
8468
  /**
8420
8469
  * Creates a new procedure
@@ -8424,6 +8473,7 @@ var ProcedureService = class extends BaseService {
8424
8473
  async createProcedure(data) {
8425
8474
  var _a;
8426
8475
  const validatedData = createProcedureSchema.parse(data);
8476
+ const procedureId = this.generateId();
8427
8477
  const [category, subcategory, technology, product] = await Promise.all([
8428
8478
  this.categoryService.getById(validatedData.categoryId),
8429
8479
  this.subcategoryService.getById(
@@ -8463,6 +8513,14 @@ var ProcedureService = class extends BaseService {
8463
8513
  );
8464
8514
  }
8465
8515
  const practitioner = practitionerSnapshot.data();
8516
+ let processedPhotos = [];
8517
+ if (validatedData.photos && validatedData.photos.length > 0) {
8518
+ processedPhotos = await this.processMediaArray(
8519
+ validatedData.photos,
8520
+ procedureId,
8521
+ "procedure-photos"
8522
+ );
8523
+ }
8466
8524
  const clinicInfo = {
8467
8525
  id: clinicSnapshot.id,
8468
8526
  name: clinic.name,
@@ -8479,10 +8537,10 @@ var ProcedureService = class extends BaseService {
8479
8537
  rating: ((_a = practitioner.reviewInfo) == null ? void 0 : _a.averageRating) || 0,
8480
8538
  services: practitioner.procedures || []
8481
8539
  };
8482
- const procedureId = this.generateId();
8483
8540
  const newProcedure = {
8484
8541
  id: procedureId,
8485
8542
  ...validatedData,
8543
+ photos: processedPhotos,
8486
8544
  category,
8487
8545
  // Embed full objects
8488
8546
  subcategory,
@@ -8585,6 +8643,13 @@ var ProcedureService = class extends BaseService {
8585
8643
  const oldClinicId = existingProcedure.clinicBranchId;
8586
8644
  let newPractitioner = null;
8587
8645
  let newClinic = null;
8646
+ if (validatedData.photos !== void 0) {
8647
+ updatedProcedureData.photos = await this.processMediaArray(
8648
+ validatedData.photos,
8649
+ id,
8650
+ "procedure-photos"
8651
+ );
8652
+ }
8588
8653
  if (validatedData.practitionerId && validatedData.practitionerId !== oldPractitionerId) {
8589
8654
  practitionerChanged = true;
8590
8655
  const newPractitionerRef = (0, import_firestore27.doc)(
package/dist/index.mjs CHANGED
@@ -8342,7 +8342,7 @@ var createProcedureSchema = z21.object({
8342
8342
  // Max 8 hours
8343
8343
  practitionerId: z21.string().min(1),
8344
8344
  clinicBranchId: z21.string().min(1),
8345
- photos: z21.array(z21.string()).optional()
8345
+ photos: z21.array(mediaResourceSchema).optional()
8346
8346
  });
8347
8347
  var updateProcedureSchema = z21.object({
8348
8348
  name: z21.string().min(3).max(100).optional(),
@@ -8358,7 +8358,7 @@ var updateProcedureSchema = z21.object({
8358
8358
  technologyId: z21.string().optional(),
8359
8359
  productId: z21.string().optional(),
8360
8360
  clinicBranchId: z21.string().optional(),
8361
- photos: z21.array(z21.string()).optional()
8361
+ photos: z21.array(mediaResourceSchema).optional()
8362
8362
  });
8363
8363
  var procedureSchema = createProcedureSchema.extend({
8364
8364
  id: z21.string().min(1),
@@ -8398,12 +8398,61 @@ var procedureSchema = createProcedureSchema.extend({
8398
8398
  // src/services/procedure/procedure.service.ts
8399
8399
  import { distanceBetween as distanceBetween6, geohashQueryBounds as geohashQueryBounds5 } from "geofire-common";
8400
8400
  var ProcedureService = class extends BaseService {
8401
- constructor(db, auth, app, categoryService, subcategoryService, technologyService, productService) {
8401
+ constructor(db, auth, app, categoryService, subcategoryService, technologyService, productService, mediaService) {
8402
8402
  super(db, auth, app);
8403
8403
  this.categoryService = categoryService;
8404
8404
  this.subcategoryService = subcategoryService;
8405
8405
  this.technologyService = technologyService;
8406
8406
  this.productService = productService;
8407
+ this.mediaService = mediaService;
8408
+ }
8409
+ /**
8410
+ * Process media resource (string URL or File object)
8411
+ * @param media String URL or File object
8412
+ * @param ownerId Owner ID for the media (usually procedureId)
8413
+ * @param collectionName Collection name for organizing files
8414
+ * @returns URL string after processing
8415
+ */
8416
+ async processMedia(media, ownerId, collectionName) {
8417
+ if (!media) return null;
8418
+ if (typeof media === "string") {
8419
+ return media;
8420
+ }
8421
+ if (media instanceof File || media instanceof Blob) {
8422
+ console.log(
8423
+ `[ProcedureService] Uploading ${collectionName} media for ${ownerId}`
8424
+ );
8425
+ const metadata = await this.mediaService.uploadMedia(
8426
+ media,
8427
+ ownerId,
8428
+ "public" /* PUBLIC */,
8429
+ collectionName
8430
+ );
8431
+ return metadata.url;
8432
+ }
8433
+ return null;
8434
+ }
8435
+ /**
8436
+ * Process array of media resources (strings or Files)
8437
+ * @param mediaArray Array of string URLs or File objects
8438
+ * @param ownerId Owner ID for the media
8439
+ * @param collectionName Collection name for organizing files
8440
+ * @returns Array of URL strings after processing
8441
+ */
8442
+ async processMediaArray(mediaArray, ownerId, collectionName) {
8443
+ if (!mediaArray || mediaArray.length === 0) return [];
8444
+ const result = [];
8445
+ for (const media of mediaArray) {
8446
+ const processedUrl = await this.processMedia(
8447
+ media,
8448
+ ownerId,
8449
+ collectionName
8450
+ );
8451
+ if (processedUrl) {
8452
+ result.push(processedUrl);
8453
+ }
8454
+ }
8455
+ return result;
8407
8456
  }
8408
8457
  /**
8409
8458
  * Creates a new procedure
@@ -8413,6 +8462,7 @@ var ProcedureService = class extends BaseService {
8413
8462
  async createProcedure(data) {
8414
8463
  var _a;
8415
8464
  const validatedData = createProcedureSchema.parse(data);
8465
+ const procedureId = this.generateId();
8416
8466
  const [category, subcategory, technology, product] = await Promise.all([
8417
8467
  this.categoryService.getById(validatedData.categoryId),
8418
8468
  this.subcategoryService.getById(
@@ -8452,6 +8502,14 @@ var ProcedureService = class extends BaseService {
8452
8502
  );
8453
8503
  }
8454
8504
  const practitioner = practitionerSnapshot.data();
8505
+ let processedPhotos = [];
8506
+ if (validatedData.photos && validatedData.photos.length > 0) {
8507
+ processedPhotos = await this.processMediaArray(
8508
+ validatedData.photos,
8509
+ procedureId,
8510
+ "procedure-photos"
8511
+ );
8512
+ }
8455
8513
  const clinicInfo = {
8456
8514
  id: clinicSnapshot.id,
8457
8515
  name: clinic.name,
@@ -8468,10 +8526,10 @@ var ProcedureService = class extends BaseService {
8468
8526
  rating: ((_a = practitioner.reviewInfo) == null ? void 0 : _a.averageRating) || 0,
8469
8527
  services: practitioner.procedures || []
8470
8528
  };
8471
- const procedureId = this.generateId();
8472
8529
  const newProcedure = {
8473
8530
  id: procedureId,
8474
8531
  ...validatedData,
8532
+ photos: processedPhotos,
8475
8533
  category,
8476
8534
  // Embed full objects
8477
8535
  subcategory,
@@ -8574,6 +8632,13 @@ var ProcedureService = class extends BaseService {
8574
8632
  const oldClinicId = existingProcedure.clinicBranchId;
8575
8633
  let newPractitioner = null;
8576
8634
  let newClinic = null;
8635
+ if (validatedData.photos !== void 0) {
8636
+ updatedProcedureData.photos = await this.processMediaArray(
8637
+ validatedData.photos,
8638
+ id,
8639
+ "procedure-photos"
8640
+ );
8641
+ }
8577
8642
  if (validatedData.practitionerId && validatedData.practitionerId !== oldPractitionerId) {
8578
8643
  practitionerChanged = true;
8579
8644
  const newPractitionerRef = doc16(
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.12",
4
+ "version": "1.7.14",
5
5
  "description": "Firebase authentication service with anonymous upgrade support",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.mjs",