@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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@blackcode_sa/metaestetics-api",
3
3
  "private": false,
4
- "version": "1.12.0",
4
+ "version": "1.12.2",
5
5
  "description": "Firebase authentication service with anonymous upgrade support",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.mjs",
@@ -22,6 +22,7 @@ export type {
22
22
  Technology,
23
23
  TechnologyDocumentationTemplate,
24
24
  } from "../types/technology.types";
25
+ export type { ProcedureProduct } from "../types/procedure-product.types";
25
26
 
26
27
  // Static pricing enums
27
28
  export { PricingMeasure, Currency } from "../types/static/pricing.types";
@@ -7,3 +7,4 @@ export * from "./requirement.types";
7
7
  export * from "./subcategory.types";
8
8
  export * from "./technology.types";
9
9
  export * from "./static";
10
+ export * from "./procedure-product.types";
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @fileoverview Defines the ProcedureProduct type, which represents a product associated with a procedure,
3
+ * including its pricing information. This is used to allow procedures to have multiple products with different prices.
4
+ * @packageDocumentation
5
+ */
6
+ import { Product } from "./product.types";
7
+ import { Currency, PricingMeasure } from "./static/pricing.types";
8
+
9
+ /**
10
+ * Represents a product associated with a procedure, including its specific pricing information.
11
+ */
12
+ export interface ProcedureProduct {
13
+ /**
14
+ * The product used in the procedure.
15
+ * @see {@link Product}
16
+ */
17
+ product: Product;
18
+
19
+ /**
20
+ * The price of the procedure when using this specific product.
21
+ */
22
+ price: number;
23
+
24
+ /**
25
+ * The currency for the price of this product.
26
+ * @see {@link Currency}
27
+ */
28
+ currency: Currency;
29
+
30
+ /**
31
+ * How the price is measured (e.g., per ml, per zone).
32
+ * @see {@link PricingMeasure}
33
+ */
34
+ pricingMeasure: PricingMeasure;
35
+
36
+ // Default product
37
+ isDefault?: boolean;
38
+ }
@@ -193,7 +193,8 @@ export class PractitionerService extends BaseService {
193
193
  };
194
194
 
195
195
  // Create practitioner object
196
- const fullNameLower = `${validData.basicInfo.firstName} ${validData.basicInfo.lastName}`.toLowerCase();
196
+ const fullNameLower =
197
+ `${validData.basicInfo.firstName} ${validData.basicInfo.lastName}`.toLowerCase();
197
198
  const practitioner: Omit<Practitioner, "createdAt" | "updatedAt"> & {
198
199
  createdAt: FieldValue;
199
200
  updatedAt: FieldValue;
@@ -349,7 +350,8 @@ export class PractitionerService extends BaseService {
349
350
  const proceduresInfo: ProcedureSummaryInfo[] = [];
350
351
 
351
352
  // Add fullNameLower for draft
352
- const fullNameLowerDraft = `${validatedData.basicInfo.firstName} ${validatedData.basicInfo.lastName}`.toLowerCase();
353
+ const fullNameLowerDraft =
354
+ `${validatedData.basicInfo.firstName} ${validatedData.basicInfo.lastName}`.toLowerCase();
353
355
  const practitionerData: Omit<Practitioner, "createdAt" | "updatedAt"> & {
354
356
  createdAt: ReturnType<typeof serverTimestamp>;
355
357
  updatedAt: ReturnType<typeof serverTimestamp>;
@@ -726,7 +728,9 @@ export class PractitionerService extends BaseService {
726
728
  const currentPractitioner = practitionerDoc.data() as Practitioner;
727
729
 
728
730
  // Process basicInfo if it's being updated to handle profile photo uploads
729
- let processedData: UpdatePractitionerData & { fullNameLower?: string } = { ...validData };
731
+ let processedData: UpdatePractitionerData & { fullNameLower?: string } = {
732
+ ...validData,
733
+ };
730
734
  if (validData.basicInfo) {
731
735
  processedData.basicInfo = await this.processBasicInfo(
732
736
  validData.basicInfo as PractitionerBasicInfo & {
@@ -735,7 +739,8 @@ export class PractitionerService extends BaseService {
735
739
  practitionerId
736
740
  );
737
741
  // Always update fullNameLower when basicInfo changes
738
- processedData.fullNameLower = `${processedData.basicInfo.firstName} ${processedData.basicInfo.lastName}`.toLowerCase();
742
+ processedData.fullNameLower =
743
+ `${processedData.basicInfo.firstName} ${processedData.basicInfo.lastName}`.toLowerCase();
739
744
  }
740
745
 
741
746
  // Prepare update data
@@ -1043,19 +1048,24 @@ export class PractitionerService extends BaseService {
1043
1048
  includeDraftPractitioners?: boolean;
1044
1049
  }): Promise<{ practitioners: Practitioner[]; lastDoc: any }> {
1045
1050
  try {
1046
- console.log("[PRACTITIONER_SERVICE] Starting practitioner filtering with fallback strategies");
1051
+ console.log(
1052
+ "[PRACTITIONER_SERVICE] Starting practitioner filtering with fallback strategies"
1053
+ );
1047
1054
 
1048
1055
  // Geo query debug i validacija
1049
1056
  if (filters.location && filters.radiusInKm) {
1050
- console.log('[PRACTITIONER_SERVICE] Executing geo query:', {
1057
+ console.log("[PRACTITIONER_SERVICE] Executing geo query:", {
1051
1058
  location: filters.location,
1052
1059
  radius: filters.radiusInKm,
1053
- serviceName: 'PractitionerService'
1060
+ serviceName: "PractitionerService",
1054
1061
  });
1055
-
1062
+
1056
1063
  // Validacija location podataka
1057
1064
  if (!filters.location.latitude || !filters.location.longitude) {
1058
- console.warn('[PRACTITIONER_SERVICE] Invalid location data:', filters.location);
1065
+ console.warn(
1066
+ "[PRACTITIONER_SERVICE] Invalid location data:",
1067
+ filters.location
1068
+ );
1059
1069
  filters.location = undefined;
1060
1070
  filters.radiusInKm = undefined;
1061
1071
  }
@@ -1064,10 +1074,12 @@ export class PractitionerService extends BaseService {
1064
1074
  // Strategy 1: Try fullNameLower search if nameSearch exists
1065
1075
  if (filters.nameSearch && filters.nameSearch.trim()) {
1066
1076
  try {
1067
- console.log("[PRACTITIONER_SERVICE] Strategy 1: Trying fullNameLower search");
1077
+ console.log(
1078
+ "[PRACTITIONER_SERVICE] Strategy 1: Trying fullNameLower search"
1079
+ );
1068
1080
  const searchTerm = filters.nameSearch.trim().toLowerCase();
1069
1081
  const constraints: any[] = [];
1070
-
1082
+
1071
1083
  if (!filters.includeDraftPractitioners) {
1072
1084
  constraints.push(where("status", "==", PractitionerStatus.ACTIVE));
1073
1085
  }
@@ -1087,13 +1099,23 @@ export class PractitionerService extends BaseService {
1087
1099
  }
1088
1100
  constraints.push(limit(filters.pagination || 10));
1089
1101
 
1090
- const q = query(collection(this.db, PRACTITIONERS_COLLECTION), ...constraints);
1102
+ const q = query(
1103
+ collection(this.db, PRACTITIONERS_COLLECTION),
1104
+ ...constraints
1105
+ );
1091
1106
  const querySnapshot = await getDocs(q);
1092
- const practitioners = querySnapshot.docs.map(doc => ({ ...doc.data(), id: doc.id } as Practitioner));
1093
- const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
1094
-
1095
- console.log(`[PRACTITIONER_SERVICE] Strategy 1 success: ${practitioners.length} practitioners`);
1096
-
1107
+ const practitioners = querySnapshot.docs.map(
1108
+ (doc) => ({ ...doc.data(), id: doc.id } as Practitioner)
1109
+ );
1110
+ const lastDoc =
1111
+ querySnapshot.docs.length > 0
1112
+ ? querySnapshot.docs[querySnapshot.docs.length - 1]
1113
+ : null;
1114
+
1115
+ console.log(
1116
+ `[PRACTITIONER_SERVICE] Strategy 1 success: ${practitioners.length} practitioners`
1117
+ );
1118
+
1097
1119
  // Fix Load More - ako je broj rezultata manji od pagination, nema više
1098
1120
  if (practitioners.length < (filters.pagination || 10)) {
1099
1121
  return { practitioners, lastDoc: null };
@@ -1106,9 +1128,11 @@ export class PractitionerService extends BaseService {
1106
1128
 
1107
1129
  // Strategy 2: Basic query with createdAt ordering (no name search)
1108
1130
  try {
1109
- console.log("[PRACTITIONER_SERVICE] Strategy 2: Basic query with createdAt ordering");
1131
+ console.log(
1132
+ "[PRACTITIONER_SERVICE] Strategy 2: Basic query with createdAt ordering"
1133
+ );
1110
1134
  const constraints: any[] = [];
1111
-
1135
+
1112
1136
  if (!filters.includeDraftPractitioners) {
1113
1137
  constraints.push(where("status", "==", PractitionerStatus.ACTIVE));
1114
1138
  }
@@ -1116,17 +1140,26 @@ export class PractitionerService extends BaseService {
1116
1140
 
1117
1141
  // Add other filters that work well with Firestore
1118
1142
  if (filters.certifications && filters.certifications.length > 0) {
1119
- const certificationsToMatch = filters.certifications as CertificationSpecialty[];
1143
+ const certificationsToMatch =
1144
+ filters.certifications as CertificationSpecialty[];
1120
1145
  constraints.push(
1121
- where("certification.specialties", "array-contains-any", certificationsToMatch)
1146
+ where(
1147
+ "certification.specialties",
1148
+ "array-contains-any",
1149
+ certificationsToMatch
1150
+ )
1122
1151
  );
1123
1152
  }
1124
1153
 
1125
1154
  if (filters.minRating !== undefined) {
1126
- constraints.push(where("reviewInfo.averageRating", ">=", filters.minRating));
1155
+ constraints.push(
1156
+ where("reviewInfo.averageRating", ">=", filters.minRating)
1157
+ );
1127
1158
  }
1128
1159
  if (filters.maxRating !== undefined) {
1129
- constraints.push(where("reviewInfo.averageRating", "<=", filters.maxRating));
1160
+ constraints.push(
1161
+ where("reviewInfo.averageRating", "<=", filters.maxRating)
1162
+ );
1130
1163
  }
1131
1164
 
1132
1165
  constraints.push(orderBy("createdAt", "desc"));
@@ -1148,9 +1181,14 @@ export class PractitionerService extends BaseService {
1148
1181
  constraints.push(limit(filters.pagination || 10));
1149
1182
  }
1150
1183
 
1151
- const q = query(collection(this.db, PRACTITIONERS_COLLECTION), ...constraints);
1184
+ const q = query(
1185
+ collection(this.db, PRACTITIONERS_COLLECTION),
1186
+ ...constraints
1187
+ );
1152
1188
  const querySnapshot = await getDocs(q);
1153
- let practitioners = querySnapshot.docs.map(doc => ({ ...doc.data(), id: doc.id } as Practitioner));
1189
+ let practitioners = querySnapshot.docs.map(
1190
+ (doc) => ({ ...doc.data(), id: doc.id } as Practitioner)
1191
+ );
1154
1192
 
1155
1193
  // Apply geo filter if needed (this is the only in-memory filter we keep)
1156
1194
  if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
@@ -1167,7 +1205,7 @@ export class PractitionerService extends BaseService {
1167
1205
  return distanceInKm <= radiusInKm;
1168
1206
  });
1169
1207
  });
1170
-
1208
+
1171
1209
  // Ograniči na pagination broj nakon geo filtera
1172
1210
  practitioners = practitioners.slice(0, filters.pagination || 10);
1173
1211
  }
@@ -1175,9 +1213,14 @@ export class PractitionerService extends BaseService {
1175
1213
  // Apply all remaining client-side filters using centralized function
1176
1214
  practitioners = this.applyInMemoryFilters(practitioners, filters);
1177
1215
 
1178
- const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
1179
- console.log(`[PRACTITIONER_SERVICE] Strategy 2 success: ${practitioners.length} practitioners`);
1180
-
1216
+ const lastDoc =
1217
+ querySnapshot.docs.length > 0
1218
+ ? querySnapshot.docs[querySnapshot.docs.length - 1]
1219
+ : null;
1220
+ console.log(
1221
+ `[PRACTITIONER_SERVICE] Strategy 2 success: ${practitioners.length} practitioners`
1222
+ );
1223
+
1181
1224
  // Fix Load More - ako je broj rezultata manji od pagination, nema više
1182
1225
  if (practitioners.length < (filters.pagination || 10)) {
1183
1226
  return { practitioners, lastDoc: null };
@@ -1189,23 +1232,35 @@ export class PractitionerService extends BaseService {
1189
1232
 
1190
1233
  // Strategy 3: Minimal query fallback
1191
1234
  try {
1192
- console.log("[PRACTITIONER_SERVICE] Strategy 3: Minimal query fallback");
1235
+ console.log(
1236
+ "[PRACTITIONER_SERVICE] Strategy 3: Minimal query fallback"
1237
+ );
1193
1238
  const constraints: any[] = [
1194
1239
  where("isActive", "==", true),
1195
1240
  orderBy("createdAt", "desc"),
1196
- limit(filters.pagination || 10)
1241
+ limit(filters.pagination || 10),
1197
1242
  ];
1198
1243
 
1199
- const q = query(collection(this.db, PRACTITIONERS_COLLECTION), ...constraints);
1244
+ const q = query(
1245
+ collection(this.db, PRACTITIONERS_COLLECTION),
1246
+ ...constraints
1247
+ );
1200
1248
  const querySnapshot = await getDocs(q);
1201
- let practitioners = querySnapshot.docs.map(doc => ({ ...doc.data(), id: doc.id } as Practitioner));
1249
+ let practitioners = querySnapshot.docs.map(
1250
+ (doc) => ({ ...doc.data(), id: doc.id } as Practitioner)
1251
+ );
1202
1252
 
1203
1253
  // Apply all client-side filters using centralized function
1204
1254
  practitioners = this.applyInMemoryFilters(practitioners, filters);
1205
1255
 
1206
- const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
1207
- console.log(`[PRACTITIONER_SERVICE] Strategy 3 success: ${practitioners.length} practitioners`);
1208
-
1256
+ const lastDoc =
1257
+ querySnapshot.docs.length > 0
1258
+ ? querySnapshot.docs[querySnapshot.docs.length - 1]
1259
+ : null;
1260
+ console.log(
1261
+ `[PRACTITIONER_SERVICE] Strategy 3 success: ${practitioners.length} practitioners`
1262
+ );
1263
+
1209
1264
  // Fix Load More - ako je broj rezultata manji od pagination, nema više
1210
1265
  if (practitioners.length < (filters.pagination || 10)) {
1211
1266
  return { practitioners, lastDoc: null };
@@ -1217,41 +1272,56 @@ export class PractitionerService extends BaseService {
1217
1272
 
1218
1273
  // Strategy 4: Client-side filtering fallback (kao u procedure/clinic services)
1219
1274
  try {
1220
- console.log("[PRACTITIONER_SERVICE] Strategy 4: Client-side filtering fallback");
1221
-
1275
+ console.log(
1276
+ "[PRACTITIONER_SERVICE] Strategy 4: Client-side filtering fallback"
1277
+ );
1278
+
1222
1279
  const constraints: any[] = [
1223
1280
  where("isActive", "==", true),
1224
1281
  where("status", "==", PractitionerStatus.ACTIVE),
1225
1282
  orderBy("createdAt", "desc"),
1226
- limit(filters.pagination || 10)
1283
+ limit(filters.pagination || 10),
1227
1284
  ];
1228
1285
 
1229
- const q = query(collection(this.db, PRACTITIONERS_COLLECTION), ...constraints);
1286
+ const q = query(
1287
+ collection(this.db, PRACTITIONERS_COLLECTION),
1288
+ ...constraints
1289
+ );
1230
1290
  const querySnapshot = await getDocs(q);
1231
- let practitioners = querySnapshot.docs.map(doc => ({ ...doc.data(), id: doc.id } as Practitioner));
1291
+ let practitioners = querySnapshot.docs.map(
1292
+ (doc) => ({ ...doc.data(), id: doc.id } as Practitioner)
1293
+ );
1232
1294
 
1233
1295
  // Apply all client-side filters using centralized function
1234
1296
  practitioners = this.applyInMemoryFilters(practitioners, filters);
1235
1297
 
1236
- const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
1237
- console.log(`[PRACTITIONER_SERVICE] Strategy 4 success: ${practitioners.length} practitioners`);
1238
-
1298
+ const lastDoc =
1299
+ querySnapshot.docs.length > 0
1300
+ ? querySnapshot.docs[querySnapshot.docs.length - 1]
1301
+ : null;
1302
+ console.log(
1303
+ `[PRACTITIONER_SERVICE] Strategy 4 success: ${practitioners.length} practitioners`
1304
+ );
1305
+
1239
1306
  // Fix Load More - ako je broj rezultata manji od pagination, nema više
1240
1307
  if (practitioners.length < (filters.pagination || 10)) {
1241
1308
  return { practitioners, lastDoc: null };
1242
1309
  }
1243
1310
  return { practitioners, lastDoc };
1244
-
1245
1311
  } catch (error) {
1246
1312
  console.log("[PRACTITIONER_SERVICE] Strategy 4 failed:", error);
1247
1313
  }
1248
1314
 
1249
1315
  // All strategies failed
1250
- console.log("[PRACTITIONER_SERVICE] All strategies failed, returning empty result");
1316
+ console.log(
1317
+ "[PRACTITIONER_SERVICE] All strategies failed, returning empty result"
1318
+ );
1251
1319
  return { practitioners: [], lastDoc: null };
1252
-
1253
1320
  } catch (error) {
1254
- console.error("[PRACTITIONER_SERVICE] Error filtering practitioners:", error);
1321
+ console.error(
1322
+ "[PRACTITIONER_SERVICE] Error filtering practitioners:",
1323
+ error
1324
+ );
1255
1325
  return { practitioners: [], lastDoc: null };
1256
1326
  }
1257
1327
  }
@@ -1260,91 +1330,128 @@ export class PractitionerService extends BaseService {
1260
1330
  * Applies in-memory filters to practitioners array
1261
1331
  * Used when Firestore queries fail or for complex filtering
1262
1332
  */
1263
- private applyInMemoryFilters(practitioners: Practitioner[], filters: any): Practitioner[] {
1333
+ private applyInMemoryFilters(
1334
+ practitioners: Practitioner[],
1335
+ filters: any
1336
+ ): Practitioner[] {
1264
1337
  let filteredPractitioners = [...practitioners]; // Create copy to avoid mutating original
1265
1338
 
1266
1339
  // Name search filter
1267
1340
  if (filters.nameSearch && filters.nameSearch.trim()) {
1268
1341
  const searchTerm = filters.nameSearch.trim().toLowerCase();
1269
- filteredPractitioners = filteredPractitioners.filter(practitioner => {
1270
- const firstName = (practitioner.basicInfo?.firstName || '').toLowerCase();
1271
- const lastName = (practitioner.basicInfo?.lastName || '').toLowerCase();
1342
+ filteredPractitioners = filteredPractitioners.filter((practitioner) => {
1343
+ const firstName = (
1344
+ practitioner.basicInfo?.firstName || ""
1345
+ ).toLowerCase();
1346
+ const lastName = (practitioner.basicInfo?.lastName || "").toLowerCase();
1272
1347
  const fullName = `${firstName} ${lastName}`.trim();
1273
- const fullNameLower = practitioner.fullNameLower || '';
1274
-
1275
- return firstName.includes(searchTerm) ||
1276
- lastName.includes(searchTerm) ||
1277
- fullName.includes(searchTerm) ||
1278
- fullNameLower.includes(searchTerm);
1348
+ const fullNameLower = practitioner.fullNameLower || "";
1349
+
1350
+ return (
1351
+ firstName.includes(searchTerm) ||
1352
+ lastName.includes(searchTerm) ||
1353
+ fullName.includes(searchTerm) ||
1354
+ fullNameLower.includes(searchTerm)
1355
+ );
1279
1356
  });
1280
- console.log(`[PRACTITIONER_SERVICE] Applied name filter, results: ${filteredPractitioners.length}`);
1357
+ console.log(
1358
+ `[PRACTITIONER_SERVICE] Applied name filter, results: ${filteredPractitioners.length}`
1359
+ );
1281
1360
  }
1282
1361
 
1283
1362
  // Certifications filtering
1284
1363
  if (filters.certifications && filters.certifications.length > 0) {
1285
1364
  const certificationsToMatch = filters.certifications;
1286
- filteredPractitioners = filteredPractitioners.filter(practitioner => {
1365
+ filteredPractitioners = filteredPractitioners.filter((practitioner) => {
1287
1366
  const practitionerCerts = practitioner.certification?.specialties || [];
1288
- return certificationsToMatch.some((cert: any) => practitionerCerts.includes(cert as CertificationSpecialty));
1367
+ return certificationsToMatch.some((cert: any) =>
1368
+ practitionerCerts.includes(cert as CertificationSpecialty)
1369
+ );
1289
1370
  });
1290
- console.log(`[PRACTITIONER_SERVICE] Applied certifications filter, results: ${filteredPractitioners.length}`);
1371
+ console.log(
1372
+ `[PRACTITIONER_SERVICE] Applied certifications filter, results: ${filteredPractitioners.length}`
1373
+ );
1291
1374
  }
1292
1375
 
1293
- // Specialties filtering
1376
+ // Specialties filtering
1294
1377
  if (filters.specialties && filters.specialties.length > 0) {
1295
1378
  const specialtiesToMatch = filters.specialties;
1296
- filteredPractitioners = filteredPractitioners.filter(practitioner => {
1379
+ filteredPractitioners = filteredPractitioners.filter((practitioner) => {
1297
1380
  const practitionerSpecs = practitioner.certification?.specialties || [];
1298
- return specialtiesToMatch.some((spec: any) => practitionerSpecs.includes(spec));
1381
+ return specialtiesToMatch.some((spec: any) =>
1382
+ practitionerSpecs.includes(spec)
1383
+ );
1299
1384
  });
1300
- console.log(`[PRACTITIONER_SERVICE] Applied specialties filter, results: ${filteredPractitioners.length}`);
1385
+ console.log(
1386
+ `[PRACTITIONER_SERVICE] Applied specialties filter, results: ${filteredPractitioners.length}`
1387
+ );
1301
1388
  }
1302
1389
 
1303
1390
  // Rating filtering
1304
1391
  if (filters.minRating !== undefined || filters.maxRating !== undefined) {
1305
- filteredPractitioners = filteredPractitioners.filter(practitioner => {
1392
+ filteredPractitioners = filteredPractitioners.filter((practitioner) => {
1306
1393
  const rating = practitioner.reviewInfo?.averageRating || 0;
1307
- if (filters.minRating !== undefined && rating < filters.minRating) return false;
1308
- if (filters.maxRating !== undefined && rating > filters.maxRating) return false;
1394
+ if (filters.minRating !== undefined && rating < filters.minRating)
1395
+ return false;
1396
+ if (filters.maxRating !== undefined && rating > filters.maxRating)
1397
+ return false;
1309
1398
  return true;
1310
1399
  });
1311
- console.log(`[PRACTITIONER_SERVICE] Applied rating filter, results: ${filteredPractitioners.length}`);
1400
+ console.log(
1401
+ `[PRACTITIONER_SERVICE] Applied rating filter, results: ${filteredPractitioners.length}`
1402
+ );
1312
1403
  }
1313
1404
 
1314
1405
  // Procedure family filtering
1315
1406
  if (filters.procedureFamily) {
1316
- filteredPractitioners = filteredPractitioners.filter(practitioner => {
1407
+ filteredPractitioners = filteredPractitioners.filter((practitioner) => {
1317
1408
  const proceduresInfo = practitioner.proceduresInfo || [];
1318
- return proceduresInfo.some(proc => proc.family === filters.procedureFamily);
1409
+ return proceduresInfo.some(
1410
+ (proc) => proc.family === filters.procedureFamily
1411
+ );
1319
1412
  });
1320
- console.log(`[PRACTITIONER_SERVICE] Applied procedure family filter, results: ${filteredPractitioners.length}`);
1413
+ console.log(
1414
+ `[PRACTITIONER_SERVICE] Applied procedure family filter, results: ${filteredPractitioners.length}`
1415
+ );
1321
1416
  }
1322
1417
 
1323
1418
  // Procedure category filtering
1324
1419
  if (filters.procedureCategory) {
1325
- filteredPractitioners = filteredPractitioners.filter(practitioner => {
1420
+ filteredPractitioners = filteredPractitioners.filter((practitioner) => {
1326
1421
  const proceduresInfo = practitioner.proceduresInfo || [];
1327
- return proceduresInfo.some(proc => proc.categoryName === filters.procedureCategory);
1422
+ return proceduresInfo.some(
1423
+ (proc) => proc.categoryName === filters.procedureCategory
1424
+ );
1328
1425
  });
1329
- console.log(`[PRACTITIONER_SERVICE] Applied procedure category filter, results: ${filteredPractitioners.length}`);
1426
+ console.log(
1427
+ `[PRACTITIONER_SERVICE] Applied procedure category filter, results: ${filteredPractitioners.length}`
1428
+ );
1330
1429
  }
1331
1430
 
1332
1431
  // Procedure subcategory filtering
1333
1432
  if (filters.procedureSubcategory) {
1334
- filteredPractitioners = filteredPractitioners.filter(practitioner => {
1433
+ filteredPractitioners = filteredPractitioners.filter((practitioner) => {
1335
1434
  const proceduresInfo = practitioner.proceduresInfo || [];
1336
- return proceduresInfo.some(proc => proc.subcategoryName === filters.procedureSubcategory);
1435
+ return proceduresInfo.some(
1436
+ (proc) => proc.subcategoryName === filters.procedureSubcategory
1437
+ );
1337
1438
  });
1338
- console.log(`[PRACTITIONER_SERVICE] Applied procedure subcategory filter, results: ${filteredPractitioners.length}`);
1439
+ console.log(
1440
+ `[PRACTITIONER_SERVICE] Applied procedure subcategory filter, results: ${filteredPractitioners.length}`
1441
+ );
1339
1442
  }
1340
1443
 
1341
1444
  // Procedure technology filtering
1342
1445
  if (filters.procedureTechnology) {
1343
- filteredPractitioners = filteredPractitioners.filter(practitioner => {
1446
+ filteredPractitioners = filteredPractitioners.filter((practitioner) => {
1344
1447
  const proceduresInfo = practitioner.proceduresInfo || [];
1345
- return proceduresInfo.some(proc => proc.technologyName === filters.procedureTechnology);
1448
+ return proceduresInfo.some(
1449
+ (proc) => proc.technologyName === filters.procedureTechnology
1450
+ );
1346
1451
  });
1347
- console.log(`[PRACTITIONER_SERVICE] Applied procedure technology filter, results: ${filteredPractitioners.length}`);
1452
+ console.log(
1453
+ `[PRACTITIONER_SERVICE] Applied procedure technology filter, results: ${filteredPractitioners.length}`
1454
+ );
1348
1455
  }
1349
1456
 
1350
1457
  // Geo-radius filter
@@ -1362,7 +1469,9 @@ export class PractitionerService extends BaseService {
1362
1469
  return distanceInKm <= radiusInKm;
1363
1470
  });
1364
1471
  });
1365
- console.log(`[PRACTITIONER_SERVICE] Applied geo filter, results: ${filteredPractitioners.length}`);
1472
+ console.log(
1473
+ `[PRACTITIONER_SERVICE] Applied geo filter, results: ${filteredPractitioners.length}`
1474
+ );
1366
1475
  }
1367
1476
 
1368
1477
  return filteredPractitioners;
@@ -1457,6 +1566,15 @@ export class PractitionerService extends BaseService {
1457
1566
  price: 0,
1458
1567
  currency: Currency.EUR,
1459
1568
  pricingMeasure: PricingMeasure.PER_SESSION,
1569
+ productsMetadata: [
1570
+ {
1571
+ productId: "free-consultation-product",
1572
+ price: 0,
1573
+ currency: Currency.EUR,
1574
+ pricingMeasure: PricingMeasure.PER_SESSION,
1575
+ isDefault: true,
1576
+ },
1577
+ ],
1460
1578
  duration: 30, // 30 minutes consultation
1461
1579
  practitionerId: practitionerId,
1462
1580
  clinicBranchId: clinicId,