@blackcode_sa/metaestetics-api 1.7.20 → 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 +0 -1
- package/dist/admin/index.d.ts +0 -1
- package/dist/index.d.mts +39 -19
- package/dist/index.d.ts +39 -19
- package/dist/index.js +1116 -951
- package/dist/index.mjs +1132 -965
- package/package.json +1 -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/types/patient/index.ts +25 -23
- package/src/validations/patient.schema.ts +4 -4
package/dist/index.js
CHANGED
|
@@ -1194,12 +1194,309 @@ 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
|
|
1202
|
+
var import_firestore3 = require("firebase/firestore");
|
|
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);
|
|
1213
|
+
}
|
|
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");
|
|
1203
1500
|
|
|
1204
1501
|
// src/types/patient/medical-info.types.ts
|
|
1205
1502
|
var PATIENT_MEDICAL_INFO_COLLECTION = "medical_info";
|
|
@@ -1228,11 +1525,19 @@ var Gender = /* @__PURE__ */ ((Gender2) => {
|
|
|
1228
1525
|
})(Gender || {});
|
|
1229
1526
|
|
|
1230
1527
|
// src/validations/patient.schema.ts
|
|
1231
|
-
var
|
|
1232
|
-
var
|
|
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
|
+
]);
|
|
1233
1538
|
|
|
1234
1539
|
// src/validations/patient/medical-info.schema.ts
|
|
1235
|
-
var
|
|
1540
|
+
var import_zod6 = require("zod");
|
|
1236
1541
|
|
|
1237
1542
|
// src/types/patient/allergies.ts
|
|
1238
1543
|
var AllergyType = /* @__PURE__ */ ((AllergyType2) => {
|
|
@@ -1321,80 +1626,80 @@ var Contraindication = /* @__PURE__ */ ((Contraindication2) => {
|
|
|
1321
1626
|
})(Contraindication || {});
|
|
1322
1627
|
|
|
1323
1628
|
// src/validations/common.schema.ts
|
|
1324
|
-
var
|
|
1325
|
-
var
|
|
1326
|
-
var timestampSchema2 =
|
|
1327
|
-
|
|
1328
|
-
seconds:
|
|
1329
|
-
nanoseconds:
|
|
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()
|
|
1330
1635
|
}),
|
|
1331
|
-
|
|
1636
|
+
import_zod5.z.instanceof(import_firestore4.Timestamp)
|
|
1332
1637
|
]).transform((data) => {
|
|
1333
|
-
if (data instanceof
|
|
1638
|
+
if (data instanceof import_firestore4.Timestamp) {
|
|
1334
1639
|
return data;
|
|
1335
1640
|
}
|
|
1336
|
-
return new
|
|
1641
|
+
return new import_firestore4.Timestamp(data.seconds, data.nanoseconds);
|
|
1337
1642
|
});
|
|
1338
1643
|
|
|
1339
1644
|
// src/validations/patient/medical-info.schema.ts
|
|
1340
|
-
var allergySubtypeSchema =
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
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")
|
|
1346
1651
|
]);
|
|
1347
|
-
var allergySchema =
|
|
1348
|
-
type:
|
|
1652
|
+
var allergySchema = import_zod6.z.object({
|
|
1653
|
+
type: import_zod6.z.nativeEnum(AllergyType),
|
|
1349
1654
|
subtype: allergySubtypeSchema,
|
|
1350
|
-
name:
|
|
1351
|
-
severity:
|
|
1352
|
-
reaction:
|
|
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(),
|
|
1353
1658
|
diagnosed: timestampSchema2.optional().nullable(),
|
|
1354
|
-
notes:
|
|
1659
|
+
notes: import_zod6.z.string().optional().nullable()
|
|
1355
1660
|
});
|
|
1356
|
-
var vitalStatsSchema =
|
|
1357
|
-
height:
|
|
1358
|
-
weight:
|
|
1359
|
-
bloodType:
|
|
1360
|
-
bloodPressure:
|
|
1361
|
-
systolic:
|
|
1362
|
-
diastolic:
|
|
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),
|
|
1363
1668
|
lastMeasured: timestampSchema2
|
|
1364
1669
|
}).optional()
|
|
1365
1670
|
});
|
|
1366
|
-
var blockingConditionSchema =
|
|
1367
|
-
condition:
|
|
1671
|
+
var blockingConditionSchema = import_zod6.z.object({
|
|
1672
|
+
condition: import_zod6.z.nativeEnum(BlockingCondition),
|
|
1368
1673
|
diagnosedAt: timestampSchema2,
|
|
1369
|
-
notes:
|
|
1370
|
-
isActive:
|
|
1674
|
+
notes: import_zod6.z.string().optional().nullable(),
|
|
1675
|
+
isActive: import_zod6.z.boolean()
|
|
1371
1676
|
});
|
|
1372
|
-
var contraindicationSchema =
|
|
1373
|
-
condition:
|
|
1677
|
+
var contraindicationSchema = import_zod6.z.object({
|
|
1678
|
+
condition: import_zod6.z.nativeEnum(Contraindication),
|
|
1374
1679
|
lastOccurrence: timestampSchema2,
|
|
1375
|
-
frequency:
|
|
1376
|
-
notes:
|
|
1377
|
-
isActive:
|
|
1680
|
+
frequency: import_zod6.z.enum(["rare", "occasional", "frequent"]),
|
|
1681
|
+
notes: import_zod6.z.string().optional().nullable(),
|
|
1682
|
+
isActive: import_zod6.z.boolean()
|
|
1378
1683
|
});
|
|
1379
|
-
var medicationSchema =
|
|
1380
|
-
name:
|
|
1381
|
-
dosage:
|
|
1382
|
-
frequency:
|
|
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),
|
|
1383
1688
|
startDate: timestampSchema2.optional().nullable(),
|
|
1384
1689
|
endDate: timestampSchema2.optional().nullable(),
|
|
1385
|
-
prescribedBy:
|
|
1690
|
+
prescribedBy: import_zod6.z.string().optional().nullable()
|
|
1386
1691
|
});
|
|
1387
|
-
var patientMedicalInfoSchema =
|
|
1388
|
-
patientId:
|
|
1692
|
+
var patientMedicalInfoSchema = import_zod6.z.object({
|
|
1693
|
+
patientId: import_zod6.z.string(),
|
|
1389
1694
|
vitalStats: vitalStatsSchema,
|
|
1390
|
-
blockingConditions:
|
|
1391
|
-
contraindications:
|
|
1392
|
-
allergies:
|
|
1393
|
-
currentMedications:
|
|
1394
|
-
emergencyNotes:
|
|
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(),
|
|
1395
1700
|
lastUpdated: timestampSchema2,
|
|
1396
|
-
updatedBy:
|
|
1397
|
-
verifiedBy:
|
|
1701
|
+
updatedBy: import_zod6.z.string(),
|
|
1702
|
+
verifiedBy: import_zod6.z.string().optional(),
|
|
1398
1703
|
verifiedAt: timestampSchema2.optional()
|
|
1399
1704
|
});
|
|
1400
1705
|
var createPatientMedicalInfoSchema = patientMedicalInfoSchema.omit({
|
|
@@ -1408,141 +1713,140 @@ var updatePatientMedicalInfoSchema = createPatientMedicalInfoSchema.partial();
|
|
|
1408
1713
|
var updateVitalStatsSchema = vitalStatsSchema;
|
|
1409
1714
|
var addAllergySchema = allergySchema;
|
|
1410
1715
|
var updateAllergySchema = allergySchema.partial().extend({
|
|
1411
|
-
allergyIndex:
|
|
1716
|
+
allergyIndex: import_zod6.z.number().min(0)
|
|
1412
1717
|
});
|
|
1413
1718
|
var addBlockingConditionSchema = blockingConditionSchema;
|
|
1414
1719
|
var updateBlockingConditionSchema = blockingConditionSchema.partial().extend({
|
|
1415
|
-
conditionIndex:
|
|
1720
|
+
conditionIndex: import_zod6.z.number().min(0)
|
|
1416
1721
|
});
|
|
1417
1722
|
var addContraindicationSchema = contraindicationSchema;
|
|
1418
1723
|
var updateContraindicationSchema = contraindicationSchema.partial().extend({
|
|
1419
|
-
contraindicationIndex:
|
|
1724
|
+
contraindicationIndex: import_zod6.z.number().min(0)
|
|
1420
1725
|
});
|
|
1421
1726
|
var addMedicationSchema = medicationSchema;
|
|
1422
1727
|
var updateMedicationSchema = medicationSchema.partial().extend({
|
|
1423
|
-
medicationIndex:
|
|
1728
|
+
medicationIndex: import_zod6.z.number().min(0)
|
|
1424
1729
|
});
|
|
1425
1730
|
|
|
1426
1731
|
// src/validations/patient.schema.ts
|
|
1427
|
-
var locationDataSchema =
|
|
1428
|
-
latitude:
|
|
1429
|
-
longitude:
|
|
1430
|
-
geohash:
|
|
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()
|
|
1431
1736
|
});
|
|
1432
|
-
var addressDataSchema =
|
|
1433
|
-
address:
|
|
1434
|
-
city:
|
|
1435
|
-
country:
|
|
1436
|
-
postalCode:
|
|
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()
|
|
1437
1742
|
});
|
|
1438
|
-
var emergencyContactSchema =
|
|
1439
|
-
name:
|
|
1440
|
-
relationship:
|
|
1441
|
-
phoneNumber:
|
|
1442
|
-
isNotifiable:
|
|
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()
|
|
1443
1748
|
});
|
|
1444
|
-
var gamificationSchema =
|
|
1445
|
-
level:
|
|
1446
|
-
points:
|
|
1749
|
+
var gamificationSchema = import_zod7.z.object({
|
|
1750
|
+
level: import_zod7.z.number(),
|
|
1751
|
+
points: import_zod7.z.number()
|
|
1447
1752
|
});
|
|
1448
|
-
var patientLocationInfoSchema =
|
|
1449
|
-
patientId:
|
|
1450
|
-
userRef:
|
|
1753
|
+
var patientLocationInfoSchema = import_zod7.z.object({
|
|
1754
|
+
patientId: import_zod7.z.string(),
|
|
1755
|
+
userRef: import_zod7.z.string(),
|
|
1451
1756
|
locationData: locationDataSchema,
|
|
1452
|
-
createdAt:
|
|
1453
|
-
updatedAt:
|
|
1757
|
+
createdAt: import_zod7.z.instanceof(import_firestore5.Timestamp),
|
|
1758
|
+
updatedAt: import_zod7.z.instanceof(import_firestore5.Timestamp)
|
|
1454
1759
|
});
|
|
1455
|
-
var createPatientLocationInfoSchema =
|
|
1456
|
-
patientId:
|
|
1457
|
-
userRef:
|
|
1760
|
+
var createPatientLocationInfoSchema = import_zod7.z.object({
|
|
1761
|
+
patientId: import_zod7.z.string(),
|
|
1762
|
+
userRef: import_zod7.z.string(),
|
|
1458
1763
|
locationData: locationDataSchema
|
|
1459
1764
|
});
|
|
1460
|
-
var patientSensitiveInfoSchema =
|
|
1461
|
-
patientId:
|
|
1462
|
-
userRef:
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
alternativePhoneNumber: import_zod6.z.string().optional(),
|
|
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(),
|
|
1471
1775
|
addressData: addressDataSchema.optional(),
|
|
1472
|
-
emergencyContacts:
|
|
1473
|
-
createdAt:
|
|
1474
|
-
updatedAt:
|
|
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)
|
|
1475
1779
|
});
|
|
1476
|
-
var patientDoctorSchema =
|
|
1477
|
-
userRef:
|
|
1478
|
-
assignedAt:
|
|
1479
|
-
assignedBy:
|
|
1480
|
-
isActive:
|
|
1481
|
-
notes:
|
|
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()
|
|
1482
1786
|
});
|
|
1483
|
-
var patientClinicSchema =
|
|
1484
|
-
clinicId:
|
|
1485
|
-
assignedAt:
|
|
1486
|
-
assignedBy:
|
|
1487
|
-
isActive:
|
|
1488
|
-
notes:
|
|
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()
|
|
1489
1793
|
});
|
|
1490
|
-
var patientProfileSchema =
|
|
1491
|
-
id:
|
|
1492
|
-
userRef:
|
|
1493
|
-
displayName:
|
|
1494
|
-
profilePhoto: import_zod6.z.string().url().nullable(),
|
|
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(),
|
|
1495
1798
|
gamification: gamificationSchema,
|
|
1496
|
-
expoTokens:
|
|
1497
|
-
isActive:
|
|
1498
|
-
isVerified:
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
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)
|
|
1505
1810
|
});
|
|
1506
|
-
var createPatientProfileSchema =
|
|
1507
|
-
userRef:
|
|
1508
|
-
displayName:
|
|
1509
|
-
|
|
1510
|
-
expoTokens: import_zod6.z.array(import_zod6.z.string()),
|
|
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()),
|
|
1511
1815
|
gamification: gamificationSchema.optional(),
|
|
1512
|
-
isActive:
|
|
1513
|
-
isVerified:
|
|
1514
|
-
doctors:
|
|
1515
|
-
clinics:
|
|
1516
|
-
doctorIds:
|
|
1517
|
-
clinicIds:
|
|
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()
|
|
1518
1822
|
});
|
|
1519
|
-
var createPatientSensitiveInfoSchema =
|
|
1520
|
-
patientId:
|
|
1521
|
-
userRef:
|
|
1522
|
-
photoUrl:
|
|
1523
|
-
firstName:
|
|
1524
|
-
lastName:
|
|
1525
|
-
dateOfBirth:
|
|
1526
|
-
gender:
|
|
1527
|
-
email:
|
|
1528
|
-
phoneNumber:
|
|
1529
|
-
alternativePhoneNumber:
|
|
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(),
|
|
1530
1834
|
addressData: addressDataSchema.optional(),
|
|
1531
|
-
emergencyContacts:
|
|
1835
|
+
emergencyContacts: import_zod7.z.array(emergencyContactSchema).optional()
|
|
1532
1836
|
});
|
|
1533
|
-
var searchPatientsSchema =
|
|
1534
|
-
clinicId:
|
|
1535
|
-
practitionerId:
|
|
1837
|
+
var searchPatientsSchema = import_zod7.z.object({
|
|
1838
|
+
clinicId: import_zod7.z.string().optional(),
|
|
1839
|
+
practitionerId: import_zod7.z.string().optional()
|
|
1536
1840
|
}).refine((data) => data.clinicId || data.practitionerId, {
|
|
1537
1841
|
message: "At least one of clinicId or practitionerId must be provided",
|
|
1538
1842
|
path: []
|
|
1539
1843
|
// Optional: specify a path like ['clinicId'] or ['practitionerId']
|
|
1540
1844
|
});
|
|
1541
|
-
var requesterInfoSchema =
|
|
1542
|
-
id:
|
|
1543
|
-
role:
|
|
1544
|
-
associatedClinicId:
|
|
1545
|
-
associatedPractitionerId:
|
|
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()
|
|
1546
1850
|
}).refine(
|
|
1547
1851
|
(data) => {
|
|
1548
1852
|
if (data.role === "clinic_admin") {
|
|
@@ -1559,36 +1863,68 @@ var requesterInfoSchema = import_zod6.z.object({
|
|
|
1559
1863
|
);
|
|
1560
1864
|
|
|
1561
1865
|
// src/services/patient/utils/docs.utils.ts
|
|
1562
|
-
var
|
|
1866
|
+
var import_firestore7 = require("firebase/firestore");
|
|
1563
1867
|
|
|
1564
1868
|
// src/services/patient/utils/sensitive.utils.ts
|
|
1565
|
-
var
|
|
1566
|
-
var
|
|
1567
|
-
var
|
|
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) => {
|
|
1568
1893
|
try {
|
|
1569
1894
|
if (data.userRef !== requesterUserId) {
|
|
1570
1895
|
throw new Error("Only patient can create their sensitive information");
|
|
1571
1896
|
}
|
|
1572
1897
|
const validatedData = createPatientSensitiveInfoSchema.parse(data);
|
|
1573
|
-
const sensitiveDoc = await (0,
|
|
1898
|
+
const sensitiveDoc = await (0, import_firestore6.getDoc)(
|
|
1574
1899
|
getSensitiveInfoDocRef(db, data.patientId)
|
|
1575
1900
|
);
|
|
1576
1901
|
if (sensitiveDoc.exists()) {
|
|
1577
1902
|
throw new Error("Sensitive information already exists for this patient");
|
|
1578
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
|
+
}
|
|
1579
1914
|
const sensitiveInfoData = {
|
|
1580
1915
|
...validatedData,
|
|
1581
|
-
|
|
1582
|
-
|
|
1916
|
+
photoUrl: processedPhotoUrl,
|
|
1917
|
+
createdAt: (0, import_firestore6.serverTimestamp)(),
|
|
1918
|
+
updatedAt: (0, import_firestore6.serverTimestamp)()
|
|
1583
1919
|
};
|
|
1584
|
-
await (0,
|
|
1585
|
-
const createdDoc = await (0,
|
|
1920
|
+
await (0, import_firestore6.setDoc)(getSensitiveInfoDocRef(db, data.patientId), sensitiveInfoData);
|
|
1921
|
+
const createdDoc = await (0, import_firestore6.getDoc)(getSensitiveInfoDocRef(db, data.patientId));
|
|
1586
1922
|
if (!createdDoc.exists()) {
|
|
1587
1923
|
throw new Error("Failed to create sensitive information");
|
|
1588
1924
|
}
|
|
1589
1925
|
return createdDoc.data();
|
|
1590
1926
|
} catch (error) {
|
|
1591
|
-
if (error instanceof
|
|
1927
|
+
if (error instanceof import_zod8.z.ZodError) {
|
|
1592
1928
|
throw new Error("Invalid sensitive info data: " + error.message);
|
|
1593
1929
|
}
|
|
1594
1930
|
throw error;
|
|
@@ -1596,17 +1932,32 @@ var createSensitiveInfoUtil = async (db, data, requesterUserId) => {
|
|
|
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().url(),
|
|
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);
|
|
@@ -3967,399 +4430,101 @@ var ClinicAdminService = class extends BaseService {
|
|
|
3967
4430
|
async syncOwnerClinics(adminId) {
|
|
3968
4431
|
return syncOwnerClinics(
|
|
3969
4432
|
this.db,
|
|
3970
|
-
adminId,
|
|
3971
|
-
this.getClinicService(),
|
|
3972
|
-
this.getClinicGroupService()
|
|
3973
|
-
);
|
|
3974
|
-
}
|
|
3975
|
-
/**
|
|
3976
|
-
* Kreira novi admin profil
|
|
3977
|
-
*/
|
|
3978
|
-
async createClinicAdmin(data) {
|
|
3979
|
-
return createClinicAdmin(
|
|
3980
|
-
this.db,
|
|
3981
|
-
data,
|
|
3982
|
-
this.getClinicGroupService()
|
|
3983
|
-
);
|
|
3984
|
-
}
|
|
3985
|
-
/**
|
|
3986
|
-
* Dohvata admin profil po ID-u
|
|
3987
|
-
*/
|
|
3988
|
-
async getClinicAdmin(adminId) {
|
|
3989
|
-
return getClinicAdmin(this.db, adminId);
|
|
3990
|
-
}
|
|
3991
|
-
/**
|
|
3992
|
-
* Dohvata admin profil po korisničkom ID-u
|
|
3993
|
-
*/
|
|
3994
|
-
async getClinicAdminByUserRef(userRef) {
|
|
3995
|
-
return getClinicAdminByUserRef(this.db, userRef);
|
|
3996
|
-
}
|
|
3997
|
-
/**
|
|
3998
|
-
* Dohvata sve admine u grupi
|
|
3999
|
-
*/
|
|
4000
|
-
async getClinicAdminsByGroup(clinicGroupId) {
|
|
4001
|
-
return getClinicAdminsByGroup(this.db, clinicGroupId);
|
|
4002
|
-
}
|
|
4003
|
-
/**
|
|
4004
|
-
* Ažurira admin profil
|
|
4005
|
-
*/
|
|
4006
|
-
async updateClinicAdmin(adminId, data) {
|
|
4007
|
-
return updateClinicAdmin(this.db, adminId, data);
|
|
4008
|
-
}
|
|
4009
|
-
/**
|
|
4010
|
-
* Briše admin profil
|
|
4011
|
-
*/
|
|
4012
|
-
async deleteClinicAdmin(adminId) {
|
|
4013
|
-
return deleteClinicAdmin(this.db, adminId);
|
|
4014
|
-
}
|
|
4015
|
-
/**
|
|
4016
|
-
* Dodaje kliniku u listu klinika kojima admin upravlja
|
|
4017
|
-
*/
|
|
4018
|
-
async addClinicToManaged(adminId, clinicId, requesterId) {
|
|
4019
|
-
return addClinicToManaged(
|
|
4020
|
-
this.db,
|
|
4021
|
-
adminId,
|
|
4022
|
-
clinicId,
|
|
4023
|
-
requesterId,
|
|
4024
|
-
this.getClinicService()
|
|
4025
|
-
);
|
|
4026
|
-
}
|
|
4027
|
-
/**
|
|
4028
|
-
* Uklanja kliniku iz liste klinika kojima admin upravlja
|
|
4029
|
-
*/
|
|
4030
|
-
async removeClinicFromManaged(adminId, clinicId, requesterId) {
|
|
4031
|
-
return removeClinicFromManaged(
|
|
4032
|
-
this.db,
|
|
4033
|
-
adminId,
|
|
4034
|
-
clinicId,
|
|
4035
|
-
requesterId
|
|
4036
|
-
);
|
|
4037
|
-
}
|
|
4038
|
-
/**
|
|
4039
|
-
* Dohvata sve klinike kojima admin upravlja
|
|
4040
|
-
*/
|
|
4041
|
-
async getManagedClinics(adminId) {
|
|
4042
|
-
return getManagedClinics(
|
|
4043
|
-
this.db,
|
|
4044
|
-
adminId,
|
|
4045
|
-
this.getClinicService()
|
|
4046
|
-
);
|
|
4047
|
-
}
|
|
4048
|
-
/**
|
|
4049
|
-
* Dohvata sve aktivne klinike kojima admin upravlja
|
|
4050
|
-
*/
|
|
4051
|
-
async getActiveManagedClinics(adminId) {
|
|
4052
|
-
return getActiveManagedClinics(
|
|
4053
|
-
this.db,
|
|
4054
|
-
adminId,
|
|
4055
|
-
this.getClinicService()
|
|
4056
|
-
);
|
|
4057
|
-
}
|
|
4058
|
-
// TODO: Add more methods for clinic admins for managing permissions, editing profiles by the admin, or by the clinic group owner and so on
|
|
4059
|
-
// Generally refactor admin permissions and clinic group permissions and systems for admin management
|
|
4060
|
-
};
|
|
4061
|
-
|
|
4062
|
-
// src/services/practitioner/practitioner.service.ts
|
|
4063
|
-
var import_firestore18 = require("firebase/firestore");
|
|
4064
|
-
|
|
4065
|
-
// src/services/media/media.service.ts
|
|
4066
|
-
var import_firestore15 = require("firebase/firestore");
|
|
4067
|
-
var import_storage4 = require("firebase/storage");
|
|
4068
|
-
var import_firestore16 = require("firebase/firestore");
|
|
4069
|
-
var MediaAccessLevel = /* @__PURE__ */ ((MediaAccessLevel2) => {
|
|
4070
|
-
MediaAccessLevel2["PUBLIC"] = "public";
|
|
4071
|
-
MediaAccessLevel2["PRIVATE"] = "private";
|
|
4072
|
-
MediaAccessLevel2["CONFIDENTIAL"] = "confidential";
|
|
4073
|
-
return MediaAccessLevel2;
|
|
4074
|
-
})(MediaAccessLevel || {});
|
|
4075
|
-
var MEDIA_METADATA_COLLECTION = "media_metadata";
|
|
4076
|
-
var MediaService = class extends BaseService {
|
|
4077
|
-
constructor(db, auth, app) {
|
|
4078
|
-
super(db, auth, app);
|
|
4079
|
-
}
|
|
4080
|
-
/**
|
|
4081
|
-
* Upload a media file, store its metadata, and return the metadata including the URL.
|
|
4082
|
-
* @param file - The file to upload.
|
|
4083
|
-
* @param ownerId - ID of the owner (user, patient, clinic, etc.).
|
|
4084
|
-
* @param accessLevel - Access level (public, private, confidential).
|
|
4085
|
-
* @param collectionName - The logical collection name this media belongs to (e.g., 'patient_profile_pictures', 'clinic_logos').
|
|
4086
|
-
* @param originalFileName - Optional: the original name of the file, if not using file.name.
|
|
4087
|
-
* @returns Promise with the media metadata.
|
|
4088
|
-
*/
|
|
4089
|
-
async uploadMedia(file, ownerId, accessLevel, collectionName, originalFileName) {
|
|
4090
|
-
const mediaId = this.generateId();
|
|
4091
|
-
const fileNameToUse = originalFileName || (file instanceof File ? file.name : file.toString());
|
|
4092
|
-
const uniqueFileName = `${mediaId}-${fileNameToUse}`;
|
|
4093
|
-
const filePath = `media/${accessLevel}/${ownerId}/${collectionName}/${uniqueFileName}`;
|
|
4094
|
-
console.log(`[MediaService] Uploading file to: ${filePath}`);
|
|
4095
|
-
const storageRef = (0, import_storage4.ref)(this.storage, filePath);
|
|
4096
|
-
try {
|
|
4097
|
-
const uploadResult = await (0, import_storage4.uploadBytes)(storageRef, file, {
|
|
4098
|
-
contentType: file.type
|
|
4099
|
-
});
|
|
4100
|
-
console.log("[MediaService] File uploaded successfully", uploadResult);
|
|
4101
|
-
const downloadURL = await (0, import_storage4.getDownloadURL)(uploadResult.ref);
|
|
4102
|
-
console.log("[MediaService] Got download URL:", downloadURL);
|
|
4103
|
-
const metadata = {
|
|
4104
|
-
id: mediaId,
|
|
4105
|
-
name: fileNameToUse,
|
|
4106
|
-
url: downloadURL,
|
|
4107
|
-
contentType: file.type,
|
|
4108
|
-
size: file.size,
|
|
4109
|
-
createdAt: import_firestore15.Timestamp.now(),
|
|
4110
|
-
accessLevel,
|
|
4111
|
-
ownerId,
|
|
4112
|
-
collectionName,
|
|
4113
|
-
path: filePath
|
|
4114
|
-
};
|
|
4115
|
-
const metadataDocRef = (0, import_firestore16.doc)(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
4116
|
-
await (0, import_firestore16.setDoc)(metadataDocRef, metadata);
|
|
4117
|
-
console.log("[MediaService] Metadata stored in Firestore:", mediaId);
|
|
4118
|
-
return metadata;
|
|
4119
|
-
} catch (error) {
|
|
4120
|
-
console.error("[MediaService] Error during media upload:", error);
|
|
4121
|
-
throw error;
|
|
4122
|
-
}
|
|
4433
|
+
adminId,
|
|
4434
|
+
this.getClinicService(),
|
|
4435
|
+
this.getClinicGroupService()
|
|
4436
|
+
);
|
|
4123
4437
|
}
|
|
4124
4438
|
/**
|
|
4125
|
-
*
|
|
4126
|
-
* @param mediaId - ID of the media.
|
|
4127
|
-
* @returns Promise with the media metadata or null if not found.
|
|
4439
|
+
* Kreira novi admin profil
|
|
4128
4440
|
*/
|
|
4129
|
-
async
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
return docSnap.data();
|
|
4136
|
-
}
|
|
4137
|
-
console.log("[MediaService] No metadata found for ID:", mediaId);
|
|
4138
|
-
return null;
|
|
4441
|
+
async createClinicAdmin(data) {
|
|
4442
|
+
return createClinicAdmin(
|
|
4443
|
+
this.db,
|
|
4444
|
+
data,
|
|
4445
|
+
this.getClinicGroupService()
|
|
4446
|
+
);
|
|
4139
4447
|
}
|
|
4140
4448
|
/**
|
|
4141
|
-
*
|
|
4142
|
-
* @param url - The public URL of the media file.
|
|
4143
|
-
* @returns Promise with the media metadata or null if not found.
|
|
4449
|
+
* Dohvata admin profil po ID-u
|
|
4144
4450
|
*/
|
|
4145
|
-
async
|
|
4146
|
-
|
|
4147
|
-
const q = (0, import_firestore16.query)(
|
|
4148
|
-
(0, import_firestore16.collection)(this.db, MEDIA_METADATA_COLLECTION),
|
|
4149
|
-
(0, import_firestore16.where)("url", "==", url),
|
|
4150
|
-
(0, import_firestore16.limit)(1)
|
|
4151
|
-
);
|
|
4152
|
-
try {
|
|
4153
|
-
const querySnapshot = await (0, import_firestore16.getDocs)(q);
|
|
4154
|
-
if (!querySnapshot.empty) {
|
|
4155
|
-
const metadata = querySnapshot.docs[0].data();
|
|
4156
|
-
console.log("[MediaService] Metadata found by URL:", metadata);
|
|
4157
|
-
return metadata;
|
|
4158
|
-
}
|
|
4159
|
-
console.log("[MediaService] No metadata found for URL:", url);
|
|
4160
|
-
return null;
|
|
4161
|
-
} catch (error) {
|
|
4162
|
-
console.error("[MediaService] Error fetching metadata by URL:", error);
|
|
4163
|
-
throw error;
|
|
4164
|
-
}
|
|
4451
|
+
async getClinicAdmin(adminId) {
|
|
4452
|
+
return getClinicAdmin(this.db, adminId);
|
|
4165
4453
|
}
|
|
4166
4454
|
/**
|
|
4167
|
-
*
|
|
4168
|
-
* @param mediaId - ID of the media to delete.
|
|
4455
|
+
* Dohvata admin profil po korisničkom ID-u
|
|
4169
4456
|
*/
|
|
4170
|
-
async
|
|
4171
|
-
|
|
4172
|
-
const metadata = await this.getMediaMetadata(mediaId);
|
|
4173
|
-
if (!metadata) {
|
|
4174
|
-
console.warn(
|
|
4175
|
-
`[MediaService] Metadata not found for media ID ${mediaId}. Cannot delete.`
|
|
4176
|
-
);
|
|
4177
|
-
return;
|
|
4178
|
-
}
|
|
4179
|
-
const storageFileRef = (0, import_storage4.ref)(this.storage, metadata.path);
|
|
4180
|
-
try {
|
|
4181
|
-
await (0, import_storage4.deleteObject)(storageFileRef);
|
|
4182
|
-
console.log(`[MediaService] File deleted from Storage: ${metadata.path}`);
|
|
4183
|
-
const metadataDocRef = (0, import_firestore16.doc)(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
4184
|
-
await (0, import_firestore16.deleteDoc)(metadataDocRef);
|
|
4185
|
-
console.log(
|
|
4186
|
-
`[MediaService] Metadata deleted from Firestore for ID: ${mediaId}`
|
|
4187
|
-
);
|
|
4188
|
-
} catch (error) {
|
|
4189
|
-
console.error(`[MediaService] Error deleting media ${mediaId}:`, error);
|
|
4190
|
-
throw error;
|
|
4191
|
-
}
|
|
4457
|
+
async getClinicAdminByUserRef(userRef) {
|
|
4458
|
+
return getClinicAdminByUserRef(this.db, userRef);
|
|
4192
4459
|
}
|
|
4193
4460
|
/**
|
|
4194
|
-
*
|
|
4195
|
-
* to a new path reflecting the new access level, and updating its metadata.
|
|
4196
|
-
* @param mediaId - ID of the media to update.
|
|
4197
|
-
* @param newAccessLevel - New access level.
|
|
4198
|
-
* @returns Promise with the updated media metadata, or null if metadata not found.
|
|
4461
|
+
* Dohvata sve admine u grupi
|
|
4199
4462
|
*/
|
|
4200
|
-
async
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4463
|
+
async getClinicAdminsByGroup(clinicGroupId) {
|
|
4464
|
+
return getClinicAdminsByGroup(this.db, clinicGroupId);
|
|
4465
|
+
}
|
|
4466
|
+
/**
|
|
4467
|
+
* Ažurira admin profil
|
|
4468
|
+
*/
|
|
4469
|
+
async updateClinicAdmin(adminId, data) {
|
|
4470
|
+
return updateClinicAdmin(this.db, adminId, data);
|
|
4471
|
+
}
|
|
4472
|
+
/**
|
|
4473
|
+
* Briše admin profil
|
|
4474
|
+
*/
|
|
4475
|
+
async deleteClinicAdmin(adminId) {
|
|
4476
|
+
return deleteClinicAdmin(this.db, adminId);
|
|
4477
|
+
}
|
|
4478
|
+
/**
|
|
4479
|
+
* Dodaje kliniku u listu klinika kojima admin upravlja
|
|
4480
|
+
*/
|
|
4481
|
+
async addClinicToManaged(adminId, clinicId, requesterId) {
|
|
4482
|
+
return addClinicToManaged(
|
|
4483
|
+
this.db,
|
|
4484
|
+
adminId,
|
|
4485
|
+
clinicId,
|
|
4486
|
+
requesterId,
|
|
4487
|
+
this.getClinicService()
|
|
4204
4488
|
);
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
);
|
|
4216
|
-
const metadataDocRef = (0, import_firestore16.doc)(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
4217
|
-
try {
|
|
4218
|
-
await (0, import_firestore16.updateDoc)(metadataDocRef, { updatedAt: import_firestore15.Timestamp.now() });
|
|
4219
|
-
return { ...metadata, updatedAt: import_firestore15.Timestamp.now() };
|
|
4220
|
-
} catch (error) {
|
|
4221
|
-
console.error(
|
|
4222
|
-
`[MediaService] Error updating timestamp for media ID ${mediaId}:`,
|
|
4223
|
-
error
|
|
4224
|
-
);
|
|
4225
|
-
throw error;
|
|
4226
|
-
}
|
|
4227
|
-
}
|
|
4228
|
-
const oldStoragePath = metadata.path;
|
|
4229
|
-
const fileNamePart = `${metadata.id}-${metadata.name}`;
|
|
4230
|
-
const newStoragePath = `media/${newAccessLevel}/${metadata.ownerId}/${metadata.collectionName}/${fileNamePart}`;
|
|
4231
|
-
console.log(
|
|
4232
|
-
`[MediaService] Moving file for ${mediaId} from ${oldStoragePath} to ${newStoragePath}`
|
|
4489
|
+
}
|
|
4490
|
+
/**
|
|
4491
|
+
* Uklanja kliniku iz liste klinika kojima admin upravlja
|
|
4492
|
+
*/
|
|
4493
|
+
async removeClinicFromManaged(adminId, clinicId, requesterId) {
|
|
4494
|
+
return removeClinicFromManaged(
|
|
4495
|
+
this.db,
|
|
4496
|
+
adminId,
|
|
4497
|
+
clinicId,
|
|
4498
|
+
requesterId
|
|
4233
4499
|
);
|
|
4234
|
-
const oldStorageFileRef = (0, import_storage4.ref)(this.storage, oldStoragePath);
|
|
4235
|
-
const newStorageFileRef = (0, import_storage4.ref)(this.storage, newStoragePath);
|
|
4236
|
-
try {
|
|
4237
|
-
console.log(`[MediaService] Downloading bytes from ${oldStoragePath}`);
|
|
4238
|
-
const fileBytes = await (0, import_storage4.getBytes)(oldStorageFileRef);
|
|
4239
|
-
console.log(
|
|
4240
|
-
`[MediaService] Successfully downloaded ${fileBytes.byteLength} bytes from ${oldStoragePath}`
|
|
4241
|
-
);
|
|
4242
|
-
console.log(`[MediaService] Uploading bytes to ${newStoragePath}`);
|
|
4243
|
-
await (0, import_storage4.uploadBytes)(newStorageFileRef, fileBytes, {
|
|
4244
|
-
contentType: metadata.contentType
|
|
4245
|
-
});
|
|
4246
|
-
console.log(
|
|
4247
|
-
`[MediaService] Successfully uploaded bytes to ${newStoragePath}`
|
|
4248
|
-
);
|
|
4249
|
-
const newDownloadURL = await (0, import_storage4.getDownloadURL)(newStorageFileRef);
|
|
4250
|
-
console.log(
|
|
4251
|
-
`[MediaService] Got new download URL for ${newStoragePath}: ${newDownloadURL}`
|
|
4252
|
-
);
|
|
4253
|
-
const updateData = {
|
|
4254
|
-
accessLevel: newAccessLevel,
|
|
4255
|
-
path: newStoragePath,
|
|
4256
|
-
url: newDownloadURL,
|
|
4257
|
-
updatedAt: import_firestore15.Timestamp.now()
|
|
4258
|
-
};
|
|
4259
|
-
const metadataDocRef = (0, import_firestore16.doc)(this.db, MEDIA_METADATA_COLLECTION, mediaId);
|
|
4260
|
-
console.log(
|
|
4261
|
-
`[MediaService] Updating Firestore metadata for ${mediaId} with new data:`,
|
|
4262
|
-
updateData
|
|
4263
|
-
);
|
|
4264
|
-
await (0, import_firestore16.updateDoc)(metadataDocRef, updateData);
|
|
4265
|
-
console.log(
|
|
4266
|
-
`[MediaService] Successfully updated Firestore metadata for ${mediaId}`
|
|
4267
|
-
);
|
|
4268
|
-
try {
|
|
4269
|
-
console.log(`[MediaService] Deleting old file from ${oldStoragePath}`);
|
|
4270
|
-
await (0, import_storage4.deleteObject)(oldStorageFileRef);
|
|
4271
|
-
console.log(
|
|
4272
|
-
`[MediaService] Successfully deleted old file from ${oldStoragePath}`
|
|
4273
|
-
);
|
|
4274
|
-
} catch (deleteError) {
|
|
4275
|
-
console.error(
|
|
4276
|
-
`[MediaService] Failed to delete old file from ${oldStoragePath} for media ID ${mediaId}. This file is now orphaned. Error:`,
|
|
4277
|
-
deleteError
|
|
4278
|
-
);
|
|
4279
|
-
}
|
|
4280
|
-
return { ...metadata, ...updateData };
|
|
4281
|
-
} catch (error) {
|
|
4282
|
-
console.error(
|
|
4283
|
-
`[MediaService] Error updating media access level and moving file for ${mediaId}:`,
|
|
4284
|
-
error
|
|
4285
|
-
);
|
|
4286
|
-
if (newStorageFileRef && error.code !== "storage/object-not-found" && ((_a = error.message) == null ? void 0 : _a.includes("uploadBytes"))) {
|
|
4287
|
-
console.warn(
|
|
4288
|
-
`[MediaService] Attempting to delete partially uploaded file at ${newStoragePath} due to error.`
|
|
4289
|
-
);
|
|
4290
|
-
try {
|
|
4291
|
-
await (0, import_storage4.deleteObject)(newStorageFileRef);
|
|
4292
|
-
console.warn(
|
|
4293
|
-
`[MediaService] Cleaned up partially uploaded file at ${newStoragePath}.`
|
|
4294
|
-
);
|
|
4295
|
-
} catch (cleanupError) {
|
|
4296
|
-
console.error(
|
|
4297
|
-
`[MediaService] Failed to cleanup partially uploaded file at ${newStoragePath}:`,
|
|
4298
|
-
cleanupError
|
|
4299
|
-
);
|
|
4300
|
-
}
|
|
4301
|
-
}
|
|
4302
|
-
throw error;
|
|
4303
|
-
}
|
|
4304
4500
|
}
|
|
4305
4501
|
/**
|
|
4306
|
-
*
|
|
4307
|
-
* @param ownerId - ID of the owner.
|
|
4308
|
-
* @param collectionName - Optional: Filter by collection name.
|
|
4309
|
-
* @param accessLevel - Optional: Filter by access level.
|
|
4310
|
-
* @param count - Optional: Number of items to fetch.
|
|
4311
|
-
* @param startAfterId - Optional: ID of the document to start after (for pagination).
|
|
4502
|
+
* Dohvata sve klinike kojima admin upravlja
|
|
4312
4503
|
*/
|
|
4313
|
-
async
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
}
|
|
4319
|
-
if (accessLevel) {
|
|
4320
|
-
qConstraints.push((0, import_firestore16.where)("accessLevel", "==", accessLevel));
|
|
4321
|
-
}
|
|
4322
|
-
qConstraints.push((0, import_firestore16.orderBy)("createdAt", "desc"));
|
|
4323
|
-
if (count) {
|
|
4324
|
-
qConstraints.push((0, import_firestore16.limit)(count));
|
|
4325
|
-
}
|
|
4326
|
-
if (startAfterId) {
|
|
4327
|
-
const startAfterDoc = await this.getMediaMetadata(startAfterId);
|
|
4328
|
-
if (startAfterDoc) {
|
|
4329
|
-
}
|
|
4330
|
-
}
|
|
4331
|
-
const finalQuery = (0, import_firestore16.query)(
|
|
4332
|
-
(0, import_firestore16.collection)(this.db, MEDIA_METADATA_COLLECTION),
|
|
4333
|
-
...qConstraints
|
|
4504
|
+
async getManagedClinics(adminId) {
|
|
4505
|
+
return getManagedClinics(
|
|
4506
|
+
this.db,
|
|
4507
|
+
adminId,
|
|
4508
|
+
this.getClinicService()
|
|
4334
4509
|
);
|
|
4335
|
-
try {
|
|
4336
|
-
const querySnapshot = await (0, import_firestore16.getDocs)(finalQuery);
|
|
4337
|
-
const mediaList = querySnapshot.docs.map(
|
|
4338
|
-
(doc34) => doc34.data()
|
|
4339
|
-
);
|
|
4340
|
-
console.log(`[MediaService] Found ${mediaList.length} media items.`);
|
|
4341
|
-
return mediaList;
|
|
4342
|
-
} catch (error) {
|
|
4343
|
-
console.error("[MediaService] Error listing media:", error);
|
|
4344
|
-
throw error;
|
|
4345
|
-
}
|
|
4346
4510
|
}
|
|
4347
4511
|
/**
|
|
4348
|
-
*
|
|
4349
|
-
* @param mediaId - ID of the media.
|
|
4512
|
+
* Dohvata sve aktivne klinike kojima admin upravlja
|
|
4350
4513
|
*/
|
|
4351
|
-
async
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
}
|
|
4358
|
-
console.log(`[MediaService] URL not found for media ID: ${mediaId}`);
|
|
4359
|
-
return null;
|
|
4514
|
+
async getActiveManagedClinics(adminId) {
|
|
4515
|
+
return getActiveManagedClinics(
|
|
4516
|
+
this.db,
|
|
4517
|
+
adminId,
|
|
4518
|
+
this.getClinicService()
|
|
4519
|
+
);
|
|
4360
4520
|
}
|
|
4521
|
+
// TODO: Add more methods for clinic admins for managing permissions, editing profiles by the admin, or by the clinic group owner and so on
|
|
4522
|
+
// Generally refactor admin permissions and clinic group permissions and systems for admin management
|
|
4361
4523
|
};
|
|
4362
4524
|
|
|
4525
|
+
// src/services/practitioner/practitioner.service.ts
|
|
4526
|
+
var import_firestore18 = require("firebase/firestore");
|
|
4527
|
+
|
|
4363
4528
|
// src/validations/practitioner.schema.ts
|
|
4364
4529
|
var import_zod14 = require("zod");
|
|
4365
4530
|
var import_firestore17 = require("firebase/firestore");
|
|
@@ -5647,7 +5812,7 @@ var import_geofire_common3 = require("geofire-common");
|
|
|
5647
5812
|
var import_zod17 = require("zod");
|
|
5648
5813
|
|
|
5649
5814
|
// src/services/clinic/utils/photos.utils.ts
|
|
5650
|
-
var
|
|
5815
|
+
var import_storage4 = require("firebase/storage");
|
|
5651
5816
|
async function uploadPhoto(photo, entityType, entityId, photoType, app, fileName) {
|
|
5652
5817
|
if (!photo || typeof photo !== "string" || !photo.startsWith("data:")) {
|
|
5653
5818
|
return photo;
|
|
@@ -5656,9 +5821,9 @@ async function uploadPhoto(photo, entityType, entityId, photoType, app, fileName
|
|
|
5656
5821
|
console.log(
|
|
5657
5822
|
`[PHOTO_UTILS] Uploading ${photoType} for ${entityType}/${entityId}`
|
|
5658
5823
|
);
|
|
5659
|
-
const storage = (0,
|
|
5824
|
+
const storage = (0, import_storage4.getStorage)(app);
|
|
5660
5825
|
const storageFileName = fileName || `${photoType}-${Date.now()}`;
|
|
5661
|
-
const storageRef = (0,
|
|
5826
|
+
const storageRef = (0, import_storage4.ref)(
|
|
5662
5827
|
storage,
|
|
5663
5828
|
`${entityType}/${entityId}/${storageFileName}`
|
|
5664
5829
|
);
|
|
@@ -5670,8 +5835,8 @@ async function uploadPhoto(photo, entityType, entityId, photoType, app, fileName
|
|
|
5670
5835
|
byteArrays.push(byteCharacters.charCodeAt(i));
|
|
5671
5836
|
}
|
|
5672
5837
|
const blob = new Blob([new Uint8Array(byteArrays)], { type: contentType });
|
|
5673
|
-
await (0,
|
|
5674
|
-
const downloadUrl = await (0,
|
|
5838
|
+
await (0, import_storage4.uploadBytes)(storageRef, blob, { contentType });
|
|
5839
|
+
const downloadUrl = await (0, import_storage4.getDownloadURL)(storageRef);
|
|
5675
5840
|
console.log(`[PHOTO_UTILS] ${photoType} uploaded successfully`, {
|
|
5676
5841
|
downloadUrl
|
|
5677
5842
|
});
|