@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/dist/admin/index.d.mts +1 -2
- package/dist/admin/index.d.ts +1 -2
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/backoffice/index.d.mts +6 -1
- package/dist/backoffice/index.d.ts +6 -1
- package/dist/index.d.mts +80 -45
- package/dist/index.d.ts +80 -45
- package/dist/index.js +1635 -1407
- package/dist/index.mjs +1656 -1426
- package/package.json +1 -1
- package/src/admin/booking/booking.admin.ts +4 -1
- package/src/services/patient/patient.service.ts +162 -10
- package/src/services/patient/utils/profile.utils.ts +124 -135
- package/src/services/patient/utils/sensitive.utils.ts +76 -2
- package/src/services/practitioner/practitioner.service.ts +92 -3
- package/src/services/procedure/procedure.service.ts +8 -2
- package/src/types/patient/index.ts +25 -23
- package/src/types/practitioner/index.ts +2 -1
- package/src/validations/media.schema.ts +1 -1
- package/src/validations/patient.schema.ts +4 -4
- package/src/validations/practitioner.schema.ts +3 -2
package/package.json
CHANGED
|
@@ -613,7 +613,10 @@ export class BookingAdmin {
|
|
|
613
613
|
};
|
|
614
614
|
const practitionerInfo: PractitionerProfileInfo = {
|
|
615
615
|
id: practitionerSnap.id,
|
|
616
|
-
practitionerPhoto:
|
|
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(
|
|
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(
|
|
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
|
-
|
|
457
|
-
|
|
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
|
-
|
|
461
|
-
|
|
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
|
-
|
|
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
|