@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.js
CHANGED
|
@@ -6595,7 +6595,9 @@ var PractitionerService = class extends BaseService {
|
|
|
6595
6595
|
throw new Error(`Practitioner ${practitionerId} not found`);
|
|
6596
6596
|
}
|
|
6597
6597
|
const currentPractitioner = practitionerDoc.data();
|
|
6598
|
-
let processedData = {
|
|
6598
|
+
let processedData = {
|
|
6599
|
+
...validData
|
|
6600
|
+
};
|
|
6599
6601
|
if (validData.basicInfo) {
|
|
6600
6602
|
processedData.basicInfo = await this.processBasicInfo(
|
|
6601
6603
|
validData.basicInfo,
|
|
@@ -6829,7 +6831,9 @@ var PractitionerService = class extends BaseService {
|
|
|
6829
6831
|
*/
|
|
6830
6832
|
async getPractitionersByFilters(filters) {
|
|
6831
6833
|
try {
|
|
6832
|
-
console.log(
|
|
6834
|
+
console.log(
|
|
6835
|
+
"[PRACTITIONER_SERVICE] Starting practitioner filtering with fallback strategies"
|
|
6836
|
+
);
|
|
6833
6837
|
if (filters.location && filters.radiusInKm) {
|
|
6834
6838
|
console.log("[PRACTITIONER_SERVICE] Executing geo query:", {
|
|
6835
6839
|
location: filters.location,
|
|
@@ -6837,14 +6841,19 @@ var PractitionerService = class extends BaseService {
|
|
|
6837
6841
|
serviceName: "PractitionerService"
|
|
6838
6842
|
});
|
|
6839
6843
|
if (!filters.location.latitude || !filters.location.longitude) {
|
|
6840
|
-
console.warn(
|
|
6844
|
+
console.warn(
|
|
6845
|
+
"[PRACTITIONER_SERVICE] Invalid location data:",
|
|
6846
|
+
filters.location
|
|
6847
|
+
);
|
|
6841
6848
|
filters.location = void 0;
|
|
6842
6849
|
filters.radiusInKm = void 0;
|
|
6843
6850
|
}
|
|
6844
6851
|
}
|
|
6845
6852
|
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
6846
6853
|
try {
|
|
6847
|
-
console.log(
|
|
6854
|
+
console.log(
|
|
6855
|
+
"[PRACTITIONER_SERVICE] Strategy 1: Trying fullNameLower search"
|
|
6856
|
+
);
|
|
6848
6857
|
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
6849
6858
|
const constraints = [];
|
|
6850
6859
|
if (!filters.includeDraftPractitioners) {
|
|
@@ -6864,11 +6873,18 @@ var PractitionerService = class extends BaseService {
|
|
|
6864
6873
|
}
|
|
6865
6874
|
}
|
|
6866
6875
|
constraints.push((0, import_firestore21.limit)(filters.pagination || 10));
|
|
6867
|
-
const q = (0, import_firestore21.query)(
|
|
6876
|
+
const q = (0, import_firestore21.query)(
|
|
6877
|
+
(0, import_firestore21.collection)(this.db, PRACTITIONERS_COLLECTION),
|
|
6878
|
+
...constraints
|
|
6879
|
+
);
|
|
6868
6880
|
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
6869
|
-
const practitioners = querySnapshot.docs.map(
|
|
6881
|
+
const practitioners = querySnapshot.docs.map(
|
|
6882
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
6883
|
+
);
|
|
6870
6884
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
6871
|
-
console.log(
|
|
6885
|
+
console.log(
|
|
6886
|
+
`[PRACTITIONER_SERVICE] Strategy 1 success: ${practitioners.length} practitioners`
|
|
6887
|
+
);
|
|
6872
6888
|
if (practitioners.length < (filters.pagination || 10)) {
|
|
6873
6889
|
return { practitioners, lastDoc: null };
|
|
6874
6890
|
}
|
|
@@ -6878,7 +6894,9 @@ var PractitionerService = class extends BaseService {
|
|
|
6878
6894
|
}
|
|
6879
6895
|
}
|
|
6880
6896
|
try {
|
|
6881
|
-
console.log(
|
|
6897
|
+
console.log(
|
|
6898
|
+
"[PRACTITIONER_SERVICE] Strategy 2: Basic query with createdAt ordering"
|
|
6899
|
+
);
|
|
6882
6900
|
const constraints = [];
|
|
6883
6901
|
if (!filters.includeDraftPractitioners) {
|
|
6884
6902
|
constraints.push((0, import_firestore21.where)("status", "==", "active" /* ACTIVE */));
|
|
@@ -6887,14 +6905,22 @@ var PractitionerService = class extends BaseService {
|
|
|
6887
6905
|
if (filters.certifications && filters.certifications.length > 0) {
|
|
6888
6906
|
const certificationsToMatch = filters.certifications;
|
|
6889
6907
|
constraints.push(
|
|
6890
|
-
(0, import_firestore21.where)(
|
|
6908
|
+
(0, import_firestore21.where)(
|
|
6909
|
+
"certification.specialties",
|
|
6910
|
+
"array-contains-any",
|
|
6911
|
+
certificationsToMatch
|
|
6912
|
+
)
|
|
6891
6913
|
);
|
|
6892
6914
|
}
|
|
6893
6915
|
if (filters.minRating !== void 0) {
|
|
6894
|
-
constraints.push(
|
|
6916
|
+
constraints.push(
|
|
6917
|
+
(0, import_firestore21.where)("reviewInfo.averageRating", ">=", filters.minRating)
|
|
6918
|
+
);
|
|
6895
6919
|
}
|
|
6896
6920
|
if (filters.maxRating !== void 0) {
|
|
6897
|
-
constraints.push(
|
|
6921
|
+
constraints.push(
|
|
6922
|
+
(0, import_firestore21.where)("reviewInfo.averageRating", "<=", filters.maxRating)
|
|
6923
|
+
);
|
|
6898
6924
|
}
|
|
6899
6925
|
constraints.push((0, import_firestore21.orderBy)("createdAt", "desc"));
|
|
6900
6926
|
if (filters.location && filters.radiusInKm) {
|
|
@@ -6911,9 +6937,14 @@ var PractitionerService = class extends BaseService {
|
|
|
6911
6937
|
}
|
|
6912
6938
|
constraints.push((0, import_firestore21.limit)(filters.pagination || 10));
|
|
6913
6939
|
}
|
|
6914
|
-
const q = (0, import_firestore21.query)(
|
|
6940
|
+
const q = (0, import_firestore21.query)(
|
|
6941
|
+
(0, import_firestore21.collection)(this.db, PRACTITIONERS_COLLECTION),
|
|
6942
|
+
...constraints
|
|
6943
|
+
);
|
|
6915
6944
|
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
6916
|
-
let practitioners = querySnapshot.docs.map(
|
|
6945
|
+
let practitioners = querySnapshot.docs.map(
|
|
6946
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
6947
|
+
);
|
|
6917
6948
|
if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
|
|
6918
6949
|
const location = filters.location;
|
|
6919
6950
|
const radiusInKm = filters.radiusInKm;
|
|
@@ -6932,7 +6963,9 @@ var PractitionerService = class extends BaseService {
|
|
|
6932
6963
|
}
|
|
6933
6964
|
practitioners = this.applyInMemoryFilters(practitioners, filters);
|
|
6934
6965
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
6935
|
-
console.log(
|
|
6966
|
+
console.log(
|
|
6967
|
+
`[PRACTITIONER_SERVICE] Strategy 2 success: ${practitioners.length} practitioners`
|
|
6968
|
+
);
|
|
6936
6969
|
if (practitioners.length < (filters.pagination || 10)) {
|
|
6937
6970
|
return { practitioners, lastDoc: null };
|
|
6938
6971
|
}
|
|
@@ -6941,18 +6974,27 @@ var PractitionerService = class extends BaseService {
|
|
|
6941
6974
|
console.log("[PRACTITIONER_SERVICE] Strategy 2 failed:", error);
|
|
6942
6975
|
}
|
|
6943
6976
|
try {
|
|
6944
|
-
console.log(
|
|
6977
|
+
console.log(
|
|
6978
|
+
"[PRACTITIONER_SERVICE] Strategy 3: Minimal query fallback"
|
|
6979
|
+
);
|
|
6945
6980
|
const constraints = [
|
|
6946
6981
|
(0, import_firestore21.where)("isActive", "==", true),
|
|
6947
6982
|
(0, import_firestore21.orderBy)("createdAt", "desc"),
|
|
6948
6983
|
(0, import_firestore21.limit)(filters.pagination || 10)
|
|
6949
6984
|
];
|
|
6950
|
-
const q = (0, import_firestore21.query)(
|
|
6985
|
+
const q = (0, import_firestore21.query)(
|
|
6986
|
+
(0, import_firestore21.collection)(this.db, PRACTITIONERS_COLLECTION),
|
|
6987
|
+
...constraints
|
|
6988
|
+
);
|
|
6951
6989
|
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
6952
|
-
let practitioners = querySnapshot.docs.map(
|
|
6990
|
+
let practitioners = querySnapshot.docs.map(
|
|
6991
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
6992
|
+
);
|
|
6953
6993
|
practitioners = this.applyInMemoryFilters(practitioners, filters);
|
|
6954
6994
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
6955
|
-
console.log(
|
|
6995
|
+
console.log(
|
|
6996
|
+
`[PRACTITIONER_SERVICE] Strategy 3 success: ${practitioners.length} practitioners`
|
|
6997
|
+
);
|
|
6956
6998
|
if (practitioners.length < (filters.pagination || 10)) {
|
|
6957
6999
|
return { practitioners, lastDoc: null };
|
|
6958
7000
|
}
|
|
@@ -6961,19 +7003,28 @@ var PractitionerService = class extends BaseService {
|
|
|
6961
7003
|
console.log("[PRACTITIONER_SERVICE] Strategy 3 failed:", error);
|
|
6962
7004
|
}
|
|
6963
7005
|
try {
|
|
6964
|
-
console.log(
|
|
7006
|
+
console.log(
|
|
7007
|
+
"[PRACTITIONER_SERVICE] Strategy 4: Client-side filtering fallback"
|
|
7008
|
+
);
|
|
6965
7009
|
const constraints = [
|
|
6966
7010
|
(0, import_firestore21.where)("isActive", "==", true),
|
|
6967
7011
|
(0, import_firestore21.where)("status", "==", "active" /* ACTIVE */),
|
|
6968
7012
|
(0, import_firestore21.orderBy)("createdAt", "desc"),
|
|
6969
7013
|
(0, import_firestore21.limit)(filters.pagination || 10)
|
|
6970
7014
|
];
|
|
6971
|
-
const q = (0, import_firestore21.query)(
|
|
7015
|
+
const q = (0, import_firestore21.query)(
|
|
7016
|
+
(0, import_firestore21.collection)(this.db, PRACTITIONERS_COLLECTION),
|
|
7017
|
+
...constraints
|
|
7018
|
+
);
|
|
6972
7019
|
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
6973
|
-
let practitioners = querySnapshot.docs.map(
|
|
7020
|
+
let practitioners = querySnapshot.docs.map(
|
|
7021
|
+
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
7022
|
+
);
|
|
6974
7023
|
practitioners = this.applyInMemoryFilters(practitioners, filters);
|
|
6975
7024
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
6976
|
-
console.log(
|
|
7025
|
+
console.log(
|
|
7026
|
+
`[PRACTITIONER_SERVICE] Strategy 4 success: ${practitioners.length} practitioners`
|
|
7027
|
+
);
|
|
6977
7028
|
if (practitioners.length < (filters.pagination || 10)) {
|
|
6978
7029
|
return { practitioners, lastDoc: null };
|
|
6979
7030
|
}
|
|
@@ -6981,10 +7032,15 @@ var PractitionerService = class extends BaseService {
|
|
|
6981
7032
|
} catch (error) {
|
|
6982
7033
|
console.log("[PRACTITIONER_SERVICE] Strategy 4 failed:", error);
|
|
6983
7034
|
}
|
|
6984
|
-
console.log(
|
|
7035
|
+
console.log(
|
|
7036
|
+
"[PRACTITIONER_SERVICE] All strategies failed, returning empty result"
|
|
7037
|
+
);
|
|
6985
7038
|
return { practitioners: [], lastDoc: null };
|
|
6986
7039
|
} catch (error) {
|
|
6987
|
-
console.error(
|
|
7040
|
+
console.error(
|
|
7041
|
+
"[PRACTITIONER_SERVICE] Error filtering practitioners:",
|
|
7042
|
+
error
|
|
7043
|
+
);
|
|
6988
7044
|
return { practitioners: [], lastDoc: null };
|
|
6989
7045
|
}
|
|
6990
7046
|
}
|
|
@@ -7004,63 +7060,93 @@ var PractitionerService = class extends BaseService {
|
|
|
7004
7060
|
const fullNameLower = practitioner.fullNameLower || "";
|
|
7005
7061
|
return firstName.includes(searchTerm) || lastName.includes(searchTerm) || fullName.includes(searchTerm) || fullNameLower.includes(searchTerm);
|
|
7006
7062
|
});
|
|
7007
|
-
console.log(
|
|
7063
|
+
console.log(
|
|
7064
|
+
`[PRACTITIONER_SERVICE] Applied name filter, results: ${filteredPractitioners.length}`
|
|
7065
|
+
);
|
|
7008
7066
|
}
|
|
7009
7067
|
if (filters.certifications && filters.certifications.length > 0) {
|
|
7010
7068
|
const certificationsToMatch = filters.certifications;
|
|
7011
7069
|
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7012
7070
|
var _a;
|
|
7013
7071
|
const practitionerCerts = ((_a = practitioner.certification) == null ? void 0 : _a.specialties) || [];
|
|
7014
|
-
return certificationsToMatch.some(
|
|
7072
|
+
return certificationsToMatch.some(
|
|
7073
|
+
(cert) => practitionerCerts.includes(cert)
|
|
7074
|
+
);
|
|
7015
7075
|
});
|
|
7016
|
-
console.log(
|
|
7076
|
+
console.log(
|
|
7077
|
+
`[PRACTITIONER_SERVICE] Applied certifications filter, results: ${filteredPractitioners.length}`
|
|
7078
|
+
);
|
|
7017
7079
|
}
|
|
7018
7080
|
if (filters.specialties && filters.specialties.length > 0) {
|
|
7019
7081
|
const specialtiesToMatch = filters.specialties;
|
|
7020
7082
|
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7021
7083
|
var _a;
|
|
7022
7084
|
const practitionerSpecs = ((_a = practitioner.certification) == null ? void 0 : _a.specialties) || [];
|
|
7023
|
-
return specialtiesToMatch.some(
|
|
7085
|
+
return specialtiesToMatch.some(
|
|
7086
|
+
(spec) => practitionerSpecs.includes(spec)
|
|
7087
|
+
);
|
|
7024
7088
|
});
|
|
7025
|
-
console.log(
|
|
7089
|
+
console.log(
|
|
7090
|
+
`[PRACTITIONER_SERVICE] Applied specialties filter, results: ${filteredPractitioners.length}`
|
|
7091
|
+
);
|
|
7026
7092
|
}
|
|
7027
7093
|
if (filters.minRating !== void 0 || filters.maxRating !== void 0) {
|
|
7028
7094
|
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7029
7095
|
var _a;
|
|
7030
7096
|
const rating = ((_a = practitioner.reviewInfo) == null ? void 0 : _a.averageRating) || 0;
|
|
7031
|
-
if (filters.minRating !== void 0 && rating < filters.minRating)
|
|
7032
|
-
|
|
7097
|
+
if (filters.minRating !== void 0 && rating < filters.minRating)
|
|
7098
|
+
return false;
|
|
7099
|
+
if (filters.maxRating !== void 0 && rating > filters.maxRating)
|
|
7100
|
+
return false;
|
|
7033
7101
|
return true;
|
|
7034
7102
|
});
|
|
7035
|
-
console.log(
|
|
7103
|
+
console.log(
|
|
7104
|
+
`[PRACTITIONER_SERVICE] Applied rating filter, results: ${filteredPractitioners.length}`
|
|
7105
|
+
);
|
|
7036
7106
|
}
|
|
7037
7107
|
if (filters.procedureFamily) {
|
|
7038
7108
|
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7039
7109
|
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
7040
|
-
return proceduresInfo.some(
|
|
7110
|
+
return proceduresInfo.some(
|
|
7111
|
+
(proc) => proc.family === filters.procedureFamily
|
|
7112
|
+
);
|
|
7041
7113
|
});
|
|
7042
|
-
console.log(
|
|
7114
|
+
console.log(
|
|
7115
|
+
`[PRACTITIONER_SERVICE] Applied procedure family filter, results: ${filteredPractitioners.length}`
|
|
7116
|
+
);
|
|
7043
7117
|
}
|
|
7044
7118
|
if (filters.procedureCategory) {
|
|
7045
7119
|
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7046
7120
|
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
7047
|
-
return proceduresInfo.some(
|
|
7121
|
+
return proceduresInfo.some(
|
|
7122
|
+
(proc) => proc.categoryName === filters.procedureCategory
|
|
7123
|
+
);
|
|
7048
7124
|
});
|
|
7049
|
-
console.log(
|
|
7125
|
+
console.log(
|
|
7126
|
+
`[PRACTITIONER_SERVICE] Applied procedure category filter, results: ${filteredPractitioners.length}`
|
|
7127
|
+
);
|
|
7050
7128
|
}
|
|
7051
7129
|
if (filters.procedureSubcategory) {
|
|
7052
7130
|
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7053
7131
|
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
7054
|
-
return proceduresInfo.some(
|
|
7132
|
+
return proceduresInfo.some(
|
|
7133
|
+
(proc) => proc.subcategoryName === filters.procedureSubcategory
|
|
7134
|
+
);
|
|
7055
7135
|
});
|
|
7056
|
-
console.log(
|
|
7136
|
+
console.log(
|
|
7137
|
+
`[PRACTITIONER_SERVICE] Applied procedure subcategory filter, results: ${filteredPractitioners.length}`
|
|
7138
|
+
);
|
|
7057
7139
|
}
|
|
7058
7140
|
if (filters.procedureTechnology) {
|
|
7059
7141
|
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7060
7142
|
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
7061
|
-
return proceduresInfo.some(
|
|
7143
|
+
return proceduresInfo.some(
|
|
7144
|
+
(proc) => proc.technologyName === filters.procedureTechnology
|
|
7145
|
+
);
|
|
7062
7146
|
});
|
|
7063
|
-
console.log(
|
|
7147
|
+
console.log(
|
|
7148
|
+
`[PRACTITIONER_SERVICE] Applied procedure technology filter, results: ${filteredPractitioners.length}`
|
|
7149
|
+
);
|
|
7064
7150
|
}
|
|
7065
7151
|
if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
|
|
7066
7152
|
const location = filters.location;
|
|
@@ -7076,7 +7162,9 @@ var PractitionerService = class extends BaseService {
|
|
|
7076
7162
|
return distanceInKm <= radiusInKm;
|
|
7077
7163
|
});
|
|
7078
7164
|
});
|
|
7079
|
-
console.log(
|
|
7165
|
+
console.log(
|
|
7166
|
+
`[PRACTITIONER_SERVICE] Applied geo filter, results: ${filteredPractitioners.length}`
|
|
7167
|
+
);
|
|
7080
7168
|
}
|
|
7081
7169
|
return filteredPractitioners;
|
|
7082
7170
|
}
|
|
@@ -7141,6 +7229,15 @@ var PractitionerService = class extends BaseService {
|
|
|
7141
7229
|
price: 0,
|
|
7142
7230
|
currency: "EUR" /* EUR */,
|
|
7143
7231
|
pricingMeasure: "per_session" /* PER_SESSION */,
|
|
7232
|
+
productsMetadata: [
|
|
7233
|
+
{
|
|
7234
|
+
productId: "free-consultation-product",
|
|
7235
|
+
price: 0,
|
|
7236
|
+
currency: "EUR" /* EUR */,
|
|
7237
|
+
pricingMeasure: "per_session" /* PER_SESSION */,
|
|
7238
|
+
isDefault: true
|
|
7239
|
+
}
|
|
7240
|
+
],
|
|
7144
7241
|
duration: 30,
|
|
7145
7242
|
// 30 minutes consultation
|
|
7146
7243
|
practitionerId,
|
|
@@ -14732,67 +14829,141 @@ var PatientRequirementsService = class extends BaseService {
|
|
|
14732
14829
|
var import_firestore46 = require("firebase/firestore");
|
|
14733
14830
|
|
|
14734
14831
|
// src/validations/procedure.schema.ts
|
|
14832
|
+
var import_zod25 = require("zod");
|
|
14833
|
+
|
|
14834
|
+
// src/validations/procedure-product.schema.ts
|
|
14735
14835
|
var import_zod24 = require("zod");
|
|
14736
|
-
var
|
|
14737
|
-
|
|
14738
|
-
|
|
14739
|
-
|
|
14740
|
-
|
|
14741
|
-
|
|
14742
|
-
|
|
14743
|
-
|
|
14744
|
-
|
|
14745
|
-
|
|
14746
|
-
price: import_zod24.z.number().min(0),
|
|
14836
|
+
var procedureProductDataSchema = import_zod24.z.object({
|
|
14837
|
+
/**
|
|
14838
|
+
* The ID of the product. Must be a non-empty string.
|
|
14839
|
+
* @validation
|
|
14840
|
+
*/
|
|
14841
|
+
productId: import_zod24.z.string().min(1, "Product ID is required"),
|
|
14842
|
+
/**
|
|
14843
|
+
* The price of the product. Must be a non-negative number.
|
|
14844
|
+
* @validation
|
|
14845
|
+
*/
|
|
14846
|
+
price: import_zod24.z.number().min(0, "Price must be a non-negative number"),
|
|
14847
|
+
/**
|
|
14848
|
+
* The currency for the price. Must be one of the values from the Currency enum.
|
|
14849
|
+
* @validation
|
|
14850
|
+
*/
|
|
14747
14851
|
currency: import_zod24.z.nativeEnum(Currency),
|
|
14852
|
+
/**
|
|
14853
|
+
* The pricing measure for the product. Must be one of the values from the PricingMeasure enum.
|
|
14854
|
+
* @validation
|
|
14855
|
+
*/
|
|
14748
14856
|
pricingMeasure: import_zod24.z.nativeEnum(PricingMeasure),
|
|
14749
|
-
|
|
14857
|
+
/**
|
|
14858
|
+
* Whether this is the default product for the procedure.
|
|
14859
|
+
* @validation
|
|
14860
|
+
*/
|
|
14861
|
+
isDefault: import_zod24.z.boolean().optional()
|
|
14862
|
+
});
|
|
14863
|
+
|
|
14864
|
+
// src/validations/procedure.schema.ts
|
|
14865
|
+
var storedProcedureProductSchema = import_zod25.z.object({
|
|
14866
|
+
/**
|
|
14867
|
+
* The full product object used in the procedure.
|
|
14868
|
+
*/
|
|
14869
|
+
product: import_zod25.z.any(),
|
|
14870
|
+
// We'll validate the full product object separately
|
|
14871
|
+
/**
|
|
14872
|
+
* The price of the procedure when using this specific product.
|
|
14873
|
+
*/
|
|
14874
|
+
price: import_zod25.z.number().min(0, "Price must be a non-negative number"),
|
|
14875
|
+
/**
|
|
14876
|
+
* The currency for the price of this product.
|
|
14877
|
+
*/
|
|
14878
|
+
currency: import_zod25.z.nativeEnum(Currency),
|
|
14879
|
+
/**
|
|
14880
|
+
* How the price is measured (e.g., per ml, per zone).
|
|
14881
|
+
*/
|
|
14882
|
+
pricingMeasure: import_zod25.z.nativeEnum(PricingMeasure),
|
|
14883
|
+
/**
|
|
14884
|
+
* Whether this is the default product for the procedure.
|
|
14885
|
+
*/
|
|
14886
|
+
isDefault: import_zod25.z.boolean().optional()
|
|
14887
|
+
});
|
|
14888
|
+
var createProcedureSchema = import_zod25.z.object({
|
|
14889
|
+
name: import_zod25.z.string().min(1).max(200),
|
|
14890
|
+
// Optional: service will derive from name if not provided by client
|
|
14891
|
+
nameLower: import_zod25.z.string().min(1).max(200).optional(),
|
|
14892
|
+
description: import_zod25.z.string().min(1).max(2e3),
|
|
14893
|
+
family: import_zod25.z.nativeEnum(ProcedureFamily),
|
|
14894
|
+
categoryId: import_zod25.z.string().min(1),
|
|
14895
|
+
subcategoryId: import_zod25.z.string().min(1),
|
|
14896
|
+
technologyId: import_zod25.z.string().min(1),
|
|
14897
|
+
productId: import_zod25.z.string().min(1),
|
|
14898
|
+
price: import_zod25.z.number().min(0),
|
|
14899
|
+
currency: import_zod25.z.nativeEnum(Currency),
|
|
14900
|
+
pricingMeasure: import_zod25.z.nativeEnum(PricingMeasure),
|
|
14901
|
+
productsMetadata: import_zod25.z.array(procedureProductDataSchema).min(1),
|
|
14902
|
+
duration: import_zod25.z.number().min(1).max(480),
|
|
14750
14903
|
// Max 8 hours
|
|
14751
|
-
practitionerId:
|
|
14752
|
-
clinicBranchId:
|
|
14753
|
-
photos:
|
|
14904
|
+
practitionerId: import_zod25.z.string().min(1),
|
|
14905
|
+
clinicBranchId: import_zod25.z.string().min(1),
|
|
14906
|
+
photos: import_zod25.z.array(mediaResourceSchema).optional()
|
|
14754
14907
|
});
|
|
14755
|
-
var updateProcedureSchema =
|
|
14756
|
-
name:
|
|
14757
|
-
nameLower:
|
|
14758
|
-
description:
|
|
14759
|
-
price:
|
|
14760
|
-
currency:
|
|
14761
|
-
pricingMeasure:
|
|
14762
|
-
|
|
14763
|
-
|
|
14764
|
-
|
|
14765
|
-
|
|
14766
|
-
|
|
14767
|
-
|
|
14768
|
-
|
|
14769
|
-
|
|
14770
|
-
|
|
14908
|
+
var updateProcedureSchema = import_zod25.z.object({
|
|
14909
|
+
name: import_zod25.z.string().min(3).max(100).optional(),
|
|
14910
|
+
nameLower: import_zod25.z.string().min(1).max(200).optional(),
|
|
14911
|
+
description: import_zod25.z.string().min(3).max(1e3).optional(),
|
|
14912
|
+
price: import_zod25.z.number().min(0).optional(),
|
|
14913
|
+
currency: import_zod25.z.nativeEnum(Currency).optional(),
|
|
14914
|
+
pricingMeasure: import_zod25.z.nativeEnum(PricingMeasure).optional(),
|
|
14915
|
+
productsMetadata: import_zod25.z.array(procedureProductDataSchema).min(1).optional(),
|
|
14916
|
+
duration: import_zod25.z.number().min(0).optional(),
|
|
14917
|
+
isActive: import_zod25.z.boolean().optional(),
|
|
14918
|
+
practitionerId: import_zod25.z.string().optional(),
|
|
14919
|
+
categoryId: import_zod25.z.string().optional(),
|
|
14920
|
+
subcategoryId: import_zod25.z.string().optional(),
|
|
14921
|
+
technologyId: import_zod25.z.string().optional(),
|
|
14922
|
+
productId: import_zod25.z.string().optional(),
|
|
14923
|
+
clinicBranchId: import_zod25.z.string().optional(),
|
|
14924
|
+
photos: import_zod25.z.array(mediaResourceSchema).optional()
|
|
14771
14925
|
});
|
|
14772
|
-
var procedureSchema =
|
|
14773
|
-
id:
|
|
14774
|
-
|
|
14775
|
-
|
|
14926
|
+
var procedureSchema = import_zod25.z.object({
|
|
14927
|
+
id: import_zod25.z.string().min(1),
|
|
14928
|
+
name: import_zod25.z.string().min(1).max(200),
|
|
14929
|
+
nameLower: import_zod25.z.string().min(1).max(200),
|
|
14930
|
+
description: import_zod25.z.string().min(1).max(2e3),
|
|
14931
|
+
family: import_zod25.z.nativeEnum(ProcedureFamily),
|
|
14932
|
+
category: import_zod25.z.any(),
|
|
14776
14933
|
// We'll validate the full category object separately
|
|
14777
|
-
subcategory:
|
|
14934
|
+
subcategory: import_zod25.z.any(),
|
|
14778
14935
|
// We'll validate the full subcategory object separately
|
|
14779
|
-
technology:
|
|
14936
|
+
technology: import_zod25.z.any(),
|
|
14780
14937
|
// We'll validate the full technology object separately
|
|
14781
|
-
product:
|
|
14938
|
+
product: import_zod25.z.any(),
|
|
14782
14939
|
// We'll validate the full product object separately
|
|
14783
|
-
|
|
14940
|
+
productsMetadata: import_zod25.z.array(storedProcedureProductSchema).min(1),
|
|
14941
|
+
// Use stored format schema
|
|
14942
|
+
price: import_zod25.z.number().min(0),
|
|
14943
|
+
currency: import_zod25.z.nativeEnum(Currency),
|
|
14944
|
+
pricingMeasure: import_zod25.z.nativeEnum(PricingMeasure),
|
|
14945
|
+
duration: import_zod25.z.number().min(1).max(480),
|
|
14946
|
+
practitionerId: import_zod25.z.string().min(1),
|
|
14947
|
+
clinicBranchId: import_zod25.z.string().min(1),
|
|
14948
|
+
photos: import_zod25.z.array(import_zod25.z.string()).optional(),
|
|
14949
|
+
// Stored as URL strings
|
|
14950
|
+
blockingConditions: import_zod25.z.array(import_zod25.z.any()),
|
|
14784
14951
|
// We'll validate blocking conditions separately
|
|
14785
|
-
contraindications:
|
|
14952
|
+
contraindications: import_zod25.z.array(import_zod25.z.any()),
|
|
14786
14953
|
// We'll validate contraindications separately
|
|
14787
|
-
|
|
14954
|
+
contraindicationIds: import_zod25.z.array(import_zod25.z.string()),
|
|
14955
|
+
// Array of IDs for efficient querying
|
|
14956
|
+
treatmentBenefits: import_zod25.z.array(import_zod25.z.any()),
|
|
14788
14957
|
// We'll validate treatment benefits separately
|
|
14789
|
-
|
|
14958
|
+
treatmentBenefitIds: import_zod25.z.array(import_zod25.z.string()),
|
|
14959
|
+
// Array of IDs for efficient querying
|
|
14960
|
+
preRequirements: import_zod25.z.array(import_zod25.z.any()),
|
|
14790
14961
|
// We'll validate requirements separately
|
|
14791
|
-
postRequirements:
|
|
14962
|
+
postRequirements: import_zod25.z.array(import_zod25.z.any()),
|
|
14792
14963
|
// We'll validate requirements separately
|
|
14793
|
-
certificationRequirement:
|
|
14964
|
+
certificationRequirement: import_zod25.z.any(),
|
|
14794
14965
|
// We'll validate certification requirement separately
|
|
14795
|
-
documentationTemplates:
|
|
14966
|
+
documentationTemplates: import_zod25.z.array(import_zod25.z.any()),
|
|
14796
14967
|
// We'll validate documentation templates separately
|
|
14797
14968
|
clinicInfo: clinicInfoSchema,
|
|
14798
14969
|
// Clinic info validation
|
|
@@ -14800,9 +14971,9 @@ var procedureSchema = createProcedureSchema.extend({
|
|
|
14800
14971
|
// Doctor info validation
|
|
14801
14972
|
reviewInfo: procedureReviewInfoSchema,
|
|
14802
14973
|
// Procedure review info validation
|
|
14803
|
-
isActive:
|
|
14804
|
-
createdAt:
|
|
14805
|
-
updatedAt:
|
|
14974
|
+
isActive: import_zod25.z.boolean(),
|
|
14975
|
+
createdAt: import_zod25.z.date(),
|
|
14976
|
+
updatedAt: import_zod25.z.date()
|
|
14806
14977
|
});
|
|
14807
14978
|
|
|
14808
14979
|
// src/services/procedure/procedure.service.ts
|
|
@@ -14829,9 +15000,7 @@ var ProcedureService = class extends BaseService {
|
|
|
14829
15000
|
return media;
|
|
14830
15001
|
}
|
|
14831
15002
|
if (media instanceof File || media instanceof Blob) {
|
|
14832
|
-
console.log(
|
|
14833
|
-
`[ProcedureService] Uploading ${collectionName} media for ${ownerId}`
|
|
14834
|
-
);
|
|
15003
|
+
console.log(`[ProcedureService] Uploading ${collectionName} media for ${ownerId}`);
|
|
14835
15004
|
const metadata = await this.mediaService.uploadMedia(
|
|
14836
15005
|
media,
|
|
14837
15006
|
ownerId,
|
|
@@ -14853,17 +15022,38 @@ var ProcedureService = class extends BaseService {
|
|
|
14853
15022
|
if (!mediaArray || mediaArray.length === 0) return [];
|
|
14854
15023
|
const result = [];
|
|
14855
15024
|
for (const media of mediaArray) {
|
|
14856
|
-
const processedUrl = await this.processMedia(
|
|
14857
|
-
media,
|
|
14858
|
-
ownerId,
|
|
14859
|
-
collectionName
|
|
14860
|
-
);
|
|
15025
|
+
const processedUrl = await this.processMedia(media, ownerId, collectionName);
|
|
14861
15026
|
if (processedUrl) {
|
|
14862
15027
|
result.push(processedUrl);
|
|
14863
15028
|
}
|
|
14864
15029
|
}
|
|
14865
15030
|
return result;
|
|
14866
15031
|
}
|
|
15032
|
+
/**
|
|
15033
|
+
* Transforms validated procedure product data (with productId) to ProcedureProduct objects (with full product)
|
|
15034
|
+
* @param productsMetadata Array of validated procedure product data
|
|
15035
|
+
* @param technologyId Technology ID to fetch products from
|
|
15036
|
+
* @returns Array of ProcedureProduct objects with full product information
|
|
15037
|
+
*/
|
|
15038
|
+
async transformProductsMetadata(productsMetadata, technologyId) {
|
|
15039
|
+
const transformedProducts = [];
|
|
15040
|
+
for (const productData of productsMetadata) {
|
|
15041
|
+
const product = await this.productService.getById(technologyId, productData.productId);
|
|
15042
|
+
if (!product) {
|
|
15043
|
+
throw new Error(
|
|
15044
|
+
`Product with ID ${productData.productId} not found for technology ${technologyId}`
|
|
15045
|
+
);
|
|
15046
|
+
}
|
|
15047
|
+
transformedProducts.push({
|
|
15048
|
+
product,
|
|
15049
|
+
price: productData.price,
|
|
15050
|
+
currency: productData.currency,
|
|
15051
|
+
pricingMeasure: productData.pricingMeasure,
|
|
15052
|
+
isDefault: productData.isDefault
|
|
15053
|
+
});
|
|
15054
|
+
}
|
|
15055
|
+
return transformedProducts;
|
|
15056
|
+
}
|
|
14867
15057
|
/**
|
|
14868
15058
|
* Creates a new procedure
|
|
14869
15059
|
* @param data - The data for creating a new procedure
|
|
@@ -14875,41 +15065,23 @@ var ProcedureService = class extends BaseService {
|
|
|
14875
15065
|
const procedureId = this.generateId();
|
|
14876
15066
|
const [category, subcategory, technology, product] = await Promise.all([
|
|
14877
15067
|
this.categoryService.getById(validatedData.categoryId),
|
|
14878
|
-
this.subcategoryService.getById(
|
|
14879
|
-
validatedData.categoryId,
|
|
14880
|
-
validatedData.subcategoryId
|
|
14881
|
-
),
|
|
15068
|
+
this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
|
|
14882
15069
|
this.technologyService.getById(validatedData.technologyId),
|
|
14883
|
-
this.productService.getById(
|
|
14884
|
-
validatedData.technologyId,
|
|
14885
|
-
validatedData.productId
|
|
14886
|
-
)
|
|
15070
|
+
this.productService.getById(validatedData.technologyId, validatedData.productId)
|
|
14887
15071
|
]);
|
|
14888
15072
|
if (!category || !subcategory || !technology || !product) {
|
|
14889
15073
|
throw new Error("One or more required base entities not found");
|
|
14890
15074
|
}
|
|
14891
|
-
const clinicRef = (0, import_firestore46.doc)(
|
|
14892
|
-
this.db,
|
|
14893
|
-
CLINICS_COLLECTION,
|
|
14894
|
-
validatedData.clinicBranchId
|
|
14895
|
-
);
|
|
15075
|
+
const clinicRef = (0, import_firestore46.doc)(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId);
|
|
14896
15076
|
const clinicSnapshot = await (0, import_firestore46.getDoc)(clinicRef);
|
|
14897
15077
|
if (!clinicSnapshot.exists()) {
|
|
14898
|
-
throw new Error(
|
|
14899
|
-
`Clinic with ID ${validatedData.clinicBranchId} not found`
|
|
14900
|
-
);
|
|
15078
|
+
throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
|
|
14901
15079
|
}
|
|
14902
15080
|
const clinic = clinicSnapshot.data();
|
|
14903
|
-
const practitionerRef = (0, import_firestore46.doc)(
|
|
14904
|
-
this.db,
|
|
14905
|
-
PRACTITIONERS_COLLECTION,
|
|
14906
|
-
validatedData.practitionerId
|
|
14907
|
-
);
|
|
15081
|
+
const practitionerRef = (0, import_firestore46.doc)(this.db, PRACTITIONERS_COLLECTION, validatedData.practitionerId);
|
|
14908
15082
|
const practitionerSnapshot = await (0, import_firestore46.getDoc)(practitionerRef);
|
|
14909
15083
|
if (!practitionerSnapshot.exists()) {
|
|
14910
|
-
throw new Error(
|
|
14911
|
-
`Practitioner with ID ${validatedData.practitionerId} not found`
|
|
14912
|
-
);
|
|
15084
|
+
throw new Error(`Practitioner with ID ${validatedData.practitionerId} not found`);
|
|
14913
15085
|
}
|
|
14914
15086
|
const practitioner = practitionerSnapshot.data();
|
|
14915
15087
|
let processedPhotos = [];
|
|
@@ -14920,6 +15092,10 @@ var ProcedureService = class extends BaseService {
|
|
|
14920
15092
|
"procedure-photos"
|
|
14921
15093
|
);
|
|
14922
15094
|
}
|
|
15095
|
+
const transformedProductsMetadata = await this.transformProductsMetadata(
|
|
15096
|
+
validatedData.productsMetadata,
|
|
15097
|
+
validatedData.technologyId
|
|
15098
|
+
);
|
|
14923
15099
|
const clinicInfo = {
|
|
14924
15100
|
id: clinicSnapshot.id,
|
|
14925
15101
|
name: clinic.name,
|
|
@@ -14937,9 +15113,10 @@ var ProcedureService = class extends BaseService {
|
|
|
14937
15113
|
rating: ((_a = practitioner.reviewInfo) == null ? void 0 : _a.averageRating) || 0,
|
|
14938
15114
|
services: practitioner.procedures || []
|
|
14939
15115
|
};
|
|
15116
|
+
const { productsMetadata: _, ...validatedDataWithoutProductsMetadata } = validatedData;
|
|
14940
15117
|
const newProcedure = {
|
|
14941
15118
|
id: procedureId,
|
|
14942
|
-
...
|
|
15119
|
+
...validatedDataWithoutProductsMetadata,
|
|
14943
15120
|
// Ensure nameLower is always set even if omitted by client
|
|
14944
15121
|
nameLower: validatedData.nameLower || validatedData.name.toLowerCase(),
|
|
14945
15122
|
photos: processedPhotos,
|
|
@@ -14948,6 +15125,8 @@ var ProcedureService = class extends BaseService {
|
|
|
14948
15125
|
subcategory,
|
|
14949
15126
|
technology,
|
|
14950
15127
|
product,
|
|
15128
|
+
productsMetadata: transformedProductsMetadata,
|
|
15129
|
+
// Use transformed data, not original
|
|
14951
15130
|
blockingConditions: technology.blockingConditions,
|
|
14952
15131
|
contraindications: technology.contraindications || [],
|
|
14953
15132
|
contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
|
|
@@ -15001,24 +15180,16 @@ var ProcedureService = class extends BaseService {
|
|
|
15001
15180
|
const validatedData = createProcedureSchema.parse(validationData);
|
|
15002
15181
|
const [category, subcategory, technology, product, clinicSnapshot] = await Promise.all([
|
|
15003
15182
|
this.categoryService.getById(validatedData.categoryId),
|
|
15004
|
-
this.subcategoryService.getById(
|
|
15005
|
-
validatedData.categoryId,
|
|
15006
|
-
validatedData.subcategoryId
|
|
15007
|
-
),
|
|
15183
|
+
this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
|
|
15008
15184
|
this.technologyService.getById(validatedData.technologyId),
|
|
15009
|
-
this.productService.getById(
|
|
15010
|
-
validatedData.technologyId,
|
|
15011
|
-
validatedData.productId
|
|
15012
|
-
),
|
|
15185
|
+
this.productService.getById(validatedData.technologyId, validatedData.productId),
|
|
15013
15186
|
(0, import_firestore46.getDoc)((0, import_firestore46.doc)(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId))
|
|
15014
15187
|
]);
|
|
15015
15188
|
if (!category || !subcategory || !technology || !product) {
|
|
15016
15189
|
throw new Error("One or more required base entities not found");
|
|
15017
15190
|
}
|
|
15018
15191
|
if (!clinicSnapshot.exists()) {
|
|
15019
|
-
throw new Error(
|
|
15020
|
-
`Clinic with ID ${validatedData.clinicBranchId} not found`
|
|
15021
|
-
);
|
|
15192
|
+
throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
|
|
15022
15193
|
}
|
|
15023
15194
|
const clinic = clinicSnapshot.data();
|
|
15024
15195
|
let processedPhotos = [];
|
|
@@ -15030,6 +15201,10 @@ var ProcedureService = class extends BaseService {
|
|
|
15030
15201
|
"procedure-photos-batch"
|
|
15031
15202
|
);
|
|
15032
15203
|
}
|
|
15204
|
+
const transformedProductsMetadata = await this.transformProductsMetadata(
|
|
15205
|
+
validatedData.productsMetadata,
|
|
15206
|
+
validatedData.technologyId
|
|
15207
|
+
);
|
|
15033
15208
|
const practitionersMap = /* @__PURE__ */ new Map();
|
|
15034
15209
|
for (let i = 0; i < practitionerIds.length; i += 30) {
|
|
15035
15210
|
const chunk = practitionerIds.slice(i, i + 30);
|
|
@@ -15044,12 +15219,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15044
15219
|
}
|
|
15045
15220
|
if (practitionersMap.size !== practitionerIds.length) {
|
|
15046
15221
|
const foundIds = Array.from(practitionersMap.keys());
|
|
15047
|
-
const notFoundIds = practitionerIds.filter(
|
|
15048
|
-
|
|
15049
|
-
);
|
|
15050
|
-
throw new Error(
|
|
15051
|
-
`The following practitioners were not found: ${notFoundIds.join(", ")}`
|
|
15052
|
-
);
|
|
15222
|
+
const notFoundIds = practitionerIds.filter((id) => !foundIds.includes(id));
|
|
15223
|
+
throw new Error(`The following practitioners were not found: ${notFoundIds.join(", ")}`);
|
|
15053
15224
|
}
|
|
15054
15225
|
const batch = (0, import_firestore46.writeBatch)(this.db);
|
|
15055
15226
|
const createdProcedureIds = [];
|
|
@@ -15074,9 +15245,10 @@ var ProcedureService = class extends BaseService {
|
|
|
15074
15245
|
const procedureId = this.generateId();
|
|
15075
15246
|
createdProcedureIds.push(procedureId);
|
|
15076
15247
|
const procedureRef = (0, import_firestore46.doc)(this.db, PROCEDURES_COLLECTION, procedureId);
|
|
15248
|
+
const { productsMetadata: _, ...validatedDataWithoutProductsMetadata } = validatedData;
|
|
15077
15249
|
const newProcedure = {
|
|
15078
15250
|
id: procedureId,
|
|
15079
|
-
...
|
|
15251
|
+
...validatedDataWithoutProductsMetadata,
|
|
15080
15252
|
nameLower: validatedData.nameLower || validatedData.name.toLowerCase(),
|
|
15081
15253
|
practitionerId,
|
|
15082
15254
|
// Override practitionerId with the correct one
|
|
@@ -15085,6 +15257,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15085
15257
|
subcategory,
|
|
15086
15258
|
technology,
|
|
15087
15259
|
product,
|
|
15260
|
+
productsMetadata: transformedProductsMetadata,
|
|
15261
|
+
// Use transformed data, not original
|
|
15088
15262
|
blockingConditions: technology.blockingConditions,
|
|
15089
15263
|
contraindications: technology.contraindications || [],
|
|
15090
15264
|
contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
|
|
@@ -15119,10 +15293,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15119
15293
|
const fetchedProcedures = [];
|
|
15120
15294
|
for (let i = 0; i < createdProcedureIds.length; i += 30) {
|
|
15121
15295
|
const chunk = createdProcedureIds.slice(i, i + 30);
|
|
15122
|
-
const q = (0, import_firestore46.query)(
|
|
15123
|
-
(0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION),
|
|
15124
|
-
(0, import_firestore46.where)((0, import_firestore46.documentId)(), "in", chunk)
|
|
15125
|
-
);
|
|
15296
|
+
const q = (0, import_firestore46.query)((0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION), (0, import_firestore46.where)((0, import_firestore46.documentId)(), "in", chunk));
|
|
15126
15297
|
const snapshot = await (0, import_firestore46.getDocs)(q);
|
|
15127
15298
|
snapshot.forEach((doc38) => {
|
|
15128
15299
|
fetchedProcedures.push(doc38.data());
|
|
@@ -15192,7 +15363,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15192
15363
|
* @returns The updated procedure
|
|
15193
15364
|
*/
|
|
15194
15365
|
async updateProcedure(id, data) {
|
|
15195
|
-
var _a, _b, _c;
|
|
15366
|
+
var _a, _b, _c, _d;
|
|
15196
15367
|
const validatedData = updateProcedureSchema.parse(data);
|
|
15197
15368
|
const procedureRef = (0, import_firestore46.doc)(this.db, PROCEDURES_COLLECTION, id);
|
|
15198
15369
|
const procedureSnapshot = await (0, import_firestore46.getDoc)(procedureRef);
|
|
@@ -15200,7 +15371,19 @@ var ProcedureService = class extends BaseService {
|
|
|
15200
15371
|
throw new Error(`Procedure with ID ${id} not found`);
|
|
15201
15372
|
}
|
|
15202
15373
|
const existingProcedure = procedureSnapshot.data();
|
|
15203
|
-
let updatedProcedureData = {
|
|
15374
|
+
let updatedProcedureData = {};
|
|
15375
|
+
if (validatedData.name !== void 0) updatedProcedureData.name = validatedData.name;
|
|
15376
|
+
if (validatedData.description !== void 0)
|
|
15377
|
+
updatedProcedureData.description = validatedData.description;
|
|
15378
|
+
if (validatedData.price !== void 0) updatedProcedureData.price = validatedData.price;
|
|
15379
|
+
if (validatedData.currency !== void 0)
|
|
15380
|
+
updatedProcedureData.currency = validatedData.currency;
|
|
15381
|
+
if (validatedData.pricingMeasure !== void 0)
|
|
15382
|
+
updatedProcedureData.pricingMeasure = validatedData.pricingMeasure;
|
|
15383
|
+
if (validatedData.duration !== void 0)
|
|
15384
|
+
updatedProcedureData.duration = validatedData.duration;
|
|
15385
|
+
if (validatedData.isActive !== void 0)
|
|
15386
|
+
updatedProcedureData.isActive = validatedData.isActive;
|
|
15204
15387
|
let practitionerChanged = false;
|
|
15205
15388
|
let clinicChanged = false;
|
|
15206
15389
|
const oldPractitionerId = existingProcedure.practitionerId;
|
|
@@ -15214,6 +15397,16 @@ var ProcedureService = class extends BaseService {
|
|
|
15214
15397
|
"procedure-photos"
|
|
15215
15398
|
);
|
|
15216
15399
|
}
|
|
15400
|
+
if (validatedData.productsMetadata !== void 0) {
|
|
15401
|
+
const technologyId = (_a = validatedData.technologyId) != null ? _a : existingProcedure.technology.id;
|
|
15402
|
+
if (!technologyId) {
|
|
15403
|
+
throw new Error("Technology ID is required for updating products metadata");
|
|
15404
|
+
}
|
|
15405
|
+
updatedProcedureData.productsMetadata = await this.transformProductsMetadata(
|
|
15406
|
+
validatedData.productsMetadata,
|
|
15407
|
+
technologyId
|
|
15408
|
+
);
|
|
15409
|
+
}
|
|
15217
15410
|
if (validatedData.practitionerId && validatedData.practitionerId !== oldPractitionerId) {
|
|
15218
15411
|
practitionerChanged = true;
|
|
15219
15412
|
const newPractitionerRef = (0, import_firestore46.doc)(
|
|
@@ -15223,9 +15416,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15223
15416
|
);
|
|
15224
15417
|
const newPractitionerSnap = await (0, import_firestore46.getDoc)(newPractitionerRef);
|
|
15225
15418
|
if (!newPractitionerSnap.exists())
|
|
15226
|
-
throw new Error(
|
|
15227
|
-
`New Practitioner ${validatedData.practitionerId} not found`
|
|
15228
|
-
);
|
|
15419
|
+
throw new Error(`New Practitioner ${validatedData.practitionerId} not found`);
|
|
15229
15420
|
newPractitioner = newPractitionerSnap.data();
|
|
15230
15421
|
updatedProcedureData.doctorInfo = {
|
|
15231
15422
|
id: newPractitioner.id,
|
|
@@ -15233,17 +15424,13 @@ var ProcedureService = class extends BaseService {
|
|
|
15233
15424
|
description: newPractitioner.basicInfo.bio || "",
|
|
15234
15425
|
photo: typeof newPractitioner.basicInfo.profileImageUrl === "string" ? newPractitioner.basicInfo.profileImageUrl : "",
|
|
15235
15426
|
// Default to empty string if not a processed URL
|
|
15236
|
-
rating: ((
|
|
15427
|
+
rating: ((_b = newPractitioner.reviewInfo) == null ? void 0 : _b.averageRating) || 0,
|
|
15237
15428
|
services: newPractitioner.procedures || []
|
|
15238
15429
|
};
|
|
15239
15430
|
}
|
|
15240
15431
|
if (validatedData.clinicBranchId && validatedData.clinicBranchId !== oldClinicId) {
|
|
15241
15432
|
clinicChanged = true;
|
|
15242
|
-
const newClinicRef = (0, import_firestore46.doc)(
|
|
15243
|
-
this.db,
|
|
15244
|
-
CLINICS_COLLECTION,
|
|
15245
|
-
validatedData.clinicBranchId
|
|
15246
|
-
);
|
|
15433
|
+
const newClinicRef = (0, import_firestore46.doc)(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId);
|
|
15247
15434
|
const newClinicSnap = await (0, import_firestore46.getDoc)(newClinicRef);
|
|
15248
15435
|
if (!newClinicSnap.exists())
|
|
15249
15436
|
throw new Error(`New Clinic ${validatedData.clinicBranchId} not found`);
|
|
@@ -15262,11 +15449,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15262
15449
|
updatedProcedureData.nameLower = validatedData.name.toLowerCase();
|
|
15263
15450
|
}
|
|
15264
15451
|
if (validatedData.categoryId) {
|
|
15265
|
-
const category = await this.categoryService.getById(
|
|
15266
|
-
|
|
15267
|
-
);
|
|
15268
|
-
if (!category)
|
|
15269
|
-
throw new Error(`Category ${validatedData.categoryId} not found`);
|
|
15452
|
+
const category = await this.categoryService.getById(validatedData.categoryId);
|
|
15453
|
+
if (!category) throw new Error(`Category ${validatedData.categoryId} not found`);
|
|
15270
15454
|
updatedProcedureData.category = category;
|
|
15271
15455
|
finalCategoryId = category.id;
|
|
15272
15456
|
}
|
|
@@ -15281,34 +15465,26 @@ var ProcedureService = class extends BaseService {
|
|
|
15281
15465
|
);
|
|
15282
15466
|
updatedProcedureData.subcategory = subcategory;
|
|
15283
15467
|
} else if (validatedData.subcategoryId) {
|
|
15284
|
-
console.warn(
|
|
15285
|
-
"Attempted to update subcategory without a valid categoryId"
|
|
15286
|
-
);
|
|
15468
|
+
console.warn("Attempted to update subcategory without a valid categoryId");
|
|
15287
15469
|
}
|
|
15288
15470
|
let finalTechnologyId = existingProcedure.technology.id;
|
|
15289
15471
|
if (validatedData.technologyId) {
|
|
15290
|
-
const technology = await this.technologyService.getById(
|
|
15291
|
-
|
|
15292
|
-
);
|
|
15293
|
-
if (!technology)
|
|
15294
|
-
throw new Error(`Technology ${validatedData.technologyId} not found`);
|
|
15472
|
+
const technology = await this.technologyService.getById(validatedData.technologyId);
|
|
15473
|
+
if (!technology) throw new Error(`Technology ${validatedData.technologyId} not found`);
|
|
15295
15474
|
updatedProcedureData.technology = technology;
|
|
15296
15475
|
finalTechnologyId = technology.id;
|
|
15297
15476
|
updatedProcedureData.blockingConditions = technology.blockingConditions;
|
|
15298
15477
|
updatedProcedureData.contraindications = technology.contraindications || [];
|
|
15299
|
-
updatedProcedureData.contraindicationIds = ((
|
|
15478
|
+
updatedProcedureData.contraindicationIds = ((_c = technology.contraindications) == null ? void 0 : _c.map((c) => c.id)) || [];
|
|
15300
15479
|
updatedProcedureData.treatmentBenefits = technology.benefits;
|
|
15301
|
-
updatedProcedureData.treatmentBenefitIds = ((
|
|
15480
|
+
updatedProcedureData.treatmentBenefitIds = ((_d = technology.benefits) == null ? void 0 : _d.map((b) => b.id)) || [];
|
|
15302
15481
|
updatedProcedureData.preRequirements = technology.requirements.pre;
|
|
15303
15482
|
updatedProcedureData.postRequirements = technology.requirements.post;
|
|
15304
15483
|
updatedProcedureData.certificationRequirement = technology.certificationRequirement;
|
|
15305
15484
|
updatedProcedureData.documentationTemplates = technology.documentationTemplates || [];
|
|
15306
15485
|
}
|
|
15307
15486
|
if (validatedData.productId && finalTechnologyId) {
|
|
15308
|
-
const product = await this.productService.getById(
|
|
15309
|
-
finalTechnologyId,
|
|
15310
|
-
validatedData.productId
|
|
15311
|
-
);
|
|
15487
|
+
const product = await this.productService.getById(finalTechnologyId, validatedData.productId);
|
|
15312
15488
|
if (!product)
|
|
15313
15489
|
throw new Error(
|
|
15314
15490
|
`Product ${validatedData.productId} not found for technology ${finalTechnologyId}`
|
|
@@ -15390,11 +15566,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15390
15566
|
limit21(pagination)
|
|
15391
15567
|
);
|
|
15392
15568
|
} else {
|
|
15393
|
-
proceduresQuery = (0, import_firestore46.query)(
|
|
15394
|
-
proceduresCollection,
|
|
15395
|
-
(0, import_firestore46.orderBy)("name"),
|
|
15396
|
-
limit21(pagination)
|
|
15397
|
-
);
|
|
15569
|
+
proceduresQuery = (0, import_firestore46.query)(proceduresCollection, (0, import_firestore46.orderBy)("name"), limit21(pagination));
|
|
15398
15570
|
}
|
|
15399
15571
|
} else {
|
|
15400
15572
|
proceduresQuery = (0, import_firestore46.query)(proceduresCollection, (0, import_firestore46.orderBy)("name"));
|
|
@@ -15443,9 +15615,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15443
15615
|
*/
|
|
15444
15616
|
async getProceduresByFilters(filters) {
|
|
15445
15617
|
try {
|
|
15446
|
-
console.log(
|
|
15447
|
-
"[PROCEDURE_SERVICE] Starting procedure filtering with multiple strategies"
|
|
15448
|
-
);
|
|
15618
|
+
console.log("[PROCEDURE_SERVICE] Starting procedure filtering with multiple strategies");
|
|
15449
15619
|
if (filters.location && filters.radiusInKm) {
|
|
15450
15620
|
console.log("[PROCEDURE_SERVICE] Executing geo query:", {
|
|
15451
15621
|
location: filters.location,
|
|
@@ -15453,10 +15623,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15453
15623
|
serviceName: "ProcedureService"
|
|
15454
15624
|
});
|
|
15455
15625
|
if (!filters.location.latitude || !filters.location.longitude) {
|
|
15456
|
-
console.warn(
|
|
15457
|
-
"[PROCEDURE_SERVICE] Invalid location data:",
|
|
15458
|
-
filters.location
|
|
15459
|
-
);
|
|
15626
|
+
console.warn("[PROCEDURE_SERVICE] Invalid location data:", filters.location);
|
|
15460
15627
|
filters.location = void 0;
|
|
15461
15628
|
filters.radiusInKm = void 0;
|
|
15462
15629
|
}
|
|
@@ -15476,19 +15643,13 @@ var ProcedureService = class extends BaseService {
|
|
|
15476
15643
|
constraints.push((0, import_firestore46.where)("family", "==", filters.procedureFamily));
|
|
15477
15644
|
}
|
|
15478
15645
|
if (filters.procedureCategory) {
|
|
15479
|
-
constraints.push(
|
|
15480
|
-
(0, import_firestore46.where)("category.id", "==", filters.procedureCategory)
|
|
15481
|
-
);
|
|
15646
|
+
constraints.push((0, import_firestore46.where)("category.id", "==", filters.procedureCategory));
|
|
15482
15647
|
}
|
|
15483
15648
|
if (filters.procedureSubcategory) {
|
|
15484
|
-
constraints.push(
|
|
15485
|
-
(0, import_firestore46.where)("subcategory.id", "==", filters.procedureSubcategory)
|
|
15486
|
-
);
|
|
15649
|
+
constraints.push((0, import_firestore46.where)("subcategory.id", "==", filters.procedureSubcategory));
|
|
15487
15650
|
}
|
|
15488
15651
|
if (filters.procedureTechnology) {
|
|
15489
|
-
constraints.push(
|
|
15490
|
-
(0, import_firestore46.where)("technology.id", "==", filters.procedureTechnology)
|
|
15491
|
-
);
|
|
15652
|
+
constraints.push((0, import_firestore46.where)("technology.id", "==", filters.procedureTechnology));
|
|
15492
15653
|
}
|
|
15493
15654
|
if (filters.minPrice !== void 0) {
|
|
15494
15655
|
constraints.push((0, import_firestore46.where)("price", ">=", filters.minPrice));
|
|
@@ -15497,32 +15658,20 @@ var ProcedureService = class extends BaseService {
|
|
|
15497
15658
|
constraints.push((0, import_firestore46.where)("price", "<=", filters.maxPrice));
|
|
15498
15659
|
}
|
|
15499
15660
|
if (filters.minRating !== void 0) {
|
|
15500
|
-
constraints.push(
|
|
15501
|
-
(0, import_firestore46.where)("reviewInfo.averageRating", ">=", filters.minRating)
|
|
15502
|
-
);
|
|
15661
|
+
constraints.push((0, import_firestore46.where)("reviewInfo.averageRating", ">=", filters.minRating));
|
|
15503
15662
|
}
|
|
15504
15663
|
if (filters.maxRating !== void 0) {
|
|
15505
|
-
constraints.push(
|
|
15506
|
-
(0, import_firestore46.where)("reviewInfo.averageRating", "<=", filters.maxRating)
|
|
15507
|
-
);
|
|
15664
|
+
constraints.push((0, import_firestore46.where)("reviewInfo.averageRating", "<=", filters.maxRating));
|
|
15508
15665
|
}
|
|
15509
15666
|
if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
|
|
15510
15667
|
const benefitIdsToMatch = filters.treatmentBenefits;
|
|
15511
|
-
constraints.push(
|
|
15512
|
-
(0, import_firestore46.where)(
|
|
15513
|
-
"treatmentBenefitIds",
|
|
15514
|
-
"array-contains-any",
|
|
15515
|
-
benefitIdsToMatch
|
|
15516
|
-
)
|
|
15517
|
-
);
|
|
15668
|
+
constraints.push((0, import_firestore46.where)("treatmentBenefitIds", "array-contains-any", benefitIdsToMatch));
|
|
15518
15669
|
}
|
|
15519
15670
|
return constraints;
|
|
15520
15671
|
};
|
|
15521
15672
|
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
15522
15673
|
try {
|
|
15523
|
-
console.log(
|
|
15524
|
-
"[PROCEDURE_SERVICE] Strategy 1: Trying nameLower search"
|
|
15525
|
-
);
|
|
15674
|
+
console.log("[PROCEDURE_SERVICE] Strategy 1: Trying nameLower search");
|
|
15526
15675
|
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
15527
15676
|
const constraints = getBaseConstraints();
|
|
15528
15677
|
constraints.push((0, import_firestore46.where)("nameLower", ">=", searchTerm));
|
|
@@ -15538,18 +15687,13 @@ var ProcedureService = class extends BaseService {
|
|
|
15538
15687
|
}
|
|
15539
15688
|
}
|
|
15540
15689
|
constraints.push((0, import_firestore46.limit)(filters.pagination || 10));
|
|
15541
|
-
const q = (0, import_firestore46.query)(
|
|
15542
|
-
(0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION),
|
|
15543
|
-
...constraints
|
|
15544
|
-
);
|
|
15690
|
+
const q = (0, import_firestore46.query)((0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15545
15691
|
const querySnapshot = await (0, import_firestore46.getDocs)(q);
|
|
15546
15692
|
const procedures = querySnapshot.docs.map(
|
|
15547
15693
|
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
15548
15694
|
);
|
|
15549
15695
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15550
|
-
console.log(
|
|
15551
|
-
`[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`
|
|
15552
|
-
);
|
|
15696
|
+
console.log(`[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`);
|
|
15553
15697
|
if (procedures.length < (filters.pagination || 10)) {
|
|
15554
15698
|
return { procedures, lastDoc: null };
|
|
15555
15699
|
}
|
|
@@ -15560,9 +15704,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15560
15704
|
}
|
|
15561
15705
|
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
15562
15706
|
try {
|
|
15563
|
-
console.log(
|
|
15564
|
-
"[PROCEDURE_SERVICE] Strategy 2: Trying name field search"
|
|
15565
|
-
);
|
|
15707
|
+
console.log("[PROCEDURE_SERVICE] Strategy 2: Trying name field search");
|
|
15566
15708
|
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
15567
15709
|
const constraints = getBaseConstraints();
|
|
15568
15710
|
constraints.push((0, import_firestore46.where)("name", ">=", searchTerm));
|
|
@@ -15578,18 +15720,13 @@ var ProcedureService = class extends BaseService {
|
|
|
15578
15720
|
}
|
|
15579
15721
|
}
|
|
15580
15722
|
constraints.push((0, import_firestore46.limit)(filters.pagination || 10));
|
|
15581
|
-
const q = (0, import_firestore46.query)(
|
|
15582
|
-
(0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION),
|
|
15583
|
-
...constraints
|
|
15584
|
-
);
|
|
15723
|
+
const q = (0, import_firestore46.query)((0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15585
15724
|
const querySnapshot = await (0, import_firestore46.getDocs)(q);
|
|
15586
15725
|
const procedures = querySnapshot.docs.map(
|
|
15587
15726
|
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
15588
15727
|
);
|
|
15589
15728
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15590
|
-
console.log(
|
|
15591
|
-
`[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`
|
|
15592
|
-
);
|
|
15729
|
+
console.log(`[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`);
|
|
15593
15730
|
if (procedures.length < (filters.pagination || 10)) {
|
|
15594
15731
|
return { procedures, lastDoc: null };
|
|
15595
15732
|
}
|
|
@@ -15614,19 +15751,14 @@ var ProcedureService = class extends BaseService {
|
|
|
15614
15751
|
}
|
|
15615
15752
|
}
|
|
15616
15753
|
constraints.push((0, import_firestore46.limit)(filters.pagination || 10));
|
|
15617
|
-
const q = (0, import_firestore46.query)(
|
|
15618
|
-
(0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION),
|
|
15619
|
-
...constraints
|
|
15620
|
-
);
|
|
15754
|
+
const q = (0, import_firestore46.query)((0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15621
15755
|
const querySnapshot = await (0, import_firestore46.getDocs)(q);
|
|
15622
15756
|
let procedures = querySnapshot.docs.map(
|
|
15623
15757
|
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
15624
15758
|
);
|
|
15625
15759
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15626
15760
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15627
|
-
console.log(
|
|
15628
|
-
`[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`
|
|
15629
|
-
);
|
|
15761
|
+
console.log(`[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`);
|
|
15630
15762
|
if (procedures.length < (filters.pagination || 10)) {
|
|
15631
15763
|
return { procedures, lastDoc: null };
|
|
15632
15764
|
}
|
|
@@ -15641,19 +15773,14 @@ var ProcedureService = class extends BaseService {
|
|
|
15641
15773
|
(0, import_firestore46.orderBy)("createdAt", "desc"),
|
|
15642
15774
|
(0, import_firestore46.limit)(filters.pagination || 10)
|
|
15643
15775
|
];
|
|
15644
|
-
const q = (0, import_firestore46.query)(
|
|
15645
|
-
(0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION),
|
|
15646
|
-
...constraints
|
|
15647
|
-
);
|
|
15776
|
+
const q = (0, import_firestore46.query)((0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15648
15777
|
const querySnapshot = await (0, import_firestore46.getDocs)(q);
|
|
15649
15778
|
let procedures = querySnapshot.docs.map(
|
|
15650
15779
|
(doc38) => ({ ...doc38.data(), id: doc38.id })
|
|
15651
15780
|
);
|
|
15652
15781
|
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15653
15782
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15654
|
-
console.log(
|
|
15655
|
-
`[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`
|
|
15656
|
-
);
|
|
15783
|
+
console.log(`[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`);
|
|
15657
15784
|
if (procedures.length < (filters.pagination || 10)) {
|
|
15658
15785
|
return { procedures, lastDoc: null };
|
|
15659
15786
|
}
|
|
@@ -15661,9 +15788,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15661
15788
|
} catch (error) {
|
|
15662
15789
|
console.log("[PROCEDURE_SERVICE] Strategy 4 failed:", error);
|
|
15663
15790
|
}
|
|
15664
|
-
console.log(
|
|
15665
|
-
"[PROCEDURE_SERVICE] All strategies failed, returning empty result"
|
|
15666
|
-
);
|
|
15791
|
+
console.log("[PROCEDURE_SERVICE] All strategies failed, returning empty result");
|
|
15667
15792
|
return { procedures: [], lastDoc: null };
|
|
15668
15793
|
} catch (error) {
|
|
15669
15794
|
console.error("[PROCEDURE_SERVICE] Error filtering procedures:", error);
|
|
@@ -15683,17 +15808,13 @@ var ProcedureService = class extends BaseService {
|
|
|
15683
15808
|
const nameLower = procedure.nameLower || "";
|
|
15684
15809
|
return name.includes(searchTerm) || nameLower.includes(searchTerm);
|
|
15685
15810
|
});
|
|
15686
|
-
console.log(
|
|
15687
|
-
`[PROCEDURE_SERVICE] Applied name filter, results: ${filteredProcedures.length}`
|
|
15688
|
-
);
|
|
15811
|
+
console.log(`[PROCEDURE_SERVICE] Applied name filter, results: ${filteredProcedures.length}`);
|
|
15689
15812
|
}
|
|
15690
15813
|
if (filters.minPrice !== void 0 || filters.maxPrice !== void 0) {
|
|
15691
15814
|
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15692
15815
|
const price = procedure.price || 0;
|
|
15693
|
-
if (filters.minPrice !== void 0 && price < filters.minPrice)
|
|
15694
|
-
|
|
15695
|
-
if (filters.maxPrice !== void 0 && price > filters.maxPrice)
|
|
15696
|
-
return false;
|
|
15816
|
+
if (filters.minPrice !== void 0 && price < filters.minPrice) return false;
|
|
15817
|
+
if (filters.maxPrice !== void 0 && price > filters.maxPrice) return false;
|
|
15697
15818
|
return true;
|
|
15698
15819
|
});
|
|
15699
15820
|
console.log(
|
|
@@ -15704,10 +15825,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15704
15825
|
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15705
15826
|
var _a;
|
|
15706
15827
|
const rating = ((_a = procedure.reviewInfo) == null ? void 0 : _a.averageRating) || 0;
|
|
15707
|
-
if (filters.minRating !== void 0 && rating < filters.minRating)
|
|
15708
|
-
|
|
15709
|
-
if (filters.maxRating !== void 0 && rating > filters.maxRating)
|
|
15710
|
-
return false;
|
|
15828
|
+
if (filters.minRating !== void 0 && rating < filters.minRating) return false;
|
|
15829
|
+
if (filters.maxRating !== void 0 && rating > filters.maxRating) return false;
|
|
15711
15830
|
return true;
|
|
15712
15831
|
});
|
|
15713
15832
|
console.log(
|
|
@@ -15783,12 +15902,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15783
15902
|
procedure.distance = distance;
|
|
15784
15903
|
return distance <= radiusInKm;
|
|
15785
15904
|
});
|
|
15786
|
-
console.log(
|
|
15787
|
-
|
|
15788
|
-
);
|
|
15789
|
-
filteredProcedures.sort(
|
|
15790
|
-
(a, b) => (a.distance || 0) - (b.distance || 0)
|
|
15791
|
-
);
|
|
15905
|
+
console.log(`[PROCEDURE_SERVICE] Applied geo filter, results: ${filteredProcedures.length}`);
|
|
15906
|
+
filteredProcedures.sort((a, b) => (a.distance || 0) - (b.distance || 0));
|
|
15792
15907
|
}
|
|
15793
15908
|
return filteredProcedures;
|
|
15794
15909
|
}
|
|
@@ -15800,30 +15915,19 @@ var ProcedureService = class extends BaseService {
|
|
|
15800
15915
|
if (!location || !radiusInKm) {
|
|
15801
15916
|
return Promise.resolve({ procedures: [], lastDoc: null });
|
|
15802
15917
|
}
|
|
15803
|
-
const bounds = (0, import_geofire_common8.geohashQueryBounds)(
|
|
15804
|
-
[location.latitude, location.longitude],
|
|
15805
|
-
radiusInKm * 1e3
|
|
15806
|
-
);
|
|
15918
|
+
const bounds = (0, import_geofire_common8.geohashQueryBounds)([location.latitude, location.longitude], radiusInKm * 1e3);
|
|
15807
15919
|
const fetches = bounds.map((b) => {
|
|
15808
15920
|
const constraints = [
|
|
15809
15921
|
(0, import_firestore46.where)("clinicInfo.location.geohash", ">=", b[0]),
|
|
15810
15922
|
(0, import_firestore46.where)("clinicInfo.location.geohash", "<=", b[1]),
|
|
15811
|
-
(0, import_firestore46.where)(
|
|
15812
|
-
"isActive",
|
|
15813
|
-
"==",
|
|
15814
|
-
filters.isActive !== void 0 ? filters.isActive : true
|
|
15815
|
-
)
|
|
15923
|
+
(0, import_firestore46.where)("isActive", "==", filters.isActive !== void 0 ? filters.isActive : true)
|
|
15816
15924
|
];
|
|
15817
|
-
return (0, import_firestore46.getDocs)(
|
|
15818
|
-
(0, import_firestore46.query)((0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION), ...constraints)
|
|
15819
|
-
);
|
|
15925
|
+
return (0, import_firestore46.getDocs)((0, import_firestore46.query)((0, import_firestore46.collection)(this.db, PROCEDURES_COLLECTION), ...constraints));
|
|
15820
15926
|
});
|
|
15821
15927
|
return Promise.all(fetches).then((snaps) => {
|
|
15822
15928
|
const collected = [];
|
|
15823
15929
|
snaps.forEach((snap) => {
|
|
15824
|
-
snap.docs.forEach(
|
|
15825
|
-
(d) => collected.push({ ...d.data(), id: d.id })
|
|
15826
|
-
);
|
|
15930
|
+
snap.docs.forEach((d) => collected.push({ ...d.data(), id: d.id }));
|
|
15827
15931
|
});
|
|
15828
15932
|
const uniqueMap = /* @__PURE__ */ new Map();
|
|
15829
15933
|
for (const p of collected) {
|
|
@@ -15834,9 +15938,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15834
15938
|
const pageSize = filters.pagination || 10;
|
|
15835
15939
|
let startIndex = 0;
|
|
15836
15940
|
if (filters.lastDoc && typeof filters.lastDoc === "object" && filters.lastDoc.id) {
|
|
15837
|
-
const idx = procedures.findIndex(
|
|
15838
|
-
(p) => p.id === filters.lastDoc.id
|
|
15839
|
-
);
|
|
15941
|
+
const idx = procedures.findIndex((p) => p.id === filters.lastDoc.id);
|
|
15840
15942
|
if (idx >= 0) startIndex = idx + 1;
|
|
15841
15943
|
}
|
|
15842
15944
|
const page = procedures.slice(startIndex, startIndex + pageSize);
|
|
@@ -15877,11 +15979,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15877
15979
|
throw new Error(`Clinic with ID ${data.clinicBranchId} not found`);
|
|
15878
15980
|
}
|
|
15879
15981
|
const clinic = clinicSnapshot.data();
|
|
15880
|
-
const practitionerRef = (0, import_firestore46.doc)(
|
|
15881
|
-
this.db,
|
|
15882
|
-
PRACTITIONERS_COLLECTION,
|
|
15883
|
-
data.practitionerId
|
|
15884
|
-
);
|
|
15982
|
+
const practitionerRef = (0, import_firestore46.doc)(this.db, PRACTITIONERS_COLLECTION, data.practitionerId);
|
|
15885
15983
|
const practitionerSnapshot = await (0, import_firestore46.getDoc)(practitionerRef);
|
|
15886
15984
|
if (!practitionerSnapshot.exists()) {
|
|
15887
15985
|
throw new Error(`Practitioner with ID ${data.practitionerId} not found`);
|
|
@@ -15889,12 +15987,12 @@ var ProcedureService = class extends BaseService {
|
|
|
15889
15987
|
const practitioner = practitionerSnapshot.data();
|
|
15890
15988
|
let processedPhotos = [];
|
|
15891
15989
|
if (data.photos && data.photos.length > 0) {
|
|
15892
|
-
processedPhotos = await this.processMediaArray(
|
|
15893
|
-
data.photos,
|
|
15894
|
-
procedureId,
|
|
15895
|
-
"procedure-photos"
|
|
15896
|
-
);
|
|
15990
|
+
processedPhotos = await this.processMediaArray(data.photos, procedureId, "procedure-photos");
|
|
15897
15991
|
}
|
|
15992
|
+
const transformedProductsMetadata = await this.transformProductsMetadata(
|
|
15993
|
+
data.productsMetadata,
|
|
15994
|
+
data.technologyId
|
|
15995
|
+
);
|
|
15898
15996
|
const clinicInfo = {
|
|
15899
15997
|
id: clinicSnapshot.id,
|
|
15900
15998
|
name: clinic.name,
|
|
@@ -15925,9 +16023,10 @@ var ProcedureService = class extends BaseService {
|
|
|
15925
16023
|
createdAt: /* @__PURE__ */ new Date(),
|
|
15926
16024
|
updatedAt: /* @__PURE__ */ new Date()
|
|
15927
16025
|
};
|
|
16026
|
+
const { productsMetadata: _, ...dataWithoutProductsMetadata } = data;
|
|
15928
16027
|
const newProcedure = {
|
|
15929
16028
|
id: procedureId,
|
|
15930
|
-
...
|
|
16029
|
+
...dataWithoutProductsMetadata,
|
|
15931
16030
|
nameLower: data.nameLower || data.name.toLowerCase(),
|
|
15932
16031
|
photos: processedPhotos,
|
|
15933
16032
|
category,
|
|
@@ -15935,6 +16034,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15935
16034
|
technology,
|
|
15936
16035
|
product: consultationProduct,
|
|
15937
16036
|
// Use placeholder product
|
|
16037
|
+
productsMetadata: transformedProductsMetadata,
|
|
16038
|
+
// Use transformed data, not original
|
|
15938
16039
|
blockingConditions: technology.blockingConditions,
|
|
15939
16040
|
contraindications: technology.contraindications || [],
|
|
15940
16041
|
contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
|
|
@@ -15994,7 +16095,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15994
16095
|
|
|
15995
16096
|
// src/services/reviews/reviews.service.ts
|
|
15996
16097
|
var import_firestore47 = require("firebase/firestore");
|
|
15997
|
-
var
|
|
16098
|
+
var import_zod26 = require("zod");
|
|
15998
16099
|
var ReviewService = class extends BaseService {
|
|
15999
16100
|
constructor(db, auth, app) {
|
|
16000
16101
|
super(db, auth, app);
|
|
@@ -16081,7 +16182,7 @@ var ReviewService = class extends BaseService {
|
|
|
16081
16182
|
});
|
|
16082
16183
|
return review;
|
|
16083
16184
|
} catch (error) {
|
|
16084
|
-
if (error instanceof
|
|
16185
|
+
if (error instanceof import_zod26.z.ZodError) {
|
|
16085
16186
|
throw new Error(`Invalid review data: ${error.message}`);
|
|
16086
16187
|
}
|
|
16087
16188
|
throw error;
|