@blackcode_sa/metaestetics-api 1.11.2 → 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 +331 -318
- package/dist/admin/index.d.ts +331 -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 +4429 -4034
- package/dist/index.d.ts +4429 -4034
- package/dist/index.js +1644 -666
- package/dist/index.mjs +1408 -402
- 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 +4 -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/appointment.schema.ts +1 -0
- 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";
|
|
@@ -438,7 +440,8 @@ var appointmentMetadataSchema = z3.object({
|
|
|
438
440
|
selectedZones: z3.array(z3.string()).nullable(),
|
|
439
441
|
zonePhotos: z3.record(z3.string(), beforeAfterPerZoneSchema).nullable(),
|
|
440
442
|
zoneBilling: z3.record(z3.string(), billingPerZoneSchema).nullable(),
|
|
441
|
-
finalbilling: finalBillingSchema.nullable()
|
|
443
|
+
finalbilling: finalBillingSchema.nullable(),
|
|
444
|
+
finalizationNotes: z3.string().nullable()
|
|
442
445
|
});
|
|
443
446
|
var createAppointmentSchema = z3.object({
|
|
444
447
|
clinicBranchId: z3.string().min(MIN_STRING_LENGTH, "Clinic branch ID is required"),
|
|
@@ -581,7 +584,6 @@ import {
|
|
|
581
584
|
getDocs,
|
|
582
585
|
query,
|
|
583
586
|
where,
|
|
584
|
-
setDoc,
|
|
585
587
|
updateDoc,
|
|
586
588
|
serverTimestamp,
|
|
587
589
|
Timestamp,
|
|
@@ -818,44 +820,48 @@ async function updateAppointmentUtil(db, appointmentId, data) {
|
|
|
818
820
|
const validPreReqIds = currentAppointment.preProcedureRequirements.map(
|
|
819
821
|
(req) => req.id
|
|
820
822
|
);
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
if (invalidPreReqIds.length > 0) {
|
|
825
|
-
throw new Error(
|
|
826
|
-
`Invalid pre-requirement IDs: ${invalidPreReqIds.join(", ")}`
|
|
823
|
+
if (Array.isArray(data.completedPreRequirements)) {
|
|
824
|
+
const invalidPreReqIds = data.completedPreRequirements.filter(
|
|
825
|
+
(id) => !validPreReqIds.includes(id)
|
|
827
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
|
+
];
|
|
828
838
|
}
|
|
829
|
-
completedPreRequirements = [
|
|
830
|
-
.../* @__PURE__ */ new Set([
|
|
831
|
-
...completedPreRequirements,
|
|
832
|
-
...data.completedPreRequirements
|
|
833
|
-
])
|
|
834
|
-
];
|
|
835
839
|
}
|
|
836
840
|
if (data.completedPostRequirements) {
|
|
837
841
|
const validPostReqIds = currentAppointment.postProcedureRequirements.map(
|
|
838
842
|
(req) => req.id
|
|
839
843
|
);
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
if (invalidPostReqIds.length > 0) {
|
|
844
|
-
throw new Error(
|
|
845
|
-
`Invalid post-requirement IDs: ${invalidPostReqIds.join(", ")}`
|
|
844
|
+
if (Array.isArray(data.completedPostRequirements)) {
|
|
845
|
+
const invalidPostReqIds = data.completedPostRequirements.filter(
|
|
846
|
+
(id) => !validPostReqIds.includes(id)
|
|
846
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
|
+
];
|
|
847
859
|
}
|
|
848
|
-
completedPostRequirements = [
|
|
849
|
-
.../* @__PURE__ */ new Set([
|
|
850
|
-
...completedPostRequirements,
|
|
851
|
-
...data.completedPostRequirements
|
|
852
|
-
])
|
|
853
|
-
];
|
|
854
860
|
}
|
|
855
861
|
const updateData = {
|
|
856
862
|
...data,
|
|
857
|
-
completedPreRequirements,
|
|
858
|
-
completedPostRequirements,
|
|
863
|
+
completedPreRequirements: Array.isArray(data.completedPreRequirements) ? completedPreRequirements : data.completedPreRequirements,
|
|
864
|
+
completedPostRequirements: Array.isArray(data.completedPostRequirements) ? completedPostRequirements : data.completedPostRequirements,
|
|
859
865
|
updatedAt: serverTimestamp()
|
|
860
866
|
};
|
|
861
867
|
Object.keys(updateData).forEach((key) => {
|
|
@@ -905,7 +911,7 @@ async function updateCalendarEventStatus(db, calendarEventId, appointmentStatus)
|
|
|
905
911
|
case "canceled_clinic" /* CANCELED_CLINIC */:
|
|
906
912
|
calendarStatus = "canceled";
|
|
907
913
|
break;
|
|
908
|
-
case
|
|
914
|
+
case "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */:
|
|
909
915
|
calendarStatus = "rescheduled";
|
|
910
916
|
break;
|
|
911
917
|
case "completed" /* COMPLETED */:
|
|
@@ -979,7 +985,7 @@ async function searchAppointmentsUtil(db, params) {
|
|
|
979
985
|
const q = query(collection(db, APPOINTMENTS_COLLECTION), ...constraints);
|
|
980
986
|
const querySnapshot = await getDocs(q);
|
|
981
987
|
const appointments = querySnapshot.docs.map(
|
|
982
|
-
(
|
|
988
|
+
(doc38) => doc38.data()
|
|
983
989
|
);
|
|
984
990
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
985
991
|
return { appointments, lastDoc };
|
|
@@ -1786,7 +1792,7 @@ var AppointmentService = class extends BaseService {
|
|
|
1786
1792
|
);
|
|
1787
1793
|
const querySnapshot = await getDocs2(q);
|
|
1788
1794
|
const appointments = querySnapshot.docs.map(
|
|
1789
|
-
(
|
|
1795
|
+
(doc38) => doc38.data()
|
|
1790
1796
|
);
|
|
1791
1797
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
1792
1798
|
console.log(
|
|
@@ -1859,7 +1865,7 @@ var AppointmentService = class extends BaseService {
|
|
|
1859
1865
|
);
|
|
1860
1866
|
const querySnapshot = await getDocs2(q);
|
|
1861
1867
|
const appointments = querySnapshot.docs.map(
|
|
1862
|
-
(
|
|
1868
|
+
(doc38) => doc38.data()
|
|
1863
1869
|
);
|
|
1864
1870
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
1865
1871
|
console.log(
|
|
@@ -2411,8 +2417,8 @@ var MediaAccessLevel = /* @__PURE__ */ ((MediaAccessLevel2) => {
|
|
|
2411
2417
|
})(MediaAccessLevel || {});
|
|
2412
2418
|
var MEDIA_METADATA_COLLECTION = "media_metadata";
|
|
2413
2419
|
var MediaService = class extends BaseService {
|
|
2414
|
-
constructor(
|
|
2415
|
-
super(
|
|
2420
|
+
constructor(...args) {
|
|
2421
|
+
super(...args);
|
|
2416
2422
|
}
|
|
2417
2423
|
/**
|
|
2418
2424
|
* Upload a media file, store its metadata, and return the metadata including the URL.
|
|
@@ -2672,7 +2678,7 @@ var MediaService = class extends BaseService {
|
|
|
2672
2678
|
try {
|
|
2673
2679
|
const querySnapshot = await getDocs3(finalQuery);
|
|
2674
2680
|
const mediaList = querySnapshot.docs.map(
|
|
2675
|
-
(
|
|
2681
|
+
(doc38) => doc38.data()
|
|
2676
2682
|
);
|
|
2677
2683
|
console.log(`[MediaService] Found ${mediaList.length} media items.`);
|
|
2678
2684
|
return mediaList;
|
|
@@ -2735,8 +2741,8 @@ var getPatientsByClinicUtil = async (db, clinicId, options) => {
|
|
|
2735
2741
|
}
|
|
2736
2742
|
const patientsSnapshot = await getDocs4(q);
|
|
2737
2743
|
const patients = [];
|
|
2738
|
-
patientsSnapshot.forEach((
|
|
2739
|
-
patients.push(
|
|
2744
|
+
patientsSnapshot.forEach((doc38) => {
|
|
2745
|
+
patients.push(doc38.data());
|
|
2740
2746
|
});
|
|
2741
2747
|
console.log(
|
|
2742
2748
|
`[getPatientsByClinicUtil] Found ${patients.length} patients for clinic ID: ${clinicId}`
|
|
@@ -2798,23 +2804,6 @@ var BlockingCondition = /* @__PURE__ */ ((BlockingCondition2) => {
|
|
|
2798
2804
|
return BlockingCondition2;
|
|
2799
2805
|
})(BlockingCondition || {});
|
|
2800
2806
|
|
|
2801
|
-
// src/backoffice/types/static/contraindication.types.ts
|
|
2802
|
-
var Contraindication = /* @__PURE__ */ ((Contraindication2) => {
|
|
2803
|
-
Contraindication2["SENSITIVE_SKIN"] = "sensitive_skin";
|
|
2804
|
-
Contraindication2["RECENT_TANNING"] = "recent_tanning";
|
|
2805
|
-
Contraindication2["RECENT_BOTOX"] = "recent_botox";
|
|
2806
|
-
Contraindication2["RECENT_FILLERS"] = "recent_fillers";
|
|
2807
|
-
Contraindication2["SKIN_ALLERGIES"] = "skin_allergies";
|
|
2808
|
-
Contraindication2["MEDICATIONS"] = "medications";
|
|
2809
|
-
Contraindication2["RECENT_CHEMICAL_PEEL"] = "recent_chemical_peel";
|
|
2810
|
-
Contraindication2["RECENT_LASER"] = "recent_laser";
|
|
2811
|
-
Contraindication2["SKIN_INFLAMMATION"] = "skin_inflammation";
|
|
2812
|
-
Contraindication2["OPEN_WOUNDS"] = "open_wounds";
|
|
2813
|
-
Contraindication2["HERPES_SIMPLEX"] = "herpes_simplex";
|
|
2814
|
-
Contraindication2["COLD_SORES"] = "cold_sores";
|
|
2815
|
-
return Contraindication2;
|
|
2816
|
-
})(Contraindication || {});
|
|
2817
|
-
|
|
2818
2807
|
// src/validations/common.schema.ts
|
|
2819
2808
|
import { z as z5 } from "zod";
|
|
2820
2809
|
import { Timestamp as Timestamp4 } from "firebase/firestore";
|
|
@@ -2869,8 +2858,13 @@ var blockingConditionSchema = z6.object({
|
|
|
2869
2858
|
notes: z6.string().optional().nullable(),
|
|
2870
2859
|
isActive: z6.boolean()
|
|
2871
2860
|
});
|
|
2861
|
+
var contraindicationDynamicSchema = z6.object({
|
|
2862
|
+
id: z6.string(),
|
|
2863
|
+
name: z6.string(),
|
|
2864
|
+
description: z6.string().optional()
|
|
2865
|
+
});
|
|
2872
2866
|
var contraindicationSchema = z6.object({
|
|
2873
|
-
condition:
|
|
2867
|
+
condition: contraindicationDynamicSchema,
|
|
2874
2868
|
lastOccurrence: timestampSchema,
|
|
2875
2869
|
frequency: z6.enum(["rare", "occasional", "frequent"]),
|
|
2876
2870
|
notes: z6.string().optional().nullable(),
|
|
@@ -3110,8 +3104,8 @@ var getPatientsByPractitionerUtil = async (db, practitionerId, options) => {
|
|
|
3110
3104
|
}
|
|
3111
3105
|
const patientsSnapshot = await getDocs5(q);
|
|
3112
3106
|
const patients = [];
|
|
3113
|
-
patientsSnapshot.forEach((
|
|
3114
|
-
patients.push(
|
|
3107
|
+
patientsSnapshot.forEach((doc38) => {
|
|
3108
|
+
patients.push(doc38.data());
|
|
3115
3109
|
});
|
|
3116
3110
|
console.log(
|
|
3117
3111
|
`[getPatientsByPractitionerUtil] Found ${patients.length} patients for practitioner ID: ${practitionerId}`
|
|
@@ -3890,7 +3884,7 @@ async function getClinicAdminsByGroup(db, clinicGroupId) {
|
|
|
3890
3884
|
where6("clinicGroupId", "==", clinicGroupId)
|
|
3891
3885
|
);
|
|
3892
3886
|
const querySnapshot = await getDocs6(q);
|
|
3893
|
-
return querySnapshot.docs.map((
|
|
3887
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
3894
3888
|
}
|
|
3895
3889
|
async function updateClinicAdmin(db, adminId, data) {
|
|
3896
3890
|
const admin = await getClinicAdmin(db, adminId);
|
|
@@ -4571,9 +4565,9 @@ var updateAllergyUtil = async (db, patientId, data, requesterId, requesterRoles)
|
|
|
4571
4565
|
};
|
|
4572
4566
|
var removeAllergyUtil = async (db, patientId, allergyIndex, requesterId, requesterRoles) => {
|
|
4573
4567
|
await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
|
|
4574
|
-
const
|
|
4575
|
-
if (!
|
|
4576
|
-
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();
|
|
4577
4571
|
if (allergyIndex >= medicalInfo.allergies.length) {
|
|
4578
4572
|
throw new Error("Invalid allergy index");
|
|
4579
4573
|
}
|
|
@@ -4600,9 +4594,9 @@ var updateBlockingConditionUtil = async (db, patientId, data, requesterId, reque
|
|
|
4600
4594
|
await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
|
|
4601
4595
|
const validatedData = updateBlockingConditionSchema.parse(data);
|
|
4602
4596
|
const { conditionIndex, ...updateData } = validatedData;
|
|
4603
|
-
const
|
|
4604
|
-
if (!
|
|
4605
|
-
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();
|
|
4606
4600
|
if (conditionIndex >= medicalInfo.blockingConditions.length) {
|
|
4607
4601
|
throw new Error("Invalid blocking condition index");
|
|
4608
4602
|
}
|
|
@@ -4619,9 +4613,9 @@ var updateBlockingConditionUtil = async (db, patientId, data, requesterId, reque
|
|
|
4619
4613
|
};
|
|
4620
4614
|
var removeBlockingConditionUtil = async (db, patientId, conditionIndex, requesterId, requesterRoles) => {
|
|
4621
4615
|
await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
|
|
4622
|
-
const
|
|
4623
|
-
if (!
|
|
4624
|
-
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();
|
|
4625
4619
|
if (conditionIndex >= medicalInfo.blockingConditions.length) {
|
|
4626
4620
|
throw new Error("Invalid blocking condition index");
|
|
4627
4621
|
}
|
|
@@ -4648,9 +4642,9 @@ var updateContraindicationUtil = async (db, patientId, data, requesterId, reques
|
|
|
4648
4642
|
await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
|
|
4649
4643
|
const validatedData = updateContraindicationSchema.parse(data);
|
|
4650
4644
|
const { contraindicationIndex, ...updateData } = validatedData;
|
|
4651
|
-
const
|
|
4652
|
-
if (!
|
|
4653
|
-
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();
|
|
4654
4648
|
if (contraindicationIndex >= medicalInfo.contraindications.length) {
|
|
4655
4649
|
throw new Error("Invalid contraindication index");
|
|
4656
4650
|
}
|
|
@@ -4667,9 +4661,9 @@ var updateContraindicationUtil = async (db, patientId, data, requesterId, reques
|
|
|
4667
4661
|
};
|
|
4668
4662
|
var removeContraindicationUtil = async (db, patientId, contraindicationIndex, requesterId, requesterRoles) => {
|
|
4669
4663
|
await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
|
|
4670
|
-
const
|
|
4671
|
-
if (!
|
|
4672
|
-
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();
|
|
4673
4667
|
if (contraindicationIndex >= medicalInfo.contraindications.length) {
|
|
4674
4668
|
throw new Error("Invalid contraindication index");
|
|
4675
4669
|
}
|
|
@@ -4696,9 +4690,9 @@ var updateMedicationUtil = async (db, patientId, data, requesterId, requesterRol
|
|
|
4696
4690
|
await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
|
|
4697
4691
|
const validatedData = updateMedicationSchema.parse(data);
|
|
4698
4692
|
const { medicationIndex, ...updateData } = validatedData;
|
|
4699
|
-
const
|
|
4700
|
-
if (!
|
|
4701
|
-
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();
|
|
4702
4696
|
if (medicationIndex >= medicalInfo.currentMedications.length) {
|
|
4703
4697
|
throw new Error("Invalid medication index");
|
|
4704
4698
|
}
|
|
@@ -4715,9 +4709,9 @@ var updateMedicationUtil = async (db, patientId, data, requesterId, requesterRol
|
|
|
4715
4709
|
};
|
|
4716
4710
|
var removeMedicationUtil = async (db, patientId, medicationIndex, requesterId, requesterRoles) => {
|
|
4717
4711
|
await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
|
|
4718
|
-
const
|
|
4719
|
-
if (!
|
|
4720
|
-
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();
|
|
4721
4715
|
if (medicationIndex >= medicalInfo.currentMedications.length) {
|
|
4722
4716
|
throw new Error("Invalid medication index");
|
|
4723
4717
|
}
|
|
@@ -5020,7 +5014,7 @@ var searchPatientsUtil = async (db, params, requester) => {
|
|
|
5020
5014
|
const finalQuery = query8(patientsCollectionRef, ...constraints);
|
|
5021
5015
|
const querySnapshot = await getDocs8(finalQuery);
|
|
5022
5016
|
const patients = querySnapshot.docs.map(
|
|
5023
|
-
(
|
|
5017
|
+
(doc38) => doc38.data()
|
|
5024
5018
|
);
|
|
5025
5019
|
console.log(
|
|
5026
5020
|
`[searchPatientsUtil] Found ${patients.length} patients matching criteria.`
|
|
@@ -5052,8 +5046,8 @@ var getAllPatientsUtil = async (db, options) => {
|
|
|
5052
5046
|
}
|
|
5053
5047
|
const patientsSnapshot = await getDocs8(q);
|
|
5054
5048
|
const patients = [];
|
|
5055
|
-
patientsSnapshot.forEach((
|
|
5056
|
-
patients.push(
|
|
5049
|
+
patientsSnapshot.forEach((doc38) => {
|
|
5050
|
+
patients.push(doc38.data());
|
|
5057
5051
|
});
|
|
5058
5052
|
console.log(`[getAllPatientsUtil] Found ${patients.length} patients`);
|
|
5059
5053
|
return patients;
|
|
@@ -5186,7 +5180,7 @@ var getActiveInviteTokensByClinicUtil = async (db, clinicId) => {
|
|
|
5186
5180
|
if (querySnapshot.empty) {
|
|
5187
5181
|
return [];
|
|
5188
5182
|
}
|
|
5189
|
-
return querySnapshot.docs.map((
|
|
5183
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
5190
5184
|
};
|
|
5191
5185
|
var getActiveInviteTokensByPatientUtil = async (db, patientId) => {
|
|
5192
5186
|
const tokensRef = collection9(
|
|
@@ -5204,7 +5198,7 @@ var getActiveInviteTokensByPatientUtil = async (db, patientId) => {
|
|
|
5204
5198
|
if (querySnapshot.empty) {
|
|
5205
5199
|
return [];
|
|
5206
5200
|
}
|
|
5207
|
-
return querySnapshot.docs.map((
|
|
5201
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
5208
5202
|
};
|
|
5209
5203
|
|
|
5210
5204
|
// src/services/patient/patient.service.ts
|
|
@@ -6493,7 +6487,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6493
6487
|
where10("expiresAt", ">", Timestamp14.now())
|
|
6494
6488
|
);
|
|
6495
6489
|
const querySnapshot = await getDocs10(q);
|
|
6496
|
-
return querySnapshot.docs.map((
|
|
6490
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
6497
6491
|
}
|
|
6498
6492
|
/**
|
|
6499
6493
|
* Gets a token by its string value and validates it
|
|
@@ -6603,7 +6597,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6603
6597
|
where10("status", "==", "active" /* ACTIVE */)
|
|
6604
6598
|
);
|
|
6605
6599
|
const querySnapshot = await getDocs10(q);
|
|
6606
|
-
return querySnapshot.docs.map((
|
|
6600
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
6607
6601
|
}
|
|
6608
6602
|
/**
|
|
6609
6603
|
* Dohvata sve zdravstvene radnike za određenu kliniku
|
|
@@ -6615,7 +6609,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6615
6609
|
where10("isActive", "==", true)
|
|
6616
6610
|
);
|
|
6617
6611
|
const querySnapshot = await getDocs10(q);
|
|
6618
|
-
return querySnapshot.docs.map((
|
|
6612
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
6619
6613
|
}
|
|
6620
6614
|
/**
|
|
6621
6615
|
* Dohvata sve draft zdravstvene radnike za određenu kliniku sa statusom DRAFT
|
|
@@ -6627,7 +6621,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6627
6621
|
where10("status", "==", "draft" /* DRAFT */)
|
|
6628
6622
|
);
|
|
6629
6623
|
const querySnapshot = await getDocs10(q);
|
|
6630
|
-
return querySnapshot.docs.map((
|
|
6624
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
6631
6625
|
}
|
|
6632
6626
|
/**
|
|
6633
6627
|
* Updates a practitioner
|
|
@@ -6842,7 +6836,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6842
6836
|
);
|
|
6843
6837
|
const querySnapshot = await getDocs10(q);
|
|
6844
6838
|
const practitioners = querySnapshot.docs.map(
|
|
6845
|
-
(
|
|
6839
|
+
(doc38) => doc38.data()
|
|
6846
6840
|
);
|
|
6847
6841
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
6848
6842
|
return {
|
|
@@ -6916,7 +6910,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6916
6910
|
constraints.push(limit7(filters.pagination || 10));
|
|
6917
6911
|
const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
|
|
6918
6912
|
const querySnapshot = await getDocs10(q);
|
|
6919
|
-
const practitioners = querySnapshot.docs.map((
|
|
6913
|
+
const practitioners = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
|
|
6920
6914
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
6921
6915
|
console.log(`[PRACTITIONER_SERVICE] Strategy 1 success: ${practitioners.length} practitioners`);
|
|
6922
6916
|
if (practitioners.length < (filters.pagination || 10)) {
|
|
@@ -6963,7 +6957,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6963
6957
|
}
|
|
6964
6958
|
const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
|
|
6965
6959
|
const querySnapshot = await getDocs10(q);
|
|
6966
|
-
let practitioners = querySnapshot.docs.map((
|
|
6960
|
+
let practitioners = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
|
|
6967
6961
|
if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
|
|
6968
6962
|
const location = filters.location;
|
|
6969
6963
|
const radiusInKm = filters.radiusInKm;
|
|
@@ -6999,7 +6993,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6999
6993
|
];
|
|
7000
6994
|
const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
|
|
7001
6995
|
const querySnapshot = await getDocs10(q);
|
|
7002
|
-
let practitioners = querySnapshot.docs.map((
|
|
6996
|
+
let practitioners = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
|
|
7003
6997
|
practitioners = this.applyInMemoryFilters(practitioners, filters);
|
|
7004
6998
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
7005
6999
|
console.log(`[PRACTITIONER_SERVICE] Strategy 3 success: ${practitioners.length} practitioners`);
|
|
@@ -7020,7 +7014,7 @@ var PractitionerService = class extends BaseService {
|
|
|
7020
7014
|
];
|
|
7021
7015
|
const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
|
|
7022
7016
|
const querySnapshot = await getDocs10(q);
|
|
7023
|
-
let practitioners = querySnapshot.docs.map((
|
|
7017
|
+
let practitioners = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
|
|
7024
7018
|
practitioners = this.applyInMemoryFilters(practitioners, filters);
|
|
7025
7019
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
7026
7020
|
console.log(`[PRACTITIONER_SERVICE] Strategy 4 success: ${practitioners.length} practitioners`);
|
|
@@ -7535,7 +7529,7 @@ var UserService = class extends BaseService {
|
|
|
7535
7529
|
];
|
|
7536
7530
|
const q = query11(collection11(this.db, USERS_COLLECTION), ...constraints);
|
|
7537
7531
|
const querySnapshot = await getDocs11(q);
|
|
7538
|
-
const users = querySnapshot.docs.map((
|
|
7532
|
+
const users = querySnapshot.docs.map((doc38) => doc38.data());
|
|
7539
7533
|
return users.map((userData) => userSchema.parse(userData));
|
|
7540
7534
|
}
|
|
7541
7535
|
/**
|
|
@@ -7915,7 +7909,7 @@ async function getAllActiveGroups(db) {
|
|
|
7915
7909
|
where12("isActive", "==", true)
|
|
7916
7910
|
);
|
|
7917
7911
|
const querySnapshot = await getDocs12(q);
|
|
7918
|
-
return querySnapshot.docs.map((
|
|
7912
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
7919
7913
|
}
|
|
7920
7914
|
async function updateClinicGroup(db, groupId, data, app) {
|
|
7921
7915
|
console.log("[CLINIC_GROUP] Updating clinic group", { groupId });
|
|
@@ -8383,7 +8377,7 @@ async function getClinicsByGroup(db, groupId) {
|
|
|
8383
8377
|
where13("isActive", "==", true)
|
|
8384
8378
|
);
|
|
8385
8379
|
const querySnapshot = await getDocs13(q);
|
|
8386
|
-
return querySnapshot.docs.map((
|
|
8380
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
8387
8381
|
}
|
|
8388
8382
|
async function updateClinic(db, clinicId, data, adminId, clinicAdminService, app) {
|
|
8389
8383
|
console.log("[CLINIC] Starting clinic update", { clinicId, adminId });
|
|
@@ -8577,7 +8571,7 @@ async function getClinicsByAdmin(db, adminId, options = {}, clinicAdminService,
|
|
|
8577
8571
|
}
|
|
8578
8572
|
const q = query13(collection13(db, CLINICS_COLLECTION), ...constraints);
|
|
8579
8573
|
const querySnapshot = await getDocs13(q);
|
|
8580
|
-
return querySnapshot.docs.map((
|
|
8574
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
8581
8575
|
}
|
|
8582
8576
|
async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGroupService) {
|
|
8583
8577
|
return getClinicsByAdmin(
|
|
@@ -8622,11 +8616,11 @@ async function getAllClinics(db, pagination, lastDoc) {
|
|
|
8622
8616
|
}
|
|
8623
8617
|
const clinicsSnapshot = await getDocs13(clinicsQuery);
|
|
8624
8618
|
const lastVisible = clinicsSnapshot.docs[clinicsSnapshot.docs.length - 1];
|
|
8625
|
-
const clinics = clinicsSnapshot.docs.map((
|
|
8626
|
-
const data =
|
|
8619
|
+
const clinics = clinicsSnapshot.docs.map((doc38) => {
|
|
8620
|
+
const data = doc38.data();
|
|
8627
8621
|
return {
|
|
8628
8622
|
...data,
|
|
8629
|
-
id:
|
|
8623
|
+
id: doc38.id
|
|
8630
8624
|
};
|
|
8631
8625
|
});
|
|
8632
8626
|
return {
|
|
@@ -8653,8 +8647,8 @@ async function getAllClinicsInRange(db, center, rangeInKm, pagination, lastDoc)
|
|
|
8653
8647
|
];
|
|
8654
8648
|
const q = query13(collection13(db, CLINICS_COLLECTION), ...constraints);
|
|
8655
8649
|
const querySnapshot = await getDocs13(q);
|
|
8656
|
-
for (const
|
|
8657
|
-
const clinic =
|
|
8650
|
+
for (const doc38 of querySnapshot.docs) {
|
|
8651
|
+
const clinic = doc38.data();
|
|
8658
8652
|
const distance = distanceBetween2(
|
|
8659
8653
|
[center.latitude, center.longitude],
|
|
8660
8654
|
[clinic.location.latitude, clinic.location.longitude]
|
|
@@ -8776,8 +8770,8 @@ async function findClinicsInRadius(db, center, radiusInKm, filters) {
|
|
|
8776
8770
|
}
|
|
8777
8771
|
const q = query14(collection14(db, CLINICS_COLLECTION), ...constraints);
|
|
8778
8772
|
const querySnapshot = await getDocs14(q);
|
|
8779
|
-
for (const
|
|
8780
|
-
const clinic =
|
|
8773
|
+
for (const doc38 of querySnapshot.docs) {
|
|
8774
|
+
const clinic = doc38.data();
|
|
8781
8775
|
const distance = distanceBetween3(
|
|
8782
8776
|
[center.latitude, center.longitude],
|
|
8783
8777
|
[clinic.location.latitude, clinic.location.longitude]
|
|
@@ -8906,7 +8900,7 @@ async function getClinicsByFilters(db, filters) {
|
|
|
8906
8900
|
constraints.push(limit9(filters.pagination || 5));
|
|
8907
8901
|
const q = query15(collection15(db, CLINICS_COLLECTION), ...constraints);
|
|
8908
8902
|
const querySnapshot = await getDocs15(q);
|
|
8909
|
-
let clinics = querySnapshot.docs.map((
|
|
8903
|
+
let clinics = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
|
|
8910
8904
|
clinics = applyInMemoryFilters(clinics, filters);
|
|
8911
8905
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
8912
8906
|
console.log(`[CLINIC_SERVICE] Strategy 1 success: ${clinics.length} clinics`);
|
|
@@ -8938,7 +8932,7 @@ async function getClinicsByFilters(db, filters) {
|
|
|
8938
8932
|
constraints.push(limit9(filters.pagination || 5));
|
|
8939
8933
|
const q = query15(collection15(db, CLINICS_COLLECTION), ...constraints);
|
|
8940
8934
|
const querySnapshot = await getDocs15(q);
|
|
8941
|
-
let clinics = querySnapshot.docs.map((
|
|
8935
|
+
let clinics = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
|
|
8942
8936
|
clinics = applyInMemoryFilters(clinics, filters);
|
|
8943
8937
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
8944
8938
|
console.log(`[CLINIC_SERVICE] Strategy 2 success: ${clinics.length} clinics`);
|
|
@@ -8968,7 +8962,7 @@ async function getClinicsByFilters(db, filters) {
|
|
|
8968
8962
|
constraints.push(limit9(filters.pagination || 5));
|
|
8969
8963
|
const q = query15(collection15(db, CLINICS_COLLECTION), ...constraints);
|
|
8970
8964
|
const querySnapshot = await getDocs15(q);
|
|
8971
|
-
let clinics = querySnapshot.docs.map((
|
|
8965
|
+
let clinics = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
|
|
8972
8966
|
clinics = applyInMemoryFilters(clinics, filters);
|
|
8973
8967
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
8974
8968
|
console.log(`[CLINIC_SERVICE] Strategy 3 success: ${clinics.length} clinics`);
|
|
@@ -8988,7 +8982,7 @@ async function getClinicsByFilters(db, filters) {
|
|
|
8988
8982
|
];
|
|
8989
8983
|
const q = query15(collection15(db, CLINICS_COLLECTION), ...constraints);
|
|
8990
8984
|
const querySnapshot = await getDocs15(q);
|
|
8991
|
-
let clinics = querySnapshot.docs.map((
|
|
8985
|
+
let clinics = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
|
|
8992
8986
|
clinics = applyInMemoryFilters(clinics, filters);
|
|
8993
8987
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
8994
8988
|
console.log(`[CLINIC_SERVICE] Strategy 4 success: ${clinics.length} clinics`);
|
|
@@ -9564,11 +9558,11 @@ var ClinicService = class extends BaseService {
|
|
|
9564
9558
|
async getClinicsForMap() {
|
|
9565
9559
|
const clinicsRef = collection16(this.db, CLINICS_COLLECTION);
|
|
9566
9560
|
const snapshot = await getDocs16(clinicsRef);
|
|
9567
|
-
const clinicsForMap = snapshot.docs.map((
|
|
9561
|
+
const clinicsForMap = snapshot.docs.map((doc38) => {
|
|
9568
9562
|
var _a, _b, _c;
|
|
9569
|
-
const data =
|
|
9563
|
+
const data = doc38.data();
|
|
9570
9564
|
return {
|
|
9571
|
-
id:
|
|
9565
|
+
id: doc38.id,
|
|
9572
9566
|
name: data.name,
|
|
9573
9567
|
address: ((_a = data.location) == null ? void 0 : _a.address) || "",
|
|
9574
9568
|
latitude: (_b = data.location) == null ? void 0 : _b.latitude,
|
|
@@ -10775,7 +10769,7 @@ async function updatePractitionerCalendarEventUtil(db, practitionerId, eventId,
|
|
|
10775
10769
|
}
|
|
10776
10770
|
|
|
10777
10771
|
// src/services/calendar/utils/appointment.utils.ts
|
|
10778
|
-
async function
|
|
10772
|
+
async function createAppointmentUtil(db, clinicId, practitionerId, patientId, eventData, generateId2) {
|
|
10779
10773
|
const eventId = generateId2();
|
|
10780
10774
|
const autoConfirm = await checkAutoConfirmAppointmentsUtil(db, clinicId);
|
|
10781
10775
|
const initialStatus = autoConfirm ? "confirmed" /* CONFIRMED */ : "pending" /* PENDING */;
|
|
@@ -10922,7 +10916,7 @@ async function searchCalendarEventsUtil(db, params) {
|
|
|
10922
10916
|
const finalQuery = query21(collectionRef, ...constraints);
|
|
10923
10917
|
const querySnapshot = await getDocs21(finalQuery);
|
|
10924
10918
|
const events = querySnapshot.docs.map(
|
|
10925
|
-
(
|
|
10919
|
+
(doc38) => ({ id: doc38.id, ...doc38.data() })
|
|
10926
10920
|
);
|
|
10927
10921
|
return events;
|
|
10928
10922
|
} catch (error) {
|
|
@@ -11015,7 +11009,7 @@ async function getPractitionerSyncedCalendarsUtil(db, practitionerId) {
|
|
|
11015
11009
|
);
|
|
11016
11010
|
const q = query22(calendarsRef, orderBy11("createdAt", "desc"));
|
|
11017
11011
|
const querySnapshot = await getDocs22(q);
|
|
11018
|
-
return querySnapshot.docs.map((
|
|
11012
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
11019
11013
|
}
|
|
11020
11014
|
async function getPatientSyncedCalendarUtil(db, patientId, calendarId) {
|
|
11021
11015
|
const calendarRef = getPatientSyncedCalendarDocRef(db, patientId, calendarId);
|
|
@@ -11032,7 +11026,7 @@ async function getPatientSyncedCalendarsUtil(db, patientId) {
|
|
|
11032
11026
|
);
|
|
11033
11027
|
const q = query22(calendarsRef, orderBy11("createdAt", "desc"));
|
|
11034
11028
|
const querySnapshot = await getDocs22(q);
|
|
11035
|
-
return querySnapshot.docs.map((
|
|
11029
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
11036
11030
|
}
|
|
11037
11031
|
async function getClinicSyncedCalendarUtil(db, clinicId, calendarId) {
|
|
11038
11032
|
const calendarRef = getClinicSyncedCalendarDocRef(db, clinicId, calendarId);
|
|
@@ -11049,7 +11043,7 @@ async function getClinicSyncedCalendarsUtil(db, clinicId) {
|
|
|
11049
11043
|
);
|
|
11050
11044
|
const q = query22(calendarsRef, orderBy11("createdAt", "desc"));
|
|
11051
11045
|
const querySnapshot = await getDocs22(q);
|
|
11052
|
-
return querySnapshot.docs.map((
|
|
11046
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
11053
11047
|
}
|
|
11054
11048
|
async function updatePractitionerSyncedCalendarUtil(db, practitionerId, calendarId, updateData) {
|
|
11055
11049
|
const calendarRef = getPractitionerSyncedCalendarDocRef(
|
|
@@ -12117,7 +12111,7 @@ var CalendarServiceV2 = class extends BaseService {
|
|
|
12117
12111
|
syncStatus: "internal" /* INTERNAL */,
|
|
12118
12112
|
eventType: "appointment" /* APPOINTMENT */
|
|
12119
12113
|
};
|
|
12120
|
-
const appointment = await
|
|
12114
|
+
const appointment = await createAppointmentUtil(
|
|
12121
12115
|
this.db,
|
|
12122
12116
|
params.clinicId,
|
|
12123
12117
|
params.doctorId,
|
|
@@ -12404,9 +12398,9 @@ var CalendarServiceV2 = class extends BaseService {
|
|
|
12404
12398
|
where23("eventTime.start", "<=", Timestamp26.fromDate(endDate))
|
|
12405
12399
|
);
|
|
12406
12400
|
const eventsSnapshot = await getDocs23(q);
|
|
12407
|
-
const events = eventsSnapshot.docs.map((
|
|
12408
|
-
id:
|
|
12409
|
-
...
|
|
12401
|
+
const events = eventsSnapshot.docs.map((doc38) => ({
|
|
12402
|
+
id: doc38.id,
|
|
12403
|
+
...doc38.data()
|
|
12410
12404
|
}));
|
|
12411
12405
|
const calendars = await this.syncedCalendarsService.getPractitionerSyncedCalendars(
|
|
12412
12406
|
doctorId
|
|
@@ -13040,7 +13034,7 @@ var CalendarServiceV2 = class extends BaseService {
|
|
|
13040
13034
|
])
|
|
13041
13035
|
);
|
|
13042
13036
|
const querySnapshot = await getDocs23(q);
|
|
13043
|
-
return querySnapshot.docs.map((
|
|
13037
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
13044
13038
|
}
|
|
13045
13039
|
/**
|
|
13046
13040
|
* Calculates available time slots based on working hours, schedule and existing appointments
|
|
@@ -13585,7 +13579,7 @@ var PractitionerInviteService = class extends BaseService {
|
|
|
13585
13579
|
...constraints
|
|
13586
13580
|
);
|
|
13587
13581
|
const querySnapshot = await getDocs24(q);
|
|
13588
|
-
return querySnapshot.docs.map((
|
|
13582
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
13589
13583
|
} catch (error) {
|
|
13590
13584
|
console.error(
|
|
13591
13585
|
"[PractitionerInviteService] Error getting doctor invites:",
|
|
@@ -13614,7 +13608,7 @@ var PractitionerInviteService = class extends BaseService {
|
|
|
13614
13608
|
...constraints
|
|
13615
13609
|
);
|
|
13616
13610
|
const querySnapshot = await getDocs24(q);
|
|
13617
|
-
return querySnapshot.docs.map((
|
|
13611
|
+
return querySnapshot.docs.map((doc38) => doc38.data());
|
|
13618
13612
|
} catch (error) {
|
|
13619
13613
|
console.error(
|
|
13620
13614
|
"[PractitionerInviteService] Error getting clinic invites:",
|
|
@@ -13770,7 +13764,7 @@ var PractitionerInviteService = class extends BaseService {
|
|
|
13770
13764
|
);
|
|
13771
13765
|
const querySnapshot = await getDocs24(q);
|
|
13772
13766
|
let invites = querySnapshot.docs.map(
|
|
13773
|
-
(
|
|
13767
|
+
(doc38) => doc38.data()
|
|
13774
13768
|
);
|
|
13775
13769
|
if (filters.fromDate) {
|
|
13776
13770
|
invites = invites.filter(
|
|
@@ -13886,9 +13880,10 @@ import {
|
|
|
13886
13880
|
limit as limit12,
|
|
13887
13881
|
startAfter as startAfter10
|
|
13888
13882
|
} from "firebase/firestore";
|
|
13883
|
+
import { getCountFromServer } from "firebase/firestore";
|
|
13889
13884
|
var DocumentationTemplateService = class extends BaseService {
|
|
13890
|
-
constructor() {
|
|
13891
|
-
super(...
|
|
13885
|
+
constructor(...args) {
|
|
13886
|
+
super(...args);
|
|
13892
13887
|
this.collectionRef = collection25(
|
|
13893
13888
|
this.db,
|
|
13894
13889
|
DOCUMENTATION_TEMPLATES_COLLECTION
|
|
@@ -14040,8 +14035,8 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
14040
14035
|
const q = query25(versionsCollectionRef, orderBy13("version", "desc"));
|
|
14041
14036
|
const querySnapshot = await getDocs25(q);
|
|
14042
14037
|
const versions = [];
|
|
14043
|
-
querySnapshot.forEach((
|
|
14044
|
-
versions.push(
|
|
14038
|
+
querySnapshot.forEach((doc38) => {
|
|
14039
|
+
versions.push(doc38.data());
|
|
14045
14040
|
});
|
|
14046
14041
|
return versions;
|
|
14047
14042
|
}
|
|
@@ -14072,15 +14067,97 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
14072
14067
|
const querySnapshot = await getDocs25(q);
|
|
14073
14068
|
const templates = [];
|
|
14074
14069
|
let lastVisible = null;
|
|
14075
|
-
querySnapshot.forEach((
|
|
14076
|
-
templates.push(
|
|
14077
|
-
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;
|
|
14078
14117
|
});
|
|
14079
14118
|
return {
|
|
14080
14119
|
templates,
|
|
14081
14120
|
lastDoc: lastVisible
|
|
14082
14121
|
};
|
|
14083
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
|
+
}
|
|
14084
14161
|
/**
|
|
14085
14162
|
* Get templates by tags
|
|
14086
14163
|
* @param tags - Tags to filter by
|
|
@@ -14102,9 +14179,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
14102
14179
|
const querySnapshot = await getDocs25(q);
|
|
14103
14180
|
const templates = [];
|
|
14104
14181
|
let lastVisible = null;
|
|
14105
|
-
querySnapshot.forEach((
|
|
14106
|
-
templates.push(
|
|
14107
|
-
lastVisible =
|
|
14182
|
+
querySnapshot.forEach((doc38) => {
|
|
14183
|
+
templates.push(doc38.data());
|
|
14184
|
+
lastVisible = doc38;
|
|
14108
14185
|
});
|
|
14109
14186
|
return {
|
|
14110
14187
|
templates,
|
|
@@ -14131,9 +14208,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
14131
14208
|
const querySnapshot = await getDocs25(q);
|
|
14132
14209
|
const templates = [];
|
|
14133
14210
|
let lastVisible = null;
|
|
14134
|
-
querySnapshot.forEach((
|
|
14135
|
-
templates.push(
|
|
14136
|
-
lastVisible =
|
|
14211
|
+
querySnapshot.forEach((doc38) => {
|
|
14212
|
+
templates.push(doc38.data());
|
|
14213
|
+
lastVisible = doc38;
|
|
14137
14214
|
});
|
|
14138
14215
|
return {
|
|
14139
14216
|
templates,
|
|
@@ -14159,8 +14236,8 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
14159
14236
|
}
|
|
14160
14237
|
const querySnapshot = await getDocs25(q);
|
|
14161
14238
|
const templates = [];
|
|
14162
|
-
querySnapshot.forEach((
|
|
14163
|
-
templates.push(
|
|
14239
|
+
querySnapshot.forEach((doc38) => {
|
|
14240
|
+
templates.push(doc38.data());
|
|
14164
14241
|
});
|
|
14165
14242
|
return templates;
|
|
14166
14243
|
}
|
|
@@ -14366,9 +14443,9 @@ var FilledDocumentService = class extends BaseService {
|
|
|
14366
14443
|
const querySnapshot = await getDocs26(q);
|
|
14367
14444
|
const documents = [];
|
|
14368
14445
|
let lastVisible = null;
|
|
14369
|
-
querySnapshot.forEach((
|
|
14370
|
-
documents.push(
|
|
14371
|
-
lastVisible =
|
|
14446
|
+
querySnapshot.forEach((doc38) => {
|
|
14447
|
+
documents.push(doc38.data());
|
|
14448
|
+
lastVisible = doc38;
|
|
14372
14449
|
});
|
|
14373
14450
|
return {
|
|
14374
14451
|
documents,
|
|
@@ -14590,9 +14667,9 @@ var NotificationService = class extends BaseService {
|
|
|
14590
14667
|
orderBy15("notificationTime", "desc")
|
|
14591
14668
|
);
|
|
14592
14669
|
const querySnapshot = await getDocs27(q);
|
|
14593
|
-
return querySnapshot.docs.map((
|
|
14594
|
-
id:
|
|
14595
|
-
...
|
|
14670
|
+
return querySnapshot.docs.map((doc38) => ({
|
|
14671
|
+
id: doc38.id,
|
|
14672
|
+
...doc38.data()
|
|
14596
14673
|
}));
|
|
14597
14674
|
}
|
|
14598
14675
|
/**
|
|
@@ -14606,9 +14683,9 @@ var NotificationService = class extends BaseService {
|
|
|
14606
14683
|
orderBy15("notificationTime", "desc")
|
|
14607
14684
|
);
|
|
14608
14685
|
const querySnapshot = await getDocs27(q);
|
|
14609
|
-
return querySnapshot.docs.map((
|
|
14610
|
-
id:
|
|
14611
|
-
...
|
|
14686
|
+
return querySnapshot.docs.map((doc38) => ({
|
|
14687
|
+
id: doc38.id,
|
|
14688
|
+
...doc38.data()
|
|
14612
14689
|
}));
|
|
14613
14690
|
}
|
|
14614
14691
|
/**
|
|
@@ -14680,9 +14757,9 @@ var NotificationService = class extends BaseService {
|
|
|
14680
14757
|
orderBy15("notificationTime", "desc")
|
|
14681
14758
|
);
|
|
14682
14759
|
const querySnapshot = await getDocs27(q);
|
|
14683
|
-
return querySnapshot.docs.map((
|
|
14684
|
-
id:
|
|
14685
|
-
...
|
|
14760
|
+
return querySnapshot.docs.map((doc38) => ({
|
|
14761
|
+
id: doc38.id,
|
|
14762
|
+
...doc38.data()
|
|
14686
14763
|
}));
|
|
14687
14764
|
}
|
|
14688
14765
|
/**
|
|
@@ -14695,9 +14772,9 @@ var NotificationService = class extends BaseService {
|
|
|
14695
14772
|
orderBy15("notificationTime", "desc")
|
|
14696
14773
|
);
|
|
14697
14774
|
const querySnapshot = await getDocs27(q);
|
|
14698
|
-
return querySnapshot.docs.map((
|
|
14699
|
-
id:
|
|
14700
|
-
...
|
|
14775
|
+
return querySnapshot.docs.map((doc38) => ({
|
|
14776
|
+
id: doc38.id,
|
|
14777
|
+
...doc38.data()
|
|
14701
14778
|
}));
|
|
14702
14779
|
}
|
|
14703
14780
|
};
|
|
@@ -15001,7 +15078,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15001
15078
|
return media;
|
|
15002
15079
|
}
|
|
15003
15080
|
if (media instanceof File || media instanceof Blob) {
|
|
15004
|
-
console.log(
|
|
15081
|
+
console.log(
|
|
15082
|
+
`[ProcedureService] Uploading ${collectionName} media for ${ownerId}`
|
|
15083
|
+
);
|
|
15005
15084
|
const metadata = await this.mediaService.uploadMedia(
|
|
15006
15085
|
media,
|
|
15007
15086
|
ownerId,
|
|
@@ -15023,7 +15102,11 @@ var ProcedureService = class extends BaseService {
|
|
|
15023
15102
|
if (!mediaArray || mediaArray.length === 0) return [];
|
|
15024
15103
|
const result = [];
|
|
15025
15104
|
for (const media of mediaArray) {
|
|
15026
|
-
const processedUrl = await this.processMedia(
|
|
15105
|
+
const processedUrl = await this.processMedia(
|
|
15106
|
+
media,
|
|
15107
|
+
ownerId,
|
|
15108
|
+
collectionName
|
|
15109
|
+
);
|
|
15027
15110
|
if (processedUrl) {
|
|
15028
15111
|
result.push(processedUrl);
|
|
15029
15112
|
}
|
|
@@ -15036,28 +15119,46 @@ var ProcedureService = class extends BaseService {
|
|
|
15036
15119
|
* @returns The created procedure
|
|
15037
15120
|
*/
|
|
15038
15121
|
async createProcedure(data) {
|
|
15039
|
-
var _a;
|
|
15122
|
+
var _a, _b, _c;
|
|
15040
15123
|
const validatedData = createProcedureSchema.parse(data);
|
|
15041
15124
|
const procedureId = this.generateId();
|
|
15042
15125
|
const [category, subcategory, technology, product] = await Promise.all([
|
|
15043
15126
|
this.categoryService.getById(validatedData.categoryId),
|
|
15044
|
-
this.subcategoryService.getById(
|
|
15127
|
+
this.subcategoryService.getById(
|
|
15128
|
+
validatedData.categoryId,
|
|
15129
|
+
validatedData.subcategoryId
|
|
15130
|
+
),
|
|
15045
15131
|
this.technologyService.getById(validatedData.technologyId),
|
|
15046
|
-
this.productService.getById(
|
|
15132
|
+
this.productService.getById(
|
|
15133
|
+
validatedData.technologyId,
|
|
15134
|
+
validatedData.productId
|
|
15135
|
+
)
|
|
15047
15136
|
]);
|
|
15048
15137
|
if (!category || !subcategory || !technology || !product) {
|
|
15049
15138
|
throw new Error("One or more required base entities not found");
|
|
15050
15139
|
}
|
|
15051
|
-
const clinicRef = doc30(
|
|
15140
|
+
const clinicRef = doc30(
|
|
15141
|
+
this.db,
|
|
15142
|
+
CLINICS_COLLECTION,
|
|
15143
|
+
validatedData.clinicBranchId
|
|
15144
|
+
);
|
|
15052
15145
|
const clinicSnapshot = await getDoc32(clinicRef);
|
|
15053
15146
|
if (!clinicSnapshot.exists()) {
|
|
15054
|
-
throw new Error(
|
|
15147
|
+
throw new Error(
|
|
15148
|
+
`Clinic with ID ${validatedData.clinicBranchId} not found`
|
|
15149
|
+
);
|
|
15055
15150
|
}
|
|
15056
15151
|
const clinic = clinicSnapshot.data();
|
|
15057
|
-
const practitionerRef = doc30(
|
|
15152
|
+
const practitionerRef = doc30(
|
|
15153
|
+
this.db,
|
|
15154
|
+
PRACTITIONERS_COLLECTION,
|
|
15155
|
+
validatedData.practitionerId
|
|
15156
|
+
);
|
|
15058
15157
|
const practitionerSnapshot = await getDoc32(practitionerRef);
|
|
15059
15158
|
if (!practitionerSnapshot.exists()) {
|
|
15060
|
-
throw new Error(
|
|
15159
|
+
throw new Error(
|
|
15160
|
+
`Practitioner with ID ${validatedData.practitionerId} not found`
|
|
15161
|
+
);
|
|
15061
15162
|
}
|
|
15062
15163
|
const practitioner = practitionerSnapshot.data();
|
|
15063
15164
|
let processedPhotos = [];
|
|
@@ -15098,7 +15199,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15098
15199
|
product,
|
|
15099
15200
|
blockingConditions: technology.blockingConditions,
|
|
15100
15201
|
contraindications: technology.contraindications || [],
|
|
15202
|
+
contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
|
|
15101
15203
|
treatmentBenefits: technology.benefits,
|
|
15204
|
+
treatmentBenefitIds: ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [],
|
|
15102
15205
|
preRequirements: technology.requirements.pre,
|
|
15103
15206
|
postRequirements: technology.requirements.post,
|
|
15104
15207
|
certificationRequirement: technology.certificationRequirement,
|
|
@@ -15139,7 +15242,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15139
15242
|
* @returns A promise that resolves to an array of the newly created procedures.
|
|
15140
15243
|
*/
|
|
15141
15244
|
async bulkCreateProcedures(baseData, practitionerIds) {
|
|
15142
|
-
var _a;
|
|
15245
|
+
var _a, _b, _c;
|
|
15143
15246
|
if (!practitionerIds || practitionerIds.length === 0) {
|
|
15144
15247
|
throw new Error("Practitioner IDs array cannot be empty.");
|
|
15145
15248
|
}
|
|
@@ -15147,16 +15250,24 @@ var ProcedureService = class extends BaseService {
|
|
|
15147
15250
|
const validatedData = createProcedureSchema.parse(validationData);
|
|
15148
15251
|
const [category, subcategory, technology, product, clinicSnapshot] = await Promise.all([
|
|
15149
15252
|
this.categoryService.getById(validatedData.categoryId),
|
|
15150
|
-
this.subcategoryService.getById(
|
|
15253
|
+
this.subcategoryService.getById(
|
|
15254
|
+
validatedData.categoryId,
|
|
15255
|
+
validatedData.subcategoryId
|
|
15256
|
+
),
|
|
15151
15257
|
this.technologyService.getById(validatedData.technologyId),
|
|
15152
|
-
this.productService.getById(
|
|
15258
|
+
this.productService.getById(
|
|
15259
|
+
validatedData.technologyId,
|
|
15260
|
+
validatedData.productId
|
|
15261
|
+
),
|
|
15153
15262
|
getDoc32(doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId))
|
|
15154
15263
|
]);
|
|
15155
15264
|
if (!category || !subcategory || !technology || !product) {
|
|
15156
15265
|
throw new Error("One or more required base entities not found");
|
|
15157
15266
|
}
|
|
15158
15267
|
if (!clinicSnapshot.exists()) {
|
|
15159
|
-
throw new Error(
|
|
15268
|
+
throw new Error(
|
|
15269
|
+
`Clinic with ID ${validatedData.clinicBranchId} not found`
|
|
15270
|
+
);
|
|
15160
15271
|
}
|
|
15161
15272
|
const clinic = clinicSnapshot.data();
|
|
15162
15273
|
let processedPhotos = [];
|
|
@@ -15176,14 +15287,18 @@ var ProcedureService = class extends BaseService {
|
|
|
15176
15287
|
where29(documentId2(), "in", chunk)
|
|
15177
15288
|
);
|
|
15178
15289
|
const practitionersSnapshot = await getDocs29(practitionersQuery);
|
|
15179
|
-
practitionersSnapshot.docs.forEach((
|
|
15180
|
-
practitionersMap.set(
|
|
15290
|
+
practitionersSnapshot.docs.forEach((doc38) => {
|
|
15291
|
+
practitionersMap.set(doc38.id, doc38.data());
|
|
15181
15292
|
});
|
|
15182
15293
|
}
|
|
15183
15294
|
if (practitionersMap.size !== practitionerIds.length) {
|
|
15184
15295
|
const foundIds = Array.from(practitionersMap.keys());
|
|
15185
|
-
const notFoundIds = practitionerIds.filter(
|
|
15186
|
-
|
|
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
|
+
);
|
|
15187
15302
|
}
|
|
15188
15303
|
const batch = writeBatch6(this.db);
|
|
15189
15304
|
const createdProcedureIds = [];
|
|
@@ -15221,7 +15336,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15221
15336
|
product,
|
|
15222
15337
|
blockingConditions: technology.blockingConditions,
|
|
15223
15338
|
contraindications: technology.contraindications || [],
|
|
15339
|
+
contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
|
|
15224
15340
|
treatmentBenefits: technology.benefits,
|
|
15341
|
+
treatmentBenefitIds: ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [],
|
|
15225
15342
|
preRequirements: technology.requirements.pre,
|
|
15226
15343
|
postRequirements: technology.requirements.post,
|
|
15227
15344
|
certificationRequirement: technology.certificationRequirement,
|
|
@@ -15251,10 +15368,13 @@ var ProcedureService = class extends BaseService {
|
|
|
15251
15368
|
const fetchedProcedures = [];
|
|
15252
15369
|
for (let i = 0; i < createdProcedureIds.length; i += 30) {
|
|
15253
15370
|
const chunk = createdProcedureIds.slice(i, i + 30);
|
|
15254
|
-
const q = query29(
|
|
15371
|
+
const q = query29(
|
|
15372
|
+
collection29(this.db, PROCEDURES_COLLECTION),
|
|
15373
|
+
where29(documentId2(), "in", chunk)
|
|
15374
|
+
);
|
|
15255
15375
|
const snapshot = await getDocs29(q);
|
|
15256
|
-
snapshot.forEach((
|
|
15257
|
-
fetchedProcedures.push(
|
|
15376
|
+
snapshot.forEach((doc38) => {
|
|
15377
|
+
fetchedProcedures.push(doc38.data());
|
|
15258
15378
|
});
|
|
15259
15379
|
}
|
|
15260
15380
|
return fetchedProcedures;
|
|
@@ -15284,7 +15404,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15284
15404
|
where29("isActive", "==", true)
|
|
15285
15405
|
);
|
|
15286
15406
|
const snapshot = await getDocs29(q);
|
|
15287
|
-
return snapshot.docs.map((
|
|
15407
|
+
return snapshot.docs.map((doc38) => doc38.data());
|
|
15288
15408
|
}
|
|
15289
15409
|
/**
|
|
15290
15410
|
* Gets all procedures for a practitioner
|
|
@@ -15298,7 +15418,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15298
15418
|
where29("isActive", "==", true)
|
|
15299
15419
|
);
|
|
15300
15420
|
const snapshot = await getDocs29(q);
|
|
15301
|
-
return snapshot.docs.map((
|
|
15421
|
+
return snapshot.docs.map((doc38) => doc38.data());
|
|
15302
15422
|
}
|
|
15303
15423
|
/**
|
|
15304
15424
|
* Gets all inactive procedures for a practitioner
|
|
@@ -15312,7 +15432,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15312
15432
|
where29("isActive", "==", false)
|
|
15313
15433
|
);
|
|
15314
15434
|
const snapshot = await getDocs29(q);
|
|
15315
|
-
return snapshot.docs.map((
|
|
15435
|
+
return snapshot.docs.map((doc38) => doc38.data());
|
|
15316
15436
|
}
|
|
15317
15437
|
/**
|
|
15318
15438
|
* Updates a procedure
|
|
@@ -15321,7 +15441,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15321
15441
|
* @returns The updated procedure
|
|
15322
15442
|
*/
|
|
15323
15443
|
async updateProcedure(id, data) {
|
|
15324
|
-
var _a;
|
|
15444
|
+
var _a, _b, _c;
|
|
15325
15445
|
const validatedData = updateProcedureSchema.parse(data);
|
|
15326
15446
|
const procedureRef = doc30(this.db, PROCEDURES_COLLECTION, id);
|
|
15327
15447
|
const procedureSnapshot = await getDoc32(procedureRef);
|
|
@@ -15352,7 +15472,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15352
15472
|
);
|
|
15353
15473
|
const newPractitionerSnap = await getDoc32(newPractitionerRef);
|
|
15354
15474
|
if (!newPractitionerSnap.exists())
|
|
15355
|
-
throw new Error(
|
|
15475
|
+
throw new Error(
|
|
15476
|
+
`New Practitioner ${validatedData.practitionerId} not found`
|
|
15477
|
+
);
|
|
15356
15478
|
newPractitioner = newPractitionerSnap.data();
|
|
15357
15479
|
updatedProcedureData.doctorInfo = {
|
|
15358
15480
|
id: newPractitioner.id,
|
|
@@ -15366,7 +15488,11 @@ var ProcedureService = class extends BaseService {
|
|
|
15366
15488
|
}
|
|
15367
15489
|
if (validatedData.clinicBranchId && validatedData.clinicBranchId !== oldClinicId) {
|
|
15368
15490
|
clinicChanged = true;
|
|
15369
|
-
const newClinicRef = doc30(
|
|
15491
|
+
const newClinicRef = doc30(
|
|
15492
|
+
this.db,
|
|
15493
|
+
CLINICS_COLLECTION,
|
|
15494
|
+
validatedData.clinicBranchId
|
|
15495
|
+
);
|
|
15370
15496
|
const newClinicSnap = await getDoc32(newClinicRef);
|
|
15371
15497
|
if (!newClinicSnap.exists())
|
|
15372
15498
|
throw new Error(`New Clinic ${validatedData.clinicBranchId} not found`);
|
|
@@ -15385,8 +15511,11 @@ var ProcedureService = class extends BaseService {
|
|
|
15385
15511
|
updatedProcedureData.nameLower = validatedData.name.toLowerCase();
|
|
15386
15512
|
}
|
|
15387
15513
|
if (validatedData.categoryId) {
|
|
15388
|
-
const category = await this.categoryService.getById(
|
|
15389
|
-
|
|
15514
|
+
const category = await this.categoryService.getById(
|
|
15515
|
+
validatedData.categoryId
|
|
15516
|
+
);
|
|
15517
|
+
if (!category)
|
|
15518
|
+
throw new Error(`Category ${validatedData.categoryId} not found`);
|
|
15390
15519
|
updatedProcedureData.category = category;
|
|
15391
15520
|
finalCategoryId = category.id;
|
|
15392
15521
|
}
|
|
@@ -15401,23 +15530,34 @@ var ProcedureService = class extends BaseService {
|
|
|
15401
15530
|
);
|
|
15402
15531
|
updatedProcedureData.subcategory = subcategory;
|
|
15403
15532
|
} else if (validatedData.subcategoryId) {
|
|
15404
|
-
console.warn(
|
|
15533
|
+
console.warn(
|
|
15534
|
+
"Attempted to update subcategory without a valid categoryId"
|
|
15535
|
+
);
|
|
15405
15536
|
}
|
|
15406
15537
|
let finalTechnologyId = existingProcedure.technology.id;
|
|
15407
15538
|
if (validatedData.technologyId) {
|
|
15408
|
-
const technology = await this.technologyService.getById(
|
|
15409
|
-
|
|
15539
|
+
const technology = await this.technologyService.getById(
|
|
15540
|
+
validatedData.technologyId
|
|
15541
|
+
);
|
|
15542
|
+
if (!technology)
|
|
15543
|
+
throw new Error(`Technology ${validatedData.technologyId} not found`);
|
|
15410
15544
|
updatedProcedureData.technology = technology;
|
|
15411
15545
|
finalTechnologyId = technology.id;
|
|
15412
15546
|
updatedProcedureData.blockingConditions = technology.blockingConditions;
|
|
15547
|
+
updatedProcedureData.contraindications = technology.contraindications || [];
|
|
15548
|
+
updatedProcedureData.contraindicationIds = ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [];
|
|
15413
15549
|
updatedProcedureData.treatmentBenefits = technology.benefits;
|
|
15550
|
+
updatedProcedureData.treatmentBenefitIds = ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [];
|
|
15414
15551
|
updatedProcedureData.preRequirements = technology.requirements.pre;
|
|
15415
15552
|
updatedProcedureData.postRequirements = technology.requirements.post;
|
|
15416
15553
|
updatedProcedureData.certificationRequirement = technology.certificationRequirement;
|
|
15417
15554
|
updatedProcedureData.documentationTemplates = technology.documentationTemplates || [];
|
|
15418
15555
|
}
|
|
15419
15556
|
if (validatedData.productId && finalTechnologyId) {
|
|
15420
|
-
const product = await this.productService.getById(
|
|
15557
|
+
const product = await this.productService.getById(
|
|
15558
|
+
finalTechnologyId,
|
|
15559
|
+
validatedData.productId
|
|
15560
|
+
);
|
|
15421
15561
|
if (!product)
|
|
15422
15562
|
throw new Error(
|
|
15423
15563
|
`Product ${validatedData.productId} not found for technology ${finalTechnologyId}`
|
|
@@ -15489,28 +15629,32 @@ var ProcedureService = class extends BaseService {
|
|
|
15489
15629
|
const proceduresCollection = collection29(this.db, PROCEDURES_COLLECTION);
|
|
15490
15630
|
let proceduresQuery = query29(proceduresCollection);
|
|
15491
15631
|
if (pagination && pagination > 0) {
|
|
15492
|
-
const { limit:
|
|
15632
|
+
const { limit: limit21, startAfter: startAfter19 } = await import("firebase/firestore");
|
|
15493
15633
|
if (lastDoc) {
|
|
15494
15634
|
proceduresQuery = query29(
|
|
15495
15635
|
proceduresCollection,
|
|
15496
15636
|
orderBy17("name"),
|
|
15497
15637
|
// Use imported orderBy
|
|
15498
|
-
|
|
15499
|
-
|
|
15638
|
+
startAfter19(lastDoc),
|
|
15639
|
+
limit21(pagination)
|
|
15500
15640
|
);
|
|
15501
15641
|
} else {
|
|
15502
|
-
proceduresQuery = query29(
|
|
15642
|
+
proceduresQuery = query29(
|
|
15643
|
+
proceduresCollection,
|
|
15644
|
+
orderBy17("name"),
|
|
15645
|
+
limit21(pagination)
|
|
15646
|
+
);
|
|
15503
15647
|
}
|
|
15504
15648
|
} else {
|
|
15505
15649
|
proceduresQuery = query29(proceduresCollection, orderBy17("name"));
|
|
15506
15650
|
}
|
|
15507
15651
|
const proceduresSnapshot = await getDocs29(proceduresQuery);
|
|
15508
15652
|
const lastVisible = proceduresSnapshot.docs[proceduresSnapshot.docs.length - 1];
|
|
15509
|
-
const procedures = proceduresSnapshot.docs.map((
|
|
15510
|
-
const data =
|
|
15653
|
+
const procedures = proceduresSnapshot.docs.map((doc38) => {
|
|
15654
|
+
const data = doc38.data();
|
|
15511
15655
|
return {
|
|
15512
15656
|
...data,
|
|
15513
|
-
id:
|
|
15657
|
+
id: doc38.id
|
|
15514
15658
|
// Ensure ID is present
|
|
15515
15659
|
};
|
|
15516
15660
|
});
|
|
@@ -15530,7 +15674,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15530
15674
|
*
|
|
15531
15675
|
* @param filters - Various filters to apply
|
|
15532
15676
|
* @param filters.nameSearch - Optional search text for procedure name
|
|
15533
|
-
* @param filters.
|
|
15677
|
+
* @param filters.treatmentBenefitIds - Optional array of treatment benefits to filter by
|
|
15534
15678
|
* @param filters.procedureFamily - Optional procedure family to filter by
|
|
15535
15679
|
* @param filters.procedureCategory - Optional procedure category to filter by
|
|
15536
15680
|
* @param filters.procedureSubcategory - Optional procedure subcategory to filter by
|
|
@@ -15548,7 +15692,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15548
15692
|
*/
|
|
15549
15693
|
async getProceduresByFilters(filters) {
|
|
15550
15694
|
try {
|
|
15551
|
-
console.log(
|
|
15695
|
+
console.log(
|
|
15696
|
+
"[PROCEDURE_SERVICE] Starting procedure filtering with multiple strategies"
|
|
15697
|
+
);
|
|
15552
15698
|
if (filters.location && filters.radiusInKm) {
|
|
15553
15699
|
console.log("[PROCEDURE_SERVICE] Executing geo query:", {
|
|
15554
15700
|
location: filters.location,
|
|
@@ -15556,7 +15702,10 @@ var ProcedureService = class extends BaseService {
|
|
|
15556
15702
|
serviceName: "ProcedureService"
|
|
15557
15703
|
});
|
|
15558
15704
|
if (!filters.location.latitude || !filters.location.longitude) {
|
|
15559
|
-
console.warn(
|
|
15705
|
+
console.warn(
|
|
15706
|
+
"[PROCEDURE_SERVICE] Invalid location data:",
|
|
15707
|
+
filters.location
|
|
15708
|
+
);
|
|
15560
15709
|
filters.location = void 0;
|
|
15561
15710
|
filters.radiusInKm = void 0;
|
|
15562
15711
|
}
|
|
@@ -15576,13 +15725,19 @@ var ProcedureService = class extends BaseService {
|
|
|
15576
15725
|
constraints.push(where29("family", "==", filters.procedureFamily));
|
|
15577
15726
|
}
|
|
15578
15727
|
if (filters.procedureCategory) {
|
|
15579
|
-
constraints.push(
|
|
15728
|
+
constraints.push(
|
|
15729
|
+
where29("category.id", "==", filters.procedureCategory)
|
|
15730
|
+
);
|
|
15580
15731
|
}
|
|
15581
15732
|
if (filters.procedureSubcategory) {
|
|
15582
|
-
constraints.push(
|
|
15733
|
+
constraints.push(
|
|
15734
|
+
where29("subcategory.id", "==", filters.procedureSubcategory)
|
|
15735
|
+
);
|
|
15583
15736
|
}
|
|
15584
15737
|
if (filters.procedureTechnology) {
|
|
15585
|
-
constraints.push(
|
|
15738
|
+
constraints.push(
|
|
15739
|
+
where29("technology.id", "==", filters.procedureTechnology)
|
|
15740
|
+
);
|
|
15586
15741
|
}
|
|
15587
15742
|
if (filters.minPrice !== void 0) {
|
|
15588
15743
|
constraints.push(where29("price", ">=", filters.minPrice));
|
|
@@ -15591,20 +15746,32 @@ var ProcedureService = class extends BaseService {
|
|
|
15591
15746
|
constraints.push(where29("price", "<=", filters.maxPrice));
|
|
15592
15747
|
}
|
|
15593
15748
|
if (filters.minRating !== void 0) {
|
|
15594
|
-
constraints.push(
|
|
15749
|
+
constraints.push(
|
|
15750
|
+
where29("reviewInfo.averageRating", ">=", filters.minRating)
|
|
15751
|
+
);
|
|
15595
15752
|
}
|
|
15596
15753
|
if (filters.maxRating !== void 0) {
|
|
15597
|
-
constraints.push(
|
|
15754
|
+
constraints.push(
|
|
15755
|
+
where29("reviewInfo.averageRating", "<=", filters.maxRating)
|
|
15756
|
+
);
|
|
15598
15757
|
}
|
|
15599
15758
|
if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
|
|
15600
|
-
const
|
|
15601
|
-
constraints.push(
|
|
15759
|
+
const benefitIdsToMatch = filters.treatmentBenefits;
|
|
15760
|
+
constraints.push(
|
|
15761
|
+
where29(
|
|
15762
|
+
"treatmentBenefitIds",
|
|
15763
|
+
"array-contains-any",
|
|
15764
|
+
benefitIdsToMatch
|
|
15765
|
+
)
|
|
15766
|
+
);
|
|
15602
15767
|
}
|
|
15603
15768
|
return constraints;
|
|
15604
15769
|
};
|
|
15605
15770
|
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
15606
15771
|
try {
|
|
15607
|
-
console.log(
|
|
15772
|
+
console.log(
|
|
15773
|
+
"[PROCEDURE_SERVICE] Strategy 1: Trying nameLower search"
|
|
15774
|
+
);
|
|
15608
15775
|
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
15609
15776
|
const constraints = getBaseConstraints();
|
|
15610
15777
|
constraints.push(where29("nameLower", ">=", searchTerm));
|
|
@@ -15620,13 +15787,18 @@ var ProcedureService = class extends BaseService {
|
|
|
15620
15787
|
}
|
|
15621
15788
|
}
|
|
15622
15789
|
constraints.push(limit15(filters.pagination || 10));
|
|
15623
|
-
const q = query29(
|
|
15790
|
+
const q = query29(
|
|
15791
|
+
collection29(this.db, PROCEDURES_COLLECTION),
|
|
15792
|
+
...constraints
|
|
15793
|
+
);
|
|
15624
15794
|
const querySnapshot = await getDocs29(q);
|
|
15625
15795
|
const procedures = querySnapshot.docs.map(
|
|
15626
|
-
(
|
|
15796
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
15627
15797
|
);
|
|
15628
15798
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15629
|
-
console.log(
|
|
15799
|
+
console.log(
|
|
15800
|
+
`[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`
|
|
15801
|
+
);
|
|
15630
15802
|
if (procedures.length < (filters.pagination || 10)) {
|
|
15631
15803
|
return { procedures, lastDoc: null };
|
|
15632
15804
|
}
|
|
@@ -15637,7 +15809,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15637
15809
|
}
|
|
15638
15810
|
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
15639
15811
|
try {
|
|
15640
|
-
console.log(
|
|
15812
|
+
console.log(
|
|
15813
|
+
"[PROCEDURE_SERVICE] Strategy 2: Trying name field search"
|
|
15814
|
+
);
|
|
15641
15815
|
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
15642
15816
|
const constraints = getBaseConstraints();
|
|
15643
15817
|
constraints.push(where29("name", ">=", searchTerm));
|
|
@@ -15653,13 +15827,18 @@ var ProcedureService = class extends BaseService {
|
|
|
15653
15827
|
}
|
|
15654
15828
|
}
|
|
15655
15829
|
constraints.push(limit15(filters.pagination || 10));
|
|
15656
|
-
const q = query29(
|
|
15830
|
+
const q = query29(
|
|
15831
|
+
collection29(this.db, PROCEDURES_COLLECTION),
|
|
15832
|
+
...constraints
|
|
15833
|
+
);
|
|
15657
15834
|
const querySnapshot = await getDocs29(q);
|
|
15658
15835
|
const procedures = querySnapshot.docs.map(
|
|
15659
|
-
(
|
|
15836
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
15660
15837
|
);
|
|
15661
15838
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15662
|
-
console.log(
|
|
15839
|
+
console.log(
|
|
15840
|
+
`[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`
|
|
15841
|
+
);
|
|
15663
15842
|
if (procedures.length < (filters.pagination || 10)) {
|
|
15664
15843
|
return { procedures, lastDoc: null };
|
|
15665
15844
|
}
|
|
@@ -15684,14 +15863,19 @@ var ProcedureService = class extends BaseService {
|
|
|
15684
15863
|
}
|
|
15685
15864
|
}
|
|
15686
15865
|
constraints.push(limit15(filters.pagination || 10));
|
|
15687
|
-
const q = query29(
|
|
15866
|
+
const q = query29(
|
|
15867
|
+
collection29(this.db, PROCEDURES_COLLECTION),
|
|
15868
|
+
...constraints
|
|
15869
|
+
);
|
|
15688
15870
|
const querySnapshot = await getDocs29(q);
|
|
15689
15871
|
let procedures = querySnapshot.docs.map(
|
|
15690
|
-
(
|
|
15872
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
15691
15873
|
);
|
|
15692
15874
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15693
15875
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15694
|
-
console.log(
|
|
15876
|
+
console.log(
|
|
15877
|
+
`[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`
|
|
15878
|
+
);
|
|
15695
15879
|
if (procedures.length < (filters.pagination || 10)) {
|
|
15696
15880
|
return { procedures, lastDoc: null };
|
|
15697
15881
|
}
|
|
@@ -15706,14 +15890,19 @@ var ProcedureService = class extends BaseService {
|
|
|
15706
15890
|
orderBy17("createdAt", "desc"),
|
|
15707
15891
|
limit15(filters.pagination || 10)
|
|
15708
15892
|
];
|
|
15709
|
-
const q = query29(
|
|
15893
|
+
const q = query29(
|
|
15894
|
+
collection29(this.db, PROCEDURES_COLLECTION),
|
|
15895
|
+
...constraints
|
|
15896
|
+
);
|
|
15710
15897
|
const querySnapshot = await getDocs29(q);
|
|
15711
15898
|
let procedures = querySnapshot.docs.map(
|
|
15712
|
-
(
|
|
15899
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
15713
15900
|
);
|
|
15714
15901
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15715
15902
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15716
|
-
console.log(
|
|
15903
|
+
console.log(
|
|
15904
|
+
`[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`
|
|
15905
|
+
);
|
|
15717
15906
|
if (procedures.length < (filters.pagination || 10)) {
|
|
15718
15907
|
return { procedures, lastDoc: null };
|
|
15719
15908
|
}
|
|
@@ -15721,7 +15910,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15721
15910
|
} catch (error) {
|
|
15722
15911
|
console.log("[PROCEDURE_SERVICE] Strategy 4 failed:", error);
|
|
15723
15912
|
}
|
|
15724
|
-
console.log(
|
|
15913
|
+
console.log(
|
|
15914
|
+
"[PROCEDURE_SERVICE] All strategies failed, returning empty result"
|
|
15915
|
+
);
|
|
15725
15916
|
return { procedures: [], lastDoc: null };
|
|
15726
15917
|
} catch (error) {
|
|
15727
15918
|
console.error("[PROCEDURE_SERVICE] Error filtering procedures:", error);
|
|
@@ -15741,13 +15932,17 @@ var ProcedureService = class extends BaseService {
|
|
|
15741
15932
|
const nameLower = procedure.nameLower || "";
|
|
15742
15933
|
return name.includes(searchTerm) || nameLower.includes(searchTerm);
|
|
15743
15934
|
});
|
|
15744
|
-
console.log(
|
|
15935
|
+
console.log(
|
|
15936
|
+
`[PROCEDURE_SERVICE] Applied name filter, results: ${filteredProcedures.length}`
|
|
15937
|
+
);
|
|
15745
15938
|
}
|
|
15746
15939
|
if (filters.minPrice !== void 0 || filters.maxPrice !== void 0) {
|
|
15747
15940
|
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15748
15941
|
const price = procedure.price || 0;
|
|
15749
|
-
if (filters.minPrice !== void 0 && price < filters.minPrice)
|
|
15750
|
-
|
|
15942
|
+
if (filters.minPrice !== void 0 && price < filters.minPrice)
|
|
15943
|
+
return false;
|
|
15944
|
+
if (filters.maxPrice !== void 0 && price > filters.maxPrice)
|
|
15945
|
+
return false;
|
|
15751
15946
|
return true;
|
|
15752
15947
|
});
|
|
15753
15948
|
console.log(
|
|
@@ -15758,8 +15953,10 @@ var ProcedureService = class extends BaseService {
|
|
|
15758
15953
|
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15759
15954
|
var _a;
|
|
15760
15955
|
const rating = ((_a = procedure.reviewInfo) == null ? void 0 : _a.averageRating) || 0;
|
|
15761
|
-
if (filters.minRating !== void 0 && rating < filters.minRating)
|
|
15762
|
-
|
|
15956
|
+
if (filters.minRating !== void 0 && rating < filters.minRating)
|
|
15957
|
+
return false;
|
|
15958
|
+
if (filters.maxRating !== void 0 && rating > filters.maxRating)
|
|
15959
|
+
return false;
|
|
15763
15960
|
return true;
|
|
15764
15961
|
});
|
|
15765
15962
|
console.log(
|
|
@@ -15767,10 +15964,12 @@ var ProcedureService = class extends BaseService {
|
|
|
15767
15964
|
);
|
|
15768
15965
|
}
|
|
15769
15966
|
if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
|
|
15770
|
-
const
|
|
15967
|
+
const benefitIdsToMatch = filters.treatmentBenefits;
|
|
15771
15968
|
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15772
|
-
const
|
|
15773
|
-
return
|
|
15969
|
+
const procedureBenefitIds = procedure.treatmentBenefitIds || [];
|
|
15970
|
+
return benefitIdsToMatch.some(
|
|
15971
|
+
(benefitId) => procedureBenefitIds.includes(benefitId)
|
|
15972
|
+
);
|
|
15774
15973
|
});
|
|
15775
15974
|
console.log(
|
|
15776
15975
|
`[PROCEDURE_SERVICE] Applied benefits filter, results: ${filteredProcedures.length}`
|
|
@@ -15833,8 +16032,12 @@ var ProcedureService = class extends BaseService {
|
|
|
15833
16032
|
procedure.distance = distance;
|
|
15834
16033
|
return distance <= radiusInKm;
|
|
15835
16034
|
});
|
|
15836
|
-
console.log(
|
|
15837
|
-
|
|
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
|
+
);
|
|
15838
16041
|
}
|
|
15839
16042
|
return filteredProcedures;
|
|
15840
16043
|
}
|
|
@@ -15846,19 +16049,30 @@ var ProcedureService = class extends BaseService {
|
|
|
15846
16049
|
if (!location || !radiusInKm) {
|
|
15847
16050
|
return Promise.resolve({ procedures: [], lastDoc: null });
|
|
15848
16051
|
}
|
|
15849
|
-
const bounds = geohashQueryBounds5(
|
|
16052
|
+
const bounds = geohashQueryBounds5(
|
|
16053
|
+
[location.latitude, location.longitude],
|
|
16054
|
+
radiusInKm * 1e3
|
|
16055
|
+
);
|
|
15850
16056
|
const fetches = bounds.map((b) => {
|
|
15851
16057
|
const constraints = [
|
|
15852
16058
|
where29("clinicInfo.location.geohash", ">=", b[0]),
|
|
15853
16059
|
where29("clinicInfo.location.geohash", "<=", b[1]),
|
|
15854
|
-
where29(
|
|
16060
|
+
where29(
|
|
16061
|
+
"isActive",
|
|
16062
|
+
"==",
|
|
16063
|
+
filters.isActive !== void 0 ? filters.isActive : true
|
|
16064
|
+
)
|
|
15855
16065
|
];
|
|
15856
|
-
return getDocs29(
|
|
16066
|
+
return getDocs29(
|
|
16067
|
+
query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints)
|
|
16068
|
+
);
|
|
15857
16069
|
});
|
|
15858
16070
|
return Promise.all(fetches).then((snaps) => {
|
|
15859
16071
|
const collected = [];
|
|
15860
16072
|
snaps.forEach((snap) => {
|
|
15861
|
-
snap.docs.forEach(
|
|
16073
|
+
snap.docs.forEach(
|
|
16074
|
+
(d) => collected.push({ ...d.data(), id: d.id })
|
|
16075
|
+
);
|
|
15862
16076
|
});
|
|
15863
16077
|
const uniqueMap = /* @__PURE__ */ new Map();
|
|
15864
16078
|
for (const p of collected) {
|
|
@@ -15869,7 +16083,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15869
16083
|
const pageSize = filters.pagination || 10;
|
|
15870
16084
|
let startIndex = 0;
|
|
15871
16085
|
if (filters.lastDoc && typeof filters.lastDoc === "object" && filters.lastDoc.id) {
|
|
15872
|
-
const idx = procedures.findIndex(
|
|
16086
|
+
const idx = procedures.findIndex(
|
|
16087
|
+
(p) => p.id === filters.lastDoc.id
|
|
16088
|
+
);
|
|
15873
16089
|
if (idx >= 0) startIndex = idx + 1;
|
|
15874
16090
|
}
|
|
15875
16091
|
const page = procedures.slice(startIndex, startIndex + pageSize);
|
|
@@ -15894,7 +16110,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15894
16110
|
* @returns The created procedure
|
|
15895
16111
|
*/
|
|
15896
16112
|
async createConsultationProcedure(data) {
|
|
15897
|
-
var _a;
|
|
16113
|
+
var _a, _b, _c;
|
|
15898
16114
|
const procedureId = this.generateId();
|
|
15899
16115
|
const [category, subcategory, technology] = await Promise.all([
|
|
15900
16116
|
this.categoryService.getById(data.categoryId),
|
|
@@ -15910,7 +16126,11 @@ var ProcedureService = class extends BaseService {
|
|
|
15910
16126
|
throw new Error(`Clinic with ID ${data.clinicBranchId} not found`);
|
|
15911
16127
|
}
|
|
15912
16128
|
const clinic = clinicSnapshot.data();
|
|
15913
|
-
const practitionerRef = doc30(
|
|
16129
|
+
const practitionerRef = doc30(
|
|
16130
|
+
this.db,
|
|
16131
|
+
PRACTITIONERS_COLLECTION,
|
|
16132
|
+
data.practitionerId
|
|
16133
|
+
);
|
|
15914
16134
|
const practitionerSnapshot = await getDoc32(practitionerRef);
|
|
15915
16135
|
if (!practitionerSnapshot.exists()) {
|
|
15916
16136
|
throw new Error(`Practitioner with ID ${data.practitionerId} not found`);
|
|
@@ -15918,7 +16138,11 @@ var ProcedureService = class extends BaseService {
|
|
|
15918
16138
|
const practitioner = practitionerSnapshot.data();
|
|
15919
16139
|
let processedPhotos = [];
|
|
15920
16140
|
if (data.photos && data.photos.length > 0) {
|
|
15921
|
-
processedPhotos = await this.processMediaArray(
|
|
16141
|
+
processedPhotos = await this.processMediaArray(
|
|
16142
|
+
data.photos,
|
|
16143
|
+
procedureId,
|
|
16144
|
+
"procedure-photos"
|
|
16145
|
+
);
|
|
15922
16146
|
}
|
|
15923
16147
|
const clinicInfo = {
|
|
15924
16148
|
id: clinicSnapshot.id,
|
|
@@ -15944,6 +16168,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15944
16168
|
brandName: "Consultation",
|
|
15945
16169
|
technologyId: data.technologyId,
|
|
15946
16170
|
technologyName: technology.name,
|
|
16171
|
+
categoryId: technology.categoryId,
|
|
16172
|
+
subcategoryId: technology.subcategoryId,
|
|
15947
16173
|
isActive: true,
|
|
15948
16174
|
createdAt: /* @__PURE__ */ new Date(),
|
|
15949
16175
|
updatedAt: /* @__PURE__ */ new Date()
|
|
@@ -15960,7 +16186,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15960
16186
|
// Use placeholder product
|
|
15961
16187
|
blockingConditions: technology.blockingConditions,
|
|
15962
16188
|
contraindications: technology.contraindications || [],
|
|
16189
|
+
contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
|
|
15963
16190
|
treatmentBenefits: technology.benefits,
|
|
16191
|
+
treatmentBenefitIds: ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [],
|
|
15964
16192
|
preRequirements: technology.requirements.pre,
|
|
15965
16193
|
postRequirements: technology.requirements.post,
|
|
15966
16194
|
certificationRequirement: technology.certificationRequirement,
|
|
@@ -15996,11 +16224,11 @@ var ProcedureService = class extends BaseService {
|
|
|
15996
16224
|
async getProceduresForMap() {
|
|
15997
16225
|
const proceduresRef = collection29(this.db, PROCEDURES_COLLECTION);
|
|
15998
16226
|
const snapshot = await getDocs29(proceduresRef);
|
|
15999
|
-
const proceduresForMap = snapshot.docs.map((
|
|
16227
|
+
const proceduresForMap = snapshot.docs.map((doc38) => {
|
|
16000
16228
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
16001
|
-
const data =
|
|
16229
|
+
const data = doc38.data();
|
|
16002
16230
|
return {
|
|
16003
|
-
id:
|
|
16231
|
+
id: doc38.id,
|
|
16004
16232
|
name: data.name,
|
|
16005
16233
|
clinicId: (_a = data.clinicInfo) == null ? void 0 : _a.id,
|
|
16006
16234
|
clinicName: (_b = data.clinicInfo) == null ? void 0 : _b.name,
|
|
@@ -16142,7 +16370,7 @@ var ReviewService = class extends BaseService {
|
|
|
16142
16370
|
where30("patientId", "==", patientId)
|
|
16143
16371
|
);
|
|
16144
16372
|
const snapshot = await getDocs30(q);
|
|
16145
|
-
return snapshot.docs.map((
|
|
16373
|
+
return snapshot.docs.map((doc38) => doc38.data());
|
|
16146
16374
|
}
|
|
16147
16375
|
/**
|
|
16148
16376
|
* Gets all reviews for a specific clinic
|
|
@@ -16155,7 +16383,7 @@ var ReviewService = class extends BaseService {
|
|
|
16155
16383
|
where30("clinicReview.clinicId", "==", clinicId)
|
|
16156
16384
|
);
|
|
16157
16385
|
const snapshot = await getDocs30(q);
|
|
16158
|
-
return snapshot.docs.map((
|
|
16386
|
+
return snapshot.docs.map((doc38) => doc38.data());
|
|
16159
16387
|
}
|
|
16160
16388
|
/**
|
|
16161
16389
|
* Gets all reviews for a specific practitioner
|
|
@@ -16168,7 +16396,7 @@ var ReviewService = class extends BaseService {
|
|
|
16168
16396
|
where30("practitionerReview.practitionerId", "==", practitionerId)
|
|
16169
16397
|
);
|
|
16170
16398
|
const snapshot = await getDocs30(q);
|
|
16171
|
-
return snapshot.docs.map((
|
|
16399
|
+
return snapshot.docs.map((doc38) => doc38.data());
|
|
16172
16400
|
}
|
|
16173
16401
|
/**
|
|
16174
16402
|
* Gets all reviews for a specific procedure
|
|
@@ -16181,7 +16409,7 @@ var ReviewService = class extends BaseService {
|
|
|
16181
16409
|
where30("procedureReview.procedureId", "==", procedureId)
|
|
16182
16410
|
);
|
|
16183
16411
|
const snapshot = await getDocs30(q);
|
|
16184
|
-
return snapshot.docs.map((
|
|
16412
|
+
return snapshot.docs.map((doc38) => doc38.data());
|
|
16185
16413
|
}
|
|
16186
16414
|
/**
|
|
16187
16415
|
* Gets all reviews for a specific appointment
|
|
@@ -16287,7 +16515,11 @@ import {
|
|
|
16287
16515
|
getDocs as getDocs31,
|
|
16288
16516
|
query as query31,
|
|
16289
16517
|
updateDoc as updateDoc30,
|
|
16290
|
-
where as where31
|
|
16518
|
+
where as where31,
|
|
16519
|
+
limit as limit16,
|
|
16520
|
+
orderBy as orderBy18,
|
|
16521
|
+
startAfter as startAfter14,
|
|
16522
|
+
getCountFromServer as getCountFromServer2
|
|
16291
16523
|
} from "firebase/firestore";
|
|
16292
16524
|
|
|
16293
16525
|
// src/backoffice/types/brand.types.ts
|
|
@@ -16308,6 +16540,7 @@ var BrandService = class extends BaseService {
|
|
|
16308
16540
|
const now = /* @__PURE__ */ new Date();
|
|
16309
16541
|
const newBrand = {
|
|
16310
16542
|
...brand,
|
|
16543
|
+
name_lowercase: brand.name.toLowerCase(),
|
|
16311
16544
|
createdAt: now,
|
|
16312
16545
|
updatedAt: now,
|
|
16313
16546
|
isActive: true
|
|
@@ -16316,15 +16549,69 @@ var BrandService = class extends BaseService {
|
|
|
16316
16549
|
return { id: docRef.id, ...newBrand };
|
|
16317
16550
|
}
|
|
16318
16551
|
/**
|
|
16319
|
-
* 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).
|
|
16320
16603
|
*/
|
|
16321
|
-
async
|
|
16322
|
-
const q = query31(
|
|
16604
|
+
async getAllForFilter() {
|
|
16605
|
+
const q = query31(
|
|
16606
|
+
this.getBrandsRef(),
|
|
16607
|
+
where31("isActive", "==", true),
|
|
16608
|
+
orderBy18("name")
|
|
16609
|
+
);
|
|
16323
16610
|
const snapshot = await getDocs31(q);
|
|
16324
16611
|
return snapshot.docs.map(
|
|
16325
|
-
(
|
|
16326
|
-
id:
|
|
16327
|
-
...
|
|
16612
|
+
(doc38) => ({
|
|
16613
|
+
id: doc38.id,
|
|
16614
|
+
...doc38.data()
|
|
16328
16615
|
})
|
|
16329
16616
|
);
|
|
16330
16617
|
}
|
|
@@ -16336,6 +16623,9 @@ var BrandService = class extends BaseService {
|
|
|
16336
16623
|
...brand,
|
|
16337
16624
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16338
16625
|
};
|
|
16626
|
+
if (brand.name) {
|
|
16627
|
+
updateData.name_lowercase = brand.name.toLowerCase();
|
|
16628
|
+
}
|
|
16339
16629
|
const docRef = doc32(this.getBrandsRef(), brandId);
|
|
16340
16630
|
await updateDoc30(docRef, updateData);
|
|
16341
16631
|
return this.getById(brandId);
|
|
@@ -16367,9 +16657,13 @@ import {
|
|
|
16367
16657
|
addDoc as addDoc4,
|
|
16368
16658
|
collection as collection32,
|
|
16369
16659
|
doc as doc33,
|
|
16660
|
+
getCountFromServer as getCountFromServer3,
|
|
16370
16661
|
getDoc as getDoc35,
|
|
16371
16662
|
getDocs as getDocs32,
|
|
16663
|
+
limit as limit17,
|
|
16664
|
+
orderBy as orderBy19,
|
|
16372
16665
|
query as query32,
|
|
16666
|
+
startAfter as startAfter15,
|
|
16373
16667
|
updateDoc as updateDoc31,
|
|
16374
16668
|
where as where32
|
|
16375
16669
|
} from "firebase/firestore";
|
|
@@ -16402,37 +16696,87 @@ var CategoryService = class extends BaseService {
|
|
|
16402
16696
|
return { id: docRef.id, ...newCategory };
|
|
16403
16697
|
}
|
|
16404
16698
|
/**
|
|
16405
|
-
*
|
|
16406
|
-
* @
|
|
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
|
|
16407
16720
|
*/
|
|
16408
|
-
async
|
|
16721
|
+
async getAllForFilter() {
|
|
16409
16722
|
const q = query32(this.categoriesRef, where32("isActive", "==", true));
|
|
16410
16723
|
const snapshot = await getDocs32(q);
|
|
16411
16724
|
return snapshot.docs.map(
|
|
16412
|
-
(
|
|
16413
|
-
id:
|
|
16414
|
-
...
|
|
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()
|
|
16415
16750
|
})
|
|
16416
16751
|
);
|
|
16752
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
16753
|
+
return { categories, lastVisible: newLastVisible };
|
|
16417
16754
|
}
|
|
16418
16755
|
/**
|
|
16419
|
-
* Vraća sve aktivne kategorije za određenu familiju procedura
|
|
16756
|
+
* Vraća sve aktivne kategorije za određenu familiju procedura sa paginacijom
|
|
16420
16757
|
* @param family - Familija procedura (aesthetics/surgery)
|
|
16758
|
+
* @param options - Pagination options
|
|
16421
16759
|
* @returns Lista kategorija koje pripadaju traženoj familiji
|
|
16422
16760
|
*/
|
|
16423
|
-
async getAllByFamily(family) {
|
|
16424
|
-
const
|
|
16425
|
-
|
|
16761
|
+
async getAllByFamily(family, options = {}) {
|
|
16762
|
+
const { active = true, limit: queryLimit = 10, lastVisible } = options;
|
|
16763
|
+
const constraints = [
|
|
16426
16764
|
where32("family", "==", family),
|
|
16427
|
-
where32("isActive", "==",
|
|
16428
|
-
|
|
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);
|
|
16429
16771
|
const snapshot = await getDocs32(q);
|
|
16430
|
-
|
|
16431
|
-
(
|
|
16432
|
-
id:
|
|
16433
|
-
...
|
|
16772
|
+
const categories = snapshot.docs.map(
|
|
16773
|
+
(doc38) => ({
|
|
16774
|
+
id: doc38.id,
|
|
16775
|
+
...doc38.data()
|
|
16434
16776
|
})
|
|
16435
16777
|
);
|
|
16778
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
16779
|
+
return { categories, lastVisible: newLastVisible };
|
|
16436
16780
|
}
|
|
16437
16781
|
/**
|
|
16438
16782
|
* Ažurira postojeću kategoriju
|
|
@@ -16456,6 +16800,13 @@ var CategoryService = class extends BaseService {
|
|
|
16456
16800
|
async delete(id) {
|
|
16457
16801
|
await this.update(id, { isActive: false });
|
|
16458
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
|
+
}
|
|
16459
16810
|
/**
|
|
16460
16811
|
* Vraća kategoriju po ID-u
|
|
16461
16812
|
* @param id - ID tražene kategorije
|
|
@@ -16476,10 +16827,17 @@ var CategoryService = class extends BaseService {
|
|
|
16476
16827
|
import {
|
|
16477
16828
|
addDoc as addDoc5,
|
|
16478
16829
|
collection as collection33,
|
|
16830
|
+
collectionGroup as collectionGroup2,
|
|
16831
|
+
deleteDoc as deleteDoc20,
|
|
16479
16832
|
doc as doc34,
|
|
16833
|
+
getCountFromServer as getCountFromServer4,
|
|
16480
16834
|
getDoc as getDoc36,
|
|
16481
16835
|
getDocs as getDocs33,
|
|
16836
|
+
limit as limit18,
|
|
16837
|
+
orderBy as orderBy20,
|
|
16482
16838
|
query as query33,
|
|
16839
|
+
setDoc as setDoc28,
|
|
16840
|
+
startAfter as startAfter16,
|
|
16483
16841
|
updateDoc as updateDoc32,
|
|
16484
16842
|
where as where33
|
|
16485
16843
|
} from "firebase/firestore";
|
|
@@ -16523,20 +16881,110 @@ var SubcategoryService = class extends BaseService {
|
|
|
16523
16881
|
return { id: docRef.id, ...newSubcategory };
|
|
16524
16882
|
}
|
|
16525
16883
|
/**
|
|
16526
|
-
*
|
|
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
|
|
16527
16903
|
* @param categoryId - ID kategorije čije podkategorije tražimo
|
|
16528
|
-
* @
|
|
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
|
|
16529
16933
|
*/
|
|
16530
|
-
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) {
|
|
16531
16962
|
const q = query33(
|
|
16532
16963
|
this.getSubcategoriesRef(categoryId),
|
|
16533
16964
|
where33("isActive", "==", true)
|
|
16534
16965
|
);
|
|
16535
|
-
const
|
|
16536
|
-
return
|
|
16537
|
-
(
|
|
16538
|
-
id:
|
|
16539
|
-
...
|
|
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()
|
|
16540
16988
|
})
|
|
16541
16989
|
);
|
|
16542
16990
|
}
|
|
@@ -16548,13 +16996,42 @@ var SubcategoryService = class extends BaseService {
|
|
|
16548
16996
|
* @returns Ažurirana podkategorija
|
|
16549
16997
|
*/
|
|
16550
16998
|
async update(categoryId, subcategoryId, subcategory) {
|
|
16551
|
-
const
|
|
16552
|
-
|
|
16553
|
-
|
|
16554
|
-
|
|
16555
|
-
|
|
16556
|
-
|
|
16557
|
-
|
|
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
|
+
}
|
|
16558
17035
|
}
|
|
16559
17036
|
/**
|
|
16560
17037
|
* Soft delete podkategorije (postavlja isActive na false)
|
|
@@ -16564,6 +17041,14 @@ var SubcategoryService = class extends BaseService {
|
|
|
16564
17041
|
async delete(categoryId, subcategoryId) {
|
|
16565
17042
|
await this.update(categoryId, subcategoryId, { isActive: false });
|
|
16566
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
|
+
}
|
|
16567
17052
|
/**
|
|
16568
17053
|
* Vraća podkategoriju po ID-u
|
|
16569
17054
|
* @param categoryId - ID kategorije kojoj pripada podkategorija
|
|
@@ -16588,7 +17073,10 @@ import {
|
|
|
16588
17073
|
doc as doc35,
|
|
16589
17074
|
getDoc as getDoc37,
|
|
16590
17075
|
getDocs as getDocs34,
|
|
17076
|
+
limit as limit19,
|
|
17077
|
+
orderBy as orderBy21,
|
|
16591
17078
|
query as query34,
|
|
17079
|
+
startAfter as startAfter17,
|
|
16592
17080
|
updateDoc as updateDoc33,
|
|
16593
17081
|
where as where34,
|
|
16594
17082
|
arrayUnion as arrayUnion9,
|
|
@@ -16600,137 +17088,185 @@ var DEFAULT_CERTIFICATION_REQUIREMENT = {
|
|
|
16600
17088
|
};
|
|
16601
17089
|
var TechnologyService = class extends BaseService {
|
|
16602
17090
|
/**
|
|
16603
|
-
*
|
|
17091
|
+
* Reference to the Firestore collection of technologies.
|
|
16604
17092
|
*/
|
|
16605
|
-
|
|
17093
|
+
get technologiesRef() {
|
|
16606
17094
|
return collection34(this.db, TECHNOLOGIES_COLLECTION);
|
|
16607
17095
|
}
|
|
16608
17096
|
/**
|
|
16609
|
-
*
|
|
16610
|
-
* @param technology -
|
|
16611
|
-
* @returns
|
|
17097
|
+
* Creates a new technology.
|
|
17098
|
+
* @param technology - Data for the new technology.
|
|
17099
|
+
* @returns The created technology with its generated ID.
|
|
16612
17100
|
*/
|
|
16613
17101
|
async create(technology) {
|
|
16614
17102
|
const now = /* @__PURE__ */ new Date();
|
|
16615
17103
|
const newTechnology = {
|
|
16616
|
-
|
|
16617
|
-
|
|
16618
|
-
|
|
16619
|
-
|
|
16620
|
-
|
|
16621
|
-
|
|
16622
|
-
post: []
|
|
16623
|
-
},
|
|
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: [] },
|
|
16624
17110
|
blockingConditions: technology.blockingConditions || [],
|
|
16625
17111
|
contraindications: technology.contraindications || [],
|
|
16626
17112
|
benefits: technology.benefits || [],
|
|
16627
|
-
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
|
|
16628
17118
|
};
|
|
16629
|
-
|
|
17119
|
+
if (technology.technicalDetails) {
|
|
17120
|
+
newTechnology.technicalDetails = technology.technicalDetails;
|
|
17121
|
+
}
|
|
17122
|
+
const docRef = await addDoc6(this.technologiesRef, newTechnology);
|
|
16630
17123
|
return { id: docRef.id, ...newTechnology };
|
|
16631
17124
|
}
|
|
16632
17125
|
/**
|
|
16633
|
-
*
|
|
16634
|
-
* @
|
|
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.
|
|
16635
17129
|
*/
|
|
16636
|
-
async
|
|
16637
|
-
const q = query34(this.
|
|
17130
|
+
async getTechnologyCounts(active = true) {
|
|
17131
|
+
const q = query34(this.technologiesRef, where34("isActive", "==", active));
|
|
16638
17132
|
const snapshot = await getDocs34(q);
|
|
16639
|
-
|
|
16640
|
-
|
|
16641
|
-
|
|
16642
|
-
|
|
16643
|
-
|
|
16644
|
-
|
|
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;
|
|
16645
17139
|
}
|
|
16646
17140
|
/**
|
|
16647
|
-
*
|
|
16648
|
-
* @param
|
|
16649
|
-
* @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.
|
|
16650
17144
|
*/
|
|
16651
|
-
async
|
|
16652
|
-
const q = query34(
|
|
16653
|
-
this.getTechnologiesRef(),
|
|
16654
|
-
where34("isActive", "==", true),
|
|
16655
|
-
where34("family", "==", family)
|
|
16656
|
-
);
|
|
17145
|
+
async getTechnologyCountsByCategory(active = true) {
|
|
17146
|
+
const q = query34(this.technologiesRef, where34("isActive", "==", active));
|
|
16657
17147
|
const snapshot = await getDocs34(q);
|
|
16658
|
-
|
|
16659
|
-
|
|
16660
|
-
|
|
16661
|
-
|
|
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()
|
|
16662
17174
|
})
|
|
16663
17175
|
);
|
|
17176
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
17177
|
+
return { technologies, lastVisible: newLastVisible };
|
|
16664
17178
|
}
|
|
16665
17179
|
/**
|
|
16666
|
-
*
|
|
16667
|
-
* @param categoryId - ID
|
|
16668
|
-
* @
|
|
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.
|
|
16669
17184
|
*/
|
|
16670
|
-
async getAllByCategoryId(categoryId) {
|
|
16671
|
-
const
|
|
16672
|
-
|
|
16673
|
-
where34("
|
|
16674
|
-
where34("
|
|
16675
|
-
|
|
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);
|
|
16676
17195
|
const snapshot = await getDocs34(q);
|
|
16677
|
-
|
|
16678
|
-
(
|
|
16679
|
-
id:
|
|
16680
|
-
...
|
|
17196
|
+
const technologies = snapshot.docs.map(
|
|
17197
|
+
(doc38) => ({
|
|
17198
|
+
id: doc38.id,
|
|
17199
|
+
...doc38.data()
|
|
16681
17200
|
})
|
|
16682
17201
|
);
|
|
17202
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
17203
|
+
return { technologies, lastVisible: newLastVisible };
|
|
16683
17204
|
}
|
|
16684
17205
|
/**
|
|
16685
|
-
*
|
|
16686
|
-
* @param subcategoryId - ID
|
|
16687
|
-
* @
|
|
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.
|
|
16688
17210
|
*/
|
|
16689
|
-
async getAllBySubcategoryId(subcategoryId) {
|
|
16690
|
-
const
|
|
16691
|
-
|
|
16692
|
-
where34("
|
|
16693
|
-
where34("
|
|
16694
|
-
|
|
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);
|
|
16695
17221
|
const snapshot = await getDocs34(q);
|
|
16696
|
-
|
|
16697
|
-
(
|
|
16698
|
-
id:
|
|
16699
|
-
...
|
|
17222
|
+
const technologies = snapshot.docs.map(
|
|
17223
|
+
(doc38) => ({
|
|
17224
|
+
id: doc38.id,
|
|
17225
|
+
...doc38.data()
|
|
16700
17226
|
})
|
|
16701
17227
|
);
|
|
17228
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
17229
|
+
return { technologies, lastVisible: newLastVisible };
|
|
16702
17230
|
}
|
|
16703
17231
|
/**
|
|
16704
|
-
*
|
|
16705
|
-
* @param
|
|
16706
|
-
* @param technology -
|
|
16707
|
-
* @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.
|
|
16708
17236
|
*/
|
|
16709
|
-
async update(
|
|
16710
|
-
const updateData = {
|
|
16711
|
-
|
|
16712
|
-
|
|
16713
|
-
|
|
16714
|
-
|
|
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);
|
|
16715
17246
|
await updateDoc33(docRef, updateData);
|
|
16716
|
-
return this.getById(
|
|
17247
|
+
return this.getById(id);
|
|
16717
17248
|
}
|
|
16718
17249
|
/**
|
|
16719
|
-
* Soft
|
|
16720
|
-
* @param
|
|
17250
|
+
* Soft deletes a technology.
|
|
17251
|
+
* @param id - The ID of the technology to delete.
|
|
16721
17252
|
*/
|
|
16722
|
-
async delete(
|
|
16723
|
-
await this.update(
|
|
16724
|
-
isActive: false
|
|
16725
|
-
});
|
|
17253
|
+
async delete(id) {
|
|
17254
|
+
await this.update(id, { isActive: false });
|
|
16726
17255
|
}
|
|
16727
17256
|
/**
|
|
16728
|
-
*
|
|
16729
|
-
* @param
|
|
16730
|
-
* @returns Tehnologija ili null ako ne postoji
|
|
17257
|
+
* Reactivates a technology.
|
|
17258
|
+
* @param id - The ID of the technology to reactivate.
|
|
16731
17259
|
*/
|
|
16732
|
-
async
|
|
16733
|
-
|
|
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);
|
|
16734
17270
|
const docSnap = await getDoc37(docRef);
|
|
16735
17271
|
if (!docSnap.exists()) return null;
|
|
16736
17272
|
return {
|
|
@@ -16745,7 +17281,7 @@ var TechnologyService = class extends BaseService {
|
|
|
16745
17281
|
* @returns Ažurirana tehnologija sa novim zahtevom
|
|
16746
17282
|
*/
|
|
16747
17283
|
async addRequirement(technologyId, requirement) {
|
|
16748
|
-
const docRef = doc35(this.
|
|
17284
|
+
const docRef = doc35(this.technologiesRef, technologyId);
|
|
16749
17285
|
const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
|
|
16750
17286
|
await updateDoc33(docRef, {
|
|
16751
17287
|
[requirementType]: arrayUnion9(requirement),
|
|
@@ -16760,7 +17296,7 @@ var TechnologyService = class extends BaseService {
|
|
|
16760
17296
|
* @returns Ažurirana tehnologija bez uklonjenog zahteva
|
|
16761
17297
|
*/
|
|
16762
17298
|
async removeRequirement(technologyId, requirement) {
|
|
16763
|
-
const docRef = doc35(this.
|
|
17299
|
+
const docRef = doc35(this.technologiesRef, technologyId);
|
|
16764
17300
|
const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
|
|
16765
17301
|
await updateDoc33(docRef, {
|
|
16766
17302
|
[requirementType]: arrayRemove8(requirement),
|
|
@@ -16800,7 +17336,7 @@ var TechnologyService = class extends BaseService {
|
|
|
16800
17336
|
* @returns Ažurirana tehnologija
|
|
16801
17337
|
*/
|
|
16802
17338
|
async addBlockingCondition(technologyId, condition) {
|
|
16803
|
-
const docRef = doc35(this.
|
|
17339
|
+
const docRef = doc35(this.technologiesRef, technologyId);
|
|
16804
17340
|
await updateDoc33(docRef, {
|
|
16805
17341
|
blockingConditions: arrayUnion9(condition),
|
|
16806
17342
|
updatedAt: /* @__PURE__ */ new Date()
|
|
@@ -16814,7 +17350,7 @@ var TechnologyService = class extends BaseService {
|
|
|
16814
17350
|
* @returns Ažurirana tehnologija
|
|
16815
17351
|
*/
|
|
16816
17352
|
async removeBlockingCondition(technologyId, condition) {
|
|
16817
|
-
const docRef = doc35(this.
|
|
17353
|
+
const docRef = doc35(this.technologiesRef, technologyId);
|
|
16818
17354
|
await updateDoc33(docRef, {
|
|
16819
17355
|
blockingConditions: arrayRemove8(condition),
|
|
16820
17356
|
updatedAt: /* @__PURE__ */ new Date()
|
|
@@ -16828,9 +17364,17 @@ var TechnologyService = class extends BaseService {
|
|
|
16828
17364
|
* @returns Ažurirana tehnologija
|
|
16829
17365
|
*/
|
|
16830
17366
|
async addContraindication(technologyId, contraindication) {
|
|
16831
|
-
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
|
+
}
|
|
16832
17376
|
await updateDoc33(docRef, {
|
|
16833
|
-
contraindications:
|
|
17377
|
+
contraindications: [...existingContraindications, contraindication],
|
|
16834
17378
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16835
17379
|
});
|
|
16836
17380
|
return this.getById(technologyId);
|
|
@@ -16842,9 +17386,45 @@ var TechnologyService = class extends BaseService {
|
|
|
16842
17386
|
* @returns Ažurirana tehnologija
|
|
16843
17387
|
*/
|
|
16844
17388
|
async removeContraindication(technologyId, contraindication) {
|
|
16845
|
-
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;
|
|
16846
17426
|
await updateDoc33(docRef, {
|
|
16847
|
-
contraindications:
|
|
17427
|
+
contraindications: updatedContraindications,
|
|
16848
17428
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16849
17429
|
});
|
|
16850
17430
|
return this.getById(technologyId);
|
|
@@ -16856,9 +17436,17 @@ var TechnologyService = class extends BaseService {
|
|
|
16856
17436
|
* @returns Ažurirana tehnologija
|
|
16857
17437
|
*/
|
|
16858
17438
|
async addBenefit(technologyId, benefit) {
|
|
16859
|
-
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
|
+
}
|
|
16860
17448
|
await updateDoc33(docRef, {
|
|
16861
|
-
benefits:
|
|
17449
|
+
benefits: [...existingBenefits, benefit],
|
|
16862
17450
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16863
17451
|
});
|
|
16864
17452
|
return this.getById(technologyId);
|
|
@@ -16870,9 +17458,45 @@ var TechnologyService = class extends BaseService {
|
|
|
16870
17458
|
* @returns Ažurirana tehnologija
|
|
16871
17459
|
*/
|
|
16872
17460
|
async removeBenefit(technologyId, benefit) {
|
|
16873
|
-
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;
|
|
16874
17498
|
await updateDoc33(docRef, {
|
|
16875
|
-
benefits:
|
|
17499
|
+
benefits: updatedBenefits,
|
|
16876
17500
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16877
17501
|
});
|
|
16878
17502
|
return this.getById(technologyId);
|
|
@@ -16911,7 +17535,7 @@ var TechnologyService = class extends BaseService {
|
|
|
16911
17535
|
* @returns Ažurirana tehnologija
|
|
16912
17536
|
*/
|
|
16913
17537
|
async updateCertificationRequirement(technologyId, certificationRequirement) {
|
|
16914
|
-
const docRef = doc35(this.
|
|
17538
|
+
const docRef = doc35(this.technologiesRef, technologyId);
|
|
16915
17539
|
await updateDoc33(docRef, {
|
|
16916
17540
|
certificationRequirement,
|
|
16917
17541
|
updatedAt: /* @__PURE__ */ new Date()
|
|
@@ -16989,7 +17613,7 @@ var TechnologyService = class extends BaseService {
|
|
|
16989
17613
|
*/
|
|
16990
17614
|
async getAllowedTechnologies(practitioner) {
|
|
16991
17615
|
const allTechnologies = await this.getAll();
|
|
16992
|
-
const allowedTechnologies = allTechnologies.filter(
|
|
17616
|
+
const allowedTechnologies = allTechnologies.technologies.filter(
|
|
16993
17617
|
(technology) => this.validateCertification(
|
|
16994
17618
|
technology.certificationRequirement,
|
|
16995
17619
|
practitioner.certification
|
|
@@ -17009,18 +17633,61 @@ var TechnologyService = class extends BaseService {
|
|
|
17009
17633
|
subcategories
|
|
17010
17634
|
};
|
|
17011
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
|
+
}
|
|
17012
17674
|
};
|
|
17013
17675
|
|
|
17014
17676
|
// src/backoffice/services/product.service.ts
|
|
17015
17677
|
import {
|
|
17016
17678
|
addDoc as addDoc7,
|
|
17017
17679
|
collection as collection35,
|
|
17680
|
+
collectionGroup as collectionGroup3,
|
|
17018
17681
|
doc as doc36,
|
|
17019
17682
|
getDoc as getDoc38,
|
|
17020
17683
|
getDocs as getDocs35,
|
|
17021
17684
|
query as query35,
|
|
17022
17685
|
updateDoc as updateDoc34,
|
|
17023
|
-
where as where35
|
|
17686
|
+
where as where35,
|
|
17687
|
+
limit as limit20,
|
|
17688
|
+
orderBy as orderBy22,
|
|
17689
|
+
startAfter as startAfter18,
|
|
17690
|
+
getCountFromServer as getCountFromServer6
|
|
17024
17691
|
} from "firebase/firestore";
|
|
17025
17692
|
|
|
17026
17693
|
// src/backoffice/types/product.types.ts
|
|
@@ -17061,20 +17728,102 @@ var ProductService = class extends BaseService {
|
|
|
17061
17728
|
return { id: productRef.id, ...newProduct };
|
|
17062
17729
|
}
|
|
17063
17730
|
/**
|
|
17064
|
-
* 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.
|
|
17065
17733
|
*/
|
|
17066
|
-
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));
|
|
17067
17759
|
const q = query35(
|
|
17068
|
-
this.
|
|
17069
|
-
|
|
17760
|
+
collectionGroup3(this.db, PRODUCTS_COLLECTION),
|
|
17761
|
+
...constraints
|
|
17070
17762
|
);
|
|
17071
17763
|
const snapshot = await getDocs35(q);
|
|
17072
|
-
|
|
17073
|
-
(
|
|
17074
|
-
id:
|
|
17075
|
-
...
|
|
17764
|
+
const products = snapshot.docs.map(
|
|
17765
|
+
(doc38) => ({
|
|
17766
|
+
id: doc38.id,
|
|
17767
|
+
...doc38.data()
|
|
17076
17768
|
})
|
|
17077
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;
|
|
17078
17827
|
}
|
|
17079
17828
|
/**
|
|
17080
17829
|
* Gets all products for a brand by filtering through all technologies
|
|
@@ -17092,9 +17841,9 @@ var ProductService = class extends BaseService {
|
|
|
17092
17841
|
const snapshot = await getDocs35(q);
|
|
17093
17842
|
products.push(
|
|
17094
17843
|
...snapshot.docs.map(
|
|
17095
|
-
(
|
|
17096
|
-
id:
|
|
17097
|
-
...
|
|
17844
|
+
(doc38) => ({
|
|
17845
|
+
id: doc38.id,
|
|
17846
|
+
...doc38.data()
|
|
17098
17847
|
})
|
|
17099
17848
|
)
|
|
17100
17849
|
);
|
|
@@ -17135,6 +17884,262 @@ var ProductService = class extends BaseService {
|
|
|
17135
17884
|
}
|
|
17136
17885
|
};
|
|
17137
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
|
+
|
|
17138
18143
|
// src/backoffice/types/static/treatment-benefit.types.ts
|
|
17139
18144
|
var TreatmentBenefit = /* @__PURE__ */ ((TreatmentBenefit2) => {
|
|
17140
18145
|
TreatmentBenefit2["WRINKLE_REDUCTION"] = "wrinkle_reduction";
|
|
@@ -17193,6 +18198,7 @@ export {
|
|
|
17193
18198
|
ClinicPhotoTag,
|
|
17194
18199
|
ClinicService,
|
|
17195
18200
|
ClinicTag,
|
|
18201
|
+
ConstantsService,
|
|
17196
18202
|
Contraindication,
|
|
17197
18203
|
CosmeticAllergySubtype,
|
|
17198
18204
|
Currency,
|