@blackcode_sa/metaestetics-api 1.12.0 → 1.12.2
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 +36 -3
- package/dist/admin/index.d.ts +36 -3
- package/dist/backoffice/index.d.mts +33 -1
- package/dist/backoffice/index.d.ts +33 -1
- package/dist/index.d.mts +60 -6
- package/dist/index.d.ts +60 -6
- package/dist/index.js +394 -293
- package/dist/index.mjs +394 -293
- package/package.json +1 -1
- package/src/backoffice/expo-safe/index.ts +1 -0
- package/src/backoffice/types/index.ts +1 -0
- package/src/backoffice/types/procedure-product.types.ts +38 -0
- package/src/services/practitioner/practitioner.service.ts +201 -83
- package/src/services/procedure/README.md +76 -1
- package/src/services/procedure/procedure.service.ts +346 -442
- package/src/types/procedure/index.ts +19 -3
- package/src/validations/procedure-product.schema.ts +41 -0
- package/src/validations/procedure.schema.ts +59 -8
package/dist/index.mjs
CHANGED
|
@@ -6639,7 +6639,9 @@ var PractitionerService = class extends BaseService {
|
|
|
6639
6639
|
throw new Error(`Practitioner ${practitionerId} not found`);
|
|
6640
6640
|
}
|
|
6641
6641
|
const currentPractitioner = practitionerDoc.data();
|
|
6642
|
-
let processedData = {
|
|
6642
|
+
let processedData = {
|
|
6643
|
+
...validData
|
|
6644
|
+
};
|
|
6643
6645
|
if (validData.basicInfo) {
|
|
6644
6646
|
processedData.basicInfo = await this.processBasicInfo(
|
|
6645
6647
|
validData.basicInfo,
|
|
@@ -6873,7 +6875,9 @@ var PractitionerService = class extends BaseService {
|
|
|
6873
6875
|
*/
|
|
6874
6876
|
async getPractitionersByFilters(filters) {
|
|
6875
6877
|
try {
|
|
6876
|
-
console.log(
|
|
6878
|
+
console.log(
|
|
6879
|
+
"[PRACTITIONER_SERVICE] Starting practitioner filtering with fallback strategies"
|
|
6880
|
+
);
|
|
6877
6881
|
if (filters.location && filters.radiusInKm) {
|
|
6878
6882
|
console.log("[PRACTITIONER_SERVICE] Executing geo query:", {
|
|
6879
6883
|
location: filters.location,
|
|
@@ -6881,14 +6885,19 @@ var PractitionerService = class extends BaseService {
|
|
|
6881
6885
|
serviceName: "PractitionerService"
|
|
6882
6886
|
});
|
|
6883
6887
|
if (!filters.location.latitude || !filters.location.longitude) {
|
|
6884
|
-
console.warn(
|
|
6888
|
+
console.warn(
|
|
6889
|
+
"[PRACTITIONER_SERVICE] Invalid location data:",
|
|
6890
|
+
filters.location
|
|
6891
|
+
);
|
|
6885
6892
|
filters.location = void 0;
|
|
6886
6893
|
filters.radiusInKm = void 0;
|
|
6887
6894
|
}
|
|
6888
6895
|
}
|
|
6889
6896
|
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
6890
6897
|
try {
|
|
6891
|
-
console.log(
|
|
6898
|
+
console.log(
|
|
6899
|
+
"[PRACTITIONER_SERVICE] Strategy 1: Trying fullNameLower search"
|
|
6900
|
+
);
|
|
6892
6901
|
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
6893
6902
|
const constraints = [];
|
|
6894
6903
|
if (!filters.includeDraftPractitioners) {
|
|
@@ -6908,11 +6917,18 @@ var PractitionerService = class extends BaseService {
|
|
|
6908
6917
|
}
|
|
6909
6918
|
}
|
|
6910
6919
|
constraints.push(limit7(filters.pagination || 10));
|
|
6911
|
-
const q = query10(
|
|
6920
|
+
const q = query10(
|
|
6921
|
+
collection10(this.db, PRACTITIONERS_COLLECTION),
|
|
6922
|
+
...constraints
|
|
6923
|
+
);
|
|
6912
6924
|
const querySnapshot = await getDocs10(q);
|
|
6913
|
-
const practitioners = querySnapshot.docs.map(
|
|
6925
|
+
const practitioners = querySnapshot.docs.map(
|
|
6926
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
6927
|
+
);
|
|
6914
6928
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
6915
|
-
console.log(
|
|
6929
|
+
console.log(
|
|
6930
|
+
`[PRACTITIONER_SERVICE] Strategy 1 success: ${practitioners.length} practitioners`
|
|
6931
|
+
);
|
|
6916
6932
|
if (practitioners.length < (filters.pagination || 10)) {
|
|
6917
6933
|
return { practitioners, lastDoc: null };
|
|
6918
6934
|
}
|
|
@@ -6922,7 +6938,9 @@ var PractitionerService = class extends BaseService {
|
|
|
6922
6938
|
}
|
|
6923
6939
|
}
|
|
6924
6940
|
try {
|
|
6925
|
-
console.log(
|
|
6941
|
+
console.log(
|
|
6942
|
+
"[PRACTITIONER_SERVICE] Strategy 2: Basic query with createdAt ordering"
|
|
6943
|
+
);
|
|
6926
6944
|
const constraints = [];
|
|
6927
6945
|
if (!filters.includeDraftPractitioners) {
|
|
6928
6946
|
constraints.push(where10("status", "==", "active" /* ACTIVE */));
|
|
@@ -6931,14 +6949,22 @@ var PractitionerService = class extends BaseService {
|
|
|
6931
6949
|
if (filters.certifications && filters.certifications.length > 0) {
|
|
6932
6950
|
const certificationsToMatch = filters.certifications;
|
|
6933
6951
|
constraints.push(
|
|
6934
|
-
where10(
|
|
6952
|
+
where10(
|
|
6953
|
+
"certification.specialties",
|
|
6954
|
+
"array-contains-any",
|
|
6955
|
+
certificationsToMatch
|
|
6956
|
+
)
|
|
6935
6957
|
);
|
|
6936
6958
|
}
|
|
6937
6959
|
if (filters.minRating !== void 0) {
|
|
6938
|
-
constraints.push(
|
|
6960
|
+
constraints.push(
|
|
6961
|
+
where10("reviewInfo.averageRating", ">=", filters.minRating)
|
|
6962
|
+
);
|
|
6939
6963
|
}
|
|
6940
6964
|
if (filters.maxRating !== void 0) {
|
|
6941
|
-
constraints.push(
|
|
6965
|
+
constraints.push(
|
|
6966
|
+
where10("reviewInfo.averageRating", "<=", filters.maxRating)
|
|
6967
|
+
);
|
|
6942
6968
|
}
|
|
6943
6969
|
constraints.push(orderBy4("createdAt", "desc"));
|
|
6944
6970
|
if (filters.location && filters.radiusInKm) {
|
|
@@ -6955,9 +6981,14 @@ var PractitionerService = class extends BaseService {
|
|
|
6955
6981
|
}
|
|
6956
6982
|
constraints.push(limit7(filters.pagination || 10));
|
|
6957
6983
|
}
|
|
6958
|
-
const q = query10(
|
|
6984
|
+
const q = query10(
|
|
6985
|
+
collection10(this.db, PRACTITIONERS_COLLECTION),
|
|
6986
|
+
...constraints
|
|
6987
|
+
);
|
|
6959
6988
|
const querySnapshot = await getDocs10(q);
|
|
6960
|
-
let practitioners = querySnapshot.docs.map(
|
|
6989
|
+
let practitioners = querySnapshot.docs.map(
|
|
6990
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
6991
|
+
);
|
|
6961
6992
|
if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
|
|
6962
6993
|
const location = filters.location;
|
|
6963
6994
|
const radiusInKm = filters.radiusInKm;
|
|
@@ -6976,7 +7007,9 @@ var PractitionerService = class extends BaseService {
|
|
|
6976
7007
|
}
|
|
6977
7008
|
practitioners = this.applyInMemoryFilters(practitioners, filters);
|
|
6978
7009
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
6979
|
-
console.log(
|
|
7010
|
+
console.log(
|
|
7011
|
+
`[PRACTITIONER_SERVICE] Strategy 2 success: ${practitioners.length} practitioners`
|
|
7012
|
+
);
|
|
6980
7013
|
if (practitioners.length < (filters.pagination || 10)) {
|
|
6981
7014
|
return { practitioners, lastDoc: null };
|
|
6982
7015
|
}
|
|
@@ -6985,18 +7018,27 @@ var PractitionerService = class extends BaseService {
|
|
|
6985
7018
|
console.log("[PRACTITIONER_SERVICE] Strategy 2 failed:", error);
|
|
6986
7019
|
}
|
|
6987
7020
|
try {
|
|
6988
|
-
console.log(
|
|
7021
|
+
console.log(
|
|
7022
|
+
"[PRACTITIONER_SERVICE] Strategy 3: Minimal query fallback"
|
|
7023
|
+
);
|
|
6989
7024
|
const constraints = [
|
|
6990
7025
|
where10("isActive", "==", true),
|
|
6991
7026
|
orderBy4("createdAt", "desc"),
|
|
6992
7027
|
limit7(filters.pagination || 10)
|
|
6993
7028
|
];
|
|
6994
|
-
const q = query10(
|
|
7029
|
+
const q = query10(
|
|
7030
|
+
collection10(this.db, PRACTITIONERS_COLLECTION),
|
|
7031
|
+
...constraints
|
|
7032
|
+
);
|
|
6995
7033
|
const querySnapshot = await getDocs10(q);
|
|
6996
|
-
let practitioners = querySnapshot.docs.map(
|
|
7034
|
+
let practitioners = querySnapshot.docs.map(
|
|
7035
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
7036
|
+
);
|
|
6997
7037
|
practitioners = this.applyInMemoryFilters(practitioners, filters);
|
|
6998
7038
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
6999
|
-
console.log(
|
|
7039
|
+
console.log(
|
|
7040
|
+
`[PRACTITIONER_SERVICE] Strategy 3 success: ${practitioners.length} practitioners`
|
|
7041
|
+
);
|
|
7000
7042
|
if (practitioners.length < (filters.pagination || 10)) {
|
|
7001
7043
|
return { practitioners, lastDoc: null };
|
|
7002
7044
|
}
|
|
@@ -7005,19 +7047,28 @@ var PractitionerService = class extends BaseService {
|
|
|
7005
7047
|
console.log("[PRACTITIONER_SERVICE] Strategy 3 failed:", error);
|
|
7006
7048
|
}
|
|
7007
7049
|
try {
|
|
7008
|
-
console.log(
|
|
7050
|
+
console.log(
|
|
7051
|
+
"[PRACTITIONER_SERVICE] Strategy 4: Client-side filtering fallback"
|
|
7052
|
+
);
|
|
7009
7053
|
const constraints = [
|
|
7010
7054
|
where10("isActive", "==", true),
|
|
7011
7055
|
where10("status", "==", "active" /* ACTIVE */),
|
|
7012
7056
|
orderBy4("createdAt", "desc"),
|
|
7013
7057
|
limit7(filters.pagination || 10)
|
|
7014
7058
|
];
|
|
7015
|
-
const q = query10(
|
|
7059
|
+
const q = query10(
|
|
7060
|
+
collection10(this.db, PRACTITIONERS_COLLECTION),
|
|
7061
|
+
...constraints
|
|
7062
|
+
);
|
|
7016
7063
|
const querySnapshot = await getDocs10(q);
|
|
7017
|
-
let practitioners = querySnapshot.docs.map(
|
|
7064
|
+
let practitioners = querySnapshot.docs.map(
|
|
7065
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
7066
|
+
);
|
|
7018
7067
|
practitioners = this.applyInMemoryFilters(practitioners, filters);
|
|
7019
7068
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
7020
|
-
console.log(
|
|
7069
|
+
console.log(
|
|
7070
|
+
`[PRACTITIONER_SERVICE] Strategy 4 success: ${practitioners.length} practitioners`
|
|
7071
|
+
);
|
|
7021
7072
|
if (practitioners.length < (filters.pagination || 10)) {
|
|
7022
7073
|
return { practitioners, lastDoc: null };
|
|
7023
7074
|
}
|
|
@@ -7025,10 +7076,15 @@ var PractitionerService = class extends BaseService {
|
|
|
7025
7076
|
} catch (error) {
|
|
7026
7077
|
console.log("[PRACTITIONER_SERVICE] Strategy 4 failed:", error);
|
|
7027
7078
|
}
|
|
7028
|
-
console.log(
|
|
7079
|
+
console.log(
|
|
7080
|
+
"[PRACTITIONER_SERVICE] All strategies failed, returning empty result"
|
|
7081
|
+
);
|
|
7029
7082
|
return { practitioners: [], lastDoc: null };
|
|
7030
7083
|
} catch (error) {
|
|
7031
|
-
console.error(
|
|
7084
|
+
console.error(
|
|
7085
|
+
"[PRACTITIONER_SERVICE] Error filtering practitioners:",
|
|
7086
|
+
error
|
|
7087
|
+
);
|
|
7032
7088
|
return { practitioners: [], lastDoc: null };
|
|
7033
7089
|
}
|
|
7034
7090
|
}
|
|
@@ -7048,63 +7104,93 @@ var PractitionerService = class extends BaseService {
|
|
|
7048
7104
|
const fullNameLower = practitioner.fullNameLower || "";
|
|
7049
7105
|
return firstName.includes(searchTerm) || lastName.includes(searchTerm) || fullName.includes(searchTerm) || fullNameLower.includes(searchTerm);
|
|
7050
7106
|
});
|
|
7051
|
-
console.log(
|
|
7107
|
+
console.log(
|
|
7108
|
+
`[PRACTITIONER_SERVICE] Applied name filter, results: ${filteredPractitioners.length}`
|
|
7109
|
+
);
|
|
7052
7110
|
}
|
|
7053
7111
|
if (filters.certifications && filters.certifications.length > 0) {
|
|
7054
7112
|
const certificationsToMatch = filters.certifications;
|
|
7055
7113
|
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7056
7114
|
var _a;
|
|
7057
7115
|
const practitionerCerts = ((_a = practitioner.certification) == null ? void 0 : _a.specialties) || [];
|
|
7058
|
-
return certificationsToMatch.some(
|
|
7116
|
+
return certificationsToMatch.some(
|
|
7117
|
+
(cert) => practitionerCerts.includes(cert)
|
|
7118
|
+
);
|
|
7059
7119
|
});
|
|
7060
|
-
console.log(
|
|
7120
|
+
console.log(
|
|
7121
|
+
`[PRACTITIONER_SERVICE] Applied certifications filter, results: ${filteredPractitioners.length}`
|
|
7122
|
+
);
|
|
7061
7123
|
}
|
|
7062
7124
|
if (filters.specialties && filters.specialties.length > 0) {
|
|
7063
7125
|
const specialtiesToMatch = filters.specialties;
|
|
7064
7126
|
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7065
7127
|
var _a;
|
|
7066
7128
|
const practitionerSpecs = ((_a = practitioner.certification) == null ? void 0 : _a.specialties) || [];
|
|
7067
|
-
return specialtiesToMatch.some(
|
|
7129
|
+
return specialtiesToMatch.some(
|
|
7130
|
+
(spec) => practitionerSpecs.includes(spec)
|
|
7131
|
+
);
|
|
7068
7132
|
});
|
|
7069
|
-
console.log(
|
|
7133
|
+
console.log(
|
|
7134
|
+
`[PRACTITIONER_SERVICE] Applied specialties filter, results: ${filteredPractitioners.length}`
|
|
7135
|
+
);
|
|
7070
7136
|
}
|
|
7071
7137
|
if (filters.minRating !== void 0 || filters.maxRating !== void 0) {
|
|
7072
7138
|
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7073
7139
|
var _a;
|
|
7074
7140
|
const rating = ((_a = practitioner.reviewInfo) == null ? void 0 : _a.averageRating) || 0;
|
|
7075
|
-
if (filters.minRating !== void 0 && rating < filters.minRating)
|
|
7076
|
-
|
|
7141
|
+
if (filters.minRating !== void 0 && rating < filters.minRating)
|
|
7142
|
+
return false;
|
|
7143
|
+
if (filters.maxRating !== void 0 && rating > filters.maxRating)
|
|
7144
|
+
return false;
|
|
7077
7145
|
return true;
|
|
7078
7146
|
});
|
|
7079
|
-
console.log(
|
|
7147
|
+
console.log(
|
|
7148
|
+
`[PRACTITIONER_SERVICE] Applied rating filter, results: ${filteredPractitioners.length}`
|
|
7149
|
+
);
|
|
7080
7150
|
}
|
|
7081
7151
|
if (filters.procedureFamily) {
|
|
7082
7152
|
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7083
7153
|
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
7084
|
-
return proceduresInfo.some(
|
|
7154
|
+
return proceduresInfo.some(
|
|
7155
|
+
(proc) => proc.family === filters.procedureFamily
|
|
7156
|
+
);
|
|
7085
7157
|
});
|
|
7086
|
-
console.log(
|
|
7158
|
+
console.log(
|
|
7159
|
+
`[PRACTITIONER_SERVICE] Applied procedure family filter, results: ${filteredPractitioners.length}`
|
|
7160
|
+
);
|
|
7087
7161
|
}
|
|
7088
7162
|
if (filters.procedureCategory) {
|
|
7089
7163
|
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7090
7164
|
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
7091
|
-
return proceduresInfo.some(
|
|
7165
|
+
return proceduresInfo.some(
|
|
7166
|
+
(proc) => proc.categoryName === filters.procedureCategory
|
|
7167
|
+
);
|
|
7092
7168
|
});
|
|
7093
|
-
console.log(
|
|
7169
|
+
console.log(
|
|
7170
|
+
`[PRACTITIONER_SERVICE] Applied procedure category filter, results: ${filteredPractitioners.length}`
|
|
7171
|
+
);
|
|
7094
7172
|
}
|
|
7095
7173
|
if (filters.procedureSubcategory) {
|
|
7096
7174
|
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7097
7175
|
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
7098
|
-
return proceduresInfo.some(
|
|
7176
|
+
return proceduresInfo.some(
|
|
7177
|
+
(proc) => proc.subcategoryName === filters.procedureSubcategory
|
|
7178
|
+
);
|
|
7099
7179
|
});
|
|
7100
|
-
console.log(
|
|
7180
|
+
console.log(
|
|
7181
|
+
`[PRACTITIONER_SERVICE] Applied procedure subcategory filter, results: ${filteredPractitioners.length}`
|
|
7182
|
+
);
|
|
7101
7183
|
}
|
|
7102
7184
|
if (filters.procedureTechnology) {
|
|
7103
7185
|
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7104
7186
|
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
7105
|
-
return proceduresInfo.some(
|
|
7187
|
+
return proceduresInfo.some(
|
|
7188
|
+
(proc) => proc.technologyName === filters.procedureTechnology
|
|
7189
|
+
);
|
|
7106
7190
|
});
|
|
7107
|
-
console.log(
|
|
7191
|
+
console.log(
|
|
7192
|
+
`[PRACTITIONER_SERVICE] Applied procedure technology filter, results: ${filteredPractitioners.length}`
|
|
7193
|
+
);
|
|
7108
7194
|
}
|
|
7109
7195
|
if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
|
|
7110
7196
|
const location = filters.location;
|
|
@@ -7120,7 +7206,9 @@ var PractitionerService = class extends BaseService {
|
|
|
7120
7206
|
return distanceInKm <= radiusInKm;
|
|
7121
7207
|
});
|
|
7122
7208
|
});
|
|
7123
|
-
console.log(
|
|
7209
|
+
console.log(
|
|
7210
|
+
`[PRACTITIONER_SERVICE] Applied geo filter, results: ${filteredPractitioners.length}`
|
|
7211
|
+
);
|
|
7124
7212
|
}
|
|
7125
7213
|
return filteredPractitioners;
|
|
7126
7214
|
}
|
|
@@ -7185,6 +7273,15 @@ var PractitionerService = class extends BaseService {
|
|
|
7185
7273
|
price: 0,
|
|
7186
7274
|
currency: "EUR" /* EUR */,
|
|
7187
7275
|
pricingMeasure: "per_session" /* PER_SESSION */,
|
|
7276
|
+
productsMetadata: [
|
|
7277
|
+
{
|
|
7278
|
+
productId: "free-consultation-product",
|
|
7279
|
+
price: 0,
|
|
7280
|
+
currency: "EUR" /* EUR */,
|
|
7281
|
+
pricingMeasure: "per_session" /* PER_SESSION */,
|
|
7282
|
+
isDefault: true
|
|
7283
|
+
}
|
|
7284
|
+
],
|
|
7188
7285
|
duration: 30,
|
|
7189
7286
|
// 30 minutes consultation
|
|
7190
7287
|
practitionerId,
|
|
@@ -14981,67 +15078,141 @@ import {
|
|
|
14981
15078
|
} from "firebase/firestore";
|
|
14982
15079
|
|
|
14983
15080
|
// src/validations/procedure.schema.ts
|
|
15081
|
+
import { z as z25 } from "zod";
|
|
15082
|
+
|
|
15083
|
+
// src/validations/procedure-product.schema.ts
|
|
14984
15084
|
import { z as z24 } from "zod";
|
|
14985
|
-
var
|
|
14986
|
-
|
|
14987
|
-
|
|
14988
|
-
|
|
14989
|
-
|
|
14990
|
-
|
|
14991
|
-
|
|
14992
|
-
|
|
14993
|
-
|
|
14994
|
-
|
|
14995
|
-
price: z24.number().min(0),
|
|
15085
|
+
var procedureProductDataSchema = z24.object({
|
|
15086
|
+
/**
|
|
15087
|
+
* The ID of the product. Must be a non-empty string.
|
|
15088
|
+
* @validation
|
|
15089
|
+
*/
|
|
15090
|
+
productId: z24.string().min(1, "Product ID is required"),
|
|
15091
|
+
/**
|
|
15092
|
+
* The price of the product. Must be a non-negative number.
|
|
15093
|
+
* @validation
|
|
15094
|
+
*/
|
|
15095
|
+
price: z24.number().min(0, "Price must be a non-negative number"),
|
|
15096
|
+
/**
|
|
15097
|
+
* The currency for the price. Must be one of the values from the Currency enum.
|
|
15098
|
+
* @validation
|
|
15099
|
+
*/
|
|
14996
15100
|
currency: z24.nativeEnum(Currency),
|
|
15101
|
+
/**
|
|
15102
|
+
* The pricing measure for the product. Must be one of the values from the PricingMeasure enum.
|
|
15103
|
+
* @validation
|
|
15104
|
+
*/
|
|
14997
15105
|
pricingMeasure: z24.nativeEnum(PricingMeasure),
|
|
14998
|
-
|
|
15106
|
+
/**
|
|
15107
|
+
* Whether this is the default product for the procedure.
|
|
15108
|
+
* @validation
|
|
15109
|
+
*/
|
|
15110
|
+
isDefault: z24.boolean().optional()
|
|
15111
|
+
});
|
|
15112
|
+
|
|
15113
|
+
// src/validations/procedure.schema.ts
|
|
15114
|
+
var storedProcedureProductSchema = z25.object({
|
|
15115
|
+
/**
|
|
15116
|
+
* The full product object used in the procedure.
|
|
15117
|
+
*/
|
|
15118
|
+
product: z25.any(),
|
|
15119
|
+
// We'll validate the full product object separately
|
|
15120
|
+
/**
|
|
15121
|
+
* The price of the procedure when using this specific product.
|
|
15122
|
+
*/
|
|
15123
|
+
price: z25.number().min(0, "Price must be a non-negative number"),
|
|
15124
|
+
/**
|
|
15125
|
+
* The currency for the price of this product.
|
|
15126
|
+
*/
|
|
15127
|
+
currency: z25.nativeEnum(Currency),
|
|
15128
|
+
/**
|
|
15129
|
+
* How the price is measured (e.g., per ml, per zone).
|
|
15130
|
+
*/
|
|
15131
|
+
pricingMeasure: z25.nativeEnum(PricingMeasure),
|
|
15132
|
+
/**
|
|
15133
|
+
* Whether this is the default product for the procedure.
|
|
15134
|
+
*/
|
|
15135
|
+
isDefault: z25.boolean().optional()
|
|
15136
|
+
});
|
|
15137
|
+
var createProcedureSchema = z25.object({
|
|
15138
|
+
name: z25.string().min(1).max(200),
|
|
15139
|
+
// Optional: service will derive from name if not provided by client
|
|
15140
|
+
nameLower: z25.string().min(1).max(200).optional(),
|
|
15141
|
+
description: z25.string().min(1).max(2e3),
|
|
15142
|
+
family: z25.nativeEnum(ProcedureFamily),
|
|
15143
|
+
categoryId: z25.string().min(1),
|
|
15144
|
+
subcategoryId: z25.string().min(1),
|
|
15145
|
+
technologyId: z25.string().min(1),
|
|
15146
|
+
productId: z25.string().min(1),
|
|
15147
|
+
price: z25.number().min(0),
|
|
15148
|
+
currency: z25.nativeEnum(Currency),
|
|
15149
|
+
pricingMeasure: z25.nativeEnum(PricingMeasure),
|
|
15150
|
+
productsMetadata: z25.array(procedureProductDataSchema).min(1),
|
|
15151
|
+
duration: z25.number().min(1).max(480),
|
|
14999
15152
|
// Max 8 hours
|
|
15000
|
-
practitionerId:
|
|
15001
|
-
clinicBranchId:
|
|
15002
|
-
photos:
|
|
15153
|
+
practitionerId: z25.string().min(1),
|
|
15154
|
+
clinicBranchId: z25.string().min(1),
|
|
15155
|
+
photos: z25.array(mediaResourceSchema).optional()
|
|
15003
15156
|
});
|
|
15004
|
-
var updateProcedureSchema =
|
|
15005
|
-
name:
|
|
15006
|
-
nameLower:
|
|
15007
|
-
description:
|
|
15008
|
-
price:
|
|
15009
|
-
currency:
|
|
15010
|
-
pricingMeasure:
|
|
15011
|
-
|
|
15012
|
-
|
|
15013
|
-
|
|
15014
|
-
|
|
15015
|
-
|
|
15016
|
-
|
|
15017
|
-
|
|
15018
|
-
|
|
15019
|
-
|
|
15157
|
+
var updateProcedureSchema = z25.object({
|
|
15158
|
+
name: z25.string().min(3).max(100).optional(),
|
|
15159
|
+
nameLower: z25.string().min(1).max(200).optional(),
|
|
15160
|
+
description: z25.string().min(3).max(1e3).optional(),
|
|
15161
|
+
price: z25.number().min(0).optional(),
|
|
15162
|
+
currency: z25.nativeEnum(Currency).optional(),
|
|
15163
|
+
pricingMeasure: z25.nativeEnum(PricingMeasure).optional(),
|
|
15164
|
+
productsMetadata: z25.array(procedureProductDataSchema).min(1).optional(),
|
|
15165
|
+
duration: z25.number().min(0).optional(),
|
|
15166
|
+
isActive: z25.boolean().optional(),
|
|
15167
|
+
practitionerId: z25.string().optional(),
|
|
15168
|
+
categoryId: z25.string().optional(),
|
|
15169
|
+
subcategoryId: z25.string().optional(),
|
|
15170
|
+
technologyId: z25.string().optional(),
|
|
15171
|
+
productId: z25.string().optional(),
|
|
15172
|
+
clinicBranchId: z25.string().optional(),
|
|
15173
|
+
photos: z25.array(mediaResourceSchema).optional()
|
|
15020
15174
|
});
|
|
15021
|
-
var procedureSchema =
|
|
15022
|
-
id:
|
|
15023
|
-
|
|
15024
|
-
|
|
15175
|
+
var procedureSchema = z25.object({
|
|
15176
|
+
id: z25.string().min(1),
|
|
15177
|
+
name: z25.string().min(1).max(200),
|
|
15178
|
+
nameLower: z25.string().min(1).max(200),
|
|
15179
|
+
description: z25.string().min(1).max(2e3),
|
|
15180
|
+
family: z25.nativeEnum(ProcedureFamily),
|
|
15181
|
+
category: z25.any(),
|
|
15025
15182
|
// We'll validate the full category object separately
|
|
15026
|
-
subcategory:
|
|
15183
|
+
subcategory: z25.any(),
|
|
15027
15184
|
// We'll validate the full subcategory object separately
|
|
15028
|
-
technology:
|
|
15185
|
+
technology: z25.any(),
|
|
15029
15186
|
// We'll validate the full technology object separately
|
|
15030
|
-
product:
|
|
15187
|
+
product: z25.any(),
|
|
15031
15188
|
// We'll validate the full product object separately
|
|
15032
|
-
|
|
15189
|
+
productsMetadata: z25.array(storedProcedureProductSchema).min(1),
|
|
15190
|
+
// Use stored format schema
|
|
15191
|
+
price: z25.number().min(0),
|
|
15192
|
+
currency: z25.nativeEnum(Currency),
|
|
15193
|
+
pricingMeasure: z25.nativeEnum(PricingMeasure),
|
|
15194
|
+
duration: z25.number().min(1).max(480),
|
|
15195
|
+
practitionerId: z25.string().min(1),
|
|
15196
|
+
clinicBranchId: z25.string().min(1),
|
|
15197
|
+
photos: z25.array(z25.string()).optional(),
|
|
15198
|
+
// Stored as URL strings
|
|
15199
|
+
blockingConditions: z25.array(z25.any()),
|
|
15033
15200
|
// We'll validate blocking conditions separately
|
|
15034
|
-
contraindications:
|
|
15201
|
+
contraindications: z25.array(z25.any()),
|
|
15035
15202
|
// We'll validate contraindications separately
|
|
15036
|
-
|
|
15203
|
+
contraindicationIds: z25.array(z25.string()),
|
|
15204
|
+
// Array of IDs for efficient querying
|
|
15205
|
+
treatmentBenefits: z25.array(z25.any()),
|
|
15037
15206
|
// We'll validate treatment benefits separately
|
|
15038
|
-
|
|
15207
|
+
treatmentBenefitIds: z25.array(z25.string()),
|
|
15208
|
+
// Array of IDs for efficient querying
|
|
15209
|
+
preRequirements: z25.array(z25.any()),
|
|
15039
15210
|
// We'll validate requirements separately
|
|
15040
|
-
postRequirements:
|
|
15211
|
+
postRequirements: z25.array(z25.any()),
|
|
15041
15212
|
// We'll validate requirements separately
|
|
15042
|
-
certificationRequirement:
|
|
15213
|
+
certificationRequirement: z25.any(),
|
|
15043
15214
|
// We'll validate certification requirement separately
|
|
15044
|
-
documentationTemplates:
|
|
15215
|
+
documentationTemplates: z25.array(z25.any()),
|
|
15045
15216
|
// We'll validate documentation templates separately
|
|
15046
15217
|
clinicInfo: clinicInfoSchema,
|
|
15047
15218
|
// Clinic info validation
|
|
@@ -15049,9 +15220,9 @@ var procedureSchema = createProcedureSchema.extend({
|
|
|
15049
15220
|
// Doctor info validation
|
|
15050
15221
|
reviewInfo: procedureReviewInfoSchema,
|
|
15051
15222
|
// Procedure review info validation
|
|
15052
|
-
isActive:
|
|
15053
|
-
createdAt:
|
|
15054
|
-
updatedAt:
|
|
15223
|
+
isActive: z25.boolean(),
|
|
15224
|
+
createdAt: z25.date(),
|
|
15225
|
+
updatedAt: z25.date()
|
|
15055
15226
|
});
|
|
15056
15227
|
|
|
15057
15228
|
// src/services/procedure/procedure.service.ts
|
|
@@ -15078,9 +15249,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15078
15249
|
return media;
|
|
15079
15250
|
}
|
|
15080
15251
|
if (media instanceof File || media instanceof Blob) {
|
|
15081
|
-
console.log(
|
|
15082
|
-
`[ProcedureService] Uploading ${collectionName} media for ${ownerId}`
|
|
15083
|
-
);
|
|
15252
|
+
console.log(`[ProcedureService] Uploading ${collectionName} media for ${ownerId}`);
|
|
15084
15253
|
const metadata = await this.mediaService.uploadMedia(
|
|
15085
15254
|
media,
|
|
15086
15255
|
ownerId,
|
|
@@ -15102,17 +15271,38 @@ var ProcedureService = class extends BaseService {
|
|
|
15102
15271
|
if (!mediaArray || mediaArray.length === 0) return [];
|
|
15103
15272
|
const result = [];
|
|
15104
15273
|
for (const media of mediaArray) {
|
|
15105
|
-
const processedUrl = await this.processMedia(
|
|
15106
|
-
media,
|
|
15107
|
-
ownerId,
|
|
15108
|
-
collectionName
|
|
15109
|
-
);
|
|
15274
|
+
const processedUrl = await this.processMedia(media, ownerId, collectionName);
|
|
15110
15275
|
if (processedUrl) {
|
|
15111
15276
|
result.push(processedUrl);
|
|
15112
15277
|
}
|
|
15113
15278
|
}
|
|
15114
15279
|
return result;
|
|
15115
15280
|
}
|
|
15281
|
+
/**
|
|
15282
|
+
* Transforms validated procedure product data (with productId) to ProcedureProduct objects (with full product)
|
|
15283
|
+
* @param productsMetadata Array of validated procedure product data
|
|
15284
|
+
* @param technologyId Technology ID to fetch products from
|
|
15285
|
+
* @returns Array of ProcedureProduct objects with full product information
|
|
15286
|
+
*/
|
|
15287
|
+
async transformProductsMetadata(productsMetadata, technologyId) {
|
|
15288
|
+
const transformedProducts = [];
|
|
15289
|
+
for (const productData of productsMetadata) {
|
|
15290
|
+
const product = await this.productService.getById(technologyId, productData.productId);
|
|
15291
|
+
if (!product) {
|
|
15292
|
+
throw new Error(
|
|
15293
|
+
`Product with ID ${productData.productId} not found for technology ${technologyId}`
|
|
15294
|
+
);
|
|
15295
|
+
}
|
|
15296
|
+
transformedProducts.push({
|
|
15297
|
+
product,
|
|
15298
|
+
price: productData.price,
|
|
15299
|
+
currency: productData.currency,
|
|
15300
|
+
pricingMeasure: productData.pricingMeasure,
|
|
15301
|
+
isDefault: productData.isDefault
|
|
15302
|
+
});
|
|
15303
|
+
}
|
|
15304
|
+
return transformedProducts;
|
|
15305
|
+
}
|
|
15116
15306
|
/**
|
|
15117
15307
|
* Creates a new procedure
|
|
15118
15308
|
* @param data - The data for creating a new procedure
|
|
@@ -15124,41 +15314,23 @@ var ProcedureService = class extends BaseService {
|
|
|
15124
15314
|
const procedureId = this.generateId();
|
|
15125
15315
|
const [category, subcategory, technology, product] = await Promise.all([
|
|
15126
15316
|
this.categoryService.getById(validatedData.categoryId),
|
|
15127
|
-
this.subcategoryService.getById(
|
|
15128
|
-
validatedData.categoryId,
|
|
15129
|
-
validatedData.subcategoryId
|
|
15130
|
-
),
|
|
15317
|
+
this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
|
|
15131
15318
|
this.technologyService.getById(validatedData.technologyId),
|
|
15132
|
-
this.productService.getById(
|
|
15133
|
-
validatedData.technologyId,
|
|
15134
|
-
validatedData.productId
|
|
15135
|
-
)
|
|
15319
|
+
this.productService.getById(validatedData.technologyId, validatedData.productId)
|
|
15136
15320
|
]);
|
|
15137
15321
|
if (!category || !subcategory || !technology || !product) {
|
|
15138
15322
|
throw new Error("One or more required base entities not found");
|
|
15139
15323
|
}
|
|
15140
|
-
const clinicRef = doc30(
|
|
15141
|
-
this.db,
|
|
15142
|
-
CLINICS_COLLECTION,
|
|
15143
|
-
validatedData.clinicBranchId
|
|
15144
|
-
);
|
|
15324
|
+
const clinicRef = doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId);
|
|
15145
15325
|
const clinicSnapshot = await getDoc32(clinicRef);
|
|
15146
15326
|
if (!clinicSnapshot.exists()) {
|
|
15147
|
-
throw new Error(
|
|
15148
|
-
`Clinic with ID ${validatedData.clinicBranchId} not found`
|
|
15149
|
-
);
|
|
15327
|
+
throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
|
|
15150
15328
|
}
|
|
15151
15329
|
const clinic = clinicSnapshot.data();
|
|
15152
|
-
const practitionerRef = doc30(
|
|
15153
|
-
this.db,
|
|
15154
|
-
PRACTITIONERS_COLLECTION,
|
|
15155
|
-
validatedData.practitionerId
|
|
15156
|
-
);
|
|
15330
|
+
const practitionerRef = doc30(this.db, PRACTITIONERS_COLLECTION, validatedData.practitionerId);
|
|
15157
15331
|
const practitionerSnapshot = await getDoc32(practitionerRef);
|
|
15158
15332
|
if (!practitionerSnapshot.exists()) {
|
|
15159
|
-
throw new Error(
|
|
15160
|
-
`Practitioner with ID ${validatedData.practitionerId} not found`
|
|
15161
|
-
);
|
|
15333
|
+
throw new Error(`Practitioner with ID ${validatedData.practitionerId} not found`);
|
|
15162
15334
|
}
|
|
15163
15335
|
const practitioner = practitionerSnapshot.data();
|
|
15164
15336
|
let processedPhotos = [];
|
|
@@ -15169,6 +15341,10 @@ var ProcedureService = class extends BaseService {
|
|
|
15169
15341
|
"procedure-photos"
|
|
15170
15342
|
);
|
|
15171
15343
|
}
|
|
15344
|
+
const transformedProductsMetadata = await this.transformProductsMetadata(
|
|
15345
|
+
validatedData.productsMetadata,
|
|
15346
|
+
validatedData.technologyId
|
|
15347
|
+
);
|
|
15172
15348
|
const clinicInfo = {
|
|
15173
15349
|
id: clinicSnapshot.id,
|
|
15174
15350
|
name: clinic.name,
|
|
@@ -15186,9 +15362,10 @@ var ProcedureService = class extends BaseService {
|
|
|
15186
15362
|
rating: ((_a = practitioner.reviewInfo) == null ? void 0 : _a.averageRating) || 0,
|
|
15187
15363
|
services: practitioner.procedures || []
|
|
15188
15364
|
};
|
|
15365
|
+
const { productsMetadata: _, ...validatedDataWithoutProductsMetadata } = validatedData;
|
|
15189
15366
|
const newProcedure = {
|
|
15190
15367
|
id: procedureId,
|
|
15191
|
-
...
|
|
15368
|
+
...validatedDataWithoutProductsMetadata,
|
|
15192
15369
|
// Ensure nameLower is always set even if omitted by client
|
|
15193
15370
|
nameLower: validatedData.nameLower || validatedData.name.toLowerCase(),
|
|
15194
15371
|
photos: processedPhotos,
|
|
@@ -15197,6 +15374,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15197
15374
|
subcategory,
|
|
15198
15375
|
technology,
|
|
15199
15376
|
product,
|
|
15377
|
+
productsMetadata: transformedProductsMetadata,
|
|
15378
|
+
// Use transformed data, not original
|
|
15200
15379
|
blockingConditions: technology.blockingConditions,
|
|
15201
15380
|
contraindications: technology.contraindications || [],
|
|
15202
15381
|
contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
|
|
@@ -15250,24 +15429,16 @@ var ProcedureService = class extends BaseService {
|
|
|
15250
15429
|
const validatedData = createProcedureSchema.parse(validationData);
|
|
15251
15430
|
const [category, subcategory, technology, product, clinicSnapshot] = await Promise.all([
|
|
15252
15431
|
this.categoryService.getById(validatedData.categoryId),
|
|
15253
|
-
this.subcategoryService.getById(
|
|
15254
|
-
validatedData.categoryId,
|
|
15255
|
-
validatedData.subcategoryId
|
|
15256
|
-
),
|
|
15432
|
+
this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
|
|
15257
15433
|
this.technologyService.getById(validatedData.technologyId),
|
|
15258
|
-
this.productService.getById(
|
|
15259
|
-
validatedData.technologyId,
|
|
15260
|
-
validatedData.productId
|
|
15261
|
-
),
|
|
15434
|
+
this.productService.getById(validatedData.technologyId, validatedData.productId),
|
|
15262
15435
|
getDoc32(doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId))
|
|
15263
15436
|
]);
|
|
15264
15437
|
if (!category || !subcategory || !technology || !product) {
|
|
15265
15438
|
throw new Error("One or more required base entities not found");
|
|
15266
15439
|
}
|
|
15267
15440
|
if (!clinicSnapshot.exists()) {
|
|
15268
|
-
throw new Error(
|
|
15269
|
-
`Clinic with ID ${validatedData.clinicBranchId} not found`
|
|
15270
|
-
);
|
|
15441
|
+
throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
|
|
15271
15442
|
}
|
|
15272
15443
|
const clinic = clinicSnapshot.data();
|
|
15273
15444
|
let processedPhotos = [];
|
|
@@ -15279,6 +15450,10 @@ var ProcedureService = class extends BaseService {
|
|
|
15279
15450
|
"procedure-photos-batch"
|
|
15280
15451
|
);
|
|
15281
15452
|
}
|
|
15453
|
+
const transformedProductsMetadata = await this.transformProductsMetadata(
|
|
15454
|
+
validatedData.productsMetadata,
|
|
15455
|
+
validatedData.technologyId
|
|
15456
|
+
);
|
|
15282
15457
|
const practitionersMap = /* @__PURE__ */ new Map();
|
|
15283
15458
|
for (let i = 0; i < practitionerIds.length; i += 30) {
|
|
15284
15459
|
const chunk = practitionerIds.slice(i, i + 30);
|
|
@@ -15293,12 +15468,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15293
15468
|
}
|
|
15294
15469
|
if (practitionersMap.size !== practitionerIds.length) {
|
|
15295
15470
|
const foundIds = Array.from(practitionersMap.keys());
|
|
15296
|
-
const notFoundIds = practitionerIds.filter(
|
|
15297
|
-
|
|
15298
|
-
);
|
|
15299
|
-
throw new Error(
|
|
15300
|
-
`The following practitioners were not found: ${notFoundIds.join(", ")}`
|
|
15301
|
-
);
|
|
15471
|
+
const notFoundIds = practitionerIds.filter((id) => !foundIds.includes(id));
|
|
15472
|
+
throw new Error(`The following practitioners were not found: ${notFoundIds.join(", ")}`);
|
|
15302
15473
|
}
|
|
15303
15474
|
const batch = writeBatch6(this.db);
|
|
15304
15475
|
const createdProcedureIds = [];
|
|
@@ -15323,9 +15494,10 @@ var ProcedureService = class extends BaseService {
|
|
|
15323
15494
|
const procedureId = this.generateId();
|
|
15324
15495
|
createdProcedureIds.push(procedureId);
|
|
15325
15496
|
const procedureRef = doc30(this.db, PROCEDURES_COLLECTION, procedureId);
|
|
15497
|
+
const { productsMetadata: _, ...validatedDataWithoutProductsMetadata } = validatedData;
|
|
15326
15498
|
const newProcedure = {
|
|
15327
15499
|
id: procedureId,
|
|
15328
|
-
...
|
|
15500
|
+
...validatedDataWithoutProductsMetadata,
|
|
15329
15501
|
nameLower: validatedData.nameLower || validatedData.name.toLowerCase(),
|
|
15330
15502
|
practitionerId,
|
|
15331
15503
|
// Override practitionerId with the correct one
|
|
@@ -15334,6 +15506,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15334
15506
|
subcategory,
|
|
15335
15507
|
technology,
|
|
15336
15508
|
product,
|
|
15509
|
+
productsMetadata: transformedProductsMetadata,
|
|
15510
|
+
// Use transformed data, not original
|
|
15337
15511
|
blockingConditions: technology.blockingConditions,
|
|
15338
15512
|
contraindications: technology.contraindications || [],
|
|
15339
15513
|
contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
|
|
@@ -15368,10 +15542,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15368
15542
|
const fetchedProcedures = [];
|
|
15369
15543
|
for (let i = 0; i < createdProcedureIds.length; i += 30) {
|
|
15370
15544
|
const chunk = createdProcedureIds.slice(i, i + 30);
|
|
15371
|
-
const q = query29(
|
|
15372
|
-
collection29(this.db, PROCEDURES_COLLECTION),
|
|
15373
|
-
where29(documentId2(), "in", chunk)
|
|
15374
|
-
);
|
|
15545
|
+
const q = query29(collection29(this.db, PROCEDURES_COLLECTION), where29(documentId2(), "in", chunk));
|
|
15375
15546
|
const snapshot = await getDocs29(q);
|
|
15376
15547
|
snapshot.forEach((doc38) => {
|
|
15377
15548
|
fetchedProcedures.push(doc38.data());
|
|
@@ -15441,7 +15612,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15441
15612
|
* @returns The updated procedure
|
|
15442
15613
|
*/
|
|
15443
15614
|
async updateProcedure(id, data) {
|
|
15444
|
-
var _a, _b, _c;
|
|
15615
|
+
var _a, _b, _c, _d;
|
|
15445
15616
|
const validatedData = updateProcedureSchema.parse(data);
|
|
15446
15617
|
const procedureRef = doc30(this.db, PROCEDURES_COLLECTION, id);
|
|
15447
15618
|
const procedureSnapshot = await getDoc32(procedureRef);
|
|
@@ -15449,7 +15620,19 @@ var ProcedureService = class extends BaseService {
|
|
|
15449
15620
|
throw new Error(`Procedure with ID ${id} not found`);
|
|
15450
15621
|
}
|
|
15451
15622
|
const existingProcedure = procedureSnapshot.data();
|
|
15452
|
-
let updatedProcedureData = {
|
|
15623
|
+
let updatedProcedureData = {};
|
|
15624
|
+
if (validatedData.name !== void 0) updatedProcedureData.name = validatedData.name;
|
|
15625
|
+
if (validatedData.description !== void 0)
|
|
15626
|
+
updatedProcedureData.description = validatedData.description;
|
|
15627
|
+
if (validatedData.price !== void 0) updatedProcedureData.price = validatedData.price;
|
|
15628
|
+
if (validatedData.currency !== void 0)
|
|
15629
|
+
updatedProcedureData.currency = validatedData.currency;
|
|
15630
|
+
if (validatedData.pricingMeasure !== void 0)
|
|
15631
|
+
updatedProcedureData.pricingMeasure = validatedData.pricingMeasure;
|
|
15632
|
+
if (validatedData.duration !== void 0)
|
|
15633
|
+
updatedProcedureData.duration = validatedData.duration;
|
|
15634
|
+
if (validatedData.isActive !== void 0)
|
|
15635
|
+
updatedProcedureData.isActive = validatedData.isActive;
|
|
15453
15636
|
let practitionerChanged = false;
|
|
15454
15637
|
let clinicChanged = false;
|
|
15455
15638
|
const oldPractitionerId = existingProcedure.practitionerId;
|
|
@@ -15463,6 +15646,16 @@ var ProcedureService = class extends BaseService {
|
|
|
15463
15646
|
"procedure-photos"
|
|
15464
15647
|
);
|
|
15465
15648
|
}
|
|
15649
|
+
if (validatedData.productsMetadata !== void 0) {
|
|
15650
|
+
const technologyId = (_a = validatedData.technologyId) != null ? _a : existingProcedure.technology.id;
|
|
15651
|
+
if (!technologyId) {
|
|
15652
|
+
throw new Error("Technology ID is required for updating products metadata");
|
|
15653
|
+
}
|
|
15654
|
+
updatedProcedureData.productsMetadata = await this.transformProductsMetadata(
|
|
15655
|
+
validatedData.productsMetadata,
|
|
15656
|
+
technologyId
|
|
15657
|
+
);
|
|
15658
|
+
}
|
|
15466
15659
|
if (validatedData.practitionerId && validatedData.practitionerId !== oldPractitionerId) {
|
|
15467
15660
|
practitionerChanged = true;
|
|
15468
15661
|
const newPractitionerRef = doc30(
|
|
@@ -15472,9 +15665,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15472
15665
|
);
|
|
15473
15666
|
const newPractitionerSnap = await getDoc32(newPractitionerRef);
|
|
15474
15667
|
if (!newPractitionerSnap.exists())
|
|
15475
|
-
throw new Error(
|
|
15476
|
-
`New Practitioner ${validatedData.practitionerId} not found`
|
|
15477
|
-
);
|
|
15668
|
+
throw new Error(`New Practitioner ${validatedData.practitionerId} not found`);
|
|
15478
15669
|
newPractitioner = newPractitionerSnap.data();
|
|
15479
15670
|
updatedProcedureData.doctorInfo = {
|
|
15480
15671
|
id: newPractitioner.id,
|
|
@@ -15482,17 +15673,13 @@ var ProcedureService = class extends BaseService {
|
|
|
15482
15673
|
description: newPractitioner.basicInfo.bio || "",
|
|
15483
15674
|
photo: typeof newPractitioner.basicInfo.profileImageUrl === "string" ? newPractitioner.basicInfo.profileImageUrl : "",
|
|
15484
15675
|
// Default to empty string if not a processed URL
|
|
15485
|
-
rating: ((
|
|
15676
|
+
rating: ((_b = newPractitioner.reviewInfo) == null ? void 0 : _b.averageRating) || 0,
|
|
15486
15677
|
services: newPractitioner.procedures || []
|
|
15487
15678
|
};
|
|
15488
15679
|
}
|
|
15489
15680
|
if (validatedData.clinicBranchId && validatedData.clinicBranchId !== oldClinicId) {
|
|
15490
15681
|
clinicChanged = true;
|
|
15491
|
-
const newClinicRef = doc30(
|
|
15492
|
-
this.db,
|
|
15493
|
-
CLINICS_COLLECTION,
|
|
15494
|
-
validatedData.clinicBranchId
|
|
15495
|
-
);
|
|
15682
|
+
const newClinicRef = doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId);
|
|
15496
15683
|
const newClinicSnap = await getDoc32(newClinicRef);
|
|
15497
15684
|
if (!newClinicSnap.exists())
|
|
15498
15685
|
throw new Error(`New Clinic ${validatedData.clinicBranchId} not found`);
|
|
@@ -15511,11 +15698,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15511
15698
|
updatedProcedureData.nameLower = validatedData.name.toLowerCase();
|
|
15512
15699
|
}
|
|
15513
15700
|
if (validatedData.categoryId) {
|
|
15514
|
-
const category = await this.categoryService.getById(
|
|
15515
|
-
|
|
15516
|
-
);
|
|
15517
|
-
if (!category)
|
|
15518
|
-
throw new Error(`Category ${validatedData.categoryId} not found`);
|
|
15701
|
+
const category = await this.categoryService.getById(validatedData.categoryId);
|
|
15702
|
+
if (!category) throw new Error(`Category ${validatedData.categoryId} not found`);
|
|
15519
15703
|
updatedProcedureData.category = category;
|
|
15520
15704
|
finalCategoryId = category.id;
|
|
15521
15705
|
}
|
|
@@ -15530,34 +15714,26 @@ var ProcedureService = class extends BaseService {
|
|
|
15530
15714
|
);
|
|
15531
15715
|
updatedProcedureData.subcategory = subcategory;
|
|
15532
15716
|
} else if (validatedData.subcategoryId) {
|
|
15533
|
-
console.warn(
|
|
15534
|
-
"Attempted to update subcategory without a valid categoryId"
|
|
15535
|
-
);
|
|
15717
|
+
console.warn("Attempted to update subcategory without a valid categoryId");
|
|
15536
15718
|
}
|
|
15537
15719
|
let finalTechnologyId = existingProcedure.technology.id;
|
|
15538
15720
|
if (validatedData.technologyId) {
|
|
15539
|
-
const technology = await this.technologyService.getById(
|
|
15540
|
-
|
|
15541
|
-
);
|
|
15542
|
-
if (!technology)
|
|
15543
|
-
throw new Error(`Technology ${validatedData.technologyId} not found`);
|
|
15721
|
+
const technology = await this.technologyService.getById(validatedData.technologyId);
|
|
15722
|
+
if (!technology) throw new Error(`Technology ${validatedData.technologyId} not found`);
|
|
15544
15723
|
updatedProcedureData.technology = technology;
|
|
15545
15724
|
finalTechnologyId = technology.id;
|
|
15546
15725
|
updatedProcedureData.blockingConditions = technology.blockingConditions;
|
|
15547
15726
|
updatedProcedureData.contraindications = technology.contraindications || [];
|
|
15548
|
-
updatedProcedureData.contraindicationIds = ((
|
|
15727
|
+
updatedProcedureData.contraindicationIds = ((_c = technology.contraindications) == null ? void 0 : _c.map((c) => c.id)) || [];
|
|
15549
15728
|
updatedProcedureData.treatmentBenefits = technology.benefits;
|
|
15550
|
-
updatedProcedureData.treatmentBenefitIds = ((
|
|
15729
|
+
updatedProcedureData.treatmentBenefitIds = ((_d = technology.benefits) == null ? void 0 : _d.map((b) => b.id)) || [];
|
|
15551
15730
|
updatedProcedureData.preRequirements = technology.requirements.pre;
|
|
15552
15731
|
updatedProcedureData.postRequirements = technology.requirements.post;
|
|
15553
15732
|
updatedProcedureData.certificationRequirement = technology.certificationRequirement;
|
|
15554
15733
|
updatedProcedureData.documentationTemplates = technology.documentationTemplates || [];
|
|
15555
15734
|
}
|
|
15556
15735
|
if (validatedData.productId && finalTechnologyId) {
|
|
15557
|
-
const product = await this.productService.getById(
|
|
15558
|
-
finalTechnologyId,
|
|
15559
|
-
validatedData.productId
|
|
15560
|
-
);
|
|
15736
|
+
const product = await this.productService.getById(finalTechnologyId, validatedData.productId);
|
|
15561
15737
|
if (!product)
|
|
15562
15738
|
throw new Error(
|
|
15563
15739
|
`Product ${validatedData.productId} not found for technology ${finalTechnologyId}`
|
|
@@ -15639,11 +15815,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15639
15815
|
limit21(pagination)
|
|
15640
15816
|
);
|
|
15641
15817
|
} else {
|
|
15642
|
-
proceduresQuery = query29(
|
|
15643
|
-
proceduresCollection,
|
|
15644
|
-
orderBy17("name"),
|
|
15645
|
-
limit21(pagination)
|
|
15646
|
-
);
|
|
15818
|
+
proceduresQuery = query29(proceduresCollection, orderBy17("name"), limit21(pagination));
|
|
15647
15819
|
}
|
|
15648
15820
|
} else {
|
|
15649
15821
|
proceduresQuery = query29(proceduresCollection, orderBy17("name"));
|
|
@@ -15692,9 +15864,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15692
15864
|
*/
|
|
15693
15865
|
async getProceduresByFilters(filters) {
|
|
15694
15866
|
try {
|
|
15695
|
-
console.log(
|
|
15696
|
-
"[PROCEDURE_SERVICE] Starting procedure filtering with multiple strategies"
|
|
15697
|
-
);
|
|
15867
|
+
console.log("[PROCEDURE_SERVICE] Starting procedure filtering with multiple strategies");
|
|
15698
15868
|
if (filters.location && filters.radiusInKm) {
|
|
15699
15869
|
console.log("[PROCEDURE_SERVICE] Executing geo query:", {
|
|
15700
15870
|
location: filters.location,
|
|
@@ -15702,10 +15872,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15702
15872
|
serviceName: "ProcedureService"
|
|
15703
15873
|
});
|
|
15704
15874
|
if (!filters.location.latitude || !filters.location.longitude) {
|
|
15705
|
-
console.warn(
|
|
15706
|
-
"[PROCEDURE_SERVICE] Invalid location data:",
|
|
15707
|
-
filters.location
|
|
15708
|
-
);
|
|
15875
|
+
console.warn("[PROCEDURE_SERVICE] Invalid location data:", filters.location);
|
|
15709
15876
|
filters.location = void 0;
|
|
15710
15877
|
filters.radiusInKm = void 0;
|
|
15711
15878
|
}
|
|
@@ -15725,19 +15892,13 @@ var ProcedureService = class extends BaseService {
|
|
|
15725
15892
|
constraints.push(where29("family", "==", filters.procedureFamily));
|
|
15726
15893
|
}
|
|
15727
15894
|
if (filters.procedureCategory) {
|
|
15728
|
-
constraints.push(
|
|
15729
|
-
where29("category.id", "==", filters.procedureCategory)
|
|
15730
|
-
);
|
|
15895
|
+
constraints.push(where29("category.id", "==", filters.procedureCategory));
|
|
15731
15896
|
}
|
|
15732
15897
|
if (filters.procedureSubcategory) {
|
|
15733
|
-
constraints.push(
|
|
15734
|
-
where29("subcategory.id", "==", filters.procedureSubcategory)
|
|
15735
|
-
);
|
|
15898
|
+
constraints.push(where29("subcategory.id", "==", filters.procedureSubcategory));
|
|
15736
15899
|
}
|
|
15737
15900
|
if (filters.procedureTechnology) {
|
|
15738
|
-
constraints.push(
|
|
15739
|
-
where29("technology.id", "==", filters.procedureTechnology)
|
|
15740
|
-
);
|
|
15901
|
+
constraints.push(where29("technology.id", "==", filters.procedureTechnology));
|
|
15741
15902
|
}
|
|
15742
15903
|
if (filters.minPrice !== void 0) {
|
|
15743
15904
|
constraints.push(where29("price", ">=", filters.minPrice));
|
|
@@ -15746,32 +15907,20 @@ var ProcedureService = class extends BaseService {
|
|
|
15746
15907
|
constraints.push(where29("price", "<=", filters.maxPrice));
|
|
15747
15908
|
}
|
|
15748
15909
|
if (filters.minRating !== void 0) {
|
|
15749
|
-
constraints.push(
|
|
15750
|
-
where29("reviewInfo.averageRating", ">=", filters.minRating)
|
|
15751
|
-
);
|
|
15910
|
+
constraints.push(where29("reviewInfo.averageRating", ">=", filters.minRating));
|
|
15752
15911
|
}
|
|
15753
15912
|
if (filters.maxRating !== void 0) {
|
|
15754
|
-
constraints.push(
|
|
15755
|
-
where29("reviewInfo.averageRating", "<=", filters.maxRating)
|
|
15756
|
-
);
|
|
15913
|
+
constraints.push(where29("reviewInfo.averageRating", "<=", filters.maxRating));
|
|
15757
15914
|
}
|
|
15758
15915
|
if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
|
|
15759
15916
|
const benefitIdsToMatch = filters.treatmentBenefits;
|
|
15760
|
-
constraints.push(
|
|
15761
|
-
where29(
|
|
15762
|
-
"treatmentBenefitIds",
|
|
15763
|
-
"array-contains-any",
|
|
15764
|
-
benefitIdsToMatch
|
|
15765
|
-
)
|
|
15766
|
-
);
|
|
15917
|
+
constraints.push(where29("treatmentBenefitIds", "array-contains-any", benefitIdsToMatch));
|
|
15767
15918
|
}
|
|
15768
15919
|
return constraints;
|
|
15769
15920
|
};
|
|
15770
15921
|
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
15771
15922
|
try {
|
|
15772
|
-
console.log(
|
|
15773
|
-
"[PROCEDURE_SERVICE] Strategy 1: Trying nameLower search"
|
|
15774
|
-
);
|
|
15923
|
+
console.log("[PROCEDURE_SERVICE] Strategy 1: Trying nameLower search");
|
|
15775
15924
|
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
15776
15925
|
const constraints = getBaseConstraints();
|
|
15777
15926
|
constraints.push(where29("nameLower", ">=", searchTerm));
|
|
@@ -15787,18 +15936,13 @@ var ProcedureService = class extends BaseService {
|
|
|
15787
15936
|
}
|
|
15788
15937
|
}
|
|
15789
15938
|
constraints.push(limit15(filters.pagination || 10));
|
|
15790
|
-
const q = query29(
|
|
15791
|
-
collection29(this.db, PROCEDURES_COLLECTION),
|
|
15792
|
-
...constraints
|
|
15793
|
-
);
|
|
15939
|
+
const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15794
15940
|
const querySnapshot = await getDocs29(q);
|
|
15795
15941
|
const procedures = querySnapshot.docs.map(
|
|
15796
15942
|
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
15797
15943
|
);
|
|
15798
15944
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15799
|
-
console.log(
|
|
15800
|
-
`[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`
|
|
15801
|
-
);
|
|
15945
|
+
console.log(`[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`);
|
|
15802
15946
|
if (procedures.length < (filters.pagination || 10)) {
|
|
15803
15947
|
return { procedures, lastDoc: null };
|
|
15804
15948
|
}
|
|
@@ -15809,9 +15953,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15809
15953
|
}
|
|
15810
15954
|
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
15811
15955
|
try {
|
|
15812
|
-
console.log(
|
|
15813
|
-
"[PROCEDURE_SERVICE] Strategy 2: Trying name field search"
|
|
15814
|
-
);
|
|
15956
|
+
console.log("[PROCEDURE_SERVICE] Strategy 2: Trying name field search");
|
|
15815
15957
|
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
15816
15958
|
const constraints = getBaseConstraints();
|
|
15817
15959
|
constraints.push(where29("name", ">=", searchTerm));
|
|
@@ -15827,18 +15969,13 @@ var ProcedureService = class extends BaseService {
|
|
|
15827
15969
|
}
|
|
15828
15970
|
}
|
|
15829
15971
|
constraints.push(limit15(filters.pagination || 10));
|
|
15830
|
-
const q = query29(
|
|
15831
|
-
collection29(this.db, PROCEDURES_COLLECTION),
|
|
15832
|
-
...constraints
|
|
15833
|
-
);
|
|
15972
|
+
const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15834
15973
|
const querySnapshot = await getDocs29(q);
|
|
15835
15974
|
const procedures = querySnapshot.docs.map(
|
|
15836
15975
|
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
15837
15976
|
);
|
|
15838
15977
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15839
|
-
console.log(
|
|
15840
|
-
`[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`
|
|
15841
|
-
);
|
|
15978
|
+
console.log(`[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`);
|
|
15842
15979
|
if (procedures.length < (filters.pagination || 10)) {
|
|
15843
15980
|
return { procedures, lastDoc: null };
|
|
15844
15981
|
}
|
|
@@ -15863,19 +16000,14 @@ var ProcedureService = class extends BaseService {
|
|
|
15863
16000
|
}
|
|
15864
16001
|
}
|
|
15865
16002
|
constraints.push(limit15(filters.pagination || 10));
|
|
15866
|
-
const q = query29(
|
|
15867
|
-
collection29(this.db, PROCEDURES_COLLECTION),
|
|
15868
|
-
...constraints
|
|
15869
|
-
);
|
|
16003
|
+
const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15870
16004
|
const querySnapshot = await getDocs29(q);
|
|
15871
16005
|
let procedures = querySnapshot.docs.map(
|
|
15872
16006
|
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
15873
16007
|
);
|
|
15874
16008
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15875
16009
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15876
|
-
console.log(
|
|
15877
|
-
`[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`
|
|
15878
|
-
);
|
|
16010
|
+
console.log(`[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`);
|
|
15879
16011
|
if (procedures.length < (filters.pagination || 10)) {
|
|
15880
16012
|
return { procedures, lastDoc: null };
|
|
15881
16013
|
}
|
|
@@ -15890,19 +16022,14 @@ var ProcedureService = class extends BaseService {
|
|
|
15890
16022
|
orderBy17("createdAt", "desc"),
|
|
15891
16023
|
limit15(filters.pagination || 10)
|
|
15892
16024
|
];
|
|
15893
|
-
const q = query29(
|
|
15894
|
-
collection29(this.db, PROCEDURES_COLLECTION),
|
|
15895
|
-
...constraints
|
|
15896
|
-
);
|
|
16025
|
+
const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15897
16026
|
const querySnapshot = await getDocs29(q);
|
|
15898
16027
|
let procedures = querySnapshot.docs.map(
|
|
15899
16028
|
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
15900
16029
|
);
|
|
15901
16030
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15902
16031
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15903
|
-
console.log(
|
|
15904
|
-
`[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`
|
|
15905
|
-
);
|
|
16032
|
+
console.log(`[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`);
|
|
15906
16033
|
if (procedures.length < (filters.pagination || 10)) {
|
|
15907
16034
|
return { procedures, lastDoc: null };
|
|
15908
16035
|
}
|
|
@@ -15910,9 +16037,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15910
16037
|
} catch (error) {
|
|
15911
16038
|
console.log("[PROCEDURE_SERVICE] Strategy 4 failed:", error);
|
|
15912
16039
|
}
|
|
15913
|
-
console.log(
|
|
15914
|
-
"[PROCEDURE_SERVICE] All strategies failed, returning empty result"
|
|
15915
|
-
);
|
|
16040
|
+
console.log("[PROCEDURE_SERVICE] All strategies failed, returning empty result");
|
|
15916
16041
|
return { procedures: [], lastDoc: null };
|
|
15917
16042
|
} catch (error) {
|
|
15918
16043
|
console.error("[PROCEDURE_SERVICE] Error filtering procedures:", error);
|
|
@@ -15932,17 +16057,13 @@ var ProcedureService = class extends BaseService {
|
|
|
15932
16057
|
const nameLower = procedure.nameLower || "";
|
|
15933
16058
|
return name.includes(searchTerm) || nameLower.includes(searchTerm);
|
|
15934
16059
|
});
|
|
15935
|
-
console.log(
|
|
15936
|
-
`[PROCEDURE_SERVICE] Applied name filter, results: ${filteredProcedures.length}`
|
|
15937
|
-
);
|
|
16060
|
+
console.log(`[PROCEDURE_SERVICE] Applied name filter, results: ${filteredProcedures.length}`);
|
|
15938
16061
|
}
|
|
15939
16062
|
if (filters.minPrice !== void 0 || filters.maxPrice !== void 0) {
|
|
15940
16063
|
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15941
16064
|
const price = procedure.price || 0;
|
|
15942
|
-
if (filters.minPrice !== void 0 && price < filters.minPrice)
|
|
15943
|
-
|
|
15944
|
-
if (filters.maxPrice !== void 0 && price > filters.maxPrice)
|
|
15945
|
-
return false;
|
|
16065
|
+
if (filters.minPrice !== void 0 && price < filters.minPrice) return false;
|
|
16066
|
+
if (filters.maxPrice !== void 0 && price > filters.maxPrice) return false;
|
|
15946
16067
|
return true;
|
|
15947
16068
|
});
|
|
15948
16069
|
console.log(
|
|
@@ -15953,10 +16074,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15953
16074
|
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15954
16075
|
var _a;
|
|
15955
16076
|
const rating = ((_a = procedure.reviewInfo) == null ? void 0 : _a.averageRating) || 0;
|
|
15956
|
-
if (filters.minRating !== void 0 && rating < filters.minRating)
|
|
15957
|
-
|
|
15958
|
-
if (filters.maxRating !== void 0 && rating > filters.maxRating)
|
|
15959
|
-
return false;
|
|
16077
|
+
if (filters.minRating !== void 0 && rating < filters.minRating) return false;
|
|
16078
|
+
if (filters.maxRating !== void 0 && rating > filters.maxRating) return false;
|
|
15960
16079
|
return true;
|
|
15961
16080
|
});
|
|
15962
16081
|
console.log(
|
|
@@ -16032,12 +16151,8 @@ var ProcedureService = class extends BaseService {
|
|
|
16032
16151
|
procedure.distance = distance;
|
|
16033
16152
|
return distance <= radiusInKm;
|
|
16034
16153
|
});
|
|
16035
|
-
console.log(
|
|
16036
|
-
|
|
16037
|
-
);
|
|
16038
|
-
filteredProcedures.sort(
|
|
16039
|
-
(a, b) => (a.distance || 0) - (b.distance || 0)
|
|
16040
|
-
);
|
|
16154
|
+
console.log(`[PROCEDURE_SERVICE] Applied geo filter, results: ${filteredProcedures.length}`);
|
|
16155
|
+
filteredProcedures.sort((a, b) => (a.distance || 0) - (b.distance || 0));
|
|
16041
16156
|
}
|
|
16042
16157
|
return filteredProcedures;
|
|
16043
16158
|
}
|
|
@@ -16049,30 +16164,19 @@ var ProcedureService = class extends BaseService {
|
|
|
16049
16164
|
if (!location || !radiusInKm) {
|
|
16050
16165
|
return Promise.resolve({ procedures: [], lastDoc: null });
|
|
16051
16166
|
}
|
|
16052
|
-
const bounds = geohashQueryBounds5(
|
|
16053
|
-
[location.latitude, location.longitude],
|
|
16054
|
-
radiusInKm * 1e3
|
|
16055
|
-
);
|
|
16167
|
+
const bounds = geohashQueryBounds5([location.latitude, location.longitude], radiusInKm * 1e3);
|
|
16056
16168
|
const fetches = bounds.map((b) => {
|
|
16057
16169
|
const constraints = [
|
|
16058
16170
|
where29("clinicInfo.location.geohash", ">=", b[0]),
|
|
16059
16171
|
where29("clinicInfo.location.geohash", "<=", b[1]),
|
|
16060
|
-
where29(
|
|
16061
|
-
"isActive",
|
|
16062
|
-
"==",
|
|
16063
|
-
filters.isActive !== void 0 ? filters.isActive : true
|
|
16064
|
-
)
|
|
16172
|
+
where29("isActive", "==", filters.isActive !== void 0 ? filters.isActive : true)
|
|
16065
16173
|
];
|
|
16066
|
-
return getDocs29(
|
|
16067
|
-
query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints)
|
|
16068
|
-
);
|
|
16174
|
+
return getDocs29(query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints));
|
|
16069
16175
|
});
|
|
16070
16176
|
return Promise.all(fetches).then((snaps) => {
|
|
16071
16177
|
const collected = [];
|
|
16072
16178
|
snaps.forEach((snap) => {
|
|
16073
|
-
snap.docs.forEach(
|
|
16074
|
-
(d) => collected.push({ ...d.data(), id: d.id })
|
|
16075
|
-
);
|
|
16179
|
+
snap.docs.forEach((d) => collected.push({ ...d.data(), id: d.id }));
|
|
16076
16180
|
});
|
|
16077
16181
|
const uniqueMap = /* @__PURE__ */ new Map();
|
|
16078
16182
|
for (const p of collected) {
|
|
@@ -16083,9 +16187,7 @@ var ProcedureService = class extends BaseService {
|
|
|
16083
16187
|
const pageSize = filters.pagination || 10;
|
|
16084
16188
|
let startIndex = 0;
|
|
16085
16189
|
if (filters.lastDoc && typeof filters.lastDoc === "object" && filters.lastDoc.id) {
|
|
16086
|
-
const idx = procedures.findIndex(
|
|
16087
|
-
(p) => p.id === filters.lastDoc.id
|
|
16088
|
-
);
|
|
16190
|
+
const idx = procedures.findIndex((p) => p.id === filters.lastDoc.id);
|
|
16089
16191
|
if (idx >= 0) startIndex = idx + 1;
|
|
16090
16192
|
}
|
|
16091
16193
|
const page = procedures.slice(startIndex, startIndex + pageSize);
|
|
@@ -16126,11 +16228,7 @@ var ProcedureService = class extends BaseService {
|
|
|
16126
16228
|
throw new Error(`Clinic with ID ${data.clinicBranchId} not found`);
|
|
16127
16229
|
}
|
|
16128
16230
|
const clinic = clinicSnapshot.data();
|
|
16129
|
-
const practitionerRef = doc30(
|
|
16130
|
-
this.db,
|
|
16131
|
-
PRACTITIONERS_COLLECTION,
|
|
16132
|
-
data.practitionerId
|
|
16133
|
-
);
|
|
16231
|
+
const practitionerRef = doc30(this.db, PRACTITIONERS_COLLECTION, data.practitionerId);
|
|
16134
16232
|
const practitionerSnapshot = await getDoc32(practitionerRef);
|
|
16135
16233
|
if (!practitionerSnapshot.exists()) {
|
|
16136
16234
|
throw new Error(`Practitioner with ID ${data.practitionerId} not found`);
|
|
@@ -16138,12 +16236,12 @@ var ProcedureService = class extends BaseService {
|
|
|
16138
16236
|
const practitioner = practitionerSnapshot.data();
|
|
16139
16237
|
let processedPhotos = [];
|
|
16140
16238
|
if (data.photos && data.photos.length > 0) {
|
|
16141
|
-
processedPhotos = await this.processMediaArray(
|
|
16142
|
-
data.photos,
|
|
16143
|
-
procedureId,
|
|
16144
|
-
"procedure-photos"
|
|
16145
|
-
);
|
|
16239
|
+
processedPhotos = await this.processMediaArray(data.photos, procedureId, "procedure-photos");
|
|
16146
16240
|
}
|
|
16241
|
+
const transformedProductsMetadata = await this.transformProductsMetadata(
|
|
16242
|
+
data.productsMetadata,
|
|
16243
|
+
data.technologyId
|
|
16244
|
+
);
|
|
16147
16245
|
const clinicInfo = {
|
|
16148
16246
|
id: clinicSnapshot.id,
|
|
16149
16247
|
name: clinic.name,
|
|
@@ -16174,9 +16272,10 @@ var ProcedureService = class extends BaseService {
|
|
|
16174
16272
|
createdAt: /* @__PURE__ */ new Date(),
|
|
16175
16273
|
updatedAt: /* @__PURE__ */ new Date()
|
|
16176
16274
|
};
|
|
16275
|
+
const { productsMetadata: _, ...dataWithoutProductsMetadata } = data;
|
|
16177
16276
|
const newProcedure = {
|
|
16178
16277
|
id: procedureId,
|
|
16179
|
-
...
|
|
16278
|
+
...dataWithoutProductsMetadata,
|
|
16180
16279
|
nameLower: data.nameLower || data.name.toLowerCase(),
|
|
16181
16280
|
photos: processedPhotos,
|
|
16182
16281
|
category,
|
|
@@ -16184,6 +16283,8 @@ var ProcedureService = class extends BaseService {
|
|
|
16184
16283
|
technology,
|
|
16185
16284
|
product: consultationProduct,
|
|
16186
16285
|
// Use placeholder product
|
|
16286
|
+
productsMetadata: transformedProductsMetadata,
|
|
16287
|
+
// Use transformed data, not original
|
|
16187
16288
|
blockingConditions: technology.blockingConditions,
|
|
16188
16289
|
contraindications: technology.contraindications || [],
|
|
16189
16290
|
contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
|
|
@@ -16253,7 +16354,7 @@ import {
|
|
|
16253
16354
|
deleteDoc as deleteDoc19,
|
|
16254
16355
|
serverTimestamp as serverTimestamp26
|
|
16255
16356
|
} from "firebase/firestore";
|
|
16256
|
-
import { z as
|
|
16357
|
+
import { z as z26 } from "zod";
|
|
16257
16358
|
var ReviewService = class extends BaseService {
|
|
16258
16359
|
constructor(db, auth, app) {
|
|
16259
16360
|
super(db, auth, app);
|
|
@@ -16340,7 +16441,7 @@ var ReviewService = class extends BaseService {
|
|
|
16340
16441
|
});
|
|
16341
16442
|
return review;
|
|
16342
16443
|
} catch (error) {
|
|
16343
|
-
if (error instanceof
|
|
16444
|
+
if (error instanceof z26.ZodError) {
|
|
16344
16445
|
throw new Error(`Invalid review data: ${error.message}`);
|
|
16345
16446
|
}
|
|
16346
16447
|
throw error;
|