@blackcode_sa/metaestetics-api 1.5.31 → 1.5.33
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 +337 -1
- package/dist/admin/index.d.ts +337 -1
- package/dist/admin/index.js +597 -14
- package/dist/admin/index.mjs +595 -14
- package/dist/backoffice/index.d.mts +2 -0
- package/dist/backoffice/index.d.ts +2 -0
- package/dist/index.d.mts +102 -1
- package/dist/index.d.ts +102 -1
- package/dist/index.js +945 -267
- package/dist/index.mjs +968 -283
- package/package.json +1 -1
- package/src/admin/booking/booking.admin.ts +234 -0
- package/src/admin/booking/booking.calculator.ts +686 -0
- package/src/admin/booking/booking.types.ts +56 -0
- package/src/admin/booking/index.ts +3 -0
- package/src/admin/index.ts +3 -0
- package/src/index.ts +5 -0
- package/src/services/appointment/appointment.service.ts +603 -0
- package/src/services/appointment/index.ts +2 -0
- package/src/services/appointment/utils/appointment.utils.ts +590 -0
- package/src/services/clinic/clinic.service.ts +6 -0
- package/src/services/clinic/utils/filter.utils.ts +27 -1
- package/src/services/procedure/procedure.service.ts +43 -5
- package/src/types/appointment/index.ts +161 -0
- package/src/types/procedure/index.ts +2 -0
- package/src/validations/appointment.schema.ts +125 -0
package/dist/index.mjs
CHANGED
|
@@ -1349,9 +1349,9 @@ var addAllergyUtil = async (db, patientId, data, userRef) => {
|
|
|
1349
1349
|
var updateAllergyUtil = async (db, patientId, data, userRef) => {
|
|
1350
1350
|
const validatedData = updateAllergySchema.parse(data);
|
|
1351
1351
|
const { allergyIndex, ...updateData } = validatedData;
|
|
1352
|
-
const
|
|
1353
|
-
if (!
|
|
1354
|
-
const medicalInfo =
|
|
1352
|
+
const doc29 = await getDoc3(getMedicalInfoDocRef(db, patientId));
|
|
1353
|
+
if (!doc29.exists()) throw new Error("Medical info not found");
|
|
1354
|
+
const medicalInfo = doc29.data();
|
|
1355
1355
|
if (allergyIndex >= medicalInfo.allergies.length) {
|
|
1356
1356
|
throw new Error("Invalid allergy index");
|
|
1357
1357
|
}
|
|
@@ -1367,9 +1367,9 @@ var updateAllergyUtil = async (db, patientId, data, userRef) => {
|
|
|
1367
1367
|
});
|
|
1368
1368
|
};
|
|
1369
1369
|
var removeAllergyUtil = async (db, patientId, allergyIndex, userRef) => {
|
|
1370
|
-
const
|
|
1371
|
-
if (!
|
|
1372
|
-
const medicalInfo =
|
|
1370
|
+
const doc29 = await getDoc3(getMedicalInfoDocRef(db, patientId));
|
|
1371
|
+
if (!doc29.exists()) throw new Error("Medical info not found");
|
|
1372
|
+
const medicalInfo = doc29.data();
|
|
1373
1373
|
if (allergyIndex >= medicalInfo.allergies.length) {
|
|
1374
1374
|
throw new Error("Invalid allergy index");
|
|
1375
1375
|
}
|
|
@@ -1394,9 +1394,9 @@ var addBlockingConditionUtil = async (db, patientId, data, userRef) => {
|
|
|
1394
1394
|
var updateBlockingConditionUtil = async (db, patientId, data, userRef) => {
|
|
1395
1395
|
const validatedData = updateBlockingConditionSchema.parse(data);
|
|
1396
1396
|
const { conditionIndex, ...updateData } = validatedData;
|
|
1397
|
-
const
|
|
1398
|
-
if (!
|
|
1399
|
-
const medicalInfo =
|
|
1397
|
+
const doc29 = await getDoc3(getMedicalInfoDocRef(db, patientId));
|
|
1398
|
+
if (!doc29.exists()) throw new Error("Medical info not found");
|
|
1399
|
+
const medicalInfo = doc29.data();
|
|
1400
1400
|
if (conditionIndex >= medicalInfo.blockingConditions.length) {
|
|
1401
1401
|
throw new Error("Invalid blocking condition index");
|
|
1402
1402
|
}
|
|
@@ -1412,9 +1412,9 @@ var updateBlockingConditionUtil = async (db, patientId, data, userRef) => {
|
|
|
1412
1412
|
});
|
|
1413
1413
|
};
|
|
1414
1414
|
var removeBlockingConditionUtil = async (db, patientId, conditionIndex, userRef) => {
|
|
1415
|
-
const
|
|
1416
|
-
if (!
|
|
1417
|
-
const medicalInfo =
|
|
1415
|
+
const doc29 = await getDoc3(getMedicalInfoDocRef(db, patientId));
|
|
1416
|
+
if (!doc29.exists()) throw new Error("Medical info not found");
|
|
1417
|
+
const medicalInfo = doc29.data();
|
|
1418
1418
|
if (conditionIndex >= medicalInfo.blockingConditions.length) {
|
|
1419
1419
|
throw new Error("Invalid blocking condition index");
|
|
1420
1420
|
}
|
|
@@ -1439,9 +1439,9 @@ var addContraindicationUtil = async (db, patientId, data, userRef) => {
|
|
|
1439
1439
|
var updateContraindicationUtil = async (db, patientId, data, userRef) => {
|
|
1440
1440
|
const validatedData = updateContraindicationSchema.parse(data);
|
|
1441
1441
|
const { contraindicationIndex, ...updateData } = validatedData;
|
|
1442
|
-
const
|
|
1443
|
-
if (!
|
|
1444
|
-
const medicalInfo =
|
|
1442
|
+
const doc29 = await getDoc3(getMedicalInfoDocRef(db, patientId));
|
|
1443
|
+
if (!doc29.exists()) throw new Error("Medical info not found");
|
|
1444
|
+
const medicalInfo = doc29.data();
|
|
1445
1445
|
if (contraindicationIndex >= medicalInfo.contraindications.length) {
|
|
1446
1446
|
throw new Error("Invalid contraindication index");
|
|
1447
1447
|
}
|
|
@@ -1457,9 +1457,9 @@ var updateContraindicationUtil = async (db, patientId, data, userRef) => {
|
|
|
1457
1457
|
});
|
|
1458
1458
|
};
|
|
1459
1459
|
var removeContraindicationUtil = async (db, patientId, contraindicationIndex, userRef) => {
|
|
1460
|
-
const
|
|
1461
|
-
if (!
|
|
1462
|
-
const medicalInfo =
|
|
1460
|
+
const doc29 = await getDoc3(getMedicalInfoDocRef(db, patientId));
|
|
1461
|
+
if (!doc29.exists()) throw new Error("Medical info not found");
|
|
1462
|
+
const medicalInfo = doc29.data();
|
|
1463
1463
|
if (contraindicationIndex >= medicalInfo.contraindications.length) {
|
|
1464
1464
|
throw new Error("Invalid contraindication index");
|
|
1465
1465
|
}
|
|
@@ -1484,9 +1484,9 @@ var addMedicationUtil = async (db, patientId, data, userRef) => {
|
|
|
1484
1484
|
var updateMedicationUtil = async (db, patientId, data, userRef) => {
|
|
1485
1485
|
const validatedData = updateMedicationSchema.parse(data);
|
|
1486
1486
|
const { medicationIndex, ...updateData } = validatedData;
|
|
1487
|
-
const
|
|
1488
|
-
if (!
|
|
1489
|
-
const medicalInfo =
|
|
1487
|
+
const doc29 = await getDoc3(getMedicalInfoDocRef(db, patientId));
|
|
1488
|
+
if (!doc29.exists()) throw new Error("Medical info not found");
|
|
1489
|
+
const medicalInfo = doc29.data();
|
|
1490
1490
|
if (medicationIndex >= medicalInfo.currentMedications.length) {
|
|
1491
1491
|
throw new Error("Invalid medication index");
|
|
1492
1492
|
}
|
|
@@ -1502,9 +1502,9 @@ var updateMedicationUtil = async (db, patientId, data, userRef) => {
|
|
|
1502
1502
|
});
|
|
1503
1503
|
};
|
|
1504
1504
|
var removeMedicationUtil = async (db, patientId, medicationIndex, userRef) => {
|
|
1505
|
-
const
|
|
1506
|
-
if (!
|
|
1507
|
-
const medicalInfo =
|
|
1505
|
+
const doc29 = await getDoc3(getMedicalInfoDocRef(db, patientId));
|
|
1506
|
+
if (!doc29.exists()) throw new Error("Medical info not found");
|
|
1507
|
+
const medicalInfo = doc29.data();
|
|
1508
1508
|
if (medicationIndex >= medicalInfo.currentMedications.length) {
|
|
1509
1509
|
throw new Error("Invalid medication index");
|
|
1510
1510
|
}
|
|
@@ -1782,7 +1782,7 @@ var searchPatientsUtil = async (db, params, requester) => {
|
|
|
1782
1782
|
try {
|
|
1783
1783
|
const finalQuery = query2(patientsCollectionRef, ...constraints);
|
|
1784
1784
|
const querySnapshot = await getDocs2(finalQuery);
|
|
1785
|
-
const patients = querySnapshot.docs.map((
|
|
1785
|
+
const patients = querySnapshot.docs.map((doc29) => doc29.data());
|
|
1786
1786
|
console.log(`[searchPatientsUtil] Found ${patients.length} patients matching criteria.`);
|
|
1787
1787
|
return patients;
|
|
1788
1788
|
} catch (error) {
|
|
@@ -1806,8 +1806,8 @@ var getAllPatientsUtil = async (db, options) => {
|
|
|
1806
1806
|
}
|
|
1807
1807
|
const patientsSnapshot = await getDocs2(q);
|
|
1808
1808
|
const patients = [];
|
|
1809
|
-
patientsSnapshot.forEach((
|
|
1810
|
-
patients.push(
|
|
1809
|
+
patientsSnapshot.forEach((doc29) => {
|
|
1810
|
+
patients.push(doc29.data());
|
|
1811
1811
|
});
|
|
1812
1812
|
console.log(`[getAllPatientsUtil] Found ${patients.length} patients`);
|
|
1813
1813
|
return patients;
|
|
@@ -3165,7 +3165,7 @@ async function getClinicAdminsByGroup(db, clinicGroupId) {
|
|
|
3165
3165
|
where3("clinicGroupId", "==", clinicGroupId)
|
|
3166
3166
|
);
|
|
3167
3167
|
const querySnapshot = await getDocs3(q);
|
|
3168
|
-
return querySnapshot.docs.map((
|
|
3168
|
+
return querySnapshot.docs.map((doc29) => doc29.data());
|
|
3169
3169
|
}
|
|
3170
3170
|
async function updateClinicAdmin(db, adminId, data) {
|
|
3171
3171
|
const admin = await getClinicAdmin(db, adminId);
|
|
@@ -3687,7 +3687,7 @@ var PractitionerService = class extends BaseService {
|
|
|
3687
3687
|
where4("expiresAt", ">", Timestamp8.now())
|
|
3688
3688
|
);
|
|
3689
3689
|
const querySnapshot = await getDocs4(q);
|
|
3690
|
-
return querySnapshot.docs.map((
|
|
3690
|
+
return querySnapshot.docs.map((doc29) => doc29.data());
|
|
3691
3691
|
}
|
|
3692
3692
|
/**
|
|
3693
3693
|
* Gets a token by its string value and validates it
|
|
@@ -3770,7 +3770,7 @@ var PractitionerService = class extends BaseService {
|
|
|
3770
3770
|
where4("status", "==", "active" /* ACTIVE */)
|
|
3771
3771
|
);
|
|
3772
3772
|
const querySnapshot = await getDocs4(q);
|
|
3773
|
-
return querySnapshot.docs.map((
|
|
3773
|
+
return querySnapshot.docs.map((doc29) => doc29.data());
|
|
3774
3774
|
}
|
|
3775
3775
|
/**
|
|
3776
3776
|
* Dohvata sve zdravstvene radnike za određenu kliniku
|
|
@@ -3782,7 +3782,7 @@ var PractitionerService = class extends BaseService {
|
|
|
3782
3782
|
where4("isActive", "==", true)
|
|
3783
3783
|
);
|
|
3784
3784
|
const querySnapshot = await getDocs4(q);
|
|
3785
|
-
return querySnapshot.docs.map((
|
|
3785
|
+
return querySnapshot.docs.map((doc29) => doc29.data());
|
|
3786
3786
|
}
|
|
3787
3787
|
/**
|
|
3788
3788
|
* Dohvata sve draft zdravstvene radnike za određenu kliniku sa statusom DRAFT
|
|
@@ -3794,7 +3794,7 @@ var PractitionerService = class extends BaseService {
|
|
|
3794
3794
|
where4("status", "==", "draft" /* DRAFT */)
|
|
3795
3795
|
);
|
|
3796
3796
|
const querySnapshot = await getDocs4(q);
|
|
3797
|
-
return querySnapshot.docs.map((
|
|
3797
|
+
return querySnapshot.docs.map((doc29) => doc29.data());
|
|
3798
3798
|
}
|
|
3799
3799
|
/**
|
|
3800
3800
|
* Updates a practitioner
|
|
@@ -3976,7 +3976,7 @@ var PractitionerService = class extends BaseService {
|
|
|
3976
3976
|
);
|
|
3977
3977
|
const querySnapshot = await getDocs4(q);
|
|
3978
3978
|
const practitioners = querySnapshot.docs.map(
|
|
3979
|
-
(
|
|
3979
|
+
(doc29) => doc29.data()
|
|
3980
3980
|
);
|
|
3981
3981
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
3982
3982
|
return {
|
|
@@ -4047,8 +4047,8 @@ var PractitionerService = class extends BaseService {
|
|
|
4047
4047
|
console.log(
|
|
4048
4048
|
`[PRACTITIONER_SERVICE] Found ${querySnapshot.docs.length} practitioners with base query`
|
|
4049
4049
|
);
|
|
4050
|
-
let practitioners = querySnapshot.docs.map((
|
|
4051
|
-
return { ...
|
|
4050
|
+
let practitioners = querySnapshot.docs.map((doc29) => {
|
|
4051
|
+
return { ...doc29.data(), id: doc29.id };
|
|
4052
4052
|
});
|
|
4053
4053
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
4054
4054
|
if (filters.nameSearch && filters.nameSearch.trim() !== "") {
|
|
@@ -4302,7 +4302,7 @@ var UserService = class extends BaseService {
|
|
|
4302
4302
|
];
|
|
4303
4303
|
const q = query5(collection5(this.db, USERS_COLLECTION), ...constraints);
|
|
4304
4304
|
const querySnapshot = await getDocs5(q);
|
|
4305
|
-
const users = querySnapshot.docs.map((
|
|
4305
|
+
const users = querySnapshot.docs.map((doc29) => doc29.data());
|
|
4306
4306
|
return Promise.all(users.map((userData) => userSchema.parse(userData)));
|
|
4307
4307
|
}
|
|
4308
4308
|
/**
|
|
@@ -4682,7 +4682,7 @@ async function getAllActiveGroups(db) {
|
|
|
4682
4682
|
where6("isActive", "==", true)
|
|
4683
4683
|
);
|
|
4684
4684
|
const querySnapshot = await getDocs6(q);
|
|
4685
|
-
return querySnapshot.docs.map((
|
|
4685
|
+
return querySnapshot.docs.map((doc29) => doc29.data());
|
|
4686
4686
|
}
|
|
4687
4687
|
async function updateClinicGroup(db, groupId, data, app) {
|
|
4688
4688
|
console.log("[CLINIC_GROUP] Updating clinic group", { groupId });
|
|
@@ -5106,7 +5106,7 @@ async function getClinicsByGroup(db, groupId) {
|
|
|
5106
5106
|
where7("isActive", "==", true)
|
|
5107
5107
|
);
|
|
5108
5108
|
const querySnapshot = await getDocs7(q);
|
|
5109
|
-
return querySnapshot.docs.map((
|
|
5109
|
+
return querySnapshot.docs.map((doc29) => doc29.data());
|
|
5110
5110
|
}
|
|
5111
5111
|
async function updateClinic(db, clinicId, data, adminId, clinicAdminService, app) {
|
|
5112
5112
|
console.log("[CLINIC] Starting clinic update", { clinicId, adminId });
|
|
@@ -5300,7 +5300,7 @@ async function getClinicsByAdmin(db, adminId, options = {}, clinicAdminService,
|
|
|
5300
5300
|
}
|
|
5301
5301
|
const q = query7(collection7(db, CLINICS_COLLECTION), ...constraints);
|
|
5302
5302
|
const querySnapshot = await getDocs7(q);
|
|
5303
|
-
return querySnapshot.docs.map((
|
|
5303
|
+
return querySnapshot.docs.map((doc29) => doc29.data());
|
|
5304
5304
|
}
|
|
5305
5305
|
async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGroupService) {
|
|
5306
5306
|
return getClinicsByAdmin(
|
|
@@ -5345,11 +5345,11 @@ async function getAllClinics(db, pagination, lastDoc) {
|
|
|
5345
5345
|
}
|
|
5346
5346
|
const clinicsSnapshot = await getDocs7(clinicsQuery);
|
|
5347
5347
|
const lastVisible = clinicsSnapshot.docs[clinicsSnapshot.docs.length - 1];
|
|
5348
|
-
const clinics = clinicsSnapshot.docs.map((
|
|
5349
|
-
const data =
|
|
5348
|
+
const clinics = clinicsSnapshot.docs.map((doc29) => {
|
|
5349
|
+
const data = doc29.data();
|
|
5350
5350
|
return {
|
|
5351
5351
|
...data,
|
|
5352
|
-
id:
|
|
5352
|
+
id: doc29.id
|
|
5353
5353
|
};
|
|
5354
5354
|
});
|
|
5355
5355
|
return {
|
|
@@ -5376,8 +5376,8 @@ async function getAllClinicsInRange(db, center, rangeInKm, pagination, lastDoc)
|
|
|
5376
5376
|
];
|
|
5377
5377
|
const q = query7(collection7(db, CLINICS_COLLECTION), ...constraints);
|
|
5378
5378
|
const querySnapshot = await getDocs7(q);
|
|
5379
|
-
for (const
|
|
5380
|
-
const clinic =
|
|
5379
|
+
for (const doc29 of querySnapshot.docs) {
|
|
5380
|
+
const clinic = doc29.data();
|
|
5381
5381
|
const distance = distanceBetween2(
|
|
5382
5382
|
[center.latitude, center.longitude],
|
|
5383
5383
|
[clinic.location.latitude, clinic.location.longitude]
|
|
@@ -5499,8 +5499,8 @@ async function findClinicsInRadius(db, center, radiusInKm, filters) {
|
|
|
5499
5499
|
}
|
|
5500
5500
|
const q = query8(collection8(db, CLINICS_COLLECTION), ...constraints);
|
|
5501
5501
|
const querySnapshot = await getDocs8(q);
|
|
5502
|
-
for (const
|
|
5503
|
-
const clinic =
|
|
5502
|
+
for (const doc29 of querySnapshot.docs) {
|
|
5503
|
+
const clinic = doc29.data();
|
|
5504
5504
|
const distance = distanceBetween3(
|
|
5505
5505
|
[center.latitude, center.longitude],
|
|
5506
5506
|
[clinic.location.latitude, clinic.location.longitude]
|
|
@@ -5532,7 +5532,6 @@ import {
|
|
|
5532
5532
|
getDocs as getDocs9,
|
|
5533
5533
|
startAfter as startAfter4,
|
|
5534
5534
|
limit as limit4,
|
|
5535
|
-
documentId,
|
|
5536
5535
|
orderBy as orderBy2
|
|
5537
5536
|
} from "firebase/firestore";
|
|
5538
5537
|
import { geohashQueryBounds as geohashQueryBounds3, distanceBetween as distanceBetween4 } from "geofire-common";
|
|
@@ -5574,7 +5573,7 @@ async function getClinicsByFilters(db, filters) {
|
|
|
5574
5573
|
} else if (filters.pagination && filters.pagination > 0) {
|
|
5575
5574
|
constraints.push(limit4(filters.pagination));
|
|
5576
5575
|
}
|
|
5577
|
-
constraints.push(orderBy2(
|
|
5576
|
+
constraints.push(orderBy2("location.geohash"));
|
|
5578
5577
|
let clinicsResult = [];
|
|
5579
5578
|
let lastVisibleDoc = null;
|
|
5580
5579
|
if (isGeoQuery) {
|
|
@@ -5597,8 +5596,8 @@ async function getClinicsByFilters(db, filters) {
|
|
|
5597
5596
|
console.log(
|
|
5598
5597
|
`[FILTER_UTILS] Found ${querySnapshot.docs.length} clinics in geo bound`
|
|
5599
5598
|
);
|
|
5600
|
-
for (const
|
|
5601
|
-
const clinic = { ...
|
|
5599
|
+
for (const doc29 of querySnapshot.docs) {
|
|
5600
|
+
const clinic = { ...doc29.data(), id: doc29.id };
|
|
5602
5601
|
const distance = distanceBetween4(
|
|
5603
5602
|
[center.latitude, center.longitude],
|
|
5604
5603
|
[clinic.location.latitude, clinic.location.longitude]
|
|
@@ -5654,10 +5653,29 @@ async function getClinicsByFilters(db, filters) {
|
|
|
5654
5653
|
console.log(
|
|
5655
5654
|
`[FILTER_UTILS] Found ${querySnapshot.docs.length} clinics with regular query`
|
|
5656
5655
|
);
|
|
5657
|
-
const clinics = querySnapshot.docs.map((
|
|
5658
|
-
return { ...
|
|
5656
|
+
const clinics = querySnapshot.docs.map((doc29) => {
|
|
5657
|
+
return { ...doc29.data(), id: doc29.id };
|
|
5659
5658
|
});
|
|
5660
5659
|
let filteredClinics = clinics;
|
|
5660
|
+
if (filters.center) {
|
|
5661
|
+
const center = filters.center;
|
|
5662
|
+
const clinicsWithDistance = [];
|
|
5663
|
+
filteredClinics.forEach((clinic) => {
|
|
5664
|
+
const distance = distanceBetween4(
|
|
5665
|
+
[center.latitude, center.longitude],
|
|
5666
|
+
[clinic.location.latitude, clinic.location.longitude]
|
|
5667
|
+
);
|
|
5668
|
+
clinicsWithDistance.push({
|
|
5669
|
+
...clinic,
|
|
5670
|
+
distance: distance / 1e3
|
|
5671
|
+
// Convert to kilometers
|
|
5672
|
+
});
|
|
5673
|
+
});
|
|
5674
|
+
filteredClinics = clinicsWithDistance;
|
|
5675
|
+
filteredClinics.sort(
|
|
5676
|
+
(a, b) => a.distance - b.distance
|
|
5677
|
+
);
|
|
5678
|
+
}
|
|
5661
5679
|
if (filters.tags && filters.tags.length > 1) {
|
|
5662
5680
|
filteredClinics = filteredClinics.filter((clinic) => {
|
|
5663
5681
|
return filters.tags.every((tag) => clinic.tags.includes(tag));
|
|
@@ -5946,6 +5964,12 @@ var ClinicService = class extends BaseService {
|
|
|
5946
5964
|
lastDoc
|
|
5947
5965
|
);
|
|
5948
5966
|
}
|
|
5967
|
+
/**
|
|
5968
|
+
* Get clinics based on multiple filtering criteria
|
|
5969
|
+
*
|
|
5970
|
+
* @param filters - Various filters to apply
|
|
5971
|
+
* @returns Filtered clinics and the last document for pagination
|
|
5972
|
+
*/
|
|
5949
5973
|
async getClinicsByFilters(filters) {
|
|
5950
5974
|
return getClinicsByFilters(this.db, filters);
|
|
5951
5975
|
}
|
|
@@ -6693,9 +6717,9 @@ var NotificationService = class extends BaseService {
|
|
|
6693
6717
|
orderBy3("notificationTime", "desc")
|
|
6694
6718
|
);
|
|
6695
6719
|
const querySnapshot = await getDocs12(q);
|
|
6696
|
-
return querySnapshot.docs.map((
|
|
6697
|
-
id:
|
|
6698
|
-
...
|
|
6720
|
+
return querySnapshot.docs.map((doc29) => ({
|
|
6721
|
+
id: doc29.id,
|
|
6722
|
+
...doc29.data()
|
|
6699
6723
|
}));
|
|
6700
6724
|
}
|
|
6701
6725
|
/**
|
|
@@ -6709,9 +6733,9 @@ var NotificationService = class extends BaseService {
|
|
|
6709
6733
|
orderBy3("notificationTime", "desc")
|
|
6710
6734
|
);
|
|
6711
6735
|
const querySnapshot = await getDocs12(q);
|
|
6712
|
-
return querySnapshot.docs.map((
|
|
6713
|
-
id:
|
|
6714
|
-
...
|
|
6736
|
+
return querySnapshot.docs.map((doc29) => ({
|
|
6737
|
+
id: doc29.id,
|
|
6738
|
+
...doc29.data()
|
|
6715
6739
|
}));
|
|
6716
6740
|
}
|
|
6717
6741
|
/**
|
|
@@ -6783,9 +6807,9 @@ var NotificationService = class extends BaseService {
|
|
|
6783
6807
|
orderBy3("notificationTime", "desc")
|
|
6784
6808
|
);
|
|
6785
6809
|
const querySnapshot = await getDocs12(q);
|
|
6786
|
-
return querySnapshot.docs.map((
|
|
6787
|
-
id:
|
|
6788
|
-
...
|
|
6810
|
+
return querySnapshot.docs.map((doc29) => ({
|
|
6811
|
+
id: doc29.id,
|
|
6812
|
+
...doc29.data()
|
|
6789
6813
|
}));
|
|
6790
6814
|
}
|
|
6791
6815
|
/**
|
|
@@ -6798,9 +6822,9 @@ var NotificationService = class extends BaseService {
|
|
|
6798
6822
|
orderBy3("notificationTime", "desc")
|
|
6799
6823
|
);
|
|
6800
6824
|
const querySnapshot = await getDocs12(q);
|
|
6801
|
-
return querySnapshot.docs.map((
|
|
6802
|
-
id:
|
|
6803
|
-
...
|
|
6825
|
+
return querySnapshot.docs.map((doc29) => ({
|
|
6826
|
+
id: doc29.id,
|
|
6827
|
+
...doc29.data()
|
|
6804
6828
|
}));
|
|
6805
6829
|
}
|
|
6806
6830
|
};
|
|
@@ -6819,8 +6843,7 @@ import {
|
|
|
6819
6843
|
serverTimestamp as serverTimestamp14,
|
|
6820
6844
|
orderBy as orderBy4,
|
|
6821
6845
|
limit as limit5,
|
|
6822
|
-
startAfter as startAfter5
|
|
6823
|
-
documentId as documentId2
|
|
6846
|
+
startAfter as startAfter5
|
|
6824
6847
|
} from "firebase/firestore";
|
|
6825
6848
|
|
|
6826
6849
|
// src/types/procedure/index.ts
|
|
@@ -7032,7 +7055,7 @@ var ProcedureService = class extends BaseService {
|
|
|
7032
7055
|
where13("isActive", "==", true)
|
|
7033
7056
|
);
|
|
7034
7057
|
const snapshot = await getDocs13(q);
|
|
7035
|
-
return snapshot.docs.map((
|
|
7058
|
+
return snapshot.docs.map((doc29) => doc29.data());
|
|
7036
7059
|
}
|
|
7037
7060
|
/**
|
|
7038
7061
|
* Gets all procedures for a practitioner
|
|
@@ -7046,7 +7069,7 @@ var ProcedureService = class extends BaseService {
|
|
|
7046
7069
|
where13("isActive", "==", true)
|
|
7047
7070
|
);
|
|
7048
7071
|
const snapshot = await getDocs13(q);
|
|
7049
|
-
return snapshot.docs.map((
|
|
7072
|
+
return snapshot.docs.map((doc29) => doc29.data());
|
|
7050
7073
|
}
|
|
7051
7074
|
/**
|
|
7052
7075
|
* Updates a procedure
|
|
@@ -7250,11 +7273,11 @@ var ProcedureService = class extends BaseService {
|
|
|
7250
7273
|
}
|
|
7251
7274
|
const proceduresSnapshot = await getDocs13(proceduresQuery);
|
|
7252
7275
|
const lastVisible = proceduresSnapshot.docs[proceduresSnapshot.docs.length - 1];
|
|
7253
|
-
const procedures = proceduresSnapshot.docs.map((
|
|
7254
|
-
const data =
|
|
7276
|
+
const procedures = proceduresSnapshot.docs.map((doc29) => {
|
|
7277
|
+
const data = doc29.data();
|
|
7255
7278
|
return {
|
|
7256
7279
|
...data,
|
|
7257
|
-
id:
|
|
7280
|
+
id: doc29.id
|
|
7258
7281
|
// Ensure ID is present
|
|
7259
7282
|
};
|
|
7260
7283
|
});
|
|
@@ -7304,7 +7327,7 @@ var ProcedureService = class extends BaseService {
|
|
|
7304
7327
|
if (filters.procedureFamily) {
|
|
7305
7328
|
constraints.push(where13("family", "==", filters.procedureFamily));
|
|
7306
7329
|
}
|
|
7307
|
-
constraints.push(orderBy4(
|
|
7330
|
+
constraints.push(orderBy4("clinicInfo.location.geohash"));
|
|
7308
7331
|
if (filters.pagination && filters.pagination > 0 && filters.lastDoc) {
|
|
7309
7332
|
constraints.push(startAfter5(filters.lastDoc));
|
|
7310
7333
|
constraints.push(limit5(filters.pagination));
|
|
@@ -7336,8 +7359,8 @@ var ProcedureService = class extends BaseService {
|
|
|
7336
7359
|
console.log(
|
|
7337
7360
|
`[PROCEDURE_SERVICE] Found ${querySnapshot.docs.length} procedures in geo bound`
|
|
7338
7361
|
);
|
|
7339
|
-
for (const
|
|
7340
|
-
const procedure = { ...
|
|
7362
|
+
for (const doc29 of querySnapshot.docs) {
|
|
7363
|
+
const procedure = { ...doc29.data(), id: doc29.id };
|
|
7341
7364
|
const distance = distanceBetween6(
|
|
7342
7365
|
[center.latitude, center.longitude],
|
|
7343
7366
|
[
|
|
@@ -7388,12 +7411,41 @@ var ProcedureService = class extends BaseService {
|
|
|
7388
7411
|
console.log(
|
|
7389
7412
|
`[PROCEDURE_SERVICE] Found ${querySnapshot.docs.length} procedures with regular query`
|
|
7390
7413
|
);
|
|
7391
|
-
const procedures = querySnapshot.docs.map((
|
|
7392
|
-
return { ...
|
|
7414
|
+
const procedures = querySnapshot.docs.map((doc29) => {
|
|
7415
|
+
return { ...doc29.data(), id: doc29.id };
|
|
7393
7416
|
});
|
|
7394
|
-
|
|
7417
|
+
if (filters.location) {
|
|
7418
|
+
const center = filters.location;
|
|
7419
|
+
const proceduresWithDistance = [];
|
|
7420
|
+
procedures.forEach((procedure) => {
|
|
7421
|
+
const distance = distanceBetween6(
|
|
7422
|
+
[center.latitude, center.longitude],
|
|
7423
|
+
[
|
|
7424
|
+
procedure.clinicInfo.location.latitude,
|
|
7425
|
+
procedure.clinicInfo.location.longitude
|
|
7426
|
+
]
|
|
7427
|
+
);
|
|
7428
|
+
proceduresWithDistance.push({
|
|
7429
|
+
...procedure,
|
|
7430
|
+
distance: distance / 1e3
|
|
7431
|
+
// Convert to kilometers
|
|
7432
|
+
});
|
|
7433
|
+
});
|
|
7434
|
+
let filteredProcedures = proceduresWithDistance;
|
|
7435
|
+
filteredProcedures = this.applyInMemoryFilters(
|
|
7436
|
+
filteredProcedures,
|
|
7437
|
+
filters
|
|
7438
|
+
);
|
|
7439
|
+
filteredProcedures.sort((a, b) => a.distance - b.distance);
|
|
7440
|
+
proceduresResult = filteredProcedures;
|
|
7441
|
+
} else {
|
|
7442
|
+
let filteredProcedures = this.applyInMemoryFilters(
|
|
7443
|
+
procedures,
|
|
7444
|
+
filters
|
|
7445
|
+
);
|
|
7446
|
+
proceduresResult = filteredProcedures;
|
|
7447
|
+
}
|
|
7395
7448
|
lastVisibleDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
7396
|
-
proceduresResult = filteredProcedures;
|
|
7397
7449
|
}
|
|
7398
7450
|
return {
|
|
7399
7451
|
procedures: proceduresResult,
|
|
@@ -7591,9 +7643,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
7591
7643
|
const querySnapshot = await getDocs14(q);
|
|
7592
7644
|
const templates = [];
|
|
7593
7645
|
let lastVisible = null;
|
|
7594
|
-
querySnapshot.forEach((
|
|
7595
|
-
templates.push(
|
|
7596
|
-
lastVisible =
|
|
7646
|
+
querySnapshot.forEach((doc29) => {
|
|
7647
|
+
templates.push(doc29.data());
|
|
7648
|
+
lastVisible = doc29;
|
|
7597
7649
|
});
|
|
7598
7650
|
return {
|
|
7599
7651
|
templates,
|
|
@@ -7621,9 +7673,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
7621
7673
|
const querySnapshot = await getDocs14(q);
|
|
7622
7674
|
const templates = [];
|
|
7623
7675
|
let lastVisible = null;
|
|
7624
|
-
querySnapshot.forEach((
|
|
7625
|
-
templates.push(
|
|
7626
|
-
lastVisible =
|
|
7676
|
+
querySnapshot.forEach((doc29) => {
|
|
7677
|
+
templates.push(doc29.data());
|
|
7678
|
+
lastVisible = doc29;
|
|
7627
7679
|
});
|
|
7628
7680
|
return {
|
|
7629
7681
|
templates,
|
|
@@ -7650,9 +7702,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
7650
7702
|
const querySnapshot = await getDocs14(q);
|
|
7651
7703
|
const templates = [];
|
|
7652
7704
|
let lastVisible = null;
|
|
7653
|
-
querySnapshot.forEach((
|
|
7654
|
-
templates.push(
|
|
7655
|
-
lastVisible =
|
|
7705
|
+
querySnapshot.forEach((doc29) => {
|
|
7706
|
+
templates.push(doc29.data());
|
|
7707
|
+
lastVisible = doc29;
|
|
7656
7708
|
});
|
|
7657
7709
|
return {
|
|
7658
7710
|
templates,
|
|
@@ -7777,9 +7829,9 @@ var FilledDocumentService = class extends BaseService {
|
|
|
7777
7829
|
const querySnapshot = await getDocs15(q);
|
|
7778
7830
|
const documents = [];
|
|
7779
7831
|
let lastVisible = null;
|
|
7780
|
-
querySnapshot.forEach((
|
|
7781
|
-
documents.push(
|
|
7782
|
-
lastVisible =
|
|
7832
|
+
querySnapshot.forEach((doc29) => {
|
|
7833
|
+
documents.push(doc29.data());
|
|
7834
|
+
lastVisible = doc29;
|
|
7783
7835
|
});
|
|
7784
7836
|
return {
|
|
7785
7837
|
documents,
|
|
@@ -7806,9 +7858,9 @@ var FilledDocumentService = class extends BaseService {
|
|
|
7806
7858
|
const querySnapshot = await getDocs15(q);
|
|
7807
7859
|
const documents = [];
|
|
7808
7860
|
let lastVisible = null;
|
|
7809
|
-
querySnapshot.forEach((
|
|
7810
|
-
documents.push(
|
|
7811
|
-
lastVisible =
|
|
7861
|
+
querySnapshot.forEach((doc29) => {
|
|
7862
|
+
documents.push(doc29.data());
|
|
7863
|
+
lastVisible = doc29;
|
|
7812
7864
|
});
|
|
7813
7865
|
return {
|
|
7814
7866
|
documents,
|
|
@@ -7835,9 +7887,9 @@ var FilledDocumentService = class extends BaseService {
|
|
|
7835
7887
|
const querySnapshot = await getDocs15(q);
|
|
7836
7888
|
const documents = [];
|
|
7837
7889
|
let lastVisible = null;
|
|
7838
|
-
querySnapshot.forEach((
|
|
7839
|
-
documents.push(
|
|
7840
|
-
lastVisible =
|
|
7890
|
+
querySnapshot.forEach((doc29) => {
|
|
7891
|
+
documents.push(doc29.data());
|
|
7892
|
+
lastVisible = doc29;
|
|
7841
7893
|
});
|
|
7842
7894
|
return {
|
|
7843
7895
|
documents,
|
|
@@ -7864,9 +7916,9 @@ var FilledDocumentService = class extends BaseService {
|
|
|
7864
7916
|
const querySnapshot = await getDocs15(q);
|
|
7865
7917
|
const documents = [];
|
|
7866
7918
|
let lastVisible = null;
|
|
7867
|
-
querySnapshot.forEach((
|
|
7868
|
-
documents.push(
|
|
7869
|
-
lastVisible =
|
|
7919
|
+
querySnapshot.forEach((doc29) => {
|
|
7920
|
+
documents.push(doc29.data());
|
|
7921
|
+
lastVisible = doc29;
|
|
7870
7922
|
});
|
|
7871
7923
|
return {
|
|
7872
7924
|
documents,
|
|
@@ -7893,9 +7945,9 @@ var FilledDocumentService = class extends BaseService {
|
|
|
7893
7945
|
const querySnapshot = await getDocs15(q);
|
|
7894
7946
|
const documents = [];
|
|
7895
7947
|
let lastVisible = null;
|
|
7896
|
-
querySnapshot.forEach((
|
|
7897
|
-
documents.push(
|
|
7898
|
-
lastVisible =
|
|
7948
|
+
querySnapshot.forEach((doc29) => {
|
|
7949
|
+
documents.push(doc29.data());
|
|
7950
|
+
lastVisible = doc29;
|
|
7899
7951
|
});
|
|
7900
7952
|
return {
|
|
7901
7953
|
documents,
|
|
@@ -8451,7 +8503,7 @@ async function searchCalendarEventsUtil(db, params) {
|
|
|
8451
8503
|
const finalQuery = query19(collectionRef, ...constraints);
|
|
8452
8504
|
const querySnapshot = await getDocs19(finalQuery);
|
|
8453
8505
|
const events = querySnapshot.docs.map(
|
|
8454
|
-
(
|
|
8506
|
+
(doc29) => ({ id: doc29.id, ...doc29.data() })
|
|
8455
8507
|
);
|
|
8456
8508
|
return events;
|
|
8457
8509
|
} catch (error) {
|
|
@@ -8544,7 +8596,7 @@ async function getPractitionerSyncedCalendarsUtil(db, practitionerId) {
|
|
|
8544
8596
|
);
|
|
8545
8597
|
const q = query20(calendarsRef, orderBy11("createdAt", "desc"));
|
|
8546
8598
|
const querySnapshot = await getDocs20(q);
|
|
8547
|
-
return querySnapshot.docs.map((
|
|
8599
|
+
return querySnapshot.docs.map((doc29) => doc29.data());
|
|
8548
8600
|
}
|
|
8549
8601
|
async function getPatientSyncedCalendarUtil(db, patientId, calendarId) {
|
|
8550
8602
|
const calendarRef = getPatientSyncedCalendarDocRef(db, patientId, calendarId);
|
|
@@ -8561,7 +8613,7 @@ async function getPatientSyncedCalendarsUtil(db, patientId) {
|
|
|
8561
8613
|
);
|
|
8562
8614
|
const q = query20(calendarsRef, orderBy11("createdAt", "desc"));
|
|
8563
8615
|
const querySnapshot = await getDocs20(q);
|
|
8564
|
-
return querySnapshot.docs.map((
|
|
8616
|
+
return querySnapshot.docs.map((doc29) => doc29.data());
|
|
8565
8617
|
}
|
|
8566
8618
|
async function getClinicSyncedCalendarUtil(db, clinicId, calendarId) {
|
|
8567
8619
|
const calendarRef = getClinicSyncedCalendarDocRef(db, clinicId, calendarId);
|
|
@@ -8578,7 +8630,7 @@ async function getClinicSyncedCalendarsUtil(db, clinicId) {
|
|
|
8578
8630
|
);
|
|
8579
8631
|
const q = query20(calendarsRef, orderBy11("createdAt", "desc"));
|
|
8580
8632
|
const querySnapshot = await getDocs20(q);
|
|
8581
|
-
return querySnapshot.docs.map((
|
|
8633
|
+
return querySnapshot.docs.map((doc29) => doc29.data());
|
|
8582
8634
|
}
|
|
8583
8635
|
async function updatePractitionerSyncedCalendarUtil(db, practitionerId, calendarId, updateData) {
|
|
8584
8636
|
const calendarRef = getPractitionerSyncedCalendarDocRef(
|
|
@@ -9933,9 +9985,9 @@ var CalendarServiceV2 = class extends BaseService {
|
|
|
9933
9985
|
where21("eventTime.start", "<=", Timestamp25.fromDate(endDate))
|
|
9934
9986
|
);
|
|
9935
9987
|
const eventsSnapshot = await getDocs21(q);
|
|
9936
|
-
const events = eventsSnapshot.docs.map((
|
|
9937
|
-
id:
|
|
9938
|
-
...
|
|
9988
|
+
const events = eventsSnapshot.docs.map((doc29) => ({
|
|
9989
|
+
id: doc29.id,
|
|
9990
|
+
...doc29.data()
|
|
9939
9991
|
}));
|
|
9940
9992
|
const calendars = await this.syncedCalendarsService.getPractitionerSyncedCalendars(
|
|
9941
9993
|
doctorId
|
|
@@ -10567,7 +10619,7 @@ var CalendarServiceV2 = class extends BaseService {
|
|
|
10567
10619
|
])
|
|
10568
10620
|
);
|
|
10569
10621
|
const querySnapshot = await getDocs21(q);
|
|
10570
|
-
return querySnapshot.docs.map((
|
|
10622
|
+
return querySnapshot.docs.map((doc29) => doc29.data());
|
|
10571
10623
|
}
|
|
10572
10624
|
/**
|
|
10573
10625
|
* Calculates available time slots based on working hours, schedule and existing appointments
|
|
@@ -10691,16 +10743,637 @@ var CalendarServiceV2 = class extends BaseService {
|
|
|
10691
10743
|
// #endregion
|
|
10692
10744
|
};
|
|
10693
10745
|
|
|
10694
|
-
// src/
|
|
10746
|
+
// src/services/reviews/reviews.service.ts
|
|
10695
10747
|
import {
|
|
10696
|
-
addDoc as addDoc3,
|
|
10697
10748
|
collection as collection22,
|
|
10698
10749
|
doc as doc23,
|
|
10699
10750
|
getDoc as getDoc25,
|
|
10700
10751
|
getDocs as getDocs22,
|
|
10701
10752
|
query as query22,
|
|
10753
|
+
where as where22,
|
|
10702
10754
|
updateDoc as updateDoc24,
|
|
10703
|
-
|
|
10755
|
+
setDoc as setDoc22,
|
|
10756
|
+
deleteDoc as deleteDoc15,
|
|
10757
|
+
serverTimestamp as serverTimestamp22,
|
|
10758
|
+
writeBatch as writeBatch7
|
|
10759
|
+
} from "firebase/firestore";
|
|
10760
|
+
|
|
10761
|
+
// src/types/reviews/index.ts
|
|
10762
|
+
var REVIEWS_COLLECTION = "reviews";
|
|
10763
|
+
|
|
10764
|
+
// src/services/reviews/reviews.service.ts
|
|
10765
|
+
import { z as z21 } from "zod";
|
|
10766
|
+
var ReviewService = class extends BaseService {
|
|
10767
|
+
constructor(db, auth, app) {
|
|
10768
|
+
super(db, auth, app);
|
|
10769
|
+
}
|
|
10770
|
+
/**
|
|
10771
|
+
* Creates a new review and updates related entities
|
|
10772
|
+
* @param data - The review data to create
|
|
10773
|
+
* @param appointmentId - ID of the completed appointment
|
|
10774
|
+
* @returns The created review
|
|
10775
|
+
*/
|
|
10776
|
+
async createReview(data, appointmentId) {
|
|
10777
|
+
try {
|
|
10778
|
+
const validatedData = createReviewSchema.parse(data);
|
|
10779
|
+
const ratings = [];
|
|
10780
|
+
if (data.clinicReview) {
|
|
10781
|
+
const clinicRatings = [
|
|
10782
|
+
data.clinicReview.cleanliness,
|
|
10783
|
+
data.clinicReview.facilities,
|
|
10784
|
+
data.clinicReview.staffFriendliness,
|
|
10785
|
+
data.clinicReview.waitingTime,
|
|
10786
|
+
data.clinicReview.accessibility
|
|
10787
|
+
];
|
|
10788
|
+
const clinicAverage = this.calculateAverage(clinicRatings);
|
|
10789
|
+
data.clinicReview.overallRating = clinicAverage;
|
|
10790
|
+
ratings.push(clinicAverage);
|
|
10791
|
+
}
|
|
10792
|
+
if (data.practitionerReview) {
|
|
10793
|
+
const practitionerRatings = [
|
|
10794
|
+
data.practitionerReview.knowledgeAndExpertise,
|
|
10795
|
+
data.practitionerReview.communicationSkills,
|
|
10796
|
+
data.practitionerReview.bedSideManner,
|
|
10797
|
+
data.practitionerReview.thoroughness,
|
|
10798
|
+
data.practitionerReview.trustworthiness
|
|
10799
|
+
];
|
|
10800
|
+
const practitionerAverage = this.calculateAverage(practitionerRatings);
|
|
10801
|
+
data.practitionerReview.overallRating = practitionerAverage;
|
|
10802
|
+
ratings.push(practitionerAverage);
|
|
10803
|
+
}
|
|
10804
|
+
if (data.procedureReview) {
|
|
10805
|
+
const procedureRatings = [
|
|
10806
|
+
data.procedureReview.effectivenessOfTreatment,
|
|
10807
|
+
data.procedureReview.outcomeExplanation,
|
|
10808
|
+
data.procedureReview.painManagement,
|
|
10809
|
+
data.procedureReview.followUpCare,
|
|
10810
|
+
data.procedureReview.valueForMoney
|
|
10811
|
+
];
|
|
10812
|
+
const procedureAverage = this.calculateAverage(procedureRatings);
|
|
10813
|
+
data.procedureReview.overallRating = procedureAverage;
|
|
10814
|
+
ratings.push(procedureAverage);
|
|
10815
|
+
}
|
|
10816
|
+
const overallRating = this.calculateAverage(ratings);
|
|
10817
|
+
const reviewId = this.generateId();
|
|
10818
|
+
if (data.clinicReview) {
|
|
10819
|
+
data.clinicReview.id = this.generateId();
|
|
10820
|
+
data.clinicReview.fullReviewId = reviewId;
|
|
10821
|
+
}
|
|
10822
|
+
if (data.practitionerReview) {
|
|
10823
|
+
data.practitionerReview.id = this.generateId();
|
|
10824
|
+
data.practitionerReview.fullReviewId = reviewId;
|
|
10825
|
+
}
|
|
10826
|
+
if (data.procedureReview) {
|
|
10827
|
+
data.procedureReview.id = this.generateId();
|
|
10828
|
+
data.procedureReview.fullReviewId = reviewId;
|
|
10829
|
+
}
|
|
10830
|
+
const now = /* @__PURE__ */ new Date();
|
|
10831
|
+
const review = {
|
|
10832
|
+
id: reviewId,
|
|
10833
|
+
appointmentId,
|
|
10834
|
+
patientId: data.patientId,
|
|
10835
|
+
clinicReview: data.clinicReview,
|
|
10836
|
+
practitionerReview: data.practitionerReview,
|
|
10837
|
+
procedureReview: data.procedureReview,
|
|
10838
|
+
overallComment: data.overallComment,
|
|
10839
|
+
overallRating,
|
|
10840
|
+
createdAt: now,
|
|
10841
|
+
updatedAt: now
|
|
10842
|
+
};
|
|
10843
|
+
reviewSchema.parse(review);
|
|
10844
|
+
const docRef = doc23(this.db, REVIEWS_COLLECTION, reviewId);
|
|
10845
|
+
await setDoc22(docRef, {
|
|
10846
|
+
...review,
|
|
10847
|
+
createdAt: serverTimestamp22(),
|
|
10848
|
+
updatedAt: serverTimestamp22()
|
|
10849
|
+
});
|
|
10850
|
+
const updatePromises = [];
|
|
10851
|
+
if (data.clinicReview) {
|
|
10852
|
+
updatePromises.push(
|
|
10853
|
+
this.updateClinicReviewInfo(data.clinicReview.clinicId)
|
|
10854
|
+
);
|
|
10855
|
+
}
|
|
10856
|
+
if (data.practitionerReview) {
|
|
10857
|
+
updatePromises.push(
|
|
10858
|
+
this.updatePractitionerReviewInfo(
|
|
10859
|
+
data.practitionerReview.practitionerId
|
|
10860
|
+
)
|
|
10861
|
+
);
|
|
10862
|
+
}
|
|
10863
|
+
if (data.procedureReview) {
|
|
10864
|
+
updatePromises.push(
|
|
10865
|
+
this.updateProcedureReviewInfo(data.procedureReview.procedureId)
|
|
10866
|
+
);
|
|
10867
|
+
}
|
|
10868
|
+
await Promise.all(updatePromises);
|
|
10869
|
+
return review;
|
|
10870
|
+
} catch (error) {
|
|
10871
|
+
if (error instanceof z21.ZodError) {
|
|
10872
|
+
throw new Error(`Invalid review data: ${error.message}`);
|
|
10873
|
+
}
|
|
10874
|
+
throw error;
|
|
10875
|
+
}
|
|
10876
|
+
}
|
|
10877
|
+
/**
|
|
10878
|
+
* Gets a review by ID
|
|
10879
|
+
* @param reviewId The ID of the review to get
|
|
10880
|
+
* @returns The review if found, null otherwise
|
|
10881
|
+
*/
|
|
10882
|
+
async getReview(reviewId) {
|
|
10883
|
+
const docRef = doc23(this.db, REVIEWS_COLLECTION, reviewId);
|
|
10884
|
+
const docSnap = await getDoc25(docRef);
|
|
10885
|
+
if (!docSnap.exists()) {
|
|
10886
|
+
return null;
|
|
10887
|
+
}
|
|
10888
|
+
return docSnap.data();
|
|
10889
|
+
}
|
|
10890
|
+
/**
|
|
10891
|
+
* Gets all reviews for a specific patient
|
|
10892
|
+
* @param patientId The ID of the patient
|
|
10893
|
+
* @returns Array of reviews for the patient
|
|
10894
|
+
*/
|
|
10895
|
+
async getReviewsByPatient(patientId) {
|
|
10896
|
+
const q = query22(
|
|
10897
|
+
collection22(this.db, REVIEWS_COLLECTION),
|
|
10898
|
+
where22("patientId", "==", patientId)
|
|
10899
|
+
);
|
|
10900
|
+
const snapshot = await getDocs22(q);
|
|
10901
|
+
return snapshot.docs.map((doc29) => doc29.data());
|
|
10902
|
+
}
|
|
10903
|
+
/**
|
|
10904
|
+
* Gets all reviews for a specific clinic
|
|
10905
|
+
* @param clinicId The ID of the clinic
|
|
10906
|
+
* @returns Array of reviews containing clinic reviews
|
|
10907
|
+
*/
|
|
10908
|
+
async getReviewsByClinic(clinicId) {
|
|
10909
|
+
const q = query22(
|
|
10910
|
+
collection22(this.db, REVIEWS_COLLECTION),
|
|
10911
|
+
where22("clinicReview.clinicId", "==", clinicId)
|
|
10912
|
+
);
|
|
10913
|
+
const snapshot = await getDocs22(q);
|
|
10914
|
+
return snapshot.docs.map((doc29) => doc29.data());
|
|
10915
|
+
}
|
|
10916
|
+
/**
|
|
10917
|
+
* Gets all reviews for a specific practitioner
|
|
10918
|
+
* @param practitionerId The ID of the practitioner
|
|
10919
|
+
* @returns Array of reviews containing practitioner reviews
|
|
10920
|
+
*/
|
|
10921
|
+
async getReviewsByPractitioner(practitionerId) {
|
|
10922
|
+
const q = query22(
|
|
10923
|
+
collection22(this.db, REVIEWS_COLLECTION),
|
|
10924
|
+
where22("practitionerReview.practitionerId", "==", practitionerId)
|
|
10925
|
+
);
|
|
10926
|
+
const snapshot = await getDocs22(q);
|
|
10927
|
+
return snapshot.docs.map((doc29) => doc29.data());
|
|
10928
|
+
}
|
|
10929
|
+
/**
|
|
10930
|
+
* Gets all reviews for a specific procedure
|
|
10931
|
+
* @param procedureId The ID of the procedure
|
|
10932
|
+
* @returns Array of reviews containing procedure reviews
|
|
10933
|
+
*/
|
|
10934
|
+
async getReviewsByProcedure(procedureId) {
|
|
10935
|
+
const q = query22(
|
|
10936
|
+
collection22(this.db, REVIEWS_COLLECTION),
|
|
10937
|
+
where22("procedureReview.procedureId", "==", procedureId)
|
|
10938
|
+
);
|
|
10939
|
+
const snapshot = await getDocs22(q);
|
|
10940
|
+
return snapshot.docs.map((doc29) => doc29.data());
|
|
10941
|
+
}
|
|
10942
|
+
/**
|
|
10943
|
+
* Gets all reviews for a specific appointment
|
|
10944
|
+
* @param appointmentId The ID of the appointment
|
|
10945
|
+
* @returns The review for the appointment if found, null otherwise
|
|
10946
|
+
*/
|
|
10947
|
+
async getReviewByAppointment(appointmentId) {
|
|
10948
|
+
const q = query22(
|
|
10949
|
+
collection22(this.db, REVIEWS_COLLECTION),
|
|
10950
|
+
where22("appointmentId", "==", appointmentId)
|
|
10951
|
+
);
|
|
10952
|
+
const snapshot = await getDocs22(q);
|
|
10953
|
+
if (snapshot.empty) {
|
|
10954
|
+
return null;
|
|
10955
|
+
}
|
|
10956
|
+
return snapshot.docs[0].data();
|
|
10957
|
+
}
|
|
10958
|
+
/**
|
|
10959
|
+
* Deletes a review and updates related entities
|
|
10960
|
+
* @param reviewId The ID of the review to delete
|
|
10961
|
+
*/
|
|
10962
|
+
async deleteReview(reviewId) {
|
|
10963
|
+
const review = await this.getReview(reviewId);
|
|
10964
|
+
if (!review) {
|
|
10965
|
+
throw new Error(`Review with ID ${reviewId} not found`);
|
|
10966
|
+
}
|
|
10967
|
+
await deleteDoc15(doc23(this.db, REVIEWS_COLLECTION, reviewId));
|
|
10968
|
+
const updatePromises = [];
|
|
10969
|
+
if (review.clinicReview) {
|
|
10970
|
+
updatePromises.push(
|
|
10971
|
+
this.updateClinicReviewInfo(
|
|
10972
|
+
review.clinicReview.clinicId,
|
|
10973
|
+
review.clinicReview,
|
|
10974
|
+
true
|
|
10975
|
+
)
|
|
10976
|
+
);
|
|
10977
|
+
}
|
|
10978
|
+
if (review.practitionerReview) {
|
|
10979
|
+
updatePromises.push(
|
|
10980
|
+
this.updatePractitionerReviewInfo(
|
|
10981
|
+
review.practitionerReview.practitionerId,
|
|
10982
|
+
review.practitionerReview,
|
|
10983
|
+
true
|
|
10984
|
+
)
|
|
10985
|
+
);
|
|
10986
|
+
}
|
|
10987
|
+
if (review.procedureReview) {
|
|
10988
|
+
updatePromises.push(
|
|
10989
|
+
this.updateProcedureReviewInfo(
|
|
10990
|
+
review.procedureReview.procedureId,
|
|
10991
|
+
review.procedureReview,
|
|
10992
|
+
true
|
|
10993
|
+
)
|
|
10994
|
+
);
|
|
10995
|
+
}
|
|
10996
|
+
await Promise.all(updatePromises);
|
|
10997
|
+
}
|
|
10998
|
+
/**
|
|
10999
|
+
* Updates the review info for a clinic
|
|
11000
|
+
* @param clinicId The ID of the clinic to update
|
|
11001
|
+
* @param newReview Optional new review being added or removed
|
|
11002
|
+
* @param isRemoval Whether this update is for a review removal
|
|
11003
|
+
* @returns The updated clinic review info
|
|
11004
|
+
*/
|
|
11005
|
+
async updateClinicReviewInfo(clinicId, newReview, isRemoval = false) {
|
|
11006
|
+
const clinicDoc = await getDoc25(doc23(this.db, CLINICS_COLLECTION, clinicId));
|
|
11007
|
+
if (!clinicDoc.exists()) {
|
|
11008
|
+
throw new Error(`Clinic with ID ${clinicId} not found`);
|
|
11009
|
+
}
|
|
11010
|
+
const clinicData = clinicDoc.data();
|
|
11011
|
+
const currentReviewInfo = clinicData.reviewInfo || {
|
|
11012
|
+
totalReviews: 0,
|
|
11013
|
+
averageRating: 0,
|
|
11014
|
+
cleanliness: 0,
|
|
11015
|
+
facilities: 0,
|
|
11016
|
+
staffFriendliness: 0,
|
|
11017
|
+
waitingTime: 0,
|
|
11018
|
+
accessibility: 0,
|
|
11019
|
+
recommendationPercentage: 0
|
|
11020
|
+
};
|
|
11021
|
+
if (currentReviewInfo.totalReviews === 0 && !newReview) {
|
|
11022
|
+
await updateDoc24(doc23(this.db, CLINICS_COLLECTION, clinicId), {
|
|
11023
|
+
reviewInfo: currentReviewInfo,
|
|
11024
|
+
updatedAt: serverTimestamp22()
|
|
11025
|
+
});
|
|
11026
|
+
return currentReviewInfo;
|
|
11027
|
+
}
|
|
11028
|
+
let updatedReviewInfo;
|
|
11029
|
+
if (newReview) {
|
|
11030
|
+
const oldTotal = currentReviewInfo.totalReviews;
|
|
11031
|
+
const newTotal = isRemoval ? oldTotal - 1 : oldTotal + 1;
|
|
11032
|
+
if (newTotal === 0) {
|
|
11033
|
+
updatedReviewInfo = {
|
|
11034
|
+
totalReviews: 0,
|
|
11035
|
+
averageRating: 0,
|
|
11036
|
+
cleanliness: 0,
|
|
11037
|
+
facilities: 0,
|
|
11038
|
+
staffFriendliness: 0,
|
|
11039
|
+
waitingTime: 0,
|
|
11040
|
+
accessibility: 0,
|
|
11041
|
+
recommendationPercentage: 0
|
|
11042
|
+
};
|
|
11043
|
+
} else {
|
|
11044
|
+
const updateAverage = (currentAvg, newValue) => {
|
|
11045
|
+
const currentSum = currentAvg * oldTotal;
|
|
11046
|
+
const newSum = isRemoval ? currentSum - newValue : currentSum + newValue;
|
|
11047
|
+
const newAvg = newSum / newTotal;
|
|
11048
|
+
return Math.round(newAvg * 10) / 10;
|
|
11049
|
+
};
|
|
11050
|
+
const currentRecommendations = currentReviewInfo.recommendationPercentage / 100 * oldTotal;
|
|
11051
|
+
const newRecommendations = isRemoval ? newReview.wouldRecommend ? currentRecommendations - 1 : currentRecommendations : newReview.wouldRecommend ? currentRecommendations + 1 : currentRecommendations;
|
|
11052
|
+
const newRecommendationPercentage = newRecommendations / newTotal * 100;
|
|
11053
|
+
updatedReviewInfo = {
|
|
11054
|
+
totalReviews: newTotal,
|
|
11055
|
+
averageRating: updateAverage(
|
|
11056
|
+
currentReviewInfo.averageRating,
|
|
11057
|
+
newReview.overallRating
|
|
11058
|
+
),
|
|
11059
|
+
cleanliness: updateAverage(
|
|
11060
|
+
currentReviewInfo.cleanliness,
|
|
11061
|
+
newReview.cleanliness
|
|
11062
|
+
),
|
|
11063
|
+
facilities: updateAverage(
|
|
11064
|
+
currentReviewInfo.facilities,
|
|
11065
|
+
newReview.facilities
|
|
11066
|
+
),
|
|
11067
|
+
staffFriendliness: updateAverage(
|
|
11068
|
+
currentReviewInfo.staffFriendliness,
|
|
11069
|
+
newReview.staffFriendliness
|
|
11070
|
+
),
|
|
11071
|
+
waitingTime: updateAverage(
|
|
11072
|
+
currentReviewInfo.waitingTime,
|
|
11073
|
+
newReview.waitingTime
|
|
11074
|
+
),
|
|
11075
|
+
accessibility: updateAverage(
|
|
11076
|
+
currentReviewInfo.accessibility,
|
|
11077
|
+
newReview.accessibility
|
|
11078
|
+
),
|
|
11079
|
+
recommendationPercentage: Math.round(newRecommendationPercentage * 10) / 10
|
|
11080
|
+
};
|
|
11081
|
+
}
|
|
11082
|
+
} else {
|
|
11083
|
+
updatedReviewInfo = { ...currentReviewInfo };
|
|
11084
|
+
}
|
|
11085
|
+
await updateDoc24(doc23(this.db, CLINICS_COLLECTION, clinicId), {
|
|
11086
|
+
reviewInfo: updatedReviewInfo,
|
|
11087
|
+
updatedAt: serverTimestamp22()
|
|
11088
|
+
});
|
|
11089
|
+
return updatedReviewInfo;
|
|
11090
|
+
}
|
|
11091
|
+
/**
|
|
11092
|
+
* Updates the review info for a practitioner
|
|
11093
|
+
* @param practitionerId The ID of the practitioner to update
|
|
11094
|
+
* @param newReview Optional new review being added or removed
|
|
11095
|
+
* @param isRemoval Whether this update is for a review removal
|
|
11096
|
+
* @returns The updated practitioner review info
|
|
11097
|
+
*/
|
|
11098
|
+
async updatePractitionerReviewInfo(practitionerId, newReview, isRemoval = false) {
|
|
11099
|
+
const practitionerDoc = await getDoc25(
|
|
11100
|
+
doc23(this.db, PRACTITIONERS_COLLECTION, practitionerId)
|
|
11101
|
+
);
|
|
11102
|
+
if (!practitionerDoc.exists()) {
|
|
11103
|
+
throw new Error(`Practitioner with ID ${practitionerId} not found`);
|
|
11104
|
+
}
|
|
11105
|
+
const practitionerData = practitionerDoc.data();
|
|
11106
|
+
const currentReviewInfo = practitionerData.reviewInfo || {
|
|
11107
|
+
totalReviews: 0,
|
|
11108
|
+
averageRating: 0,
|
|
11109
|
+
knowledgeAndExpertise: 0,
|
|
11110
|
+
communicationSkills: 0,
|
|
11111
|
+
bedSideManner: 0,
|
|
11112
|
+
thoroughness: 0,
|
|
11113
|
+
trustworthiness: 0,
|
|
11114
|
+
recommendationPercentage: 0
|
|
11115
|
+
};
|
|
11116
|
+
if (currentReviewInfo.totalReviews === 0 && !newReview) {
|
|
11117
|
+
await updateDoc24(doc23(this.db, PRACTITIONERS_COLLECTION, practitionerId), {
|
|
11118
|
+
reviewInfo: currentReviewInfo,
|
|
11119
|
+
updatedAt: serverTimestamp22()
|
|
11120
|
+
});
|
|
11121
|
+
return currentReviewInfo;
|
|
11122
|
+
}
|
|
11123
|
+
let updatedReviewInfo;
|
|
11124
|
+
if (newReview) {
|
|
11125
|
+
const oldTotal = currentReviewInfo.totalReviews;
|
|
11126
|
+
const newTotal = isRemoval ? oldTotal - 1 : oldTotal + 1;
|
|
11127
|
+
if (newTotal === 0) {
|
|
11128
|
+
updatedReviewInfo = {
|
|
11129
|
+
totalReviews: 0,
|
|
11130
|
+
averageRating: 0,
|
|
11131
|
+
knowledgeAndExpertise: 0,
|
|
11132
|
+
communicationSkills: 0,
|
|
11133
|
+
bedSideManner: 0,
|
|
11134
|
+
thoroughness: 0,
|
|
11135
|
+
trustworthiness: 0,
|
|
11136
|
+
recommendationPercentage: 0
|
|
11137
|
+
};
|
|
11138
|
+
} else {
|
|
11139
|
+
const updateAverage = (currentAvg, newValue) => {
|
|
11140
|
+
const currentSum = currentAvg * oldTotal;
|
|
11141
|
+
const newSum = isRemoval ? currentSum - newValue : currentSum + newValue;
|
|
11142
|
+
const newAvg = newSum / newTotal;
|
|
11143
|
+
return Math.round(newAvg * 10) / 10;
|
|
11144
|
+
};
|
|
11145
|
+
const currentRecommendations = currentReviewInfo.recommendationPercentage / 100 * oldTotal;
|
|
11146
|
+
const newRecommendations = isRemoval ? newReview.wouldRecommend ? currentRecommendations - 1 : currentRecommendations : newReview.wouldRecommend ? currentRecommendations + 1 : currentRecommendations;
|
|
11147
|
+
const newRecommendationPercentage = newRecommendations / newTotal * 100;
|
|
11148
|
+
updatedReviewInfo = {
|
|
11149
|
+
totalReviews: newTotal,
|
|
11150
|
+
averageRating: updateAverage(
|
|
11151
|
+
currentReviewInfo.averageRating,
|
|
11152
|
+
newReview.overallRating
|
|
11153
|
+
),
|
|
11154
|
+
knowledgeAndExpertise: updateAverage(
|
|
11155
|
+
currentReviewInfo.knowledgeAndExpertise,
|
|
11156
|
+
newReview.knowledgeAndExpertise
|
|
11157
|
+
),
|
|
11158
|
+
communicationSkills: updateAverage(
|
|
11159
|
+
currentReviewInfo.communicationSkills,
|
|
11160
|
+
newReview.communicationSkills
|
|
11161
|
+
),
|
|
11162
|
+
bedSideManner: updateAverage(
|
|
11163
|
+
currentReviewInfo.bedSideManner,
|
|
11164
|
+
newReview.bedSideManner
|
|
11165
|
+
),
|
|
11166
|
+
thoroughness: updateAverage(
|
|
11167
|
+
currentReviewInfo.thoroughness,
|
|
11168
|
+
newReview.thoroughness
|
|
11169
|
+
),
|
|
11170
|
+
trustworthiness: updateAverage(
|
|
11171
|
+
currentReviewInfo.trustworthiness,
|
|
11172
|
+
newReview.trustworthiness
|
|
11173
|
+
),
|
|
11174
|
+
recommendationPercentage: Math.round(newRecommendationPercentage * 10) / 10
|
|
11175
|
+
};
|
|
11176
|
+
}
|
|
11177
|
+
} else {
|
|
11178
|
+
updatedReviewInfo = { ...currentReviewInfo };
|
|
11179
|
+
}
|
|
11180
|
+
await updateDoc24(doc23(this.db, PRACTITIONERS_COLLECTION, practitionerId), {
|
|
11181
|
+
reviewInfo: updatedReviewInfo,
|
|
11182
|
+
updatedAt: serverTimestamp22()
|
|
11183
|
+
});
|
|
11184
|
+
await this.updateDoctorInfoInProcedures(
|
|
11185
|
+
practitionerId,
|
|
11186
|
+
updatedReviewInfo.averageRating
|
|
11187
|
+
);
|
|
11188
|
+
return updatedReviewInfo;
|
|
11189
|
+
}
|
|
11190
|
+
/**
|
|
11191
|
+
* Updates the review info for a procedure
|
|
11192
|
+
* @param procedureId The ID of the procedure to update
|
|
11193
|
+
* @param newReview Optional new review being added or removed
|
|
11194
|
+
* @param isRemoval Whether this update is for a review removal
|
|
11195
|
+
* @returns The updated procedure review info
|
|
11196
|
+
*/
|
|
11197
|
+
async updateProcedureReviewInfo(procedureId, newReview, isRemoval = false) {
|
|
11198
|
+
const procedureDoc = await getDoc25(
|
|
11199
|
+
doc23(this.db, PROCEDURES_COLLECTION, procedureId)
|
|
11200
|
+
);
|
|
11201
|
+
if (!procedureDoc.exists()) {
|
|
11202
|
+
throw new Error(`Procedure with ID ${procedureId} not found`);
|
|
11203
|
+
}
|
|
11204
|
+
const procedureData = procedureDoc.data();
|
|
11205
|
+
const currentReviewInfo = procedureData.reviewInfo || {
|
|
11206
|
+
totalReviews: 0,
|
|
11207
|
+
averageRating: 0,
|
|
11208
|
+
effectivenessOfTreatment: 0,
|
|
11209
|
+
outcomeExplanation: 0,
|
|
11210
|
+
painManagement: 0,
|
|
11211
|
+
followUpCare: 0,
|
|
11212
|
+
valueForMoney: 0,
|
|
11213
|
+
recommendationPercentage: 0
|
|
11214
|
+
};
|
|
11215
|
+
if (currentReviewInfo.totalReviews === 0 && !newReview) {
|
|
11216
|
+
await updateDoc24(doc23(this.db, PROCEDURES_COLLECTION, procedureId), {
|
|
11217
|
+
reviewInfo: currentReviewInfo,
|
|
11218
|
+
updatedAt: serverTimestamp22()
|
|
11219
|
+
});
|
|
11220
|
+
return currentReviewInfo;
|
|
11221
|
+
}
|
|
11222
|
+
let updatedReviewInfo;
|
|
11223
|
+
if (newReview) {
|
|
11224
|
+
const oldTotal = currentReviewInfo.totalReviews;
|
|
11225
|
+
const newTotal = isRemoval ? oldTotal - 1 : oldTotal + 1;
|
|
11226
|
+
if (newTotal === 0) {
|
|
11227
|
+
updatedReviewInfo = {
|
|
11228
|
+
totalReviews: 0,
|
|
11229
|
+
averageRating: 0,
|
|
11230
|
+
effectivenessOfTreatment: 0,
|
|
11231
|
+
outcomeExplanation: 0,
|
|
11232
|
+
painManagement: 0,
|
|
11233
|
+
followUpCare: 0,
|
|
11234
|
+
valueForMoney: 0,
|
|
11235
|
+
recommendationPercentage: 0
|
|
11236
|
+
};
|
|
11237
|
+
} else {
|
|
11238
|
+
const updateAverage = (currentAvg, newValue) => {
|
|
11239
|
+
const currentSum = currentAvg * oldTotal;
|
|
11240
|
+
const newSum = isRemoval ? currentSum - newValue : currentSum + newValue;
|
|
11241
|
+
const newAvg = newSum / newTotal;
|
|
11242
|
+
return Math.round(newAvg * 10) / 10;
|
|
11243
|
+
};
|
|
11244
|
+
const currentRecommendations = currentReviewInfo.recommendationPercentage / 100 * oldTotal;
|
|
11245
|
+
const newRecommendations = isRemoval ? newReview.wouldRecommend ? currentRecommendations - 1 : currentRecommendations : newReview.wouldRecommend ? currentRecommendations + 1 : currentRecommendations;
|
|
11246
|
+
const newRecommendationPercentage = newRecommendations / newTotal * 100;
|
|
11247
|
+
updatedReviewInfo = {
|
|
11248
|
+
totalReviews: newTotal,
|
|
11249
|
+
averageRating: updateAverage(
|
|
11250
|
+
currentReviewInfo.averageRating,
|
|
11251
|
+
newReview.overallRating
|
|
11252
|
+
),
|
|
11253
|
+
effectivenessOfTreatment: updateAverage(
|
|
11254
|
+
currentReviewInfo.effectivenessOfTreatment,
|
|
11255
|
+
newReview.effectivenessOfTreatment
|
|
11256
|
+
),
|
|
11257
|
+
outcomeExplanation: updateAverage(
|
|
11258
|
+
currentReviewInfo.outcomeExplanation,
|
|
11259
|
+
newReview.outcomeExplanation
|
|
11260
|
+
),
|
|
11261
|
+
painManagement: updateAverage(
|
|
11262
|
+
currentReviewInfo.painManagement,
|
|
11263
|
+
newReview.painManagement
|
|
11264
|
+
),
|
|
11265
|
+
followUpCare: updateAverage(
|
|
11266
|
+
currentReviewInfo.followUpCare,
|
|
11267
|
+
newReview.followUpCare
|
|
11268
|
+
),
|
|
11269
|
+
valueForMoney: updateAverage(
|
|
11270
|
+
currentReviewInfo.valueForMoney,
|
|
11271
|
+
newReview.valueForMoney
|
|
11272
|
+
),
|
|
11273
|
+
recommendationPercentage: Math.round(newRecommendationPercentage * 10) / 10
|
|
11274
|
+
};
|
|
11275
|
+
}
|
|
11276
|
+
} else {
|
|
11277
|
+
updatedReviewInfo = { ...currentReviewInfo };
|
|
11278
|
+
}
|
|
11279
|
+
await updateDoc24(doc23(this.db, PROCEDURES_COLLECTION, procedureId), {
|
|
11280
|
+
reviewInfo: updatedReviewInfo,
|
|
11281
|
+
updatedAt: serverTimestamp22()
|
|
11282
|
+
});
|
|
11283
|
+
return updatedReviewInfo;
|
|
11284
|
+
}
|
|
11285
|
+
/**
|
|
11286
|
+
* Updates doctorInfo rating in all procedures for a practitioner
|
|
11287
|
+
* @param practitionerId The ID of the practitioner
|
|
11288
|
+
* @param rating The new rating to set
|
|
11289
|
+
*/
|
|
11290
|
+
async updateDoctorInfoInProcedures(practitionerId, rating) {
|
|
11291
|
+
const q = query22(
|
|
11292
|
+
collection22(this.db, PROCEDURES_COLLECTION),
|
|
11293
|
+
where22("practitionerId", "==", practitionerId)
|
|
11294
|
+
);
|
|
11295
|
+
const snapshot = await getDocs22(q);
|
|
11296
|
+
if (snapshot.empty) {
|
|
11297
|
+
return;
|
|
11298
|
+
}
|
|
11299
|
+
const batch = writeBatch7(this.db);
|
|
11300
|
+
snapshot.docs.forEach((docSnapshot) => {
|
|
11301
|
+
const procedureRef = doc23(this.db, PROCEDURES_COLLECTION, docSnapshot.id);
|
|
11302
|
+
batch.update(procedureRef, {
|
|
11303
|
+
"doctorInfo.rating": rating,
|
|
11304
|
+
updatedAt: serverTimestamp22()
|
|
11305
|
+
});
|
|
11306
|
+
});
|
|
11307
|
+
await batch.commit();
|
|
11308
|
+
}
|
|
11309
|
+
/**
|
|
11310
|
+
* Verifies a review as checked by admin/staff
|
|
11311
|
+
* @param reviewId The ID of the review to verify
|
|
11312
|
+
*/
|
|
11313
|
+
async verifyReview(reviewId) {
|
|
11314
|
+
const review = await this.getReview(reviewId);
|
|
11315
|
+
if (!review) {
|
|
11316
|
+
throw new Error(`Review with ID ${reviewId} not found`);
|
|
11317
|
+
}
|
|
11318
|
+
const batch = writeBatch7(this.db);
|
|
11319
|
+
batch.update(doc23(this.db, REVIEWS_COLLECTION, reviewId), {
|
|
11320
|
+
updatedAt: serverTimestamp22()
|
|
11321
|
+
});
|
|
11322
|
+
if (review.clinicReview) {
|
|
11323
|
+
review.clinicReview.isVerified = true;
|
|
11324
|
+
}
|
|
11325
|
+
if (review.practitionerReview) {
|
|
11326
|
+
review.practitionerReview.isVerified = true;
|
|
11327
|
+
}
|
|
11328
|
+
if (review.procedureReview) {
|
|
11329
|
+
review.procedureReview.isVerified = true;
|
|
11330
|
+
}
|
|
11331
|
+
await batch.commit();
|
|
11332
|
+
const updatePromises = [];
|
|
11333
|
+
if (review.clinicReview) {
|
|
11334
|
+
updatePromises.push(
|
|
11335
|
+
this.updateClinicReviewInfo(review.clinicReview.clinicId)
|
|
11336
|
+
);
|
|
11337
|
+
}
|
|
11338
|
+
if (review.practitionerReview) {
|
|
11339
|
+
updatePromises.push(
|
|
11340
|
+
this.updatePractitionerReviewInfo(
|
|
11341
|
+
review.practitionerReview.practitionerId
|
|
11342
|
+
)
|
|
11343
|
+
);
|
|
11344
|
+
}
|
|
11345
|
+
if (review.procedureReview) {
|
|
11346
|
+
updatePromises.push(
|
|
11347
|
+
this.updateProcedureReviewInfo(review.procedureReview.procedureId)
|
|
11348
|
+
);
|
|
11349
|
+
}
|
|
11350
|
+
await Promise.all(updatePromises);
|
|
11351
|
+
}
|
|
11352
|
+
/**
|
|
11353
|
+
* Calculates the average of an array of numbers
|
|
11354
|
+
* @param numbers Array of numbers to average
|
|
11355
|
+
* @returns The average, or 0 if the array is empty
|
|
11356
|
+
*/
|
|
11357
|
+
calculateAverage(numbers) {
|
|
11358
|
+
if (numbers.length === 0) {
|
|
11359
|
+
return 0;
|
|
11360
|
+
}
|
|
11361
|
+
const sum = numbers.reduce((a, b) => a + b, 0);
|
|
11362
|
+
const avg = sum / numbers.length;
|
|
11363
|
+
return Math.round(avg * 10) / 10;
|
|
11364
|
+
}
|
|
11365
|
+
};
|
|
11366
|
+
|
|
11367
|
+
// src/backoffice/services/brand.service.ts
|
|
11368
|
+
import {
|
|
11369
|
+
addDoc as addDoc3,
|
|
11370
|
+
collection as collection23,
|
|
11371
|
+
doc as doc24,
|
|
11372
|
+
getDoc as getDoc26,
|
|
11373
|
+
getDocs as getDocs23,
|
|
11374
|
+
query as query23,
|
|
11375
|
+
updateDoc as updateDoc25,
|
|
11376
|
+
where as where23
|
|
10704
11377
|
} from "firebase/firestore";
|
|
10705
11378
|
|
|
10706
11379
|
// src/backoffice/types/brand.types.ts
|
|
@@ -10712,7 +11385,7 @@ var BrandService = class extends BaseService {
|
|
|
10712
11385
|
* Gets reference to brands collection
|
|
10713
11386
|
*/
|
|
10714
11387
|
getBrandsRef() {
|
|
10715
|
-
return
|
|
11388
|
+
return collection23(this.db, BRANDS_COLLECTION);
|
|
10716
11389
|
}
|
|
10717
11390
|
/**
|
|
10718
11391
|
* Creates a new brand
|
|
@@ -10732,12 +11405,12 @@ var BrandService = class extends BaseService {
|
|
|
10732
11405
|
* Gets all active brands
|
|
10733
11406
|
*/
|
|
10734
11407
|
async getAll() {
|
|
10735
|
-
const q =
|
|
10736
|
-
const snapshot = await
|
|
11408
|
+
const q = query23(this.getBrandsRef(), where23("isActive", "==", true));
|
|
11409
|
+
const snapshot = await getDocs23(q);
|
|
10737
11410
|
return snapshot.docs.map(
|
|
10738
|
-
(
|
|
10739
|
-
id:
|
|
10740
|
-
...
|
|
11411
|
+
(doc29) => ({
|
|
11412
|
+
id: doc29.id,
|
|
11413
|
+
...doc29.data()
|
|
10741
11414
|
})
|
|
10742
11415
|
);
|
|
10743
11416
|
}
|
|
@@ -10749,8 +11422,8 @@ var BrandService = class extends BaseService {
|
|
|
10749
11422
|
...brand,
|
|
10750
11423
|
updatedAt: /* @__PURE__ */ new Date()
|
|
10751
11424
|
};
|
|
10752
|
-
const docRef =
|
|
10753
|
-
await
|
|
11425
|
+
const docRef = doc24(this.getBrandsRef(), brandId);
|
|
11426
|
+
await updateDoc25(docRef, updateData);
|
|
10754
11427
|
return this.getById(brandId);
|
|
10755
11428
|
}
|
|
10756
11429
|
/**
|
|
@@ -10765,8 +11438,8 @@ var BrandService = class extends BaseService {
|
|
|
10765
11438
|
* Gets a brand by ID
|
|
10766
11439
|
*/
|
|
10767
11440
|
async getById(brandId) {
|
|
10768
|
-
const docRef =
|
|
10769
|
-
const docSnap = await
|
|
11441
|
+
const docRef = doc24(this.getBrandsRef(), brandId);
|
|
11442
|
+
const docSnap = await getDoc26(docRef);
|
|
10770
11443
|
if (!docSnap.exists()) return null;
|
|
10771
11444
|
return {
|
|
10772
11445
|
id: docSnap.id,
|
|
@@ -10778,13 +11451,13 @@ var BrandService = class extends BaseService {
|
|
|
10778
11451
|
// src/backoffice/services/category.service.ts
|
|
10779
11452
|
import {
|
|
10780
11453
|
addDoc as addDoc4,
|
|
10781
|
-
collection as
|
|
10782
|
-
doc as
|
|
10783
|
-
getDoc as
|
|
10784
|
-
getDocs as
|
|
10785
|
-
query as
|
|
10786
|
-
updateDoc as
|
|
10787
|
-
where as
|
|
11454
|
+
collection as collection24,
|
|
11455
|
+
doc as doc25,
|
|
11456
|
+
getDoc as getDoc27,
|
|
11457
|
+
getDocs as getDocs24,
|
|
11458
|
+
query as query24,
|
|
11459
|
+
updateDoc as updateDoc26,
|
|
11460
|
+
where as where24
|
|
10788
11461
|
} from "firebase/firestore";
|
|
10789
11462
|
|
|
10790
11463
|
// src/backoffice/types/category.types.ts
|
|
@@ -10796,7 +11469,7 @@ var CategoryService = class extends BaseService {
|
|
|
10796
11469
|
* Referenca na Firestore kolekciju kategorija
|
|
10797
11470
|
*/
|
|
10798
11471
|
get categoriesRef() {
|
|
10799
|
-
return
|
|
11472
|
+
return collection24(this.db, CATEGORIES_COLLECTION);
|
|
10800
11473
|
}
|
|
10801
11474
|
/**
|
|
10802
11475
|
* Kreira novu kategoriju u sistemu
|
|
@@ -10819,12 +11492,12 @@ var CategoryService = class extends BaseService {
|
|
|
10819
11492
|
* @returns Lista aktivnih kategorija
|
|
10820
11493
|
*/
|
|
10821
11494
|
async getAll() {
|
|
10822
|
-
const q =
|
|
10823
|
-
const snapshot = await
|
|
11495
|
+
const q = query24(this.categoriesRef, where24("isActive", "==", true));
|
|
11496
|
+
const snapshot = await getDocs24(q);
|
|
10824
11497
|
return snapshot.docs.map(
|
|
10825
|
-
(
|
|
10826
|
-
id:
|
|
10827
|
-
...
|
|
11498
|
+
(doc29) => ({
|
|
11499
|
+
id: doc29.id,
|
|
11500
|
+
...doc29.data()
|
|
10828
11501
|
})
|
|
10829
11502
|
);
|
|
10830
11503
|
}
|
|
@@ -10834,16 +11507,16 @@ var CategoryService = class extends BaseService {
|
|
|
10834
11507
|
* @returns Lista kategorija koje pripadaju traženoj familiji
|
|
10835
11508
|
*/
|
|
10836
11509
|
async getAllByFamily(family) {
|
|
10837
|
-
const q =
|
|
11510
|
+
const q = query24(
|
|
10838
11511
|
this.categoriesRef,
|
|
10839
|
-
|
|
10840
|
-
|
|
11512
|
+
where24("family", "==", family),
|
|
11513
|
+
where24("isActive", "==", true)
|
|
10841
11514
|
);
|
|
10842
|
-
const snapshot = await
|
|
11515
|
+
const snapshot = await getDocs24(q);
|
|
10843
11516
|
return snapshot.docs.map(
|
|
10844
|
-
(
|
|
10845
|
-
id:
|
|
10846
|
-
...
|
|
11517
|
+
(doc29) => ({
|
|
11518
|
+
id: doc29.id,
|
|
11519
|
+
...doc29.data()
|
|
10847
11520
|
})
|
|
10848
11521
|
);
|
|
10849
11522
|
}
|
|
@@ -10858,8 +11531,8 @@ var CategoryService = class extends BaseService {
|
|
|
10858
11531
|
...category,
|
|
10859
11532
|
updatedAt: /* @__PURE__ */ new Date()
|
|
10860
11533
|
};
|
|
10861
|
-
const docRef =
|
|
10862
|
-
await
|
|
11534
|
+
const docRef = doc25(this.categoriesRef, id);
|
|
11535
|
+
await updateDoc26(docRef, updateData);
|
|
10863
11536
|
return this.getById(id);
|
|
10864
11537
|
}
|
|
10865
11538
|
/**
|
|
@@ -10875,8 +11548,8 @@ var CategoryService = class extends BaseService {
|
|
|
10875
11548
|
* @returns Kategorija ili null ako ne postoji
|
|
10876
11549
|
*/
|
|
10877
11550
|
async getById(id) {
|
|
10878
|
-
const docRef =
|
|
10879
|
-
const docSnap = await
|
|
11551
|
+
const docRef = doc25(this.categoriesRef, id);
|
|
11552
|
+
const docSnap = await getDoc27(docRef);
|
|
10880
11553
|
if (!docSnap.exists()) return null;
|
|
10881
11554
|
return {
|
|
10882
11555
|
id: docSnap.id,
|
|
@@ -10888,13 +11561,13 @@ var CategoryService = class extends BaseService {
|
|
|
10888
11561
|
// src/backoffice/services/subcategory.service.ts
|
|
10889
11562
|
import {
|
|
10890
11563
|
addDoc as addDoc5,
|
|
10891
|
-
collection as
|
|
10892
|
-
doc as
|
|
10893
|
-
getDoc as
|
|
10894
|
-
getDocs as
|
|
10895
|
-
query as
|
|
10896
|
-
updateDoc as
|
|
10897
|
-
where as
|
|
11564
|
+
collection as collection25,
|
|
11565
|
+
doc as doc26,
|
|
11566
|
+
getDoc as getDoc28,
|
|
11567
|
+
getDocs as getDocs25,
|
|
11568
|
+
query as query25,
|
|
11569
|
+
updateDoc as updateDoc27,
|
|
11570
|
+
where as where25
|
|
10898
11571
|
} from "firebase/firestore";
|
|
10899
11572
|
|
|
10900
11573
|
// src/backoffice/types/subcategory.types.ts
|
|
@@ -10907,7 +11580,7 @@ var SubcategoryService = class extends BaseService {
|
|
|
10907
11580
|
* @param categoryId - ID roditeljske kategorije
|
|
10908
11581
|
*/
|
|
10909
11582
|
getSubcategoriesRef(categoryId) {
|
|
10910
|
-
return
|
|
11583
|
+
return collection25(
|
|
10911
11584
|
this.db,
|
|
10912
11585
|
CATEGORIES_COLLECTION,
|
|
10913
11586
|
categoryId,
|
|
@@ -10941,15 +11614,15 @@ var SubcategoryService = class extends BaseService {
|
|
|
10941
11614
|
* @returns Lista aktivnih podkategorija
|
|
10942
11615
|
*/
|
|
10943
11616
|
async getAllByCategoryId(categoryId) {
|
|
10944
|
-
const q =
|
|
11617
|
+
const q = query25(
|
|
10945
11618
|
this.getSubcategoriesRef(categoryId),
|
|
10946
|
-
|
|
11619
|
+
where25("isActive", "==", true)
|
|
10947
11620
|
);
|
|
10948
|
-
const snapshot = await
|
|
11621
|
+
const snapshot = await getDocs25(q);
|
|
10949
11622
|
return snapshot.docs.map(
|
|
10950
|
-
(
|
|
10951
|
-
id:
|
|
10952
|
-
...
|
|
11623
|
+
(doc29) => ({
|
|
11624
|
+
id: doc29.id,
|
|
11625
|
+
...doc29.data()
|
|
10953
11626
|
})
|
|
10954
11627
|
);
|
|
10955
11628
|
}
|
|
@@ -10965,8 +11638,8 @@ var SubcategoryService = class extends BaseService {
|
|
|
10965
11638
|
...subcategory,
|
|
10966
11639
|
updatedAt: /* @__PURE__ */ new Date()
|
|
10967
11640
|
};
|
|
10968
|
-
const docRef =
|
|
10969
|
-
await
|
|
11641
|
+
const docRef = doc26(this.getSubcategoriesRef(categoryId), subcategoryId);
|
|
11642
|
+
await updateDoc27(docRef, updateData);
|
|
10970
11643
|
return this.getById(categoryId, subcategoryId);
|
|
10971
11644
|
}
|
|
10972
11645
|
/**
|
|
@@ -10984,8 +11657,8 @@ var SubcategoryService = class extends BaseService {
|
|
|
10984
11657
|
* @returns Podkategorija ili null ako ne postoji
|
|
10985
11658
|
*/
|
|
10986
11659
|
async getById(categoryId, subcategoryId) {
|
|
10987
|
-
const docRef =
|
|
10988
|
-
const docSnap = await
|
|
11660
|
+
const docRef = doc26(this.getSubcategoriesRef(categoryId), subcategoryId);
|
|
11661
|
+
const docSnap = await getDoc28(docRef);
|
|
10989
11662
|
if (!docSnap.exists()) return null;
|
|
10990
11663
|
return {
|
|
10991
11664
|
id: docSnap.id,
|
|
@@ -10997,13 +11670,13 @@ var SubcategoryService = class extends BaseService {
|
|
|
10997
11670
|
// src/backoffice/services/technology.service.ts
|
|
10998
11671
|
import {
|
|
10999
11672
|
addDoc as addDoc6,
|
|
11000
|
-
collection as
|
|
11001
|
-
doc as
|
|
11002
|
-
getDoc as
|
|
11003
|
-
getDocs as
|
|
11004
|
-
query as
|
|
11005
|
-
updateDoc as
|
|
11006
|
-
where as
|
|
11673
|
+
collection as collection26,
|
|
11674
|
+
doc as doc27,
|
|
11675
|
+
getDoc as getDoc29,
|
|
11676
|
+
getDocs as getDocs26,
|
|
11677
|
+
query as query26,
|
|
11678
|
+
updateDoc as updateDoc28,
|
|
11679
|
+
where as where26,
|
|
11007
11680
|
arrayUnion as arrayUnion8,
|
|
11008
11681
|
arrayRemove as arrayRemove7
|
|
11009
11682
|
} from "firebase/firestore";
|
|
@@ -11021,7 +11694,7 @@ var TechnologyService = class extends BaseService {
|
|
|
11021
11694
|
* Vraća referencu na Firestore kolekciju tehnologija
|
|
11022
11695
|
*/
|
|
11023
11696
|
getTechnologiesRef() {
|
|
11024
|
-
return
|
|
11697
|
+
return collection26(this.db, TECHNOLOGIES_COLLECTION);
|
|
11025
11698
|
}
|
|
11026
11699
|
/**
|
|
11027
11700
|
* Kreira novu tehnologiju
|
|
@@ -11052,12 +11725,12 @@ var TechnologyService = class extends BaseService {
|
|
|
11052
11725
|
* @returns Lista aktivnih tehnologija
|
|
11053
11726
|
*/
|
|
11054
11727
|
async getAll() {
|
|
11055
|
-
const q =
|
|
11056
|
-
const snapshot = await
|
|
11728
|
+
const q = query26(this.getTechnologiesRef(), where26("isActive", "==", true));
|
|
11729
|
+
const snapshot = await getDocs26(q);
|
|
11057
11730
|
return snapshot.docs.map(
|
|
11058
|
-
(
|
|
11059
|
-
id:
|
|
11060
|
-
...
|
|
11731
|
+
(doc29) => ({
|
|
11732
|
+
id: doc29.id,
|
|
11733
|
+
...doc29.data()
|
|
11061
11734
|
})
|
|
11062
11735
|
);
|
|
11063
11736
|
}
|
|
@@ -11067,16 +11740,16 @@ var TechnologyService = class extends BaseService {
|
|
|
11067
11740
|
* @returns Lista aktivnih tehnologija
|
|
11068
11741
|
*/
|
|
11069
11742
|
async getAllByFamily(family) {
|
|
11070
|
-
const q =
|
|
11743
|
+
const q = query26(
|
|
11071
11744
|
this.getTechnologiesRef(),
|
|
11072
|
-
|
|
11073
|
-
|
|
11745
|
+
where26("isActive", "==", true),
|
|
11746
|
+
where26("family", "==", family)
|
|
11074
11747
|
);
|
|
11075
|
-
const snapshot = await
|
|
11748
|
+
const snapshot = await getDocs26(q);
|
|
11076
11749
|
return snapshot.docs.map(
|
|
11077
|
-
(
|
|
11078
|
-
id:
|
|
11079
|
-
...
|
|
11750
|
+
(doc29) => ({
|
|
11751
|
+
id: doc29.id,
|
|
11752
|
+
...doc29.data()
|
|
11080
11753
|
})
|
|
11081
11754
|
);
|
|
11082
11755
|
}
|
|
@@ -11086,16 +11759,16 @@ var TechnologyService = class extends BaseService {
|
|
|
11086
11759
|
* @returns Lista aktivnih tehnologija
|
|
11087
11760
|
*/
|
|
11088
11761
|
async getAllByCategoryId(categoryId) {
|
|
11089
|
-
const q =
|
|
11762
|
+
const q = query26(
|
|
11090
11763
|
this.getTechnologiesRef(),
|
|
11091
|
-
|
|
11092
|
-
|
|
11764
|
+
where26("isActive", "==", true),
|
|
11765
|
+
where26("categoryId", "==", categoryId)
|
|
11093
11766
|
);
|
|
11094
|
-
const snapshot = await
|
|
11767
|
+
const snapshot = await getDocs26(q);
|
|
11095
11768
|
return snapshot.docs.map(
|
|
11096
|
-
(
|
|
11097
|
-
id:
|
|
11098
|
-
...
|
|
11769
|
+
(doc29) => ({
|
|
11770
|
+
id: doc29.id,
|
|
11771
|
+
...doc29.data()
|
|
11099
11772
|
})
|
|
11100
11773
|
);
|
|
11101
11774
|
}
|
|
@@ -11105,16 +11778,16 @@ var TechnologyService = class extends BaseService {
|
|
|
11105
11778
|
* @returns Lista aktivnih tehnologija
|
|
11106
11779
|
*/
|
|
11107
11780
|
async getAllBySubcategoryId(subcategoryId) {
|
|
11108
|
-
const q =
|
|
11781
|
+
const q = query26(
|
|
11109
11782
|
this.getTechnologiesRef(),
|
|
11110
|
-
|
|
11111
|
-
|
|
11783
|
+
where26("isActive", "==", true),
|
|
11784
|
+
where26("subcategoryId", "==", subcategoryId)
|
|
11112
11785
|
);
|
|
11113
|
-
const snapshot = await
|
|
11786
|
+
const snapshot = await getDocs26(q);
|
|
11114
11787
|
return snapshot.docs.map(
|
|
11115
|
-
(
|
|
11116
|
-
id:
|
|
11117
|
-
...
|
|
11788
|
+
(doc29) => ({
|
|
11789
|
+
id: doc29.id,
|
|
11790
|
+
...doc29.data()
|
|
11118
11791
|
})
|
|
11119
11792
|
);
|
|
11120
11793
|
}
|
|
@@ -11129,8 +11802,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11129
11802
|
...technology,
|
|
11130
11803
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11131
11804
|
};
|
|
11132
|
-
const docRef =
|
|
11133
|
-
await
|
|
11805
|
+
const docRef = doc27(this.getTechnologiesRef(), technologyId);
|
|
11806
|
+
await updateDoc28(docRef, updateData);
|
|
11134
11807
|
return this.getById(technologyId);
|
|
11135
11808
|
}
|
|
11136
11809
|
/**
|
|
@@ -11148,8 +11821,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11148
11821
|
* @returns Tehnologija ili null ako ne postoji
|
|
11149
11822
|
*/
|
|
11150
11823
|
async getById(technologyId) {
|
|
11151
|
-
const docRef =
|
|
11152
|
-
const docSnap = await
|
|
11824
|
+
const docRef = doc27(this.getTechnologiesRef(), technologyId);
|
|
11825
|
+
const docSnap = await getDoc29(docRef);
|
|
11153
11826
|
if (!docSnap.exists()) return null;
|
|
11154
11827
|
return {
|
|
11155
11828
|
id: docSnap.id,
|
|
@@ -11163,9 +11836,9 @@ var TechnologyService = class extends BaseService {
|
|
|
11163
11836
|
* @returns Ažurirana tehnologija sa novim zahtevom
|
|
11164
11837
|
*/
|
|
11165
11838
|
async addRequirement(technologyId, requirement) {
|
|
11166
|
-
const docRef =
|
|
11839
|
+
const docRef = doc27(this.getTechnologiesRef(), technologyId);
|
|
11167
11840
|
const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
|
|
11168
|
-
await
|
|
11841
|
+
await updateDoc28(docRef, {
|
|
11169
11842
|
[requirementType]: arrayUnion8(requirement),
|
|
11170
11843
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11171
11844
|
});
|
|
@@ -11178,9 +11851,9 @@ var TechnologyService = class extends BaseService {
|
|
|
11178
11851
|
* @returns Ažurirana tehnologija bez uklonjenog zahteva
|
|
11179
11852
|
*/
|
|
11180
11853
|
async removeRequirement(technologyId, requirement) {
|
|
11181
|
-
const docRef =
|
|
11854
|
+
const docRef = doc27(this.getTechnologiesRef(), technologyId);
|
|
11182
11855
|
const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
|
|
11183
|
-
await
|
|
11856
|
+
await updateDoc28(docRef, {
|
|
11184
11857
|
[requirementType]: arrayRemove7(requirement),
|
|
11185
11858
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11186
11859
|
});
|
|
@@ -11218,8 +11891,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11218
11891
|
* @returns Ažurirana tehnologija
|
|
11219
11892
|
*/
|
|
11220
11893
|
async addBlockingCondition(technologyId, condition) {
|
|
11221
|
-
const docRef =
|
|
11222
|
-
await
|
|
11894
|
+
const docRef = doc27(this.getTechnologiesRef(), technologyId);
|
|
11895
|
+
await updateDoc28(docRef, {
|
|
11223
11896
|
blockingConditions: arrayUnion8(condition),
|
|
11224
11897
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11225
11898
|
});
|
|
@@ -11232,8 +11905,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11232
11905
|
* @returns Ažurirana tehnologija
|
|
11233
11906
|
*/
|
|
11234
11907
|
async removeBlockingCondition(technologyId, condition) {
|
|
11235
|
-
const docRef =
|
|
11236
|
-
await
|
|
11908
|
+
const docRef = doc27(this.getTechnologiesRef(), technologyId);
|
|
11909
|
+
await updateDoc28(docRef, {
|
|
11237
11910
|
blockingConditions: arrayRemove7(condition),
|
|
11238
11911
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11239
11912
|
});
|
|
@@ -11246,8 +11919,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11246
11919
|
* @returns Ažurirana tehnologija
|
|
11247
11920
|
*/
|
|
11248
11921
|
async addContraindication(technologyId, contraindication) {
|
|
11249
|
-
const docRef =
|
|
11250
|
-
await
|
|
11922
|
+
const docRef = doc27(this.getTechnologiesRef(), technologyId);
|
|
11923
|
+
await updateDoc28(docRef, {
|
|
11251
11924
|
contraindications: arrayUnion8(contraindication),
|
|
11252
11925
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11253
11926
|
});
|
|
@@ -11260,8 +11933,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11260
11933
|
* @returns Ažurirana tehnologija
|
|
11261
11934
|
*/
|
|
11262
11935
|
async removeContraindication(technologyId, contraindication) {
|
|
11263
|
-
const docRef =
|
|
11264
|
-
await
|
|
11936
|
+
const docRef = doc27(this.getTechnologiesRef(), technologyId);
|
|
11937
|
+
await updateDoc28(docRef, {
|
|
11265
11938
|
contraindications: arrayRemove7(contraindication),
|
|
11266
11939
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11267
11940
|
});
|
|
@@ -11274,8 +11947,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11274
11947
|
* @returns Ažurirana tehnologija
|
|
11275
11948
|
*/
|
|
11276
11949
|
async addBenefit(technologyId, benefit) {
|
|
11277
|
-
const docRef =
|
|
11278
|
-
await
|
|
11950
|
+
const docRef = doc27(this.getTechnologiesRef(), technologyId);
|
|
11951
|
+
await updateDoc28(docRef, {
|
|
11279
11952
|
benefits: arrayUnion8(benefit),
|
|
11280
11953
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11281
11954
|
});
|
|
@@ -11288,8 +11961,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11288
11961
|
* @returns Ažurirana tehnologija
|
|
11289
11962
|
*/
|
|
11290
11963
|
async removeBenefit(technologyId, benefit) {
|
|
11291
|
-
const docRef =
|
|
11292
|
-
await
|
|
11964
|
+
const docRef = doc27(this.getTechnologiesRef(), technologyId);
|
|
11965
|
+
await updateDoc28(docRef, {
|
|
11293
11966
|
benefits: arrayRemove7(benefit),
|
|
11294
11967
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11295
11968
|
});
|
|
@@ -11329,8 +12002,8 @@ var TechnologyService = class extends BaseService {
|
|
|
11329
12002
|
* @returns Ažurirana tehnologija
|
|
11330
12003
|
*/
|
|
11331
12004
|
async updateCertificationRequirement(technologyId, certificationRequirement) {
|
|
11332
|
-
const docRef =
|
|
11333
|
-
await
|
|
12005
|
+
const docRef = doc27(this.getTechnologiesRef(), technologyId);
|
|
12006
|
+
await updateDoc28(docRef, {
|
|
11334
12007
|
certificationRequirement,
|
|
11335
12008
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11336
12009
|
});
|
|
@@ -11432,13 +12105,13 @@ var TechnologyService = class extends BaseService {
|
|
|
11432
12105
|
// src/backoffice/services/product.service.ts
|
|
11433
12106
|
import {
|
|
11434
12107
|
addDoc as addDoc7,
|
|
11435
|
-
collection as
|
|
11436
|
-
doc as
|
|
11437
|
-
getDoc as
|
|
11438
|
-
getDocs as
|
|
11439
|
-
query as
|
|
11440
|
-
updateDoc as
|
|
11441
|
-
where as
|
|
12108
|
+
collection as collection27,
|
|
12109
|
+
doc as doc28,
|
|
12110
|
+
getDoc as getDoc30,
|
|
12111
|
+
getDocs as getDocs27,
|
|
12112
|
+
query as query27,
|
|
12113
|
+
updateDoc as updateDoc29,
|
|
12114
|
+
where as where27
|
|
11442
12115
|
} from "firebase/firestore";
|
|
11443
12116
|
|
|
11444
12117
|
// src/backoffice/types/product.types.ts
|
|
@@ -11452,7 +12125,7 @@ var ProductService = class extends BaseService {
|
|
|
11452
12125
|
* @returns Firestore collection reference
|
|
11453
12126
|
*/
|
|
11454
12127
|
getProductsRef(technologyId) {
|
|
11455
|
-
return
|
|
12128
|
+
return collection27(
|
|
11456
12129
|
this.db,
|
|
11457
12130
|
TECHNOLOGIES_COLLECTION,
|
|
11458
12131
|
technologyId,
|
|
@@ -11482,15 +12155,15 @@ var ProductService = class extends BaseService {
|
|
|
11482
12155
|
* Gets all products for a technology
|
|
11483
12156
|
*/
|
|
11484
12157
|
async getAllByTechnology(technologyId) {
|
|
11485
|
-
const q =
|
|
12158
|
+
const q = query27(
|
|
11486
12159
|
this.getProductsRef(technologyId),
|
|
11487
|
-
|
|
12160
|
+
where27("isActive", "==", true)
|
|
11488
12161
|
);
|
|
11489
|
-
const snapshot = await
|
|
12162
|
+
const snapshot = await getDocs27(q);
|
|
11490
12163
|
return snapshot.docs.map(
|
|
11491
|
-
(
|
|
11492
|
-
id:
|
|
11493
|
-
...
|
|
12164
|
+
(doc29) => ({
|
|
12165
|
+
id: doc29.id,
|
|
12166
|
+
...doc29.data()
|
|
11494
12167
|
})
|
|
11495
12168
|
);
|
|
11496
12169
|
}
|
|
@@ -11498,21 +12171,21 @@ var ProductService = class extends BaseService {
|
|
|
11498
12171
|
* Gets all products for a brand by filtering through all technologies
|
|
11499
12172
|
*/
|
|
11500
12173
|
async getAllByBrand(brandId) {
|
|
11501
|
-
const allTechnologiesRef =
|
|
11502
|
-
const technologiesSnapshot = await
|
|
12174
|
+
const allTechnologiesRef = collection27(this.db, TECHNOLOGIES_COLLECTION);
|
|
12175
|
+
const technologiesSnapshot = await getDocs27(allTechnologiesRef);
|
|
11503
12176
|
const products = [];
|
|
11504
12177
|
for (const techDoc of technologiesSnapshot.docs) {
|
|
11505
|
-
const q =
|
|
12178
|
+
const q = query27(
|
|
11506
12179
|
this.getProductsRef(techDoc.id),
|
|
11507
|
-
|
|
11508
|
-
|
|
12180
|
+
where27("brandId", "==", brandId),
|
|
12181
|
+
where27("isActive", "==", true)
|
|
11509
12182
|
);
|
|
11510
|
-
const snapshot = await
|
|
12183
|
+
const snapshot = await getDocs27(q);
|
|
11511
12184
|
products.push(
|
|
11512
12185
|
...snapshot.docs.map(
|
|
11513
|
-
(
|
|
11514
|
-
id:
|
|
11515
|
-
...
|
|
12186
|
+
(doc29) => ({
|
|
12187
|
+
id: doc29.id,
|
|
12188
|
+
...doc29.data()
|
|
11516
12189
|
})
|
|
11517
12190
|
)
|
|
11518
12191
|
);
|
|
@@ -11527,8 +12200,8 @@ var ProductService = class extends BaseService {
|
|
|
11527
12200
|
...product,
|
|
11528
12201
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11529
12202
|
};
|
|
11530
|
-
const docRef =
|
|
11531
|
-
await
|
|
12203
|
+
const docRef = doc28(this.getProductsRef(technologyId), productId);
|
|
12204
|
+
await updateDoc29(docRef, updateData);
|
|
11532
12205
|
return this.getById(technologyId, productId);
|
|
11533
12206
|
}
|
|
11534
12207
|
/**
|
|
@@ -11543,8 +12216,8 @@ var ProductService = class extends BaseService {
|
|
|
11543
12216
|
* Gets a product by ID
|
|
11544
12217
|
*/
|
|
11545
12218
|
async getById(technologyId, productId) {
|
|
11546
|
-
const docRef =
|
|
11547
|
-
const docSnap = await
|
|
12219
|
+
const docRef = doc28(this.getProductsRef(technologyId), productId);
|
|
12220
|
+
const docSnap = await getDoc30(docRef);
|
|
11548
12221
|
if (!docSnap.exists()) return null;
|
|
11549
12222
|
return {
|
|
11550
12223
|
id: docSnap.id,
|
|
@@ -11554,54 +12227,54 @@ var ProductService = class extends BaseService {
|
|
|
11554
12227
|
};
|
|
11555
12228
|
|
|
11556
12229
|
// src/validations/notification.schema.ts
|
|
11557
|
-
import { z as
|
|
11558
|
-
var baseNotificationSchema =
|
|
11559
|
-
id:
|
|
11560
|
-
userId:
|
|
11561
|
-
notificationTime:
|
|
12230
|
+
import { z as z22 } from "zod";
|
|
12231
|
+
var baseNotificationSchema = z22.object({
|
|
12232
|
+
id: z22.string().optional(),
|
|
12233
|
+
userId: z22.string(),
|
|
12234
|
+
notificationTime: z22.any(),
|
|
11562
12235
|
// Timestamp
|
|
11563
|
-
notificationType:
|
|
11564
|
-
notificationTokens:
|
|
11565
|
-
status:
|
|
11566
|
-
createdAt:
|
|
12236
|
+
notificationType: z22.nativeEnum(NotificationType),
|
|
12237
|
+
notificationTokens: z22.array(z22.string()),
|
|
12238
|
+
status: z22.nativeEnum(NotificationStatus),
|
|
12239
|
+
createdAt: z22.any().optional(),
|
|
11567
12240
|
// Timestamp
|
|
11568
|
-
updatedAt:
|
|
12241
|
+
updatedAt: z22.any().optional(),
|
|
11569
12242
|
// Timestamp
|
|
11570
|
-
title:
|
|
11571
|
-
body:
|
|
11572
|
-
isRead:
|
|
11573
|
-
userRole:
|
|
12243
|
+
title: z22.string(),
|
|
12244
|
+
body: z22.string(),
|
|
12245
|
+
isRead: z22.boolean(),
|
|
12246
|
+
userRole: z22.nativeEnum(UserRole)
|
|
11574
12247
|
});
|
|
11575
12248
|
var preRequirementNotificationSchema = baseNotificationSchema.extend({
|
|
11576
|
-
notificationType:
|
|
11577
|
-
treatmentId:
|
|
11578
|
-
requirements:
|
|
11579
|
-
deadline:
|
|
12249
|
+
notificationType: z22.literal("preRequirement" /* PRE_REQUIREMENT */),
|
|
12250
|
+
treatmentId: z22.string(),
|
|
12251
|
+
requirements: z22.array(z22.string()),
|
|
12252
|
+
deadline: z22.any()
|
|
11580
12253
|
// Timestamp
|
|
11581
12254
|
});
|
|
11582
12255
|
var postRequirementNotificationSchema = baseNotificationSchema.extend({
|
|
11583
|
-
notificationType:
|
|
11584
|
-
treatmentId:
|
|
11585
|
-
requirements:
|
|
11586
|
-
deadline:
|
|
12256
|
+
notificationType: z22.literal("postRequirement" /* POST_REQUIREMENT */),
|
|
12257
|
+
treatmentId: z22.string(),
|
|
12258
|
+
requirements: z22.array(z22.string()),
|
|
12259
|
+
deadline: z22.any()
|
|
11587
12260
|
// Timestamp
|
|
11588
12261
|
});
|
|
11589
12262
|
var appointmentReminderNotificationSchema = baseNotificationSchema.extend({
|
|
11590
|
-
notificationType:
|
|
11591
|
-
appointmentId:
|
|
11592
|
-
appointmentTime:
|
|
12263
|
+
notificationType: z22.literal("appointmentReminder" /* APPOINTMENT_REMINDER */),
|
|
12264
|
+
appointmentId: z22.string(),
|
|
12265
|
+
appointmentTime: z22.any(),
|
|
11593
12266
|
// Timestamp
|
|
11594
|
-
treatmentType:
|
|
11595
|
-
doctorName:
|
|
12267
|
+
treatmentType: z22.string(),
|
|
12268
|
+
doctorName: z22.string()
|
|
11596
12269
|
});
|
|
11597
12270
|
var appointmentNotificationSchema = baseNotificationSchema.extend({
|
|
11598
|
-
notificationType:
|
|
11599
|
-
appointmentId:
|
|
11600
|
-
appointmentStatus:
|
|
11601
|
-
previousStatus:
|
|
11602
|
-
reason:
|
|
12271
|
+
notificationType: z22.literal("appointmentNotification" /* APPOINTMENT_NOTIFICATION */),
|
|
12272
|
+
appointmentId: z22.string(),
|
|
12273
|
+
appointmentStatus: z22.string(),
|
|
12274
|
+
previousStatus: z22.string(),
|
|
12275
|
+
reason: z22.string().optional()
|
|
11603
12276
|
});
|
|
11604
|
-
var notificationSchema =
|
|
12277
|
+
var notificationSchema = z22.discriminatedUnion("notificationType", [
|
|
11605
12278
|
preRequirementNotificationSchema,
|
|
11606
12279
|
postRequirementNotificationSchema,
|
|
11607
12280
|
appointmentReminderNotificationSchema,
|
|
@@ -11628,8 +12301,17 @@ var TreatmentBenefit = /* @__PURE__ */ ((TreatmentBenefit2) => {
|
|
|
11628
12301
|
return TreatmentBenefit2;
|
|
11629
12302
|
})(TreatmentBenefit || {});
|
|
11630
12303
|
|
|
11631
|
-
// src/types/
|
|
11632
|
-
var
|
|
12304
|
+
// src/backoffice/types/requirement.types.ts
|
|
12305
|
+
var TimeUnit = /* @__PURE__ */ ((TimeUnit2) => {
|
|
12306
|
+
TimeUnit2["HOURS"] = "hours";
|
|
12307
|
+
TimeUnit2["DAYS"] = "days";
|
|
12308
|
+
return TimeUnit2;
|
|
12309
|
+
})(TimeUnit || {});
|
|
12310
|
+
var RequirementType = /* @__PURE__ */ ((RequirementType2) => {
|
|
12311
|
+
RequirementType2["PRE"] = "pre";
|
|
12312
|
+
RequirementType2["POST"] = "post";
|
|
12313
|
+
return RequirementType2;
|
|
12314
|
+
})(RequirementType || {});
|
|
11633
12315
|
export {
|
|
11634
12316
|
AUTH_ERRORS,
|
|
11635
12317
|
AdminTokenStatus,
|
|
@@ -11693,6 +12375,8 @@ export {
|
|
|
11693
12375
|
ProductService,
|
|
11694
12376
|
REGISTER_TOKENS_COLLECTION,
|
|
11695
12377
|
REVIEWS_COLLECTION,
|
|
12378
|
+
RequirementType,
|
|
12379
|
+
ReviewService,
|
|
11696
12380
|
SYNCED_CALENDARS_COLLECTION,
|
|
11697
12381
|
SearchLocationEnum,
|
|
11698
12382
|
SubcategoryService,
|
|
@@ -11700,6 +12384,7 @@ export {
|
|
|
11700
12384
|
SyncedCalendarProvider,
|
|
11701
12385
|
SyncedCalendarsService,
|
|
11702
12386
|
TechnologyService,
|
|
12387
|
+
TimeUnit,
|
|
11703
12388
|
TreatmentBenefit,
|
|
11704
12389
|
USER_ERRORS,
|
|
11705
12390
|
UserService,
|