@blackcode_sa/metaestetics-api 1.8.18 → 1.11.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 +9 -0
- package/dist/admin/index.d.ts +9 -0
- package/dist/admin/index.js +98 -79
- package/dist/admin/index.mjs +98 -79
- package/dist/backoffice/index.d.mts +1 -0
- package/dist/backoffice/index.d.ts +1 -0
- package/dist/index.d.mts +17 -2
- package/dist/index.d.ts +17 -2
- package/dist/index.js +239 -159
- package/dist/index.mjs +241 -161
- package/package.json +3 -1
- package/src/admin/booking/booking.admin.ts +2 -0
- package/src/admin/booking/booking.calculator.ts +121 -117
- package/src/admin/booking/booking.types.ts +3 -0
- package/src/services/clinic/clinic.service.ts +40 -10
- package/src/services/clinic/utils/filter.utils.ts +180 -96
- package/src/services/procedure/procedure.service.ts +329 -364
- package/src/types/appointment/index.ts +4 -0
- package/src/types/clinic/index.ts +2 -0
- package/src/validations/appointment.schema.ts +2 -0
- package/src/validations/clinic.schema.ts +2 -0
- package/src/validations/procedure.schema.ts +8 -10
package/dist/index.js
CHANGED
|
@@ -583,7 +583,8 @@ var createAppointmentSchema = import_zod3.z.object({
|
|
|
583
583
|
currency: import_zod3.z.string().min(1, "Currency is required"),
|
|
584
584
|
patientNotes: import_zod3.z.string().max(MAX_STRING_LENGTH, "Patient notes too long").nullable().optional(),
|
|
585
585
|
initialStatus: appointmentStatusSchema,
|
|
586
|
-
initialPaymentStatus: paymentStatusSchema.optional().default("unpaid" /* UNPAID */)
|
|
586
|
+
initialPaymentStatus: paymentStatusSchema.optional().default("unpaid" /* UNPAID */),
|
|
587
|
+
clinic_tz: import_zod3.z.string().min(1, "Timezone is required")
|
|
587
588
|
}).refine((data) => data.appointmentEndTime > data.appointmentStartTime, {
|
|
588
589
|
message: "Appointment end time must be after start time",
|
|
589
590
|
path: ["appointmentEndTime"]
|
|
@@ -617,6 +618,7 @@ var updateAppointmentSchema = import_zod3.z.object({
|
|
|
617
618
|
cost: import_zod3.z.number().min(0).optional(),
|
|
618
619
|
clinicBranchId: import_zod3.z.string().min(MIN_STRING_LENGTH).optional(),
|
|
619
620
|
practitionerId: import_zod3.z.string().min(MIN_STRING_LENGTH).optional(),
|
|
621
|
+
clinic_tz: import_zod3.z.string().min(MIN_STRING_LENGTH).optional(),
|
|
620
622
|
linkedForms: import_zod3.z.union([import_zod3.z.array(linkedFormInfoSchema).max(MAX_ARRAY_LENGTH), import_zod3.z.any()]).optional(),
|
|
621
623
|
media: import_zod3.z.union([
|
|
622
624
|
import_zod3.z.array(appointmentMediaItemSchema).max(MAX_ARRAY_LENGTH),
|
|
@@ -3453,7 +3455,8 @@ var clinicLocationSchema = import_zod10.z.object({
|
|
|
3453
3455
|
postalCode: import_zod10.z.string(),
|
|
3454
3456
|
latitude: import_zod10.z.number().min(-90).max(90),
|
|
3455
3457
|
longitude: import_zod10.z.number().min(-180).max(180),
|
|
3456
|
-
geohash: import_zod10.z.string().nullable().optional()
|
|
3458
|
+
geohash: import_zod10.z.string().nullable().optional(),
|
|
3459
|
+
tz: import_zod10.z.string().nullable().optional()
|
|
3457
3460
|
});
|
|
3458
3461
|
var workingHoursTimeSchema = import_zod10.z.object({
|
|
3459
3462
|
open: import_zod10.z.string(),
|
|
@@ -3607,6 +3610,7 @@ var createClinicGroupSchema = import_zod10.z.object({
|
|
|
3607
3610
|
calendarSyncEnabled: import_zod10.z.boolean().optional(),
|
|
3608
3611
|
autoConfirmAppointments: import_zod10.z.boolean().optional(),
|
|
3609
3612
|
businessIdentificationNumber: import_zod10.z.string().optional().nullable(),
|
|
3613
|
+
tz: import_zod10.z.string().nullable().optional(),
|
|
3610
3614
|
onboarding: import_zod10.z.object({
|
|
3611
3615
|
completed: import_zod10.z.boolean().optional().default(false),
|
|
3612
3616
|
step: import_zod10.z.number().optional().default(1)
|
|
@@ -8271,6 +8275,7 @@ var ClinicGroupService = class extends BaseService {
|
|
|
8271
8275
|
|
|
8272
8276
|
// src/services/clinic/clinic.service.ts
|
|
8273
8277
|
var import_firestore27 = require("firebase/firestore");
|
|
8278
|
+
var import_functions2 = require("firebase/functions");
|
|
8274
8279
|
var import_geofire_common7 = require("geofire-common");
|
|
8275
8280
|
var import_zod20 = require("zod");
|
|
8276
8281
|
|
|
@@ -8710,6 +8715,7 @@ async function findClinicsInRadius(db, center, radiusInKm, filters) {
|
|
|
8710
8715
|
var import_firestore26 = require("firebase/firestore");
|
|
8711
8716
|
var import_geofire_common6 = require("geofire-common");
|
|
8712
8717
|
async function getClinicsByFilters(db, filters) {
|
|
8718
|
+
var _a;
|
|
8713
8719
|
try {
|
|
8714
8720
|
console.log("[CLINIC_SERVICE] Starting clinic filtering with multiple strategies");
|
|
8715
8721
|
if (filters.center && filters.radiusInKm) {
|
|
@@ -8724,10 +8730,53 @@ async function getClinicsByFilters(db, filters) {
|
|
|
8724
8730
|
filters.radiusInKm = void 0;
|
|
8725
8731
|
}
|
|
8726
8732
|
}
|
|
8733
|
+
if (filters.center && filters.radiusInKm) {
|
|
8734
|
+
try {
|
|
8735
|
+
console.log("[CLINIC_SERVICE] Strategy 0: Geohash bounds prefilter");
|
|
8736
|
+
const bounds = (0, import_geofire_common6.geohashQueryBounds)(
|
|
8737
|
+
[filters.center.latitude, filters.center.longitude],
|
|
8738
|
+
(filters.radiusInKm || 0) * 1e3
|
|
8739
|
+
);
|
|
8740
|
+
const collected = [];
|
|
8741
|
+
for (const b of bounds) {
|
|
8742
|
+
const constraints = [
|
|
8743
|
+
(0, import_firestore26.where)("location.geohash", ">=", b[0]),
|
|
8744
|
+
(0, import_firestore26.where)("location.geohash", "<=", b[1]),
|
|
8745
|
+
(0, import_firestore26.where)("isActive", "==", (_a = filters.isActive) != null ? _a : true)
|
|
8746
|
+
];
|
|
8747
|
+
if (filters.tags && filters.tags.length > 0) {
|
|
8748
|
+
constraints.push((0, import_firestore26.where)("tags", "array-contains", filters.tags[0]));
|
|
8749
|
+
}
|
|
8750
|
+
const q0 = (0, import_firestore26.query)((0, import_firestore26.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
8751
|
+
const snap = await (0, import_firestore26.getDocs)(q0);
|
|
8752
|
+
snap.docs.forEach((d) => collected.push({ ...d.data(), id: d.id }));
|
|
8753
|
+
}
|
|
8754
|
+
const uniqueMap = /* @__PURE__ */ new Map();
|
|
8755
|
+
for (const c of collected) {
|
|
8756
|
+
uniqueMap.set(c.id, c);
|
|
8757
|
+
}
|
|
8758
|
+
let clinics = Array.from(uniqueMap.values());
|
|
8759
|
+
clinics = applyInMemoryFilters(clinics, filters);
|
|
8760
|
+
const pageSize = filters.pagination || 5;
|
|
8761
|
+
let startIndex = 0;
|
|
8762
|
+
if (filters.lastDoc && typeof filters.lastDoc === "object" && filters.lastDoc.id) {
|
|
8763
|
+
const idx = clinics.findIndex((c) => c.id === filters.lastDoc.id);
|
|
8764
|
+
if (idx >= 0) startIndex = idx + 1;
|
|
8765
|
+
}
|
|
8766
|
+
const page = clinics.slice(startIndex, startIndex + pageSize);
|
|
8767
|
+
const newLastDoc = page.length === pageSize ? page[page.length - 1] : null;
|
|
8768
|
+
console.log(
|
|
8769
|
+
`[CLINIC_SERVICE] Strategy 0 success: ${page.length} clinics (of ${clinics.length})`
|
|
8770
|
+
);
|
|
8771
|
+
return { clinics: page, lastDoc: newLastDoc };
|
|
8772
|
+
} catch (geoErr) {
|
|
8773
|
+
console.log("[CLINIC_SERVICE] Strategy 0 failed:", geoErr);
|
|
8774
|
+
}
|
|
8775
|
+
}
|
|
8727
8776
|
const getBaseConstraints = () => {
|
|
8728
|
-
var
|
|
8777
|
+
var _a2;
|
|
8729
8778
|
const constraints = [];
|
|
8730
|
-
constraints.push((0, import_firestore26.where)("isActive", "==", (
|
|
8779
|
+
constraints.push((0, import_firestore26.where)("isActive", "==", (_a2 = filters.isActive) != null ? _a2 : true));
|
|
8731
8780
|
if (filters.tags && filters.tags.length > 0) {
|
|
8732
8781
|
constraints.push((0, import_firestore26.where)("tags", "array-contains", filters.tags[0]));
|
|
8733
8782
|
}
|
|
@@ -8804,7 +8853,9 @@ async function getClinicsByFilters(db, filters) {
|
|
|
8804
8853
|
}
|
|
8805
8854
|
}
|
|
8806
8855
|
try {
|
|
8807
|
-
console.log(
|
|
8856
|
+
console.log(
|
|
8857
|
+
"[CLINIC_SERVICE] Strategy 3: Using createdAt ordering with client-side filtering"
|
|
8858
|
+
);
|
|
8808
8859
|
const constraints = getBaseConstraints();
|
|
8809
8860
|
constraints.push((0, import_firestore26.orderBy)("createdAt", "desc"));
|
|
8810
8861
|
if (filters.lastDoc) {
|
|
@@ -8859,20 +8910,24 @@ async function getClinicsByFilters(db, filters) {
|
|
|
8859
8910
|
}
|
|
8860
8911
|
function applyInMemoryFilters(clinics, filters) {
|
|
8861
8912
|
let filteredClinics = [...clinics];
|
|
8862
|
-
console.log(
|
|
8913
|
+
console.log(
|
|
8914
|
+
`[CLINIC_SERVICE] Applying in-memory filters - input: ${filteredClinics.length} clinics`
|
|
8915
|
+
);
|
|
8863
8916
|
if (filters.tags && filters.tags.length > 1) {
|
|
8864
8917
|
const initialCount = filteredClinics.length;
|
|
8865
8918
|
filteredClinics = filteredClinics.filter(
|
|
8866
8919
|
(clinic) => filters.tags.every((tag) => clinic.tags.includes(tag))
|
|
8867
8920
|
);
|
|
8868
|
-
console.log(
|
|
8921
|
+
console.log(
|
|
8922
|
+
`[CLINIC_SERVICE] Applied multi-tag filter: ${initialCount} \u2192 ${filteredClinics.length}`
|
|
8923
|
+
);
|
|
8869
8924
|
}
|
|
8870
8925
|
if (filters.tags && filters.tags.length === 1) {
|
|
8871
8926
|
const initialCount = filteredClinics.length;
|
|
8872
|
-
filteredClinics = filteredClinics.filter(
|
|
8873
|
-
|
|
8927
|
+
filteredClinics = filteredClinics.filter((clinic) => clinic.tags.includes(filters.tags[0]));
|
|
8928
|
+
console.log(
|
|
8929
|
+
`[CLINIC_SERVICE] Applied single-tag filter: ${initialCount} \u2192 ${filteredClinics.length}`
|
|
8874
8930
|
);
|
|
8875
|
-
console.log(`[CLINIC_SERVICE] Applied single-tag filter: ${initialCount} \u2192 ${filteredClinics.length}`);
|
|
8876
8931
|
}
|
|
8877
8932
|
if (filters.minRating !== void 0 || filters.maxRating !== void 0) {
|
|
8878
8933
|
const initialCount = filteredClinics.length;
|
|
@@ -8883,7 +8938,9 @@ function applyInMemoryFilters(clinics, filters) {
|
|
|
8883
8938
|
if (filters.maxRating !== void 0 && rating > filters.maxRating) return false;
|
|
8884
8939
|
return true;
|
|
8885
8940
|
});
|
|
8886
|
-
console.log(
|
|
8941
|
+
console.log(
|
|
8942
|
+
`[CLINIC_SERVICE] Applied rating filter (${filters.minRating}-${filters.maxRating}): ${initialCount} \u2192 ${filteredClinics.length}`
|
|
8943
|
+
);
|
|
8887
8944
|
}
|
|
8888
8945
|
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
8889
8946
|
const initialCount = filteredClinics.length;
|
|
@@ -8893,7 +8950,9 @@ function applyInMemoryFilters(clinics, filters) {
|
|
|
8893
8950
|
const nameLower = clinic.nameLower || "";
|
|
8894
8951
|
return name.includes(searchTerm) || nameLower.includes(searchTerm);
|
|
8895
8952
|
});
|
|
8896
|
-
console.log(
|
|
8953
|
+
console.log(
|
|
8954
|
+
`[CLINIC_SERVICE] Applied name search filter: ${initialCount} \u2192 ${filteredClinics.length}`
|
|
8955
|
+
);
|
|
8897
8956
|
}
|
|
8898
8957
|
if (filters.procedureFamily) {
|
|
8899
8958
|
const initialCount = filteredClinics.length;
|
|
@@ -8901,7 +8960,9 @@ function applyInMemoryFilters(clinics, filters) {
|
|
|
8901
8960
|
const proceduresInfo = clinic.proceduresInfo || [];
|
|
8902
8961
|
return proceduresInfo.some((proc) => proc.family === filters.procedureFamily);
|
|
8903
8962
|
});
|
|
8904
|
-
console.log(
|
|
8963
|
+
console.log(
|
|
8964
|
+
`[CLINIC_SERVICE] Applied procedure family filter: ${initialCount} \u2192 ${filteredClinics.length}`
|
|
8965
|
+
);
|
|
8905
8966
|
}
|
|
8906
8967
|
if (filters.procedureCategory) {
|
|
8907
8968
|
const initialCount = filteredClinics.length;
|
|
@@ -8909,7 +8970,9 @@ function applyInMemoryFilters(clinics, filters) {
|
|
|
8909
8970
|
const proceduresInfo = clinic.proceduresInfo || [];
|
|
8910
8971
|
return proceduresInfo.some((proc) => proc.categoryName === filters.procedureCategory);
|
|
8911
8972
|
});
|
|
8912
|
-
console.log(
|
|
8973
|
+
console.log(
|
|
8974
|
+
`[CLINIC_SERVICE] Applied procedure category filter: ${initialCount} \u2192 ${filteredClinics.length}`
|
|
8975
|
+
);
|
|
8913
8976
|
}
|
|
8914
8977
|
if (filters.procedureSubcategory) {
|
|
8915
8978
|
const initialCount = filteredClinics.length;
|
|
@@ -8917,7 +8980,9 @@ function applyInMemoryFilters(clinics, filters) {
|
|
|
8917
8980
|
const proceduresInfo = clinic.proceduresInfo || [];
|
|
8918
8981
|
return proceduresInfo.some((proc) => proc.subcategoryName === filters.procedureSubcategory);
|
|
8919
8982
|
});
|
|
8920
|
-
console.log(
|
|
8983
|
+
console.log(
|
|
8984
|
+
`[CLINIC_SERVICE] Applied procedure subcategory filter: ${initialCount} \u2192 ${filteredClinics.length}`
|
|
8985
|
+
);
|
|
8921
8986
|
}
|
|
8922
8987
|
if (filters.procedureTechnology) {
|
|
8923
8988
|
const initialCount = filteredClinics.length;
|
|
@@ -8925,7 +8990,9 @@ function applyInMemoryFilters(clinics, filters) {
|
|
|
8925
8990
|
const proceduresInfo = clinic.proceduresInfo || [];
|
|
8926
8991
|
return proceduresInfo.some((proc) => proc.technologyName === filters.procedureTechnology);
|
|
8927
8992
|
});
|
|
8928
|
-
console.log(
|
|
8993
|
+
console.log(
|
|
8994
|
+
`[CLINIC_SERVICE] Applied procedure technology filter: ${initialCount} \u2192 ${filteredClinics.length}`
|
|
8995
|
+
);
|
|
8929
8996
|
}
|
|
8930
8997
|
if (filters.center && filters.radiusInKm) {
|
|
8931
8998
|
const initialCount = filteredClinics.length;
|
|
@@ -8939,11 +9006,15 @@ function applyInMemoryFilters(clinics, filters) {
|
|
|
8939
9006
|
[filters.center.latitude, filters.center.longitude],
|
|
8940
9007
|
[clinic.location.latitude, clinic.location.longitude]
|
|
8941
9008
|
) / 1e3;
|
|
8942
|
-
console.log(
|
|
9009
|
+
console.log(
|
|
9010
|
+
`[CLINIC_SERVICE] Clinic ${clinic.name}: distance ${distance.toFixed(2)}km (limit: ${filters.radiusInKm}km)`
|
|
9011
|
+
);
|
|
8943
9012
|
clinic.distance = distance;
|
|
8944
9013
|
return distance <= filters.radiusInKm;
|
|
8945
9014
|
});
|
|
8946
|
-
console.log(
|
|
9015
|
+
console.log(
|
|
9016
|
+
`[CLINIC_SERVICE] Applied geo filter (${filters.radiusInKm}km): ${initialCount} \u2192 ${filteredClinics.length}`
|
|
9017
|
+
);
|
|
8947
9018
|
filteredClinics.sort((a, b) => (a.distance || 0) - (b.distance || 0));
|
|
8948
9019
|
}
|
|
8949
9020
|
console.log(`[CLINIC_SERVICE] Final filtered result: ${filteredClinics.length} clinics`);
|
|
@@ -8957,6 +9028,27 @@ var ClinicService = class extends BaseService {
|
|
|
8957
9028
|
this.clinicAdminService = clinicAdminService;
|
|
8958
9029
|
this.clinicGroupService = clinicGroupService;
|
|
8959
9030
|
this.mediaService = mediaService;
|
|
9031
|
+
this.functions = (0, import_functions2.getFunctions)(app);
|
|
9032
|
+
}
|
|
9033
|
+
/**
|
|
9034
|
+
* Get timezone from coordinates using the callable function
|
|
9035
|
+
* @param lat Latitude
|
|
9036
|
+
* @param lng Longitude
|
|
9037
|
+
* @returns IANA timezone string
|
|
9038
|
+
*/
|
|
9039
|
+
async getTimezone(lat, lng) {
|
|
9040
|
+
try {
|
|
9041
|
+
const getTimezoneFromCoordinates = (0, import_functions2.httpsCallable)(
|
|
9042
|
+
this.functions,
|
|
9043
|
+
"getTimezoneFromCoordinates"
|
|
9044
|
+
);
|
|
9045
|
+
const result = await getTimezoneFromCoordinates({ lat, lng });
|
|
9046
|
+
const data = result.data;
|
|
9047
|
+
return data.timezone;
|
|
9048
|
+
} catch (error) {
|
|
9049
|
+
console.error("Error getting timezone:", error);
|
|
9050
|
+
return null;
|
|
9051
|
+
}
|
|
8960
9052
|
}
|
|
8961
9053
|
/**
|
|
8962
9054
|
* Process media resource (string URL or File object)
|
|
@@ -9069,6 +9161,7 @@ var ClinicService = class extends BaseService {
|
|
|
9069
9161
|
);
|
|
9070
9162
|
const location = validatedData.location;
|
|
9071
9163
|
const hash = (0, import_geofire_common7.geohashForLocation)([location.latitude, location.longitude]);
|
|
9164
|
+
const tz = await this.getTimezone(location.latitude, location.longitude);
|
|
9072
9165
|
const defaultReviewInfo = {
|
|
9073
9166
|
totalReviews: 0,
|
|
9074
9167
|
averageRating: 0,
|
|
@@ -9086,7 +9179,7 @@ var ClinicService = class extends BaseService {
|
|
|
9086
9179
|
nameLower: validatedData.name.toLowerCase(),
|
|
9087
9180
|
// Add this line
|
|
9088
9181
|
description: validatedData.description,
|
|
9089
|
-
location: { ...location, geohash: hash },
|
|
9182
|
+
location: { ...location, geohash: hash, tz },
|
|
9090
9183
|
contactInfo: validatedData.contactInfo,
|
|
9091
9184
|
workingHours: validatedData.workingHours,
|
|
9092
9185
|
tags: validatedData.tags,
|
|
@@ -9190,9 +9283,11 @@ var ClinicService = class extends BaseService {
|
|
|
9190
9283
|
}
|
|
9191
9284
|
if (validatedData.location) {
|
|
9192
9285
|
const loc = validatedData.location;
|
|
9286
|
+
const tz = await this.getTimezone(loc.latitude, loc.longitude);
|
|
9193
9287
|
updatePayload.location = {
|
|
9194
9288
|
...loc,
|
|
9195
|
-
geohash: (0, import_geofire_common7.geohashForLocation)([loc.latitude, loc.longitude])
|
|
9289
|
+
geohash: (0, import_geofire_common7.geohashForLocation)([loc.latitude, loc.longitude]),
|
|
9290
|
+
tz
|
|
9196
9291
|
};
|
|
9197
9292
|
}
|
|
9198
9293
|
updatePayload.updatedAt = (0, import_firestore27.serverTimestamp)();
|
|
@@ -14565,7 +14660,8 @@ var import_firestore45 = require("firebase/firestore");
|
|
|
14565
14660
|
var import_zod24 = require("zod");
|
|
14566
14661
|
var createProcedureSchema = import_zod24.z.object({
|
|
14567
14662
|
name: import_zod24.z.string().min(1).max(200),
|
|
14568
|
-
|
|
14663
|
+
// Optional: service will derive from name if not provided by client
|
|
14664
|
+
nameLower: import_zod24.z.string().min(1).max(200).optional(),
|
|
14569
14665
|
description: import_zod24.z.string().min(1).max(2e3),
|
|
14570
14666
|
family: import_zod24.z.nativeEnum(ProcedureFamily),
|
|
14571
14667
|
categoryId: import_zod24.z.string().min(1),
|
|
@@ -14658,9 +14754,7 @@ var ProcedureService = class extends BaseService {
|
|
|
14658
14754
|
return media;
|
|
14659
14755
|
}
|
|
14660
14756
|
if (media instanceof File || media instanceof Blob) {
|
|
14661
|
-
console.log(
|
|
14662
|
-
`[ProcedureService] Uploading ${collectionName} media for ${ownerId}`
|
|
14663
|
-
);
|
|
14757
|
+
console.log(`[ProcedureService] Uploading ${collectionName} media for ${ownerId}`);
|
|
14664
14758
|
const metadata = await this.mediaService.uploadMedia(
|
|
14665
14759
|
media,
|
|
14666
14760
|
ownerId,
|
|
@@ -14682,11 +14776,7 @@ var ProcedureService = class extends BaseService {
|
|
|
14682
14776
|
if (!mediaArray || mediaArray.length === 0) return [];
|
|
14683
14777
|
const result = [];
|
|
14684
14778
|
for (const media of mediaArray) {
|
|
14685
|
-
const processedUrl = await this.processMedia(
|
|
14686
|
-
media,
|
|
14687
|
-
ownerId,
|
|
14688
|
-
collectionName
|
|
14689
|
-
);
|
|
14779
|
+
const processedUrl = await this.processMedia(media, ownerId, collectionName);
|
|
14690
14780
|
if (processedUrl) {
|
|
14691
14781
|
result.push(processedUrl);
|
|
14692
14782
|
}
|
|
@@ -14704,41 +14794,23 @@ var ProcedureService = class extends BaseService {
|
|
|
14704
14794
|
const procedureId = this.generateId();
|
|
14705
14795
|
const [category, subcategory, technology, product] = await Promise.all([
|
|
14706
14796
|
this.categoryService.getById(validatedData.categoryId),
|
|
14707
|
-
this.subcategoryService.getById(
|
|
14708
|
-
validatedData.categoryId,
|
|
14709
|
-
validatedData.subcategoryId
|
|
14710
|
-
),
|
|
14797
|
+
this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
|
|
14711
14798
|
this.technologyService.getById(validatedData.technologyId),
|
|
14712
|
-
this.productService.getById(
|
|
14713
|
-
validatedData.technologyId,
|
|
14714
|
-
validatedData.productId
|
|
14715
|
-
)
|
|
14799
|
+
this.productService.getById(validatedData.technologyId, validatedData.productId)
|
|
14716
14800
|
]);
|
|
14717
14801
|
if (!category || !subcategory || !technology || !product) {
|
|
14718
14802
|
throw new Error("One or more required base entities not found");
|
|
14719
14803
|
}
|
|
14720
|
-
const clinicRef = (0, import_firestore45.doc)(
|
|
14721
|
-
this.db,
|
|
14722
|
-
CLINICS_COLLECTION,
|
|
14723
|
-
validatedData.clinicBranchId
|
|
14724
|
-
);
|
|
14804
|
+
const clinicRef = (0, import_firestore45.doc)(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId);
|
|
14725
14805
|
const clinicSnapshot = await (0, import_firestore45.getDoc)(clinicRef);
|
|
14726
14806
|
if (!clinicSnapshot.exists()) {
|
|
14727
|
-
throw new Error(
|
|
14728
|
-
`Clinic with ID ${validatedData.clinicBranchId} not found`
|
|
14729
|
-
);
|
|
14807
|
+
throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
|
|
14730
14808
|
}
|
|
14731
14809
|
const clinic = clinicSnapshot.data();
|
|
14732
|
-
const practitionerRef = (0, import_firestore45.doc)(
|
|
14733
|
-
this.db,
|
|
14734
|
-
PRACTITIONERS_COLLECTION,
|
|
14735
|
-
validatedData.practitionerId
|
|
14736
|
-
);
|
|
14810
|
+
const practitionerRef = (0, import_firestore45.doc)(this.db, PRACTITIONERS_COLLECTION, validatedData.practitionerId);
|
|
14737
14811
|
const practitionerSnapshot = await (0, import_firestore45.getDoc)(practitionerRef);
|
|
14738
14812
|
if (!practitionerSnapshot.exists()) {
|
|
14739
|
-
throw new Error(
|
|
14740
|
-
`Practitioner with ID ${validatedData.practitionerId} not found`
|
|
14741
|
-
);
|
|
14813
|
+
throw new Error(`Practitioner with ID ${validatedData.practitionerId} not found`);
|
|
14742
14814
|
}
|
|
14743
14815
|
const practitioner = practitionerSnapshot.data();
|
|
14744
14816
|
let processedPhotos = [];
|
|
@@ -14769,6 +14841,7 @@ var ProcedureService = class extends BaseService {
|
|
|
14769
14841
|
const newProcedure = {
|
|
14770
14842
|
id: procedureId,
|
|
14771
14843
|
...validatedData,
|
|
14844
|
+
// Ensure nameLower is always set even if omitted by client
|
|
14772
14845
|
nameLower: validatedData.nameLower || validatedData.name.toLowerCase(),
|
|
14773
14846
|
photos: processedPhotos,
|
|
14774
14847
|
category,
|
|
@@ -14827,24 +14900,16 @@ var ProcedureService = class extends BaseService {
|
|
|
14827
14900
|
const validatedData = createProcedureSchema.parse(validationData);
|
|
14828
14901
|
const [category, subcategory, technology, product, clinicSnapshot] = await Promise.all([
|
|
14829
14902
|
this.categoryService.getById(validatedData.categoryId),
|
|
14830
|
-
this.subcategoryService.getById(
|
|
14831
|
-
validatedData.categoryId,
|
|
14832
|
-
validatedData.subcategoryId
|
|
14833
|
-
),
|
|
14903
|
+
this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
|
|
14834
14904
|
this.technologyService.getById(validatedData.technologyId),
|
|
14835
|
-
this.productService.getById(
|
|
14836
|
-
validatedData.technologyId,
|
|
14837
|
-
validatedData.productId
|
|
14838
|
-
),
|
|
14905
|
+
this.productService.getById(validatedData.technologyId, validatedData.productId),
|
|
14839
14906
|
(0, import_firestore45.getDoc)((0, import_firestore45.doc)(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId))
|
|
14840
14907
|
]);
|
|
14841
14908
|
if (!category || !subcategory || !technology || !product) {
|
|
14842
14909
|
throw new Error("One or more required base entities not found");
|
|
14843
14910
|
}
|
|
14844
14911
|
if (!clinicSnapshot.exists()) {
|
|
14845
|
-
throw new Error(
|
|
14846
|
-
`Clinic with ID ${validatedData.clinicBranchId} not found`
|
|
14847
|
-
);
|
|
14912
|
+
throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
|
|
14848
14913
|
}
|
|
14849
14914
|
const clinic = clinicSnapshot.data();
|
|
14850
14915
|
let processedPhotos = [];
|
|
@@ -14870,12 +14935,8 @@ var ProcedureService = class extends BaseService {
|
|
|
14870
14935
|
}
|
|
14871
14936
|
if (practitionersMap.size !== practitionerIds.length) {
|
|
14872
14937
|
const foundIds = Array.from(practitionersMap.keys());
|
|
14873
|
-
const notFoundIds = practitionerIds.filter(
|
|
14874
|
-
|
|
14875
|
-
);
|
|
14876
|
-
throw new Error(
|
|
14877
|
-
`The following practitioners were not found: ${notFoundIds.join(", ")}`
|
|
14878
|
-
);
|
|
14938
|
+
const notFoundIds = practitionerIds.filter((id) => !foundIds.includes(id));
|
|
14939
|
+
throw new Error(`The following practitioners were not found: ${notFoundIds.join(", ")}`);
|
|
14879
14940
|
}
|
|
14880
14941
|
const batch = (0, import_firestore45.writeBatch)(this.db);
|
|
14881
14942
|
const createdProcedureIds = [];
|
|
@@ -14943,10 +15004,7 @@ var ProcedureService = class extends BaseService {
|
|
|
14943
15004
|
const fetchedProcedures = [];
|
|
14944
15005
|
for (let i = 0; i < createdProcedureIds.length; i += 30) {
|
|
14945
15006
|
const chunk = createdProcedureIds.slice(i, i + 30);
|
|
14946
|
-
const q = (0, import_firestore45.query)(
|
|
14947
|
-
(0, import_firestore45.collection)(this.db, PROCEDURES_COLLECTION),
|
|
14948
|
-
(0, import_firestore45.where)((0, import_firestore45.documentId)(), "in", chunk)
|
|
14949
|
-
);
|
|
15007
|
+
const q = (0, import_firestore45.query)((0, import_firestore45.collection)(this.db, PROCEDURES_COLLECTION), (0, import_firestore45.where)((0, import_firestore45.documentId)(), "in", chunk));
|
|
14950
15008
|
const snapshot = await (0, import_firestore45.getDocs)(q);
|
|
14951
15009
|
snapshot.forEach((doc37) => {
|
|
14952
15010
|
fetchedProcedures.push(doc37.data());
|
|
@@ -15047,9 +15105,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15047
15105
|
);
|
|
15048
15106
|
const newPractitionerSnap = await (0, import_firestore45.getDoc)(newPractitionerRef);
|
|
15049
15107
|
if (!newPractitionerSnap.exists())
|
|
15050
|
-
throw new Error(
|
|
15051
|
-
`New Practitioner ${validatedData.practitionerId} not found`
|
|
15052
|
-
);
|
|
15108
|
+
throw new Error(`New Practitioner ${validatedData.practitionerId} not found`);
|
|
15053
15109
|
newPractitioner = newPractitionerSnap.data();
|
|
15054
15110
|
updatedProcedureData.doctorInfo = {
|
|
15055
15111
|
id: newPractitioner.id,
|
|
@@ -15063,11 +15119,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15063
15119
|
}
|
|
15064
15120
|
if (validatedData.clinicBranchId && validatedData.clinicBranchId !== oldClinicId) {
|
|
15065
15121
|
clinicChanged = true;
|
|
15066
|
-
const newClinicRef = (0, import_firestore45.doc)(
|
|
15067
|
-
this.db,
|
|
15068
|
-
CLINICS_COLLECTION,
|
|
15069
|
-
validatedData.clinicBranchId
|
|
15070
|
-
);
|
|
15122
|
+
const newClinicRef = (0, import_firestore45.doc)(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId);
|
|
15071
15123
|
const newClinicSnap = await (0, import_firestore45.getDoc)(newClinicRef);
|
|
15072
15124
|
if (!newClinicSnap.exists())
|
|
15073
15125
|
throw new Error(`New Clinic ${validatedData.clinicBranchId} not found`);
|
|
@@ -15086,11 +15138,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15086
15138
|
updatedProcedureData.nameLower = validatedData.name.toLowerCase();
|
|
15087
15139
|
}
|
|
15088
15140
|
if (validatedData.categoryId) {
|
|
15089
|
-
const category = await this.categoryService.getById(
|
|
15090
|
-
|
|
15091
|
-
);
|
|
15092
|
-
if (!category)
|
|
15093
|
-
throw new Error(`Category ${validatedData.categoryId} not found`);
|
|
15141
|
+
const category = await this.categoryService.getById(validatedData.categoryId);
|
|
15142
|
+
if (!category) throw new Error(`Category ${validatedData.categoryId} not found`);
|
|
15094
15143
|
updatedProcedureData.category = category;
|
|
15095
15144
|
finalCategoryId = category.id;
|
|
15096
15145
|
}
|
|
@@ -15105,17 +15154,12 @@ var ProcedureService = class extends BaseService {
|
|
|
15105
15154
|
);
|
|
15106
15155
|
updatedProcedureData.subcategory = subcategory;
|
|
15107
15156
|
} else if (validatedData.subcategoryId) {
|
|
15108
|
-
console.warn(
|
|
15109
|
-
"Attempted to update subcategory without a valid categoryId"
|
|
15110
|
-
);
|
|
15157
|
+
console.warn("Attempted to update subcategory without a valid categoryId");
|
|
15111
15158
|
}
|
|
15112
15159
|
let finalTechnologyId = existingProcedure.technology.id;
|
|
15113
15160
|
if (validatedData.technologyId) {
|
|
15114
|
-
const technology = await this.technologyService.getById(
|
|
15115
|
-
|
|
15116
|
-
);
|
|
15117
|
-
if (!technology)
|
|
15118
|
-
throw new Error(`Technology ${validatedData.technologyId} not found`);
|
|
15161
|
+
const technology = await this.technologyService.getById(validatedData.technologyId);
|
|
15162
|
+
if (!technology) throw new Error(`Technology ${validatedData.technologyId} not found`);
|
|
15119
15163
|
updatedProcedureData.technology = technology;
|
|
15120
15164
|
finalTechnologyId = technology.id;
|
|
15121
15165
|
updatedProcedureData.blockingConditions = technology.blockingConditions;
|
|
@@ -15126,10 +15170,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15126
15170
|
updatedProcedureData.documentationTemplates = technology.documentationTemplates || [];
|
|
15127
15171
|
}
|
|
15128
15172
|
if (validatedData.productId && finalTechnologyId) {
|
|
15129
|
-
const product = await this.productService.getById(
|
|
15130
|
-
finalTechnologyId,
|
|
15131
|
-
validatedData.productId
|
|
15132
|
-
);
|
|
15173
|
+
const product = await this.productService.getById(finalTechnologyId, validatedData.productId);
|
|
15133
15174
|
if (!product)
|
|
15134
15175
|
throw new Error(
|
|
15135
15176
|
`Product ${validatedData.productId} not found for technology ${finalTechnologyId}`
|
|
@@ -15211,11 +15252,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15211
15252
|
limit16(pagination)
|
|
15212
15253
|
);
|
|
15213
15254
|
} else {
|
|
15214
|
-
proceduresQuery = (0, import_firestore45.query)(
|
|
15215
|
-
proceduresCollection,
|
|
15216
|
-
(0, import_firestore45.orderBy)("name"),
|
|
15217
|
-
limit16(pagination)
|
|
15218
|
-
);
|
|
15255
|
+
proceduresQuery = (0, import_firestore45.query)(proceduresCollection, (0, import_firestore45.orderBy)("name"), limit16(pagination));
|
|
15219
15256
|
}
|
|
15220
15257
|
} else {
|
|
15221
15258
|
proceduresQuery = (0, import_firestore45.query)(proceduresCollection, (0, import_firestore45.orderBy)("name"));
|
|
@@ -15338,7 +15375,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15338
15375
|
constraints.push((0, import_firestore45.limit)(filters.pagination || 10));
|
|
15339
15376
|
const q = (0, import_firestore45.query)((0, import_firestore45.collection)(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15340
15377
|
const querySnapshot = await (0, import_firestore45.getDocs)(q);
|
|
15341
|
-
const procedures = querySnapshot.docs.map(
|
|
15378
|
+
const procedures = querySnapshot.docs.map(
|
|
15379
|
+
(doc37) => ({ ...doc37.data(), id: doc37.id })
|
|
15380
|
+
);
|
|
15342
15381
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15343
15382
|
console.log(`[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`);
|
|
15344
15383
|
if (procedures.length < (filters.pagination || 10)) {
|
|
@@ -15369,7 +15408,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15369
15408
|
constraints.push((0, import_firestore45.limit)(filters.pagination || 10));
|
|
15370
15409
|
const q = (0, import_firestore45.query)((0, import_firestore45.collection)(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15371
15410
|
const querySnapshot = await (0, import_firestore45.getDocs)(q);
|
|
15372
|
-
const procedures = querySnapshot.docs.map(
|
|
15411
|
+
const procedures = querySnapshot.docs.map(
|
|
15412
|
+
(doc37) => ({ ...doc37.data(), id: doc37.id })
|
|
15413
|
+
);
|
|
15373
15414
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15374
15415
|
console.log(`[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`);
|
|
15375
15416
|
if (procedures.length < (filters.pagination || 10)) {
|
|
@@ -15381,7 +15422,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15381
15422
|
}
|
|
15382
15423
|
}
|
|
15383
15424
|
try {
|
|
15384
|
-
console.log(
|
|
15425
|
+
console.log(
|
|
15426
|
+
"[PROCEDURE_SERVICE] Strategy 3: Using createdAt orderBy with client-side filtering"
|
|
15427
|
+
);
|
|
15385
15428
|
const constraints = getBaseConstraints();
|
|
15386
15429
|
constraints.push((0, import_firestore45.orderBy)("createdAt", "desc"));
|
|
15387
15430
|
if (filters.lastDoc) {
|
|
@@ -15396,7 +15439,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15396
15439
|
constraints.push((0, import_firestore45.limit)(filters.pagination || 10));
|
|
15397
15440
|
const q = (0, import_firestore45.query)((0, import_firestore45.collection)(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15398
15441
|
const querySnapshot = await (0, import_firestore45.getDocs)(q);
|
|
15399
|
-
let procedures = querySnapshot.docs.map(
|
|
15442
|
+
let procedures = querySnapshot.docs.map(
|
|
15443
|
+
(doc37) => ({ ...doc37.data(), id: doc37.id })
|
|
15444
|
+
);
|
|
15400
15445
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15401
15446
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15402
15447
|
console.log(`[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`);
|
|
@@ -15416,7 +15461,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15416
15461
|
];
|
|
15417
15462
|
const q = (0, import_firestore45.query)((0, import_firestore45.collection)(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15418
15463
|
const querySnapshot = await (0, import_firestore45.getDocs)(q);
|
|
15419
|
-
let procedures = querySnapshot.docs.map(
|
|
15464
|
+
let procedures = querySnapshot.docs.map(
|
|
15465
|
+
(doc37) => ({ ...doc37.data(), id: doc37.id })
|
|
15466
|
+
);
|
|
15420
15467
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15421
15468
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15422
15469
|
console.log(`[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`);
|
|
@@ -15456,7 +15503,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15456
15503
|
if (filters.maxPrice !== void 0 && price > filters.maxPrice) return false;
|
|
15457
15504
|
return true;
|
|
15458
15505
|
});
|
|
15459
|
-
console.log(
|
|
15506
|
+
console.log(
|
|
15507
|
+
`[PROCEDURE_SERVICE] Applied price filter (${filters.minPrice}-${filters.maxPrice}), results: ${filteredProcedures.length}`
|
|
15508
|
+
);
|
|
15460
15509
|
}
|
|
15461
15510
|
if (filters.minRating !== void 0 || filters.maxRating !== void 0) {
|
|
15462
15511
|
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
@@ -15466,7 +15515,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15466
15515
|
if (filters.maxRating !== void 0 && rating > filters.maxRating) return false;
|
|
15467
15516
|
return true;
|
|
15468
15517
|
});
|
|
15469
|
-
console.log(
|
|
15518
|
+
console.log(
|
|
15519
|
+
`[PROCEDURE_SERVICE] Applied rating filter, results: ${filteredProcedures.length}`
|
|
15520
|
+
);
|
|
15470
15521
|
}
|
|
15471
15522
|
if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
|
|
15472
15523
|
const benefitsToMatch = filters.treatmentBenefits;
|
|
@@ -15474,32 +15525,50 @@ var ProcedureService = class extends BaseService {
|
|
|
15474
15525
|
const procedureBenefits = procedure.treatmentBenefits || [];
|
|
15475
15526
|
return benefitsToMatch.some((benefit) => procedureBenefits.includes(benefit));
|
|
15476
15527
|
});
|
|
15477
|
-
console.log(
|
|
15528
|
+
console.log(
|
|
15529
|
+
`[PROCEDURE_SERVICE] Applied benefits filter, results: ${filteredProcedures.length}`
|
|
15530
|
+
);
|
|
15478
15531
|
}
|
|
15479
15532
|
if (filters.procedureFamily) {
|
|
15480
|
-
filteredProcedures = filteredProcedures.filter(
|
|
15481
|
-
|
|
15533
|
+
filteredProcedures = filteredProcedures.filter(
|
|
15534
|
+
(procedure) => procedure.family === filters.procedureFamily
|
|
15535
|
+
);
|
|
15536
|
+
console.log(
|
|
15537
|
+
`[PROCEDURE_SERVICE] Applied family filter, results: ${filteredProcedures.length}`
|
|
15538
|
+
);
|
|
15482
15539
|
}
|
|
15483
15540
|
if (filters.procedureCategory) {
|
|
15484
|
-
filteredProcedures = filteredProcedures.filter(
|
|
15485
|
-
|
|
15486
|
-
|
|
15487
|
-
|
|
15488
|
-
|
|
15541
|
+
filteredProcedures = filteredProcedures.filter(
|
|
15542
|
+
(procedure) => {
|
|
15543
|
+
var _a;
|
|
15544
|
+
return ((_a = procedure.category) == null ? void 0 : _a.id) === filters.procedureCategory;
|
|
15545
|
+
}
|
|
15546
|
+
);
|
|
15547
|
+
console.log(
|
|
15548
|
+
`[PROCEDURE_SERVICE] Applied category filter, results: ${filteredProcedures.length}`
|
|
15549
|
+
);
|
|
15489
15550
|
}
|
|
15490
15551
|
if (filters.procedureSubcategory) {
|
|
15491
|
-
filteredProcedures = filteredProcedures.filter(
|
|
15492
|
-
|
|
15493
|
-
|
|
15494
|
-
|
|
15495
|
-
|
|
15552
|
+
filteredProcedures = filteredProcedures.filter(
|
|
15553
|
+
(procedure) => {
|
|
15554
|
+
var _a;
|
|
15555
|
+
return ((_a = procedure.subcategory) == null ? void 0 : _a.id) === filters.procedureSubcategory;
|
|
15556
|
+
}
|
|
15557
|
+
);
|
|
15558
|
+
console.log(
|
|
15559
|
+
`[PROCEDURE_SERVICE] Applied subcategory filter, results: ${filteredProcedures.length}`
|
|
15560
|
+
);
|
|
15496
15561
|
}
|
|
15497
15562
|
if (filters.procedureTechnology) {
|
|
15498
|
-
filteredProcedures = filteredProcedures.filter(
|
|
15499
|
-
|
|
15500
|
-
|
|
15501
|
-
|
|
15502
|
-
|
|
15563
|
+
filteredProcedures = filteredProcedures.filter(
|
|
15564
|
+
(procedure) => {
|
|
15565
|
+
var _a;
|
|
15566
|
+
return ((_a = procedure.technology) == null ? void 0 : _a.id) === filters.procedureTechnology;
|
|
15567
|
+
}
|
|
15568
|
+
);
|
|
15569
|
+
console.log(
|
|
15570
|
+
`[PROCEDURE_SERVICE] Applied technology filter, results: ${filteredProcedures.length}`
|
|
15571
|
+
);
|
|
15503
15572
|
}
|
|
15504
15573
|
if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
|
|
15505
15574
|
const location = filters.location;
|
|
@@ -15523,29 +15592,48 @@ var ProcedureService = class extends BaseService {
|
|
|
15523
15592
|
return filteredProcedures;
|
|
15524
15593
|
}
|
|
15525
15594
|
handleGeoQuery(filters) {
|
|
15526
|
-
console.log("[PROCEDURE_SERVICE] Executing geo query with
|
|
15595
|
+
console.log("[PROCEDURE_SERVICE] Executing geo query with geohash bounds");
|
|
15527
15596
|
try {
|
|
15528
15597
|
const location = filters.location;
|
|
15529
15598
|
const radiusInKm = filters.radiusInKm;
|
|
15530
|
-
|
|
15531
|
-
|
|
15532
|
-
|
|
15533
|
-
|
|
15534
|
-
|
|
15599
|
+
if (!location || !radiusInKm) {
|
|
15600
|
+
return Promise.resolve({ procedures: [], lastDoc: null });
|
|
15601
|
+
}
|
|
15602
|
+
const bounds = (0, import_geofire_common8.geohashQueryBounds)([location.latitude, location.longitude], radiusInKm * 1e3);
|
|
15603
|
+
const fetches = bounds.map((b) => {
|
|
15604
|
+
const constraints = [
|
|
15605
|
+
(0, import_firestore45.where)("clinicInfo.location.geohash", ">=", b[0]),
|
|
15606
|
+
(0, import_firestore45.where)("clinicInfo.location.geohash", "<=", b[1]),
|
|
15607
|
+
(0, import_firestore45.where)("isActive", "==", filters.isActive !== void 0 ? filters.isActive : true)
|
|
15608
|
+
];
|
|
15609
|
+
return (0, import_firestore45.getDocs)((0, import_firestore45.query)((0, import_firestore45.collection)(this.db, PROCEDURES_COLLECTION), ...constraints));
|
|
15535
15610
|
});
|
|
15536
|
-
|
|
15537
|
-
|
|
15538
|
-
(
|
|
15539
|
-
|
|
15540
|
-
|
|
15541
|
-
|
|
15542
|
-
|
|
15543
|
-
|
|
15544
|
-
|
|
15611
|
+
return Promise.all(fetches).then((snaps) => {
|
|
15612
|
+
const collected = [];
|
|
15613
|
+
snaps.forEach((snap) => {
|
|
15614
|
+
snap.docs.forEach((d) => collected.push({ ...d.data(), id: d.id }));
|
|
15615
|
+
});
|
|
15616
|
+
const uniqueMap = /* @__PURE__ */ new Map();
|
|
15617
|
+
for (const p of collected) {
|
|
15618
|
+
uniqueMap.set(p.id, p);
|
|
15619
|
+
}
|
|
15620
|
+
let procedures = Array.from(uniqueMap.values());
|
|
15545
15621
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15546
|
-
|
|
15547
|
-
|
|
15548
|
-
|
|
15622
|
+
const pageSize = filters.pagination || 10;
|
|
15623
|
+
let startIndex = 0;
|
|
15624
|
+
if (filters.lastDoc && typeof filters.lastDoc === "object" && filters.lastDoc.id) {
|
|
15625
|
+
const idx = procedures.findIndex((p) => p.id === filters.lastDoc.id);
|
|
15626
|
+
if (idx >= 0) startIndex = idx + 1;
|
|
15627
|
+
}
|
|
15628
|
+
const page = procedures.slice(startIndex, startIndex + pageSize);
|
|
15629
|
+
const newLastDoc = page.length === pageSize ? page[page.length - 1] : null;
|
|
15630
|
+
console.log(
|
|
15631
|
+
`[PROCEDURE_SERVICE] Geo query success: ${page.length} (of ${procedures.length}) within ${radiusInKm}km`
|
|
15632
|
+
);
|
|
15633
|
+
return { procedures: page, lastDoc: newLastDoc };
|
|
15634
|
+
}).catch((err) => {
|
|
15635
|
+
console.error("[PROCEDURE_SERVICE] Geo bounds fetch failed:", err);
|
|
15636
|
+
return { procedures: [], lastDoc: null };
|
|
15549
15637
|
});
|
|
15550
15638
|
} catch (error) {
|
|
15551
15639
|
console.error("[PROCEDURE_SERVICE] Geo query failed:", error);
|
|
@@ -15575,11 +15663,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15575
15663
|
throw new Error(`Clinic with ID ${data.clinicBranchId} not found`);
|
|
15576
15664
|
}
|
|
15577
15665
|
const clinic = clinicSnapshot.data();
|
|
15578
|
-
const practitionerRef = (0, import_firestore45.doc)(
|
|
15579
|
-
this.db,
|
|
15580
|
-
PRACTITIONERS_COLLECTION,
|
|
15581
|
-
data.practitionerId
|
|
15582
|
-
);
|
|
15666
|
+
const practitionerRef = (0, import_firestore45.doc)(this.db, PRACTITIONERS_COLLECTION, data.practitionerId);
|
|
15583
15667
|
const practitionerSnapshot = await (0, import_firestore45.getDoc)(practitionerRef);
|
|
15584
15668
|
if (!practitionerSnapshot.exists()) {
|
|
15585
15669
|
throw new Error(`Practitioner with ID ${data.practitionerId} not found`);
|
|
@@ -15587,11 +15671,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15587
15671
|
const practitioner = practitionerSnapshot.data();
|
|
15588
15672
|
let processedPhotos = [];
|
|
15589
15673
|
if (data.photos && data.photos.length > 0) {
|
|
15590
|
-
processedPhotos = await this.processMediaArray(
|
|
15591
|
-
data.photos,
|
|
15592
|
-
procedureId,
|
|
15593
|
-
"procedure-photos"
|
|
15594
|
-
);
|
|
15674
|
+
processedPhotos = await this.processMediaArray(data.photos, procedureId, "procedure-photos");
|
|
15595
15675
|
}
|
|
15596
15676
|
const clinicInfo = {
|
|
15597
15677
|
id: clinicSnapshot.id,
|
|
@@ -15895,7 +15975,7 @@ var import_auth9 = require("firebase/auth");
|
|
|
15895
15975
|
var import_analytics = require("firebase/analytics");
|
|
15896
15976
|
var import_react_native = require("react-native");
|
|
15897
15977
|
var import_storage4 = require("firebase/storage");
|
|
15898
|
-
var
|
|
15978
|
+
var import_functions3 = require("firebase/functions");
|
|
15899
15979
|
var firebaseInstance = null;
|
|
15900
15980
|
var initializeFirebase = (config) => {
|
|
15901
15981
|
if (!firebaseInstance) {
|
|
@@ -15903,7 +15983,7 @@ var initializeFirebase = (config) => {
|
|
|
15903
15983
|
const db = (0, import_firestore47.getFirestore)(app);
|
|
15904
15984
|
const auth = (0, import_auth9.getAuth)(app);
|
|
15905
15985
|
const storage = (0, import_storage4.getStorage)(app);
|
|
15906
|
-
const functions = (0,
|
|
15986
|
+
const functions = (0, import_functions3.getFunctions)(app);
|
|
15907
15987
|
let analytics = null;
|
|
15908
15988
|
if (typeof window !== "undefined" && import_react_native.Platform.OS === "web") {
|
|
15909
15989
|
analytics = (0, import_analytics.getAnalytics)(app);
|