@blackcode_sa/metaestetics-api 1.11.3 → 1.12.0
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 +329 -318
- package/dist/admin/index.d.ts +329 -318
- package/dist/backoffice/index.d.mts +1166 -430
- package/dist/backoffice/index.d.ts +1166 -430
- package/dist/backoffice/index.js +1128 -245
- package/dist/backoffice/index.mjs +1119 -209
- package/dist/index.d.mts +4428 -4035
- package/dist/index.d.ts +4428 -4035
- package/dist/index.js +1642 -665
- package/dist/index.mjs +1406 -401
- package/package.json +1 -1
- package/src/backoffice/expo-safe/index.ts +3 -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 +1 -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/procedure/procedure.service.ts +436 -234
- 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 +20 -17
- package/src/validations/clinic.schema.ts +1 -6
- package/src/validations/patient/medical-info.schema.ts +7 -2
- 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.mjs
CHANGED
|
@@ -17,11 +17,13 @@ import { getFunctions } from "firebase/functions";
|
|
|
17
17
|
// src/services/base.service.ts
|
|
18
18
|
import { getStorage } from "firebase/storage";
|
|
19
19
|
var BaseService = class {
|
|
20
|
-
constructor(db, auth, app) {
|
|
20
|
+
constructor(db, auth, app, storage) {
|
|
21
21
|
this.db = db;
|
|
22
22
|
this.auth = auth;
|
|
23
23
|
this.app = app;
|
|
24
|
-
|
|
24
|
+
if (app) {
|
|
25
|
+
this.storage = storage || getStorage(app);
|
|
26
|
+
}
|
|
25
27
|
}
|
|
26
28
|
/**
|
|
27
29
|
* Generiše jedinstveni ID za dokumente
|
|
@@ -53,13 +55,13 @@ var AppointmentStatus = /* @__PURE__ */ ((AppointmentStatus2) => {
|
|
|
53
55
|
AppointmentStatus2["RESCHEDULED_BY_CLINIC"] = "rescheduled_by_clinic";
|
|
54
56
|
return AppointmentStatus2;
|
|
55
57
|
})(AppointmentStatus || {});
|
|
56
|
-
var PaymentStatus = /* @__PURE__ */ ((
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return
|
|
58
|
+
var PaymentStatus = /* @__PURE__ */ ((PaymentStatus4) => {
|
|
59
|
+
PaymentStatus4["UNPAID"] = "unpaid";
|
|
60
|
+
PaymentStatus4["PAID"] = "paid";
|
|
61
|
+
PaymentStatus4["PARTIALLY_PAID"] = "partially_paid";
|
|
62
|
+
PaymentStatus4["REFUNDED"] = "refunded";
|
|
63
|
+
PaymentStatus4["NOT_APPLICABLE"] = "not_applicable";
|
|
64
|
+
return PaymentStatus4;
|
|
63
65
|
})(PaymentStatus || {});
|
|
64
66
|
var MediaType = /* @__PURE__ */ ((MediaType2) => {
|
|
65
67
|
MediaType2["BEFORE_PHOTO"] = "before_photo";
|
|
@@ -582,7 +584,6 @@ import {
|
|
|
582
584
|
getDocs,
|
|
583
585
|
query,
|
|
584
586
|
where,
|
|
585
|
-
setDoc,
|
|
586
587
|
updateDoc,
|
|
587
588
|
serverTimestamp,
|
|
588
589
|
Timestamp,
|
|
@@ -819,44 +820,48 @@ async function updateAppointmentUtil(db, appointmentId, data) {
|
|
|
819
820
|
const validPreReqIds = currentAppointment.preProcedureRequirements.map(
|
|
820
821
|
(req) => req.id
|
|
821
822
|
);
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
if (invalidPreReqIds.length > 0) {
|
|
826
|
-
throw new Error(
|
|
827
|
-
`Invalid pre-requirement IDs: ${invalidPreReqIds.join(", ")}`
|
|
823
|
+
if (Array.isArray(data.completedPreRequirements)) {
|
|
824
|
+
const invalidPreReqIds = data.completedPreRequirements.filter(
|
|
825
|
+
(id) => !validPreReqIds.includes(id)
|
|
828
826
|
);
|
|
827
|
+
if (invalidPreReqIds.length > 0) {
|
|
828
|
+
throw new Error(
|
|
829
|
+
`Invalid pre-requirement IDs: ${invalidPreReqIds.join(", ")}`
|
|
830
|
+
);
|
|
831
|
+
}
|
|
832
|
+
completedPreRequirements = [
|
|
833
|
+
.../* @__PURE__ */ new Set([
|
|
834
|
+
...completedPreRequirements,
|
|
835
|
+
...data.completedPreRequirements
|
|
836
|
+
])
|
|
837
|
+
];
|
|
829
838
|
}
|
|
830
|
-
completedPreRequirements = [
|
|
831
|
-
.../* @__PURE__ */ new Set([
|
|
832
|
-
...completedPreRequirements,
|
|
833
|
-
...data.completedPreRequirements
|
|
834
|
-
])
|
|
835
|
-
];
|
|
836
839
|
}
|
|
837
840
|
if (data.completedPostRequirements) {
|
|
838
841
|
const validPostReqIds = currentAppointment.postProcedureRequirements.map(
|
|
839
842
|
(req) => req.id
|
|
840
843
|
);
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
if (invalidPostReqIds.length > 0) {
|
|
845
|
-
throw new Error(
|
|
846
|
-
`Invalid post-requirement IDs: ${invalidPostReqIds.join(", ")}`
|
|
844
|
+
if (Array.isArray(data.completedPostRequirements)) {
|
|
845
|
+
const invalidPostReqIds = data.completedPostRequirements.filter(
|
|
846
|
+
(id) => !validPostReqIds.includes(id)
|
|
847
847
|
);
|
|
848
|
+
if (invalidPostReqIds.length > 0) {
|
|
849
|
+
throw new Error(
|
|
850
|
+
`Invalid post-requirement IDs: ${invalidPostReqIds.join(", ")}`
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
completedPostRequirements = [
|
|
854
|
+
.../* @__PURE__ */ new Set([
|
|
855
|
+
...completedPostRequirements,
|
|
856
|
+
...data.completedPostRequirements
|
|
857
|
+
])
|
|
858
|
+
];
|
|
848
859
|
}
|
|
849
|
-
completedPostRequirements = [
|
|
850
|
-
.../* @__PURE__ */ new Set([
|
|
851
|
-
...completedPostRequirements,
|
|
852
|
-
...data.completedPostRequirements
|
|
853
|
-
])
|
|
854
|
-
];
|
|
855
860
|
}
|
|
856
861
|
const updateData = {
|
|
857
862
|
...data,
|
|
858
|
-
completedPreRequirements,
|
|
859
|
-
completedPostRequirements,
|
|
863
|
+
completedPreRequirements: Array.isArray(data.completedPreRequirements) ? completedPreRequirements : data.completedPreRequirements,
|
|
864
|
+
completedPostRequirements: Array.isArray(data.completedPostRequirements) ? completedPostRequirements : data.completedPostRequirements,
|
|
860
865
|
updatedAt: serverTimestamp()
|
|
861
866
|
};
|
|
862
867
|
Object.keys(updateData).forEach((key) => {
|
|
@@ -906,7 +911,7 @@ async function updateCalendarEventStatus(db, calendarEventId, appointmentStatus)
|
|
|
906
911
|
case "canceled_clinic" /* CANCELED_CLINIC */:
|
|
907
912
|
calendarStatus = "canceled";
|
|
908
913
|
break;
|
|
909
|
-
case
|
|
914
|
+
case "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */:
|
|
910
915
|
calendarStatus = "rescheduled";
|
|
911
916
|
break;
|
|
912
917
|
case "completed" /* COMPLETED */:
|
|
@@ -980,7 +985,7 @@ async function searchAppointmentsUtil(db, params) {
|
|
|
980
985
|
const q = query(collection(db, APPOINTMENTS_COLLECTION), ...constraints);
|
|
981
986
|
const querySnapshot = await getDocs(q);
|
|
982
987
|
const appointments = querySnapshot.docs.map(
|
|
983
|
-
(
|
|
988
|
+
(doc38) => doc38.data()
|
|
984
989
|
);
|
|
985
990
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
986
991
|
return { appointments, lastDoc };
|
|
@@ -1787,7 +1792,7 @@ var AppointmentService = class extends BaseService {
|
|
|
1787
1792
|
);
|
|
1788
1793
|
const querySnapshot = await getDocs2(q);
|
|
1789
1794
|
const appointments = querySnapshot.docs.map(
|
|
1790
|
-
(
|
|
1795
|
+
(doc38) => doc38.data()
|
|
1791
1796
|
);
|
|
1792
1797
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
1793
1798
|
console.log(
|
|
@@ -1860,7 +1865,7 @@ var AppointmentService = class extends BaseService {
|
|
|
1860
1865
|
);
|
|
1861
1866
|
const querySnapshot = await getDocs2(q);
|
|
1862
1867
|
const appointments = querySnapshot.docs.map(
|
|
1863
|
-
(
|
|
1868
|
+
(doc38) => doc38.data()
|
|
1864
1869
|
);
|
|
1865
1870
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
1866
1871
|
console.log(
|
|
@@ -2412,8 +2417,8 @@ var MediaAccessLevel = /* @__PURE__ */ ((MediaAccessLevel2) => {
|
|
|
2412
2417
|
})(MediaAccessLevel || {});
|
|
2413
2418
|
var MEDIA_METADATA_COLLECTION = "media_metadata";
|
|
2414
2419
|
var MediaService = class extends BaseService {
|
|
2415
|
-
constructor(
|
|
2416
|
-
super(
|
|
2420
|
+
constructor(...args) {
|
|
2421
|
+
super(...args);
|
|
2417
2422
|
}
|
|
2418
2423
|
/**
|
|
2419
2424
|
* Upload a media file, store its metadata, and return the metadata including the URL.
|
|
@@ -2673,7 +2678,7 @@ var MediaService = class extends BaseService {
|
|
|
2673
2678
|
try {
|
|
2674
2679
|
const querySnapshot = await getDocs3(finalQuery);
|
|
2675
2680
|
const mediaList = querySnapshot.docs.map(
|
|
2676
|
-
(
|
|
2681
|
+
(doc38) => doc38.data()
|
|
2677
2682
|
);
|
|
2678
2683
|
console.log(`[MediaService] Found ${mediaList.length} media items.`);
|
|
2679
2684
|
return mediaList;
|
|
@@ -2736,8 +2741,8 @@ var getPatientsByClinicUtil = async (db, clinicId, options) => {
|
|
|
2736
2741
|
}
|
|
2737
2742
|
const patientsSnapshot = await getDocs4(q);
|
|
2738
2743
|
const patients = [];
|
|
2739
|
-
patientsSnapshot.forEach((
|
|
2740
|
-
patients.push(
|
|
2744
|
+
patientsSnapshot.forEach((doc38) => {
|
|
2745
|
+
patients.push(doc38.data());
|
|
2741
2746
|
});
|
|
2742
2747
|
console.log(
|
|
2743
2748
|
`[getPatientsByClinicUtil] Found ${patients.length} patients for clinic ID: ${clinicId}`
|
|
@@ -2799,23 +2804,6 @@ var BlockingCondition = /* @__PURE__ */ ((BlockingCondition2) => {
|
|
|
2799
2804
|
return BlockingCondition2;
|
|
2800
2805
|
})(BlockingCondition || {});
|
|
2801
2806
|
|
|
2802
|
-
// src/backoffice/types/static/contraindication.types.ts
|
|
2803
|
-
var Contraindication = /* @__PURE__ */ ((Contraindication2) => {
|
|
2804
|
-
Contraindication2["SENSITIVE_SKIN"] = "sensitive_skin";
|
|
2805
|
-
Contraindication2["RECENT_TANNING"] = "recent_tanning";
|
|
2806
|
-
Contraindication2["RECENT_BOTOX"] = "recent_botox";
|
|
2807
|
-
Contraindication2["RECENT_FILLERS"] = "recent_fillers";
|
|
2808
|
-
Contraindication2["SKIN_ALLERGIES"] = "skin_allergies";
|
|
2809
|
-
Contraindication2["MEDICATIONS"] = "medications";
|
|
2810
|
-
Contraindication2["RECENT_CHEMICAL_PEEL"] = "recent_chemical_peel";
|
|
2811
|
-
Contraindication2["RECENT_LASER"] = "recent_laser";
|
|
2812
|
-
Contraindication2["SKIN_INFLAMMATION"] = "skin_inflammation";
|
|
2813
|
-
Contraindication2["OPEN_WOUNDS"] = "open_wounds";
|
|
2814
|
-
Contraindication2["HERPES_SIMPLEX"] = "herpes_simplex";
|
|
2815
|
-
Contraindication2["COLD_SORES"] = "cold_sores";
|
|
2816
|
-
return Contraindication2;
|
|
2817
|
-
})(Contraindication || {});
|
|
2818
|
-
|
|
2819
2807
|
// src/validations/common.schema.ts
|
|
2820
2808
|
import { z as z5 } from "zod";
|
|
2821
2809
|
import { Timestamp as Timestamp4 } from "firebase/firestore";
|
|
@@ -2870,8 +2858,13 @@ var blockingConditionSchema = z6.object({
|
|
|
2870
2858
|
notes: z6.string().optional().nullable(),
|
|
2871
2859
|
isActive: z6.boolean()
|
|
2872
2860
|
});
|
|
2861
|
+
var contraindicationDynamicSchema = z6.object({
|
|
2862
|
+
id: z6.string(),
|
|
2863
|
+
name: z6.string(),
|
|
2864
|
+
description: z6.string().optional()
|
|
2865
|
+
});
|
|
2873
2866
|
var contraindicationSchema = z6.object({
|
|
2874
|
-
condition:
|
|
2867
|
+
condition: contraindicationDynamicSchema,
|
|
2875
2868
|
lastOccurrence: timestampSchema,
|
|
2876
2869
|
frequency: z6.enum(["rare", "occasional", "frequent"]),
|
|
2877
2870
|
notes: z6.string().optional().nullable(),
|
|
@@ -3111,8 +3104,8 @@ var getPatientsByPractitionerUtil = async (db, practitionerId, options) => {
|
|
|
3111
3104
|
}
|
|
3112
3105
|
const patientsSnapshot = await getDocs5(q);
|
|
3113
3106
|
const patients = [];
|
|
3114
|
-
patientsSnapshot.forEach((
|
|
3115
|
-
patients.push(
|
|
3107
|
+
patientsSnapshot.forEach((doc38) => {
|
|
3108
|
+
patients.push(doc38.data());
|
|
3116
3109
|
});
|
|
3117
3110
|
console.log(
|
|
3118
3111
|
`[getPatientsByPractitionerUtil] Found ${patients.length} patients for practitioner ID: ${practitionerId}`
|
|
@@ -3891,7 +3884,7 @@ async function getClinicAdminsByGroup(db, clinicGroupId) {
|
|
|
3891
3884
|
where6("clinicGroupId", "==", clinicGroupId)
|
|
3892
3885
|
);
|
|
3893
3886
|
const querySnapshot = await getDocs6(q);
|
|
3894
|
-
return querySnapshot.docs.map((
|
|
3887
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
3895
3888
|
}
|
|
3896
3889
|
async function updateClinicAdmin(db, adminId, data) {
|
|
3897
3890
|
const admin = await getClinicAdmin(db, adminId);
|
|
@@ -4572,9 +4565,9 @@ var updateAllergyUtil = async (db, patientId, data, requesterId, requesterRoles)
|
|
|
4572
4565
|
};
|
|
4573
4566
|
var removeAllergyUtil = async (db, patientId, allergyIndex, requesterId, requesterRoles) => {
|
|
4574
4567
|
await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
|
|
4575
|
-
const
|
|
4576
|
-
if (!
|
|
4577
|
-
const medicalInfo =
|
|
4568
|
+
const doc38 = await getDoc10(getMedicalInfoDocRef(db, patientId));
|
|
4569
|
+
if (!doc38.exists()) throw new Error("Medical info not found");
|
|
4570
|
+
const medicalInfo = doc38.data();
|
|
4578
4571
|
if (allergyIndex >= medicalInfo.allergies.length) {
|
|
4579
4572
|
throw new Error("Invalid allergy index");
|
|
4580
4573
|
}
|
|
@@ -4601,9 +4594,9 @@ var updateBlockingConditionUtil = async (db, patientId, data, requesterId, reque
|
|
|
4601
4594
|
await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
|
|
4602
4595
|
const validatedData = updateBlockingConditionSchema.parse(data);
|
|
4603
4596
|
const { conditionIndex, ...updateData } = validatedData;
|
|
4604
|
-
const
|
|
4605
|
-
if (!
|
|
4606
|
-
const medicalInfo =
|
|
4597
|
+
const doc38 = await getDoc10(getMedicalInfoDocRef(db, patientId));
|
|
4598
|
+
if (!doc38.exists()) throw new Error("Medical info not found");
|
|
4599
|
+
const medicalInfo = doc38.data();
|
|
4607
4600
|
if (conditionIndex >= medicalInfo.blockingConditions.length) {
|
|
4608
4601
|
throw new Error("Invalid blocking condition index");
|
|
4609
4602
|
}
|
|
@@ -4620,9 +4613,9 @@ var updateBlockingConditionUtil = async (db, patientId, data, requesterId, reque
|
|
|
4620
4613
|
};
|
|
4621
4614
|
var removeBlockingConditionUtil = async (db, patientId, conditionIndex, requesterId, requesterRoles) => {
|
|
4622
4615
|
await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
|
|
4623
|
-
const
|
|
4624
|
-
if (!
|
|
4625
|
-
const medicalInfo =
|
|
4616
|
+
const doc38 = await getDoc10(getMedicalInfoDocRef(db, patientId));
|
|
4617
|
+
if (!doc38.exists()) throw new Error("Medical info not found");
|
|
4618
|
+
const medicalInfo = doc38.data();
|
|
4626
4619
|
if (conditionIndex >= medicalInfo.blockingConditions.length) {
|
|
4627
4620
|
throw new Error("Invalid blocking condition index");
|
|
4628
4621
|
}
|
|
@@ -4649,9 +4642,9 @@ var updateContraindicationUtil = async (db, patientId, data, requesterId, reques
|
|
|
4649
4642
|
await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
|
|
4650
4643
|
const validatedData = updateContraindicationSchema.parse(data);
|
|
4651
4644
|
const { contraindicationIndex, ...updateData } = validatedData;
|
|
4652
|
-
const
|
|
4653
|
-
if (!
|
|
4654
|
-
const medicalInfo =
|
|
4645
|
+
const doc38 = await getDoc10(getMedicalInfoDocRef(db, patientId));
|
|
4646
|
+
if (!doc38.exists()) throw new Error("Medical info not found");
|
|
4647
|
+
const medicalInfo = doc38.data();
|
|
4655
4648
|
if (contraindicationIndex >= medicalInfo.contraindications.length) {
|
|
4656
4649
|
throw new Error("Invalid contraindication index");
|
|
4657
4650
|
}
|
|
@@ -4668,9 +4661,9 @@ var updateContraindicationUtil = async (db, patientId, data, requesterId, reques
|
|
|
4668
4661
|
};
|
|
4669
4662
|
var removeContraindicationUtil = async (db, patientId, contraindicationIndex, requesterId, requesterRoles) => {
|
|
4670
4663
|
await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
|
|
4671
|
-
const
|
|
4672
|
-
if (!
|
|
4673
|
-
const medicalInfo =
|
|
4664
|
+
const doc38 = await getDoc10(getMedicalInfoDocRef(db, patientId));
|
|
4665
|
+
if (!doc38.exists()) throw new Error("Medical info not found");
|
|
4666
|
+
const medicalInfo = doc38.data();
|
|
4674
4667
|
if (contraindicationIndex >= medicalInfo.contraindications.length) {
|
|
4675
4668
|
throw new Error("Invalid contraindication index");
|
|
4676
4669
|
}
|
|
@@ -4697,9 +4690,9 @@ var updateMedicationUtil = async (db, patientId, data, requesterId, requesterRol
|
|
|
4697
4690
|
await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
|
|
4698
4691
|
const validatedData = updateMedicationSchema.parse(data);
|
|
4699
4692
|
const { medicationIndex, ...updateData } = validatedData;
|
|
4700
|
-
const
|
|
4701
|
-
if (!
|
|
4702
|
-
const medicalInfo =
|
|
4693
|
+
const doc38 = await getDoc10(getMedicalInfoDocRef(db, patientId));
|
|
4694
|
+
if (!doc38.exists()) throw new Error("Medical info not found");
|
|
4695
|
+
const medicalInfo = doc38.data();
|
|
4703
4696
|
if (medicationIndex >= medicalInfo.currentMedications.length) {
|
|
4704
4697
|
throw new Error("Invalid medication index");
|
|
4705
4698
|
}
|
|
@@ -4716,9 +4709,9 @@ var updateMedicationUtil = async (db, patientId, data, requesterId, requesterRol
|
|
|
4716
4709
|
};
|
|
4717
4710
|
var removeMedicationUtil = async (db, patientId, medicationIndex, requesterId, requesterRoles) => {
|
|
4718
4711
|
await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
|
|
4719
|
-
const
|
|
4720
|
-
if (!
|
|
4721
|
-
const medicalInfo =
|
|
4712
|
+
const doc38 = await getDoc10(getMedicalInfoDocRef(db, patientId));
|
|
4713
|
+
if (!doc38.exists()) throw new Error("Medical info not found");
|
|
4714
|
+
const medicalInfo = doc38.data();
|
|
4722
4715
|
if (medicationIndex >= medicalInfo.currentMedications.length) {
|
|
4723
4716
|
throw new Error("Invalid medication index");
|
|
4724
4717
|
}
|
|
@@ -5021,7 +5014,7 @@ var searchPatientsUtil = async (db, params, requester) => {
|
|
|
5021
5014
|
const finalQuery = query8(patientsCollectionRef, ...constraints);
|
|
5022
5015
|
const querySnapshot = await getDocs8(finalQuery);
|
|
5023
5016
|
const patients = querySnapshot.docs.map(
|
|
5024
|
-
(
|
|
5017
|
+
(doc38) => doc38.data()
|
|
5025
5018
|
);
|
|
5026
5019
|
console.log(
|
|
5027
5020
|
`[searchPatientsUtil] Found ${patients.length} patients matching criteria.`
|
|
@@ -5053,8 +5046,8 @@ var getAllPatientsUtil = async (db, options) => {
|
|
|
5053
5046
|
}
|
|
5054
5047
|
const patientsSnapshot = await getDocs8(q);
|
|
5055
5048
|
const patients = [];
|
|
5056
|
-
patientsSnapshot.forEach((
|
|
5057
|
-
patients.push(
|
|
5049
|
+
patientsSnapshot.forEach((doc38) => {
|
|
5050
|
+
patients.push(doc38.data());
|
|
5058
5051
|
});
|
|
5059
5052
|
console.log(`[getAllPatientsUtil] Found ${patients.length} patients`);
|
|
5060
5053
|
return patients;
|
|
@@ -5187,7 +5180,7 @@ var getActiveInviteTokensByClinicUtil = async (db, clinicId) => {
|
|
|
5187
5180
|
if (querySnapshot.empty) {
|
|
5188
5181
|
return [];
|
|
5189
5182
|
}
|
|
5190
|
-
return querySnapshot.docs.map((
|
|
5183
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
5191
5184
|
};
|
|
5192
5185
|
var getActiveInviteTokensByPatientUtil = async (db, patientId) => {
|
|
5193
5186
|
const tokensRef = collection9(
|
|
@@ -5205,7 +5198,7 @@ var getActiveInviteTokensByPatientUtil = async (db, patientId) => {
|
|
|
5205
5198
|
if (querySnapshot.empty) {
|
|
5206
5199
|
return [];
|
|
5207
5200
|
}
|
|
5208
|
-
return querySnapshot.docs.map((
|
|
5201
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
5209
5202
|
};
|
|
5210
5203
|
|
|
5211
5204
|
// src/services/patient/patient.service.ts
|
|
@@ -6494,7 +6487,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6494
6487
|
where10("expiresAt", ">", Timestamp14.now())
|
|
6495
6488
|
);
|
|
6496
6489
|
const querySnapshot = await getDocs10(q);
|
|
6497
|
-
return querySnapshot.docs.map((
|
|
6490
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
6498
6491
|
}
|
|
6499
6492
|
/**
|
|
6500
6493
|
* Gets a token by its string value and validates it
|
|
@@ -6604,7 +6597,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6604
6597
|
where10("status", "==", "active" /* ACTIVE */)
|
|
6605
6598
|
);
|
|
6606
6599
|
const querySnapshot = await getDocs10(q);
|
|
6607
|
-
return querySnapshot.docs.map((
|
|
6600
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
6608
6601
|
}
|
|
6609
6602
|
/**
|
|
6610
6603
|
* Dohvata sve zdravstvene radnike za određenu kliniku
|
|
@@ -6616,7 +6609,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6616
6609
|
where10("isActive", "==", true)
|
|
6617
6610
|
);
|
|
6618
6611
|
const querySnapshot = await getDocs10(q);
|
|
6619
|
-
return querySnapshot.docs.map((
|
|
6612
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
6620
6613
|
}
|
|
6621
6614
|
/**
|
|
6622
6615
|
* Dohvata sve draft zdravstvene radnike za određenu kliniku sa statusom DRAFT
|
|
@@ -6628,7 +6621,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6628
6621
|
where10("status", "==", "draft" /* DRAFT */)
|
|
6629
6622
|
);
|
|
6630
6623
|
const querySnapshot = await getDocs10(q);
|
|
6631
|
-
return querySnapshot.docs.map((
|
|
6624
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
6632
6625
|
}
|
|
6633
6626
|
/**
|
|
6634
6627
|
* Updates a practitioner
|
|
@@ -6843,7 +6836,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6843
6836
|
);
|
|
6844
6837
|
const querySnapshot = await getDocs10(q);
|
|
6845
6838
|
const practitioners = querySnapshot.docs.map(
|
|
6846
|
-
(
|
|
6839
|
+
(doc38) => doc38.data()
|
|
6847
6840
|
);
|
|
6848
6841
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
6849
6842
|
return {
|
|
@@ -6917,7 +6910,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6917
6910
|
constraints.push(limit7(filters.pagination || 10));
|
|
6918
6911
|
const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
|
|
6919
6912
|
const querySnapshot = await getDocs10(q);
|
|
6920
|
-
const practitioners = querySnapshot.docs.map((
|
|
6913
|
+
const practitioners = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
|
|
6921
6914
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
6922
6915
|
console.log(`[PRACTITIONER_SERVICE] Strategy 1 success: ${practitioners.length} practitioners`);
|
|
6923
6916
|
if (practitioners.length < (filters.pagination || 10)) {
|
|
@@ -6964,7 +6957,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6964
6957
|
}
|
|
6965
6958
|
const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
|
|
6966
6959
|
const querySnapshot = await getDocs10(q);
|
|
6967
|
-
let practitioners = querySnapshot.docs.map((
|
|
6960
|
+
let practitioners = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
|
|
6968
6961
|
if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
|
|
6969
6962
|
const location = filters.location;
|
|
6970
6963
|
const radiusInKm = filters.radiusInKm;
|
|
@@ -7000,7 +6993,7 @@ var PractitionerService = class extends BaseService {
|
|
|
7000
6993
|
];
|
|
7001
6994
|
const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
|
|
7002
6995
|
const querySnapshot = await getDocs10(q);
|
|
7003
|
-
let practitioners = querySnapshot.docs.map((
|
|
6996
|
+
let practitioners = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
|
|
7004
6997
|
practitioners = this.applyInMemoryFilters(practitioners, filters);
|
|
7005
6998
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
7006
6999
|
console.log(`[PRACTITIONER_SERVICE] Strategy 3 success: ${practitioners.length} practitioners`);
|
|
@@ -7021,7 +7014,7 @@ var PractitionerService = class extends BaseService {
|
|
|
7021
7014
|
];
|
|
7022
7015
|
const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
|
|
7023
7016
|
const querySnapshot = await getDocs10(q);
|
|
7024
|
-
let practitioners = querySnapshot.docs.map((
|
|
7017
|
+
let practitioners = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
|
|
7025
7018
|
practitioners = this.applyInMemoryFilters(practitioners, filters);
|
|
7026
7019
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
7027
7020
|
console.log(`[PRACTITIONER_SERVICE] Strategy 4 success: ${practitioners.length} practitioners`);
|
|
@@ -7536,7 +7529,7 @@ var UserService = class extends BaseService {
|
|
|
7536
7529
|
];
|
|
7537
7530
|
const q = query11(collection11(this.db, USERS_COLLECTION), ...constraints);
|
|
7538
7531
|
const querySnapshot = await getDocs11(q);
|
|
7539
|
-
const users = querySnapshot.docs.map((
|
|
7532
|
+
const users = querySnapshot.docs.map((doc38) => doc38.data());
|
|
7540
7533
|
return users.map((userData) => userSchema.parse(userData));
|
|
7541
7534
|
}
|
|
7542
7535
|
/**
|
|
@@ -7916,7 +7909,7 @@ async function getAllActiveGroups(db) {
|
|
|
7916
7909
|
where12("isActive", "==", true)
|
|
7917
7910
|
);
|
|
7918
7911
|
const querySnapshot = await getDocs12(q);
|
|
7919
|
-
return querySnapshot.docs.map((
|
|
7912
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
7920
7913
|
}
|
|
7921
7914
|
async function updateClinicGroup(db, groupId, data, app) {
|
|
7922
7915
|
console.log("[CLINIC_GROUP] Updating clinic group", { groupId });
|
|
@@ -8384,7 +8377,7 @@ async function getClinicsByGroup(db, groupId) {
|
|
|
8384
8377
|
where13("isActive", "==", true)
|
|
8385
8378
|
);
|
|
8386
8379
|
const querySnapshot = await getDocs13(q);
|
|
8387
|
-
return querySnapshot.docs.map((
|
|
8380
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
8388
8381
|
}
|
|
8389
8382
|
async function updateClinic(db, clinicId, data, adminId, clinicAdminService, app) {
|
|
8390
8383
|
console.log("[CLINIC] Starting clinic update", { clinicId, adminId });
|
|
@@ -8578,7 +8571,7 @@ async function getClinicsByAdmin(db, adminId, options = {}, clinicAdminService,
|
|
|
8578
8571
|
}
|
|
8579
8572
|
const q = query13(collection13(db, CLINICS_COLLECTION), ...constraints);
|
|
8580
8573
|
const querySnapshot = await getDocs13(q);
|
|
8581
|
-
return querySnapshot.docs.map((
|
|
8574
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
8582
8575
|
}
|
|
8583
8576
|
async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGroupService) {
|
|
8584
8577
|
return getClinicsByAdmin(
|
|
@@ -8623,11 +8616,11 @@ async function getAllClinics(db, pagination, lastDoc) {
|
|
|
8623
8616
|
}
|
|
8624
8617
|
const clinicsSnapshot = await getDocs13(clinicsQuery);
|
|
8625
8618
|
const lastVisible = clinicsSnapshot.docs[clinicsSnapshot.docs.length - 1];
|
|
8626
|
-
const clinics = clinicsSnapshot.docs.map((
|
|
8627
|
-
const data =
|
|
8619
|
+
const clinics = clinicsSnapshot.docs.map((doc38) => {
|
|
8620
|
+
const data = doc38.data();
|
|
8628
8621
|
return {
|
|
8629
8622
|
...data,
|
|
8630
|
-
id:
|
|
8623
|
+
id: doc38.id
|
|
8631
8624
|
};
|
|
8632
8625
|
});
|
|
8633
8626
|
return {
|
|
@@ -8654,8 +8647,8 @@ async function getAllClinicsInRange(db, center, rangeInKm, pagination, lastDoc)
|
|
|
8654
8647
|
];
|
|
8655
8648
|
const q = query13(collection13(db, CLINICS_COLLECTION), ...constraints);
|
|
8656
8649
|
const querySnapshot = await getDocs13(q);
|
|
8657
|
-
for (const
|
|
8658
|
-
const clinic =
|
|
8650
|
+
for (const doc38 of querySnapshot.docs) {
|
|
8651
|
+
const clinic = doc38.data();
|
|
8659
8652
|
const distance = distanceBetween2(
|
|
8660
8653
|
[center.latitude, center.longitude],
|
|
8661
8654
|
[clinic.location.latitude, clinic.location.longitude]
|
|
@@ -8777,8 +8770,8 @@ async function findClinicsInRadius(db, center, radiusInKm, filters) {
|
|
|
8777
8770
|
}
|
|
8778
8771
|
const q = query14(collection14(db, CLINICS_COLLECTION), ...constraints);
|
|
8779
8772
|
const querySnapshot = await getDocs14(q);
|
|
8780
|
-
for (const
|
|
8781
|
-
const clinic =
|
|
8773
|
+
for (const doc38 of querySnapshot.docs) {
|
|
8774
|
+
const clinic = doc38.data();
|
|
8782
8775
|
const distance = distanceBetween3(
|
|
8783
8776
|
[center.latitude, center.longitude],
|
|
8784
8777
|
[clinic.location.latitude, clinic.location.longitude]
|
|
@@ -8907,7 +8900,7 @@ async function getClinicsByFilters(db, filters) {
|
|
|
8907
8900
|
constraints.push(limit9(filters.pagination || 5));
|
|
8908
8901
|
const q = query15(collection15(db, CLINICS_COLLECTION), ...constraints);
|
|
8909
8902
|
const querySnapshot = await getDocs15(q);
|
|
8910
|
-
let clinics = querySnapshot.docs.map((
|
|
8903
|
+
let clinics = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
|
|
8911
8904
|
clinics = applyInMemoryFilters(clinics, filters);
|
|
8912
8905
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
8913
8906
|
console.log(`[CLINIC_SERVICE] Strategy 1 success: ${clinics.length} clinics`);
|
|
@@ -8939,7 +8932,7 @@ async function getClinicsByFilters(db, filters) {
|
|
|
8939
8932
|
constraints.push(limit9(filters.pagination || 5));
|
|
8940
8933
|
const q = query15(collection15(db, CLINICS_COLLECTION), ...constraints);
|
|
8941
8934
|
const querySnapshot = await getDocs15(q);
|
|
8942
|
-
let clinics = querySnapshot.docs.map((
|
|
8935
|
+
let clinics = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
|
|
8943
8936
|
clinics = applyInMemoryFilters(clinics, filters);
|
|
8944
8937
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
8945
8938
|
console.log(`[CLINIC_SERVICE] Strategy 2 success: ${clinics.length} clinics`);
|
|
@@ -8969,7 +8962,7 @@ async function getClinicsByFilters(db, filters) {
|
|
|
8969
8962
|
constraints.push(limit9(filters.pagination || 5));
|
|
8970
8963
|
const q = query15(collection15(db, CLINICS_COLLECTION), ...constraints);
|
|
8971
8964
|
const querySnapshot = await getDocs15(q);
|
|
8972
|
-
let clinics = querySnapshot.docs.map((
|
|
8965
|
+
let clinics = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
|
|
8973
8966
|
clinics = applyInMemoryFilters(clinics, filters);
|
|
8974
8967
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
8975
8968
|
console.log(`[CLINIC_SERVICE] Strategy 3 success: ${clinics.length} clinics`);
|
|
@@ -8989,7 +8982,7 @@ async function getClinicsByFilters(db, filters) {
|
|
|
8989
8982
|
];
|
|
8990
8983
|
const q = query15(collection15(db, CLINICS_COLLECTION), ...constraints);
|
|
8991
8984
|
const querySnapshot = await getDocs15(q);
|
|
8992
|
-
let clinics = querySnapshot.docs.map((
|
|
8985
|
+
let clinics = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
|
|
8993
8986
|
clinics = applyInMemoryFilters(clinics, filters);
|
|
8994
8987
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
8995
8988
|
console.log(`[CLINIC_SERVICE] Strategy 4 success: ${clinics.length} clinics`);
|
|
@@ -9565,11 +9558,11 @@ var ClinicService = class extends BaseService {
|
|
|
9565
9558
|
async getClinicsForMap() {
|
|
9566
9559
|
const clinicsRef = collection16(this.db, CLINICS_COLLECTION);
|
|
9567
9560
|
const snapshot = await getDocs16(clinicsRef);
|
|
9568
|
-
const clinicsForMap = snapshot.docs.map((
|
|
9561
|
+
const clinicsForMap = snapshot.docs.map((doc38) => {
|
|
9569
9562
|
var _a, _b, _c;
|
|
9570
|
-
const data =
|
|
9563
|
+
const data = doc38.data();
|
|
9571
9564
|
return {
|
|
9572
|
-
id:
|
|
9565
|
+
id: doc38.id,
|
|
9573
9566
|
name: data.name,
|
|
9574
9567
|
address: ((_a = data.location) == null ? void 0 : _a.address) || "",
|
|
9575
9568
|
latitude: (_b = data.location) == null ? void 0 : _b.latitude,
|
|
@@ -10776,7 +10769,7 @@ async function updatePractitionerCalendarEventUtil(db, practitionerId, eventId,
|
|
|
10776
10769
|
}
|
|
10777
10770
|
|
|
10778
10771
|
// src/services/calendar/utils/appointment.utils.ts
|
|
10779
|
-
async function
|
|
10772
|
+
async function createAppointmentUtil(db, clinicId, practitionerId, patientId, eventData, generateId2) {
|
|
10780
10773
|
const eventId = generateId2();
|
|
10781
10774
|
const autoConfirm = await checkAutoConfirmAppointmentsUtil(db, clinicId);
|
|
10782
10775
|
const initialStatus = autoConfirm ? "confirmed" /* CONFIRMED */ : "pending" /* PENDING */;
|
|
@@ -10923,7 +10916,7 @@ async function searchCalendarEventsUtil(db, params) {
|
|
|
10923
10916
|
const finalQuery = query21(collectionRef, ...constraints);
|
|
10924
10917
|
const querySnapshot = await getDocs21(finalQuery);
|
|
10925
10918
|
const events = querySnapshot.docs.map(
|
|
10926
|
-
(
|
|
10919
|
+
(doc38) => ({ id: doc38.id, ...doc38.data() })
|
|
10927
10920
|
);
|
|
10928
10921
|
return events;
|
|
10929
10922
|
} catch (error) {
|
|
@@ -11016,7 +11009,7 @@ async function getPractitionerSyncedCalendarsUtil(db, practitionerId) {
|
|
|
11016
11009
|
);
|
|
11017
11010
|
const q = query22(calendarsRef, orderBy11("createdAt", "desc"));
|
|
11018
11011
|
const querySnapshot = await getDocs22(q);
|
|
11019
|
-
return querySnapshot.docs.map((
|
|
11012
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
11020
11013
|
}
|
|
11021
11014
|
async function getPatientSyncedCalendarUtil(db, patientId, calendarId) {
|
|
11022
11015
|
const calendarRef = getPatientSyncedCalendarDocRef(db, patientId, calendarId);
|
|
@@ -11033,7 +11026,7 @@ async function getPatientSyncedCalendarsUtil(db, patientId) {
|
|
|
11033
11026
|
);
|
|
11034
11027
|
const q = query22(calendarsRef, orderBy11("createdAt", "desc"));
|
|
11035
11028
|
const querySnapshot = await getDocs22(q);
|
|
11036
|
-
return querySnapshot.docs.map((
|
|
11029
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
11037
11030
|
}
|
|
11038
11031
|
async function getClinicSyncedCalendarUtil(db, clinicId, calendarId) {
|
|
11039
11032
|
const calendarRef = getClinicSyncedCalendarDocRef(db, clinicId, calendarId);
|
|
@@ -11050,7 +11043,7 @@ async function getClinicSyncedCalendarsUtil(db, clinicId) {
|
|
|
11050
11043
|
);
|
|
11051
11044
|
const q = query22(calendarsRef, orderBy11("createdAt", "desc"));
|
|
11052
11045
|
const querySnapshot = await getDocs22(q);
|
|
11053
|
-
return querySnapshot.docs.map((
|
|
11046
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
11054
11047
|
}
|
|
11055
11048
|
async function updatePractitionerSyncedCalendarUtil(db, practitionerId, calendarId, updateData) {
|
|
11056
11049
|
const calendarRef = getPractitionerSyncedCalendarDocRef(
|
|
@@ -12118,7 +12111,7 @@ var CalendarServiceV2 = class extends BaseService {
|
|
|
12118
12111
|
syncStatus: "internal" /* INTERNAL */,
|
|
12119
12112
|
eventType: "appointment" /* APPOINTMENT */
|
|
12120
12113
|
};
|
|
12121
|
-
const appointment = await
|
|
12114
|
+
const appointment = await createAppointmentUtil(
|
|
12122
12115
|
this.db,
|
|
12123
12116
|
params.clinicId,
|
|
12124
12117
|
params.doctorId,
|
|
@@ -12405,9 +12398,9 @@ var CalendarServiceV2 = class extends BaseService {
|
|
|
12405
12398
|
where23("eventTime.start", "<=", Timestamp26.fromDate(endDate))
|
|
12406
12399
|
);
|
|
12407
12400
|
const eventsSnapshot = await getDocs23(q);
|
|
12408
|
-
const events = eventsSnapshot.docs.map((
|
|
12409
|
-
id:
|
|
12410
|
-
...
|
|
12401
|
+
const events = eventsSnapshot.docs.map((doc38) => ({
|
|
12402
|
+
id: doc38.id,
|
|
12403
|
+
...doc38.data()
|
|
12411
12404
|
}));
|
|
12412
12405
|
const calendars = await this.syncedCalendarsService.getPractitionerSyncedCalendars(
|
|
12413
12406
|
doctorId
|
|
@@ -13041,7 +13034,7 @@ var CalendarServiceV2 = class extends BaseService {
|
|
|
13041
13034
|
])
|
|
13042
13035
|
);
|
|
13043
13036
|
const querySnapshot = await getDocs23(q);
|
|
13044
|
-
return querySnapshot.docs.map((
|
|
13037
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
13045
13038
|
}
|
|
13046
13039
|
/**
|
|
13047
13040
|
* Calculates available time slots based on working hours, schedule and existing appointments
|
|
@@ -13586,7 +13579,7 @@ var PractitionerInviteService = class extends BaseService {
|
|
|
13586
13579
|
...constraints
|
|
13587
13580
|
);
|
|
13588
13581
|
const querySnapshot = await getDocs24(q);
|
|
13589
|
-
return querySnapshot.docs.map((
|
|
13582
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
13590
13583
|
} catch (error) {
|
|
13591
13584
|
console.error(
|
|
13592
13585
|
"[PractitionerInviteService] Error getting doctor invites:",
|
|
@@ -13615,7 +13608,7 @@ var PractitionerInviteService = class extends BaseService {
|
|
|
13615
13608
|
...constraints
|
|
13616
13609
|
);
|
|
13617
13610
|
const querySnapshot = await getDocs24(q);
|
|
13618
|
-
return querySnapshot.docs.map((
|
|
13611
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
13619
13612
|
} catch (error) {
|
|
13620
13613
|
console.error(
|
|
13621
13614
|
"[PractitionerInviteService] Error getting clinic invites:",
|
|
@@ -13771,7 +13764,7 @@ var PractitionerInviteService = class extends BaseService {
|
|
|
13771
13764
|
);
|
|
13772
13765
|
const querySnapshot = await getDocs24(q);
|
|
13773
13766
|
let invites = querySnapshot.docs.map(
|
|
13774
|
-
(
|
|
13767
|
+
(doc38) => doc38.data()
|
|
13775
13768
|
);
|
|
13776
13769
|
if (filters.fromDate) {
|
|
13777
13770
|
invites = invites.filter(
|
|
@@ -13887,9 +13880,10 @@ import {
|
|
|
13887
13880
|
limit as limit12,
|
|
13888
13881
|
startAfter as startAfter10
|
|
13889
13882
|
} from "firebase/firestore";
|
|
13883
|
+
import { getCountFromServer } from "firebase/firestore";
|
|
13890
13884
|
var DocumentationTemplateService = class extends BaseService {
|
|
13891
|
-
constructor() {
|
|
13892
|
-
super(...
|
|
13885
|
+
constructor(...args) {
|
|
13886
|
+
super(...args);
|
|
13893
13887
|
this.collectionRef = collection25(
|
|
13894
13888
|
this.db,
|
|
13895
13889
|
DOCUMENTATION_TEMPLATES_COLLECTION
|
|
@@ -14041,8 +14035,8 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
14041
14035
|
const q = query25(versionsCollectionRef, orderBy13("version", "desc"));
|
|
14042
14036
|
const querySnapshot = await getDocs25(q);
|
|
14043
14037
|
const versions = [];
|
|
14044
|
-
querySnapshot.forEach((
|
|
14045
|
-
versions.push(
|
|
14038
|
+
querySnapshot.forEach((doc38) => {
|
|
14039
|
+
versions.push(doc38.data());
|
|
14046
14040
|
});
|
|
14047
14041
|
return versions;
|
|
14048
14042
|
}
|
|
@@ -14073,15 +14067,97 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
14073
14067
|
const querySnapshot = await getDocs25(q);
|
|
14074
14068
|
const templates = [];
|
|
14075
14069
|
let lastVisible = null;
|
|
14076
|
-
querySnapshot.forEach((
|
|
14077
|
-
templates.push(
|
|
14078
|
-
lastVisible =
|
|
14070
|
+
querySnapshot.forEach((doc38) => {
|
|
14071
|
+
templates.push(doc38.data());
|
|
14072
|
+
lastVisible = doc38;
|
|
14073
|
+
});
|
|
14074
|
+
return {
|
|
14075
|
+
templates,
|
|
14076
|
+
lastDoc: lastVisible
|
|
14077
|
+
};
|
|
14078
|
+
}
|
|
14079
|
+
/**
|
|
14080
|
+
* Get all active templates with optional filters and pagination.
|
|
14081
|
+
* @param options - Options for filtering and pagination.
|
|
14082
|
+
* @returns A promise that resolves to the templates and the last visible document.
|
|
14083
|
+
*/
|
|
14084
|
+
async getTemplates(options) {
|
|
14085
|
+
const {
|
|
14086
|
+
pageSize = 20,
|
|
14087
|
+
lastDoc,
|
|
14088
|
+
isUserForm,
|
|
14089
|
+
isRequired,
|
|
14090
|
+
sortingOrder
|
|
14091
|
+
} = options;
|
|
14092
|
+
const constraints = [
|
|
14093
|
+
where25("isActive", "==", true),
|
|
14094
|
+
orderBy13("sortingOrder", "asc"),
|
|
14095
|
+
orderBy13("title", "asc"),
|
|
14096
|
+
limit12(pageSize)
|
|
14097
|
+
];
|
|
14098
|
+
if (isUserForm !== void 0) {
|
|
14099
|
+
constraints.push(where25("isUserForm", "==", isUserForm));
|
|
14100
|
+
}
|
|
14101
|
+
if (isRequired !== void 0) {
|
|
14102
|
+
constraints.push(where25("isRequired", "==", isRequired));
|
|
14103
|
+
}
|
|
14104
|
+
if (sortingOrder !== void 0) {
|
|
14105
|
+
constraints.push(where25("sortingOrder", "==", sortingOrder));
|
|
14106
|
+
}
|
|
14107
|
+
if (lastDoc) {
|
|
14108
|
+
constraints.push(startAfter10(lastDoc));
|
|
14109
|
+
}
|
|
14110
|
+
const q = query25(this.collectionRef, ...constraints.filter((c) => c));
|
|
14111
|
+
const querySnapshot = await getDocs25(q);
|
|
14112
|
+
const templates = [];
|
|
14113
|
+
let lastVisible = null;
|
|
14114
|
+
querySnapshot.forEach((doc38) => {
|
|
14115
|
+
templates.push(doc38.data());
|
|
14116
|
+
lastVisible = doc38;
|
|
14079
14117
|
});
|
|
14080
14118
|
return {
|
|
14081
14119
|
templates,
|
|
14082
14120
|
lastDoc: lastVisible
|
|
14083
14121
|
};
|
|
14084
14122
|
}
|
|
14123
|
+
/**
|
|
14124
|
+
* Get the total count of active templates with optional filters.
|
|
14125
|
+
* @param options - Options for filtering.
|
|
14126
|
+
* @returns A promise that resolves to the total count of templates.
|
|
14127
|
+
*/
|
|
14128
|
+
async getTemplatesCount(options) {
|
|
14129
|
+
const { isUserForm, isRequired, sortingOrder } = options;
|
|
14130
|
+
const constraints = [where25("isActive", "==", true)];
|
|
14131
|
+
if (isUserForm !== void 0) {
|
|
14132
|
+
constraints.push(where25("isUserForm", "==", isUserForm));
|
|
14133
|
+
}
|
|
14134
|
+
if (isRequired !== void 0) {
|
|
14135
|
+
constraints.push(where25("isRequired", "==", isRequired));
|
|
14136
|
+
}
|
|
14137
|
+
if (sortingOrder !== void 0) {
|
|
14138
|
+
constraints.push(where25("sortingOrder", "==", sortingOrder));
|
|
14139
|
+
}
|
|
14140
|
+
const q = query25(this.collectionRef, ...constraints.filter((c) => c));
|
|
14141
|
+
const snapshot = await getCountFromServer(q);
|
|
14142
|
+
return snapshot.data().count;
|
|
14143
|
+
}
|
|
14144
|
+
/**
|
|
14145
|
+
* Get all active templates without pagination for filtering purposes.
|
|
14146
|
+
* @returns A promise that resolves to an array of all active templates.
|
|
14147
|
+
*/
|
|
14148
|
+
async getAllActiveTemplates() {
|
|
14149
|
+
const q = query25(
|
|
14150
|
+
this.collectionRef,
|
|
14151
|
+
where25("isActive", "==", true),
|
|
14152
|
+
orderBy13("title", "asc")
|
|
14153
|
+
);
|
|
14154
|
+
const querySnapshot = await getDocs25(q);
|
|
14155
|
+
const templates = [];
|
|
14156
|
+
querySnapshot.forEach((doc38) => {
|
|
14157
|
+
templates.push(doc38.data());
|
|
14158
|
+
});
|
|
14159
|
+
return templates;
|
|
14160
|
+
}
|
|
14085
14161
|
/**
|
|
14086
14162
|
* Get templates by tags
|
|
14087
14163
|
* @param tags - Tags to filter by
|
|
@@ -14103,9 +14179,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
14103
14179
|
const querySnapshot = await getDocs25(q);
|
|
14104
14180
|
const templates = [];
|
|
14105
14181
|
let lastVisible = null;
|
|
14106
|
-
querySnapshot.forEach((
|
|
14107
|
-
templates.push(
|
|
14108
|
-
lastVisible =
|
|
14182
|
+
querySnapshot.forEach((doc38) => {
|
|
14183
|
+
templates.push(doc38.data());
|
|
14184
|
+
lastVisible = doc38;
|
|
14109
14185
|
});
|
|
14110
14186
|
return {
|
|
14111
14187
|
templates,
|
|
@@ -14132,9 +14208,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
14132
14208
|
const querySnapshot = await getDocs25(q);
|
|
14133
14209
|
const templates = [];
|
|
14134
14210
|
let lastVisible = null;
|
|
14135
|
-
querySnapshot.forEach((
|
|
14136
|
-
templates.push(
|
|
14137
|
-
lastVisible =
|
|
14211
|
+
querySnapshot.forEach((doc38) => {
|
|
14212
|
+
templates.push(doc38.data());
|
|
14213
|
+
lastVisible = doc38;
|
|
14138
14214
|
});
|
|
14139
14215
|
return {
|
|
14140
14216
|
templates,
|
|
@@ -14160,8 +14236,8 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
14160
14236
|
}
|
|
14161
14237
|
const querySnapshot = await getDocs25(q);
|
|
14162
14238
|
const templates = [];
|
|
14163
|
-
querySnapshot.forEach((
|
|
14164
|
-
templates.push(
|
|
14239
|
+
querySnapshot.forEach((doc38) => {
|
|
14240
|
+
templates.push(doc38.data());
|
|
14165
14241
|
});
|
|
14166
14242
|
return templates;
|
|
14167
14243
|
}
|
|
@@ -14367,9 +14443,9 @@ var FilledDocumentService = class extends BaseService {
|
|
|
14367
14443
|
const querySnapshot = await getDocs26(q);
|
|
14368
14444
|
const documents = [];
|
|
14369
14445
|
let lastVisible = null;
|
|
14370
|
-
querySnapshot.forEach((
|
|
14371
|
-
documents.push(
|
|
14372
|
-
lastVisible =
|
|
14446
|
+
querySnapshot.forEach((doc38) => {
|
|
14447
|
+
documents.push(doc38.data());
|
|
14448
|
+
lastVisible = doc38;
|
|
14373
14449
|
});
|
|
14374
14450
|
return {
|
|
14375
14451
|
documents,
|
|
@@ -14591,9 +14667,9 @@ var NotificationService = class extends BaseService {
|
|
|
14591
14667
|
orderBy15("notificationTime", "desc")
|
|
14592
14668
|
);
|
|
14593
14669
|
const querySnapshot = await getDocs27(q);
|
|
14594
|
-
return querySnapshot.docs.map((
|
|
14595
|
-
id:
|
|
14596
|
-
...
|
|
14670
|
+
return querySnapshot.docs.map((doc38) => ({
|
|
14671
|
+
id: doc38.id,
|
|
14672
|
+
...doc38.data()
|
|
14597
14673
|
}));
|
|
14598
14674
|
}
|
|
14599
14675
|
/**
|
|
@@ -14607,9 +14683,9 @@ var NotificationService = class extends BaseService {
|
|
|
14607
14683
|
orderBy15("notificationTime", "desc")
|
|
14608
14684
|
);
|
|
14609
14685
|
const querySnapshot = await getDocs27(q);
|
|
14610
|
-
return querySnapshot.docs.map((
|
|
14611
|
-
id:
|
|
14612
|
-
...
|
|
14686
|
+
return querySnapshot.docs.map((doc38) => ({
|
|
14687
|
+
id: doc38.id,
|
|
14688
|
+
...doc38.data()
|
|
14613
14689
|
}));
|
|
14614
14690
|
}
|
|
14615
14691
|
/**
|
|
@@ -14681,9 +14757,9 @@ var NotificationService = class extends BaseService {
|
|
|
14681
14757
|
orderBy15("notificationTime", "desc")
|
|
14682
14758
|
);
|
|
14683
14759
|
const querySnapshot = await getDocs27(q);
|
|
14684
|
-
return querySnapshot.docs.map((
|
|
14685
|
-
id:
|
|
14686
|
-
...
|
|
14760
|
+
return querySnapshot.docs.map((doc38) => ({
|
|
14761
|
+
id: doc38.id,
|
|
14762
|
+
...doc38.data()
|
|
14687
14763
|
}));
|
|
14688
14764
|
}
|
|
14689
14765
|
/**
|
|
@@ -14696,9 +14772,9 @@ var NotificationService = class extends BaseService {
|
|
|
14696
14772
|
orderBy15("notificationTime", "desc")
|
|
14697
14773
|
);
|
|
14698
14774
|
const querySnapshot = await getDocs27(q);
|
|
14699
|
-
return querySnapshot.docs.map((
|
|
14700
|
-
id:
|
|
14701
|
-
...
|
|
14775
|
+
return querySnapshot.docs.map((doc38) => ({
|
|
14776
|
+
id: doc38.id,
|
|
14777
|
+
...doc38.data()
|
|
14702
14778
|
}));
|
|
14703
14779
|
}
|
|
14704
14780
|
};
|
|
@@ -15002,7 +15078,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15002
15078
|
return media;
|
|
15003
15079
|
}
|
|
15004
15080
|
if (media instanceof File || media instanceof Blob) {
|
|
15005
|
-
console.log(
|
|
15081
|
+
console.log(
|
|
15082
|
+
`[ProcedureService] Uploading ${collectionName} media for ${ownerId}`
|
|
15083
|
+
);
|
|
15006
15084
|
const metadata = await this.mediaService.uploadMedia(
|
|
15007
15085
|
media,
|
|
15008
15086
|
ownerId,
|
|
@@ -15024,7 +15102,11 @@ var ProcedureService = class extends BaseService {
|
|
|
15024
15102
|
if (!mediaArray || mediaArray.length === 0) return [];
|
|
15025
15103
|
const result = [];
|
|
15026
15104
|
for (const media of mediaArray) {
|
|
15027
|
-
const processedUrl = await this.processMedia(
|
|
15105
|
+
const processedUrl = await this.processMedia(
|
|
15106
|
+
media,
|
|
15107
|
+
ownerId,
|
|
15108
|
+
collectionName
|
|
15109
|
+
);
|
|
15028
15110
|
if (processedUrl) {
|
|
15029
15111
|
result.push(processedUrl);
|
|
15030
15112
|
}
|
|
@@ -15037,28 +15119,46 @@ var ProcedureService = class extends BaseService {
|
|
|
15037
15119
|
* @returns The created procedure
|
|
15038
15120
|
*/
|
|
15039
15121
|
async createProcedure(data) {
|
|
15040
|
-
var _a;
|
|
15122
|
+
var _a, _b, _c;
|
|
15041
15123
|
const validatedData = createProcedureSchema.parse(data);
|
|
15042
15124
|
const procedureId = this.generateId();
|
|
15043
15125
|
const [category, subcategory, technology, product] = await Promise.all([
|
|
15044
15126
|
this.categoryService.getById(validatedData.categoryId),
|
|
15045
|
-
this.subcategoryService.getById(
|
|
15127
|
+
this.subcategoryService.getById(
|
|
15128
|
+
validatedData.categoryId,
|
|
15129
|
+
validatedData.subcategoryId
|
|
15130
|
+
),
|
|
15046
15131
|
this.technologyService.getById(validatedData.technologyId),
|
|
15047
|
-
this.productService.getById(
|
|
15132
|
+
this.productService.getById(
|
|
15133
|
+
validatedData.technologyId,
|
|
15134
|
+
validatedData.productId
|
|
15135
|
+
)
|
|
15048
15136
|
]);
|
|
15049
15137
|
if (!category || !subcategory || !technology || !product) {
|
|
15050
15138
|
throw new Error("One or more required base entities not found");
|
|
15051
15139
|
}
|
|
15052
|
-
const clinicRef = doc30(
|
|
15140
|
+
const clinicRef = doc30(
|
|
15141
|
+
this.db,
|
|
15142
|
+
CLINICS_COLLECTION,
|
|
15143
|
+
validatedData.clinicBranchId
|
|
15144
|
+
);
|
|
15053
15145
|
const clinicSnapshot = await getDoc32(clinicRef);
|
|
15054
15146
|
if (!clinicSnapshot.exists()) {
|
|
15055
|
-
throw new Error(
|
|
15147
|
+
throw new Error(
|
|
15148
|
+
`Clinic with ID ${validatedData.clinicBranchId} not found`
|
|
15149
|
+
);
|
|
15056
15150
|
}
|
|
15057
15151
|
const clinic = clinicSnapshot.data();
|
|
15058
|
-
const practitionerRef = doc30(
|
|
15152
|
+
const practitionerRef = doc30(
|
|
15153
|
+
this.db,
|
|
15154
|
+
PRACTITIONERS_COLLECTION,
|
|
15155
|
+
validatedData.practitionerId
|
|
15156
|
+
);
|
|
15059
15157
|
const practitionerSnapshot = await getDoc32(practitionerRef);
|
|
15060
15158
|
if (!practitionerSnapshot.exists()) {
|
|
15061
|
-
throw new Error(
|
|
15159
|
+
throw new Error(
|
|
15160
|
+
`Practitioner with ID ${validatedData.practitionerId} not found`
|
|
15161
|
+
);
|
|
15062
15162
|
}
|
|
15063
15163
|
const practitioner = practitionerSnapshot.data();
|
|
15064
15164
|
let processedPhotos = [];
|
|
@@ -15099,7 +15199,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15099
15199
|
product,
|
|
15100
15200
|
blockingConditions: technology.blockingConditions,
|
|
15101
15201
|
contraindications: technology.contraindications || [],
|
|
15202
|
+
contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
|
|
15102
15203
|
treatmentBenefits: technology.benefits,
|
|
15204
|
+
treatmentBenefitIds: ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [],
|
|
15103
15205
|
preRequirements: technology.requirements.pre,
|
|
15104
15206
|
postRequirements: technology.requirements.post,
|
|
15105
15207
|
certificationRequirement: technology.certificationRequirement,
|
|
@@ -15140,7 +15242,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15140
15242
|
* @returns A promise that resolves to an array of the newly created procedures.
|
|
15141
15243
|
*/
|
|
15142
15244
|
async bulkCreateProcedures(baseData, practitionerIds) {
|
|
15143
|
-
var _a;
|
|
15245
|
+
var _a, _b, _c;
|
|
15144
15246
|
if (!practitionerIds || practitionerIds.length === 0) {
|
|
15145
15247
|
throw new Error("Practitioner IDs array cannot be empty.");
|
|
15146
15248
|
}
|
|
@@ -15148,16 +15250,24 @@ var ProcedureService = class extends BaseService {
|
|
|
15148
15250
|
const validatedData = createProcedureSchema.parse(validationData);
|
|
15149
15251
|
const [category, subcategory, technology, product, clinicSnapshot] = await Promise.all([
|
|
15150
15252
|
this.categoryService.getById(validatedData.categoryId),
|
|
15151
|
-
this.subcategoryService.getById(
|
|
15253
|
+
this.subcategoryService.getById(
|
|
15254
|
+
validatedData.categoryId,
|
|
15255
|
+
validatedData.subcategoryId
|
|
15256
|
+
),
|
|
15152
15257
|
this.technologyService.getById(validatedData.technologyId),
|
|
15153
|
-
this.productService.getById(
|
|
15258
|
+
this.productService.getById(
|
|
15259
|
+
validatedData.technologyId,
|
|
15260
|
+
validatedData.productId
|
|
15261
|
+
),
|
|
15154
15262
|
getDoc32(doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId))
|
|
15155
15263
|
]);
|
|
15156
15264
|
if (!category || !subcategory || !technology || !product) {
|
|
15157
15265
|
throw new Error("One or more required base entities not found");
|
|
15158
15266
|
}
|
|
15159
15267
|
if (!clinicSnapshot.exists()) {
|
|
15160
|
-
throw new Error(
|
|
15268
|
+
throw new Error(
|
|
15269
|
+
`Clinic with ID ${validatedData.clinicBranchId} not found`
|
|
15270
|
+
);
|
|
15161
15271
|
}
|
|
15162
15272
|
const clinic = clinicSnapshot.data();
|
|
15163
15273
|
let processedPhotos = [];
|
|
@@ -15177,14 +15287,18 @@ var ProcedureService = class extends BaseService {
|
|
|
15177
15287
|
where29(documentId2(), "in", chunk)
|
|
15178
15288
|
);
|
|
15179
15289
|
const practitionersSnapshot = await getDocs29(practitionersQuery);
|
|
15180
|
-
practitionersSnapshot.docs.forEach((
|
|
15181
|
-
practitionersMap.set(
|
|
15290
|
+
practitionersSnapshot.docs.forEach((doc38) => {
|
|
15291
|
+
practitionersMap.set(doc38.id, doc38.data());
|
|
15182
15292
|
});
|
|
15183
15293
|
}
|
|
15184
15294
|
if (practitionersMap.size !== practitionerIds.length) {
|
|
15185
15295
|
const foundIds = Array.from(practitionersMap.keys());
|
|
15186
|
-
const notFoundIds = practitionerIds.filter(
|
|
15187
|
-
|
|
15296
|
+
const notFoundIds = practitionerIds.filter(
|
|
15297
|
+
(id) => !foundIds.includes(id)
|
|
15298
|
+
);
|
|
15299
|
+
throw new Error(
|
|
15300
|
+
`The following practitioners were not found: ${notFoundIds.join(", ")}`
|
|
15301
|
+
);
|
|
15188
15302
|
}
|
|
15189
15303
|
const batch = writeBatch6(this.db);
|
|
15190
15304
|
const createdProcedureIds = [];
|
|
@@ -15222,7 +15336,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15222
15336
|
product,
|
|
15223
15337
|
blockingConditions: technology.blockingConditions,
|
|
15224
15338
|
contraindications: technology.contraindications || [],
|
|
15339
|
+
contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
|
|
15225
15340
|
treatmentBenefits: technology.benefits,
|
|
15341
|
+
treatmentBenefitIds: ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [],
|
|
15226
15342
|
preRequirements: technology.requirements.pre,
|
|
15227
15343
|
postRequirements: technology.requirements.post,
|
|
15228
15344
|
certificationRequirement: technology.certificationRequirement,
|
|
@@ -15252,10 +15368,13 @@ var ProcedureService = class extends BaseService {
|
|
|
15252
15368
|
const fetchedProcedures = [];
|
|
15253
15369
|
for (let i = 0; i < createdProcedureIds.length; i += 30) {
|
|
15254
15370
|
const chunk = createdProcedureIds.slice(i, i + 30);
|
|
15255
|
-
const q = query29(
|
|
15371
|
+
const q = query29(
|
|
15372
|
+
collection29(this.db, PROCEDURES_COLLECTION),
|
|
15373
|
+
where29(documentId2(), "in", chunk)
|
|
15374
|
+
);
|
|
15256
15375
|
const snapshot = await getDocs29(q);
|
|
15257
|
-
snapshot.forEach((
|
|
15258
|
-
fetchedProcedures.push(
|
|
15376
|
+
snapshot.forEach((doc38) => {
|
|
15377
|
+
fetchedProcedures.push(doc38.data());
|
|
15259
15378
|
});
|
|
15260
15379
|
}
|
|
15261
15380
|
return fetchedProcedures;
|
|
@@ -15285,7 +15404,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15285
15404
|
where29("isActive", "==", true)
|
|
15286
15405
|
);
|
|
15287
15406
|
const snapshot = await getDocs29(q);
|
|
15288
|
-
return snapshot.docs.map((
|
|
15407
|
+
return snapshot.docs.map((doc38) => doc38.data());
|
|
15289
15408
|
}
|
|
15290
15409
|
/**
|
|
15291
15410
|
* Gets all procedures for a practitioner
|
|
@@ -15299,7 +15418,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15299
15418
|
where29("isActive", "==", true)
|
|
15300
15419
|
);
|
|
15301
15420
|
const snapshot = await getDocs29(q);
|
|
15302
|
-
return snapshot.docs.map((
|
|
15421
|
+
return snapshot.docs.map((doc38) => doc38.data());
|
|
15303
15422
|
}
|
|
15304
15423
|
/**
|
|
15305
15424
|
* Gets all inactive procedures for a practitioner
|
|
@@ -15313,7 +15432,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15313
15432
|
where29("isActive", "==", false)
|
|
15314
15433
|
);
|
|
15315
15434
|
const snapshot = await getDocs29(q);
|
|
15316
|
-
return snapshot.docs.map((
|
|
15435
|
+
return snapshot.docs.map((doc38) => doc38.data());
|
|
15317
15436
|
}
|
|
15318
15437
|
/**
|
|
15319
15438
|
* Updates a procedure
|
|
@@ -15322,7 +15441,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15322
15441
|
* @returns The updated procedure
|
|
15323
15442
|
*/
|
|
15324
15443
|
async updateProcedure(id, data) {
|
|
15325
|
-
var _a;
|
|
15444
|
+
var _a, _b, _c;
|
|
15326
15445
|
const validatedData = updateProcedureSchema.parse(data);
|
|
15327
15446
|
const procedureRef = doc30(this.db, PROCEDURES_COLLECTION, id);
|
|
15328
15447
|
const procedureSnapshot = await getDoc32(procedureRef);
|
|
@@ -15353,7 +15472,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15353
15472
|
);
|
|
15354
15473
|
const newPractitionerSnap = await getDoc32(newPractitionerRef);
|
|
15355
15474
|
if (!newPractitionerSnap.exists())
|
|
15356
|
-
throw new Error(
|
|
15475
|
+
throw new Error(
|
|
15476
|
+
`New Practitioner ${validatedData.practitionerId} not found`
|
|
15477
|
+
);
|
|
15357
15478
|
newPractitioner = newPractitionerSnap.data();
|
|
15358
15479
|
updatedProcedureData.doctorInfo = {
|
|
15359
15480
|
id: newPractitioner.id,
|
|
@@ -15367,7 +15488,11 @@ var ProcedureService = class extends BaseService {
|
|
|
15367
15488
|
}
|
|
15368
15489
|
if (validatedData.clinicBranchId && validatedData.clinicBranchId !== oldClinicId) {
|
|
15369
15490
|
clinicChanged = true;
|
|
15370
|
-
const newClinicRef = doc30(
|
|
15491
|
+
const newClinicRef = doc30(
|
|
15492
|
+
this.db,
|
|
15493
|
+
CLINICS_COLLECTION,
|
|
15494
|
+
validatedData.clinicBranchId
|
|
15495
|
+
);
|
|
15371
15496
|
const newClinicSnap = await getDoc32(newClinicRef);
|
|
15372
15497
|
if (!newClinicSnap.exists())
|
|
15373
15498
|
throw new Error(`New Clinic ${validatedData.clinicBranchId} not found`);
|
|
@@ -15386,8 +15511,11 @@ var ProcedureService = class extends BaseService {
|
|
|
15386
15511
|
updatedProcedureData.nameLower = validatedData.name.toLowerCase();
|
|
15387
15512
|
}
|
|
15388
15513
|
if (validatedData.categoryId) {
|
|
15389
|
-
const category = await this.categoryService.getById(
|
|
15390
|
-
|
|
15514
|
+
const category = await this.categoryService.getById(
|
|
15515
|
+
validatedData.categoryId
|
|
15516
|
+
);
|
|
15517
|
+
if (!category)
|
|
15518
|
+
throw new Error(`Category ${validatedData.categoryId} not found`);
|
|
15391
15519
|
updatedProcedureData.category = category;
|
|
15392
15520
|
finalCategoryId = category.id;
|
|
15393
15521
|
}
|
|
@@ -15402,23 +15530,34 @@ var ProcedureService = class extends BaseService {
|
|
|
15402
15530
|
);
|
|
15403
15531
|
updatedProcedureData.subcategory = subcategory;
|
|
15404
15532
|
} else if (validatedData.subcategoryId) {
|
|
15405
|
-
console.warn(
|
|
15533
|
+
console.warn(
|
|
15534
|
+
"Attempted to update subcategory without a valid categoryId"
|
|
15535
|
+
);
|
|
15406
15536
|
}
|
|
15407
15537
|
let finalTechnologyId = existingProcedure.technology.id;
|
|
15408
15538
|
if (validatedData.technologyId) {
|
|
15409
|
-
const technology = await this.technologyService.getById(
|
|
15410
|
-
|
|
15539
|
+
const technology = await this.technologyService.getById(
|
|
15540
|
+
validatedData.technologyId
|
|
15541
|
+
);
|
|
15542
|
+
if (!technology)
|
|
15543
|
+
throw new Error(`Technology ${validatedData.technologyId} not found`);
|
|
15411
15544
|
updatedProcedureData.technology = technology;
|
|
15412
15545
|
finalTechnologyId = technology.id;
|
|
15413
15546
|
updatedProcedureData.blockingConditions = technology.blockingConditions;
|
|
15547
|
+
updatedProcedureData.contraindications = technology.contraindications || [];
|
|
15548
|
+
updatedProcedureData.contraindicationIds = ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [];
|
|
15414
15549
|
updatedProcedureData.treatmentBenefits = technology.benefits;
|
|
15550
|
+
updatedProcedureData.treatmentBenefitIds = ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [];
|
|
15415
15551
|
updatedProcedureData.preRequirements = technology.requirements.pre;
|
|
15416
15552
|
updatedProcedureData.postRequirements = technology.requirements.post;
|
|
15417
15553
|
updatedProcedureData.certificationRequirement = technology.certificationRequirement;
|
|
15418
15554
|
updatedProcedureData.documentationTemplates = technology.documentationTemplates || [];
|
|
15419
15555
|
}
|
|
15420
15556
|
if (validatedData.productId && finalTechnologyId) {
|
|
15421
|
-
const product = await this.productService.getById(
|
|
15557
|
+
const product = await this.productService.getById(
|
|
15558
|
+
finalTechnologyId,
|
|
15559
|
+
validatedData.productId
|
|
15560
|
+
);
|
|
15422
15561
|
if (!product)
|
|
15423
15562
|
throw new Error(
|
|
15424
15563
|
`Product ${validatedData.productId} not found for technology ${finalTechnologyId}`
|
|
@@ -15490,28 +15629,32 @@ var ProcedureService = class extends BaseService {
|
|
|
15490
15629
|
const proceduresCollection = collection29(this.db, PROCEDURES_COLLECTION);
|
|
15491
15630
|
let proceduresQuery = query29(proceduresCollection);
|
|
15492
15631
|
if (pagination && pagination > 0) {
|
|
15493
|
-
const { limit:
|
|
15632
|
+
const { limit: limit21, startAfter: startAfter19 } = await import("firebase/firestore");
|
|
15494
15633
|
if (lastDoc) {
|
|
15495
15634
|
proceduresQuery = query29(
|
|
15496
15635
|
proceduresCollection,
|
|
15497
15636
|
orderBy17("name"),
|
|
15498
15637
|
// Use imported orderBy
|
|
15499
|
-
|
|
15500
|
-
|
|
15638
|
+
startAfter19(lastDoc),
|
|
15639
|
+
limit21(pagination)
|
|
15501
15640
|
);
|
|
15502
15641
|
} else {
|
|
15503
|
-
proceduresQuery = query29(
|
|
15642
|
+
proceduresQuery = query29(
|
|
15643
|
+
proceduresCollection,
|
|
15644
|
+
orderBy17("name"),
|
|
15645
|
+
limit21(pagination)
|
|
15646
|
+
);
|
|
15504
15647
|
}
|
|
15505
15648
|
} else {
|
|
15506
15649
|
proceduresQuery = query29(proceduresCollection, orderBy17("name"));
|
|
15507
15650
|
}
|
|
15508
15651
|
const proceduresSnapshot = await getDocs29(proceduresQuery);
|
|
15509
15652
|
const lastVisible = proceduresSnapshot.docs[proceduresSnapshot.docs.length - 1];
|
|
15510
|
-
const procedures = proceduresSnapshot.docs.map((
|
|
15511
|
-
const data =
|
|
15653
|
+
const procedures = proceduresSnapshot.docs.map((doc38) => {
|
|
15654
|
+
const data = doc38.data();
|
|
15512
15655
|
return {
|
|
15513
15656
|
...data,
|
|
15514
|
-
id:
|
|
15657
|
+
id: doc38.id
|
|
15515
15658
|
// Ensure ID is present
|
|
15516
15659
|
};
|
|
15517
15660
|
});
|
|
@@ -15531,7 +15674,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15531
15674
|
*
|
|
15532
15675
|
* @param filters - Various filters to apply
|
|
15533
15676
|
* @param filters.nameSearch - Optional search text for procedure name
|
|
15534
|
-
* @param filters.
|
|
15677
|
+
* @param filters.treatmentBenefitIds - Optional array of treatment benefits to filter by
|
|
15535
15678
|
* @param filters.procedureFamily - Optional procedure family to filter by
|
|
15536
15679
|
* @param filters.procedureCategory - Optional procedure category to filter by
|
|
15537
15680
|
* @param filters.procedureSubcategory - Optional procedure subcategory to filter by
|
|
@@ -15549,7 +15692,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15549
15692
|
*/
|
|
15550
15693
|
async getProceduresByFilters(filters) {
|
|
15551
15694
|
try {
|
|
15552
|
-
console.log(
|
|
15695
|
+
console.log(
|
|
15696
|
+
"[PROCEDURE_SERVICE] Starting procedure filtering with multiple strategies"
|
|
15697
|
+
);
|
|
15553
15698
|
if (filters.location && filters.radiusInKm) {
|
|
15554
15699
|
console.log("[PROCEDURE_SERVICE] Executing geo query:", {
|
|
15555
15700
|
location: filters.location,
|
|
@@ -15557,7 +15702,10 @@ var ProcedureService = class extends BaseService {
|
|
|
15557
15702
|
serviceName: "ProcedureService"
|
|
15558
15703
|
});
|
|
15559
15704
|
if (!filters.location.latitude || !filters.location.longitude) {
|
|
15560
|
-
console.warn(
|
|
15705
|
+
console.warn(
|
|
15706
|
+
"[PROCEDURE_SERVICE] Invalid location data:",
|
|
15707
|
+
filters.location
|
|
15708
|
+
);
|
|
15561
15709
|
filters.location = void 0;
|
|
15562
15710
|
filters.radiusInKm = void 0;
|
|
15563
15711
|
}
|
|
@@ -15577,13 +15725,19 @@ var ProcedureService = class extends BaseService {
|
|
|
15577
15725
|
constraints.push(where29("family", "==", filters.procedureFamily));
|
|
15578
15726
|
}
|
|
15579
15727
|
if (filters.procedureCategory) {
|
|
15580
|
-
constraints.push(
|
|
15728
|
+
constraints.push(
|
|
15729
|
+
where29("category.id", "==", filters.procedureCategory)
|
|
15730
|
+
);
|
|
15581
15731
|
}
|
|
15582
15732
|
if (filters.procedureSubcategory) {
|
|
15583
|
-
constraints.push(
|
|
15733
|
+
constraints.push(
|
|
15734
|
+
where29("subcategory.id", "==", filters.procedureSubcategory)
|
|
15735
|
+
);
|
|
15584
15736
|
}
|
|
15585
15737
|
if (filters.procedureTechnology) {
|
|
15586
|
-
constraints.push(
|
|
15738
|
+
constraints.push(
|
|
15739
|
+
where29("technology.id", "==", filters.procedureTechnology)
|
|
15740
|
+
);
|
|
15587
15741
|
}
|
|
15588
15742
|
if (filters.minPrice !== void 0) {
|
|
15589
15743
|
constraints.push(where29("price", ">=", filters.minPrice));
|
|
@@ -15592,20 +15746,32 @@ var ProcedureService = class extends BaseService {
|
|
|
15592
15746
|
constraints.push(where29("price", "<=", filters.maxPrice));
|
|
15593
15747
|
}
|
|
15594
15748
|
if (filters.minRating !== void 0) {
|
|
15595
|
-
constraints.push(
|
|
15749
|
+
constraints.push(
|
|
15750
|
+
where29("reviewInfo.averageRating", ">=", filters.minRating)
|
|
15751
|
+
);
|
|
15596
15752
|
}
|
|
15597
15753
|
if (filters.maxRating !== void 0) {
|
|
15598
|
-
constraints.push(
|
|
15754
|
+
constraints.push(
|
|
15755
|
+
where29("reviewInfo.averageRating", "<=", filters.maxRating)
|
|
15756
|
+
);
|
|
15599
15757
|
}
|
|
15600
15758
|
if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
|
|
15601
|
-
const
|
|
15602
|
-
constraints.push(
|
|
15759
|
+
const benefitIdsToMatch = filters.treatmentBenefits;
|
|
15760
|
+
constraints.push(
|
|
15761
|
+
where29(
|
|
15762
|
+
"treatmentBenefitIds",
|
|
15763
|
+
"array-contains-any",
|
|
15764
|
+
benefitIdsToMatch
|
|
15765
|
+
)
|
|
15766
|
+
);
|
|
15603
15767
|
}
|
|
15604
15768
|
return constraints;
|
|
15605
15769
|
};
|
|
15606
15770
|
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
15607
15771
|
try {
|
|
15608
|
-
console.log(
|
|
15772
|
+
console.log(
|
|
15773
|
+
"[PROCEDURE_SERVICE] Strategy 1: Trying nameLower search"
|
|
15774
|
+
);
|
|
15609
15775
|
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
15610
15776
|
const constraints = getBaseConstraints();
|
|
15611
15777
|
constraints.push(where29("nameLower", ">=", searchTerm));
|
|
@@ -15621,13 +15787,18 @@ var ProcedureService = class extends BaseService {
|
|
|
15621
15787
|
}
|
|
15622
15788
|
}
|
|
15623
15789
|
constraints.push(limit15(filters.pagination || 10));
|
|
15624
|
-
const q = query29(
|
|
15790
|
+
const q = query29(
|
|
15791
|
+
collection29(this.db, PROCEDURES_COLLECTION),
|
|
15792
|
+
...constraints
|
|
15793
|
+
);
|
|
15625
15794
|
const querySnapshot = await getDocs29(q);
|
|
15626
15795
|
const procedures = querySnapshot.docs.map(
|
|
15627
|
-
(
|
|
15796
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
15628
15797
|
);
|
|
15629
15798
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15630
|
-
console.log(
|
|
15799
|
+
console.log(
|
|
15800
|
+
`[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`
|
|
15801
|
+
);
|
|
15631
15802
|
if (procedures.length < (filters.pagination || 10)) {
|
|
15632
15803
|
return { procedures, lastDoc: null };
|
|
15633
15804
|
}
|
|
@@ -15638,7 +15809,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15638
15809
|
}
|
|
15639
15810
|
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
15640
15811
|
try {
|
|
15641
|
-
console.log(
|
|
15812
|
+
console.log(
|
|
15813
|
+
"[PROCEDURE_SERVICE] Strategy 2: Trying name field search"
|
|
15814
|
+
);
|
|
15642
15815
|
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
15643
15816
|
const constraints = getBaseConstraints();
|
|
15644
15817
|
constraints.push(where29("name", ">=", searchTerm));
|
|
@@ -15654,13 +15827,18 @@ var ProcedureService = class extends BaseService {
|
|
|
15654
15827
|
}
|
|
15655
15828
|
}
|
|
15656
15829
|
constraints.push(limit15(filters.pagination || 10));
|
|
15657
|
-
const q = query29(
|
|
15830
|
+
const q = query29(
|
|
15831
|
+
collection29(this.db, PROCEDURES_COLLECTION),
|
|
15832
|
+
...constraints
|
|
15833
|
+
);
|
|
15658
15834
|
const querySnapshot = await getDocs29(q);
|
|
15659
15835
|
const procedures = querySnapshot.docs.map(
|
|
15660
|
-
(
|
|
15836
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
15661
15837
|
);
|
|
15662
15838
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15663
|
-
console.log(
|
|
15839
|
+
console.log(
|
|
15840
|
+
`[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`
|
|
15841
|
+
);
|
|
15664
15842
|
if (procedures.length < (filters.pagination || 10)) {
|
|
15665
15843
|
return { procedures, lastDoc: null };
|
|
15666
15844
|
}
|
|
@@ -15685,14 +15863,19 @@ var ProcedureService = class extends BaseService {
|
|
|
15685
15863
|
}
|
|
15686
15864
|
}
|
|
15687
15865
|
constraints.push(limit15(filters.pagination || 10));
|
|
15688
|
-
const q = query29(
|
|
15866
|
+
const q = query29(
|
|
15867
|
+
collection29(this.db, PROCEDURES_COLLECTION),
|
|
15868
|
+
...constraints
|
|
15869
|
+
);
|
|
15689
15870
|
const querySnapshot = await getDocs29(q);
|
|
15690
15871
|
let procedures = querySnapshot.docs.map(
|
|
15691
|
-
(
|
|
15872
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
15692
15873
|
);
|
|
15693
15874
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15694
15875
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15695
|
-
console.log(
|
|
15876
|
+
console.log(
|
|
15877
|
+
`[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`
|
|
15878
|
+
);
|
|
15696
15879
|
if (procedures.length < (filters.pagination || 10)) {
|
|
15697
15880
|
return { procedures, lastDoc: null };
|
|
15698
15881
|
}
|
|
@@ -15707,14 +15890,19 @@ var ProcedureService = class extends BaseService {
|
|
|
15707
15890
|
orderBy17("createdAt", "desc"),
|
|
15708
15891
|
limit15(filters.pagination || 10)
|
|
15709
15892
|
];
|
|
15710
|
-
const q = query29(
|
|
15893
|
+
const q = query29(
|
|
15894
|
+
collection29(this.db, PROCEDURES_COLLECTION),
|
|
15895
|
+
...constraints
|
|
15896
|
+
);
|
|
15711
15897
|
const querySnapshot = await getDocs29(q);
|
|
15712
15898
|
let procedures = querySnapshot.docs.map(
|
|
15713
|
-
(
|
|
15899
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
15714
15900
|
);
|
|
15715
15901
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15716
15902
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15717
|
-
console.log(
|
|
15903
|
+
console.log(
|
|
15904
|
+
`[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`
|
|
15905
|
+
);
|
|
15718
15906
|
if (procedures.length < (filters.pagination || 10)) {
|
|
15719
15907
|
return { procedures, lastDoc: null };
|
|
15720
15908
|
}
|
|
@@ -15722,7 +15910,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15722
15910
|
} catch (error) {
|
|
15723
15911
|
console.log("[PROCEDURE_SERVICE] Strategy 4 failed:", error);
|
|
15724
15912
|
}
|
|
15725
|
-
console.log(
|
|
15913
|
+
console.log(
|
|
15914
|
+
"[PROCEDURE_SERVICE] All strategies failed, returning empty result"
|
|
15915
|
+
);
|
|
15726
15916
|
return { procedures: [], lastDoc: null };
|
|
15727
15917
|
} catch (error) {
|
|
15728
15918
|
console.error("[PROCEDURE_SERVICE] Error filtering procedures:", error);
|
|
@@ -15742,13 +15932,17 @@ var ProcedureService = class extends BaseService {
|
|
|
15742
15932
|
const nameLower = procedure.nameLower || "";
|
|
15743
15933
|
return name.includes(searchTerm) || nameLower.includes(searchTerm);
|
|
15744
15934
|
});
|
|
15745
|
-
console.log(
|
|
15935
|
+
console.log(
|
|
15936
|
+
`[PROCEDURE_SERVICE] Applied name filter, results: ${filteredProcedures.length}`
|
|
15937
|
+
);
|
|
15746
15938
|
}
|
|
15747
15939
|
if (filters.minPrice !== void 0 || filters.maxPrice !== void 0) {
|
|
15748
15940
|
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15749
15941
|
const price = procedure.price || 0;
|
|
15750
|
-
if (filters.minPrice !== void 0 && price < filters.minPrice)
|
|
15751
|
-
|
|
15942
|
+
if (filters.minPrice !== void 0 && price < filters.minPrice)
|
|
15943
|
+
return false;
|
|
15944
|
+
if (filters.maxPrice !== void 0 && price > filters.maxPrice)
|
|
15945
|
+
return false;
|
|
15752
15946
|
return true;
|
|
15753
15947
|
});
|
|
15754
15948
|
console.log(
|
|
@@ -15759,8 +15953,10 @@ var ProcedureService = class extends BaseService {
|
|
|
15759
15953
|
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15760
15954
|
var _a;
|
|
15761
15955
|
const rating = ((_a = procedure.reviewInfo) == null ? void 0 : _a.averageRating) || 0;
|
|
15762
|
-
if (filters.minRating !== void 0 && rating < filters.minRating)
|
|
15763
|
-
|
|
15956
|
+
if (filters.minRating !== void 0 && rating < filters.minRating)
|
|
15957
|
+
return false;
|
|
15958
|
+
if (filters.maxRating !== void 0 && rating > filters.maxRating)
|
|
15959
|
+
return false;
|
|
15764
15960
|
return true;
|
|
15765
15961
|
});
|
|
15766
15962
|
console.log(
|
|
@@ -15768,10 +15964,12 @@ var ProcedureService = class extends BaseService {
|
|
|
15768
15964
|
);
|
|
15769
15965
|
}
|
|
15770
15966
|
if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
|
|
15771
|
-
const
|
|
15967
|
+
const benefitIdsToMatch = filters.treatmentBenefits;
|
|
15772
15968
|
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15773
|
-
const
|
|
15774
|
-
return
|
|
15969
|
+
const procedureBenefitIds = procedure.treatmentBenefitIds || [];
|
|
15970
|
+
return benefitIdsToMatch.some(
|
|
15971
|
+
(benefitId) => procedureBenefitIds.includes(benefitId)
|
|
15972
|
+
);
|
|
15775
15973
|
});
|
|
15776
15974
|
console.log(
|
|
15777
15975
|
`[PROCEDURE_SERVICE] Applied benefits filter, results: ${filteredProcedures.length}`
|
|
@@ -15834,8 +16032,12 @@ var ProcedureService = class extends BaseService {
|
|
|
15834
16032
|
procedure.distance = distance;
|
|
15835
16033
|
return distance <= radiusInKm;
|
|
15836
16034
|
});
|
|
15837
|
-
console.log(
|
|
15838
|
-
|
|
16035
|
+
console.log(
|
|
16036
|
+
`[PROCEDURE_SERVICE] Applied geo filter, results: ${filteredProcedures.length}`
|
|
16037
|
+
);
|
|
16038
|
+
filteredProcedures.sort(
|
|
16039
|
+
(a, b) => (a.distance || 0) - (b.distance || 0)
|
|
16040
|
+
);
|
|
15839
16041
|
}
|
|
15840
16042
|
return filteredProcedures;
|
|
15841
16043
|
}
|
|
@@ -15847,19 +16049,30 @@ var ProcedureService = class extends BaseService {
|
|
|
15847
16049
|
if (!location || !radiusInKm) {
|
|
15848
16050
|
return Promise.resolve({ procedures: [], lastDoc: null });
|
|
15849
16051
|
}
|
|
15850
|
-
const bounds = geohashQueryBounds5(
|
|
16052
|
+
const bounds = geohashQueryBounds5(
|
|
16053
|
+
[location.latitude, location.longitude],
|
|
16054
|
+
radiusInKm * 1e3
|
|
16055
|
+
);
|
|
15851
16056
|
const fetches = bounds.map((b) => {
|
|
15852
16057
|
const constraints = [
|
|
15853
16058
|
where29("clinicInfo.location.geohash", ">=", b[0]),
|
|
15854
16059
|
where29("clinicInfo.location.geohash", "<=", b[1]),
|
|
15855
|
-
where29(
|
|
16060
|
+
where29(
|
|
16061
|
+
"isActive",
|
|
16062
|
+
"==",
|
|
16063
|
+
filters.isActive !== void 0 ? filters.isActive : true
|
|
16064
|
+
)
|
|
15856
16065
|
];
|
|
15857
|
-
return getDocs29(
|
|
16066
|
+
return getDocs29(
|
|
16067
|
+
query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints)
|
|
16068
|
+
);
|
|
15858
16069
|
});
|
|
15859
16070
|
return Promise.all(fetches).then((snaps) => {
|
|
15860
16071
|
const collected = [];
|
|
15861
16072
|
snaps.forEach((snap) => {
|
|
15862
|
-
snap.docs.forEach(
|
|
16073
|
+
snap.docs.forEach(
|
|
16074
|
+
(d) => collected.push({ ...d.data(), id: d.id })
|
|
16075
|
+
);
|
|
15863
16076
|
});
|
|
15864
16077
|
const uniqueMap = /* @__PURE__ */ new Map();
|
|
15865
16078
|
for (const p of collected) {
|
|
@@ -15870,7 +16083,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15870
16083
|
const pageSize = filters.pagination || 10;
|
|
15871
16084
|
let startIndex = 0;
|
|
15872
16085
|
if (filters.lastDoc && typeof filters.lastDoc === "object" && filters.lastDoc.id) {
|
|
15873
|
-
const idx = procedures.findIndex(
|
|
16086
|
+
const idx = procedures.findIndex(
|
|
16087
|
+
(p) => p.id === filters.lastDoc.id
|
|
16088
|
+
);
|
|
15874
16089
|
if (idx >= 0) startIndex = idx + 1;
|
|
15875
16090
|
}
|
|
15876
16091
|
const page = procedures.slice(startIndex, startIndex + pageSize);
|
|
@@ -15895,7 +16110,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15895
16110
|
* @returns The created procedure
|
|
15896
16111
|
*/
|
|
15897
16112
|
async createConsultationProcedure(data) {
|
|
15898
|
-
var _a;
|
|
16113
|
+
var _a, _b, _c;
|
|
15899
16114
|
const procedureId = this.generateId();
|
|
15900
16115
|
const [category, subcategory, technology] = await Promise.all([
|
|
15901
16116
|
this.categoryService.getById(data.categoryId),
|
|
@@ -15911,7 +16126,11 @@ var ProcedureService = class extends BaseService {
|
|
|
15911
16126
|
throw new Error(`Clinic with ID ${data.clinicBranchId} not found`);
|
|
15912
16127
|
}
|
|
15913
16128
|
const clinic = clinicSnapshot.data();
|
|
15914
|
-
const practitionerRef = doc30(
|
|
16129
|
+
const practitionerRef = doc30(
|
|
16130
|
+
this.db,
|
|
16131
|
+
PRACTITIONERS_COLLECTION,
|
|
16132
|
+
data.practitionerId
|
|
16133
|
+
);
|
|
15915
16134
|
const practitionerSnapshot = await getDoc32(practitionerRef);
|
|
15916
16135
|
if (!practitionerSnapshot.exists()) {
|
|
15917
16136
|
throw new Error(`Practitioner with ID ${data.practitionerId} not found`);
|
|
@@ -15919,7 +16138,11 @@ var ProcedureService = class extends BaseService {
|
|
|
15919
16138
|
const practitioner = practitionerSnapshot.data();
|
|
15920
16139
|
let processedPhotos = [];
|
|
15921
16140
|
if (data.photos && data.photos.length > 0) {
|
|
15922
|
-
processedPhotos = await this.processMediaArray(
|
|
16141
|
+
processedPhotos = await this.processMediaArray(
|
|
16142
|
+
data.photos,
|
|
16143
|
+
procedureId,
|
|
16144
|
+
"procedure-photos"
|
|
16145
|
+
);
|
|
15923
16146
|
}
|
|
15924
16147
|
const clinicInfo = {
|
|
15925
16148
|
id: clinicSnapshot.id,
|
|
@@ -15945,6 +16168,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15945
16168
|
brandName: "Consultation",
|
|
15946
16169
|
technologyId: data.technologyId,
|
|
15947
16170
|
technologyName: technology.name,
|
|
16171
|
+
categoryId: technology.categoryId,
|
|
16172
|
+
subcategoryId: technology.subcategoryId,
|
|
15948
16173
|
isActive: true,
|
|
15949
16174
|
createdAt: /* @__PURE__ */ new Date(),
|
|
15950
16175
|
updatedAt: /* @__PURE__ */ new Date()
|
|
@@ -15961,7 +16186,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15961
16186
|
// Use placeholder product
|
|
15962
16187
|
blockingConditions: technology.blockingConditions,
|
|
15963
16188
|
contraindications: technology.contraindications || [],
|
|
16189
|
+
contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
|
|
15964
16190
|
treatmentBenefits: technology.benefits,
|
|
16191
|
+
treatmentBenefitIds: ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [],
|
|
15965
16192
|
preRequirements: technology.requirements.pre,
|
|
15966
16193
|
postRequirements: technology.requirements.post,
|
|
15967
16194
|
certificationRequirement: technology.certificationRequirement,
|
|
@@ -15997,11 +16224,11 @@ var ProcedureService = class extends BaseService {
|
|
|
15997
16224
|
async getProceduresForMap() {
|
|
15998
16225
|
const proceduresRef = collection29(this.db, PROCEDURES_COLLECTION);
|
|
15999
16226
|
const snapshot = await getDocs29(proceduresRef);
|
|
16000
|
-
const proceduresForMap = snapshot.docs.map((
|
|
16227
|
+
const proceduresForMap = snapshot.docs.map((doc38) => {
|
|
16001
16228
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
16002
|
-
const data =
|
|
16229
|
+
const data = doc38.data();
|
|
16003
16230
|
return {
|
|
16004
|
-
id:
|
|
16231
|
+
id: doc38.id,
|
|
16005
16232
|
name: data.name,
|
|
16006
16233
|
clinicId: (_a = data.clinicInfo) == null ? void 0 : _a.id,
|
|
16007
16234
|
clinicName: (_b = data.clinicInfo) == null ? void 0 : _b.name,
|
|
@@ -16143,7 +16370,7 @@ var ReviewService = class extends BaseService {
|
|
|
16143
16370
|
where30("patientId", "==", patientId)
|
|
16144
16371
|
);
|
|
16145
16372
|
const snapshot = await getDocs30(q);
|
|
16146
|
-
return snapshot.docs.map((
|
|
16373
|
+
return snapshot.docs.map((doc38) => doc38.data());
|
|
16147
16374
|
}
|
|
16148
16375
|
/**
|
|
16149
16376
|
* Gets all reviews for a specific clinic
|
|
@@ -16156,7 +16383,7 @@ var ReviewService = class extends BaseService {
|
|
|
16156
16383
|
where30("clinicReview.clinicId", "==", clinicId)
|
|
16157
16384
|
);
|
|
16158
16385
|
const snapshot = await getDocs30(q);
|
|
16159
|
-
return snapshot.docs.map((
|
|
16386
|
+
return snapshot.docs.map((doc38) => doc38.data());
|
|
16160
16387
|
}
|
|
16161
16388
|
/**
|
|
16162
16389
|
* Gets all reviews for a specific practitioner
|
|
@@ -16169,7 +16396,7 @@ var ReviewService = class extends BaseService {
|
|
|
16169
16396
|
where30("practitionerReview.practitionerId", "==", practitionerId)
|
|
16170
16397
|
);
|
|
16171
16398
|
const snapshot = await getDocs30(q);
|
|
16172
|
-
return snapshot.docs.map((
|
|
16399
|
+
return snapshot.docs.map((doc38) => doc38.data());
|
|
16173
16400
|
}
|
|
16174
16401
|
/**
|
|
16175
16402
|
* Gets all reviews for a specific procedure
|
|
@@ -16182,7 +16409,7 @@ var ReviewService = class extends BaseService {
|
|
|
16182
16409
|
where30("procedureReview.procedureId", "==", procedureId)
|
|
16183
16410
|
);
|
|
16184
16411
|
const snapshot = await getDocs30(q);
|
|
16185
|
-
return snapshot.docs.map((
|
|
16412
|
+
return snapshot.docs.map((doc38) => doc38.data());
|
|
16186
16413
|
}
|
|
16187
16414
|
/**
|
|
16188
16415
|
* Gets all reviews for a specific appointment
|
|
@@ -16288,7 +16515,11 @@ import {
|
|
|
16288
16515
|
getDocs as getDocs31,
|
|
16289
16516
|
query as query31,
|
|
16290
16517
|
updateDoc as updateDoc30,
|
|
16291
|
-
where as where31
|
|
16518
|
+
where as where31,
|
|
16519
|
+
limit as limit16,
|
|
16520
|
+
orderBy as orderBy18,
|
|
16521
|
+
startAfter as startAfter14,
|
|
16522
|
+
getCountFromServer as getCountFromServer2
|
|
16292
16523
|
} from "firebase/firestore";
|
|
16293
16524
|
|
|
16294
16525
|
// src/backoffice/types/brand.types.ts
|
|
@@ -16309,6 +16540,7 @@ var BrandService = class extends BaseService {
|
|
|
16309
16540
|
const now = /* @__PURE__ */ new Date();
|
|
16310
16541
|
const newBrand = {
|
|
16311
16542
|
...brand,
|
|
16543
|
+
name_lowercase: brand.name.toLowerCase(),
|
|
16312
16544
|
createdAt: now,
|
|
16313
16545
|
updatedAt: now,
|
|
16314
16546
|
isActive: true
|
|
@@ -16317,15 +16549,69 @@ var BrandService = class extends BaseService {
|
|
|
16317
16549
|
return { id: docRef.id, ...newBrand };
|
|
16318
16550
|
}
|
|
16319
16551
|
/**
|
|
16320
|
-
* Gets
|
|
16552
|
+
* Gets a paginated list of active brands, optionally filtered by name.
|
|
16553
|
+
* @param rowsPerPage - The number of brands to fetch.
|
|
16554
|
+
* @param searchTerm - An optional string to filter brand names by (starts-with search).
|
|
16555
|
+
* @param lastVisible - An optional document snapshot to use as a cursor for pagination.
|
|
16556
|
+
*/
|
|
16557
|
+
async getAll(rowsPerPage, searchTerm, lastVisible) {
|
|
16558
|
+
const constraints = [
|
|
16559
|
+
where31("isActive", "==", true),
|
|
16560
|
+
orderBy18("name_lowercase")
|
|
16561
|
+
];
|
|
16562
|
+
if (searchTerm) {
|
|
16563
|
+
const lowercasedSearchTerm = searchTerm.toLowerCase();
|
|
16564
|
+
constraints.push(where31("name_lowercase", ">=", lowercasedSearchTerm));
|
|
16565
|
+
constraints.push(
|
|
16566
|
+
where31("name_lowercase", "<=", lowercasedSearchTerm + "\uF8FF")
|
|
16567
|
+
);
|
|
16568
|
+
}
|
|
16569
|
+
if (lastVisible) {
|
|
16570
|
+
constraints.push(startAfter14(lastVisible));
|
|
16571
|
+
}
|
|
16572
|
+
constraints.push(limit16(rowsPerPage));
|
|
16573
|
+
const q = query31(this.getBrandsRef(), ...constraints);
|
|
16574
|
+
const snapshot = await getDocs31(q);
|
|
16575
|
+
const brands = snapshot.docs.map(
|
|
16576
|
+
(doc38) => ({
|
|
16577
|
+
id: doc38.id,
|
|
16578
|
+
...doc38.data()
|
|
16579
|
+
})
|
|
16580
|
+
);
|
|
16581
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
16582
|
+
return { brands, lastVisible: newLastVisible };
|
|
16583
|
+
}
|
|
16584
|
+
/**
|
|
16585
|
+
* Gets the total count of active brands, optionally filtered by name.
|
|
16586
|
+
* @param searchTerm - An optional string to filter brand names by (starts-with search).
|
|
16587
|
+
*/
|
|
16588
|
+
async getBrandsCount(searchTerm) {
|
|
16589
|
+
const constraints = [where31("isActive", "==", true)];
|
|
16590
|
+
if (searchTerm) {
|
|
16591
|
+
const lowercasedSearchTerm = searchTerm.toLowerCase();
|
|
16592
|
+
constraints.push(where31("name_lowercase", ">=", lowercasedSearchTerm));
|
|
16593
|
+
constraints.push(
|
|
16594
|
+
where31("name_lowercase", "<=", lowercasedSearchTerm + "\uF8FF")
|
|
16595
|
+
);
|
|
16596
|
+
}
|
|
16597
|
+
const q = query31(this.getBrandsRef(), ...constraints);
|
|
16598
|
+
const snapshot = await getCountFromServer2(q);
|
|
16599
|
+
return snapshot.data().count;
|
|
16600
|
+
}
|
|
16601
|
+
/**
|
|
16602
|
+
* Gets all active brands for filter dropdowns (not paginated).
|
|
16321
16603
|
*/
|
|
16322
|
-
async
|
|
16323
|
-
const q = query31(
|
|
16604
|
+
async getAllForFilter() {
|
|
16605
|
+
const q = query31(
|
|
16606
|
+
this.getBrandsRef(),
|
|
16607
|
+
where31("isActive", "==", true),
|
|
16608
|
+
orderBy18("name")
|
|
16609
|
+
);
|
|
16324
16610
|
const snapshot = await getDocs31(q);
|
|
16325
16611
|
return snapshot.docs.map(
|
|
16326
|
-
(
|
|
16327
|
-
id:
|
|
16328
|
-
...
|
|
16612
|
+
(doc38) => ({
|
|
16613
|
+
id: doc38.id,
|
|
16614
|
+
...doc38.data()
|
|
16329
16615
|
})
|
|
16330
16616
|
);
|
|
16331
16617
|
}
|
|
@@ -16337,6 +16623,9 @@ var BrandService = class extends BaseService {
|
|
|
16337
16623
|
...brand,
|
|
16338
16624
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16339
16625
|
};
|
|
16626
|
+
if (brand.name) {
|
|
16627
|
+
updateData.name_lowercase = brand.name.toLowerCase();
|
|
16628
|
+
}
|
|
16340
16629
|
const docRef = doc32(this.getBrandsRef(), brandId);
|
|
16341
16630
|
await updateDoc30(docRef, updateData);
|
|
16342
16631
|
return this.getById(brandId);
|
|
@@ -16368,9 +16657,13 @@ import {
|
|
|
16368
16657
|
addDoc as addDoc4,
|
|
16369
16658
|
collection as collection32,
|
|
16370
16659
|
doc as doc33,
|
|
16660
|
+
getCountFromServer as getCountFromServer3,
|
|
16371
16661
|
getDoc as getDoc35,
|
|
16372
16662
|
getDocs as getDocs32,
|
|
16663
|
+
limit as limit17,
|
|
16664
|
+
orderBy as orderBy19,
|
|
16373
16665
|
query as query32,
|
|
16666
|
+
startAfter as startAfter15,
|
|
16374
16667
|
updateDoc as updateDoc31,
|
|
16375
16668
|
where as where32
|
|
16376
16669
|
} from "firebase/firestore";
|
|
@@ -16403,37 +16696,87 @@ var CategoryService = class extends BaseService {
|
|
|
16403
16696
|
return { id: docRef.id, ...newCategory };
|
|
16404
16697
|
}
|
|
16405
16698
|
/**
|
|
16406
|
-
*
|
|
16407
|
-
* @
|
|
16699
|
+
* Returns counts of categories for each family.
|
|
16700
|
+
* @param active - Whether to count active or inactive categories.
|
|
16701
|
+
* @returns A record mapping family to category count.
|
|
16702
|
+
*/
|
|
16703
|
+
async getCategoryCounts(active = true) {
|
|
16704
|
+
const counts = {};
|
|
16705
|
+
const families = Object.values(ProcedureFamily);
|
|
16706
|
+
for (const family of families) {
|
|
16707
|
+
const q = query32(
|
|
16708
|
+
this.categoriesRef,
|
|
16709
|
+
where32("family", "==", family),
|
|
16710
|
+
where32("isActive", "==", active)
|
|
16711
|
+
);
|
|
16712
|
+
const snapshot = await getCountFromServer3(q);
|
|
16713
|
+
counts[family] = snapshot.data().count;
|
|
16714
|
+
}
|
|
16715
|
+
return counts;
|
|
16716
|
+
}
|
|
16717
|
+
/**
|
|
16718
|
+
* Vraća sve kategorije za potrebe filtera (bez paginacije)
|
|
16719
|
+
* @returns Lista svih aktivnih kategorija
|
|
16408
16720
|
*/
|
|
16409
|
-
async
|
|
16721
|
+
async getAllForFilter() {
|
|
16410
16722
|
const q = query32(this.categoriesRef, where32("isActive", "==", true));
|
|
16411
16723
|
const snapshot = await getDocs32(q);
|
|
16412
16724
|
return snapshot.docs.map(
|
|
16413
|
-
(
|
|
16414
|
-
id:
|
|
16415
|
-
...
|
|
16725
|
+
(doc38) => ({
|
|
16726
|
+
id: doc38.id,
|
|
16727
|
+
...doc38.data()
|
|
16728
|
+
})
|
|
16729
|
+
);
|
|
16730
|
+
}
|
|
16731
|
+
/**
|
|
16732
|
+
* Vraća sve kategorije sa paginacijom
|
|
16733
|
+
* @param options - Pagination and filter options
|
|
16734
|
+
* @returns Lista kategorija i poslednji vidljiv dokument
|
|
16735
|
+
*/
|
|
16736
|
+
async getAll(options = {}) {
|
|
16737
|
+
const { active = true, limit: queryLimit = 10, lastVisible } = options;
|
|
16738
|
+
const constraints = [
|
|
16739
|
+
where32("isActive", "==", active),
|
|
16740
|
+
orderBy19("name"),
|
|
16741
|
+
queryLimit ? limit17(queryLimit) : void 0,
|
|
16742
|
+
lastVisible ? startAfter15(lastVisible) : void 0
|
|
16743
|
+
].filter((c) => !!c);
|
|
16744
|
+
const q = query32(this.categoriesRef, ...constraints);
|
|
16745
|
+
const snapshot = await getDocs32(q);
|
|
16746
|
+
const categories = snapshot.docs.map(
|
|
16747
|
+
(doc38) => ({
|
|
16748
|
+
id: doc38.id,
|
|
16749
|
+
...doc38.data()
|
|
16416
16750
|
})
|
|
16417
16751
|
);
|
|
16752
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
16753
|
+
return { categories, lastVisible: newLastVisible };
|
|
16418
16754
|
}
|
|
16419
16755
|
/**
|
|
16420
|
-
* Vraća sve aktivne kategorije za određenu familiju procedura
|
|
16756
|
+
* Vraća sve aktivne kategorije za određenu familiju procedura sa paginacijom
|
|
16421
16757
|
* @param family - Familija procedura (aesthetics/surgery)
|
|
16758
|
+
* @param options - Pagination options
|
|
16422
16759
|
* @returns Lista kategorija koje pripadaju traženoj familiji
|
|
16423
16760
|
*/
|
|
16424
|
-
async getAllByFamily(family) {
|
|
16425
|
-
const
|
|
16426
|
-
|
|
16761
|
+
async getAllByFamily(family, options = {}) {
|
|
16762
|
+
const { active = true, limit: queryLimit = 10, lastVisible } = options;
|
|
16763
|
+
const constraints = [
|
|
16427
16764
|
where32("family", "==", family),
|
|
16428
|
-
where32("isActive", "==",
|
|
16429
|
-
|
|
16765
|
+
where32("isActive", "==", active),
|
|
16766
|
+
orderBy19("name"),
|
|
16767
|
+
queryLimit ? limit17(queryLimit) : void 0,
|
|
16768
|
+
lastVisible ? startAfter15(lastVisible) : void 0
|
|
16769
|
+
].filter((c) => !!c);
|
|
16770
|
+
const q = query32(this.categoriesRef, ...constraints);
|
|
16430
16771
|
const snapshot = await getDocs32(q);
|
|
16431
|
-
|
|
16432
|
-
(
|
|
16433
|
-
id:
|
|
16434
|
-
...
|
|
16772
|
+
const categories = snapshot.docs.map(
|
|
16773
|
+
(doc38) => ({
|
|
16774
|
+
id: doc38.id,
|
|
16775
|
+
...doc38.data()
|
|
16435
16776
|
})
|
|
16436
16777
|
);
|
|
16778
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
16779
|
+
return { categories, lastVisible: newLastVisible };
|
|
16437
16780
|
}
|
|
16438
16781
|
/**
|
|
16439
16782
|
* Ažurira postojeću kategoriju
|
|
@@ -16457,6 +16800,13 @@ var CategoryService = class extends BaseService {
|
|
|
16457
16800
|
async delete(id) {
|
|
16458
16801
|
await this.update(id, { isActive: false });
|
|
16459
16802
|
}
|
|
16803
|
+
/**
|
|
16804
|
+
* Reactivates a category by setting its isActive flag to true.
|
|
16805
|
+
* @param id - The ID of the category to reactivate.
|
|
16806
|
+
*/
|
|
16807
|
+
async reactivate(id) {
|
|
16808
|
+
await this.update(id, { isActive: true });
|
|
16809
|
+
}
|
|
16460
16810
|
/**
|
|
16461
16811
|
* Vraća kategoriju po ID-u
|
|
16462
16812
|
* @param id - ID tražene kategorije
|
|
@@ -16477,10 +16827,17 @@ var CategoryService = class extends BaseService {
|
|
|
16477
16827
|
import {
|
|
16478
16828
|
addDoc as addDoc5,
|
|
16479
16829
|
collection as collection33,
|
|
16830
|
+
collectionGroup as collectionGroup2,
|
|
16831
|
+
deleteDoc as deleteDoc20,
|
|
16480
16832
|
doc as doc34,
|
|
16833
|
+
getCountFromServer as getCountFromServer4,
|
|
16481
16834
|
getDoc as getDoc36,
|
|
16482
16835
|
getDocs as getDocs33,
|
|
16836
|
+
limit as limit18,
|
|
16837
|
+
orderBy as orderBy20,
|
|
16483
16838
|
query as query33,
|
|
16839
|
+
setDoc as setDoc28,
|
|
16840
|
+
startAfter as startAfter16,
|
|
16484
16841
|
updateDoc as updateDoc32,
|
|
16485
16842
|
where as where33
|
|
16486
16843
|
} from "firebase/firestore";
|
|
@@ -16524,20 +16881,110 @@ var SubcategoryService = class extends BaseService {
|
|
|
16524
16881
|
return { id: docRef.id, ...newSubcategory };
|
|
16525
16882
|
}
|
|
16526
16883
|
/**
|
|
16527
|
-
*
|
|
16884
|
+
* Returns counts of subcategories for all categories.
|
|
16885
|
+
* @param active - Whether to count active or inactive subcategories.
|
|
16886
|
+
* @returns A record mapping category ID to subcategory count.
|
|
16887
|
+
*/
|
|
16888
|
+
async getSubcategoryCounts(active = true) {
|
|
16889
|
+
const categoriesRef = collection33(this.db, CATEGORIES_COLLECTION);
|
|
16890
|
+
const categoriesSnapshot = await getDocs33(categoriesRef);
|
|
16891
|
+
const counts = {};
|
|
16892
|
+
for (const categoryDoc of categoriesSnapshot.docs) {
|
|
16893
|
+
const categoryId = categoryDoc.id;
|
|
16894
|
+
const subcategoriesRef = this.getSubcategoriesRef(categoryId);
|
|
16895
|
+
const q = query33(subcategoriesRef, where33("isActive", "==", active));
|
|
16896
|
+
const snapshot = await getCountFromServer4(q);
|
|
16897
|
+
counts[categoryId] = snapshot.data().count;
|
|
16898
|
+
}
|
|
16899
|
+
return counts;
|
|
16900
|
+
}
|
|
16901
|
+
/**
|
|
16902
|
+
* Vraća sve aktivne podkategorije za određenu kategoriju sa paginacijom
|
|
16528
16903
|
* @param categoryId - ID kategorije čije podkategorije tražimo
|
|
16529
|
-
* @
|
|
16904
|
+
* @param options - Pagination options
|
|
16905
|
+
* @returns Lista aktivnih podkategorija i poslednji vidljiv dokument
|
|
16906
|
+
*/
|
|
16907
|
+
async getAllByCategoryId(categoryId, options = {}) {
|
|
16908
|
+
const { active = true, limit: queryLimit = 10, lastVisible } = options;
|
|
16909
|
+
const constraints = [
|
|
16910
|
+
where33("isActive", "==", active),
|
|
16911
|
+
orderBy20("name"),
|
|
16912
|
+
queryLimit ? limit18(queryLimit) : void 0,
|
|
16913
|
+
lastVisible ? startAfter16(lastVisible) : void 0
|
|
16914
|
+
].filter((c) => !!c);
|
|
16915
|
+
const q = query33(this.getSubcategoriesRef(categoryId), ...constraints);
|
|
16916
|
+
const querySnapshot = await getDocs33(q);
|
|
16917
|
+
const subcategories = querySnapshot.docs.map(
|
|
16918
|
+
(doc38) => ({
|
|
16919
|
+
id: doc38.id,
|
|
16920
|
+
...doc38.data()
|
|
16921
|
+
})
|
|
16922
|
+
);
|
|
16923
|
+
const newLastVisible = querySnapshot.docs[querySnapshot.docs.length - 1];
|
|
16924
|
+
return { subcategories, lastVisible: newLastVisible };
|
|
16925
|
+
}
|
|
16926
|
+
/**
|
|
16927
|
+
* Vraća sve podkategorije sa paginacijom koristeći collection group query.
|
|
16928
|
+
* NOTE: This query requires a composite index in Firestore on the 'subcategories' collection group.
|
|
16929
|
+
* The index should be on 'isActive' (ascending) and 'name' (ascending).
|
|
16930
|
+
* Firestore will provide a link to create this index in the console error if it's missing.
|
|
16931
|
+
* @param options - Pagination options
|
|
16932
|
+
* @returns Lista podkategorija i poslednji vidljiv dokument
|
|
16530
16933
|
*/
|
|
16531
|
-
async
|
|
16934
|
+
async getAll(options = {}) {
|
|
16935
|
+
const { active = true, limit: queryLimit = 10, lastVisible } = options;
|
|
16936
|
+
const constraints = [
|
|
16937
|
+
where33("isActive", "==", active),
|
|
16938
|
+
orderBy20("name"),
|
|
16939
|
+
queryLimit ? limit18(queryLimit) : void 0,
|
|
16940
|
+
lastVisible ? startAfter16(lastVisible) : void 0
|
|
16941
|
+
].filter((c) => !!c);
|
|
16942
|
+
const q = query33(
|
|
16943
|
+
collectionGroup2(this.db, SUBCATEGORIES_COLLECTION),
|
|
16944
|
+
...constraints
|
|
16945
|
+
);
|
|
16946
|
+
const querySnapshot = await getDocs33(q);
|
|
16947
|
+
const subcategories = querySnapshot.docs.map(
|
|
16948
|
+
(doc38) => ({
|
|
16949
|
+
id: doc38.id,
|
|
16950
|
+
...doc38.data()
|
|
16951
|
+
})
|
|
16952
|
+
);
|
|
16953
|
+
const newLastVisible = querySnapshot.docs[querySnapshot.docs.length - 1];
|
|
16954
|
+
return { subcategories, lastVisible: newLastVisible };
|
|
16955
|
+
}
|
|
16956
|
+
/**
|
|
16957
|
+
* Vraća sve subkategorije za određenu kategoriju za potrebe filtera (bez paginacije)
|
|
16958
|
+
* @param categoryId - ID kategorije čije subkategorije tražimo
|
|
16959
|
+
* @returns Lista svih aktivnih subkategorija
|
|
16960
|
+
*/
|
|
16961
|
+
async getAllForFilterByCategoryId(categoryId) {
|
|
16532
16962
|
const q = query33(
|
|
16533
16963
|
this.getSubcategoriesRef(categoryId),
|
|
16534
16964
|
where33("isActive", "==", true)
|
|
16535
16965
|
);
|
|
16536
|
-
const
|
|
16537
|
-
return
|
|
16538
|
-
(
|
|
16539
|
-
id:
|
|
16540
|
-
...
|
|
16966
|
+
const querySnapshot = await getDocs33(q);
|
|
16967
|
+
return querySnapshot.docs.map(
|
|
16968
|
+
(doc38) => ({
|
|
16969
|
+
id: doc38.id,
|
|
16970
|
+
...doc38.data()
|
|
16971
|
+
})
|
|
16972
|
+
);
|
|
16973
|
+
}
|
|
16974
|
+
/**
|
|
16975
|
+
* Vraća sve subkategorije za potrebe filtera (bez paginacije)
|
|
16976
|
+
* @returns Lista svih aktivnih subkategorija
|
|
16977
|
+
*/
|
|
16978
|
+
async getAllForFilter() {
|
|
16979
|
+
const q = query33(
|
|
16980
|
+
collectionGroup2(this.db, SUBCATEGORIES_COLLECTION),
|
|
16981
|
+
where33("isActive", "==", true)
|
|
16982
|
+
);
|
|
16983
|
+
const querySnapshot = await getDocs33(q);
|
|
16984
|
+
return querySnapshot.docs.map(
|
|
16985
|
+
(doc38) => ({
|
|
16986
|
+
id: doc38.id,
|
|
16987
|
+
...doc38.data()
|
|
16541
16988
|
})
|
|
16542
16989
|
);
|
|
16543
16990
|
}
|
|
@@ -16549,13 +16996,42 @@ var SubcategoryService = class extends BaseService {
|
|
|
16549
16996
|
* @returns Ažurirana podkategorija
|
|
16550
16997
|
*/
|
|
16551
16998
|
async update(categoryId, subcategoryId, subcategory) {
|
|
16552
|
-
const
|
|
16553
|
-
|
|
16554
|
-
|
|
16555
|
-
|
|
16556
|
-
|
|
16557
|
-
|
|
16558
|
-
|
|
16999
|
+
const newCategoryId = subcategory.categoryId;
|
|
17000
|
+
if (newCategoryId && newCategoryId !== categoryId) {
|
|
17001
|
+
const oldDocRef = doc34(
|
|
17002
|
+
this.getSubcategoriesRef(categoryId),
|
|
17003
|
+
subcategoryId
|
|
17004
|
+
);
|
|
17005
|
+
const docSnap = await getDoc36(oldDocRef);
|
|
17006
|
+
if (!docSnap.exists()) {
|
|
17007
|
+
throw new Error("Subcategory to update does not exist.");
|
|
17008
|
+
}
|
|
17009
|
+
const existingData = docSnap.data();
|
|
17010
|
+
const newData = {
|
|
17011
|
+
...existingData,
|
|
17012
|
+
...subcategory,
|
|
17013
|
+
categoryId: newCategoryId,
|
|
17014
|
+
// Ensure categoryId is updated
|
|
17015
|
+
createdAt: existingData.createdAt,
|
|
17016
|
+
// Preserve original creation date
|
|
17017
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
17018
|
+
};
|
|
17019
|
+
const newDocRef = doc34(
|
|
17020
|
+
this.getSubcategoriesRef(newCategoryId),
|
|
17021
|
+
subcategoryId
|
|
17022
|
+
);
|
|
17023
|
+
await setDoc28(newDocRef, newData);
|
|
17024
|
+
await deleteDoc20(oldDocRef);
|
|
17025
|
+
return { id: subcategoryId, ...newData };
|
|
17026
|
+
} else {
|
|
17027
|
+
const updateData = {
|
|
17028
|
+
...subcategory,
|
|
17029
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
17030
|
+
};
|
|
17031
|
+
const docRef = doc34(this.getSubcategoriesRef(categoryId), subcategoryId);
|
|
17032
|
+
await updateDoc32(docRef, updateData);
|
|
17033
|
+
return this.getById(categoryId, subcategoryId);
|
|
17034
|
+
}
|
|
16559
17035
|
}
|
|
16560
17036
|
/**
|
|
16561
17037
|
* Soft delete podkategorije (postavlja isActive na false)
|
|
@@ -16565,6 +17041,14 @@ var SubcategoryService = class extends BaseService {
|
|
|
16565
17041
|
async delete(categoryId, subcategoryId) {
|
|
16566
17042
|
await this.update(categoryId, subcategoryId, { isActive: false });
|
|
16567
17043
|
}
|
|
17044
|
+
/**
|
|
17045
|
+
* Reactivates a subcategory by setting its isActive flag to true.
|
|
17046
|
+
* @param categoryId - The ID of the category to which the subcategory belongs.
|
|
17047
|
+
* @param subcategoryId - The ID of the subcategory to reactivate.
|
|
17048
|
+
*/
|
|
17049
|
+
async reactivate(categoryId, subcategoryId) {
|
|
17050
|
+
await this.update(categoryId, subcategoryId, { isActive: true });
|
|
17051
|
+
}
|
|
16568
17052
|
/**
|
|
16569
17053
|
* Vraća podkategoriju po ID-u
|
|
16570
17054
|
* @param categoryId - ID kategorije kojoj pripada podkategorija
|
|
@@ -16589,7 +17073,10 @@ import {
|
|
|
16589
17073
|
doc as doc35,
|
|
16590
17074
|
getDoc as getDoc37,
|
|
16591
17075
|
getDocs as getDocs34,
|
|
17076
|
+
limit as limit19,
|
|
17077
|
+
orderBy as orderBy21,
|
|
16592
17078
|
query as query34,
|
|
17079
|
+
startAfter as startAfter17,
|
|
16593
17080
|
updateDoc as updateDoc33,
|
|
16594
17081
|
where as where34,
|
|
16595
17082
|
arrayUnion as arrayUnion9,
|
|
@@ -16601,137 +17088,185 @@ var DEFAULT_CERTIFICATION_REQUIREMENT = {
|
|
|
16601
17088
|
};
|
|
16602
17089
|
var TechnologyService = class extends BaseService {
|
|
16603
17090
|
/**
|
|
16604
|
-
*
|
|
17091
|
+
* Reference to the Firestore collection of technologies.
|
|
16605
17092
|
*/
|
|
16606
|
-
|
|
17093
|
+
get technologiesRef() {
|
|
16607
17094
|
return collection34(this.db, TECHNOLOGIES_COLLECTION);
|
|
16608
17095
|
}
|
|
16609
17096
|
/**
|
|
16610
|
-
*
|
|
16611
|
-
* @param technology -
|
|
16612
|
-
* @returns
|
|
17097
|
+
* Creates a new technology.
|
|
17098
|
+
* @param technology - Data for the new technology.
|
|
17099
|
+
* @returns The created technology with its generated ID.
|
|
16613
17100
|
*/
|
|
16614
17101
|
async create(technology) {
|
|
16615
17102
|
const now = /* @__PURE__ */ new Date();
|
|
16616
17103
|
const newTechnology = {
|
|
16617
|
-
|
|
16618
|
-
|
|
16619
|
-
|
|
16620
|
-
|
|
16621
|
-
|
|
16622
|
-
|
|
16623
|
-
post: []
|
|
16624
|
-
},
|
|
17104
|
+
name: technology.name,
|
|
17105
|
+
description: technology.description,
|
|
17106
|
+
family: technology.family,
|
|
17107
|
+
categoryId: technology.categoryId,
|
|
17108
|
+
subcategoryId: technology.subcategoryId,
|
|
17109
|
+
requirements: technology.requirements || { pre: [], post: [] },
|
|
16625
17110
|
blockingConditions: technology.blockingConditions || [],
|
|
16626
17111
|
contraindications: technology.contraindications || [],
|
|
16627
17112
|
benefits: technology.benefits || [],
|
|
16628
|
-
certificationRequirement: technology.certificationRequirement || DEFAULT_CERTIFICATION_REQUIREMENT
|
|
17113
|
+
certificationRequirement: technology.certificationRequirement || DEFAULT_CERTIFICATION_REQUIREMENT,
|
|
17114
|
+
documentationTemplates: technology.documentationTemplates || [],
|
|
17115
|
+
isActive: true,
|
|
17116
|
+
createdAt: now,
|
|
17117
|
+
updatedAt: now
|
|
16629
17118
|
};
|
|
16630
|
-
|
|
17119
|
+
if (technology.technicalDetails) {
|
|
17120
|
+
newTechnology.technicalDetails = technology.technicalDetails;
|
|
17121
|
+
}
|
|
17122
|
+
const docRef = await addDoc6(this.technologiesRef, newTechnology);
|
|
16631
17123
|
return { id: docRef.id, ...newTechnology };
|
|
16632
17124
|
}
|
|
16633
17125
|
/**
|
|
16634
|
-
*
|
|
16635
|
-
* @
|
|
17126
|
+
* Returns counts of technologies for each subcategory.
|
|
17127
|
+
* @param active - Whether to count active or inactive technologies.
|
|
17128
|
+
* @returns A record mapping subcategory ID to technology count.
|
|
16636
17129
|
*/
|
|
16637
|
-
async
|
|
16638
|
-
const q = query34(this.
|
|
17130
|
+
async getTechnologyCounts(active = true) {
|
|
17131
|
+
const q = query34(this.technologiesRef, where34("isActive", "==", active));
|
|
16639
17132
|
const snapshot = await getDocs34(q);
|
|
16640
|
-
|
|
16641
|
-
|
|
16642
|
-
|
|
16643
|
-
|
|
16644
|
-
|
|
16645
|
-
|
|
17133
|
+
const counts = {};
|
|
17134
|
+
snapshot.docs.forEach((doc38) => {
|
|
17135
|
+
const tech = doc38.data();
|
|
17136
|
+
counts[tech.subcategoryId] = (counts[tech.subcategoryId] || 0) + 1;
|
|
17137
|
+
});
|
|
17138
|
+
return counts;
|
|
16646
17139
|
}
|
|
16647
17140
|
/**
|
|
16648
|
-
*
|
|
16649
|
-
* @param
|
|
16650
|
-
* @returns
|
|
17141
|
+
* Returns counts of technologies for each category.
|
|
17142
|
+
* @param active - Whether to count active or inactive technologies.
|
|
17143
|
+
* @returns A record mapping category ID to technology count.
|
|
16651
17144
|
*/
|
|
16652
|
-
async
|
|
16653
|
-
const q = query34(
|
|
16654
|
-
this.getTechnologiesRef(),
|
|
16655
|
-
where34("isActive", "==", true),
|
|
16656
|
-
where34("family", "==", family)
|
|
16657
|
-
);
|
|
17145
|
+
async getTechnologyCountsByCategory(active = true) {
|
|
17146
|
+
const q = query34(this.technologiesRef, where34("isActive", "==", active));
|
|
16658
17147
|
const snapshot = await getDocs34(q);
|
|
16659
|
-
|
|
16660
|
-
|
|
16661
|
-
|
|
16662
|
-
|
|
17148
|
+
const counts = {};
|
|
17149
|
+
snapshot.docs.forEach((doc38) => {
|
|
17150
|
+
const tech = doc38.data();
|
|
17151
|
+
counts[tech.categoryId] = (counts[tech.categoryId] || 0) + 1;
|
|
17152
|
+
});
|
|
17153
|
+
return counts;
|
|
17154
|
+
}
|
|
17155
|
+
/**
|
|
17156
|
+
* Returns all technologies with pagination.
|
|
17157
|
+
* @param options - Pagination and filter options.
|
|
17158
|
+
* @returns A list of technologies and the last visible document.
|
|
17159
|
+
*/
|
|
17160
|
+
async getAll(options = {}) {
|
|
17161
|
+
const { active = true, limit: queryLimit = 10, lastVisible } = options;
|
|
17162
|
+
const constraints = [
|
|
17163
|
+
where34("isActive", "==", active),
|
|
17164
|
+
orderBy21("name"),
|
|
17165
|
+
queryLimit ? limit19(queryLimit) : void 0,
|
|
17166
|
+
lastVisible ? startAfter17(lastVisible) : void 0
|
|
17167
|
+
].filter((c) => !!c);
|
|
17168
|
+
const q = query34(this.technologiesRef, ...constraints);
|
|
17169
|
+
const snapshot = await getDocs34(q);
|
|
17170
|
+
const technologies = snapshot.docs.map(
|
|
17171
|
+
(doc38) => ({
|
|
17172
|
+
id: doc38.id,
|
|
17173
|
+
...doc38.data()
|
|
16663
17174
|
})
|
|
16664
17175
|
);
|
|
17176
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
17177
|
+
return { technologies, lastVisible: newLastVisible };
|
|
16665
17178
|
}
|
|
16666
17179
|
/**
|
|
16667
|
-
*
|
|
16668
|
-
* @param categoryId - ID
|
|
16669
|
-
* @
|
|
17180
|
+
* Returns all technologies for a specific category with pagination.
|
|
17181
|
+
* @param categoryId - The ID of the category.
|
|
17182
|
+
* @param options - Pagination options.
|
|
17183
|
+
* @returns A list of technologies for the specified category.
|
|
16670
17184
|
*/
|
|
16671
|
-
async getAllByCategoryId(categoryId) {
|
|
16672
|
-
const
|
|
16673
|
-
|
|
16674
|
-
where34("
|
|
16675
|
-
where34("
|
|
16676
|
-
|
|
17185
|
+
async getAllByCategoryId(categoryId, options = {}) {
|
|
17186
|
+
const { active = true, limit: queryLimit = 10, lastVisible } = options;
|
|
17187
|
+
const constraints = [
|
|
17188
|
+
where34("categoryId", "==", categoryId),
|
|
17189
|
+
where34("isActive", "==", active),
|
|
17190
|
+
orderBy21("name"),
|
|
17191
|
+
queryLimit ? limit19(queryLimit) : void 0,
|
|
17192
|
+
lastVisible ? startAfter17(lastVisible) : void 0
|
|
17193
|
+
].filter((c) => !!c);
|
|
17194
|
+
const q = query34(this.technologiesRef, ...constraints);
|
|
16677
17195
|
const snapshot = await getDocs34(q);
|
|
16678
|
-
|
|
16679
|
-
(
|
|
16680
|
-
id:
|
|
16681
|
-
...
|
|
17196
|
+
const technologies = snapshot.docs.map(
|
|
17197
|
+
(doc38) => ({
|
|
17198
|
+
id: doc38.id,
|
|
17199
|
+
...doc38.data()
|
|
16682
17200
|
})
|
|
16683
17201
|
);
|
|
17202
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
17203
|
+
return { technologies, lastVisible: newLastVisible };
|
|
16684
17204
|
}
|
|
16685
17205
|
/**
|
|
16686
|
-
*
|
|
16687
|
-
* @param subcategoryId - ID
|
|
16688
|
-
* @
|
|
17206
|
+
* Returns all technologies for a specific subcategory with pagination.
|
|
17207
|
+
* @param subcategoryId - The ID of the subcategory.
|
|
17208
|
+
* @param options - Pagination options.
|
|
17209
|
+
* @returns A list of technologies for the specified subcategory.
|
|
16689
17210
|
*/
|
|
16690
|
-
async getAllBySubcategoryId(subcategoryId) {
|
|
16691
|
-
const
|
|
16692
|
-
|
|
16693
|
-
where34("
|
|
16694
|
-
where34("
|
|
16695
|
-
|
|
17211
|
+
async getAllBySubcategoryId(subcategoryId, options = {}) {
|
|
17212
|
+
const { active = true, limit: queryLimit = 10, lastVisible } = options;
|
|
17213
|
+
const constraints = [
|
|
17214
|
+
where34("subcategoryId", "==", subcategoryId),
|
|
17215
|
+
where34("isActive", "==", active),
|
|
17216
|
+
orderBy21("name"),
|
|
17217
|
+
queryLimit ? limit19(queryLimit) : void 0,
|
|
17218
|
+
lastVisible ? startAfter17(lastVisible) : void 0
|
|
17219
|
+
].filter((c) => !!c);
|
|
17220
|
+
const q = query34(this.technologiesRef, ...constraints);
|
|
16696
17221
|
const snapshot = await getDocs34(q);
|
|
16697
|
-
|
|
16698
|
-
(
|
|
16699
|
-
id:
|
|
16700
|
-
...
|
|
17222
|
+
const technologies = snapshot.docs.map(
|
|
17223
|
+
(doc38) => ({
|
|
17224
|
+
id: doc38.id,
|
|
17225
|
+
...doc38.data()
|
|
16701
17226
|
})
|
|
16702
17227
|
);
|
|
17228
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
17229
|
+
return { technologies, lastVisible: newLastVisible };
|
|
16703
17230
|
}
|
|
16704
17231
|
/**
|
|
16705
|
-
*
|
|
16706
|
-
* @param
|
|
16707
|
-
* @param technology -
|
|
16708
|
-
* @returns
|
|
17232
|
+
* Updates an existing technology.
|
|
17233
|
+
* @param id - The ID of the technology to update.
|
|
17234
|
+
* @param technology - New data for the technology.
|
|
17235
|
+
* @returns The updated technology.
|
|
16709
17236
|
*/
|
|
16710
|
-
async update(
|
|
16711
|
-
const updateData = {
|
|
16712
|
-
|
|
16713
|
-
|
|
16714
|
-
|
|
16715
|
-
|
|
17237
|
+
async update(id, technology) {
|
|
17238
|
+
const updateData = { ...technology };
|
|
17239
|
+
Object.keys(updateData).forEach((key) => {
|
|
17240
|
+
if (updateData[key] === void 0) {
|
|
17241
|
+
delete updateData[key];
|
|
17242
|
+
}
|
|
17243
|
+
});
|
|
17244
|
+
updateData.updatedAt = /* @__PURE__ */ new Date();
|
|
17245
|
+
const docRef = doc35(this.technologiesRef, id);
|
|
16716
17246
|
await updateDoc33(docRef, updateData);
|
|
16717
|
-
return this.getById(
|
|
17247
|
+
return this.getById(id);
|
|
16718
17248
|
}
|
|
16719
17249
|
/**
|
|
16720
|
-
* Soft
|
|
16721
|
-
* @param
|
|
17250
|
+
* Soft deletes a technology.
|
|
17251
|
+
* @param id - The ID of the technology to delete.
|
|
16722
17252
|
*/
|
|
16723
|
-
async delete(
|
|
16724
|
-
await this.update(
|
|
16725
|
-
isActive: false
|
|
16726
|
-
});
|
|
17253
|
+
async delete(id) {
|
|
17254
|
+
await this.update(id, { isActive: false });
|
|
16727
17255
|
}
|
|
16728
17256
|
/**
|
|
16729
|
-
*
|
|
16730
|
-
* @param
|
|
16731
|
-
* @returns Tehnologija ili null ako ne postoji
|
|
17257
|
+
* Reactivates a technology.
|
|
17258
|
+
* @param id - The ID of the technology to reactivate.
|
|
16732
17259
|
*/
|
|
16733
|
-
async
|
|
16734
|
-
|
|
17260
|
+
async reactivate(id) {
|
|
17261
|
+
await this.update(id, { isActive: true });
|
|
17262
|
+
}
|
|
17263
|
+
/**
|
|
17264
|
+
* Returns a technology by its ID.
|
|
17265
|
+
* @param id - The ID of the requested technology.
|
|
17266
|
+
* @returns The technology or null if it doesn't exist.
|
|
17267
|
+
*/
|
|
17268
|
+
async getById(id) {
|
|
17269
|
+
const docRef = doc35(this.technologiesRef, id);
|
|
16735
17270
|
const docSnap = await getDoc37(docRef);
|
|
16736
17271
|
if (!docSnap.exists()) return null;
|
|
16737
17272
|
return {
|
|
@@ -16746,7 +17281,7 @@ var TechnologyService = class extends BaseService {
|
|
|
16746
17281
|
* @returns Ažurirana tehnologija sa novim zahtevom
|
|
16747
17282
|
*/
|
|
16748
17283
|
async addRequirement(technologyId, requirement) {
|
|
16749
|
-
const docRef = doc35(this.
|
|
17284
|
+
const docRef = doc35(this.technologiesRef, technologyId);
|
|
16750
17285
|
const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
|
|
16751
17286
|
await updateDoc33(docRef, {
|
|
16752
17287
|
[requirementType]: arrayUnion9(requirement),
|
|
@@ -16761,7 +17296,7 @@ var TechnologyService = class extends BaseService {
|
|
|
16761
17296
|
* @returns Ažurirana tehnologija bez uklonjenog zahteva
|
|
16762
17297
|
*/
|
|
16763
17298
|
async removeRequirement(technologyId, requirement) {
|
|
16764
|
-
const docRef = doc35(this.
|
|
17299
|
+
const docRef = doc35(this.technologiesRef, technologyId);
|
|
16765
17300
|
const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
|
|
16766
17301
|
await updateDoc33(docRef, {
|
|
16767
17302
|
[requirementType]: arrayRemove8(requirement),
|
|
@@ -16801,7 +17336,7 @@ var TechnologyService = class extends BaseService {
|
|
|
16801
17336
|
* @returns Ažurirana tehnologija
|
|
16802
17337
|
*/
|
|
16803
17338
|
async addBlockingCondition(technologyId, condition) {
|
|
16804
|
-
const docRef = doc35(this.
|
|
17339
|
+
const docRef = doc35(this.technologiesRef, technologyId);
|
|
16805
17340
|
await updateDoc33(docRef, {
|
|
16806
17341
|
blockingConditions: arrayUnion9(condition),
|
|
16807
17342
|
updatedAt: /* @__PURE__ */ new Date()
|
|
@@ -16815,7 +17350,7 @@ var TechnologyService = class extends BaseService {
|
|
|
16815
17350
|
* @returns Ažurirana tehnologija
|
|
16816
17351
|
*/
|
|
16817
17352
|
async removeBlockingCondition(technologyId, condition) {
|
|
16818
|
-
const docRef = doc35(this.
|
|
17353
|
+
const docRef = doc35(this.technologiesRef, technologyId);
|
|
16819
17354
|
await updateDoc33(docRef, {
|
|
16820
17355
|
blockingConditions: arrayRemove8(condition),
|
|
16821
17356
|
updatedAt: /* @__PURE__ */ new Date()
|
|
@@ -16829,9 +17364,17 @@ var TechnologyService = class extends BaseService {
|
|
|
16829
17364
|
* @returns Ažurirana tehnologija
|
|
16830
17365
|
*/
|
|
16831
17366
|
async addContraindication(technologyId, contraindication) {
|
|
16832
|
-
const docRef = doc35(this.
|
|
17367
|
+
const docRef = doc35(this.technologiesRef, technologyId);
|
|
17368
|
+
const technology = await this.getById(technologyId);
|
|
17369
|
+
if (!technology) {
|
|
17370
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
17371
|
+
}
|
|
17372
|
+
const existingContraindications = technology.contraindications || [];
|
|
17373
|
+
if (existingContraindications.some((c) => c.id === contraindication.id)) {
|
|
17374
|
+
return technology;
|
|
17375
|
+
}
|
|
16833
17376
|
await updateDoc33(docRef, {
|
|
16834
|
-
contraindications:
|
|
17377
|
+
contraindications: [...existingContraindications, contraindication],
|
|
16835
17378
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16836
17379
|
});
|
|
16837
17380
|
return this.getById(technologyId);
|
|
@@ -16843,9 +17386,45 @@ var TechnologyService = class extends BaseService {
|
|
|
16843
17386
|
* @returns Ažurirana tehnologija
|
|
16844
17387
|
*/
|
|
16845
17388
|
async removeContraindication(technologyId, contraindication) {
|
|
16846
|
-
const docRef = doc35(this.
|
|
17389
|
+
const docRef = doc35(this.technologiesRef, technologyId);
|
|
17390
|
+
const technology = await this.getById(technologyId);
|
|
17391
|
+
if (!technology) {
|
|
17392
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
17393
|
+
}
|
|
17394
|
+
const updatedContraindications = (technology.contraindications || []).filter((c) => c.id !== contraindication.id);
|
|
17395
|
+
await updateDoc33(docRef, {
|
|
17396
|
+
contraindications: updatedContraindications,
|
|
17397
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
17398
|
+
});
|
|
17399
|
+
return this.getById(technologyId);
|
|
17400
|
+
}
|
|
17401
|
+
/**
|
|
17402
|
+
* Updates an existing contraindication in a technology's list.
|
|
17403
|
+
* If the contraindication does not exist, it will not be added.
|
|
17404
|
+
* @param technologyId - ID of the technology
|
|
17405
|
+
* @param contraindication - The updated contraindication object
|
|
17406
|
+
* @returns The updated technology
|
|
17407
|
+
*/
|
|
17408
|
+
async updateContraindication(technologyId, contraindication) {
|
|
17409
|
+
const docRef = doc35(this.technologiesRef, technologyId);
|
|
17410
|
+
const technology = await this.getById(technologyId);
|
|
17411
|
+
if (!technology) {
|
|
17412
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
17413
|
+
}
|
|
17414
|
+
const contraindications = technology.contraindications || [];
|
|
17415
|
+
const index = contraindications.findIndex(
|
|
17416
|
+
(c) => c.id === contraindication.id
|
|
17417
|
+
);
|
|
17418
|
+
if (index === -1) {
|
|
17419
|
+
console.warn(
|
|
17420
|
+
`Contraindication with id ${contraindication.id} not found for technology ${technologyId}. No update performed.`
|
|
17421
|
+
);
|
|
17422
|
+
return technology;
|
|
17423
|
+
}
|
|
17424
|
+
const updatedContraindications = [...contraindications];
|
|
17425
|
+
updatedContraindications[index] = contraindication;
|
|
16847
17426
|
await updateDoc33(docRef, {
|
|
16848
|
-
contraindications:
|
|
17427
|
+
contraindications: updatedContraindications,
|
|
16849
17428
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16850
17429
|
});
|
|
16851
17430
|
return this.getById(technologyId);
|
|
@@ -16857,9 +17436,17 @@ var TechnologyService = class extends BaseService {
|
|
|
16857
17436
|
* @returns Ažurirana tehnologija
|
|
16858
17437
|
*/
|
|
16859
17438
|
async addBenefit(technologyId, benefit) {
|
|
16860
|
-
const docRef = doc35(this.
|
|
17439
|
+
const docRef = doc35(this.technologiesRef, technologyId);
|
|
17440
|
+
const technology = await this.getById(technologyId);
|
|
17441
|
+
if (!technology) {
|
|
17442
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
17443
|
+
}
|
|
17444
|
+
const existingBenefits = technology.benefits || [];
|
|
17445
|
+
if (existingBenefits.some((b) => b.id === benefit.id)) {
|
|
17446
|
+
return technology;
|
|
17447
|
+
}
|
|
16861
17448
|
await updateDoc33(docRef, {
|
|
16862
|
-
benefits:
|
|
17449
|
+
benefits: [...existingBenefits, benefit],
|
|
16863
17450
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16864
17451
|
});
|
|
16865
17452
|
return this.getById(technologyId);
|
|
@@ -16871,9 +17458,45 @@ var TechnologyService = class extends BaseService {
|
|
|
16871
17458
|
* @returns Ažurirana tehnologija
|
|
16872
17459
|
*/
|
|
16873
17460
|
async removeBenefit(technologyId, benefit) {
|
|
16874
|
-
const docRef = doc35(this.
|
|
17461
|
+
const docRef = doc35(this.technologiesRef, technologyId);
|
|
17462
|
+
const technology = await this.getById(technologyId);
|
|
17463
|
+
if (!technology) {
|
|
17464
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
17465
|
+
}
|
|
17466
|
+
const updatedBenefits = (technology.benefits || []).filter(
|
|
17467
|
+
(b) => b.id !== benefit.id
|
|
17468
|
+
);
|
|
17469
|
+
await updateDoc33(docRef, {
|
|
17470
|
+
benefits: updatedBenefits,
|
|
17471
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
17472
|
+
});
|
|
17473
|
+
return this.getById(technologyId);
|
|
17474
|
+
}
|
|
17475
|
+
/**
|
|
17476
|
+
* Updates an existing benefit in a technology's list.
|
|
17477
|
+
* If the benefit does not exist, it will not be added.
|
|
17478
|
+
* @param technologyId - ID of the technology
|
|
17479
|
+
* @param benefit - The updated benefit object
|
|
17480
|
+
* @returns The updated technology
|
|
17481
|
+
*/
|
|
17482
|
+
async updateBenefit(technologyId, benefit) {
|
|
17483
|
+
const docRef = doc35(this.technologiesRef, technologyId);
|
|
17484
|
+
const technology = await this.getById(technologyId);
|
|
17485
|
+
if (!technology) {
|
|
17486
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
17487
|
+
}
|
|
17488
|
+
const benefits = technology.benefits || [];
|
|
17489
|
+
const index = benefits.findIndex((b) => b.id === benefit.id);
|
|
17490
|
+
if (index === -1) {
|
|
17491
|
+
console.warn(
|
|
17492
|
+
`Benefit with id ${benefit.id} not found for technology ${technologyId}. No update performed.`
|
|
17493
|
+
);
|
|
17494
|
+
return technology;
|
|
17495
|
+
}
|
|
17496
|
+
const updatedBenefits = [...benefits];
|
|
17497
|
+
updatedBenefits[index] = benefit;
|
|
16875
17498
|
await updateDoc33(docRef, {
|
|
16876
|
-
benefits:
|
|
17499
|
+
benefits: updatedBenefits,
|
|
16877
17500
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16878
17501
|
});
|
|
16879
17502
|
return this.getById(technologyId);
|
|
@@ -16912,7 +17535,7 @@ var TechnologyService = class extends BaseService {
|
|
|
16912
17535
|
* @returns Ažurirana tehnologija
|
|
16913
17536
|
*/
|
|
16914
17537
|
async updateCertificationRequirement(technologyId, certificationRequirement) {
|
|
16915
|
-
const docRef = doc35(this.
|
|
17538
|
+
const docRef = doc35(this.technologiesRef, technologyId);
|
|
16916
17539
|
await updateDoc33(docRef, {
|
|
16917
17540
|
certificationRequirement,
|
|
16918
17541
|
updatedAt: /* @__PURE__ */ new Date()
|
|
@@ -16990,7 +17613,7 @@ var TechnologyService = class extends BaseService {
|
|
|
16990
17613
|
*/
|
|
16991
17614
|
async getAllowedTechnologies(practitioner) {
|
|
16992
17615
|
const allTechnologies = await this.getAll();
|
|
16993
|
-
const allowedTechnologies = allTechnologies.filter(
|
|
17616
|
+
const allowedTechnologies = allTechnologies.technologies.filter(
|
|
16994
17617
|
(technology) => this.validateCertification(
|
|
16995
17618
|
technology.certificationRequirement,
|
|
16996
17619
|
practitioner.certification
|
|
@@ -17010,18 +17633,61 @@ var TechnologyService = class extends BaseService {
|
|
|
17010
17633
|
subcategories
|
|
17011
17634
|
};
|
|
17012
17635
|
}
|
|
17636
|
+
/**
|
|
17637
|
+
* Gets all active technologies for a subcategory for filter dropdowns.
|
|
17638
|
+
* @param categoryId - The ID of the parent category.
|
|
17639
|
+
* @param subcategoryId - The ID of the subcategory.
|
|
17640
|
+
*/
|
|
17641
|
+
async getAllForFilterBySubcategoryId(categoryId, subcategoryId) {
|
|
17642
|
+
const q = query34(
|
|
17643
|
+
collection34(this.db, TECHNOLOGIES_COLLECTION),
|
|
17644
|
+
where34("isActive", "==", true),
|
|
17645
|
+
where34("categoryId", "==", categoryId),
|
|
17646
|
+
where34("subcategoryId", "==", subcategoryId),
|
|
17647
|
+
orderBy21("name")
|
|
17648
|
+
);
|
|
17649
|
+
const snapshot = await getDocs34(q);
|
|
17650
|
+
return snapshot.docs.map(
|
|
17651
|
+
(doc38) => ({
|
|
17652
|
+
id: doc38.id,
|
|
17653
|
+
...doc38.data()
|
|
17654
|
+
})
|
|
17655
|
+
);
|
|
17656
|
+
}
|
|
17657
|
+
/**
|
|
17658
|
+
* Gets all active technologies for filter dropdowns.
|
|
17659
|
+
*/
|
|
17660
|
+
async getAllForFilter() {
|
|
17661
|
+
const q = query34(
|
|
17662
|
+
collection34(this.db, TECHNOLOGIES_COLLECTION),
|
|
17663
|
+
where34("isActive", "==", true),
|
|
17664
|
+
orderBy21("name")
|
|
17665
|
+
);
|
|
17666
|
+
const snapshot = await getDocs34(q);
|
|
17667
|
+
return snapshot.docs.map(
|
|
17668
|
+
(doc38) => ({
|
|
17669
|
+
id: doc38.id,
|
|
17670
|
+
...doc38.data()
|
|
17671
|
+
})
|
|
17672
|
+
);
|
|
17673
|
+
}
|
|
17013
17674
|
};
|
|
17014
17675
|
|
|
17015
17676
|
// src/backoffice/services/product.service.ts
|
|
17016
17677
|
import {
|
|
17017
17678
|
addDoc as addDoc7,
|
|
17018
17679
|
collection as collection35,
|
|
17680
|
+
collectionGroup as collectionGroup3,
|
|
17019
17681
|
doc as doc36,
|
|
17020
17682
|
getDoc as getDoc38,
|
|
17021
17683
|
getDocs as getDocs35,
|
|
17022
17684
|
query as query35,
|
|
17023
17685
|
updateDoc as updateDoc34,
|
|
17024
|
-
where as where35
|
|
17686
|
+
where as where35,
|
|
17687
|
+
limit as limit20,
|
|
17688
|
+
orderBy as orderBy22,
|
|
17689
|
+
startAfter as startAfter18,
|
|
17690
|
+
getCountFromServer as getCountFromServer6
|
|
17025
17691
|
} from "firebase/firestore";
|
|
17026
17692
|
|
|
17027
17693
|
// src/backoffice/types/product.types.ts
|
|
@@ -17062,20 +17728,102 @@ var ProductService = class extends BaseService {
|
|
|
17062
17728
|
return { id: productRef.id, ...newProduct };
|
|
17063
17729
|
}
|
|
17064
17730
|
/**
|
|
17065
|
-
* Gets all products
|
|
17731
|
+
* Gets a paginated list of all products, with optional filters.
|
|
17732
|
+
* This uses a collectionGroup query to search across all technologies.
|
|
17066
17733
|
*/
|
|
17067
|
-
async
|
|
17734
|
+
async getAll(options) {
|
|
17735
|
+
const {
|
|
17736
|
+
rowsPerPage,
|
|
17737
|
+
lastVisible,
|
|
17738
|
+
categoryId,
|
|
17739
|
+
subcategoryId,
|
|
17740
|
+
technologyId
|
|
17741
|
+
} = options;
|
|
17742
|
+
const constraints = [
|
|
17743
|
+
where35("isActive", "==", true),
|
|
17744
|
+
orderBy22("name")
|
|
17745
|
+
];
|
|
17746
|
+
if (categoryId) {
|
|
17747
|
+
constraints.push(where35("categoryId", "==", categoryId));
|
|
17748
|
+
}
|
|
17749
|
+
if (subcategoryId) {
|
|
17750
|
+
constraints.push(where35("subcategoryId", "==", subcategoryId));
|
|
17751
|
+
}
|
|
17752
|
+
if (technologyId) {
|
|
17753
|
+
constraints.push(where35("technologyId", "==", technologyId));
|
|
17754
|
+
}
|
|
17755
|
+
if (lastVisible) {
|
|
17756
|
+
constraints.push(startAfter18(lastVisible));
|
|
17757
|
+
}
|
|
17758
|
+
constraints.push(limit20(rowsPerPage));
|
|
17068
17759
|
const q = query35(
|
|
17069
|
-
this.
|
|
17070
|
-
|
|
17760
|
+
collectionGroup3(this.db, PRODUCTS_COLLECTION),
|
|
17761
|
+
...constraints
|
|
17071
17762
|
);
|
|
17072
17763
|
const snapshot = await getDocs35(q);
|
|
17073
|
-
|
|
17074
|
-
(
|
|
17075
|
-
id:
|
|
17076
|
-
...
|
|
17764
|
+
const products = snapshot.docs.map(
|
|
17765
|
+
(doc38) => ({
|
|
17766
|
+
id: doc38.id,
|
|
17767
|
+
...doc38.data()
|
|
17077
17768
|
})
|
|
17078
17769
|
);
|
|
17770
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
17771
|
+
return { products, lastVisible: newLastVisible };
|
|
17772
|
+
}
|
|
17773
|
+
/**
|
|
17774
|
+
* Gets the total count of active products, with optional filters.
|
|
17775
|
+
*/
|
|
17776
|
+
async getProductsCount(options) {
|
|
17777
|
+
const { categoryId, subcategoryId, technologyId } = options;
|
|
17778
|
+
const constraints = [where35("isActive", "==", true)];
|
|
17779
|
+
if (categoryId) {
|
|
17780
|
+
constraints.push(where35("categoryId", "==", categoryId));
|
|
17781
|
+
}
|
|
17782
|
+
if (subcategoryId) {
|
|
17783
|
+
constraints.push(where35("subcategoryId", "==", subcategoryId));
|
|
17784
|
+
}
|
|
17785
|
+
if (technologyId) {
|
|
17786
|
+
constraints.push(where35("technologyId", "==", technologyId));
|
|
17787
|
+
}
|
|
17788
|
+
const q = query35(
|
|
17789
|
+
collectionGroup3(this.db, PRODUCTS_COLLECTION),
|
|
17790
|
+
...constraints
|
|
17791
|
+
);
|
|
17792
|
+
const snapshot = await getCountFromServer6(q);
|
|
17793
|
+
return snapshot.data().count;
|
|
17794
|
+
}
|
|
17795
|
+
/**
|
|
17796
|
+
* Gets counts of active products grouped by category, subcategory, and technology.
|
|
17797
|
+
* This uses a single collectionGroup query for efficiency.
|
|
17798
|
+
*/
|
|
17799
|
+
async getProductCounts() {
|
|
17800
|
+
const q = query35(
|
|
17801
|
+
collectionGroup3(this.db, PRODUCTS_COLLECTION),
|
|
17802
|
+
where35("isActive", "==", true)
|
|
17803
|
+
);
|
|
17804
|
+
const snapshot = await getDocs35(q);
|
|
17805
|
+
const counts = {
|
|
17806
|
+
byCategory: {},
|
|
17807
|
+
bySubcategory: {},
|
|
17808
|
+
byTechnology: {}
|
|
17809
|
+
};
|
|
17810
|
+
if (snapshot.empty) {
|
|
17811
|
+
return counts;
|
|
17812
|
+
}
|
|
17813
|
+
snapshot.docs.forEach((doc38) => {
|
|
17814
|
+
const product = doc38.data();
|
|
17815
|
+
const { categoryId, subcategoryId, technologyId } = product;
|
|
17816
|
+
if (categoryId) {
|
|
17817
|
+
counts.byCategory[categoryId] = (counts.byCategory[categoryId] || 0) + 1;
|
|
17818
|
+
}
|
|
17819
|
+
if (subcategoryId) {
|
|
17820
|
+
counts.bySubcategory[subcategoryId] = (counts.bySubcategory[subcategoryId] || 0) + 1;
|
|
17821
|
+
}
|
|
17822
|
+
if (technologyId) {
|
|
17823
|
+
counts.byTechnology[technologyId] = (counts.byTechnology[technologyId] || 0) + 1;
|
|
17824
|
+
}
|
|
17825
|
+
});
|
|
17826
|
+
return counts;
|
|
17079
17827
|
}
|
|
17080
17828
|
/**
|
|
17081
17829
|
* Gets all products for a brand by filtering through all technologies
|
|
@@ -17093,9 +17841,9 @@ var ProductService = class extends BaseService {
|
|
|
17093
17841
|
const snapshot = await getDocs35(q);
|
|
17094
17842
|
products.push(
|
|
17095
17843
|
...snapshot.docs.map(
|
|
17096
|
-
(
|
|
17097
|
-
id:
|
|
17098
|
-
...
|
|
17844
|
+
(doc38) => ({
|
|
17845
|
+
id: doc38.id,
|
|
17846
|
+
...doc38.data()
|
|
17099
17847
|
})
|
|
17100
17848
|
)
|
|
17101
17849
|
);
|
|
@@ -17136,6 +17884,262 @@ var ProductService = class extends BaseService {
|
|
|
17136
17884
|
}
|
|
17137
17885
|
};
|
|
17138
17886
|
|
|
17887
|
+
// src/backoffice/services/constants.service.ts
|
|
17888
|
+
import {
|
|
17889
|
+
arrayRemove as arrayRemove9,
|
|
17890
|
+
arrayUnion as arrayUnion10,
|
|
17891
|
+
doc as doc37,
|
|
17892
|
+
getDoc as getDoc39,
|
|
17893
|
+
setDoc as setDoc29,
|
|
17894
|
+
updateDoc as updateDoc35
|
|
17895
|
+
} from "firebase/firestore";
|
|
17896
|
+
var ADMIN_CONSTANTS_COLLECTION = "admin-constants";
|
|
17897
|
+
var TREATMENT_BENEFITS_DOC = "treatment-benefits";
|
|
17898
|
+
var CONTRAINDICATIONS_DOC = "contraindications";
|
|
17899
|
+
var ConstantsService = class extends BaseService {
|
|
17900
|
+
/**
|
|
17901
|
+
* @description Gets the reference to the document holding treatment benefits.
|
|
17902
|
+
* @private
|
|
17903
|
+
* @type {DocumentReference}
|
|
17904
|
+
*/
|
|
17905
|
+
get treatmentBenefitsDocRef() {
|
|
17906
|
+
return doc37(this.db, ADMIN_CONSTANTS_COLLECTION, TREATMENT_BENEFITS_DOC);
|
|
17907
|
+
}
|
|
17908
|
+
/**
|
|
17909
|
+
* @description Gets the reference to the document holding contraindications.
|
|
17910
|
+
* @private
|
|
17911
|
+
* @type {DocumentReference}
|
|
17912
|
+
*/
|
|
17913
|
+
get contraindicationsDocRef() {
|
|
17914
|
+
return doc37(this.db, ADMIN_CONSTANTS_COLLECTION, CONTRAINDICATIONS_DOC);
|
|
17915
|
+
}
|
|
17916
|
+
// =================================================================
|
|
17917
|
+
// Treatment Benefits
|
|
17918
|
+
// =================================================================
|
|
17919
|
+
/**
|
|
17920
|
+
* @description Retrieves all treatment benefits without pagination.
|
|
17921
|
+
* @returns {Promise<TreatmentBenefitDynamic[]>} An array of all treatment benefits.
|
|
17922
|
+
*/
|
|
17923
|
+
async getAllBenefitsForFilter() {
|
|
17924
|
+
const docSnap = await getDoc39(this.treatmentBenefitsDocRef);
|
|
17925
|
+
if (!docSnap.exists()) {
|
|
17926
|
+
return [];
|
|
17927
|
+
}
|
|
17928
|
+
return docSnap.data().benefits;
|
|
17929
|
+
}
|
|
17930
|
+
/**
|
|
17931
|
+
* @description Retrieves a paginated list of treatment benefits.
|
|
17932
|
+
* @param {{ page: number; limit: number }} options - Pagination options.
|
|
17933
|
+
* @returns {Promise<{ benefits: TreatmentBenefitDynamic[]; total: number }>} A paginated list of benefits and the total count.
|
|
17934
|
+
*/
|
|
17935
|
+
async getAllBenefits(options) {
|
|
17936
|
+
const allBenefits = await this.getAllBenefitsForFilter();
|
|
17937
|
+
const { page, limit: limit21 } = options;
|
|
17938
|
+
const startIndex = page * limit21;
|
|
17939
|
+
const endIndex = startIndex + limit21;
|
|
17940
|
+
const paginatedBenefits = allBenefits.slice(startIndex, endIndex);
|
|
17941
|
+
return { benefits: paginatedBenefits, total: allBenefits.length };
|
|
17942
|
+
}
|
|
17943
|
+
/**
|
|
17944
|
+
* @description Adds a new treatment benefit.
|
|
17945
|
+
* @param {Omit<TreatmentBenefitDynamic, "id">} benefit - The treatment benefit to add, without an ID.
|
|
17946
|
+
* @returns {Promise<TreatmentBenefitDynamic>} The newly created treatment benefit with its generated ID.
|
|
17947
|
+
*/
|
|
17948
|
+
async addTreatmentBenefit(benefit) {
|
|
17949
|
+
const newBenefit = {
|
|
17950
|
+
id: this.generateId(),
|
|
17951
|
+
...benefit
|
|
17952
|
+
};
|
|
17953
|
+
const docSnap = await getDoc39(this.treatmentBenefitsDocRef);
|
|
17954
|
+
if (!docSnap.exists()) {
|
|
17955
|
+
await setDoc29(this.treatmentBenefitsDocRef, { benefits: [newBenefit] });
|
|
17956
|
+
} else {
|
|
17957
|
+
await updateDoc35(this.treatmentBenefitsDocRef, {
|
|
17958
|
+
benefits: arrayUnion10(newBenefit)
|
|
17959
|
+
});
|
|
17960
|
+
}
|
|
17961
|
+
return newBenefit;
|
|
17962
|
+
}
|
|
17963
|
+
/**
|
|
17964
|
+
* @description Retrieves a single treatment benefit by its ID.
|
|
17965
|
+
* @param {string} benefitId - The ID of the treatment benefit to retrieve.
|
|
17966
|
+
* @returns {Promise<TreatmentBenefitDynamic | undefined>} The found treatment benefit or undefined.
|
|
17967
|
+
*/
|
|
17968
|
+
async getBenefitById(benefitId) {
|
|
17969
|
+
const benefits = await this.getAllBenefitsForFilter();
|
|
17970
|
+
return benefits.find((b) => b.id === benefitId);
|
|
17971
|
+
}
|
|
17972
|
+
/**
|
|
17973
|
+
* @description Searches for treatment benefits by name (case-insensitive).
|
|
17974
|
+
* @param {string} searchTerm - The term to search for in the benefit names.
|
|
17975
|
+
* @returns {Promise<TreatmentBenefitDynamic[]>} An array of matching treatment benefits.
|
|
17976
|
+
*/
|
|
17977
|
+
async searchBenefitsByName(searchTerm) {
|
|
17978
|
+
const benefits = await this.getAllBenefitsForFilter();
|
|
17979
|
+
const normalizedSearchTerm = searchTerm.toLowerCase();
|
|
17980
|
+
return benefits.filter(
|
|
17981
|
+
(b) => b.name.toLowerCase().includes(normalizedSearchTerm)
|
|
17982
|
+
);
|
|
17983
|
+
}
|
|
17984
|
+
/**
|
|
17985
|
+
* @description Updates an existing treatment benefit.
|
|
17986
|
+
* @param {TreatmentBenefitDynamic} benefit - The treatment benefit with updated data. Its ID must match an existing benefit.
|
|
17987
|
+
* @returns {Promise<TreatmentBenefitDynamic>} The updated treatment benefit.
|
|
17988
|
+
* @throws {Error} If the treatment benefit is not found.
|
|
17989
|
+
*/
|
|
17990
|
+
async updateTreatmentBenefit(benefit) {
|
|
17991
|
+
const benefits = await this.getAllBenefitsForFilter();
|
|
17992
|
+
const benefitIndex = benefits.findIndex((b) => b.id === benefit.id);
|
|
17993
|
+
if (benefitIndex === -1) {
|
|
17994
|
+
throw new Error("Treatment benefit not found.");
|
|
17995
|
+
}
|
|
17996
|
+
benefits[benefitIndex] = benefit;
|
|
17997
|
+
await updateDoc35(this.treatmentBenefitsDocRef, { benefits });
|
|
17998
|
+
return benefit;
|
|
17999
|
+
}
|
|
18000
|
+
/**
|
|
18001
|
+
* @description Deletes a treatment benefit by its ID.
|
|
18002
|
+
* @param {string} benefitId - The ID of the treatment benefit to delete.
|
|
18003
|
+
* @returns {Promise<void>}
|
|
18004
|
+
*/
|
|
18005
|
+
async deleteTreatmentBenefit(benefitId) {
|
|
18006
|
+
const benefits = await this.getAllBenefitsForFilter();
|
|
18007
|
+
const benefitToRemove = benefits.find((b) => b.id === benefitId);
|
|
18008
|
+
if (!benefitToRemove) {
|
|
18009
|
+
return;
|
|
18010
|
+
}
|
|
18011
|
+
await updateDoc35(this.treatmentBenefitsDocRef, {
|
|
18012
|
+
benefits: arrayRemove9(benefitToRemove)
|
|
18013
|
+
});
|
|
18014
|
+
}
|
|
18015
|
+
// =================================================================
|
|
18016
|
+
// Contraindications
|
|
18017
|
+
// =================================================================
|
|
18018
|
+
/**
|
|
18019
|
+
* @description Retrieves all contraindications without pagination.
|
|
18020
|
+
* @returns {Promise<ContraindicationDynamic[]>} An array of all contraindications.
|
|
18021
|
+
*/
|
|
18022
|
+
async getAllContraindicationsForFilter() {
|
|
18023
|
+
const docSnap = await getDoc39(this.contraindicationsDocRef);
|
|
18024
|
+
if (!docSnap.exists()) {
|
|
18025
|
+
return [];
|
|
18026
|
+
}
|
|
18027
|
+
return docSnap.data().contraindications;
|
|
18028
|
+
}
|
|
18029
|
+
/**
|
|
18030
|
+
* @description Retrieves a paginated list of contraindications.
|
|
18031
|
+
* @param {{ page: number; limit: number }} options - Pagination options.
|
|
18032
|
+
* @returns {Promise<{ contraindications: ContraindicationDynamic[]; total: number }>} A paginated list and the total count.
|
|
18033
|
+
*/
|
|
18034
|
+
async getAllContraindications(options) {
|
|
18035
|
+
const allContraindications = await this.getAllContraindicationsForFilter();
|
|
18036
|
+
const { page, limit: limit21 } = options;
|
|
18037
|
+
const startIndex = page * limit21;
|
|
18038
|
+
const endIndex = startIndex + limit21;
|
|
18039
|
+
const paginatedContraindications = allContraindications.slice(
|
|
18040
|
+
startIndex,
|
|
18041
|
+
endIndex
|
|
18042
|
+
);
|
|
18043
|
+
return {
|
|
18044
|
+
contraindications: paginatedContraindications,
|
|
18045
|
+
total: allContraindications.length
|
|
18046
|
+
};
|
|
18047
|
+
}
|
|
18048
|
+
/**
|
|
18049
|
+
* @description Adds a new contraindication.
|
|
18050
|
+
* @param {Omit<ContraindicationDynamic, "id">} contraindication - The contraindication to add, without an ID.
|
|
18051
|
+
* @returns {Promise<ContraindicationDynamic>} The newly created contraindication with its generated ID.
|
|
18052
|
+
*/
|
|
18053
|
+
async addContraindication(contraindication) {
|
|
18054
|
+
const newContraindication = {
|
|
18055
|
+
id: this.generateId(),
|
|
18056
|
+
...contraindication
|
|
18057
|
+
};
|
|
18058
|
+
const docSnap = await getDoc39(this.contraindicationsDocRef);
|
|
18059
|
+
if (!docSnap.exists()) {
|
|
18060
|
+
await setDoc29(this.contraindicationsDocRef, {
|
|
18061
|
+
contraindications: [newContraindication]
|
|
18062
|
+
});
|
|
18063
|
+
} else {
|
|
18064
|
+
await updateDoc35(this.contraindicationsDocRef, {
|
|
18065
|
+
contraindications: arrayUnion10(newContraindication)
|
|
18066
|
+
});
|
|
18067
|
+
}
|
|
18068
|
+
return newContraindication;
|
|
18069
|
+
}
|
|
18070
|
+
/**
|
|
18071
|
+
* @description Retrieves a single contraindication by its ID.
|
|
18072
|
+
* @param {string} contraindicationId - The ID of the contraindication to retrieve.
|
|
18073
|
+
* @returns {Promise<ContraindicationDynamic | undefined>} The found contraindication or undefined.
|
|
18074
|
+
*/
|
|
18075
|
+
async getContraindicationById(contraindicationId) {
|
|
18076
|
+
const contraindications = await this.getAllContraindicationsForFilter();
|
|
18077
|
+
return contraindications.find((c) => c.id === contraindicationId);
|
|
18078
|
+
}
|
|
18079
|
+
/**
|
|
18080
|
+
* @description Searches for contraindications by name (case-insensitive).
|
|
18081
|
+
* @param {string} searchTerm - The term to search for in the contraindication names.
|
|
18082
|
+
* @returns {Promise<ContraindicationDynamic[]>} An array of matching contraindications.
|
|
18083
|
+
*/
|
|
18084
|
+
async searchContraindicationsByName(searchTerm) {
|
|
18085
|
+
const contraindications = await this.getAllContraindicationsForFilter();
|
|
18086
|
+
const normalizedSearchTerm = searchTerm.toLowerCase();
|
|
18087
|
+
return contraindications.filter(
|
|
18088
|
+
(c) => c.name.toLowerCase().includes(normalizedSearchTerm)
|
|
18089
|
+
);
|
|
18090
|
+
}
|
|
18091
|
+
/**
|
|
18092
|
+
* @description Updates an existing contraindication.
|
|
18093
|
+
* @param {ContraindicationDynamic} contraindication - The contraindication with updated data. Its ID must match an existing one.
|
|
18094
|
+
* @returns {Promise<ContraindicationDynamic>} The updated contraindication.
|
|
18095
|
+
* @throws {Error} If the contraindication is not found.
|
|
18096
|
+
*/
|
|
18097
|
+
async updateContraindication(contraindication) {
|
|
18098
|
+
const contraindications = await this.getAllContraindicationsForFilter();
|
|
18099
|
+
const index = contraindications.findIndex(
|
|
18100
|
+
(c) => c.id === contraindication.id
|
|
18101
|
+
);
|
|
18102
|
+
if (index === -1) {
|
|
18103
|
+
throw new Error("Contraindication not found.");
|
|
18104
|
+
}
|
|
18105
|
+
contraindications[index] = contraindication;
|
|
18106
|
+
await updateDoc35(this.contraindicationsDocRef, { contraindications });
|
|
18107
|
+
return contraindication;
|
|
18108
|
+
}
|
|
18109
|
+
/**
|
|
18110
|
+
* @description Deletes a contraindication by its ID.
|
|
18111
|
+
* @param {string} contraindicationId - The ID of the contraindication to delete.
|
|
18112
|
+
* @returns {Promise<void>}
|
|
18113
|
+
*/
|
|
18114
|
+
async deleteContraindication(contraindicationId) {
|
|
18115
|
+
const contraindications = await this.getAllContraindicationsForFilter();
|
|
18116
|
+
const toRemove = contraindications.find((c) => c.id === contraindicationId);
|
|
18117
|
+
if (!toRemove) {
|
|
18118
|
+
return;
|
|
18119
|
+
}
|
|
18120
|
+
await updateDoc35(this.contraindicationsDocRef, {
|
|
18121
|
+
contraindications: arrayRemove9(toRemove)
|
|
18122
|
+
});
|
|
18123
|
+
}
|
|
18124
|
+
};
|
|
18125
|
+
|
|
18126
|
+
// src/backoffice/types/static/contraindication.types.ts
|
|
18127
|
+
var Contraindication = /* @__PURE__ */ ((Contraindication2) => {
|
|
18128
|
+
Contraindication2["SENSITIVE_SKIN"] = "sensitive_skin";
|
|
18129
|
+
Contraindication2["RECENT_TANNING"] = "recent_tanning";
|
|
18130
|
+
Contraindication2["RECENT_BOTOX"] = "recent_botox";
|
|
18131
|
+
Contraindication2["RECENT_FILLERS"] = "recent_fillers";
|
|
18132
|
+
Contraindication2["SKIN_ALLERGIES"] = "skin_allergies";
|
|
18133
|
+
Contraindication2["MEDICATIONS"] = "medications";
|
|
18134
|
+
Contraindication2["RECENT_CHEMICAL_PEEL"] = "recent_chemical_peel";
|
|
18135
|
+
Contraindication2["RECENT_LASER"] = "recent_laser";
|
|
18136
|
+
Contraindication2["SKIN_INFLAMMATION"] = "skin_inflammation";
|
|
18137
|
+
Contraindication2["OPEN_WOUNDS"] = "open_wounds";
|
|
18138
|
+
Contraindication2["HERPES_SIMPLEX"] = "herpes_simplex";
|
|
18139
|
+
Contraindication2["COLD_SORES"] = "cold_sores";
|
|
18140
|
+
return Contraindication2;
|
|
18141
|
+
})(Contraindication || {});
|
|
18142
|
+
|
|
17139
18143
|
// src/backoffice/types/static/treatment-benefit.types.ts
|
|
17140
18144
|
var TreatmentBenefit = /* @__PURE__ */ ((TreatmentBenefit2) => {
|
|
17141
18145
|
TreatmentBenefit2["WRINKLE_REDUCTION"] = "wrinkle_reduction";
|
|
@@ -17194,6 +18198,7 @@ export {
|
|
|
17194
18198
|
ClinicPhotoTag,
|
|
17195
18199
|
ClinicService,
|
|
17196
18200
|
ClinicTag,
|
|
18201
|
+
ConstantsService,
|
|
17197
18202
|
Contraindication,
|
|
17198
18203
|
CosmeticAllergySubtype,
|
|
17199
18204
|
Currency,
|