@blackcode_sa/metaestetics-api 1.11.3 → 1.12.1
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 +378 -334
- package/dist/admin/index.d.ts +378 -334
- package/dist/backoffice/index.d.mts +1198 -430
- package/dist/backoffice/index.d.ts +1198 -430
- package/dist/backoffice/index.js +1128 -245
- package/dist/backoffice/index.mjs +1119 -209
- package/dist/index.d.mts +4478 -4031
- package/dist/index.d.ts +4478 -4031
- package/dist/index.js +1974 -757
- package/dist/index.mjs +1735 -490
- package/package.json +1 -1
- package/src/backoffice/expo-safe/index.ts +4 -0
- package/src/backoffice/services/README.md +40 -0
- package/src/backoffice/services/brand.service.ts +85 -6
- package/src/backoffice/services/category.service.ts +92 -10
- package/src/backoffice/services/constants.service.ts +308 -0
- package/src/backoffice/services/documentation-template.service.ts +56 -2
- package/src/backoffice/services/index.ts +1 -0
- package/src/backoffice/services/product.service.ts +126 -5
- package/src/backoffice/services/requirement.service.ts +13 -0
- package/src/backoffice/services/subcategory.service.ts +184 -13
- package/src/backoffice/services/technology.service.ts +344 -129
- package/src/backoffice/types/admin-constants.types.ts +69 -0
- package/src/backoffice/types/brand.types.ts +1 -0
- package/src/backoffice/types/index.ts +2 -0
- package/src/backoffice/types/procedure-product.types.ts +38 -0
- package/src/backoffice/types/product.types.ts +31 -4
- package/src/backoffice/types/static/contraindication.types.ts +1 -0
- package/src/backoffice/types/static/treatment-benefit.types.ts +1 -0
- package/src/backoffice/types/technology.types.ts +113 -4
- package/src/backoffice/validations/schemas.ts +35 -9
- package/src/services/appointment/appointment.service.ts +0 -5
- package/src/services/appointment/utils/appointment.utils.ts +124 -113
- package/src/services/base.service.ts +10 -3
- package/src/services/documentation-templates/documentation-template.service.ts +116 -0
- package/src/services/media/media.service.ts +2 -2
- package/src/services/practitioner/practitioner.service.ts +201 -83
- package/src/services/procedure/README.md +76 -1
- package/src/services/procedure/procedure.service.ts +538 -235
- package/src/types/appointment/index.ts +2 -3
- package/src/types/clinic/index.ts +1 -6
- package/src/types/patient/medical-info.types.ts +3 -3
- package/src/types/procedure/index.ts +39 -20
- package/src/validations/clinic.schema.ts +1 -6
- package/src/validations/patient/medical-info.schema.ts +7 -2
- package/src/validations/procedure-product.schema.ts +41 -0
- package/src/validations/procedure.schema.ts +59 -8
- package/src/backoffice/services/__tests__/brand.service.test.ts +0 -196
- package/src/backoffice/services/__tests__/category.service.test.ts +0 -201
- package/src/backoffice/services/__tests__/product.service.test.ts +0 -358
- package/src/backoffice/services/__tests__/requirement.service.test.ts +0 -226
- package/src/backoffice/services/__tests__/subcategory.service.test.ts +0 -181
- package/src/backoffice/services/__tests__/technology.service.test.ts +0 -1097
package/dist/index.js
CHANGED
|
@@ -56,6 +56,7 @@ __export(index_exports, {
|
|
|
56
56
|
ClinicPhotoTag: () => ClinicPhotoTag,
|
|
57
57
|
ClinicService: () => ClinicService,
|
|
58
58
|
ClinicTag: () => ClinicTag,
|
|
59
|
+
ConstantsService: () => ConstantsService,
|
|
59
60
|
Contraindication: () => Contraindication,
|
|
60
61
|
CosmeticAllergySubtype: () => CosmeticAllergySubtype,
|
|
61
62
|
Currency: () => Currency,
|
|
@@ -145,11 +146,13 @@ var import_functions = require("firebase/functions");
|
|
|
145
146
|
// src/services/base.service.ts
|
|
146
147
|
var import_storage = require("firebase/storage");
|
|
147
148
|
var BaseService = class {
|
|
148
|
-
constructor(db, auth, app) {
|
|
149
|
+
constructor(db, auth, app, storage) {
|
|
149
150
|
this.db = db;
|
|
150
151
|
this.auth = auth;
|
|
151
152
|
this.app = app;
|
|
152
|
-
|
|
153
|
+
if (app) {
|
|
154
|
+
this.storage = storage || (0, import_storage.getStorage)(app);
|
|
155
|
+
}
|
|
153
156
|
}
|
|
154
157
|
/**
|
|
155
158
|
* Generiše jedinstveni ID za dokumente
|
|
@@ -181,13 +184,13 @@ var AppointmentStatus = /* @__PURE__ */ ((AppointmentStatus2) => {
|
|
|
181
184
|
AppointmentStatus2["RESCHEDULED_BY_CLINIC"] = "rescheduled_by_clinic";
|
|
182
185
|
return AppointmentStatus2;
|
|
183
186
|
})(AppointmentStatus || {});
|
|
184
|
-
var PaymentStatus = /* @__PURE__ */ ((
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
return
|
|
187
|
+
var PaymentStatus = /* @__PURE__ */ ((PaymentStatus4) => {
|
|
188
|
+
PaymentStatus4["UNPAID"] = "unpaid";
|
|
189
|
+
PaymentStatus4["PAID"] = "paid";
|
|
190
|
+
PaymentStatus4["PARTIALLY_PAID"] = "partially_paid";
|
|
191
|
+
PaymentStatus4["REFUNDED"] = "refunded";
|
|
192
|
+
PaymentStatus4["NOT_APPLICABLE"] = "not_applicable";
|
|
193
|
+
return PaymentStatus4;
|
|
191
194
|
})(PaymentStatus || {});
|
|
192
195
|
var MediaType = /* @__PURE__ */ ((MediaType2) => {
|
|
193
196
|
MediaType2["BEFORE_PHOTO"] = "before_photo";
|
|
@@ -933,44 +936,48 @@ async function updateAppointmentUtil(db, appointmentId, data) {
|
|
|
933
936
|
const validPreReqIds = currentAppointment.preProcedureRequirements.map(
|
|
934
937
|
(req) => req.id
|
|
935
938
|
);
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
if (invalidPreReqIds.length > 0) {
|
|
940
|
-
throw new Error(
|
|
941
|
-
`Invalid pre-requirement IDs: ${invalidPreReqIds.join(", ")}`
|
|
939
|
+
if (Array.isArray(data.completedPreRequirements)) {
|
|
940
|
+
const invalidPreReqIds = data.completedPreRequirements.filter(
|
|
941
|
+
(id) => !validPreReqIds.includes(id)
|
|
942
942
|
);
|
|
943
|
+
if (invalidPreReqIds.length > 0) {
|
|
944
|
+
throw new Error(
|
|
945
|
+
`Invalid pre-requirement IDs: ${invalidPreReqIds.join(", ")}`
|
|
946
|
+
);
|
|
947
|
+
}
|
|
948
|
+
completedPreRequirements = [
|
|
949
|
+
.../* @__PURE__ */ new Set([
|
|
950
|
+
...completedPreRequirements,
|
|
951
|
+
...data.completedPreRequirements
|
|
952
|
+
])
|
|
953
|
+
];
|
|
943
954
|
}
|
|
944
|
-
completedPreRequirements = [
|
|
945
|
-
.../* @__PURE__ */ new Set([
|
|
946
|
-
...completedPreRequirements,
|
|
947
|
-
...data.completedPreRequirements
|
|
948
|
-
])
|
|
949
|
-
];
|
|
950
955
|
}
|
|
951
956
|
if (data.completedPostRequirements) {
|
|
952
957
|
const validPostReqIds = currentAppointment.postProcedureRequirements.map(
|
|
953
958
|
(req) => req.id
|
|
954
959
|
);
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
if (invalidPostReqIds.length > 0) {
|
|
959
|
-
throw new Error(
|
|
960
|
-
`Invalid post-requirement IDs: ${invalidPostReqIds.join(", ")}`
|
|
960
|
+
if (Array.isArray(data.completedPostRequirements)) {
|
|
961
|
+
const invalidPostReqIds = data.completedPostRequirements.filter(
|
|
962
|
+
(id) => !validPostReqIds.includes(id)
|
|
961
963
|
);
|
|
964
|
+
if (invalidPostReqIds.length > 0) {
|
|
965
|
+
throw new Error(
|
|
966
|
+
`Invalid post-requirement IDs: ${invalidPostReqIds.join(", ")}`
|
|
967
|
+
);
|
|
968
|
+
}
|
|
969
|
+
completedPostRequirements = [
|
|
970
|
+
.../* @__PURE__ */ new Set([
|
|
971
|
+
...completedPostRequirements,
|
|
972
|
+
...data.completedPostRequirements
|
|
973
|
+
])
|
|
974
|
+
];
|
|
962
975
|
}
|
|
963
|
-
completedPostRequirements = [
|
|
964
|
-
.../* @__PURE__ */ new Set([
|
|
965
|
-
...completedPostRequirements,
|
|
966
|
-
...data.completedPostRequirements
|
|
967
|
-
])
|
|
968
|
-
];
|
|
969
976
|
}
|
|
970
977
|
const updateData = {
|
|
971
978
|
...data,
|
|
972
|
-
completedPreRequirements,
|
|
973
|
-
completedPostRequirements,
|
|
979
|
+
completedPreRequirements: Array.isArray(data.completedPreRequirements) ? completedPreRequirements : data.completedPreRequirements,
|
|
980
|
+
completedPostRequirements: Array.isArray(data.completedPostRequirements) ? completedPostRequirements : data.completedPostRequirements,
|
|
974
981
|
updatedAt: (0, import_firestore.serverTimestamp)()
|
|
975
982
|
};
|
|
976
983
|
Object.keys(updateData).forEach((key) => {
|
|
@@ -1020,7 +1027,7 @@ async function updateCalendarEventStatus(db, calendarEventId, appointmentStatus)
|
|
|
1020
1027
|
case "canceled_clinic" /* CANCELED_CLINIC */:
|
|
1021
1028
|
calendarStatus = "canceled";
|
|
1022
1029
|
break;
|
|
1023
|
-
case
|
|
1030
|
+
case "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */:
|
|
1024
1031
|
calendarStatus = "rescheduled";
|
|
1025
1032
|
break;
|
|
1026
1033
|
case "completed" /* COMPLETED */:
|
|
@@ -1094,7 +1101,7 @@ async function searchAppointmentsUtil(db, params) {
|
|
|
1094
1101
|
const q = (0, import_firestore.query)((0, import_firestore.collection)(db, APPOINTMENTS_COLLECTION), ...constraints);
|
|
1095
1102
|
const querySnapshot = await (0, import_firestore.getDocs)(q);
|
|
1096
1103
|
const appointments = querySnapshot.docs.map(
|
|
1097
|
-
(
|
|
1104
|
+
(doc38) => doc38.data()
|
|
1098
1105
|
);
|
|
1099
1106
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
1100
1107
|
return { appointments, lastDoc };
|
|
@@ -1901,7 +1908,7 @@ var AppointmentService = class extends BaseService {
|
|
|
1901
1908
|
);
|
|
1902
1909
|
const querySnapshot = await (0, import_firestore2.getDocs)(q);
|
|
1903
1910
|
const appointments = querySnapshot.docs.map(
|
|
1904
|
-
(
|
|
1911
|
+
(doc38) => doc38.data()
|
|
1905
1912
|
);
|
|
1906
1913
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
1907
1914
|
console.log(
|
|
@@ -1974,7 +1981,7 @@ var AppointmentService = class extends BaseService {
|
|
|
1974
1981
|
);
|
|
1975
1982
|
const querySnapshot = await (0, import_firestore2.getDocs)(q);
|
|
1976
1983
|
const appointments = querySnapshot.docs.map(
|
|
1977
|
-
(
|
|
1984
|
+
(doc38) => doc38.data()
|
|
1978
1985
|
);
|
|
1979
1986
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
1980
1987
|
console.log(
|
|
@@ -2470,8 +2477,8 @@ var MediaAccessLevel = /* @__PURE__ */ ((MediaAccessLevel2) => {
|
|
|
2470
2477
|
})(MediaAccessLevel || {});
|
|
2471
2478
|
var MEDIA_METADATA_COLLECTION = "media_metadata";
|
|
2472
2479
|
var MediaService = class extends BaseService {
|
|
2473
|
-
constructor(
|
|
2474
|
-
super(
|
|
2480
|
+
constructor(...args) {
|
|
2481
|
+
super(...args);
|
|
2475
2482
|
}
|
|
2476
2483
|
/**
|
|
2477
2484
|
* Upload a media file, store its metadata, and return the metadata including the URL.
|
|
@@ -2731,7 +2738,7 @@ var MediaService = class extends BaseService {
|
|
|
2731
2738
|
try {
|
|
2732
2739
|
const querySnapshot = await (0, import_firestore4.getDocs)(finalQuery);
|
|
2733
2740
|
const mediaList = querySnapshot.docs.map(
|
|
2734
|
-
(
|
|
2741
|
+
(doc38) => doc38.data()
|
|
2735
2742
|
);
|
|
2736
2743
|
console.log(`[MediaService] Found ${mediaList.length} media items.`);
|
|
2737
2744
|
return mediaList;
|
|
@@ -2785,8 +2792,8 @@ var getPatientsByClinicUtil = async (db, clinicId, options) => {
|
|
|
2785
2792
|
}
|
|
2786
2793
|
const patientsSnapshot = await (0, import_firestore5.getDocs)(q);
|
|
2787
2794
|
const patients = [];
|
|
2788
|
-
patientsSnapshot.forEach((
|
|
2789
|
-
patients.push(
|
|
2795
|
+
patientsSnapshot.forEach((doc38) => {
|
|
2796
|
+
patients.push(doc38.data());
|
|
2790
2797
|
});
|
|
2791
2798
|
console.log(
|
|
2792
2799
|
`[getPatientsByClinicUtil] Found ${patients.length} patients for clinic ID: ${clinicId}`
|
|
@@ -2836,23 +2843,6 @@ var BlockingCondition = /* @__PURE__ */ ((BlockingCondition2) => {
|
|
|
2836
2843
|
return BlockingCondition2;
|
|
2837
2844
|
})(BlockingCondition || {});
|
|
2838
2845
|
|
|
2839
|
-
// src/backoffice/types/static/contraindication.types.ts
|
|
2840
|
-
var Contraindication = /* @__PURE__ */ ((Contraindication2) => {
|
|
2841
|
-
Contraindication2["SENSITIVE_SKIN"] = "sensitive_skin";
|
|
2842
|
-
Contraindication2["RECENT_TANNING"] = "recent_tanning";
|
|
2843
|
-
Contraindication2["RECENT_BOTOX"] = "recent_botox";
|
|
2844
|
-
Contraindication2["RECENT_FILLERS"] = "recent_fillers";
|
|
2845
|
-
Contraindication2["SKIN_ALLERGIES"] = "skin_allergies";
|
|
2846
|
-
Contraindication2["MEDICATIONS"] = "medications";
|
|
2847
|
-
Contraindication2["RECENT_CHEMICAL_PEEL"] = "recent_chemical_peel";
|
|
2848
|
-
Contraindication2["RECENT_LASER"] = "recent_laser";
|
|
2849
|
-
Contraindication2["SKIN_INFLAMMATION"] = "skin_inflammation";
|
|
2850
|
-
Contraindication2["OPEN_WOUNDS"] = "open_wounds";
|
|
2851
|
-
Contraindication2["HERPES_SIMPLEX"] = "herpes_simplex";
|
|
2852
|
-
Contraindication2["COLD_SORES"] = "cold_sores";
|
|
2853
|
-
return Contraindication2;
|
|
2854
|
-
})(Contraindication || {});
|
|
2855
|
-
|
|
2856
2846
|
// src/validations/common.schema.ts
|
|
2857
2847
|
var import_zod5 = require("zod");
|
|
2858
2848
|
var import_firestore6 = require("firebase/firestore");
|
|
@@ -2907,8 +2897,13 @@ var blockingConditionSchema = import_zod6.z.object({
|
|
|
2907
2897
|
notes: import_zod6.z.string().optional().nullable(),
|
|
2908
2898
|
isActive: import_zod6.z.boolean()
|
|
2909
2899
|
});
|
|
2900
|
+
var contraindicationDynamicSchema = import_zod6.z.object({
|
|
2901
|
+
id: import_zod6.z.string(),
|
|
2902
|
+
name: import_zod6.z.string(),
|
|
2903
|
+
description: import_zod6.z.string().optional()
|
|
2904
|
+
});
|
|
2910
2905
|
var contraindicationSchema = import_zod6.z.object({
|
|
2911
|
-
condition:
|
|
2906
|
+
condition: contraindicationDynamicSchema,
|
|
2912
2907
|
lastOccurrence: timestampSchema,
|
|
2913
2908
|
frequency: import_zod6.z.enum(["rare", "occasional", "frequent"]),
|
|
2914
2909
|
notes: import_zod6.z.string().optional().nullable(),
|
|
@@ -3139,8 +3134,8 @@ var getPatientsByPractitionerUtil = async (db, practitionerId, options) => {
|
|
|
3139
3134
|
}
|
|
3140
3135
|
const patientsSnapshot = await (0, import_firestore8.getDocs)(q);
|
|
3141
3136
|
const patients = [];
|
|
3142
|
-
patientsSnapshot.forEach((
|
|
3143
|
-
patients.push(
|
|
3137
|
+
patientsSnapshot.forEach((doc38) => {
|
|
3138
|
+
patients.push(doc38.data());
|
|
3144
3139
|
});
|
|
3145
3140
|
console.log(
|
|
3146
3141
|
`[getPatientsByPractitionerUtil] Found ${patients.length} patients for practitioner ID: ${practitionerId}`
|
|
@@ -3907,7 +3902,7 @@ async function getClinicAdminsByGroup(db, clinicGroupId) {
|
|
|
3907
3902
|
(0, import_firestore10.where)("clinicGroupId", "==", clinicGroupId)
|
|
3908
3903
|
);
|
|
3909
3904
|
const querySnapshot = await (0, import_firestore10.getDocs)(q);
|
|
3910
|
-
return querySnapshot.docs.map((
|
|
3905
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
3911
3906
|
}
|
|
3912
3907
|
async function updateClinicAdmin(db, adminId, data) {
|
|
3913
3908
|
const admin = await getClinicAdmin(db, adminId);
|
|
@@ -4570,9 +4565,9 @@ var updateAllergyUtil = async (db, patientId, data, requesterId, requesterRoles)
|
|
|
4570
4565
|
};
|
|
4571
4566
|
var removeAllergyUtil = async (db, patientId, allergyIndex, requesterId, requesterRoles) => {
|
|
4572
4567
|
await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
|
|
4573
|
-
const
|
|
4574
|
-
if (!
|
|
4575
|
-
const medicalInfo =
|
|
4568
|
+
const doc38 = await (0, import_firestore15.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
4569
|
+
if (!doc38.exists()) throw new Error("Medical info not found");
|
|
4570
|
+
const medicalInfo = doc38.data();
|
|
4576
4571
|
if (allergyIndex >= medicalInfo.allergies.length) {
|
|
4577
4572
|
throw new Error("Invalid allergy index");
|
|
4578
4573
|
}
|
|
@@ -4599,9 +4594,9 @@ var updateBlockingConditionUtil = async (db, patientId, data, requesterId, reque
|
|
|
4599
4594
|
await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
|
|
4600
4595
|
const validatedData = updateBlockingConditionSchema.parse(data);
|
|
4601
4596
|
const { conditionIndex, ...updateData } = validatedData;
|
|
4602
|
-
const
|
|
4603
|
-
if (!
|
|
4604
|
-
const medicalInfo =
|
|
4597
|
+
const doc38 = await (0, import_firestore15.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
4598
|
+
if (!doc38.exists()) throw new Error("Medical info not found");
|
|
4599
|
+
const medicalInfo = doc38.data();
|
|
4605
4600
|
if (conditionIndex >= medicalInfo.blockingConditions.length) {
|
|
4606
4601
|
throw new Error("Invalid blocking condition index");
|
|
4607
4602
|
}
|
|
@@ -4618,9 +4613,9 @@ var updateBlockingConditionUtil = async (db, patientId, data, requesterId, reque
|
|
|
4618
4613
|
};
|
|
4619
4614
|
var removeBlockingConditionUtil = async (db, patientId, conditionIndex, requesterId, requesterRoles) => {
|
|
4620
4615
|
await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
|
|
4621
|
-
const
|
|
4622
|
-
if (!
|
|
4623
|
-
const medicalInfo =
|
|
4616
|
+
const doc38 = await (0, import_firestore15.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
4617
|
+
if (!doc38.exists()) throw new Error("Medical info not found");
|
|
4618
|
+
const medicalInfo = doc38.data();
|
|
4624
4619
|
if (conditionIndex >= medicalInfo.blockingConditions.length) {
|
|
4625
4620
|
throw new Error("Invalid blocking condition index");
|
|
4626
4621
|
}
|
|
@@ -4647,9 +4642,9 @@ var updateContraindicationUtil = async (db, patientId, data, requesterId, reques
|
|
|
4647
4642
|
await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
|
|
4648
4643
|
const validatedData = updateContraindicationSchema.parse(data);
|
|
4649
4644
|
const { contraindicationIndex, ...updateData } = validatedData;
|
|
4650
|
-
const
|
|
4651
|
-
if (!
|
|
4652
|
-
const medicalInfo =
|
|
4645
|
+
const doc38 = await (0, import_firestore15.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
4646
|
+
if (!doc38.exists()) throw new Error("Medical info not found");
|
|
4647
|
+
const medicalInfo = doc38.data();
|
|
4653
4648
|
if (contraindicationIndex >= medicalInfo.contraindications.length) {
|
|
4654
4649
|
throw new Error("Invalid contraindication index");
|
|
4655
4650
|
}
|
|
@@ -4666,9 +4661,9 @@ var updateContraindicationUtil = async (db, patientId, data, requesterId, reques
|
|
|
4666
4661
|
};
|
|
4667
4662
|
var removeContraindicationUtil = async (db, patientId, contraindicationIndex, requesterId, requesterRoles) => {
|
|
4668
4663
|
await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
|
|
4669
|
-
const
|
|
4670
|
-
if (!
|
|
4671
|
-
const medicalInfo =
|
|
4664
|
+
const doc38 = await (0, import_firestore15.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
4665
|
+
if (!doc38.exists()) throw new Error("Medical info not found");
|
|
4666
|
+
const medicalInfo = doc38.data();
|
|
4672
4667
|
if (contraindicationIndex >= medicalInfo.contraindications.length) {
|
|
4673
4668
|
throw new Error("Invalid contraindication index");
|
|
4674
4669
|
}
|
|
@@ -4695,9 +4690,9 @@ var updateMedicationUtil = async (db, patientId, data, requesterId, requesterRol
|
|
|
4695
4690
|
await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
|
|
4696
4691
|
const validatedData = updateMedicationSchema.parse(data);
|
|
4697
4692
|
const { medicationIndex, ...updateData } = validatedData;
|
|
4698
|
-
const
|
|
4699
|
-
if (!
|
|
4700
|
-
const medicalInfo =
|
|
4693
|
+
const doc38 = await (0, import_firestore15.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
4694
|
+
if (!doc38.exists()) throw new Error("Medical info not found");
|
|
4695
|
+
const medicalInfo = doc38.data();
|
|
4701
4696
|
if (medicationIndex >= medicalInfo.currentMedications.length) {
|
|
4702
4697
|
throw new Error("Invalid medication index");
|
|
4703
4698
|
}
|
|
@@ -4714,9 +4709,9 @@ var updateMedicationUtil = async (db, patientId, data, requesterId, requesterRol
|
|
|
4714
4709
|
};
|
|
4715
4710
|
var removeMedicationUtil = async (db, patientId, medicationIndex, requesterId, requesterRoles) => {
|
|
4716
4711
|
await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
|
|
4717
|
-
const
|
|
4718
|
-
if (!
|
|
4719
|
-
const medicalInfo =
|
|
4712
|
+
const doc38 = await (0, import_firestore15.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
4713
|
+
if (!doc38.exists()) throw new Error("Medical info not found");
|
|
4714
|
+
const medicalInfo = doc38.data();
|
|
4720
4715
|
if (medicationIndex >= medicalInfo.currentMedications.length) {
|
|
4721
4716
|
throw new Error("Invalid medication index");
|
|
4722
4717
|
}
|
|
@@ -5003,7 +4998,7 @@ var searchPatientsUtil = async (db, params, requester) => {
|
|
|
5003
4998
|
const finalQuery = (0, import_firestore16.query)(patientsCollectionRef, ...constraints);
|
|
5004
4999
|
const querySnapshot = await (0, import_firestore16.getDocs)(finalQuery);
|
|
5005
5000
|
const patients = querySnapshot.docs.map(
|
|
5006
|
-
(
|
|
5001
|
+
(doc38) => doc38.data()
|
|
5007
5002
|
);
|
|
5008
5003
|
console.log(
|
|
5009
5004
|
`[searchPatientsUtil] Found ${patients.length} patients matching criteria.`
|
|
@@ -5035,8 +5030,8 @@ var getAllPatientsUtil = async (db, options) => {
|
|
|
5035
5030
|
}
|
|
5036
5031
|
const patientsSnapshot = await (0, import_firestore16.getDocs)(q);
|
|
5037
5032
|
const patients = [];
|
|
5038
|
-
patientsSnapshot.forEach((
|
|
5039
|
-
patients.push(
|
|
5033
|
+
patientsSnapshot.forEach((doc38) => {
|
|
5034
|
+
patients.push(doc38.data());
|
|
5040
5035
|
});
|
|
5041
5036
|
console.log(`[getAllPatientsUtil] Found ${patients.length} patients`);
|
|
5042
5037
|
return patients;
|
|
@@ -5158,7 +5153,7 @@ var getActiveInviteTokensByClinicUtil = async (db, clinicId) => {
|
|
|
5158
5153
|
if (querySnapshot.empty) {
|
|
5159
5154
|
return [];
|
|
5160
5155
|
}
|
|
5161
|
-
return querySnapshot.docs.map((
|
|
5156
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
5162
5157
|
};
|
|
5163
5158
|
var getActiveInviteTokensByPatientUtil = async (db, patientId) => {
|
|
5164
5159
|
const tokensRef = (0, import_firestore17.collection)(
|
|
@@ -5176,7 +5171,7 @@ var getActiveInviteTokensByPatientUtil = async (db, patientId) => {
|
|
|
5176
5171
|
if (querySnapshot.empty) {
|
|
5177
5172
|
return [];
|
|
5178
5173
|
}
|
|
5179
|
-
return querySnapshot.docs.map((
|
|
5174
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
5180
5175
|
};
|
|
5181
5176
|
|
|
5182
5177
|
// src/services/patient/patient.service.ts
|
|
@@ -6448,7 +6443,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6448
6443
|
(0, import_firestore21.where)("expiresAt", ">", import_firestore21.Timestamp.now())
|
|
6449
6444
|
);
|
|
6450
6445
|
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
6451
|
-
return querySnapshot.docs.map((
|
|
6446
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
6452
6447
|
}
|
|
6453
6448
|
/**
|
|
6454
6449
|
* Gets a token by its string value and validates it
|
|
@@ -6558,7 +6553,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6558
6553
|
(0, import_firestore21.where)("status", "==", "active" /* ACTIVE */)
|
|
6559
6554
|
);
|
|
6560
6555
|
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
6561
|
-
return querySnapshot.docs.map((
|
|
6556
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
6562
6557
|
}
|
|
6563
6558
|
/**
|
|
6564
6559
|
* Dohvata sve zdravstvene radnike za određenu kliniku
|
|
@@ -6570,7 +6565,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6570
6565
|
(0, import_firestore21.where)("isActive", "==", true)
|
|
6571
6566
|
);
|
|
6572
6567
|
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
6573
|
-
return querySnapshot.docs.map((
|
|
6568
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
6574
6569
|
}
|
|
6575
6570
|
/**
|
|
6576
6571
|
* Dohvata sve draft zdravstvene radnike za određenu kliniku sa statusom DRAFT
|
|
@@ -6582,7 +6577,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6582
6577
|
(0, import_firestore21.where)("status", "==", "draft" /* DRAFT */)
|
|
6583
6578
|
);
|
|
6584
6579
|
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
6585
|
-
return querySnapshot.docs.map((
|
|
6580
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
6586
6581
|
}
|
|
6587
6582
|
/**
|
|
6588
6583
|
* Updates a practitioner
|
|
@@ -6600,7 +6595,9 @@ var PractitionerService = class extends BaseService {
|
|
|
6600
6595
|
throw new Error(`Practitioner ${practitionerId} not found`);
|
|
6601
6596
|
}
|
|
6602
6597
|
const currentPractitioner = practitionerDoc.data();
|
|
6603
|
-
let processedData = {
|
|
6598
|
+
let processedData = {
|
|
6599
|
+
...validData
|
|
6600
|
+
};
|
|
6604
6601
|
if (validData.basicInfo) {
|
|
6605
6602
|
processedData.basicInfo = await this.processBasicInfo(
|
|
6606
6603
|
validData.basicInfo,
|
|
@@ -6797,7 +6794,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6797
6794
|
);
|
|
6798
6795
|
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
6799
6796
|
const practitioners = querySnapshot.docs.map(
|
|
6800
|
-
(
|
|
6797
|
+
(doc38) => doc38.data()
|
|
6801
6798
|
);
|
|
6802
6799
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
6803
6800
|
return {
|
|
@@ -6834,7 +6831,9 @@ var PractitionerService = class extends BaseService {
|
|
|
6834
6831
|
*/
|
|
6835
6832
|
async getPractitionersByFilters(filters) {
|
|
6836
6833
|
try {
|
|
6837
|
-
console.log(
|
|
6834
|
+
console.log(
|
|
6835
|
+
"[PRACTITIONER_SERVICE] Starting practitioner filtering with fallback strategies"
|
|
6836
|
+
);
|
|
6838
6837
|
if (filters.location && filters.radiusInKm) {
|
|
6839
6838
|
console.log("[PRACTITIONER_SERVICE] Executing geo query:", {
|
|
6840
6839
|
location: filters.location,
|
|
@@ -6842,14 +6841,19 @@ var PractitionerService = class extends BaseService {
|
|
|
6842
6841
|
serviceName: "PractitionerService"
|
|
6843
6842
|
});
|
|
6844
6843
|
if (!filters.location.latitude || !filters.location.longitude) {
|
|
6845
|
-
console.warn(
|
|
6844
|
+
console.warn(
|
|
6845
|
+
"[PRACTITIONER_SERVICE] Invalid location data:",
|
|
6846
|
+
filters.location
|
|
6847
|
+
);
|
|
6846
6848
|
filters.location = void 0;
|
|
6847
6849
|
filters.radiusInKm = void 0;
|
|
6848
6850
|
}
|
|
6849
6851
|
}
|
|
6850
6852
|
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
6851
6853
|
try {
|
|
6852
|
-
console.log(
|
|
6854
|
+
console.log(
|
|
6855
|
+
"[PRACTITIONER_SERVICE] Strategy 1: Trying fullNameLower search"
|
|
6856
|
+
);
|
|
6853
6857
|
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
6854
6858
|
const constraints = [];
|
|
6855
6859
|
if (!filters.includeDraftPractitioners) {
|
|
@@ -6869,11 +6873,18 @@ var PractitionerService = class extends BaseService {
|
|
|
6869
6873
|
}
|
|
6870
6874
|
}
|
|
6871
6875
|
constraints.push((0, import_firestore21.limit)(filters.pagination || 10));
|
|
6872
|
-
const q = (0, import_firestore21.query)(
|
|
6876
|
+
const q = (0, import_firestore21.query)(
|
|
6877
|
+
(0, import_firestore21.collection)(this.db, PRACTITIONERS_COLLECTION),
|
|
6878
|
+
...constraints
|
|
6879
|
+
);
|
|
6873
6880
|
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
6874
|
-
const practitioners = querySnapshot.docs.map(
|
|
6881
|
+
const practitioners = querySnapshot.docs.map(
|
|
6882
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
6883
|
+
);
|
|
6875
6884
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
6876
|
-
console.log(
|
|
6885
|
+
console.log(
|
|
6886
|
+
`[PRACTITIONER_SERVICE] Strategy 1 success: ${practitioners.length} practitioners`
|
|
6887
|
+
);
|
|
6877
6888
|
if (practitioners.length < (filters.pagination || 10)) {
|
|
6878
6889
|
return { practitioners, lastDoc: null };
|
|
6879
6890
|
}
|
|
@@ -6883,7 +6894,9 @@ var PractitionerService = class extends BaseService {
|
|
|
6883
6894
|
}
|
|
6884
6895
|
}
|
|
6885
6896
|
try {
|
|
6886
|
-
console.log(
|
|
6897
|
+
console.log(
|
|
6898
|
+
"[PRACTITIONER_SERVICE] Strategy 2: Basic query with createdAt ordering"
|
|
6899
|
+
);
|
|
6887
6900
|
const constraints = [];
|
|
6888
6901
|
if (!filters.includeDraftPractitioners) {
|
|
6889
6902
|
constraints.push((0, import_firestore21.where)("status", "==", "active" /* ACTIVE */));
|
|
@@ -6892,14 +6905,22 @@ var PractitionerService = class extends BaseService {
|
|
|
6892
6905
|
if (filters.certifications && filters.certifications.length > 0) {
|
|
6893
6906
|
const certificationsToMatch = filters.certifications;
|
|
6894
6907
|
constraints.push(
|
|
6895
|
-
(0, import_firestore21.where)(
|
|
6908
|
+
(0, import_firestore21.where)(
|
|
6909
|
+
"certification.specialties",
|
|
6910
|
+
"array-contains-any",
|
|
6911
|
+
certificationsToMatch
|
|
6912
|
+
)
|
|
6896
6913
|
);
|
|
6897
6914
|
}
|
|
6898
6915
|
if (filters.minRating !== void 0) {
|
|
6899
|
-
constraints.push(
|
|
6916
|
+
constraints.push(
|
|
6917
|
+
(0, import_firestore21.where)("reviewInfo.averageRating", ">=", filters.minRating)
|
|
6918
|
+
);
|
|
6900
6919
|
}
|
|
6901
6920
|
if (filters.maxRating !== void 0) {
|
|
6902
|
-
constraints.push(
|
|
6921
|
+
constraints.push(
|
|
6922
|
+
(0, import_firestore21.where)("reviewInfo.averageRating", "<=", filters.maxRating)
|
|
6923
|
+
);
|
|
6903
6924
|
}
|
|
6904
6925
|
constraints.push((0, import_firestore21.orderBy)("createdAt", "desc"));
|
|
6905
6926
|
if (filters.location && filters.radiusInKm) {
|
|
@@ -6916,9 +6937,14 @@ var PractitionerService = class extends BaseService {
|
|
|
6916
6937
|
}
|
|
6917
6938
|
constraints.push((0, import_firestore21.limit)(filters.pagination || 10));
|
|
6918
6939
|
}
|
|
6919
|
-
const q = (0, import_firestore21.query)(
|
|
6940
|
+
const q = (0, import_firestore21.query)(
|
|
6941
|
+
(0, import_firestore21.collection)(this.db, PRACTITIONERS_COLLECTION),
|
|
6942
|
+
...constraints
|
|
6943
|
+
);
|
|
6920
6944
|
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
6921
|
-
let practitioners = querySnapshot.docs.map(
|
|
6945
|
+
let practitioners = querySnapshot.docs.map(
|
|
6946
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
6947
|
+
);
|
|
6922
6948
|
if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
|
|
6923
6949
|
const location = filters.location;
|
|
6924
6950
|
const radiusInKm = filters.radiusInKm;
|
|
@@ -6937,7 +6963,9 @@ var PractitionerService = class extends BaseService {
|
|
|
6937
6963
|
}
|
|
6938
6964
|
practitioners = this.applyInMemoryFilters(practitioners, filters);
|
|
6939
6965
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
6940
|
-
console.log(
|
|
6966
|
+
console.log(
|
|
6967
|
+
`[PRACTITIONER_SERVICE] Strategy 2 success: ${practitioners.length} practitioners`
|
|
6968
|
+
);
|
|
6941
6969
|
if (practitioners.length < (filters.pagination || 10)) {
|
|
6942
6970
|
return { practitioners, lastDoc: null };
|
|
6943
6971
|
}
|
|
@@ -6946,18 +6974,27 @@ var PractitionerService = class extends BaseService {
|
|
|
6946
6974
|
console.log("[PRACTITIONER_SERVICE] Strategy 2 failed:", error);
|
|
6947
6975
|
}
|
|
6948
6976
|
try {
|
|
6949
|
-
console.log(
|
|
6977
|
+
console.log(
|
|
6978
|
+
"[PRACTITIONER_SERVICE] Strategy 3: Minimal query fallback"
|
|
6979
|
+
);
|
|
6950
6980
|
const constraints = [
|
|
6951
6981
|
(0, import_firestore21.where)("isActive", "==", true),
|
|
6952
6982
|
(0, import_firestore21.orderBy)("createdAt", "desc"),
|
|
6953
6983
|
(0, import_firestore21.limit)(filters.pagination || 10)
|
|
6954
6984
|
];
|
|
6955
|
-
const q = (0, import_firestore21.query)(
|
|
6985
|
+
const q = (0, import_firestore21.query)(
|
|
6986
|
+
(0, import_firestore21.collection)(this.db, PRACTITIONERS_COLLECTION),
|
|
6987
|
+
...constraints
|
|
6988
|
+
);
|
|
6956
6989
|
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
6957
|
-
let practitioners = querySnapshot.docs.map(
|
|
6990
|
+
let practitioners = querySnapshot.docs.map(
|
|
6991
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
6992
|
+
);
|
|
6958
6993
|
practitioners = this.applyInMemoryFilters(practitioners, filters);
|
|
6959
6994
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
6960
|
-
console.log(
|
|
6995
|
+
console.log(
|
|
6996
|
+
`[PRACTITIONER_SERVICE] Strategy 3 success: ${practitioners.length} practitioners`
|
|
6997
|
+
);
|
|
6961
6998
|
if (practitioners.length < (filters.pagination || 10)) {
|
|
6962
6999
|
return { practitioners, lastDoc: null };
|
|
6963
7000
|
}
|
|
@@ -6966,19 +7003,28 @@ var PractitionerService = class extends BaseService {
|
|
|
6966
7003
|
console.log("[PRACTITIONER_SERVICE] Strategy 3 failed:", error);
|
|
6967
7004
|
}
|
|
6968
7005
|
try {
|
|
6969
|
-
console.log(
|
|
7006
|
+
console.log(
|
|
7007
|
+
"[PRACTITIONER_SERVICE] Strategy 4: Client-side filtering fallback"
|
|
7008
|
+
);
|
|
6970
7009
|
const constraints = [
|
|
6971
7010
|
(0, import_firestore21.where)("isActive", "==", true),
|
|
6972
7011
|
(0, import_firestore21.where)("status", "==", "active" /* ACTIVE */),
|
|
6973
7012
|
(0, import_firestore21.orderBy)("createdAt", "desc"),
|
|
6974
7013
|
(0, import_firestore21.limit)(filters.pagination || 10)
|
|
6975
7014
|
];
|
|
6976
|
-
const q = (0, import_firestore21.query)(
|
|
7015
|
+
const q = (0, import_firestore21.query)(
|
|
7016
|
+
(0, import_firestore21.collection)(this.db, PRACTITIONERS_COLLECTION),
|
|
7017
|
+
...constraints
|
|
7018
|
+
);
|
|
6977
7019
|
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
6978
|
-
let practitioners = querySnapshot.docs.map(
|
|
7020
|
+
let practitioners = querySnapshot.docs.map(
|
|
7021
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
7022
|
+
);
|
|
6979
7023
|
practitioners = this.applyInMemoryFilters(practitioners, filters);
|
|
6980
7024
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
6981
|
-
console.log(
|
|
7025
|
+
console.log(
|
|
7026
|
+
`[PRACTITIONER_SERVICE] Strategy 4 success: ${practitioners.length} practitioners`
|
|
7027
|
+
);
|
|
6982
7028
|
if (practitioners.length < (filters.pagination || 10)) {
|
|
6983
7029
|
return { practitioners, lastDoc: null };
|
|
6984
7030
|
}
|
|
@@ -6986,10 +7032,15 @@ var PractitionerService = class extends BaseService {
|
|
|
6986
7032
|
} catch (error) {
|
|
6987
7033
|
console.log("[PRACTITIONER_SERVICE] Strategy 4 failed:", error);
|
|
6988
7034
|
}
|
|
6989
|
-
console.log(
|
|
7035
|
+
console.log(
|
|
7036
|
+
"[PRACTITIONER_SERVICE] All strategies failed, returning empty result"
|
|
7037
|
+
);
|
|
6990
7038
|
return { practitioners: [], lastDoc: null };
|
|
6991
7039
|
} catch (error) {
|
|
6992
|
-
console.error(
|
|
7040
|
+
console.error(
|
|
7041
|
+
"[PRACTITIONER_SERVICE] Error filtering practitioners:",
|
|
7042
|
+
error
|
|
7043
|
+
);
|
|
6993
7044
|
return { practitioners: [], lastDoc: null };
|
|
6994
7045
|
}
|
|
6995
7046
|
}
|
|
@@ -7009,63 +7060,93 @@ var PractitionerService = class extends BaseService {
|
|
|
7009
7060
|
const fullNameLower = practitioner.fullNameLower || "";
|
|
7010
7061
|
return firstName.includes(searchTerm) || lastName.includes(searchTerm) || fullName.includes(searchTerm) || fullNameLower.includes(searchTerm);
|
|
7011
7062
|
});
|
|
7012
|
-
console.log(
|
|
7063
|
+
console.log(
|
|
7064
|
+
`[PRACTITIONER_SERVICE] Applied name filter, results: ${filteredPractitioners.length}`
|
|
7065
|
+
);
|
|
7013
7066
|
}
|
|
7014
7067
|
if (filters.certifications && filters.certifications.length > 0) {
|
|
7015
7068
|
const certificationsToMatch = filters.certifications;
|
|
7016
7069
|
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7017
7070
|
var _a;
|
|
7018
7071
|
const practitionerCerts = ((_a = practitioner.certification) == null ? void 0 : _a.specialties) || [];
|
|
7019
|
-
return certificationsToMatch.some(
|
|
7072
|
+
return certificationsToMatch.some(
|
|
7073
|
+
(cert) => practitionerCerts.includes(cert)
|
|
7074
|
+
);
|
|
7020
7075
|
});
|
|
7021
|
-
console.log(
|
|
7076
|
+
console.log(
|
|
7077
|
+
`[PRACTITIONER_SERVICE] Applied certifications filter, results: ${filteredPractitioners.length}`
|
|
7078
|
+
);
|
|
7022
7079
|
}
|
|
7023
7080
|
if (filters.specialties && filters.specialties.length > 0) {
|
|
7024
7081
|
const specialtiesToMatch = filters.specialties;
|
|
7025
7082
|
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7026
7083
|
var _a;
|
|
7027
7084
|
const practitionerSpecs = ((_a = practitioner.certification) == null ? void 0 : _a.specialties) || [];
|
|
7028
|
-
return specialtiesToMatch.some(
|
|
7085
|
+
return specialtiesToMatch.some(
|
|
7086
|
+
(spec) => practitionerSpecs.includes(spec)
|
|
7087
|
+
);
|
|
7029
7088
|
});
|
|
7030
|
-
console.log(
|
|
7089
|
+
console.log(
|
|
7090
|
+
`[PRACTITIONER_SERVICE] Applied specialties filter, results: ${filteredPractitioners.length}`
|
|
7091
|
+
);
|
|
7031
7092
|
}
|
|
7032
7093
|
if (filters.minRating !== void 0 || filters.maxRating !== void 0) {
|
|
7033
7094
|
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7034
7095
|
var _a;
|
|
7035
7096
|
const rating = ((_a = practitioner.reviewInfo) == null ? void 0 : _a.averageRating) || 0;
|
|
7036
|
-
if (filters.minRating !== void 0 && rating < filters.minRating)
|
|
7037
|
-
|
|
7097
|
+
if (filters.minRating !== void 0 && rating < filters.minRating)
|
|
7098
|
+
return false;
|
|
7099
|
+
if (filters.maxRating !== void 0 && rating > filters.maxRating)
|
|
7100
|
+
return false;
|
|
7038
7101
|
return true;
|
|
7039
7102
|
});
|
|
7040
|
-
console.log(
|
|
7103
|
+
console.log(
|
|
7104
|
+
`[PRACTITIONER_SERVICE] Applied rating filter, results: ${filteredPractitioners.length}`
|
|
7105
|
+
);
|
|
7041
7106
|
}
|
|
7042
7107
|
if (filters.procedureFamily) {
|
|
7043
7108
|
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7044
7109
|
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
7045
|
-
return proceduresInfo.some(
|
|
7110
|
+
return proceduresInfo.some(
|
|
7111
|
+
(proc) => proc.family === filters.procedureFamily
|
|
7112
|
+
);
|
|
7046
7113
|
});
|
|
7047
|
-
console.log(
|
|
7114
|
+
console.log(
|
|
7115
|
+
`[PRACTITIONER_SERVICE] Applied procedure family filter, results: ${filteredPractitioners.length}`
|
|
7116
|
+
);
|
|
7048
7117
|
}
|
|
7049
7118
|
if (filters.procedureCategory) {
|
|
7050
7119
|
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7051
7120
|
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
7052
|
-
return proceduresInfo.some(
|
|
7121
|
+
return proceduresInfo.some(
|
|
7122
|
+
(proc) => proc.categoryName === filters.procedureCategory
|
|
7123
|
+
);
|
|
7053
7124
|
});
|
|
7054
|
-
console.log(
|
|
7125
|
+
console.log(
|
|
7126
|
+
`[PRACTITIONER_SERVICE] Applied procedure category filter, results: ${filteredPractitioners.length}`
|
|
7127
|
+
);
|
|
7055
7128
|
}
|
|
7056
7129
|
if (filters.procedureSubcategory) {
|
|
7057
7130
|
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7058
7131
|
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
7059
|
-
return proceduresInfo.some(
|
|
7132
|
+
return proceduresInfo.some(
|
|
7133
|
+
(proc) => proc.subcategoryName === filters.procedureSubcategory
|
|
7134
|
+
);
|
|
7060
7135
|
});
|
|
7061
|
-
console.log(
|
|
7136
|
+
console.log(
|
|
7137
|
+
`[PRACTITIONER_SERVICE] Applied procedure subcategory filter, results: ${filteredPractitioners.length}`
|
|
7138
|
+
);
|
|
7062
7139
|
}
|
|
7063
7140
|
if (filters.procedureTechnology) {
|
|
7064
7141
|
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7065
7142
|
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
7066
|
-
return proceduresInfo.some(
|
|
7143
|
+
return proceduresInfo.some(
|
|
7144
|
+
(proc) => proc.technologyName === filters.procedureTechnology
|
|
7145
|
+
);
|
|
7067
7146
|
});
|
|
7068
|
-
console.log(
|
|
7147
|
+
console.log(
|
|
7148
|
+
`[PRACTITIONER_SERVICE] Applied procedure technology filter, results: ${filteredPractitioners.length}`
|
|
7149
|
+
);
|
|
7069
7150
|
}
|
|
7070
7151
|
if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
|
|
7071
7152
|
const location = filters.location;
|
|
@@ -7081,7 +7162,9 @@ var PractitionerService = class extends BaseService {
|
|
|
7081
7162
|
return distanceInKm <= radiusInKm;
|
|
7082
7163
|
});
|
|
7083
7164
|
});
|
|
7084
|
-
console.log(
|
|
7165
|
+
console.log(
|
|
7166
|
+
`[PRACTITIONER_SERVICE] Applied geo filter, results: ${filteredPractitioners.length}`
|
|
7167
|
+
);
|
|
7085
7168
|
}
|
|
7086
7169
|
return filteredPractitioners;
|
|
7087
7170
|
}
|
|
@@ -7146,6 +7229,15 @@ var PractitionerService = class extends BaseService {
|
|
|
7146
7229
|
price: 0,
|
|
7147
7230
|
currency: "EUR" /* EUR */,
|
|
7148
7231
|
pricingMeasure: "per_session" /* PER_SESSION */,
|
|
7232
|
+
productsMetadata: [
|
|
7233
|
+
{
|
|
7234
|
+
productId: "free-consultation-product",
|
|
7235
|
+
price: 0,
|
|
7236
|
+
currency: "EUR" /* EUR */,
|
|
7237
|
+
pricingMeasure: "per_session" /* PER_SESSION */,
|
|
7238
|
+
isDefault: true
|
|
7239
|
+
}
|
|
7240
|
+
],
|
|
7149
7241
|
duration: 30,
|
|
7150
7242
|
// 30 minutes consultation
|
|
7151
7243
|
practitionerId,
|
|
@@ -7490,7 +7582,7 @@ var UserService = class extends BaseService {
|
|
|
7490
7582
|
];
|
|
7491
7583
|
const q = (0, import_firestore22.query)((0, import_firestore22.collection)(this.db, USERS_COLLECTION), ...constraints);
|
|
7492
7584
|
const querySnapshot = await (0, import_firestore22.getDocs)(q);
|
|
7493
|
-
const users = querySnapshot.docs.map((
|
|
7585
|
+
const users = querySnapshot.docs.map((doc38) => doc38.data());
|
|
7494
7586
|
return users.map((userData) => userSchema.parse(userData));
|
|
7495
7587
|
}
|
|
7496
7588
|
/**
|
|
@@ -7854,7 +7946,7 @@ async function getAllActiveGroups(db) {
|
|
|
7854
7946
|
(0, import_firestore23.where)("isActive", "==", true)
|
|
7855
7947
|
);
|
|
7856
7948
|
const querySnapshot = await (0, import_firestore23.getDocs)(q);
|
|
7857
|
-
return querySnapshot.docs.map((
|
|
7949
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
7858
7950
|
}
|
|
7859
7951
|
async function updateClinicGroup(db, groupId, data, app) {
|
|
7860
7952
|
console.log("[CLINIC_GROUP] Updating clinic group", { groupId });
|
|
@@ -8295,7 +8387,7 @@ async function getClinicsByGroup(db, groupId) {
|
|
|
8295
8387
|
(0, import_firestore24.where)("isActive", "==", true)
|
|
8296
8388
|
);
|
|
8297
8389
|
const querySnapshot = await (0, import_firestore24.getDocs)(q);
|
|
8298
|
-
return querySnapshot.docs.map((
|
|
8390
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
8299
8391
|
}
|
|
8300
8392
|
async function updateClinic(db, clinicId, data, adminId, clinicAdminService, app) {
|
|
8301
8393
|
console.log("[CLINIC] Starting clinic update", { clinicId, adminId });
|
|
@@ -8489,7 +8581,7 @@ async function getClinicsByAdmin(db, adminId, options = {}, clinicAdminService,
|
|
|
8489
8581
|
}
|
|
8490
8582
|
const q = (0, import_firestore24.query)((0, import_firestore24.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
8491
8583
|
const querySnapshot = await (0, import_firestore24.getDocs)(q);
|
|
8492
|
-
return querySnapshot.docs.map((
|
|
8584
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
8493
8585
|
}
|
|
8494
8586
|
async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGroupService) {
|
|
8495
8587
|
return getClinicsByAdmin(
|
|
@@ -8534,11 +8626,11 @@ async function getAllClinics(db, pagination, lastDoc) {
|
|
|
8534
8626
|
}
|
|
8535
8627
|
const clinicsSnapshot = await (0, import_firestore24.getDocs)(clinicsQuery);
|
|
8536
8628
|
const lastVisible = clinicsSnapshot.docs[clinicsSnapshot.docs.length - 1];
|
|
8537
|
-
const clinics = clinicsSnapshot.docs.map((
|
|
8538
|
-
const data =
|
|
8629
|
+
const clinics = clinicsSnapshot.docs.map((doc38) => {
|
|
8630
|
+
const data = doc38.data();
|
|
8539
8631
|
return {
|
|
8540
8632
|
...data,
|
|
8541
|
-
id:
|
|
8633
|
+
id: doc38.id
|
|
8542
8634
|
};
|
|
8543
8635
|
});
|
|
8544
8636
|
return {
|
|
@@ -8565,8 +8657,8 @@ async function getAllClinicsInRange(db, center, rangeInKm, pagination, lastDoc)
|
|
|
8565
8657
|
];
|
|
8566
8658
|
const q = (0, import_firestore24.query)((0, import_firestore24.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
8567
8659
|
const querySnapshot = await (0, import_firestore24.getDocs)(q);
|
|
8568
|
-
for (const
|
|
8569
|
-
const clinic =
|
|
8660
|
+
for (const doc38 of querySnapshot.docs) {
|
|
8661
|
+
const clinic = doc38.data();
|
|
8570
8662
|
const distance = (0, import_geofire_common4.distanceBetween)(
|
|
8571
8663
|
[center.latitude, center.longitude],
|
|
8572
8664
|
[clinic.location.latitude, clinic.location.longitude]
|
|
@@ -8683,8 +8775,8 @@ async function findClinicsInRadius(db, center, radiusInKm, filters) {
|
|
|
8683
8775
|
}
|
|
8684
8776
|
const q = (0, import_firestore25.query)((0, import_firestore25.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
8685
8777
|
const querySnapshot = await (0, import_firestore25.getDocs)(q);
|
|
8686
|
-
for (const
|
|
8687
|
-
const clinic =
|
|
8778
|
+
for (const doc38 of querySnapshot.docs) {
|
|
8779
|
+
const clinic = doc38.data();
|
|
8688
8780
|
const distance = (0, import_geofire_common5.distanceBetween)(
|
|
8689
8781
|
[center.latitude, center.longitude],
|
|
8690
8782
|
[clinic.location.latitude, clinic.location.longitude]
|
|
@@ -8805,7 +8897,7 @@ async function getClinicsByFilters(db, filters) {
|
|
|
8805
8897
|
constraints.push((0, import_firestore26.limit)(filters.pagination || 5));
|
|
8806
8898
|
const q = (0, import_firestore26.query)((0, import_firestore26.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
8807
8899
|
const querySnapshot = await (0, import_firestore26.getDocs)(q);
|
|
8808
|
-
let clinics = querySnapshot.docs.map((
|
|
8900
|
+
let clinics = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
|
|
8809
8901
|
clinics = applyInMemoryFilters(clinics, filters);
|
|
8810
8902
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
8811
8903
|
console.log(`[CLINIC_SERVICE] Strategy 1 success: ${clinics.length} clinics`);
|
|
@@ -8837,7 +8929,7 @@ async function getClinicsByFilters(db, filters) {
|
|
|
8837
8929
|
constraints.push((0, import_firestore26.limit)(filters.pagination || 5));
|
|
8838
8930
|
const q = (0, import_firestore26.query)((0, import_firestore26.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
8839
8931
|
const querySnapshot = await (0, import_firestore26.getDocs)(q);
|
|
8840
|
-
let clinics = querySnapshot.docs.map((
|
|
8932
|
+
let clinics = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
|
|
8841
8933
|
clinics = applyInMemoryFilters(clinics, filters);
|
|
8842
8934
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
8843
8935
|
console.log(`[CLINIC_SERVICE] Strategy 2 success: ${clinics.length} clinics`);
|
|
@@ -8867,7 +8959,7 @@ async function getClinicsByFilters(db, filters) {
|
|
|
8867
8959
|
constraints.push((0, import_firestore26.limit)(filters.pagination || 5));
|
|
8868
8960
|
const q = (0, import_firestore26.query)((0, import_firestore26.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
8869
8961
|
const querySnapshot = await (0, import_firestore26.getDocs)(q);
|
|
8870
|
-
let clinics = querySnapshot.docs.map((
|
|
8962
|
+
let clinics = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
|
|
8871
8963
|
clinics = applyInMemoryFilters(clinics, filters);
|
|
8872
8964
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
8873
8965
|
console.log(`[CLINIC_SERVICE] Strategy 3 success: ${clinics.length} clinics`);
|
|
@@ -8887,7 +8979,7 @@ async function getClinicsByFilters(db, filters) {
|
|
|
8887
8979
|
];
|
|
8888
8980
|
const q = (0, import_firestore26.query)((0, import_firestore26.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
8889
8981
|
const querySnapshot = await (0, import_firestore26.getDocs)(q);
|
|
8890
|
-
let clinics = querySnapshot.docs.map((
|
|
8982
|
+
let clinics = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
|
|
8891
8983
|
clinics = applyInMemoryFilters(clinics, filters);
|
|
8892
8984
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
8893
8985
|
console.log(`[CLINIC_SERVICE] Strategy 4 success: ${clinics.length} clinics`);
|
|
@@ -9463,11 +9555,11 @@ var ClinicService = class extends BaseService {
|
|
|
9463
9555
|
async getClinicsForMap() {
|
|
9464
9556
|
const clinicsRef = (0, import_firestore27.collection)(this.db, CLINICS_COLLECTION);
|
|
9465
9557
|
const snapshot = await (0, import_firestore27.getDocs)(clinicsRef);
|
|
9466
|
-
const clinicsForMap = snapshot.docs.map((
|
|
9558
|
+
const clinicsForMap = snapshot.docs.map((doc38) => {
|
|
9467
9559
|
var _a, _b, _c;
|
|
9468
|
-
const data =
|
|
9560
|
+
const data = doc38.data();
|
|
9469
9561
|
return {
|
|
9470
|
-
id:
|
|
9562
|
+
id: doc38.id,
|
|
9471
9563
|
name: data.name,
|
|
9472
9564
|
address: ((_a = data.location) == null ? void 0 : _a.address) || "",
|
|
9473
9565
|
latitude: (_b = data.location) == null ? void 0 : _b.latitude,
|
|
@@ -10628,7 +10720,7 @@ async function updatePractitionerCalendarEventUtil(db, practitionerId, eventId,
|
|
|
10628
10720
|
}
|
|
10629
10721
|
|
|
10630
10722
|
// src/services/calendar/utils/appointment.utils.ts
|
|
10631
|
-
async function
|
|
10723
|
+
async function createAppointmentUtil(db, clinicId, practitionerId, patientId, eventData, generateId2) {
|
|
10632
10724
|
const eventId = generateId2();
|
|
10633
10725
|
const autoConfirm = await checkAutoConfirmAppointmentsUtil(db, clinicId);
|
|
10634
10726
|
const initialStatus = autoConfirm ? "confirmed" /* CONFIRMED */ : "pending" /* PENDING */;
|
|
@@ -10762,7 +10854,7 @@ async function searchCalendarEventsUtil(db, params) {
|
|
|
10762
10854
|
const finalQuery = (0, import_firestore33.query)(collectionRef, ...constraints);
|
|
10763
10855
|
const querySnapshot = await (0, import_firestore33.getDocs)(finalQuery);
|
|
10764
10856
|
const events = querySnapshot.docs.map(
|
|
10765
|
-
(
|
|
10857
|
+
(doc38) => ({ id: doc38.id, ...doc38.data() })
|
|
10766
10858
|
);
|
|
10767
10859
|
return events;
|
|
10768
10860
|
} catch (error) {
|
|
@@ -10844,7 +10936,7 @@ async function getPractitionerSyncedCalendarsUtil(db, practitionerId) {
|
|
|
10844
10936
|
);
|
|
10845
10937
|
const q = (0, import_firestore34.query)(calendarsRef, (0, import_firestore34.orderBy)("createdAt", "desc"));
|
|
10846
10938
|
const querySnapshot = await (0, import_firestore34.getDocs)(q);
|
|
10847
|
-
return querySnapshot.docs.map((
|
|
10939
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
10848
10940
|
}
|
|
10849
10941
|
async function getPatientSyncedCalendarUtil(db, patientId, calendarId) {
|
|
10850
10942
|
const calendarRef = getPatientSyncedCalendarDocRef(db, patientId, calendarId);
|
|
@@ -10861,7 +10953,7 @@ async function getPatientSyncedCalendarsUtil(db, patientId) {
|
|
|
10861
10953
|
);
|
|
10862
10954
|
const q = (0, import_firestore34.query)(calendarsRef, (0, import_firestore34.orderBy)("createdAt", "desc"));
|
|
10863
10955
|
const querySnapshot = await (0, import_firestore34.getDocs)(q);
|
|
10864
|
-
return querySnapshot.docs.map((
|
|
10956
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
10865
10957
|
}
|
|
10866
10958
|
async function getClinicSyncedCalendarUtil(db, clinicId, calendarId) {
|
|
10867
10959
|
const calendarRef = getClinicSyncedCalendarDocRef(db, clinicId, calendarId);
|
|
@@ -10878,7 +10970,7 @@ async function getClinicSyncedCalendarsUtil(db, clinicId) {
|
|
|
10878
10970
|
);
|
|
10879
10971
|
const q = (0, import_firestore34.query)(calendarsRef, (0, import_firestore34.orderBy)("createdAt", "desc"));
|
|
10880
10972
|
const querySnapshot = await (0, import_firestore34.getDocs)(q);
|
|
10881
|
-
return querySnapshot.docs.map((
|
|
10973
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
10882
10974
|
}
|
|
10883
10975
|
async function updatePractitionerSyncedCalendarUtil(db, practitionerId, calendarId, updateData) {
|
|
10884
10976
|
const calendarRef = getPractitionerSyncedCalendarDocRef(
|
|
@@ -11946,7 +12038,7 @@ var CalendarServiceV2 = class extends BaseService {
|
|
|
11946
12038
|
syncStatus: "internal" /* INTERNAL */,
|
|
11947
12039
|
eventType: "appointment" /* APPOINTMENT */
|
|
11948
12040
|
};
|
|
11949
|
-
const appointment = await
|
|
12041
|
+
const appointment = await createAppointmentUtil(
|
|
11950
12042
|
this.db,
|
|
11951
12043
|
params.clinicId,
|
|
11952
12044
|
params.doctorId,
|
|
@@ -12233,9 +12325,9 @@ var CalendarServiceV2 = class extends BaseService {
|
|
|
12233
12325
|
(0, import_firestore37.where)("eventTime.start", "<=", import_firestore36.Timestamp.fromDate(endDate))
|
|
12234
12326
|
);
|
|
12235
12327
|
const eventsSnapshot = await (0, import_firestore37.getDocs)(q);
|
|
12236
|
-
const events = eventsSnapshot.docs.map((
|
|
12237
|
-
id:
|
|
12238
|
-
...
|
|
12328
|
+
const events = eventsSnapshot.docs.map((doc38) => ({
|
|
12329
|
+
id: doc38.id,
|
|
12330
|
+
...doc38.data()
|
|
12239
12331
|
}));
|
|
12240
12332
|
const calendars = await this.syncedCalendarsService.getPractitionerSyncedCalendars(
|
|
12241
12333
|
doctorId
|
|
@@ -12869,7 +12961,7 @@ var CalendarServiceV2 = class extends BaseService {
|
|
|
12869
12961
|
])
|
|
12870
12962
|
);
|
|
12871
12963
|
const querySnapshot = await (0, import_firestore37.getDocs)(q);
|
|
12872
|
-
return querySnapshot.docs.map((
|
|
12964
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
12873
12965
|
}
|
|
12874
12966
|
/**
|
|
12875
12967
|
* Calculates available time slots based on working hours, schedule and existing appointments
|
|
@@ -13400,7 +13492,7 @@ var PractitionerInviteService = class extends BaseService {
|
|
|
13400
13492
|
...constraints
|
|
13401
13493
|
);
|
|
13402
13494
|
const querySnapshot = await (0, import_firestore40.getDocs)(q);
|
|
13403
|
-
return querySnapshot.docs.map((
|
|
13495
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
13404
13496
|
} catch (error) {
|
|
13405
13497
|
console.error(
|
|
13406
13498
|
"[PractitionerInviteService] Error getting doctor invites:",
|
|
@@ -13429,7 +13521,7 @@ var PractitionerInviteService = class extends BaseService {
|
|
|
13429
13521
|
...constraints
|
|
13430
13522
|
);
|
|
13431
13523
|
const querySnapshot = await (0, import_firestore40.getDocs)(q);
|
|
13432
|
-
return querySnapshot.docs.map((
|
|
13524
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
13433
13525
|
} catch (error) {
|
|
13434
13526
|
console.error(
|
|
13435
13527
|
"[PractitionerInviteService] Error getting clinic invites:",
|
|
@@ -13585,7 +13677,7 @@ var PractitionerInviteService = class extends BaseService {
|
|
|
13585
13677
|
);
|
|
13586
13678
|
const querySnapshot = await (0, import_firestore40.getDocs)(q);
|
|
13587
13679
|
let invites = querySnapshot.docs.map(
|
|
13588
|
-
(
|
|
13680
|
+
(doc38) => doc38.data()
|
|
13589
13681
|
);
|
|
13590
13682
|
if (filters.fromDate) {
|
|
13591
13683
|
invites = invites.filter(
|
|
@@ -13688,9 +13780,10 @@ var PractitionerInviteService = class extends BaseService {
|
|
|
13688
13780
|
|
|
13689
13781
|
// src/services/documentation-templates/documentation-template.service.ts
|
|
13690
13782
|
var import_firestore41 = require("firebase/firestore");
|
|
13783
|
+
var import_firestore42 = require("firebase/firestore");
|
|
13691
13784
|
var DocumentationTemplateService = class extends BaseService {
|
|
13692
|
-
constructor() {
|
|
13693
|
-
super(...
|
|
13785
|
+
constructor(...args) {
|
|
13786
|
+
super(...args);
|
|
13694
13787
|
this.collectionRef = (0, import_firestore41.collection)(
|
|
13695
13788
|
this.db,
|
|
13696
13789
|
DOCUMENTATION_TEMPLATES_COLLECTION
|
|
@@ -13842,8 +13935,8 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
13842
13935
|
const q = (0, import_firestore41.query)(versionsCollectionRef, (0, import_firestore41.orderBy)("version", "desc"));
|
|
13843
13936
|
const querySnapshot = await (0, import_firestore41.getDocs)(q);
|
|
13844
13937
|
const versions = [];
|
|
13845
|
-
querySnapshot.forEach((
|
|
13846
|
-
versions.push(
|
|
13938
|
+
querySnapshot.forEach((doc38) => {
|
|
13939
|
+
versions.push(doc38.data());
|
|
13847
13940
|
});
|
|
13848
13941
|
return versions;
|
|
13849
13942
|
}
|
|
@@ -13874,15 +13967,97 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
13874
13967
|
const querySnapshot = await (0, import_firestore41.getDocs)(q);
|
|
13875
13968
|
const templates = [];
|
|
13876
13969
|
let lastVisible = null;
|
|
13877
|
-
querySnapshot.forEach((
|
|
13878
|
-
templates.push(
|
|
13879
|
-
lastVisible =
|
|
13970
|
+
querySnapshot.forEach((doc38) => {
|
|
13971
|
+
templates.push(doc38.data());
|
|
13972
|
+
lastVisible = doc38;
|
|
13973
|
+
});
|
|
13974
|
+
return {
|
|
13975
|
+
templates,
|
|
13976
|
+
lastDoc: lastVisible
|
|
13977
|
+
};
|
|
13978
|
+
}
|
|
13979
|
+
/**
|
|
13980
|
+
* Get all active templates with optional filters and pagination.
|
|
13981
|
+
* @param options - Options for filtering and pagination.
|
|
13982
|
+
* @returns A promise that resolves to the templates and the last visible document.
|
|
13983
|
+
*/
|
|
13984
|
+
async getTemplates(options) {
|
|
13985
|
+
const {
|
|
13986
|
+
pageSize = 20,
|
|
13987
|
+
lastDoc,
|
|
13988
|
+
isUserForm,
|
|
13989
|
+
isRequired,
|
|
13990
|
+
sortingOrder
|
|
13991
|
+
} = options;
|
|
13992
|
+
const constraints = [
|
|
13993
|
+
(0, import_firestore41.where)("isActive", "==", true),
|
|
13994
|
+
(0, import_firestore41.orderBy)("sortingOrder", "asc"),
|
|
13995
|
+
(0, import_firestore41.orderBy)("title", "asc"),
|
|
13996
|
+
(0, import_firestore41.limit)(pageSize)
|
|
13997
|
+
];
|
|
13998
|
+
if (isUserForm !== void 0) {
|
|
13999
|
+
constraints.push((0, import_firestore41.where)("isUserForm", "==", isUserForm));
|
|
14000
|
+
}
|
|
14001
|
+
if (isRequired !== void 0) {
|
|
14002
|
+
constraints.push((0, import_firestore41.where)("isRequired", "==", isRequired));
|
|
14003
|
+
}
|
|
14004
|
+
if (sortingOrder !== void 0) {
|
|
14005
|
+
constraints.push((0, import_firestore41.where)("sortingOrder", "==", sortingOrder));
|
|
14006
|
+
}
|
|
14007
|
+
if (lastDoc) {
|
|
14008
|
+
constraints.push((0, import_firestore41.startAfter)(lastDoc));
|
|
14009
|
+
}
|
|
14010
|
+
const q = (0, import_firestore41.query)(this.collectionRef, ...constraints.filter((c) => c));
|
|
14011
|
+
const querySnapshot = await (0, import_firestore41.getDocs)(q);
|
|
14012
|
+
const templates = [];
|
|
14013
|
+
let lastVisible = null;
|
|
14014
|
+
querySnapshot.forEach((doc38) => {
|
|
14015
|
+
templates.push(doc38.data());
|
|
14016
|
+
lastVisible = doc38;
|
|
13880
14017
|
});
|
|
13881
14018
|
return {
|
|
13882
14019
|
templates,
|
|
13883
14020
|
lastDoc: lastVisible
|
|
13884
14021
|
};
|
|
13885
14022
|
}
|
|
14023
|
+
/**
|
|
14024
|
+
* Get the total count of active templates with optional filters.
|
|
14025
|
+
* @param options - Options for filtering.
|
|
14026
|
+
* @returns A promise that resolves to the total count of templates.
|
|
14027
|
+
*/
|
|
14028
|
+
async getTemplatesCount(options) {
|
|
14029
|
+
const { isUserForm, isRequired, sortingOrder } = options;
|
|
14030
|
+
const constraints = [(0, import_firestore41.where)("isActive", "==", true)];
|
|
14031
|
+
if (isUserForm !== void 0) {
|
|
14032
|
+
constraints.push((0, import_firestore41.where)("isUserForm", "==", isUserForm));
|
|
14033
|
+
}
|
|
14034
|
+
if (isRequired !== void 0) {
|
|
14035
|
+
constraints.push((0, import_firestore41.where)("isRequired", "==", isRequired));
|
|
14036
|
+
}
|
|
14037
|
+
if (sortingOrder !== void 0) {
|
|
14038
|
+
constraints.push((0, import_firestore41.where)("sortingOrder", "==", sortingOrder));
|
|
14039
|
+
}
|
|
14040
|
+
const q = (0, import_firestore41.query)(this.collectionRef, ...constraints.filter((c) => c));
|
|
14041
|
+
const snapshot = await (0, import_firestore42.getCountFromServer)(q);
|
|
14042
|
+
return snapshot.data().count;
|
|
14043
|
+
}
|
|
14044
|
+
/**
|
|
14045
|
+
* Get all active templates without pagination for filtering purposes.
|
|
14046
|
+
* @returns A promise that resolves to an array of all active templates.
|
|
14047
|
+
*/
|
|
14048
|
+
async getAllActiveTemplates() {
|
|
14049
|
+
const q = (0, import_firestore41.query)(
|
|
14050
|
+
this.collectionRef,
|
|
14051
|
+
(0, import_firestore41.where)("isActive", "==", true),
|
|
14052
|
+
(0, import_firestore41.orderBy)("title", "asc")
|
|
14053
|
+
);
|
|
14054
|
+
const querySnapshot = await (0, import_firestore41.getDocs)(q);
|
|
14055
|
+
const templates = [];
|
|
14056
|
+
querySnapshot.forEach((doc38) => {
|
|
14057
|
+
templates.push(doc38.data());
|
|
14058
|
+
});
|
|
14059
|
+
return templates;
|
|
14060
|
+
}
|
|
13886
14061
|
/**
|
|
13887
14062
|
* Get templates by tags
|
|
13888
14063
|
* @param tags - Tags to filter by
|
|
@@ -13904,9 +14079,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
13904
14079
|
const querySnapshot = await (0, import_firestore41.getDocs)(q);
|
|
13905
14080
|
const templates = [];
|
|
13906
14081
|
let lastVisible = null;
|
|
13907
|
-
querySnapshot.forEach((
|
|
13908
|
-
templates.push(
|
|
13909
|
-
lastVisible =
|
|
14082
|
+
querySnapshot.forEach((doc38) => {
|
|
14083
|
+
templates.push(doc38.data());
|
|
14084
|
+
lastVisible = doc38;
|
|
13910
14085
|
});
|
|
13911
14086
|
return {
|
|
13912
14087
|
templates,
|
|
@@ -13933,9 +14108,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
13933
14108
|
const querySnapshot = await (0, import_firestore41.getDocs)(q);
|
|
13934
14109
|
const templates = [];
|
|
13935
14110
|
let lastVisible = null;
|
|
13936
|
-
querySnapshot.forEach((
|
|
13937
|
-
templates.push(
|
|
13938
|
-
lastVisible =
|
|
14111
|
+
querySnapshot.forEach((doc38) => {
|
|
14112
|
+
templates.push(doc38.data());
|
|
14113
|
+
lastVisible = doc38;
|
|
13939
14114
|
});
|
|
13940
14115
|
return {
|
|
13941
14116
|
templates,
|
|
@@ -13961,15 +14136,15 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
13961
14136
|
}
|
|
13962
14137
|
const querySnapshot = await (0, import_firestore41.getDocs)(q);
|
|
13963
14138
|
const templates = [];
|
|
13964
|
-
querySnapshot.forEach((
|
|
13965
|
-
templates.push(
|
|
14139
|
+
querySnapshot.forEach((doc38) => {
|
|
14140
|
+
templates.push(doc38.data());
|
|
13966
14141
|
});
|
|
13967
14142
|
return templates;
|
|
13968
14143
|
}
|
|
13969
14144
|
};
|
|
13970
14145
|
|
|
13971
14146
|
// src/services/documentation-templates/filled-document.service.ts
|
|
13972
|
-
var
|
|
14147
|
+
var import_firestore43 = require("firebase/firestore");
|
|
13973
14148
|
var FilledDocumentService = class extends BaseService {
|
|
13974
14149
|
constructor(...args) {
|
|
13975
14150
|
super(...args);
|
|
@@ -14024,7 +14199,7 @@ var FilledDocumentService = class extends BaseService {
|
|
|
14024
14199
|
values: initialValues,
|
|
14025
14200
|
status: initialStatus
|
|
14026
14201
|
};
|
|
14027
|
-
const docRef = (0,
|
|
14202
|
+
const docRef = (0, import_firestore43.doc)(
|
|
14028
14203
|
this.db,
|
|
14029
14204
|
APPOINTMENTS_COLLECTION,
|
|
14030
14205
|
// Replaced "appointments"
|
|
@@ -14032,7 +14207,7 @@ var FilledDocumentService = class extends BaseService {
|
|
|
14032
14207
|
formSubcollection,
|
|
14033
14208
|
documentId3
|
|
14034
14209
|
);
|
|
14035
|
-
await (0,
|
|
14210
|
+
await (0, import_firestore43.setDoc)(docRef, filledDocument);
|
|
14036
14211
|
return filledDocument;
|
|
14037
14212
|
}
|
|
14038
14213
|
/**
|
|
@@ -14044,7 +14219,7 @@ var FilledDocumentService = class extends BaseService {
|
|
|
14044
14219
|
*/
|
|
14045
14220
|
async getFilledDocumentFromAppointmentById(appointmentId, formId, isUserForm) {
|
|
14046
14221
|
const formSubcollection = this.getFormSubcollectionPath(isUserForm);
|
|
14047
|
-
const docRef = (0,
|
|
14222
|
+
const docRef = (0, import_firestore43.doc)(
|
|
14048
14223
|
this.db,
|
|
14049
14224
|
APPOINTMENTS_COLLECTION,
|
|
14050
14225
|
// Replaced "appointments"
|
|
@@ -14052,7 +14227,7 @@ var FilledDocumentService = class extends BaseService {
|
|
|
14052
14227
|
formSubcollection,
|
|
14053
14228
|
formId
|
|
14054
14229
|
);
|
|
14055
|
-
const docSnap = await (0,
|
|
14230
|
+
const docSnap = await (0, import_firestore43.getDoc)(docRef);
|
|
14056
14231
|
if (!docSnap.exists()) {
|
|
14057
14232
|
return null;
|
|
14058
14233
|
}
|
|
@@ -14069,7 +14244,7 @@ var FilledDocumentService = class extends BaseService {
|
|
|
14069
14244
|
*/
|
|
14070
14245
|
async updateFilledDocumentInAppointment(appointmentId, formId, isUserForm, values, status) {
|
|
14071
14246
|
const formSubcollection = this.getFormSubcollectionPath(isUserForm);
|
|
14072
|
-
const docRef = (0,
|
|
14247
|
+
const docRef = (0, import_firestore43.doc)(
|
|
14073
14248
|
this.db,
|
|
14074
14249
|
APPOINTMENTS_COLLECTION,
|
|
14075
14250
|
// Replaced "appointments"
|
|
@@ -14101,7 +14276,7 @@ var FilledDocumentService = class extends BaseService {
|
|
|
14101
14276
|
}
|
|
14102
14277
|
if (Object.keys(updatePayload).length === 1 && "updatedAt" in updatePayload) {
|
|
14103
14278
|
}
|
|
14104
|
-
await (0,
|
|
14279
|
+
await (0, import_firestore43.updateDoc)(docRef, updatePayload);
|
|
14105
14280
|
return { ...existingDoc, ...updatePayload };
|
|
14106
14281
|
}
|
|
14107
14282
|
/**
|
|
@@ -14111,20 +14286,20 @@ var FilledDocumentService = class extends BaseService {
|
|
|
14111
14286
|
* @param lastDoc Last document from previous page for pagination.
|
|
14112
14287
|
*/
|
|
14113
14288
|
async getFilledUserFormsForAppointment(appointmentId, pageSize = 20, lastDoc) {
|
|
14114
|
-
const subcollectionRef = (0,
|
|
14289
|
+
const subcollectionRef = (0, import_firestore43.collection)(
|
|
14115
14290
|
this.db,
|
|
14116
14291
|
APPOINTMENTS_COLLECTION,
|
|
14117
14292
|
// Replaced "appointments"
|
|
14118
14293
|
appointmentId,
|
|
14119
14294
|
USER_FORMS_SUBCOLLECTION
|
|
14120
14295
|
);
|
|
14121
|
-
let q = (0,
|
|
14296
|
+
let q = (0, import_firestore43.query)(
|
|
14122
14297
|
subcollectionRef,
|
|
14123
|
-
(0,
|
|
14124
|
-
(0,
|
|
14298
|
+
(0, import_firestore43.orderBy)("updatedAt", "desc"),
|
|
14299
|
+
(0, import_firestore43.limit)(pageSize)
|
|
14125
14300
|
);
|
|
14126
14301
|
if (lastDoc) {
|
|
14127
|
-
q = (0,
|
|
14302
|
+
q = (0, import_firestore43.query)(q, (0, import_firestore43.startAfter)(lastDoc));
|
|
14128
14303
|
}
|
|
14129
14304
|
return this.executeQuery(q);
|
|
14130
14305
|
}
|
|
@@ -14135,31 +14310,31 @@ var FilledDocumentService = class extends BaseService {
|
|
|
14135
14310
|
* @param lastDoc Last document from previous page for pagination.
|
|
14136
14311
|
*/
|
|
14137
14312
|
async getFilledDoctorFormsForAppointment(appointmentId, pageSize = 20, lastDoc) {
|
|
14138
|
-
const subcollectionRef = (0,
|
|
14313
|
+
const subcollectionRef = (0, import_firestore43.collection)(
|
|
14139
14314
|
this.db,
|
|
14140
14315
|
APPOINTMENTS_COLLECTION,
|
|
14141
14316
|
// Replaced "appointments"
|
|
14142
14317
|
appointmentId,
|
|
14143
14318
|
DOCTOR_FORMS_SUBCOLLECTION
|
|
14144
14319
|
);
|
|
14145
|
-
let q = (0,
|
|
14320
|
+
let q = (0, import_firestore43.query)(
|
|
14146
14321
|
subcollectionRef,
|
|
14147
|
-
(0,
|
|
14148
|
-
(0,
|
|
14322
|
+
(0, import_firestore43.orderBy)("updatedAt", "desc"),
|
|
14323
|
+
(0, import_firestore43.limit)(pageSize)
|
|
14149
14324
|
);
|
|
14150
14325
|
if (lastDoc) {
|
|
14151
|
-
q = (0,
|
|
14326
|
+
q = (0, import_firestore43.query)(q, (0, import_firestore43.startAfter)(lastDoc));
|
|
14152
14327
|
}
|
|
14153
14328
|
return this.executeQuery(q);
|
|
14154
14329
|
}
|
|
14155
14330
|
// Helper to execute query and return documents + lastDoc
|
|
14156
14331
|
async executeQuery(q) {
|
|
14157
|
-
const querySnapshot = await (0,
|
|
14332
|
+
const querySnapshot = await (0, import_firestore43.getDocs)(q);
|
|
14158
14333
|
const documents = [];
|
|
14159
14334
|
let lastVisible = null;
|
|
14160
|
-
querySnapshot.forEach((
|
|
14161
|
-
documents.push(
|
|
14162
|
-
lastVisible =
|
|
14335
|
+
querySnapshot.forEach((doc38) => {
|
|
14336
|
+
documents.push(doc38.data());
|
|
14337
|
+
lastVisible = doc38;
|
|
14163
14338
|
});
|
|
14164
14339
|
return {
|
|
14165
14340
|
documents,
|
|
@@ -14318,14 +14493,14 @@ var FilledDocumentService = class extends BaseService {
|
|
|
14318
14493
|
};
|
|
14319
14494
|
|
|
14320
14495
|
// src/services/notifications/notification.service.ts
|
|
14321
|
-
var
|
|
14496
|
+
var import_firestore44 = require("firebase/firestore");
|
|
14322
14497
|
var NotificationService = class extends BaseService {
|
|
14323
14498
|
/**
|
|
14324
14499
|
* Kreira novu notifikaciju
|
|
14325
14500
|
*/
|
|
14326
14501
|
async createNotification(notification) {
|
|
14327
|
-
const notificationsRef = (0,
|
|
14328
|
-
const now =
|
|
14502
|
+
const notificationsRef = (0, import_firestore44.collection)(this.db, NOTIFICATIONS_COLLECTION);
|
|
14503
|
+
const now = import_firestore44.Timestamp.now();
|
|
14329
14504
|
const notificationData = {
|
|
14330
14505
|
...notification,
|
|
14331
14506
|
createdAt: now,
|
|
@@ -14334,7 +14509,7 @@ var NotificationService = class extends BaseService {
|
|
|
14334
14509
|
isRead: false,
|
|
14335
14510
|
userRole: notification.userRole || "patient" /* PATIENT */
|
|
14336
14511
|
};
|
|
14337
|
-
const docRef = await (0,
|
|
14512
|
+
const docRef = await (0, import_firestore44.addDoc)(notificationsRef, notificationData);
|
|
14338
14513
|
return {
|
|
14339
14514
|
...notificationData,
|
|
14340
14515
|
id: docRef.id
|
|
@@ -14344,12 +14519,12 @@ var NotificationService = class extends BaseService {
|
|
|
14344
14519
|
* Dohvata notifikaciju po ID-u
|
|
14345
14520
|
*/
|
|
14346
14521
|
async getNotification(notificationId) {
|
|
14347
|
-
const notificationRef = (0,
|
|
14522
|
+
const notificationRef = (0, import_firestore44.doc)(
|
|
14348
14523
|
this.db,
|
|
14349
14524
|
NOTIFICATIONS_COLLECTION,
|
|
14350
14525
|
notificationId
|
|
14351
14526
|
);
|
|
14352
|
-
const notificationDoc = await (0,
|
|
14527
|
+
const notificationDoc = await (0, import_firestore44.getDoc)(notificationRef);
|
|
14353
14528
|
if (!notificationDoc.exists()) {
|
|
14354
14529
|
return null;
|
|
14355
14530
|
}
|
|
@@ -14362,45 +14537,45 @@ var NotificationService = class extends BaseService {
|
|
|
14362
14537
|
* Dohvata sve notifikacije za korisnika
|
|
14363
14538
|
*/
|
|
14364
14539
|
async getUserNotifications(userId) {
|
|
14365
|
-
const q = (0,
|
|
14366
|
-
(0,
|
|
14367
|
-
(0,
|
|
14368
|
-
(0,
|
|
14369
|
-
);
|
|
14370
|
-
const querySnapshot = await (0,
|
|
14371
|
-
return querySnapshot.docs.map((
|
|
14372
|
-
id:
|
|
14373
|
-
...
|
|
14540
|
+
const q = (0, import_firestore44.query)(
|
|
14541
|
+
(0, import_firestore44.collection)(this.db, NOTIFICATIONS_COLLECTION),
|
|
14542
|
+
(0, import_firestore44.where)("userId", "==", userId),
|
|
14543
|
+
(0, import_firestore44.orderBy)("notificationTime", "desc")
|
|
14544
|
+
);
|
|
14545
|
+
const querySnapshot = await (0, import_firestore44.getDocs)(q);
|
|
14546
|
+
return querySnapshot.docs.map((doc38) => ({
|
|
14547
|
+
id: doc38.id,
|
|
14548
|
+
...doc38.data()
|
|
14374
14549
|
}));
|
|
14375
14550
|
}
|
|
14376
14551
|
/**
|
|
14377
14552
|
* Dohvata nepročitane notifikacije za korisnika
|
|
14378
14553
|
*/
|
|
14379
14554
|
async getUnreadNotifications(userId) {
|
|
14380
|
-
const q = (0,
|
|
14381
|
-
(0,
|
|
14382
|
-
(0,
|
|
14383
|
-
(0,
|
|
14384
|
-
(0,
|
|
14385
|
-
);
|
|
14386
|
-
const querySnapshot = await (0,
|
|
14387
|
-
return querySnapshot.docs.map((
|
|
14388
|
-
id:
|
|
14389
|
-
...
|
|
14555
|
+
const q = (0, import_firestore44.query)(
|
|
14556
|
+
(0, import_firestore44.collection)(this.db, NOTIFICATIONS_COLLECTION),
|
|
14557
|
+
(0, import_firestore44.where)("userId", "==", userId),
|
|
14558
|
+
(0, import_firestore44.where)("isRead", "==", false),
|
|
14559
|
+
(0, import_firestore44.orderBy)("notificationTime", "desc")
|
|
14560
|
+
);
|
|
14561
|
+
const querySnapshot = await (0, import_firestore44.getDocs)(q);
|
|
14562
|
+
return querySnapshot.docs.map((doc38) => ({
|
|
14563
|
+
id: doc38.id,
|
|
14564
|
+
...doc38.data()
|
|
14390
14565
|
}));
|
|
14391
14566
|
}
|
|
14392
14567
|
/**
|
|
14393
14568
|
* Označava notifikaciju kao pročitanu
|
|
14394
14569
|
*/
|
|
14395
14570
|
async markAsRead(notificationId) {
|
|
14396
|
-
const notificationRef = (0,
|
|
14571
|
+
const notificationRef = (0, import_firestore44.doc)(
|
|
14397
14572
|
this.db,
|
|
14398
14573
|
NOTIFICATIONS_COLLECTION,
|
|
14399
14574
|
notificationId
|
|
14400
14575
|
);
|
|
14401
|
-
await (0,
|
|
14576
|
+
await (0, import_firestore44.updateDoc)(notificationRef, {
|
|
14402
14577
|
isRead: true,
|
|
14403
|
-
updatedAt:
|
|
14578
|
+
updatedAt: import_firestore44.Timestamp.now()
|
|
14404
14579
|
});
|
|
14405
14580
|
}
|
|
14406
14581
|
/**
|
|
@@ -14408,16 +14583,16 @@ var NotificationService = class extends BaseService {
|
|
|
14408
14583
|
*/
|
|
14409
14584
|
async markAllAsRead(userId) {
|
|
14410
14585
|
const notifications = await this.getUnreadNotifications(userId);
|
|
14411
|
-
const batch = (0,
|
|
14586
|
+
const batch = (0, import_firestore44.writeBatch)(this.db);
|
|
14412
14587
|
notifications.forEach((notification) => {
|
|
14413
|
-
const notificationRef = (0,
|
|
14588
|
+
const notificationRef = (0, import_firestore44.doc)(
|
|
14414
14589
|
this.db,
|
|
14415
14590
|
NOTIFICATIONS_COLLECTION,
|
|
14416
14591
|
notification.id
|
|
14417
14592
|
);
|
|
14418
14593
|
batch.update(notificationRef, {
|
|
14419
14594
|
isRead: true,
|
|
14420
|
-
updatedAt:
|
|
14595
|
+
updatedAt: import_firestore44.Timestamp.now()
|
|
14421
14596
|
});
|
|
14422
14597
|
});
|
|
14423
14598
|
await batch.commit();
|
|
@@ -14426,74 +14601,74 @@ var NotificationService = class extends BaseService {
|
|
|
14426
14601
|
* Ažurira status notifikacije
|
|
14427
14602
|
*/
|
|
14428
14603
|
async updateNotificationStatus(notificationId, status) {
|
|
14429
|
-
const notificationRef = (0,
|
|
14604
|
+
const notificationRef = (0, import_firestore44.doc)(
|
|
14430
14605
|
this.db,
|
|
14431
14606
|
NOTIFICATIONS_COLLECTION,
|
|
14432
14607
|
notificationId
|
|
14433
14608
|
);
|
|
14434
|
-
await (0,
|
|
14609
|
+
await (0, import_firestore44.updateDoc)(notificationRef, {
|
|
14435
14610
|
status,
|
|
14436
|
-
updatedAt:
|
|
14611
|
+
updatedAt: import_firestore44.Timestamp.now()
|
|
14437
14612
|
});
|
|
14438
14613
|
}
|
|
14439
14614
|
/**
|
|
14440
14615
|
* Briše notifikaciju
|
|
14441
14616
|
*/
|
|
14442
14617
|
async deleteNotification(notificationId) {
|
|
14443
|
-
const notificationRef = (0,
|
|
14618
|
+
const notificationRef = (0, import_firestore44.doc)(
|
|
14444
14619
|
this.db,
|
|
14445
14620
|
NOTIFICATIONS_COLLECTION,
|
|
14446
14621
|
notificationId
|
|
14447
14622
|
);
|
|
14448
|
-
await (0,
|
|
14623
|
+
await (0, import_firestore44.deleteDoc)(notificationRef);
|
|
14449
14624
|
}
|
|
14450
14625
|
/**
|
|
14451
14626
|
* Dohvata notifikacije po tipu
|
|
14452
14627
|
*/
|
|
14453
14628
|
async getNotificationsByType(userId, type) {
|
|
14454
|
-
const q = (0,
|
|
14455
|
-
(0,
|
|
14456
|
-
(0,
|
|
14457
|
-
(0,
|
|
14458
|
-
(0,
|
|
14459
|
-
);
|
|
14460
|
-
const querySnapshot = await (0,
|
|
14461
|
-
return querySnapshot.docs.map((
|
|
14462
|
-
id:
|
|
14463
|
-
...
|
|
14629
|
+
const q = (0, import_firestore44.query)(
|
|
14630
|
+
(0, import_firestore44.collection)(this.db, NOTIFICATIONS_COLLECTION),
|
|
14631
|
+
(0, import_firestore44.where)("userId", "==", userId),
|
|
14632
|
+
(0, import_firestore44.where)("notificationType", "==", type),
|
|
14633
|
+
(0, import_firestore44.orderBy)("notificationTime", "desc")
|
|
14634
|
+
);
|
|
14635
|
+
const querySnapshot = await (0, import_firestore44.getDocs)(q);
|
|
14636
|
+
return querySnapshot.docs.map((doc38) => ({
|
|
14637
|
+
id: doc38.id,
|
|
14638
|
+
...doc38.data()
|
|
14464
14639
|
}));
|
|
14465
14640
|
}
|
|
14466
14641
|
/**
|
|
14467
14642
|
* Dohvata notifikacije za određeni termin
|
|
14468
14643
|
*/
|
|
14469
14644
|
async getAppointmentNotifications(appointmentId) {
|
|
14470
|
-
const q = (0,
|
|
14471
|
-
(0,
|
|
14472
|
-
(0,
|
|
14473
|
-
(0,
|
|
14474
|
-
);
|
|
14475
|
-
const querySnapshot = await (0,
|
|
14476
|
-
return querySnapshot.docs.map((
|
|
14477
|
-
id:
|
|
14478
|
-
...
|
|
14645
|
+
const q = (0, import_firestore44.query)(
|
|
14646
|
+
(0, import_firestore44.collection)(this.db, NOTIFICATIONS_COLLECTION),
|
|
14647
|
+
(0, import_firestore44.where)("appointmentId", "==", appointmentId),
|
|
14648
|
+
(0, import_firestore44.orderBy)("notificationTime", "desc")
|
|
14649
|
+
);
|
|
14650
|
+
const querySnapshot = await (0, import_firestore44.getDocs)(q);
|
|
14651
|
+
return querySnapshot.docs.map((doc38) => ({
|
|
14652
|
+
id: doc38.id,
|
|
14653
|
+
...doc38.data()
|
|
14479
14654
|
}));
|
|
14480
14655
|
}
|
|
14481
14656
|
};
|
|
14482
14657
|
|
|
14483
14658
|
// src/services/patient/patientRequirements.service.ts
|
|
14484
|
-
var
|
|
14659
|
+
var import_firestore45 = require("firebase/firestore");
|
|
14485
14660
|
var PatientRequirementsService = class extends BaseService {
|
|
14486
14661
|
constructor(db, auth, app) {
|
|
14487
14662
|
super(db, auth, app);
|
|
14488
14663
|
}
|
|
14489
14664
|
getPatientRequirementsCollectionRef(patientId) {
|
|
14490
|
-
return (0,
|
|
14665
|
+
return (0, import_firestore45.collection)(
|
|
14491
14666
|
this.db,
|
|
14492
14667
|
`patients/${patientId}/${PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME}`
|
|
14493
14668
|
);
|
|
14494
14669
|
}
|
|
14495
14670
|
getPatientRequirementDocRef(patientId, instanceId) {
|
|
14496
|
-
return (0,
|
|
14671
|
+
return (0, import_firestore45.doc)(
|
|
14497
14672
|
this.getPatientRequirementsCollectionRef(patientId),
|
|
14498
14673
|
instanceId
|
|
14499
14674
|
);
|
|
@@ -14506,7 +14681,7 @@ var PatientRequirementsService = class extends BaseService {
|
|
|
14506
14681
|
*/
|
|
14507
14682
|
async getPatientRequirementInstance(patientId, instanceId) {
|
|
14508
14683
|
const docRef = this.getPatientRequirementDocRef(patientId, instanceId);
|
|
14509
|
-
const docSnap = await (0,
|
|
14684
|
+
const docSnap = await (0, import_firestore45.getDoc)(docRef);
|
|
14510
14685
|
if (!docSnap.exists()) {
|
|
14511
14686
|
return null;
|
|
14512
14687
|
}
|
|
@@ -14525,22 +14700,22 @@ var PatientRequirementsService = class extends BaseService {
|
|
|
14525
14700
|
*/
|
|
14526
14701
|
async getAllPatientRequirementInstances(patientId, filters, pageLimit = 20, lastVisible) {
|
|
14527
14702
|
const collRef = this.getPatientRequirementsCollectionRef(patientId);
|
|
14528
|
-
let q = (0,
|
|
14703
|
+
let q = (0, import_firestore45.query)(collRef, (0, import_firestore45.orderBy)("createdAt", "desc"));
|
|
14529
14704
|
const queryConstraints = [];
|
|
14530
14705
|
if ((filters == null ? void 0 : filters.appointmentId) && filters.appointmentId !== "all") {
|
|
14531
14706
|
queryConstraints.push(
|
|
14532
|
-
(0,
|
|
14707
|
+
(0, import_firestore45.where)("appointmentId", "==", filters.appointmentId)
|
|
14533
14708
|
);
|
|
14534
14709
|
}
|
|
14535
14710
|
if ((filters == null ? void 0 : filters.statuses) && filters.statuses.length > 0) {
|
|
14536
|
-
queryConstraints.push((0,
|
|
14711
|
+
queryConstraints.push((0, import_firestore45.where)("overallStatus", "in", filters.statuses));
|
|
14537
14712
|
}
|
|
14538
14713
|
if (lastVisible) {
|
|
14539
|
-
queryConstraints.push((0,
|
|
14714
|
+
queryConstraints.push((0, import_firestore45.startAfter)(lastVisible));
|
|
14540
14715
|
}
|
|
14541
|
-
queryConstraints.push((0,
|
|
14542
|
-
q = (0,
|
|
14543
|
-
const snapshot = await (0,
|
|
14716
|
+
queryConstraints.push((0, import_firestore45.limit)(pageLimit));
|
|
14717
|
+
q = (0, import_firestore45.query)(collRef, ...queryConstraints);
|
|
14718
|
+
const snapshot = await (0, import_firestore45.getDocs)(q);
|
|
14544
14719
|
let requirements = snapshot.docs.map((docSnap) => {
|
|
14545
14720
|
const data = docSnap.data();
|
|
14546
14721
|
return { id: docSnap.id, ...data };
|
|
@@ -14583,7 +14758,7 @@ var PatientRequirementsService = class extends BaseService {
|
|
|
14583
14758
|
*/
|
|
14584
14759
|
async completeInstruction(patientId, instanceId, instructionId) {
|
|
14585
14760
|
const instanceRef = this.getPatientRequirementDocRef(patientId, instanceId);
|
|
14586
|
-
const instanceSnap = await (0,
|
|
14761
|
+
const instanceSnap = await (0, import_firestore45.getDoc)(instanceRef);
|
|
14587
14762
|
if (!instanceSnap.exists()) {
|
|
14588
14763
|
throw new Error(
|
|
14589
14764
|
`PatientRequirementInstance ${instanceId} not found for patient ${patientId}.`
|
|
@@ -14611,7 +14786,7 @@ var PatientRequirementsService = class extends BaseService {
|
|
|
14611
14786
|
`Instruction ${instructionId} is in status ${instructionToUpdate.status} and cannot be marked as completed.`
|
|
14612
14787
|
);
|
|
14613
14788
|
}
|
|
14614
|
-
const now =
|
|
14789
|
+
const now = import_firestore45.Timestamp.now();
|
|
14615
14790
|
const updatedInstructions = [...instance.instructions];
|
|
14616
14791
|
updatedInstructions[instructionIndex] = {
|
|
14617
14792
|
...instructionToUpdate,
|
|
@@ -14638,7 +14813,7 @@ var PatientRequirementsService = class extends BaseService {
|
|
|
14638
14813
|
if (newOverallStatus !== instance.overallStatus) {
|
|
14639
14814
|
updatePayload.overallStatus = newOverallStatus;
|
|
14640
14815
|
}
|
|
14641
|
-
await (0,
|
|
14816
|
+
await (0, import_firestore45.updateDoc)(instanceRef, updatePayload);
|
|
14642
14817
|
return {
|
|
14643
14818
|
...instance,
|
|
14644
14819
|
instructions: updatedInstructions,
|
|
@@ -14651,70 +14826,144 @@ var PatientRequirementsService = class extends BaseService {
|
|
|
14651
14826
|
};
|
|
14652
14827
|
|
|
14653
14828
|
// src/services/procedure/procedure.service.ts
|
|
14654
|
-
var
|
|
14829
|
+
var import_firestore46 = require("firebase/firestore");
|
|
14655
14830
|
|
|
14656
14831
|
// src/validations/procedure.schema.ts
|
|
14832
|
+
var import_zod25 = require("zod");
|
|
14833
|
+
|
|
14834
|
+
// src/validations/procedure-product.schema.ts
|
|
14657
14835
|
var import_zod24 = require("zod");
|
|
14658
|
-
var
|
|
14659
|
-
|
|
14660
|
-
|
|
14661
|
-
|
|
14662
|
-
|
|
14663
|
-
|
|
14664
|
-
|
|
14665
|
-
|
|
14666
|
-
|
|
14667
|
-
|
|
14668
|
-
price: import_zod24.z.number().min(0),
|
|
14836
|
+
var procedureProductDataSchema = import_zod24.z.object({
|
|
14837
|
+
/**
|
|
14838
|
+
* The ID of the product. Must be a non-empty string.
|
|
14839
|
+
* @validation
|
|
14840
|
+
*/
|
|
14841
|
+
productId: import_zod24.z.string().min(1, "Product ID is required"),
|
|
14842
|
+
/**
|
|
14843
|
+
* The price of the product. Must be a non-negative number.
|
|
14844
|
+
* @validation
|
|
14845
|
+
*/
|
|
14846
|
+
price: import_zod24.z.number().min(0, "Price must be a non-negative number"),
|
|
14847
|
+
/**
|
|
14848
|
+
* The currency for the price. Must be one of the values from the Currency enum.
|
|
14849
|
+
* @validation
|
|
14850
|
+
*/
|
|
14669
14851
|
currency: import_zod24.z.nativeEnum(Currency),
|
|
14852
|
+
/**
|
|
14853
|
+
* The pricing measure for the product. Must be one of the values from the PricingMeasure enum.
|
|
14854
|
+
* @validation
|
|
14855
|
+
*/
|
|
14670
14856
|
pricingMeasure: import_zod24.z.nativeEnum(PricingMeasure),
|
|
14671
|
-
|
|
14857
|
+
/**
|
|
14858
|
+
* Whether this is the default product for the procedure.
|
|
14859
|
+
* @validation
|
|
14860
|
+
*/
|
|
14861
|
+
isDefault: import_zod24.z.boolean().optional()
|
|
14862
|
+
});
|
|
14863
|
+
|
|
14864
|
+
// src/validations/procedure.schema.ts
|
|
14865
|
+
var storedProcedureProductSchema = import_zod25.z.object({
|
|
14866
|
+
/**
|
|
14867
|
+
* The full product object used in the procedure.
|
|
14868
|
+
*/
|
|
14869
|
+
product: import_zod25.z.any(),
|
|
14870
|
+
// We'll validate the full product object separately
|
|
14871
|
+
/**
|
|
14872
|
+
* The price of the procedure when using this specific product.
|
|
14873
|
+
*/
|
|
14874
|
+
price: import_zod25.z.number().min(0, "Price must be a non-negative number"),
|
|
14875
|
+
/**
|
|
14876
|
+
* The currency for the price of this product.
|
|
14877
|
+
*/
|
|
14878
|
+
currency: import_zod25.z.nativeEnum(Currency),
|
|
14879
|
+
/**
|
|
14880
|
+
* How the price is measured (e.g., per ml, per zone).
|
|
14881
|
+
*/
|
|
14882
|
+
pricingMeasure: import_zod25.z.nativeEnum(PricingMeasure),
|
|
14883
|
+
/**
|
|
14884
|
+
* Whether this is the default product for the procedure.
|
|
14885
|
+
*/
|
|
14886
|
+
isDefault: import_zod25.z.boolean().optional()
|
|
14887
|
+
});
|
|
14888
|
+
var createProcedureSchema = import_zod25.z.object({
|
|
14889
|
+
name: import_zod25.z.string().min(1).max(200),
|
|
14890
|
+
// Optional: service will derive from name if not provided by client
|
|
14891
|
+
nameLower: import_zod25.z.string().min(1).max(200).optional(),
|
|
14892
|
+
description: import_zod25.z.string().min(1).max(2e3),
|
|
14893
|
+
family: import_zod25.z.nativeEnum(ProcedureFamily),
|
|
14894
|
+
categoryId: import_zod25.z.string().min(1),
|
|
14895
|
+
subcategoryId: import_zod25.z.string().min(1),
|
|
14896
|
+
technologyId: import_zod25.z.string().min(1),
|
|
14897
|
+
productId: import_zod25.z.string().min(1),
|
|
14898
|
+
price: import_zod25.z.number().min(0),
|
|
14899
|
+
currency: import_zod25.z.nativeEnum(Currency),
|
|
14900
|
+
pricingMeasure: import_zod25.z.nativeEnum(PricingMeasure),
|
|
14901
|
+
productsMetadata: import_zod25.z.array(procedureProductDataSchema).min(1),
|
|
14902
|
+
duration: import_zod25.z.number().min(1).max(480),
|
|
14672
14903
|
// Max 8 hours
|
|
14673
|
-
practitionerId:
|
|
14674
|
-
clinicBranchId:
|
|
14675
|
-
photos:
|
|
14904
|
+
practitionerId: import_zod25.z.string().min(1),
|
|
14905
|
+
clinicBranchId: import_zod25.z.string().min(1),
|
|
14906
|
+
photos: import_zod25.z.array(mediaResourceSchema).optional()
|
|
14676
14907
|
});
|
|
14677
|
-
var updateProcedureSchema =
|
|
14678
|
-
name:
|
|
14679
|
-
nameLower:
|
|
14680
|
-
description:
|
|
14681
|
-
price:
|
|
14682
|
-
currency:
|
|
14683
|
-
pricingMeasure:
|
|
14684
|
-
|
|
14685
|
-
|
|
14686
|
-
|
|
14687
|
-
|
|
14688
|
-
|
|
14689
|
-
|
|
14690
|
-
|
|
14691
|
-
|
|
14692
|
-
|
|
14908
|
+
var updateProcedureSchema = import_zod25.z.object({
|
|
14909
|
+
name: import_zod25.z.string().min(3).max(100).optional(),
|
|
14910
|
+
nameLower: import_zod25.z.string().min(1).max(200).optional(),
|
|
14911
|
+
description: import_zod25.z.string().min(3).max(1e3).optional(),
|
|
14912
|
+
price: import_zod25.z.number().min(0).optional(),
|
|
14913
|
+
currency: import_zod25.z.nativeEnum(Currency).optional(),
|
|
14914
|
+
pricingMeasure: import_zod25.z.nativeEnum(PricingMeasure).optional(),
|
|
14915
|
+
productsMetadata: import_zod25.z.array(procedureProductDataSchema).min(1).optional(),
|
|
14916
|
+
duration: import_zod25.z.number().min(0).optional(),
|
|
14917
|
+
isActive: import_zod25.z.boolean().optional(),
|
|
14918
|
+
practitionerId: import_zod25.z.string().optional(),
|
|
14919
|
+
categoryId: import_zod25.z.string().optional(),
|
|
14920
|
+
subcategoryId: import_zod25.z.string().optional(),
|
|
14921
|
+
technologyId: import_zod25.z.string().optional(),
|
|
14922
|
+
productId: import_zod25.z.string().optional(),
|
|
14923
|
+
clinicBranchId: import_zod25.z.string().optional(),
|
|
14924
|
+
photos: import_zod25.z.array(mediaResourceSchema).optional()
|
|
14693
14925
|
});
|
|
14694
|
-
var procedureSchema =
|
|
14695
|
-
id:
|
|
14696
|
-
|
|
14697
|
-
|
|
14926
|
+
var procedureSchema = import_zod25.z.object({
|
|
14927
|
+
id: import_zod25.z.string().min(1),
|
|
14928
|
+
name: import_zod25.z.string().min(1).max(200),
|
|
14929
|
+
nameLower: import_zod25.z.string().min(1).max(200),
|
|
14930
|
+
description: import_zod25.z.string().min(1).max(2e3),
|
|
14931
|
+
family: import_zod25.z.nativeEnum(ProcedureFamily),
|
|
14932
|
+
category: import_zod25.z.any(),
|
|
14698
14933
|
// We'll validate the full category object separately
|
|
14699
|
-
subcategory:
|
|
14934
|
+
subcategory: import_zod25.z.any(),
|
|
14700
14935
|
// We'll validate the full subcategory object separately
|
|
14701
|
-
technology:
|
|
14936
|
+
technology: import_zod25.z.any(),
|
|
14702
14937
|
// We'll validate the full technology object separately
|
|
14703
|
-
product:
|
|
14938
|
+
product: import_zod25.z.any(),
|
|
14704
14939
|
// We'll validate the full product object separately
|
|
14705
|
-
|
|
14940
|
+
productsMetadata: import_zod25.z.array(storedProcedureProductSchema).min(1),
|
|
14941
|
+
// Use stored format schema
|
|
14942
|
+
price: import_zod25.z.number().min(0),
|
|
14943
|
+
currency: import_zod25.z.nativeEnum(Currency),
|
|
14944
|
+
pricingMeasure: import_zod25.z.nativeEnum(PricingMeasure),
|
|
14945
|
+
duration: import_zod25.z.number().min(1).max(480),
|
|
14946
|
+
practitionerId: import_zod25.z.string().min(1),
|
|
14947
|
+
clinicBranchId: import_zod25.z.string().min(1),
|
|
14948
|
+
photos: import_zod25.z.array(import_zod25.z.string()).optional(),
|
|
14949
|
+
// Stored as URL strings
|
|
14950
|
+
blockingConditions: import_zod25.z.array(import_zod25.z.any()),
|
|
14706
14951
|
// We'll validate blocking conditions separately
|
|
14707
|
-
contraindications:
|
|
14952
|
+
contraindications: import_zod25.z.array(import_zod25.z.any()),
|
|
14708
14953
|
// We'll validate contraindications separately
|
|
14709
|
-
|
|
14954
|
+
contraindicationIds: import_zod25.z.array(import_zod25.z.string()),
|
|
14955
|
+
// Array of IDs for efficient querying
|
|
14956
|
+
treatmentBenefits: import_zod25.z.array(import_zod25.z.any()),
|
|
14710
14957
|
// We'll validate treatment benefits separately
|
|
14711
|
-
|
|
14958
|
+
treatmentBenefitIds: import_zod25.z.array(import_zod25.z.string()),
|
|
14959
|
+
// Array of IDs for efficient querying
|
|
14960
|
+
preRequirements: import_zod25.z.array(import_zod25.z.any()),
|
|
14712
14961
|
// We'll validate requirements separately
|
|
14713
|
-
postRequirements:
|
|
14962
|
+
postRequirements: import_zod25.z.array(import_zod25.z.any()),
|
|
14714
14963
|
// We'll validate requirements separately
|
|
14715
|
-
certificationRequirement:
|
|
14964
|
+
certificationRequirement: import_zod25.z.any(),
|
|
14716
14965
|
// We'll validate certification requirement separately
|
|
14717
|
-
documentationTemplates:
|
|
14966
|
+
documentationTemplates: import_zod25.z.array(import_zod25.z.any()),
|
|
14718
14967
|
// We'll validate documentation templates separately
|
|
14719
14968
|
clinicInfo: clinicInfoSchema,
|
|
14720
14969
|
// Clinic info validation
|
|
@@ -14722,9 +14971,9 @@ var procedureSchema = createProcedureSchema.extend({
|
|
|
14722
14971
|
// Doctor info validation
|
|
14723
14972
|
reviewInfo: procedureReviewInfoSchema,
|
|
14724
14973
|
// Procedure review info validation
|
|
14725
|
-
isActive:
|
|
14726
|
-
createdAt:
|
|
14727
|
-
updatedAt:
|
|
14974
|
+
isActive: import_zod25.z.boolean(),
|
|
14975
|
+
createdAt: import_zod25.z.date(),
|
|
14976
|
+
updatedAt: import_zod25.z.date()
|
|
14728
14977
|
});
|
|
14729
14978
|
|
|
14730
14979
|
// src/services/procedure/procedure.service.ts
|
|
@@ -14751,7 +15000,9 @@ var ProcedureService = class extends BaseService {
|
|
|
14751
15000
|
return media;
|
|
14752
15001
|
}
|
|
14753
15002
|
if (media instanceof File || media instanceof Blob) {
|
|
14754
|
-
console.log(
|
|
15003
|
+
console.log(
|
|
15004
|
+
`[ProcedureService] Uploading ${collectionName} media for ${ownerId}`
|
|
15005
|
+
);
|
|
14755
15006
|
const metadata = await this.mediaService.uploadMedia(
|
|
14756
15007
|
media,
|
|
14757
15008
|
ownerId,
|
|
@@ -14773,41 +15024,91 @@ var ProcedureService = class extends BaseService {
|
|
|
14773
15024
|
if (!mediaArray || mediaArray.length === 0) return [];
|
|
14774
15025
|
const result = [];
|
|
14775
15026
|
for (const media of mediaArray) {
|
|
14776
|
-
const processedUrl = await this.processMedia(
|
|
15027
|
+
const processedUrl = await this.processMedia(
|
|
15028
|
+
media,
|
|
15029
|
+
ownerId,
|
|
15030
|
+
collectionName
|
|
15031
|
+
);
|
|
14777
15032
|
if (processedUrl) {
|
|
14778
15033
|
result.push(processedUrl);
|
|
14779
15034
|
}
|
|
14780
15035
|
}
|
|
14781
15036
|
return result;
|
|
14782
15037
|
}
|
|
15038
|
+
/**
|
|
15039
|
+
* Transforms validated procedure product data (with productId) to ProcedureProduct objects (with full product)
|
|
15040
|
+
* @param productsMetadata Array of validated procedure product data
|
|
15041
|
+
* @param technologyId Technology ID to fetch products from
|
|
15042
|
+
* @returns Array of ProcedureProduct objects with full product information
|
|
15043
|
+
*/
|
|
15044
|
+
async transformProductsMetadata(productsMetadata, technologyId) {
|
|
15045
|
+
const transformedProducts = [];
|
|
15046
|
+
for (const productData of productsMetadata) {
|
|
15047
|
+
const product = await this.productService.getById(
|
|
15048
|
+
technologyId,
|
|
15049
|
+
productData.productId
|
|
15050
|
+
);
|
|
15051
|
+
if (!product) {
|
|
15052
|
+
throw new Error(
|
|
15053
|
+
`Product with ID ${productData.productId} not found for technology ${technologyId}`
|
|
15054
|
+
);
|
|
15055
|
+
}
|
|
15056
|
+
transformedProducts.push({
|
|
15057
|
+
product,
|
|
15058
|
+
price: productData.price,
|
|
15059
|
+
currency: productData.currency,
|
|
15060
|
+
pricingMeasure: productData.pricingMeasure,
|
|
15061
|
+
isDefault: productData.isDefault
|
|
15062
|
+
});
|
|
15063
|
+
}
|
|
15064
|
+
return transformedProducts;
|
|
15065
|
+
}
|
|
14783
15066
|
/**
|
|
14784
15067
|
* Creates a new procedure
|
|
14785
15068
|
* @param data - The data for creating a new procedure
|
|
14786
15069
|
* @returns The created procedure
|
|
14787
15070
|
*/
|
|
14788
15071
|
async createProcedure(data) {
|
|
14789
|
-
var _a;
|
|
15072
|
+
var _a, _b, _c;
|
|
14790
15073
|
const validatedData = createProcedureSchema.parse(data);
|
|
14791
15074
|
const procedureId = this.generateId();
|
|
14792
15075
|
const [category, subcategory, technology, product] = await Promise.all([
|
|
14793
15076
|
this.categoryService.getById(validatedData.categoryId),
|
|
14794
|
-
this.subcategoryService.getById(
|
|
15077
|
+
this.subcategoryService.getById(
|
|
15078
|
+
validatedData.categoryId,
|
|
15079
|
+
validatedData.subcategoryId
|
|
15080
|
+
),
|
|
14795
15081
|
this.technologyService.getById(validatedData.technologyId),
|
|
14796
|
-
this.productService.getById(
|
|
15082
|
+
this.productService.getById(
|
|
15083
|
+
validatedData.technologyId,
|
|
15084
|
+
validatedData.productId
|
|
15085
|
+
)
|
|
14797
15086
|
]);
|
|
14798
15087
|
if (!category || !subcategory || !technology || !product) {
|
|
14799
15088
|
throw new Error("One or more required base entities not found");
|
|
14800
15089
|
}
|
|
14801
|
-
const clinicRef = (0,
|
|
14802
|
-
|
|
15090
|
+
const clinicRef = (0, import_firestore46.doc)(
|
|
15091
|
+
this.db,
|
|
15092
|
+
CLINICS_COLLECTION,
|
|
15093
|
+
validatedData.clinicBranchId
|
|
15094
|
+
);
|
|
15095
|
+
const clinicSnapshot = await (0, import_firestore46.getDoc)(clinicRef);
|
|
14803
15096
|
if (!clinicSnapshot.exists()) {
|
|
14804
|
-
throw new Error(
|
|
15097
|
+
throw new Error(
|
|
15098
|
+
`Clinic with ID ${validatedData.clinicBranchId} not found`
|
|
15099
|
+
);
|
|
14805
15100
|
}
|
|
14806
15101
|
const clinic = clinicSnapshot.data();
|
|
14807
|
-
const practitionerRef = (0,
|
|
14808
|
-
|
|
15102
|
+
const practitionerRef = (0, import_firestore46.doc)(
|
|
15103
|
+
this.db,
|
|
15104
|
+
PRACTITIONERS_COLLECTION,
|
|
15105
|
+
validatedData.practitionerId
|
|
15106
|
+
);
|
|
15107
|
+
const practitionerSnapshot = await (0, import_firestore46.getDoc)(practitionerRef);
|
|
14809
15108
|
if (!practitionerSnapshot.exists()) {
|
|
14810
|
-
throw new Error(
|
|
15109
|
+
throw new Error(
|
|
15110
|
+
`Practitioner with ID ${validatedData.practitionerId} not found`
|
|
15111
|
+
);
|
|
14811
15112
|
}
|
|
14812
15113
|
const practitioner = practitionerSnapshot.data();
|
|
14813
15114
|
let processedPhotos = [];
|
|
@@ -14818,6 +15119,10 @@ var ProcedureService = class extends BaseService {
|
|
|
14818
15119
|
"procedure-photos"
|
|
14819
15120
|
);
|
|
14820
15121
|
}
|
|
15122
|
+
const transformedProductsMetadata = await this.transformProductsMetadata(
|
|
15123
|
+
validatedData.productsMetadata,
|
|
15124
|
+
validatedData.technologyId
|
|
15125
|
+
);
|
|
14821
15126
|
const clinicInfo = {
|
|
14822
15127
|
id: clinicSnapshot.id,
|
|
14823
15128
|
name: clinic.name,
|
|
@@ -14846,9 +15151,12 @@ var ProcedureService = class extends BaseService {
|
|
|
14846
15151
|
subcategory,
|
|
14847
15152
|
technology,
|
|
14848
15153
|
product,
|
|
15154
|
+
productsMetadata: transformedProductsMetadata,
|
|
14849
15155
|
blockingConditions: technology.blockingConditions,
|
|
14850
15156
|
contraindications: technology.contraindications || [],
|
|
15157
|
+
contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
|
|
14851
15158
|
treatmentBenefits: technology.benefits,
|
|
15159
|
+
treatmentBenefitIds: ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [],
|
|
14852
15160
|
preRequirements: technology.requirements.pre,
|
|
14853
15161
|
postRequirements: technology.requirements.post,
|
|
14854
15162
|
certificationRequirement: technology.certificationRequirement,
|
|
@@ -14871,13 +15179,13 @@ var ProcedureService = class extends BaseService {
|
|
|
14871
15179
|
isActive: true
|
|
14872
15180
|
// Default to active
|
|
14873
15181
|
};
|
|
14874
|
-
const procedureRef = (0,
|
|
14875
|
-
await (0,
|
|
15182
|
+
const procedureRef = (0, import_firestore46.doc)(this.db, PROCEDURES_COLLECTION, procedureId);
|
|
15183
|
+
await (0, import_firestore46.setDoc)(procedureRef, {
|
|
14876
15184
|
...newProcedure,
|
|
14877
|
-
createdAt: (0,
|
|
14878
|
-
updatedAt: (0,
|
|
15185
|
+
createdAt: (0, import_firestore46.serverTimestamp)(),
|
|
15186
|
+
updatedAt: (0, import_firestore46.serverTimestamp)()
|
|
14879
15187
|
});
|
|
14880
|
-
const savedDoc = await (0,
|
|
15188
|
+
const savedDoc = await (0, import_firestore46.getDoc)(procedureRef);
|
|
14881
15189
|
return savedDoc.data();
|
|
14882
15190
|
}
|
|
14883
15191
|
/**
|
|
@@ -14889,7 +15197,7 @@ var ProcedureService = class extends BaseService {
|
|
|
14889
15197
|
* @returns A promise that resolves to an array of the newly created procedures.
|
|
14890
15198
|
*/
|
|
14891
15199
|
async bulkCreateProcedures(baseData, practitionerIds) {
|
|
14892
|
-
var _a;
|
|
15200
|
+
var _a, _b, _c;
|
|
14893
15201
|
if (!practitionerIds || practitionerIds.length === 0) {
|
|
14894
15202
|
throw new Error("Practitioner IDs array cannot be empty.");
|
|
14895
15203
|
}
|
|
@@ -14897,16 +15205,24 @@ var ProcedureService = class extends BaseService {
|
|
|
14897
15205
|
const validatedData = createProcedureSchema.parse(validationData);
|
|
14898
15206
|
const [category, subcategory, technology, product, clinicSnapshot] = await Promise.all([
|
|
14899
15207
|
this.categoryService.getById(validatedData.categoryId),
|
|
14900
|
-
this.subcategoryService.getById(
|
|
15208
|
+
this.subcategoryService.getById(
|
|
15209
|
+
validatedData.categoryId,
|
|
15210
|
+
validatedData.subcategoryId
|
|
15211
|
+
),
|
|
14901
15212
|
this.technologyService.getById(validatedData.technologyId),
|
|
14902
|
-
this.productService.getById(
|
|
14903
|
-
|
|
15213
|
+
this.productService.getById(
|
|
15214
|
+
validatedData.technologyId,
|
|
15215
|
+
validatedData.productId
|
|
15216
|
+
),
|
|
15217
|
+
(0, import_firestore46.getDoc)((0, import_firestore46.doc)(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId))
|
|
14904
15218
|
]);
|
|
14905
15219
|
if (!category || !subcategory || !technology || !product) {
|
|
14906
15220
|
throw new Error("One or more required base entities not found");
|
|
14907
15221
|
}
|
|
14908
15222
|
if (!clinicSnapshot.exists()) {
|
|
14909
|
-
throw new Error(
|
|
15223
|
+
throw new Error(
|
|
15224
|
+
`Clinic with ID ${validatedData.clinicBranchId} not found`
|
|
15225
|
+
);
|
|
14910
15226
|
}
|
|
14911
15227
|
const clinic = clinicSnapshot.data();
|
|
14912
15228
|
let processedPhotos = [];
|
|
@@ -14918,24 +15234,32 @@ var ProcedureService = class extends BaseService {
|
|
|
14918
15234
|
"procedure-photos-batch"
|
|
14919
15235
|
);
|
|
14920
15236
|
}
|
|
15237
|
+
const transformedProductsMetadata = await this.transformProductsMetadata(
|
|
15238
|
+
validatedData.productsMetadata,
|
|
15239
|
+
validatedData.technologyId
|
|
15240
|
+
);
|
|
14921
15241
|
const practitionersMap = /* @__PURE__ */ new Map();
|
|
14922
15242
|
for (let i = 0; i < practitionerIds.length; i += 30) {
|
|
14923
15243
|
const chunk = practitionerIds.slice(i, i + 30);
|
|
14924
|
-
const practitionersQuery = (0,
|
|
14925
|
-
(0,
|
|
14926
|
-
(0,
|
|
15244
|
+
const practitionersQuery = (0, import_firestore46.query)(
|
|
15245
|
+
(0, import_firestore46.collection)(this.db, PRACTITIONERS_COLLECTION),
|
|
15246
|
+
(0, import_firestore46.where)((0, import_firestore46.documentId)(), "in", chunk)
|
|
14927
15247
|
);
|
|
14928
|
-
const practitionersSnapshot = await (0,
|
|
14929
|
-
practitionersSnapshot.docs.forEach((
|
|
14930
|
-
practitionersMap.set(
|
|
15248
|
+
const practitionersSnapshot = await (0, import_firestore46.getDocs)(practitionersQuery);
|
|
15249
|
+
practitionersSnapshot.docs.forEach((doc38) => {
|
|
15250
|
+
practitionersMap.set(doc38.id, doc38.data());
|
|
14931
15251
|
});
|
|
14932
15252
|
}
|
|
14933
15253
|
if (practitionersMap.size !== practitionerIds.length) {
|
|
14934
15254
|
const foundIds = Array.from(practitionersMap.keys());
|
|
14935
|
-
const notFoundIds = practitionerIds.filter(
|
|
14936
|
-
|
|
15255
|
+
const notFoundIds = practitionerIds.filter(
|
|
15256
|
+
(id) => !foundIds.includes(id)
|
|
15257
|
+
);
|
|
15258
|
+
throw new Error(
|
|
15259
|
+
`The following practitioners were not found: ${notFoundIds.join(", ")}`
|
|
15260
|
+
);
|
|
14937
15261
|
}
|
|
14938
|
-
const batch = (0,
|
|
15262
|
+
const batch = (0, import_firestore46.writeBatch)(this.db);
|
|
14939
15263
|
const createdProcedureIds = [];
|
|
14940
15264
|
const clinicInfo = {
|
|
14941
15265
|
id: clinicSnapshot.id,
|
|
@@ -14957,7 +15281,7 @@ var ProcedureService = class extends BaseService {
|
|
|
14957
15281
|
};
|
|
14958
15282
|
const procedureId = this.generateId();
|
|
14959
15283
|
createdProcedureIds.push(procedureId);
|
|
14960
|
-
const procedureRef = (0,
|
|
15284
|
+
const procedureRef = (0, import_firestore46.doc)(this.db, PROCEDURES_COLLECTION, procedureId);
|
|
14961
15285
|
const newProcedure = {
|
|
14962
15286
|
id: procedureId,
|
|
14963
15287
|
...validatedData,
|
|
@@ -14969,9 +15293,12 @@ var ProcedureService = class extends BaseService {
|
|
|
14969
15293
|
subcategory,
|
|
14970
15294
|
technology,
|
|
14971
15295
|
product,
|
|
15296
|
+
productsMetadata: transformedProductsMetadata,
|
|
14972
15297
|
blockingConditions: technology.blockingConditions,
|
|
14973
15298
|
contraindications: technology.contraindications || [],
|
|
15299
|
+
contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
|
|
14974
15300
|
treatmentBenefits: technology.benefits,
|
|
15301
|
+
treatmentBenefitIds: ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [],
|
|
14975
15302
|
preRequirements: technology.requirements.pre,
|
|
14976
15303
|
postRequirements: technology.requirements.post,
|
|
14977
15304
|
certificationRequirement: technology.certificationRequirement,
|
|
@@ -14993,18 +15320,21 @@ var ProcedureService = class extends BaseService {
|
|
|
14993
15320
|
};
|
|
14994
15321
|
batch.set(procedureRef, {
|
|
14995
15322
|
...newProcedure,
|
|
14996
|
-
createdAt: (0,
|
|
14997
|
-
updatedAt: (0,
|
|
15323
|
+
createdAt: (0, import_firestore46.serverTimestamp)(),
|
|
15324
|
+
updatedAt: (0, import_firestore46.serverTimestamp)()
|
|
14998
15325
|
});
|
|
14999
15326
|
}
|
|
15000
15327
|
await batch.commit();
|
|
15001
15328
|
const fetchedProcedures = [];
|
|
15002
15329
|
for (let i = 0; i < createdProcedureIds.length; i += 30) {
|
|
15003
15330
|
const chunk = createdProcedureIds.slice(i, i + 30);
|
|
15004
|
-
const q = (0,
|
|
15005
|
-
|
|
15006
|
-
|
|
15007
|
-
|
|
15331
|
+
const q = (0, import_firestore46.query)(
|
|
15332
|
+
(0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION),
|
|
15333
|
+
(0, import_firestore46.where)((0, import_firestore46.documentId)(), "in", chunk)
|
|
15334
|
+
);
|
|
15335
|
+
const snapshot = await (0, import_firestore46.getDocs)(q);
|
|
15336
|
+
snapshot.forEach((doc38) => {
|
|
15337
|
+
fetchedProcedures.push(doc38.data());
|
|
15008
15338
|
});
|
|
15009
15339
|
}
|
|
15010
15340
|
return fetchedProcedures;
|
|
@@ -15015,8 +15345,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15015
15345
|
* @returns The procedure if found, null otherwise
|
|
15016
15346
|
*/
|
|
15017
15347
|
async getProcedure(id) {
|
|
15018
|
-
const docRef = (0,
|
|
15019
|
-
const docSnap = await (0,
|
|
15348
|
+
const docRef = (0, import_firestore46.doc)(this.db, PROCEDURES_COLLECTION, id);
|
|
15349
|
+
const docSnap = await (0, import_firestore46.getDoc)(docRef);
|
|
15020
15350
|
if (!docSnap.exists()) {
|
|
15021
15351
|
return null;
|
|
15022
15352
|
}
|
|
@@ -15028,13 +15358,13 @@ var ProcedureService = class extends BaseService {
|
|
|
15028
15358
|
* @returns List of procedures
|
|
15029
15359
|
*/
|
|
15030
15360
|
async getProceduresByClinicBranch(clinicBranchId) {
|
|
15031
|
-
const q = (0,
|
|
15032
|
-
(0,
|
|
15033
|
-
(0,
|
|
15034
|
-
(0,
|
|
15361
|
+
const q = (0, import_firestore46.query)(
|
|
15362
|
+
(0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION),
|
|
15363
|
+
(0, import_firestore46.where)("clinicBranchId", "==", clinicBranchId),
|
|
15364
|
+
(0, import_firestore46.where)("isActive", "==", true)
|
|
15035
15365
|
);
|
|
15036
|
-
const snapshot = await (0,
|
|
15037
|
-
return snapshot.docs.map((
|
|
15366
|
+
const snapshot = await (0, import_firestore46.getDocs)(q);
|
|
15367
|
+
return snapshot.docs.map((doc38) => doc38.data());
|
|
15038
15368
|
}
|
|
15039
15369
|
/**
|
|
15040
15370
|
* Gets all procedures for a practitioner
|
|
@@ -15042,13 +15372,13 @@ var ProcedureService = class extends BaseService {
|
|
|
15042
15372
|
* @returns List of procedures
|
|
15043
15373
|
*/
|
|
15044
15374
|
async getProceduresByPractitioner(practitionerId) {
|
|
15045
|
-
const q = (0,
|
|
15046
|
-
(0,
|
|
15047
|
-
(0,
|
|
15048
|
-
(0,
|
|
15375
|
+
const q = (0, import_firestore46.query)(
|
|
15376
|
+
(0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION),
|
|
15377
|
+
(0, import_firestore46.where)("practitionerId", "==", practitionerId),
|
|
15378
|
+
(0, import_firestore46.where)("isActive", "==", true)
|
|
15049
15379
|
);
|
|
15050
|
-
const snapshot = await (0,
|
|
15051
|
-
return snapshot.docs.map((
|
|
15380
|
+
const snapshot = await (0, import_firestore46.getDocs)(q);
|
|
15381
|
+
return snapshot.docs.map((doc38) => doc38.data());
|
|
15052
15382
|
}
|
|
15053
15383
|
/**
|
|
15054
15384
|
* Gets all inactive procedures for a practitioner
|
|
@@ -15056,13 +15386,13 @@ var ProcedureService = class extends BaseService {
|
|
|
15056
15386
|
* @returns List of inactive procedures
|
|
15057
15387
|
*/
|
|
15058
15388
|
async getInactiveProceduresByPractitioner(practitionerId) {
|
|
15059
|
-
const q = (0,
|
|
15060
|
-
(0,
|
|
15061
|
-
(0,
|
|
15062
|
-
(0,
|
|
15389
|
+
const q = (0, import_firestore46.query)(
|
|
15390
|
+
(0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION),
|
|
15391
|
+
(0, import_firestore46.where)("practitionerId", "==", practitionerId),
|
|
15392
|
+
(0, import_firestore46.where)("isActive", "==", false)
|
|
15063
15393
|
);
|
|
15064
|
-
const snapshot = await (0,
|
|
15065
|
-
return snapshot.docs.map((
|
|
15394
|
+
const snapshot = await (0, import_firestore46.getDocs)(q);
|
|
15395
|
+
return snapshot.docs.map((doc38) => doc38.data());
|
|
15066
15396
|
}
|
|
15067
15397
|
/**
|
|
15068
15398
|
* Updates a procedure
|
|
@@ -15071,15 +15401,29 @@ var ProcedureService = class extends BaseService {
|
|
|
15071
15401
|
* @returns The updated procedure
|
|
15072
15402
|
*/
|
|
15073
15403
|
async updateProcedure(id, data) {
|
|
15074
|
-
var _a;
|
|
15404
|
+
var _a, _b, _c, _d;
|
|
15075
15405
|
const validatedData = updateProcedureSchema.parse(data);
|
|
15076
|
-
const procedureRef = (0,
|
|
15077
|
-
const procedureSnapshot = await (0,
|
|
15406
|
+
const procedureRef = (0, import_firestore46.doc)(this.db, PROCEDURES_COLLECTION, id);
|
|
15407
|
+
const procedureSnapshot = await (0, import_firestore46.getDoc)(procedureRef);
|
|
15078
15408
|
if (!procedureSnapshot.exists()) {
|
|
15079
15409
|
throw new Error(`Procedure with ID ${id} not found`);
|
|
15080
15410
|
}
|
|
15081
15411
|
const existingProcedure = procedureSnapshot.data();
|
|
15082
|
-
let updatedProcedureData = {
|
|
15412
|
+
let updatedProcedureData = {};
|
|
15413
|
+
if (validatedData.name !== void 0)
|
|
15414
|
+
updatedProcedureData.name = validatedData.name;
|
|
15415
|
+
if (validatedData.description !== void 0)
|
|
15416
|
+
updatedProcedureData.description = validatedData.description;
|
|
15417
|
+
if (validatedData.price !== void 0)
|
|
15418
|
+
updatedProcedureData.price = validatedData.price;
|
|
15419
|
+
if (validatedData.currency !== void 0)
|
|
15420
|
+
updatedProcedureData.currency = validatedData.currency;
|
|
15421
|
+
if (validatedData.pricingMeasure !== void 0)
|
|
15422
|
+
updatedProcedureData.pricingMeasure = validatedData.pricingMeasure;
|
|
15423
|
+
if (validatedData.duration !== void 0)
|
|
15424
|
+
updatedProcedureData.duration = validatedData.duration;
|
|
15425
|
+
if (validatedData.isActive !== void 0)
|
|
15426
|
+
updatedProcedureData.isActive = validatedData.isActive;
|
|
15083
15427
|
let practitionerChanged = false;
|
|
15084
15428
|
let clinicChanged = false;
|
|
15085
15429
|
const oldPractitionerId = existingProcedure.practitionerId;
|
|
@@ -15093,16 +15437,30 @@ var ProcedureService = class extends BaseService {
|
|
|
15093
15437
|
"procedure-photos"
|
|
15094
15438
|
);
|
|
15095
15439
|
}
|
|
15096
|
-
if (validatedData.
|
|
15097
|
-
|
|
15098
|
-
|
|
15099
|
-
|
|
15440
|
+
if (validatedData.productsMetadata !== void 0) {
|
|
15441
|
+
const technologyId = (_a = validatedData.technologyId) != null ? _a : existingProcedure.technology.id;
|
|
15442
|
+
if (!technologyId) {
|
|
15443
|
+
throw new Error(
|
|
15444
|
+
"Technology ID is required for updating products metadata"
|
|
15445
|
+
);
|
|
15446
|
+
}
|
|
15447
|
+
updatedProcedureData.productsMetadata = await this.transformProductsMetadata(
|
|
15448
|
+
validatedData.productsMetadata,
|
|
15449
|
+
technologyId
|
|
15450
|
+
);
|
|
15451
|
+
}
|
|
15452
|
+
if (validatedData.practitionerId && validatedData.practitionerId !== oldPractitionerId) {
|
|
15453
|
+
practitionerChanged = true;
|
|
15454
|
+
const newPractitionerRef = (0, import_firestore46.doc)(
|
|
15455
|
+
this.db,
|
|
15100
15456
|
PRACTITIONERS_COLLECTION,
|
|
15101
15457
|
validatedData.practitionerId
|
|
15102
15458
|
);
|
|
15103
|
-
const newPractitionerSnap = await (0,
|
|
15459
|
+
const newPractitionerSnap = await (0, import_firestore46.getDoc)(newPractitionerRef);
|
|
15104
15460
|
if (!newPractitionerSnap.exists())
|
|
15105
|
-
throw new Error(
|
|
15461
|
+
throw new Error(
|
|
15462
|
+
`New Practitioner ${validatedData.practitionerId} not found`
|
|
15463
|
+
);
|
|
15106
15464
|
newPractitioner = newPractitionerSnap.data();
|
|
15107
15465
|
updatedProcedureData.doctorInfo = {
|
|
15108
15466
|
id: newPractitioner.id,
|
|
@@ -15110,14 +15468,18 @@ var ProcedureService = class extends BaseService {
|
|
|
15110
15468
|
description: newPractitioner.basicInfo.bio || "",
|
|
15111
15469
|
photo: typeof newPractitioner.basicInfo.profileImageUrl === "string" ? newPractitioner.basicInfo.profileImageUrl : "",
|
|
15112
15470
|
// Default to empty string if not a processed URL
|
|
15113
|
-
rating: ((
|
|
15471
|
+
rating: ((_b = newPractitioner.reviewInfo) == null ? void 0 : _b.averageRating) || 0,
|
|
15114
15472
|
services: newPractitioner.procedures || []
|
|
15115
15473
|
};
|
|
15116
15474
|
}
|
|
15117
15475
|
if (validatedData.clinicBranchId && validatedData.clinicBranchId !== oldClinicId) {
|
|
15118
15476
|
clinicChanged = true;
|
|
15119
|
-
const newClinicRef = (0,
|
|
15120
|
-
|
|
15477
|
+
const newClinicRef = (0, import_firestore46.doc)(
|
|
15478
|
+
this.db,
|
|
15479
|
+
CLINICS_COLLECTION,
|
|
15480
|
+
validatedData.clinicBranchId
|
|
15481
|
+
);
|
|
15482
|
+
const newClinicSnap = await (0, import_firestore46.getDoc)(newClinicRef);
|
|
15121
15483
|
if (!newClinicSnap.exists())
|
|
15122
15484
|
throw new Error(`New Clinic ${validatedData.clinicBranchId} not found`);
|
|
15123
15485
|
newClinic = newClinicSnap.data();
|
|
@@ -15135,8 +15497,11 @@ var ProcedureService = class extends BaseService {
|
|
|
15135
15497
|
updatedProcedureData.nameLower = validatedData.name.toLowerCase();
|
|
15136
15498
|
}
|
|
15137
15499
|
if (validatedData.categoryId) {
|
|
15138
|
-
const category = await this.categoryService.getById(
|
|
15139
|
-
|
|
15500
|
+
const category = await this.categoryService.getById(
|
|
15501
|
+
validatedData.categoryId
|
|
15502
|
+
);
|
|
15503
|
+
if (!category)
|
|
15504
|
+
throw new Error(`Category ${validatedData.categoryId} not found`);
|
|
15140
15505
|
updatedProcedureData.category = category;
|
|
15141
15506
|
finalCategoryId = category.id;
|
|
15142
15507
|
}
|
|
@@ -15151,23 +15516,34 @@ var ProcedureService = class extends BaseService {
|
|
|
15151
15516
|
);
|
|
15152
15517
|
updatedProcedureData.subcategory = subcategory;
|
|
15153
15518
|
} else if (validatedData.subcategoryId) {
|
|
15154
|
-
console.warn(
|
|
15519
|
+
console.warn(
|
|
15520
|
+
"Attempted to update subcategory without a valid categoryId"
|
|
15521
|
+
);
|
|
15155
15522
|
}
|
|
15156
15523
|
let finalTechnologyId = existingProcedure.technology.id;
|
|
15157
15524
|
if (validatedData.technologyId) {
|
|
15158
|
-
const technology = await this.technologyService.getById(
|
|
15159
|
-
|
|
15525
|
+
const technology = await this.technologyService.getById(
|
|
15526
|
+
validatedData.technologyId
|
|
15527
|
+
);
|
|
15528
|
+
if (!technology)
|
|
15529
|
+
throw new Error(`Technology ${validatedData.technologyId} not found`);
|
|
15160
15530
|
updatedProcedureData.technology = technology;
|
|
15161
15531
|
finalTechnologyId = technology.id;
|
|
15162
15532
|
updatedProcedureData.blockingConditions = technology.blockingConditions;
|
|
15533
|
+
updatedProcedureData.contraindications = technology.contraindications || [];
|
|
15534
|
+
updatedProcedureData.contraindicationIds = ((_c = technology.contraindications) == null ? void 0 : _c.map((c) => c.id)) || [];
|
|
15163
15535
|
updatedProcedureData.treatmentBenefits = technology.benefits;
|
|
15536
|
+
updatedProcedureData.treatmentBenefitIds = ((_d = technology.benefits) == null ? void 0 : _d.map((b) => b.id)) || [];
|
|
15164
15537
|
updatedProcedureData.preRequirements = technology.requirements.pre;
|
|
15165
15538
|
updatedProcedureData.postRequirements = technology.requirements.post;
|
|
15166
15539
|
updatedProcedureData.certificationRequirement = technology.certificationRequirement;
|
|
15167
15540
|
updatedProcedureData.documentationTemplates = technology.documentationTemplates || [];
|
|
15168
15541
|
}
|
|
15169
15542
|
if (validatedData.productId && finalTechnologyId) {
|
|
15170
|
-
const product = await this.productService.getById(
|
|
15543
|
+
const product = await this.productService.getById(
|
|
15544
|
+
finalTechnologyId,
|
|
15545
|
+
validatedData.productId
|
|
15546
|
+
);
|
|
15171
15547
|
if (!product)
|
|
15172
15548
|
throw new Error(
|
|
15173
15549
|
`Product ${validatedData.productId} not found for technology ${finalTechnologyId}`
|
|
@@ -15176,11 +15552,11 @@ var ProcedureService = class extends BaseService {
|
|
|
15176
15552
|
} else if (validatedData.productId) {
|
|
15177
15553
|
console.warn("Attempted to update product without a valid technologyId");
|
|
15178
15554
|
}
|
|
15179
|
-
await (0,
|
|
15555
|
+
await (0, import_firestore46.updateDoc)(procedureRef, {
|
|
15180
15556
|
...updatedProcedureData,
|
|
15181
|
-
updatedAt: (0,
|
|
15557
|
+
updatedAt: (0, import_firestore46.serverTimestamp)()
|
|
15182
15558
|
});
|
|
15183
|
-
const updatedSnapshot = await (0,
|
|
15559
|
+
const updatedSnapshot = await (0, import_firestore46.getDoc)(procedureRef);
|
|
15184
15560
|
return updatedSnapshot.data();
|
|
15185
15561
|
}
|
|
15186
15562
|
/**
|
|
@@ -15188,15 +15564,15 @@ var ProcedureService = class extends BaseService {
|
|
|
15188
15564
|
* @param id - The ID of the procedure to deactivate
|
|
15189
15565
|
*/
|
|
15190
15566
|
async deactivateProcedure(id) {
|
|
15191
|
-
const procedureRef = (0,
|
|
15192
|
-
const procedureSnap = await (0,
|
|
15567
|
+
const procedureRef = (0, import_firestore46.doc)(this.db, PROCEDURES_COLLECTION, id);
|
|
15568
|
+
const procedureSnap = await (0, import_firestore46.getDoc)(procedureRef);
|
|
15193
15569
|
if (!procedureSnap.exists()) {
|
|
15194
15570
|
console.warn(`Procedure ${id} not found for deactivation.`);
|
|
15195
15571
|
return;
|
|
15196
15572
|
}
|
|
15197
|
-
await (0,
|
|
15573
|
+
await (0, import_firestore46.updateDoc)(procedureRef, {
|
|
15198
15574
|
isActive: false,
|
|
15199
|
-
updatedAt: (0,
|
|
15575
|
+
updatedAt: (0, import_firestore46.serverTimestamp)()
|
|
15200
15576
|
});
|
|
15201
15577
|
}
|
|
15202
15578
|
/**
|
|
@@ -15205,12 +15581,12 @@ var ProcedureService = class extends BaseService {
|
|
|
15205
15581
|
* @returns A boolean indicating if the deletion was successful
|
|
15206
15582
|
*/
|
|
15207
15583
|
async deleteProcedure(id) {
|
|
15208
|
-
const procedureRef = (0,
|
|
15209
|
-
const procedureSnapshot = await (0,
|
|
15584
|
+
const procedureRef = (0, import_firestore46.doc)(this.db, PROCEDURES_COLLECTION, id);
|
|
15585
|
+
const procedureSnapshot = await (0, import_firestore46.getDoc)(procedureRef);
|
|
15210
15586
|
if (!procedureSnapshot.exists()) {
|
|
15211
15587
|
return false;
|
|
15212
15588
|
}
|
|
15213
|
-
await (0,
|
|
15589
|
+
await (0, import_firestore46.deleteDoc)(procedureRef);
|
|
15214
15590
|
return true;
|
|
15215
15591
|
}
|
|
15216
15592
|
/**
|
|
@@ -15236,31 +15612,35 @@ var ProcedureService = class extends BaseService {
|
|
|
15236
15612
|
*/
|
|
15237
15613
|
async getAllProcedures(pagination, lastDoc) {
|
|
15238
15614
|
try {
|
|
15239
|
-
const proceduresCollection = (0,
|
|
15240
|
-
let proceduresQuery = (0,
|
|
15615
|
+
const proceduresCollection = (0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION);
|
|
15616
|
+
let proceduresQuery = (0, import_firestore46.query)(proceduresCollection);
|
|
15241
15617
|
if (pagination && pagination > 0) {
|
|
15242
|
-
const { limit:
|
|
15618
|
+
const { limit: limit21, startAfter: startAfter19 } = await import("firebase/firestore");
|
|
15243
15619
|
if (lastDoc) {
|
|
15244
|
-
proceduresQuery = (0,
|
|
15620
|
+
proceduresQuery = (0, import_firestore46.query)(
|
|
15245
15621
|
proceduresCollection,
|
|
15246
|
-
(0,
|
|
15622
|
+
(0, import_firestore46.orderBy)("name"),
|
|
15247
15623
|
// Use imported orderBy
|
|
15248
|
-
|
|
15249
|
-
|
|
15624
|
+
startAfter19(lastDoc),
|
|
15625
|
+
limit21(pagination)
|
|
15250
15626
|
);
|
|
15251
15627
|
} else {
|
|
15252
|
-
proceduresQuery = (0,
|
|
15628
|
+
proceduresQuery = (0, import_firestore46.query)(
|
|
15629
|
+
proceduresCollection,
|
|
15630
|
+
(0, import_firestore46.orderBy)("name"),
|
|
15631
|
+
limit21(pagination)
|
|
15632
|
+
);
|
|
15253
15633
|
}
|
|
15254
15634
|
} else {
|
|
15255
|
-
proceduresQuery = (0,
|
|
15635
|
+
proceduresQuery = (0, import_firestore46.query)(proceduresCollection, (0, import_firestore46.orderBy)("name"));
|
|
15256
15636
|
}
|
|
15257
|
-
const proceduresSnapshot = await (0,
|
|
15637
|
+
const proceduresSnapshot = await (0, import_firestore46.getDocs)(proceduresQuery);
|
|
15258
15638
|
const lastVisible = proceduresSnapshot.docs[proceduresSnapshot.docs.length - 1];
|
|
15259
|
-
const procedures = proceduresSnapshot.docs.map((
|
|
15260
|
-
const data =
|
|
15639
|
+
const procedures = proceduresSnapshot.docs.map((doc38) => {
|
|
15640
|
+
const data = doc38.data();
|
|
15261
15641
|
return {
|
|
15262
15642
|
...data,
|
|
15263
|
-
id:
|
|
15643
|
+
id: doc38.id
|
|
15264
15644
|
// Ensure ID is present
|
|
15265
15645
|
};
|
|
15266
15646
|
});
|
|
@@ -15280,7 +15660,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15280
15660
|
*
|
|
15281
15661
|
* @param filters - Various filters to apply
|
|
15282
15662
|
* @param filters.nameSearch - Optional search text for procedure name
|
|
15283
|
-
* @param filters.
|
|
15663
|
+
* @param filters.treatmentBenefitIds - Optional array of treatment benefits to filter by
|
|
15284
15664
|
* @param filters.procedureFamily - Optional procedure family to filter by
|
|
15285
15665
|
* @param filters.procedureCategory - Optional procedure category to filter by
|
|
15286
15666
|
* @param filters.procedureSubcategory - Optional procedure subcategory to filter by
|
|
@@ -15298,7 +15678,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15298
15678
|
*/
|
|
15299
15679
|
async getProceduresByFilters(filters) {
|
|
15300
15680
|
try {
|
|
15301
|
-
console.log(
|
|
15681
|
+
console.log(
|
|
15682
|
+
"[PROCEDURE_SERVICE] Starting procedure filtering with multiple strategies"
|
|
15683
|
+
);
|
|
15302
15684
|
if (filters.location && filters.radiusInKm) {
|
|
15303
15685
|
console.log("[PROCEDURE_SERVICE] Executing geo query:", {
|
|
15304
15686
|
location: filters.location,
|
|
@@ -15306,7 +15688,10 @@ var ProcedureService = class extends BaseService {
|
|
|
15306
15688
|
serviceName: "ProcedureService"
|
|
15307
15689
|
});
|
|
15308
15690
|
if (!filters.location.latitude || !filters.location.longitude) {
|
|
15309
|
-
console.warn(
|
|
15691
|
+
console.warn(
|
|
15692
|
+
"[PROCEDURE_SERVICE] Invalid location data:",
|
|
15693
|
+
filters.location
|
|
15694
|
+
);
|
|
15310
15695
|
filters.location = void 0;
|
|
15311
15696
|
filters.radiusInKm = void 0;
|
|
15312
15697
|
}
|
|
@@ -15318,65 +15703,88 @@ var ProcedureService = class extends BaseService {
|
|
|
15318
15703
|
const getBaseConstraints = () => {
|
|
15319
15704
|
const constraints = [];
|
|
15320
15705
|
if (filters.isActive !== void 0) {
|
|
15321
|
-
constraints.push((0,
|
|
15706
|
+
constraints.push((0, import_firestore46.where)("isActive", "==", filters.isActive));
|
|
15322
15707
|
} else {
|
|
15323
|
-
constraints.push((0,
|
|
15708
|
+
constraints.push((0, import_firestore46.where)("isActive", "==", true));
|
|
15324
15709
|
}
|
|
15325
15710
|
if (filters.procedureFamily) {
|
|
15326
|
-
constraints.push((0,
|
|
15711
|
+
constraints.push((0, import_firestore46.where)("family", "==", filters.procedureFamily));
|
|
15327
15712
|
}
|
|
15328
15713
|
if (filters.procedureCategory) {
|
|
15329
|
-
constraints.push(
|
|
15714
|
+
constraints.push(
|
|
15715
|
+
(0, import_firestore46.where)("category.id", "==", filters.procedureCategory)
|
|
15716
|
+
);
|
|
15330
15717
|
}
|
|
15331
15718
|
if (filters.procedureSubcategory) {
|
|
15332
|
-
constraints.push(
|
|
15719
|
+
constraints.push(
|
|
15720
|
+
(0, import_firestore46.where)("subcategory.id", "==", filters.procedureSubcategory)
|
|
15721
|
+
);
|
|
15333
15722
|
}
|
|
15334
15723
|
if (filters.procedureTechnology) {
|
|
15335
|
-
constraints.push(
|
|
15724
|
+
constraints.push(
|
|
15725
|
+
(0, import_firestore46.where)("technology.id", "==", filters.procedureTechnology)
|
|
15726
|
+
);
|
|
15336
15727
|
}
|
|
15337
15728
|
if (filters.minPrice !== void 0) {
|
|
15338
|
-
constraints.push((0,
|
|
15729
|
+
constraints.push((0, import_firestore46.where)("price", ">=", filters.minPrice));
|
|
15339
15730
|
}
|
|
15340
15731
|
if (filters.maxPrice !== void 0) {
|
|
15341
|
-
constraints.push((0,
|
|
15732
|
+
constraints.push((0, import_firestore46.where)("price", "<=", filters.maxPrice));
|
|
15342
15733
|
}
|
|
15343
15734
|
if (filters.minRating !== void 0) {
|
|
15344
|
-
constraints.push(
|
|
15735
|
+
constraints.push(
|
|
15736
|
+
(0, import_firestore46.where)("reviewInfo.averageRating", ">=", filters.minRating)
|
|
15737
|
+
);
|
|
15345
15738
|
}
|
|
15346
15739
|
if (filters.maxRating !== void 0) {
|
|
15347
|
-
constraints.push(
|
|
15740
|
+
constraints.push(
|
|
15741
|
+
(0, import_firestore46.where)("reviewInfo.averageRating", "<=", filters.maxRating)
|
|
15742
|
+
);
|
|
15348
15743
|
}
|
|
15349
15744
|
if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
|
|
15350
|
-
const
|
|
15351
|
-
constraints.push(
|
|
15745
|
+
const benefitIdsToMatch = filters.treatmentBenefits;
|
|
15746
|
+
constraints.push(
|
|
15747
|
+
(0, import_firestore46.where)(
|
|
15748
|
+
"treatmentBenefitIds",
|
|
15749
|
+
"array-contains-any",
|
|
15750
|
+
benefitIdsToMatch
|
|
15751
|
+
)
|
|
15752
|
+
);
|
|
15352
15753
|
}
|
|
15353
15754
|
return constraints;
|
|
15354
15755
|
};
|
|
15355
15756
|
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
15356
15757
|
try {
|
|
15357
|
-
console.log(
|
|
15758
|
+
console.log(
|
|
15759
|
+
"[PROCEDURE_SERVICE] Strategy 1: Trying nameLower search"
|
|
15760
|
+
);
|
|
15358
15761
|
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
15359
15762
|
const constraints = getBaseConstraints();
|
|
15360
|
-
constraints.push((0,
|
|
15361
|
-
constraints.push((0,
|
|
15362
|
-
constraints.push((0,
|
|
15763
|
+
constraints.push((0, import_firestore46.where)("nameLower", ">=", searchTerm));
|
|
15764
|
+
constraints.push((0, import_firestore46.where)("nameLower", "<=", searchTerm + "\uF8FF"));
|
|
15765
|
+
constraints.push((0, import_firestore46.orderBy)("nameLower"));
|
|
15363
15766
|
if (filters.lastDoc) {
|
|
15364
15767
|
if (typeof filters.lastDoc.data === "function") {
|
|
15365
|
-
constraints.push((0,
|
|
15768
|
+
constraints.push((0, import_firestore46.startAfter)(filters.lastDoc));
|
|
15366
15769
|
} else if (Array.isArray(filters.lastDoc)) {
|
|
15367
|
-
constraints.push((0,
|
|
15770
|
+
constraints.push((0, import_firestore46.startAfter)(...filters.lastDoc));
|
|
15368
15771
|
} else {
|
|
15369
|
-
constraints.push((0,
|
|
15772
|
+
constraints.push((0, import_firestore46.startAfter)(filters.lastDoc));
|
|
15370
15773
|
}
|
|
15371
15774
|
}
|
|
15372
|
-
constraints.push((0,
|
|
15373
|
-
const q = (0,
|
|
15374
|
-
|
|
15775
|
+
constraints.push((0, import_firestore46.limit)(filters.pagination || 10));
|
|
15776
|
+
const q = (0, import_firestore46.query)(
|
|
15777
|
+
(0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION),
|
|
15778
|
+
...constraints
|
|
15779
|
+
);
|
|
15780
|
+
const querySnapshot = await (0, import_firestore46.getDocs)(q);
|
|
15375
15781
|
const procedures = querySnapshot.docs.map(
|
|
15376
|
-
(
|
|
15782
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
15377
15783
|
);
|
|
15378
15784
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15379
|
-
console.log(
|
|
15785
|
+
console.log(
|
|
15786
|
+
`[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`
|
|
15787
|
+
);
|
|
15380
15788
|
if (procedures.length < (filters.pagination || 10)) {
|
|
15381
15789
|
return { procedures, lastDoc: null };
|
|
15382
15790
|
}
|
|
@@ -15387,29 +15795,36 @@ var ProcedureService = class extends BaseService {
|
|
|
15387
15795
|
}
|
|
15388
15796
|
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
15389
15797
|
try {
|
|
15390
|
-
console.log(
|
|
15798
|
+
console.log(
|
|
15799
|
+
"[PROCEDURE_SERVICE] Strategy 2: Trying name field search"
|
|
15800
|
+
);
|
|
15391
15801
|
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
15392
15802
|
const constraints = getBaseConstraints();
|
|
15393
|
-
constraints.push((0,
|
|
15394
|
-
constraints.push((0,
|
|
15395
|
-
constraints.push((0,
|
|
15803
|
+
constraints.push((0, import_firestore46.where)("name", ">=", searchTerm));
|
|
15804
|
+
constraints.push((0, import_firestore46.where)("name", "<=", searchTerm + "\uF8FF"));
|
|
15805
|
+
constraints.push((0, import_firestore46.orderBy)("name"));
|
|
15396
15806
|
if (filters.lastDoc) {
|
|
15397
15807
|
if (typeof filters.lastDoc.data === "function") {
|
|
15398
|
-
constraints.push((0,
|
|
15808
|
+
constraints.push((0, import_firestore46.startAfter)(filters.lastDoc));
|
|
15399
15809
|
} else if (Array.isArray(filters.lastDoc)) {
|
|
15400
|
-
constraints.push((0,
|
|
15810
|
+
constraints.push((0, import_firestore46.startAfter)(...filters.lastDoc));
|
|
15401
15811
|
} else {
|
|
15402
|
-
constraints.push((0,
|
|
15812
|
+
constraints.push((0, import_firestore46.startAfter)(filters.lastDoc));
|
|
15403
15813
|
}
|
|
15404
15814
|
}
|
|
15405
|
-
constraints.push((0,
|
|
15406
|
-
const q = (0,
|
|
15407
|
-
|
|
15815
|
+
constraints.push((0, import_firestore46.limit)(filters.pagination || 10));
|
|
15816
|
+
const q = (0, import_firestore46.query)(
|
|
15817
|
+
(0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION),
|
|
15818
|
+
...constraints
|
|
15819
|
+
);
|
|
15820
|
+
const querySnapshot = await (0, import_firestore46.getDocs)(q);
|
|
15408
15821
|
const procedures = querySnapshot.docs.map(
|
|
15409
|
-
(
|
|
15822
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
15410
15823
|
);
|
|
15411
15824
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15412
|
-
console.log(
|
|
15825
|
+
console.log(
|
|
15826
|
+
`[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`
|
|
15827
|
+
);
|
|
15413
15828
|
if (procedures.length < (filters.pagination || 10)) {
|
|
15414
15829
|
return { procedures, lastDoc: null };
|
|
15415
15830
|
}
|
|
@@ -15423,25 +15838,30 @@ var ProcedureService = class extends BaseService {
|
|
|
15423
15838
|
"[PROCEDURE_SERVICE] Strategy 3: Using createdAt orderBy with client-side filtering"
|
|
15424
15839
|
);
|
|
15425
15840
|
const constraints = getBaseConstraints();
|
|
15426
|
-
constraints.push((0,
|
|
15841
|
+
constraints.push((0, import_firestore46.orderBy)("createdAt", "desc"));
|
|
15427
15842
|
if (filters.lastDoc) {
|
|
15428
15843
|
if (typeof filters.lastDoc.data === "function") {
|
|
15429
|
-
constraints.push((0,
|
|
15844
|
+
constraints.push((0, import_firestore46.startAfter)(filters.lastDoc));
|
|
15430
15845
|
} else if (Array.isArray(filters.lastDoc)) {
|
|
15431
|
-
constraints.push((0,
|
|
15846
|
+
constraints.push((0, import_firestore46.startAfter)(...filters.lastDoc));
|
|
15432
15847
|
} else {
|
|
15433
|
-
constraints.push((0,
|
|
15848
|
+
constraints.push((0, import_firestore46.startAfter)(filters.lastDoc));
|
|
15434
15849
|
}
|
|
15435
15850
|
}
|
|
15436
|
-
constraints.push((0,
|
|
15437
|
-
const q = (0,
|
|
15438
|
-
|
|
15851
|
+
constraints.push((0, import_firestore46.limit)(filters.pagination || 10));
|
|
15852
|
+
const q = (0, import_firestore46.query)(
|
|
15853
|
+
(0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION),
|
|
15854
|
+
...constraints
|
|
15855
|
+
);
|
|
15856
|
+
const querySnapshot = await (0, import_firestore46.getDocs)(q);
|
|
15439
15857
|
let procedures = querySnapshot.docs.map(
|
|
15440
|
-
(
|
|
15858
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
15441
15859
|
);
|
|
15442
15860
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15443
15861
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15444
|
-
console.log(
|
|
15862
|
+
console.log(
|
|
15863
|
+
`[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`
|
|
15864
|
+
);
|
|
15445
15865
|
if (procedures.length < (filters.pagination || 10)) {
|
|
15446
15866
|
return { procedures, lastDoc: null };
|
|
15447
15867
|
}
|
|
@@ -15452,18 +15872,23 @@ var ProcedureService = class extends BaseService {
|
|
|
15452
15872
|
try {
|
|
15453
15873
|
console.log("[PROCEDURE_SERVICE] Strategy 4: Minimal query fallback");
|
|
15454
15874
|
const constraints = [
|
|
15455
|
-
(0,
|
|
15456
|
-
(0,
|
|
15457
|
-
(0,
|
|
15875
|
+
(0, import_firestore46.where)("isActive", "==", true),
|
|
15876
|
+
(0, import_firestore46.orderBy)("createdAt", "desc"),
|
|
15877
|
+
(0, import_firestore46.limit)(filters.pagination || 10)
|
|
15458
15878
|
];
|
|
15459
|
-
const q = (0,
|
|
15460
|
-
|
|
15879
|
+
const q = (0, import_firestore46.query)(
|
|
15880
|
+
(0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION),
|
|
15881
|
+
...constraints
|
|
15882
|
+
);
|
|
15883
|
+
const querySnapshot = await (0, import_firestore46.getDocs)(q);
|
|
15461
15884
|
let procedures = querySnapshot.docs.map(
|
|
15462
|
-
(
|
|
15885
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
15463
15886
|
);
|
|
15464
15887
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15465
15888
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15466
|
-
console.log(
|
|
15889
|
+
console.log(
|
|
15890
|
+
`[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`
|
|
15891
|
+
);
|
|
15467
15892
|
if (procedures.length < (filters.pagination || 10)) {
|
|
15468
15893
|
return { procedures, lastDoc: null };
|
|
15469
15894
|
}
|
|
@@ -15471,7 +15896,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15471
15896
|
} catch (error) {
|
|
15472
15897
|
console.log("[PROCEDURE_SERVICE] Strategy 4 failed:", error);
|
|
15473
15898
|
}
|
|
15474
|
-
console.log(
|
|
15899
|
+
console.log(
|
|
15900
|
+
"[PROCEDURE_SERVICE] All strategies failed, returning empty result"
|
|
15901
|
+
);
|
|
15475
15902
|
return { procedures: [], lastDoc: null };
|
|
15476
15903
|
} catch (error) {
|
|
15477
15904
|
console.error("[PROCEDURE_SERVICE] Error filtering procedures:", error);
|
|
@@ -15491,13 +15918,17 @@ var ProcedureService = class extends BaseService {
|
|
|
15491
15918
|
const nameLower = procedure.nameLower || "";
|
|
15492
15919
|
return name.includes(searchTerm) || nameLower.includes(searchTerm);
|
|
15493
15920
|
});
|
|
15494
|
-
console.log(
|
|
15921
|
+
console.log(
|
|
15922
|
+
`[PROCEDURE_SERVICE] Applied name filter, results: ${filteredProcedures.length}`
|
|
15923
|
+
);
|
|
15495
15924
|
}
|
|
15496
15925
|
if (filters.minPrice !== void 0 || filters.maxPrice !== void 0) {
|
|
15497
15926
|
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15498
15927
|
const price = procedure.price || 0;
|
|
15499
|
-
if (filters.minPrice !== void 0 && price < filters.minPrice)
|
|
15500
|
-
|
|
15928
|
+
if (filters.minPrice !== void 0 && price < filters.minPrice)
|
|
15929
|
+
return false;
|
|
15930
|
+
if (filters.maxPrice !== void 0 && price > filters.maxPrice)
|
|
15931
|
+
return false;
|
|
15501
15932
|
return true;
|
|
15502
15933
|
});
|
|
15503
15934
|
console.log(
|
|
@@ -15508,8 +15939,10 @@ var ProcedureService = class extends BaseService {
|
|
|
15508
15939
|
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15509
15940
|
var _a;
|
|
15510
15941
|
const rating = ((_a = procedure.reviewInfo) == null ? void 0 : _a.averageRating) || 0;
|
|
15511
|
-
if (filters.minRating !== void 0 && rating < filters.minRating)
|
|
15512
|
-
|
|
15942
|
+
if (filters.minRating !== void 0 && rating < filters.minRating)
|
|
15943
|
+
return false;
|
|
15944
|
+
if (filters.maxRating !== void 0 && rating > filters.maxRating)
|
|
15945
|
+
return false;
|
|
15513
15946
|
return true;
|
|
15514
15947
|
});
|
|
15515
15948
|
console.log(
|
|
@@ -15517,10 +15950,12 @@ var ProcedureService = class extends BaseService {
|
|
|
15517
15950
|
);
|
|
15518
15951
|
}
|
|
15519
15952
|
if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
|
|
15520
|
-
const
|
|
15953
|
+
const benefitIdsToMatch = filters.treatmentBenefits;
|
|
15521
15954
|
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15522
|
-
const
|
|
15523
|
-
return
|
|
15955
|
+
const procedureBenefitIds = procedure.treatmentBenefitIds || [];
|
|
15956
|
+
return benefitIdsToMatch.some(
|
|
15957
|
+
(benefitId) => procedureBenefitIds.includes(benefitId)
|
|
15958
|
+
);
|
|
15524
15959
|
});
|
|
15525
15960
|
console.log(
|
|
15526
15961
|
`[PROCEDURE_SERVICE] Applied benefits filter, results: ${filteredProcedures.length}`
|
|
@@ -15583,8 +16018,12 @@ var ProcedureService = class extends BaseService {
|
|
|
15583
16018
|
procedure.distance = distance;
|
|
15584
16019
|
return distance <= radiusInKm;
|
|
15585
16020
|
});
|
|
15586
|
-
console.log(
|
|
15587
|
-
|
|
16021
|
+
console.log(
|
|
16022
|
+
`[PROCEDURE_SERVICE] Applied geo filter, results: ${filteredProcedures.length}`
|
|
16023
|
+
);
|
|
16024
|
+
filteredProcedures.sort(
|
|
16025
|
+
(a, b) => (a.distance || 0) - (b.distance || 0)
|
|
16026
|
+
);
|
|
15588
16027
|
}
|
|
15589
16028
|
return filteredProcedures;
|
|
15590
16029
|
}
|
|
@@ -15596,19 +16035,30 @@ var ProcedureService = class extends BaseService {
|
|
|
15596
16035
|
if (!location || !radiusInKm) {
|
|
15597
16036
|
return Promise.resolve({ procedures: [], lastDoc: null });
|
|
15598
16037
|
}
|
|
15599
|
-
const bounds = (0, import_geofire_common8.geohashQueryBounds)(
|
|
16038
|
+
const bounds = (0, import_geofire_common8.geohashQueryBounds)(
|
|
16039
|
+
[location.latitude, location.longitude],
|
|
16040
|
+
radiusInKm * 1e3
|
|
16041
|
+
);
|
|
15600
16042
|
const fetches = bounds.map((b) => {
|
|
15601
16043
|
const constraints = [
|
|
15602
|
-
(0,
|
|
15603
|
-
(0,
|
|
15604
|
-
(0,
|
|
16044
|
+
(0, import_firestore46.where)("clinicInfo.location.geohash", ">=", b[0]),
|
|
16045
|
+
(0, import_firestore46.where)("clinicInfo.location.geohash", "<=", b[1]),
|
|
16046
|
+
(0, import_firestore46.where)(
|
|
16047
|
+
"isActive",
|
|
16048
|
+
"==",
|
|
16049
|
+
filters.isActive !== void 0 ? filters.isActive : true
|
|
16050
|
+
)
|
|
15605
16051
|
];
|
|
15606
|
-
return (0,
|
|
16052
|
+
return (0, import_firestore46.getDocs)(
|
|
16053
|
+
(0, import_firestore46.query)((0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION), ...constraints)
|
|
16054
|
+
);
|
|
15607
16055
|
});
|
|
15608
16056
|
return Promise.all(fetches).then((snaps) => {
|
|
15609
16057
|
const collected = [];
|
|
15610
16058
|
snaps.forEach((snap) => {
|
|
15611
|
-
snap.docs.forEach(
|
|
16059
|
+
snap.docs.forEach(
|
|
16060
|
+
(d) => collected.push({ ...d.data(), id: d.id })
|
|
16061
|
+
);
|
|
15612
16062
|
});
|
|
15613
16063
|
const uniqueMap = /* @__PURE__ */ new Map();
|
|
15614
16064
|
for (const p of collected) {
|
|
@@ -15619,7 +16069,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15619
16069
|
const pageSize = filters.pagination || 10;
|
|
15620
16070
|
let startIndex = 0;
|
|
15621
16071
|
if (filters.lastDoc && typeof filters.lastDoc === "object" && filters.lastDoc.id) {
|
|
15622
|
-
const idx = procedures.findIndex(
|
|
16072
|
+
const idx = procedures.findIndex(
|
|
16073
|
+
(p) => p.id === filters.lastDoc.id
|
|
16074
|
+
);
|
|
15623
16075
|
if (idx >= 0) startIndex = idx + 1;
|
|
15624
16076
|
}
|
|
15625
16077
|
const page = procedures.slice(startIndex, startIndex + pageSize);
|
|
@@ -15644,7 +16096,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15644
16096
|
* @returns The created procedure
|
|
15645
16097
|
*/
|
|
15646
16098
|
async createConsultationProcedure(data) {
|
|
15647
|
-
var _a;
|
|
16099
|
+
var _a, _b, _c;
|
|
15648
16100
|
const procedureId = this.generateId();
|
|
15649
16101
|
const [category, subcategory, technology] = await Promise.all([
|
|
15650
16102
|
this.categoryService.getById(data.categoryId),
|
|
@@ -15654,22 +16106,34 @@ var ProcedureService = class extends BaseService {
|
|
|
15654
16106
|
if (!category || !subcategory || !technology) {
|
|
15655
16107
|
throw new Error("One or more required base entities not found");
|
|
15656
16108
|
}
|
|
15657
|
-
const clinicRef = (0,
|
|
15658
|
-
const clinicSnapshot = await (0,
|
|
16109
|
+
const clinicRef = (0, import_firestore46.doc)(this.db, CLINICS_COLLECTION, data.clinicBranchId);
|
|
16110
|
+
const clinicSnapshot = await (0, import_firestore46.getDoc)(clinicRef);
|
|
15659
16111
|
if (!clinicSnapshot.exists()) {
|
|
15660
16112
|
throw new Error(`Clinic with ID ${data.clinicBranchId} not found`);
|
|
15661
16113
|
}
|
|
15662
16114
|
const clinic = clinicSnapshot.data();
|
|
15663
|
-
const practitionerRef = (0,
|
|
15664
|
-
|
|
16115
|
+
const practitionerRef = (0, import_firestore46.doc)(
|
|
16116
|
+
this.db,
|
|
16117
|
+
PRACTITIONERS_COLLECTION,
|
|
16118
|
+
data.practitionerId
|
|
16119
|
+
);
|
|
16120
|
+
const practitionerSnapshot = await (0, import_firestore46.getDoc)(practitionerRef);
|
|
15665
16121
|
if (!practitionerSnapshot.exists()) {
|
|
15666
16122
|
throw new Error(`Practitioner with ID ${data.practitionerId} not found`);
|
|
15667
16123
|
}
|
|
15668
16124
|
const practitioner = practitionerSnapshot.data();
|
|
15669
16125
|
let processedPhotos = [];
|
|
15670
16126
|
if (data.photos && data.photos.length > 0) {
|
|
15671
|
-
processedPhotos = await this.processMediaArray(
|
|
16127
|
+
processedPhotos = await this.processMediaArray(
|
|
16128
|
+
data.photos,
|
|
16129
|
+
procedureId,
|
|
16130
|
+
"procedure-photos"
|
|
16131
|
+
);
|
|
15672
16132
|
}
|
|
16133
|
+
const transformedProductsMetadata = await this.transformProductsMetadata(
|
|
16134
|
+
data.productsMetadata,
|
|
16135
|
+
data.technologyId
|
|
16136
|
+
);
|
|
15673
16137
|
const clinicInfo = {
|
|
15674
16138
|
id: clinicSnapshot.id,
|
|
15675
16139
|
name: clinic.name,
|
|
@@ -15694,6 +16158,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15694
16158
|
brandName: "Consultation",
|
|
15695
16159
|
technologyId: data.technologyId,
|
|
15696
16160
|
technologyName: technology.name,
|
|
16161
|
+
categoryId: technology.categoryId,
|
|
16162
|
+
subcategoryId: technology.subcategoryId,
|
|
15697
16163
|
isActive: true,
|
|
15698
16164
|
createdAt: /* @__PURE__ */ new Date(),
|
|
15699
16165
|
updatedAt: /* @__PURE__ */ new Date()
|
|
@@ -15708,9 +16174,12 @@ var ProcedureService = class extends BaseService {
|
|
|
15708
16174
|
technology,
|
|
15709
16175
|
product: consultationProduct,
|
|
15710
16176
|
// Use placeholder product
|
|
16177
|
+
productsMetadata: transformedProductsMetadata,
|
|
15711
16178
|
blockingConditions: technology.blockingConditions,
|
|
15712
16179
|
contraindications: technology.contraindications || [],
|
|
16180
|
+
contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
|
|
15713
16181
|
treatmentBenefits: technology.benefits,
|
|
16182
|
+
treatmentBenefitIds: ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [],
|
|
15714
16183
|
preRequirements: technology.requirements.pre,
|
|
15715
16184
|
postRequirements: technology.requirements.post,
|
|
15716
16185
|
certificationRequirement: technology.certificationRequirement,
|
|
@@ -15729,13 +16198,13 @@ var ProcedureService = class extends BaseService {
|
|
|
15729
16198
|
},
|
|
15730
16199
|
isActive: true
|
|
15731
16200
|
};
|
|
15732
|
-
const procedureRef = (0,
|
|
15733
|
-
await (0,
|
|
16201
|
+
const procedureRef = (0, import_firestore46.doc)(this.db, PROCEDURES_COLLECTION, procedureId);
|
|
16202
|
+
await (0, import_firestore46.setDoc)(procedureRef, {
|
|
15734
16203
|
...newProcedure,
|
|
15735
|
-
createdAt: (0,
|
|
15736
|
-
updatedAt: (0,
|
|
16204
|
+
createdAt: (0, import_firestore46.serverTimestamp)(),
|
|
16205
|
+
updatedAt: (0, import_firestore46.serverTimestamp)()
|
|
15737
16206
|
});
|
|
15738
|
-
const savedDoc = await (0,
|
|
16207
|
+
const savedDoc = await (0, import_firestore46.getDoc)(procedureRef);
|
|
15739
16208
|
return savedDoc.data();
|
|
15740
16209
|
}
|
|
15741
16210
|
/**
|
|
@@ -15744,13 +16213,13 @@ var ProcedureService = class extends BaseService {
|
|
|
15744
16213
|
* @returns Array of minimal procedure info for map
|
|
15745
16214
|
*/
|
|
15746
16215
|
async getProceduresForMap() {
|
|
15747
|
-
const proceduresRef = (0,
|
|
15748
|
-
const snapshot = await (0,
|
|
15749
|
-
const proceduresForMap = snapshot.docs.map((
|
|
16216
|
+
const proceduresRef = (0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION);
|
|
16217
|
+
const snapshot = await (0, import_firestore46.getDocs)(proceduresRef);
|
|
16218
|
+
const proceduresForMap = snapshot.docs.map((doc38) => {
|
|
15750
16219
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
15751
|
-
const data =
|
|
16220
|
+
const data = doc38.data();
|
|
15752
16221
|
return {
|
|
15753
|
-
id:
|
|
16222
|
+
id: doc38.id,
|
|
15754
16223
|
name: data.name,
|
|
15755
16224
|
clinicId: (_a = data.clinicInfo) == null ? void 0 : _a.id,
|
|
15756
16225
|
clinicName: (_b = data.clinicInfo) == null ? void 0 : _b.name,
|
|
@@ -15764,8 +16233,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15764
16233
|
};
|
|
15765
16234
|
|
|
15766
16235
|
// src/services/reviews/reviews.service.ts
|
|
15767
|
-
var
|
|
15768
|
-
var
|
|
16236
|
+
var import_firestore47 = require("firebase/firestore");
|
|
16237
|
+
var import_zod26 = require("zod");
|
|
15769
16238
|
var ReviewService = class extends BaseService {
|
|
15770
16239
|
constructor(db, auth, app) {
|
|
15771
16240
|
super(db, auth, app);
|
|
@@ -15844,15 +16313,15 @@ var ReviewService = class extends BaseService {
|
|
|
15844
16313
|
updatedAt: now
|
|
15845
16314
|
};
|
|
15846
16315
|
reviewSchema.parse(review);
|
|
15847
|
-
const docRef = (0,
|
|
15848
|
-
await (0,
|
|
16316
|
+
const docRef = (0, import_firestore47.doc)(this.db, REVIEWS_COLLECTION, reviewId);
|
|
16317
|
+
await (0, import_firestore47.setDoc)(docRef, {
|
|
15849
16318
|
...review,
|
|
15850
|
-
createdAt: (0,
|
|
15851
|
-
updatedAt: (0,
|
|
16319
|
+
createdAt: (0, import_firestore47.serverTimestamp)(),
|
|
16320
|
+
updatedAt: (0, import_firestore47.serverTimestamp)()
|
|
15852
16321
|
});
|
|
15853
16322
|
return review;
|
|
15854
16323
|
} catch (error) {
|
|
15855
|
-
if (error instanceof
|
|
16324
|
+
if (error instanceof import_zod26.z.ZodError) {
|
|
15856
16325
|
throw new Error(`Invalid review data: ${error.message}`);
|
|
15857
16326
|
}
|
|
15858
16327
|
throw error;
|
|
@@ -15864,8 +16333,8 @@ var ReviewService = class extends BaseService {
|
|
|
15864
16333
|
* @returns The review if found, null otherwise
|
|
15865
16334
|
*/
|
|
15866
16335
|
async getReview(reviewId) {
|
|
15867
|
-
const docRef = (0,
|
|
15868
|
-
const docSnap = await (0,
|
|
16336
|
+
const docRef = (0, import_firestore47.doc)(this.db, REVIEWS_COLLECTION, reviewId);
|
|
16337
|
+
const docSnap = await (0, import_firestore47.getDoc)(docRef);
|
|
15869
16338
|
if (!docSnap.exists()) {
|
|
15870
16339
|
return null;
|
|
15871
16340
|
}
|
|
@@ -15877,12 +16346,12 @@ var ReviewService = class extends BaseService {
|
|
|
15877
16346
|
* @returns Array of reviews for the patient
|
|
15878
16347
|
*/
|
|
15879
16348
|
async getReviewsByPatient(patientId) {
|
|
15880
|
-
const q = (0,
|
|
15881
|
-
(0,
|
|
15882
|
-
(0,
|
|
16349
|
+
const q = (0, import_firestore47.query)(
|
|
16350
|
+
(0, import_firestore47.collection)(this.db, REVIEWS_COLLECTION),
|
|
16351
|
+
(0, import_firestore47.where)("patientId", "==", patientId)
|
|
15883
16352
|
);
|
|
15884
|
-
const snapshot = await (0,
|
|
15885
|
-
return snapshot.docs.map((
|
|
16353
|
+
const snapshot = await (0, import_firestore47.getDocs)(q);
|
|
16354
|
+
return snapshot.docs.map((doc38) => doc38.data());
|
|
15886
16355
|
}
|
|
15887
16356
|
/**
|
|
15888
16357
|
* Gets all reviews for a specific clinic
|
|
@@ -15890,12 +16359,12 @@ var ReviewService = class extends BaseService {
|
|
|
15890
16359
|
* @returns Array of reviews containing clinic reviews
|
|
15891
16360
|
*/
|
|
15892
16361
|
async getReviewsByClinic(clinicId) {
|
|
15893
|
-
const q = (0,
|
|
15894
|
-
(0,
|
|
15895
|
-
(0,
|
|
16362
|
+
const q = (0, import_firestore47.query)(
|
|
16363
|
+
(0, import_firestore47.collection)(this.db, REVIEWS_COLLECTION),
|
|
16364
|
+
(0, import_firestore47.where)("clinicReview.clinicId", "==", clinicId)
|
|
15896
16365
|
);
|
|
15897
|
-
const snapshot = await (0,
|
|
15898
|
-
return snapshot.docs.map((
|
|
16366
|
+
const snapshot = await (0, import_firestore47.getDocs)(q);
|
|
16367
|
+
return snapshot.docs.map((doc38) => doc38.data());
|
|
15899
16368
|
}
|
|
15900
16369
|
/**
|
|
15901
16370
|
* Gets all reviews for a specific practitioner
|
|
@@ -15903,12 +16372,12 @@ var ReviewService = class extends BaseService {
|
|
|
15903
16372
|
* @returns Array of reviews containing practitioner reviews
|
|
15904
16373
|
*/
|
|
15905
16374
|
async getReviewsByPractitioner(practitionerId) {
|
|
15906
|
-
const q = (0,
|
|
15907
|
-
(0,
|
|
15908
|
-
(0,
|
|
16375
|
+
const q = (0, import_firestore47.query)(
|
|
16376
|
+
(0, import_firestore47.collection)(this.db, REVIEWS_COLLECTION),
|
|
16377
|
+
(0, import_firestore47.where)("practitionerReview.practitionerId", "==", practitionerId)
|
|
15909
16378
|
);
|
|
15910
|
-
const snapshot = await (0,
|
|
15911
|
-
return snapshot.docs.map((
|
|
16379
|
+
const snapshot = await (0, import_firestore47.getDocs)(q);
|
|
16380
|
+
return snapshot.docs.map((doc38) => doc38.data());
|
|
15912
16381
|
}
|
|
15913
16382
|
/**
|
|
15914
16383
|
* Gets all reviews for a specific procedure
|
|
@@ -15916,12 +16385,12 @@ var ReviewService = class extends BaseService {
|
|
|
15916
16385
|
* @returns Array of reviews containing procedure reviews
|
|
15917
16386
|
*/
|
|
15918
16387
|
async getReviewsByProcedure(procedureId) {
|
|
15919
|
-
const q = (0,
|
|
15920
|
-
(0,
|
|
15921
|
-
(0,
|
|
16388
|
+
const q = (0, import_firestore47.query)(
|
|
16389
|
+
(0, import_firestore47.collection)(this.db, REVIEWS_COLLECTION),
|
|
16390
|
+
(0, import_firestore47.where)("procedureReview.procedureId", "==", procedureId)
|
|
15922
16391
|
);
|
|
15923
|
-
const snapshot = await (0,
|
|
15924
|
-
return snapshot.docs.map((
|
|
16392
|
+
const snapshot = await (0, import_firestore47.getDocs)(q);
|
|
16393
|
+
return snapshot.docs.map((doc38) => doc38.data());
|
|
15925
16394
|
}
|
|
15926
16395
|
/**
|
|
15927
16396
|
* Gets all reviews for a specific appointment
|
|
@@ -15929,11 +16398,11 @@ var ReviewService = class extends BaseService {
|
|
|
15929
16398
|
* @returns The review for the appointment if found, null otherwise
|
|
15930
16399
|
*/
|
|
15931
16400
|
async getReviewByAppointment(appointmentId) {
|
|
15932
|
-
const q = (0,
|
|
15933
|
-
(0,
|
|
15934
|
-
(0,
|
|
16401
|
+
const q = (0, import_firestore47.query)(
|
|
16402
|
+
(0, import_firestore47.collection)(this.db, REVIEWS_COLLECTION),
|
|
16403
|
+
(0, import_firestore47.where)("appointmentId", "==", appointmentId)
|
|
15935
16404
|
);
|
|
15936
|
-
const snapshot = await (0,
|
|
16405
|
+
const snapshot = await (0, import_firestore47.getDocs)(q);
|
|
15937
16406
|
if (snapshot.empty) {
|
|
15938
16407
|
return null;
|
|
15939
16408
|
}
|
|
@@ -15948,7 +16417,7 @@ var ReviewService = class extends BaseService {
|
|
|
15948
16417
|
if (!review) {
|
|
15949
16418
|
throw new Error(`Review with ID ${reviewId} not found`);
|
|
15950
16419
|
}
|
|
15951
|
-
await (0,
|
|
16420
|
+
await (0, import_firestore47.deleteDoc)((0, import_firestore47.doc)(this.db, REVIEWS_COLLECTION, reviewId));
|
|
15952
16421
|
}
|
|
15953
16422
|
/**
|
|
15954
16423
|
* Calculates the average of an array of numbers
|
|
@@ -15967,7 +16436,7 @@ var ReviewService = class extends BaseService {
|
|
|
15967
16436
|
|
|
15968
16437
|
// src/config/firebase.ts
|
|
15969
16438
|
var import_app = require("firebase/app");
|
|
15970
|
-
var
|
|
16439
|
+
var import_firestore48 = require("firebase/firestore");
|
|
15971
16440
|
var import_auth9 = require("firebase/auth");
|
|
15972
16441
|
var import_analytics = require("firebase/analytics");
|
|
15973
16442
|
var import_react_native = require("react-native");
|
|
@@ -15977,7 +16446,7 @@ var firebaseInstance = null;
|
|
|
15977
16446
|
var initializeFirebase = (config) => {
|
|
15978
16447
|
if (!firebaseInstance) {
|
|
15979
16448
|
const app = (0, import_app.initializeApp)(config);
|
|
15980
|
-
const db = (0,
|
|
16449
|
+
const db = (0, import_firestore48.getFirestore)(app);
|
|
15981
16450
|
const auth = (0, import_auth9.getAuth)(app);
|
|
15982
16451
|
const storage = (0, import_storage4.getStorage)(app);
|
|
15983
16452
|
const functions = (0, import_functions3.getFunctions)(app);
|
|
@@ -16019,7 +16488,7 @@ var getFirebaseFunctions = async () => {
|
|
|
16019
16488
|
};
|
|
16020
16489
|
|
|
16021
16490
|
// src/backoffice/services/brand.service.ts
|
|
16022
|
-
var
|
|
16491
|
+
var import_firestore49 = require("firebase/firestore");
|
|
16023
16492
|
|
|
16024
16493
|
// src/backoffice/types/brand.types.ts
|
|
16025
16494
|
var BRANDS_COLLECTION = "brands";
|
|
@@ -16030,7 +16499,7 @@ var BrandService = class extends BaseService {
|
|
|
16030
16499
|
* Gets reference to brands collection
|
|
16031
16500
|
*/
|
|
16032
16501
|
getBrandsRef() {
|
|
16033
|
-
return (0,
|
|
16502
|
+
return (0, import_firestore49.collection)(this.db, BRANDS_COLLECTION);
|
|
16034
16503
|
}
|
|
16035
16504
|
/**
|
|
16036
16505
|
* Creates a new brand
|
|
@@ -16039,23 +16508,78 @@ var BrandService = class extends BaseService {
|
|
|
16039
16508
|
const now = /* @__PURE__ */ new Date();
|
|
16040
16509
|
const newBrand = {
|
|
16041
16510
|
...brand,
|
|
16511
|
+
name_lowercase: brand.name.toLowerCase(),
|
|
16042
16512
|
createdAt: now,
|
|
16043
16513
|
updatedAt: now,
|
|
16044
16514
|
isActive: true
|
|
16045
16515
|
};
|
|
16046
|
-
const docRef = await (0,
|
|
16516
|
+
const docRef = await (0, import_firestore49.addDoc)(this.getBrandsRef(), newBrand);
|
|
16047
16517
|
return { id: docRef.id, ...newBrand };
|
|
16048
16518
|
}
|
|
16049
16519
|
/**
|
|
16050
|
-
* Gets
|
|
16520
|
+
* Gets a paginated list of active brands, optionally filtered by name.
|
|
16521
|
+
* @param rowsPerPage - The number of brands to fetch.
|
|
16522
|
+
* @param searchTerm - An optional string to filter brand names by (starts-with search).
|
|
16523
|
+
* @param lastVisible - An optional document snapshot to use as a cursor for pagination.
|
|
16051
16524
|
*/
|
|
16052
|
-
async getAll() {
|
|
16053
|
-
const
|
|
16054
|
-
|
|
16525
|
+
async getAll(rowsPerPage, searchTerm, lastVisible) {
|
|
16526
|
+
const constraints = [
|
|
16527
|
+
(0, import_firestore49.where)("isActive", "==", true),
|
|
16528
|
+
(0, import_firestore49.orderBy)("name_lowercase")
|
|
16529
|
+
];
|
|
16530
|
+
if (searchTerm) {
|
|
16531
|
+
const lowercasedSearchTerm = searchTerm.toLowerCase();
|
|
16532
|
+
constraints.push((0, import_firestore49.where)("name_lowercase", ">=", lowercasedSearchTerm));
|
|
16533
|
+
constraints.push(
|
|
16534
|
+
(0, import_firestore49.where)("name_lowercase", "<=", lowercasedSearchTerm + "\uF8FF")
|
|
16535
|
+
);
|
|
16536
|
+
}
|
|
16537
|
+
if (lastVisible) {
|
|
16538
|
+
constraints.push((0, import_firestore49.startAfter)(lastVisible));
|
|
16539
|
+
}
|
|
16540
|
+
constraints.push((0, import_firestore49.limit)(rowsPerPage));
|
|
16541
|
+
const q = (0, import_firestore49.query)(this.getBrandsRef(), ...constraints);
|
|
16542
|
+
const snapshot = await (0, import_firestore49.getDocs)(q);
|
|
16543
|
+
const brands = snapshot.docs.map(
|
|
16544
|
+
(doc38) => ({
|
|
16545
|
+
id: doc38.id,
|
|
16546
|
+
...doc38.data()
|
|
16547
|
+
})
|
|
16548
|
+
);
|
|
16549
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
16550
|
+
return { brands, lastVisible: newLastVisible };
|
|
16551
|
+
}
|
|
16552
|
+
/**
|
|
16553
|
+
* Gets the total count of active brands, optionally filtered by name.
|
|
16554
|
+
* @param searchTerm - An optional string to filter brand names by (starts-with search).
|
|
16555
|
+
*/
|
|
16556
|
+
async getBrandsCount(searchTerm) {
|
|
16557
|
+
const constraints = [(0, import_firestore49.where)("isActive", "==", true)];
|
|
16558
|
+
if (searchTerm) {
|
|
16559
|
+
const lowercasedSearchTerm = searchTerm.toLowerCase();
|
|
16560
|
+
constraints.push((0, import_firestore49.where)("name_lowercase", ">=", lowercasedSearchTerm));
|
|
16561
|
+
constraints.push(
|
|
16562
|
+
(0, import_firestore49.where)("name_lowercase", "<=", lowercasedSearchTerm + "\uF8FF")
|
|
16563
|
+
);
|
|
16564
|
+
}
|
|
16565
|
+
const q = (0, import_firestore49.query)(this.getBrandsRef(), ...constraints);
|
|
16566
|
+
const snapshot = await (0, import_firestore49.getCountFromServer)(q);
|
|
16567
|
+
return snapshot.data().count;
|
|
16568
|
+
}
|
|
16569
|
+
/**
|
|
16570
|
+
* Gets all active brands for filter dropdowns (not paginated).
|
|
16571
|
+
*/
|
|
16572
|
+
async getAllForFilter() {
|
|
16573
|
+
const q = (0, import_firestore49.query)(
|
|
16574
|
+
this.getBrandsRef(),
|
|
16575
|
+
(0, import_firestore49.where)("isActive", "==", true),
|
|
16576
|
+
(0, import_firestore49.orderBy)("name")
|
|
16577
|
+
);
|
|
16578
|
+
const snapshot = await (0, import_firestore49.getDocs)(q);
|
|
16055
16579
|
return snapshot.docs.map(
|
|
16056
|
-
(
|
|
16057
|
-
id:
|
|
16058
|
-
...
|
|
16580
|
+
(doc38) => ({
|
|
16581
|
+
id: doc38.id,
|
|
16582
|
+
...doc38.data()
|
|
16059
16583
|
})
|
|
16060
16584
|
);
|
|
16061
16585
|
}
|
|
@@ -16067,8 +16591,11 @@ var BrandService = class extends BaseService {
|
|
|
16067
16591
|
...brand,
|
|
16068
16592
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16069
16593
|
};
|
|
16070
|
-
|
|
16071
|
-
|
|
16594
|
+
if (brand.name) {
|
|
16595
|
+
updateData.name_lowercase = brand.name.toLowerCase();
|
|
16596
|
+
}
|
|
16597
|
+
const docRef = (0, import_firestore49.doc)(this.getBrandsRef(), brandId);
|
|
16598
|
+
await (0, import_firestore49.updateDoc)(docRef, updateData);
|
|
16072
16599
|
return this.getById(brandId);
|
|
16073
16600
|
}
|
|
16074
16601
|
/**
|
|
@@ -16083,8 +16610,8 @@ var BrandService = class extends BaseService {
|
|
|
16083
16610
|
* Gets a brand by ID
|
|
16084
16611
|
*/
|
|
16085
16612
|
async getById(brandId) {
|
|
16086
|
-
const docRef = (0,
|
|
16087
|
-
const docSnap = await (0,
|
|
16613
|
+
const docRef = (0, import_firestore49.doc)(this.getBrandsRef(), brandId);
|
|
16614
|
+
const docSnap = await (0, import_firestore49.getDoc)(docRef);
|
|
16088
16615
|
if (!docSnap.exists()) return null;
|
|
16089
16616
|
return {
|
|
16090
16617
|
id: docSnap.id,
|
|
@@ -16094,7 +16621,7 @@ var BrandService = class extends BaseService {
|
|
|
16094
16621
|
};
|
|
16095
16622
|
|
|
16096
16623
|
// src/backoffice/services/category.service.ts
|
|
16097
|
-
var
|
|
16624
|
+
var import_firestore50 = require("firebase/firestore");
|
|
16098
16625
|
|
|
16099
16626
|
// src/backoffice/types/category.types.ts
|
|
16100
16627
|
var CATEGORIES_COLLECTION = "backoffice_categories";
|
|
@@ -16105,7 +16632,7 @@ var CategoryService = class extends BaseService {
|
|
|
16105
16632
|
* Referenca na Firestore kolekciju kategorija
|
|
16106
16633
|
*/
|
|
16107
16634
|
get categoriesRef() {
|
|
16108
|
-
return (0,
|
|
16635
|
+
return (0, import_firestore50.collection)(this.db, CATEGORIES_COLLECTION);
|
|
16109
16636
|
}
|
|
16110
16637
|
/**
|
|
16111
16638
|
* Kreira novu kategoriju u sistemu
|
|
@@ -16120,41 +16647,91 @@ var CategoryService = class extends BaseService {
|
|
|
16120
16647
|
updatedAt: now,
|
|
16121
16648
|
isActive: true
|
|
16122
16649
|
};
|
|
16123
|
-
const docRef = await (0,
|
|
16650
|
+
const docRef = await (0, import_firestore50.addDoc)(this.categoriesRef, newCategory);
|
|
16124
16651
|
return { id: docRef.id, ...newCategory };
|
|
16125
16652
|
}
|
|
16126
16653
|
/**
|
|
16127
|
-
*
|
|
16128
|
-
* @
|
|
16654
|
+
* Returns counts of categories for each family.
|
|
16655
|
+
* @param active - Whether to count active or inactive categories.
|
|
16656
|
+
* @returns A record mapping family to category count.
|
|
16129
16657
|
*/
|
|
16130
|
-
async
|
|
16131
|
-
const
|
|
16132
|
-
const
|
|
16658
|
+
async getCategoryCounts(active = true) {
|
|
16659
|
+
const counts = {};
|
|
16660
|
+
const families = Object.values(ProcedureFamily);
|
|
16661
|
+
for (const family of families) {
|
|
16662
|
+
const q = (0, import_firestore50.query)(
|
|
16663
|
+
this.categoriesRef,
|
|
16664
|
+
(0, import_firestore50.where)("family", "==", family),
|
|
16665
|
+
(0, import_firestore50.where)("isActive", "==", active)
|
|
16666
|
+
);
|
|
16667
|
+
const snapshot = await (0, import_firestore50.getCountFromServer)(q);
|
|
16668
|
+
counts[family] = snapshot.data().count;
|
|
16669
|
+
}
|
|
16670
|
+
return counts;
|
|
16671
|
+
}
|
|
16672
|
+
/**
|
|
16673
|
+
* Vraća sve kategorije za potrebe filtera (bez paginacije)
|
|
16674
|
+
* @returns Lista svih aktivnih kategorija
|
|
16675
|
+
*/
|
|
16676
|
+
async getAllForFilter() {
|
|
16677
|
+
const q = (0, import_firestore50.query)(this.categoriesRef, (0, import_firestore50.where)("isActive", "==", true));
|
|
16678
|
+
const snapshot = await (0, import_firestore50.getDocs)(q);
|
|
16133
16679
|
return snapshot.docs.map(
|
|
16134
|
-
(
|
|
16135
|
-
id:
|
|
16136
|
-
...
|
|
16680
|
+
(doc38) => ({
|
|
16681
|
+
id: doc38.id,
|
|
16682
|
+
...doc38.data()
|
|
16683
|
+
})
|
|
16684
|
+
);
|
|
16685
|
+
}
|
|
16686
|
+
/**
|
|
16687
|
+
* Vraća sve kategorije sa paginacijom
|
|
16688
|
+
* @param options - Pagination and filter options
|
|
16689
|
+
* @returns Lista kategorija i poslednji vidljiv dokument
|
|
16690
|
+
*/
|
|
16691
|
+
async getAll(options = {}) {
|
|
16692
|
+
const { active = true, limit: queryLimit = 10, lastVisible } = options;
|
|
16693
|
+
const constraints = [
|
|
16694
|
+
(0, import_firestore50.where)("isActive", "==", active),
|
|
16695
|
+
(0, import_firestore50.orderBy)("name"),
|
|
16696
|
+
queryLimit ? (0, import_firestore50.limit)(queryLimit) : void 0,
|
|
16697
|
+
lastVisible ? (0, import_firestore50.startAfter)(lastVisible) : void 0
|
|
16698
|
+
].filter((c) => !!c);
|
|
16699
|
+
const q = (0, import_firestore50.query)(this.categoriesRef, ...constraints);
|
|
16700
|
+
const snapshot = await (0, import_firestore50.getDocs)(q);
|
|
16701
|
+
const categories = snapshot.docs.map(
|
|
16702
|
+
(doc38) => ({
|
|
16703
|
+
id: doc38.id,
|
|
16704
|
+
...doc38.data()
|
|
16137
16705
|
})
|
|
16138
16706
|
);
|
|
16707
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
16708
|
+
return { categories, lastVisible: newLastVisible };
|
|
16139
16709
|
}
|
|
16140
16710
|
/**
|
|
16141
|
-
* Vraća sve aktivne kategorije za određenu familiju procedura
|
|
16711
|
+
* Vraća sve aktivne kategorije za određenu familiju procedura sa paginacijom
|
|
16142
16712
|
* @param family - Familija procedura (aesthetics/surgery)
|
|
16713
|
+
* @param options - Pagination options
|
|
16143
16714
|
* @returns Lista kategorija koje pripadaju traženoj familiji
|
|
16144
16715
|
*/
|
|
16145
|
-
async getAllByFamily(family) {
|
|
16146
|
-
const
|
|
16147
|
-
|
|
16148
|
-
(0,
|
|
16149
|
-
(0,
|
|
16150
|
-
|
|
16151
|
-
|
|
16152
|
-
|
|
16153
|
-
|
|
16154
|
-
|
|
16155
|
-
|
|
16716
|
+
async getAllByFamily(family, options = {}) {
|
|
16717
|
+
const { active = true, limit: queryLimit = 10, lastVisible } = options;
|
|
16718
|
+
const constraints = [
|
|
16719
|
+
(0, import_firestore50.where)("family", "==", family),
|
|
16720
|
+
(0, import_firestore50.where)("isActive", "==", active),
|
|
16721
|
+
(0, import_firestore50.orderBy)("name"),
|
|
16722
|
+
queryLimit ? (0, import_firestore50.limit)(queryLimit) : void 0,
|
|
16723
|
+
lastVisible ? (0, import_firestore50.startAfter)(lastVisible) : void 0
|
|
16724
|
+
].filter((c) => !!c);
|
|
16725
|
+
const q = (0, import_firestore50.query)(this.categoriesRef, ...constraints);
|
|
16726
|
+
const snapshot = await (0, import_firestore50.getDocs)(q);
|
|
16727
|
+
const categories = snapshot.docs.map(
|
|
16728
|
+
(doc38) => ({
|
|
16729
|
+
id: doc38.id,
|
|
16730
|
+
...doc38.data()
|
|
16156
16731
|
})
|
|
16157
16732
|
);
|
|
16733
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
16734
|
+
return { categories, lastVisible: newLastVisible };
|
|
16158
16735
|
}
|
|
16159
16736
|
/**
|
|
16160
16737
|
* Ažurira postojeću kategoriju
|
|
@@ -16167,8 +16744,8 @@ var CategoryService = class extends BaseService {
|
|
|
16167
16744
|
...category,
|
|
16168
16745
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16169
16746
|
};
|
|
16170
|
-
const docRef = (0,
|
|
16171
|
-
await (0,
|
|
16747
|
+
const docRef = (0, import_firestore50.doc)(this.categoriesRef, id);
|
|
16748
|
+
await (0, import_firestore50.updateDoc)(docRef, updateData);
|
|
16172
16749
|
return this.getById(id);
|
|
16173
16750
|
}
|
|
16174
16751
|
/**
|
|
@@ -16178,14 +16755,21 @@ var CategoryService = class extends BaseService {
|
|
|
16178
16755
|
async delete(id) {
|
|
16179
16756
|
await this.update(id, { isActive: false });
|
|
16180
16757
|
}
|
|
16758
|
+
/**
|
|
16759
|
+
* Reactivates a category by setting its isActive flag to true.
|
|
16760
|
+
* @param id - The ID of the category to reactivate.
|
|
16761
|
+
*/
|
|
16762
|
+
async reactivate(id) {
|
|
16763
|
+
await this.update(id, { isActive: true });
|
|
16764
|
+
}
|
|
16181
16765
|
/**
|
|
16182
16766
|
* Vraća kategoriju po ID-u
|
|
16183
16767
|
* @param id - ID tražene kategorije
|
|
16184
16768
|
* @returns Kategorija ili null ako ne postoji
|
|
16185
16769
|
*/
|
|
16186
16770
|
async getById(id) {
|
|
16187
|
-
const docRef = (0,
|
|
16188
|
-
const docSnap = await (0,
|
|
16771
|
+
const docRef = (0, import_firestore50.doc)(this.categoriesRef, id);
|
|
16772
|
+
const docSnap = await (0, import_firestore50.getDoc)(docRef);
|
|
16189
16773
|
if (!docSnap.exists()) return null;
|
|
16190
16774
|
return {
|
|
16191
16775
|
id: docSnap.id,
|
|
@@ -16195,7 +16779,7 @@ var CategoryService = class extends BaseService {
|
|
|
16195
16779
|
};
|
|
16196
16780
|
|
|
16197
16781
|
// src/backoffice/services/subcategory.service.ts
|
|
16198
|
-
var
|
|
16782
|
+
var import_firestore51 = require("firebase/firestore");
|
|
16199
16783
|
|
|
16200
16784
|
// src/backoffice/types/subcategory.types.ts
|
|
16201
16785
|
var SUBCATEGORIES_COLLECTION = "subcategories";
|
|
@@ -16207,7 +16791,7 @@ var SubcategoryService = class extends BaseService {
|
|
|
16207
16791
|
* @param categoryId - ID roditeljske kategorije
|
|
16208
16792
|
*/
|
|
16209
16793
|
getSubcategoriesRef(categoryId) {
|
|
16210
|
-
return (0,
|
|
16794
|
+
return (0, import_firestore51.collection)(
|
|
16211
16795
|
this.db,
|
|
16212
16796
|
CATEGORIES_COLLECTION,
|
|
16213
16797
|
categoryId,
|
|
@@ -16229,27 +16813,117 @@ var SubcategoryService = class extends BaseService {
|
|
|
16229
16813
|
updatedAt: now,
|
|
16230
16814
|
isActive: true
|
|
16231
16815
|
};
|
|
16232
|
-
const docRef = await (0,
|
|
16816
|
+
const docRef = await (0, import_firestore51.addDoc)(
|
|
16233
16817
|
this.getSubcategoriesRef(categoryId),
|
|
16234
16818
|
newSubcategory
|
|
16235
16819
|
);
|
|
16236
16820
|
return { id: docRef.id, ...newSubcategory };
|
|
16237
16821
|
}
|
|
16238
16822
|
/**
|
|
16239
|
-
*
|
|
16823
|
+
* Returns counts of subcategories for all categories.
|
|
16824
|
+
* @param active - Whether to count active or inactive subcategories.
|
|
16825
|
+
* @returns A record mapping category ID to subcategory count.
|
|
16826
|
+
*/
|
|
16827
|
+
async getSubcategoryCounts(active = true) {
|
|
16828
|
+
const categoriesRef = (0, import_firestore51.collection)(this.db, CATEGORIES_COLLECTION);
|
|
16829
|
+
const categoriesSnapshot = await (0, import_firestore51.getDocs)(categoriesRef);
|
|
16830
|
+
const counts = {};
|
|
16831
|
+
for (const categoryDoc of categoriesSnapshot.docs) {
|
|
16832
|
+
const categoryId = categoryDoc.id;
|
|
16833
|
+
const subcategoriesRef = this.getSubcategoriesRef(categoryId);
|
|
16834
|
+
const q = (0, import_firestore51.query)(subcategoriesRef, (0, import_firestore51.where)("isActive", "==", active));
|
|
16835
|
+
const snapshot = await (0, import_firestore51.getCountFromServer)(q);
|
|
16836
|
+
counts[categoryId] = snapshot.data().count;
|
|
16837
|
+
}
|
|
16838
|
+
return counts;
|
|
16839
|
+
}
|
|
16840
|
+
/**
|
|
16841
|
+
* Vraća sve aktivne podkategorije za određenu kategoriju sa paginacijom
|
|
16240
16842
|
* @param categoryId - ID kategorije čije podkategorije tražimo
|
|
16241
|
-
* @
|
|
16843
|
+
* @param options - Pagination options
|
|
16844
|
+
* @returns Lista aktivnih podkategorija i poslednji vidljiv dokument
|
|
16845
|
+
*/
|
|
16846
|
+
async getAllByCategoryId(categoryId, options = {}) {
|
|
16847
|
+
const { active = true, limit: queryLimit = 10, lastVisible } = options;
|
|
16848
|
+
const constraints = [
|
|
16849
|
+
(0, import_firestore51.where)("isActive", "==", active),
|
|
16850
|
+
(0, import_firestore51.orderBy)("name"),
|
|
16851
|
+
queryLimit ? (0, import_firestore51.limit)(queryLimit) : void 0,
|
|
16852
|
+
lastVisible ? (0, import_firestore51.startAfter)(lastVisible) : void 0
|
|
16853
|
+
].filter((c) => !!c);
|
|
16854
|
+
const q = (0, import_firestore51.query)(this.getSubcategoriesRef(categoryId), ...constraints);
|
|
16855
|
+
const querySnapshot = await (0, import_firestore51.getDocs)(q);
|
|
16856
|
+
const subcategories = querySnapshot.docs.map(
|
|
16857
|
+
(doc38) => ({
|
|
16858
|
+
id: doc38.id,
|
|
16859
|
+
...doc38.data()
|
|
16860
|
+
})
|
|
16861
|
+
);
|
|
16862
|
+
const newLastVisible = querySnapshot.docs[querySnapshot.docs.length - 1];
|
|
16863
|
+
return { subcategories, lastVisible: newLastVisible };
|
|
16864
|
+
}
|
|
16865
|
+
/**
|
|
16866
|
+
* Vraća sve podkategorije sa paginacijom koristeći collection group query.
|
|
16867
|
+
* NOTE: This query requires a composite index in Firestore on the 'subcategories' collection group.
|
|
16868
|
+
* The index should be on 'isActive' (ascending) and 'name' (ascending).
|
|
16869
|
+
* Firestore will provide a link to create this index in the console error if it's missing.
|
|
16870
|
+
* @param options - Pagination options
|
|
16871
|
+
* @returns Lista podkategorija i poslednji vidljiv dokument
|
|
16242
16872
|
*/
|
|
16243
|
-
async
|
|
16244
|
-
const
|
|
16873
|
+
async getAll(options = {}) {
|
|
16874
|
+
const { active = true, limit: queryLimit = 10, lastVisible } = options;
|
|
16875
|
+
const constraints = [
|
|
16876
|
+
(0, import_firestore51.where)("isActive", "==", active),
|
|
16877
|
+
(0, import_firestore51.orderBy)("name"),
|
|
16878
|
+
queryLimit ? (0, import_firestore51.limit)(queryLimit) : void 0,
|
|
16879
|
+
lastVisible ? (0, import_firestore51.startAfter)(lastVisible) : void 0
|
|
16880
|
+
].filter((c) => !!c);
|
|
16881
|
+
const q = (0, import_firestore51.query)(
|
|
16882
|
+
(0, import_firestore51.collectionGroup)(this.db, SUBCATEGORIES_COLLECTION),
|
|
16883
|
+
...constraints
|
|
16884
|
+
);
|
|
16885
|
+
const querySnapshot = await (0, import_firestore51.getDocs)(q);
|
|
16886
|
+
const subcategories = querySnapshot.docs.map(
|
|
16887
|
+
(doc38) => ({
|
|
16888
|
+
id: doc38.id,
|
|
16889
|
+
...doc38.data()
|
|
16890
|
+
})
|
|
16891
|
+
);
|
|
16892
|
+
const newLastVisible = querySnapshot.docs[querySnapshot.docs.length - 1];
|
|
16893
|
+
return { subcategories, lastVisible: newLastVisible };
|
|
16894
|
+
}
|
|
16895
|
+
/**
|
|
16896
|
+
* Vraća sve subkategorije za određenu kategoriju za potrebe filtera (bez paginacije)
|
|
16897
|
+
* @param categoryId - ID kategorije čije subkategorije tražimo
|
|
16898
|
+
* @returns Lista svih aktivnih subkategorija
|
|
16899
|
+
*/
|
|
16900
|
+
async getAllForFilterByCategoryId(categoryId) {
|
|
16901
|
+
const q = (0, import_firestore51.query)(
|
|
16245
16902
|
this.getSubcategoriesRef(categoryId),
|
|
16246
|
-
(0,
|
|
16903
|
+
(0, import_firestore51.where)("isActive", "==", true)
|
|
16247
16904
|
);
|
|
16248
|
-
const
|
|
16249
|
-
return
|
|
16250
|
-
(
|
|
16251
|
-
id:
|
|
16252
|
-
...
|
|
16905
|
+
const querySnapshot = await (0, import_firestore51.getDocs)(q);
|
|
16906
|
+
return querySnapshot.docs.map(
|
|
16907
|
+
(doc38) => ({
|
|
16908
|
+
id: doc38.id,
|
|
16909
|
+
...doc38.data()
|
|
16910
|
+
})
|
|
16911
|
+
);
|
|
16912
|
+
}
|
|
16913
|
+
/**
|
|
16914
|
+
* Vraća sve subkategorije za potrebe filtera (bez paginacije)
|
|
16915
|
+
* @returns Lista svih aktivnih subkategorija
|
|
16916
|
+
*/
|
|
16917
|
+
async getAllForFilter() {
|
|
16918
|
+
const q = (0, import_firestore51.query)(
|
|
16919
|
+
(0, import_firestore51.collectionGroup)(this.db, SUBCATEGORIES_COLLECTION),
|
|
16920
|
+
(0, import_firestore51.where)("isActive", "==", true)
|
|
16921
|
+
);
|
|
16922
|
+
const querySnapshot = await (0, import_firestore51.getDocs)(q);
|
|
16923
|
+
return querySnapshot.docs.map(
|
|
16924
|
+
(doc38) => ({
|
|
16925
|
+
id: doc38.id,
|
|
16926
|
+
...doc38.data()
|
|
16253
16927
|
})
|
|
16254
16928
|
);
|
|
16255
16929
|
}
|
|
@@ -16261,13 +16935,42 @@ var SubcategoryService = class extends BaseService {
|
|
|
16261
16935
|
* @returns Ažurirana podkategorija
|
|
16262
16936
|
*/
|
|
16263
16937
|
async update(categoryId, subcategoryId, subcategory) {
|
|
16264
|
-
const
|
|
16265
|
-
|
|
16266
|
-
|
|
16267
|
-
|
|
16268
|
-
|
|
16269
|
-
|
|
16270
|
-
|
|
16938
|
+
const newCategoryId = subcategory.categoryId;
|
|
16939
|
+
if (newCategoryId && newCategoryId !== categoryId) {
|
|
16940
|
+
const oldDocRef = (0, import_firestore51.doc)(
|
|
16941
|
+
this.getSubcategoriesRef(categoryId),
|
|
16942
|
+
subcategoryId
|
|
16943
|
+
);
|
|
16944
|
+
const docSnap = await (0, import_firestore51.getDoc)(oldDocRef);
|
|
16945
|
+
if (!docSnap.exists()) {
|
|
16946
|
+
throw new Error("Subcategory to update does not exist.");
|
|
16947
|
+
}
|
|
16948
|
+
const existingData = docSnap.data();
|
|
16949
|
+
const newData = {
|
|
16950
|
+
...existingData,
|
|
16951
|
+
...subcategory,
|
|
16952
|
+
categoryId: newCategoryId,
|
|
16953
|
+
// Ensure categoryId is updated
|
|
16954
|
+
createdAt: existingData.createdAt,
|
|
16955
|
+
// Preserve original creation date
|
|
16956
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
16957
|
+
};
|
|
16958
|
+
const newDocRef = (0, import_firestore51.doc)(
|
|
16959
|
+
this.getSubcategoriesRef(newCategoryId),
|
|
16960
|
+
subcategoryId
|
|
16961
|
+
);
|
|
16962
|
+
await (0, import_firestore51.setDoc)(newDocRef, newData);
|
|
16963
|
+
await (0, import_firestore51.deleteDoc)(oldDocRef);
|
|
16964
|
+
return { id: subcategoryId, ...newData };
|
|
16965
|
+
} else {
|
|
16966
|
+
const updateData = {
|
|
16967
|
+
...subcategory,
|
|
16968
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
16969
|
+
};
|
|
16970
|
+
const docRef = (0, import_firestore51.doc)(this.getSubcategoriesRef(categoryId), subcategoryId);
|
|
16971
|
+
await (0, import_firestore51.updateDoc)(docRef, updateData);
|
|
16972
|
+
return this.getById(categoryId, subcategoryId);
|
|
16973
|
+
}
|
|
16271
16974
|
}
|
|
16272
16975
|
/**
|
|
16273
16976
|
* Soft delete podkategorije (postavlja isActive na false)
|
|
@@ -16277,6 +16980,14 @@ var SubcategoryService = class extends BaseService {
|
|
|
16277
16980
|
async delete(categoryId, subcategoryId) {
|
|
16278
16981
|
await this.update(categoryId, subcategoryId, { isActive: false });
|
|
16279
16982
|
}
|
|
16983
|
+
/**
|
|
16984
|
+
* Reactivates a subcategory by setting its isActive flag to true.
|
|
16985
|
+
* @param categoryId - The ID of the category to which the subcategory belongs.
|
|
16986
|
+
* @param subcategoryId - The ID of the subcategory to reactivate.
|
|
16987
|
+
*/
|
|
16988
|
+
async reactivate(categoryId, subcategoryId) {
|
|
16989
|
+
await this.update(categoryId, subcategoryId, { isActive: true });
|
|
16990
|
+
}
|
|
16280
16991
|
/**
|
|
16281
16992
|
* Vraća podkategoriju po ID-u
|
|
16282
16993
|
* @param categoryId - ID kategorije kojoj pripada podkategorija
|
|
@@ -16284,8 +16995,8 @@ var SubcategoryService = class extends BaseService {
|
|
|
16284
16995
|
* @returns Podkategorija ili null ako ne postoji
|
|
16285
16996
|
*/
|
|
16286
16997
|
async getById(categoryId, subcategoryId) {
|
|
16287
|
-
const docRef = (0,
|
|
16288
|
-
const docSnap = await (0,
|
|
16998
|
+
const docRef = (0, import_firestore51.doc)(this.getSubcategoriesRef(categoryId), subcategoryId);
|
|
16999
|
+
const docSnap = await (0, import_firestore51.getDoc)(docRef);
|
|
16289
17000
|
if (!docSnap.exists()) return null;
|
|
16290
17001
|
return {
|
|
16291
17002
|
id: docSnap.id,
|
|
@@ -16295,145 +17006,193 @@ var SubcategoryService = class extends BaseService {
|
|
|
16295
17006
|
};
|
|
16296
17007
|
|
|
16297
17008
|
// src/backoffice/services/technology.service.ts
|
|
16298
|
-
var
|
|
17009
|
+
var import_firestore52 = require("firebase/firestore");
|
|
16299
17010
|
var DEFAULT_CERTIFICATION_REQUIREMENT = {
|
|
16300
17011
|
minimumLevel: "aesthetician" /* AESTHETICIAN */,
|
|
16301
17012
|
requiredSpecialties: []
|
|
16302
17013
|
};
|
|
16303
17014
|
var TechnologyService = class extends BaseService {
|
|
16304
17015
|
/**
|
|
16305
|
-
*
|
|
17016
|
+
* Reference to the Firestore collection of technologies.
|
|
16306
17017
|
*/
|
|
16307
|
-
|
|
16308
|
-
return (0,
|
|
17018
|
+
get technologiesRef() {
|
|
17019
|
+
return (0, import_firestore52.collection)(this.db, TECHNOLOGIES_COLLECTION);
|
|
16309
17020
|
}
|
|
16310
17021
|
/**
|
|
16311
|
-
*
|
|
16312
|
-
* @param technology -
|
|
16313
|
-
* @returns
|
|
17022
|
+
* Creates a new technology.
|
|
17023
|
+
* @param technology - Data for the new technology.
|
|
17024
|
+
* @returns The created technology with its generated ID.
|
|
16314
17025
|
*/
|
|
16315
17026
|
async create(technology) {
|
|
16316
17027
|
const now = /* @__PURE__ */ new Date();
|
|
16317
17028
|
const newTechnology = {
|
|
16318
|
-
|
|
16319
|
-
|
|
16320
|
-
|
|
16321
|
-
|
|
16322
|
-
|
|
16323
|
-
|
|
16324
|
-
post: []
|
|
16325
|
-
},
|
|
17029
|
+
name: technology.name,
|
|
17030
|
+
description: technology.description,
|
|
17031
|
+
family: technology.family,
|
|
17032
|
+
categoryId: technology.categoryId,
|
|
17033
|
+
subcategoryId: technology.subcategoryId,
|
|
17034
|
+
requirements: technology.requirements || { pre: [], post: [] },
|
|
16326
17035
|
blockingConditions: technology.blockingConditions || [],
|
|
16327
17036
|
contraindications: technology.contraindications || [],
|
|
16328
17037
|
benefits: technology.benefits || [],
|
|
16329
|
-
certificationRequirement: technology.certificationRequirement || DEFAULT_CERTIFICATION_REQUIREMENT
|
|
17038
|
+
certificationRequirement: technology.certificationRequirement || DEFAULT_CERTIFICATION_REQUIREMENT,
|
|
17039
|
+
documentationTemplates: technology.documentationTemplates || [],
|
|
17040
|
+
isActive: true,
|
|
17041
|
+
createdAt: now,
|
|
17042
|
+
updatedAt: now
|
|
16330
17043
|
};
|
|
16331
|
-
|
|
17044
|
+
if (technology.technicalDetails) {
|
|
17045
|
+
newTechnology.technicalDetails = technology.technicalDetails;
|
|
17046
|
+
}
|
|
17047
|
+
const docRef = await (0, import_firestore52.addDoc)(this.technologiesRef, newTechnology);
|
|
16332
17048
|
return { id: docRef.id, ...newTechnology };
|
|
16333
17049
|
}
|
|
16334
17050
|
/**
|
|
16335
|
-
*
|
|
16336
|
-
* @
|
|
17051
|
+
* Returns counts of technologies for each subcategory.
|
|
17052
|
+
* @param active - Whether to count active or inactive technologies.
|
|
17053
|
+
* @returns A record mapping subcategory ID to technology count.
|
|
16337
17054
|
*/
|
|
16338
|
-
async
|
|
16339
|
-
const q = (0,
|
|
16340
|
-
const snapshot = await (0,
|
|
16341
|
-
|
|
16342
|
-
|
|
16343
|
-
|
|
16344
|
-
|
|
16345
|
-
|
|
16346
|
-
|
|
17055
|
+
async getTechnologyCounts(active = true) {
|
|
17056
|
+
const q = (0, import_firestore52.query)(this.technologiesRef, (0, import_firestore52.where)("isActive", "==", active));
|
|
17057
|
+
const snapshot = await (0, import_firestore52.getDocs)(q);
|
|
17058
|
+
const counts = {};
|
|
17059
|
+
snapshot.docs.forEach((doc38) => {
|
|
17060
|
+
const tech = doc38.data();
|
|
17061
|
+
counts[tech.subcategoryId] = (counts[tech.subcategoryId] || 0) + 1;
|
|
17062
|
+
});
|
|
17063
|
+
return counts;
|
|
16347
17064
|
}
|
|
16348
17065
|
/**
|
|
16349
|
-
*
|
|
16350
|
-
* @param
|
|
16351
|
-
* @returns
|
|
17066
|
+
* Returns counts of technologies for each category.
|
|
17067
|
+
* @param active - Whether to count active or inactive technologies.
|
|
17068
|
+
* @returns A record mapping category ID to technology count.
|
|
16352
17069
|
*/
|
|
16353
|
-
async
|
|
16354
|
-
const q = (0,
|
|
16355
|
-
|
|
16356
|
-
|
|
16357
|
-
|
|
16358
|
-
|
|
16359
|
-
|
|
16360
|
-
|
|
16361
|
-
|
|
16362
|
-
|
|
16363
|
-
|
|
17070
|
+
async getTechnologyCountsByCategory(active = true) {
|
|
17071
|
+
const q = (0, import_firestore52.query)(this.technologiesRef, (0, import_firestore52.where)("isActive", "==", active));
|
|
17072
|
+
const snapshot = await (0, import_firestore52.getDocs)(q);
|
|
17073
|
+
const counts = {};
|
|
17074
|
+
snapshot.docs.forEach((doc38) => {
|
|
17075
|
+
const tech = doc38.data();
|
|
17076
|
+
counts[tech.categoryId] = (counts[tech.categoryId] || 0) + 1;
|
|
17077
|
+
});
|
|
17078
|
+
return counts;
|
|
17079
|
+
}
|
|
17080
|
+
/**
|
|
17081
|
+
* Returns all technologies with pagination.
|
|
17082
|
+
* @param options - Pagination and filter options.
|
|
17083
|
+
* @returns A list of technologies and the last visible document.
|
|
17084
|
+
*/
|
|
17085
|
+
async getAll(options = {}) {
|
|
17086
|
+
const { active = true, limit: queryLimit = 10, lastVisible } = options;
|
|
17087
|
+
const constraints = [
|
|
17088
|
+
(0, import_firestore52.where)("isActive", "==", active),
|
|
17089
|
+
(0, import_firestore52.orderBy)("name"),
|
|
17090
|
+
queryLimit ? (0, import_firestore52.limit)(queryLimit) : void 0,
|
|
17091
|
+
lastVisible ? (0, import_firestore52.startAfter)(lastVisible) : void 0
|
|
17092
|
+
].filter((c) => !!c);
|
|
17093
|
+
const q = (0, import_firestore52.query)(this.technologiesRef, ...constraints);
|
|
17094
|
+
const snapshot = await (0, import_firestore52.getDocs)(q);
|
|
17095
|
+
const technologies = snapshot.docs.map(
|
|
17096
|
+
(doc38) => ({
|
|
17097
|
+
id: doc38.id,
|
|
17098
|
+
...doc38.data()
|
|
16364
17099
|
})
|
|
16365
17100
|
);
|
|
17101
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
17102
|
+
return { technologies, lastVisible: newLastVisible };
|
|
16366
17103
|
}
|
|
16367
17104
|
/**
|
|
16368
|
-
*
|
|
16369
|
-
* @param categoryId - ID
|
|
16370
|
-
* @
|
|
17105
|
+
* Returns all technologies for a specific category with pagination.
|
|
17106
|
+
* @param categoryId - The ID of the category.
|
|
17107
|
+
* @param options - Pagination options.
|
|
17108
|
+
* @returns A list of technologies for the specified category.
|
|
16371
17109
|
*/
|
|
16372
|
-
async getAllByCategoryId(categoryId) {
|
|
16373
|
-
const
|
|
16374
|
-
|
|
16375
|
-
(0,
|
|
16376
|
-
(0,
|
|
16377
|
-
|
|
16378
|
-
|
|
16379
|
-
|
|
16380
|
-
|
|
16381
|
-
|
|
16382
|
-
|
|
17110
|
+
async getAllByCategoryId(categoryId, options = {}) {
|
|
17111
|
+
const { active = true, limit: queryLimit = 10, lastVisible } = options;
|
|
17112
|
+
const constraints = [
|
|
17113
|
+
(0, import_firestore52.where)("categoryId", "==", categoryId),
|
|
17114
|
+
(0, import_firestore52.where)("isActive", "==", active),
|
|
17115
|
+
(0, import_firestore52.orderBy)("name"),
|
|
17116
|
+
queryLimit ? (0, import_firestore52.limit)(queryLimit) : void 0,
|
|
17117
|
+
lastVisible ? (0, import_firestore52.startAfter)(lastVisible) : void 0
|
|
17118
|
+
].filter((c) => !!c);
|
|
17119
|
+
const q = (0, import_firestore52.query)(this.technologiesRef, ...constraints);
|
|
17120
|
+
const snapshot = await (0, import_firestore52.getDocs)(q);
|
|
17121
|
+
const technologies = snapshot.docs.map(
|
|
17122
|
+
(doc38) => ({
|
|
17123
|
+
id: doc38.id,
|
|
17124
|
+
...doc38.data()
|
|
16383
17125
|
})
|
|
16384
17126
|
);
|
|
17127
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
17128
|
+
return { technologies, lastVisible: newLastVisible };
|
|
16385
17129
|
}
|
|
16386
17130
|
/**
|
|
16387
|
-
*
|
|
16388
|
-
* @param subcategoryId - ID
|
|
16389
|
-
* @
|
|
17131
|
+
* Returns all technologies for a specific subcategory with pagination.
|
|
17132
|
+
* @param subcategoryId - The ID of the subcategory.
|
|
17133
|
+
* @param options - Pagination options.
|
|
17134
|
+
* @returns A list of technologies for the specified subcategory.
|
|
16390
17135
|
*/
|
|
16391
|
-
async getAllBySubcategoryId(subcategoryId) {
|
|
16392
|
-
const
|
|
16393
|
-
|
|
16394
|
-
(0,
|
|
16395
|
-
(0,
|
|
16396
|
-
|
|
16397
|
-
|
|
16398
|
-
|
|
16399
|
-
|
|
16400
|
-
|
|
16401
|
-
|
|
17136
|
+
async getAllBySubcategoryId(subcategoryId, options = {}) {
|
|
17137
|
+
const { active = true, limit: queryLimit = 10, lastVisible } = options;
|
|
17138
|
+
const constraints = [
|
|
17139
|
+
(0, import_firestore52.where)("subcategoryId", "==", subcategoryId),
|
|
17140
|
+
(0, import_firestore52.where)("isActive", "==", active),
|
|
17141
|
+
(0, import_firestore52.orderBy)("name"),
|
|
17142
|
+
queryLimit ? (0, import_firestore52.limit)(queryLimit) : void 0,
|
|
17143
|
+
lastVisible ? (0, import_firestore52.startAfter)(lastVisible) : void 0
|
|
17144
|
+
].filter((c) => !!c);
|
|
17145
|
+
const q = (0, import_firestore52.query)(this.technologiesRef, ...constraints);
|
|
17146
|
+
const snapshot = await (0, import_firestore52.getDocs)(q);
|
|
17147
|
+
const technologies = snapshot.docs.map(
|
|
17148
|
+
(doc38) => ({
|
|
17149
|
+
id: doc38.id,
|
|
17150
|
+
...doc38.data()
|
|
16402
17151
|
})
|
|
16403
17152
|
);
|
|
17153
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
17154
|
+
return { technologies, lastVisible: newLastVisible };
|
|
16404
17155
|
}
|
|
16405
17156
|
/**
|
|
16406
|
-
*
|
|
16407
|
-
* @param
|
|
16408
|
-
* @param technology -
|
|
16409
|
-
* @returns
|
|
17157
|
+
* Updates an existing technology.
|
|
17158
|
+
* @param id - The ID of the technology to update.
|
|
17159
|
+
* @param technology - New data for the technology.
|
|
17160
|
+
* @returns The updated technology.
|
|
16410
17161
|
*/
|
|
16411
|
-
async update(
|
|
16412
|
-
const updateData = {
|
|
16413
|
-
|
|
16414
|
-
|
|
16415
|
-
|
|
16416
|
-
|
|
16417
|
-
|
|
16418
|
-
|
|
17162
|
+
async update(id, technology) {
|
|
17163
|
+
const updateData = { ...technology };
|
|
17164
|
+
Object.keys(updateData).forEach((key) => {
|
|
17165
|
+
if (updateData[key] === void 0) {
|
|
17166
|
+
delete updateData[key];
|
|
17167
|
+
}
|
|
17168
|
+
});
|
|
17169
|
+
updateData.updatedAt = /* @__PURE__ */ new Date();
|
|
17170
|
+
const docRef = (0, import_firestore52.doc)(this.technologiesRef, id);
|
|
17171
|
+
await (0, import_firestore52.updateDoc)(docRef, updateData);
|
|
17172
|
+
return this.getById(id);
|
|
16419
17173
|
}
|
|
16420
17174
|
/**
|
|
16421
|
-
* Soft
|
|
16422
|
-
* @param
|
|
17175
|
+
* Soft deletes a technology.
|
|
17176
|
+
* @param id - The ID of the technology to delete.
|
|
16423
17177
|
*/
|
|
16424
|
-
async delete(
|
|
16425
|
-
await this.update(
|
|
16426
|
-
isActive: false
|
|
16427
|
-
});
|
|
17178
|
+
async delete(id) {
|
|
17179
|
+
await this.update(id, { isActive: false });
|
|
16428
17180
|
}
|
|
16429
17181
|
/**
|
|
16430
|
-
*
|
|
16431
|
-
* @param
|
|
16432
|
-
* @returns Tehnologija ili null ako ne postoji
|
|
17182
|
+
* Reactivates a technology.
|
|
17183
|
+
* @param id - The ID of the technology to reactivate.
|
|
16433
17184
|
*/
|
|
16434
|
-
async
|
|
16435
|
-
|
|
16436
|
-
|
|
17185
|
+
async reactivate(id) {
|
|
17186
|
+
await this.update(id, { isActive: true });
|
|
17187
|
+
}
|
|
17188
|
+
/**
|
|
17189
|
+
* Returns a technology by its ID.
|
|
17190
|
+
* @param id - The ID of the requested technology.
|
|
17191
|
+
* @returns The technology or null if it doesn't exist.
|
|
17192
|
+
*/
|
|
17193
|
+
async getById(id) {
|
|
17194
|
+
const docRef = (0, import_firestore52.doc)(this.technologiesRef, id);
|
|
17195
|
+
const docSnap = await (0, import_firestore52.getDoc)(docRef);
|
|
16437
17196
|
if (!docSnap.exists()) return null;
|
|
16438
17197
|
return {
|
|
16439
17198
|
id: docSnap.id,
|
|
@@ -16447,10 +17206,10 @@ var TechnologyService = class extends BaseService {
|
|
|
16447
17206
|
* @returns Ažurirana tehnologija sa novim zahtevom
|
|
16448
17207
|
*/
|
|
16449
17208
|
async addRequirement(technologyId, requirement) {
|
|
16450
|
-
const docRef = (0,
|
|
17209
|
+
const docRef = (0, import_firestore52.doc)(this.technologiesRef, technologyId);
|
|
16451
17210
|
const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
|
|
16452
|
-
await (0,
|
|
16453
|
-
[requirementType]: (0,
|
|
17211
|
+
await (0, import_firestore52.updateDoc)(docRef, {
|
|
17212
|
+
[requirementType]: (0, import_firestore52.arrayUnion)(requirement),
|
|
16454
17213
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16455
17214
|
});
|
|
16456
17215
|
return this.getById(technologyId);
|
|
@@ -16462,10 +17221,10 @@ var TechnologyService = class extends BaseService {
|
|
|
16462
17221
|
* @returns Ažurirana tehnologija bez uklonjenog zahteva
|
|
16463
17222
|
*/
|
|
16464
17223
|
async removeRequirement(technologyId, requirement) {
|
|
16465
|
-
const docRef = (0,
|
|
17224
|
+
const docRef = (0, import_firestore52.doc)(this.technologiesRef, technologyId);
|
|
16466
17225
|
const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
|
|
16467
|
-
await (0,
|
|
16468
|
-
[requirementType]: (0,
|
|
17226
|
+
await (0, import_firestore52.updateDoc)(docRef, {
|
|
17227
|
+
[requirementType]: (0, import_firestore52.arrayRemove)(requirement),
|
|
16469
17228
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16470
17229
|
});
|
|
16471
17230
|
return this.getById(technologyId);
|
|
@@ -16502,9 +17261,9 @@ var TechnologyService = class extends BaseService {
|
|
|
16502
17261
|
* @returns Ažurirana tehnologija
|
|
16503
17262
|
*/
|
|
16504
17263
|
async addBlockingCondition(technologyId, condition) {
|
|
16505
|
-
const docRef = (0,
|
|
16506
|
-
await (0,
|
|
16507
|
-
blockingConditions: (0,
|
|
17264
|
+
const docRef = (0, import_firestore52.doc)(this.technologiesRef, technologyId);
|
|
17265
|
+
await (0, import_firestore52.updateDoc)(docRef, {
|
|
17266
|
+
blockingConditions: (0, import_firestore52.arrayUnion)(condition),
|
|
16508
17267
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16509
17268
|
});
|
|
16510
17269
|
return this.getById(technologyId);
|
|
@@ -16516,9 +17275,9 @@ var TechnologyService = class extends BaseService {
|
|
|
16516
17275
|
* @returns Ažurirana tehnologija
|
|
16517
17276
|
*/
|
|
16518
17277
|
async removeBlockingCondition(technologyId, condition) {
|
|
16519
|
-
const docRef = (0,
|
|
16520
|
-
await (0,
|
|
16521
|
-
blockingConditions: (0,
|
|
17278
|
+
const docRef = (0, import_firestore52.doc)(this.technologiesRef, technologyId);
|
|
17279
|
+
await (0, import_firestore52.updateDoc)(docRef, {
|
|
17280
|
+
blockingConditions: (0, import_firestore52.arrayRemove)(condition),
|
|
16522
17281
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16523
17282
|
});
|
|
16524
17283
|
return this.getById(technologyId);
|
|
@@ -16530,9 +17289,17 @@ var TechnologyService = class extends BaseService {
|
|
|
16530
17289
|
* @returns Ažurirana tehnologija
|
|
16531
17290
|
*/
|
|
16532
17291
|
async addContraindication(technologyId, contraindication) {
|
|
16533
|
-
const docRef = (0,
|
|
16534
|
-
await (
|
|
16535
|
-
|
|
17292
|
+
const docRef = (0, import_firestore52.doc)(this.technologiesRef, technologyId);
|
|
17293
|
+
const technology = await this.getById(technologyId);
|
|
17294
|
+
if (!technology) {
|
|
17295
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
17296
|
+
}
|
|
17297
|
+
const existingContraindications = technology.contraindications || [];
|
|
17298
|
+
if (existingContraindications.some((c) => c.id === contraindication.id)) {
|
|
17299
|
+
return technology;
|
|
17300
|
+
}
|
|
17301
|
+
await (0, import_firestore52.updateDoc)(docRef, {
|
|
17302
|
+
contraindications: [...existingContraindications, contraindication],
|
|
16536
17303
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16537
17304
|
});
|
|
16538
17305
|
return this.getById(technologyId);
|
|
@@ -16544,9 +17311,45 @@ var TechnologyService = class extends BaseService {
|
|
|
16544
17311
|
* @returns Ažurirana tehnologija
|
|
16545
17312
|
*/
|
|
16546
17313
|
async removeContraindication(technologyId, contraindication) {
|
|
16547
|
-
const docRef = (0,
|
|
16548
|
-
await (
|
|
16549
|
-
|
|
17314
|
+
const docRef = (0, import_firestore52.doc)(this.technologiesRef, technologyId);
|
|
17315
|
+
const technology = await this.getById(technologyId);
|
|
17316
|
+
if (!technology) {
|
|
17317
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
17318
|
+
}
|
|
17319
|
+
const updatedContraindications = (technology.contraindications || []).filter((c) => c.id !== contraindication.id);
|
|
17320
|
+
await (0, import_firestore52.updateDoc)(docRef, {
|
|
17321
|
+
contraindications: updatedContraindications,
|
|
17322
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
17323
|
+
});
|
|
17324
|
+
return this.getById(technologyId);
|
|
17325
|
+
}
|
|
17326
|
+
/**
|
|
17327
|
+
* Updates an existing contraindication in a technology's list.
|
|
17328
|
+
* If the contraindication does not exist, it will not be added.
|
|
17329
|
+
* @param technologyId - ID of the technology
|
|
17330
|
+
* @param contraindication - The updated contraindication object
|
|
17331
|
+
* @returns The updated technology
|
|
17332
|
+
*/
|
|
17333
|
+
async updateContraindication(technologyId, contraindication) {
|
|
17334
|
+
const docRef = (0, import_firestore52.doc)(this.technologiesRef, technologyId);
|
|
17335
|
+
const technology = await this.getById(technologyId);
|
|
17336
|
+
if (!technology) {
|
|
17337
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
17338
|
+
}
|
|
17339
|
+
const contraindications = technology.contraindications || [];
|
|
17340
|
+
const index = contraindications.findIndex(
|
|
17341
|
+
(c) => c.id === contraindication.id
|
|
17342
|
+
);
|
|
17343
|
+
if (index === -1) {
|
|
17344
|
+
console.warn(
|
|
17345
|
+
`Contraindication with id ${contraindication.id} not found for technology ${technologyId}. No update performed.`
|
|
17346
|
+
);
|
|
17347
|
+
return technology;
|
|
17348
|
+
}
|
|
17349
|
+
const updatedContraindications = [...contraindications];
|
|
17350
|
+
updatedContraindications[index] = contraindication;
|
|
17351
|
+
await (0, import_firestore52.updateDoc)(docRef, {
|
|
17352
|
+
contraindications: updatedContraindications,
|
|
16550
17353
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16551
17354
|
});
|
|
16552
17355
|
return this.getById(technologyId);
|
|
@@ -16558,9 +17361,17 @@ var TechnologyService = class extends BaseService {
|
|
|
16558
17361
|
* @returns Ažurirana tehnologija
|
|
16559
17362
|
*/
|
|
16560
17363
|
async addBenefit(technologyId, benefit) {
|
|
16561
|
-
const docRef = (0,
|
|
16562
|
-
await (
|
|
16563
|
-
|
|
17364
|
+
const docRef = (0, import_firestore52.doc)(this.technologiesRef, technologyId);
|
|
17365
|
+
const technology = await this.getById(technologyId);
|
|
17366
|
+
if (!technology) {
|
|
17367
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
17368
|
+
}
|
|
17369
|
+
const existingBenefits = technology.benefits || [];
|
|
17370
|
+
if (existingBenefits.some((b) => b.id === benefit.id)) {
|
|
17371
|
+
return technology;
|
|
17372
|
+
}
|
|
17373
|
+
await (0, import_firestore52.updateDoc)(docRef, {
|
|
17374
|
+
benefits: [...existingBenefits, benefit],
|
|
16564
17375
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16565
17376
|
});
|
|
16566
17377
|
return this.getById(technologyId);
|
|
@@ -16572,9 +17383,45 @@ var TechnologyService = class extends BaseService {
|
|
|
16572
17383
|
* @returns Ažurirana tehnologija
|
|
16573
17384
|
*/
|
|
16574
17385
|
async removeBenefit(technologyId, benefit) {
|
|
16575
|
-
const docRef = (0,
|
|
16576
|
-
await (
|
|
16577
|
-
|
|
17386
|
+
const docRef = (0, import_firestore52.doc)(this.technologiesRef, technologyId);
|
|
17387
|
+
const technology = await this.getById(technologyId);
|
|
17388
|
+
if (!technology) {
|
|
17389
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
17390
|
+
}
|
|
17391
|
+
const updatedBenefits = (technology.benefits || []).filter(
|
|
17392
|
+
(b) => b.id !== benefit.id
|
|
17393
|
+
);
|
|
17394
|
+
await (0, import_firestore52.updateDoc)(docRef, {
|
|
17395
|
+
benefits: updatedBenefits,
|
|
17396
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
17397
|
+
});
|
|
17398
|
+
return this.getById(technologyId);
|
|
17399
|
+
}
|
|
17400
|
+
/**
|
|
17401
|
+
* Updates an existing benefit in a technology's list.
|
|
17402
|
+
* If the benefit does not exist, it will not be added.
|
|
17403
|
+
* @param technologyId - ID of the technology
|
|
17404
|
+
* @param benefit - The updated benefit object
|
|
17405
|
+
* @returns The updated technology
|
|
17406
|
+
*/
|
|
17407
|
+
async updateBenefit(technologyId, benefit) {
|
|
17408
|
+
const docRef = (0, import_firestore52.doc)(this.technologiesRef, technologyId);
|
|
17409
|
+
const technology = await this.getById(technologyId);
|
|
17410
|
+
if (!technology) {
|
|
17411
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
17412
|
+
}
|
|
17413
|
+
const benefits = technology.benefits || [];
|
|
17414
|
+
const index = benefits.findIndex((b) => b.id === benefit.id);
|
|
17415
|
+
if (index === -1) {
|
|
17416
|
+
console.warn(
|
|
17417
|
+
`Benefit with id ${benefit.id} not found for technology ${technologyId}. No update performed.`
|
|
17418
|
+
);
|
|
17419
|
+
return technology;
|
|
17420
|
+
}
|
|
17421
|
+
const updatedBenefits = [...benefits];
|
|
17422
|
+
updatedBenefits[index] = benefit;
|
|
17423
|
+
await (0, import_firestore52.updateDoc)(docRef, {
|
|
17424
|
+
benefits: updatedBenefits,
|
|
16578
17425
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16579
17426
|
});
|
|
16580
17427
|
return this.getById(technologyId);
|
|
@@ -16613,8 +17460,8 @@ var TechnologyService = class extends BaseService {
|
|
|
16613
17460
|
* @returns Ažurirana tehnologija
|
|
16614
17461
|
*/
|
|
16615
17462
|
async updateCertificationRequirement(technologyId, certificationRequirement) {
|
|
16616
|
-
const docRef = (0,
|
|
16617
|
-
await (0,
|
|
17463
|
+
const docRef = (0, import_firestore52.doc)(this.technologiesRef, technologyId);
|
|
17464
|
+
await (0, import_firestore52.updateDoc)(docRef, {
|
|
16618
17465
|
certificationRequirement,
|
|
16619
17466
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16620
17467
|
});
|
|
@@ -16691,7 +17538,7 @@ var TechnologyService = class extends BaseService {
|
|
|
16691
17538
|
*/
|
|
16692
17539
|
async getAllowedTechnologies(practitioner) {
|
|
16693
17540
|
const allTechnologies = await this.getAll();
|
|
16694
|
-
const allowedTechnologies = allTechnologies.filter(
|
|
17541
|
+
const allowedTechnologies = allTechnologies.technologies.filter(
|
|
16695
17542
|
(technology) => this.validateCertification(
|
|
16696
17543
|
technology.certificationRequirement,
|
|
16697
17544
|
practitioner.certification
|
|
@@ -16711,10 +17558,48 @@ var TechnologyService = class extends BaseService {
|
|
|
16711
17558
|
subcategories
|
|
16712
17559
|
};
|
|
16713
17560
|
}
|
|
17561
|
+
/**
|
|
17562
|
+
* Gets all active technologies for a subcategory for filter dropdowns.
|
|
17563
|
+
* @param categoryId - The ID of the parent category.
|
|
17564
|
+
* @param subcategoryId - The ID of the subcategory.
|
|
17565
|
+
*/
|
|
17566
|
+
async getAllForFilterBySubcategoryId(categoryId, subcategoryId) {
|
|
17567
|
+
const q = (0, import_firestore52.query)(
|
|
17568
|
+
(0, import_firestore52.collection)(this.db, TECHNOLOGIES_COLLECTION),
|
|
17569
|
+
(0, import_firestore52.where)("isActive", "==", true),
|
|
17570
|
+
(0, import_firestore52.where)("categoryId", "==", categoryId),
|
|
17571
|
+
(0, import_firestore52.where)("subcategoryId", "==", subcategoryId),
|
|
17572
|
+
(0, import_firestore52.orderBy)("name")
|
|
17573
|
+
);
|
|
17574
|
+
const snapshot = await (0, import_firestore52.getDocs)(q);
|
|
17575
|
+
return snapshot.docs.map(
|
|
17576
|
+
(doc38) => ({
|
|
17577
|
+
id: doc38.id,
|
|
17578
|
+
...doc38.data()
|
|
17579
|
+
})
|
|
17580
|
+
);
|
|
17581
|
+
}
|
|
17582
|
+
/**
|
|
17583
|
+
* Gets all active technologies for filter dropdowns.
|
|
17584
|
+
*/
|
|
17585
|
+
async getAllForFilter() {
|
|
17586
|
+
const q = (0, import_firestore52.query)(
|
|
17587
|
+
(0, import_firestore52.collection)(this.db, TECHNOLOGIES_COLLECTION),
|
|
17588
|
+
(0, import_firestore52.where)("isActive", "==", true),
|
|
17589
|
+
(0, import_firestore52.orderBy)("name")
|
|
17590
|
+
);
|
|
17591
|
+
const snapshot = await (0, import_firestore52.getDocs)(q);
|
|
17592
|
+
return snapshot.docs.map(
|
|
17593
|
+
(doc38) => ({
|
|
17594
|
+
id: doc38.id,
|
|
17595
|
+
...doc38.data()
|
|
17596
|
+
})
|
|
17597
|
+
);
|
|
17598
|
+
}
|
|
16714
17599
|
};
|
|
16715
17600
|
|
|
16716
17601
|
// src/backoffice/services/product.service.ts
|
|
16717
|
-
var
|
|
17602
|
+
var import_firestore53 = require("firebase/firestore");
|
|
16718
17603
|
|
|
16719
17604
|
// src/backoffice/types/product.types.ts
|
|
16720
17605
|
var PRODUCTS_COLLECTION = "products";
|
|
@@ -16727,7 +17612,7 @@ var ProductService = class extends BaseService {
|
|
|
16727
17612
|
* @returns Firestore collection reference
|
|
16728
17613
|
*/
|
|
16729
17614
|
getProductsRef(technologyId) {
|
|
16730
|
-
return (0,
|
|
17615
|
+
return (0, import_firestore53.collection)(
|
|
16731
17616
|
this.db,
|
|
16732
17617
|
TECHNOLOGIES_COLLECTION,
|
|
16733
17618
|
technologyId,
|
|
@@ -16747,47 +17632,129 @@ var ProductService = class extends BaseService {
|
|
|
16747
17632
|
updatedAt: now,
|
|
16748
17633
|
isActive: true
|
|
16749
17634
|
};
|
|
16750
|
-
const productRef = await (0,
|
|
17635
|
+
const productRef = await (0, import_firestore53.addDoc)(
|
|
16751
17636
|
this.getProductsRef(technologyId),
|
|
16752
17637
|
newProduct
|
|
16753
17638
|
);
|
|
16754
17639
|
return { id: productRef.id, ...newProduct };
|
|
16755
17640
|
}
|
|
16756
17641
|
/**
|
|
16757
|
-
* Gets all products
|
|
17642
|
+
* Gets a paginated list of all products, with optional filters.
|
|
17643
|
+
* This uses a collectionGroup query to search across all technologies.
|
|
16758
17644
|
*/
|
|
16759
|
-
async
|
|
16760
|
-
const
|
|
16761
|
-
|
|
16762
|
-
|
|
16763
|
-
|
|
16764
|
-
|
|
16765
|
-
|
|
16766
|
-
|
|
16767
|
-
|
|
16768
|
-
|
|
17645
|
+
async getAll(options) {
|
|
17646
|
+
const {
|
|
17647
|
+
rowsPerPage,
|
|
17648
|
+
lastVisible,
|
|
17649
|
+
categoryId,
|
|
17650
|
+
subcategoryId,
|
|
17651
|
+
technologyId
|
|
17652
|
+
} = options;
|
|
17653
|
+
const constraints = [
|
|
17654
|
+
(0, import_firestore53.where)("isActive", "==", true),
|
|
17655
|
+
(0, import_firestore53.orderBy)("name")
|
|
17656
|
+
];
|
|
17657
|
+
if (categoryId) {
|
|
17658
|
+
constraints.push((0, import_firestore53.where)("categoryId", "==", categoryId));
|
|
17659
|
+
}
|
|
17660
|
+
if (subcategoryId) {
|
|
17661
|
+
constraints.push((0, import_firestore53.where)("subcategoryId", "==", subcategoryId));
|
|
17662
|
+
}
|
|
17663
|
+
if (technologyId) {
|
|
17664
|
+
constraints.push((0, import_firestore53.where)("technologyId", "==", technologyId));
|
|
17665
|
+
}
|
|
17666
|
+
if (lastVisible) {
|
|
17667
|
+
constraints.push((0, import_firestore53.startAfter)(lastVisible));
|
|
17668
|
+
}
|
|
17669
|
+
constraints.push((0, import_firestore53.limit)(rowsPerPage));
|
|
17670
|
+
const q = (0, import_firestore53.query)(
|
|
17671
|
+
(0, import_firestore53.collectionGroup)(this.db, PRODUCTS_COLLECTION),
|
|
17672
|
+
...constraints
|
|
17673
|
+
);
|
|
17674
|
+
const snapshot = await (0, import_firestore53.getDocs)(q);
|
|
17675
|
+
const products = snapshot.docs.map(
|
|
17676
|
+
(doc38) => ({
|
|
17677
|
+
id: doc38.id,
|
|
17678
|
+
...doc38.data()
|
|
16769
17679
|
})
|
|
16770
17680
|
);
|
|
17681
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
17682
|
+
return { products, lastVisible: newLastVisible };
|
|
17683
|
+
}
|
|
17684
|
+
/**
|
|
17685
|
+
* Gets the total count of active products, with optional filters.
|
|
17686
|
+
*/
|
|
17687
|
+
async getProductsCount(options) {
|
|
17688
|
+
const { categoryId, subcategoryId, technologyId } = options;
|
|
17689
|
+
const constraints = [(0, import_firestore53.where)("isActive", "==", true)];
|
|
17690
|
+
if (categoryId) {
|
|
17691
|
+
constraints.push((0, import_firestore53.where)("categoryId", "==", categoryId));
|
|
17692
|
+
}
|
|
17693
|
+
if (subcategoryId) {
|
|
17694
|
+
constraints.push((0, import_firestore53.where)("subcategoryId", "==", subcategoryId));
|
|
17695
|
+
}
|
|
17696
|
+
if (technologyId) {
|
|
17697
|
+
constraints.push((0, import_firestore53.where)("technologyId", "==", technologyId));
|
|
17698
|
+
}
|
|
17699
|
+
const q = (0, import_firestore53.query)(
|
|
17700
|
+
(0, import_firestore53.collectionGroup)(this.db, PRODUCTS_COLLECTION),
|
|
17701
|
+
...constraints
|
|
17702
|
+
);
|
|
17703
|
+
const snapshot = await (0, import_firestore53.getCountFromServer)(q);
|
|
17704
|
+
return snapshot.data().count;
|
|
17705
|
+
}
|
|
17706
|
+
/**
|
|
17707
|
+
* Gets counts of active products grouped by category, subcategory, and technology.
|
|
17708
|
+
* This uses a single collectionGroup query for efficiency.
|
|
17709
|
+
*/
|
|
17710
|
+
async getProductCounts() {
|
|
17711
|
+
const q = (0, import_firestore53.query)(
|
|
17712
|
+
(0, import_firestore53.collectionGroup)(this.db, PRODUCTS_COLLECTION),
|
|
17713
|
+
(0, import_firestore53.where)("isActive", "==", true)
|
|
17714
|
+
);
|
|
17715
|
+
const snapshot = await (0, import_firestore53.getDocs)(q);
|
|
17716
|
+
const counts = {
|
|
17717
|
+
byCategory: {},
|
|
17718
|
+
bySubcategory: {},
|
|
17719
|
+
byTechnology: {}
|
|
17720
|
+
};
|
|
17721
|
+
if (snapshot.empty) {
|
|
17722
|
+
return counts;
|
|
17723
|
+
}
|
|
17724
|
+
snapshot.docs.forEach((doc38) => {
|
|
17725
|
+
const product = doc38.data();
|
|
17726
|
+
const { categoryId, subcategoryId, technologyId } = product;
|
|
17727
|
+
if (categoryId) {
|
|
17728
|
+
counts.byCategory[categoryId] = (counts.byCategory[categoryId] || 0) + 1;
|
|
17729
|
+
}
|
|
17730
|
+
if (subcategoryId) {
|
|
17731
|
+
counts.bySubcategory[subcategoryId] = (counts.bySubcategory[subcategoryId] || 0) + 1;
|
|
17732
|
+
}
|
|
17733
|
+
if (technologyId) {
|
|
17734
|
+
counts.byTechnology[technologyId] = (counts.byTechnology[technologyId] || 0) + 1;
|
|
17735
|
+
}
|
|
17736
|
+
});
|
|
17737
|
+
return counts;
|
|
16771
17738
|
}
|
|
16772
17739
|
/**
|
|
16773
17740
|
* Gets all products for a brand by filtering through all technologies
|
|
16774
17741
|
*/
|
|
16775
17742
|
async getAllByBrand(brandId) {
|
|
16776
|
-
const allTechnologiesRef = (0,
|
|
16777
|
-
const technologiesSnapshot = await (0,
|
|
17743
|
+
const allTechnologiesRef = (0, import_firestore53.collection)(this.db, TECHNOLOGIES_COLLECTION);
|
|
17744
|
+
const technologiesSnapshot = await (0, import_firestore53.getDocs)(allTechnologiesRef);
|
|
16778
17745
|
const products = [];
|
|
16779
17746
|
for (const techDoc of technologiesSnapshot.docs) {
|
|
16780
|
-
const q = (0,
|
|
17747
|
+
const q = (0, import_firestore53.query)(
|
|
16781
17748
|
this.getProductsRef(techDoc.id),
|
|
16782
|
-
(0,
|
|
16783
|
-
(0,
|
|
17749
|
+
(0, import_firestore53.where)("brandId", "==", brandId),
|
|
17750
|
+
(0, import_firestore53.where)("isActive", "==", true)
|
|
16784
17751
|
);
|
|
16785
|
-
const snapshot = await (0,
|
|
17752
|
+
const snapshot = await (0, import_firestore53.getDocs)(q);
|
|
16786
17753
|
products.push(
|
|
16787
17754
|
...snapshot.docs.map(
|
|
16788
|
-
(
|
|
16789
|
-
id:
|
|
16790
|
-
...
|
|
17755
|
+
(doc38) => ({
|
|
17756
|
+
id: doc38.id,
|
|
17757
|
+
...doc38.data()
|
|
16791
17758
|
})
|
|
16792
17759
|
)
|
|
16793
17760
|
);
|
|
@@ -16802,8 +17769,8 @@ var ProductService = class extends BaseService {
|
|
|
16802
17769
|
...product,
|
|
16803
17770
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16804
17771
|
};
|
|
16805
|
-
const docRef = (0,
|
|
16806
|
-
await (0,
|
|
17772
|
+
const docRef = (0, import_firestore53.doc)(this.getProductsRef(technologyId), productId);
|
|
17773
|
+
await (0, import_firestore53.updateDoc)(docRef, updateData);
|
|
16807
17774
|
return this.getById(technologyId, productId);
|
|
16808
17775
|
}
|
|
16809
17776
|
/**
|
|
@@ -16818,8 +17785,8 @@ var ProductService = class extends BaseService {
|
|
|
16818
17785
|
* Gets a product by ID
|
|
16819
17786
|
*/
|
|
16820
17787
|
async getById(technologyId, productId) {
|
|
16821
|
-
const docRef = (0,
|
|
16822
|
-
const docSnap = await (0,
|
|
17788
|
+
const docRef = (0, import_firestore53.doc)(this.getProductsRef(technologyId), productId);
|
|
17789
|
+
const docSnap = await (0, import_firestore53.getDoc)(docRef);
|
|
16823
17790
|
if (!docSnap.exists()) return null;
|
|
16824
17791
|
return {
|
|
16825
17792
|
id: docSnap.id,
|
|
@@ -16828,6 +17795,255 @@ var ProductService = class extends BaseService {
|
|
|
16828
17795
|
}
|
|
16829
17796
|
};
|
|
16830
17797
|
|
|
17798
|
+
// src/backoffice/services/constants.service.ts
|
|
17799
|
+
var import_firestore54 = require("firebase/firestore");
|
|
17800
|
+
var ADMIN_CONSTANTS_COLLECTION = "admin-constants";
|
|
17801
|
+
var TREATMENT_BENEFITS_DOC = "treatment-benefits";
|
|
17802
|
+
var CONTRAINDICATIONS_DOC = "contraindications";
|
|
17803
|
+
var ConstantsService = class extends BaseService {
|
|
17804
|
+
/**
|
|
17805
|
+
* @description Gets the reference to the document holding treatment benefits.
|
|
17806
|
+
* @private
|
|
17807
|
+
* @type {DocumentReference}
|
|
17808
|
+
*/
|
|
17809
|
+
get treatmentBenefitsDocRef() {
|
|
17810
|
+
return (0, import_firestore54.doc)(this.db, ADMIN_CONSTANTS_COLLECTION, TREATMENT_BENEFITS_DOC);
|
|
17811
|
+
}
|
|
17812
|
+
/**
|
|
17813
|
+
* @description Gets the reference to the document holding contraindications.
|
|
17814
|
+
* @private
|
|
17815
|
+
* @type {DocumentReference}
|
|
17816
|
+
*/
|
|
17817
|
+
get contraindicationsDocRef() {
|
|
17818
|
+
return (0, import_firestore54.doc)(this.db, ADMIN_CONSTANTS_COLLECTION, CONTRAINDICATIONS_DOC);
|
|
17819
|
+
}
|
|
17820
|
+
// =================================================================
|
|
17821
|
+
// Treatment Benefits
|
|
17822
|
+
// =================================================================
|
|
17823
|
+
/**
|
|
17824
|
+
* @description Retrieves all treatment benefits without pagination.
|
|
17825
|
+
* @returns {Promise<TreatmentBenefitDynamic[]>} An array of all treatment benefits.
|
|
17826
|
+
*/
|
|
17827
|
+
async getAllBenefitsForFilter() {
|
|
17828
|
+
const docSnap = await (0, import_firestore54.getDoc)(this.treatmentBenefitsDocRef);
|
|
17829
|
+
if (!docSnap.exists()) {
|
|
17830
|
+
return [];
|
|
17831
|
+
}
|
|
17832
|
+
return docSnap.data().benefits;
|
|
17833
|
+
}
|
|
17834
|
+
/**
|
|
17835
|
+
* @description Retrieves a paginated list of treatment benefits.
|
|
17836
|
+
* @param {{ page: number; limit: number }} options - Pagination options.
|
|
17837
|
+
* @returns {Promise<{ benefits: TreatmentBenefitDynamic[]; total: number }>} A paginated list of benefits and the total count.
|
|
17838
|
+
*/
|
|
17839
|
+
async getAllBenefits(options) {
|
|
17840
|
+
const allBenefits = await this.getAllBenefitsForFilter();
|
|
17841
|
+
const { page, limit: limit21 } = options;
|
|
17842
|
+
const startIndex = page * limit21;
|
|
17843
|
+
const endIndex = startIndex + limit21;
|
|
17844
|
+
const paginatedBenefits = allBenefits.slice(startIndex, endIndex);
|
|
17845
|
+
return { benefits: paginatedBenefits, total: allBenefits.length };
|
|
17846
|
+
}
|
|
17847
|
+
/**
|
|
17848
|
+
* @description Adds a new treatment benefit.
|
|
17849
|
+
* @param {Omit<TreatmentBenefitDynamic, "id">} benefit - The treatment benefit to add, without an ID.
|
|
17850
|
+
* @returns {Promise<TreatmentBenefitDynamic>} The newly created treatment benefit with its generated ID.
|
|
17851
|
+
*/
|
|
17852
|
+
async addTreatmentBenefit(benefit) {
|
|
17853
|
+
const newBenefit = {
|
|
17854
|
+
id: this.generateId(),
|
|
17855
|
+
...benefit
|
|
17856
|
+
};
|
|
17857
|
+
const docSnap = await (0, import_firestore54.getDoc)(this.treatmentBenefitsDocRef);
|
|
17858
|
+
if (!docSnap.exists()) {
|
|
17859
|
+
await (0, import_firestore54.setDoc)(this.treatmentBenefitsDocRef, { benefits: [newBenefit] });
|
|
17860
|
+
} else {
|
|
17861
|
+
await (0, import_firestore54.updateDoc)(this.treatmentBenefitsDocRef, {
|
|
17862
|
+
benefits: (0, import_firestore54.arrayUnion)(newBenefit)
|
|
17863
|
+
});
|
|
17864
|
+
}
|
|
17865
|
+
return newBenefit;
|
|
17866
|
+
}
|
|
17867
|
+
/**
|
|
17868
|
+
* @description Retrieves a single treatment benefit by its ID.
|
|
17869
|
+
* @param {string} benefitId - The ID of the treatment benefit to retrieve.
|
|
17870
|
+
* @returns {Promise<TreatmentBenefitDynamic | undefined>} The found treatment benefit or undefined.
|
|
17871
|
+
*/
|
|
17872
|
+
async getBenefitById(benefitId) {
|
|
17873
|
+
const benefits = await this.getAllBenefitsForFilter();
|
|
17874
|
+
return benefits.find((b) => b.id === benefitId);
|
|
17875
|
+
}
|
|
17876
|
+
/**
|
|
17877
|
+
* @description Searches for treatment benefits by name (case-insensitive).
|
|
17878
|
+
* @param {string} searchTerm - The term to search for in the benefit names.
|
|
17879
|
+
* @returns {Promise<TreatmentBenefitDynamic[]>} An array of matching treatment benefits.
|
|
17880
|
+
*/
|
|
17881
|
+
async searchBenefitsByName(searchTerm) {
|
|
17882
|
+
const benefits = await this.getAllBenefitsForFilter();
|
|
17883
|
+
const normalizedSearchTerm = searchTerm.toLowerCase();
|
|
17884
|
+
return benefits.filter(
|
|
17885
|
+
(b) => b.name.toLowerCase().includes(normalizedSearchTerm)
|
|
17886
|
+
);
|
|
17887
|
+
}
|
|
17888
|
+
/**
|
|
17889
|
+
* @description Updates an existing treatment benefit.
|
|
17890
|
+
* @param {TreatmentBenefitDynamic} benefit - The treatment benefit with updated data. Its ID must match an existing benefit.
|
|
17891
|
+
* @returns {Promise<TreatmentBenefitDynamic>} The updated treatment benefit.
|
|
17892
|
+
* @throws {Error} If the treatment benefit is not found.
|
|
17893
|
+
*/
|
|
17894
|
+
async updateTreatmentBenefit(benefit) {
|
|
17895
|
+
const benefits = await this.getAllBenefitsForFilter();
|
|
17896
|
+
const benefitIndex = benefits.findIndex((b) => b.id === benefit.id);
|
|
17897
|
+
if (benefitIndex === -1) {
|
|
17898
|
+
throw new Error("Treatment benefit not found.");
|
|
17899
|
+
}
|
|
17900
|
+
benefits[benefitIndex] = benefit;
|
|
17901
|
+
await (0, import_firestore54.updateDoc)(this.treatmentBenefitsDocRef, { benefits });
|
|
17902
|
+
return benefit;
|
|
17903
|
+
}
|
|
17904
|
+
/**
|
|
17905
|
+
* @description Deletes a treatment benefit by its ID.
|
|
17906
|
+
* @param {string} benefitId - The ID of the treatment benefit to delete.
|
|
17907
|
+
* @returns {Promise<void>}
|
|
17908
|
+
*/
|
|
17909
|
+
async deleteTreatmentBenefit(benefitId) {
|
|
17910
|
+
const benefits = await this.getAllBenefitsForFilter();
|
|
17911
|
+
const benefitToRemove = benefits.find((b) => b.id === benefitId);
|
|
17912
|
+
if (!benefitToRemove) {
|
|
17913
|
+
return;
|
|
17914
|
+
}
|
|
17915
|
+
await (0, import_firestore54.updateDoc)(this.treatmentBenefitsDocRef, {
|
|
17916
|
+
benefits: (0, import_firestore54.arrayRemove)(benefitToRemove)
|
|
17917
|
+
});
|
|
17918
|
+
}
|
|
17919
|
+
// =================================================================
|
|
17920
|
+
// Contraindications
|
|
17921
|
+
// =================================================================
|
|
17922
|
+
/**
|
|
17923
|
+
* @description Retrieves all contraindications without pagination.
|
|
17924
|
+
* @returns {Promise<ContraindicationDynamic[]>} An array of all contraindications.
|
|
17925
|
+
*/
|
|
17926
|
+
async getAllContraindicationsForFilter() {
|
|
17927
|
+
const docSnap = await (0, import_firestore54.getDoc)(this.contraindicationsDocRef);
|
|
17928
|
+
if (!docSnap.exists()) {
|
|
17929
|
+
return [];
|
|
17930
|
+
}
|
|
17931
|
+
return docSnap.data().contraindications;
|
|
17932
|
+
}
|
|
17933
|
+
/**
|
|
17934
|
+
* @description Retrieves a paginated list of contraindications.
|
|
17935
|
+
* @param {{ page: number; limit: number }} options - Pagination options.
|
|
17936
|
+
* @returns {Promise<{ contraindications: ContraindicationDynamic[]; total: number }>} A paginated list and the total count.
|
|
17937
|
+
*/
|
|
17938
|
+
async getAllContraindications(options) {
|
|
17939
|
+
const allContraindications = await this.getAllContraindicationsForFilter();
|
|
17940
|
+
const { page, limit: limit21 } = options;
|
|
17941
|
+
const startIndex = page * limit21;
|
|
17942
|
+
const endIndex = startIndex + limit21;
|
|
17943
|
+
const paginatedContraindications = allContraindications.slice(
|
|
17944
|
+
startIndex,
|
|
17945
|
+
endIndex
|
|
17946
|
+
);
|
|
17947
|
+
return {
|
|
17948
|
+
contraindications: paginatedContraindications,
|
|
17949
|
+
total: allContraindications.length
|
|
17950
|
+
};
|
|
17951
|
+
}
|
|
17952
|
+
/**
|
|
17953
|
+
* @description Adds a new contraindication.
|
|
17954
|
+
* @param {Omit<ContraindicationDynamic, "id">} contraindication - The contraindication to add, without an ID.
|
|
17955
|
+
* @returns {Promise<ContraindicationDynamic>} The newly created contraindication with its generated ID.
|
|
17956
|
+
*/
|
|
17957
|
+
async addContraindication(contraindication) {
|
|
17958
|
+
const newContraindication = {
|
|
17959
|
+
id: this.generateId(),
|
|
17960
|
+
...contraindication
|
|
17961
|
+
};
|
|
17962
|
+
const docSnap = await (0, import_firestore54.getDoc)(this.contraindicationsDocRef);
|
|
17963
|
+
if (!docSnap.exists()) {
|
|
17964
|
+
await (0, import_firestore54.setDoc)(this.contraindicationsDocRef, {
|
|
17965
|
+
contraindications: [newContraindication]
|
|
17966
|
+
});
|
|
17967
|
+
} else {
|
|
17968
|
+
await (0, import_firestore54.updateDoc)(this.contraindicationsDocRef, {
|
|
17969
|
+
contraindications: (0, import_firestore54.arrayUnion)(newContraindication)
|
|
17970
|
+
});
|
|
17971
|
+
}
|
|
17972
|
+
return newContraindication;
|
|
17973
|
+
}
|
|
17974
|
+
/**
|
|
17975
|
+
* @description Retrieves a single contraindication by its ID.
|
|
17976
|
+
* @param {string} contraindicationId - The ID of the contraindication to retrieve.
|
|
17977
|
+
* @returns {Promise<ContraindicationDynamic | undefined>} The found contraindication or undefined.
|
|
17978
|
+
*/
|
|
17979
|
+
async getContraindicationById(contraindicationId) {
|
|
17980
|
+
const contraindications = await this.getAllContraindicationsForFilter();
|
|
17981
|
+
return contraindications.find((c) => c.id === contraindicationId);
|
|
17982
|
+
}
|
|
17983
|
+
/**
|
|
17984
|
+
* @description Searches for contraindications by name (case-insensitive).
|
|
17985
|
+
* @param {string} searchTerm - The term to search for in the contraindication names.
|
|
17986
|
+
* @returns {Promise<ContraindicationDynamic[]>} An array of matching contraindications.
|
|
17987
|
+
*/
|
|
17988
|
+
async searchContraindicationsByName(searchTerm) {
|
|
17989
|
+
const contraindications = await this.getAllContraindicationsForFilter();
|
|
17990
|
+
const normalizedSearchTerm = searchTerm.toLowerCase();
|
|
17991
|
+
return contraindications.filter(
|
|
17992
|
+
(c) => c.name.toLowerCase().includes(normalizedSearchTerm)
|
|
17993
|
+
);
|
|
17994
|
+
}
|
|
17995
|
+
/**
|
|
17996
|
+
* @description Updates an existing contraindication.
|
|
17997
|
+
* @param {ContraindicationDynamic} contraindication - The contraindication with updated data. Its ID must match an existing one.
|
|
17998
|
+
* @returns {Promise<ContraindicationDynamic>} The updated contraindication.
|
|
17999
|
+
* @throws {Error} If the contraindication is not found.
|
|
18000
|
+
*/
|
|
18001
|
+
async updateContraindication(contraindication) {
|
|
18002
|
+
const contraindications = await this.getAllContraindicationsForFilter();
|
|
18003
|
+
const index = contraindications.findIndex(
|
|
18004
|
+
(c) => c.id === contraindication.id
|
|
18005
|
+
);
|
|
18006
|
+
if (index === -1) {
|
|
18007
|
+
throw new Error("Contraindication not found.");
|
|
18008
|
+
}
|
|
18009
|
+
contraindications[index] = contraindication;
|
|
18010
|
+
await (0, import_firestore54.updateDoc)(this.contraindicationsDocRef, { contraindications });
|
|
18011
|
+
return contraindication;
|
|
18012
|
+
}
|
|
18013
|
+
/**
|
|
18014
|
+
* @description Deletes a contraindication by its ID.
|
|
18015
|
+
* @param {string} contraindicationId - The ID of the contraindication to delete.
|
|
18016
|
+
* @returns {Promise<void>}
|
|
18017
|
+
*/
|
|
18018
|
+
async deleteContraindication(contraindicationId) {
|
|
18019
|
+
const contraindications = await this.getAllContraindicationsForFilter();
|
|
18020
|
+
const toRemove = contraindications.find((c) => c.id === contraindicationId);
|
|
18021
|
+
if (!toRemove) {
|
|
18022
|
+
return;
|
|
18023
|
+
}
|
|
18024
|
+
await (0, import_firestore54.updateDoc)(this.contraindicationsDocRef, {
|
|
18025
|
+
contraindications: (0, import_firestore54.arrayRemove)(toRemove)
|
|
18026
|
+
});
|
|
18027
|
+
}
|
|
18028
|
+
};
|
|
18029
|
+
|
|
18030
|
+
// src/backoffice/types/static/contraindication.types.ts
|
|
18031
|
+
var Contraindication = /* @__PURE__ */ ((Contraindication2) => {
|
|
18032
|
+
Contraindication2["SENSITIVE_SKIN"] = "sensitive_skin";
|
|
18033
|
+
Contraindication2["RECENT_TANNING"] = "recent_tanning";
|
|
18034
|
+
Contraindication2["RECENT_BOTOX"] = "recent_botox";
|
|
18035
|
+
Contraindication2["RECENT_FILLERS"] = "recent_fillers";
|
|
18036
|
+
Contraindication2["SKIN_ALLERGIES"] = "skin_allergies";
|
|
18037
|
+
Contraindication2["MEDICATIONS"] = "medications";
|
|
18038
|
+
Contraindication2["RECENT_CHEMICAL_PEEL"] = "recent_chemical_peel";
|
|
18039
|
+
Contraindication2["RECENT_LASER"] = "recent_laser";
|
|
18040
|
+
Contraindication2["SKIN_INFLAMMATION"] = "skin_inflammation";
|
|
18041
|
+
Contraindication2["OPEN_WOUNDS"] = "open_wounds";
|
|
18042
|
+
Contraindication2["HERPES_SIMPLEX"] = "herpes_simplex";
|
|
18043
|
+
Contraindication2["COLD_SORES"] = "cold_sores";
|
|
18044
|
+
return Contraindication2;
|
|
18045
|
+
})(Contraindication || {});
|
|
18046
|
+
|
|
16831
18047
|
// src/backoffice/types/static/treatment-benefit.types.ts
|
|
16832
18048
|
var TreatmentBenefit = /* @__PURE__ */ ((TreatmentBenefit2) => {
|
|
16833
18049
|
TreatmentBenefit2["WRINKLE_REDUCTION"] = "wrinkle_reduction";
|
|
@@ -16887,6 +18103,7 @@ var RequirementType = /* @__PURE__ */ ((RequirementType2) => {
|
|
|
16887
18103
|
ClinicPhotoTag,
|
|
16888
18104
|
ClinicService,
|
|
16889
18105
|
ClinicTag,
|
|
18106
|
+
ConstantsService,
|
|
16890
18107
|
Contraindication,
|
|
16891
18108
|
CosmeticAllergySubtype,
|
|
16892
18109
|
Currency,
|