@blackcode_sa/metaestetics-api 1.7.19 → 1.7.21
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 +1 -2
- package/dist/admin/index.d.ts +1 -2
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/backoffice/index.d.mts +6 -1
- package/dist/backoffice/index.d.ts +6 -1
- package/dist/index.d.mts +80 -45
- package/dist/index.d.ts +80 -45
- package/dist/index.js +1635 -1407
- package/dist/index.mjs +1656 -1426
- package/package.json +1 -1
- package/src/admin/booking/booking.admin.ts +4 -1
- package/src/services/patient/patient.service.ts +162 -10
- package/src/services/patient/utils/profile.utils.ts +124 -135
- package/src/services/patient/utils/sensitive.utils.ts +76 -2
- package/src/services/practitioner/practitioner.service.ts +92 -3
- package/src/services/procedure/procedure.service.ts +8 -2
- package/src/types/patient/index.ts +25 -23
- package/src/types/practitioner/index.ts +2 -1
- package/src/validations/media.schema.ts +1 -1
- package/src/validations/patient.schema.ts +4 -4
- package/src/validations/practitioner.schema.ts +3 -2
package/dist/index.js
CHANGED
|
@@ -1096,7 +1096,7 @@ var BaseService = class {
|
|
|
1096
1096
|
};
|
|
1097
1097
|
|
|
1098
1098
|
// src/services/user.service.ts
|
|
1099
|
-
var
|
|
1099
|
+
var import_firestore19 = require("firebase/firestore");
|
|
1100
1100
|
|
|
1101
1101
|
// src/errors/user.errors.ts
|
|
1102
1102
|
var USER_ERRORS = {
|
|
@@ -1194,419 +1194,770 @@ var USER_ERRORS = {
|
|
|
1194
1194
|
var import_zod16 = require("zod");
|
|
1195
1195
|
|
|
1196
1196
|
// src/services/patient/patient.service.ts
|
|
1197
|
-
var
|
|
1197
|
+
var import_firestore14 = require("firebase/firestore");
|
|
1198
1198
|
|
|
1199
|
-
// src/services/
|
|
1200
|
-
var
|
|
1199
|
+
// src/services/media/media.service.ts
|
|
1200
|
+
var import_firestore2 = require("firebase/firestore");
|
|
1201
1201
|
var import_storage3 = require("firebase/storage");
|
|
1202
|
-
var import_zod8 = require("zod");
|
|
1203
|
-
|
|
1204
|
-
// src/types/patient/medical-info.types.ts
|
|
1205
|
-
var PATIENT_MEDICAL_INFO_COLLECTION = "medical_info";
|
|
1206
|
-
var DEFAULT_MEDICAL_INFO = {
|
|
1207
|
-
vitalStats: {},
|
|
1208
|
-
blockingConditions: [],
|
|
1209
|
-
contraindications: [],
|
|
1210
|
-
allergies: [],
|
|
1211
|
-
currentMedications: []
|
|
1212
|
-
};
|
|
1213
|
-
|
|
1214
|
-
// src/types/patient/index.ts
|
|
1215
|
-
var PATIENTS_COLLECTION = "patients";
|
|
1216
|
-
var PATIENT_SENSITIVE_INFO_COLLECTION = "sensitive-info";
|
|
1217
|
-
var PATIENT_MEDICAL_HISTORY_COLLECTION = "medical-history";
|
|
1218
|
-
var PATIENT_APPOINTMENTS_COLLECTION = "appointments";
|
|
1219
|
-
var PATIENT_LOCATION_INFO_COLLECTION = "location-info";
|
|
1220
|
-
var Gender = /* @__PURE__ */ ((Gender2) => {
|
|
1221
|
-
Gender2["MALE"] = "male";
|
|
1222
|
-
Gender2["FEMALE"] = "female";
|
|
1223
|
-
Gender2["TRANSGENDER_MALE"] = "transgender_male";
|
|
1224
|
-
Gender2["TRANSGENDER_FEMALE"] = "transgender_female";
|
|
1225
|
-
Gender2["PREFER_NOT_TO_SAY"] = "prefer_not_to_say";
|
|
1226
|
-
Gender2["OTHER"] = "other";
|
|
1227
|
-
return Gender2;
|
|
1228
|
-
})(Gender || {});
|
|
1229
|
-
|
|
1230
|
-
// src/validations/patient.schema.ts
|
|
1231
|
-
var import_zod6 = require("zod");
|
|
1232
1202
|
var import_firestore3 = require("firebase/firestore");
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
AllergyType2["COSMETIC"] = "cosmetic";
|
|
1244
|
-
AllergyType2["OTHER"] = "other";
|
|
1245
|
-
return AllergyType2;
|
|
1246
|
-
})(AllergyType || {});
|
|
1247
|
-
var MedicationAllergySubtype = /* @__PURE__ */ ((MedicationAllergySubtype2) => {
|
|
1248
|
-
MedicationAllergySubtype2["ANTIBIOTICS"] = "antibiotics";
|
|
1249
|
-
MedicationAllergySubtype2["NSAIDS"] = "nsaids";
|
|
1250
|
-
MedicationAllergySubtype2["OPIOIDS"] = "opioids";
|
|
1251
|
-
MedicationAllergySubtype2["ANESTHETICS"] = "anesthetics";
|
|
1252
|
-
MedicationAllergySubtype2["VACCINES"] = "vaccines";
|
|
1253
|
-
MedicationAllergySubtype2["OTHER"] = "other";
|
|
1254
|
-
return MedicationAllergySubtype2;
|
|
1255
|
-
})(MedicationAllergySubtype || {});
|
|
1256
|
-
var FoodAllergySubtype = /* @__PURE__ */ ((FoodAllergySubtype2) => {
|
|
1257
|
-
FoodAllergySubtype2["NUTS"] = "nuts";
|
|
1258
|
-
FoodAllergySubtype2["SHELLFISH"] = "shellfish";
|
|
1259
|
-
FoodAllergySubtype2["DAIRY"] = "dairy";
|
|
1260
|
-
FoodAllergySubtype2["EGGS"] = "eggs";
|
|
1261
|
-
FoodAllergySubtype2["WHEAT"] = "wheat";
|
|
1262
|
-
FoodAllergySubtype2["SOY"] = "soy";
|
|
1263
|
-
FoodAllergySubtype2["FISH"] = "fish";
|
|
1264
|
-
FoodAllergySubtype2["FRUITS"] = "fruits";
|
|
1265
|
-
FoodAllergySubtype2["OTHER"] = "other";
|
|
1266
|
-
return FoodAllergySubtype2;
|
|
1267
|
-
})(FoodAllergySubtype || {});
|
|
1268
|
-
var EnvironmentalAllergySubtype = /* @__PURE__ */ ((EnvironmentalAllergySubtype2) => {
|
|
1269
|
-
EnvironmentalAllergySubtype2["POLLEN"] = "pollen";
|
|
1270
|
-
EnvironmentalAllergySubtype2["DUST"] = "dust";
|
|
1271
|
-
EnvironmentalAllergySubtype2["MOLD"] = "mold";
|
|
1272
|
-
EnvironmentalAllergySubtype2["PET_DANDER"] = "pet_dander";
|
|
1273
|
-
EnvironmentalAllergySubtype2["INSECTS"] = "insects";
|
|
1274
|
-
EnvironmentalAllergySubtype2["OTHER"] = "other";
|
|
1275
|
-
return EnvironmentalAllergySubtype2;
|
|
1276
|
-
})(EnvironmentalAllergySubtype || {});
|
|
1277
|
-
var CosmeticAllergySubtype = /* @__PURE__ */ ((CosmeticAllergySubtype2) => {
|
|
1278
|
-
CosmeticAllergySubtype2["FRAGRANCES"] = "fragrances";
|
|
1279
|
-
CosmeticAllergySubtype2["PRESERVATIVES"] = "preservatives";
|
|
1280
|
-
CosmeticAllergySubtype2["DYES"] = "dyes";
|
|
1281
|
-
CosmeticAllergySubtype2["METALS"] = "metals";
|
|
1282
|
-
CosmeticAllergySubtype2["OTHER"] = "other";
|
|
1283
|
-
return CosmeticAllergySubtype2;
|
|
1284
|
-
})(CosmeticAllergySubtype || {});
|
|
1285
|
-
|
|
1286
|
-
// src/backoffice/types/static/blocking-condition.types.ts
|
|
1287
|
-
var BlockingCondition = /* @__PURE__ */ ((BlockingCondition2) => {
|
|
1288
|
-
BlockingCondition2["PREGNANCY"] = "pregnancy";
|
|
1289
|
-
BlockingCondition2["BREASTFEEDING"] = "breastfeeding";
|
|
1290
|
-
BlockingCondition2["ACTIVE_INFECTION"] = "active_infection";
|
|
1291
|
-
BlockingCondition2["SKIN_CONDITION"] = "skin_condition";
|
|
1292
|
-
BlockingCondition2["AUTOIMMUNE_DISEASE"] = "autoimmune_disease";
|
|
1293
|
-
BlockingCondition2["BLOOD_THINNERS"] = "blood_thinners";
|
|
1294
|
-
BlockingCondition2["RECENT_SURGERY"] = "recent_surgery";
|
|
1295
|
-
BlockingCondition2["DIABETES"] = "diabetes";
|
|
1296
|
-
BlockingCondition2["HEART_CONDITION"] = "heart_condition";
|
|
1297
|
-
BlockingCondition2["HIGH_BLOOD_PRESSURE"] = "high_blood_pressure";
|
|
1298
|
-
BlockingCondition2["KELOID_SCARRING"] = "keloid_scarring";
|
|
1299
|
-
BlockingCondition2["METAL_IMPLANTS"] = "metal_implants";
|
|
1300
|
-
BlockingCondition2["PACEMAKER"] = "pacemaker";
|
|
1301
|
-
BlockingCondition2["CANCER"] = "cancer";
|
|
1302
|
-
BlockingCondition2["EPILEPSY"] = "epilepsy";
|
|
1303
|
-
return BlockingCondition2;
|
|
1304
|
-
})(BlockingCondition || {});
|
|
1305
|
-
|
|
1306
|
-
// src/backoffice/types/static/contraindication.types.ts
|
|
1307
|
-
var Contraindication = /* @__PURE__ */ ((Contraindication2) => {
|
|
1308
|
-
Contraindication2["SENSITIVE_SKIN"] = "sensitive_skin";
|
|
1309
|
-
Contraindication2["RECENT_TANNING"] = "recent_tanning";
|
|
1310
|
-
Contraindication2["RECENT_BOTOX"] = "recent_botox";
|
|
1311
|
-
Contraindication2["RECENT_FILLERS"] = "recent_fillers";
|
|
1312
|
-
Contraindication2["SKIN_ALLERGIES"] = "skin_allergies";
|
|
1313
|
-
Contraindication2["MEDICATIONS"] = "medications";
|
|
1314
|
-
Contraindication2["RECENT_CHEMICAL_PEEL"] = "recent_chemical_peel";
|
|
1315
|
-
Contraindication2["RECENT_LASER"] = "recent_laser";
|
|
1316
|
-
Contraindication2["SKIN_INFLAMMATION"] = "skin_inflammation";
|
|
1317
|
-
Contraindication2["OPEN_WOUNDS"] = "open_wounds";
|
|
1318
|
-
Contraindication2["HERPES_SIMPLEX"] = "herpes_simplex";
|
|
1319
|
-
Contraindication2["COLD_SORES"] = "cold_sores";
|
|
1320
|
-
return Contraindication2;
|
|
1321
|
-
})(Contraindication || {});
|
|
1322
|
-
|
|
1323
|
-
// src/validations/common.schema.ts
|
|
1324
|
-
var import_zod4 = require("zod");
|
|
1325
|
-
var import_firestore2 = require("firebase/firestore");
|
|
1326
|
-
var timestampSchema2 = import_zod4.z.union([
|
|
1327
|
-
import_zod4.z.object({
|
|
1328
|
-
seconds: import_zod4.z.number(),
|
|
1329
|
-
nanoseconds: import_zod4.z.number()
|
|
1330
|
-
}),
|
|
1331
|
-
import_zod4.z.instanceof(import_firestore2.Timestamp)
|
|
1332
|
-
]).transform((data) => {
|
|
1333
|
-
if (data instanceof import_firestore2.Timestamp) {
|
|
1334
|
-
return data;
|
|
1335
|
-
}
|
|
1336
|
-
return new import_firestore2.Timestamp(data.seconds, data.nanoseconds);
|
|
1337
|
-
});
|
|
1338
|
-
|
|
1339
|
-
// src/validations/patient/medical-info.schema.ts
|
|
1340
|
-
var allergySubtypeSchema = import_zod5.z.union([
|
|
1341
|
-
import_zod5.z.nativeEnum(MedicationAllergySubtype),
|
|
1342
|
-
import_zod5.z.nativeEnum(FoodAllergySubtype),
|
|
1343
|
-
import_zod5.z.nativeEnum(EnvironmentalAllergySubtype),
|
|
1344
|
-
import_zod5.z.nativeEnum(CosmeticAllergySubtype),
|
|
1345
|
-
import_zod5.z.literal("other")
|
|
1346
|
-
]);
|
|
1347
|
-
var allergySchema = import_zod5.z.object({
|
|
1348
|
-
type: import_zod5.z.nativeEnum(AllergyType),
|
|
1349
|
-
subtype: allergySubtypeSchema,
|
|
1350
|
-
name: import_zod5.z.string().optional().nullable(),
|
|
1351
|
-
severity: import_zod5.z.enum(["mild", "moderate", "severe"]).optional(),
|
|
1352
|
-
reaction: import_zod5.z.string().optional().nullable(),
|
|
1353
|
-
diagnosed: timestampSchema2.optional().nullable(),
|
|
1354
|
-
notes: import_zod5.z.string().optional().nullable()
|
|
1355
|
-
});
|
|
1356
|
-
var vitalStatsSchema = import_zod5.z.object({
|
|
1357
|
-
height: import_zod5.z.number().positive().optional(),
|
|
1358
|
-
weight: import_zod5.z.number().positive().optional(),
|
|
1359
|
-
bloodType: import_zod5.z.enum(["A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-"]).optional(),
|
|
1360
|
-
bloodPressure: import_zod5.z.object({
|
|
1361
|
-
systolic: import_zod5.z.number().min(70).max(200),
|
|
1362
|
-
diastolic: import_zod5.z.number().min(40).max(130),
|
|
1363
|
-
lastMeasured: timestampSchema2
|
|
1364
|
-
}).optional()
|
|
1365
|
-
});
|
|
1366
|
-
var blockingConditionSchema = import_zod5.z.object({
|
|
1367
|
-
condition: import_zod5.z.nativeEnum(BlockingCondition),
|
|
1368
|
-
diagnosedAt: timestampSchema2,
|
|
1369
|
-
notes: import_zod5.z.string().optional().nullable(),
|
|
1370
|
-
isActive: import_zod5.z.boolean()
|
|
1371
|
-
});
|
|
1372
|
-
var contraindicationSchema = import_zod5.z.object({
|
|
1373
|
-
condition: import_zod5.z.nativeEnum(Contraindication),
|
|
1374
|
-
lastOccurrence: timestampSchema2,
|
|
1375
|
-
frequency: import_zod5.z.enum(["rare", "occasional", "frequent"]),
|
|
1376
|
-
notes: import_zod5.z.string().optional().nullable(),
|
|
1377
|
-
isActive: import_zod5.z.boolean()
|
|
1378
|
-
});
|
|
1379
|
-
var medicationSchema = import_zod5.z.object({
|
|
1380
|
-
name: import_zod5.z.string().min(1),
|
|
1381
|
-
dosage: import_zod5.z.string().min(1),
|
|
1382
|
-
frequency: import_zod5.z.string().min(1),
|
|
1383
|
-
startDate: timestampSchema2.optional().nullable(),
|
|
1384
|
-
endDate: timestampSchema2.optional().nullable(),
|
|
1385
|
-
prescribedBy: import_zod5.z.string().optional().nullable()
|
|
1386
|
-
});
|
|
1387
|
-
var patientMedicalInfoSchema = import_zod5.z.object({
|
|
1388
|
-
patientId: import_zod5.z.string(),
|
|
1389
|
-
vitalStats: vitalStatsSchema,
|
|
1390
|
-
blockingConditions: import_zod5.z.array(blockingConditionSchema),
|
|
1391
|
-
contraindications: import_zod5.z.array(contraindicationSchema),
|
|
1392
|
-
allergies: import_zod5.z.array(allergySchema),
|
|
1393
|
-
currentMedications: import_zod5.z.array(medicationSchema),
|
|
1394
|
-
emergencyNotes: import_zod5.z.string().optional(),
|
|
1395
|
-
lastUpdated: timestampSchema2,
|
|
1396
|
-
updatedBy: import_zod5.z.string(),
|
|
1397
|
-
verifiedBy: import_zod5.z.string().optional(),
|
|
1398
|
-
verifiedAt: timestampSchema2.optional()
|
|
1399
|
-
});
|
|
1400
|
-
var createPatientMedicalInfoSchema = patientMedicalInfoSchema.omit({
|
|
1401
|
-
patientId: true,
|
|
1402
|
-
lastUpdated: true,
|
|
1403
|
-
updatedBy: true,
|
|
1404
|
-
verifiedBy: true,
|
|
1405
|
-
verifiedAt: true
|
|
1406
|
-
});
|
|
1407
|
-
var updatePatientMedicalInfoSchema = createPatientMedicalInfoSchema.partial();
|
|
1408
|
-
var updateVitalStatsSchema = vitalStatsSchema;
|
|
1409
|
-
var addAllergySchema = allergySchema;
|
|
1410
|
-
var updateAllergySchema = allergySchema.partial().extend({
|
|
1411
|
-
allergyIndex: import_zod5.z.number().min(0)
|
|
1412
|
-
});
|
|
1413
|
-
var addBlockingConditionSchema = blockingConditionSchema;
|
|
1414
|
-
var updateBlockingConditionSchema = blockingConditionSchema.partial().extend({
|
|
1415
|
-
conditionIndex: import_zod5.z.number().min(0)
|
|
1416
|
-
});
|
|
1417
|
-
var addContraindicationSchema = contraindicationSchema;
|
|
1418
|
-
var updateContraindicationSchema = contraindicationSchema.partial().extend({
|
|
1419
|
-
contraindicationIndex: import_zod5.z.number().min(0)
|
|
1420
|
-
});
|
|
1421
|
-
var addMedicationSchema = medicationSchema;
|
|
1422
|
-
var updateMedicationSchema = medicationSchema.partial().extend({
|
|
1423
|
-
medicationIndex: import_zod5.z.number().min(0)
|
|
1424
|
-
});
|
|
1425
|
-
|
|
1426
|
-
// src/validations/patient.schema.ts
|
|
1427
|
-
var locationDataSchema = import_zod6.z.object({
|
|
1428
|
-
latitude: import_zod6.z.number().min(-90).max(90),
|
|
1429
|
-
longitude: import_zod6.z.number().min(-180).max(180),
|
|
1430
|
-
geohash: import_zod6.z.string().optional()
|
|
1431
|
-
});
|
|
1432
|
-
var addressDataSchema = import_zod6.z.object({
|
|
1433
|
-
address: import_zod6.z.string(),
|
|
1434
|
-
city: import_zod6.z.string(),
|
|
1435
|
-
country: import_zod6.z.string(),
|
|
1436
|
-
postalCode: import_zod6.z.string()
|
|
1437
|
-
});
|
|
1438
|
-
var emergencyContactSchema = import_zod6.z.object({
|
|
1439
|
-
name: import_zod6.z.string(),
|
|
1440
|
-
relationship: import_zod6.z.string(),
|
|
1441
|
-
phoneNumber: import_zod6.z.string(),
|
|
1442
|
-
isNotifiable: import_zod6.z.boolean()
|
|
1443
|
-
});
|
|
1444
|
-
var gamificationSchema = import_zod6.z.object({
|
|
1445
|
-
level: import_zod6.z.number(),
|
|
1446
|
-
points: import_zod6.z.number()
|
|
1447
|
-
});
|
|
1448
|
-
var patientLocationInfoSchema = import_zod6.z.object({
|
|
1449
|
-
patientId: import_zod6.z.string(),
|
|
1450
|
-
userRef: import_zod6.z.string(),
|
|
1451
|
-
locationData: locationDataSchema,
|
|
1452
|
-
createdAt: import_zod6.z.instanceof(import_firestore3.Timestamp),
|
|
1453
|
-
updatedAt: import_zod6.z.instanceof(import_firestore3.Timestamp)
|
|
1454
|
-
});
|
|
1455
|
-
var createPatientLocationInfoSchema = import_zod6.z.object({
|
|
1456
|
-
patientId: import_zod6.z.string(),
|
|
1457
|
-
userRef: import_zod6.z.string(),
|
|
1458
|
-
locationData: locationDataSchema
|
|
1459
|
-
});
|
|
1460
|
-
var patientSensitiveInfoSchema = import_zod6.z.object({
|
|
1461
|
-
patientId: import_zod6.z.string(),
|
|
1462
|
-
userRef: import_zod6.z.string(),
|
|
1463
|
-
photoUrl: import_zod6.z.string().optional(),
|
|
1464
|
-
firstName: import_zod6.z.string().min(2),
|
|
1465
|
-
lastName: import_zod6.z.string().min(2),
|
|
1466
|
-
dateOfBirth: import_zod6.z.instanceof(import_firestore3.Timestamp).nullable(),
|
|
1467
|
-
gender: import_zod6.z.nativeEnum(Gender),
|
|
1468
|
-
email: import_zod6.z.string().email().optional(),
|
|
1469
|
-
phoneNumber: import_zod6.z.string().optional(),
|
|
1470
|
-
alternativePhoneNumber: import_zod6.z.string().optional(),
|
|
1471
|
-
addressData: addressDataSchema.optional(),
|
|
1472
|
-
emergencyContacts: import_zod6.z.array(emergencyContactSchema).optional(),
|
|
1473
|
-
createdAt: import_zod6.z.instanceof(import_firestore3.Timestamp),
|
|
1474
|
-
updatedAt: import_zod6.z.instanceof(import_firestore3.Timestamp)
|
|
1475
|
-
});
|
|
1476
|
-
var patientDoctorSchema = import_zod6.z.object({
|
|
1477
|
-
userRef: import_zod6.z.string(),
|
|
1478
|
-
assignedAt: import_zod6.z.instanceof(import_firestore3.Timestamp),
|
|
1479
|
-
assignedBy: import_zod6.z.string().optional(),
|
|
1480
|
-
isActive: import_zod6.z.boolean(),
|
|
1481
|
-
notes: import_zod6.z.string().optional()
|
|
1482
|
-
});
|
|
1483
|
-
var patientClinicSchema = import_zod6.z.object({
|
|
1484
|
-
clinicId: import_zod6.z.string(),
|
|
1485
|
-
assignedAt: import_zod6.z.instanceof(import_firestore3.Timestamp),
|
|
1486
|
-
assignedBy: import_zod6.z.string().optional(),
|
|
1487
|
-
isActive: import_zod6.z.boolean(),
|
|
1488
|
-
notes: import_zod6.z.string().optional()
|
|
1489
|
-
});
|
|
1490
|
-
var patientProfileSchema = import_zod6.z.object({
|
|
1491
|
-
id: import_zod6.z.string(),
|
|
1492
|
-
userRef: import_zod6.z.string(),
|
|
1493
|
-
displayName: import_zod6.z.string(),
|
|
1494
|
-
profilePhoto: import_zod6.z.string().url().nullable(),
|
|
1495
|
-
gamification: gamificationSchema,
|
|
1496
|
-
expoTokens: import_zod6.z.array(import_zod6.z.string()),
|
|
1497
|
-
isActive: import_zod6.z.boolean(),
|
|
1498
|
-
isVerified: import_zod6.z.boolean(),
|
|
1499
|
-
doctors: import_zod6.z.array(patientDoctorSchema),
|
|
1500
|
-
clinics: import_zod6.z.array(patientClinicSchema),
|
|
1501
|
-
doctorIds: import_zod6.z.array(import_zod6.z.string()),
|
|
1502
|
-
clinicIds: import_zod6.z.array(import_zod6.z.string()),
|
|
1503
|
-
createdAt: import_zod6.z.instanceof(import_firestore3.Timestamp),
|
|
1504
|
-
updatedAt: import_zod6.z.instanceof(import_firestore3.Timestamp)
|
|
1505
|
-
});
|
|
1506
|
-
var createPatientProfileSchema = import_zod6.z.object({
|
|
1507
|
-
userRef: import_zod6.z.string(),
|
|
1508
|
-
displayName: import_zod6.z.string(),
|
|
1509
|
-
profilePhoto: import_zod6.z.string().url().nullable().optional(),
|
|
1510
|
-
expoTokens: import_zod6.z.array(import_zod6.z.string()),
|
|
1511
|
-
gamification: gamificationSchema.optional(),
|
|
1512
|
-
isActive: import_zod6.z.boolean(),
|
|
1513
|
-
isVerified: import_zod6.z.boolean(),
|
|
1514
|
-
doctors: import_zod6.z.array(patientDoctorSchema).optional(),
|
|
1515
|
-
clinics: import_zod6.z.array(patientClinicSchema).optional(),
|
|
1516
|
-
doctorIds: import_zod6.z.array(import_zod6.z.string()).optional(),
|
|
1517
|
-
clinicIds: import_zod6.z.array(import_zod6.z.string()).optional()
|
|
1518
|
-
});
|
|
1519
|
-
var createPatientSensitiveInfoSchema = import_zod6.z.object({
|
|
1520
|
-
patientId: import_zod6.z.string(),
|
|
1521
|
-
userRef: import_zod6.z.string(),
|
|
1522
|
-
photoUrl: import_zod6.z.string().optional(),
|
|
1523
|
-
firstName: import_zod6.z.string().min(2),
|
|
1524
|
-
lastName: import_zod6.z.string().min(2),
|
|
1525
|
-
dateOfBirth: import_zod6.z.instanceof(import_firestore3.Timestamp).nullable(),
|
|
1526
|
-
gender: import_zod6.z.nativeEnum(Gender),
|
|
1527
|
-
email: import_zod6.z.string().email().optional(),
|
|
1528
|
-
phoneNumber: import_zod6.z.string().optional(),
|
|
1529
|
-
alternativePhoneNumber: import_zod6.z.string().optional(),
|
|
1530
|
-
addressData: addressDataSchema.optional(),
|
|
1531
|
-
emergencyContacts: import_zod6.z.array(emergencyContactSchema).optional()
|
|
1532
|
-
});
|
|
1533
|
-
var searchPatientsSchema = import_zod6.z.object({
|
|
1534
|
-
clinicId: import_zod6.z.string().optional(),
|
|
1535
|
-
practitionerId: import_zod6.z.string().optional()
|
|
1536
|
-
}).refine((data) => data.clinicId || data.practitionerId, {
|
|
1537
|
-
message: "At least one of clinicId or practitionerId must be provided",
|
|
1538
|
-
path: []
|
|
1539
|
-
// Optional: specify a path like ['clinicId'] or ['practitionerId']
|
|
1540
|
-
});
|
|
1541
|
-
var requesterInfoSchema = import_zod6.z.object({
|
|
1542
|
-
id: import_zod6.z.string(),
|
|
1543
|
-
role: import_zod6.z.enum(["clinic_admin", "practitioner"]),
|
|
1544
|
-
associatedClinicId: import_zod6.z.string().optional(),
|
|
1545
|
-
associatedPractitionerId: import_zod6.z.string().optional()
|
|
1546
|
-
}).refine(
|
|
1547
|
-
(data) => {
|
|
1548
|
-
if (data.role === "clinic_admin") {
|
|
1549
|
-
return !!data.associatedClinicId;
|
|
1550
|
-
} else if (data.role === "practitioner") {
|
|
1551
|
-
return !!data.associatedPractitionerId;
|
|
1552
|
-
}
|
|
1553
|
-
return false;
|
|
1554
|
-
},
|
|
1555
|
-
{
|
|
1556
|
-
message: "Associated ID (clinic or practitioner) is required based on role",
|
|
1557
|
-
path: ["associatedClinicId", "associatedPractitionerId"]
|
|
1203
|
+
var MediaAccessLevel = /* @__PURE__ */ ((MediaAccessLevel2) => {
|
|
1204
|
+
MediaAccessLevel2["PUBLIC"] = "public";
|
|
1205
|
+
MediaAccessLevel2["PRIVATE"] = "private";
|
|
1206
|
+
MediaAccessLevel2["CONFIDENTIAL"] = "confidential";
|
|
1207
|
+
return MediaAccessLevel2;
|
|
1208
|
+
})(MediaAccessLevel || {});
|
|
1209
|
+
var MEDIA_METADATA_COLLECTION = "media_metadata";
|
|
1210
|
+
var MediaService = class extends BaseService {
|
|
1211
|
+
constructor(db, auth, app) {
|
|
1212
|
+
super(db, auth, app);
|
|
1558
1213
|
}
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
}
|
|
1572
|
-
const
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1214
|
+
/**
|
|
1215
|
+
* Upload a media file, store its metadata, and return the metadata including the URL.
|
|
1216
|
+
* @param file - The file to upload.
|
|
1217
|
+
* @param ownerId - ID of the owner (user, patient, clinic, etc.).
|
|
1218
|
+
* @param accessLevel - Access level (public, private, confidential).
|
|
1219
|
+
* @param collectionName - The logical collection name this media belongs to (e.g., 'patient_profile_pictures', 'clinic_logos').
|
|
1220
|
+
* @param originalFileName - Optional: the original name of the file, if not using file.name.
|
|
1221
|
+
* @returns Promise with the media metadata.
|
|
1222
|
+
*/
|
|
1223
|
+
async uploadMedia(file, ownerId, accessLevel, collectionName, originalFileName) {
|
|
1224
|
+
const mediaId = this.generateId();
|
|
1225
|
+
const fileNameToUse = originalFileName || (file instanceof File ? file.name : file.toString());
|
|
1226
|
+
const uniqueFileName = `${mediaId}-${fileNameToUse}`;
|
|
1227
|
+
const filePath = `media/${accessLevel}/${ownerId}/${collectionName}/${uniqueFileName}`;
|
|
1228
|
+
console.log(`[MediaService] Uploading file to: ${filePath}`);
|
|
1229
|
+
const storageRef = (0, import_storage3.ref)(this.storage, filePath);
|
|
1230
|
+
try {
|
|
1231
|
+
const uploadResult = await (0, import_storage3.uploadBytes)(storageRef, file, {
|
|
1232
|
+
contentType: file.type
|
|
1233
|
+
});
|
|
1234
|
+
console.log("[MediaService] File uploaded successfully", uploadResult);
|
|
1235
|
+
const downloadURL = await (0, import_storage3.getDownloadURL)(uploadResult.ref);
|
|
1236
|
+
console.log("[MediaService] Got download URL:", downloadURL);
|
|
1237
|
+
const metadata = {
|
|
1238
|
+
id: mediaId,
|
|
1239
|
+
name: fileNameToUse,
|
|
1240
|
+
url: downloadURL,
|
|
1241
|
+
contentType: file.type,
|
|
1242
|
+
size: file.size,
|
|
1243
|
+
createdAt: import_firestore2.Timestamp.now(),
|
|
1244
|
+
accessLevel,
|
|
1245
|
+
ownerId,
|
|
1246
|
+
collectionName,
|
|
1247
|
+
path: filePath
|
|
1248
|
+
};
|
|
1249
|
+
const metadataDocRef = (0, import_firestore3.doc)(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
1250
|
+
await (0, import_firestore3.setDoc)(metadataDocRef, metadata);
|
|
1251
|
+
console.log("[MediaService] Metadata stored in Firestore:", mediaId);
|
|
1252
|
+
return metadata;
|
|
1253
|
+
} catch (error) {
|
|
1254
|
+
console.error("[MediaService] Error during media upload:", error);
|
|
1255
|
+
throw error;
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
/**
|
|
1259
|
+
* Get media metadata from Firestore by its ID.
|
|
1260
|
+
* @param mediaId - ID of the media.
|
|
1261
|
+
* @returns Promise with the media metadata or null if not found.
|
|
1262
|
+
*/
|
|
1263
|
+
async getMediaMetadata(mediaId) {
|
|
1264
|
+
console.log(`[MediaService] Getting media metadata for ID: ${mediaId}`);
|
|
1265
|
+
const docRef = (0, import_firestore3.doc)(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
1266
|
+
const docSnap = await (0, import_firestore3.getDoc)(docRef);
|
|
1267
|
+
if (docSnap.exists()) {
|
|
1268
|
+
console.log("[MediaService] Metadata found:", docSnap.data());
|
|
1269
|
+
return docSnap.data();
|
|
1270
|
+
}
|
|
1271
|
+
console.log("[MediaService] No metadata found for ID:", mediaId);
|
|
1272
|
+
return null;
|
|
1273
|
+
}
|
|
1274
|
+
/**
|
|
1275
|
+
* Get media metadata from Firestore by its public URL.
|
|
1276
|
+
* @param url - The public URL of the media file.
|
|
1277
|
+
* @returns Promise with the media metadata or null if not found.
|
|
1278
|
+
*/
|
|
1279
|
+
async getMediaMetadataByUrl(url) {
|
|
1280
|
+
console.log(`[MediaService] Getting media metadata by URL: ${url}`);
|
|
1281
|
+
const q = (0, import_firestore3.query)(
|
|
1282
|
+
(0, import_firestore3.collection)(this.db, MEDIA_METADATA_COLLECTION),
|
|
1283
|
+
(0, import_firestore3.where)("url", "==", url),
|
|
1284
|
+
(0, import_firestore3.limit)(1)
|
|
1285
|
+
);
|
|
1286
|
+
try {
|
|
1287
|
+
const querySnapshot = await (0, import_firestore3.getDocs)(q);
|
|
1288
|
+
if (!querySnapshot.empty) {
|
|
1289
|
+
const metadata = querySnapshot.docs[0].data();
|
|
1290
|
+
console.log("[MediaService] Metadata found by URL:", metadata);
|
|
1291
|
+
return metadata;
|
|
1292
|
+
}
|
|
1293
|
+
console.log("[MediaService] No metadata found for URL:", url);
|
|
1294
|
+
return null;
|
|
1295
|
+
} catch (error) {
|
|
1296
|
+
console.error("[MediaService] Error fetching metadata by URL:", error);
|
|
1297
|
+
throw error;
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
/**
|
|
1301
|
+
* Delete media from storage and remove metadata from Firestore.
|
|
1302
|
+
* @param mediaId - ID of the media to delete.
|
|
1303
|
+
*/
|
|
1304
|
+
async deleteMedia(mediaId) {
|
|
1305
|
+
console.log(`[MediaService] Deleting media with ID: ${mediaId}`);
|
|
1306
|
+
const metadata = await this.getMediaMetadata(mediaId);
|
|
1307
|
+
if (!metadata) {
|
|
1308
|
+
console.warn(
|
|
1309
|
+
`[MediaService] Metadata not found for media ID ${mediaId}. Cannot delete.`
|
|
1310
|
+
);
|
|
1311
|
+
return;
|
|
1312
|
+
}
|
|
1313
|
+
const storageFileRef = (0, import_storage3.ref)(this.storage, metadata.path);
|
|
1314
|
+
try {
|
|
1315
|
+
await (0, import_storage3.deleteObject)(storageFileRef);
|
|
1316
|
+
console.log(`[MediaService] File deleted from Storage: ${metadata.path}`);
|
|
1317
|
+
const metadataDocRef = (0, import_firestore3.doc)(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
1318
|
+
await (0, import_firestore3.deleteDoc)(metadataDocRef);
|
|
1319
|
+
console.log(
|
|
1320
|
+
`[MediaService] Metadata deleted from Firestore for ID: ${mediaId}`
|
|
1321
|
+
);
|
|
1322
|
+
} catch (error) {
|
|
1323
|
+
console.error(`[MediaService] Error deleting media ${mediaId}:`, error);
|
|
1324
|
+
throw error;
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
/**
|
|
1328
|
+
* Update media access level. This involves moving the file in Firebase Storage
|
|
1329
|
+
* to a new path reflecting the new access level, and updating its metadata.
|
|
1330
|
+
* @param mediaId - ID of the media to update.
|
|
1331
|
+
* @param newAccessLevel - New access level.
|
|
1332
|
+
* @returns Promise with the updated media metadata, or null if metadata not found.
|
|
1333
|
+
*/
|
|
1334
|
+
async updateMediaAccessLevel(mediaId, newAccessLevel) {
|
|
1335
|
+
var _a;
|
|
1336
|
+
console.log(
|
|
1337
|
+
`[MediaService] Attempting to update access level for media ID: ${mediaId} to ${newAccessLevel}`
|
|
1338
|
+
);
|
|
1339
|
+
const metadata = await this.getMediaMetadata(mediaId);
|
|
1340
|
+
if (!metadata) {
|
|
1341
|
+
console.warn(
|
|
1342
|
+
`[MediaService] Metadata not found for media ID ${mediaId}. Cannot update access level.`
|
|
1343
|
+
);
|
|
1344
|
+
return null;
|
|
1345
|
+
}
|
|
1346
|
+
if (metadata.accessLevel === newAccessLevel) {
|
|
1347
|
+
console.log(
|
|
1348
|
+
`[MediaService] Media ID ${mediaId} already has access level ${newAccessLevel}. Updating timestamp only.`
|
|
1349
|
+
);
|
|
1350
|
+
const metadataDocRef = (0, import_firestore3.doc)(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
1351
|
+
try {
|
|
1352
|
+
await (0, import_firestore3.updateDoc)(metadataDocRef, { updatedAt: import_firestore2.Timestamp.now() });
|
|
1353
|
+
return { ...metadata, updatedAt: import_firestore2.Timestamp.now() };
|
|
1354
|
+
} catch (error) {
|
|
1355
|
+
console.error(
|
|
1356
|
+
`[MediaService] Error updating timestamp for media ID ${mediaId}:`,
|
|
1357
|
+
error
|
|
1358
|
+
);
|
|
1359
|
+
throw error;
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
const oldStoragePath = metadata.path;
|
|
1363
|
+
const fileNamePart = `${metadata.id}-${metadata.name}`;
|
|
1364
|
+
const newStoragePath = `media/${newAccessLevel}/${metadata.ownerId}/${metadata.collectionName}/${fileNamePart}`;
|
|
1365
|
+
console.log(
|
|
1366
|
+
`[MediaService] Moving file for ${mediaId} from ${oldStoragePath} to ${newStoragePath}`
|
|
1367
|
+
);
|
|
1368
|
+
const oldStorageFileRef = (0, import_storage3.ref)(this.storage, oldStoragePath);
|
|
1369
|
+
const newStorageFileRef = (0, import_storage3.ref)(this.storage, newStoragePath);
|
|
1370
|
+
try {
|
|
1371
|
+
console.log(`[MediaService] Downloading bytes from ${oldStoragePath}`);
|
|
1372
|
+
const fileBytes = await (0, import_storage3.getBytes)(oldStorageFileRef);
|
|
1373
|
+
console.log(
|
|
1374
|
+
`[MediaService] Successfully downloaded ${fileBytes.byteLength} bytes from ${oldStoragePath}`
|
|
1375
|
+
);
|
|
1376
|
+
console.log(`[MediaService] Uploading bytes to ${newStoragePath}`);
|
|
1377
|
+
await (0, import_storage3.uploadBytes)(newStorageFileRef, fileBytes, {
|
|
1378
|
+
contentType: metadata.contentType
|
|
1379
|
+
});
|
|
1380
|
+
console.log(
|
|
1381
|
+
`[MediaService] Successfully uploaded bytes to ${newStoragePath}`
|
|
1382
|
+
);
|
|
1383
|
+
const newDownloadURL = await (0, import_storage3.getDownloadURL)(newStorageFileRef);
|
|
1384
|
+
console.log(
|
|
1385
|
+
`[MediaService] Got new download URL for ${newStoragePath}: ${newDownloadURL}`
|
|
1386
|
+
);
|
|
1387
|
+
const updateData = {
|
|
1388
|
+
accessLevel: newAccessLevel,
|
|
1389
|
+
path: newStoragePath,
|
|
1390
|
+
url: newDownloadURL,
|
|
1391
|
+
updatedAt: import_firestore2.Timestamp.now()
|
|
1392
|
+
};
|
|
1393
|
+
const metadataDocRef = (0, import_firestore3.doc)(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
1394
|
+
console.log(
|
|
1395
|
+
`[MediaService] Updating Firestore metadata for ${mediaId} with new data:`,
|
|
1396
|
+
updateData
|
|
1397
|
+
);
|
|
1398
|
+
await (0, import_firestore3.updateDoc)(metadataDocRef, updateData);
|
|
1399
|
+
console.log(
|
|
1400
|
+
`[MediaService] Successfully updated Firestore metadata for ${mediaId}`
|
|
1401
|
+
);
|
|
1402
|
+
try {
|
|
1403
|
+
console.log(`[MediaService] Deleting old file from ${oldStoragePath}`);
|
|
1404
|
+
await (0, import_storage3.deleteObject)(oldStorageFileRef);
|
|
1405
|
+
console.log(
|
|
1406
|
+
`[MediaService] Successfully deleted old file from ${oldStoragePath}`
|
|
1407
|
+
);
|
|
1408
|
+
} catch (deleteError) {
|
|
1409
|
+
console.error(
|
|
1410
|
+
`[MediaService] Failed to delete old file from ${oldStoragePath} for media ID ${mediaId}. This file is now orphaned. Error:`,
|
|
1411
|
+
deleteError
|
|
1412
|
+
);
|
|
1413
|
+
}
|
|
1414
|
+
return { ...metadata, ...updateData };
|
|
1415
|
+
} catch (error) {
|
|
1416
|
+
console.error(
|
|
1417
|
+
`[MediaService] Error updating media access level and moving file for ${mediaId}:`,
|
|
1418
|
+
error
|
|
1419
|
+
);
|
|
1420
|
+
if (newStorageFileRef && error.code !== "storage/object-not-found" && ((_a = error.message) == null ? void 0 : _a.includes("uploadBytes"))) {
|
|
1421
|
+
console.warn(
|
|
1422
|
+
`[MediaService] Attempting to delete partially uploaded file at ${newStoragePath} due to error.`
|
|
1423
|
+
);
|
|
1424
|
+
try {
|
|
1425
|
+
await (0, import_storage3.deleteObject)(newStorageFileRef);
|
|
1426
|
+
console.warn(
|
|
1427
|
+
`[MediaService] Cleaned up partially uploaded file at ${newStoragePath}.`
|
|
1428
|
+
);
|
|
1429
|
+
} catch (cleanupError) {
|
|
1430
|
+
console.error(
|
|
1431
|
+
`[MediaService] Failed to cleanup partially uploaded file at ${newStoragePath}:`,
|
|
1432
|
+
cleanupError
|
|
1433
|
+
);
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
throw error;
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
/**
|
|
1440
|
+
* List all media for an owner, optionally filtered by collection and access level.
|
|
1441
|
+
* @param ownerId - ID of the owner.
|
|
1442
|
+
* @param collectionName - Optional: Filter by collection name.
|
|
1443
|
+
* @param accessLevel - Optional: Filter by access level.
|
|
1444
|
+
* @param count - Optional: Number of items to fetch.
|
|
1445
|
+
* @param startAfterId - Optional: ID of the document to start after (for pagination).
|
|
1446
|
+
*/
|
|
1447
|
+
async listMedia(ownerId, collectionName, accessLevel, count, startAfterId) {
|
|
1448
|
+
console.log(`[MediaService] Listing media for owner: ${ownerId}`);
|
|
1449
|
+
let qConstraints = [(0, import_firestore3.where)("ownerId", "==", ownerId)];
|
|
1450
|
+
if (collectionName) {
|
|
1451
|
+
qConstraints.push((0, import_firestore3.where)("collectionName", "==", collectionName));
|
|
1452
|
+
}
|
|
1453
|
+
if (accessLevel) {
|
|
1454
|
+
qConstraints.push((0, import_firestore3.where)("accessLevel", "==", accessLevel));
|
|
1455
|
+
}
|
|
1456
|
+
qConstraints.push((0, import_firestore3.orderBy)("createdAt", "desc"));
|
|
1457
|
+
if (count) {
|
|
1458
|
+
qConstraints.push((0, import_firestore3.limit)(count));
|
|
1459
|
+
}
|
|
1460
|
+
if (startAfterId) {
|
|
1461
|
+
const startAfterDoc = await this.getMediaMetadata(startAfterId);
|
|
1462
|
+
if (startAfterDoc) {
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
const finalQuery = (0, import_firestore3.query)(
|
|
1466
|
+
(0, import_firestore3.collection)(this.db, MEDIA_METADATA_COLLECTION),
|
|
1467
|
+
...qConstraints
|
|
1468
|
+
);
|
|
1469
|
+
try {
|
|
1470
|
+
const querySnapshot = await (0, import_firestore3.getDocs)(finalQuery);
|
|
1471
|
+
const mediaList = querySnapshot.docs.map(
|
|
1472
|
+
(doc34) => doc34.data()
|
|
1473
|
+
);
|
|
1474
|
+
console.log(`[MediaService] Found ${mediaList.length} media items.`);
|
|
1475
|
+
return mediaList;
|
|
1476
|
+
} catch (error) {
|
|
1477
|
+
console.error("[MediaService] Error listing media:", error);
|
|
1478
|
+
throw error;
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
/**
|
|
1482
|
+
* Get download URL for media. (Convenience, as URL is in metadata)
|
|
1483
|
+
* @param mediaId - ID of the media.
|
|
1484
|
+
*/
|
|
1485
|
+
async getMediaDownloadUrl(mediaId) {
|
|
1486
|
+
console.log(`[MediaService] Getting download URL for media ID: ${mediaId}`);
|
|
1487
|
+
const metadata = await this.getMediaMetadata(mediaId);
|
|
1488
|
+
if (metadata && metadata.url) {
|
|
1489
|
+
console.log(`[MediaService] URL found: ${metadata.url}`);
|
|
1490
|
+
return metadata.url;
|
|
1491
|
+
}
|
|
1492
|
+
console.log(`[MediaService] URL not found for media ID: ${mediaId}`);
|
|
1493
|
+
return null;
|
|
1494
|
+
}
|
|
1495
|
+
};
|
|
1496
|
+
|
|
1497
|
+
// src/services/patient/utils/profile.utils.ts
|
|
1498
|
+
var import_firestore10 = require("firebase/firestore");
|
|
1499
|
+
var import_zod9 = require("zod");
|
|
1500
|
+
|
|
1501
|
+
// src/types/patient/medical-info.types.ts
|
|
1502
|
+
var PATIENT_MEDICAL_INFO_COLLECTION = "medical_info";
|
|
1503
|
+
var DEFAULT_MEDICAL_INFO = {
|
|
1504
|
+
vitalStats: {},
|
|
1505
|
+
blockingConditions: [],
|
|
1506
|
+
contraindications: [],
|
|
1507
|
+
allergies: [],
|
|
1508
|
+
currentMedications: []
|
|
1509
|
+
};
|
|
1510
|
+
|
|
1511
|
+
// src/types/patient/index.ts
|
|
1512
|
+
var PATIENTS_COLLECTION = "patients";
|
|
1513
|
+
var PATIENT_SENSITIVE_INFO_COLLECTION = "sensitive-info";
|
|
1514
|
+
var PATIENT_MEDICAL_HISTORY_COLLECTION = "medical-history";
|
|
1515
|
+
var PATIENT_APPOINTMENTS_COLLECTION = "appointments";
|
|
1516
|
+
var PATIENT_LOCATION_INFO_COLLECTION = "location-info";
|
|
1517
|
+
var Gender = /* @__PURE__ */ ((Gender2) => {
|
|
1518
|
+
Gender2["MALE"] = "male";
|
|
1519
|
+
Gender2["FEMALE"] = "female";
|
|
1520
|
+
Gender2["TRANSGENDER_MALE"] = "transgender_male";
|
|
1521
|
+
Gender2["TRANSGENDER_FEMALE"] = "transgender_female";
|
|
1522
|
+
Gender2["PREFER_NOT_TO_SAY"] = "prefer_not_to_say";
|
|
1523
|
+
Gender2["OTHER"] = "other";
|
|
1524
|
+
return Gender2;
|
|
1525
|
+
})(Gender || {});
|
|
1526
|
+
|
|
1527
|
+
// src/validations/patient.schema.ts
|
|
1528
|
+
var import_zod7 = require("zod");
|
|
1529
|
+
var import_firestore5 = require("firebase/firestore");
|
|
1530
|
+
|
|
1531
|
+
// src/validations/media.schema.ts
|
|
1532
|
+
var import_zod4 = require("zod");
|
|
1533
|
+
var mediaResourceSchema = import_zod4.z.union([
|
|
1534
|
+
import_zod4.z.string().url(),
|
|
1535
|
+
import_zod4.z.instanceof(File),
|
|
1536
|
+
import_zod4.z.instanceof(Blob)
|
|
1537
|
+
]);
|
|
1538
|
+
|
|
1539
|
+
// src/validations/patient/medical-info.schema.ts
|
|
1540
|
+
var import_zod6 = require("zod");
|
|
1541
|
+
|
|
1542
|
+
// src/types/patient/allergies.ts
|
|
1543
|
+
var AllergyType = /* @__PURE__ */ ((AllergyType2) => {
|
|
1544
|
+
AllergyType2["MEDICATION"] = "medication";
|
|
1545
|
+
AllergyType2["FOOD"] = "food";
|
|
1546
|
+
AllergyType2["ENVIRONMENTAL"] = "environmental";
|
|
1547
|
+
AllergyType2["LATEX"] = "latex";
|
|
1548
|
+
AllergyType2["COSMETIC"] = "cosmetic";
|
|
1549
|
+
AllergyType2["OTHER"] = "other";
|
|
1550
|
+
return AllergyType2;
|
|
1551
|
+
})(AllergyType || {});
|
|
1552
|
+
var MedicationAllergySubtype = /* @__PURE__ */ ((MedicationAllergySubtype2) => {
|
|
1553
|
+
MedicationAllergySubtype2["ANTIBIOTICS"] = "antibiotics";
|
|
1554
|
+
MedicationAllergySubtype2["NSAIDS"] = "nsaids";
|
|
1555
|
+
MedicationAllergySubtype2["OPIOIDS"] = "opioids";
|
|
1556
|
+
MedicationAllergySubtype2["ANESTHETICS"] = "anesthetics";
|
|
1557
|
+
MedicationAllergySubtype2["VACCINES"] = "vaccines";
|
|
1558
|
+
MedicationAllergySubtype2["OTHER"] = "other";
|
|
1559
|
+
return MedicationAllergySubtype2;
|
|
1560
|
+
})(MedicationAllergySubtype || {});
|
|
1561
|
+
var FoodAllergySubtype = /* @__PURE__ */ ((FoodAllergySubtype2) => {
|
|
1562
|
+
FoodAllergySubtype2["NUTS"] = "nuts";
|
|
1563
|
+
FoodAllergySubtype2["SHELLFISH"] = "shellfish";
|
|
1564
|
+
FoodAllergySubtype2["DAIRY"] = "dairy";
|
|
1565
|
+
FoodAllergySubtype2["EGGS"] = "eggs";
|
|
1566
|
+
FoodAllergySubtype2["WHEAT"] = "wheat";
|
|
1567
|
+
FoodAllergySubtype2["SOY"] = "soy";
|
|
1568
|
+
FoodAllergySubtype2["FISH"] = "fish";
|
|
1569
|
+
FoodAllergySubtype2["FRUITS"] = "fruits";
|
|
1570
|
+
FoodAllergySubtype2["OTHER"] = "other";
|
|
1571
|
+
return FoodAllergySubtype2;
|
|
1572
|
+
})(FoodAllergySubtype || {});
|
|
1573
|
+
var EnvironmentalAllergySubtype = /* @__PURE__ */ ((EnvironmentalAllergySubtype2) => {
|
|
1574
|
+
EnvironmentalAllergySubtype2["POLLEN"] = "pollen";
|
|
1575
|
+
EnvironmentalAllergySubtype2["DUST"] = "dust";
|
|
1576
|
+
EnvironmentalAllergySubtype2["MOLD"] = "mold";
|
|
1577
|
+
EnvironmentalAllergySubtype2["PET_DANDER"] = "pet_dander";
|
|
1578
|
+
EnvironmentalAllergySubtype2["INSECTS"] = "insects";
|
|
1579
|
+
EnvironmentalAllergySubtype2["OTHER"] = "other";
|
|
1580
|
+
return EnvironmentalAllergySubtype2;
|
|
1581
|
+
})(EnvironmentalAllergySubtype || {});
|
|
1582
|
+
var CosmeticAllergySubtype = /* @__PURE__ */ ((CosmeticAllergySubtype2) => {
|
|
1583
|
+
CosmeticAllergySubtype2["FRAGRANCES"] = "fragrances";
|
|
1584
|
+
CosmeticAllergySubtype2["PRESERVATIVES"] = "preservatives";
|
|
1585
|
+
CosmeticAllergySubtype2["DYES"] = "dyes";
|
|
1586
|
+
CosmeticAllergySubtype2["METALS"] = "metals";
|
|
1587
|
+
CosmeticAllergySubtype2["OTHER"] = "other";
|
|
1588
|
+
return CosmeticAllergySubtype2;
|
|
1589
|
+
})(CosmeticAllergySubtype || {});
|
|
1590
|
+
|
|
1591
|
+
// src/backoffice/types/static/blocking-condition.types.ts
|
|
1592
|
+
var BlockingCondition = /* @__PURE__ */ ((BlockingCondition2) => {
|
|
1593
|
+
BlockingCondition2["PREGNANCY"] = "pregnancy";
|
|
1594
|
+
BlockingCondition2["BREASTFEEDING"] = "breastfeeding";
|
|
1595
|
+
BlockingCondition2["ACTIVE_INFECTION"] = "active_infection";
|
|
1596
|
+
BlockingCondition2["SKIN_CONDITION"] = "skin_condition";
|
|
1597
|
+
BlockingCondition2["AUTOIMMUNE_DISEASE"] = "autoimmune_disease";
|
|
1598
|
+
BlockingCondition2["BLOOD_THINNERS"] = "blood_thinners";
|
|
1599
|
+
BlockingCondition2["RECENT_SURGERY"] = "recent_surgery";
|
|
1600
|
+
BlockingCondition2["DIABETES"] = "diabetes";
|
|
1601
|
+
BlockingCondition2["HEART_CONDITION"] = "heart_condition";
|
|
1602
|
+
BlockingCondition2["HIGH_BLOOD_PRESSURE"] = "high_blood_pressure";
|
|
1603
|
+
BlockingCondition2["KELOID_SCARRING"] = "keloid_scarring";
|
|
1604
|
+
BlockingCondition2["METAL_IMPLANTS"] = "metal_implants";
|
|
1605
|
+
BlockingCondition2["PACEMAKER"] = "pacemaker";
|
|
1606
|
+
BlockingCondition2["CANCER"] = "cancer";
|
|
1607
|
+
BlockingCondition2["EPILEPSY"] = "epilepsy";
|
|
1608
|
+
return BlockingCondition2;
|
|
1609
|
+
})(BlockingCondition || {});
|
|
1610
|
+
|
|
1611
|
+
// src/backoffice/types/static/contraindication.types.ts
|
|
1612
|
+
var Contraindication = /* @__PURE__ */ ((Contraindication2) => {
|
|
1613
|
+
Contraindication2["SENSITIVE_SKIN"] = "sensitive_skin";
|
|
1614
|
+
Contraindication2["RECENT_TANNING"] = "recent_tanning";
|
|
1615
|
+
Contraindication2["RECENT_BOTOX"] = "recent_botox";
|
|
1616
|
+
Contraindication2["RECENT_FILLERS"] = "recent_fillers";
|
|
1617
|
+
Contraindication2["SKIN_ALLERGIES"] = "skin_allergies";
|
|
1618
|
+
Contraindication2["MEDICATIONS"] = "medications";
|
|
1619
|
+
Contraindication2["RECENT_CHEMICAL_PEEL"] = "recent_chemical_peel";
|
|
1620
|
+
Contraindication2["RECENT_LASER"] = "recent_laser";
|
|
1621
|
+
Contraindication2["SKIN_INFLAMMATION"] = "skin_inflammation";
|
|
1622
|
+
Contraindication2["OPEN_WOUNDS"] = "open_wounds";
|
|
1623
|
+
Contraindication2["HERPES_SIMPLEX"] = "herpes_simplex";
|
|
1624
|
+
Contraindication2["COLD_SORES"] = "cold_sores";
|
|
1625
|
+
return Contraindication2;
|
|
1626
|
+
})(Contraindication || {});
|
|
1627
|
+
|
|
1628
|
+
// src/validations/common.schema.ts
|
|
1629
|
+
var import_zod5 = require("zod");
|
|
1630
|
+
var import_firestore4 = require("firebase/firestore");
|
|
1631
|
+
var timestampSchema2 = import_zod5.z.union([
|
|
1632
|
+
import_zod5.z.object({
|
|
1633
|
+
seconds: import_zod5.z.number(),
|
|
1634
|
+
nanoseconds: import_zod5.z.number()
|
|
1635
|
+
}),
|
|
1636
|
+
import_zod5.z.instanceof(import_firestore4.Timestamp)
|
|
1637
|
+
]).transform((data) => {
|
|
1638
|
+
if (data instanceof import_firestore4.Timestamp) {
|
|
1639
|
+
return data;
|
|
1640
|
+
}
|
|
1641
|
+
return new import_firestore4.Timestamp(data.seconds, data.nanoseconds);
|
|
1642
|
+
});
|
|
1643
|
+
|
|
1644
|
+
// src/validations/patient/medical-info.schema.ts
|
|
1645
|
+
var allergySubtypeSchema = import_zod6.z.union([
|
|
1646
|
+
import_zod6.z.nativeEnum(MedicationAllergySubtype),
|
|
1647
|
+
import_zod6.z.nativeEnum(FoodAllergySubtype),
|
|
1648
|
+
import_zod6.z.nativeEnum(EnvironmentalAllergySubtype),
|
|
1649
|
+
import_zod6.z.nativeEnum(CosmeticAllergySubtype),
|
|
1650
|
+
import_zod6.z.literal("other")
|
|
1651
|
+
]);
|
|
1652
|
+
var allergySchema = import_zod6.z.object({
|
|
1653
|
+
type: import_zod6.z.nativeEnum(AllergyType),
|
|
1654
|
+
subtype: allergySubtypeSchema,
|
|
1655
|
+
name: import_zod6.z.string().optional().nullable(),
|
|
1656
|
+
severity: import_zod6.z.enum(["mild", "moderate", "severe"]).optional(),
|
|
1657
|
+
reaction: import_zod6.z.string().optional().nullable(),
|
|
1658
|
+
diagnosed: timestampSchema2.optional().nullable(),
|
|
1659
|
+
notes: import_zod6.z.string().optional().nullable()
|
|
1660
|
+
});
|
|
1661
|
+
var vitalStatsSchema = import_zod6.z.object({
|
|
1662
|
+
height: import_zod6.z.number().positive().optional(),
|
|
1663
|
+
weight: import_zod6.z.number().positive().optional(),
|
|
1664
|
+
bloodType: import_zod6.z.enum(["A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-"]).optional(),
|
|
1665
|
+
bloodPressure: import_zod6.z.object({
|
|
1666
|
+
systolic: import_zod6.z.number().min(70).max(200),
|
|
1667
|
+
diastolic: import_zod6.z.number().min(40).max(130),
|
|
1668
|
+
lastMeasured: timestampSchema2
|
|
1669
|
+
}).optional()
|
|
1670
|
+
});
|
|
1671
|
+
var blockingConditionSchema = import_zod6.z.object({
|
|
1672
|
+
condition: import_zod6.z.nativeEnum(BlockingCondition),
|
|
1673
|
+
diagnosedAt: timestampSchema2,
|
|
1674
|
+
notes: import_zod6.z.string().optional().nullable(),
|
|
1675
|
+
isActive: import_zod6.z.boolean()
|
|
1676
|
+
});
|
|
1677
|
+
var contraindicationSchema = import_zod6.z.object({
|
|
1678
|
+
condition: import_zod6.z.nativeEnum(Contraindication),
|
|
1679
|
+
lastOccurrence: timestampSchema2,
|
|
1680
|
+
frequency: import_zod6.z.enum(["rare", "occasional", "frequent"]),
|
|
1681
|
+
notes: import_zod6.z.string().optional().nullable(),
|
|
1682
|
+
isActive: import_zod6.z.boolean()
|
|
1683
|
+
});
|
|
1684
|
+
var medicationSchema = import_zod6.z.object({
|
|
1685
|
+
name: import_zod6.z.string().min(1),
|
|
1686
|
+
dosage: import_zod6.z.string().min(1),
|
|
1687
|
+
frequency: import_zod6.z.string().min(1),
|
|
1688
|
+
startDate: timestampSchema2.optional().nullable(),
|
|
1689
|
+
endDate: timestampSchema2.optional().nullable(),
|
|
1690
|
+
prescribedBy: import_zod6.z.string().optional().nullable()
|
|
1691
|
+
});
|
|
1692
|
+
var patientMedicalInfoSchema = import_zod6.z.object({
|
|
1693
|
+
patientId: import_zod6.z.string(),
|
|
1694
|
+
vitalStats: vitalStatsSchema,
|
|
1695
|
+
blockingConditions: import_zod6.z.array(blockingConditionSchema),
|
|
1696
|
+
contraindications: import_zod6.z.array(contraindicationSchema),
|
|
1697
|
+
allergies: import_zod6.z.array(allergySchema),
|
|
1698
|
+
currentMedications: import_zod6.z.array(medicationSchema),
|
|
1699
|
+
emergencyNotes: import_zod6.z.string().optional(),
|
|
1700
|
+
lastUpdated: timestampSchema2,
|
|
1701
|
+
updatedBy: import_zod6.z.string(),
|
|
1702
|
+
verifiedBy: import_zod6.z.string().optional(),
|
|
1703
|
+
verifiedAt: timestampSchema2.optional()
|
|
1704
|
+
});
|
|
1705
|
+
var createPatientMedicalInfoSchema = patientMedicalInfoSchema.omit({
|
|
1706
|
+
patientId: true,
|
|
1707
|
+
lastUpdated: true,
|
|
1708
|
+
updatedBy: true,
|
|
1709
|
+
verifiedBy: true,
|
|
1710
|
+
verifiedAt: true
|
|
1711
|
+
});
|
|
1712
|
+
var updatePatientMedicalInfoSchema = createPatientMedicalInfoSchema.partial();
|
|
1713
|
+
var updateVitalStatsSchema = vitalStatsSchema;
|
|
1714
|
+
var addAllergySchema = allergySchema;
|
|
1715
|
+
var updateAllergySchema = allergySchema.partial().extend({
|
|
1716
|
+
allergyIndex: import_zod6.z.number().min(0)
|
|
1717
|
+
});
|
|
1718
|
+
var addBlockingConditionSchema = blockingConditionSchema;
|
|
1719
|
+
var updateBlockingConditionSchema = blockingConditionSchema.partial().extend({
|
|
1720
|
+
conditionIndex: import_zod6.z.number().min(0)
|
|
1721
|
+
});
|
|
1722
|
+
var addContraindicationSchema = contraindicationSchema;
|
|
1723
|
+
var updateContraindicationSchema = contraindicationSchema.partial().extend({
|
|
1724
|
+
contraindicationIndex: import_zod6.z.number().min(0)
|
|
1725
|
+
});
|
|
1726
|
+
var addMedicationSchema = medicationSchema;
|
|
1727
|
+
var updateMedicationSchema = medicationSchema.partial().extend({
|
|
1728
|
+
medicationIndex: import_zod6.z.number().min(0)
|
|
1729
|
+
});
|
|
1730
|
+
|
|
1731
|
+
// src/validations/patient.schema.ts
|
|
1732
|
+
var locationDataSchema = import_zod7.z.object({
|
|
1733
|
+
latitude: import_zod7.z.number().min(-90).max(90),
|
|
1734
|
+
longitude: import_zod7.z.number().min(-180).max(180),
|
|
1735
|
+
geohash: import_zod7.z.string().optional()
|
|
1736
|
+
});
|
|
1737
|
+
var addressDataSchema = import_zod7.z.object({
|
|
1738
|
+
address: import_zod7.z.string(),
|
|
1739
|
+
city: import_zod7.z.string(),
|
|
1740
|
+
country: import_zod7.z.string(),
|
|
1741
|
+
postalCode: import_zod7.z.string()
|
|
1742
|
+
});
|
|
1743
|
+
var emergencyContactSchema = import_zod7.z.object({
|
|
1744
|
+
name: import_zod7.z.string(),
|
|
1745
|
+
relationship: import_zod7.z.string(),
|
|
1746
|
+
phoneNumber: import_zod7.z.string(),
|
|
1747
|
+
isNotifiable: import_zod7.z.boolean()
|
|
1748
|
+
});
|
|
1749
|
+
var gamificationSchema = import_zod7.z.object({
|
|
1750
|
+
level: import_zod7.z.number(),
|
|
1751
|
+
points: import_zod7.z.number()
|
|
1752
|
+
});
|
|
1753
|
+
var patientLocationInfoSchema = import_zod7.z.object({
|
|
1754
|
+
patientId: import_zod7.z.string(),
|
|
1755
|
+
userRef: import_zod7.z.string(),
|
|
1756
|
+
locationData: locationDataSchema,
|
|
1757
|
+
createdAt: import_zod7.z.instanceof(import_firestore5.Timestamp),
|
|
1758
|
+
updatedAt: import_zod7.z.instanceof(import_firestore5.Timestamp)
|
|
1759
|
+
});
|
|
1760
|
+
var createPatientLocationInfoSchema = import_zod7.z.object({
|
|
1761
|
+
patientId: import_zod7.z.string(),
|
|
1762
|
+
userRef: import_zod7.z.string(),
|
|
1763
|
+
locationData: locationDataSchema
|
|
1764
|
+
});
|
|
1765
|
+
var patientSensitiveInfoSchema = import_zod7.z.object({
|
|
1766
|
+
patientId: import_zod7.z.string(),
|
|
1767
|
+
userRef: import_zod7.z.string(),
|
|
1768
|
+
firstName: import_zod7.z.string().min(2),
|
|
1769
|
+
lastName: import_zod7.z.string().min(2),
|
|
1770
|
+
dateOfBirth: import_zod7.z.instanceof(import_firestore5.Timestamp).nullable(),
|
|
1771
|
+
gender: import_zod7.z.nativeEnum(Gender),
|
|
1772
|
+
email: import_zod7.z.string().email().optional(),
|
|
1773
|
+
phoneNumber: import_zod7.z.string().optional(),
|
|
1774
|
+
alternativePhoneNumber: import_zod7.z.string().optional(),
|
|
1775
|
+
addressData: addressDataSchema.optional(),
|
|
1776
|
+
emergencyContacts: import_zod7.z.array(emergencyContactSchema).optional(),
|
|
1777
|
+
createdAt: import_zod7.z.instanceof(import_firestore5.Timestamp),
|
|
1778
|
+
updatedAt: import_zod7.z.instanceof(import_firestore5.Timestamp)
|
|
1779
|
+
});
|
|
1780
|
+
var patientDoctorSchema = import_zod7.z.object({
|
|
1781
|
+
userRef: import_zod7.z.string(),
|
|
1782
|
+
assignedAt: import_zod7.z.instanceof(import_firestore5.Timestamp),
|
|
1783
|
+
assignedBy: import_zod7.z.string().optional(),
|
|
1784
|
+
isActive: import_zod7.z.boolean(),
|
|
1785
|
+
notes: import_zod7.z.string().optional()
|
|
1786
|
+
});
|
|
1787
|
+
var patientClinicSchema = import_zod7.z.object({
|
|
1788
|
+
clinicId: import_zod7.z.string(),
|
|
1789
|
+
assignedAt: import_zod7.z.instanceof(import_firestore5.Timestamp),
|
|
1790
|
+
assignedBy: import_zod7.z.string().optional(),
|
|
1791
|
+
isActive: import_zod7.z.boolean(),
|
|
1792
|
+
notes: import_zod7.z.string().optional()
|
|
1793
|
+
});
|
|
1794
|
+
var patientProfileSchema = import_zod7.z.object({
|
|
1795
|
+
id: import_zod7.z.string(),
|
|
1796
|
+
userRef: import_zod7.z.string(),
|
|
1797
|
+
displayName: import_zod7.z.string(),
|
|
1798
|
+
gamification: gamificationSchema,
|
|
1799
|
+
expoTokens: import_zod7.z.array(import_zod7.z.string()),
|
|
1800
|
+
isActive: import_zod7.z.boolean(),
|
|
1801
|
+
isVerified: import_zod7.z.boolean(),
|
|
1802
|
+
phoneNumber: import_zod7.z.string().nullable().optional(),
|
|
1803
|
+
dateOfBirth: import_zod7.z.instanceof(import_firestore5.Timestamp).nullable().optional(),
|
|
1804
|
+
doctors: import_zod7.z.array(patientDoctorSchema),
|
|
1805
|
+
clinics: import_zod7.z.array(patientClinicSchema),
|
|
1806
|
+
doctorIds: import_zod7.z.array(import_zod7.z.string()),
|
|
1807
|
+
clinicIds: import_zod7.z.array(import_zod7.z.string()),
|
|
1808
|
+
createdAt: import_zod7.z.instanceof(import_firestore5.Timestamp),
|
|
1809
|
+
updatedAt: import_zod7.z.instanceof(import_firestore5.Timestamp)
|
|
1810
|
+
});
|
|
1811
|
+
var createPatientProfileSchema = import_zod7.z.object({
|
|
1812
|
+
userRef: import_zod7.z.string(),
|
|
1813
|
+
displayName: import_zod7.z.string(),
|
|
1814
|
+
expoTokens: import_zod7.z.array(import_zod7.z.string()),
|
|
1815
|
+
gamification: gamificationSchema.optional(),
|
|
1816
|
+
isActive: import_zod7.z.boolean(),
|
|
1817
|
+
isVerified: import_zod7.z.boolean(),
|
|
1818
|
+
doctors: import_zod7.z.array(patientDoctorSchema).optional(),
|
|
1819
|
+
clinics: import_zod7.z.array(patientClinicSchema).optional(),
|
|
1820
|
+
doctorIds: import_zod7.z.array(import_zod7.z.string()).optional(),
|
|
1821
|
+
clinicIds: import_zod7.z.array(import_zod7.z.string()).optional()
|
|
1822
|
+
});
|
|
1823
|
+
var createPatientSensitiveInfoSchema = import_zod7.z.object({
|
|
1824
|
+
patientId: import_zod7.z.string(),
|
|
1825
|
+
userRef: import_zod7.z.string(),
|
|
1826
|
+
photoUrl: mediaResourceSchema.nullable().optional(),
|
|
1827
|
+
firstName: import_zod7.z.string().min(2),
|
|
1828
|
+
lastName: import_zod7.z.string().min(2),
|
|
1829
|
+
dateOfBirth: import_zod7.z.instanceof(import_firestore5.Timestamp).nullable(),
|
|
1830
|
+
gender: import_zod7.z.nativeEnum(Gender),
|
|
1831
|
+
email: import_zod7.z.string().email().optional(),
|
|
1832
|
+
phoneNumber: import_zod7.z.string().optional(),
|
|
1833
|
+
alternativePhoneNumber: import_zod7.z.string().optional(),
|
|
1834
|
+
addressData: addressDataSchema.optional(),
|
|
1835
|
+
emergencyContacts: import_zod7.z.array(emergencyContactSchema).optional()
|
|
1836
|
+
});
|
|
1837
|
+
var searchPatientsSchema = import_zod7.z.object({
|
|
1838
|
+
clinicId: import_zod7.z.string().optional(),
|
|
1839
|
+
practitionerId: import_zod7.z.string().optional()
|
|
1840
|
+
}).refine((data) => data.clinicId || data.practitionerId, {
|
|
1841
|
+
message: "At least one of clinicId or practitionerId must be provided",
|
|
1842
|
+
path: []
|
|
1843
|
+
// Optional: specify a path like ['clinicId'] or ['practitionerId']
|
|
1844
|
+
});
|
|
1845
|
+
var requesterInfoSchema = import_zod7.z.object({
|
|
1846
|
+
id: import_zod7.z.string(),
|
|
1847
|
+
role: import_zod7.z.enum(["clinic_admin", "practitioner"]),
|
|
1848
|
+
associatedClinicId: import_zod7.z.string().optional(),
|
|
1849
|
+
associatedPractitionerId: import_zod7.z.string().optional()
|
|
1850
|
+
}).refine(
|
|
1851
|
+
(data) => {
|
|
1852
|
+
if (data.role === "clinic_admin") {
|
|
1853
|
+
return !!data.associatedClinicId;
|
|
1854
|
+
} else if (data.role === "practitioner") {
|
|
1855
|
+
return !!data.associatedPractitionerId;
|
|
1856
|
+
}
|
|
1857
|
+
return false;
|
|
1858
|
+
},
|
|
1859
|
+
{
|
|
1860
|
+
message: "Associated ID (clinic or practitioner) is required based on role",
|
|
1861
|
+
path: ["associatedClinicId", "associatedPractitionerId"]
|
|
1862
|
+
}
|
|
1863
|
+
);
|
|
1864
|
+
|
|
1865
|
+
// src/services/patient/utils/docs.utils.ts
|
|
1866
|
+
var import_firestore7 = require("firebase/firestore");
|
|
1867
|
+
|
|
1868
|
+
// src/services/patient/utils/sensitive.utils.ts
|
|
1869
|
+
var import_firestore6 = require("firebase/firestore");
|
|
1870
|
+
var import_zod8 = require("zod");
|
|
1871
|
+
var handlePhotoUrlUpload = async (photoUrl, patientId, mediaService) => {
|
|
1872
|
+
if (!photoUrl) {
|
|
1873
|
+
return null;
|
|
1874
|
+
}
|
|
1875
|
+
if (typeof photoUrl === "string") {
|
|
1876
|
+
return photoUrl;
|
|
1877
|
+
}
|
|
1878
|
+
if (photoUrl instanceof File || photoUrl instanceof Blob) {
|
|
1879
|
+
const mediaMetadata = await mediaService.uploadMedia(
|
|
1880
|
+
photoUrl,
|
|
1881
|
+
patientId,
|
|
1882
|
+
// Using patientId as ownerId
|
|
1883
|
+
"private" /* PRIVATE */,
|
|
1884
|
+
// Sensitive info should be private
|
|
1885
|
+
"patient_sensitive_photos",
|
|
1886
|
+
photoUrl instanceof File ? photoUrl.name : `sensitive_photo_${patientId}`
|
|
1887
|
+
);
|
|
1888
|
+
return mediaMetadata.url;
|
|
1889
|
+
}
|
|
1890
|
+
return null;
|
|
1891
|
+
};
|
|
1892
|
+
var createSensitiveInfoUtil = async (db, data, requesterUserId, mediaService) => {
|
|
1893
|
+
try {
|
|
1894
|
+
if (data.userRef !== requesterUserId) {
|
|
1895
|
+
throw new Error("Only patient can create their sensitive information");
|
|
1896
|
+
}
|
|
1897
|
+
const validatedData = createPatientSensitiveInfoSchema.parse(data);
|
|
1898
|
+
const sensitiveDoc = await (0, import_firestore6.getDoc)(
|
|
1899
|
+
getSensitiveInfoDocRef(db, data.patientId)
|
|
1900
|
+
);
|
|
1901
|
+
if (sensitiveDoc.exists()) {
|
|
1902
|
+
throw new Error("Sensitive information already exists for this patient");
|
|
1903
|
+
}
|
|
1904
|
+
let processedPhotoUrl = null;
|
|
1905
|
+
if (validatedData.photoUrl && mediaService) {
|
|
1906
|
+
processedPhotoUrl = await handlePhotoUrlUpload(
|
|
1907
|
+
validatedData.photoUrl,
|
|
1908
|
+
data.patientId,
|
|
1909
|
+
mediaService
|
|
1910
|
+
);
|
|
1911
|
+
} else if (typeof validatedData.photoUrl === "string") {
|
|
1912
|
+
processedPhotoUrl = validatedData.photoUrl;
|
|
1913
|
+
}
|
|
1914
|
+
const sensitiveInfoData = {
|
|
1915
|
+
...validatedData,
|
|
1916
|
+
photoUrl: processedPhotoUrl,
|
|
1917
|
+
createdAt: (0, import_firestore6.serverTimestamp)(),
|
|
1918
|
+
updatedAt: (0, import_firestore6.serverTimestamp)()
|
|
1919
|
+
};
|
|
1920
|
+
await (0, import_firestore6.setDoc)(getSensitiveInfoDocRef(db, data.patientId), sensitiveInfoData);
|
|
1921
|
+
const createdDoc = await (0, import_firestore6.getDoc)(getSensitiveInfoDocRef(db, data.patientId));
|
|
1922
|
+
if (!createdDoc.exists()) {
|
|
1923
|
+
throw new Error("Failed to create sensitive information");
|
|
1924
|
+
}
|
|
1925
|
+
return createdDoc.data();
|
|
1926
|
+
} catch (error) {
|
|
1927
|
+
if (error instanceof import_zod8.z.ZodError) {
|
|
1928
|
+
throw new Error("Invalid sensitive info data: " + error.message);
|
|
1929
|
+
}
|
|
1594
1930
|
throw error;
|
|
1595
1931
|
}
|
|
1596
1932
|
};
|
|
1597
1933
|
var getSensitiveInfoUtil = async (db, patientId, requesterUserId) => {
|
|
1598
1934
|
await initSensitiveInfoDocIfNotExists(db, patientId, requesterUserId);
|
|
1599
|
-
const sensitiveDoc = await (0,
|
|
1935
|
+
const sensitiveDoc = await (0, import_firestore6.getDoc)(getSensitiveInfoDocRef(db, patientId));
|
|
1600
1936
|
return sensitiveDoc.exists() ? sensitiveDoc.data() : null;
|
|
1601
1937
|
};
|
|
1602
|
-
var updateSensitiveInfoUtil = async (db, patientId, data, requesterUserId) => {
|
|
1938
|
+
var updateSensitiveInfoUtil = async (db, patientId, data, requesterUserId, mediaService) => {
|
|
1603
1939
|
await initSensitiveInfoDocIfNotExists(db, patientId, requesterUserId);
|
|
1940
|
+
let processedPhotoUrl = void 0;
|
|
1941
|
+
if (data.photoUrl !== void 0) {
|
|
1942
|
+
if (mediaService) {
|
|
1943
|
+
processedPhotoUrl = await handlePhotoUrlUpload(
|
|
1944
|
+
data.photoUrl,
|
|
1945
|
+
patientId,
|
|
1946
|
+
mediaService
|
|
1947
|
+
);
|
|
1948
|
+
} else if (typeof data.photoUrl === "string" || data.photoUrl === null) {
|
|
1949
|
+
processedPhotoUrl = data.photoUrl;
|
|
1950
|
+
} else {
|
|
1951
|
+
throw new Error("MediaService required to process photo upload");
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1604
1954
|
const updateData = {
|
|
1605
1955
|
...data,
|
|
1606
|
-
|
|
1956
|
+
photoUrl: processedPhotoUrl,
|
|
1957
|
+
updatedAt: (0, import_firestore6.serverTimestamp)()
|
|
1607
1958
|
};
|
|
1608
|
-
await (0,
|
|
1609
|
-
const updatedDoc = await (0,
|
|
1959
|
+
await (0, import_firestore6.updateDoc)(getSensitiveInfoDocRef(db, patientId), updateData);
|
|
1960
|
+
const updatedDoc = await (0, import_firestore6.getDoc)(getSensitiveInfoDocRef(db, patientId));
|
|
1610
1961
|
if (!updatedDoc.exists()) {
|
|
1611
1962
|
throw new Error("Failed to retrieve updated sensitive information");
|
|
1612
1963
|
}
|
|
@@ -1615,21 +1966,21 @@ var updateSensitiveInfoUtil = async (db, patientId, data, requesterUserId) => {
|
|
|
1615
1966
|
|
|
1616
1967
|
// src/services/patient/utils/docs.utils.ts
|
|
1617
1968
|
var getPatientDocRef = (db, patientId) => {
|
|
1618
|
-
return (0,
|
|
1969
|
+
return (0, import_firestore7.doc)(db, PATIENTS_COLLECTION, patientId);
|
|
1619
1970
|
};
|
|
1620
1971
|
var getPatientDocRefByUserRef = async (db, userRef) => {
|
|
1621
|
-
const patientsRef = (0,
|
|
1622
|
-
const q = (0,
|
|
1623
|
-
const querySnapshot = await (0,
|
|
1972
|
+
const patientsRef = (0, import_firestore7.collection)(db, PATIENTS_COLLECTION);
|
|
1973
|
+
const q = (0, import_firestore7.query)(patientsRef, (0, import_firestore7.where)("userRef", "==", userRef));
|
|
1974
|
+
const querySnapshot = await (0, import_firestore7.getDocs)(q);
|
|
1624
1975
|
if (querySnapshot.empty) {
|
|
1625
1976
|
throw new Error("Patient profile not found");
|
|
1626
1977
|
}
|
|
1627
|
-
return (0,
|
|
1978
|
+
return (0, import_firestore7.doc)(db, PATIENTS_COLLECTION, querySnapshot.docs[0].id);
|
|
1628
1979
|
};
|
|
1629
1980
|
var getSensitiveInfoDocRef = (db, patientId) => {
|
|
1630
1981
|
const path = `${PATIENTS_COLLECTION}/${patientId}/${PATIENT_SENSITIVE_INFO_COLLECTION}/${patientId}`;
|
|
1631
1982
|
console.log(`[getSensitiveInfoDocRef] Creating reference with path: ${path}`);
|
|
1632
|
-
return (0,
|
|
1983
|
+
return (0, import_firestore7.doc)(
|
|
1633
1984
|
db,
|
|
1634
1985
|
PATIENTS_COLLECTION,
|
|
1635
1986
|
patientId,
|
|
@@ -1640,7 +1991,7 @@ var getSensitiveInfoDocRef = (db, patientId) => {
|
|
|
1640
1991
|
var getLocationInfoDocRef = (db, patientId) => {
|
|
1641
1992
|
const path = `${PATIENTS_COLLECTION}/${patientId}/${PATIENT_LOCATION_INFO_COLLECTION}/${patientId}`;
|
|
1642
1993
|
console.log(`[getLocationInfoDocRef] Creating reference with path: ${path}`);
|
|
1643
|
-
return (0,
|
|
1994
|
+
return (0, import_firestore7.doc)(
|
|
1644
1995
|
db,
|
|
1645
1996
|
PATIENTS_COLLECTION,
|
|
1646
1997
|
patientId,
|
|
@@ -1651,7 +2002,7 @@ var getLocationInfoDocRef = (db, patientId) => {
|
|
|
1651
2002
|
var getMedicalInfoDocRef = (db, patientId) => {
|
|
1652
2003
|
const path = `${PATIENTS_COLLECTION}/${patientId}/${PATIENT_MEDICAL_INFO_COLLECTION}/${patientId}`;
|
|
1653
2004
|
console.log(`[getMedicalInfoDocRef] Creating reference with path: ${path}`);
|
|
1654
|
-
return (0,
|
|
2005
|
+
return (0, import_firestore7.doc)(
|
|
1655
2006
|
db,
|
|
1656
2007
|
PATIENTS_COLLECTION,
|
|
1657
2008
|
patientId,
|
|
@@ -1668,7 +2019,7 @@ var initSensitiveInfoDocIfNotExists = async (db, patientId, userRef) => {
|
|
|
1668
2019
|
console.log(
|
|
1669
2020
|
`[initSensitiveInfoDocIfNotExists] Got document reference: ${sensitiveInfoRef.path}`
|
|
1670
2021
|
);
|
|
1671
|
-
const sensitiveDoc = await (0,
|
|
2022
|
+
const sensitiveDoc = await (0, import_firestore7.getDoc)(sensitiveInfoRef);
|
|
1672
2023
|
console.log(
|
|
1673
2024
|
`[initSensitiveInfoDocIfNotExists] Document exists: ${sensitiveDoc.exists()}`
|
|
1674
2025
|
);
|
|
@@ -1692,7 +2043,7 @@ var initSensitiveInfoDocIfNotExists = async (db, patientId, userRef) => {
|
|
|
1692
2043
|
)
|
|
1693
2044
|
);
|
|
1694
2045
|
await createSensitiveInfoUtil(db, defaultSensitiveInfo, userRef);
|
|
1695
|
-
const verifyDoc = await (0,
|
|
2046
|
+
const verifyDoc = await (0, import_firestore7.getDoc)(sensitiveInfoRef);
|
|
1696
2047
|
console.log(
|
|
1697
2048
|
`[initSensitiveInfoDocIfNotExists] Verification - document exists: ${verifyDoc.exists()}`
|
|
1698
2049
|
);
|
|
@@ -1709,10 +2060,10 @@ var initSensitiveInfoDocIfNotExists = async (db, patientId, userRef) => {
|
|
|
1709
2060
|
};
|
|
1710
2061
|
|
|
1711
2062
|
// src/services/patient/utils/medical.utils.ts
|
|
1712
|
-
var
|
|
2063
|
+
var import_firestore9 = require("firebase/firestore");
|
|
1713
2064
|
|
|
1714
2065
|
// src/services/patient/utils/practitioner.utils.ts
|
|
1715
|
-
var
|
|
2066
|
+
var import_firestore8 = require("firebase/firestore");
|
|
1716
2067
|
|
|
1717
2068
|
// src/types/practitioner/index.ts
|
|
1718
2069
|
var PRACTITIONERS_COLLECTION = "practitioners";
|
|
@@ -1737,23 +2088,23 @@ var getPatientsByPractitionerUtil = async (db, practitionerId, options) => {
|
|
|
1737
2088
|
`[getPatientsByPractitionerUtil] Fetching patients for practitioner ID: ${practitionerId} with options:`,
|
|
1738
2089
|
options
|
|
1739
2090
|
);
|
|
1740
|
-
const patientsCollection = (0,
|
|
2091
|
+
const patientsCollection = (0, import_firestore8.collection)(db, PATIENTS_COLLECTION);
|
|
1741
2092
|
const constraints = [
|
|
1742
|
-
(0,
|
|
2093
|
+
(0, import_firestore8.where)("doctorIds", "array-contains", practitionerId)
|
|
1743
2094
|
];
|
|
1744
|
-
let q = (0,
|
|
2095
|
+
let q = (0, import_firestore8.query)(patientsCollection, ...constraints);
|
|
1745
2096
|
if (options == null ? void 0 : options.limit) {
|
|
1746
|
-
q = (0,
|
|
2097
|
+
q = (0, import_firestore8.query)(q, (0, import_firestore8.limit)(options.limit));
|
|
1747
2098
|
}
|
|
1748
2099
|
if (options == null ? void 0 : options.startAfter) {
|
|
1749
|
-
const startAfterDoc = await (0,
|
|
1750
|
-
(0,
|
|
2100
|
+
const startAfterDoc = await (0, import_firestore8.getDoc)(
|
|
2101
|
+
(0, import_firestore8.doc)(db, PATIENTS_COLLECTION, options.startAfter)
|
|
1751
2102
|
);
|
|
1752
2103
|
if (startAfterDoc.exists()) {
|
|
1753
|
-
q = (0,
|
|
2104
|
+
q = (0, import_firestore8.query)(q, (0, import_firestore8.startAfter)(startAfterDoc));
|
|
1754
2105
|
}
|
|
1755
2106
|
}
|
|
1756
|
-
const patientsSnapshot = await (0,
|
|
2107
|
+
const patientsSnapshot = await (0, import_firestore8.getDocs)(q);
|
|
1757
2108
|
const patients = [];
|
|
1758
2109
|
patientsSnapshot.forEach((doc34) => {
|
|
1759
2110
|
patients.push(doc34.data());
|
|
@@ -1786,7 +2137,7 @@ var getPatientsByPractitionerWithDetailsUtil = async (db, practitionerId, option
|
|
|
1786
2137
|
const patientProfilesWithDetails = await Promise.all(
|
|
1787
2138
|
patientProfiles.map(async (profile) => {
|
|
1788
2139
|
try {
|
|
1789
|
-
const sensitiveInfoDoc = await (0,
|
|
2140
|
+
const sensitiveInfoDoc = await (0, import_firestore8.getDoc)(
|
|
1790
2141
|
getSensitiveInfoDocRef(db, profile.id)
|
|
1791
2142
|
);
|
|
1792
2143
|
const sensitiveInfo = sensitiveInfoDoc.exists() ? sensitiveInfoDoc.data() : void 0;
|
|
@@ -1822,13 +2173,13 @@ var getPractitionerProfileByUserRef = async (db, userRef) => {
|
|
|
1822
2173
|
console.log(
|
|
1823
2174
|
`[getPractitionerProfileByUserRef] Fetching practitioner with userRef: ${userRef}`
|
|
1824
2175
|
);
|
|
1825
|
-
const practitionersCollection = (0,
|
|
1826
|
-
const q = (0,
|
|
2176
|
+
const practitionersCollection = (0, import_firestore8.collection)(db, PRACTITIONERS_COLLECTION);
|
|
2177
|
+
const q = (0, import_firestore8.query)(
|
|
1827
2178
|
practitionersCollection,
|
|
1828
|
-
(0,
|
|
1829
|
-
(0,
|
|
2179
|
+
(0, import_firestore8.where)("userRef", "==", userRef),
|
|
2180
|
+
(0, import_firestore8.limit)(1)
|
|
1830
2181
|
);
|
|
1831
|
-
const querySnapshot = await (0,
|
|
2182
|
+
const querySnapshot = await (0, import_firestore8.getDocs)(q);
|
|
1832
2183
|
if (querySnapshot.empty) {
|
|
1833
2184
|
console.log(
|
|
1834
2185
|
`[getPractitionerProfileByUserRef] No practitioner found with userRef: ${userRef}`
|
|
@@ -1862,7 +2213,7 @@ var ensureMedicalInfoExists = async (db, patientId, userRef) => {
|
|
|
1862
2213
|
console.log(
|
|
1863
2214
|
`[ensureMedicalInfoExists] Got document reference: ${medicalInfoRef.path}`
|
|
1864
2215
|
);
|
|
1865
|
-
const medicalInfoDoc = await (0,
|
|
2216
|
+
const medicalInfoDoc = await (0, import_firestore9.getDoc)(medicalInfoRef);
|
|
1866
2217
|
console.log(
|
|
1867
2218
|
`[ensureMedicalInfoExists] Document exists: ${medicalInfoDoc.exists()}`
|
|
1868
2219
|
);
|
|
@@ -1870,7 +2221,7 @@ var ensureMedicalInfoExists = async (db, patientId, userRef) => {
|
|
|
1870
2221
|
const defaultData = {
|
|
1871
2222
|
...DEFAULT_MEDICAL_INFO,
|
|
1872
2223
|
patientId,
|
|
1873
|
-
lastUpdated: (0,
|
|
2224
|
+
lastUpdated: (0, import_firestore9.serverTimestamp)(),
|
|
1874
2225
|
updatedBy: userRef
|
|
1875
2226
|
};
|
|
1876
2227
|
console.log(
|
|
@@ -1880,9 +2231,9 @@ var ensureMedicalInfoExists = async (db, patientId, userRef) => {
|
|
|
1880
2231
|
(key, value) => value && typeof value === "object" && value.constructor && value.constructor.name === "Object" ? "[serverTimestamp]" : value
|
|
1881
2232
|
)
|
|
1882
2233
|
);
|
|
1883
|
-
await (0,
|
|
2234
|
+
await (0, import_firestore9.setDoc)(medicalInfoRef, defaultData);
|
|
1884
2235
|
console.log(`[ensureMedicalInfoExists] Document created successfully`);
|
|
1885
|
-
const verifyDoc = await (0,
|
|
2236
|
+
const verifyDoc = await (0, import_firestore9.getDoc)(medicalInfoRef);
|
|
1886
2237
|
console.log(
|
|
1887
2238
|
`[ensureMedicalInfoExists] Verification - document exists: ${verifyDoc.exists()}`
|
|
1888
2239
|
);
|
|
@@ -1898,7 +2249,7 @@ var ensureMedicalInfoExists = async (db, patientId, userRef) => {
|
|
|
1898
2249
|
};
|
|
1899
2250
|
var checkMedicalAccessUtil = async (db, patientId, userRef, userRoles) => {
|
|
1900
2251
|
var _a;
|
|
1901
|
-
const patientDoc = await (0,
|
|
2252
|
+
const patientDoc = await (0, import_firestore9.getDoc)(getPatientDocRef(db, patientId));
|
|
1902
2253
|
if (!patientDoc.exists()) {
|
|
1903
2254
|
throw new Error("Patient profile not found");
|
|
1904
2255
|
}
|
|
@@ -1931,17 +2282,17 @@ var checkMedicalAccessUtil = async (db, patientId, userRef, userRoles) => {
|
|
|
1931
2282
|
var createMedicalInfoUtil = async (db, patientId, data, userRef, userRoles) => {
|
|
1932
2283
|
await checkMedicalAccessUtil(db, patientId, userRef, userRoles);
|
|
1933
2284
|
const validatedData = createPatientMedicalInfoSchema.parse(data);
|
|
1934
|
-
await (0,
|
|
2285
|
+
await (0, import_firestore9.setDoc)(getMedicalInfoDocRef(db, patientId), {
|
|
1935
2286
|
...validatedData,
|
|
1936
2287
|
patientId,
|
|
1937
|
-
lastUpdated:
|
|
2288
|
+
lastUpdated: import_firestore9.Timestamp.now(),
|
|
1938
2289
|
updatedBy: userRef
|
|
1939
2290
|
});
|
|
1940
2291
|
};
|
|
1941
2292
|
var getMedicalInfoUtil = async (db, patientId, userRef, userRoles) => {
|
|
1942
2293
|
await checkMedicalAccessUtil(db, patientId, userRef, userRoles);
|
|
1943
2294
|
const docRef = getMedicalInfoDocRef(db, patientId);
|
|
1944
|
-
const snapshot = await (0,
|
|
2295
|
+
const snapshot = await (0, import_firestore9.getDoc)(docRef);
|
|
1945
2296
|
if (!snapshot.exists()) {
|
|
1946
2297
|
throw new Error("Medicinske informacije nisu prona\u0111ene");
|
|
1947
2298
|
}
|
|
@@ -1950,25 +2301,25 @@ var getMedicalInfoUtil = async (db, patientId, userRef, userRoles) => {
|
|
|
1950
2301
|
var updateVitalStatsUtil = async (db, patientId, data, userRef) => {
|
|
1951
2302
|
await ensureMedicalInfoExists(db, patientId, userRef);
|
|
1952
2303
|
const validatedData = updateVitalStatsSchema.parse(data);
|
|
1953
|
-
await (0,
|
|
2304
|
+
await (0, import_firestore9.updateDoc)(getMedicalInfoDocRef(db, patientId), {
|
|
1954
2305
|
vitalStats: validatedData,
|
|
1955
|
-
lastUpdated: (0,
|
|
2306
|
+
lastUpdated: (0, import_firestore9.serverTimestamp)(),
|
|
1956
2307
|
updatedBy: userRef
|
|
1957
2308
|
});
|
|
1958
2309
|
};
|
|
1959
2310
|
var addAllergyUtil = async (db, patientId, data, userRef) => {
|
|
1960
2311
|
await ensureMedicalInfoExists(db, patientId, userRef);
|
|
1961
2312
|
const validatedData = addAllergySchema.parse(data);
|
|
1962
|
-
await (0,
|
|
1963
|
-
allergies: (0,
|
|
1964
|
-
lastUpdated: (0,
|
|
2313
|
+
await (0, import_firestore9.updateDoc)(getMedicalInfoDocRef(db, patientId), {
|
|
2314
|
+
allergies: (0, import_firestore9.arrayUnion)(validatedData),
|
|
2315
|
+
lastUpdated: (0, import_firestore9.serverTimestamp)(),
|
|
1965
2316
|
updatedBy: userRef
|
|
1966
2317
|
});
|
|
1967
2318
|
};
|
|
1968
2319
|
var updateAllergyUtil = async (db, patientId, data, userRef) => {
|
|
1969
2320
|
const validatedData = updateAllergySchema.parse(data);
|
|
1970
2321
|
const { allergyIndex, ...updateData } = validatedData;
|
|
1971
|
-
const docSnapshot = await (0,
|
|
2322
|
+
const docSnapshot = await (0, import_firestore9.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
1972
2323
|
if (!docSnapshot.exists()) throw new Error("Medical info not found");
|
|
1973
2324
|
const medicalInfo = patientMedicalInfoSchema.parse(docSnapshot.data());
|
|
1974
2325
|
if (allergyIndex >= medicalInfo.allergies.length) {
|
|
@@ -1979,14 +2330,14 @@ var updateAllergyUtil = async (db, patientId, data, userRef) => {
|
|
|
1979
2330
|
...updatedAllergies[allergyIndex],
|
|
1980
2331
|
...updateData
|
|
1981
2332
|
};
|
|
1982
|
-
await (0,
|
|
2333
|
+
await (0, import_firestore9.updateDoc)(getMedicalInfoDocRef(db, patientId), {
|
|
1983
2334
|
allergies: updatedAllergies,
|
|
1984
|
-
lastUpdated: (0,
|
|
2335
|
+
lastUpdated: (0, import_firestore9.serverTimestamp)(),
|
|
1985
2336
|
updatedBy: userRef
|
|
1986
2337
|
});
|
|
1987
2338
|
};
|
|
1988
2339
|
var removeAllergyUtil = async (db, patientId, allergyIndex, userRef) => {
|
|
1989
|
-
const doc34 = await (0,
|
|
2340
|
+
const doc34 = await (0, import_firestore9.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
1990
2341
|
if (!doc34.exists()) throw new Error("Medical info not found");
|
|
1991
2342
|
const medicalInfo = doc34.data();
|
|
1992
2343
|
if (allergyIndex >= medicalInfo.allergies.length) {
|
|
@@ -1995,25 +2346,25 @@ var removeAllergyUtil = async (db, patientId, allergyIndex, userRef) => {
|
|
|
1995
2346
|
const updatedAllergies = medicalInfo.allergies.filter(
|
|
1996
2347
|
(_, index) => index !== allergyIndex
|
|
1997
2348
|
);
|
|
1998
|
-
await (0,
|
|
2349
|
+
await (0, import_firestore9.updateDoc)(getMedicalInfoDocRef(db, patientId), {
|
|
1999
2350
|
allergies: updatedAllergies,
|
|
2000
|
-
lastUpdated: (0,
|
|
2351
|
+
lastUpdated: (0, import_firestore9.serverTimestamp)(),
|
|
2001
2352
|
updatedBy: userRef
|
|
2002
2353
|
});
|
|
2003
2354
|
};
|
|
2004
2355
|
var addBlockingConditionUtil = async (db, patientId, data, userRef) => {
|
|
2005
2356
|
await ensureMedicalInfoExists(db, patientId, userRef);
|
|
2006
2357
|
const validatedData = addBlockingConditionSchema.parse(data);
|
|
2007
|
-
await (0,
|
|
2008
|
-
blockingConditions: (0,
|
|
2009
|
-
lastUpdated: (0,
|
|
2358
|
+
await (0, import_firestore9.updateDoc)(getMedicalInfoDocRef(db, patientId), {
|
|
2359
|
+
blockingConditions: (0, import_firestore9.arrayUnion)(validatedData),
|
|
2360
|
+
lastUpdated: (0, import_firestore9.serverTimestamp)(),
|
|
2010
2361
|
updatedBy: userRef
|
|
2011
2362
|
});
|
|
2012
2363
|
};
|
|
2013
2364
|
var updateBlockingConditionUtil = async (db, patientId, data, userRef) => {
|
|
2014
2365
|
const validatedData = updateBlockingConditionSchema.parse(data);
|
|
2015
2366
|
const { conditionIndex, ...updateData } = validatedData;
|
|
2016
|
-
const doc34 = await (0,
|
|
2367
|
+
const doc34 = await (0, import_firestore9.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
2017
2368
|
if (!doc34.exists()) throw new Error("Medical info not found");
|
|
2018
2369
|
const medicalInfo = doc34.data();
|
|
2019
2370
|
if (conditionIndex >= medicalInfo.blockingConditions.length) {
|
|
@@ -2024,14 +2375,14 @@ var updateBlockingConditionUtil = async (db, patientId, data, userRef) => {
|
|
|
2024
2375
|
...updatedConditions[conditionIndex],
|
|
2025
2376
|
...updateData
|
|
2026
2377
|
};
|
|
2027
|
-
await (0,
|
|
2378
|
+
await (0, import_firestore9.updateDoc)(getMedicalInfoDocRef(db, patientId), {
|
|
2028
2379
|
blockingConditions: updatedConditions,
|
|
2029
|
-
lastUpdated: (0,
|
|
2380
|
+
lastUpdated: (0, import_firestore9.serverTimestamp)(),
|
|
2030
2381
|
updatedBy: userRef
|
|
2031
2382
|
});
|
|
2032
2383
|
};
|
|
2033
2384
|
var removeBlockingConditionUtil = async (db, patientId, conditionIndex, userRef) => {
|
|
2034
|
-
const doc34 = await (0,
|
|
2385
|
+
const doc34 = await (0, import_firestore9.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
2035
2386
|
if (!doc34.exists()) throw new Error("Medical info not found");
|
|
2036
2387
|
const medicalInfo = doc34.data();
|
|
2037
2388
|
if (conditionIndex >= medicalInfo.blockingConditions.length) {
|
|
@@ -2040,25 +2391,25 @@ var removeBlockingConditionUtil = async (db, patientId, conditionIndex, userRef)
|
|
|
2040
2391
|
const updatedConditions = medicalInfo.blockingConditions.filter(
|
|
2041
2392
|
(_, index) => index !== conditionIndex
|
|
2042
2393
|
);
|
|
2043
|
-
await (0,
|
|
2394
|
+
await (0, import_firestore9.updateDoc)(getMedicalInfoDocRef(db, patientId), {
|
|
2044
2395
|
blockingConditions: updatedConditions,
|
|
2045
|
-
lastUpdated: (0,
|
|
2396
|
+
lastUpdated: (0, import_firestore9.serverTimestamp)(),
|
|
2046
2397
|
updatedBy: userRef
|
|
2047
2398
|
});
|
|
2048
2399
|
};
|
|
2049
2400
|
var addContraindicationUtil = async (db, patientId, data, userRef) => {
|
|
2050
2401
|
await ensureMedicalInfoExists(db, patientId, userRef);
|
|
2051
2402
|
const validatedData = addContraindicationSchema.parse(data);
|
|
2052
|
-
await (0,
|
|
2053
|
-
contraindications: (0,
|
|
2054
|
-
lastUpdated: (0,
|
|
2403
|
+
await (0, import_firestore9.updateDoc)(getMedicalInfoDocRef(db, patientId), {
|
|
2404
|
+
contraindications: (0, import_firestore9.arrayUnion)(validatedData),
|
|
2405
|
+
lastUpdated: (0, import_firestore9.serverTimestamp)(),
|
|
2055
2406
|
updatedBy: userRef
|
|
2056
2407
|
});
|
|
2057
2408
|
};
|
|
2058
2409
|
var updateContraindicationUtil = async (db, patientId, data, userRef) => {
|
|
2059
2410
|
const validatedData = updateContraindicationSchema.parse(data);
|
|
2060
2411
|
const { contraindicationIndex, ...updateData } = validatedData;
|
|
2061
|
-
const doc34 = await (0,
|
|
2412
|
+
const doc34 = await (0, import_firestore9.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
2062
2413
|
if (!doc34.exists()) throw new Error("Medical info not found");
|
|
2063
2414
|
const medicalInfo = doc34.data();
|
|
2064
2415
|
if (contraindicationIndex >= medicalInfo.contraindications.length) {
|
|
@@ -2069,14 +2420,14 @@ var updateContraindicationUtil = async (db, patientId, data, userRef) => {
|
|
|
2069
2420
|
...updatedContraindications[contraindicationIndex],
|
|
2070
2421
|
...updateData
|
|
2071
2422
|
};
|
|
2072
|
-
await (0,
|
|
2423
|
+
await (0, import_firestore9.updateDoc)(getMedicalInfoDocRef(db, patientId), {
|
|
2073
2424
|
contraindications: updatedContraindications,
|
|
2074
|
-
lastUpdated: (0,
|
|
2425
|
+
lastUpdated: (0, import_firestore9.serverTimestamp)(),
|
|
2075
2426
|
updatedBy: userRef
|
|
2076
2427
|
});
|
|
2077
2428
|
};
|
|
2078
2429
|
var removeContraindicationUtil = async (db, patientId, contraindicationIndex, userRef) => {
|
|
2079
|
-
const doc34 = await (0,
|
|
2430
|
+
const doc34 = await (0, import_firestore9.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
2080
2431
|
if (!doc34.exists()) throw new Error("Medical info not found");
|
|
2081
2432
|
const medicalInfo = doc34.data();
|
|
2082
2433
|
if (contraindicationIndex >= medicalInfo.contraindications.length) {
|
|
@@ -2085,25 +2436,25 @@ var removeContraindicationUtil = async (db, patientId, contraindicationIndex, us
|
|
|
2085
2436
|
const updatedContraindications = medicalInfo.contraindications.filter(
|
|
2086
2437
|
(_, index) => index !== contraindicationIndex
|
|
2087
2438
|
);
|
|
2088
|
-
await (0,
|
|
2439
|
+
await (0, import_firestore9.updateDoc)(getMedicalInfoDocRef(db, patientId), {
|
|
2089
2440
|
contraindications: updatedContraindications,
|
|
2090
|
-
lastUpdated: (0,
|
|
2441
|
+
lastUpdated: (0, import_firestore9.serverTimestamp)(),
|
|
2091
2442
|
updatedBy: userRef
|
|
2092
2443
|
});
|
|
2093
2444
|
};
|
|
2094
2445
|
var addMedicationUtil = async (db, patientId, data, userRef) => {
|
|
2095
2446
|
await ensureMedicalInfoExists(db, patientId, userRef);
|
|
2096
2447
|
const validatedData = addMedicationSchema.parse(data);
|
|
2097
|
-
await (0,
|
|
2098
|
-
currentMedications: (0,
|
|
2099
|
-
lastUpdated: (0,
|
|
2448
|
+
await (0, import_firestore9.updateDoc)(getMedicalInfoDocRef(db, patientId), {
|
|
2449
|
+
currentMedications: (0, import_firestore9.arrayUnion)(validatedData),
|
|
2450
|
+
lastUpdated: (0, import_firestore9.serverTimestamp)(),
|
|
2100
2451
|
updatedBy: userRef
|
|
2101
2452
|
});
|
|
2102
2453
|
};
|
|
2103
2454
|
var updateMedicationUtil = async (db, patientId, data, userRef) => {
|
|
2104
2455
|
const validatedData = updateMedicationSchema.parse(data);
|
|
2105
2456
|
const { medicationIndex, ...updateData } = validatedData;
|
|
2106
|
-
const doc34 = await (0,
|
|
2457
|
+
const doc34 = await (0, import_firestore9.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
2107
2458
|
if (!doc34.exists()) throw new Error("Medical info not found");
|
|
2108
2459
|
const medicalInfo = doc34.data();
|
|
2109
2460
|
if (medicationIndex >= medicalInfo.currentMedications.length) {
|
|
@@ -2114,14 +2465,14 @@ var updateMedicationUtil = async (db, patientId, data, userRef) => {
|
|
|
2114
2465
|
...updatedMedications[medicationIndex],
|
|
2115
2466
|
...updateData
|
|
2116
2467
|
};
|
|
2117
|
-
await (0,
|
|
2468
|
+
await (0, import_firestore9.updateDoc)(getMedicalInfoDocRef(db, patientId), {
|
|
2118
2469
|
currentMedications: updatedMedications,
|
|
2119
|
-
lastUpdated: (0,
|
|
2470
|
+
lastUpdated: (0, import_firestore9.serverTimestamp)(),
|
|
2120
2471
|
updatedBy: userRef
|
|
2121
2472
|
});
|
|
2122
2473
|
};
|
|
2123
2474
|
var removeMedicationUtil = async (db, patientId, medicationIndex, userRef) => {
|
|
2124
|
-
const doc34 = await (0,
|
|
2475
|
+
const doc34 = await (0, import_firestore9.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
2125
2476
|
if (!doc34.exists()) throw new Error("Medical info not found");
|
|
2126
2477
|
const medicalInfo = doc34.data();
|
|
2127
2478
|
if (medicationIndex >= medicalInfo.currentMedications.length) {
|
|
@@ -2130,9 +2481,9 @@ var removeMedicationUtil = async (db, patientId, medicationIndex, userRef) => {
|
|
|
2130
2481
|
const updatedMedications = medicalInfo.currentMedications.filter(
|
|
2131
2482
|
(_, index) => index !== medicationIndex
|
|
2132
2483
|
);
|
|
2133
|
-
await (0,
|
|
2484
|
+
await (0, import_firestore9.updateDoc)(getMedicalInfoDocRef(db, patientId), {
|
|
2134
2485
|
currentMedications: updatedMedications,
|
|
2135
|
-
lastUpdated: (0,
|
|
2486
|
+
lastUpdated: (0, import_firestore9.serverTimestamp)(),
|
|
2136
2487
|
updatedBy: userRef
|
|
2137
2488
|
});
|
|
2138
2489
|
};
|
|
@@ -2149,7 +2500,6 @@ var createPatientProfileUtil = async (db, data, generateId2) => {
|
|
|
2149
2500
|
id: patientId,
|
|
2150
2501
|
userRef: validatedData.userRef,
|
|
2151
2502
|
displayName: validatedData.displayName,
|
|
2152
|
-
profilePhoto: validatedData.profilePhoto || null,
|
|
2153
2503
|
expoTokens: validatedData.expoTokens,
|
|
2154
2504
|
gamification: validatedData.gamification || {
|
|
2155
2505
|
level: 1,
|
|
@@ -2161,15 +2511,15 @@ var createPatientProfileUtil = async (db, data, generateId2) => {
|
|
|
2161
2511
|
clinics: validatedData.clinics || [],
|
|
2162
2512
|
doctorIds: ((_a = validatedData.doctors) == null ? void 0 : _a.map((d) => d.userRef)) || [],
|
|
2163
2513
|
clinicIds: ((_b = validatedData.clinics) == null ? void 0 : _b.map((c) => c.clinicId)) || [],
|
|
2164
|
-
createdAt: (0,
|
|
2165
|
-
updatedAt: (0,
|
|
2514
|
+
createdAt: (0, import_firestore10.serverTimestamp)(),
|
|
2515
|
+
updatedAt: (0, import_firestore10.serverTimestamp)()
|
|
2166
2516
|
};
|
|
2167
2517
|
patientProfileSchema.parse({
|
|
2168
2518
|
...patientData,
|
|
2169
|
-
createdAt:
|
|
2170
|
-
updatedAt:
|
|
2519
|
+
createdAt: import_firestore10.Timestamp.now(),
|
|
2520
|
+
updatedAt: import_firestore10.Timestamp.now()
|
|
2171
2521
|
});
|
|
2172
|
-
await (0,
|
|
2522
|
+
await (0, import_firestore10.setDoc)(getPatientDocRef(db, patientId), patientData);
|
|
2173
2523
|
console.log(`[createPatientProfileUtil] Creating sensitive info document`);
|
|
2174
2524
|
let sensitiveInfoSuccess = false;
|
|
2175
2525
|
try {
|
|
@@ -2183,81 +2533,103 @@ var createPatientProfileUtil = async (db, data, generateId2) => {
|
|
|
2183
2533
|
);
|
|
2184
2534
|
sensitiveInfoSuccess = true;
|
|
2185
2535
|
} catch (sensitiveError) {
|
|
2186
|
-
console.error(
|
|
2536
|
+
console.error(
|
|
2537
|
+
`[createPatientProfileUtil] Error creating sensitive info:`,
|
|
2538
|
+
sensitiveError
|
|
2539
|
+
);
|
|
2187
2540
|
}
|
|
2188
2541
|
console.log(`[createPatientProfileUtil] Creating medical info document`);
|
|
2189
2542
|
let medicalInfoSuccess = false;
|
|
2190
2543
|
try {
|
|
2191
2544
|
await ensureMedicalInfoExists(db, patientId, validatedData.userRef);
|
|
2192
|
-
console.log(
|
|
2545
|
+
console.log(
|
|
2546
|
+
`[createPatientProfileUtil] Medical info document created successfully`
|
|
2547
|
+
);
|
|
2193
2548
|
medicalInfoSuccess = true;
|
|
2194
2549
|
} catch (medicalError) {
|
|
2195
|
-
console.error(
|
|
2550
|
+
console.error(
|
|
2551
|
+
`[createPatientProfileUtil] Error creating medical info:`,
|
|
2552
|
+
medicalError
|
|
2553
|
+
);
|
|
2196
2554
|
}
|
|
2197
2555
|
if (!sensitiveInfoSuccess || !medicalInfoSuccess) {
|
|
2198
|
-
console.log(
|
|
2556
|
+
console.log(
|
|
2557
|
+
`[createPatientProfileUtil] Using fallback method to create documents`
|
|
2558
|
+
);
|
|
2199
2559
|
try {
|
|
2200
2560
|
await testCreateSubDocuments(db, patientId, validatedData.userRef);
|
|
2201
|
-
console.log(
|
|
2561
|
+
console.log(
|
|
2562
|
+
`[createPatientProfileUtil] Fallback method completed successfully`
|
|
2563
|
+
);
|
|
2202
2564
|
} catch (fallbackError) {
|
|
2203
|
-
console.error(
|
|
2565
|
+
console.error(
|
|
2566
|
+
`[createPatientProfileUtil] Fallback method failed:`,
|
|
2567
|
+
fallbackError
|
|
2568
|
+
);
|
|
2204
2569
|
}
|
|
2205
2570
|
}
|
|
2206
2571
|
console.log(`[createPatientProfileUtil] Verifying patient document exists`);
|
|
2207
|
-
const patientDoc = await (0,
|
|
2572
|
+
const patientDoc = await (0, import_firestore10.getDoc)(getPatientDocRef(db, patientId));
|
|
2208
2573
|
if (!patientDoc.exists()) {
|
|
2209
|
-
console.error(
|
|
2574
|
+
console.error(
|
|
2575
|
+
`[createPatientProfileUtil] Patient document not found after creation`
|
|
2576
|
+
);
|
|
2210
2577
|
throw new Error("Failed to create patient profile");
|
|
2211
2578
|
}
|
|
2212
|
-
console.log(
|
|
2579
|
+
console.log(
|
|
2580
|
+
`[createPatientProfileUtil] Patient profile creation completed successfully`
|
|
2581
|
+
);
|
|
2213
2582
|
return patientDoc.data();
|
|
2214
2583
|
} catch (error) {
|
|
2215
|
-
console.error(
|
|
2216
|
-
|
|
2584
|
+
console.error(
|
|
2585
|
+
`[createPatientProfileUtil] Error in patient profile creation:`,
|
|
2586
|
+
error
|
|
2587
|
+
);
|
|
2588
|
+
if (error instanceof import_zod9.z.ZodError) {
|
|
2217
2589
|
throw new Error("Invalid patient data: " + error.message);
|
|
2218
2590
|
}
|
|
2219
2591
|
throw error;
|
|
2220
2592
|
}
|
|
2221
2593
|
};
|
|
2222
2594
|
var getPatientProfileUtil = async (db, patientId) => {
|
|
2223
|
-
const patientDoc = await (0,
|
|
2595
|
+
const patientDoc = await (0, import_firestore10.getDoc)(getPatientDocRef(db, patientId));
|
|
2224
2596
|
return patientDoc.exists() ? patientDoc.data() : null;
|
|
2225
2597
|
};
|
|
2226
2598
|
var getPatientProfileByUserRefUtil = async (db, userRef) => {
|
|
2227
2599
|
try {
|
|
2228
2600
|
const docRef = await getPatientDocRefByUserRef(db, userRef);
|
|
2229
|
-
const patientDoc = await (0,
|
|
2601
|
+
const patientDoc = await (0, import_firestore10.getDoc)(docRef);
|
|
2230
2602
|
return patientDoc.exists() ? patientDoc.data() : null;
|
|
2231
2603
|
} catch (error) {
|
|
2232
2604
|
return null;
|
|
2233
2605
|
}
|
|
2234
2606
|
};
|
|
2235
2607
|
var addExpoTokenUtil = async (db, patientId, token) => {
|
|
2236
|
-
await (0,
|
|
2237
|
-
expoTokens: (0,
|
|
2238
|
-
updatedAt: (0,
|
|
2608
|
+
await (0, import_firestore10.updateDoc)(getPatientDocRef(db, patientId), {
|
|
2609
|
+
expoTokens: (0, import_firestore10.arrayUnion)(token),
|
|
2610
|
+
updatedAt: (0, import_firestore10.serverTimestamp)()
|
|
2239
2611
|
});
|
|
2240
2612
|
};
|
|
2241
2613
|
var removeExpoTokenUtil = async (db, patientId, token) => {
|
|
2242
|
-
await (0,
|
|
2243
|
-
expoTokens: (0,
|
|
2244
|
-
updatedAt: (0,
|
|
2614
|
+
await (0, import_firestore10.updateDoc)(getPatientDocRef(db, patientId), {
|
|
2615
|
+
expoTokens: (0, import_firestore10.arrayRemove)(token),
|
|
2616
|
+
updatedAt: (0, import_firestore10.serverTimestamp)()
|
|
2245
2617
|
});
|
|
2246
2618
|
};
|
|
2247
2619
|
var addPointsUtil = async (db, patientId, points) => {
|
|
2248
|
-
await (0,
|
|
2249
|
-
"gamification.points": (0,
|
|
2250
|
-
updatedAt: (0,
|
|
2620
|
+
await (0, import_firestore10.updateDoc)(getPatientDocRef(db, patientId), {
|
|
2621
|
+
"gamification.points": (0, import_firestore10.increment)(points),
|
|
2622
|
+
updatedAt: (0, import_firestore10.serverTimestamp)()
|
|
2251
2623
|
});
|
|
2252
2624
|
};
|
|
2253
2625
|
var updatePatientProfileUtil = async (db, patientId, data) => {
|
|
2254
2626
|
try {
|
|
2255
2627
|
const updateData = {
|
|
2256
2628
|
...data,
|
|
2257
|
-
updatedAt: (0,
|
|
2629
|
+
updatedAt: (0, import_firestore10.serverTimestamp)()
|
|
2258
2630
|
};
|
|
2259
|
-
await (0,
|
|
2260
|
-
const updatedDoc = await (0,
|
|
2631
|
+
await (0, import_firestore10.updateDoc)(getPatientDocRef(db, patientId), updateData);
|
|
2632
|
+
const updatedDoc = await (0, import_firestore10.getDoc)(getPatientDocRef(db, patientId));
|
|
2261
2633
|
if (!updatedDoc.exists()) {
|
|
2262
2634
|
throw new Error("Patient profile not found after update");
|
|
2263
2635
|
}
|
|
@@ -2270,7 +2642,7 @@ var updatePatientProfileUtil = async (db, patientId, data) => {
|
|
|
2270
2642
|
var updatePatientProfileByUserRefUtil = async (db, userRef, data) => {
|
|
2271
2643
|
try {
|
|
2272
2644
|
const docRef = await getPatientDocRefByUserRef(db, userRef);
|
|
2273
|
-
const patientDoc = await (0,
|
|
2645
|
+
const patientDoc = await (0, import_firestore10.getDoc)(docRef);
|
|
2274
2646
|
if (!patientDoc.exists()) {
|
|
2275
2647
|
throw new Error("Patient profile not found");
|
|
2276
2648
|
}
|
|
@@ -2278,49 +2650,10 @@ var updatePatientProfileByUserRefUtil = async (db, userRef, data) => {
|
|
|
2278
2650
|
return updatePatientProfileUtil(db, patientData.id, data);
|
|
2279
2651
|
} catch (error) {
|
|
2280
2652
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2281
|
-
throw new Error(
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
var uploadProfilePhotoUtil = async (storage, patientId, file) => {
|
|
2285
|
-
const photoRef = (0, import_storage3.ref)(storage, `patient-photos/${patientId}/profile-photo`);
|
|
2286
|
-
await (0, import_storage3.uploadBytes)(photoRef, file);
|
|
2287
|
-
return (0, import_storage3.getDownloadURL)(photoRef);
|
|
2288
|
-
};
|
|
2289
|
-
var updateProfilePhotoUtil = async (storage, db, patientId, file) => {
|
|
2290
|
-
const patientDoc = await (0, import_firestore8.getDoc)(getPatientDocRef(db, patientId));
|
|
2291
|
-
if (!patientDoc.exists()) throw new Error("Patient profile not found");
|
|
2292
|
-
const patientData = patientDoc.data();
|
|
2293
|
-
if (patientData.profilePhoto) {
|
|
2294
|
-
try {
|
|
2295
|
-
const oldPhotoRef = (0, import_storage3.ref)(storage, patientData.profilePhoto);
|
|
2296
|
-
await (0, import_storage3.deleteObject)(oldPhotoRef);
|
|
2297
|
-
} catch (error) {
|
|
2298
|
-
console.warn("Failed to delete old profile photo:", error);
|
|
2299
|
-
}
|
|
2300
|
-
}
|
|
2301
|
-
const newPhotoUrl = await uploadProfilePhotoUtil(storage, patientId, file);
|
|
2302
|
-
await (0, import_firestore8.updateDoc)(getPatientDocRef(db, patientId), {
|
|
2303
|
-
profilePhoto: newPhotoUrl,
|
|
2304
|
-
updatedAt: (0, import_firestore8.serverTimestamp)()
|
|
2305
|
-
});
|
|
2306
|
-
return newPhotoUrl;
|
|
2307
|
-
};
|
|
2308
|
-
var deleteProfilePhotoUtil = async (storage, db, patientId) => {
|
|
2309
|
-
const patientDoc = await (0, import_firestore8.getDoc)(getPatientDocRef(db, patientId));
|
|
2310
|
-
if (!patientDoc.exists()) throw new Error("Patient profile not found");
|
|
2311
|
-
const patientData = patientDoc.data();
|
|
2312
|
-
if (patientData.profilePhoto) {
|
|
2313
|
-
try {
|
|
2314
|
-
const photoRef = (0, import_storage3.ref)(storage, patientData.profilePhoto);
|
|
2315
|
-
await (0, import_storage3.deleteObject)(photoRef);
|
|
2316
|
-
} catch (error) {
|
|
2317
|
-
console.warn("Failed to delete profile photo:", error);
|
|
2318
|
-
}
|
|
2653
|
+
throw new Error(
|
|
2654
|
+
`Failed to update patient profile by user ref: ${errorMessage}`
|
|
2655
|
+
);
|
|
2319
2656
|
}
|
|
2320
|
-
await (0, import_firestore8.updateDoc)(getPatientDocRef(db, patientId), {
|
|
2321
|
-
profilePhoto: null,
|
|
2322
|
-
updatedAt: (0, import_firestore8.serverTimestamp)()
|
|
2323
|
-
});
|
|
2324
2657
|
};
|
|
2325
2658
|
var testCreateSubDocuments = async (db, patientId, userRef) => {
|
|
2326
2659
|
console.log(
|
|
@@ -2329,33 +2662,41 @@ var testCreateSubDocuments = async (db, patientId, userRef) => {
|
|
|
2329
2662
|
try {
|
|
2330
2663
|
console.log(`[testCreateSubDocuments] Testing sensitive info creation`);
|
|
2331
2664
|
const sensitiveInfoRef = getSensitiveInfoDocRef(db, patientId);
|
|
2332
|
-
console.log(
|
|
2665
|
+
console.log(
|
|
2666
|
+
`[testCreateSubDocuments] Sensitive info path: ${sensitiveInfoRef.path}`
|
|
2667
|
+
);
|
|
2333
2668
|
const defaultSensitiveInfo = {
|
|
2334
2669
|
patientId,
|
|
2335
2670
|
userRef,
|
|
2336
2671
|
photoUrl: "",
|
|
2337
2672
|
firstName: "Name",
|
|
2338
2673
|
lastName: "Surname",
|
|
2339
|
-
dateOfBirth:
|
|
2674
|
+
dateOfBirth: import_firestore10.Timestamp.now(),
|
|
2340
2675
|
gender: "prefer_not_to_say" /* PREFER_NOT_TO_SAY */,
|
|
2341
2676
|
email: "test@example.com",
|
|
2342
2677
|
phoneNumber: "",
|
|
2343
|
-
createdAt:
|
|
2344
|
-
updatedAt:
|
|
2678
|
+
createdAt: import_firestore10.Timestamp.now(),
|
|
2679
|
+
updatedAt: import_firestore10.Timestamp.now()
|
|
2345
2680
|
};
|
|
2346
|
-
await (0,
|
|
2347
|
-
console.log(
|
|
2681
|
+
await (0, import_firestore10.setDoc)(sensitiveInfoRef, defaultSensitiveInfo);
|
|
2682
|
+
console.log(
|
|
2683
|
+
`[testCreateSubDocuments] Sensitive info document created directly`
|
|
2684
|
+
);
|
|
2348
2685
|
console.log(`[testCreateSubDocuments] Testing medical info creation`);
|
|
2349
2686
|
const medicalInfoRef = getMedicalInfoDocRef(db, patientId);
|
|
2350
|
-
console.log(
|
|
2687
|
+
console.log(
|
|
2688
|
+
`[testCreateSubDocuments] Medical info path: ${medicalInfoRef.path}`
|
|
2689
|
+
);
|
|
2351
2690
|
const defaultMedicalInfo = {
|
|
2352
2691
|
...DEFAULT_MEDICAL_INFO,
|
|
2353
2692
|
patientId,
|
|
2354
|
-
lastUpdated:
|
|
2693
|
+
lastUpdated: import_firestore10.Timestamp.now(),
|
|
2355
2694
|
updatedBy: userRef
|
|
2356
2695
|
};
|
|
2357
|
-
await (0,
|
|
2358
|
-
console.log(
|
|
2696
|
+
await (0, import_firestore10.setDoc)(medicalInfoRef, defaultMedicalInfo);
|
|
2697
|
+
console.log(
|
|
2698
|
+
`[testCreateSubDocuments] Medical info document created directly`
|
|
2699
|
+
);
|
|
2359
2700
|
console.log(`[testCreateSubDocuments] Test completed successfully`);
|
|
2360
2701
|
} catch (error) {
|
|
2361
2702
|
console.error(`[testCreateSubDocuments] Error:`, error);
|
|
@@ -2366,10 +2707,12 @@ var searchPatientsUtil = async (db, params, requester) => {
|
|
|
2366
2707
|
searchPatientsSchema.parse(params);
|
|
2367
2708
|
requesterInfoSchema.parse(requester);
|
|
2368
2709
|
const constraints = [];
|
|
2369
|
-
const patientsCollectionRef = (0,
|
|
2710
|
+
const patientsCollectionRef = (0, import_firestore10.collection)(db, PATIENTS_COLLECTION);
|
|
2370
2711
|
if (requester.role === "clinic_admin") {
|
|
2371
2712
|
if (!requester.associatedClinicId) {
|
|
2372
|
-
throw new Error(
|
|
2713
|
+
throw new Error(
|
|
2714
|
+
"Associated clinic ID is required for clinic admin search."
|
|
2715
|
+
);
|
|
2373
2716
|
}
|
|
2374
2717
|
if (params.clinicId && params.clinicId !== requester.associatedClinicId) {
|
|
2375
2718
|
console.warn(
|
|
@@ -2377,13 +2720,19 @@ var searchPatientsUtil = async (db, params, requester) => {
|
|
|
2377
2720
|
);
|
|
2378
2721
|
return [];
|
|
2379
2722
|
}
|
|
2380
|
-
constraints.push(
|
|
2723
|
+
constraints.push(
|
|
2724
|
+
(0, import_firestore10.where)("clinicIds", "array-contains", requester.associatedClinicId)
|
|
2725
|
+
);
|
|
2381
2726
|
if (params.practitionerId) {
|
|
2382
|
-
constraints.push(
|
|
2727
|
+
constraints.push(
|
|
2728
|
+
(0, import_firestore10.where)("doctorIds", "array-contains", params.practitionerId)
|
|
2729
|
+
);
|
|
2383
2730
|
}
|
|
2384
2731
|
} else if (requester.role === "practitioner") {
|
|
2385
2732
|
if (!requester.associatedPractitionerId) {
|
|
2386
|
-
throw new Error(
|
|
2733
|
+
throw new Error(
|
|
2734
|
+
"Associated practitioner ID is required for practitioner search."
|
|
2735
|
+
);
|
|
2387
2736
|
}
|
|
2388
2737
|
if (params.practitionerId && params.practitionerId !== requester.associatedPractitionerId) {
|
|
2389
2738
|
console.warn(
|
|
@@ -2391,18 +2740,24 @@ var searchPatientsUtil = async (db, params, requester) => {
|
|
|
2391
2740
|
);
|
|
2392
2741
|
return [];
|
|
2393
2742
|
}
|
|
2394
|
-
constraints.push(
|
|
2743
|
+
constraints.push(
|
|
2744
|
+
(0, import_firestore10.where)("doctorIds", "array-contains", requester.associatedPractitionerId)
|
|
2745
|
+
);
|
|
2395
2746
|
if (params.clinicId) {
|
|
2396
|
-
constraints.push((0,
|
|
2747
|
+
constraints.push((0, import_firestore10.where)("clinicIds", "array-contains", params.clinicId));
|
|
2397
2748
|
}
|
|
2398
2749
|
} else {
|
|
2399
2750
|
throw new Error("Invalid requester role.");
|
|
2400
2751
|
}
|
|
2401
2752
|
try {
|
|
2402
|
-
const finalQuery = (0,
|
|
2403
|
-
const querySnapshot = await (0,
|
|
2404
|
-
const patients = querySnapshot.docs.map(
|
|
2405
|
-
|
|
2753
|
+
const finalQuery = (0, import_firestore10.query)(patientsCollectionRef, ...constraints);
|
|
2754
|
+
const querySnapshot = await (0, import_firestore10.getDocs)(finalQuery);
|
|
2755
|
+
const patients = querySnapshot.docs.map(
|
|
2756
|
+
(doc34) => doc34.data()
|
|
2757
|
+
);
|
|
2758
|
+
console.log(
|
|
2759
|
+
`[searchPatientsUtil] Found ${patients.length} patients matching criteria.`
|
|
2760
|
+
);
|
|
2406
2761
|
return patients;
|
|
2407
2762
|
} catch (error) {
|
|
2408
2763
|
console.error("[searchPatientsUtil] Error searching patients:", error);
|
|
@@ -2411,19 +2766,24 @@ var searchPatientsUtil = async (db, params, requester) => {
|
|
|
2411
2766
|
};
|
|
2412
2767
|
var getAllPatientsUtil = async (db, options) => {
|
|
2413
2768
|
try {
|
|
2414
|
-
console.log(
|
|
2415
|
-
|
|
2416
|
-
|
|
2769
|
+
console.log(
|
|
2770
|
+
`[getAllPatientsUtil] Fetching patients with options:`,
|
|
2771
|
+
options
|
|
2772
|
+
);
|
|
2773
|
+
const patientsCollection = (0, import_firestore10.collection)(db, PATIENTS_COLLECTION);
|
|
2774
|
+
let q = (0, import_firestore10.query)(patientsCollection);
|
|
2417
2775
|
if (options == null ? void 0 : options.limit) {
|
|
2418
|
-
q = (0,
|
|
2776
|
+
q = (0, import_firestore10.query)(q, (0, import_firestore10.limit)(options.limit));
|
|
2419
2777
|
}
|
|
2420
2778
|
if (options == null ? void 0 : options.startAfter) {
|
|
2421
|
-
const startAfterDoc = await (0,
|
|
2779
|
+
const startAfterDoc = await (0, import_firestore10.getDoc)(
|
|
2780
|
+
(0, import_firestore10.doc)(db, PATIENTS_COLLECTION, options.startAfter)
|
|
2781
|
+
);
|
|
2422
2782
|
if (startAfterDoc.exists()) {
|
|
2423
|
-
q = (0,
|
|
2783
|
+
q = (0, import_firestore10.query)(q, (0, import_firestore10.startAfter)(startAfterDoc));
|
|
2424
2784
|
}
|
|
2425
2785
|
}
|
|
2426
|
-
const patientsSnapshot = await (0,
|
|
2786
|
+
const patientsSnapshot = await (0, import_firestore10.getDocs)(q);
|
|
2427
2787
|
const patients = [];
|
|
2428
2788
|
patientsSnapshot.forEach((doc34) => {
|
|
2429
2789
|
patients.push(doc34.data());
|
|
@@ -2439,8 +2799,8 @@ var getAllPatientsUtil = async (db, options) => {
|
|
|
2439
2799
|
};
|
|
2440
2800
|
|
|
2441
2801
|
// src/services/patient/utils/location.utils.ts
|
|
2442
|
-
var
|
|
2443
|
-
var
|
|
2802
|
+
var import_firestore11 = require("firebase/firestore");
|
|
2803
|
+
var import_zod10 = require("zod");
|
|
2444
2804
|
var import_geofire_common = require("geofire-common");
|
|
2445
2805
|
var updatePatientLocationUtil = async (db, patientId, latitude, longitude) => {
|
|
2446
2806
|
const locationData = {
|
|
@@ -2450,9 +2810,9 @@ var updatePatientLocationUtil = async (db, patientId, latitude, longitude) => {
|
|
|
2450
2810
|
};
|
|
2451
2811
|
const updateData = {
|
|
2452
2812
|
locationData,
|
|
2453
|
-
updatedAt: (0,
|
|
2813
|
+
updatedAt: (0, import_firestore11.serverTimestamp)()
|
|
2454
2814
|
};
|
|
2455
|
-
await (0,
|
|
2815
|
+
await (0, import_firestore11.updateDoc)(getLocationInfoDocRef(db, patientId), updateData);
|
|
2456
2816
|
};
|
|
2457
2817
|
var createLocationInfoUtil = async (db, data, requesterId) => {
|
|
2458
2818
|
try {
|
|
@@ -2469,17 +2829,17 @@ var createLocationInfoUtil = async (db, data, requesterId) => {
|
|
|
2469
2829
|
validatedData.locationData.longitude
|
|
2470
2830
|
])
|
|
2471
2831
|
},
|
|
2472
|
-
createdAt: (0,
|
|
2473
|
-
updatedAt: (0,
|
|
2832
|
+
createdAt: (0, import_firestore11.serverTimestamp)(),
|
|
2833
|
+
updatedAt: (0, import_firestore11.serverTimestamp)()
|
|
2474
2834
|
};
|
|
2475
|
-
await (0,
|
|
2476
|
-
const locationDoc = await (0,
|
|
2835
|
+
await (0, import_firestore11.setDoc)(getLocationInfoDocRef(db, data.patientId), locationData);
|
|
2836
|
+
const locationDoc = await (0, import_firestore11.getDoc)(getLocationInfoDocRef(db, data.patientId));
|
|
2477
2837
|
if (!locationDoc.exists()) {
|
|
2478
2838
|
throw new Error("Failed to create location information");
|
|
2479
2839
|
}
|
|
2480
2840
|
return locationDoc.data();
|
|
2481
2841
|
} catch (error) {
|
|
2482
|
-
if (error instanceof
|
|
2842
|
+
if (error instanceof import_zod10.z.ZodError) {
|
|
2483
2843
|
throw new Error("Invalid location data: " + error.message);
|
|
2484
2844
|
}
|
|
2485
2845
|
throw error;
|
|
@@ -2489,7 +2849,7 @@ var getLocationInfoUtil = async (db, patientId, requesterId) => {
|
|
|
2489
2849
|
if (patientId !== requesterId) {
|
|
2490
2850
|
throw new Error("Unauthorized access to location information");
|
|
2491
2851
|
}
|
|
2492
|
-
const locationDoc = await (0,
|
|
2852
|
+
const locationDoc = await (0, import_firestore11.getDoc)(getLocationInfoDocRef(db, patientId));
|
|
2493
2853
|
return locationDoc.exists() ? locationDoc.data() : null;
|
|
2494
2854
|
};
|
|
2495
2855
|
var updateLocationInfoUtil = async (db, patientId, data, requesterId) => {
|
|
@@ -2506,8 +2866,8 @@ var updateLocationInfoUtil = async (db, patientId, data, requesterId) => {
|
|
|
2506
2866
|
])
|
|
2507
2867
|
};
|
|
2508
2868
|
}
|
|
2509
|
-
updateData.updatedAt = (0,
|
|
2510
|
-
await (0,
|
|
2869
|
+
updateData.updatedAt = (0, import_firestore11.serverTimestamp)();
|
|
2870
|
+
await (0, import_firestore11.updateDoc)(getLocationInfoDocRef(db, patientId), updateData);
|
|
2511
2871
|
const updatedInfo = await getLocationInfoUtil(db, patientId, requesterId);
|
|
2512
2872
|
if (!updatedInfo) {
|
|
2513
2873
|
throw new Error("Failed to retrieve updated location information");
|
|
@@ -2516,127 +2876,127 @@ var updateLocationInfoUtil = async (db, patientId, data, requesterId) => {
|
|
|
2516
2876
|
};
|
|
2517
2877
|
|
|
2518
2878
|
// src/services/patient/utils/medical-stuff.utils.ts
|
|
2519
|
-
var
|
|
2879
|
+
var import_firestore12 = require("firebase/firestore");
|
|
2520
2880
|
var addDoctorUtil = async (db, patientId, doctorRef, assignedBy) => {
|
|
2521
2881
|
var _a;
|
|
2522
2882
|
const newDoctor = {
|
|
2523
2883
|
userRef: doctorRef,
|
|
2524
|
-
assignedAt:
|
|
2884
|
+
assignedAt: import_firestore12.Timestamp.now(),
|
|
2525
2885
|
assignedBy,
|
|
2526
2886
|
isActive: true
|
|
2527
2887
|
};
|
|
2528
|
-
const patientDoc = await (0,
|
|
2888
|
+
const patientDoc = await (0, import_firestore12.getDoc)(getPatientDocRef(db, patientId));
|
|
2529
2889
|
if (!patientDoc.exists()) throw new Error("Patient profile not found");
|
|
2530
2890
|
const patientData = patientDoc.data();
|
|
2531
2891
|
const existingDoctorIndex = (_a = patientData.doctors) == null ? void 0 : _a.findIndex(
|
|
2532
2892
|
(d) => d.userRef === doctorRef
|
|
2533
2893
|
);
|
|
2534
2894
|
const updates = {
|
|
2535
|
-
updatedAt: (0,
|
|
2536
|
-
doctorIds: (0,
|
|
2895
|
+
updatedAt: (0, import_firestore12.serverTimestamp)(),
|
|
2896
|
+
doctorIds: (0, import_firestore12.arrayUnion)(doctorRef)
|
|
2537
2897
|
};
|
|
2538
2898
|
if (existingDoctorIndex !== void 0 && existingDoctorIndex > -1) {
|
|
2539
2899
|
const updatedDoctors = [...patientData.doctors];
|
|
2540
2900
|
updatedDoctors[existingDoctorIndex] = {
|
|
2541
2901
|
...updatedDoctors[existingDoctorIndex],
|
|
2542
2902
|
isActive: true,
|
|
2543
|
-
assignedAt:
|
|
2903
|
+
assignedAt: import_firestore12.Timestamp.now(),
|
|
2544
2904
|
assignedBy
|
|
2545
2905
|
};
|
|
2546
2906
|
updates.doctors = updatedDoctors;
|
|
2547
2907
|
} else {
|
|
2548
|
-
updates.doctors = (0,
|
|
2908
|
+
updates.doctors = (0, import_firestore12.arrayUnion)(newDoctor);
|
|
2549
2909
|
}
|
|
2550
|
-
await (0,
|
|
2910
|
+
await (0, import_firestore12.updateDoc)(getPatientDocRef(db, patientId), updates);
|
|
2551
2911
|
};
|
|
2552
2912
|
var removeDoctorUtil = async (db, patientId, doctorRef) => {
|
|
2553
2913
|
var _a;
|
|
2554
2914
|
const patientDocRef = getPatientDocRef(db, patientId);
|
|
2555
|
-
const patientDoc = await (0,
|
|
2915
|
+
const patientDoc = await (0, import_firestore12.getDoc)(patientDocRef);
|
|
2556
2916
|
if (!patientDoc.exists()) throw new Error("Patient profile not found");
|
|
2557
2917
|
const patientData = patientDoc.data();
|
|
2558
2918
|
const updatedDoctors = ((_a = patientData.doctors) == null ? void 0 : _a.filter((doctor) => doctor.userRef !== doctorRef)) || [];
|
|
2559
|
-
await (0,
|
|
2919
|
+
await (0, import_firestore12.updateDoc)(patientDocRef, {
|
|
2560
2920
|
doctors: updatedDoctors,
|
|
2561
2921
|
// Set the filtered array
|
|
2562
|
-
doctorIds: (0,
|
|
2922
|
+
doctorIds: (0, import_firestore12.arrayRemove)(doctorRef),
|
|
2563
2923
|
// Remove ID from the denormalized list
|
|
2564
|
-
updatedAt: (0,
|
|
2924
|
+
updatedAt: (0, import_firestore12.serverTimestamp)()
|
|
2565
2925
|
});
|
|
2566
2926
|
};
|
|
2567
2927
|
var addClinicUtil = async (db, patientId, clinicId, assignedBy) => {
|
|
2568
2928
|
var _a;
|
|
2569
2929
|
const newClinic = {
|
|
2570
2930
|
clinicId,
|
|
2571
|
-
assignedAt:
|
|
2931
|
+
assignedAt: import_firestore12.Timestamp.now(),
|
|
2572
2932
|
assignedBy,
|
|
2573
2933
|
isActive: true
|
|
2574
2934
|
};
|
|
2575
|
-
const patientDoc = await (0,
|
|
2935
|
+
const patientDoc = await (0, import_firestore12.getDoc)(getPatientDocRef(db, patientId));
|
|
2576
2936
|
if (!patientDoc.exists()) throw new Error("Patient profile not found");
|
|
2577
2937
|
const patientData = patientDoc.data();
|
|
2578
2938
|
const existingClinicIndex = (_a = patientData.clinics) == null ? void 0 : _a.findIndex(
|
|
2579
2939
|
(c) => c.clinicId === clinicId
|
|
2580
2940
|
);
|
|
2581
2941
|
const updates = {
|
|
2582
|
-
updatedAt: (0,
|
|
2583
|
-
clinicIds: (0,
|
|
2942
|
+
updatedAt: (0, import_firestore12.serverTimestamp)(),
|
|
2943
|
+
clinicIds: (0, import_firestore12.arrayUnion)(clinicId)
|
|
2584
2944
|
};
|
|
2585
2945
|
if (existingClinicIndex !== void 0 && existingClinicIndex > -1) {
|
|
2586
2946
|
const updatedClinics = [...patientData.clinics];
|
|
2587
2947
|
updatedClinics[existingClinicIndex] = {
|
|
2588
2948
|
...updatedClinics[existingClinicIndex],
|
|
2589
2949
|
isActive: true,
|
|
2590
|
-
assignedAt:
|
|
2950
|
+
assignedAt: import_firestore12.Timestamp.now(),
|
|
2591
2951
|
assignedBy
|
|
2592
2952
|
};
|
|
2593
2953
|
updates.clinics = updatedClinics;
|
|
2594
2954
|
} else {
|
|
2595
|
-
updates.clinics = (0,
|
|
2955
|
+
updates.clinics = (0, import_firestore12.arrayUnion)(newClinic);
|
|
2596
2956
|
}
|
|
2597
|
-
await (0,
|
|
2957
|
+
await (0, import_firestore12.updateDoc)(getPatientDocRef(db, patientId), updates);
|
|
2598
2958
|
};
|
|
2599
2959
|
var removeClinicUtil = async (db, patientId, clinicId) => {
|
|
2600
2960
|
var _a;
|
|
2601
2961
|
const patientDocRef = getPatientDocRef(db, patientId);
|
|
2602
|
-
const patientDoc = await (0,
|
|
2962
|
+
const patientDoc = await (0, import_firestore12.getDoc)(patientDocRef);
|
|
2603
2963
|
if (!patientDoc.exists()) throw new Error("Patient profile not found");
|
|
2604
2964
|
const patientData = patientDoc.data();
|
|
2605
2965
|
const updatedClinics = ((_a = patientData.clinics) == null ? void 0 : _a.filter((clinic) => clinic.clinicId !== clinicId)) || [];
|
|
2606
|
-
await (0,
|
|
2966
|
+
await (0, import_firestore12.updateDoc)(patientDocRef, {
|
|
2607
2967
|
clinics: updatedClinics,
|
|
2608
2968
|
// Set the filtered array
|
|
2609
|
-
clinicIds: (0,
|
|
2969
|
+
clinicIds: (0, import_firestore12.arrayRemove)(clinicId),
|
|
2610
2970
|
// Remove ID from the denormalized list
|
|
2611
|
-
updatedAt: (0,
|
|
2971
|
+
updatedAt: (0, import_firestore12.serverTimestamp)()
|
|
2612
2972
|
});
|
|
2613
2973
|
};
|
|
2614
2974
|
|
|
2615
2975
|
// src/services/patient/utils/clinic.utils.ts
|
|
2616
|
-
var
|
|
2976
|
+
var import_firestore13 = require("firebase/firestore");
|
|
2617
2977
|
var getPatientsByClinicUtil = async (db, clinicId, options) => {
|
|
2618
2978
|
try {
|
|
2619
2979
|
console.log(
|
|
2620
2980
|
`[getPatientsByClinicUtil] Fetching patients for clinic ID: ${clinicId} with options:`,
|
|
2621
2981
|
options
|
|
2622
2982
|
);
|
|
2623
|
-
const patientsCollection = (0,
|
|
2983
|
+
const patientsCollection = (0, import_firestore13.collection)(db, PATIENTS_COLLECTION);
|
|
2624
2984
|
const constraints = [
|
|
2625
|
-
(0,
|
|
2985
|
+
(0, import_firestore13.where)("clinicIds", "array-contains", clinicId)
|
|
2626
2986
|
];
|
|
2627
|
-
let q = (0,
|
|
2987
|
+
let q = (0, import_firestore13.query)(patientsCollection, ...constraints);
|
|
2628
2988
|
if (options == null ? void 0 : options.limit) {
|
|
2629
|
-
q = (0,
|
|
2989
|
+
q = (0, import_firestore13.query)(q, (0, import_firestore13.limit)(options.limit));
|
|
2630
2990
|
}
|
|
2631
2991
|
if (options == null ? void 0 : options.startAfter) {
|
|
2632
|
-
const startAfterDoc = await (0,
|
|
2633
|
-
(0,
|
|
2992
|
+
const startAfterDoc = await (0, import_firestore13.getDoc)(
|
|
2993
|
+
(0, import_firestore13.doc)(db, PATIENTS_COLLECTION, options.startAfter)
|
|
2634
2994
|
);
|
|
2635
2995
|
if (startAfterDoc.exists()) {
|
|
2636
|
-
q = (0,
|
|
2996
|
+
q = (0, import_firestore13.query)(q, (0, import_firestore13.startAfter)(startAfterDoc));
|
|
2637
2997
|
}
|
|
2638
2998
|
}
|
|
2639
|
-
const patientsSnapshot = await (0,
|
|
2999
|
+
const patientsSnapshot = await (0, import_firestore13.getDocs)(q);
|
|
2640
3000
|
const patients = [];
|
|
2641
3001
|
patientsSnapshot.forEach((doc34) => {
|
|
2642
3002
|
patients.push(doc34.data());
|
|
@@ -2660,6 +3020,7 @@ var getPatientsByClinicUtil = async (db, clinicId, options) => {
|
|
|
2660
3020
|
var PatientService = class extends BaseService {
|
|
2661
3021
|
constructor(db, auth, app) {
|
|
2662
3022
|
super(db, auth, app);
|
|
3023
|
+
this.mediaService = new MediaService(db, auth, app);
|
|
2663
3024
|
}
|
|
2664
3025
|
// Metode za rad sa profilom pacijenta
|
|
2665
3026
|
async createPatientProfile(data) {
|
|
@@ -2696,7 +3057,12 @@ var PatientService = class extends BaseService {
|
|
|
2696
3057
|
}
|
|
2697
3058
|
// Metode za rad sa osetljivim informacijama
|
|
2698
3059
|
async createSensitiveInfo(data, requesterUserId) {
|
|
2699
|
-
return createSensitiveInfoUtil(
|
|
3060
|
+
return createSensitiveInfoUtil(
|
|
3061
|
+
this.db,
|
|
3062
|
+
data,
|
|
3063
|
+
requesterUserId,
|
|
3064
|
+
this.mediaService
|
|
3065
|
+
);
|
|
2700
3066
|
}
|
|
2701
3067
|
async getSensitiveInfo(patientId, requesterUserId) {
|
|
2702
3068
|
return getSensitiveInfoUtil(this.db, patientId, requesterUserId);
|
|
@@ -2707,7 +3073,13 @@ var PatientService = class extends BaseService {
|
|
|
2707
3073
|
return this.getSensitiveInfo(profile.id, requesterUserId);
|
|
2708
3074
|
}
|
|
2709
3075
|
async updateSensitiveInfo(patientId, data, requesterUserId) {
|
|
2710
|
-
return updateSensitiveInfoUtil(
|
|
3076
|
+
return updateSensitiveInfoUtil(
|
|
3077
|
+
this.db,
|
|
3078
|
+
patientId,
|
|
3079
|
+
data,
|
|
3080
|
+
requesterUserId,
|
|
3081
|
+
this.mediaService
|
|
3082
|
+
);
|
|
2711
3083
|
}
|
|
2712
3084
|
// Metode za rad sa medicinskim informacijama
|
|
2713
3085
|
async createMedicalInfo(patientId, data) {
|
|
@@ -2840,8 +3212,8 @@ var PatientService = class extends BaseService {
|
|
|
2840
3212
|
if (!this.auth.currentUser) {
|
|
2841
3213
|
throw new Error("No authenticated user");
|
|
2842
3214
|
}
|
|
2843
|
-
const userDoc = await (0,
|
|
2844
|
-
(0,
|
|
3215
|
+
const userDoc = await (0, import_firestore14.getDoc)(
|
|
3216
|
+
(0, import_firestore14.doc)(this.db, "users", this.auth.currentUser.uid)
|
|
2845
3217
|
);
|
|
2846
3218
|
if (!userDoc.exists()) {
|
|
2847
3219
|
throw new Error("User not found");
|
|
@@ -2852,7 +3224,7 @@ var PatientService = class extends BaseService {
|
|
|
2852
3224
|
* Briše profil pacijenta i sve povezane subkolekcije
|
|
2853
3225
|
*/
|
|
2854
3226
|
async deletePatientProfile(patientId) {
|
|
2855
|
-
const batch = (0,
|
|
3227
|
+
const batch = (0, import_firestore14.writeBatch)(this.db);
|
|
2856
3228
|
batch.delete(getSensitiveInfoDocRef(this.db, patientId));
|
|
2857
3229
|
batch.delete(getLocationInfoDocRef(this.db, patientId));
|
|
2858
3230
|
batch.delete(getMedicalInfoDocRef(this.db, patientId));
|
|
@@ -2876,14 +3248,113 @@ var PatientService = class extends BaseService {
|
|
|
2876
3248
|
await removeClinicUtil(this.db, patientId, clinicId);
|
|
2877
3249
|
}
|
|
2878
3250
|
// Metode za rad sa profilnom slikom
|
|
3251
|
+
/**
|
|
3252
|
+
* Uploads a profile photo for a patient
|
|
3253
|
+
* @param patientId - ID of the patient
|
|
3254
|
+
* @param file - File or Blob to upload
|
|
3255
|
+
* @returns URL of the uploaded photo
|
|
3256
|
+
*/
|
|
2879
3257
|
async uploadProfilePhoto(patientId, file) {
|
|
2880
|
-
|
|
3258
|
+
console.log(
|
|
3259
|
+
`[PatientService] Uploading profile photo for patient ${patientId}`
|
|
3260
|
+
);
|
|
3261
|
+
const mediaMetadata = await this.mediaService.uploadMedia(
|
|
3262
|
+
file,
|
|
3263
|
+
patientId,
|
|
3264
|
+
// Using patientId as ownerId
|
|
3265
|
+
"private" /* PRIVATE */,
|
|
3266
|
+
// Profile photos should be private
|
|
3267
|
+
"patient_profile_photos",
|
|
3268
|
+
file instanceof File ? file.name : `profile_photo_${patientId}`
|
|
3269
|
+
);
|
|
3270
|
+
await (0, import_firestore14.updateDoc)(getSensitiveInfoDocRef(this.db, patientId), {
|
|
3271
|
+
photoUrl: mediaMetadata.url,
|
|
3272
|
+
updatedAt: (0, import_firestore14.serverTimestamp)()
|
|
3273
|
+
});
|
|
3274
|
+
return mediaMetadata.url;
|
|
2881
3275
|
}
|
|
3276
|
+
/**
|
|
3277
|
+
* Updates a patient's profile photo (replaces existing one)
|
|
3278
|
+
* @param patientId - ID of the patient
|
|
3279
|
+
* @param file - New file or Blob to upload
|
|
3280
|
+
* @returns URL of the new uploaded photo
|
|
3281
|
+
*/
|
|
2882
3282
|
async updateProfilePhoto(patientId, file) {
|
|
2883
|
-
|
|
3283
|
+
console.log(
|
|
3284
|
+
`[PatientService] Updating profile photo for patient ${patientId}`
|
|
3285
|
+
);
|
|
3286
|
+
const currentUser = await this.getCurrentUser();
|
|
3287
|
+
const currentSensitiveInfo = await this.getSensitiveInfo(
|
|
3288
|
+
patientId,
|
|
3289
|
+
currentUser.uid
|
|
3290
|
+
);
|
|
3291
|
+
if ((currentSensitiveInfo == null ? void 0 : currentSensitiveInfo.photoUrl) && typeof currentSensitiveInfo.photoUrl === "string") {
|
|
3292
|
+
try {
|
|
3293
|
+
const existingMediaMetadata = await this.mediaService.getMediaMetadataByUrl(
|
|
3294
|
+
currentSensitiveInfo.photoUrl
|
|
3295
|
+
);
|
|
3296
|
+
if (existingMediaMetadata) {
|
|
3297
|
+
await this.mediaService.deleteMedia(existingMediaMetadata.id);
|
|
3298
|
+
}
|
|
3299
|
+
} catch (error) {
|
|
3300
|
+
console.warn(
|
|
3301
|
+
`[PatientService] Could not delete old profile photo for patient ${patientId}:`,
|
|
3302
|
+
error
|
|
3303
|
+
);
|
|
3304
|
+
}
|
|
3305
|
+
}
|
|
3306
|
+
return this.uploadProfilePhoto(patientId, file);
|
|
2884
3307
|
}
|
|
3308
|
+
/**
|
|
3309
|
+
* Deletes a patient's profile photo
|
|
3310
|
+
* @param patientId - ID of the patient
|
|
3311
|
+
*/
|
|
2885
3312
|
async deleteProfilePhoto(patientId) {
|
|
2886
|
-
|
|
3313
|
+
console.log(
|
|
3314
|
+
`[PatientService] Deleting profile photo for patient ${patientId}`
|
|
3315
|
+
);
|
|
3316
|
+
const currentUser = await this.getCurrentUser();
|
|
3317
|
+
const currentSensitiveInfo = await this.getSensitiveInfo(
|
|
3318
|
+
patientId,
|
|
3319
|
+
currentUser.uid
|
|
3320
|
+
);
|
|
3321
|
+
if ((currentSensitiveInfo == null ? void 0 : currentSensitiveInfo.photoUrl) && typeof currentSensitiveInfo.photoUrl === "string") {
|
|
3322
|
+
try {
|
|
3323
|
+
const existingMediaMetadata = await this.mediaService.getMediaMetadataByUrl(
|
|
3324
|
+
currentSensitiveInfo.photoUrl
|
|
3325
|
+
);
|
|
3326
|
+
if (existingMediaMetadata) {
|
|
3327
|
+
await this.mediaService.deleteMedia(existingMediaMetadata.id);
|
|
3328
|
+
}
|
|
3329
|
+
} catch (error) {
|
|
3330
|
+
console.warn(
|
|
3331
|
+
`[PatientService] Could not delete profile photo for patient ${patientId}:`,
|
|
3332
|
+
error
|
|
3333
|
+
);
|
|
3334
|
+
}
|
|
3335
|
+
await (0, import_firestore14.updateDoc)(getSensitiveInfoDocRef(this.db, patientId), {
|
|
3336
|
+
photoUrl: null,
|
|
3337
|
+
updatedAt: (0, import_firestore14.serverTimestamp)()
|
|
3338
|
+
});
|
|
3339
|
+
}
|
|
3340
|
+
}
|
|
3341
|
+
/**
|
|
3342
|
+
* Handles profile photo upload for patients (supports MediaResource)
|
|
3343
|
+
* @param photoUrl - MediaResource (File, Blob, or URL string) from CreatePatientSensitiveInfoData
|
|
3344
|
+
* @param patientId - ID of the patient
|
|
3345
|
+
* @returns URL string of the uploaded or existing photo
|
|
3346
|
+
*/
|
|
3347
|
+
async handleProfilePhotoUpload(photoUrl, patientId) {
|
|
3348
|
+
if (!photoUrl) {
|
|
3349
|
+
return void 0;
|
|
3350
|
+
}
|
|
3351
|
+
if (typeof photoUrl === "string") {
|
|
3352
|
+
return photoUrl;
|
|
3353
|
+
}
|
|
3354
|
+
if (photoUrl instanceof File || photoUrl instanceof Blob) {
|
|
3355
|
+
return this.uploadProfilePhoto(patientId, photoUrl);
|
|
3356
|
+
}
|
|
3357
|
+
return void 0;
|
|
2887
3358
|
}
|
|
2888
3359
|
// Metode za ažuriranje profila
|
|
2889
3360
|
async updatePatientProfile(patientId, data) {
|
|
@@ -2976,7 +3447,7 @@ var PatientService = class extends BaseService {
|
|
|
2976
3447
|
};
|
|
2977
3448
|
|
|
2978
3449
|
// src/services/clinic/utils/admin.utils.ts
|
|
2979
|
-
var
|
|
3450
|
+
var import_firestore16 = require("firebase/firestore");
|
|
2980
3451
|
|
|
2981
3452
|
// src/types/clinic/preferences.types.ts
|
|
2982
3453
|
var PracticeType = /* @__PURE__ */ ((PracticeType2) => {
|
|
@@ -3103,131 +3574,131 @@ var SubscriptionModel = /* @__PURE__ */ ((SubscriptionModel2) => {
|
|
|
3103
3574
|
|
|
3104
3575
|
// src/validations/clinic.schema.ts
|
|
3105
3576
|
var import_zod13 = require("zod");
|
|
3106
|
-
var
|
|
3577
|
+
var import_firestore15 = require("firebase/firestore");
|
|
3107
3578
|
|
|
3108
3579
|
// src/validations/reviews.schema.ts
|
|
3109
|
-
var
|
|
3110
|
-
var baseReviewSchema =
|
|
3111
|
-
id:
|
|
3112
|
-
patientId:
|
|
3113
|
-
fullReviewId:
|
|
3114
|
-
createdAt:
|
|
3115
|
-
updatedAt:
|
|
3116
|
-
comment:
|
|
3117
|
-
isVerified:
|
|
3118
|
-
isPublished:
|
|
3580
|
+
var import_zod11 = require("zod");
|
|
3581
|
+
var baseReviewSchema = import_zod11.z.object({
|
|
3582
|
+
id: import_zod11.z.string().min(1),
|
|
3583
|
+
patientId: import_zod11.z.string().min(1),
|
|
3584
|
+
fullReviewId: import_zod11.z.string().min(1),
|
|
3585
|
+
createdAt: import_zod11.z.date(),
|
|
3586
|
+
updatedAt: import_zod11.z.date(),
|
|
3587
|
+
comment: import_zod11.z.string().min(1).max(2e3),
|
|
3588
|
+
isVerified: import_zod11.z.boolean(),
|
|
3589
|
+
isPublished: import_zod11.z.boolean()
|
|
3119
3590
|
});
|
|
3120
|
-
var baseReviewCreateSchema =
|
|
3121
|
-
patientId:
|
|
3122
|
-
comment:
|
|
3123
|
-
isVerified:
|
|
3124
|
-
isPublished:
|
|
3591
|
+
var baseReviewCreateSchema = import_zod11.z.object({
|
|
3592
|
+
patientId: import_zod11.z.string().min(1),
|
|
3593
|
+
comment: import_zod11.z.string().min(1).max(2e3),
|
|
3594
|
+
isVerified: import_zod11.z.boolean().default(false),
|
|
3595
|
+
isPublished: import_zod11.z.boolean().default(true)
|
|
3125
3596
|
});
|
|
3126
3597
|
var clinicReviewSchema = baseReviewSchema.extend({
|
|
3127
|
-
clinicId:
|
|
3128
|
-
cleanliness:
|
|
3129
|
-
facilities:
|
|
3130
|
-
staffFriendliness:
|
|
3131
|
-
waitingTime:
|
|
3132
|
-
accessibility:
|
|
3133
|
-
overallRating:
|
|
3134
|
-
wouldRecommend:
|
|
3598
|
+
clinicId: import_zod11.z.string().min(1),
|
|
3599
|
+
cleanliness: import_zod11.z.number().min(1).max(5),
|
|
3600
|
+
facilities: import_zod11.z.number().min(1).max(5),
|
|
3601
|
+
staffFriendliness: import_zod11.z.number().min(1).max(5),
|
|
3602
|
+
waitingTime: import_zod11.z.number().min(1).max(5),
|
|
3603
|
+
accessibility: import_zod11.z.number().min(1).max(5),
|
|
3604
|
+
overallRating: import_zod11.z.number().min(1).max(5),
|
|
3605
|
+
wouldRecommend: import_zod11.z.boolean()
|
|
3135
3606
|
});
|
|
3136
3607
|
var createClinicReviewSchema = baseReviewCreateSchema.extend({
|
|
3137
|
-
clinicId:
|
|
3138
|
-
cleanliness:
|
|
3139
|
-
facilities:
|
|
3140
|
-
staffFriendliness:
|
|
3141
|
-
waitingTime:
|
|
3142
|
-
accessibility:
|
|
3143
|
-
wouldRecommend:
|
|
3608
|
+
clinicId: import_zod11.z.string().min(1),
|
|
3609
|
+
cleanliness: import_zod11.z.number().min(1).max(5),
|
|
3610
|
+
facilities: import_zod11.z.number().min(1).max(5),
|
|
3611
|
+
staffFriendliness: import_zod11.z.number().min(1).max(5),
|
|
3612
|
+
waitingTime: import_zod11.z.number().min(1).max(5),
|
|
3613
|
+
accessibility: import_zod11.z.number().min(1).max(5),
|
|
3614
|
+
wouldRecommend: import_zod11.z.boolean()
|
|
3144
3615
|
});
|
|
3145
3616
|
var practitionerReviewSchema = baseReviewSchema.extend({
|
|
3146
|
-
practitionerId:
|
|
3147
|
-
knowledgeAndExpertise:
|
|
3148
|
-
communicationSkills:
|
|
3149
|
-
bedSideManner:
|
|
3150
|
-
thoroughness:
|
|
3151
|
-
trustworthiness:
|
|
3152
|
-
overallRating:
|
|
3153
|
-
wouldRecommend:
|
|
3617
|
+
practitionerId: import_zod11.z.string().min(1),
|
|
3618
|
+
knowledgeAndExpertise: import_zod11.z.number().min(1).max(5),
|
|
3619
|
+
communicationSkills: import_zod11.z.number().min(1).max(5),
|
|
3620
|
+
bedSideManner: import_zod11.z.number().min(1).max(5),
|
|
3621
|
+
thoroughness: import_zod11.z.number().min(1).max(5),
|
|
3622
|
+
trustworthiness: import_zod11.z.number().min(1).max(5),
|
|
3623
|
+
overallRating: import_zod11.z.number().min(1).max(5),
|
|
3624
|
+
wouldRecommend: import_zod11.z.boolean()
|
|
3154
3625
|
});
|
|
3155
3626
|
var createPractitionerReviewSchema = baseReviewCreateSchema.extend({
|
|
3156
|
-
practitionerId:
|
|
3157
|
-
knowledgeAndExpertise:
|
|
3158
|
-
communicationSkills:
|
|
3159
|
-
bedSideManner:
|
|
3160
|
-
thoroughness:
|
|
3161
|
-
trustworthiness:
|
|
3162
|
-
wouldRecommend:
|
|
3627
|
+
practitionerId: import_zod11.z.string().min(1),
|
|
3628
|
+
knowledgeAndExpertise: import_zod11.z.number().min(1).max(5),
|
|
3629
|
+
communicationSkills: import_zod11.z.number().min(1).max(5),
|
|
3630
|
+
bedSideManner: import_zod11.z.number().min(1).max(5),
|
|
3631
|
+
thoroughness: import_zod11.z.number().min(1).max(5),
|
|
3632
|
+
trustworthiness: import_zod11.z.number().min(1).max(5),
|
|
3633
|
+
wouldRecommend: import_zod11.z.boolean()
|
|
3163
3634
|
});
|
|
3164
3635
|
var procedureReviewSchema = baseReviewSchema.extend({
|
|
3165
|
-
procedureId:
|
|
3166
|
-
effectivenessOfTreatment:
|
|
3167
|
-
outcomeExplanation:
|
|
3168
|
-
painManagement:
|
|
3169
|
-
followUpCare:
|
|
3170
|
-
valueForMoney:
|
|
3171
|
-
overallRating:
|
|
3172
|
-
wouldRecommend:
|
|
3636
|
+
procedureId: import_zod11.z.string().min(1),
|
|
3637
|
+
effectivenessOfTreatment: import_zod11.z.number().min(1).max(5),
|
|
3638
|
+
outcomeExplanation: import_zod11.z.number().min(1).max(5),
|
|
3639
|
+
painManagement: import_zod11.z.number().min(1).max(5),
|
|
3640
|
+
followUpCare: import_zod11.z.number().min(1).max(5),
|
|
3641
|
+
valueForMoney: import_zod11.z.number().min(1).max(5),
|
|
3642
|
+
overallRating: import_zod11.z.number().min(1).max(5),
|
|
3643
|
+
wouldRecommend: import_zod11.z.boolean()
|
|
3173
3644
|
});
|
|
3174
3645
|
var createProcedureReviewSchema = baseReviewCreateSchema.extend({
|
|
3175
|
-
procedureId:
|
|
3176
|
-
effectivenessOfTreatment:
|
|
3177
|
-
outcomeExplanation:
|
|
3178
|
-
painManagement:
|
|
3179
|
-
followUpCare:
|
|
3180
|
-
valueForMoney:
|
|
3181
|
-
wouldRecommend:
|
|
3646
|
+
procedureId: import_zod11.z.string().min(1),
|
|
3647
|
+
effectivenessOfTreatment: import_zod11.z.number().min(1).max(5),
|
|
3648
|
+
outcomeExplanation: import_zod11.z.number().min(1).max(5),
|
|
3649
|
+
painManagement: import_zod11.z.number().min(1).max(5),
|
|
3650
|
+
followUpCare: import_zod11.z.number().min(1).max(5),
|
|
3651
|
+
valueForMoney: import_zod11.z.number().min(1).max(5),
|
|
3652
|
+
wouldRecommend: import_zod11.z.boolean()
|
|
3182
3653
|
});
|
|
3183
|
-
var clinicReviewInfoSchema =
|
|
3184
|
-
totalReviews:
|
|
3185
|
-
averageRating:
|
|
3186
|
-
cleanliness:
|
|
3187
|
-
facilities:
|
|
3188
|
-
staffFriendliness:
|
|
3189
|
-
waitingTime:
|
|
3190
|
-
accessibility:
|
|
3191
|
-
recommendationPercentage:
|
|
3654
|
+
var clinicReviewInfoSchema = import_zod11.z.object({
|
|
3655
|
+
totalReviews: import_zod11.z.number().min(0),
|
|
3656
|
+
averageRating: import_zod11.z.number().min(0).max(5),
|
|
3657
|
+
cleanliness: import_zod11.z.number().min(0).max(5),
|
|
3658
|
+
facilities: import_zod11.z.number().min(0).max(5),
|
|
3659
|
+
staffFriendliness: import_zod11.z.number().min(0).max(5),
|
|
3660
|
+
waitingTime: import_zod11.z.number().min(0).max(5),
|
|
3661
|
+
accessibility: import_zod11.z.number().min(0).max(5),
|
|
3662
|
+
recommendationPercentage: import_zod11.z.number().min(0).max(100)
|
|
3192
3663
|
});
|
|
3193
|
-
var practitionerReviewInfoSchema =
|
|
3194
|
-
totalReviews:
|
|
3195
|
-
averageRating:
|
|
3196
|
-
knowledgeAndExpertise:
|
|
3197
|
-
communicationSkills:
|
|
3198
|
-
bedSideManner:
|
|
3199
|
-
thoroughness:
|
|
3200
|
-
trustworthiness:
|
|
3201
|
-
recommendationPercentage:
|
|
3664
|
+
var practitionerReviewInfoSchema = import_zod11.z.object({
|
|
3665
|
+
totalReviews: import_zod11.z.number().min(0),
|
|
3666
|
+
averageRating: import_zod11.z.number().min(0).max(5),
|
|
3667
|
+
knowledgeAndExpertise: import_zod11.z.number().min(0).max(5),
|
|
3668
|
+
communicationSkills: import_zod11.z.number().min(0).max(5),
|
|
3669
|
+
bedSideManner: import_zod11.z.number().min(0).max(5),
|
|
3670
|
+
thoroughness: import_zod11.z.number().min(0).max(5),
|
|
3671
|
+
trustworthiness: import_zod11.z.number().min(0).max(5),
|
|
3672
|
+
recommendationPercentage: import_zod11.z.number().min(0).max(100)
|
|
3202
3673
|
});
|
|
3203
|
-
var procedureReviewInfoSchema =
|
|
3204
|
-
totalReviews:
|
|
3205
|
-
averageRating:
|
|
3206
|
-
effectivenessOfTreatment:
|
|
3207
|
-
outcomeExplanation:
|
|
3208
|
-
painManagement:
|
|
3209
|
-
followUpCare:
|
|
3210
|
-
valueForMoney:
|
|
3211
|
-
recommendationPercentage:
|
|
3674
|
+
var procedureReviewInfoSchema = import_zod11.z.object({
|
|
3675
|
+
totalReviews: import_zod11.z.number().min(0),
|
|
3676
|
+
averageRating: import_zod11.z.number().min(0).max(5),
|
|
3677
|
+
effectivenessOfTreatment: import_zod11.z.number().min(0).max(5),
|
|
3678
|
+
outcomeExplanation: import_zod11.z.number().min(0).max(5),
|
|
3679
|
+
painManagement: import_zod11.z.number().min(0).max(5),
|
|
3680
|
+
followUpCare: import_zod11.z.number().min(0).max(5),
|
|
3681
|
+
valueForMoney: import_zod11.z.number().min(0).max(5),
|
|
3682
|
+
recommendationPercentage: import_zod11.z.number().min(0).max(100)
|
|
3212
3683
|
});
|
|
3213
|
-
var reviewSchema =
|
|
3214
|
-
id:
|
|
3215
|
-
appointmentId:
|
|
3216
|
-
patientId:
|
|
3217
|
-
createdAt:
|
|
3218
|
-
updatedAt:
|
|
3684
|
+
var reviewSchema = import_zod11.z.object({
|
|
3685
|
+
id: import_zod11.z.string().min(1),
|
|
3686
|
+
appointmentId: import_zod11.z.string().min(1),
|
|
3687
|
+
patientId: import_zod11.z.string().min(1),
|
|
3688
|
+
createdAt: import_zod11.z.date(),
|
|
3689
|
+
updatedAt: import_zod11.z.date(),
|
|
3219
3690
|
clinicReview: clinicReviewSchema.optional(),
|
|
3220
3691
|
practitionerReview: practitionerReviewSchema.optional(),
|
|
3221
3692
|
procedureReview: procedureReviewSchema.optional(),
|
|
3222
|
-
overallComment:
|
|
3223
|
-
overallRating:
|
|
3693
|
+
overallComment: import_zod11.z.string().min(1).max(2e3),
|
|
3694
|
+
overallRating: import_zod11.z.number().min(1).max(5)
|
|
3224
3695
|
});
|
|
3225
|
-
var createReviewSchema =
|
|
3226
|
-
patientId:
|
|
3696
|
+
var createReviewSchema = import_zod11.z.object({
|
|
3697
|
+
patientId: import_zod11.z.string().min(1),
|
|
3227
3698
|
clinicReview: createClinicReviewSchema.optional(),
|
|
3228
3699
|
practitionerReview: createPractitionerReviewSchema.optional(),
|
|
3229
3700
|
procedureReview: createProcedureReviewSchema.optional(),
|
|
3230
|
-
overallComment:
|
|
3701
|
+
overallComment: import_zod11.z.string().min(1).max(2e3)
|
|
3231
3702
|
}).refine(
|
|
3232
3703
|
(data) => {
|
|
3233
3704
|
return data.clinicReview || data.practitionerReview || data.procedureReview;
|
|
@@ -3239,7 +3710,7 @@ var createReviewSchema = import_zod10.z.object({
|
|
|
3239
3710
|
);
|
|
3240
3711
|
|
|
3241
3712
|
// src/validations/shared.schema.ts
|
|
3242
|
-
var
|
|
3713
|
+
var import_zod12 = require("zod");
|
|
3243
3714
|
|
|
3244
3715
|
// src/backoffice/types/static/procedure-family.types.ts
|
|
3245
3716
|
var ProcedureFamily = /* @__PURE__ */ ((ProcedureFamily2) => {
|
|
@@ -3268,65 +3739,57 @@ var Currency = /* @__PURE__ */ ((Currency2) => {
|
|
|
3268
3739
|
})(Currency || {});
|
|
3269
3740
|
|
|
3270
3741
|
// src/validations/shared.schema.ts
|
|
3271
|
-
var sharedClinicContactInfoSchema =
|
|
3272
|
-
email:
|
|
3273
|
-
phoneNumber:
|
|
3274
|
-
alternativePhoneNumber:
|
|
3275
|
-
website:
|
|
3742
|
+
var sharedClinicContactInfoSchema = import_zod12.z.object({
|
|
3743
|
+
email: import_zod12.z.string().email(),
|
|
3744
|
+
phoneNumber: import_zod12.z.string(),
|
|
3745
|
+
alternativePhoneNumber: import_zod12.z.string().nullable().optional(),
|
|
3746
|
+
website: import_zod12.z.string().nullable().optional()
|
|
3276
3747
|
});
|
|
3277
|
-
var sharedClinicLocationSchema =
|
|
3278
|
-
address:
|
|
3279
|
-
city:
|
|
3280
|
-
country:
|
|
3281
|
-
postalCode:
|
|
3282
|
-
latitude:
|
|
3283
|
-
longitude:
|
|
3284
|
-
geohash:
|
|
3748
|
+
var sharedClinicLocationSchema = import_zod12.z.object({
|
|
3749
|
+
address: import_zod12.z.string(),
|
|
3750
|
+
city: import_zod12.z.string(),
|
|
3751
|
+
country: import_zod12.z.string(),
|
|
3752
|
+
postalCode: import_zod12.z.string(),
|
|
3753
|
+
latitude: import_zod12.z.number().min(-90).max(90),
|
|
3754
|
+
longitude: import_zod12.z.number().min(-180).max(180),
|
|
3755
|
+
geohash: import_zod12.z.string().nullable().optional()
|
|
3285
3756
|
});
|
|
3286
|
-
var procedureSummaryInfoSchema =
|
|
3287
|
-
id:
|
|
3288
|
-
name:
|
|
3289
|
-
description:
|
|
3290
|
-
photo:
|
|
3291
|
-
family:
|
|
3292
|
-
categoryName:
|
|
3293
|
-
subcategoryName:
|
|
3294
|
-
technologyName:
|
|
3295
|
-
price:
|
|
3296
|
-
pricingMeasure:
|
|
3297
|
-
currency:
|
|
3298
|
-
duration:
|
|
3299
|
-
clinicId:
|
|
3300
|
-
clinicName:
|
|
3301
|
-
practitionerId:
|
|
3302
|
-
practitionerName:
|
|
3757
|
+
var procedureSummaryInfoSchema = import_zod12.z.object({
|
|
3758
|
+
id: import_zod12.z.string().min(1),
|
|
3759
|
+
name: import_zod12.z.string().min(1),
|
|
3760
|
+
description: import_zod12.z.string().optional(),
|
|
3761
|
+
photo: import_zod12.z.string().optional(),
|
|
3762
|
+
family: import_zod12.z.nativeEnum(ProcedureFamily),
|
|
3763
|
+
categoryName: import_zod12.z.string(),
|
|
3764
|
+
subcategoryName: import_zod12.z.string(),
|
|
3765
|
+
technologyName: import_zod12.z.string(),
|
|
3766
|
+
price: import_zod12.z.number().nonnegative(),
|
|
3767
|
+
pricingMeasure: import_zod12.z.nativeEnum(PricingMeasure),
|
|
3768
|
+
currency: import_zod12.z.nativeEnum(Currency),
|
|
3769
|
+
duration: import_zod12.z.number().int().positive(),
|
|
3770
|
+
clinicId: import_zod12.z.string().min(1),
|
|
3771
|
+
clinicName: import_zod12.z.string().min(1),
|
|
3772
|
+
practitionerId: import_zod12.z.string().min(1),
|
|
3773
|
+
practitionerName: import_zod12.z.string().min(1)
|
|
3303
3774
|
});
|
|
3304
|
-
var clinicInfoSchema =
|
|
3305
|
-
id:
|
|
3306
|
-
featuredPhoto:
|
|
3307
|
-
name:
|
|
3308
|
-
description:
|
|
3775
|
+
var clinicInfoSchema = import_zod12.z.object({
|
|
3776
|
+
id: import_zod12.z.string(),
|
|
3777
|
+
featuredPhoto: import_zod12.z.string(),
|
|
3778
|
+
name: import_zod12.z.string(),
|
|
3779
|
+
description: import_zod12.z.string().nullable().optional(),
|
|
3309
3780
|
location: sharedClinicLocationSchema,
|
|
3310
3781
|
contactInfo: sharedClinicContactInfoSchema
|
|
3311
3782
|
});
|
|
3312
|
-
var doctorInfoSchema =
|
|
3313
|
-
id:
|
|
3314
|
-
name:
|
|
3315
|
-
description:
|
|
3316
|
-
photo:
|
|
3317
|
-
rating:
|
|
3318
|
-
services:
|
|
3783
|
+
var doctorInfoSchema = import_zod12.z.object({
|
|
3784
|
+
id: import_zod12.z.string(),
|
|
3785
|
+
name: import_zod12.z.string(),
|
|
3786
|
+
description: import_zod12.z.string().nullable().optional(),
|
|
3787
|
+
photo: import_zod12.z.string(),
|
|
3788
|
+
rating: import_zod12.z.number().min(0).max(5),
|
|
3789
|
+
services: import_zod12.z.array(import_zod12.z.string())
|
|
3319
3790
|
// List of procedure IDs practitioner offers
|
|
3320
3791
|
});
|
|
3321
3792
|
|
|
3322
|
-
// src/validations/media.schema.ts
|
|
3323
|
-
var import_zod12 = require("zod");
|
|
3324
|
-
var mediaResourceSchema = import_zod12.z.union([
|
|
3325
|
-
import_zod12.z.string(),
|
|
3326
|
-
import_zod12.z.instanceof(File),
|
|
3327
|
-
import_zod12.z.instanceof(Blob)
|
|
3328
|
-
]);
|
|
3329
|
-
|
|
3330
3793
|
// src/validations/clinic.schema.ts
|
|
3331
3794
|
var clinicContactInfoSchema = import_zod13.z.object({
|
|
3332
3795
|
email: import_zod13.z.string().email(),
|
|
@@ -3386,8 +3849,8 @@ var clinicAdminSchema = import_zod13.z.object({
|
|
|
3386
3849
|
clinicsManagedInfo: import_zod13.z.array(clinicInfoSchema),
|
|
3387
3850
|
contactInfo: contactPersonSchema,
|
|
3388
3851
|
roleTitle: import_zod13.z.string(),
|
|
3389
|
-
createdAt: import_zod13.z.instanceof(Date).or(import_zod13.z.instanceof(
|
|
3390
|
-
updatedAt: import_zod13.z.instanceof(Date).or(import_zod13.z.instanceof(
|
|
3852
|
+
createdAt: import_zod13.z.instanceof(Date).or(import_zod13.z.instanceof(import_firestore15.Timestamp)),
|
|
3853
|
+
updatedAt: import_zod13.z.instanceof(Date).or(import_zod13.z.instanceof(import_firestore15.Timestamp)),
|
|
3391
3854
|
isActive: import_zod13.z.boolean()
|
|
3392
3855
|
});
|
|
3393
3856
|
var adminTokenSchema = import_zod13.z.object({
|
|
@@ -3396,9 +3859,9 @@ var adminTokenSchema = import_zod13.z.object({
|
|
|
3396
3859
|
email: import_zod13.z.string().email().optional().nullable(),
|
|
3397
3860
|
status: import_zod13.z.nativeEnum(AdminTokenStatus),
|
|
3398
3861
|
usedByUserRef: import_zod13.z.string().optional(),
|
|
3399
|
-
createdAt: import_zod13.z.instanceof(Date).or(import_zod13.z.instanceof(
|
|
3862
|
+
createdAt: import_zod13.z.instanceof(Date).or(import_zod13.z.instanceof(import_firestore15.Timestamp)),
|
|
3400
3863
|
// Timestamp
|
|
3401
|
-
expiresAt: import_zod13.z.instanceof(Date).or(import_zod13.z.instanceof(
|
|
3864
|
+
expiresAt: import_zod13.z.instanceof(Date).or(import_zod13.z.instanceof(import_firestore15.Timestamp))
|
|
3402
3865
|
// Timestamp
|
|
3403
3866
|
});
|
|
3404
3867
|
var createAdminTokenSchema = import_zod13.z.object({
|
|
@@ -3418,9 +3881,9 @@ var clinicGroupSchema = import_zod13.z.object({
|
|
|
3418
3881
|
adminsInfo: import_zod13.z.array(adminInfoSchema),
|
|
3419
3882
|
adminTokens: import_zod13.z.array(adminTokenSchema),
|
|
3420
3883
|
ownerId: import_zod13.z.string().nullable(),
|
|
3421
|
-
createdAt: import_zod13.z.instanceof(Date).or(import_zod13.z.instanceof(
|
|
3884
|
+
createdAt: import_zod13.z.instanceof(Date).or(import_zod13.z.instanceof(import_firestore15.Timestamp)),
|
|
3422
3885
|
// Timestamp
|
|
3423
|
-
updatedAt: import_zod13.z.instanceof(Date).or(import_zod13.z.instanceof(
|
|
3886
|
+
updatedAt: import_zod13.z.instanceof(Date).or(import_zod13.z.instanceof(import_firestore15.Timestamp)),
|
|
3424
3887
|
// Timestamp
|
|
3425
3888
|
isActive: import_zod13.z.boolean(),
|
|
3426
3889
|
logo: mediaResourceSchema.optional().nullable(),
|
|
@@ -3462,9 +3925,9 @@ var clinicSchema = import_zod13.z.object({
|
|
|
3462
3925
|
// Use the correct schema for aggregated procedure info
|
|
3463
3926
|
reviewInfo: clinicReviewInfoSchema,
|
|
3464
3927
|
admins: import_zod13.z.array(import_zod13.z.string()),
|
|
3465
|
-
createdAt: import_zod13.z.instanceof(Date).or(import_zod13.z.instanceof(
|
|
3928
|
+
createdAt: import_zod13.z.instanceof(Date).or(import_zod13.z.instanceof(import_firestore15.Timestamp)),
|
|
3466
3929
|
// Timestamp
|
|
3467
|
-
updatedAt: import_zod13.z.instanceof(Date).or(import_zod13.z.instanceof(
|
|
3930
|
+
updatedAt: import_zod13.z.instanceof(Date).or(import_zod13.z.instanceof(import_firestore15.Timestamp)),
|
|
3468
3931
|
// Timestamp
|
|
3469
3932
|
isActive: import_zod13.z.boolean(),
|
|
3470
3933
|
isVerified: import_zod13.z.boolean(),
|
|
@@ -3686,7 +4149,7 @@ async function createClinicAdmin(db, data, clinicGroupService) {
|
|
|
3686
4149
|
}
|
|
3687
4150
|
console.log("[CLINIC_ADMIN] Preparing admin data object");
|
|
3688
4151
|
const adminData = {
|
|
3689
|
-
id: (0,
|
|
4152
|
+
id: (0, import_firestore16.doc)((0, import_firestore16.collection)(db, CLINIC_ADMINS_COLLECTION)).id,
|
|
3690
4153
|
// Generate a new ID for the admin document
|
|
3691
4154
|
userRef: validatedData.userRef,
|
|
3692
4155
|
clinicGroupId: clinicGroupId || "",
|
|
@@ -3699,15 +4162,15 @@ async function createClinicAdmin(db, data, clinicGroupService) {
|
|
|
3699
4162
|
contactInfo: validatedData.contactInfo,
|
|
3700
4163
|
roleTitle: validatedData.roleTitle,
|
|
3701
4164
|
isActive: validatedData.isActive,
|
|
3702
|
-
createdAt: (0,
|
|
3703
|
-
updatedAt: (0,
|
|
4165
|
+
createdAt: (0, import_firestore16.serverTimestamp)(),
|
|
4166
|
+
updatedAt: (0, import_firestore16.serverTimestamp)()
|
|
3704
4167
|
};
|
|
3705
4168
|
console.log("[CLINIC_ADMIN] Validating complete admin object");
|
|
3706
4169
|
try {
|
|
3707
4170
|
clinicAdminSchema.parse({
|
|
3708
4171
|
...adminData,
|
|
3709
|
-
createdAt:
|
|
3710
|
-
updatedAt:
|
|
4172
|
+
createdAt: import_firestore16.Timestamp.now(),
|
|
4173
|
+
updatedAt: import_firestore16.Timestamp.now()
|
|
3711
4174
|
});
|
|
3712
4175
|
console.log("[CLINIC_ADMIN] Admin object validation passed");
|
|
3713
4176
|
} catch (schemaError) {
|
|
@@ -3721,7 +4184,7 @@ async function createClinicAdmin(db, data, clinicGroupService) {
|
|
|
3721
4184
|
adminId: adminData.id
|
|
3722
4185
|
});
|
|
3723
4186
|
try {
|
|
3724
|
-
await (0,
|
|
4187
|
+
await (0, import_firestore16.setDoc)((0, import_firestore16.doc)(db, CLINIC_ADMINS_COLLECTION, adminData.id), adminData);
|
|
3725
4188
|
console.log("[CLINIC_ADMIN] Admin saved successfully");
|
|
3726
4189
|
} catch (firestoreError) {
|
|
3727
4190
|
console.error(
|
|
@@ -3770,30 +4233,30 @@ async function checkClinicGroupExists(db, groupId, clinicGroupService) {
|
|
|
3770
4233
|
return !!group;
|
|
3771
4234
|
}
|
|
3772
4235
|
async function getClinicAdmin(db, adminId) {
|
|
3773
|
-
const docRef = (0,
|
|
3774
|
-
const docSnap = await (0,
|
|
4236
|
+
const docRef = (0, import_firestore16.doc)(db, CLINIC_ADMINS_COLLECTION, adminId);
|
|
4237
|
+
const docSnap = await (0, import_firestore16.getDoc)(docRef);
|
|
3775
4238
|
if (docSnap.exists()) {
|
|
3776
4239
|
return docSnap.data();
|
|
3777
4240
|
}
|
|
3778
4241
|
return null;
|
|
3779
4242
|
}
|
|
3780
4243
|
async function getClinicAdminByUserRef(db, userRef) {
|
|
3781
|
-
const q = (0,
|
|
3782
|
-
(0,
|
|
3783
|
-
(0,
|
|
4244
|
+
const q = (0, import_firestore16.query)(
|
|
4245
|
+
(0, import_firestore16.collection)(db, CLINIC_ADMINS_COLLECTION),
|
|
4246
|
+
(0, import_firestore16.where)("userRef", "==", userRef)
|
|
3784
4247
|
);
|
|
3785
|
-
const querySnapshot = await (0,
|
|
4248
|
+
const querySnapshot = await (0, import_firestore16.getDocs)(q);
|
|
3786
4249
|
if (querySnapshot.empty) {
|
|
3787
4250
|
return null;
|
|
3788
4251
|
}
|
|
3789
4252
|
return querySnapshot.docs[0].data();
|
|
3790
4253
|
}
|
|
3791
4254
|
async function getClinicAdminsByGroup(db, clinicGroupId) {
|
|
3792
|
-
const q = (0,
|
|
3793
|
-
(0,
|
|
3794
|
-
(0,
|
|
4255
|
+
const q = (0, import_firestore16.query)(
|
|
4256
|
+
(0, import_firestore16.collection)(db, CLINIC_ADMINS_COLLECTION),
|
|
4257
|
+
(0, import_firestore16.where)("clinicGroupId", "==", clinicGroupId)
|
|
3795
4258
|
);
|
|
3796
|
-
const querySnapshot = await (0,
|
|
4259
|
+
const querySnapshot = await (0, import_firestore16.getDocs)(q);
|
|
3797
4260
|
return querySnapshot.docs.map((doc34) => doc34.data());
|
|
3798
4261
|
}
|
|
3799
4262
|
async function updateClinicAdmin(db, adminId, data) {
|
|
@@ -3803,9 +4266,9 @@ async function updateClinicAdmin(db, adminId, data) {
|
|
|
3803
4266
|
}
|
|
3804
4267
|
const updatedData = {
|
|
3805
4268
|
...data,
|
|
3806
|
-
updatedAt: (0,
|
|
4269
|
+
updatedAt: (0, import_firestore16.serverTimestamp)()
|
|
3807
4270
|
};
|
|
3808
|
-
await (0,
|
|
4271
|
+
await (0, import_firestore16.updateDoc)((0, import_firestore16.doc)(db, CLINIC_ADMINS_COLLECTION, adminId), updatedData);
|
|
3809
4272
|
const updatedAdmin = await getClinicAdmin(db, adminId);
|
|
3810
4273
|
if (!updatedAdmin) {
|
|
3811
4274
|
throw new Error("Failed to retrieve updated admin");
|
|
@@ -3817,7 +4280,7 @@ async function deleteClinicAdmin(db, adminId) {
|
|
|
3817
4280
|
if (!admin) {
|
|
3818
4281
|
throw new Error("Clinic admin not found");
|
|
3819
4282
|
}
|
|
3820
|
-
await (0,
|
|
4283
|
+
await (0, import_firestore16.deleteDoc)((0, import_firestore16.doc)(db, CLINIC_ADMINS_COLLECTION, adminId));
|
|
3821
4284
|
}
|
|
3822
4285
|
async function addClinicToManaged(db, adminId, clinicId, requesterId, clinicService) {
|
|
3823
4286
|
const admin = await getClinicAdmin(db, adminId);
|
|
@@ -4060,11 +4523,11 @@ var ClinicAdminService = class extends BaseService {
|
|
|
4060
4523
|
};
|
|
4061
4524
|
|
|
4062
4525
|
// src/services/practitioner/practitioner.service.ts
|
|
4063
|
-
var
|
|
4526
|
+
var import_firestore18 = require("firebase/firestore");
|
|
4064
4527
|
|
|
4065
4528
|
// src/validations/practitioner.schema.ts
|
|
4066
4529
|
var import_zod14 = require("zod");
|
|
4067
|
-
var
|
|
4530
|
+
var import_firestore17 = require("firebase/firestore");
|
|
4068
4531
|
|
|
4069
4532
|
// src/backoffice/types/static/certification.types.ts
|
|
4070
4533
|
var CertificationLevel = /* @__PURE__ */ ((CertificationLevel2) => {
|
|
@@ -4097,9 +4560,9 @@ var practitionerBasicInfoSchema = import_zod14.z.object({
|
|
|
4097
4560
|
title: import_zod14.z.string().min(2).max(100),
|
|
4098
4561
|
email: import_zod14.z.string().email(),
|
|
4099
4562
|
phoneNumber: import_zod14.z.string().regex(/^\+?[1-9]\d{1,14}$/, "Invalid phone number"),
|
|
4100
|
-
dateOfBirth: import_zod14.z.instanceof(
|
|
4563
|
+
dateOfBirth: import_zod14.z.instanceof(import_firestore17.Timestamp).or(import_zod14.z.date()),
|
|
4101
4564
|
gender: import_zod14.z.enum(["male", "female", "other"]),
|
|
4102
|
-
profileImageUrl:
|
|
4565
|
+
profileImageUrl: mediaResourceSchema.optional(),
|
|
4103
4566
|
bio: import_zod14.z.string().max(1e3).optional(),
|
|
4104
4567
|
languages: import_zod14.z.array(import_zod14.z.string()).min(1)
|
|
4105
4568
|
});
|
|
@@ -4108,8 +4571,8 @@ var practitionerCertificationSchema = import_zod14.z.object({
|
|
|
4108
4571
|
specialties: import_zod14.z.array(import_zod14.z.nativeEnum(CertificationSpecialty)),
|
|
4109
4572
|
licenseNumber: import_zod14.z.string().min(3).max(50),
|
|
4110
4573
|
issuingAuthority: import_zod14.z.string().min(2).max(100),
|
|
4111
|
-
issueDate: import_zod14.z.instanceof(
|
|
4112
|
-
expiryDate: import_zod14.z.instanceof(
|
|
4574
|
+
issueDate: import_zod14.z.instanceof(import_firestore17.Timestamp).or(import_zod14.z.date()),
|
|
4575
|
+
expiryDate: import_zod14.z.instanceof(import_firestore17.Timestamp).or(import_zod14.z.date()).optional(),
|
|
4113
4576
|
verificationStatus: import_zod14.z.enum(["pending", "verified", "rejected"])
|
|
4114
4577
|
});
|
|
4115
4578
|
var timeSlotSchema = import_zod14.z.object({
|
|
@@ -4126,8 +4589,8 @@ var practitionerWorkingHoursSchema = import_zod14.z.object({
|
|
|
4126
4589
|
friday: timeSlotSchema,
|
|
4127
4590
|
saturday: timeSlotSchema,
|
|
4128
4591
|
sunday: timeSlotSchema,
|
|
4129
|
-
createdAt: import_zod14.z.instanceof(
|
|
4130
|
-
updatedAt: import_zod14.z.instanceof(
|
|
4592
|
+
createdAt: import_zod14.z.instanceof(import_firestore17.Timestamp).or(import_zod14.z.date()),
|
|
4593
|
+
updatedAt: import_zod14.z.instanceof(import_firestore17.Timestamp).or(import_zod14.z.date())
|
|
4131
4594
|
});
|
|
4132
4595
|
var practitionerClinicWorkingHoursSchema = import_zod14.z.object({
|
|
4133
4596
|
clinicId: import_zod14.z.string().min(1),
|
|
@@ -4141,8 +4604,8 @@ var practitionerClinicWorkingHoursSchema = import_zod14.z.object({
|
|
|
4141
4604
|
sunday: timeSlotSchema
|
|
4142
4605
|
}),
|
|
4143
4606
|
isActive: import_zod14.z.boolean(),
|
|
4144
|
-
createdAt: import_zod14.z.instanceof(
|
|
4145
|
-
updatedAt: import_zod14.z.instanceof(
|
|
4607
|
+
createdAt: import_zod14.z.instanceof(import_firestore17.Timestamp).or(import_zod14.z.date()),
|
|
4608
|
+
updatedAt: import_zod14.z.instanceof(import_firestore17.Timestamp).or(import_zod14.z.date())
|
|
4146
4609
|
});
|
|
4147
4610
|
var practitionerSchema = import_zod14.z.object({
|
|
4148
4611
|
id: import_zod14.z.string().min(1),
|
|
@@ -4158,8 +4621,8 @@ var practitionerSchema = import_zod14.z.object({
|
|
|
4158
4621
|
isActive: import_zod14.z.boolean(),
|
|
4159
4622
|
isVerified: import_zod14.z.boolean(),
|
|
4160
4623
|
status: import_zod14.z.nativeEnum(PractitionerStatus),
|
|
4161
|
-
createdAt: import_zod14.z.instanceof(
|
|
4162
|
-
updatedAt: import_zod14.z.instanceof(
|
|
4624
|
+
createdAt: import_zod14.z.instanceof(import_firestore17.Timestamp).or(import_zod14.z.date()),
|
|
4625
|
+
updatedAt: import_zod14.z.instanceof(import_firestore17.Timestamp).or(import_zod14.z.date())
|
|
4163
4626
|
});
|
|
4164
4627
|
var createPractitionerSchema = import_zod14.z.object({
|
|
4165
4628
|
userRef: import_zod14.z.string().min(1),
|
|
@@ -4191,10 +4654,10 @@ var practitionerTokenSchema = import_zod14.z.object({
|
|
|
4191
4654
|
clinicId: import_zod14.z.string().min(1),
|
|
4192
4655
|
status: import_zod14.z.nativeEnum(PractitionerTokenStatus),
|
|
4193
4656
|
createdBy: import_zod14.z.string().min(1),
|
|
4194
|
-
createdAt: import_zod14.z.instanceof(
|
|
4195
|
-
expiresAt: import_zod14.z.instanceof(
|
|
4657
|
+
createdAt: import_zod14.z.instanceof(import_firestore17.Timestamp).or(import_zod14.z.date()),
|
|
4658
|
+
expiresAt: import_zod14.z.instanceof(import_firestore17.Timestamp).or(import_zod14.z.date()),
|
|
4196
4659
|
usedBy: import_zod14.z.string().optional(),
|
|
4197
|
-
usedAt: import_zod14.z.instanceof(
|
|
4660
|
+
usedAt: import_zod14.z.instanceof(import_firestore17.Timestamp).or(import_zod14.z.date()).optional()
|
|
4198
4661
|
});
|
|
4199
4662
|
var createPractitionerTokenSchema = import_zod14.z.object({
|
|
4200
4663
|
practitionerId: import_zod14.z.string().min(1),
|
|
@@ -4211,7 +4674,7 @@ var practitionerSignupSchema = import_zod14.z.object({
|
|
|
4211
4674
|
profileData: import_zod14.z.object({
|
|
4212
4675
|
basicInfo: import_zod14.z.object({
|
|
4213
4676
|
phoneNumber: import_zod14.z.string().optional(),
|
|
4214
|
-
profileImageUrl:
|
|
4677
|
+
profileImageUrl: mediaResourceSchema.optional(),
|
|
4215
4678
|
gender: import_zod14.z.enum(["male", "female", "other"]).optional(),
|
|
4216
4679
|
bio: import_zod14.z.string().optional()
|
|
4217
4680
|
}).optional(),
|
|
@@ -4226,6 +4689,7 @@ var PractitionerService = class extends BaseService {
|
|
|
4226
4689
|
constructor(db, auth, app, clinicService) {
|
|
4227
4690
|
super(db, auth, app);
|
|
4228
4691
|
this.clinicService = clinicService;
|
|
4692
|
+
this.mediaService = new MediaService(db, auth, app);
|
|
4229
4693
|
}
|
|
4230
4694
|
getClinicService() {
|
|
4231
4695
|
if (!this.clinicService) {
|
|
@@ -4236,6 +4700,53 @@ var PractitionerService = class extends BaseService {
|
|
|
4236
4700
|
setClinicService(clinicService) {
|
|
4237
4701
|
this.clinicService = clinicService;
|
|
4238
4702
|
}
|
|
4703
|
+
/**
|
|
4704
|
+
* Handles profile photo upload for practitioners
|
|
4705
|
+
* @param profilePhoto - MediaResource (File, Blob, or URL string)
|
|
4706
|
+
* @param practitionerId - ID of the practitioner
|
|
4707
|
+
* @returns URL string of the uploaded or existing photo
|
|
4708
|
+
*/
|
|
4709
|
+
async handleProfilePhotoUpload(profilePhoto, practitionerId) {
|
|
4710
|
+
if (!profilePhoto) {
|
|
4711
|
+
return void 0;
|
|
4712
|
+
}
|
|
4713
|
+
if (typeof profilePhoto === "string") {
|
|
4714
|
+
return profilePhoto;
|
|
4715
|
+
}
|
|
4716
|
+
if (profilePhoto instanceof File || profilePhoto instanceof Blob) {
|
|
4717
|
+
console.log(
|
|
4718
|
+
`[PractitionerService] Uploading profile photo for practitioner ${practitionerId}`
|
|
4719
|
+
);
|
|
4720
|
+
const mediaMetadata = await this.mediaService.uploadMedia(
|
|
4721
|
+
profilePhoto,
|
|
4722
|
+
practitionerId,
|
|
4723
|
+
// Using practitionerId as ownerId
|
|
4724
|
+
"public" /* PUBLIC */,
|
|
4725
|
+
// Profile photos should be public
|
|
4726
|
+
"practitioner_profile_photos",
|
|
4727
|
+
profilePhoto instanceof File ? profilePhoto.name : `profile_photo_${practitionerId}`
|
|
4728
|
+
);
|
|
4729
|
+
return mediaMetadata.url;
|
|
4730
|
+
}
|
|
4731
|
+
return void 0;
|
|
4732
|
+
}
|
|
4733
|
+
/**
|
|
4734
|
+
* Processes BasicPractitionerInfo to handle profile photo uploads
|
|
4735
|
+
* @param basicInfo - The basic info containing potential MediaResource profile photo
|
|
4736
|
+
* @param practitionerId - ID of the practitioner
|
|
4737
|
+
* @returns Processed basic info with URL string for profileImageUrl
|
|
4738
|
+
*/
|
|
4739
|
+
async processBasicInfo(basicInfo, practitionerId) {
|
|
4740
|
+
const processedBasicInfo = { ...basicInfo };
|
|
4741
|
+
if (basicInfo.profileImageUrl) {
|
|
4742
|
+
const uploadedUrl = await this.handleProfilePhotoUpload(
|
|
4743
|
+
basicInfo.profileImageUrl,
|
|
4744
|
+
practitionerId
|
|
4745
|
+
);
|
|
4746
|
+
processedBasicInfo.profileImageUrl = uploadedUrl;
|
|
4747
|
+
}
|
|
4748
|
+
return processedBasicInfo;
|
|
4749
|
+
}
|
|
4239
4750
|
/**
|
|
4240
4751
|
* Creates a new practitioner
|
|
4241
4752
|
*/
|
|
@@ -4256,7 +4767,10 @@ var PractitionerService = class extends BaseService {
|
|
|
4256
4767
|
const practitioner = {
|
|
4257
4768
|
id: practitionerId,
|
|
4258
4769
|
userRef: validData.userRef,
|
|
4259
|
-
basicInfo:
|
|
4770
|
+
basicInfo: await this.processBasicInfo(
|
|
4771
|
+
validData.basicInfo,
|
|
4772
|
+
practitionerId
|
|
4773
|
+
),
|
|
4260
4774
|
certification: validData.certification,
|
|
4261
4775
|
clinics: validData.clinics || [],
|
|
4262
4776
|
clinicWorkingHours: validData.clinicWorkingHours || [],
|
|
@@ -4267,20 +4781,20 @@ var PractitionerService = class extends BaseService {
|
|
|
4267
4781
|
isActive: validData.isActive !== void 0 ? validData.isActive : true,
|
|
4268
4782
|
isVerified: validData.isVerified !== void 0 ? validData.isVerified : false,
|
|
4269
4783
|
status: validData.status || "active" /* ACTIVE */,
|
|
4270
|
-
createdAt: (0,
|
|
4271
|
-
updatedAt: (0,
|
|
4784
|
+
createdAt: (0, import_firestore18.serverTimestamp)(),
|
|
4785
|
+
updatedAt: (0, import_firestore18.serverTimestamp)()
|
|
4272
4786
|
};
|
|
4273
4787
|
practitionerSchema.parse({
|
|
4274
4788
|
...practitioner,
|
|
4275
|
-
createdAt:
|
|
4276
|
-
updatedAt:
|
|
4789
|
+
createdAt: import_firestore18.Timestamp.now(),
|
|
4790
|
+
updatedAt: import_firestore18.Timestamp.now()
|
|
4277
4791
|
});
|
|
4278
|
-
const practitionerRef = (0,
|
|
4792
|
+
const practitionerRef = (0, import_firestore18.doc)(
|
|
4279
4793
|
this.db,
|
|
4280
4794
|
PRACTITIONERS_COLLECTION,
|
|
4281
4795
|
practitionerId
|
|
4282
4796
|
);
|
|
4283
|
-
await (0,
|
|
4797
|
+
await (0, import_firestore18.setDoc)(practitionerRef, practitioner);
|
|
4284
4798
|
const createdPractitioner = await this.getPractitioner(practitionerId);
|
|
4285
4799
|
if (!createdPractitioner) {
|
|
4286
4800
|
throw new Error(
|
|
@@ -4356,7 +4870,10 @@ var PractitionerService = class extends BaseService {
|
|
|
4356
4870
|
id: practitionerId,
|
|
4357
4871
|
userRef: "",
|
|
4358
4872
|
// Prazno - biće popunjeno kada korisnik kreira nalog
|
|
4359
|
-
basicInfo:
|
|
4873
|
+
basicInfo: await this.processBasicInfo(
|
|
4874
|
+
validatedData.basicInfo,
|
|
4875
|
+
practitionerId
|
|
4876
|
+
),
|
|
4360
4877
|
certification: validatedData.certification,
|
|
4361
4878
|
clinics,
|
|
4362
4879
|
clinicWorkingHours: validatedData.clinicWorkingHours || [],
|
|
@@ -4367,17 +4884,17 @@ var PractitionerService = class extends BaseService {
|
|
|
4367
4884
|
isActive: validatedData.isActive !== void 0 ? validatedData.isActive : false,
|
|
4368
4885
|
isVerified: validatedData.isVerified !== void 0 ? validatedData.isVerified : false,
|
|
4369
4886
|
status: "draft" /* DRAFT */,
|
|
4370
|
-
createdAt: (0,
|
|
4371
|
-
updatedAt: (0,
|
|
4887
|
+
createdAt: (0, import_firestore18.serverTimestamp)(),
|
|
4888
|
+
updatedAt: (0, import_firestore18.serverTimestamp)()
|
|
4372
4889
|
};
|
|
4373
4890
|
practitionerSchema.parse({
|
|
4374
4891
|
...practitionerData,
|
|
4375
4892
|
userRef: "temp-for-validation",
|
|
4376
|
-
createdAt:
|
|
4377
|
-
updatedAt:
|
|
4893
|
+
createdAt: import_firestore18.Timestamp.now(),
|
|
4894
|
+
updatedAt: import_firestore18.Timestamp.now()
|
|
4378
4895
|
});
|
|
4379
|
-
await (0,
|
|
4380
|
-
(0,
|
|
4896
|
+
await (0, import_firestore18.setDoc)(
|
|
4897
|
+
(0, import_firestore18.doc)(this.db, PRACTITIONERS_COLLECTION, practitionerData.id),
|
|
4381
4898
|
practitionerData
|
|
4382
4899
|
);
|
|
4383
4900
|
const savedPractitioner = await this.getPractitioner(practitionerData.id);
|
|
@@ -4394,12 +4911,12 @@ var PractitionerService = class extends BaseService {
|
|
|
4394
4911
|
clinicId,
|
|
4395
4912
|
status: "active" /* ACTIVE */,
|
|
4396
4913
|
createdBy,
|
|
4397
|
-
createdAt:
|
|
4398
|
-
expiresAt:
|
|
4914
|
+
createdAt: import_firestore18.Timestamp.now(),
|
|
4915
|
+
expiresAt: import_firestore18.Timestamp.fromDate(expiration)
|
|
4399
4916
|
};
|
|
4400
4917
|
practitionerTokenSchema.parse(token);
|
|
4401
4918
|
const tokenPath = `${PRACTITIONERS_COLLECTION}/${practitionerId}/${REGISTER_TOKENS_COLLECTION}/${token.id}`;
|
|
4402
|
-
await (0,
|
|
4919
|
+
await (0, import_firestore18.setDoc)((0, import_firestore18.doc)(this.db, tokenPath), token);
|
|
4403
4920
|
return { practitioner: savedPractitioner, token };
|
|
4404
4921
|
} catch (error) {
|
|
4405
4922
|
if (error instanceof import_zod15.z.ZodError) {
|
|
@@ -4447,12 +4964,12 @@ var PractitionerService = class extends BaseService {
|
|
|
4447
4964
|
clinicId: validatedData.clinicId,
|
|
4448
4965
|
status: "active" /* ACTIVE */,
|
|
4449
4966
|
createdBy,
|
|
4450
|
-
createdAt:
|
|
4451
|
-
expiresAt:
|
|
4967
|
+
createdAt: import_firestore18.Timestamp.now(),
|
|
4968
|
+
expiresAt: import_firestore18.Timestamp.fromDate(expiration)
|
|
4452
4969
|
};
|
|
4453
4970
|
practitionerTokenSchema.parse(token);
|
|
4454
4971
|
const tokenPath = `${PRACTITIONERS_COLLECTION}/${validatedData.practitionerId}/${REGISTER_TOKENS_COLLECTION}/${token.id}`;
|
|
4455
|
-
await (0,
|
|
4972
|
+
await (0, import_firestore18.setDoc)((0, import_firestore18.doc)(this.db, tokenPath), token);
|
|
4456
4973
|
return token;
|
|
4457
4974
|
} catch (error) {
|
|
4458
4975
|
if (error instanceof import_zod15.z.ZodError) {
|
|
@@ -4467,16 +4984,16 @@ var PractitionerService = class extends BaseService {
|
|
|
4467
4984
|
* @returns Array of active tokens
|
|
4468
4985
|
*/
|
|
4469
4986
|
async getPractitionerActiveTokens(practitionerId) {
|
|
4470
|
-
const tokensRef = (0,
|
|
4987
|
+
const tokensRef = (0, import_firestore18.collection)(
|
|
4471
4988
|
this.db,
|
|
4472
4989
|
`${PRACTITIONERS_COLLECTION}/${practitionerId}/${REGISTER_TOKENS_COLLECTION}`
|
|
4473
4990
|
);
|
|
4474
|
-
const q = (0,
|
|
4991
|
+
const q = (0, import_firestore18.query)(
|
|
4475
4992
|
tokensRef,
|
|
4476
|
-
(0,
|
|
4477
|
-
(0,
|
|
4993
|
+
(0, import_firestore18.where)("status", "==", "active" /* ACTIVE */),
|
|
4994
|
+
(0, import_firestore18.where)("expiresAt", ">", import_firestore18.Timestamp.now())
|
|
4478
4995
|
);
|
|
4479
|
-
const querySnapshot = await (0,
|
|
4996
|
+
const querySnapshot = await (0, import_firestore18.getDocs)(q);
|
|
4480
4997
|
return querySnapshot.docs.map((doc34) => doc34.data());
|
|
4481
4998
|
}
|
|
4482
4999
|
/**
|
|
@@ -4485,11 +5002,11 @@ var PractitionerService = class extends BaseService {
|
|
|
4485
5002
|
* @returns The token if found and valid, null otherwise
|
|
4486
5003
|
*/
|
|
4487
5004
|
async validateToken(tokenString) {
|
|
4488
|
-
const practitionersRef = (0,
|
|
4489
|
-
const practitionersSnapshot = await (0,
|
|
5005
|
+
const practitionersRef = (0, import_firestore18.collection)(this.db, PRACTITIONERS_COLLECTION);
|
|
5006
|
+
const practitionersSnapshot = await (0, import_firestore18.getDocs)(practitionersRef);
|
|
4490
5007
|
for (const practitionerDoc of practitionersSnapshot.docs) {
|
|
4491
5008
|
const practitionerId = practitionerDoc.id;
|
|
4492
|
-
const tokensRef = (0,
|
|
5009
|
+
const tokensRef = (0, import_firestore18.collection)(
|
|
4493
5010
|
this.db,
|
|
4494
5011
|
`${PRACTITIONERS_COLLECTION}/${practitionerId}/${REGISTER_TOKENS_COLLECTION}`
|
|
4495
5012
|
);
|
|
@@ -4497,17 +5014,17 @@ var PractitionerService = class extends BaseService {
|
|
|
4497
5014
|
`[PRACTITIONER] Validating token for practitioner ${practitionerId}`,
|
|
4498
5015
|
{
|
|
4499
5016
|
tokenString,
|
|
4500
|
-
timestamp:
|
|
5017
|
+
timestamp: import_firestore18.Timestamp.now().toDate()
|
|
4501
5018
|
}
|
|
4502
5019
|
);
|
|
4503
|
-
const q = (0,
|
|
5020
|
+
const q = (0, import_firestore18.query)(
|
|
4504
5021
|
tokensRef,
|
|
4505
|
-
(0,
|
|
4506
|
-
(0,
|
|
4507
|
-
(0,
|
|
5022
|
+
(0, import_firestore18.where)("token", "==", tokenString),
|
|
5023
|
+
(0, import_firestore18.where)("status", "==", "active" /* ACTIVE */),
|
|
5024
|
+
(0, import_firestore18.where)("expiresAt", ">", import_firestore18.Timestamp.now())
|
|
4508
5025
|
);
|
|
4509
5026
|
try {
|
|
4510
|
-
const tokenSnapshot = await (0,
|
|
5027
|
+
const tokenSnapshot = await (0, import_firestore18.getDocs)(q);
|
|
4511
5028
|
console.log(
|
|
4512
5029
|
`[PRACTITIONER] Token query results for practitioner ${practitionerId}`,
|
|
4513
5030
|
{
|
|
@@ -4540,22 +5057,22 @@ var PractitionerService = class extends BaseService {
|
|
|
4540
5057
|
* @param userId ID of the user using the token
|
|
4541
5058
|
*/
|
|
4542
5059
|
async markTokenAsUsed(tokenId, practitionerId, userId) {
|
|
4543
|
-
const tokenRef = (0,
|
|
5060
|
+
const tokenRef = (0, import_firestore18.doc)(
|
|
4544
5061
|
this.db,
|
|
4545
5062
|
`${PRACTITIONERS_COLLECTION}/${practitionerId}/${REGISTER_TOKENS_COLLECTION}/${tokenId}`
|
|
4546
5063
|
);
|
|
4547
|
-
await (0,
|
|
5064
|
+
await (0, import_firestore18.updateDoc)(tokenRef, {
|
|
4548
5065
|
status: "used" /* USED */,
|
|
4549
5066
|
usedBy: userId,
|
|
4550
|
-
usedAt:
|
|
5067
|
+
usedAt: import_firestore18.Timestamp.now()
|
|
4551
5068
|
});
|
|
4552
5069
|
}
|
|
4553
5070
|
/**
|
|
4554
5071
|
* Dohvata zdravstvenog radnika po ID-u
|
|
4555
5072
|
*/
|
|
4556
5073
|
async getPractitioner(practitionerId) {
|
|
4557
|
-
const practitionerDoc = await (0,
|
|
4558
|
-
(0,
|
|
5074
|
+
const practitionerDoc = await (0, import_firestore18.getDoc)(
|
|
5075
|
+
(0, import_firestore18.doc)(this.db, PRACTITIONERS_COLLECTION, practitionerId)
|
|
4559
5076
|
);
|
|
4560
5077
|
if (!practitionerDoc.exists()) {
|
|
4561
5078
|
return null;
|
|
@@ -4566,11 +5083,11 @@ var PractitionerService = class extends BaseService {
|
|
|
4566
5083
|
* Dohvata zdravstvenog radnika po User ID-u
|
|
4567
5084
|
*/
|
|
4568
5085
|
async getPractitionerByUserRef(userRef) {
|
|
4569
|
-
const q = (0,
|
|
4570
|
-
(0,
|
|
4571
|
-
(0,
|
|
5086
|
+
const q = (0, import_firestore18.query)(
|
|
5087
|
+
(0, import_firestore18.collection)(this.db, PRACTITIONERS_COLLECTION),
|
|
5088
|
+
(0, import_firestore18.where)("userRef", "==", userRef)
|
|
4572
5089
|
);
|
|
4573
|
-
const querySnapshot = await (0,
|
|
5090
|
+
const querySnapshot = await (0, import_firestore18.getDocs)(q);
|
|
4574
5091
|
if (querySnapshot.empty) {
|
|
4575
5092
|
return null;
|
|
4576
5093
|
}
|
|
@@ -4580,37 +5097,37 @@ var PractitionerService = class extends BaseService {
|
|
|
4580
5097
|
* Dohvata sve zdravstvene radnike za određenu kliniku sa statusom ACTIVE
|
|
4581
5098
|
*/
|
|
4582
5099
|
async getPractitionersByClinic(clinicId) {
|
|
4583
|
-
const q = (0,
|
|
4584
|
-
(0,
|
|
4585
|
-
(0,
|
|
4586
|
-
(0,
|
|
4587
|
-
(0,
|
|
5100
|
+
const q = (0, import_firestore18.query)(
|
|
5101
|
+
(0, import_firestore18.collection)(this.db, PRACTITIONERS_COLLECTION),
|
|
5102
|
+
(0, import_firestore18.where)("clinics", "array-contains", clinicId),
|
|
5103
|
+
(0, import_firestore18.where)("isActive", "==", true),
|
|
5104
|
+
(0, import_firestore18.where)("status", "==", "active" /* ACTIVE */)
|
|
4588
5105
|
);
|
|
4589
|
-
const querySnapshot = await (0,
|
|
5106
|
+
const querySnapshot = await (0, import_firestore18.getDocs)(q);
|
|
4590
5107
|
return querySnapshot.docs.map((doc34) => doc34.data());
|
|
4591
5108
|
}
|
|
4592
5109
|
/**
|
|
4593
5110
|
* Dohvata sve zdravstvene radnike za određenu kliniku
|
|
4594
5111
|
*/
|
|
4595
5112
|
async getAllPractitionersByClinic(clinicId) {
|
|
4596
|
-
const q = (0,
|
|
4597
|
-
(0,
|
|
4598
|
-
(0,
|
|
4599
|
-
(0,
|
|
5113
|
+
const q = (0, import_firestore18.query)(
|
|
5114
|
+
(0, import_firestore18.collection)(this.db, PRACTITIONERS_COLLECTION),
|
|
5115
|
+
(0, import_firestore18.where)("clinics", "array-contains", clinicId),
|
|
5116
|
+
(0, import_firestore18.where)("isActive", "==", true)
|
|
4600
5117
|
);
|
|
4601
|
-
const querySnapshot = await (0,
|
|
5118
|
+
const querySnapshot = await (0, import_firestore18.getDocs)(q);
|
|
4602
5119
|
return querySnapshot.docs.map((doc34) => doc34.data());
|
|
4603
5120
|
}
|
|
4604
5121
|
/**
|
|
4605
5122
|
* Dohvata sve draft zdravstvene radnike za određenu kliniku sa statusom DRAFT
|
|
4606
5123
|
*/
|
|
4607
5124
|
async getDraftPractitionersByClinic(clinicId) {
|
|
4608
|
-
const q = (0,
|
|
4609
|
-
(0,
|
|
4610
|
-
(0,
|
|
4611
|
-
(0,
|
|
5125
|
+
const q = (0, import_firestore18.query)(
|
|
5126
|
+
(0, import_firestore18.collection)(this.db, PRACTITIONERS_COLLECTION),
|
|
5127
|
+
(0, import_firestore18.where)("clinics", "array-contains", clinicId),
|
|
5128
|
+
(0, import_firestore18.where)("status", "==", "draft" /* DRAFT */)
|
|
4612
5129
|
);
|
|
4613
|
-
const querySnapshot = await (0,
|
|
5130
|
+
const querySnapshot = await (0, import_firestore18.getDocs)(q);
|
|
4614
5131
|
return querySnapshot.docs.map((doc34) => doc34.data());
|
|
4615
5132
|
}
|
|
4616
5133
|
/**
|
|
@@ -4619,21 +5136,28 @@ var PractitionerService = class extends BaseService {
|
|
|
4619
5136
|
async updatePractitioner(practitionerId, data) {
|
|
4620
5137
|
try {
|
|
4621
5138
|
const validData = data;
|
|
4622
|
-
const practitionerRef = (0,
|
|
5139
|
+
const practitionerRef = (0, import_firestore18.doc)(
|
|
4623
5140
|
this.db,
|
|
4624
5141
|
PRACTITIONERS_COLLECTION,
|
|
4625
5142
|
practitionerId
|
|
4626
5143
|
);
|
|
4627
|
-
const practitionerDoc = await (0,
|
|
5144
|
+
const practitionerDoc = await (0, import_firestore18.getDoc)(practitionerRef);
|
|
4628
5145
|
if (!practitionerDoc.exists()) {
|
|
4629
5146
|
throw new Error(`Practitioner ${practitionerId} not found`);
|
|
4630
5147
|
}
|
|
4631
5148
|
const currentPractitioner = practitionerDoc.data();
|
|
5149
|
+
let processedData = { ...validData };
|
|
5150
|
+
if (validData.basicInfo) {
|
|
5151
|
+
processedData.basicInfo = await this.processBasicInfo(
|
|
5152
|
+
validData.basicInfo,
|
|
5153
|
+
practitionerId
|
|
5154
|
+
);
|
|
5155
|
+
}
|
|
4632
5156
|
const updateData = {
|
|
4633
|
-
...
|
|
4634
|
-
updatedAt: (0,
|
|
5157
|
+
...processedData,
|
|
5158
|
+
updatedAt: (0, import_firestore18.serverTimestamp)()
|
|
4635
5159
|
};
|
|
4636
|
-
await (0,
|
|
5160
|
+
await (0, import_firestore18.updateDoc)(practitionerRef, updateData);
|
|
4637
5161
|
const updatedPractitioner = await this.getPractitioner(practitionerId);
|
|
4638
5162
|
if (!updatedPractitioner) {
|
|
4639
5163
|
throw new Error(
|
|
@@ -4655,12 +5179,12 @@ var PractitionerService = class extends BaseService {
|
|
|
4655
5179
|
async addClinic(practitionerId, clinicId) {
|
|
4656
5180
|
var _a;
|
|
4657
5181
|
try {
|
|
4658
|
-
const practitionerRef = (0,
|
|
5182
|
+
const practitionerRef = (0, import_firestore18.doc)(
|
|
4659
5183
|
this.db,
|
|
4660
5184
|
PRACTITIONERS_COLLECTION,
|
|
4661
5185
|
practitionerId
|
|
4662
5186
|
);
|
|
4663
|
-
const practitionerDoc = await (0,
|
|
5187
|
+
const practitionerDoc = await (0, import_firestore18.getDoc)(practitionerRef);
|
|
4664
5188
|
if (!practitionerDoc.exists()) {
|
|
4665
5189
|
throw new Error(`Practitioner ${practitionerId} not found`);
|
|
4666
5190
|
}
|
|
@@ -4671,9 +5195,9 @@ var PractitionerService = class extends BaseService {
|
|
|
4671
5195
|
);
|
|
4672
5196
|
return;
|
|
4673
5197
|
}
|
|
4674
|
-
await (0,
|
|
4675
|
-
clinics: (0,
|
|
4676
|
-
updatedAt: (0,
|
|
5198
|
+
await (0, import_firestore18.updateDoc)(practitionerRef, {
|
|
5199
|
+
clinics: (0, import_firestore18.arrayUnion)(clinicId),
|
|
5200
|
+
updatedAt: (0, import_firestore18.serverTimestamp)()
|
|
4677
5201
|
});
|
|
4678
5202
|
} catch (error) {
|
|
4679
5203
|
console.error(
|
|
@@ -4688,18 +5212,18 @@ var PractitionerService = class extends BaseService {
|
|
|
4688
5212
|
*/
|
|
4689
5213
|
async removeClinic(practitionerId, clinicId) {
|
|
4690
5214
|
try {
|
|
4691
|
-
const practitionerRef = (0,
|
|
5215
|
+
const practitionerRef = (0, import_firestore18.doc)(
|
|
4692
5216
|
this.db,
|
|
4693
5217
|
PRACTITIONERS_COLLECTION,
|
|
4694
5218
|
practitionerId
|
|
4695
5219
|
);
|
|
4696
|
-
const practitionerDoc = await (0,
|
|
5220
|
+
const practitionerDoc = await (0, import_firestore18.getDoc)(practitionerRef);
|
|
4697
5221
|
if (!practitionerDoc.exists()) {
|
|
4698
5222
|
throw new Error(`Practitioner ${practitionerId} not found`);
|
|
4699
5223
|
}
|
|
4700
|
-
await (0,
|
|
4701
|
-
clinics: (0,
|
|
4702
|
-
updatedAt: (0,
|
|
5224
|
+
await (0, import_firestore18.updateDoc)(practitionerRef, {
|
|
5225
|
+
clinics: (0, import_firestore18.arrayRemove)(clinicId),
|
|
5226
|
+
updatedAt: (0, import_firestore18.serverTimestamp)()
|
|
4703
5227
|
});
|
|
4704
5228
|
} catch (error) {
|
|
4705
5229
|
console.error(
|
|
@@ -4733,7 +5257,7 @@ var PractitionerService = class extends BaseService {
|
|
|
4733
5257
|
if (!practitioner) {
|
|
4734
5258
|
throw new Error("Practitioner not found");
|
|
4735
5259
|
}
|
|
4736
|
-
await (0,
|
|
5260
|
+
await (0, import_firestore18.deleteDoc)((0, import_firestore18.doc)(this.db, PRACTITIONERS_COLLECTION, practitionerId));
|
|
4737
5261
|
}
|
|
4738
5262
|
/**
|
|
4739
5263
|
* Validates a registration token and claims the associated draft practitioner profile
|
|
@@ -4802,21 +5326,21 @@ var PractitionerService = class extends BaseService {
|
|
|
4802
5326
|
try {
|
|
4803
5327
|
const constraints = [];
|
|
4804
5328
|
if (!(options == null ? void 0 : options.includeDraftPractitioners)) {
|
|
4805
|
-
constraints.push((0,
|
|
5329
|
+
constraints.push((0, import_firestore18.where)("status", "==", "active" /* ACTIVE */));
|
|
4806
5330
|
}
|
|
4807
|
-
constraints.push((0,
|
|
4808
|
-
constraints.push((0,
|
|
5331
|
+
constraints.push((0, import_firestore18.orderBy)("basicInfo.lastName", "asc"));
|
|
5332
|
+
constraints.push((0, import_firestore18.orderBy)("basicInfo.firstName", "asc"));
|
|
4809
5333
|
if ((options == null ? void 0 : options.pagination) && options.pagination > 0) {
|
|
4810
5334
|
if (options.lastDoc) {
|
|
4811
|
-
constraints.push((0,
|
|
5335
|
+
constraints.push((0, import_firestore18.startAfter)(options.lastDoc));
|
|
4812
5336
|
}
|
|
4813
|
-
constraints.push((0,
|
|
5337
|
+
constraints.push((0, import_firestore18.limit)(options.pagination));
|
|
4814
5338
|
}
|
|
4815
|
-
const q = (0,
|
|
4816
|
-
(0,
|
|
5339
|
+
const q = (0, import_firestore18.query)(
|
|
5340
|
+
(0, import_firestore18.collection)(this.db, PRACTITIONERS_COLLECTION),
|
|
4817
5341
|
...constraints
|
|
4818
5342
|
);
|
|
4819
|
-
const querySnapshot = await (0,
|
|
5343
|
+
const querySnapshot = await (0, import_firestore18.getDocs)(q);
|
|
4820
5344
|
const practitioners = querySnapshot.docs.map(
|
|
4821
5345
|
(doc34) => doc34.data()
|
|
4822
5346
|
);
|
|
@@ -4861,31 +5385,31 @@ var PractitionerService = class extends BaseService {
|
|
|
4861
5385
|
);
|
|
4862
5386
|
const constraints = [];
|
|
4863
5387
|
if (!filters.includeDraftPractitioners) {
|
|
4864
|
-
constraints.push((0,
|
|
5388
|
+
constraints.push((0, import_firestore18.where)("status", "==", "active" /* ACTIVE */));
|
|
4865
5389
|
}
|
|
4866
|
-
constraints.push((0,
|
|
5390
|
+
constraints.push((0, import_firestore18.where)("isActive", "==", true));
|
|
4867
5391
|
if (filters.certifications && filters.certifications.length > 0) {
|
|
4868
5392
|
constraints.push(
|
|
4869
|
-
(0,
|
|
5393
|
+
(0, import_firestore18.where)(
|
|
4870
5394
|
"certification.certifications",
|
|
4871
5395
|
"array-contains-any",
|
|
4872
5396
|
filters.certifications
|
|
4873
5397
|
)
|
|
4874
5398
|
);
|
|
4875
5399
|
}
|
|
4876
|
-
constraints.push((0,
|
|
4877
|
-
constraints.push((0,
|
|
5400
|
+
constraints.push((0, import_firestore18.orderBy)("basicInfo.lastName", "asc"));
|
|
5401
|
+
constraints.push((0, import_firestore18.orderBy)("basicInfo.firstName", "asc"));
|
|
4878
5402
|
if (filters.pagination && filters.pagination > 0) {
|
|
4879
5403
|
if (filters.lastDoc) {
|
|
4880
|
-
constraints.push((0,
|
|
5404
|
+
constraints.push((0, import_firestore18.startAfter)(filters.lastDoc));
|
|
4881
5405
|
}
|
|
4882
|
-
constraints.push((0,
|
|
5406
|
+
constraints.push((0, import_firestore18.limit)(filters.pagination));
|
|
4883
5407
|
}
|
|
4884
|
-
const q = (0,
|
|
4885
|
-
(0,
|
|
5408
|
+
const q = (0, import_firestore18.query)(
|
|
5409
|
+
(0, import_firestore18.collection)(this.db, PRACTITIONERS_COLLECTION),
|
|
4886
5410
|
...constraints
|
|
4887
5411
|
);
|
|
4888
|
-
const querySnapshot = await (0,
|
|
5412
|
+
const querySnapshot = await (0, import_firestore18.getDocs)(q);
|
|
4889
5413
|
console.log(
|
|
4890
5414
|
`[PRACTITIONER_SERVICE] Found ${querySnapshot.docs.length} practitioners with base query`
|
|
4891
5415
|
);
|
|
@@ -5007,11 +5531,11 @@ var UserService = class extends BaseService {
|
|
|
5007
5531
|
email: firebaseUser.email,
|
|
5008
5532
|
roles: roles.length > 0 ? roles : ["patient" /* PATIENT */],
|
|
5009
5533
|
isAnonymous: firebaseUser.isAnonymous,
|
|
5010
|
-
createdAt: (0,
|
|
5011
|
-
updatedAt: (0,
|
|
5012
|
-
lastLoginAt: (0,
|
|
5534
|
+
createdAt: (0, import_firestore19.serverTimestamp)(),
|
|
5535
|
+
updatedAt: (0, import_firestore19.serverTimestamp)(),
|
|
5536
|
+
lastLoginAt: (0, import_firestore19.serverTimestamp)()
|
|
5013
5537
|
};
|
|
5014
|
-
await (0,
|
|
5538
|
+
await (0, import_firestore19.setDoc)((0, import_firestore19.doc)(this.db, USERS_COLLECTION, userData.uid), userData);
|
|
5015
5539
|
if (options == null ? void 0 : options.skipProfileCreation) {
|
|
5016
5540
|
return this.getUserById(userData.uid);
|
|
5017
5541
|
}
|
|
@@ -5020,7 +5544,7 @@ var UserService = class extends BaseService {
|
|
|
5020
5544
|
roles,
|
|
5021
5545
|
options
|
|
5022
5546
|
);
|
|
5023
|
-
await (0,
|
|
5547
|
+
await (0, import_firestore19.updateDoc)((0, import_firestore19.doc)(this.db, USERS_COLLECTION, userData.uid), profiles);
|
|
5024
5548
|
return this.getUserById(userData.uid);
|
|
5025
5549
|
}
|
|
5026
5550
|
/**
|
|
@@ -5098,7 +5622,7 @@ var UserService = class extends BaseService {
|
|
|
5098
5622
|
email: "",
|
|
5099
5623
|
phoneNumber: "",
|
|
5100
5624
|
title: "",
|
|
5101
|
-
dateOfBirth:
|
|
5625
|
+
dateOfBirth: import_firestore19.Timestamp.now(),
|
|
5102
5626
|
gender: "other",
|
|
5103
5627
|
languages: ["Serbian"]
|
|
5104
5628
|
},
|
|
@@ -5107,7 +5631,7 @@ var UserService = class extends BaseService {
|
|
|
5107
5631
|
specialties: [],
|
|
5108
5632
|
licenseNumber: "",
|
|
5109
5633
|
issuingAuthority: "",
|
|
5110
|
-
issueDate:
|
|
5634
|
+
issueDate: import_firestore19.Timestamp.now(),
|
|
5111
5635
|
verificationStatus: "pending"
|
|
5112
5636
|
},
|
|
5113
5637
|
isActive: true,
|
|
@@ -5123,7 +5647,7 @@ var UserService = class extends BaseService {
|
|
|
5123
5647
|
* Dohvata korisnika po ID-u
|
|
5124
5648
|
*/
|
|
5125
5649
|
async getUserById(uid) {
|
|
5126
|
-
const userDoc = await (0,
|
|
5650
|
+
const userDoc = await (0, import_firestore19.getDoc)((0, import_firestore19.doc)(this.db, USERS_COLLECTION, uid));
|
|
5127
5651
|
if (!userDoc.exists()) {
|
|
5128
5652
|
throw USER_ERRORS.NOT_FOUND;
|
|
5129
5653
|
}
|
|
@@ -5134,19 +5658,19 @@ var UserService = class extends BaseService {
|
|
|
5134
5658
|
* Dohvata korisnika po email-u
|
|
5135
5659
|
*/
|
|
5136
5660
|
async getUserByEmail(email) {
|
|
5137
|
-
const usersRef = (0,
|
|
5138
|
-
const q = (0,
|
|
5139
|
-
const querySnapshot = await (0,
|
|
5661
|
+
const usersRef = (0, import_firestore19.collection)(this.db, USERS_COLLECTION);
|
|
5662
|
+
const q = (0, import_firestore19.query)(usersRef, (0, import_firestore19.where)("email", "==", email));
|
|
5663
|
+
const querySnapshot = await (0, import_firestore19.getDocs)(q);
|
|
5140
5664
|
if (querySnapshot.empty) return null;
|
|
5141
5665
|
const userData = querySnapshot.docs[0].data();
|
|
5142
5666
|
return userSchema.parse(userData);
|
|
5143
5667
|
}
|
|
5144
5668
|
async getUsersByRole(role) {
|
|
5145
5669
|
const constraints = [
|
|
5146
|
-
(0,
|
|
5670
|
+
(0, import_firestore19.where)("roles", "array-contains", role)
|
|
5147
5671
|
];
|
|
5148
|
-
const q = (0,
|
|
5149
|
-
const querySnapshot = await (0,
|
|
5672
|
+
const q = (0, import_firestore19.query)((0, import_firestore19.collection)(this.db, USERS_COLLECTION), ...constraints);
|
|
5673
|
+
const querySnapshot = await (0, import_firestore19.getDocs)(q);
|
|
5150
5674
|
const users = querySnapshot.docs.map((doc34) => doc34.data());
|
|
5151
5675
|
return Promise.all(users.map((userData) => userSchema.parse(userData)));
|
|
5152
5676
|
}
|
|
@@ -5154,33 +5678,33 @@ var UserService = class extends BaseService {
|
|
|
5154
5678
|
* Ažurira timestamp poslednjeg logovanja
|
|
5155
5679
|
*/
|
|
5156
5680
|
async updateUserLoginTimestamp(uid) {
|
|
5157
|
-
const userRef = (0,
|
|
5158
|
-
const userDoc = await (0,
|
|
5681
|
+
const userRef = (0, import_firestore19.doc)(this.db, USERS_COLLECTION, uid);
|
|
5682
|
+
const userDoc = await (0, import_firestore19.getDoc)(userRef);
|
|
5159
5683
|
if (!userDoc.exists()) {
|
|
5160
5684
|
throw AUTH_ERRORS.USER_NOT_FOUND;
|
|
5161
5685
|
}
|
|
5162
|
-
await (0,
|
|
5163
|
-
lastLoginAt: (0,
|
|
5164
|
-
updatedAt: (0,
|
|
5686
|
+
await (0, import_firestore19.updateDoc)(userRef, {
|
|
5687
|
+
lastLoginAt: (0, import_firestore19.serverTimestamp)(),
|
|
5688
|
+
updatedAt: (0, import_firestore19.serverTimestamp)()
|
|
5165
5689
|
});
|
|
5166
5690
|
return this.getUserById(uid);
|
|
5167
5691
|
}
|
|
5168
5692
|
async upgradeAnonymousUser(uid, email) {
|
|
5169
|
-
const userRef = (0,
|
|
5170
|
-
const userDoc = await (0,
|
|
5693
|
+
const userRef = (0, import_firestore19.doc)(this.db, USERS_COLLECTION, uid);
|
|
5694
|
+
const userDoc = await (0, import_firestore19.getDoc)(userRef);
|
|
5171
5695
|
if (!userDoc.exists()) {
|
|
5172
5696
|
throw USER_ERRORS.NOT_FOUND;
|
|
5173
5697
|
}
|
|
5174
|
-
await (0,
|
|
5698
|
+
await (0, import_firestore19.updateDoc)(userRef, {
|
|
5175
5699
|
email,
|
|
5176
5700
|
isAnonymous: false,
|
|
5177
|
-
updatedAt: (0,
|
|
5701
|
+
updatedAt: (0, import_firestore19.serverTimestamp)()
|
|
5178
5702
|
});
|
|
5179
5703
|
return this.getUserById(uid);
|
|
5180
5704
|
}
|
|
5181
5705
|
async updateUser(uid, updates) {
|
|
5182
|
-
const userRef = (0,
|
|
5183
|
-
const userDoc = await (0,
|
|
5706
|
+
const userRef = (0, import_firestore19.doc)(this.db, USERS_COLLECTION, uid);
|
|
5707
|
+
const userDoc = await (0, import_firestore19.getDoc)(userRef);
|
|
5184
5708
|
if (!userDoc.exists()) {
|
|
5185
5709
|
throw USER_ERRORS.NOT_FOUND;
|
|
5186
5710
|
}
|
|
@@ -5189,12 +5713,12 @@ var UserService = class extends BaseService {
|
|
|
5189
5713
|
const updatedUser = {
|
|
5190
5714
|
...currentUser,
|
|
5191
5715
|
...updates,
|
|
5192
|
-
updatedAt: (0,
|
|
5716
|
+
updatedAt: (0, import_firestore19.serverTimestamp)()
|
|
5193
5717
|
};
|
|
5194
5718
|
userSchema.parse(updatedUser);
|
|
5195
|
-
await (0,
|
|
5719
|
+
await (0, import_firestore19.updateDoc)(userRef, {
|
|
5196
5720
|
...updates,
|
|
5197
|
-
updatedAt: (0,
|
|
5721
|
+
updatedAt: (0, import_firestore19.serverTimestamp)()
|
|
5198
5722
|
});
|
|
5199
5723
|
return this.getUserById(uid);
|
|
5200
5724
|
} catch (error) {
|
|
@@ -5211,10 +5735,10 @@ var UserService = class extends BaseService {
|
|
|
5211
5735
|
const user = await this.getUserById(uid);
|
|
5212
5736
|
if (user.roles.includes(role)) return;
|
|
5213
5737
|
const profiles = await this.createProfilesForRoles(uid, [role], options);
|
|
5214
|
-
await (0,
|
|
5738
|
+
await (0, import_firestore19.updateDoc)((0, import_firestore19.doc)(this.db, USERS_COLLECTION, uid), {
|
|
5215
5739
|
roles: [...user.roles, role],
|
|
5216
5740
|
...profiles,
|
|
5217
|
-
updatedAt: (0,
|
|
5741
|
+
updatedAt: (0, import_firestore19.serverTimestamp)()
|
|
5218
5742
|
});
|
|
5219
5743
|
}
|
|
5220
5744
|
/**
|
|
@@ -5246,15 +5770,15 @@ var UserService = class extends BaseService {
|
|
|
5246
5770
|
}
|
|
5247
5771
|
break;
|
|
5248
5772
|
}
|
|
5249
|
-
await (0,
|
|
5773
|
+
await (0, import_firestore19.updateDoc)((0, import_firestore19.doc)(this.db, USERS_COLLECTION, uid), {
|
|
5250
5774
|
roles: user.roles.filter((r) => r !== role),
|
|
5251
|
-
updatedAt: (0,
|
|
5775
|
+
updatedAt: (0, import_firestore19.serverTimestamp)()
|
|
5252
5776
|
});
|
|
5253
5777
|
}
|
|
5254
5778
|
// Delete operations
|
|
5255
5779
|
async deleteUser(uid) {
|
|
5256
|
-
const userRef = (0,
|
|
5257
|
-
const userDoc = await (0,
|
|
5780
|
+
const userRef = (0, import_firestore19.doc)(this.db, USERS_COLLECTION, uid);
|
|
5781
|
+
const userDoc = await (0, import_firestore19.getDoc)(userRef);
|
|
5258
5782
|
if (!userDoc.exists()) {
|
|
5259
5783
|
throw USER_ERRORS.NOT_FOUND;
|
|
5260
5784
|
}
|
|
@@ -5275,7 +5799,7 @@ var UserService = class extends BaseService {
|
|
|
5275
5799
|
userData.adminProfile
|
|
5276
5800
|
);
|
|
5277
5801
|
}
|
|
5278
|
-
await (0,
|
|
5802
|
+
await (0, import_firestore19.deleteDoc)(userRef);
|
|
5279
5803
|
} catch (error) {
|
|
5280
5804
|
throw error;
|
|
5281
5805
|
}
|
|
@@ -5283,7 +5807,7 @@ var UserService = class extends BaseService {
|
|
|
5283
5807
|
};
|
|
5284
5808
|
|
|
5285
5809
|
// src/services/clinic/utils/clinic-group.utils.ts
|
|
5286
|
-
var
|
|
5810
|
+
var import_firestore20 = require("firebase/firestore");
|
|
5287
5811
|
var import_geofire_common3 = require("geofire-common");
|
|
5288
5812
|
var import_zod17 = require("zod");
|
|
5289
5813
|
|
|
@@ -5400,9 +5924,9 @@ async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdm
|
|
|
5400
5924
|
throw geohashError;
|
|
5401
5925
|
}
|
|
5402
5926
|
}
|
|
5403
|
-
const now =
|
|
5927
|
+
const now = import_firestore20.Timestamp.now();
|
|
5404
5928
|
console.log("[CLINIC_GROUP] Preparing clinic group data object");
|
|
5405
|
-
const groupId = (0,
|
|
5929
|
+
const groupId = (0, import_firestore20.doc)((0, import_firestore20.collection)(db, CLINIC_GROUPS_COLLECTION)).id;
|
|
5406
5930
|
console.log("[CLINIC_GROUP] Logo value:", {
|
|
5407
5931
|
logoValue: validatedData.logo,
|
|
5408
5932
|
logoType: validatedData.logo === null ? "null" : typeof validatedData.logo
|
|
@@ -5452,7 +5976,7 @@ async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdm
|
|
|
5452
5976
|
groupId: groupData.id
|
|
5453
5977
|
});
|
|
5454
5978
|
try {
|
|
5455
|
-
await (0,
|
|
5979
|
+
await (0, import_firestore20.setDoc)((0, import_firestore20.doc)(db, CLINIC_GROUPS_COLLECTION, groupData.id), groupData);
|
|
5456
5980
|
console.log("[CLINIC_GROUP] Clinic group saved successfully");
|
|
5457
5981
|
} catch (firestoreError) {
|
|
5458
5982
|
console.error(
|
|
@@ -5498,19 +6022,19 @@ async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdm
|
|
|
5498
6022
|
}
|
|
5499
6023
|
}
|
|
5500
6024
|
async function getClinicGroup(db, groupId) {
|
|
5501
|
-
const docRef = (0,
|
|
5502
|
-
const docSnap = await (0,
|
|
6025
|
+
const docRef = (0, import_firestore20.doc)(db, CLINIC_GROUPS_COLLECTION, groupId);
|
|
6026
|
+
const docSnap = await (0, import_firestore20.getDoc)(docRef);
|
|
5503
6027
|
if (docSnap.exists()) {
|
|
5504
6028
|
return docSnap.data();
|
|
5505
6029
|
}
|
|
5506
6030
|
return null;
|
|
5507
6031
|
}
|
|
5508
6032
|
async function getAllActiveGroups(db) {
|
|
5509
|
-
const q = (0,
|
|
5510
|
-
(0,
|
|
5511
|
-
(0,
|
|
6033
|
+
const q = (0, import_firestore20.query)(
|
|
6034
|
+
(0, import_firestore20.collection)(db, CLINIC_GROUPS_COLLECTION),
|
|
6035
|
+
(0, import_firestore20.where)("isActive", "==", true)
|
|
5512
6036
|
);
|
|
5513
|
-
const querySnapshot = await (0,
|
|
6037
|
+
const querySnapshot = await (0, import_firestore20.getDocs)(q);
|
|
5514
6038
|
return querySnapshot.docs.map((doc34) => doc34.data());
|
|
5515
6039
|
}
|
|
5516
6040
|
async function updateClinicGroup(db, groupId, data, app) {
|
|
@@ -5539,10 +6063,10 @@ async function updateClinicGroup(db, groupId, data, app) {
|
|
|
5539
6063
|
}
|
|
5540
6064
|
updatedData = {
|
|
5541
6065
|
...updatedData,
|
|
5542
|
-
updatedAt:
|
|
6066
|
+
updatedAt: import_firestore20.Timestamp.now()
|
|
5543
6067
|
};
|
|
5544
6068
|
console.log("[CLINIC_GROUP] Updating clinic group in Firestore");
|
|
5545
|
-
await (0,
|
|
6069
|
+
await (0, import_firestore20.updateDoc)((0, import_firestore20.doc)(db, CLINIC_GROUPS_COLLECTION, groupId), updatedData);
|
|
5546
6070
|
console.log("[CLINIC_GROUP] Clinic group updated successfully");
|
|
5547
6071
|
const updatedGroup = await getClinicGroup(db, groupId);
|
|
5548
6072
|
if (!updatedGroup) {
|
|
@@ -5623,10 +6147,10 @@ async function createAdminToken(db, groupId, creatorAdminId, app, data) {
|
|
|
5623
6147
|
if (!group.admins.includes(creatorAdminId)) {
|
|
5624
6148
|
throw new Error("Admin does not belong to this clinic group");
|
|
5625
6149
|
}
|
|
5626
|
-
const now =
|
|
6150
|
+
const now = import_firestore20.Timestamp.now();
|
|
5627
6151
|
const expiresInDays = (data == null ? void 0 : data.expiresInDays) || 7;
|
|
5628
6152
|
const email = (data == null ? void 0 : data.email) || null;
|
|
5629
|
-
const expiresAt = new
|
|
6153
|
+
const expiresAt = new import_firestore20.Timestamp(
|
|
5630
6154
|
now.seconds + expiresInDays * 24 * 60 * 60,
|
|
5631
6155
|
now.nanoseconds
|
|
5632
6156
|
);
|
|
@@ -5660,7 +6184,7 @@ async function verifyAndUseAdminToken(db, groupId, token, userRef, app) {
|
|
|
5660
6184
|
if (adminToken.status !== "active" /* ACTIVE */) {
|
|
5661
6185
|
throw new Error("Admin token is not active");
|
|
5662
6186
|
}
|
|
5663
|
-
const now =
|
|
6187
|
+
const now = import_firestore20.Timestamp.now();
|
|
5664
6188
|
if (adminToken.expiresAt.seconds < now.seconds) {
|
|
5665
6189
|
const updatedTokens2 = group.adminTokens.map(
|
|
5666
6190
|
(t) => t.id === adminToken.id ? { ...t, status: "expired" /* EXPIRED */ } : t
|
|
@@ -5933,24 +6457,24 @@ var import_geofire_common7 = require("geofire-common");
|
|
|
5933
6457
|
var import_zod19 = require("zod");
|
|
5934
6458
|
|
|
5935
6459
|
// src/services/clinic/utils/clinic.utils.ts
|
|
5936
|
-
var
|
|
6460
|
+
var import_firestore21 = require("firebase/firestore");
|
|
5937
6461
|
var import_geofire_common4 = require("geofire-common");
|
|
5938
6462
|
var import_zod18 = require("zod");
|
|
5939
6463
|
async function getClinic(db, clinicId) {
|
|
5940
|
-
const docRef = (0,
|
|
5941
|
-
const docSnap = await (0,
|
|
6464
|
+
const docRef = (0, import_firestore21.doc)(db, CLINICS_COLLECTION, clinicId);
|
|
6465
|
+
const docSnap = await (0, import_firestore21.getDoc)(docRef);
|
|
5942
6466
|
if (docSnap.exists()) {
|
|
5943
6467
|
return docSnap.data();
|
|
5944
6468
|
}
|
|
5945
6469
|
return null;
|
|
5946
6470
|
}
|
|
5947
6471
|
async function getClinicsByGroup(db, groupId) {
|
|
5948
|
-
const q = (0,
|
|
5949
|
-
(0,
|
|
5950
|
-
(0,
|
|
5951
|
-
(0,
|
|
6472
|
+
const q = (0, import_firestore21.query)(
|
|
6473
|
+
(0, import_firestore21.collection)(db, CLINICS_COLLECTION),
|
|
6474
|
+
(0, import_firestore21.where)("clinicGroupId", "==", groupId),
|
|
6475
|
+
(0, import_firestore21.where)("isActive", "==", true)
|
|
5952
6476
|
);
|
|
5953
|
-
const querySnapshot = await (0,
|
|
6477
|
+
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
5954
6478
|
return querySnapshot.docs.map((doc34) => doc34.data());
|
|
5955
6479
|
}
|
|
5956
6480
|
async function updateClinic(db, clinicId, data, adminId, clinicAdminService, app) {
|
|
@@ -6106,11 +6630,11 @@ async function updateClinic(db, clinicId, data, adminId, clinicAdminService, app
|
|
|
6106
6630
|
}
|
|
6107
6631
|
updatedData = {
|
|
6108
6632
|
...updatedData,
|
|
6109
|
-
updatedAt:
|
|
6633
|
+
updatedAt: import_firestore21.Timestamp.now()
|
|
6110
6634
|
};
|
|
6111
6635
|
console.log("[CLINIC] Updating clinic in Firestore");
|
|
6112
6636
|
try {
|
|
6113
|
-
await (0,
|
|
6637
|
+
await (0, import_firestore21.updateDoc)((0, import_firestore21.doc)(db, CLINICS_COLLECTION, clinicId), updatedData);
|
|
6114
6638
|
console.log("[CLINIC] Clinic updated successfully");
|
|
6115
6639
|
} catch (updateError) {
|
|
6116
6640
|
console.error("[CLINIC] Error updating clinic in Firestore:", updateError);
|
|
@@ -6139,12 +6663,12 @@ async function getClinicsByAdmin(db, adminId, options = {}, clinicAdminService,
|
|
|
6139
6663
|
if (clinicIds.length === 0) {
|
|
6140
6664
|
return [];
|
|
6141
6665
|
}
|
|
6142
|
-
const constraints = [(0,
|
|
6666
|
+
const constraints = [(0, import_firestore21.where)("id", "in", clinicIds)];
|
|
6143
6667
|
if (options.isActive !== void 0) {
|
|
6144
|
-
constraints.push((0,
|
|
6668
|
+
constraints.push((0, import_firestore21.where)("isActive", "==", options.isActive));
|
|
6145
6669
|
}
|
|
6146
|
-
const q = (0,
|
|
6147
|
-
const querySnapshot = await (0,
|
|
6670
|
+
const q = (0, import_firestore21.query)((0, import_firestore21.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
6671
|
+
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
6148
6672
|
return querySnapshot.docs.map((doc34) => doc34.data());
|
|
6149
6673
|
}
|
|
6150
6674
|
async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGroupService) {
|
|
@@ -6158,8 +6682,8 @@ async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGr
|
|
|
6158
6682
|
}
|
|
6159
6683
|
async function getClinicById(db, clinicId) {
|
|
6160
6684
|
try {
|
|
6161
|
-
const clinicRef = (0,
|
|
6162
|
-
const clinicSnapshot = await (0,
|
|
6685
|
+
const clinicRef = (0, import_firestore21.doc)(db, CLINICS_COLLECTION, clinicId);
|
|
6686
|
+
const clinicSnapshot = await (0, import_firestore21.getDoc)(clinicRef);
|
|
6163
6687
|
if (!clinicSnapshot.exists()) {
|
|
6164
6688
|
return null;
|
|
6165
6689
|
}
|
|
@@ -6175,20 +6699,20 @@ async function getClinicById(db, clinicId) {
|
|
|
6175
6699
|
}
|
|
6176
6700
|
async function getAllClinics(db, pagination, lastDoc) {
|
|
6177
6701
|
try {
|
|
6178
|
-
const clinicsCollection = (0,
|
|
6179
|
-
let clinicsQuery = (0,
|
|
6702
|
+
const clinicsCollection = (0, import_firestore21.collection)(db, CLINICS_COLLECTION);
|
|
6703
|
+
let clinicsQuery = (0, import_firestore21.query)(clinicsCollection);
|
|
6180
6704
|
if (pagination && pagination > 0) {
|
|
6181
6705
|
if (lastDoc) {
|
|
6182
|
-
clinicsQuery = (0,
|
|
6706
|
+
clinicsQuery = (0, import_firestore21.query)(
|
|
6183
6707
|
clinicsCollection,
|
|
6184
|
-
(0,
|
|
6185
|
-
(0,
|
|
6708
|
+
(0, import_firestore21.startAfter)(lastDoc),
|
|
6709
|
+
(0, import_firestore21.limit)(pagination)
|
|
6186
6710
|
);
|
|
6187
6711
|
} else {
|
|
6188
|
-
clinicsQuery = (0,
|
|
6712
|
+
clinicsQuery = (0, import_firestore21.query)(clinicsCollection, (0, import_firestore21.limit)(pagination));
|
|
6189
6713
|
}
|
|
6190
6714
|
}
|
|
6191
|
-
const clinicsSnapshot = await (0,
|
|
6715
|
+
const clinicsSnapshot = await (0, import_firestore21.getDocs)(clinicsQuery);
|
|
6192
6716
|
const lastVisible = clinicsSnapshot.docs[clinicsSnapshot.docs.length - 1];
|
|
6193
6717
|
const clinics = clinicsSnapshot.docs.map((doc34) => {
|
|
6194
6718
|
const data = doc34.data();
|
|
@@ -6215,12 +6739,12 @@ async function getAllClinicsInRange(db, center, rangeInKm, pagination, lastDoc)
|
|
|
6215
6739
|
let lastDocSnapshot = null;
|
|
6216
6740
|
for (const b of bounds) {
|
|
6217
6741
|
const constraints = [
|
|
6218
|
-
(0,
|
|
6219
|
-
(0,
|
|
6220
|
-
(0,
|
|
6742
|
+
(0, import_firestore21.where)("location.geohash", ">=", b[0]),
|
|
6743
|
+
(0, import_firestore21.where)("location.geohash", "<=", b[1]),
|
|
6744
|
+
(0, import_firestore21.where)("isActive", "==", true)
|
|
6221
6745
|
];
|
|
6222
|
-
const q = (0,
|
|
6223
|
-
const querySnapshot = await (0,
|
|
6746
|
+
const q = (0, import_firestore21.query)((0, import_firestore21.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
6747
|
+
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
6224
6748
|
for (const doc34 of querySnapshot.docs) {
|
|
6225
6749
|
const clinic = doc34.data();
|
|
6226
6750
|
const distance = (0, import_geofire_common4.distanceBetween)(
|
|
@@ -6315,7 +6839,7 @@ async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminServic
|
|
|
6315
6839
|
}
|
|
6316
6840
|
|
|
6317
6841
|
// src/services/clinic/utils/search.utils.ts
|
|
6318
|
-
var
|
|
6842
|
+
var import_firestore22 = require("firebase/firestore");
|
|
6319
6843
|
var import_geofire_common5 = require("geofire-common");
|
|
6320
6844
|
async function findClinicsInRadius(db, center, radiusInKm, filters) {
|
|
6321
6845
|
const bounds = (0, import_geofire_common5.geohashQueryBounds)(
|
|
@@ -6325,20 +6849,20 @@ async function findClinicsInRadius(db, center, radiusInKm, filters) {
|
|
|
6325
6849
|
const matchingDocs = [];
|
|
6326
6850
|
for (const b of bounds) {
|
|
6327
6851
|
const constraints = [
|
|
6328
|
-
(0,
|
|
6329
|
-
(0,
|
|
6330
|
-
(0,
|
|
6852
|
+
(0, import_firestore22.where)("location.geohash", ">=", b[0]),
|
|
6853
|
+
(0, import_firestore22.where)("location.geohash", "<=", b[1]),
|
|
6854
|
+
(0, import_firestore22.where)("isActive", "==", true)
|
|
6331
6855
|
];
|
|
6332
6856
|
if (filters == null ? void 0 : filters.services) {
|
|
6333
6857
|
constraints.push(
|
|
6334
|
-
(0,
|
|
6858
|
+
(0, import_firestore22.where)("services", "array-contains-any", filters.services)
|
|
6335
6859
|
);
|
|
6336
6860
|
}
|
|
6337
6861
|
if ((filters == null ? void 0 : filters.tags) && filters.tags.length > 0) {
|
|
6338
|
-
constraints.push((0,
|
|
6862
|
+
constraints.push((0, import_firestore22.where)("tags", "array-contains-any", filters.tags));
|
|
6339
6863
|
}
|
|
6340
|
-
const q = (0,
|
|
6341
|
-
const querySnapshot = await (0,
|
|
6864
|
+
const q = (0, import_firestore22.query)((0, import_firestore22.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
6865
|
+
const querySnapshot = await (0, import_firestore22.getDocs)(q);
|
|
6342
6866
|
for (const doc34 of querySnapshot.docs) {
|
|
6343
6867
|
const clinic = doc34.data();
|
|
6344
6868
|
const distance = (0, import_geofire_common5.distanceBetween)(
|
|
@@ -6365,7 +6889,7 @@ async function findClinicsInRadius(db, center, radiusInKm, filters) {
|
|
|
6365
6889
|
}
|
|
6366
6890
|
|
|
6367
6891
|
// src/services/clinic/utils/filter.utils.ts
|
|
6368
|
-
var
|
|
6892
|
+
var import_firestore23 = require("firebase/firestore");
|
|
6369
6893
|
var import_geofire_common6 = require("geofire-common");
|
|
6370
6894
|
async function getClinicsByFilters(db, filters) {
|
|
6371
6895
|
console.log(
|
|
@@ -6375,460 +6899,162 @@ async function getClinicsByFilters(db, filters) {
|
|
|
6375
6899
|
const isGeoQuery = filters.center && filters.radiusInKm && filters.radiusInKm > 0;
|
|
6376
6900
|
const constraints = [];
|
|
6377
6901
|
if (filters.isActive !== void 0) {
|
|
6378
|
-
constraints.push((0,
|
|
6902
|
+
constraints.push((0, import_firestore23.where)("isActive", "==", filters.isActive));
|
|
6379
6903
|
} else {
|
|
6380
|
-
constraints.push((0,
|
|
6904
|
+
constraints.push((0, import_firestore23.where)("isActive", "==", true));
|
|
6381
6905
|
}
|
|
6382
6906
|
if (filters.tags && filters.tags.length > 0) {
|
|
6383
|
-
constraints.push((0,
|
|
6907
|
+
constraints.push((0, import_firestore23.where)("tags", "array-contains", filters.tags[0]));
|
|
6384
6908
|
}
|
|
6385
6909
|
if (filters.procedureTechnology) {
|
|
6386
6910
|
constraints.push(
|
|
6387
|
-
(0,
|
|
6911
|
+
(0, import_firestore23.where)("servicesInfo.technology", "==", filters.procedureTechnology)
|
|
6388
6912
|
);
|
|
6389
6913
|
} else if (filters.procedureSubcategory) {
|
|
6390
6914
|
constraints.push(
|
|
6391
|
-
(0,
|
|
6915
|
+
(0, import_firestore23.where)("servicesInfo.subCategory", "==", filters.procedureSubcategory)
|
|
6392
6916
|
);
|
|
6393
6917
|
} else if (filters.procedureCategory) {
|
|
6394
6918
|
constraints.push(
|
|
6395
|
-
(0,
|
|
6919
|
+
(0, import_firestore23.where)("servicesInfo.category", "==", filters.procedureCategory)
|
|
6396
6920
|
);
|
|
6397
6921
|
} else if (filters.procedureFamily) {
|
|
6398
6922
|
constraints.push(
|
|
6399
|
-
(0,
|
|
6923
|
+
(0, import_firestore23.where)("servicesInfo.procedureFamily", "==", filters.procedureFamily)
|
|
6400
6924
|
);
|
|
6401
6925
|
}
|
|
6402
6926
|
if (filters.pagination && filters.pagination > 0 && filters.lastDoc) {
|
|
6403
|
-
constraints.push((0,
|
|
6404
|
-
constraints.push((0,
|
|
6927
|
+
constraints.push((0, import_firestore23.startAfter)(filters.lastDoc));
|
|
6928
|
+
constraints.push((0, import_firestore23.limit)(filters.pagination));
|
|
6405
6929
|
} else if (filters.pagination && filters.pagination > 0) {
|
|
6406
|
-
constraints.push((0,
|
|
6930
|
+
constraints.push((0, import_firestore23.limit)(filters.pagination));
|
|
6407
6931
|
}
|
|
6408
|
-
constraints.push((0,
|
|
6932
|
+
constraints.push((0, import_firestore23.orderBy)("location.geohash"));
|
|
6409
6933
|
let clinicsResult = [];
|
|
6410
6934
|
let lastVisibleDoc = null;
|
|
6411
6935
|
if (isGeoQuery) {
|
|
6412
6936
|
const center = filters.center;
|
|
6413
6937
|
const radiusInKm = filters.radiusInKm;
|
|
6414
6938
|
const bounds = (0, import_geofire_common6.geohashQueryBounds)(
|
|
6415
|
-
[center.latitude, center.longitude],
|
|
6416
|
-
radiusInKm * 1e3
|
|
6417
|
-
// Convert to meters
|
|
6418
|
-
);
|
|
6419
|
-
const matchingClinics = [];
|
|
6420
|
-
for (const bound of bounds) {
|
|
6421
|
-
const geoConstraints = [
|
|
6422
|
-
...constraints,
|
|
6423
|
-
(0, import_firestore21.where)("location.geohash", ">=", bound[0]),
|
|
6424
|
-
(0, import_firestore21.where)("location.geohash", "<=", bound[1])
|
|
6425
|
-
];
|
|
6426
|
-
const q = (0, import_firestore21.query)((0, import_firestore21.collection)(db, CLINICS_COLLECTION), ...geoConstraints);
|
|
6427
|
-
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
6428
|
-
console.log(
|
|
6429
|
-
`[FILTER_UTILS] Found ${querySnapshot.docs.length} clinics in geo bound`
|
|
6430
|
-
);
|
|
6431
|
-
for (const doc34 of querySnapshot.docs) {
|
|
6432
|
-
const clinic = { ...doc34.data(), id: doc34.id };
|
|
6433
|
-
const distance = (0, import_geofire_common6.distanceBetween)(
|
|
6434
|
-
[center.latitude, center.longitude],
|
|
6435
|
-
[clinic.location.latitude, clinic.location.longitude]
|
|
6436
|
-
);
|
|
6437
|
-
const distanceInKm = distance / 1e3;
|
|
6438
|
-
if (distanceInKm <= radiusInKm) {
|
|
6439
|
-
matchingClinics.push({
|
|
6440
|
-
...clinic,
|
|
6441
|
-
distance: distanceInKm
|
|
6442
|
-
});
|
|
6443
|
-
}
|
|
6444
|
-
}
|
|
6445
|
-
}
|
|
6446
|
-
let filteredClinics = matchingClinics;
|
|
6447
|
-
if (filters.tags && filters.tags.length > 1) {
|
|
6448
|
-
filteredClinics = filteredClinics.filter((clinic) => {
|
|
6449
|
-
return filters.tags.every((tag) => clinic.tags.includes(tag));
|
|
6450
|
-
});
|
|
6451
|
-
}
|
|
6452
|
-
if (filters.minRating !== void 0) {
|
|
6453
|
-
filteredClinics = filteredClinics.filter(
|
|
6454
|
-
(clinic) => clinic.reviewInfo.averageRating >= filters.minRating
|
|
6455
|
-
);
|
|
6456
|
-
}
|
|
6457
|
-
if (filters.maxRating !== void 0) {
|
|
6458
|
-
filteredClinics = filteredClinics.filter(
|
|
6459
|
-
(clinic) => clinic.reviewInfo.averageRating <= filters.maxRating
|
|
6460
|
-
);
|
|
6461
|
-
}
|
|
6462
|
-
filteredClinics.sort((a, b) => a.distance - b.distance);
|
|
6463
|
-
if (filters.pagination && filters.pagination > 0) {
|
|
6464
|
-
let startIndex = 0;
|
|
6465
|
-
if (filters.lastDoc) {
|
|
6466
|
-
const lastDocIndex = filteredClinics.findIndex(
|
|
6467
|
-
(clinic) => clinic.id === filters.lastDoc.id
|
|
6468
|
-
);
|
|
6469
|
-
if (lastDocIndex !== -1) {
|
|
6470
|
-
startIndex = lastDocIndex + 1;
|
|
6471
|
-
}
|
|
6472
|
-
}
|
|
6473
|
-
const paginatedClinics = filteredClinics.slice(
|
|
6474
|
-
startIndex,
|
|
6475
|
-
startIndex + filters.pagination
|
|
6476
|
-
);
|
|
6477
|
-
lastVisibleDoc = paginatedClinics.length > 0 ? paginatedClinics[paginatedClinics.length - 1] : null;
|
|
6478
|
-
clinicsResult = paginatedClinics;
|
|
6479
|
-
} else {
|
|
6480
|
-
clinicsResult = filteredClinics;
|
|
6481
|
-
}
|
|
6482
|
-
} else {
|
|
6483
|
-
const q = (0, import_firestore21.query)((0, import_firestore21.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
6484
|
-
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
6485
|
-
console.log(
|
|
6486
|
-
`[FILTER_UTILS] Found ${querySnapshot.docs.length} clinics with regular query`
|
|
6487
|
-
);
|
|
6488
|
-
const clinics = querySnapshot.docs.map((doc34) => {
|
|
6489
|
-
return { ...doc34.data(), id: doc34.id };
|
|
6490
|
-
});
|
|
6491
|
-
let filteredClinics = clinics;
|
|
6492
|
-
if (filters.center) {
|
|
6493
|
-
const center = filters.center;
|
|
6494
|
-
const clinicsWithDistance = [];
|
|
6495
|
-
filteredClinics.forEach((clinic) => {
|
|
6496
|
-
const distance = (0, import_geofire_common6.distanceBetween)(
|
|
6497
|
-
[center.latitude, center.longitude],
|
|
6498
|
-
[clinic.location.latitude, clinic.location.longitude]
|
|
6499
|
-
);
|
|
6500
|
-
clinicsWithDistance.push({
|
|
6501
|
-
...clinic,
|
|
6502
|
-
distance: distance / 1e3
|
|
6503
|
-
// Convert to kilometers
|
|
6504
|
-
});
|
|
6505
|
-
});
|
|
6506
|
-
filteredClinics = clinicsWithDistance;
|
|
6507
|
-
filteredClinics.sort(
|
|
6508
|
-
(a, b) => a.distance - b.distance
|
|
6509
|
-
);
|
|
6510
|
-
}
|
|
6511
|
-
if (filters.tags && filters.tags.length > 1) {
|
|
6512
|
-
filteredClinics = filteredClinics.filter((clinic) => {
|
|
6513
|
-
return filters.tags.every((tag) => clinic.tags.includes(tag));
|
|
6514
|
-
});
|
|
6515
|
-
}
|
|
6516
|
-
if (filters.minRating !== void 0) {
|
|
6517
|
-
filteredClinics = filteredClinics.filter(
|
|
6518
|
-
(clinic) => clinic.reviewInfo.averageRating >= filters.minRating
|
|
6519
|
-
);
|
|
6520
|
-
}
|
|
6521
|
-
if (filters.maxRating !== void 0) {
|
|
6522
|
-
filteredClinics = filteredClinics.filter(
|
|
6523
|
-
(clinic) => clinic.reviewInfo.averageRating <= filters.maxRating
|
|
6524
|
-
);
|
|
6525
|
-
}
|
|
6526
|
-
lastVisibleDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
6527
|
-
clinicsResult = filteredClinics;
|
|
6528
|
-
}
|
|
6529
|
-
return {
|
|
6530
|
-
clinics: clinicsResult,
|
|
6531
|
-
lastDoc: lastVisibleDoc
|
|
6532
|
-
};
|
|
6533
|
-
}
|
|
6534
|
-
|
|
6535
|
-
// src/services/media/media.service.ts
|
|
6536
|
-
var import_firestore22 = require("firebase/firestore");
|
|
6537
|
-
var import_storage5 = require("firebase/storage");
|
|
6538
|
-
var import_firestore23 = require("firebase/firestore");
|
|
6539
|
-
var MediaAccessLevel = /* @__PURE__ */ ((MediaAccessLevel2) => {
|
|
6540
|
-
MediaAccessLevel2["PUBLIC"] = "public";
|
|
6541
|
-
MediaAccessLevel2["PRIVATE"] = "private";
|
|
6542
|
-
MediaAccessLevel2["CONFIDENTIAL"] = "confidential";
|
|
6543
|
-
return MediaAccessLevel2;
|
|
6544
|
-
})(MediaAccessLevel || {});
|
|
6545
|
-
var MEDIA_METADATA_COLLECTION = "media_metadata";
|
|
6546
|
-
var MediaService = class extends BaseService {
|
|
6547
|
-
constructor(db, auth, app) {
|
|
6548
|
-
super(db, auth, app);
|
|
6549
|
-
}
|
|
6550
|
-
/**
|
|
6551
|
-
* Upload a media file, store its metadata, and return the metadata including the URL.
|
|
6552
|
-
* @param file - The file to upload.
|
|
6553
|
-
* @param ownerId - ID of the owner (user, patient, clinic, etc.).
|
|
6554
|
-
* @param accessLevel - Access level (public, private, confidential).
|
|
6555
|
-
* @param collectionName - The logical collection name this media belongs to (e.g., 'patient_profile_pictures', 'clinic_logos').
|
|
6556
|
-
* @param originalFileName - Optional: the original name of the file, if not using file.name.
|
|
6557
|
-
* @returns Promise with the media metadata.
|
|
6558
|
-
*/
|
|
6559
|
-
async uploadMedia(file, ownerId, accessLevel, collectionName, originalFileName) {
|
|
6560
|
-
const mediaId = this.generateId();
|
|
6561
|
-
const fileNameToUse = originalFileName || (file instanceof File ? file.name : file.toString());
|
|
6562
|
-
const uniqueFileName = `${mediaId}-${fileNameToUse}`;
|
|
6563
|
-
const filePath = `media/${accessLevel}/${ownerId}/${collectionName}/${uniqueFileName}`;
|
|
6564
|
-
console.log(`[MediaService] Uploading file to: ${filePath}`);
|
|
6565
|
-
const storageRef = (0, import_storage5.ref)(this.storage, filePath);
|
|
6566
|
-
try {
|
|
6567
|
-
const uploadResult = await (0, import_storage5.uploadBytes)(storageRef, file, {
|
|
6568
|
-
contentType: file.type
|
|
6569
|
-
});
|
|
6570
|
-
console.log("[MediaService] File uploaded successfully", uploadResult);
|
|
6571
|
-
const downloadURL = await (0, import_storage5.getDownloadURL)(uploadResult.ref);
|
|
6572
|
-
console.log("[MediaService] Got download URL:", downloadURL);
|
|
6573
|
-
const metadata = {
|
|
6574
|
-
id: mediaId,
|
|
6575
|
-
name: fileNameToUse,
|
|
6576
|
-
url: downloadURL,
|
|
6577
|
-
contentType: file.type,
|
|
6578
|
-
size: file.size,
|
|
6579
|
-
createdAt: import_firestore22.Timestamp.now(),
|
|
6580
|
-
accessLevel,
|
|
6581
|
-
ownerId,
|
|
6582
|
-
collectionName,
|
|
6583
|
-
path: filePath
|
|
6584
|
-
};
|
|
6585
|
-
const metadataDocRef = (0, import_firestore23.doc)(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
6586
|
-
await (0, import_firestore23.setDoc)(metadataDocRef, metadata);
|
|
6587
|
-
console.log("[MediaService] Metadata stored in Firestore:", mediaId);
|
|
6588
|
-
return metadata;
|
|
6589
|
-
} catch (error) {
|
|
6590
|
-
console.error("[MediaService] Error during media upload:", error);
|
|
6591
|
-
throw error;
|
|
6592
|
-
}
|
|
6593
|
-
}
|
|
6594
|
-
/**
|
|
6595
|
-
* Get media metadata from Firestore by its ID.
|
|
6596
|
-
* @param mediaId - ID of the media.
|
|
6597
|
-
* @returns Promise with the media metadata or null if not found.
|
|
6598
|
-
*/
|
|
6599
|
-
async getMediaMetadata(mediaId) {
|
|
6600
|
-
console.log(`[MediaService] Getting media metadata for ID: ${mediaId}`);
|
|
6601
|
-
const docRef = (0, import_firestore23.doc)(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
6602
|
-
const docSnap = await (0, import_firestore23.getDoc)(docRef);
|
|
6603
|
-
if (docSnap.exists()) {
|
|
6604
|
-
console.log("[MediaService] Metadata found:", docSnap.data());
|
|
6605
|
-
return docSnap.data();
|
|
6606
|
-
}
|
|
6607
|
-
console.log("[MediaService] No metadata found for ID:", mediaId);
|
|
6608
|
-
return null;
|
|
6609
|
-
}
|
|
6610
|
-
/**
|
|
6611
|
-
* Get media metadata from Firestore by its public URL.
|
|
6612
|
-
* @param url - The public URL of the media file.
|
|
6613
|
-
* @returns Promise with the media metadata or null if not found.
|
|
6614
|
-
*/
|
|
6615
|
-
async getMediaMetadataByUrl(url) {
|
|
6616
|
-
console.log(`[MediaService] Getting media metadata by URL: ${url}`);
|
|
6617
|
-
const q = (0, import_firestore23.query)(
|
|
6618
|
-
(0, import_firestore23.collection)(this.db, MEDIA_METADATA_COLLECTION),
|
|
6619
|
-
(0, import_firestore23.where)("url", "==", url),
|
|
6620
|
-
(0, import_firestore23.limit)(1)
|
|
6939
|
+
[center.latitude, center.longitude],
|
|
6940
|
+
radiusInKm * 1e3
|
|
6941
|
+
// Convert to meters
|
|
6621
6942
|
);
|
|
6622
|
-
|
|
6943
|
+
const matchingClinics = [];
|
|
6944
|
+
for (const bound of bounds) {
|
|
6945
|
+
const geoConstraints = [
|
|
6946
|
+
...constraints,
|
|
6947
|
+
(0, import_firestore23.where)("location.geohash", ">=", bound[0]),
|
|
6948
|
+
(0, import_firestore23.where)("location.geohash", "<=", bound[1])
|
|
6949
|
+
];
|
|
6950
|
+
const q = (0, import_firestore23.query)((0, import_firestore23.collection)(db, CLINICS_COLLECTION), ...geoConstraints);
|
|
6623
6951
|
const querySnapshot = await (0, import_firestore23.getDocs)(q);
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6952
|
+
console.log(
|
|
6953
|
+
`[FILTER_UTILS] Found ${querySnapshot.docs.length} clinics in geo bound`
|
|
6954
|
+
);
|
|
6955
|
+
for (const doc34 of querySnapshot.docs) {
|
|
6956
|
+
const clinic = { ...doc34.data(), id: doc34.id };
|
|
6957
|
+
const distance = (0, import_geofire_common6.distanceBetween)(
|
|
6958
|
+
[center.latitude, center.longitude],
|
|
6959
|
+
[clinic.location.latitude, clinic.location.longitude]
|
|
6960
|
+
);
|
|
6961
|
+
const distanceInKm = distance / 1e3;
|
|
6962
|
+
if (distanceInKm <= radiusInKm) {
|
|
6963
|
+
matchingClinics.push({
|
|
6964
|
+
...clinic,
|
|
6965
|
+
distance: distanceInKm
|
|
6966
|
+
});
|
|
6967
|
+
}
|
|
6628
6968
|
}
|
|
6629
|
-
console.log("[MediaService] No metadata found for URL:", url);
|
|
6630
|
-
return null;
|
|
6631
|
-
} catch (error) {
|
|
6632
|
-
console.error("[MediaService] Error fetching metadata by URL:", error);
|
|
6633
|
-
throw error;
|
|
6634
6969
|
}
|
|
6635
|
-
|
|
6636
|
-
|
|
6637
|
-
|
|
6638
|
-
|
|
6639
|
-
|
|
6640
|
-
async deleteMedia(mediaId) {
|
|
6641
|
-
console.log(`[MediaService] Deleting media with ID: ${mediaId}`);
|
|
6642
|
-
const metadata = await this.getMediaMetadata(mediaId);
|
|
6643
|
-
if (!metadata) {
|
|
6644
|
-
console.warn(
|
|
6645
|
-
`[MediaService] Metadata not found for media ID ${mediaId}. Cannot delete.`
|
|
6646
|
-
);
|
|
6647
|
-
return;
|
|
6970
|
+
let filteredClinics = matchingClinics;
|
|
6971
|
+
if (filters.tags && filters.tags.length > 1) {
|
|
6972
|
+
filteredClinics = filteredClinics.filter((clinic) => {
|
|
6973
|
+
return filters.tags.every((tag) => clinic.tags.includes(tag));
|
|
6974
|
+
});
|
|
6648
6975
|
}
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
console.log(`[MediaService] File deleted from Storage: ${metadata.path}`);
|
|
6653
|
-
const metadataDocRef = (0, import_firestore23.doc)(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
6654
|
-
await (0, import_firestore23.deleteDoc)(metadataDocRef);
|
|
6655
|
-
console.log(
|
|
6656
|
-
`[MediaService] Metadata deleted from Firestore for ID: ${mediaId}`
|
|
6976
|
+
if (filters.minRating !== void 0) {
|
|
6977
|
+
filteredClinics = filteredClinics.filter(
|
|
6978
|
+
(clinic) => clinic.reviewInfo.averageRating >= filters.minRating
|
|
6657
6979
|
);
|
|
6658
|
-
} catch (error) {
|
|
6659
|
-
console.error(`[MediaService] Error deleting media ${mediaId}:`, error);
|
|
6660
|
-
throw error;
|
|
6661
6980
|
}
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
* to a new path reflecting the new access level, and updating its metadata.
|
|
6666
|
-
* @param mediaId - ID of the media to update.
|
|
6667
|
-
* @param newAccessLevel - New access level.
|
|
6668
|
-
* @returns Promise with the updated media metadata, or null if metadata not found.
|
|
6669
|
-
*/
|
|
6670
|
-
async updateMediaAccessLevel(mediaId, newAccessLevel) {
|
|
6671
|
-
var _a;
|
|
6672
|
-
console.log(
|
|
6673
|
-
`[MediaService] Attempting to update access level for media ID: ${mediaId} to ${newAccessLevel}`
|
|
6674
|
-
);
|
|
6675
|
-
const metadata = await this.getMediaMetadata(mediaId);
|
|
6676
|
-
if (!metadata) {
|
|
6677
|
-
console.warn(
|
|
6678
|
-
`[MediaService] Metadata not found for media ID ${mediaId}. Cannot update access level.`
|
|
6981
|
+
if (filters.maxRating !== void 0) {
|
|
6982
|
+
filteredClinics = filteredClinics.filter(
|
|
6983
|
+
(clinic) => clinic.reviewInfo.averageRating <= filters.maxRating
|
|
6679
6984
|
);
|
|
6680
|
-
return null;
|
|
6681
6985
|
}
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
|
|
6685
|
-
)
|
|
6686
|
-
|
|
6687
|
-
|
|
6688
|
-
await (0, import_firestore23.updateDoc)(metadataDocRef, { updatedAt: import_firestore22.Timestamp.now() });
|
|
6689
|
-
return { ...metadata, updatedAt: import_firestore22.Timestamp.now() };
|
|
6690
|
-
} catch (error) {
|
|
6691
|
-
console.error(
|
|
6692
|
-
`[MediaService] Error updating timestamp for media ID ${mediaId}:`,
|
|
6693
|
-
error
|
|
6986
|
+
filteredClinics.sort((a, b) => a.distance - b.distance);
|
|
6987
|
+
if (filters.pagination && filters.pagination > 0) {
|
|
6988
|
+
let startIndex = 0;
|
|
6989
|
+
if (filters.lastDoc) {
|
|
6990
|
+
const lastDocIndex = filteredClinics.findIndex(
|
|
6991
|
+
(clinic) => clinic.id === filters.lastDoc.id
|
|
6694
6992
|
);
|
|
6695
|
-
|
|
6993
|
+
if (lastDocIndex !== -1) {
|
|
6994
|
+
startIndex = lastDocIndex + 1;
|
|
6995
|
+
}
|
|
6696
6996
|
}
|
|
6997
|
+
const paginatedClinics = filteredClinics.slice(
|
|
6998
|
+
startIndex,
|
|
6999
|
+
startIndex + filters.pagination
|
|
7000
|
+
);
|
|
7001
|
+
lastVisibleDoc = paginatedClinics.length > 0 ? paginatedClinics[paginatedClinics.length - 1] : null;
|
|
7002
|
+
clinicsResult = paginatedClinics;
|
|
7003
|
+
} else {
|
|
7004
|
+
clinicsResult = filteredClinics;
|
|
6697
7005
|
}
|
|
6698
|
-
|
|
6699
|
-
const
|
|
6700
|
-
const
|
|
7006
|
+
} else {
|
|
7007
|
+
const q = (0, import_firestore23.query)((0, import_firestore23.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
7008
|
+
const querySnapshot = await (0, import_firestore23.getDocs)(q);
|
|
6701
7009
|
console.log(
|
|
6702
|
-
`[
|
|
7010
|
+
`[FILTER_UTILS] Found ${querySnapshot.docs.length} clinics with regular query`
|
|
6703
7011
|
);
|
|
6704
|
-
const
|
|
6705
|
-
|
|
6706
|
-
|
|
6707
|
-
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
)
|
|
6712
|
-
|
|
6713
|
-
|
|
6714
|
-
|
|
6715
|
-
});
|
|
6716
|
-
console.log(
|
|
6717
|
-
`[MediaService] Successfully uploaded bytes to ${newStoragePath}`
|
|
6718
|
-
);
|
|
6719
|
-
const newDownloadURL = await (0, import_storage5.getDownloadURL)(newStorageFileRef);
|
|
6720
|
-
console.log(
|
|
6721
|
-
`[MediaService] Got new download URL for ${newStoragePath}: ${newDownloadURL}`
|
|
6722
|
-
);
|
|
6723
|
-
const updateData = {
|
|
6724
|
-
accessLevel: newAccessLevel,
|
|
6725
|
-
path: newStoragePath,
|
|
6726
|
-
url: newDownloadURL,
|
|
6727
|
-
updatedAt: import_firestore22.Timestamp.now()
|
|
6728
|
-
};
|
|
6729
|
-
const metadataDocRef = (0, import_firestore23.doc)(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
6730
|
-
console.log(
|
|
6731
|
-
`[MediaService] Updating Firestore metadata for ${mediaId} with new data:`,
|
|
6732
|
-
updateData
|
|
6733
|
-
);
|
|
6734
|
-
await (0, import_firestore23.updateDoc)(metadataDocRef, updateData);
|
|
6735
|
-
console.log(
|
|
6736
|
-
`[MediaService] Successfully updated Firestore metadata for ${mediaId}`
|
|
6737
|
-
);
|
|
6738
|
-
try {
|
|
6739
|
-
console.log(`[MediaService] Deleting old file from ${oldStoragePath}`);
|
|
6740
|
-
await (0, import_storage5.deleteObject)(oldStorageFileRef);
|
|
6741
|
-
console.log(
|
|
6742
|
-
`[MediaService] Successfully deleted old file from ${oldStoragePath}`
|
|
6743
|
-
);
|
|
6744
|
-
} catch (deleteError) {
|
|
6745
|
-
console.error(
|
|
6746
|
-
`[MediaService] Failed to delete old file from ${oldStoragePath} for media ID ${mediaId}. This file is now orphaned. Error:`,
|
|
6747
|
-
deleteError
|
|
7012
|
+
const clinics = querySnapshot.docs.map((doc34) => {
|
|
7013
|
+
return { ...doc34.data(), id: doc34.id };
|
|
7014
|
+
});
|
|
7015
|
+
let filteredClinics = clinics;
|
|
7016
|
+
if (filters.center) {
|
|
7017
|
+
const center = filters.center;
|
|
7018
|
+
const clinicsWithDistance = [];
|
|
7019
|
+
filteredClinics.forEach((clinic) => {
|
|
7020
|
+
const distance = (0, import_geofire_common6.distanceBetween)(
|
|
7021
|
+
[center.latitude, center.longitude],
|
|
7022
|
+
[clinic.location.latitude, clinic.location.longitude]
|
|
6748
7023
|
);
|
|
6749
|
-
|
|
6750
|
-
|
|
6751
|
-
|
|
6752
|
-
|
|
6753
|
-
|
|
6754
|
-
|
|
7024
|
+
clinicsWithDistance.push({
|
|
7025
|
+
...clinic,
|
|
7026
|
+
distance: distance / 1e3
|
|
7027
|
+
// Convert to kilometers
|
|
7028
|
+
});
|
|
7029
|
+
});
|
|
7030
|
+
filteredClinics = clinicsWithDistance;
|
|
7031
|
+
filteredClinics.sort(
|
|
7032
|
+
(a, b) => a.distance - b.distance
|
|
6755
7033
|
);
|
|
6756
|
-
if (newStorageFileRef && error.code !== "storage/object-not-found" && ((_a = error.message) == null ? void 0 : _a.includes("uploadBytes"))) {
|
|
6757
|
-
console.warn(
|
|
6758
|
-
`[MediaService] Attempting to delete partially uploaded file at ${newStoragePath} due to error.`
|
|
6759
|
-
);
|
|
6760
|
-
try {
|
|
6761
|
-
await (0, import_storage5.deleteObject)(newStorageFileRef);
|
|
6762
|
-
console.warn(
|
|
6763
|
-
`[MediaService] Cleaned up partially uploaded file at ${newStoragePath}.`
|
|
6764
|
-
);
|
|
6765
|
-
} catch (cleanupError) {
|
|
6766
|
-
console.error(
|
|
6767
|
-
`[MediaService] Failed to cleanup partially uploaded file at ${newStoragePath}:`,
|
|
6768
|
-
cleanupError
|
|
6769
|
-
);
|
|
6770
|
-
}
|
|
6771
|
-
}
|
|
6772
|
-
throw error;
|
|
6773
|
-
}
|
|
6774
|
-
}
|
|
6775
|
-
/**
|
|
6776
|
-
* List all media for an owner, optionally filtered by collection and access level.
|
|
6777
|
-
* @param ownerId - ID of the owner.
|
|
6778
|
-
* @param collectionName - Optional: Filter by collection name.
|
|
6779
|
-
* @param accessLevel - Optional: Filter by access level.
|
|
6780
|
-
* @param count - Optional: Number of items to fetch.
|
|
6781
|
-
* @param startAfterId - Optional: ID of the document to start after (for pagination).
|
|
6782
|
-
*/
|
|
6783
|
-
async listMedia(ownerId, collectionName, accessLevel, count, startAfterId) {
|
|
6784
|
-
console.log(`[MediaService] Listing media for owner: ${ownerId}`);
|
|
6785
|
-
let qConstraints = [(0, import_firestore23.where)("ownerId", "==", ownerId)];
|
|
6786
|
-
if (collectionName) {
|
|
6787
|
-
qConstraints.push((0, import_firestore23.where)("collectionName", "==", collectionName));
|
|
6788
|
-
}
|
|
6789
|
-
if (accessLevel) {
|
|
6790
|
-
qConstraints.push((0, import_firestore23.where)("accessLevel", "==", accessLevel));
|
|
6791
7034
|
}
|
|
6792
|
-
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
if (startAfterId) {
|
|
6797
|
-
const startAfterDoc = await this.getMediaMetadata(startAfterId);
|
|
6798
|
-
if (startAfterDoc) {
|
|
6799
|
-
}
|
|
7035
|
+
if (filters.tags && filters.tags.length > 1) {
|
|
7036
|
+
filteredClinics = filteredClinics.filter((clinic) => {
|
|
7037
|
+
return filters.tags.every((tag) => clinic.tags.includes(tag));
|
|
7038
|
+
});
|
|
6800
7039
|
}
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
);
|
|
6805
|
-
try {
|
|
6806
|
-
const querySnapshot = await (0, import_firestore23.getDocs)(finalQuery);
|
|
6807
|
-
const mediaList = querySnapshot.docs.map(
|
|
6808
|
-
(doc34) => doc34.data()
|
|
7040
|
+
if (filters.minRating !== void 0) {
|
|
7041
|
+
filteredClinics = filteredClinics.filter(
|
|
7042
|
+
(clinic) => clinic.reviewInfo.averageRating >= filters.minRating
|
|
6809
7043
|
);
|
|
6810
|
-
console.log(`[MediaService] Found ${mediaList.length} media items.`);
|
|
6811
|
-
return mediaList;
|
|
6812
|
-
} catch (error) {
|
|
6813
|
-
console.error("[MediaService] Error listing media:", error);
|
|
6814
|
-
throw error;
|
|
6815
7044
|
}
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
*/
|
|
6821
|
-
async getMediaDownloadUrl(mediaId) {
|
|
6822
|
-
console.log(`[MediaService] Getting download URL for media ID: ${mediaId}`);
|
|
6823
|
-
const metadata = await this.getMediaMetadata(mediaId);
|
|
6824
|
-
if (metadata && metadata.url) {
|
|
6825
|
-
console.log(`[MediaService] URL found: ${metadata.url}`);
|
|
6826
|
-
return metadata.url;
|
|
7045
|
+
if (filters.maxRating !== void 0) {
|
|
7046
|
+
filteredClinics = filteredClinics.filter(
|
|
7047
|
+
(clinic) => clinic.reviewInfo.averageRating <= filters.maxRating
|
|
7048
|
+
);
|
|
6827
7049
|
}
|
|
6828
|
-
|
|
6829
|
-
|
|
7050
|
+
lastVisibleDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
7051
|
+
clinicsResult = filteredClinics;
|
|
6830
7052
|
}
|
|
6831
|
-
|
|
7053
|
+
return {
|
|
7054
|
+
clinics: clinicsResult,
|
|
7055
|
+
lastDoc: lastVisibleDoc
|
|
7056
|
+
};
|
|
7057
|
+
}
|
|
6832
7058
|
|
|
6833
7059
|
// src/services/clinic/clinic.service.ts
|
|
6834
7060
|
var ClinicService = class extends BaseService {
|
|
@@ -8533,7 +8759,8 @@ var ProcedureService = class extends BaseService {
|
|
|
8533
8759
|
id: practitionerSnapshot.id,
|
|
8534
8760
|
name: `${practitioner.basicInfo.firstName} ${practitioner.basicInfo.lastName}`,
|
|
8535
8761
|
description: practitioner.basicInfo.bio || "",
|
|
8536
|
-
photo: practitioner.basicInfo.profileImageUrl
|
|
8762
|
+
photo: typeof practitioner.basicInfo.profileImageUrl === "string" ? practitioner.basicInfo.profileImageUrl : "",
|
|
8763
|
+
// Default to empty string if not a processed URL
|
|
8537
8764
|
rating: ((_a = practitioner.reviewInfo) == null ? void 0 : _a.averageRating) || 0,
|
|
8538
8765
|
services: practitioner.procedures || []
|
|
8539
8766
|
};
|
|
@@ -8667,7 +8894,8 @@ var ProcedureService = class extends BaseService {
|
|
|
8667
8894
|
id: newPractitioner.id,
|
|
8668
8895
|
name: `${newPractitioner.basicInfo.firstName} ${newPractitioner.basicInfo.lastName}`,
|
|
8669
8896
|
description: newPractitioner.basicInfo.bio || "",
|
|
8670
|
-
photo: newPractitioner.basicInfo.profileImageUrl
|
|
8897
|
+
photo: typeof newPractitioner.basicInfo.profileImageUrl === "string" ? newPractitioner.basicInfo.profileImageUrl : "",
|
|
8898
|
+
// Default to empty string if not a processed URL
|
|
8671
8899
|
rating: ((_a = newPractitioner.reviewInfo) == null ? void 0 : _a.averageRating) || 0,
|
|
8672
8900
|
services: newPractitioner.procedures || []
|
|
8673
8901
|
};
|