@blackcode_sa/metaestetics-api 1.12.0 → 1.12.1
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 +58 -4
- package/dist/index.d.ts +58 -4
- package/dist/index.js +336 -96
- package/dist/index.mjs +336 -96
- 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 +102 -1
- 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
|
|
@@ -15113,6 +15284,34 @@ var ProcedureService = class extends BaseService {
|
|
|
15113
15284
|
}
|
|
15114
15285
|
return result;
|
|
15115
15286
|
}
|
|
15287
|
+
/**
|
|
15288
|
+
* Transforms validated procedure product data (with productId) to ProcedureProduct objects (with full product)
|
|
15289
|
+
* @param productsMetadata Array of validated procedure product data
|
|
15290
|
+
* @param technologyId Technology ID to fetch products from
|
|
15291
|
+
* @returns Array of ProcedureProduct objects with full product information
|
|
15292
|
+
*/
|
|
15293
|
+
async transformProductsMetadata(productsMetadata, technologyId) {
|
|
15294
|
+
const transformedProducts = [];
|
|
15295
|
+
for (const productData of productsMetadata) {
|
|
15296
|
+
const product = await this.productService.getById(
|
|
15297
|
+
technologyId,
|
|
15298
|
+
productData.productId
|
|
15299
|
+
);
|
|
15300
|
+
if (!product) {
|
|
15301
|
+
throw new Error(
|
|
15302
|
+
`Product with ID ${productData.productId} not found for technology ${technologyId}`
|
|
15303
|
+
);
|
|
15304
|
+
}
|
|
15305
|
+
transformedProducts.push({
|
|
15306
|
+
product,
|
|
15307
|
+
price: productData.price,
|
|
15308
|
+
currency: productData.currency,
|
|
15309
|
+
pricingMeasure: productData.pricingMeasure,
|
|
15310
|
+
isDefault: productData.isDefault
|
|
15311
|
+
});
|
|
15312
|
+
}
|
|
15313
|
+
return transformedProducts;
|
|
15314
|
+
}
|
|
15116
15315
|
/**
|
|
15117
15316
|
* Creates a new procedure
|
|
15118
15317
|
* @param data - The data for creating a new procedure
|
|
@@ -15169,6 +15368,10 @@ var ProcedureService = class extends BaseService {
|
|
|
15169
15368
|
"procedure-photos"
|
|
15170
15369
|
);
|
|
15171
15370
|
}
|
|
15371
|
+
const transformedProductsMetadata = await this.transformProductsMetadata(
|
|
15372
|
+
validatedData.productsMetadata,
|
|
15373
|
+
validatedData.technologyId
|
|
15374
|
+
);
|
|
15172
15375
|
const clinicInfo = {
|
|
15173
15376
|
id: clinicSnapshot.id,
|
|
15174
15377
|
name: clinic.name,
|
|
@@ -15197,6 +15400,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15197
15400
|
subcategory,
|
|
15198
15401
|
technology,
|
|
15199
15402
|
product,
|
|
15403
|
+
productsMetadata: transformedProductsMetadata,
|
|
15200
15404
|
blockingConditions: technology.blockingConditions,
|
|
15201
15405
|
contraindications: technology.contraindications || [],
|
|
15202
15406
|
contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
|
|
@@ -15279,6 +15483,10 @@ var ProcedureService = class extends BaseService {
|
|
|
15279
15483
|
"procedure-photos-batch"
|
|
15280
15484
|
);
|
|
15281
15485
|
}
|
|
15486
|
+
const transformedProductsMetadata = await this.transformProductsMetadata(
|
|
15487
|
+
validatedData.productsMetadata,
|
|
15488
|
+
validatedData.technologyId
|
|
15489
|
+
);
|
|
15282
15490
|
const practitionersMap = /* @__PURE__ */ new Map();
|
|
15283
15491
|
for (let i = 0; i < practitionerIds.length; i += 30) {
|
|
15284
15492
|
const chunk = practitionerIds.slice(i, i + 30);
|
|
@@ -15334,6 +15542,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15334
15542
|
subcategory,
|
|
15335
15543
|
technology,
|
|
15336
15544
|
product,
|
|
15545
|
+
productsMetadata: transformedProductsMetadata,
|
|
15337
15546
|
blockingConditions: technology.blockingConditions,
|
|
15338
15547
|
contraindications: technology.contraindications || [],
|
|
15339
15548
|
contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
|
|
@@ -15441,7 +15650,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15441
15650
|
* @returns The updated procedure
|
|
15442
15651
|
*/
|
|
15443
15652
|
async updateProcedure(id, data) {
|
|
15444
|
-
var _a, _b, _c;
|
|
15653
|
+
var _a, _b, _c, _d;
|
|
15445
15654
|
const validatedData = updateProcedureSchema.parse(data);
|
|
15446
15655
|
const procedureRef = doc30(this.db, PROCEDURES_COLLECTION, id);
|
|
15447
15656
|
const procedureSnapshot = await getDoc32(procedureRef);
|
|
@@ -15449,7 +15658,21 @@ var ProcedureService = class extends BaseService {
|
|
|
15449
15658
|
throw new Error(`Procedure with ID ${id} not found`);
|
|
15450
15659
|
}
|
|
15451
15660
|
const existingProcedure = procedureSnapshot.data();
|
|
15452
|
-
let updatedProcedureData = {
|
|
15661
|
+
let updatedProcedureData = {};
|
|
15662
|
+
if (validatedData.name !== void 0)
|
|
15663
|
+
updatedProcedureData.name = validatedData.name;
|
|
15664
|
+
if (validatedData.description !== void 0)
|
|
15665
|
+
updatedProcedureData.description = validatedData.description;
|
|
15666
|
+
if (validatedData.price !== void 0)
|
|
15667
|
+
updatedProcedureData.price = validatedData.price;
|
|
15668
|
+
if (validatedData.currency !== void 0)
|
|
15669
|
+
updatedProcedureData.currency = validatedData.currency;
|
|
15670
|
+
if (validatedData.pricingMeasure !== void 0)
|
|
15671
|
+
updatedProcedureData.pricingMeasure = validatedData.pricingMeasure;
|
|
15672
|
+
if (validatedData.duration !== void 0)
|
|
15673
|
+
updatedProcedureData.duration = validatedData.duration;
|
|
15674
|
+
if (validatedData.isActive !== void 0)
|
|
15675
|
+
updatedProcedureData.isActive = validatedData.isActive;
|
|
15453
15676
|
let practitionerChanged = false;
|
|
15454
15677
|
let clinicChanged = false;
|
|
15455
15678
|
const oldPractitionerId = existingProcedure.practitionerId;
|
|
@@ -15463,6 +15686,18 @@ var ProcedureService = class extends BaseService {
|
|
|
15463
15686
|
"procedure-photos"
|
|
15464
15687
|
);
|
|
15465
15688
|
}
|
|
15689
|
+
if (validatedData.productsMetadata !== void 0) {
|
|
15690
|
+
const technologyId = (_a = validatedData.technologyId) != null ? _a : existingProcedure.technology.id;
|
|
15691
|
+
if (!technologyId) {
|
|
15692
|
+
throw new Error(
|
|
15693
|
+
"Technology ID is required for updating products metadata"
|
|
15694
|
+
);
|
|
15695
|
+
}
|
|
15696
|
+
updatedProcedureData.productsMetadata = await this.transformProductsMetadata(
|
|
15697
|
+
validatedData.productsMetadata,
|
|
15698
|
+
technologyId
|
|
15699
|
+
);
|
|
15700
|
+
}
|
|
15466
15701
|
if (validatedData.practitionerId && validatedData.practitionerId !== oldPractitionerId) {
|
|
15467
15702
|
practitionerChanged = true;
|
|
15468
15703
|
const newPractitionerRef = doc30(
|
|
@@ -15482,7 +15717,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15482
15717
|
description: newPractitioner.basicInfo.bio || "",
|
|
15483
15718
|
photo: typeof newPractitioner.basicInfo.profileImageUrl === "string" ? newPractitioner.basicInfo.profileImageUrl : "",
|
|
15484
15719
|
// Default to empty string if not a processed URL
|
|
15485
|
-
rating: ((
|
|
15720
|
+
rating: ((_b = newPractitioner.reviewInfo) == null ? void 0 : _b.averageRating) || 0,
|
|
15486
15721
|
services: newPractitioner.procedures || []
|
|
15487
15722
|
};
|
|
15488
15723
|
}
|
|
@@ -15545,9 +15780,9 @@ var ProcedureService = class extends BaseService {
|
|
|
15545
15780
|
finalTechnologyId = technology.id;
|
|
15546
15781
|
updatedProcedureData.blockingConditions = technology.blockingConditions;
|
|
15547
15782
|
updatedProcedureData.contraindications = technology.contraindications || [];
|
|
15548
|
-
updatedProcedureData.contraindicationIds = ((
|
|
15783
|
+
updatedProcedureData.contraindicationIds = ((_c = technology.contraindications) == null ? void 0 : _c.map((c) => c.id)) || [];
|
|
15549
15784
|
updatedProcedureData.treatmentBenefits = technology.benefits;
|
|
15550
|
-
updatedProcedureData.treatmentBenefitIds = ((
|
|
15785
|
+
updatedProcedureData.treatmentBenefitIds = ((_d = technology.benefits) == null ? void 0 : _d.map((b) => b.id)) || [];
|
|
15551
15786
|
updatedProcedureData.preRequirements = technology.requirements.pre;
|
|
15552
15787
|
updatedProcedureData.postRequirements = technology.requirements.post;
|
|
15553
15788
|
updatedProcedureData.certificationRequirement = technology.certificationRequirement;
|
|
@@ -16144,6 +16379,10 @@ var ProcedureService = class extends BaseService {
|
|
|
16144
16379
|
"procedure-photos"
|
|
16145
16380
|
);
|
|
16146
16381
|
}
|
|
16382
|
+
const transformedProductsMetadata = await this.transformProductsMetadata(
|
|
16383
|
+
data.productsMetadata,
|
|
16384
|
+
data.technologyId
|
|
16385
|
+
);
|
|
16147
16386
|
const clinicInfo = {
|
|
16148
16387
|
id: clinicSnapshot.id,
|
|
16149
16388
|
name: clinic.name,
|
|
@@ -16184,6 +16423,7 @@ var ProcedureService = class extends BaseService {
|
|
|
16184
16423
|
technology,
|
|
16185
16424
|
product: consultationProduct,
|
|
16186
16425
|
// Use placeholder product
|
|
16426
|
+
productsMetadata: transformedProductsMetadata,
|
|
16187
16427
|
blockingConditions: technology.blockingConditions,
|
|
16188
16428
|
contraindications: technology.contraindications || [],
|
|
16189
16429
|
contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
|
|
@@ -16253,7 +16493,7 @@ import {
|
|
|
16253
16493
|
deleteDoc as deleteDoc19,
|
|
16254
16494
|
serverTimestamp as serverTimestamp26
|
|
16255
16495
|
} from "firebase/firestore";
|
|
16256
|
-
import { z as
|
|
16496
|
+
import { z as z26 } from "zod";
|
|
16257
16497
|
var ReviewService = class extends BaseService {
|
|
16258
16498
|
constructor(db, auth, app) {
|
|
16259
16499
|
super(db, auth, app);
|
|
@@ -16340,7 +16580,7 @@ var ReviewService = class extends BaseService {
|
|
|
16340
16580
|
});
|
|
16341
16581
|
return review;
|
|
16342
16582
|
} catch (error) {
|
|
16343
|
-
if (error instanceof
|
|
16583
|
+
if (error instanceof z26.ZodError) {
|
|
16344
16584
|
throw new Error(`Invalid review data: ${error.message}`);
|
|
16345
16585
|
}
|
|
16346
16586
|
throw error;
|