@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.mjs
CHANGED
|
@@ -455,7 +455,8 @@ var createAppointmentSchema = z3.object({
|
|
|
455
455
|
currency: z3.string().min(1, "Currency is required"),
|
|
456
456
|
patientNotes: z3.string().max(MAX_STRING_LENGTH, "Patient notes too long").nullable().optional(),
|
|
457
457
|
initialStatus: appointmentStatusSchema,
|
|
458
|
-
initialPaymentStatus: paymentStatusSchema.optional().default("unpaid" /* UNPAID */)
|
|
458
|
+
initialPaymentStatus: paymentStatusSchema.optional().default("unpaid" /* UNPAID */),
|
|
459
|
+
clinic_tz: z3.string().min(1, "Timezone is required")
|
|
459
460
|
}).refine((data) => data.appointmentEndTime > data.appointmentStartTime, {
|
|
460
461
|
message: "Appointment end time must be after start time",
|
|
461
462
|
path: ["appointmentEndTime"]
|
|
@@ -489,6 +490,7 @@ var updateAppointmentSchema = z3.object({
|
|
|
489
490
|
cost: z3.number().min(0).optional(),
|
|
490
491
|
clinicBranchId: z3.string().min(MIN_STRING_LENGTH).optional(),
|
|
491
492
|
practitionerId: z3.string().min(MIN_STRING_LENGTH).optional(),
|
|
493
|
+
clinic_tz: z3.string().min(MIN_STRING_LENGTH).optional(),
|
|
492
494
|
linkedForms: z3.union([z3.array(linkedFormInfoSchema).max(MAX_ARRAY_LENGTH), z3.any()]).optional(),
|
|
493
495
|
media: z3.union([
|
|
494
496
|
z3.array(appointmentMediaItemSchema).max(MAX_ARRAY_LENGTH),
|
|
@@ -3437,7 +3439,8 @@ var clinicLocationSchema = z10.object({
|
|
|
3437
3439
|
postalCode: z10.string(),
|
|
3438
3440
|
latitude: z10.number().min(-90).max(90),
|
|
3439
3441
|
longitude: z10.number().min(-180).max(180),
|
|
3440
|
-
geohash: z10.string().nullable().optional()
|
|
3442
|
+
geohash: z10.string().nullable().optional(),
|
|
3443
|
+
tz: z10.string().nullable().optional()
|
|
3441
3444
|
});
|
|
3442
3445
|
var workingHoursTimeSchema = z10.object({
|
|
3443
3446
|
open: z10.string(),
|
|
@@ -3591,6 +3594,7 @@ var createClinicGroupSchema = z10.object({
|
|
|
3591
3594
|
calendarSyncEnabled: z10.boolean().optional(),
|
|
3592
3595
|
autoConfirmAppointments: z10.boolean().optional(),
|
|
3593
3596
|
businessIdentificationNumber: z10.string().optional().nullable(),
|
|
3597
|
+
tz: z10.string().nullable().optional(),
|
|
3594
3598
|
onboarding: z10.object({
|
|
3595
3599
|
completed: z10.boolean().optional().default(false),
|
|
3596
3600
|
step: z10.number().optional().default(1)
|
|
@@ -8342,6 +8346,7 @@ import {
|
|
|
8342
8346
|
writeBatch as writeBatch4,
|
|
8343
8347
|
arrayUnion as arrayUnion7
|
|
8344
8348
|
} from "firebase/firestore";
|
|
8349
|
+
import { getFunctions as getFunctions2, httpsCallable as httpsCallable2 } from "firebase/functions";
|
|
8345
8350
|
import {
|
|
8346
8351
|
geohashForLocation as geohashForLocation4
|
|
8347
8352
|
} from "geofire-common";
|
|
@@ -8810,8 +8815,9 @@ import {
|
|
|
8810
8815
|
limit as limit9,
|
|
8811
8816
|
orderBy as orderBy5
|
|
8812
8817
|
} from "firebase/firestore";
|
|
8813
|
-
import { distanceBetween as distanceBetween4 } from "geofire-common";
|
|
8818
|
+
import { geohashQueryBounds as geohashQueryBounds3, distanceBetween as distanceBetween4 } from "geofire-common";
|
|
8814
8819
|
async function getClinicsByFilters(db, filters) {
|
|
8820
|
+
var _a;
|
|
8815
8821
|
try {
|
|
8816
8822
|
console.log("[CLINIC_SERVICE] Starting clinic filtering with multiple strategies");
|
|
8817
8823
|
if (filters.center && filters.radiusInKm) {
|
|
@@ -8826,10 +8832,53 @@ async function getClinicsByFilters(db, filters) {
|
|
|
8826
8832
|
filters.radiusInKm = void 0;
|
|
8827
8833
|
}
|
|
8828
8834
|
}
|
|
8835
|
+
if (filters.center && filters.radiusInKm) {
|
|
8836
|
+
try {
|
|
8837
|
+
console.log("[CLINIC_SERVICE] Strategy 0: Geohash bounds prefilter");
|
|
8838
|
+
const bounds = geohashQueryBounds3(
|
|
8839
|
+
[filters.center.latitude, filters.center.longitude],
|
|
8840
|
+
(filters.radiusInKm || 0) * 1e3
|
|
8841
|
+
);
|
|
8842
|
+
const collected = [];
|
|
8843
|
+
for (const b of bounds) {
|
|
8844
|
+
const constraints = [
|
|
8845
|
+
where15("location.geohash", ">=", b[0]),
|
|
8846
|
+
where15("location.geohash", "<=", b[1]),
|
|
8847
|
+
where15("isActive", "==", (_a = filters.isActive) != null ? _a : true)
|
|
8848
|
+
];
|
|
8849
|
+
if (filters.tags && filters.tags.length > 0) {
|
|
8850
|
+
constraints.push(where15("tags", "array-contains", filters.tags[0]));
|
|
8851
|
+
}
|
|
8852
|
+
const q0 = query15(collection15(db, CLINICS_COLLECTION), ...constraints);
|
|
8853
|
+
const snap = await getDocs15(q0);
|
|
8854
|
+
snap.docs.forEach((d) => collected.push({ ...d.data(), id: d.id }));
|
|
8855
|
+
}
|
|
8856
|
+
const uniqueMap = /* @__PURE__ */ new Map();
|
|
8857
|
+
for (const c of collected) {
|
|
8858
|
+
uniqueMap.set(c.id, c);
|
|
8859
|
+
}
|
|
8860
|
+
let clinics = Array.from(uniqueMap.values());
|
|
8861
|
+
clinics = applyInMemoryFilters(clinics, filters);
|
|
8862
|
+
const pageSize = filters.pagination || 5;
|
|
8863
|
+
let startIndex = 0;
|
|
8864
|
+
if (filters.lastDoc && typeof filters.lastDoc === "object" && filters.lastDoc.id) {
|
|
8865
|
+
const idx = clinics.findIndex((c) => c.id === filters.lastDoc.id);
|
|
8866
|
+
if (idx >= 0) startIndex = idx + 1;
|
|
8867
|
+
}
|
|
8868
|
+
const page = clinics.slice(startIndex, startIndex + pageSize);
|
|
8869
|
+
const newLastDoc = page.length === pageSize ? page[page.length - 1] : null;
|
|
8870
|
+
console.log(
|
|
8871
|
+
`[CLINIC_SERVICE] Strategy 0 success: ${page.length} clinics (of ${clinics.length})`
|
|
8872
|
+
);
|
|
8873
|
+
return { clinics: page, lastDoc: newLastDoc };
|
|
8874
|
+
} catch (geoErr) {
|
|
8875
|
+
console.log("[CLINIC_SERVICE] Strategy 0 failed:", geoErr);
|
|
8876
|
+
}
|
|
8877
|
+
}
|
|
8829
8878
|
const getBaseConstraints = () => {
|
|
8830
|
-
var
|
|
8879
|
+
var _a2;
|
|
8831
8880
|
const constraints = [];
|
|
8832
|
-
constraints.push(where15("isActive", "==", (
|
|
8881
|
+
constraints.push(where15("isActive", "==", (_a2 = filters.isActive) != null ? _a2 : true));
|
|
8833
8882
|
if (filters.tags && filters.tags.length > 0) {
|
|
8834
8883
|
constraints.push(where15("tags", "array-contains", filters.tags[0]));
|
|
8835
8884
|
}
|
|
@@ -8906,7 +8955,9 @@ async function getClinicsByFilters(db, filters) {
|
|
|
8906
8955
|
}
|
|
8907
8956
|
}
|
|
8908
8957
|
try {
|
|
8909
|
-
console.log(
|
|
8958
|
+
console.log(
|
|
8959
|
+
"[CLINIC_SERVICE] Strategy 3: Using createdAt ordering with client-side filtering"
|
|
8960
|
+
);
|
|
8910
8961
|
const constraints = getBaseConstraints();
|
|
8911
8962
|
constraints.push(orderBy5("createdAt", "desc"));
|
|
8912
8963
|
if (filters.lastDoc) {
|
|
@@ -8961,20 +9012,24 @@ async function getClinicsByFilters(db, filters) {
|
|
|
8961
9012
|
}
|
|
8962
9013
|
function applyInMemoryFilters(clinics, filters) {
|
|
8963
9014
|
let filteredClinics = [...clinics];
|
|
8964
|
-
console.log(
|
|
9015
|
+
console.log(
|
|
9016
|
+
`[CLINIC_SERVICE] Applying in-memory filters - input: ${filteredClinics.length} clinics`
|
|
9017
|
+
);
|
|
8965
9018
|
if (filters.tags && filters.tags.length > 1) {
|
|
8966
9019
|
const initialCount = filteredClinics.length;
|
|
8967
9020
|
filteredClinics = filteredClinics.filter(
|
|
8968
9021
|
(clinic) => filters.tags.every((tag) => clinic.tags.includes(tag))
|
|
8969
9022
|
);
|
|
8970
|
-
console.log(
|
|
9023
|
+
console.log(
|
|
9024
|
+
`[CLINIC_SERVICE] Applied multi-tag filter: ${initialCount} \u2192 ${filteredClinics.length}`
|
|
9025
|
+
);
|
|
8971
9026
|
}
|
|
8972
9027
|
if (filters.tags && filters.tags.length === 1) {
|
|
8973
9028
|
const initialCount = filteredClinics.length;
|
|
8974
|
-
filteredClinics = filteredClinics.filter(
|
|
8975
|
-
|
|
9029
|
+
filteredClinics = filteredClinics.filter((clinic) => clinic.tags.includes(filters.tags[0]));
|
|
9030
|
+
console.log(
|
|
9031
|
+
`[CLINIC_SERVICE] Applied single-tag filter: ${initialCount} \u2192 ${filteredClinics.length}`
|
|
8976
9032
|
);
|
|
8977
|
-
console.log(`[CLINIC_SERVICE] Applied single-tag filter: ${initialCount} \u2192 ${filteredClinics.length}`);
|
|
8978
9033
|
}
|
|
8979
9034
|
if (filters.minRating !== void 0 || filters.maxRating !== void 0) {
|
|
8980
9035
|
const initialCount = filteredClinics.length;
|
|
@@ -8985,7 +9040,9 @@ function applyInMemoryFilters(clinics, filters) {
|
|
|
8985
9040
|
if (filters.maxRating !== void 0 && rating > filters.maxRating) return false;
|
|
8986
9041
|
return true;
|
|
8987
9042
|
});
|
|
8988
|
-
console.log(
|
|
9043
|
+
console.log(
|
|
9044
|
+
`[CLINIC_SERVICE] Applied rating filter (${filters.minRating}-${filters.maxRating}): ${initialCount} \u2192 ${filteredClinics.length}`
|
|
9045
|
+
);
|
|
8989
9046
|
}
|
|
8990
9047
|
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
8991
9048
|
const initialCount = filteredClinics.length;
|
|
@@ -8995,7 +9052,9 @@ function applyInMemoryFilters(clinics, filters) {
|
|
|
8995
9052
|
const nameLower = clinic.nameLower || "";
|
|
8996
9053
|
return name.includes(searchTerm) || nameLower.includes(searchTerm);
|
|
8997
9054
|
});
|
|
8998
|
-
console.log(
|
|
9055
|
+
console.log(
|
|
9056
|
+
`[CLINIC_SERVICE] Applied name search filter: ${initialCount} \u2192 ${filteredClinics.length}`
|
|
9057
|
+
);
|
|
8999
9058
|
}
|
|
9000
9059
|
if (filters.procedureFamily) {
|
|
9001
9060
|
const initialCount = filteredClinics.length;
|
|
@@ -9003,7 +9062,9 @@ function applyInMemoryFilters(clinics, filters) {
|
|
|
9003
9062
|
const proceduresInfo = clinic.proceduresInfo || [];
|
|
9004
9063
|
return proceduresInfo.some((proc) => proc.family === filters.procedureFamily);
|
|
9005
9064
|
});
|
|
9006
|
-
console.log(
|
|
9065
|
+
console.log(
|
|
9066
|
+
`[CLINIC_SERVICE] Applied procedure family filter: ${initialCount} \u2192 ${filteredClinics.length}`
|
|
9067
|
+
);
|
|
9007
9068
|
}
|
|
9008
9069
|
if (filters.procedureCategory) {
|
|
9009
9070
|
const initialCount = filteredClinics.length;
|
|
@@ -9011,7 +9072,9 @@ function applyInMemoryFilters(clinics, filters) {
|
|
|
9011
9072
|
const proceduresInfo = clinic.proceduresInfo || [];
|
|
9012
9073
|
return proceduresInfo.some((proc) => proc.categoryName === filters.procedureCategory);
|
|
9013
9074
|
});
|
|
9014
|
-
console.log(
|
|
9075
|
+
console.log(
|
|
9076
|
+
`[CLINIC_SERVICE] Applied procedure category filter: ${initialCount} \u2192 ${filteredClinics.length}`
|
|
9077
|
+
);
|
|
9015
9078
|
}
|
|
9016
9079
|
if (filters.procedureSubcategory) {
|
|
9017
9080
|
const initialCount = filteredClinics.length;
|
|
@@ -9019,7 +9082,9 @@ function applyInMemoryFilters(clinics, filters) {
|
|
|
9019
9082
|
const proceduresInfo = clinic.proceduresInfo || [];
|
|
9020
9083
|
return proceduresInfo.some((proc) => proc.subcategoryName === filters.procedureSubcategory);
|
|
9021
9084
|
});
|
|
9022
|
-
console.log(
|
|
9085
|
+
console.log(
|
|
9086
|
+
`[CLINIC_SERVICE] Applied procedure subcategory filter: ${initialCount} \u2192 ${filteredClinics.length}`
|
|
9087
|
+
);
|
|
9023
9088
|
}
|
|
9024
9089
|
if (filters.procedureTechnology) {
|
|
9025
9090
|
const initialCount = filteredClinics.length;
|
|
@@ -9027,7 +9092,9 @@ function applyInMemoryFilters(clinics, filters) {
|
|
|
9027
9092
|
const proceduresInfo = clinic.proceduresInfo || [];
|
|
9028
9093
|
return proceduresInfo.some((proc) => proc.technologyName === filters.procedureTechnology);
|
|
9029
9094
|
});
|
|
9030
|
-
console.log(
|
|
9095
|
+
console.log(
|
|
9096
|
+
`[CLINIC_SERVICE] Applied procedure technology filter: ${initialCount} \u2192 ${filteredClinics.length}`
|
|
9097
|
+
);
|
|
9031
9098
|
}
|
|
9032
9099
|
if (filters.center && filters.radiusInKm) {
|
|
9033
9100
|
const initialCount = filteredClinics.length;
|
|
@@ -9041,11 +9108,15 @@ function applyInMemoryFilters(clinics, filters) {
|
|
|
9041
9108
|
[filters.center.latitude, filters.center.longitude],
|
|
9042
9109
|
[clinic.location.latitude, clinic.location.longitude]
|
|
9043
9110
|
) / 1e3;
|
|
9044
|
-
console.log(
|
|
9111
|
+
console.log(
|
|
9112
|
+
`[CLINIC_SERVICE] Clinic ${clinic.name}: distance ${distance.toFixed(2)}km (limit: ${filters.radiusInKm}km)`
|
|
9113
|
+
);
|
|
9045
9114
|
clinic.distance = distance;
|
|
9046
9115
|
return distance <= filters.radiusInKm;
|
|
9047
9116
|
});
|
|
9048
|
-
console.log(
|
|
9117
|
+
console.log(
|
|
9118
|
+
`[CLINIC_SERVICE] Applied geo filter (${filters.radiusInKm}km): ${initialCount} \u2192 ${filteredClinics.length}`
|
|
9119
|
+
);
|
|
9049
9120
|
filteredClinics.sort((a, b) => (a.distance || 0) - (b.distance || 0));
|
|
9050
9121
|
}
|
|
9051
9122
|
console.log(`[CLINIC_SERVICE] Final filtered result: ${filteredClinics.length} clinics`);
|
|
@@ -9059,6 +9130,27 @@ var ClinicService = class extends BaseService {
|
|
|
9059
9130
|
this.clinicAdminService = clinicAdminService;
|
|
9060
9131
|
this.clinicGroupService = clinicGroupService;
|
|
9061
9132
|
this.mediaService = mediaService;
|
|
9133
|
+
this.functions = getFunctions2(app);
|
|
9134
|
+
}
|
|
9135
|
+
/**
|
|
9136
|
+
* Get timezone from coordinates using the callable function
|
|
9137
|
+
* @param lat Latitude
|
|
9138
|
+
* @param lng Longitude
|
|
9139
|
+
* @returns IANA timezone string
|
|
9140
|
+
*/
|
|
9141
|
+
async getTimezone(lat, lng) {
|
|
9142
|
+
try {
|
|
9143
|
+
const getTimezoneFromCoordinates = httpsCallable2(
|
|
9144
|
+
this.functions,
|
|
9145
|
+
"getTimezoneFromCoordinates"
|
|
9146
|
+
);
|
|
9147
|
+
const result = await getTimezoneFromCoordinates({ lat, lng });
|
|
9148
|
+
const data = result.data;
|
|
9149
|
+
return data.timezone;
|
|
9150
|
+
} catch (error) {
|
|
9151
|
+
console.error("Error getting timezone:", error);
|
|
9152
|
+
return null;
|
|
9153
|
+
}
|
|
9062
9154
|
}
|
|
9063
9155
|
/**
|
|
9064
9156
|
* Process media resource (string URL or File object)
|
|
@@ -9171,6 +9263,7 @@ var ClinicService = class extends BaseService {
|
|
|
9171
9263
|
);
|
|
9172
9264
|
const location = validatedData.location;
|
|
9173
9265
|
const hash = geohashForLocation4([location.latitude, location.longitude]);
|
|
9266
|
+
const tz = await this.getTimezone(location.latitude, location.longitude);
|
|
9174
9267
|
const defaultReviewInfo = {
|
|
9175
9268
|
totalReviews: 0,
|
|
9176
9269
|
averageRating: 0,
|
|
@@ -9188,7 +9281,7 @@ var ClinicService = class extends BaseService {
|
|
|
9188
9281
|
nameLower: validatedData.name.toLowerCase(),
|
|
9189
9282
|
// Add this line
|
|
9190
9283
|
description: validatedData.description,
|
|
9191
|
-
location: { ...location, geohash: hash },
|
|
9284
|
+
location: { ...location, geohash: hash, tz },
|
|
9192
9285
|
contactInfo: validatedData.contactInfo,
|
|
9193
9286
|
workingHours: validatedData.workingHours,
|
|
9194
9287
|
tags: validatedData.tags,
|
|
@@ -9292,9 +9385,11 @@ var ClinicService = class extends BaseService {
|
|
|
9292
9385
|
}
|
|
9293
9386
|
if (validatedData.location) {
|
|
9294
9387
|
const loc = validatedData.location;
|
|
9388
|
+
const tz = await this.getTimezone(loc.latitude, loc.longitude);
|
|
9295
9389
|
updatePayload.location = {
|
|
9296
9390
|
...loc,
|
|
9297
|
-
geohash: geohashForLocation4([loc.latitude, loc.longitude])
|
|
9391
|
+
geohash: geohashForLocation4([loc.latitude, loc.longitude]),
|
|
9392
|
+
tz
|
|
9298
9393
|
};
|
|
9299
9394
|
}
|
|
9300
9395
|
updatePayload.updatedAt = serverTimestamp14();
|
|
@@ -14816,7 +14911,8 @@ import {
|
|
|
14816
14911
|
import { z as z24 } from "zod";
|
|
14817
14912
|
var createProcedureSchema = z24.object({
|
|
14818
14913
|
name: z24.string().min(1).max(200),
|
|
14819
|
-
|
|
14914
|
+
// Optional: service will derive from name if not provided by client
|
|
14915
|
+
nameLower: z24.string().min(1).max(200).optional(),
|
|
14820
14916
|
description: z24.string().min(1).max(2e3),
|
|
14821
14917
|
family: z24.nativeEnum(ProcedureFamily),
|
|
14822
14918
|
categoryId: z24.string().min(1),
|
|
@@ -14886,7 +14982,7 @@ var procedureSchema = createProcedureSchema.extend({
|
|
|
14886
14982
|
});
|
|
14887
14983
|
|
|
14888
14984
|
// src/services/procedure/procedure.service.ts
|
|
14889
|
-
import { distanceBetween as distanceBetween6 } from "geofire-common";
|
|
14985
|
+
import { distanceBetween as distanceBetween6, geohashQueryBounds as geohashQueryBounds5 } from "geofire-common";
|
|
14890
14986
|
var ProcedureService = class extends BaseService {
|
|
14891
14987
|
constructor(db, auth, app, categoryService, subcategoryService, technologyService, productService, mediaService) {
|
|
14892
14988
|
super(db, auth, app);
|
|
@@ -14909,9 +15005,7 @@ var ProcedureService = class extends BaseService {
|
|
|
14909
15005
|
return media;
|
|
14910
15006
|
}
|
|
14911
15007
|
if (media instanceof File || media instanceof Blob) {
|
|
14912
|
-
console.log(
|
|
14913
|
-
`[ProcedureService] Uploading ${collectionName} media for ${ownerId}`
|
|
14914
|
-
);
|
|
15008
|
+
console.log(`[ProcedureService] Uploading ${collectionName} media for ${ownerId}`);
|
|
14915
15009
|
const metadata = await this.mediaService.uploadMedia(
|
|
14916
15010
|
media,
|
|
14917
15011
|
ownerId,
|
|
@@ -14933,11 +15027,7 @@ var ProcedureService = class extends BaseService {
|
|
|
14933
15027
|
if (!mediaArray || mediaArray.length === 0) return [];
|
|
14934
15028
|
const result = [];
|
|
14935
15029
|
for (const media of mediaArray) {
|
|
14936
|
-
const processedUrl = await this.processMedia(
|
|
14937
|
-
media,
|
|
14938
|
-
ownerId,
|
|
14939
|
-
collectionName
|
|
14940
|
-
);
|
|
15030
|
+
const processedUrl = await this.processMedia(media, ownerId, collectionName);
|
|
14941
15031
|
if (processedUrl) {
|
|
14942
15032
|
result.push(processedUrl);
|
|
14943
15033
|
}
|
|
@@ -14955,41 +15045,23 @@ var ProcedureService = class extends BaseService {
|
|
|
14955
15045
|
const procedureId = this.generateId();
|
|
14956
15046
|
const [category, subcategory, technology, product] = await Promise.all([
|
|
14957
15047
|
this.categoryService.getById(validatedData.categoryId),
|
|
14958
|
-
this.subcategoryService.getById(
|
|
14959
|
-
validatedData.categoryId,
|
|
14960
|
-
validatedData.subcategoryId
|
|
14961
|
-
),
|
|
15048
|
+
this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
|
|
14962
15049
|
this.technologyService.getById(validatedData.technologyId),
|
|
14963
|
-
this.productService.getById(
|
|
14964
|
-
validatedData.technologyId,
|
|
14965
|
-
validatedData.productId
|
|
14966
|
-
)
|
|
15050
|
+
this.productService.getById(validatedData.technologyId, validatedData.productId)
|
|
14967
15051
|
]);
|
|
14968
15052
|
if (!category || !subcategory || !technology || !product) {
|
|
14969
15053
|
throw new Error("One or more required base entities not found");
|
|
14970
15054
|
}
|
|
14971
|
-
const clinicRef = doc30(
|
|
14972
|
-
this.db,
|
|
14973
|
-
CLINICS_COLLECTION,
|
|
14974
|
-
validatedData.clinicBranchId
|
|
14975
|
-
);
|
|
15055
|
+
const clinicRef = doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId);
|
|
14976
15056
|
const clinicSnapshot = await getDoc32(clinicRef);
|
|
14977
15057
|
if (!clinicSnapshot.exists()) {
|
|
14978
|
-
throw new Error(
|
|
14979
|
-
`Clinic with ID ${validatedData.clinicBranchId} not found`
|
|
14980
|
-
);
|
|
15058
|
+
throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
|
|
14981
15059
|
}
|
|
14982
15060
|
const clinic = clinicSnapshot.data();
|
|
14983
|
-
const practitionerRef = doc30(
|
|
14984
|
-
this.db,
|
|
14985
|
-
PRACTITIONERS_COLLECTION,
|
|
14986
|
-
validatedData.practitionerId
|
|
14987
|
-
);
|
|
15061
|
+
const practitionerRef = doc30(this.db, PRACTITIONERS_COLLECTION, validatedData.practitionerId);
|
|
14988
15062
|
const practitionerSnapshot = await getDoc32(practitionerRef);
|
|
14989
15063
|
if (!practitionerSnapshot.exists()) {
|
|
14990
|
-
throw new Error(
|
|
14991
|
-
`Practitioner with ID ${validatedData.practitionerId} not found`
|
|
14992
|
-
);
|
|
15064
|
+
throw new Error(`Practitioner with ID ${validatedData.practitionerId} not found`);
|
|
14993
15065
|
}
|
|
14994
15066
|
const practitioner = practitionerSnapshot.data();
|
|
14995
15067
|
let processedPhotos = [];
|
|
@@ -15020,6 +15092,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15020
15092
|
const newProcedure = {
|
|
15021
15093
|
id: procedureId,
|
|
15022
15094
|
...validatedData,
|
|
15095
|
+
// Ensure nameLower is always set even if omitted by client
|
|
15023
15096
|
nameLower: validatedData.nameLower || validatedData.name.toLowerCase(),
|
|
15024
15097
|
photos: processedPhotos,
|
|
15025
15098
|
category,
|
|
@@ -15078,24 +15151,16 @@ var ProcedureService = class extends BaseService {
|
|
|
15078
15151
|
const validatedData = createProcedureSchema.parse(validationData);
|
|
15079
15152
|
const [category, subcategory, technology, product, clinicSnapshot] = await Promise.all([
|
|
15080
15153
|
this.categoryService.getById(validatedData.categoryId),
|
|
15081
|
-
this.subcategoryService.getById(
|
|
15082
|
-
validatedData.categoryId,
|
|
15083
|
-
validatedData.subcategoryId
|
|
15084
|
-
),
|
|
15154
|
+
this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
|
|
15085
15155
|
this.technologyService.getById(validatedData.technologyId),
|
|
15086
|
-
this.productService.getById(
|
|
15087
|
-
validatedData.technologyId,
|
|
15088
|
-
validatedData.productId
|
|
15089
|
-
),
|
|
15156
|
+
this.productService.getById(validatedData.technologyId, validatedData.productId),
|
|
15090
15157
|
getDoc32(doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId))
|
|
15091
15158
|
]);
|
|
15092
15159
|
if (!category || !subcategory || !technology || !product) {
|
|
15093
15160
|
throw new Error("One or more required base entities not found");
|
|
15094
15161
|
}
|
|
15095
15162
|
if (!clinicSnapshot.exists()) {
|
|
15096
|
-
throw new Error(
|
|
15097
|
-
`Clinic with ID ${validatedData.clinicBranchId} not found`
|
|
15098
|
-
);
|
|
15163
|
+
throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
|
|
15099
15164
|
}
|
|
15100
15165
|
const clinic = clinicSnapshot.data();
|
|
15101
15166
|
let processedPhotos = [];
|
|
@@ -15121,12 +15186,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15121
15186
|
}
|
|
15122
15187
|
if (practitionersMap.size !== practitionerIds.length) {
|
|
15123
15188
|
const foundIds = Array.from(practitionersMap.keys());
|
|
15124
|
-
const notFoundIds = practitionerIds.filter(
|
|
15125
|
-
|
|
15126
|
-
);
|
|
15127
|
-
throw new Error(
|
|
15128
|
-
`The following practitioners were not found: ${notFoundIds.join(", ")}`
|
|
15129
|
-
);
|
|
15189
|
+
const notFoundIds = practitionerIds.filter((id) => !foundIds.includes(id));
|
|
15190
|
+
throw new Error(`The following practitioners were not found: ${notFoundIds.join(", ")}`);
|
|
15130
15191
|
}
|
|
15131
15192
|
const batch = writeBatch6(this.db);
|
|
15132
15193
|
const createdProcedureIds = [];
|
|
@@ -15194,10 +15255,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15194
15255
|
const fetchedProcedures = [];
|
|
15195
15256
|
for (let i = 0; i < createdProcedureIds.length; i += 30) {
|
|
15196
15257
|
const chunk = createdProcedureIds.slice(i, i + 30);
|
|
15197
|
-
const q = query29(
|
|
15198
|
-
collection29(this.db, PROCEDURES_COLLECTION),
|
|
15199
|
-
where29(documentId2(), "in", chunk)
|
|
15200
|
-
);
|
|
15258
|
+
const q = query29(collection29(this.db, PROCEDURES_COLLECTION), where29(documentId2(), "in", chunk));
|
|
15201
15259
|
const snapshot = await getDocs29(q);
|
|
15202
15260
|
snapshot.forEach((doc37) => {
|
|
15203
15261
|
fetchedProcedures.push(doc37.data());
|
|
@@ -15298,9 +15356,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15298
15356
|
);
|
|
15299
15357
|
const newPractitionerSnap = await getDoc32(newPractitionerRef);
|
|
15300
15358
|
if (!newPractitionerSnap.exists())
|
|
15301
|
-
throw new Error(
|
|
15302
|
-
`New Practitioner ${validatedData.practitionerId} not found`
|
|
15303
|
-
);
|
|
15359
|
+
throw new Error(`New Practitioner ${validatedData.practitionerId} not found`);
|
|
15304
15360
|
newPractitioner = newPractitionerSnap.data();
|
|
15305
15361
|
updatedProcedureData.doctorInfo = {
|
|
15306
15362
|
id: newPractitioner.id,
|
|
@@ -15314,11 +15370,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15314
15370
|
}
|
|
15315
15371
|
if (validatedData.clinicBranchId && validatedData.clinicBranchId !== oldClinicId) {
|
|
15316
15372
|
clinicChanged = true;
|
|
15317
|
-
const newClinicRef = doc30(
|
|
15318
|
-
this.db,
|
|
15319
|
-
CLINICS_COLLECTION,
|
|
15320
|
-
validatedData.clinicBranchId
|
|
15321
|
-
);
|
|
15373
|
+
const newClinicRef = doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId);
|
|
15322
15374
|
const newClinicSnap = await getDoc32(newClinicRef);
|
|
15323
15375
|
if (!newClinicSnap.exists())
|
|
15324
15376
|
throw new Error(`New Clinic ${validatedData.clinicBranchId} not found`);
|
|
@@ -15337,11 +15389,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15337
15389
|
updatedProcedureData.nameLower = validatedData.name.toLowerCase();
|
|
15338
15390
|
}
|
|
15339
15391
|
if (validatedData.categoryId) {
|
|
15340
|
-
const category = await this.categoryService.getById(
|
|
15341
|
-
|
|
15342
|
-
);
|
|
15343
|
-
if (!category)
|
|
15344
|
-
throw new Error(`Category ${validatedData.categoryId} not found`);
|
|
15392
|
+
const category = await this.categoryService.getById(validatedData.categoryId);
|
|
15393
|
+
if (!category) throw new Error(`Category ${validatedData.categoryId} not found`);
|
|
15345
15394
|
updatedProcedureData.category = category;
|
|
15346
15395
|
finalCategoryId = category.id;
|
|
15347
15396
|
}
|
|
@@ -15356,17 +15405,12 @@ var ProcedureService = class extends BaseService {
|
|
|
15356
15405
|
);
|
|
15357
15406
|
updatedProcedureData.subcategory = subcategory;
|
|
15358
15407
|
} else if (validatedData.subcategoryId) {
|
|
15359
|
-
console.warn(
|
|
15360
|
-
"Attempted to update subcategory without a valid categoryId"
|
|
15361
|
-
);
|
|
15408
|
+
console.warn("Attempted to update subcategory without a valid categoryId");
|
|
15362
15409
|
}
|
|
15363
15410
|
let finalTechnologyId = existingProcedure.technology.id;
|
|
15364
15411
|
if (validatedData.technologyId) {
|
|
15365
|
-
const technology = await this.technologyService.getById(
|
|
15366
|
-
|
|
15367
|
-
);
|
|
15368
|
-
if (!technology)
|
|
15369
|
-
throw new Error(`Technology ${validatedData.technologyId} not found`);
|
|
15412
|
+
const technology = await this.technologyService.getById(validatedData.technologyId);
|
|
15413
|
+
if (!technology) throw new Error(`Technology ${validatedData.technologyId} not found`);
|
|
15370
15414
|
updatedProcedureData.technology = technology;
|
|
15371
15415
|
finalTechnologyId = technology.id;
|
|
15372
15416
|
updatedProcedureData.blockingConditions = technology.blockingConditions;
|
|
@@ -15377,10 +15421,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15377
15421
|
updatedProcedureData.documentationTemplates = technology.documentationTemplates || [];
|
|
15378
15422
|
}
|
|
15379
15423
|
if (validatedData.productId && finalTechnologyId) {
|
|
15380
|
-
const product = await this.productService.getById(
|
|
15381
|
-
finalTechnologyId,
|
|
15382
|
-
validatedData.productId
|
|
15383
|
-
);
|
|
15424
|
+
const product = await this.productService.getById(finalTechnologyId, validatedData.productId);
|
|
15384
15425
|
if (!product)
|
|
15385
15426
|
throw new Error(
|
|
15386
15427
|
`Product ${validatedData.productId} not found for technology ${finalTechnologyId}`
|
|
@@ -15462,11 +15503,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15462
15503
|
limit16(pagination)
|
|
15463
15504
|
);
|
|
15464
15505
|
} else {
|
|
15465
|
-
proceduresQuery = query29(
|
|
15466
|
-
proceduresCollection,
|
|
15467
|
-
orderBy17("name"),
|
|
15468
|
-
limit16(pagination)
|
|
15469
|
-
);
|
|
15506
|
+
proceduresQuery = query29(proceduresCollection, orderBy17("name"), limit16(pagination));
|
|
15470
15507
|
}
|
|
15471
15508
|
} else {
|
|
15472
15509
|
proceduresQuery = query29(proceduresCollection, orderBy17("name"));
|
|
@@ -15589,7 +15626,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15589
15626
|
constraints.push(limit15(filters.pagination || 10));
|
|
15590
15627
|
const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15591
15628
|
const querySnapshot = await getDocs29(q);
|
|
15592
|
-
const procedures = querySnapshot.docs.map(
|
|
15629
|
+
const procedures = querySnapshot.docs.map(
|
|
15630
|
+
(doc37) => ({ ...doc37.data(), id: doc37.id })
|
|
15631
|
+
);
|
|
15593
15632
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15594
15633
|
console.log(`[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`);
|
|
15595
15634
|
if (procedures.length < (filters.pagination || 10)) {
|
|
@@ -15620,7 +15659,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15620
15659
|
constraints.push(limit15(filters.pagination || 10));
|
|
15621
15660
|
const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15622
15661
|
const querySnapshot = await getDocs29(q);
|
|
15623
|
-
const procedures = querySnapshot.docs.map(
|
|
15662
|
+
const procedures = querySnapshot.docs.map(
|
|
15663
|
+
(doc37) => ({ ...doc37.data(), id: doc37.id })
|
|
15664
|
+
);
|
|
15624
15665
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15625
15666
|
console.log(`[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`);
|
|
15626
15667
|
if (procedures.length < (filters.pagination || 10)) {
|
|
@@ -15632,7 +15673,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15632
15673
|
}
|
|
15633
15674
|
}
|
|
15634
15675
|
try {
|
|
15635
|
-
console.log(
|
|
15676
|
+
console.log(
|
|
15677
|
+
"[PROCEDURE_SERVICE] Strategy 3: Using createdAt orderBy with client-side filtering"
|
|
15678
|
+
);
|
|
15636
15679
|
const constraints = getBaseConstraints();
|
|
15637
15680
|
constraints.push(orderBy17("createdAt", "desc"));
|
|
15638
15681
|
if (filters.lastDoc) {
|
|
@@ -15647,7 +15690,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15647
15690
|
constraints.push(limit15(filters.pagination || 10));
|
|
15648
15691
|
const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15649
15692
|
const querySnapshot = await getDocs29(q);
|
|
15650
|
-
let procedures = querySnapshot.docs.map(
|
|
15693
|
+
let procedures = querySnapshot.docs.map(
|
|
15694
|
+
(doc37) => ({ ...doc37.data(), id: doc37.id })
|
|
15695
|
+
);
|
|
15651
15696
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15652
15697
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15653
15698
|
console.log(`[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`);
|
|
@@ -15667,7 +15712,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15667
15712
|
];
|
|
15668
15713
|
const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15669
15714
|
const querySnapshot = await getDocs29(q);
|
|
15670
|
-
let procedures = querySnapshot.docs.map(
|
|
15715
|
+
let procedures = querySnapshot.docs.map(
|
|
15716
|
+
(doc37) => ({ ...doc37.data(), id: doc37.id })
|
|
15717
|
+
);
|
|
15671
15718
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15672
15719
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15673
15720
|
console.log(`[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`);
|
|
@@ -15707,7 +15754,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15707
15754
|
if (filters.maxPrice !== void 0 && price > filters.maxPrice) return false;
|
|
15708
15755
|
return true;
|
|
15709
15756
|
});
|
|
15710
|
-
console.log(
|
|
15757
|
+
console.log(
|
|
15758
|
+
`[PROCEDURE_SERVICE] Applied price filter (${filters.minPrice}-${filters.maxPrice}), results: ${filteredProcedures.length}`
|
|
15759
|
+
);
|
|
15711
15760
|
}
|
|
15712
15761
|
if (filters.minRating !== void 0 || filters.maxRating !== void 0) {
|
|
15713
15762
|
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
@@ -15717,7 +15766,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15717
15766
|
if (filters.maxRating !== void 0 && rating > filters.maxRating) return false;
|
|
15718
15767
|
return true;
|
|
15719
15768
|
});
|
|
15720
|
-
console.log(
|
|
15769
|
+
console.log(
|
|
15770
|
+
`[PROCEDURE_SERVICE] Applied rating filter, results: ${filteredProcedures.length}`
|
|
15771
|
+
);
|
|
15721
15772
|
}
|
|
15722
15773
|
if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
|
|
15723
15774
|
const benefitsToMatch = filters.treatmentBenefits;
|
|
@@ -15725,32 +15776,50 @@ var ProcedureService = class extends BaseService {
|
|
|
15725
15776
|
const procedureBenefits = procedure.treatmentBenefits || [];
|
|
15726
15777
|
return benefitsToMatch.some((benefit) => procedureBenefits.includes(benefit));
|
|
15727
15778
|
});
|
|
15728
|
-
console.log(
|
|
15779
|
+
console.log(
|
|
15780
|
+
`[PROCEDURE_SERVICE] Applied benefits filter, results: ${filteredProcedures.length}`
|
|
15781
|
+
);
|
|
15729
15782
|
}
|
|
15730
15783
|
if (filters.procedureFamily) {
|
|
15731
|
-
filteredProcedures = filteredProcedures.filter(
|
|
15732
|
-
|
|
15784
|
+
filteredProcedures = filteredProcedures.filter(
|
|
15785
|
+
(procedure) => procedure.family === filters.procedureFamily
|
|
15786
|
+
);
|
|
15787
|
+
console.log(
|
|
15788
|
+
`[PROCEDURE_SERVICE] Applied family filter, results: ${filteredProcedures.length}`
|
|
15789
|
+
);
|
|
15733
15790
|
}
|
|
15734
15791
|
if (filters.procedureCategory) {
|
|
15735
|
-
filteredProcedures = filteredProcedures.filter(
|
|
15736
|
-
|
|
15737
|
-
|
|
15738
|
-
|
|
15739
|
-
|
|
15792
|
+
filteredProcedures = filteredProcedures.filter(
|
|
15793
|
+
(procedure) => {
|
|
15794
|
+
var _a;
|
|
15795
|
+
return ((_a = procedure.category) == null ? void 0 : _a.id) === filters.procedureCategory;
|
|
15796
|
+
}
|
|
15797
|
+
);
|
|
15798
|
+
console.log(
|
|
15799
|
+
`[PROCEDURE_SERVICE] Applied category filter, results: ${filteredProcedures.length}`
|
|
15800
|
+
);
|
|
15740
15801
|
}
|
|
15741
15802
|
if (filters.procedureSubcategory) {
|
|
15742
|
-
filteredProcedures = filteredProcedures.filter(
|
|
15743
|
-
|
|
15744
|
-
|
|
15745
|
-
|
|
15746
|
-
|
|
15803
|
+
filteredProcedures = filteredProcedures.filter(
|
|
15804
|
+
(procedure) => {
|
|
15805
|
+
var _a;
|
|
15806
|
+
return ((_a = procedure.subcategory) == null ? void 0 : _a.id) === filters.procedureSubcategory;
|
|
15807
|
+
}
|
|
15808
|
+
);
|
|
15809
|
+
console.log(
|
|
15810
|
+
`[PROCEDURE_SERVICE] Applied subcategory filter, results: ${filteredProcedures.length}`
|
|
15811
|
+
);
|
|
15747
15812
|
}
|
|
15748
15813
|
if (filters.procedureTechnology) {
|
|
15749
|
-
filteredProcedures = filteredProcedures.filter(
|
|
15750
|
-
|
|
15751
|
-
|
|
15752
|
-
|
|
15753
|
-
|
|
15814
|
+
filteredProcedures = filteredProcedures.filter(
|
|
15815
|
+
(procedure) => {
|
|
15816
|
+
var _a;
|
|
15817
|
+
return ((_a = procedure.technology) == null ? void 0 : _a.id) === filters.procedureTechnology;
|
|
15818
|
+
}
|
|
15819
|
+
);
|
|
15820
|
+
console.log(
|
|
15821
|
+
`[PROCEDURE_SERVICE] Applied technology filter, results: ${filteredProcedures.length}`
|
|
15822
|
+
);
|
|
15754
15823
|
}
|
|
15755
15824
|
if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
|
|
15756
15825
|
const location = filters.location;
|
|
@@ -15774,29 +15843,48 @@ var ProcedureService = class extends BaseService {
|
|
|
15774
15843
|
return filteredProcedures;
|
|
15775
15844
|
}
|
|
15776
15845
|
handleGeoQuery(filters) {
|
|
15777
|
-
console.log("[PROCEDURE_SERVICE] Executing geo query with
|
|
15846
|
+
console.log("[PROCEDURE_SERVICE] Executing geo query with geohash bounds");
|
|
15778
15847
|
try {
|
|
15779
15848
|
const location = filters.location;
|
|
15780
15849
|
const radiusInKm = filters.radiusInKm;
|
|
15781
|
-
|
|
15782
|
-
|
|
15783
|
-
|
|
15784
|
-
|
|
15785
|
-
|
|
15850
|
+
if (!location || !radiusInKm) {
|
|
15851
|
+
return Promise.resolve({ procedures: [], lastDoc: null });
|
|
15852
|
+
}
|
|
15853
|
+
const bounds = geohashQueryBounds5([location.latitude, location.longitude], radiusInKm * 1e3);
|
|
15854
|
+
const fetches = bounds.map((b) => {
|
|
15855
|
+
const constraints = [
|
|
15856
|
+
where29("clinicInfo.location.geohash", ">=", b[0]),
|
|
15857
|
+
where29("clinicInfo.location.geohash", "<=", b[1]),
|
|
15858
|
+
where29("isActive", "==", filters.isActive !== void 0 ? filters.isActive : true)
|
|
15859
|
+
];
|
|
15860
|
+
return getDocs29(query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints));
|
|
15786
15861
|
});
|
|
15787
|
-
|
|
15788
|
-
|
|
15789
|
-
|
|
15790
|
-
|
|
15791
|
-
|
|
15792
|
-
|
|
15793
|
-
|
|
15794
|
-
|
|
15795
|
-
|
|
15862
|
+
return Promise.all(fetches).then((snaps) => {
|
|
15863
|
+
const collected = [];
|
|
15864
|
+
snaps.forEach((snap) => {
|
|
15865
|
+
snap.docs.forEach((d) => collected.push({ ...d.data(), id: d.id }));
|
|
15866
|
+
});
|
|
15867
|
+
const uniqueMap = /* @__PURE__ */ new Map();
|
|
15868
|
+
for (const p of collected) {
|
|
15869
|
+
uniqueMap.set(p.id, p);
|
|
15870
|
+
}
|
|
15871
|
+
let procedures = Array.from(uniqueMap.values());
|
|
15796
15872
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15797
|
-
|
|
15798
|
-
|
|
15799
|
-
|
|
15873
|
+
const pageSize = filters.pagination || 10;
|
|
15874
|
+
let startIndex = 0;
|
|
15875
|
+
if (filters.lastDoc && typeof filters.lastDoc === "object" && filters.lastDoc.id) {
|
|
15876
|
+
const idx = procedures.findIndex((p) => p.id === filters.lastDoc.id);
|
|
15877
|
+
if (idx >= 0) startIndex = idx + 1;
|
|
15878
|
+
}
|
|
15879
|
+
const page = procedures.slice(startIndex, startIndex + pageSize);
|
|
15880
|
+
const newLastDoc = page.length === pageSize ? page[page.length - 1] : null;
|
|
15881
|
+
console.log(
|
|
15882
|
+
`[PROCEDURE_SERVICE] Geo query success: ${page.length} (of ${procedures.length}) within ${radiusInKm}km`
|
|
15883
|
+
);
|
|
15884
|
+
return { procedures: page, lastDoc: newLastDoc };
|
|
15885
|
+
}).catch((err) => {
|
|
15886
|
+
console.error("[PROCEDURE_SERVICE] Geo bounds fetch failed:", err);
|
|
15887
|
+
return { procedures: [], lastDoc: null };
|
|
15800
15888
|
});
|
|
15801
15889
|
} catch (error) {
|
|
15802
15890
|
console.error("[PROCEDURE_SERVICE] Geo query failed:", error);
|
|
@@ -15826,11 +15914,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15826
15914
|
throw new Error(`Clinic with ID ${data.clinicBranchId} not found`);
|
|
15827
15915
|
}
|
|
15828
15916
|
const clinic = clinicSnapshot.data();
|
|
15829
|
-
const practitionerRef = doc30(
|
|
15830
|
-
this.db,
|
|
15831
|
-
PRACTITIONERS_COLLECTION,
|
|
15832
|
-
data.practitionerId
|
|
15833
|
-
);
|
|
15917
|
+
const practitionerRef = doc30(this.db, PRACTITIONERS_COLLECTION, data.practitionerId);
|
|
15834
15918
|
const practitionerSnapshot = await getDoc32(practitionerRef);
|
|
15835
15919
|
if (!practitionerSnapshot.exists()) {
|
|
15836
15920
|
throw new Error(`Practitioner with ID ${data.practitionerId} not found`);
|
|
@@ -15838,11 +15922,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15838
15922
|
const practitioner = practitionerSnapshot.data();
|
|
15839
15923
|
let processedPhotos = [];
|
|
15840
15924
|
if (data.photos && data.photos.length > 0) {
|
|
15841
|
-
processedPhotos = await this.processMediaArray(
|
|
15842
|
-
data.photos,
|
|
15843
|
-
procedureId,
|
|
15844
|
-
"procedure-photos"
|
|
15845
|
-
);
|
|
15925
|
+
processedPhotos = await this.processMediaArray(data.photos, procedureId, "procedure-photos");
|
|
15846
15926
|
}
|
|
15847
15927
|
const clinicInfo = {
|
|
15848
15928
|
id: clinicSnapshot.id,
|
|
@@ -16156,7 +16236,7 @@ import { getAuth } from "firebase/auth";
|
|
|
16156
16236
|
import { getAnalytics } from "firebase/analytics";
|
|
16157
16237
|
import { Platform } from "react-native";
|
|
16158
16238
|
import { getStorage as getStorage3 } from "firebase/storage";
|
|
16159
|
-
import { getFunctions as
|
|
16239
|
+
import { getFunctions as getFunctions3 } from "firebase/functions";
|
|
16160
16240
|
var firebaseInstance = null;
|
|
16161
16241
|
var initializeFirebase = (config) => {
|
|
16162
16242
|
if (!firebaseInstance) {
|
|
@@ -16164,7 +16244,7 @@ var initializeFirebase = (config) => {
|
|
|
16164
16244
|
const db = getFirestore2(app);
|
|
16165
16245
|
const auth = getAuth(app);
|
|
16166
16246
|
const storage = getStorage3(app);
|
|
16167
|
-
const functions =
|
|
16247
|
+
const functions = getFunctions3(app);
|
|
16168
16248
|
let analytics = null;
|
|
16169
16249
|
if (typeof window !== "undefined" && Platform.OS === "web") {
|
|
16170
16250
|
analytics = getAnalytics(app);
|