@blackcode_sa/metaestetics-api 1.4.8 → 1.4.10
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/index.d.mts +31 -16
- package/dist/index.d.ts +31 -16
- package/dist/index.js +742 -187
- package/dist/index.mjs +761 -199
- package/package.json +1 -1
- package/src/services/auth.service.ts +33 -11
- package/src/services/clinic/clinic-group.service.ts +63 -9
- package/src/services/clinic/clinic.service.ts +32 -9
- package/src/services/clinic/utils/admin.utils.ts +6 -51
- package/src/services/clinic/utils/clinic-group.utils.ts +178 -45
- package/src/services/clinic/utils/clinic.utils.ts +482 -39
- package/src/services/clinic/utils/photos.utils.ts +188 -0
- package/src/services/clinic/utils/review.utils.ts +24 -17
- package/src/services/clinic/utils/tag.utils.ts +33 -8
- package/src/types/clinic/index.ts +8 -5
- package/src/validations/clinic.schema.ts +6 -3
package/dist/index.mjs
CHANGED
|
@@ -2375,7 +2375,7 @@ var clinicGroupSchema = z9.object({
|
|
|
2375
2375
|
admins: z9.array(z9.string()),
|
|
2376
2376
|
adminsInfo: z9.array(adminInfoSchema),
|
|
2377
2377
|
adminTokens: z9.array(adminTokenSchema),
|
|
2378
|
-
ownerId: z9.string(),
|
|
2378
|
+
ownerId: z9.string().nullable(),
|
|
2379
2379
|
createdAt: z9.instanceof(Date).or(z9.instanceof(Timestamp5)),
|
|
2380
2380
|
// Timestamp
|
|
2381
2381
|
updatedAt: z9.instanceof(Date).or(z9.instanceof(Timestamp5)),
|
|
@@ -2386,7 +2386,8 @@ var clinicGroupSchema = z9.object({
|
|
|
2386
2386
|
languages: z9.array(z9.nativeEnum(Language)).optional(),
|
|
2387
2387
|
subscriptionModel: z9.nativeEnum(SubscriptionModel),
|
|
2388
2388
|
calendarSyncEnabled: z9.boolean().optional(),
|
|
2389
|
-
autoConfirmAppointments: z9.boolean().optional()
|
|
2389
|
+
autoConfirmAppointments: z9.boolean().optional(),
|
|
2390
|
+
businessIdentificationNumber: z9.string().optional().nullable()
|
|
2390
2391
|
});
|
|
2391
2392
|
var clinicReviewSchema = z9.object({
|
|
2392
2393
|
id: z9.string(),
|
|
@@ -2451,14 +2452,15 @@ var createClinicGroupSchema = z9.object({
|
|
|
2451
2452
|
hqLocation: clinicLocationSchema,
|
|
2452
2453
|
contactInfo: clinicContactInfoSchema,
|
|
2453
2454
|
contactPerson: contactPersonSchema,
|
|
2454
|
-
ownerId: z9.string(),
|
|
2455
|
+
ownerId: z9.string().nullable(),
|
|
2455
2456
|
isActive: z9.boolean(),
|
|
2456
2457
|
logo: z9.string().optional().nullable(),
|
|
2457
2458
|
practiceType: z9.nativeEnum(PracticeType).optional(),
|
|
2458
2459
|
languages: z9.array(z9.nativeEnum(Language)).optional(),
|
|
2459
2460
|
subscriptionModel: z9.nativeEnum(SubscriptionModel).optional().default("no_subscription" /* NO_SUBSCRIPTION */),
|
|
2460
2461
|
calendarSyncEnabled: z9.boolean().optional(),
|
|
2461
|
-
autoConfirmAppointments: z9.boolean().optional()
|
|
2462
|
+
autoConfirmAppointments: z9.boolean().optional(),
|
|
2463
|
+
businessIdentificationNumber: z9.string().optional().nullable()
|
|
2462
2464
|
});
|
|
2463
2465
|
var createClinicSchema = z9.object({
|
|
2464
2466
|
clinicGroupId: z9.string(),
|
|
@@ -2485,7 +2487,7 @@ var createClinicSchema = z9.object({
|
|
|
2485
2487
|
});
|
|
2486
2488
|
var createDefaultClinicGroupSchema = z9.object({
|
|
2487
2489
|
name: z9.string(),
|
|
2488
|
-
ownerId: z9.string(),
|
|
2490
|
+
ownerId: z9.string().nullable(),
|
|
2489
2491
|
contactPerson: contactPersonSchema,
|
|
2490
2492
|
contactInfo: clinicContactInfoSchema,
|
|
2491
2493
|
hqLocation: clinicLocationSchema,
|
|
@@ -2518,7 +2520,8 @@ var clinicGroupSetupSchema = z9.object({
|
|
|
2518
2520
|
description: z9.string(),
|
|
2519
2521
|
logo: z9.string(),
|
|
2520
2522
|
calendarSyncEnabled: z9.boolean(),
|
|
2521
|
-
autoConfirmAppointments: z9.boolean()
|
|
2523
|
+
autoConfirmAppointments: z9.boolean(),
|
|
2524
|
+
businessIdentificationNumber: z9.string().optional().nullable()
|
|
2522
2525
|
});
|
|
2523
2526
|
var clinicBranchSetupSchema = z9.object({
|
|
2524
2527
|
name: z9.string(),
|
|
@@ -2583,45 +2586,7 @@ async function createClinicAdmin(db, data, clinicGroupService) {
|
|
|
2583
2586
|
hasGroupId: !!clinicGroupId
|
|
2584
2587
|
});
|
|
2585
2588
|
if (validatedData.isGroupOwner && !clinicGroupId) {
|
|
2586
|
-
console.log("[CLINIC_ADMIN]
|
|
2587
|
-
const defaultGroup = {
|
|
2588
|
-
name: `${validatedData.contactInfo.firstName}'s Group`,
|
|
2589
|
-
ownerId: validatedData.userRef,
|
|
2590
|
-
contactPerson: validatedData.contactInfo,
|
|
2591
|
-
contactInfo: {
|
|
2592
|
-
email: validatedData.contactInfo.email,
|
|
2593
|
-
phoneNumber: validatedData.contactInfo.phoneNumber || ""
|
|
2594
|
-
},
|
|
2595
|
-
hqLocation: {
|
|
2596
|
-
address: "",
|
|
2597
|
-
city: "",
|
|
2598
|
-
country: "",
|
|
2599
|
-
postalCode: "",
|
|
2600
|
-
latitude: 0,
|
|
2601
|
-
longitude: 0
|
|
2602
|
-
},
|
|
2603
|
-
isActive: true
|
|
2604
|
-
};
|
|
2605
|
-
console.log("[CLINIC_ADMIN] Default group data prepared", {
|
|
2606
|
-
groupName: defaultGroup.name
|
|
2607
|
-
});
|
|
2608
|
-
try {
|
|
2609
|
-
const clinicGroup = await clinicGroupService.createClinicGroup(
|
|
2610
|
-
defaultGroup,
|
|
2611
|
-
validatedData.userRef,
|
|
2612
|
-
true
|
|
2613
|
-
);
|
|
2614
|
-
clinicGroupId = clinicGroup.id;
|
|
2615
|
-
console.log("[CLINIC_ADMIN] Default group created successfully", {
|
|
2616
|
-
groupId: clinicGroupId
|
|
2617
|
-
});
|
|
2618
|
-
} catch (groupCreationError) {
|
|
2619
|
-
console.error(
|
|
2620
|
-
"[CLINIC_ADMIN] Error creating default group:",
|
|
2621
|
-
groupCreationError
|
|
2622
|
-
);
|
|
2623
|
-
throw groupCreationError;
|
|
2624
|
-
}
|
|
2589
|
+
console.log("[CLINIC_ADMIN] Owner will be assigned to group later");
|
|
2625
2590
|
} else if (!validatedData.isGroupOwner && !clinicGroupId) {
|
|
2626
2591
|
console.error("[CLINIC_ADMIN] Missing clinic group ID for non-owner admin");
|
|
2627
2592
|
throw new Error("Clinic group ID is required for non-owner admins");
|
|
@@ -2651,16 +2616,12 @@ async function createClinicAdmin(db, data, clinicGroupService) {
|
|
|
2651
2616
|
}
|
|
2652
2617
|
}
|
|
2653
2618
|
console.log("[CLINIC_ADMIN] Preparing admin data object");
|
|
2654
|
-
if (!clinicGroupId) {
|
|
2655
|
-
console.error(
|
|
2656
|
-
"[CLINIC_ADMIN] clinicGroupId is undefined, which should not happen at this point"
|
|
2657
|
-
);
|
|
2658
|
-
throw new Error("clinicGroupId is required but was undefined");
|
|
2659
|
-
}
|
|
2660
2619
|
const adminData = {
|
|
2661
|
-
id:
|
|
2620
|
+
id: doc4(collection2(db, CLINIC_ADMINS_COLLECTION)).id,
|
|
2621
|
+
// Generate a new ID for the admin document
|
|
2662
2622
|
userRef: validatedData.userRef,
|
|
2663
|
-
clinicGroupId,
|
|
2623
|
+
clinicGroupId: clinicGroupId || "",
|
|
2624
|
+
// Empty string for now if no group ID
|
|
2664
2625
|
isGroupOwner: validatedData.isGroupOwner,
|
|
2665
2626
|
clinicsManaged: [],
|
|
2666
2627
|
// Uvek krećemo od prazne liste
|
|
@@ -3706,6 +3667,65 @@ import {
|
|
|
3706
3667
|
} from "firebase/firestore";
|
|
3707
3668
|
import { geohashForLocation as geohashForLocation2 } from "geofire-common";
|
|
3708
3669
|
import { z as z13 } from "zod";
|
|
3670
|
+
|
|
3671
|
+
// src/services/clinic/utils/photos.utils.ts
|
|
3672
|
+
import {
|
|
3673
|
+
getStorage as getStorage2,
|
|
3674
|
+
ref as ref2,
|
|
3675
|
+
uploadBytes as uploadBytes2,
|
|
3676
|
+
getDownloadURL as getDownloadURL2,
|
|
3677
|
+
deleteObject as deleteObject2
|
|
3678
|
+
} from "firebase/storage";
|
|
3679
|
+
async function uploadPhoto(photo, entityType, entityId, photoType, app, fileName) {
|
|
3680
|
+
if (!photo || typeof photo !== "string" || !photo.startsWith("data:")) {
|
|
3681
|
+
return photo;
|
|
3682
|
+
}
|
|
3683
|
+
try {
|
|
3684
|
+
console.log(
|
|
3685
|
+
`[PHOTO_UTILS] Uploading ${photoType} for ${entityType}/${entityId}`
|
|
3686
|
+
);
|
|
3687
|
+
const storage = getStorage2(app);
|
|
3688
|
+
const storageFileName = fileName || `${photoType}-${Date.now()}`;
|
|
3689
|
+
const storageRef = ref2(
|
|
3690
|
+
storage,
|
|
3691
|
+
`${entityType}/${entityId}/${storageFileName}`
|
|
3692
|
+
);
|
|
3693
|
+
const base64Data = photo.split(",")[1];
|
|
3694
|
+
const contentType = photo.split(";")[0].split(":")[1];
|
|
3695
|
+
const byteCharacters = atob(base64Data);
|
|
3696
|
+
const byteArrays = [];
|
|
3697
|
+
for (let i = 0; i < byteCharacters.length; i++) {
|
|
3698
|
+
byteArrays.push(byteCharacters.charCodeAt(i));
|
|
3699
|
+
}
|
|
3700
|
+
const blob = new Blob([new Uint8Array(byteArrays)], { type: contentType });
|
|
3701
|
+
await uploadBytes2(storageRef, blob, { contentType });
|
|
3702
|
+
const downloadUrl = await getDownloadURL2(storageRef);
|
|
3703
|
+
console.log(`[PHOTO_UTILS] ${photoType} uploaded successfully`, {
|
|
3704
|
+
downloadUrl
|
|
3705
|
+
});
|
|
3706
|
+
return downloadUrl;
|
|
3707
|
+
} catch (error) {
|
|
3708
|
+
console.error(`[PHOTO_UTILS] Error uploading ${photoType}:`, error);
|
|
3709
|
+
return null;
|
|
3710
|
+
}
|
|
3711
|
+
}
|
|
3712
|
+
async function uploadMultiplePhotos(photos, entityType, entityId, photoType, app) {
|
|
3713
|
+
if (!photos || !Array.isArray(photos) || photos.length === 0) {
|
|
3714
|
+
return [];
|
|
3715
|
+
}
|
|
3716
|
+
const uploadPromises = photos.map(
|
|
3717
|
+
(photo, index) => uploadPhoto(photo, entityType, entityId, `${photoType}-${index}`, app)
|
|
3718
|
+
);
|
|
3719
|
+
try {
|
|
3720
|
+
const results = await Promise.all(uploadPromises);
|
|
3721
|
+
return results.filter((url) => url !== null);
|
|
3722
|
+
} catch (error) {
|
|
3723
|
+
console.error(`[PHOTO_UTILS] Error uploading multiple photos:`, error);
|
|
3724
|
+
return photos.filter((photo) => !photo.startsWith("data:"));
|
|
3725
|
+
}
|
|
3726
|
+
}
|
|
3727
|
+
|
|
3728
|
+
// src/services/clinic/utils/clinic-group.utils.ts
|
|
3709
3729
|
function generateId() {
|
|
3710
3730
|
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
3711
3731
|
const timestamp = Date.now().toString(36);
|
|
@@ -3715,7 +3735,8 @@ function generateId() {
|
|
|
3715
3735
|
).join("");
|
|
3716
3736
|
return `${randomPart}-${timestamp}`;
|
|
3717
3737
|
}
|
|
3718
|
-
async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdminService) {
|
|
3738
|
+
async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdminService, app) {
|
|
3739
|
+
var _a, _b, _c, _d, _e;
|
|
3719
3740
|
console.log("[CLINIC_GROUP] Starting clinic group creation", {
|
|
3720
3741
|
ownerId,
|
|
3721
3742
|
isDefault
|
|
@@ -3769,23 +3790,49 @@ async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdm
|
|
|
3769
3790
|
}
|
|
3770
3791
|
const now = Timestamp10.now();
|
|
3771
3792
|
console.log("[CLINIC_GROUP] Preparing clinic group data object");
|
|
3793
|
+
const groupId = doc7(collection5(db, CLINIC_GROUPS_COLLECTION)).id;
|
|
3772
3794
|
console.log("[CLINIC_GROUP] Logo value:", {
|
|
3773
3795
|
logoValue: validatedData.logo,
|
|
3774
3796
|
logoType: validatedData.logo === null ? "null" : typeof validatedData.logo
|
|
3775
3797
|
});
|
|
3798
|
+
let logoUrl = await uploadPhoto(
|
|
3799
|
+
validatedData.logo || null,
|
|
3800
|
+
"clinic-groups",
|
|
3801
|
+
groupId,
|
|
3802
|
+
"logo",
|
|
3803
|
+
app
|
|
3804
|
+
);
|
|
3805
|
+
console.log("[CLINIC_GROUP] Logo processed", { logoUrl });
|
|
3776
3806
|
const groupData = {
|
|
3777
3807
|
...validatedData,
|
|
3778
|
-
id:
|
|
3808
|
+
id: groupId,
|
|
3809
|
+
name: validatedData.name,
|
|
3810
|
+
logo: logoUrl,
|
|
3811
|
+
// Use the uploaded logo URL or the original value
|
|
3779
3812
|
description: isDefault ? void 0 : validatedData.description || void 0,
|
|
3780
3813
|
hqLocation: {
|
|
3781
|
-
|
|
3814
|
+
address: validatedData.hqLocation.address || "",
|
|
3815
|
+
city: validatedData.hqLocation.city || "",
|
|
3816
|
+
country: validatedData.hqLocation.country || "",
|
|
3817
|
+
postalCode: validatedData.hqLocation.postalCode || "",
|
|
3818
|
+
latitude: validatedData.hqLocation.latitude || 0,
|
|
3819
|
+
longitude: validatedData.hqLocation.longitude || 0,
|
|
3782
3820
|
geohash: validatedData.hqLocation.geohash || void 0
|
|
3783
3821
|
},
|
|
3784
3822
|
contactInfo: {
|
|
3785
|
-
|
|
3823
|
+
email: validatedData.contactInfo.email || "",
|
|
3824
|
+
phoneNumber: validatedData.contactInfo.phoneNumber || "",
|
|
3786
3825
|
alternativePhoneNumber: isDefault ? void 0 : validatedData.contactInfo.alternativePhoneNumber || void 0,
|
|
3787
3826
|
website: isDefault ? void 0 : validatedData.contactInfo.website || void 0
|
|
3788
3827
|
},
|
|
3828
|
+
contactPerson: {
|
|
3829
|
+
firstName: ((_a = validatedData.contactPerson) == null ? void 0 : _a.firstName) || "",
|
|
3830
|
+
lastName: ((_b = validatedData.contactPerson) == null ? void 0 : _b.lastName) || "",
|
|
3831
|
+
email: ((_c = validatedData.contactPerson) == null ? void 0 : _c.email) || "",
|
|
3832
|
+
title: ((_d = validatedData.contactPerson) == null ? void 0 : _d.title) || null,
|
|
3833
|
+
phoneNumber: ((_e = validatedData.contactPerson) == null ? void 0 : _e.phoneNumber) || null
|
|
3834
|
+
},
|
|
3835
|
+
subscriptionModel: validatedData.subscriptionModel || "no_subscription" /* NO_SUBSCRIPTION */,
|
|
3789
3836
|
clinics: [],
|
|
3790
3837
|
clinicsInfo: [],
|
|
3791
3838
|
admins: [ownerId],
|
|
@@ -3873,35 +3920,75 @@ async function getAllActiveGroups(db) {
|
|
|
3873
3920
|
const querySnapshot = await getDocs5(q);
|
|
3874
3921
|
return querySnapshot.docs.map((doc14) => doc14.data());
|
|
3875
3922
|
}
|
|
3876
|
-
async function updateClinicGroup(db, groupId, data) {
|
|
3923
|
+
async function updateClinicGroup(db, groupId, data, app) {
|
|
3924
|
+
console.log("[CLINIC_GROUP] Updating clinic group", { groupId });
|
|
3877
3925
|
const group = await getClinicGroup(db, groupId);
|
|
3878
3926
|
if (!group) {
|
|
3927
|
+
console.error("[CLINIC_GROUP] Clinic group not found", { groupId });
|
|
3879
3928
|
throw new Error("Clinic group not found");
|
|
3880
3929
|
}
|
|
3881
|
-
|
|
3882
|
-
|
|
3930
|
+
let updatedData = { ...data };
|
|
3931
|
+
if (data.logo && typeof data.logo === "string" && data.logo.startsWith("data:")) {
|
|
3932
|
+
console.log("[CLINIC_GROUP] Processing logo for update");
|
|
3933
|
+
try {
|
|
3934
|
+
const logoUrl = await uploadPhoto(
|
|
3935
|
+
data.logo,
|
|
3936
|
+
"clinic-groups",
|
|
3937
|
+
groupId,
|
|
3938
|
+
"logo",
|
|
3939
|
+
app
|
|
3940
|
+
);
|
|
3941
|
+
console.log("[CLINIC_GROUP] Logo processed for update", { logoUrl });
|
|
3942
|
+
updatedData.logo = logoUrl;
|
|
3943
|
+
} catch (error) {
|
|
3944
|
+
console.error("[CLINIC_GROUP] Error processing logo for update:", error);
|
|
3945
|
+
}
|
|
3946
|
+
}
|
|
3947
|
+
updatedData = {
|
|
3948
|
+
...updatedData,
|
|
3883
3949
|
updatedAt: Timestamp10.now()
|
|
3884
3950
|
};
|
|
3951
|
+
console.log("[CLINIC_GROUP] Updating clinic group in Firestore");
|
|
3885
3952
|
await updateDoc10(doc7(db, CLINIC_GROUPS_COLLECTION, groupId), updatedData);
|
|
3953
|
+
console.log("[CLINIC_GROUP] Clinic group updated successfully");
|
|
3886
3954
|
const updatedGroup = await getClinicGroup(db, groupId);
|
|
3887
3955
|
if (!updatedGroup) {
|
|
3956
|
+
console.error("[CLINIC_GROUP] Failed to retrieve updated clinic group");
|
|
3888
3957
|
throw new Error("Failed to retrieve updated clinic group");
|
|
3889
3958
|
}
|
|
3890
3959
|
return updatedGroup;
|
|
3891
3960
|
}
|
|
3892
|
-
async function addAdminToGroup(db, groupId, adminId) {
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3961
|
+
async function addAdminToGroup(db, groupId, adminId, app) {
|
|
3962
|
+
console.log("[CLINIC_GROUP] Adding admin to group", { groupId, adminId });
|
|
3963
|
+
try {
|
|
3964
|
+
const group = await getClinicGroup(db, groupId);
|
|
3965
|
+
if (!group) {
|
|
3966
|
+
console.error("[CLINIC_GROUP] Clinic group not found", { groupId });
|
|
3967
|
+
throw new Error("Clinic group not found");
|
|
3968
|
+
}
|
|
3969
|
+
if (group.admins.includes(adminId)) {
|
|
3970
|
+
console.log("[CLINIC_GROUP] Admin is already in the group", {
|
|
3971
|
+
adminId,
|
|
3972
|
+
groupId
|
|
3973
|
+
});
|
|
3974
|
+
return;
|
|
3975
|
+
}
|
|
3976
|
+
console.log("[CLINIC_GROUP] Updating group with new admin");
|
|
3977
|
+
await updateClinicGroup(
|
|
3978
|
+
db,
|
|
3979
|
+
groupId,
|
|
3980
|
+
{
|
|
3981
|
+
admins: [...group.admins, adminId]
|
|
3982
|
+
},
|
|
3983
|
+
app
|
|
3984
|
+
);
|
|
3985
|
+
console.log("[CLINIC_GROUP] Admin added to group successfully");
|
|
3986
|
+
} catch (error) {
|
|
3987
|
+
console.error("[CLINIC_GROUP] Error adding admin to group:", error);
|
|
3988
|
+
throw error;
|
|
3899
3989
|
}
|
|
3900
|
-
await updateClinicGroup(db, groupId, {
|
|
3901
|
-
admins: [...group.admins, adminId]
|
|
3902
|
-
});
|
|
3903
3990
|
}
|
|
3904
|
-
async function removeAdminFromGroup(db, groupId, adminId) {
|
|
3991
|
+
async function removeAdminFromGroup(db, groupId, adminId, app) {
|
|
3905
3992
|
const group = await getClinicGroup(db, groupId);
|
|
3906
3993
|
if (!group) {
|
|
3907
3994
|
throw new Error("Clinic group not found");
|
|
@@ -3912,21 +3999,30 @@ async function removeAdminFromGroup(db, groupId, adminId) {
|
|
|
3912
3999
|
if (!group.admins.includes(adminId)) {
|
|
3913
4000
|
return;
|
|
3914
4001
|
}
|
|
3915
|
-
await updateClinicGroup(
|
|
3916
|
-
|
|
3917
|
-
|
|
4002
|
+
await updateClinicGroup(
|
|
4003
|
+
db,
|
|
4004
|
+
groupId,
|
|
4005
|
+
{
|
|
4006
|
+
admins: group.admins.filter((id) => id !== adminId)
|
|
4007
|
+
},
|
|
4008
|
+
app
|
|
4009
|
+
);
|
|
3918
4010
|
}
|
|
3919
|
-
async function deactivateClinicGroup(db, groupId) {
|
|
4011
|
+
async function deactivateClinicGroup(db, groupId, app) {
|
|
3920
4012
|
const group = await getClinicGroup(db, groupId);
|
|
3921
4013
|
if (!group) {
|
|
3922
4014
|
throw new Error("Clinic group not found");
|
|
3923
4015
|
}
|
|
3924
|
-
await
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
4016
|
+
await updateClinicGroup(
|
|
4017
|
+
db,
|
|
4018
|
+
groupId,
|
|
4019
|
+
{
|
|
4020
|
+
isActive: false
|
|
4021
|
+
},
|
|
4022
|
+
app
|
|
4023
|
+
);
|
|
3928
4024
|
}
|
|
3929
|
-
async function createAdminToken(db, groupId, creatorAdminId, data) {
|
|
4025
|
+
async function createAdminToken(db, groupId, creatorAdminId, app, data) {
|
|
3930
4026
|
const group = await getClinicGroup(db, groupId);
|
|
3931
4027
|
if (!group) {
|
|
3932
4028
|
throw new Error("Clinic group not found");
|
|
@@ -3947,12 +4043,17 @@ async function createAdminToken(db, groupId, creatorAdminId, data) {
|
|
|
3947
4043
|
createdAt: now,
|
|
3948
4044
|
expiresAt
|
|
3949
4045
|
};
|
|
3950
|
-
await updateClinicGroup(
|
|
3951
|
-
|
|
3952
|
-
|
|
4046
|
+
await updateClinicGroup(
|
|
4047
|
+
db,
|
|
4048
|
+
groupId,
|
|
4049
|
+
{
|
|
4050
|
+
adminTokens: [...group.adminTokens, token]
|
|
4051
|
+
},
|
|
4052
|
+
app
|
|
4053
|
+
);
|
|
3953
4054
|
return token;
|
|
3954
4055
|
}
|
|
3955
|
-
async function verifyAndUseAdminToken(db, groupId, token, userRef) {
|
|
4056
|
+
async function verifyAndUseAdminToken(db, groupId, token, userRef, app) {
|
|
3956
4057
|
const group = await getClinicGroup(db, groupId);
|
|
3957
4058
|
if (!group) {
|
|
3958
4059
|
throw new Error("Clinic group not found");
|
|
@@ -3969,9 +4070,14 @@ async function verifyAndUseAdminToken(db, groupId, token, userRef) {
|
|
|
3969
4070
|
const updatedTokens2 = group.adminTokens.map(
|
|
3970
4071
|
(t) => t.id === adminToken.id ? { ...t, status: "expired" /* EXPIRED */ } : t
|
|
3971
4072
|
);
|
|
3972
|
-
await updateClinicGroup(
|
|
3973
|
-
|
|
3974
|
-
|
|
4073
|
+
await updateClinicGroup(
|
|
4074
|
+
db,
|
|
4075
|
+
groupId,
|
|
4076
|
+
{
|
|
4077
|
+
adminTokens: updatedTokens2
|
|
4078
|
+
},
|
|
4079
|
+
app
|
|
4080
|
+
);
|
|
3975
4081
|
throw new Error("Admin token has expired");
|
|
3976
4082
|
}
|
|
3977
4083
|
const updatedTokens = group.adminTokens.map(
|
|
@@ -3981,12 +4087,17 @@ async function verifyAndUseAdminToken(db, groupId, token, userRef) {
|
|
|
3981
4087
|
usedByUserRef: userRef
|
|
3982
4088
|
} : t
|
|
3983
4089
|
);
|
|
3984
|
-
await updateClinicGroup(
|
|
3985
|
-
|
|
3986
|
-
|
|
4090
|
+
await updateClinicGroup(
|
|
4091
|
+
db,
|
|
4092
|
+
groupId,
|
|
4093
|
+
{
|
|
4094
|
+
adminTokens: updatedTokens
|
|
4095
|
+
},
|
|
4096
|
+
app
|
|
4097
|
+
);
|
|
3987
4098
|
return true;
|
|
3988
4099
|
}
|
|
3989
|
-
async function deleteAdminToken(db, groupId, tokenId, adminId) {
|
|
4100
|
+
async function deleteAdminToken(db, groupId, tokenId, adminId, app) {
|
|
3990
4101
|
const group = await getClinicGroup(db, groupId);
|
|
3991
4102
|
if (!group) {
|
|
3992
4103
|
throw new Error("Clinic group not found");
|
|
@@ -3995,11 +4106,16 @@ async function deleteAdminToken(db, groupId, tokenId, adminId) {
|
|
|
3995
4106
|
throw new Error("Admin does not belong to this clinic group");
|
|
3996
4107
|
}
|
|
3997
4108
|
const updatedTokens = group.adminTokens.filter((t) => t.id !== tokenId);
|
|
3998
|
-
await updateClinicGroup(
|
|
3999
|
-
|
|
4000
|
-
|
|
4109
|
+
await updateClinicGroup(
|
|
4110
|
+
db,
|
|
4111
|
+
groupId,
|
|
4112
|
+
{
|
|
4113
|
+
adminTokens: updatedTokens
|
|
4114
|
+
},
|
|
4115
|
+
app
|
|
4116
|
+
);
|
|
4001
4117
|
}
|
|
4002
|
-
async function getActiveAdminTokens(db, groupId, adminId) {
|
|
4118
|
+
async function getActiveAdminTokens(db, groupId, adminId, app) {
|
|
4003
4119
|
const group = await getClinicGroup(db, groupId);
|
|
4004
4120
|
if (!group) {
|
|
4005
4121
|
throw new Error("Clinic group not found");
|
|
@@ -4025,7 +4141,8 @@ var ClinicGroupService = class extends BaseService {
|
|
|
4025
4141
|
data,
|
|
4026
4142
|
ownerId,
|
|
4027
4143
|
isDefault,
|
|
4028
|
-
this.clinicAdminService
|
|
4144
|
+
this.clinicAdminService,
|
|
4145
|
+
this.app
|
|
4029
4146
|
);
|
|
4030
4147
|
}
|
|
4031
4148
|
/**
|
|
@@ -4044,25 +4161,35 @@ var ClinicGroupService = class extends BaseService {
|
|
|
4044
4161
|
* Ažurira grupaciju klinika
|
|
4045
4162
|
*/
|
|
4046
4163
|
async updateClinicGroup(groupId, data) {
|
|
4047
|
-
return updateClinicGroup(this.db, groupId, data);
|
|
4164
|
+
return updateClinicGroup(this.db, groupId, data, this.app);
|
|
4048
4165
|
}
|
|
4049
4166
|
/**
|
|
4050
4167
|
* Dodaje admina u grupaciju
|
|
4051
4168
|
*/
|
|
4052
4169
|
async addAdminToGroup(groupId, adminId) {
|
|
4053
|
-
return addAdminToGroup(
|
|
4170
|
+
return addAdminToGroup(
|
|
4171
|
+
this.db,
|
|
4172
|
+
groupId,
|
|
4173
|
+
adminId,
|
|
4174
|
+
this.app
|
|
4175
|
+
);
|
|
4054
4176
|
}
|
|
4055
4177
|
/**
|
|
4056
4178
|
* Uklanja admina iz grupacije
|
|
4057
4179
|
*/
|
|
4058
4180
|
async removeAdminFromGroup(groupId, adminId) {
|
|
4059
|
-
return removeAdminFromGroup(
|
|
4181
|
+
return removeAdminFromGroup(
|
|
4182
|
+
this.db,
|
|
4183
|
+
groupId,
|
|
4184
|
+
adminId,
|
|
4185
|
+
this.app
|
|
4186
|
+
);
|
|
4060
4187
|
}
|
|
4061
4188
|
/**
|
|
4062
4189
|
* Deaktivira grupaciju klinika
|
|
4063
4190
|
*/
|
|
4064
4191
|
async deactivateClinicGroup(groupId) {
|
|
4065
|
-
return deactivateClinicGroup(this.db, groupId);
|
|
4192
|
+
return deactivateClinicGroup(this.db, groupId, this.app);
|
|
4066
4193
|
}
|
|
4067
4194
|
/**
|
|
4068
4195
|
* Sets up additional clinic group information after initial creation
|
|
@@ -4072,18 +4199,45 @@ var ClinicGroupService = class extends BaseService {
|
|
|
4072
4199
|
* @returns The updated clinic group
|
|
4073
4200
|
*/
|
|
4074
4201
|
async setupClinicGroup(groupId, setupData) {
|
|
4202
|
+
console.log("[CLINIC_GROUP] Setting up clinic group", { groupId });
|
|
4075
4203
|
const clinicGroup = await this.getClinicGroup(groupId);
|
|
4076
4204
|
if (!clinicGroup) {
|
|
4205
|
+
console.error("[CLINIC_GROUP] Clinic group not found", { groupId });
|
|
4077
4206
|
throw new Error(`Clinic group with ID ${groupId} not found`);
|
|
4078
4207
|
}
|
|
4208
|
+
let logoUrl = setupData.logo;
|
|
4209
|
+
if (logoUrl && typeof logoUrl === "string" && logoUrl.startsWith("data:")) {
|
|
4210
|
+
console.log("[CLINIC_GROUP] Processing logo in setupClinicGroup");
|
|
4211
|
+
try {
|
|
4212
|
+
const uploadedLogoUrl = await uploadPhoto(
|
|
4213
|
+
logoUrl,
|
|
4214
|
+
"clinic-groups",
|
|
4215
|
+
groupId,
|
|
4216
|
+
"logo",
|
|
4217
|
+
this.app
|
|
4218
|
+
);
|
|
4219
|
+
console.log("[CLINIC_GROUP] Logo processed in setupClinicGroup", {
|
|
4220
|
+
uploadedLogoUrl
|
|
4221
|
+
});
|
|
4222
|
+
if (uploadedLogoUrl !== null) {
|
|
4223
|
+
logoUrl = uploadedLogoUrl;
|
|
4224
|
+
}
|
|
4225
|
+
} catch (error) {
|
|
4226
|
+
console.error(
|
|
4227
|
+
"[CLINIC_GROUP] Error processing logo in setupClinicGroup:",
|
|
4228
|
+
error
|
|
4229
|
+
);
|
|
4230
|
+
}
|
|
4231
|
+
}
|
|
4079
4232
|
const updateData = {
|
|
4080
4233
|
languages: setupData.languages,
|
|
4081
4234
|
practiceType: setupData.practiceType,
|
|
4082
4235
|
description: setupData.description,
|
|
4083
|
-
logo:
|
|
4236
|
+
logo: logoUrl,
|
|
4084
4237
|
calendarSyncEnabled: setupData.calendarSyncEnabled,
|
|
4085
4238
|
autoConfirmAppointments: setupData.autoConfirmAppointments
|
|
4086
4239
|
};
|
|
4240
|
+
console.log("[CLINIC_GROUP] Updating clinic group with setup data");
|
|
4087
4241
|
return this.updateClinicGroup(groupId, updateData);
|
|
4088
4242
|
}
|
|
4089
4243
|
/**
|
|
@@ -4094,6 +4248,7 @@ var ClinicGroupService = class extends BaseService {
|
|
|
4094
4248
|
this.db,
|
|
4095
4249
|
groupId,
|
|
4096
4250
|
creatorAdminId,
|
|
4251
|
+
this.app,
|
|
4097
4252
|
data
|
|
4098
4253
|
);
|
|
4099
4254
|
}
|
|
@@ -4105,7 +4260,8 @@ var ClinicGroupService = class extends BaseService {
|
|
|
4105
4260
|
this.db,
|
|
4106
4261
|
groupId,
|
|
4107
4262
|
token,
|
|
4108
|
-
userRef
|
|
4263
|
+
userRef,
|
|
4264
|
+
this.app
|
|
4109
4265
|
);
|
|
4110
4266
|
}
|
|
4111
4267
|
/**
|
|
@@ -4116,14 +4272,20 @@ var ClinicGroupService = class extends BaseService {
|
|
|
4116
4272
|
this.db,
|
|
4117
4273
|
groupId,
|
|
4118
4274
|
tokenId,
|
|
4119
|
-
adminId
|
|
4275
|
+
adminId,
|
|
4276
|
+
this.app
|
|
4120
4277
|
);
|
|
4121
4278
|
}
|
|
4122
4279
|
/**
|
|
4123
4280
|
* Dohvata aktivne admin tokene
|
|
4124
4281
|
*/
|
|
4125
4282
|
async getActiveAdminTokens(groupId, adminId) {
|
|
4126
|
-
return getActiveAdminTokens(
|
|
4283
|
+
return getActiveAdminTokens(
|
|
4284
|
+
this.db,
|
|
4285
|
+
groupId,
|
|
4286
|
+
adminId,
|
|
4287
|
+
this.app
|
|
4288
|
+
);
|
|
4127
4289
|
}
|
|
4128
4290
|
};
|
|
4129
4291
|
|
|
@@ -4141,44 +4303,193 @@ import {
|
|
|
4141
4303
|
} from "firebase/firestore";
|
|
4142
4304
|
import { geohashForLocation as geohashForLocation3 } from "geofire-common";
|
|
4143
4305
|
import { z as z14 } from "zod";
|
|
4144
|
-
async function createClinic(db, data, creatorAdminId, clinicGroupService, clinicAdminService) {
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4306
|
+
async function createClinic(db, data, creatorAdminId, clinicGroupService, clinicAdminService, app) {
|
|
4307
|
+
var _a;
|
|
4308
|
+
console.log("[CLINIC] Starting clinic creation", { creatorAdminId });
|
|
4309
|
+
console.log("[CLINIC] Input data:", JSON.stringify(data, null, 2));
|
|
4310
|
+
try {
|
|
4311
|
+
const validatedData2 = createClinicSchema.parse(data);
|
|
4312
|
+
console.log("[CLINIC] Data validation passed");
|
|
4313
|
+
} catch (validationError) {
|
|
4314
|
+
console.error("[CLINIC] Data validation failed:", validationError);
|
|
4315
|
+
throw validationError;
|
|
4149
4316
|
}
|
|
4150
|
-
|
|
4151
|
-
|
|
4317
|
+
const validatedData = createClinicSchema.parse(data);
|
|
4318
|
+
try {
|
|
4319
|
+
console.log("[CLINIC] Checking if admin exists and belongs to group");
|
|
4320
|
+
const admin = await clinicAdminService.getClinicAdmin(creatorAdminId);
|
|
4321
|
+
if (!admin) {
|
|
4322
|
+
console.error("[CLINIC] Admin not found", { creatorAdminId });
|
|
4323
|
+
throw new Error("Admin not found");
|
|
4324
|
+
}
|
|
4325
|
+
if (admin.clinicGroupId !== validatedData.clinicGroupId) {
|
|
4326
|
+
console.error("[CLINIC] Admin does not belong to this clinic group", {
|
|
4327
|
+
adminGroupId: admin.clinicGroupId,
|
|
4328
|
+
requestedGroupId: validatedData.clinicGroupId
|
|
4329
|
+
});
|
|
4330
|
+
throw new Error("Admin does not belong to this clinic group");
|
|
4331
|
+
}
|
|
4332
|
+
console.log("[CLINIC] Admin verified");
|
|
4333
|
+
} catch (adminError) {
|
|
4334
|
+
console.error("[CLINIC] Error verifying admin:", adminError);
|
|
4335
|
+
throw adminError;
|
|
4152
4336
|
}
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4337
|
+
try {
|
|
4338
|
+
console.log("[CLINIC] Checking if clinic group exists");
|
|
4339
|
+
const group = await clinicGroupService.getClinicGroup(
|
|
4340
|
+
validatedData.clinicGroupId
|
|
4341
|
+
);
|
|
4342
|
+
if (!group) {
|
|
4343
|
+
console.error("[CLINIC] Clinic group not found", {
|
|
4344
|
+
groupId: validatedData.clinicGroupId
|
|
4345
|
+
});
|
|
4346
|
+
throw new Error("Clinic group not found");
|
|
4347
|
+
}
|
|
4348
|
+
console.log("[CLINIC] Clinic group verified");
|
|
4349
|
+
} catch (groupError) {
|
|
4350
|
+
console.error("[CLINIC] Error verifying clinic group:", groupError);
|
|
4351
|
+
throw groupError;
|
|
4158
4352
|
}
|
|
4353
|
+
console.log("[CLINIC] Generating geohash for location");
|
|
4159
4354
|
if (validatedData.location) {
|
|
4160
|
-
|
|
4161
|
-
validatedData.location.
|
|
4162
|
-
|
|
4163
|
-
|
|
4355
|
+
try {
|
|
4356
|
+
validatedData.location.geohash = geohashForLocation3([
|
|
4357
|
+
validatedData.location.latitude,
|
|
4358
|
+
validatedData.location.longitude
|
|
4359
|
+
]);
|
|
4360
|
+
console.log("[CLINIC] Geohash generated successfully", {
|
|
4361
|
+
geohash: validatedData.location.geohash
|
|
4362
|
+
});
|
|
4363
|
+
} catch (geohashError) {
|
|
4364
|
+
console.error("[CLINIC] Error generating geohash:", geohashError);
|
|
4365
|
+
throw geohashError;
|
|
4366
|
+
}
|
|
4367
|
+
}
|
|
4368
|
+
const clinicId = doc8(collection6(db, CLINICS_COLLECTION)).id;
|
|
4369
|
+
console.log("[CLINIC] Generated clinic ID:", clinicId);
|
|
4370
|
+
console.log("[CLINIC] Processing photos");
|
|
4371
|
+
let logoUrl = null;
|
|
4372
|
+
if (validatedData.logo) {
|
|
4373
|
+
console.log("[CLINIC] Processing logo");
|
|
4374
|
+
try {
|
|
4375
|
+
logoUrl = await uploadPhoto(
|
|
4376
|
+
validatedData.logo,
|
|
4377
|
+
"clinics",
|
|
4378
|
+
clinicId,
|
|
4379
|
+
"logo",
|
|
4380
|
+
app
|
|
4381
|
+
);
|
|
4382
|
+
console.log("[CLINIC] Logo processed", { logoUrl });
|
|
4383
|
+
} catch (logoError) {
|
|
4384
|
+
console.error("[CLINIC] Error processing logo:", logoError);
|
|
4385
|
+
}
|
|
4386
|
+
}
|
|
4387
|
+
let processedPhotos = [];
|
|
4388
|
+
if (validatedData.photos && validatedData.photos.length > 0) {
|
|
4389
|
+
console.log("[CLINIC] Processing regular photos");
|
|
4390
|
+
try {
|
|
4391
|
+
processedPhotos = await uploadMultiplePhotos(
|
|
4392
|
+
validatedData.photos,
|
|
4393
|
+
"clinics",
|
|
4394
|
+
clinicId,
|
|
4395
|
+
"photo",
|
|
4396
|
+
app
|
|
4397
|
+
);
|
|
4398
|
+
console.log("[CLINIC] Regular photos processed", {
|
|
4399
|
+
count: processedPhotos.length
|
|
4400
|
+
});
|
|
4401
|
+
} catch (photosError) {
|
|
4402
|
+
console.error("[CLINIC] Error processing regular photos:", photosError);
|
|
4403
|
+
processedPhotos = validatedData.photos.filter(
|
|
4404
|
+
(photo) => !photo.startsWith("data:")
|
|
4405
|
+
);
|
|
4406
|
+
}
|
|
4407
|
+
}
|
|
4408
|
+
let processedFeaturedPhotos = [];
|
|
4409
|
+
if (validatedData.featuredPhotos && validatedData.featuredPhotos.length > 0) {
|
|
4410
|
+
console.log("[CLINIC] Processing featured photos");
|
|
4411
|
+
try {
|
|
4412
|
+
processedFeaturedPhotos = await uploadMultiplePhotos(
|
|
4413
|
+
validatedData.featuredPhotos,
|
|
4414
|
+
"clinics",
|
|
4415
|
+
clinicId,
|
|
4416
|
+
"featured",
|
|
4417
|
+
app
|
|
4418
|
+
);
|
|
4419
|
+
console.log("[CLINIC] Featured photos processed", {
|
|
4420
|
+
count: processedFeaturedPhotos.length
|
|
4421
|
+
});
|
|
4422
|
+
} catch (featuredError) {
|
|
4423
|
+
console.error(
|
|
4424
|
+
"[CLINIC] Error processing featured photos:",
|
|
4425
|
+
featuredError
|
|
4426
|
+
);
|
|
4427
|
+
processedFeaturedPhotos = validatedData.featuredPhotos.filter(
|
|
4428
|
+
(photo) => !photo.startsWith("data:")
|
|
4429
|
+
);
|
|
4430
|
+
}
|
|
4431
|
+
}
|
|
4432
|
+
let processedPhotosWithTags = validatedData.photosWithTags || [];
|
|
4433
|
+
if (processedPhotosWithTags.length > 0) {
|
|
4434
|
+
console.log("[CLINIC] Processing photos with tags");
|
|
4435
|
+
try {
|
|
4436
|
+
const updatedPhotosWithTags = [];
|
|
4437
|
+
for (const photoWithTag of processedPhotosWithTags) {
|
|
4438
|
+
if (photoWithTag.url && photoWithTag.url.startsWith("data:")) {
|
|
4439
|
+
const uploadedUrl = await uploadPhoto(
|
|
4440
|
+
photoWithTag.url,
|
|
4441
|
+
"clinics",
|
|
4442
|
+
clinicId,
|
|
4443
|
+
`tagged-${photoWithTag.tag}`,
|
|
4444
|
+
app
|
|
4445
|
+
);
|
|
4446
|
+
if (uploadedUrl) {
|
|
4447
|
+
updatedPhotosWithTags.push({
|
|
4448
|
+
url: uploadedUrl,
|
|
4449
|
+
tag: photoWithTag.tag
|
|
4450
|
+
});
|
|
4451
|
+
}
|
|
4452
|
+
} else {
|
|
4453
|
+
updatedPhotosWithTags.push(photoWithTag);
|
|
4454
|
+
}
|
|
4455
|
+
}
|
|
4456
|
+
processedPhotosWithTags = updatedPhotosWithTags;
|
|
4457
|
+
console.log("[CLINIC] Photos with tags processed", {
|
|
4458
|
+
count: processedPhotosWithTags.length
|
|
4459
|
+
});
|
|
4460
|
+
} catch (tagsError) {
|
|
4461
|
+
console.error("[CLINIC] Error processing photos with tags:", tagsError);
|
|
4462
|
+
processedPhotosWithTags = ((_a = validatedData.photosWithTags) == null ? void 0 : _a.filter(
|
|
4463
|
+
(photo) => !photo.url.startsWith("data:")
|
|
4464
|
+
)) || [];
|
|
4465
|
+
}
|
|
4164
4466
|
}
|
|
4165
4467
|
const now = Timestamp11.now();
|
|
4468
|
+
console.log("[CLINIC] Preparing clinic data object");
|
|
4166
4469
|
const clinicData = {
|
|
4167
4470
|
...validatedData,
|
|
4168
|
-
id:
|
|
4471
|
+
id: clinicId,
|
|
4169
4472
|
description: validatedData.description || void 0,
|
|
4170
4473
|
location: {
|
|
4171
|
-
|
|
4474
|
+
address: validatedData.location.address || "",
|
|
4475
|
+
city: validatedData.location.city || "",
|
|
4476
|
+
country: validatedData.location.country || "",
|
|
4477
|
+
postalCode: validatedData.location.postalCode || "",
|
|
4478
|
+
latitude: validatedData.location.latitude || 0,
|
|
4479
|
+
longitude: validatedData.location.longitude || 0,
|
|
4172
4480
|
geohash: validatedData.location.geohash || void 0
|
|
4173
4481
|
},
|
|
4174
4482
|
contactInfo: {
|
|
4175
|
-
|
|
4483
|
+
email: validatedData.contactInfo.email || "",
|
|
4484
|
+
phoneNumber: validatedData.contactInfo.phoneNumber || "",
|
|
4176
4485
|
alternativePhoneNumber: validatedData.contactInfo.alternativePhoneNumber || void 0,
|
|
4177
4486
|
website: validatedData.contactInfo.website || void 0
|
|
4178
4487
|
},
|
|
4488
|
+
logo: logoUrl || void 0,
|
|
4179
4489
|
tags: validatedData.tags || [],
|
|
4180
|
-
featuredPhotos: [],
|
|
4181
|
-
photos:
|
|
4490
|
+
featuredPhotos: processedFeaturedPhotos || [],
|
|
4491
|
+
photos: processedPhotos || [],
|
|
4492
|
+
photosWithTags: processedPhotosWithTags,
|
|
4182
4493
|
doctors: [],
|
|
4183
4494
|
doctorsInfo: [],
|
|
4184
4495
|
services: [],
|
|
@@ -4193,17 +4504,73 @@ async function createClinic(db, data, creatorAdminId, clinicGroupService, clinic
|
|
|
4193
4504
|
isVerified: false
|
|
4194
4505
|
};
|
|
4195
4506
|
try {
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4507
|
+
console.log("[CLINIC] Validating complete clinic object");
|
|
4508
|
+
try {
|
|
4509
|
+
clinicSchema.parse(clinicData);
|
|
4510
|
+
console.log("[CLINIC] Clinic validation passed");
|
|
4511
|
+
} catch (schemaError) {
|
|
4512
|
+
console.error(
|
|
4513
|
+
"[CLINIC] Clinic validation failed:",
|
|
4514
|
+
JSON.stringify(schemaError, null, 2)
|
|
4515
|
+
);
|
|
4516
|
+
throw schemaError;
|
|
4517
|
+
}
|
|
4518
|
+
console.log("[CLINIC] Saving clinic to Firestore", {
|
|
4519
|
+
clinicId: clinicData.id
|
|
4520
|
+
});
|
|
4521
|
+
try {
|
|
4522
|
+
await setDoc10(doc8(db, CLINICS_COLLECTION, clinicData.id), clinicData);
|
|
4523
|
+
console.log("[CLINIC] Clinic saved successfully");
|
|
4524
|
+
} catch (firestoreError) {
|
|
4525
|
+
console.error("[CLINIC] Error saving to Firestore:", firestoreError);
|
|
4526
|
+
throw firestoreError;
|
|
4527
|
+
}
|
|
4528
|
+
console.log("[CLINIC] Adding clinic to clinic group");
|
|
4529
|
+
try {
|
|
4530
|
+
const group = await clinicGroupService.getClinicGroup(
|
|
4531
|
+
validatedData.clinicGroupId
|
|
4532
|
+
);
|
|
4533
|
+
if (group) {
|
|
4534
|
+
await clinicGroupService.updateClinicGroup(
|
|
4535
|
+
validatedData.clinicGroupId,
|
|
4536
|
+
{
|
|
4537
|
+
clinics: [...group.clinics, clinicData.id]
|
|
4538
|
+
}
|
|
4539
|
+
);
|
|
4540
|
+
console.log("[CLINIC] Clinic added to group successfully");
|
|
4541
|
+
}
|
|
4542
|
+
} catch (groupUpdateError) {
|
|
4543
|
+
console.error("[CLINIC] Error adding clinic to group:", groupUpdateError);
|
|
4544
|
+
}
|
|
4545
|
+
console.log("[CLINIC] Adding clinic to admin's managed clinics");
|
|
4546
|
+
try {
|
|
4547
|
+
await clinicAdminService.addClinicToManaged(
|
|
4548
|
+
creatorAdminId,
|
|
4549
|
+
clinicData.id
|
|
4550
|
+
);
|
|
4551
|
+
console.log(
|
|
4552
|
+
"[CLINIC] Clinic added to admin's managed clinics successfully"
|
|
4553
|
+
);
|
|
4554
|
+
} catch (adminUpdateError) {
|
|
4555
|
+
console.error(
|
|
4556
|
+
"[CLINIC] Error adding clinic to admin's managed clinics:",
|
|
4557
|
+
adminUpdateError
|
|
4558
|
+
);
|
|
4559
|
+
}
|
|
4560
|
+
console.log("[CLINIC] Clinic creation completed successfully", {
|
|
4561
|
+
clinicId: clinicData.id,
|
|
4562
|
+
clinicName: clinicData.name
|
|
4200
4563
|
});
|
|
4201
|
-
await clinicAdminService.addClinicToManaged(creatorAdminId, clinicData.id);
|
|
4202
4564
|
return clinicData;
|
|
4203
4565
|
} catch (error) {
|
|
4204
4566
|
if (error instanceof z14.ZodError) {
|
|
4567
|
+
console.error(
|
|
4568
|
+
"[CLINIC] Zod validation error:",
|
|
4569
|
+
JSON.stringify(error.errors, null, 2)
|
|
4570
|
+
);
|
|
4205
4571
|
throw new Error("Invalid clinic data: " + error.message);
|
|
4206
4572
|
}
|
|
4573
|
+
console.error("[CLINIC] Unhandled error in createClinic:", error);
|
|
4207
4574
|
throw error;
|
|
4208
4575
|
}
|
|
4209
4576
|
}
|
|
@@ -4224,27 +4591,177 @@ async function getClinicsByGroup(db, groupId) {
|
|
|
4224
4591
|
const querySnapshot = await getDocs6(q);
|
|
4225
4592
|
return querySnapshot.docs.map((doc14) => doc14.data());
|
|
4226
4593
|
}
|
|
4227
|
-
async function updateClinic(db, clinicId, data, adminId, clinicAdminService) {
|
|
4594
|
+
async function updateClinic(db, clinicId, data, adminId, clinicAdminService, app) {
|
|
4595
|
+
console.log("[CLINIC] Starting clinic update", { clinicId, adminId });
|
|
4228
4596
|
const clinic = await getClinic(db, clinicId);
|
|
4229
4597
|
if (!clinic) {
|
|
4598
|
+
console.error("[CLINIC] Clinic not found", { clinicId });
|
|
4230
4599
|
throw new Error("Clinic not found");
|
|
4231
4600
|
}
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4601
|
+
try {
|
|
4602
|
+
console.log("[CLINIC] Checking admin permissions");
|
|
4603
|
+
const admin = await clinicAdminService.getClinicAdmin(adminId);
|
|
4604
|
+
if (!admin) {
|
|
4605
|
+
console.error("[CLINIC] Admin not found", { adminId });
|
|
4606
|
+
throw new Error("Admin not found");
|
|
4607
|
+
}
|
|
4608
|
+
const hasPermission = admin.isGroupOwner && admin.clinicGroupId === clinic.clinicGroupId || admin.clinicsManaged.includes(clinicId) && clinic.admins && clinic.admins.includes(adminId);
|
|
4609
|
+
if (!hasPermission) {
|
|
4610
|
+
console.error(
|
|
4611
|
+
"[CLINIC] Admin does not have permission to update this clinic",
|
|
4612
|
+
{
|
|
4613
|
+
adminId,
|
|
4614
|
+
clinicId,
|
|
4615
|
+
isGroupOwner: admin.isGroupOwner,
|
|
4616
|
+
clinicsManaged: admin.clinicsManaged,
|
|
4617
|
+
isClinicAdmin: clinic.admins && clinic.admins.includes(adminId)
|
|
4618
|
+
}
|
|
4619
|
+
);
|
|
4620
|
+
throw new Error("Admin does not have permission to update this clinic");
|
|
4621
|
+
}
|
|
4622
|
+
console.log("[CLINIC] Admin permissions verified");
|
|
4623
|
+
} catch (adminError) {
|
|
4624
|
+
console.error("[CLINIC] Error verifying admin permissions:", adminError);
|
|
4625
|
+
throw adminError;
|
|
4626
|
+
}
|
|
4627
|
+
let updatedData = { ...data };
|
|
4628
|
+
if (data.logo && typeof data.logo === "string" && data.logo.startsWith("data:")) {
|
|
4629
|
+
console.log("[CLINIC] Processing logo update");
|
|
4630
|
+
try {
|
|
4631
|
+
const logoUrl = await uploadPhoto(
|
|
4632
|
+
data.logo,
|
|
4633
|
+
"clinics",
|
|
4634
|
+
clinicId,
|
|
4635
|
+
"logo",
|
|
4636
|
+
app
|
|
4637
|
+
);
|
|
4638
|
+
console.log("[CLINIC] Logo update processed", { logoUrl });
|
|
4639
|
+
if (logoUrl !== null) {
|
|
4640
|
+
updatedData.logo = logoUrl;
|
|
4641
|
+
}
|
|
4642
|
+
} catch (logoError) {
|
|
4643
|
+
console.error("[CLINIC] Error processing logo update:", logoError);
|
|
4644
|
+
}
|
|
4235
4645
|
}
|
|
4236
|
-
if (
|
|
4237
|
-
|
|
4646
|
+
if (data.photos && data.photos.length > 0) {
|
|
4647
|
+
console.log("[CLINIC] Processing regular photos update");
|
|
4648
|
+
try {
|
|
4649
|
+
const dataUrlPhotos = data.photos.filter(
|
|
4650
|
+
(photo) => typeof photo === "string" && photo.startsWith("data:")
|
|
4651
|
+
);
|
|
4652
|
+
const existingPhotos = data.photos.filter(
|
|
4653
|
+
(photo) => typeof photo === "string" && !photo.startsWith("data:")
|
|
4654
|
+
);
|
|
4655
|
+
if (dataUrlPhotos.length > 0) {
|
|
4656
|
+
const uploadedPhotos = await uploadMultiplePhotos(
|
|
4657
|
+
dataUrlPhotos,
|
|
4658
|
+
"clinics",
|
|
4659
|
+
clinicId,
|
|
4660
|
+
"photo",
|
|
4661
|
+
app
|
|
4662
|
+
);
|
|
4663
|
+
console.log("[CLINIC] Regular photos update processed", {
|
|
4664
|
+
count: uploadedPhotos.length
|
|
4665
|
+
});
|
|
4666
|
+
updatedData.photos = [...existingPhotos, ...uploadedPhotos];
|
|
4667
|
+
}
|
|
4668
|
+
} catch (photosError) {
|
|
4669
|
+
console.error(
|
|
4670
|
+
"[CLINIC] Error processing regular photos update:",
|
|
4671
|
+
photosError
|
|
4672
|
+
);
|
|
4673
|
+
updatedData.photos = data.photos.filter(
|
|
4674
|
+
(photo) => typeof photo === "string" && !photo.startsWith("data:")
|
|
4675
|
+
);
|
|
4676
|
+
}
|
|
4238
4677
|
}
|
|
4239
|
-
|
|
4240
|
-
|
|
4678
|
+
if (data.featuredPhotos && data.featuredPhotos.length > 0) {
|
|
4679
|
+
console.log("[CLINIC] Processing featured photos update");
|
|
4680
|
+
try {
|
|
4681
|
+
const dataUrlPhotos = data.featuredPhotos.filter(
|
|
4682
|
+
(photo) => typeof photo === "string" && photo.startsWith("data:")
|
|
4683
|
+
);
|
|
4684
|
+
const existingPhotos = data.featuredPhotos.filter(
|
|
4685
|
+
(photo) => typeof photo === "string" && !photo.startsWith("data:")
|
|
4686
|
+
);
|
|
4687
|
+
if (dataUrlPhotos.length > 0) {
|
|
4688
|
+
const uploadedPhotos = await uploadMultiplePhotos(
|
|
4689
|
+
dataUrlPhotos,
|
|
4690
|
+
"clinics",
|
|
4691
|
+
clinicId,
|
|
4692
|
+
"featured",
|
|
4693
|
+
app
|
|
4694
|
+
);
|
|
4695
|
+
console.log("[CLINIC] Featured photos update processed", {
|
|
4696
|
+
count: uploadedPhotos.length
|
|
4697
|
+
});
|
|
4698
|
+
updatedData.featuredPhotos = [...existingPhotos, ...uploadedPhotos];
|
|
4699
|
+
}
|
|
4700
|
+
} catch (featuredError) {
|
|
4701
|
+
console.error(
|
|
4702
|
+
"[CLINIC] Error processing featured photos update:",
|
|
4703
|
+
featuredError
|
|
4704
|
+
);
|
|
4705
|
+
updatedData.featuredPhotos = data.featuredPhotos.filter(
|
|
4706
|
+
(photo) => typeof photo === "string" && !photo.startsWith("data:")
|
|
4707
|
+
);
|
|
4708
|
+
}
|
|
4709
|
+
}
|
|
4710
|
+
if (data.photosWithTags && data.photosWithTags.length > 0) {
|
|
4711
|
+
console.log("[CLINIC] Processing photos with tags update");
|
|
4712
|
+
try {
|
|
4713
|
+
const updatedPhotosWithTags = [];
|
|
4714
|
+
for (const photoWithTag of data.photosWithTags) {
|
|
4715
|
+
if (photoWithTag.url && photoWithTag.url.startsWith("data:")) {
|
|
4716
|
+
const uploadedUrl = await uploadPhoto(
|
|
4717
|
+
photoWithTag.url,
|
|
4718
|
+
"clinics",
|
|
4719
|
+
clinicId,
|
|
4720
|
+
`tagged-${photoWithTag.tag}`,
|
|
4721
|
+
app
|
|
4722
|
+
);
|
|
4723
|
+
if (uploadedUrl) {
|
|
4724
|
+
updatedPhotosWithTags.push({
|
|
4725
|
+
url: uploadedUrl,
|
|
4726
|
+
tag: photoWithTag.tag
|
|
4727
|
+
});
|
|
4728
|
+
}
|
|
4729
|
+
} else {
|
|
4730
|
+
updatedPhotosWithTags.push(photoWithTag);
|
|
4731
|
+
}
|
|
4732
|
+
}
|
|
4733
|
+
updatedData.photosWithTags = updatedPhotosWithTags;
|
|
4734
|
+
console.log("[CLINIC] Photos with tags update processed", {
|
|
4735
|
+
count: updatedPhotosWithTags.length
|
|
4736
|
+
});
|
|
4737
|
+
} catch (tagsError) {
|
|
4738
|
+
console.error(
|
|
4739
|
+
"[CLINIC] Error processing photos with tags update:",
|
|
4740
|
+
tagsError
|
|
4741
|
+
);
|
|
4742
|
+
updatedData.photosWithTags = data.photosWithTags.filter(
|
|
4743
|
+
(photo) => !photo.url.startsWith("data:")
|
|
4744
|
+
);
|
|
4745
|
+
}
|
|
4746
|
+
}
|
|
4747
|
+
updatedData = {
|
|
4748
|
+
...updatedData,
|
|
4241
4749
|
updatedAt: Timestamp11.now()
|
|
4242
4750
|
};
|
|
4243
|
-
|
|
4751
|
+
console.log("[CLINIC] Updating clinic in Firestore");
|
|
4752
|
+
try {
|
|
4753
|
+
await updateDoc11(doc8(db, CLINICS_COLLECTION, clinicId), updatedData);
|
|
4754
|
+
console.log("[CLINIC] Clinic updated successfully");
|
|
4755
|
+
} catch (updateError) {
|
|
4756
|
+
console.error("[CLINIC] Error updating clinic in Firestore:", updateError);
|
|
4757
|
+
throw updateError;
|
|
4758
|
+
}
|
|
4244
4759
|
const updatedClinic = await getClinic(db, clinicId);
|
|
4245
4760
|
if (!updatedClinic) {
|
|
4761
|
+
console.error("[CLINIC] Failed to retrieve updated clinic");
|
|
4246
4762
|
throw new Error("Failed to retrieve updated clinic");
|
|
4247
4763
|
}
|
|
4764
|
+
console.log("[CLINIC] Clinic update completed successfully");
|
|
4248
4765
|
return updatedClinic;
|
|
4249
4766
|
}
|
|
4250
4767
|
async function deactivateClinic(db, clinicId, adminId, clinicAdminService) {
|
|
@@ -4256,7 +4773,8 @@ async function deactivateClinic(db, clinicId, adminId, clinicAdminService) {
|
|
|
4256
4773
|
if (!admin) {
|
|
4257
4774
|
throw new Error("Admin not found");
|
|
4258
4775
|
}
|
|
4259
|
-
|
|
4776
|
+
const hasPermission = admin.isGroupOwner && admin.clinicGroupId === clinic.clinicGroupId || admin.clinicsManaged.includes(clinicId) && clinic.admins && clinic.admins.includes(adminId);
|
|
4777
|
+
if (!hasPermission) {
|
|
4260
4778
|
throw new Error("Admin does not have permission to deactivate this clinic");
|
|
4261
4779
|
}
|
|
4262
4780
|
await updateDoc11(doc8(db, CLINICS_COLLECTION, clinicId), {
|
|
@@ -4301,27 +4819,28 @@ async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGr
|
|
|
4301
4819
|
import {
|
|
4302
4820
|
collection as collection7,
|
|
4303
4821
|
doc as doc9,
|
|
4304
|
-
|
|
4305
|
-
|
|
4822
|
+
Timestamp as Timestamp12,
|
|
4823
|
+
getDoc as getDoc13,
|
|
4824
|
+
addDoc as addDoc2
|
|
4306
4825
|
} from "firebase/firestore";
|
|
4307
|
-
async function addReview(db, clinicId, review) {
|
|
4308
|
-
const
|
|
4309
|
-
|
|
4826
|
+
async function addReview(db, clinicId, review, app) {
|
|
4827
|
+
const clinicRef = doc9(db, "clinics", clinicId);
|
|
4828
|
+
const clinicSnap = await getDoc13(clinicRef);
|
|
4829
|
+
if (!clinicSnap.exists()) {
|
|
4310
4830
|
throw new Error("Clinic not found");
|
|
4311
4831
|
}
|
|
4832
|
+
const clinic = clinicSnap.data();
|
|
4312
4833
|
const now = Timestamp12.now();
|
|
4313
4834
|
const reviewData = {
|
|
4835
|
+
...review,
|
|
4314
4836
|
id: doc9(collection7(db, "clinic_reviews")).id,
|
|
4315
4837
|
clinicId,
|
|
4316
|
-
patientId: review.patientId,
|
|
4317
|
-
rating: review.rating,
|
|
4318
|
-
comment: review.comment,
|
|
4319
4838
|
createdAt: now,
|
|
4320
4839
|
updatedAt: now,
|
|
4321
4840
|
isVerified: false
|
|
4322
4841
|
};
|
|
4323
4842
|
clinicReviewSchema.parse(reviewData);
|
|
4324
|
-
await
|
|
4843
|
+
await addDoc2(collection7(db, "clinic_reviews"), reviewData);
|
|
4325
4844
|
const newRating = clinic.rating ? {
|
|
4326
4845
|
average: (clinic.rating.average * clinic.rating.count + review.rating) / (clinic.rating.count + 1),
|
|
4327
4846
|
count: clinic.rating.count + 1
|
|
@@ -4337,28 +4856,24 @@ async function addReview(db, clinicId, review) {
|
|
|
4337
4856
|
...clinic.reviewsInfo,
|
|
4338
4857
|
{
|
|
4339
4858
|
id: reviewData.id,
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
// This should be fetched from patient service
|
|
4345
|
-
patientPhoto: "",
|
|
4346
|
-
// This should be fetched from patient service
|
|
4347
|
-
createdAt: now,
|
|
4348
|
-
updatedAt: now
|
|
4859
|
+
patientId: reviewData.patientId,
|
|
4860
|
+
rating: reviewData.rating,
|
|
4861
|
+
comment: reviewData.comment,
|
|
4862
|
+
createdAt: reviewData.createdAt
|
|
4349
4863
|
}
|
|
4350
4864
|
]
|
|
4351
4865
|
},
|
|
4352
|
-
|
|
4353
|
-
//
|
|
4354
|
-
|
|
4355
|
-
//
|
|
4866
|
+
"system",
|
|
4867
|
+
// System update, no admin ID needed
|
|
4868
|
+
null,
|
|
4869
|
+
// No clinic admin service needed for system updates
|
|
4870
|
+
app
|
|
4356
4871
|
);
|
|
4357
4872
|
return reviewData;
|
|
4358
4873
|
}
|
|
4359
4874
|
|
|
4360
4875
|
// src/services/clinic/utils/tag.utils.ts
|
|
4361
|
-
async function addTags(db, clinicId, adminId, newTags, clinicAdminService) {
|
|
4876
|
+
async function addTags(db, clinicId, adminId, newTags, clinicAdminService, app) {
|
|
4362
4877
|
const clinic = await getClinic(db, clinicId);
|
|
4363
4878
|
if (!clinic) {
|
|
4364
4879
|
throw new Error("Clinic not found");
|
|
@@ -4367,7 +4882,8 @@ async function addTags(db, clinicId, adminId, newTags, clinicAdminService) {
|
|
|
4367
4882
|
if (!admin) {
|
|
4368
4883
|
throw new Error("Admin not found");
|
|
4369
4884
|
}
|
|
4370
|
-
|
|
4885
|
+
const hasPermission = admin.isGroupOwner && admin.clinicGroupId === clinic.clinicGroupId || admin.clinicsManaged.includes(clinicId) && clinic.admins && clinic.admins.includes(adminId);
|
|
4886
|
+
if (!hasPermission) {
|
|
4371
4887
|
throw new Error("Admin does not have permission to update this clinic");
|
|
4372
4888
|
}
|
|
4373
4889
|
const updatedTags = [.../* @__PURE__ */ new Set([...clinic.tags, ...newTags.tags || []])];
|
|
@@ -4378,10 +4894,11 @@ async function addTags(db, clinicId, adminId, newTags, clinicAdminService) {
|
|
|
4378
4894
|
tags: updatedTags
|
|
4379
4895
|
},
|
|
4380
4896
|
adminId,
|
|
4381
|
-
clinicAdminService
|
|
4897
|
+
clinicAdminService,
|
|
4898
|
+
app
|
|
4382
4899
|
);
|
|
4383
4900
|
}
|
|
4384
|
-
async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminService) {
|
|
4901
|
+
async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminService, app) {
|
|
4385
4902
|
const clinic = await getClinic(db, clinicId);
|
|
4386
4903
|
if (!clinic) {
|
|
4387
4904
|
throw new Error("Clinic not found");
|
|
@@ -4390,14 +4907,12 @@ async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminServic
|
|
|
4390
4907
|
if (!admin) {
|
|
4391
4908
|
throw new Error("Admin not found");
|
|
4392
4909
|
}
|
|
4393
|
-
|
|
4910
|
+
const hasPermission = admin.isGroupOwner && admin.clinicGroupId === clinic.clinicGroupId || admin.clinicsManaged.includes(clinicId) && clinic.admins && clinic.admins.includes(adminId);
|
|
4911
|
+
if (!hasPermission) {
|
|
4394
4912
|
throw new Error("Admin does not have permission to update this clinic");
|
|
4395
4913
|
}
|
|
4396
4914
|
const updatedTags = clinic.tags.filter(
|
|
4397
|
-
(tag) =>
|
|
4398
|
-
var _a;
|
|
4399
|
-
return !((_a = tagsToRemove.tags) == null ? void 0 : _a.includes(tag));
|
|
4400
|
-
}
|
|
4915
|
+
(tag) => !tagsToRemove.tags || !tagsToRemove.tags.includes(tag)
|
|
4401
4916
|
);
|
|
4402
4917
|
return updateClinic(
|
|
4403
4918
|
db,
|
|
@@ -4406,7 +4921,8 @@ async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminServic
|
|
|
4406
4921
|
tags: updatedTags
|
|
4407
4922
|
},
|
|
4408
4923
|
adminId,
|
|
4409
|
-
clinicAdminService
|
|
4924
|
+
clinicAdminService,
|
|
4925
|
+
app
|
|
4410
4926
|
);
|
|
4411
4927
|
}
|
|
4412
4928
|
|
|
@@ -4481,7 +4997,8 @@ var ClinicService = class extends BaseService {
|
|
|
4481
4997
|
data,
|
|
4482
4998
|
creatorAdminId,
|
|
4483
4999
|
this.clinicGroupService,
|
|
4484
|
-
this.clinicAdminService
|
|
5000
|
+
this.clinicAdminService,
|
|
5001
|
+
this.app
|
|
4485
5002
|
);
|
|
4486
5003
|
}
|
|
4487
5004
|
/**
|
|
@@ -4516,14 +5033,15 @@ var ClinicService = class extends BaseService {
|
|
|
4516
5033
|
clinicId,
|
|
4517
5034
|
data,
|
|
4518
5035
|
adminId,
|
|
4519
|
-
this.clinicAdminService
|
|
5036
|
+
this.clinicAdminService,
|
|
5037
|
+
this.app
|
|
4520
5038
|
);
|
|
4521
5039
|
}
|
|
4522
5040
|
/**
|
|
4523
5041
|
* Dodaje recenziju klinici
|
|
4524
5042
|
*/
|
|
4525
5043
|
async addReview(clinicId, review) {
|
|
4526
|
-
return addReview(this.db, clinicId, review);
|
|
5044
|
+
return addReview(this.db, clinicId, review, this.app);
|
|
4527
5045
|
}
|
|
4528
5046
|
/**
|
|
4529
5047
|
* Deaktivira kliniku
|
|
@@ -4545,7 +5063,8 @@ var ClinicService = class extends BaseService {
|
|
|
4545
5063
|
clinicId,
|
|
4546
5064
|
adminId,
|
|
4547
5065
|
newTags,
|
|
4548
|
-
this.clinicAdminService
|
|
5066
|
+
this.clinicAdminService,
|
|
5067
|
+
this.app
|
|
4549
5068
|
);
|
|
4550
5069
|
}
|
|
4551
5070
|
/**
|
|
@@ -4557,7 +5076,8 @@ var ClinicService = class extends BaseService {
|
|
|
4557
5076
|
clinicId,
|
|
4558
5077
|
adminId,
|
|
4559
5078
|
tagsToRemove,
|
|
4560
|
-
this.clinicAdminService
|
|
5079
|
+
this.clinicAdminService,
|
|
5080
|
+
this.app
|
|
4561
5081
|
);
|
|
4562
5082
|
}
|
|
4563
5083
|
/**
|
|
@@ -4592,12 +5112,21 @@ var ClinicService = class extends BaseService {
|
|
|
4592
5112
|
* @returns The created clinic
|
|
4593
5113
|
*/
|
|
4594
5114
|
async createClinicBranch(clinicGroupId, setupData, adminId) {
|
|
5115
|
+
var _a, _b;
|
|
5116
|
+
console.log("[CLINIC_SERVICE] Starting clinic branch creation", {
|
|
5117
|
+
clinicGroupId,
|
|
5118
|
+
adminId
|
|
5119
|
+
});
|
|
4595
5120
|
const clinicGroup = await this.clinicGroupService.getClinicGroup(
|
|
4596
5121
|
clinicGroupId
|
|
4597
5122
|
);
|
|
4598
5123
|
if (!clinicGroup) {
|
|
5124
|
+
console.error("[CLINIC_SERVICE] Clinic group not found", {
|
|
5125
|
+
clinicGroupId
|
|
5126
|
+
});
|
|
4599
5127
|
throw new Error(`Clinic group with ID ${clinicGroupId} not found`);
|
|
4600
5128
|
}
|
|
5129
|
+
console.log("[CLINIC_SERVICE] Clinic group verified");
|
|
4601
5130
|
const createClinicData = {
|
|
4602
5131
|
clinicGroupId,
|
|
4603
5132
|
name: setupData.name,
|
|
@@ -4606,8 +5135,8 @@ var ClinicService = class extends BaseService {
|
|
|
4606
5135
|
contactInfo: setupData.contactInfo,
|
|
4607
5136
|
workingHours: setupData.workingHours,
|
|
4608
5137
|
tags: setupData.tags,
|
|
4609
|
-
photos: setupData.photos,
|
|
4610
|
-
photosWithTags: setupData.photosWithTags,
|
|
5138
|
+
photos: setupData.photos || [],
|
|
5139
|
+
photosWithTags: setupData.photosWithTags || [],
|
|
4611
5140
|
doctors: [],
|
|
4612
5141
|
services: [],
|
|
4613
5142
|
admins: [adminId],
|
|
@@ -4616,7 +5145,17 @@ var ClinicService = class extends BaseService {
|
|
|
4616
5145
|
logo: setupData.logo,
|
|
4617
5146
|
featuredPhotos: setupData.featuredPhotos || []
|
|
4618
5147
|
};
|
|
5148
|
+
console.log("[CLINIC_SERVICE] Creating clinic branch with data", {
|
|
5149
|
+
name: createClinicData.name,
|
|
5150
|
+
hasLogo: !!createClinicData.logo,
|
|
5151
|
+
photosCount: createClinicData.photos.length,
|
|
5152
|
+
featuredPhotosCount: ((_a = createClinicData.featuredPhotos) == null ? void 0 : _a.length) || 0,
|
|
5153
|
+
photosWithTagsCount: ((_b = createClinicData.photosWithTags) == null ? void 0 : _b.length) || 0
|
|
5154
|
+
});
|
|
4619
5155
|
const clinic = await this.createClinic(createClinicData, adminId);
|
|
5156
|
+
console.log("[CLINIC_SERVICE] Clinic branch created successfully", {
|
|
5157
|
+
clinicId: clinic.id
|
|
5158
|
+
});
|
|
4620
5159
|
return clinic;
|
|
4621
5160
|
}
|
|
4622
5161
|
};
|
|
@@ -4738,7 +5277,7 @@ var AuthService = class extends BaseService {
|
|
|
4738
5277
|
"Clinic group data is required when creating a new group"
|
|
4739
5278
|
);
|
|
4740
5279
|
}
|
|
4741
|
-
console.log("[AUTH] Creating clinic admin first");
|
|
5280
|
+
console.log("[AUTH] Creating clinic admin first (without group)");
|
|
4742
5281
|
const createClinicAdminData = {
|
|
4743
5282
|
userRef: firebaseUser.uid,
|
|
4744
5283
|
isGroupOwner: true,
|
|
@@ -4746,10 +5285,16 @@ var AuthService = class extends BaseService {
|
|
|
4746
5285
|
contactInfo: contactPerson,
|
|
4747
5286
|
roleTitle: data.title,
|
|
4748
5287
|
isActive: true
|
|
5288
|
+
// No clinicGroupId yet
|
|
4749
5289
|
};
|
|
5290
|
+
let adminProfile;
|
|
4750
5291
|
try {
|
|
4751
|
-
await clinicAdminService.createClinicAdmin(
|
|
4752
|
-
|
|
5292
|
+
adminProfile = await clinicAdminService.createClinicAdmin(
|
|
5293
|
+
createClinicAdminData
|
|
5294
|
+
);
|
|
5295
|
+
console.log("[AUTH] Clinic admin created successfully", {
|
|
5296
|
+
adminId: adminProfile.id
|
|
5297
|
+
});
|
|
4753
5298
|
} catch (adminCreationError) {
|
|
4754
5299
|
console.error(
|
|
4755
5300
|
"[AUTH] Clinic admin creation failed:",
|
|
@@ -4762,7 +5307,8 @@ var AuthService = class extends BaseService {
|
|
|
4762
5307
|
hqLocation: data.clinicGroupData.hqLocation,
|
|
4763
5308
|
contactInfo: data.clinicGroupData.contactInfo,
|
|
4764
5309
|
contactPerson,
|
|
4765
|
-
ownerId:
|
|
5310
|
+
ownerId: adminProfile.id,
|
|
5311
|
+
// Use admin profile ID, not user UID
|
|
4766
5312
|
isActive: true,
|
|
4767
5313
|
logo: data.clinicGroupData.logo || null,
|
|
4768
5314
|
subscriptionModel: data.clinicGroupData.subscriptionModel || "no_subscription" /* NO_SUBSCRIPTION */
|
|
@@ -4770,13 +5316,24 @@ var AuthService = class extends BaseService {
|
|
|
4770
5316
|
console.log("[AUTH] Clinic group data prepared", {
|
|
4771
5317
|
groupName: createClinicGroupData.name
|
|
4772
5318
|
});
|
|
5319
|
+
let clinicGroup;
|
|
4773
5320
|
try {
|
|
4774
|
-
await clinicGroupService.createClinicGroup(
|
|
5321
|
+
clinicGroup = await clinicGroupService.createClinicGroup(
|
|
4775
5322
|
createClinicGroupData,
|
|
4776
|
-
|
|
4777
|
-
|
|
5323
|
+
adminProfile.id,
|
|
5324
|
+
// Use admin profile ID, not user UID
|
|
5325
|
+
false
|
|
5326
|
+
// This is not a default group since we're providing complete data
|
|
4778
5327
|
);
|
|
4779
|
-
console.log("[AUTH] Clinic group created successfully"
|
|
5328
|
+
console.log("[AUTH] Clinic group created successfully", {
|
|
5329
|
+
groupId: clinicGroup.id
|
|
5330
|
+
});
|
|
5331
|
+
console.log("[AUTH] Updating admin with clinic group ID");
|
|
5332
|
+
await clinicAdminService.updateClinicAdmin(adminProfile.id, {
|
|
5333
|
+
// Use admin profile ID, not user UID
|
|
5334
|
+
clinicGroupId: clinicGroup.id
|
|
5335
|
+
});
|
|
5336
|
+
console.log("[AUTH] Admin updated with clinic group ID successfully");
|
|
4780
5337
|
} catch (groupCreationError) {
|
|
4781
5338
|
console.error(
|
|
4782
5339
|
"[AUTH] Clinic group creation failed:",
|
|
@@ -4849,9 +5406,14 @@ var AuthService = class extends BaseService {
|
|
|
4849
5406
|
roleTitle: data.title,
|
|
4850
5407
|
isActive: true
|
|
4851
5408
|
};
|
|
5409
|
+
let adminProfile;
|
|
4852
5410
|
try {
|
|
4853
|
-
await clinicAdminService.createClinicAdmin(
|
|
4854
|
-
|
|
5411
|
+
adminProfile = await clinicAdminService.createClinicAdmin(
|
|
5412
|
+
createClinicAdminData
|
|
5413
|
+
);
|
|
5414
|
+
console.log("[AUTH] Clinic admin created successfully", {
|
|
5415
|
+
adminId: adminProfile.id
|
|
5416
|
+
});
|
|
4855
5417
|
} catch (adminCreationError) {
|
|
4856
5418
|
console.error(
|
|
4857
5419
|
"[AUTH] Clinic admin creation failed:",
|
|
@@ -5160,7 +5722,7 @@ var AuthService = class extends BaseService {
|
|
|
5160
5722
|
import {
|
|
5161
5723
|
collection as collection10,
|
|
5162
5724
|
doc as doc11,
|
|
5163
|
-
getDoc as
|
|
5725
|
+
getDoc as getDoc15,
|
|
5164
5726
|
getDocs as getDocs9,
|
|
5165
5727
|
query as query9,
|
|
5166
5728
|
where as where9,
|
|
@@ -5168,8 +5730,8 @@ import {
|
|
|
5168
5730
|
deleteDoc as deleteDoc6,
|
|
5169
5731
|
orderBy,
|
|
5170
5732
|
Timestamp as Timestamp14,
|
|
5171
|
-
addDoc,
|
|
5172
|
-
writeBatch as
|
|
5733
|
+
addDoc as addDoc3,
|
|
5734
|
+
writeBatch as writeBatch3
|
|
5173
5735
|
} from "firebase/firestore";
|
|
5174
5736
|
|
|
5175
5737
|
// src/types/notifications/index.ts
|
|
@@ -5206,7 +5768,7 @@ var NotificationService = class extends BaseService {
|
|
|
5206
5768
|
isRead: false,
|
|
5207
5769
|
userRole: notification.userRole || "patient" /* PATIENT */
|
|
5208
5770
|
};
|
|
5209
|
-
const docRef = await
|
|
5771
|
+
const docRef = await addDoc3(notificationsRef, notificationData);
|
|
5210
5772
|
return {
|
|
5211
5773
|
...notificationData,
|
|
5212
5774
|
id: docRef.id
|
|
@@ -5221,7 +5783,7 @@ var NotificationService = class extends BaseService {
|
|
|
5221
5783
|
NOTIFICATIONS_COLLECTION,
|
|
5222
5784
|
notificationId
|
|
5223
5785
|
);
|
|
5224
|
-
const notificationDoc = await
|
|
5786
|
+
const notificationDoc = await getDoc15(notificationRef);
|
|
5225
5787
|
if (!notificationDoc.exists()) {
|
|
5226
5788
|
return null;
|
|
5227
5789
|
}
|
|
@@ -5280,7 +5842,7 @@ var NotificationService = class extends BaseService {
|
|
|
5280
5842
|
*/
|
|
5281
5843
|
async markAllAsRead(userId) {
|
|
5282
5844
|
const notifications = await this.getUnreadNotifications(userId);
|
|
5283
|
-
const batch =
|
|
5845
|
+
const batch = writeBatch3(this.db);
|
|
5284
5846
|
notifications.forEach((notification) => {
|
|
5285
5847
|
const notificationRef = doc11(
|
|
5286
5848
|
this.db,
|
|
@@ -5356,7 +5918,7 @@ var NotificationService = class extends BaseService {
|
|
|
5356
5918
|
import {
|
|
5357
5919
|
collection as collection11,
|
|
5358
5920
|
doc as doc12,
|
|
5359
|
-
getDoc as
|
|
5921
|
+
getDoc as getDoc16,
|
|
5360
5922
|
getDocs as getDocs10,
|
|
5361
5923
|
setDoc as setDoc13,
|
|
5362
5924
|
updateDoc as updateDoc14,
|
|
@@ -5412,7 +5974,7 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
5412
5974
|
*/
|
|
5413
5975
|
async getTemplateById(templateId) {
|
|
5414
5976
|
const docRef = doc12(this.collectionRef, templateId);
|
|
5415
|
-
const docSnap = await
|
|
5977
|
+
const docSnap = await getDoc16(docRef);
|
|
5416
5978
|
if (!docSnap.exists()) {
|
|
5417
5979
|
return null;
|
|
5418
5980
|
}
|
|
@@ -5551,7 +6113,7 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
5551
6113
|
import {
|
|
5552
6114
|
collection as collection12,
|
|
5553
6115
|
doc as doc13,
|
|
5554
|
-
getDoc as
|
|
6116
|
+
getDoc as getDoc17,
|
|
5555
6117
|
getDocs as getDocs11,
|
|
5556
6118
|
setDoc as setDoc14,
|
|
5557
6119
|
updateDoc as updateDoc15,
|
|
@@ -5608,7 +6170,7 @@ var FilledDocumentService = class extends BaseService {
|
|
|
5608
6170
|
*/
|
|
5609
6171
|
async getFilledDocumentById(documentId) {
|
|
5610
6172
|
const docRef = doc13(this.collectionRef, documentId);
|
|
5611
|
-
const docSnap = await
|
|
6173
|
+
const docSnap = await getDoc17(docRef);
|
|
5612
6174
|
if (!docSnap.exists()) {
|
|
5613
6175
|
return null;
|
|
5614
6176
|
}
|