@blackcode_sa/metaestetics-api 1.7.19 → 1.7.21

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@blackcode_sa/metaestetics-api",
3
3
  "private": false,
4
- "version": "1.7.19",
4
+ "version": "1.7.21",
5
5
  "description": "Firebase authentication service with anonymous upgrade support",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.mjs",
@@ -613,7 +613,10 @@ export class BookingAdmin {
613
613
  };
614
614
  const practitionerInfo: PractitionerProfileInfo = {
615
615
  id: practitionerSnap.id,
616
- practitionerPhoto: practitionerData.basicInfo.profileImageUrl || null,
616
+ practitionerPhoto:
617
+ typeof practitionerData.basicInfo.profileImageUrl === "string"
618
+ ? practitionerData.basicInfo.profileImageUrl
619
+ : null,
617
620
  name: `${practitionerData.basicInfo.firstName} ${practitionerData.basicInfo.lastName}`,
618
621
  email: practitionerData.basicInfo.email,
619
622
  phone: practitionerData.basicInfo.phoneNumber || null,
@@ -7,6 +7,11 @@ import {
7
7
  serverTimestamp,
8
8
  } from "firebase/firestore";
9
9
  import { BaseService } from "../base.service";
10
+ import {
11
+ MediaService,
12
+ MediaAccessLevel,
13
+ MediaResource,
14
+ } from "../media/media.service";
10
15
  import {
11
16
  PatientProfile,
12
17
  PatientSensitiveInfo,
@@ -46,9 +51,6 @@ import {
46
51
  addExpoTokenUtil,
47
52
  removeExpoTokenUtil,
48
53
  addPointsUtil,
49
- uploadProfilePhotoUtil,
50
- updateProfilePhotoUtil,
51
- deleteProfilePhotoUtil,
52
54
  updatePatientProfileUtil,
53
55
  updatePatientProfileByUserRefUtil,
54
56
  searchPatientsUtil,
@@ -107,8 +109,11 @@ import {
107
109
  import { getPatientsByClinicUtil } from "./utils/clinic.utils";
108
110
 
109
111
  export class PatientService extends BaseService {
112
+ private mediaService: MediaService;
113
+
110
114
  constructor(db: Firestore, auth: Auth, app: FirebaseApp) {
111
115
  super(db, auth, app);
116
+ this.mediaService = new MediaService(db, auth, app);
112
117
  }
113
118
 
114
119
  // Metode za rad sa profilom pacijenta
@@ -183,7 +188,12 @@ export class PatientService extends BaseService {
183
188
  data: CreatePatientSensitiveInfoData,
184
189
  requesterUserId: string
185
190
  ): Promise<PatientSensitiveInfo> {
186
- return createSensitiveInfoUtil(this.db, data, requesterUserId);
191
+ return createSensitiveInfoUtil(
192
+ this.db,
193
+ data,
194
+ requesterUserId,
195
+ this.mediaService
196
+ );
187
197
  }
188
198
 
189
199
  async getSensitiveInfo(
@@ -207,7 +217,13 @@ export class PatientService extends BaseService {
207
217
  data: UpdatePatientSensitiveInfoData,
208
218
  requesterUserId: string
209
219
  ): Promise<PatientSensitiveInfo> {
210
- return updateSensitiveInfoUtil(this.db, patientId, data, requesterUserId);
220
+ return updateSensitiveInfoUtil(
221
+ this.db,
222
+ patientId,
223
+ data,
224
+ requesterUserId,
225
+ this.mediaService
226
+ );
211
227
  }
212
228
 
213
229
  // Metode za rad sa medicinskim informacijama
@@ -453,16 +469,152 @@ export class PatientService extends BaseService {
453
469
  }
454
470
 
455
471
  // Metode za rad sa profilnom slikom
456
- async uploadProfilePhoto(patientId: string, file: File): Promise<string> {
457
- return uploadProfilePhotoUtil(this.storage, patientId, file);
472
+ /**
473
+ * Uploads a profile photo for a patient
474
+ * @param patientId - ID of the patient
475
+ * @param file - File or Blob to upload
476
+ * @returns URL of the uploaded photo
477
+ */
478
+ async uploadProfilePhoto(
479
+ patientId: string,
480
+ file: File | Blob
481
+ ): Promise<string> {
482
+ console.log(
483
+ `[PatientService] Uploading profile photo for patient ${patientId}`
484
+ );
485
+
486
+ const mediaMetadata = await this.mediaService.uploadMedia(
487
+ file,
488
+ patientId, // Using patientId as ownerId
489
+ MediaAccessLevel.PRIVATE, // Profile photos should be private
490
+ "patient_profile_photos",
491
+ file instanceof File ? file.name : `profile_photo_${patientId}`
492
+ );
493
+
494
+ // Update the patient sensitive info with the new photo URL
495
+ await updateDoc(getSensitiveInfoDocRef(this.db, patientId), {
496
+ photoUrl: mediaMetadata.url,
497
+ updatedAt: serverTimestamp(),
498
+ });
499
+
500
+ return mediaMetadata.url;
458
501
  }
459
502
 
460
- async updateProfilePhoto(patientId: string, file: File): Promise<string> {
461
- return updateProfilePhotoUtil(this.storage, this.db, patientId, file);
503
+ /**
504
+ * Updates a patient's profile photo (replaces existing one)
505
+ * @param patientId - ID of the patient
506
+ * @param file - New file or Blob to upload
507
+ * @returns URL of the new uploaded photo
508
+ */
509
+ async updateProfilePhoto(
510
+ patientId: string,
511
+ file: File | Blob
512
+ ): Promise<string> {
513
+ console.log(
514
+ `[PatientService] Updating profile photo for patient ${patientId}`
515
+ );
516
+
517
+ // Get current patient sensitive info to check for existing photo
518
+ const currentUser = await this.getCurrentUser();
519
+ const currentSensitiveInfo = await this.getSensitiveInfo(
520
+ patientId,
521
+ currentUser.uid
522
+ );
523
+
524
+ // Delete old photo if it exists and is managed by our MediaService
525
+ if (
526
+ currentSensitiveInfo?.photoUrl &&
527
+ typeof currentSensitiveInfo.photoUrl === "string"
528
+ ) {
529
+ try {
530
+ const existingMediaMetadata =
531
+ await this.mediaService.getMediaMetadataByUrl(
532
+ currentSensitiveInfo.photoUrl
533
+ );
534
+ if (existingMediaMetadata) {
535
+ await this.mediaService.deleteMedia(existingMediaMetadata.id);
536
+ }
537
+ } catch (error) {
538
+ console.warn(
539
+ `[PatientService] Could not delete old profile photo for patient ${patientId}:`,
540
+ error
541
+ );
542
+ // Continue with upload even if deletion fails
543
+ }
544
+ }
545
+
546
+ // Upload new photo
547
+ return this.uploadProfilePhoto(patientId, file);
462
548
  }
463
549
 
550
+ /**
551
+ * Deletes a patient's profile photo
552
+ * @param patientId - ID of the patient
553
+ */
464
554
  async deleteProfilePhoto(patientId: string): Promise<void> {
465
- await deleteProfilePhotoUtil(this.storage, this.db, patientId);
555
+ console.log(
556
+ `[PatientService] Deleting profile photo for patient ${patientId}`
557
+ );
558
+
559
+ // Get current patient sensitive info to find the photo URL
560
+ const currentUser = await this.getCurrentUser();
561
+ const currentSensitiveInfo = await this.getSensitiveInfo(
562
+ patientId,
563
+ currentUser.uid
564
+ );
565
+
566
+ if (
567
+ currentSensitiveInfo?.photoUrl &&
568
+ typeof currentSensitiveInfo.photoUrl === "string"
569
+ ) {
570
+ try {
571
+ const existingMediaMetadata =
572
+ await this.mediaService.getMediaMetadataByUrl(
573
+ currentSensitiveInfo.photoUrl
574
+ );
575
+ if (existingMediaMetadata) {
576
+ await this.mediaService.deleteMedia(existingMediaMetadata.id);
577
+ }
578
+ } catch (error) {
579
+ console.warn(
580
+ `[PatientService] Could not delete profile photo for patient ${patientId}:`,
581
+ error
582
+ );
583
+ }
584
+
585
+ // Remove photo URL from patient sensitive info
586
+ await updateDoc(getSensitiveInfoDocRef(this.db, patientId), {
587
+ photoUrl: null,
588
+ updatedAt: serverTimestamp(),
589
+ });
590
+ }
591
+ }
592
+
593
+ /**
594
+ * Handles profile photo upload for patients (supports MediaResource)
595
+ * @param photoUrl - MediaResource (File, Blob, or URL string) from CreatePatientSensitiveInfoData
596
+ * @param patientId - ID of the patient
597
+ * @returns URL string of the uploaded or existing photo
598
+ */
599
+ private async handleProfilePhotoUpload(
600
+ photoUrl: MediaResource | undefined,
601
+ patientId: string
602
+ ): Promise<string | undefined> {
603
+ if (!photoUrl) {
604
+ return undefined;
605
+ }
606
+
607
+ // If it's already a URL string, return it as is
608
+ if (typeof photoUrl === "string") {
609
+ return photoUrl;
610
+ }
611
+
612
+ // If it's a File or Blob, upload it
613
+ if (photoUrl instanceof File || photoUrl instanceof Blob) {
614
+ return this.uploadProfilePhoto(patientId, photoUrl);
615
+ }
616
+
617
+ return undefined;
466
618
  }
467
619
 
468
620
  // Metode za ažuriranje profila