@blackcode_sa/metaestetics-api 1.12.26 → 1.12.28
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 +2 -0
- package/dist/admin/index.d.ts +2 -0
- package/dist/admin/index.js +31 -14
- package/dist/admin/index.mjs +31 -14
- package/dist/index.d.mts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +64 -140
- package/dist/index.mjs +65 -146
- package/package.json +1 -1
- package/src/admin/booking/booking.admin.ts +34 -12
- package/src/admin/booking/booking.calculator.ts +14 -9
- package/src/admin/booking/timezones-problem.md +49 -5
- package/src/services/clinic/clinic.service.ts +1 -1
- package/src/services/patient/patient.service.ts +117 -282
- package/src/services/patient/utils/sensitive.utils.ts +81 -67
- package/src/services/user/user.service.ts +9 -3
package/dist/admin/index.d.mts
CHANGED
|
@@ -3196,6 +3196,7 @@ declare class BookingAvailabilityCalculator {
|
|
|
3196
3196
|
* @param intervals - Final available intervals
|
|
3197
3197
|
* @param intervalMinutes - Scheduling interval in minutes
|
|
3198
3198
|
* @param durationMinutes - Procedure duration in minutes
|
|
3199
|
+
* @param tz - IANA timezone of the clinic
|
|
3199
3200
|
* @returns Array of available booking slots
|
|
3200
3201
|
*/
|
|
3201
3202
|
private static generateAvailableSlots;
|
|
@@ -3205,6 +3206,7 @@ declare class BookingAvailabilityCalculator {
|
|
|
3205
3206
|
* @param slotStart - Start time of the slot
|
|
3206
3207
|
* @param slotEnd - End time of the slot
|
|
3207
3208
|
* @param intervals - Available intervals
|
|
3209
|
+
* @param tz - IANA timezone of the clinic
|
|
3208
3210
|
* @returns True if the slot is fully contained within an available interval
|
|
3209
3211
|
*/
|
|
3210
3212
|
private static isSlotFullyAvailable;
|
package/dist/admin/index.d.ts
CHANGED
|
@@ -3196,6 +3196,7 @@ declare class BookingAvailabilityCalculator {
|
|
|
3196
3196
|
* @param intervals - Final available intervals
|
|
3197
3197
|
* @param intervalMinutes - Scheduling interval in minutes
|
|
3198
3198
|
* @param durationMinutes - Procedure duration in minutes
|
|
3199
|
+
* @param tz - IANA timezone of the clinic
|
|
3199
3200
|
* @returns Array of available booking slots
|
|
3200
3201
|
*/
|
|
3201
3202
|
private static generateAvailableSlots;
|
|
@@ -3205,6 +3206,7 @@ declare class BookingAvailabilityCalculator {
|
|
|
3205
3206
|
* @param slotStart - Start time of the slot
|
|
3206
3207
|
* @param slotEnd - End time of the slot
|
|
3207
3208
|
* @param intervals - Available intervals
|
|
3209
|
+
* @param tz - IANA timezone of the clinic
|
|
3208
3210
|
* @returns True if the slot is fully contained within an available interval
|
|
3209
3211
|
*/
|
|
3210
3212
|
private static isSlotFullyAvailable;
|
package/dist/admin/index.js
CHANGED
|
@@ -6603,7 +6603,8 @@ var BookingAvailabilityCalculator = class {
|
|
|
6603
6603
|
const availableSlots = this.generateAvailableSlots(
|
|
6604
6604
|
availableIntervals,
|
|
6605
6605
|
schedulingIntervalMinutes,
|
|
6606
|
-
procedureDurationMinutes
|
|
6606
|
+
procedureDurationMinutes,
|
|
6607
|
+
tz
|
|
6607
6608
|
);
|
|
6608
6609
|
return { availableSlots };
|
|
6609
6610
|
}
|
|
@@ -6855,19 +6856,20 @@ var BookingAvailabilityCalculator = class {
|
|
|
6855
6856
|
* @param intervals - Final available intervals
|
|
6856
6857
|
* @param intervalMinutes - Scheduling interval in minutes
|
|
6857
6858
|
* @param durationMinutes - Procedure duration in minutes
|
|
6859
|
+
* @param tz - IANA timezone of the clinic
|
|
6858
6860
|
* @returns Array of available booking slots
|
|
6859
6861
|
*/
|
|
6860
|
-
static generateAvailableSlots(intervals, intervalMinutes, durationMinutes) {
|
|
6862
|
+
static generateAvailableSlots(intervals, intervalMinutes, durationMinutes, tz) {
|
|
6861
6863
|
const slots = [];
|
|
6862
6864
|
console.log(
|
|
6863
|
-
`Generating slots with ${intervalMinutes}min intervals for ${durationMinutes}min procedure`
|
|
6865
|
+
`Generating slots with ${intervalMinutes}min intervals for ${durationMinutes}min procedure in timezone ${tz}`
|
|
6864
6866
|
);
|
|
6865
6867
|
const durationMs = durationMinutes * 60 * 1e3;
|
|
6866
6868
|
const intervalMs = intervalMinutes * 60 * 1e3;
|
|
6867
6869
|
for (const interval of intervals) {
|
|
6868
6870
|
const intervalStart = interval.start.toDate();
|
|
6869
6871
|
const intervalEnd = interval.end.toDate();
|
|
6870
|
-
let slotStart = import_luxon.DateTime.
|
|
6872
|
+
let slotStart = import_luxon.DateTime.fromMillis(intervalStart.getTime(), { zone: tz });
|
|
6871
6873
|
const minutesIntoDay = slotStart.hour * 60 + slotStart.minute;
|
|
6872
6874
|
const minutesRemainder = minutesIntoDay % intervalMinutes;
|
|
6873
6875
|
if (minutesRemainder > 0) {
|
|
@@ -6877,7 +6879,7 @@ var BookingAvailabilityCalculator = class {
|
|
|
6877
6879
|
}
|
|
6878
6880
|
while (slotStart.toMillis() + durationMs <= intervalEnd.getTime()) {
|
|
6879
6881
|
const slotEnd = slotStart.plus({ minutes: durationMinutes });
|
|
6880
|
-
if (this.isSlotFullyAvailable(slotStart, slotEnd, intervals)) {
|
|
6882
|
+
if (this.isSlotFullyAvailable(slotStart, slotEnd, intervals, tz)) {
|
|
6881
6883
|
slots.push({
|
|
6882
6884
|
start: import_firestore2.Timestamp.fromMillis(slotStart.toMillis())
|
|
6883
6885
|
});
|
|
@@ -6894,12 +6896,13 @@ var BookingAvailabilityCalculator = class {
|
|
|
6894
6896
|
* @param slotStart - Start time of the slot
|
|
6895
6897
|
* @param slotEnd - End time of the slot
|
|
6896
6898
|
* @param intervals - Available intervals
|
|
6899
|
+
* @param tz - IANA timezone of the clinic
|
|
6897
6900
|
* @returns True if the slot is fully contained within an available interval
|
|
6898
6901
|
*/
|
|
6899
|
-
static isSlotFullyAvailable(slotStart, slotEnd, intervals) {
|
|
6902
|
+
static isSlotFullyAvailable(slotStart, slotEnd, intervals, tz) {
|
|
6900
6903
|
return intervals.some((interval) => {
|
|
6901
|
-
const intervalStart = import_luxon.DateTime.fromMillis(interval.start.toMillis());
|
|
6902
|
-
const intervalEnd = import_luxon.DateTime.fromMillis(interval.end.toMillis());
|
|
6904
|
+
const intervalStart = import_luxon.DateTime.fromMillis(interval.start.toMillis(), { zone: tz });
|
|
6905
|
+
const intervalEnd = import_luxon.DateTime.fromMillis(interval.end.toMillis(), { zone: tz });
|
|
6903
6906
|
return slotStart >= intervalStart && slotEnd <= intervalEnd;
|
|
6904
6907
|
});
|
|
6905
6908
|
}
|
|
@@ -7344,16 +7347,23 @@ var BookingAdmin = class {
|
|
|
7344
7347
|
startTime: start.toDate().toISOString(),
|
|
7345
7348
|
endTime: end.toDate().toISOString()
|
|
7346
7349
|
});
|
|
7347
|
-
const
|
|
7350
|
+
const MAX_EVENT_DURATION_MS = 24 * 60 * 60 * 1e3;
|
|
7351
|
+
const queryStart = admin15.firestore.Timestamp.fromMillis(
|
|
7352
|
+
start.toMillis() - MAX_EVENT_DURATION_MS
|
|
7353
|
+
);
|
|
7354
|
+
const eventsRef = this.db.collection(`clinics/${clinicId}/calendar`).where("eventTime.start", ">=", queryStart).where("eventTime.start", "<", end).orderBy("eventTime.start");
|
|
7348
7355
|
const snapshot = await eventsRef.get();
|
|
7349
7356
|
const events = snapshot.docs.map((doc) => ({
|
|
7350
7357
|
...doc.data(),
|
|
7351
7358
|
id: doc.id
|
|
7352
|
-
}))
|
|
7359
|
+
})).filter((event) => {
|
|
7360
|
+
return event.eventTime.end.toMillis() > start.toMillis();
|
|
7361
|
+
});
|
|
7353
7362
|
Logger.debug("[BookingAdmin] Retrieved clinic calendar events", {
|
|
7354
7363
|
clinicId,
|
|
7355
7364
|
eventsCount: events.length,
|
|
7356
|
-
eventsTypes: this.summarizeEventTypes(events)
|
|
7365
|
+
eventsTypes: this.summarizeEventTypes(events),
|
|
7366
|
+
queryStartTime: queryStart.toDate().toISOString()
|
|
7357
7367
|
});
|
|
7358
7368
|
return events;
|
|
7359
7369
|
} catch (error) {
|
|
@@ -7383,16 +7393,23 @@ var BookingAdmin = class {
|
|
|
7383
7393
|
startTime: start.toDate().toISOString(),
|
|
7384
7394
|
endTime: end.toDate().toISOString()
|
|
7385
7395
|
});
|
|
7386
|
-
const
|
|
7396
|
+
const MAX_EVENT_DURATION_MS = 24 * 60 * 60 * 1e3;
|
|
7397
|
+
const queryStart = admin15.firestore.Timestamp.fromMillis(
|
|
7398
|
+
start.toMillis() - MAX_EVENT_DURATION_MS
|
|
7399
|
+
);
|
|
7400
|
+
const eventsRef = this.db.collection(`practitioners/${practitionerId}/calendar`).where("eventTime.start", ">=", queryStart).where("eventTime.start", "<", end).orderBy("eventTime.start");
|
|
7387
7401
|
const snapshot = await eventsRef.get();
|
|
7388
7402
|
const events = snapshot.docs.map((doc) => ({
|
|
7389
7403
|
...doc.data(),
|
|
7390
7404
|
id: doc.id
|
|
7391
|
-
}))
|
|
7405
|
+
})).filter((event) => {
|
|
7406
|
+
return event.eventTime.end.toMillis() > start.toMillis();
|
|
7407
|
+
});
|
|
7392
7408
|
Logger.debug("[BookingAdmin] Retrieved practitioner calendar events", {
|
|
7393
7409
|
practitionerId,
|
|
7394
7410
|
eventsCount: events.length,
|
|
7395
|
-
eventsTypes: this.summarizeEventTypes(events)
|
|
7411
|
+
eventsTypes: this.summarizeEventTypes(events),
|
|
7412
|
+
queryStartTime: queryStart.toDate().toISOString()
|
|
7396
7413
|
});
|
|
7397
7414
|
return events;
|
|
7398
7415
|
} catch (error) {
|
package/dist/admin/index.mjs
CHANGED
|
@@ -6541,7 +6541,8 @@ var BookingAvailabilityCalculator = class {
|
|
|
6541
6541
|
const availableSlots = this.generateAvailableSlots(
|
|
6542
6542
|
availableIntervals,
|
|
6543
6543
|
schedulingIntervalMinutes,
|
|
6544
|
-
procedureDurationMinutes
|
|
6544
|
+
procedureDurationMinutes,
|
|
6545
|
+
tz
|
|
6545
6546
|
);
|
|
6546
6547
|
return { availableSlots };
|
|
6547
6548
|
}
|
|
@@ -6793,19 +6794,20 @@ var BookingAvailabilityCalculator = class {
|
|
|
6793
6794
|
* @param intervals - Final available intervals
|
|
6794
6795
|
* @param intervalMinutes - Scheduling interval in minutes
|
|
6795
6796
|
* @param durationMinutes - Procedure duration in minutes
|
|
6797
|
+
* @param tz - IANA timezone of the clinic
|
|
6796
6798
|
* @returns Array of available booking slots
|
|
6797
6799
|
*/
|
|
6798
|
-
static generateAvailableSlots(intervals, intervalMinutes, durationMinutes) {
|
|
6800
|
+
static generateAvailableSlots(intervals, intervalMinutes, durationMinutes, tz) {
|
|
6799
6801
|
const slots = [];
|
|
6800
6802
|
console.log(
|
|
6801
|
-
`Generating slots with ${intervalMinutes}min intervals for ${durationMinutes}min procedure`
|
|
6803
|
+
`Generating slots with ${intervalMinutes}min intervals for ${durationMinutes}min procedure in timezone ${tz}`
|
|
6802
6804
|
);
|
|
6803
6805
|
const durationMs = durationMinutes * 60 * 1e3;
|
|
6804
6806
|
const intervalMs = intervalMinutes * 60 * 1e3;
|
|
6805
6807
|
for (const interval of intervals) {
|
|
6806
6808
|
const intervalStart = interval.start.toDate();
|
|
6807
6809
|
const intervalEnd = interval.end.toDate();
|
|
6808
|
-
let slotStart = DateTime.
|
|
6810
|
+
let slotStart = DateTime.fromMillis(intervalStart.getTime(), { zone: tz });
|
|
6809
6811
|
const minutesIntoDay = slotStart.hour * 60 + slotStart.minute;
|
|
6810
6812
|
const minutesRemainder = minutesIntoDay % intervalMinutes;
|
|
6811
6813
|
if (minutesRemainder > 0) {
|
|
@@ -6815,7 +6817,7 @@ var BookingAvailabilityCalculator = class {
|
|
|
6815
6817
|
}
|
|
6816
6818
|
while (slotStart.toMillis() + durationMs <= intervalEnd.getTime()) {
|
|
6817
6819
|
const slotEnd = slotStart.plus({ minutes: durationMinutes });
|
|
6818
|
-
if (this.isSlotFullyAvailable(slotStart, slotEnd, intervals)) {
|
|
6820
|
+
if (this.isSlotFullyAvailable(slotStart, slotEnd, intervals, tz)) {
|
|
6819
6821
|
slots.push({
|
|
6820
6822
|
start: Timestamp.fromMillis(slotStart.toMillis())
|
|
6821
6823
|
});
|
|
@@ -6832,12 +6834,13 @@ var BookingAvailabilityCalculator = class {
|
|
|
6832
6834
|
* @param slotStart - Start time of the slot
|
|
6833
6835
|
* @param slotEnd - End time of the slot
|
|
6834
6836
|
* @param intervals - Available intervals
|
|
6837
|
+
* @param tz - IANA timezone of the clinic
|
|
6835
6838
|
* @returns True if the slot is fully contained within an available interval
|
|
6836
6839
|
*/
|
|
6837
|
-
static isSlotFullyAvailable(slotStart, slotEnd, intervals) {
|
|
6840
|
+
static isSlotFullyAvailable(slotStart, slotEnd, intervals, tz) {
|
|
6838
6841
|
return intervals.some((interval) => {
|
|
6839
|
-
const intervalStart = DateTime.fromMillis(interval.start.toMillis());
|
|
6840
|
-
const intervalEnd = DateTime.fromMillis(interval.end.toMillis());
|
|
6842
|
+
const intervalStart = DateTime.fromMillis(interval.start.toMillis(), { zone: tz });
|
|
6843
|
+
const intervalEnd = DateTime.fromMillis(interval.end.toMillis(), { zone: tz });
|
|
6841
6844
|
return slotStart >= intervalStart && slotEnd <= intervalEnd;
|
|
6842
6845
|
});
|
|
6843
6846
|
}
|
|
@@ -7282,16 +7285,23 @@ var BookingAdmin = class {
|
|
|
7282
7285
|
startTime: start.toDate().toISOString(),
|
|
7283
7286
|
endTime: end.toDate().toISOString()
|
|
7284
7287
|
});
|
|
7285
|
-
const
|
|
7288
|
+
const MAX_EVENT_DURATION_MS = 24 * 60 * 60 * 1e3;
|
|
7289
|
+
const queryStart = admin15.firestore.Timestamp.fromMillis(
|
|
7290
|
+
start.toMillis() - MAX_EVENT_DURATION_MS
|
|
7291
|
+
);
|
|
7292
|
+
const eventsRef = this.db.collection(`clinics/${clinicId}/calendar`).where("eventTime.start", ">=", queryStart).where("eventTime.start", "<", end).orderBy("eventTime.start");
|
|
7286
7293
|
const snapshot = await eventsRef.get();
|
|
7287
7294
|
const events = snapshot.docs.map((doc) => ({
|
|
7288
7295
|
...doc.data(),
|
|
7289
7296
|
id: doc.id
|
|
7290
|
-
}))
|
|
7297
|
+
})).filter((event) => {
|
|
7298
|
+
return event.eventTime.end.toMillis() > start.toMillis();
|
|
7299
|
+
});
|
|
7291
7300
|
Logger.debug("[BookingAdmin] Retrieved clinic calendar events", {
|
|
7292
7301
|
clinicId,
|
|
7293
7302
|
eventsCount: events.length,
|
|
7294
|
-
eventsTypes: this.summarizeEventTypes(events)
|
|
7303
|
+
eventsTypes: this.summarizeEventTypes(events),
|
|
7304
|
+
queryStartTime: queryStart.toDate().toISOString()
|
|
7295
7305
|
});
|
|
7296
7306
|
return events;
|
|
7297
7307
|
} catch (error) {
|
|
@@ -7321,16 +7331,23 @@ var BookingAdmin = class {
|
|
|
7321
7331
|
startTime: start.toDate().toISOString(),
|
|
7322
7332
|
endTime: end.toDate().toISOString()
|
|
7323
7333
|
});
|
|
7324
|
-
const
|
|
7334
|
+
const MAX_EVENT_DURATION_MS = 24 * 60 * 60 * 1e3;
|
|
7335
|
+
const queryStart = admin15.firestore.Timestamp.fromMillis(
|
|
7336
|
+
start.toMillis() - MAX_EVENT_DURATION_MS
|
|
7337
|
+
);
|
|
7338
|
+
const eventsRef = this.db.collection(`practitioners/${practitionerId}/calendar`).where("eventTime.start", ">=", queryStart).where("eventTime.start", "<", end).orderBy("eventTime.start");
|
|
7325
7339
|
const snapshot = await eventsRef.get();
|
|
7326
7340
|
const events = snapshot.docs.map((doc) => ({
|
|
7327
7341
|
...doc.data(),
|
|
7328
7342
|
id: doc.id
|
|
7329
|
-
}))
|
|
7343
|
+
})).filter((event) => {
|
|
7344
|
+
return event.eventTime.end.toMillis() > start.toMillis();
|
|
7345
|
+
});
|
|
7330
7346
|
Logger.debug("[BookingAdmin] Retrieved practitioner calendar events", {
|
|
7331
7347
|
practitionerId,
|
|
7332
7348
|
eventsCount: events.length,
|
|
7333
|
-
eventsTypes: this.summarizeEventTypes(events)
|
|
7349
|
+
eventsTypes: this.summarizeEventTypes(events),
|
|
7350
|
+
queryStartTime: queryStart.toDate().toISOString()
|
|
7334
7351
|
});
|
|
7335
7352
|
return events;
|
|
7336
7353
|
} catch (error) {
|
package/dist/index.d.mts
CHANGED
|
@@ -4883,6 +4883,7 @@ declare class PatientService extends BaseService {
|
|
|
4883
4883
|
getSensitiveInfo(patientId: string, requesterUserId: string): Promise<PatientSensitiveInfo | null>;
|
|
4884
4884
|
getSensitiveInfoByUserRef(userRef: string, requesterUserId: string): Promise<PatientSensitiveInfo | null>;
|
|
4885
4885
|
updateSensitiveInfo(patientId: string, data: UpdatePatientSensitiveInfoData, requesterUserId: string): Promise<PatientSensitiveInfo>;
|
|
4886
|
+
claimPatientSensitiveInfo(patientId: string, userId: string): Promise<PatientSensitiveInfo>;
|
|
4886
4887
|
createMedicalInfo(patientId: string, data: CreatePatientMedicalInfoData): Promise<void>;
|
|
4887
4888
|
getMedicalInfo(patientId: string): Promise<PatientMedicalInfo>;
|
|
4888
4889
|
getMedicalInfoByUserRef(userRef: string): Promise<PatientMedicalInfo>;
|
|
@@ -4940,8 +4941,8 @@ declare class PatientService extends BaseService {
|
|
|
4940
4941
|
* @returns URL string of the uploaded or existing photo
|
|
4941
4942
|
*/
|
|
4942
4943
|
private handleProfilePhotoUpload;
|
|
4943
|
-
updatePatientProfile(patientId: string, data: Partial<Omit<PatientProfile,
|
|
4944
|
-
updatePatientProfileByUserRef(userRef: string, data: Partial<Omit<PatientProfile,
|
|
4944
|
+
updatePatientProfile(patientId: string, data: Partial<Omit<PatientProfile, 'id' | 'createdAt' | 'updatedAt'>>): Promise<PatientProfile>;
|
|
4945
|
+
updatePatientProfileByUserRef(userRef: string, data: Partial<Omit<PatientProfile, 'id' | 'createdAt' | 'updatedAt'>>): Promise<PatientProfile>;
|
|
4945
4946
|
/**
|
|
4946
4947
|
* Searches for patient profiles based on clinic/practitioner association.
|
|
4947
4948
|
* Requires information about the requester for security checks.
|
package/dist/index.d.ts
CHANGED
|
@@ -4883,6 +4883,7 @@ declare class PatientService extends BaseService {
|
|
|
4883
4883
|
getSensitiveInfo(patientId: string, requesterUserId: string): Promise<PatientSensitiveInfo | null>;
|
|
4884
4884
|
getSensitiveInfoByUserRef(userRef: string, requesterUserId: string): Promise<PatientSensitiveInfo | null>;
|
|
4885
4885
|
updateSensitiveInfo(patientId: string, data: UpdatePatientSensitiveInfoData, requesterUserId: string): Promise<PatientSensitiveInfo>;
|
|
4886
|
+
claimPatientSensitiveInfo(patientId: string, userId: string): Promise<PatientSensitiveInfo>;
|
|
4886
4887
|
createMedicalInfo(patientId: string, data: CreatePatientMedicalInfoData): Promise<void>;
|
|
4887
4888
|
getMedicalInfo(patientId: string): Promise<PatientMedicalInfo>;
|
|
4888
4889
|
getMedicalInfoByUserRef(userRef: string): Promise<PatientMedicalInfo>;
|
|
@@ -4940,8 +4941,8 @@ declare class PatientService extends BaseService {
|
|
|
4940
4941
|
* @returns URL string of the uploaded or existing photo
|
|
4941
4942
|
*/
|
|
4942
4943
|
private handleProfilePhotoUpload;
|
|
4943
|
-
updatePatientProfile(patientId: string, data: Partial<Omit<PatientProfile,
|
|
4944
|
-
updatePatientProfileByUserRef(userRef: string, data: Partial<Omit<PatientProfile,
|
|
4944
|
+
updatePatientProfile(patientId: string, data: Partial<Omit<PatientProfile, 'id' | 'createdAt' | 'updatedAt'>>): Promise<PatientProfile>;
|
|
4945
|
+
updatePatientProfileByUserRef(userRef: string, data: Partial<Omit<PatientProfile, 'id' | 'createdAt' | 'updatedAt'>>): Promise<PatientProfile>;
|
|
4945
4946
|
/**
|
|
4946
4947
|
* Searches for patient profiles based on clinic/practitioner association.
|
|
4947
4948
|
* Requires information about the requester for security checks.
|
package/dist/index.js
CHANGED
|
@@ -4232,10 +4232,7 @@ var checkSensitiveAccessUtil = async (db, patientId, requesterId, requesterRoles
|
|
|
4232
4232
|
return;
|
|
4233
4233
|
}
|
|
4234
4234
|
if (requesterRoles.includes("practitioner" /* PRACTITIONER */)) {
|
|
4235
|
-
const practitionerProfile = await getPractitionerProfileByUserRef(
|
|
4236
|
-
db,
|
|
4237
|
-
requesterId
|
|
4238
|
-
);
|
|
4235
|
+
const practitionerProfile = await getPractitionerProfileByUserRef(db, requesterId);
|
|
4239
4236
|
if (practitionerProfile && ((_a = patientData.doctorIds) == null ? void 0 : _a.includes(practitionerProfile.id))) {
|
|
4240
4237
|
return;
|
|
4241
4238
|
}
|
|
@@ -4283,16 +4280,9 @@ var handlePhotoUrlUpload = async (photoUrl, patientId, mediaService) => {
|
|
|
4283
4280
|
};
|
|
4284
4281
|
var createSensitiveInfoUtil = async (db, data, requesterId, requesterRoles, mediaService) => {
|
|
4285
4282
|
try {
|
|
4286
|
-
await checkSensitiveAccessUtil(
|
|
4287
|
-
db,
|
|
4288
|
-
data.patientId,
|
|
4289
|
-
requesterId,
|
|
4290
|
-
requesterRoles
|
|
4291
|
-
);
|
|
4283
|
+
await checkSensitiveAccessUtil(db, data.patientId, requesterId, requesterRoles);
|
|
4292
4284
|
const validatedData = createPatientSensitiveInfoSchema.parse(data);
|
|
4293
|
-
const sensitiveDoc = await (0, import_firestore11.getDoc)(
|
|
4294
|
-
getSensitiveInfoDocRef(db, data.patientId)
|
|
4295
|
-
);
|
|
4285
|
+
const sensitiveDoc = await (0, import_firestore11.getDoc)(getSensitiveInfoDocRef(db, data.patientId));
|
|
4296
4286
|
if (sensitiveDoc.exists()) {
|
|
4297
4287
|
throw new Error("Sensitive information already exists for this patient");
|
|
4298
4288
|
}
|
|
@@ -4337,11 +4327,7 @@ var updateSensitiveInfoUtil = async (db, patientId, data, requesterId, requester
|
|
|
4337
4327
|
let processedPhotoUrl = void 0;
|
|
4338
4328
|
if (data.photoUrl !== void 0) {
|
|
4339
4329
|
if (mediaService) {
|
|
4340
|
-
processedPhotoUrl = await handlePhotoUrlUpload(
|
|
4341
|
-
data.photoUrl,
|
|
4342
|
-
patientId,
|
|
4343
|
-
mediaService
|
|
4344
|
-
);
|
|
4330
|
+
processedPhotoUrl = await handlePhotoUrlUpload(data.photoUrl, patientId, mediaService);
|
|
4345
4331
|
} else if (typeof data.photoUrl === "string" || data.photoUrl === null) {
|
|
4346
4332
|
processedPhotoUrl = data.photoUrl;
|
|
4347
4333
|
} else {
|
|
@@ -4360,6 +4346,36 @@ var updateSensitiveInfoUtil = async (db, patientId, data, requesterId, requester
|
|
|
4360
4346
|
}
|
|
4361
4347
|
return updatedDoc.data();
|
|
4362
4348
|
};
|
|
4349
|
+
var claimPatientSensitiveInfoUtil = async (db, patientId, userId) => {
|
|
4350
|
+
const patientDoc = await (0, import_firestore11.getDoc)(getPatientDocRef(db, patientId));
|
|
4351
|
+
if (!patientDoc.exists()) {
|
|
4352
|
+
throw new Error("Patient profile not found");
|
|
4353
|
+
}
|
|
4354
|
+
const patientData = patientDoc.data();
|
|
4355
|
+
if (!patientData.isManual) {
|
|
4356
|
+
throw new Error("Only manually created patient profiles can be claimed");
|
|
4357
|
+
}
|
|
4358
|
+
if (patientData.userRef) {
|
|
4359
|
+
throw new Error("Patient profile has already been claimed");
|
|
4360
|
+
}
|
|
4361
|
+
const sensitiveDoc = await (0, import_firestore11.getDoc)(getSensitiveInfoDocRef(db, patientId));
|
|
4362
|
+
if (!sensitiveDoc.exists()) {
|
|
4363
|
+
throw new Error("Patient sensitive information not found");
|
|
4364
|
+
}
|
|
4365
|
+
const sensitiveData = sensitiveDoc.data();
|
|
4366
|
+
if (sensitiveData.userRef) {
|
|
4367
|
+
throw new Error("Patient sensitive information has already been claimed");
|
|
4368
|
+
}
|
|
4369
|
+
await (0, import_firestore11.updateDoc)(getSensitiveInfoDocRef(db, patientId), {
|
|
4370
|
+
userRef: userId,
|
|
4371
|
+
updatedAt: (0, import_firestore11.serverTimestamp)()
|
|
4372
|
+
});
|
|
4373
|
+
const updatedDoc = await (0, import_firestore11.getDoc)(getSensitiveInfoDocRef(db, patientId));
|
|
4374
|
+
if (!updatedDoc.exists()) {
|
|
4375
|
+
throw new Error("Failed to retrieve updated sensitive information");
|
|
4376
|
+
}
|
|
4377
|
+
return updatedDoc.data();
|
|
4378
|
+
};
|
|
4363
4379
|
|
|
4364
4380
|
// src/services/patient/utils/docs.utils.ts
|
|
4365
4381
|
var getPatientDocRef = (db, patientId) => {
|
|
@@ -5500,12 +5516,7 @@ var PatientService = class extends BaseService {
|
|
|
5500
5516
|
const currentUser = await this.getCurrentUser();
|
|
5501
5517
|
if (currentUser.uid !== requesterUserId) {
|
|
5502
5518
|
}
|
|
5503
|
-
return getSensitiveInfoUtil(
|
|
5504
|
-
this.db,
|
|
5505
|
-
patientId,
|
|
5506
|
-
requesterUserId,
|
|
5507
|
-
currentUser.roles
|
|
5508
|
-
);
|
|
5519
|
+
return getSensitiveInfoUtil(this.db, patientId, requesterUserId, currentUser.roles);
|
|
5509
5520
|
}
|
|
5510
5521
|
async getSensitiveInfoByUserRef(userRef, requesterUserId) {
|
|
5511
5522
|
const profile = await this.getPatientProfileByUserRef(userRef);
|
|
@@ -5526,25 +5537,17 @@ var PatientService = class extends BaseService {
|
|
|
5526
5537
|
this.mediaService
|
|
5527
5538
|
);
|
|
5528
5539
|
}
|
|
5540
|
+
async claimPatientSensitiveInfo(patientId, userId) {
|
|
5541
|
+
return claimPatientSensitiveInfoUtil(this.db, patientId, userId);
|
|
5542
|
+
}
|
|
5529
5543
|
// Metode za rad sa medicinskim informacijama
|
|
5530
5544
|
async createMedicalInfo(patientId, data) {
|
|
5531
5545
|
const currentUser = await this.getCurrentUser();
|
|
5532
|
-
await createMedicalInfoUtil(
|
|
5533
|
-
this.db,
|
|
5534
|
-
patientId,
|
|
5535
|
-
data,
|
|
5536
|
-
currentUser.uid,
|
|
5537
|
-
currentUser.roles
|
|
5538
|
-
);
|
|
5546
|
+
await createMedicalInfoUtil(this.db, patientId, data, currentUser.uid, currentUser.roles);
|
|
5539
5547
|
}
|
|
5540
5548
|
async getMedicalInfo(patientId) {
|
|
5541
5549
|
const currentUser = await this.getCurrentUser();
|
|
5542
|
-
return getMedicalInfoUtil(
|
|
5543
|
-
this.db,
|
|
5544
|
-
patientId,
|
|
5545
|
-
currentUser.uid,
|
|
5546
|
-
currentUser.roles
|
|
5547
|
-
);
|
|
5550
|
+
return getMedicalInfoUtil(this.db, patientId, currentUser.uid, currentUser.roles);
|
|
5548
5551
|
}
|
|
5549
5552
|
async getMedicalInfoByUserRef(userRef) {
|
|
5550
5553
|
const profile = await this.getPatientProfileByUserRef(userRef);
|
|
@@ -5554,65 +5557,29 @@ var PatientService = class extends BaseService {
|
|
|
5554
5557
|
// Metode za rad sa vitalnim statistikama
|
|
5555
5558
|
async updateVitalStats(patientId, data) {
|
|
5556
5559
|
const currentUser = await this.getCurrentUser();
|
|
5557
|
-
await updateVitalStatsUtil(
|
|
5558
|
-
this.db,
|
|
5559
|
-
patientId,
|
|
5560
|
-
data,
|
|
5561
|
-
currentUser.uid,
|
|
5562
|
-
currentUser.roles
|
|
5563
|
-
);
|
|
5560
|
+
await updateVitalStatsUtil(this.db, patientId, data, currentUser.uid, currentUser.roles);
|
|
5564
5561
|
}
|
|
5565
5562
|
// Metode za rad sa alergijama
|
|
5566
5563
|
async addAllergy(patientId, data) {
|
|
5567
5564
|
const currentUser = await this.getCurrentUser();
|
|
5568
|
-
await addAllergyUtil(
|
|
5569
|
-
this.db,
|
|
5570
|
-
patientId,
|
|
5571
|
-
data,
|
|
5572
|
-
currentUser.uid,
|
|
5573
|
-
currentUser.roles
|
|
5574
|
-
);
|
|
5565
|
+
await addAllergyUtil(this.db, patientId, data, currentUser.uid, currentUser.roles);
|
|
5575
5566
|
}
|
|
5576
5567
|
async updateAllergy(patientId, data) {
|
|
5577
5568
|
const currentUser = await this.getCurrentUser();
|
|
5578
|
-
await updateAllergyUtil(
|
|
5579
|
-
this.db,
|
|
5580
|
-
patientId,
|
|
5581
|
-
data,
|
|
5582
|
-
currentUser.uid,
|
|
5583
|
-
currentUser.roles
|
|
5584
|
-
);
|
|
5569
|
+
await updateAllergyUtil(this.db, patientId, data, currentUser.uid, currentUser.roles);
|
|
5585
5570
|
}
|
|
5586
5571
|
async removeAllergy(patientId, allergyIndex) {
|
|
5587
5572
|
const currentUser = await this.getCurrentUser();
|
|
5588
|
-
await removeAllergyUtil(
|
|
5589
|
-
this.db,
|
|
5590
|
-
patientId,
|
|
5591
|
-
allergyIndex,
|
|
5592
|
-
currentUser.uid,
|
|
5593
|
-
currentUser.roles
|
|
5594
|
-
);
|
|
5573
|
+
await removeAllergyUtil(this.db, patientId, allergyIndex, currentUser.uid, currentUser.roles);
|
|
5595
5574
|
}
|
|
5596
5575
|
// Metode za rad sa blocking conditions
|
|
5597
5576
|
async addBlockingCondition(patientId, data) {
|
|
5598
5577
|
const currentUser = await this.getCurrentUser();
|
|
5599
|
-
await addBlockingConditionUtil(
|
|
5600
|
-
this.db,
|
|
5601
|
-
patientId,
|
|
5602
|
-
data,
|
|
5603
|
-
currentUser.uid,
|
|
5604
|
-
currentUser.roles
|
|
5605
|
-
);
|
|
5578
|
+
await addBlockingConditionUtil(this.db, patientId, data, currentUser.uid, currentUser.roles);
|
|
5606
5579
|
}
|
|
5607
5580
|
async updateBlockingCondition(patientId, data) {
|
|
5608
5581
|
const currentUser = await this.getCurrentUser();
|
|
5609
|
-
await updateBlockingConditionUtil(
|
|
5610
|
-
this.db,
|
|
5611
|
-
patientId,
|
|
5612
|
-
data,
|
|
5613
|
-
currentUser.uid,
|
|
5614
|
-
currentUser.roles
|
|
5615
|
-
);
|
|
5582
|
+
await updateBlockingConditionUtil(this.db, patientId, data, currentUser.uid, currentUser.roles);
|
|
5616
5583
|
}
|
|
5617
5584
|
async removeBlockingCondition(patientId, conditionIndex) {
|
|
5618
5585
|
const currentUser = await this.getCurrentUser();
|
|
@@ -5627,23 +5594,11 @@ var PatientService = class extends BaseService {
|
|
|
5627
5594
|
// Metode za rad sa kontraindikacijama
|
|
5628
5595
|
async addContraindication(patientId, data) {
|
|
5629
5596
|
const currentUser = await this.getCurrentUser();
|
|
5630
|
-
await addContraindicationUtil(
|
|
5631
|
-
this.db,
|
|
5632
|
-
patientId,
|
|
5633
|
-
data,
|
|
5634
|
-
currentUser.uid,
|
|
5635
|
-
currentUser.roles
|
|
5636
|
-
);
|
|
5597
|
+
await addContraindicationUtil(this.db, patientId, data, currentUser.uid, currentUser.roles);
|
|
5637
5598
|
}
|
|
5638
5599
|
async updateContraindication(patientId, data) {
|
|
5639
5600
|
const currentUser = await this.getCurrentUser();
|
|
5640
|
-
await updateContraindicationUtil(
|
|
5641
|
-
this.db,
|
|
5642
|
-
patientId,
|
|
5643
|
-
data,
|
|
5644
|
-
currentUser.uid,
|
|
5645
|
-
currentUser.roles
|
|
5646
|
-
);
|
|
5601
|
+
await updateContraindicationUtil(this.db, patientId, data, currentUser.uid, currentUser.roles);
|
|
5647
5602
|
}
|
|
5648
5603
|
async removeContraindication(patientId, contraindicationIndex) {
|
|
5649
5604
|
const currentUser = await this.getCurrentUser();
|
|
@@ -5658,23 +5613,11 @@ var PatientService = class extends BaseService {
|
|
|
5658
5613
|
// Metode za rad sa medikacijama
|
|
5659
5614
|
async addMedication(patientId, data) {
|
|
5660
5615
|
const currentUser = await this.getCurrentUser();
|
|
5661
|
-
await addMedicationUtil(
|
|
5662
|
-
this.db,
|
|
5663
|
-
patientId,
|
|
5664
|
-
data,
|
|
5665
|
-
currentUser.uid,
|
|
5666
|
-
currentUser.roles
|
|
5667
|
-
);
|
|
5616
|
+
await addMedicationUtil(this.db, patientId, data, currentUser.uid, currentUser.roles);
|
|
5668
5617
|
}
|
|
5669
5618
|
async updateMedication(patientId, data) {
|
|
5670
5619
|
const currentUser = await this.getCurrentUser();
|
|
5671
|
-
await updateMedicationUtil(
|
|
5672
|
-
this.db,
|
|
5673
|
-
patientId,
|
|
5674
|
-
data,
|
|
5675
|
-
currentUser.uid,
|
|
5676
|
-
currentUser.roles
|
|
5677
|
-
);
|
|
5620
|
+
await updateMedicationUtil(this.db, patientId, data, currentUser.uid, currentUser.roles);
|
|
5678
5621
|
}
|
|
5679
5622
|
async removeMedication(patientId, medicationIndex) {
|
|
5680
5623
|
const currentUser = await this.getCurrentUser();
|
|
@@ -5715,9 +5658,7 @@ var PatientService = class extends BaseService {
|
|
|
5715
5658
|
if (!this.auth.currentUser) {
|
|
5716
5659
|
throw new Error("No authenticated user");
|
|
5717
5660
|
}
|
|
5718
|
-
const userDoc = await (0, import_firestore18.getDoc)(
|
|
5719
|
-
(0, import_firestore18.doc)(this.db, "users", this.auth.currentUser.uid)
|
|
5720
|
-
);
|
|
5661
|
+
const userDoc = await (0, import_firestore18.getDoc)((0, import_firestore18.doc)(this.db, "users", this.auth.currentUser.uid));
|
|
5721
5662
|
if (!userDoc.exists()) {
|
|
5722
5663
|
throw new Error("User not found");
|
|
5723
5664
|
}
|
|
@@ -5758,9 +5699,7 @@ var PatientService = class extends BaseService {
|
|
|
5758
5699
|
* @returns URL of the uploaded photo
|
|
5759
5700
|
*/
|
|
5760
5701
|
async uploadProfilePhoto(patientId, file) {
|
|
5761
|
-
console.log(
|
|
5762
|
-
`[PatientService] Uploading profile photo for patient ${patientId}`
|
|
5763
|
-
);
|
|
5702
|
+
console.log(`[PatientService] Uploading profile photo for patient ${patientId}`);
|
|
5764
5703
|
const mediaMetadata = await this.mediaService.uploadMedia(
|
|
5765
5704
|
file,
|
|
5766
5705
|
patientId,
|
|
@@ -5783,14 +5722,9 @@ var PatientService = class extends BaseService {
|
|
|
5783
5722
|
* @returns URL of the new uploaded photo
|
|
5784
5723
|
*/
|
|
5785
5724
|
async updateProfilePhoto(patientId, file) {
|
|
5786
|
-
console.log(
|
|
5787
|
-
`[PatientService] Updating profile photo for patient ${patientId}`
|
|
5788
|
-
);
|
|
5725
|
+
console.log(`[PatientService] Updating profile photo for patient ${patientId}`);
|
|
5789
5726
|
const currentUser = await this.getCurrentUser();
|
|
5790
|
-
const currentSensitiveInfo = await this.getSensitiveInfo(
|
|
5791
|
-
patientId,
|
|
5792
|
-
currentUser.uid
|
|
5793
|
-
);
|
|
5727
|
+
const currentSensitiveInfo = await this.getSensitiveInfo(patientId, currentUser.uid);
|
|
5794
5728
|
if ((currentSensitiveInfo == null ? void 0 : currentSensitiveInfo.photoUrl) && typeof currentSensitiveInfo.photoUrl === "string") {
|
|
5795
5729
|
try {
|
|
5796
5730
|
const existingMediaMetadata = await this.mediaService.getMediaMetadataByUrl(
|
|
@@ -5813,14 +5747,9 @@ var PatientService = class extends BaseService {
|
|
|
5813
5747
|
* @param patientId - ID of the patient
|
|
5814
5748
|
*/
|
|
5815
5749
|
async deleteProfilePhoto(patientId) {
|
|
5816
|
-
console.log(
|
|
5817
|
-
`[PatientService] Deleting profile photo for patient ${patientId}`
|
|
5818
|
-
);
|
|
5750
|
+
console.log(`[PatientService] Deleting profile photo for patient ${patientId}`);
|
|
5819
5751
|
const currentUser = await this.getCurrentUser();
|
|
5820
|
-
const currentSensitiveInfo = await this.getSensitiveInfo(
|
|
5821
|
-
patientId,
|
|
5822
|
-
currentUser.uid
|
|
5823
|
-
);
|
|
5752
|
+
const currentSensitiveInfo = await this.getSensitiveInfo(patientId, currentUser.uid);
|
|
5824
5753
|
if ((currentSensitiveInfo == null ? void 0 : currentSensitiveInfo.photoUrl) && typeof currentSensitiveInfo.photoUrl === "string") {
|
|
5825
5754
|
try {
|
|
5826
5755
|
const existingMediaMetadata = await this.mediaService.getMediaMetadataByUrl(
|
|
@@ -5892,10 +5821,7 @@ var PatientService = class extends BaseService {
|
|
|
5892
5821
|
* @returns {Promise<PatientProfile[]>} A promise resolving to an array of all patient profiles.
|
|
5893
5822
|
*/
|
|
5894
5823
|
async getAllPatients(options) {
|
|
5895
|
-
console.log(
|
|
5896
|
-
`[PatientService.getAllPatients] Fetching patients with options:`,
|
|
5897
|
-
options
|
|
5898
|
-
);
|
|
5824
|
+
console.log(`[PatientService.getAllPatients] Fetching patients with options:`, options);
|
|
5899
5825
|
return getAllPatientsUtil(this.db, options);
|
|
5900
5826
|
}
|
|
5901
5827
|
/**
|
|
@@ -5926,11 +5852,7 @@ var PatientService = class extends BaseService {
|
|
|
5926
5852
|
console.log(
|
|
5927
5853
|
`[PatientService.getPatientsByPractitionerWithDetails] Fetching detailed patient profiles for practitioner: ${practitionerId}`
|
|
5928
5854
|
);
|
|
5929
|
-
return getPatientsByPractitionerWithDetailsUtil(
|
|
5930
|
-
this.db,
|
|
5931
|
-
practitionerId,
|
|
5932
|
-
options
|
|
5933
|
-
);
|
|
5855
|
+
return getPatientsByPractitionerWithDetailsUtil(this.db, practitionerId, options);
|
|
5934
5856
|
}
|
|
5935
5857
|
/**
|
|
5936
5858
|
* Gets all patients associated with a specific clinic.
|
|
@@ -5942,9 +5864,7 @@ var PatientService = class extends BaseService {
|
|
|
5942
5864
|
* @returns {Promise<PatientProfile[]>} A promise resolving to an array of patient profiles
|
|
5943
5865
|
*/
|
|
5944
5866
|
async getPatientsByClinic(clinicId, options) {
|
|
5945
|
-
console.log(
|
|
5946
|
-
`[PatientService.getPatientsByClinic] Fetching patients for clinic: ${clinicId}`
|
|
5947
|
-
);
|
|
5867
|
+
console.log(`[PatientService.getPatientsByClinic] Fetching patients for clinic: ${clinicId}`);
|
|
5948
5868
|
return getPatientsByClinicUtil(this.db, clinicId, options);
|
|
5949
5869
|
}
|
|
5950
5870
|
/**
|
|
@@ -7639,11 +7559,15 @@ var UserService = class extends BaseService {
|
|
|
7639
7559
|
if ((await this.getUserById(userId)).patientProfile || patientProfile2.userRef) {
|
|
7640
7560
|
throw new Error("User already has a patient profile.");
|
|
7641
7561
|
}
|
|
7642
|
-
const sensitiveInfo = await patientService.
|
|
7562
|
+
const sensitiveInfo = await patientService.claimPatientSensitiveInfo(
|
|
7563
|
+
patientProfile2.id,
|
|
7564
|
+
userId
|
|
7565
|
+
);
|
|
7643
7566
|
const fullDisplayName = sensitiveInfo ? `${sensitiveInfo.firstName} ${sensitiveInfo.lastName}` : patientProfile2.displayName;
|
|
7644
7567
|
await patientService.updatePatientProfile(patientProfile2.id, {
|
|
7645
7568
|
userRef: userId,
|
|
7646
7569
|
isManual: false,
|
|
7570
|
+
isVerified: true,
|
|
7647
7571
|
displayName: fullDisplayName
|
|
7648
7572
|
});
|
|
7649
7573
|
await patientService.markPatientTokenAsUsed(token.id, token.patientId, userId);
|