@blackcode_sa/metaestetics-api 1.8.17 → 1.10.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/index.d.mts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +233 -205
- package/dist/index.mjs +236 -210
- package/package.json +1 -1
- package/src/services/clinic/clinic.service.ts +91 -142
- package/src/services/clinic/utils/filter.utils.ts +180 -96
- package/src/services/practitioner/practitioner.service.ts +31 -0
- package/src/services/procedure/procedure.service.ts +326 -362
package/dist/index.mjs
CHANGED
|
@@ -7010,6 +7010,27 @@ var PractitionerService = class extends BaseService {
|
|
|
7010
7010
|
} catch (error) {
|
|
7011
7011
|
console.log("[PRACTITIONER_SERVICE] Strategy 3 failed:", error);
|
|
7012
7012
|
}
|
|
7013
|
+
try {
|
|
7014
|
+
console.log("[PRACTITIONER_SERVICE] Strategy 4: Client-side filtering fallback");
|
|
7015
|
+
const constraints = [
|
|
7016
|
+
where10("isActive", "==", true),
|
|
7017
|
+
where10("status", "==", "active" /* ACTIVE */),
|
|
7018
|
+
orderBy4("createdAt", "desc"),
|
|
7019
|
+
limit7(filters.pagination || 10)
|
|
7020
|
+
];
|
|
7021
|
+
const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
|
|
7022
|
+
const querySnapshot = await getDocs10(q);
|
|
7023
|
+
let practitioners = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
|
|
7024
|
+
practitioners = this.applyInMemoryFilters(practitioners, filters);
|
|
7025
|
+
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
7026
|
+
console.log(`[PRACTITIONER_SERVICE] Strategy 4 success: ${practitioners.length} practitioners`);
|
|
7027
|
+
if (practitioners.length < (filters.pagination || 10)) {
|
|
7028
|
+
return { practitioners, lastDoc: null };
|
|
7029
|
+
}
|
|
7030
|
+
return { practitioners, lastDoc };
|
|
7031
|
+
} catch (error) {
|
|
7032
|
+
console.log("[PRACTITIONER_SERVICE] Strategy 4 failed:", error);
|
|
7033
|
+
}
|
|
7013
7034
|
console.log("[PRACTITIONER_SERVICE] All strategies failed, returning empty result");
|
|
7014
7035
|
return { practitioners: [], lastDoc: null };
|
|
7015
7036
|
} catch (error) {
|
|
@@ -8321,9 +8342,7 @@ import {
|
|
|
8321
8342
|
writeBatch as writeBatch4,
|
|
8322
8343
|
arrayUnion as arrayUnion7
|
|
8323
8344
|
} from "firebase/firestore";
|
|
8324
|
-
import {
|
|
8325
|
-
geohashForLocation as geohashForLocation4
|
|
8326
|
-
} from "geofire-common";
|
|
8345
|
+
import { geohashForLocation as geohashForLocation4 } from "geofire-common";
|
|
8327
8346
|
import { z as z20 } from "zod";
|
|
8328
8347
|
|
|
8329
8348
|
// src/services/clinic/utils/clinic.utils.ts
|
|
@@ -8789,8 +8808,9 @@ import {
|
|
|
8789
8808
|
limit as limit9,
|
|
8790
8809
|
orderBy as orderBy5
|
|
8791
8810
|
} from "firebase/firestore";
|
|
8792
|
-
import { distanceBetween as distanceBetween4 } from "geofire-common";
|
|
8811
|
+
import { geohashQueryBounds as geohashQueryBounds3, distanceBetween as distanceBetween4 } from "geofire-common";
|
|
8793
8812
|
async function getClinicsByFilters(db, filters) {
|
|
8813
|
+
var _a;
|
|
8794
8814
|
try {
|
|
8795
8815
|
console.log("[CLINIC_SERVICE] Starting clinic filtering with multiple strategies");
|
|
8796
8816
|
if (filters.center && filters.radiusInKm) {
|
|
@@ -8805,10 +8825,53 @@ async function getClinicsByFilters(db, filters) {
|
|
|
8805
8825
|
filters.radiusInKm = void 0;
|
|
8806
8826
|
}
|
|
8807
8827
|
}
|
|
8828
|
+
if (filters.center && filters.radiusInKm) {
|
|
8829
|
+
try {
|
|
8830
|
+
console.log("[CLINIC_SERVICE] Strategy 0: Geohash bounds prefilter");
|
|
8831
|
+
const bounds = geohashQueryBounds3(
|
|
8832
|
+
[filters.center.latitude, filters.center.longitude],
|
|
8833
|
+
(filters.radiusInKm || 0) * 1e3
|
|
8834
|
+
);
|
|
8835
|
+
const collected = [];
|
|
8836
|
+
for (const b of bounds) {
|
|
8837
|
+
const constraints = [
|
|
8838
|
+
where15("location.geohash", ">=", b[0]),
|
|
8839
|
+
where15("location.geohash", "<=", b[1]),
|
|
8840
|
+
where15("isActive", "==", (_a = filters.isActive) != null ? _a : true)
|
|
8841
|
+
];
|
|
8842
|
+
if (filters.tags && filters.tags.length > 0) {
|
|
8843
|
+
constraints.push(where15("tags", "array-contains", filters.tags[0]));
|
|
8844
|
+
}
|
|
8845
|
+
const q0 = query15(collection15(db, CLINICS_COLLECTION), ...constraints);
|
|
8846
|
+
const snap = await getDocs15(q0);
|
|
8847
|
+
snap.docs.forEach((d) => collected.push({ ...d.data(), id: d.id }));
|
|
8848
|
+
}
|
|
8849
|
+
const uniqueMap = /* @__PURE__ */ new Map();
|
|
8850
|
+
for (const c of collected) {
|
|
8851
|
+
uniqueMap.set(c.id, c);
|
|
8852
|
+
}
|
|
8853
|
+
let clinics = Array.from(uniqueMap.values());
|
|
8854
|
+
clinics = applyInMemoryFilters(clinics, filters);
|
|
8855
|
+
const pageSize = filters.pagination || 5;
|
|
8856
|
+
let startIndex = 0;
|
|
8857
|
+
if (filters.lastDoc && typeof filters.lastDoc === "object" && filters.lastDoc.id) {
|
|
8858
|
+
const idx = clinics.findIndex((c) => c.id === filters.lastDoc.id);
|
|
8859
|
+
if (idx >= 0) startIndex = idx + 1;
|
|
8860
|
+
}
|
|
8861
|
+
const page = clinics.slice(startIndex, startIndex + pageSize);
|
|
8862
|
+
const newLastDoc = page.length === pageSize ? page[page.length - 1] : null;
|
|
8863
|
+
console.log(
|
|
8864
|
+
`[CLINIC_SERVICE] Strategy 0 success: ${page.length} clinics (of ${clinics.length})`
|
|
8865
|
+
);
|
|
8866
|
+
return { clinics: page, lastDoc: newLastDoc };
|
|
8867
|
+
} catch (geoErr) {
|
|
8868
|
+
console.log("[CLINIC_SERVICE] Strategy 0 failed:", geoErr);
|
|
8869
|
+
}
|
|
8870
|
+
}
|
|
8808
8871
|
const getBaseConstraints = () => {
|
|
8809
|
-
var
|
|
8872
|
+
var _a2;
|
|
8810
8873
|
const constraints = [];
|
|
8811
|
-
constraints.push(where15("isActive", "==", (
|
|
8874
|
+
constraints.push(where15("isActive", "==", (_a2 = filters.isActive) != null ? _a2 : true));
|
|
8812
8875
|
if (filters.tags && filters.tags.length > 0) {
|
|
8813
8876
|
constraints.push(where15("tags", "array-contains", filters.tags[0]));
|
|
8814
8877
|
}
|
|
@@ -8885,7 +8948,9 @@ async function getClinicsByFilters(db, filters) {
|
|
|
8885
8948
|
}
|
|
8886
8949
|
}
|
|
8887
8950
|
try {
|
|
8888
|
-
console.log(
|
|
8951
|
+
console.log(
|
|
8952
|
+
"[CLINIC_SERVICE] Strategy 3: Using createdAt ordering with client-side filtering"
|
|
8953
|
+
);
|
|
8889
8954
|
const constraints = getBaseConstraints();
|
|
8890
8955
|
constraints.push(orderBy5("createdAt", "desc"));
|
|
8891
8956
|
if (filters.lastDoc) {
|
|
@@ -8940,20 +9005,24 @@ async function getClinicsByFilters(db, filters) {
|
|
|
8940
9005
|
}
|
|
8941
9006
|
function applyInMemoryFilters(clinics, filters) {
|
|
8942
9007
|
let filteredClinics = [...clinics];
|
|
8943
|
-
console.log(
|
|
9008
|
+
console.log(
|
|
9009
|
+
`[CLINIC_SERVICE] Applying in-memory filters - input: ${filteredClinics.length} clinics`
|
|
9010
|
+
);
|
|
8944
9011
|
if (filters.tags && filters.tags.length > 1) {
|
|
8945
9012
|
const initialCount = filteredClinics.length;
|
|
8946
9013
|
filteredClinics = filteredClinics.filter(
|
|
8947
9014
|
(clinic) => filters.tags.every((tag) => clinic.tags.includes(tag))
|
|
8948
9015
|
);
|
|
8949
|
-
console.log(
|
|
9016
|
+
console.log(
|
|
9017
|
+
`[CLINIC_SERVICE] Applied multi-tag filter: ${initialCount} \u2192 ${filteredClinics.length}`
|
|
9018
|
+
);
|
|
8950
9019
|
}
|
|
8951
9020
|
if (filters.tags && filters.tags.length === 1) {
|
|
8952
9021
|
const initialCount = filteredClinics.length;
|
|
8953
|
-
filteredClinics = filteredClinics.filter(
|
|
8954
|
-
|
|
9022
|
+
filteredClinics = filteredClinics.filter((clinic) => clinic.tags.includes(filters.tags[0]));
|
|
9023
|
+
console.log(
|
|
9024
|
+
`[CLINIC_SERVICE] Applied single-tag filter: ${initialCount} \u2192 ${filteredClinics.length}`
|
|
8955
9025
|
);
|
|
8956
|
-
console.log(`[CLINIC_SERVICE] Applied single-tag filter: ${initialCount} \u2192 ${filteredClinics.length}`);
|
|
8957
9026
|
}
|
|
8958
9027
|
if (filters.minRating !== void 0 || filters.maxRating !== void 0) {
|
|
8959
9028
|
const initialCount = filteredClinics.length;
|
|
@@ -8964,7 +9033,9 @@ function applyInMemoryFilters(clinics, filters) {
|
|
|
8964
9033
|
if (filters.maxRating !== void 0 && rating > filters.maxRating) return false;
|
|
8965
9034
|
return true;
|
|
8966
9035
|
});
|
|
8967
|
-
console.log(
|
|
9036
|
+
console.log(
|
|
9037
|
+
`[CLINIC_SERVICE] Applied rating filter (${filters.minRating}-${filters.maxRating}): ${initialCount} \u2192 ${filteredClinics.length}`
|
|
9038
|
+
);
|
|
8968
9039
|
}
|
|
8969
9040
|
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
8970
9041
|
const initialCount = filteredClinics.length;
|
|
@@ -8974,7 +9045,9 @@ function applyInMemoryFilters(clinics, filters) {
|
|
|
8974
9045
|
const nameLower = clinic.nameLower || "";
|
|
8975
9046
|
return name.includes(searchTerm) || nameLower.includes(searchTerm);
|
|
8976
9047
|
});
|
|
8977
|
-
console.log(
|
|
9048
|
+
console.log(
|
|
9049
|
+
`[CLINIC_SERVICE] Applied name search filter: ${initialCount} \u2192 ${filteredClinics.length}`
|
|
9050
|
+
);
|
|
8978
9051
|
}
|
|
8979
9052
|
if (filters.procedureFamily) {
|
|
8980
9053
|
const initialCount = filteredClinics.length;
|
|
@@ -8982,7 +9055,9 @@ function applyInMemoryFilters(clinics, filters) {
|
|
|
8982
9055
|
const proceduresInfo = clinic.proceduresInfo || [];
|
|
8983
9056
|
return proceduresInfo.some((proc) => proc.family === filters.procedureFamily);
|
|
8984
9057
|
});
|
|
8985
|
-
console.log(
|
|
9058
|
+
console.log(
|
|
9059
|
+
`[CLINIC_SERVICE] Applied procedure family filter: ${initialCount} \u2192 ${filteredClinics.length}`
|
|
9060
|
+
);
|
|
8986
9061
|
}
|
|
8987
9062
|
if (filters.procedureCategory) {
|
|
8988
9063
|
const initialCount = filteredClinics.length;
|
|
@@ -8990,7 +9065,9 @@ function applyInMemoryFilters(clinics, filters) {
|
|
|
8990
9065
|
const proceduresInfo = clinic.proceduresInfo || [];
|
|
8991
9066
|
return proceduresInfo.some((proc) => proc.categoryName === filters.procedureCategory);
|
|
8992
9067
|
});
|
|
8993
|
-
console.log(
|
|
9068
|
+
console.log(
|
|
9069
|
+
`[CLINIC_SERVICE] Applied procedure category filter: ${initialCount} \u2192 ${filteredClinics.length}`
|
|
9070
|
+
);
|
|
8994
9071
|
}
|
|
8995
9072
|
if (filters.procedureSubcategory) {
|
|
8996
9073
|
const initialCount = filteredClinics.length;
|
|
@@ -8998,7 +9075,9 @@ function applyInMemoryFilters(clinics, filters) {
|
|
|
8998
9075
|
const proceduresInfo = clinic.proceduresInfo || [];
|
|
8999
9076
|
return proceduresInfo.some((proc) => proc.subcategoryName === filters.procedureSubcategory);
|
|
9000
9077
|
});
|
|
9001
|
-
console.log(
|
|
9078
|
+
console.log(
|
|
9079
|
+
`[CLINIC_SERVICE] Applied procedure subcategory filter: ${initialCount} \u2192 ${filteredClinics.length}`
|
|
9080
|
+
);
|
|
9002
9081
|
}
|
|
9003
9082
|
if (filters.procedureTechnology) {
|
|
9004
9083
|
const initialCount = filteredClinics.length;
|
|
@@ -9006,7 +9085,9 @@ function applyInMemoryFilters(clinics, filters) {
|
|
|
9006
9085
|
const proceduresInfo = clinic.proceduresInfo || [];
|
|
9007
9086
|
return proceduresInfo.some((proc) => proc.technologyName === filters.procedureTechnology);
|
|
9008
9087
|
});
|
|
9009
|
-
console.log(
|
|
9088
|
+
console.log(
|
|
9089
|
+
`[CLINIC_SERVICE] Applied procedure technology filter: ${initialCount} \u2192 ${filteredClinics.length}`
|
|
9090
|
+
);
|
|
9010
9091
|
}
|
|
9011
9092
|
if (filters.center && filters.radiusInKm) {
|
|
9012
9093
|
const initialCount = filteredClinics.length;
|
|
@@ -9020,11 +9101,15 @@ function applyInMemoryFilters(clinics, filters) {
|
|
|
9020
9101
|
[filters.center.latitude, filters.center.longitude],
|
|
9021
9102
|
[clinic.location.latitude, clinic.location.longitude]
|
|
9022
9103
|
) / 1e3;
|
|
9023
|
-
console.log(
|
|
9104
|
+
console.log(
|
|
9105
|
+
`[CLINIC_SERVICE] Clinic ${clinic.name}: distance ${distance.toFixed(2)}km (limit: ${filters.radiusInKm}km)`
|
|
9106
|
+
);
|
|
9024
9107
|
clinic.distance = distance;
|
|
9025
9108
|
return distance <= filters.radiusInKm;
|
|
9026
9109
|
});
|
|
9027
|
-
console.log(
|
|
9110
|
+
console.log(
|
|
9111
|
+
`[CLINIC_SERVICE] Applied geo filter (${filters.radiusInKm}km): ${initialCount} \u2192 ${filteredClinics.length}`
|
|
9112
|
+
);
|
|
9028
9113
|
filteredClinics.sort((a, b) => (a.distance || 0) - (b.distance || 0));
|
|
9029
9114
|
}
|
|
9030
9115
|
console.log(`[CLINIC_SERVICE] Final filtered result: ${filteredClinics.length} clinics`);
|
|
@@ -9052,9 +9137,7 @@ var ClinicService = class extends BaseService {
|
|
|
9052
9137
|
return media;
|
|
9053
9138
|
}
|
|
9054
9139
|
if (media instanceof File || media instanceof Blob) {
|
|
9055
|
-
console.log(
|
|
9056
|
-
`[ClinicService] Uploading ${collectionName} media for ${ownerId}`
|
|
9057
|
-
);
|
|
9140
|
+
console.log(`[ClinicService] Uploading ${collectionName} media for ${ownerId}`);
|
|
9058
9141
|
const metadata = await this.mediaService.uploadMedia(
|
|
9059
9142
|
media,
|
|
9060
9143
|
ownerId,
|
|
@@ -9076,11 +9159,7 @@ var ClinicService = class extends BaseService {
|
|
|
9076
9159
|
if (!mediaArray || mediaArray.length === 0) return [];
|
|
9077
9160
|
const result = [];
|
|
9078
9161
|
for (const media of mediaArray) {
|
|
9079
|
-
const processedUrl = await this.processMedia(
|
|
9080
|
-
media,
|
|
9081
|
-
ownerId,
|
|
9082
|
-
collectionName
|
|
9083
|
-
);
|
|
9162
|
+
const processedUrl = await this.processMedia(media, ownerId, collectionName);
|
|
9084
9163
|
if (processedUrl) {
|
|
9085
9164
|
result.push(processedUrl);
|
|
9086
9165
|
}
|
|
@@ -9098,11 +9177,7 @@ var ClinicService = class extends BaseService {
|
|
|
9098
9177
|
if (!photosWithTags || photosWithTags.length === 0) return [];
|
|
9099
9178
|
const result = [];
|
|
9100
9179
|
for (const item of photosWithTags) {
|
|
9101
|
-
const processedUrl = await this.processMedia(
|
|
9102
|
-
item.url,
|
|
9103
|
-
ownerId,
|
|
9104
|
-
collectionName
|
|
9105
|
-
);
|
|
9180
|
+
const processedUrl = await this.processMedia(item.url, ownerId, collectionName);
|
|
9106
9181
|
if (processedUrl) {
|
|
9107
9182
|
result.push({
|
|
9108
9183
|
url: processedUrl,
|
|
@@ -9120,19 +9195,11 @@ var ClinicService = class extends BaseService {
|
|
|
9120
9195
|
try {
|
|
9121
9196
|
const clinicId = this.generateId();
|
|
9122
9197
|
const validatedData = createClinicSchema.parse(data);
|
|
9123
|
-
const group = await this.clinicGroupService.getClinicGroup(
|
|
9124
|
-
validatedData.clinicGroupId
|
|
9125
|
-
);
|
|
9198
|
+
const group = await this.clinicGroupService.getClinicGroup(validatedData.clinicGroupId);
|
|
9126
9199
|
if (!group) {
|
|
9127
|
-
throw new Error(
|
|
9128
|
-
`Clinic group ${validatedData.clinicGroupId} not found`
|
|
9129
|
-
);
|
|
9200
|
+
throw new Error(`Clinic group ${validatedData.clinicGroupId} not found`);
|
|
9130
9201
|
}
|
|
9131
|
-
const logoUrl = await this.processMedia(
|
|
9132
|
-
validatedData.logo,
|
|
9133
|
-
clinicId,
|
|
9134
|
-
"clinic-logos"
|
|
9135
|
-
);
|
|
9202
|
+
const logoUrl = await this.processMedia(validatedData.logo, clinicId, "clinic-logos");
|
|
9136
9203
|
const coverPhotoUrl = await this.processMedia(
|
|
9137
9204
|
validatedData.coverPhoto,
|
|
9138
9205
|
clinicId,
|
|
@@ -9222,11 +9289,7 @@ var ClinicService = class extends BaseService {
|
|
|
9222
9289
|
const validatedData = updateClinicSchema.parse(data);
|
|
9223
9290
|
const updatePayload = {};
|
|
9224
9291
|
if (validatedData.logo !== void 0) {
|
|
9225
|
-
updatePayload.logo = await this.processMedia(
|
|
9226
|
-
validatedData.logo,
|
|
9227
|
-
clinicId,
|
|
9228
|
-
"clinic-logos"
|
|
9229
|
-
);
|
|
9292
|
+
updatePayload.logo = await this.processMedia(validatedData.logo, clinicId, "clinic-logos");
|
|
9230
9293
|
}
|
|
9231
9294
|
if (validatedData.coverPhoto !== void 0) {
|
|
9232
9295
|
updatePayload.coverPhoto = await this.processMedia(
|
|
@@ -9326,22 +9389,10 @@ var ClinicService = class extends BaseService {
|
|
|
9326
9389
|
* Pretražuje klinike u određenom radijusu
|
|
9327
9390
|
*/
|
|
9328
9391
|
async findClinicsInRadius(center, radiusInKm, filters) {
|
|
9329
|
-
return findClinicsInRadius(
|
|
9330
|
-
this.db,
|
|
9331
|
-
center,
|
|
9332
|
-
radiusInKm,
|
|
9333
|
-
filters
|
|
9334
|
-
);
|
|
9392
|
+
return findClinicsInRadius(this.db, center, radiusInKm, filters);
|
|
9335
9393
|
}
|
|
9336
9394
|
async addTags(clinicId, adminId, newTags) {
|
|
9337
|
-
return addTags(
|
|
9338
|
-
this.db,
|
|
9339
|
-
clinicId,
|
|
9340
|
-
adminId,
|
|
9341
|
-
newTags,
|
|
9342
|
-
this.clinicAdminService,
|
|
9343
|
-
this.app
|
|
9344
|
-
);
|
|
9395
|
+
return addTags(this.db, clinicId, adminId, newTags, this.clinicAdminService, this.app);
|
|
9345
9396
|
}
|
|
9346
9397
|
async removeTags(clinicId, adminId, tagsToRemove) {
|
|
9347
9398
|
return removeTags(
|
|
@@ -9379,9 +9430,7 @@ var ClinicService = class extends BaseService {
|
|
|
9379
9430
|
clinicGroupId,
|
|
9380
9431
|
adminId
|
|
9381
9432
|
});
|
|
9382
|
-
const clinicGroup = await this.clinicGroupService.getClinicGroup(
|
|
9383
|
-
clinicGroupId
|
|
9384
|
-
);
|
|
9433
|
+
const clinicGroup = await this.clinicGroupService.getClinicGroup(clinicGroupId);
|
|
9385
9434
|
if (!clinicGroup) {
|
|
9386
9435
|
console.error("[CLINIC_SERVICE] Clinic group not found", {
|
|
9387
9436
|
clinicGroupId
|
|
@@ -9427,13 +9476,7 @@ var ClinicService = class extends BaseService {
|
|
|
9427
9476
|
return getAllClinics(this.db, pagination, lastDoc);
|
|
9428
9477
|
}
|
|
9429
9478
|
async getAllClinicsInRange(center, rangeInKm, pagination, lastDoc) {
|
|
9430
|
-
return getAllClinicsInRange(
|
|
9431
|
-
this.db,
|
|
9432
|
-
center,
|
|
9433
|
-
rangeInKm,
|
|
9434
|
-
pagination,
|
|
9435
|
-
lastDoc
|
|
9436
|
-
);
|
|
9479
|
+
return getAllClinicsInRange(this.db, center, rangeInKm, pagination, lastDoc);
|
|
9437
9480
|
}
|
|
9438
9481
|
/**
|
|
9439
9482
|
* Get clinics based on multiple filtering criteria
|
|
@@ -14865,7 +14908,7 @@ var procedureSchema = createProcedureSchema.extend({
|
|
|
14865
14908
|
});
|
|
14866
14909
|
|
|
14867
14910
|
// src/services/procedure/procedure.service.ts
|
|
14868
|
-
import { distanceBetween as distanceBetween6 } from "geofire-common";
|
|
14911
|
+
import { distanceBetween as distanceBetween6, geohashQueryBounds as geohashQueryBounds5 } from "geofire-common";
|
|
14869
14912
|
var ProcedureService = class extends BaseService {
|
|
14870
14913
|
constructor(db, auth, app, categoryService, subcategoryService, technologyService, productService, mediaService) {
|
|
14871
14914
|
super(db, auth, app);
|
|
@@ -14888,9 +14931,7 @@ var ProcedureService = class extends BaseService {
|
|
|
14888
14931
|
return media;
|
|
14889
14932
|
}
|
|
14890
14933
|
if (media instanceof File || media instanceof Blob) {
|
|
14891
|
-
console.log(
|
|
14892
|
-
`[ProcedureService] Uploading ${collectionName} media for ${ownerId}`
|
|
14893
|
-
);
|
|
14934
|
+
console.log(`[ProcedureService] Uploading ${collectionName} media for ${ownerId}`);
|
|
14894
14935
|
const metadata = await this.mediaService.uploadMedia(
|
|
14895
14936
|
media,
|
|
14896
14937
|
ownerId,
|
|
@@ -14912,11 +14953,7 @@ var ProcedureService = class extends BaseService {
|
|
|
14912
14953
|
if (!mediaArray || mediaArray.length === 0) return [];
|
|
14913
14954
|
const result = [];
|
|
14914
14955
|
for (const media of mediaArray) {
|
|
14915
|
-
const processedUrl = await this.processMedia(
|
|
14916
|
-
media,
|
|
14917
|
-
ownerId,
|
|
14918
|
-
collectionName
|
|
14919
|
-
);
|
|
14956
|
+
const processedUrl = await this.processMedia(media, ownerId, collectionName);
|
|
14920
14957
|
if (processedUrl) {
|
|
14921
14958
|
result.push(processedUrl);
|
|
14922
14959
|
}
|
|
@@ -14934,41 +14971,23 @@ var ProcedureService = class extends BaseService {
|
|
|
14934
14971
|
const procedureId = this.generateId();
|
|
14935
14972
|
const [category, subcategory, technology, product] = await Promise.all([
|
|
14936
14973
|
this.categoryService.getById(validatedData.categoryId),
|
|
14937
|
-
this.subcategoryService.getById(
|
|
14938
|
-
validatedData.categoryId,
|
|
14939
|
-
validatedData.subcategoryId
|
|
14940
|
-
),
|
|
14974
|
+
this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
|
|
14941
14975
|
this.technologyService.getById(validatedData.technologyId),
|
|
14942
|
-
this.productService.getById(
|
|
14943
|
-
validatedData.technologyId,
|
|
14944
|
-
validatedData.productId
|
|
14945
|
-
)
|
|
14976
|
+
this.productService.getById(validatedData.technologyId, validatedData.productId)
|
|
14946
14977
|
]);
|
|
14947
14978
|
if (!category || !subcategory || !technology || !product) {
|
|
14948
14979
|
throw new Error("One or more required base entities not found");
|
|
14949
14980
|
}
|
|
14950
|
-
const clinicRef = doc30(
|
|
14951
|
-
this.db,
|
|
14952
|
-
CLINICS_COLLECTION,
|
|
14953
|
-
validatedData.clinicBranchId
|
|
14954
|
-
);
|
|
14981
|
+
const clinicRef = doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId);
|
|
14955
14982
|
const clinicSnapshot = await getDoc32(clinicRef);
|
|
14956
14983
|
if (!clinicSnapshot.exists()) {
|
|
14957
|
-
throw new Error(
|
|
14958
|
-
`Clinic with ID ${validatedData.clinicBranchId} not found`
|
|
14959
|
-
);
|
|
14984
|
+
throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
|
|
14960
14985
|
}
|
|
14961
14986
|
const clinic = clinicSnapshot.data();
|
|
14962
|
-
const practitionerRef = doc30(
|
|
14963
|
-
this.db,
|
|
14964
|
-
PRACTITIONERS_COLLECTION,
|
|
14965
|
-
validatedData.practitionerId
|
|
14966
|
-
);
|
|
14987
|
+
const practitionerRef = doc30(this.db, PRACTITIONERS_COLLECTION, validatedData.practitionerId);
|
|
14967
14988
|
const practitionerSnapshot = await getDoc32(practitionerRef);
|
|
14968
14989
|
if (!practitionerSnapshot.exists()) {
|
|
14969
|
-
throw new Error(
|
|
14970
|
-
`Practitioner with ID ${validatedData.practitionerId} not found`
|
|
14971
|
-
);
|
|
14990
|
+
throw new Error(`Practitioner with ID ${validatedData.practitionerId} not found`);
|
|
14972
14991
|
}
|
|
14973
14992
|
const practitioner = practitionerSnapshot.data();
|
|
14974
14993
|
let processedPhotos = [];
|
|
@@ -15057,24 +15076,16 @@ var ProcedureService = class extends BaseService {
|
|
|
15057
15076
|
const validatedData = createProcedureSchema.parse(validationData);
|
|
15058
15077
|
const [category, subcategory, technology, product, clinicSnapshot] = await Promise.all([
|
|
15059
15078
|
this.categoryService.getById(validatedData.categoryId),
|
|
15060
|
-
this.subcategoryService.getById(
|
|
15061
|
-
validatedData.categoryId,
|
|
15062
|
-
validatedData.subcategoryId
|
|
15063
|
-
),
|
|
15079
|
+
this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
|
|
15064
15080
|
this.technologyService.getById(validatedData.technologyId),
|
|
15065
|
-
this.productService.getById(
|
|
15066
|
-
validatedData.technologyId,
|
|
15067
|
-
validatedData.productId
|
|
15068
|
-
),
|
|
15081
|
+
this.productService.getById(validatedData.technologyId, validatedData.productId),
|
|
15069
15082
|
getDoc32(doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId))
|
|
15070
15083
|
]);
|
|
15071
15084
|
if (!category || !subcategory || !technology || !product) {
|
|
15072
15085
|
throw new Error("One or more required base entities not found");
|
|
15073
15086
|
}
|
|
15074
15087
|
if (!clinicSnapshot.exists()) {
|
|
15075
|
-
throw new Error(
|
|
15076
|
-
`Clinic with ID ${validatedData.clinicBranchId} not found`
|
|
15077
|
-
);
|
|
15088
|
+
throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
|
|
15078
15089
|
}
|
|
15079
15090
|
const clinic = clinicSnapshot.data();
|
|
15080
15091
|
let processedPhotos = [];
|
|
@@ -15100,12 +15111,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15100
15111
|
}
|
|
15101
15112
|
if (practitionersMap.size !== practitionerIds.length) {
|
|
15102
15113
|
const foundIds = Array.from(practitionersMap.keys());
|
|
15103
|
-
const notFoundIds = practitionerIds.filter(
|
|
15104
|
-
|
|
15105
|
-
);
|
|
15106
|
-
throw new Error(
|
|
15107
|
-
`The following practitioners were not found: ${notFoundIds.join(", ")}`
|
|
15108
|
-
);
|
|
15114
|
+
const notFoundIds = practitionerIds.filter((id) => !foundIds.includes(id));
|
|
15115
|
+
throw new Error(`The following practitioners were not found: ${notFoundIds.join(", ")}`);
|
|
15109
15116
|
}
|
|
15110
15117
|
const batch = writeBatch6(this.db);
|
|
15111
15118
|
const createdProcedureIds = [];
|
|
@@ -15173,10 +15180,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15173
15180
|
const fetchedProcedures = [];
|
|
15174
15181
|
for (let i = 0; i < createdProcedureIds.length; i += 30) {
|
|
15175
15182
|
const chunk = createdProcedureIds.slice(i, i + 30);
|
|
15176
|
-
const q = query29(
|
|
15177
|
-
collection29(this.db, PROCEDURES_COLLECTION),
|
|
15178
|
-
where29(documentId2(), "in", chunk)
|
|
15179
|
-
);
|
|
15183
|
+
const q = query29(collection29(this.db, PROCEDURES_COLLECTION), where29(documentId2(), "in", chunk));
|
|
15180
15184
|
const snapshot = await getDocs29(q);
|
|
15181
15185
|
snapshot.forEach((doc37) => {
|
|
15182
15186
|
fetchedProcedures.push(doc37.data());
|
|
@@ -15277,9 +15281,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15277
15281
|
);
|
|
15278
15282
|
const newPractitionerSnap = await getDoc32(newPractitionerRef);
|
|
15279
15283
|
if (!newPractitionerSnap.exists())
|
|
15280
|
-
throw new Error(
|
|
15281
|
-
`New Practitioner ${validatedData.practitionerId} not found`
|
|
15282
|
-
);
|
|
15284
|
+
throw new Error(`New Practitioner ${validatedData.practitionerId} not found`);
|
|
15283
15285
|
newPractitioner = newPractitionerSnap.data();
|
|
15284
15286
|
updatedProcedureData.doctorInfo = {
|
|
15285
15287
|
id: newPractitioner.id,
|
|
@@ -15293,11 +15295,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15293
15295
|
}
|
|
15294
15296
|
if (validatedData.clinicBranchId && validatedData.clinicBranchId !== oldClinicId) {
|
|
15295
15297
|
clinicChanged = true;
|
|
15296
|
-
const newClinicRef = doc30(
|
|
15297
|
-
this.db,
|
|
15298
|
-
CLINICS_COLLECTION,
|
|
15299
|
-
validatedData.clinicBranchId
|
|
15300
|
-
);
|
|
15298
|
+
const newClinicRef = doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId);
|
|
15301
15299
|
const newClinicSnap = await getDoc32(newClinicRef);
|
|
15302
15300
|
if (!newClinicSnap.exists())
|
|
15303
15301
|
throw new Error(`New Clinic ${validatedData.clinicBranchId} not found`);
|
|
@@ -15316,11 +15314,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15316
15314
|
updatedProcedureData.nameLower = validatedData.name.toLowerCase();
|
|
15317
15315
|
}
|
|
15318
15316
|
if (validatedData.categoryId) {
|
|
15319
|
-
const category = await this.categoryService.getById(
|
|
15320
|
-
|
|
15321
|
-
);
|
|
15322
|
-
if (!category)
|
|
15323
|
-
throw new Error(`Category ${validatedData.categoryId} not found`);
|
|
15317
|
+
const category = await this.categoryService.getById(validatedData.categoryId);
|
|
15318
|
+
if (!category) throw new Error(`Category ${validatedData.categoryId} not found`);
|
|
15324
15319
|
updatedProcedureData.category = category;
|
|
15325
15320
|
finalCategoryId = category.id;
|
|
15326
15321
|
}
|
|
@@ -15335,17 +15330,12 @@ var ProcedureService = class extends BaseService {
|
|
|
15335
15330
|
);
|
|
15336
15331
|
updatedProcedureData.subcategory = subcategory;
|
|
15337
15332
|
} else if (validatedData.subcategoryId) {
|
|
15338
|
-
console.warn(
|
|
15339
|
-
"Attempted to update subcategory without a valid categoryId"
|
|
15340
|
-
);
|
|
15333
|
+
console.warn("Attempted to update subcategory without a valid categoryId");
|
|
15341
15334
|
}
|
|
15342
15335
|
let finalTechnologyId = existingProcedure.technology.id;
|
|
15343
15336
|
if (validatedData.technologyId) {
|
|
15344
|
-
const technology = await this.technologyService.getById(
|
|
15345
|
-
|
|
15346
|
-
);
|
|
15347
|
-
if (!technology)
|
|
15348
|
-
throw new Error(`Technology ${validatedData.technologyId} not found`);
|
|
15337
|
+
const technology = await this.technologyService.getById(validatedData.technologyId);
|
|
15338
|
+
if (!technology) throw new Error(`Technology ${validatedData.technologyId} not found`);
|
|
15349
15339
|
updatedProcedureData.technology = technology;
|
|
15350
15340
|
finalTechnologyId = technology.id;
|
|
15351
15341
|
updatedProcedureData.blockingConditions = technology.blockingConditions;
|
|
@@ -15356,10 +15346,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15356
15346
|
updatedProcedureData.documentationTemplates = technology.documentationTemplates || [];
|
|
15357
15347
|
}
|
|
15358
15348
|
if (validatedData.productId && finalTechnologyId) {
|
|
15359
|
-
const product = await this.productService.getById(
|
|
15360
|
-
finalTechnologyId,
|
|
15361
|
-
validatedData.productId
|
|
15362
|
-
);
|
|
15349
|
+
const product = await this.productService.getById(finalTechnologyId, validatedData.productId);
|
|
15363
15350
|
if (!product)
|
|
15364
15351
|
throw new Error(
|
|
15365
15352
|
`Product ${validatedData.productId} not found for technology ${finalTechnologyId}`
|
|
@@ -15441,11 +15428,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15441
15428
|
limit16(pagination)
|
|
15442
15429
|
);
|
|
15443
15430
|
} else {
|
|
15444
|
-
proceduresQuery = query29(
|
|
15445
|
-
proceduresCollection,
|
|
15446
|
-
orderBy17("name"),
|
|
15447
|
-
limit16(pagination)
|
|
15448
|
-
);
|
|
15431
|
+
proceduresQuery = query29(proceduresCollection, orderBy17("name"), limit16(pagination));
|
|
15449
15432
|
}
|
|
15450
15433
|
} else {
|
|
15451
15434
|
proceduresQuery = query29(proceduresCollection, orderBy17("name"));
|
|
@@ -15568,7 +15551,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15568
15551
|
constraints.push(limit15(filters.pagination || 10));
|
|
15569
15552
|
const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15570
15553
|
const querySnapshot = await getDocs29(q);
|
|
15571
|
-
const procedures = querySnapshot.docs.map(
|
|
15554
|
+
const procedures = querySnapshot.docs.map(
|
|
15555
|
+
(doc37) => ({ ...doc37.data(), id: doc37.id })
|
|
15556
|
+
);
|
|
15572
15557
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15573
15558
|
console.log(`[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`);
|
|
15574
15559
|
if (procedures.length < (filters.pagination || 10)) {
|
|
@@ -15599,7 +15584,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15599
15584
|
constraints.push(limit15(filters.pagination || 10));
|
|
15600
15585
|
const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15601
15586
|
const querySnapshot = await getDocs29(q);
|
|
15602
|
-
const procedures = querySnapshot.docs.map(
|
|
15587
|
+
const procedures = querySnapshot.docs.map(
|
|
15588
|
+
(doc37) => ({ ...doc37.data(), id: doc37.id })
|
|
15589
|
+
);
|
|
15603
15590
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15604
15591
|
console.log(`[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`);
|
|
15605
15592
|
if (procedures.length < (filters.pagination || 10)) {
|
|
@@ -15611,7 +15598,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15611
15598
|
}
|
|
15612
15599
|
}
|
|
15613
15600
|
try {
|
|
15614
|
-
console.log(
|
|
15601
|
+
console.log(
|
|
15602
|
+
"[PROCEDURE_SERVICE] Strategy 3: Using createdAt orderBy with client-side filtering"
|
|
15603
|
+
);
|
|
15615
15604
|
const constraints = getBaseConstraints();
|
|
15616
15605
|
constraints.push(orderBy17("createdAt", "desc"));
|
|
15617
15606
|
if (filters.lastDoc) {
|
|
@@ -15626,7 +15615,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15626
15615
|
constraints.push(limit15(filters.pagination || 10));
|
|
15627
15616
|
const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15628
15617
|
const querySnapshot = await getDocs29(q);
|
|
15629
|
-
let procedures = querySnapshot.docs.map(
|
|
15618
|
+
let procedures = querySnapshot.docs.map(
|
|
15619
|
+
(doc37) => ({ ...doc37.data(), id: doc37.id })
|
|
15620
|
+
);
|
|
15630
15621
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15631
15622
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15632
15623
|
console.log(`[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`);
|
|
@@ -15646,7 +15637,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15646
15637
|
];
|
|
15647
15638
|
const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15648
15639
|
const querySnapshot = await getDocs29(q);
|
|
15649
|
-
let procedures = querySnapshot.docs.map(
|
|
15640
|
+
let procedures = querySnapshot.docs.map(
|
|
15641
|
+
(doc37) => ({ ...doc37.data(), id: doc37.id })
|
|
15642
|
+
);
|
|
15650
15643
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15651
15644
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15652
15645
|
console.log(`[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`);
|
|
@@ -15686,7 +15679,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15686
15679
|
if (filters.maxPrice !== void 0 && price > filters.maxPrice) return false;
|
|
15687
15680
|
return true;
|
|
15688
15681
|
});
|
|
15689
|
-
console.log(
|
|
15682
|
+
console.log(
|
|
15683
|
+
`[PROCEDURE_SERVICE] Applied price filter (${filters.minPrice}-${filters.maxPrice}), results: ${filteredProcedures.length}`
|
|
15684
|
+
);
|
|
15690
15685
|
}
|
|
15691
15686
|
if (filters.minRating !== void 0 || filters.maxRating !== void 0) {
|
|
15692
15687
|
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
@@ -15696,7 +15691,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15696
15691
|
if (filters.maxRating !== void 0 && rating > filters.maxRating) return false;
|
|
15697
15692
|
return true;
|
|
15698
15693
|
});
|
|
15699
|
-
console.log(
|
|
15694
|
+
console.log(
|
|
15695
|
+
`[PROCEDURE_SERVICE] Applied rating filter, results: ${filteredProcedures.length}`
|
|
15696
|
+
);
|
|
15700
15697
|
}
|
|
15701
15698
|
if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
|
|
15702
15699
|
const benefitsToMatch = filters.treatmentBenefits;
|
|
@@ -15704,32 +15701,50 @@ var ProcedureService = class extends BaseService {
|
|
|
15704
15701
|
const procedureBenefits = procedure.treatmentBenefits || [];
|
|
15705
15702
|
return benefitsToMatch.some((benefit) => procedureBenefits.includes(benefit));
|
|
15706
15703
|
});
|
|
15707
|
-
console.log(
|
|
15704
|
+
console.log(
|
|
15705
|
+
`[PROCEDURE_SERVICE] Applied benefits filter, results: ${filteredProcedures.length}`
|
|
15706
|
+
);
|
|
15708
15707
|
}
|
|
15709
15708
|
if (filters.procedureFamily) {
|
|
15710
|
-
filteredProcedures = filteredProcedures.filter(
|
|
15711
|
-
|
|
15709
|
+
filteredProcedures = filteredProcedures.filter(
|
|
15710
|
+
(procedure) => procedure.family === filters.procedureFamily
|
|
15711
|
+
);
|
|
15712
|
+
console.log(
|
|
15713
|
+
`[PROCEDURE_SERVICE] Applied family filter, results: ${filteredProcedures.length}`
|
|
15714
|
+
);
|
|
15712
15715
|
}
|
|
15713
15716
|
if (filters.procedureCategory) {
|
|
15714
|
-
filteredProcedures = filteredProcedures.filter(
|
|
15715
|
-
|
|
15716
|
-
|
|
15717
|
-
|
|
15718
|
-
|
|
15717
|
+
filteredProcedures = filteredProcedures.filter(
|
|
15718
|
+
(procedure) => {
|
|
15719
|
+
var _a;
|
|
15720
|
+
return ((_a = procedure.category) == null ? void 0 : _a.id) === filters.procedureCategory;
|
|
15721
|
+
}
|
|
15722
|
+
);
|
|
15723
|
+
console.log(
|
|
15724
|
+
`[PROCEDURE_SERVICE] Applied category filter, results: ${filteredProcedures.length}`
|
|
15725
|
+
);
|
|
15719
15726
|
}
|
|
15720
15727
|
if (filters.procedureSubcategory) {
|
|
15721
|
-
filteredProcedures = filteredProcedures.filter(
|
|
15722
|
-
|
|
15723
|
-
|
|
15724
|
-
|
|
15725
|
-
|
|
15728
|
+
filteredProcedures = filteredProcedures.filter(
|
|
15729
|
+
(procedure) => {
|
|
15730
|
+
var _a;
|
|
15731
|
+
return ((_a = procedure.subcategory) == null ? void 0 : _a.id) === filters.procedureSubcategory;
|
|
15732
|
+
}
|
|
15733
|
+
);
|
|
15734
|
+
console.log(
|
|
15735
|
+
`[PROCEDURE_SERVICE] Applied subcategory filter, results: ${filteredProcedures.length}`
|
|
15736
|
+
);
|
|
15726
15737
|
}
|
|
15727
15738
|
if (filters.procedureTechnology) {
|
|
15728
|
-
filteredProcedures = filteredProcedures.filter(
|
|
15729
|
-
|
|
15730
|
-
|
|
15731
|
-
|
|
15732
|
-
|
|
15739
|
+
filteredProcedures = filteredProcedures.filter(
|
|
15740
|
+
(procedure) => {
|
|
15741
|
+
var _a;
|
|
15742
|
+
return ((_a = procedure.technology) == null ? void 0 : _a.id) === filters.procedureTechnology;
|
|
15743
|
+
}
|
|
15744
|
+
);
|
|
15745
|
+
console.log(
|
|
15746
|
+
`[PROCEDURE_SERVICE] Applied technology filter, results: ${filteredProcedures.length}`
|
|
15747
|
+
);
|
|
15733
15748
|
}
|
|
15734
15749
|
if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
|
|
15735
15750
|
const location = filters.location;
|
|
@@ -15753,29 +15768,48 @@ var ProcedureService = class extends BaseService {
|
|
|
15753
15768
|
return filteredProcedures;
|
|
15754
15769
|
}
|
|
15755
15770
|
handleGeoQuery(filters) {
|
|
15756
|
-
console.log("[PROCEDURE_SERVICE] Executing geo query with
|
|
15771
|
+
console.log("[PROCEDURE_SERVICE] Executing geo query with geohash bounds");
|
|
15757
15772
|
try {
|
|
15758
15773
|
const location = filters.location;
|
|
15759
15774
|
const radiusInKm = filters.radiusInKm;
|
|
15760
|
-
|
|
15761
|
-
|
|
15762
|
-
|
|
15763
|
-
|
|
15764
|
-
|
|
15775
|
+
if (!location || !radiusInKm) {
|
|
15776
|
+
return Promise.resolve({ procedures: [], lastDoc: null });
|
|
15777
|
+
}
|
|
15778
|
+
const bounds = geohashQueryBounds5([location.latitude, location.longitude], radiusInKm * 1e3);
|
|
15779
|
+
const fetches = bounds.map((b) => {
|
|
15780
|
+
const constraints = [
|
|
15781
|
+
where29("clinicInfo.location.geohash", ">=", b[0]),
|
|
15782
|
+
where29("clinicInfo.location.geohash", "<=", b[1]),
|
|
15783
|
+
where29("isActive", "==", filters.isActive !== void 0 ? filters.isActive : true)
|
|
15784
|
+
];
|
|
15785
|
+
return getDocs29(query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints));
|
|
15765
15786
|
});
|
|
15766
|
-
|
|
15767
|
-
|
|
15768
|
-
|
|
15769
|
-
|
|
15770
|
-
|
|
15771
|
-
|
|
15772
|
-
|
|
15773
|
-
|
|
15774
|
-
|
|
15787
|
+
return Promise.all(fetches).then((snaps) => {
|
|
15788
|
+
const collected = [];
|
|
15789
|
+
snaps.forEach((snap) => {
|
|
15790
|
+
snap.docs.forEach((d) => collected.push({ ...d.data(), id: d.id }));
|
|
15791
|
+
});
|
|
15792
|
+
const uniqueMap = /* @__PURE__ */ new Map();
|
|
15793
|
+
for (const p of collected) {
|
|
15794
|
+
uniqueMap.set(p.id, p);
|
|
15795
|
+
}
|
|
15796
|
+
let procedures = Array.from(uniqueMap.values());
|
|
15775
15797
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15776
|
-
|
|
15777
|
-
|
|
15778
|
-
|
|
15798
|
+
const pageSize = filters.pagination || 10;
|
|
15799
|
+
let startIndex = 0;
|
|
15800
|
+
if (filters.lastDoc && typeof filters.lastDoc === "object" && filters.lastDoc.id) {
|
|
15801
|
+
const idx = procedures.findIndex((p) => p.id === filters.lastDoc.id);
|
|
15802
|
+
if (idx >= 0) startIndex = idx + 1;
|
|
15803
|
+
}
|
|
15804
|
+
const page = procedures.slice(startIndex, startIndex + pageSize);
|
|
15805
|
+
const newLastDoc = page.length === pageSize ? page[page.length - 1] : null;
|
|
15806
|
+
console.log(
|
|
15807
|
+
`[PROCEDURE_SERVICE] Geo query success: ${page.length} (of ${procedures.length}) within ${radiusInKm}km`
|
|
15808
|
+
);
|
|
15809
|
+
return { procedures: page, lastDoc: newLastDoc };
|
|
15810
|
+
}).catch((err) => {
|
|
15811
|
+
console.error("[PROCEDURE_SERVICE] Geo bounds fetch failed:", err);
|
|
15812
|
+
return { procedures: [], lastDoc: null };
|
|
15779
15813
|
});
|
|
15780
15814
|
} catch (error) {
|
|
15781
15815
|
console.error("[PROCEDURE_SERVICE] Geo query failed:", error);
|
|
@@ -15805,11 +15839,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15805
15839
|
throw new Error(`Clinic with ID ${data.clinicBranchId} not found`);
|
|
15806
15840
|
}
|
|
15807
15841
|
const clinic = clinicSnapshot.data();
|
|
15808
|
-
const practitionerRef = doc30(
|
|
15809
|
-
this.db,
|
|
15810
|
-
PRACTITIONERS_COLLECTION,
|
|
15811
|
-
data.practitionerId
|
|
15812
|
-
);
|
|
15842
|
+
const practitionerRef = doc30(this.db, PRACTITIONERS_COLLECTION, data.practitionerId);
|
|
15813
15843
|
const practitionerSnapshot = await getDoc32(practitionerRef);
|
|
15814
15844
|
if (!practitionerSnapshot.exists()) {
|
|
15815
15845
|
throw new Error(`Practitioner with ID ${data.practitionerId} not found`);
|
|
@@ -15817,11 +15847,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15817
15847
|
const practitioner = practitionerSnapshot.data();
|
|
15818
15848
|
let processedPhotos = [];
|
|
15819
15849
|
if (data.photos && data.photos.length > 0) {
|
|
15820
|
-
processedPhotos = await this.processMediaArray(
|
|
15821
|
-
data.photos,
|
|
15822
|
-
procedureId,
|
|
15823
|
-
"procedure-photos"
|
|
15824
|
-
);
|
|
15850
|
+
processedPhotos = await this.processMediaArray(data.photos, procedureId, "procedure-photos");
|
|
15825
15851
|
}
|
|
15826
15852
|
const clinicInfo = {
|
|
15827
15853
|
id: clinicSnapshot.id,
|