@blackcode_sa/metaestetics-api 1.4.7 → 1.4.9
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 +16 -16
- package/dist/index.d.ts +16 -16
- package/dist/index.js +768 -188
- package/dist/index.mjs +787 -200
- package/package.json +1 -1
- package/src/services/auth.service.ts +52 -8
- 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 +195 -52
- 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 +5 -5
- package/src/validations/clinic.schema.ts +3 -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)),
|
|
@@ -2451,7 +2451,7 @@ var createClinicGroupSchema = z9.object({
|
|
|
2451
2451
|
hqLocation: clinicLocationSchema,
|
|
2452
2452
|
contactInfo: clinicContactInfoSchema,
|
|
2453
2453
|
contactPerson: contactPersonSchema,
|
|
2454
|
-
ownerId: z9.string(),
|
|
2454
|
+
ownerId: z9.string().nullable(),
|
|
2455
2455
|
isActive: z9.boolean(),
|
|
2456
2456
|
logo: z9.string().optional().nullable(),
|
|
2457
2457
|
practiceType: z9.nativeEnum(PracticeType).optional(),
|
|
@@ -2485,7 +2485,7 @@ var createClinicSchema = z9.object({
|
|
|
2485
2485
|
});
|
|
2486
2486
|
var createDefaultClinicGroupSchema = z9.object({
|
|
2487
2487
|
name: z9.string(),
|
|
2488
|
-
ownerId: z9.string(),
|
|
2488
|
+
ownerId: z9.string().nullable(),
|
|
2489
2489
|
contactPerson: contactPersonSchema,
|
|
2490
2490
|
contactInfo: clinicContactInfoSchema,
|
|
2491
2491
|
hqLocation: clinicLocationSchema,
|
|
@@ -2583,45 +2583,7 @@ async function createClinicAdmin(db, data, clinicGroupService) {
|
|
|
2583
2583
|
hasGroupId: !!clinicGroupId
|
|
2584
2584
|
});
|
|
2585
2585
|
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
|
-
}
|
|
2586
|
+
console.log("[CLINIC_ADMIN] Owner will be assigned to group later");
|
|
2625
2587
|
} else if (!validatedData.isGroupOwner && !clinicGroupId) {
|
|
2626
2588
|
console.error("[CLINIC_ADMIN] Missing clinic group ID for non-owner admin");
|
|
2627
2589
|
throw new Error("Clinic group ID is required for non-owner admins");
|
|
@@ -2651,16 +2613,12 @@ async function createClinicAdmin(db, data, clinicGroupService) {
|
|
|
2651
2613
|
}
|
|
2652
2614
|
}
|
|
2653
2615
|
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
2616
|
const adminData = {
|
|
2661
|
-
id:
|
|
2617
|
+
id: doc4(collection2(db, CLINIC_ADMINS_COLLECTION)).id,
|
|
2618
|
+
// Generate a new ID for the admin document
|
|
2662
2619
|
userRef: validatedData.userRef,
|
|
2663
|
-
clinicGroupId,
|
|
2620
|
+
clinicGroupId: clinicGroupId || "",
|
|
2621
|
+
// Empty string for now if no group ID
|
|
2664
2622
|
isGroupOwner: validatedData.isGroupOwner,
|
|
2665
2623
|
clinicsManaged: [],
|
|
2666
2624
|
// Uvek krećemo od prazne liste
|
|
@@ -3706,6 +3664,65 @@ import {
|
|
|
3706
3664
|
} from "firebase/firestore";
|
|
3707
3665
|
import { geohashForLocation as geohashForLocation2 } from "geofire-common";
|
|
3708
3666
|
import { z as z13 } from "zod";
|
|
3667
|
+
|
|
3668
|
+
// src/services/clinic/utils/photos.utils.ts
|
|
3669
|
+
import {
|
|
3670
|
+
getStorage as getStorage2,
|
|
3671
|
+
ref as ref2,
|
|
3672
|
+
uploadBytes as uploadBytes2,
|
|
3673
|
+
getDownloadURL as getDownloadURL2,
|
|
3674
|
+
deleteObject as deleteObject2
|
|
3675
|
+
} from "firebase/storage";
|
|
3676
|
+
async function uploadPhoto(photo, entityType, entityId, photoType, app, fileName) {
|
|
3677
|
+
if (!photo || typeof photo !== "string" || !photo.startsWith("data:")) {
|
|
3678
|
+
return photo;
|
|
3679
|
+
}
|
|
3680
|
+
try {
|
|
3681
|
+
console.log(
|
|
3682
|
+
`[PHOTO_UTILS] Uploading ${photoType} for ${entityType}/${entityId}`
|
|
3683
|
+
);
|
|
3684
|
+
const storage = getStorage2(app);
|
|
3685
|
+
const storageFileName = fileName || `${photoType}-${Date.now()}`;
|
|
3686
|
+
const storageRef = ref2(
|
|
3687
|
+
storage,
|
|
3688
|
+
`${entityType}/${entityId}/${storageFileName}`
|
|
3689
|
+
);
|
|
3690
|
+
const base64Data = photo.split(",")[1];
|
|
3691
|
+
const contentType = photo.split(";")[0].split(":")[1];
|
|
3692
|
+
const byteCharacters = atob(base64Data);
|
|
3693
|
+
const byteArrays = [];
|
|
3694
|
+
for (let i = 0; i < byteCharacters.length; i++) {
|
|
3695
|
+
byteArrays.push(byteCharacters.charCodeAt(i));
|
|
3696
|
+
}
|
|
3697
|
+
const blob = new Blob([new Uint8Array(byteArrays)], { type: contentType });
|
|
3698
|
+
await uploadBytes2(storageRef, blob, { contentType });
|
|
3699
|
+
const downloadUrl = await getDownloadURL2(storageRef);
|
|
3700
|
+
console.log(`[PHOTO_UTILS] ${photoType} uploaded successfully`, {
|
|
3701
|
+
downloadUrl
|
|
3702
|
+
});
|
|
3703
|
+
return downloadUrl;
|
|
3704
|
+
} catch (error) {
|
|
3705
|
+
console.error(`[PHOTO_UTILS] Error uploading ${photoType}:`, error);
|
|
3706
|
+
return null;
|
|
3707
|
+
}
|
|
3708
|
+
}
|
|
3709
|
+
async function uploadMultiplePhotos(photos, entityType, entityId, photoType, app) {
|
|
3710
|
+
if (!photos || !Array.isArray(photos) || photos.length === 0) {
|
|
3711
|
+
return [];
|
|
3712
|
+
}
|
|
3713
|
+
const uploadPromises = photos.map(
|
|
3714
|
+
(photo, index) => uploadPhoto(photo, entityType, entityId, `${photoType}-${index}`, app)
|
|
3715
|
+
);
|
|
3716
|
+
try {
|
|
3717
|
+
const results = await Promise.all(uploadPromises);
|
|
3718
|
+
return results.filter((url) => url !== null);
|
|
3719
|
+
} catch (error) {
|
|
3720
|
+
console.error(`[PHOTO_UTILS] Error uploading multiple photos:`, error);
|
|
3721
|
+
return photos.filter((photo) => !photo.startsWith("data:"));
|
|
3722
|
+
}
|
|
3723
|
+
}
|
|
3724
|
+
|
|
3725
|
+
// src/services/clinic/utils/clinic-group.utils.ts
|
|
3709
3726
|
function generateId() {
|
|
3710
3727
|
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
3711
3728
|
const timestamp = Date.now().toString(36);
|
|
@@ -3715,7 +3732,8 @@ function generateId() {
|
|
|
3715
3732
|
).join("");
|
|
3716
3733
|
return `${randomPart}-${timestamp}`;
|
|
3717
3734
|
}
|
|
3718
|
-
async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdminService) {
|
|
3735
|
+
async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdminService, app) {
|
|
3736
|
+
var _a, _b, _c, _d, _e;
|
|
3719
3737
|
console.log("[CLINIC_GROUP] Starting clinic group creation", {
|
|
3720
3738
|
ownerId,
|
|
3721
3739
|
isDefault
|
|
@@ -3731,14 +3749,23 @@ async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdm
|
|
|
3731
3749
|
const validatedData = createClinicGroupSchema.parse(data);
|
|
3732
3750
|
try {
|
|
3733
3751
|
console.log("[CLINIC_GROUP] Checking if owner exists", { ownerId });
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3752
|
+
if (isDefault) {
|
|
3753
|
+
console.log(
|
|
3754
|
+
"[CLINIC_GROUP] Skipping owner verification for default group creation"
|
|
3755
|
+
);
|
|
3756
|
+
} else {
|
|
3757
|
+
const owner = await clinicAdminService.getClinicAdmin(ownerId);
|
|
3758
|
+
if (!owner) {
|
|
3759
|
+
console.error(
|
|
3760
|
+
"[CLINIC_GROUP] Owner not found or is not a clinic admin",
|
|
3761
|
+
{
|
|
3762
|
+
ownerId
|
|
3763
|
+
}
|
|
3764
|
+
);
|
|
3765
|
+
throw new Error("Owner not found or is not a clinic admin");
|
|
3766
|
+
}
|
|
3767
|
+
console.log("[CLINIC_GROUP] Owner verified as clinic admin");
|
|
3740
3768
|
}
|
|
3741
|
-
console.log("[CLINIC_GROUP] Owner verified as clinic admin");
|
|
3742
3769
|
} catch (ownerError) {
|
|
3743
3770
|
console.error("[CLINIC_GROUP] Error verifying owner:", ownerError);
|
|
3744
3771
|
throw ownerError;
|
|
@@ -3760,23 +3787,49 @@ async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdm
|
|
|
3760
3787
|
}
|
|
3761
3788
|
const now = Timestamp10.now();
|
|
3762
3789
|
console.log("[CLINIC_GROUP] Preparing clinic group data object");
|
|
3790
|
+
const groupId = doc7(collection5(db, CLINIC_GROUPS_COLLECTION)).id;
|
|
3763
3791
|
console.log("[CLINIC_GROUP] Logo value:", {
|
|
3764
3792
|
logoValue: validatedData.logo,
|
|
3765
3793
|
logoType: validatedData.logo === null ? "null" : typeof validatedData.logo
|
|
3766
3794
|
});
|
|
3795
|
+
let logoUrl = await uploadPhoto(
|
|
3796
|
+
validatedData.logo || null,
|
|
3797
|
+
"clinic-groups",
|
|
3798
|
+
groupId,
|
|
3799
|
+
"logo",
|
|
3800
|
+
app
|
|
3801
|
+
);
|
|
3802
|
+
console.log("[CLINIC_GROUP] Logo processed", { logoUrl });
|
|
3767
3803
|
const groupData = {
|
|
3768
3804
|
...validatedData,
|
|
3769
|
-
id:
|
|
3805
|
+
id: groupId,
|
|
3806
|
+
name: validatedData.name,
|
|
3807
|
+
logo: logoUrl,
|
|
3808
|
+
// Use the uploaded logo URL or the original value
|
|
3770
3809
|
description: isDefault ? void 0 : validatedData.description || void 0,
|
|
3771
3810
|
hqLocation: {
|
|
3772
|
-
|
|
3811
|
+
address: validatedData.hqLocation.address || "",
|
|
3812
|
+
city: validatedData.hqLocation.city || "",
|
|
3813
|
+
country: validatedData.hqLocation.country || "",
|
|
3814
|
+
postalCode: validatedData.hqLocation.postalCode || "",
|
|
3815
|
+
latitude: validatedData.hqLocation.latitude || 0,
|
|
3816
|
+
longitude: validatedData.hqLocation.longitude || 0,
|
|
3773
3817
|
geohash: validatedData.hqLocation.geohash || void 0
|
|
3774
3818
|
},
|
|
3775
3819
|
contactInfo: {
|
|
3776
|
-
|
|
3820
|
+
email: validatedData.contactInfo.email || "",
|
|
3821
|
+
phoneNumber: validatedData.contactInfo.phoneNumber || "",
|
|
3777
3822
|
alternativePhoneNumber: isDefault ? void 0 : validatedData.contactInfo.alternativePhoneNumber || void 0,
|
|
3778
3823
|
website: isDefault ? void 0 : validatedData.contactInfo.website || void 0
|
|
3779
3824
|
},
|
|
3825
|
+
contactPerson: {
|
|
3826
|
+
firstName: ((_a = validatedData.contactPerson) == null ? void 0 : _a.firstName) || "",
|
|
3827
|
+
lastName: ((_b = validatedData.contactPerson) == null ? void 0 : _b.lastName) || "",
|
|
3828
|
+
email: ((_c = validatedData.contactPerson) == null ? void 0 : _c.email) || "",
|
|
3829
|
+
title: ((_d = validatedData.contactPerson) == null ? void 0 : _d.title) || null,
|
|
3830
|
+
phoneNumber: ((_e = validatedData.contactPerson) == null ? void 0 : _e.phoneNumber) || null
|
|
3831
|
+
},
|
|
3832
|
+
subscriptionModel: validatedData.subscriptionModel || "no_subscription" /* NO_SUBSCRIPTION */,
|
|
3780
3833
|
clinics: [],
|
|
3781
3834
|
clinicsInfo: [],
|
|
3782
3835
|
admins: [ownerId],
|
|
@@ -3864,35 +3917,75 @@ async function getAllActiveGroups(db) {
|
|
|
3864
3917
|
const querySnapshot = await getDocs5(q);
|
|
3865
3918
|
return querySnapshot.docs.map((doc14) => doc14.data());
|
|
3866
3919
|
}
|
|
3867
|
-
async function updateClinicGroup(db, groupId, data) {
|
|
3920
|
+
async function updateClinicGroup(db, groupId, data, app) {
|
|
3921
|
+
console.log("[CLINIC_GROUP] Updating clinic group", { groupId });
|
|
3868
3922
|
const group = await getClinicGroup(db, groupId);
|
|
3869
3923
|
if (!group) {
|
|
3924
|
+
console.error("[CLINIC_GROUP] Clinic group not found", { groupId });
|
|
3870
3925
|
throw new Error("Clinic group not found");
|
|
3871
3926
|
}
|
|
3872
|
-
|
|
3873
|
-
|
|
3927
|
+
let updatedData = { ...data };
|
|
3928
|
+
if (data.logo && typeof data.logo === "string" && data.logo.startsWith("data:")) {
|
|
3929
|
+
console.log("[CLINIC_GROUP] Processing logo for update");
|
|
3930
|
+
try {
|
|
3931
|
+
const logoUrl = await uploadPhoto(
|
|
3932
|
+
data.logo,
|
|
3933
|
+
"clinic-groups",
|
|
3934
|
+
groupId,
|
|
3935
|
+
"logo",
|
|
3936
|
+
app
|
|
3937
|
+
);
|
|
3938
|
+
console.log("[CLINIC_GROUP] Logo processed for update", { logoUrl });
|
|
3939
|
+
updatedData.logo = logoUrl;
|
|
3940
|
+
} catch (error) {
|
|
3941
|
+
console.error("[CLINIC_GROUP] Error processing logo for update:", error);
|
|
3942
|
+
}
|
|
3943
|
+
}
|
|
3944
|
+
updatedData = {
|
|
3945
|
+
...updatedData,
|
|
3874
3946
|
updatedAt: Timestamp10.now()
|
|
3875
3947
|
};
|
|
3948
|
+
console.log("[CLINIC_GROUP] Updating clinic group in Firestore");
|
|
3876
3949
|
await updateDoc10(doc7(db, CLINIC_GROUPS_COLLECTION, groupId), updatedData);
|
|
3950
|
+
console.log("[CLINIC_GROUP] Clinic group updated successfully");
|
|
3877
3951
|
const updatedGroup = await getClinicGroup(db, groupId);
|
|
3878
3952
|
if (!updatedGroup) {
|
|
3953
|
+
console.error("[CLINIC_GROUP] Failed to retrieve updated clinic group");
|
|
3879
3954
|
throw new Error("Failed to retrieve updated clinic group");
|
|
3880
3955
|
}
|
|
3881
3956
|
return updatedGroup;
|
|
3882
3957
|
}
|
|
3883
|
-
async function addAdminToGroup(db, groupId, adminId) {
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3958
|
+
async function addAdminToGroup(db, groupId, adminId, app) {
|
|
3959
|
+
console.log("[CLINIC_GROUP] Adding admin to group", { groupId, adminId });
|
|
3960
|
+
try {
|
|
3961
|
+
const group = await getClinicGroup(db, groupId);
|
|
3962
|
+
if (!group) {
|
|
3963
|
+
console.error("[CLINIC_GROUP] Clinic group not found", { groupId });
|
|
3964
|
+
throw new Error("Clinic group not found");
|
|
3965
|
+
}
|
|
3966
|
+
if (group.admins.includes(adminId)) {
|
|
3967
|
+
console.log("[CLINIC_GROUP] Admin is already in the group", {
|
|
3968
|
+
adminId,
|
|
3969
|
+
groupId
|
|
3970
|
+
});
|
|
3971
|
+
return;
|
|
3972
|
+
}
|
|
3973
|
+
console.log("[CLINIC_GROUP] Updating group with new admin");
|
|
3974
|
+
await updateClinicGroup(
|
|
3975
|
+
db,
|
|
3976
|
+
groupId,
|
|
3977
|
+
{
|
|
3978
|
+
admins: [...group.admins, adminId]
|
|
3979
|
+
},
|
|
3980
|
+
app
|
|
3981
|
+
);
|
|
3982
|
+
console.log("[CLINIC_GROUP] Admin added to group successfully");
|
|
3983
|
+
} catch (error) {
|
|
3984
|
+
console.error("[CLINIC_GROUP] Error adding admin to group:", error);
|
|
3985
|
+
throw error;
|
|
3890
3986
|
}
|
|
3891
|
-
await updateClinicGroup(db, groupId, {
|
|
3892
|
-
admins: [...group.admins, adminId]
|
|
3893
|
-
});
|
|
3894
3987
|
}
|
|
3895
|
-
async function removeAdminFromGroup(db, groupId, adminId) {
|
|
3988
|
+
async function removeAdminFromGroup(db, groupId, adminId, app) {
|
|
3896
3989
|
const group = await getClinicGroup(db, groupId);
|
|
3897
3990
|
if (!group) {
|
|
3898
3991
|
throw new Error("Clinic group not found");
|
|
@@ -3903,21 +3996,30 @@ async function removeAdminFromGroup(db, groupId, adminId) {
|
|
|
3903
3996
|
if (!group.admins.includes(adminId)) {
|
|
3904
3997
|
return;
|
|
3905
3998
|
}
|
|
3906
|
-
await updateClinicGroup(
|
|
3907
|
-
|
|
3908
|
-
|
|
3999
|
+
await updateClinicGroup(
|
|
4000
|
+
db,
|
|
4001
|
+
groupId,
|
|
4002
|
+
{
|
|
4003
|
+
admins: group.admins.filter((id) => id !== adminId)
|
|
4004
|
+
},
|
|
4005
|
+
app
|
|
4006
|
+
);
|
|
3909
4007
|
}
|
|
3910
|
-
async function deactivateClinicGroup(db, groupId) {
|
|
4008
|
+
async function deactivateClinicGroup(db, groupId, app) {
|
|
3911
4009
|
const group = await getClinicGroup(db, groupId);
|
|
3912
4010
|
if (!group) {
|
|
3913
4011
|
throw new Error("Clinic group not found");
|
|
3914
4012
|
}
|
|
3915
|
-
await
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
4013
|
+
await updateClinicGroup(
|
|
4014
|
+
db,
|
|
4015
|
+
groupId,
|
|
4016
|
+
{
|
|
4017
|
+
isActive: false
|
|
4018
|
+
},
|
|
4019
|
+
app
|
|
4020
|
+
);
|
|
3919
4021
|
}
|
|
3920
|
-
async function createAdminToken(db, groupId, creatorAdminId, data) {
|
|
4022
|
+
async function createAdminToken(db, groupId, creatorAdminId, app, data) {
|
|
3921
4023
|
const group = await getClinicGroup(db, groupId);
|
|
3922
4024
|
if (!group) {
|
|
3923
4025
|
throw new Error("Clinic group not found");
|
|
@@ -3938,12 +4040,17 @@ async function createAdminToken(db, groupId, creatorAdminId, data) {
|
|
|
3938
4040
|
createdAt: now,
|
|
3939
4041
|
expiresAt
|
|
3940
4042
|
};
|
|
3941
|
-
await updateClinicGroup(
|
|
3942
|
-
|
|
3943
|
-
|
|
4043
|
+
await updateClinicGroup(
|
|
4044
|
+
db,
|
|
4045
|
+
groupId,
|
|
4046
|
+
{
|
|
4047
|
+
adminTokens: [...group.adminTokens, token]
|
|
4048
|
+
},
|
|
4049
|
+
app
|
|
4050
|
+
);
|
|
3944
4051
|
return token;
|
|
3945
4052
|
}
|
|
3946
|
-
async function verifyAndUseAdminToken(db, groupId, token, userRef) {
|
|
4053
|
+
async function verifyAndUseAdminToken(db, groupId, token, userRef, app) {
|
|
3947
4054
|
const group = await getClinicGroup(db, groupId);
|
|
3948
4055
|
if (!group) {
|
|
3949
4056
|
throw new Error("Clinic group not found");
|
|
@@ -3960,9 +4067,14 @@ async function verifyAndUseAdminToken(db, groupId, token, userRef) {
|
|
|
3960
4067
|
const updatedTokens2 = group.adminTokens.map(
|
|
3961
4068
|
(t) => t.id === adminToken.id ? { ...t, status: "expired" /* EXPIRED */ } : t
|
|
3962
4069
|
);
|
|
3963
|
-
await updateClinicGroup(
|
|
3964
|
-
|
|
3965
|
-
|
|
4070
|
+
await updateClinicGroup(
|
|
4071
|
+
db,
|
|
4072
|
+
groupId,
|
|
4073
|
+
{
|
|
4074
|
+
adminTokens: updatedTokens2
|
|
4075
|
+
},
|
|
4076
|
+
app
|
|
4077
|
+
);
|
|
3966
4078
|
throw new Error("Admin token has expired");
|
|
3967
4079
|
}
|
|
3968
4080
|
const updatedTokens = group.adminTokens.map(
|
|
@@ -3972,12 +4084,17 @@ async function verifyAndUseAdminToken(db, groupId, token, userRef) {
|
|
|
3972
4084
|
usedByUserRef: userRef
|
|
3973
4085
|
} : t
|
|
3974
4086
|
);
|
|
3975
|
-
await updateClinicGroup(
|
|
3976
|
-
|
|
3977
|
-
|
|
4087
|
+
await updateClinicGroup(
|
|
4088
|
+
db,
|
|
4089
|
+
groupId,
|
|
4090
|
+
{
|
|
4091
|
+
adminTokens: updatedTokens
|
|
4092
|
+
},
|
|
4093
|
+
app
|
|
4094
|
+
);
|
|
3978
4095
|
return true;
|
|
3979
4096
|
}
|
|
3980
|
-
async function deleteAdminToken(db, groupId, tokenId, adminId) {
|
|
4097
|
+
async function deleteAdminToken(db, groupId, tokenId, adminId, app) {
|
|
3981
4098
|
const group = await getClinicGroup(db, groupId);
|
|
3982
4099
|
if (!group) {
|
|
3983
4100
|
throw new Error("Clinic group not found");
|
|
@@ -3986,11 +4103,16 @@ async function deleteAdminToken(db, groupId, tokenId, adminId) {
|
|
|
3986
4103
|
throw new Error("Admin does not belong to this clinic group");
|
|
3987
4104
|
}
|
|
3988
4105
|
const updatedTokens = group.adminTokens.filter((t) => t.id !== tokenId);
|
|
3989
|
-
await updateClinicGroup(
|
|
3990
|
-
|
|
3991
|
-
|
|
4106
|
+
await updateClinicGroup(
|
|
4107
|
+
db,
|
|
4108
|
+
groupId,
|
|
4109
|
+
{
|
|
4110
|
+
adminTokens: updatedTokens
|
|
4111
|
+
},
|
|
4112
|
+
app
|
|
4113
|
+
);
|
|
3992
4114
|
}
|
|
3993
|
-
async function getActiveAdminTokens(db, groupId, adminId) {
|
|
4115
|
+
async function getActiveAdminTokens(db, groupId, adminId, app) {
|
|
3994
4116
|
const group = await getClinicGroup(db, groupId);
|
|
3995
4117
|
if (!group) {
|
|
3996
4118
|
throw new Error("Clinic group not found");
|
|
@@ -4016,7 +4138,8 @@ var ClinicGroupService = class extends BaseService {
|
|
|
4016
4138
|
data,
|
|
4017
4139
|
ownerId,
|
|
4018
4140
|
isDefault,
|
|
4019
|
-
this.clinicAdminService
|
|
4141
|
+
this.clinicAdminService,
|
|
4142
|
+
this.app
|
|
4020
4143
|
);
|
|
4021
4144
|
}
|
|
4022
4145
|
/**
|
|
@@ -4035,25 +4158,35 @@ var ClinicGroupService = class extends BaseService {
|
|
|
4035
4158
|
* Ažurira grupaciju klinika
|
|
4036
4159
|
*/
|
|
4037
4160
|
async updateClinicGroup(groupId, data) {
|
|
4038
|
-
return updateClinicGroup(this.db, groupId, data);
|
|
4161
|
+
return updateClinicGroup(this.db, groupId, data, this.app);
|
|
4039
4162
|
}
|
|
4040
4163
|
/**
|
|
4041
4164
|
* Dodaje admina u grupaciju
|
|
4042
4165
|
*/
|
|
4043
4166
|
async addAdminToGroup(groupId, adminId) {
|
|
4044
|
-
return addAdminToGroup(
|
|
4167
|
+
return addAdminToGroup(
|
|
4168
|
+
this.db,
|
|
4169
|
+
groupId,
|
|
4170
|
+
adminId,
|
|
4171
|
+
this.app
|
|
4172
|
+
);
|
|
4045
4173
|
}
|
|
4046
4174
|
/**
|
|
4047
4175
|
* Uklanja admina iz grupacije
|
|
4048
4176
|
*/
|
|
4049
4177
|
async removeAdminFromGroup(groupId, adminId) {
|
|
4050
|
-
return removeAdminFromGroup(
|
|
4178
|
+
return removeAdminFromGroup(
|
|
4179
|
+
this.db,
|
|
4180
|
+
groupId,
|
|
4181
|
+
adminId,
|
|
4182
|
+
this.app
|
|
4183
|
+
);
|
|
4051
4184
|
}
|
|
4052
4185
|
/**
|
|
4053
4186
|
* Deaktivira grupaciju klinika
|
|
4054
4187
|
*/
|
|
4055
4188
|
async deactivateClinicGroup(groupId) {
|
|
4056
|
-
return deactivateClinicGroup(this.db, groupId);
|
|
4189
|
+
return deactivateClinicGroup(this.db, groupId, this.app);
|
|
4057
4190
|
}
|
|
4058
4191
|
/**
|
|
4059
4192
|
* Sets up additional clinic group information after initial creation
|
|
@@ -4063,18 +4196,45 @@ var ClinicGroupService = class extends BaseService {
|
|
|
4063
4196
|
* @returns The updated clinic group
|
|
4064
4197
|
*/
|
|
4065
4198
|
async setupClinicGroup(groupId, setupData) {
|
|
4199
|
+
console.log("[CLINIC_GROUP] Setting up clinic group", { groupId });
|
|
4066
4200
|
const clinicGroup = await this.getClinicGroup(groupId);
|
|
4067
4201
|
if (!clinicGroup) {
|
|
4202
|
+
console.error("[CLINIC_GROUP] Clinic group not found", { groupId });
|
|
4068
4203
|
throw new Error(`Clinic group with ID ${groupId} not found`);
|
|
4069
4204
|
}
|
|
4205
|
+
let logoUrl = setupData.logo;
|
|
4206
|
+
if (logoUrl && typeof logoUrl === "string" && logoUrl.startsWith("data:")) {
|
|
4207
|
+
console.log("[CLINIC_GROUP] Processing logo in setupClinicGroup");
|
|
4208
|
+
try {
|
|
4209
|
+
const uploadedLogoUrl = await uploadPhoto(
|
|
4210
|
+
logoUrl,
|
|
4211
|
+
"clinic-groups",
|
|
4212
|
+
groupId,
|
|
4213
|
+
"logo",
|
|
4214
|
+
this.app
|
|
4215
|
+
);
|
|
4216
|
+
console.log("[CLINIC_GROUP] Logo processed in setupClinicGroup", {
|
|
4217
|
+
uploadedLogoUrl
|
|
4218
|
+
});
|
|
4219
|
+
if (uploadedLogoUrl !== null) {
|
|
4220
|
+
logoUrl = uploadedLogoUrl;
|
|
4221
|
+
}
|
|
4222
|
+
} catch (error) {
|
|
4223
|
+
console.error(
|
|
4224
|
+
"[CLINIC_GROUP] Error processing logo in setupClinicGroup:",
|
|
4225
|
+
error
|
|
4226
|
+
);
|
|
4227
|
+
}
|
|
4228
|
+
}
|
|
4070
4229
|
const updateData = {
|
|
4071
4230
|
languages: setupData.languages,
|
|
4072
4231
|
practiceType: setupData.practiceType,
|
|
4073
4232
|
description: setupData.description,
|
|
4074
|
-
logo:
|
|
4233
|
+
logo: logoUrl,
|
|
4075
4234
|
calendarSyncEnabled: setupData.calendarSyncEnabled,
|
|
4076
4235
|
autoConfirmAppointments: setupData.autoConfirmAppointments
|
|
4077
4236
|
};
|
|
4237
|
+
console.log("[CLINIC_GROUP] Updating clinic group with setup data");
|
|
4078
4238
|
return this.updateClinicGroup(groupId, updateData);
|
|
4079
4239
|
}
|
|
4080
4240
|
/**
|
|
@@ -4085,6 +4245,7 @@ var ClinicGroupService = class extends BaseService {
|
|
|
4085
4245
|
this.db,
|
|
4086
4246
|
groupId,
|
|
4087
4247
|
creatorAdminId,
|
|
4248
|
+
this.app,
|
|
4088
4249
|
data
|
|
4089
4250
|
);
|
|
4090
4251
|
}
|
|
@@ -4096,7 +4257,8 @@ var ClinicGroupService = class extends BaseService {
|
|
|
4096
4257
|
this.db,
|
|
4097
4258
|
groupId,
|
|
4098
4259
|
token,
|
|
4099
|
-
userRef
|
|
4260
|
+
userRef,
|
|
4261
|
+
this.app
|
|
4100
4262
|
);
|
|
4101
4263
|
}
|
|
4102
4264
|
/**
|
|
@@ -4107,14 +4269,20 @@ var ClinicGroupService = class extends BaseService {
|
|
|
4107
4269
|
this.db,
|
|
4108
4270
|
groupId,
|
|
4109
4271
|
tokenId,
|
|
4110
|
-
adminId
|
|
4272
|
+
adminId,
|
|
4273
|
+
this.app
|
|
4111
4274
|
);
|
|
4112
4275
|
}
|
|
4113
4276
|
/**
|
|
4114
4277
|
* Dohvata aktivne admin tokene
|
|
4115
4278
|
*/
|
|
4116
4279
|
async getActiveAdminTokens(groupId, adminId) {
|
|
4117
|
-
return getActiveAdminTokens(
|
|
4280
|
+
return getActiveAdminTokens(
|
|
4281
|
+
this.db,
|
|
4282
|
+
groupId,
|
|
4283
|
+
adminId,
|
|
4284
|
+
this.app
|
|
4285
|
+
);
|
|
4118
4286
|
}
|
|
4119
4287
|
};
|
|
4120
4288
|
|
|
@@ -4132,44 +4300,193 @@ import {
|
|
|
4132
4300
|
} from "firebase/firestore";
|
|
4133
4301
|
import { geohashForLocation as geohashForLocation3 } from "geofire-common";
|
|
4134
4302
|
import { z as z14 } from "zod";
|
|
4135
|
-
async function createClinic(db, data, creatorAdminId, clinicGroupService, clinicAdminService) {
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4303
|
+
async function createClinic(db, data, creatorAdminId, clinicGroupService, clinicAdminService, app) {
|
|
4304
|
+
var _a;
|
|
4305
|
+
console.log("[CLINIC] Starting clinic creation", { creatorAdminId });
|
|
4306
|
+
console.log("[CLINIC] Input data:", JSON.stringify(data, null, 2));
|
|
4307
|
+
try {
|
|
4308
|
+
const validatedData2 = createClinicSchema.parse(data);
|
|
4309
|
+
console.log("[CLINIC] Data validation passed");
|
|
4310
|
+
} catch (validationError) {
|
|
4311
|
+
console.error("[CLINIC] Data validation failed:", validationError);
|
|
4312
|
+
throw validationError;
|
|
4140
4313
|
}
|
|
4141
|
-
|
|
4142
|
-
|
|
4314
|
+
const validatedData = createClinicSchema.parse(data);
|
|
4315
|
+
try {
|
|
4316
|
+
console.log("[CLINIC] Checking if admin exists and belongs to group");
|
|
4317
|
+
const admin = await clinicAdminService.getClinicAdmin(creatorAdminId);
|
|
4318
|
+
if (!admin) {
|
|
4319
|
+
console.error("[CLINIC] Admin not found", { creatorAdminId });
|
|
4320
|
+
throw new Error("Admin not found");
|
|
4321
|
+
}
|
|
4322
|
+
if (admin.clinicGroupId !== validatedData.clinicGroupId) {
|
|
4323
|
+
console.error("[CLINIC] Admin does not belong to this clinic group", {
|
|
4324
|
+
adminGroupId: admin.clinicGroupId,
|
|
4325
|
+
requestedGroupId: validatedData.clinicGroupId
|
|
4326
|
+
});
|
|
4327
|
+
throw new Error("Admin does not belong to this clinic group");
|
|
4328
|
+
}
|
|
4329
|
+
console.log("[CLINIC] Admin verified");
|
|
4330
|
+
} catch (adminError) {
|
|
4331
|
+
console.error("[CLINIC] Error verifying admin:", adminError);
|
|
4332
|
+
throw adminError;
|
|
4143
4333
|
}
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4334
|
+
try {
|
|
4335
|
+
console.log("[CLINIC] Checking if clinic group exists");
|
|
4336
|
+
const group = await clinicGroupService.getClinicGroup(
|
|
4337
|
+
validatedData.clinicGroupId
|
|
4338
|
+
);
|
|
4339
|
+
if (!group) {
|
|
4340
|
+
console.error("[CLINIC] Clinic group not found", {
|
|
4341
|
+
groupId: validatedData.clinicGroupId
|
|
4342
|
+
});
|
|
4343
|
+
throw new Error("Clinic group not found");
|
|
4344
|
+
}
|
|
4345
|
+
console.log("[CLINIC] Clinic group verified");
|
|
4346
|
+
} catch (groupError) {
|
|
4347
|
+
console.error("[CLINIC] Error verifying clinic group:", groupError);
|
|
4348
|
+
throw groupError;
|
|
4149
4349
|
}
|
|
4350
|
+
console.log("[CLINIC] Generating geohash for location");
|
|
4150
4351
|
if (validatedData.location) {
|
|
4151
|
-
|
|
4152
|
-
validatedData.location.
|
|
4153
|
-
|
|
4154
|
-
|
|
4352
|
+
try {
|
|
4353
|
+
validatedData.location.geohash = geohashForLocation3([
|
|
4354
|
+
validatedData.location.latitude,
|
|
4355
|
+
validatedData.location.longitude
|
|
4356
|
+
]);
|
|
4357
|
+
console.log("[CLINIC] Geohash generated successfully", {
|
|
4358
|
+
geohash: validatedData.location.geohash
|
|
4359
|
+
});
|
|
4360
|
+
} catch (geohashError) {
|
|
4361
|
+
console.error("[CLINIC] Error generating geohash:", geohashError);
|
|
4362
|
+
throw geohashError;
|
|
4363
|
+
}
|
|
4364
|
+
}
|
|
4365
|
+
const clinicId = doc8(collection6(db, CLINICS_COLLECTION)).id;
|
|
4366
|
+
console.log("[CLINIC] Generated clinic ID:", clinicId);
|
|
4367
|
+
console.log("[CLINIC] Processing photos");
|
|
4368
|
+
let logoUrl = null;
|
|
4369
|
+
if (validatedData.logo) {
|
|
4370
|
+
console.log("[CLINIC] Processing logo");
|
|
4371
|
+
try {
|
|
4372
|
+
logoUrl = await uploadPhoto(
|
|
4373
|
+
validatedData.logo,
|
|
4374
|
+
"clinics",
|
|
4375
|
+
clinicId,
|
|
4376
|
+
"logo",
|
|
4377
|
+
app
|
|
4378
|
+
);
|
|
4379
|
+
console.log("[CLINIC] Logo processed", { logoUrl });
|
|
4380
|
+
} catch (logoError) {
|
|
4381
|
+
console.error("[CLINIC] Error processing logo:", logoError);
|
|
4382
|
+
}
|
|
4383
|
+
}
|
|
4384
|
+
let processedPhotos = [];
|
|
4385
|
+
if (validatedData.photos && validatedData.photos.length > 0) {
|
|
4386
|
+
console.log("[CLINIC] Processing regular photos");
|
|
4387
|
+
try {
|
|
4388
|
+
processedPhotos = await uploadMultiplePhotos(
|
|
4389
|
+
validatedData.photos,
|
|
4390
|
+
"clinics",
|
|
4391
|
+
clinicId,
|
|
4392
|
+
"photo",
|
|
4393
|
+
app
|
|
4394
|
+
);
|
|
4395
|
+
console.log("[CLINIC] Regular photos processed", {
|
|
4396
|
+
count: processedPhotos.length
|
|
4397
|
+
});
|
|
4398
|
+
} catch (photosError) {
|
|
4399
|
+
console.error("[CLINIC] Error processing regular photos:", photosError);
|
|
4400
|
+
processedPhotos = validatedData.photos.filter(
|
|
4401
|
+
(photo) => !photo.startsWith("data:")
|
|
4402
|
+
);
|
|
4403
|
+
}
|
|
4404
|
+
}
|
|
4405
|
+
let processedFeaturedPhotos = [];
|
|
4406
|
+
if (validatedData.featuredPhotos && validatedData.featuredPhotos.length > 0) {
|
|
4407
|
+
console.log("[CLINIC] Processing featured photos");
|
|
4408
|
+
try {
|
|
4409
|
+
processedFeaturedPhotos = await uploadMultiplePhotos(
|
|
4410
|
+
validatedData.featuredPhotos,
|
|
4411
|
+
"clinics",
|
|
4412
|
+
clinicId,
|
|
4413
|
+
"featured",
|
|
4414
|
+
app
|
|
4415
|
+
);
|
|
4416
|
+
console.log("[CLINIC] Featured photos processed", {
|
|
4417
|
+
count: processedFeaturedPhotos.length
|
|
4418
|
+
});
|
|
4419
|
+
} catch (featuredError) {
|
|
4420
|
+
console.error(
|
|
4421
|
+
"[CLINIC] Error processing featured photos:",
|
|
4422
|
+
featuredError
|
|
4423
|
+
);
|
|
4424
|
+
processedFeaturedPhotos = validatedData.featuredPhotos.filter(
|
|
4425
|
+
(photo) => !photo.startsWith("data:")
|
|
4426
|
+
);
|
|
4427
|
+
}
|
|
4428
|
+
}
|
|
4429
|
+
let processedPhotosWithTags = validatedData.photosWithTags || [];
|
|
4430
|
+
if (processedPhotosWithTags.length > 0) {
|
|
4431
|
+
console.log("[CLINIC] Processing photos with tags");
|
|
4432
|
+
try {
|
|
4433
|
+
const updatedPhotosWithTags = [];
|
|
4434
|
+
for (const photoWithTag of processedPhotosWithTags) {
|
|
4435
|
+
if (photoWithTag.url && photoWithTag.url.startsWith("data:")) {
|
|
4436
|
+
const uploadedUrl = await uploadPhoto(
|
|
4437
|
+
photoWithTag.url,
|
|
4438
|
+
"clinics",
|
|
4439
|
+
clinicId,
|
|
4440
|
+
`tagged-${photoWithTag.tag}`,
|
|
4441
|
+
app
|
|
4442
|
+
);
|
|
4443
|
+
if (uploadedUrl) {
|
|
4444
|
+
updatedPhotosWithTags.push({
|
|
4445
|
+
url: uploadedUrl,
|
|
4446
|
+
tag: photoWithTag.tag
|
|
4447
|
+
});
|
|
4448
|
+
}
|
|
4449
|
+
} else {
|
|
4450
|
+
updatedPhotosWithTags.push(photoWithTag);
|
|
4451
|
+
}
|
|
4452
|
+
}
|
|
4453
|
+
processedPhotosWithTags = updatedPhotosWithTags;
|
|
4454
|
+
console.log("[CLINIC] Photos with tags processed", {
|
|
4455
|
+
count: processedPhotosWithTags.length
|
|
4456
|
+
});
|
|
4457
|
+
} catch (tagsError) {
|
|
4458
|
+
console.error("[CLINIC] Error processing photos with tags:", tagsError);
|
|
4459
|
+
processedPhotosWithTags = ((_a = validatedData.photosWithTags) == null ? void 0 : _a.filter(
|
|
4460
|
+
(photo) => !photo.url.startsWith("data:")
|
|
4461
|
+
)) || [];
|
|
4462
|
+
}
|
|
4155
4463
|
}
|
|
4156
4464
|
const now = Timestamp11.now();
|
|
4465
|
+
console.log("[CLINIC] Preparing clinic data object");
|
|
4157
4466
|
const clinicData = {
|
|
4158
4467
|
...validatedData,
|
|
4159
|
-
id:
|
|
4468
|
+
id: clinicId,
|
|
4160
4469
|
description: validatedData.description || void 0,
|
|
4161
4470
|
location: {
|
|
4162
|
-
|
|
4471
|
+
address: validatedData.location.address || "",
|
|
4472
|
+
city: validatedData.location.city || "",
|
|
4473
|
+
country: validatedData.location.country || "",
|
|
4474
|
+
postalCode: validatedData.location.postalCode || "",
|
|
4475
|
+
latitude: validatedData.location.latitude || 0,
|
|
4476
|
+
longitude: validatedData.location.longitude || 0,
|
|
4163
4477
|
geohash: validatedData.location.geohash || void 0
|
|
4164
4478
|
},
|
|
4165
4479
|
contactInfo: {
|
|
4166
|
-
|
|
4480
|
+
email: validatedData.contactInfo.email || "",
|
|
4481
|
+
phoneNumber: validatedData.contactInfo.phoneNumber || "",
|
|
4167
4482
|
alternativePhoneNumber: validatedData.contactInfo.alternativePhoneNumber || void 0,
|
|
4168
4483
|
website: validatedData.contactInfo.website || void 0
|
|
4169
4484
|
},
|
|
4485
|
+
logo: logoUrl || void 0,
|
|
4170
4486
|
tags: validatedData.tags || [],
|
|
4171
|
-
featuredPhotos: [],
|
|
4172
|
-
photos:
|
|
4487
|
+
featuredPhotos: processedFeaturedPhotos || [],
|
|
4488
|
+
photos: processedPhotos || [],
|
|
4489
|
+
photosWithTags: processedPhotosWithTags,
|
|
4173
4490
|
doctors: [],
|
|
4174
4491
|
doctorsInfo: [],
|
|
4175
4492
|
services: [],
|
|
@@ -4184,17 +4501,73 @@ async function createClinic(db, data, creatorAdminId, clinicGroupService, clinic
|
|
|
4184
4501
|
isVerified: false
|
|
4185
4502
|
};
|
|
4186
4503
|
try {
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4504
|
+
console.log("[CLINIC] Validating complete clinic object");
|
|
4505
|
+
try {
|
|
4506
|
+
clinicSchema.parse(clinicData);
|
|
4507
|
+
console.log("[CLINIC] Clinic validation passed");
|
|
4508
|
+
} catch (schemaError) {
|
|
4509
|
+
console.error(
|
|
4510
|
+
"[CLINIC] Clinic validation failed:",
|
|
4511
|
+
JSON.stringify(schemaError, null, 2)
|
|
4512
|
+
);
|
|
4513
|
+
throw schemaError;
|
|
4514
|
+
}
|
|
4515
|
+
console.log("[CLINIC] Saving clinic to Firestore", {
|
|
4516
|
+
clinicId: clinicData.id
|
|
4517
|
+
});
|
|
4518
|
+
try {
|
|
4519
|
+
await setDoc10(doc8(db, CLINICS_COLLECTION, clinicData.id), clinicData);
|
|
4520
|
+
console.log("[CLINIC] Clinic saved successfully");
|
|
4521
|
+
} catch (firestoreError) {
|
|
4522
|
+
console.error("[CLINIC] Error saving to Firestore:", firestoreError);
|
|
4523
|
+
throw firestoreError;
|
|
4524
|
+
}
|
|
4525
|
+
console.log("[CLINIC] Adding clinic to clinic group");
|
|
4526
|
+
try {
|
|
4527
|
+
const group = await clinicGroupService.getClinicGroup(
|
|
4528
|
+
validatedData.clinicGroupId
|
|
4529
|
+
);
|
|
4530
|
+
if (group) {
|
|
4531
|
+
await clinicGroupService.updateClinicGroup(
|
|
4532
|
+
validatedData.clinicGroupId,
|
|
4533
|
+
{
|
|
4534
|
+
clinics: [...group.clinics, clinicData.id]
|
|
4535
|
+
}
|
|
4536
|
+
);
|
|
4537
|
+
console.log("[CLINIC] Clinic added to group successfully");
|
|
4538
|
+
}
|
|
4539
|
+
} catch (groupUpdateError) {
|
|
4540
|
+
console.error("[CLINIC] Error adding clinic to group:", groupUpdateError);
|
|
4541
|
+
}
|
|
4542
|
+
console.log("[CLINIC] Adding clinic to admin's managed clinics");
|
|
4543
|
+
try {
|
|
4544
|
+
await clinicAdminService.addClinicToManaged(
|
|
4545
|
+
creatorAdminId,
|
|
4546
|
+
clinicData.id
|
|
4547
|
+
);
|
|
4548
|
+
console.log(
|
|
4549
|
+
"[CLINIC] Clinic added to admin's managed clinics successfully"
|
|
4550
|
+
);
|
|
4551
|
+
} catch (adminUpdateError) {
|
|
4552
|
+
console.error(
|
|
4553
|
+
"[CLINIC] Error adding clinic to admin's managed clinics:",
|
|
4554
|
+
adminUpdateError
|
|
4555
|
+
);
|
|
4556
|
+
}
|
|
4557
|
+
console.log("[CLINIC] Clinic creation completed successfully", {
|
|
4558
|
+
clinicId: clinicData.id,
|
|
4559
|
+
clinicName: clinicData.name
|
|
4191
4560
|
});
|
|
4192
|
-
await clinicAdminService.addClinicToManaged(creatorAdminId, clinicData.id);
|
|
4193
4561
|
return clinicData;
|
|
4194
4562
|
} catch (error) {
|
|
4195
4563
|
if (error instanceof z14.ZodError) {
|
|
4564
|
+
console.error(
|
|
4565
|
+
"[CLINIC] Zod validation error:",
|
|
4566
|
+
JSON.stringify(error.errors, null, 2)
|
|
4567
|
+
);
|
|
4196
4568
|
throw new Error("Invalid clinic data: " + error.message);
|
|
4197
4569
|
}
|
|
4570
|
+
console.error("[CLINIC] Unhandled error in createClinic:", error);
|
|
4198
4571
|
throw error;
|
|
4199
4572
|
}
|
|
4200
4573
|
}
|
|
@@ -4215,27 +4588,177 @@ async function getClinicsByGroup(db, groupId) {
|
|
|
4215
4588
|
const querySnapshot = await getDocs6(q);
|
|
4216
4589
|
return querySnapshot.docs.map((doc14) => doc14.data());
|
|
4217
4590
|
}
|
|
4218
|
-
async function updateClinic(db, clinicId, data, adminId, clinicAdminService) {
|
|
4591
|
+
async function updateClinic(db, clinicId, data, adminId, clinicAdminService, app) {
|
|
4592
|
+
console.log("[CLINIC] Starting clinic update", { clinicId, adminId });
|
|
4219
4593
|
const clinic = await getClinic(db, clinicId);
|
|
4220
4594
|
if (!clinic) {
|
|
4595
|
+
console.error("[CLINIC] Clinic not found", { clinicId });
|
|
4221
4596
|
throw new Error("Clinic not found");
|
|
4222
4597
|
}
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4598
|
+
try {
|
|
4599
|
+
console.log("[CLINIC] Checking admin permissions");
|
|
4600
|
+
const admin = await clinicAdminService.getClinicAdmin(adminId);
|
|
4601
|
+
if (!admin) {
|
|
4602
|
+
console.error("[CLINIC] Admin not found", { adminId });
|
|
4603
|
+
throw new Error("Admin not found");
|
|
4604
|
+
}
|
|
4605
|
+
const hasPermission = admin.isGroupOwner && admin.clinicGroupId === clinic.clinicGroupId || admin.clinicsManaged.includes(clinicId) && clinic.admins && clinic.admins.includes(adminId);
|
|
4606
|
+
if (!hasPermission) {
|
|
4607
|
+
console.error(
|
|
4608
|
+
"[CLINIC] Admin does not have permission to update this clinic",
|
|
4609
|
+
{
|
|
4610
|
+
adminId,
|
|
4611
|
+
clinicId,
|
|
4612
|
+
isGroupOwner: admin.isGroupOwner,
|
|
4613
|
+
clinicsManaged: admin.clinicsManaged,
|
|
4614
|
+
isClinicAdmin: clinic.admins && clinic.admins.includes(adminId)
|
|
4615
|
+
}
|
|
4616
|
+
);
|
|
4617
|
+
throw new Error("Admin does not have permission to update this clinic");
|
|
4618
|
+
}
|
|
4619
|
+
console.log("[CLINIC] Admin permissions verified");
|
|
4620
|
+
} catch (adminError) {
|
|
4621
|
+
console.error("[CLINIC] Error verifying admin permissions:", adminError);
|
|
4622
|
+
throw adminError;
|
|
4623
|
+
}
|
|
4624
|
+
let updatedData = { ...data };
|
|
4625
|
+
if (data.logo && typeof data.logo === "string" && data.logo.startsWith("data:")) {
|
|
4626
|
+
console.log("[CLINIC] Processing logo update");
|
|
4627
|
+
try {
|
|
4628
|
+
const logoUrl = await uploadPhoto(
|
|
4629
|
+
data.logo,
|
|
4630
|
+
"clinics",
|
|
4631
|
+
clinicId,
|
|
4632
|
+
"logo",
|
|
4633
|
+
app
|
|
4634
|
+
);
|
|
4635
|
+
console.log("[CLINIC] Logo update processed", { logoUrl });
|
|
4636
|
+
if (logoUrl !== null) {
|
|
4637
|
+
updatedData.logo = logoUrl;
|
|
4638
|
+
}
|
|
4639
|
+
} catch (logoError) {
|
|
4640
|
+
console.error("[CLINIC] Error processing logo update:", logoError);
|
|
4641
|
+
}
|
|
4226
4642
|
}
|
|
4227
|
-
if (
|
|
4228
|
-
|
|
4643
|
+
if (data.photos && data.photos.length > 0) {
|
|
4644
|
+
console.log("[CLINIC] Processing regular photos update");
|
|
4645
|
+
try {
|
|
4646
|
+
const dataUrlPhotos = data.photos.filter(
|
|
4647
|
+
(photo) => typeof photo === "string" && photo.startsWith("data:")
|
|
4648
|
+
);
|
|
4649
|
+
const existingPhotos = data.photos.filter(
|
|
4650
|
+
(photo) => typeof photo === "string" && !photo.startsWith("data:")
|
|
4651
|
+
);
|
|
4652
|
+
if (dataUrlPhotos.length > 0) {
|
|
4653
|
+
const uploadedPhotos = await uploadMultiplePhotos(
|
|
4654
|
+
dataUrlPhotos,
|
|
4655
|
+
"clinics",
|
|
4656
|
+
clinicId,
|
|
4657
|
+
"photo",
|
|
4658
|
+
app
|
|
4659
|
+
);
|
|
4660
|
+
console.log("[CLINIC] Regular photos update processed", {
|
|
4661
|
+
count: uploadedPhotos.length
|
|
4662
|
+
});
|
|
4663
|
+
updatedData.photos = [...existingPhotos, ...uploadedPhotos];
|
|
4664
|
+
}
|
|
4665
|
+
} catch (photosError) {
|
|
4666
|
+
console.error(
|
|
4667
|
+
"[CLINIC] Error processing regular photos update:",
|
|
4668
|
+
photosError
|
|
4669
|
+
);
|
|
4670
|
+
updatedData.photos = data.photos.filter(
|
|
4671
|
+
(photo) => typeof photo === "string" && !photo.startsWith("data:")
|
|
4672
|
+
);
|
|
4673
|
+
}
|
|
4229
4674
|
}
|
|
4230
|
-
|
|
4231
|
-
|
|
4675
|
+
if (data.featuredPhotos && data.featuredPhotos.length > 0) {
|
|
4676
|
+
console.log("[CLINIC] Processing featured photos update");
|
|
4677
|
+
try {
|
|
4678
|
+
const dataUrlPhotos = data.featuredPhotos.filter(
|
|
4679
|
+
(photo) => typeof photo === "string" && photo.startsWith("data:")
|
|
4680
|
+
);
|
|
4681
|
+
const existingPhotos = data.featuredPhotos.filter(
|
|
4682
|
+
(photo) => typeof photo === "string" && !photo.startsWith("data:")
|
|
4683
|
+
);
|
|
4684
|
+
if (dataUrlPhotos.length > 0) {
|
|
4685
|
+
const uploadedPhotos = await uploadMultiplePhotos(
|
|
4686
|
+
dataUrlPhotos,
|
|
4687
|
+
"clinics",
|
|
4688
|
+
clinicId,
|
|
4689
|
+
"featured",
|
|
4690
|
+
app
|
|
4691
|
+
);
|
|
4692
|
+
console.log("[CLINIC] Featured photos update processed", {
|
|
4693
|
+
count: uploadedPhotos.length
|
|
4694
|
+
});
|
|
4695
|
+
updatedData.featuredPhotos = [...existingPhotos, ...uploadedPhotos];
|
|
4696
|
+
}
|
|
4697
|
+
} catch (featuredError) {
|
|
4698
|
+
console.error(
|
|
4699
|
+
"[CLINIC] Error processing featured photos update:",
|
|
4700
|
+
featuredError
|
|
4701
|
+
);
|
|
4702
|
+
updatedData.featuredPhotos = data.featuredPhotos.filter(
|
|
4703
|
+
(photo) => typeof photo === "string" && !photo.startsWith("data:")
|
|
4704
|
+
);
|
|
4705
|
+
}
|
|
4706
|
+
}
|
|
4707
|
+
if (data.photosWithTags && data.photosWithTags.length > 0) {
|
|
4708
|
+
console.log("[CLINIC] Processing photos with tags update");
|
|
4709
|
+
try {
|
|
4710
|
+
const updatedPhotosWithTags = [];
|
|
4711
|
+
for (const photoWithTag of data.photosWithTags) {
|
|
4712
|
+
if (photoWithTag.url && photoWithTag.url.startsWith("data:")) {
|
|
4713
|
+
const uploadedUrl = await uploadPhoto(
|
|
4714
|
+
photoWithTag.url,
|
|
4715
|
+
"clinics",
|
|
4716
|
+
clinicId,
|
|
4717
|
+
`tagged-${photoWithTag.tag}`,
|
|
4718
|
+
app
|
|
4719
|
+
);
|
|
4720
|
+
if (uploadedUrl) {
|
|
4721
|
+
updatedPhotosWithTags.push({
|
|
4722
|
+
url: uploadedUrl,
|
|
4723
|
+
tag: photoWithTag.tag
|
|
4724
|
+
});
|
|
4725
|
+
}
|
|
4726
|
+
} else {
|
|
4727
|
+
updatedPhotosWithTags.push(photoWithTag);
|
|
4728
|
+
}
|
|
4729
|
+
}
|
|
4730
|
+
updatedData.photosWithTags = updatedPhotosWithTags;
|
|
4731
|
+
console.log("[CLINIC] Photos with tags update processed", {
|
|
4732
|
+
count: updatedPhotosWithTags.length
|
|
4733
|
+
});
|
|
4734
|
+
} catch (tagsError) {
|
|
4735
|
+
console.error(
|
|
4736
|
+
"[CLINIC] Error processing photos with tags update:",
|
|
4737
|
+
tagsError
|
|
4738
|
+
);
|
|
4739
|
+
updatedData.photosWithTags = data.photosWithTags.filter(
|
|
4740
|
+
(photo) => !photo.url.startsWith("data:")
|
|
4741
|
+
);
|
|
4742
|
+
}
|
|
4743
|
+
}
|
|
4744
|
+
updatedData = {
|
|
4745
|
+
...updatedData,
|
|
4232
4746
|
updatedAt: Timestamp11.now()
|
|
4233
4747
|
};
|
|
4234
|
-
|
|
4748
|
+
console.log("[CLINIC] Updating clinic in Firestore");
|
|
4749
|
+
try {
|
|
4750
|
+
await updateDoc11(doc8(db, CLINICS_COLLECTION, clinicId), updatedData);
|
|
4751
|
+
console.log("[CLINIC] Clinic updated successfully");
|
|
4752
|
+
} catch (updateError) {
|
|
4753
|
+
console.error("[CLINIC] Error updating clinic in Firestore:", updateError);
|
|
4754
|
+
throw updateError;
|
|
4755
|
+
}
|
|
4235
4756
|
const updatedClinic = await getClinic(db, clinicId);
|
|
4236
4757
|
if (!updatedClinic) {
|
|
4758
|
+
console.error("[CLINIC] Failed to retrieve updated clinic");
|
|
4237
4759
|
throw new Error("Failed to retrieve updated clinic");
|
|
4238
4760
|
}
|
|
4761
|
+
console.log("[CLINIC] Clinic update completed successfully");
|
|
4239
4762
|
return updatedClinic;
|
|
4240
4763
|
}
|
|
4241
4764
|
async function deactivateClinic(db, clinicId, adminId, clinicAdminService) {
|
|
@@ -4247,7 +4770,8 @@ async function deactivateClinic(db, clinicId, adminId, clinicAdminService) {
|
|
|
4247
4770
|
if (!admin) {
|
|
4248
4771
|
throw new Error("Admin not found");
|
|
4249
4772
|
}
|
|
4250
|
-
|
|
4773
|
+
const hasPermission = admin.isGroupOwner && admin.clinicGroupId === clinic.clinicGroupId || admin.clinicsManaged.includes(clinicId) && clinic.admins && clinic.admins.includes(adminId);
|
|
4774
|
+
if (!hasPermission) {
|
|
4251
4775
|
throw new Error("Admin does not have permission to deactivate this clinic");
|
|
4252
4776
|
}
|
|
4253
4777
|
await updateDoc11(doc8(db, CLINICS_COLLECTION, clinicId), {
|
|
@@ -4292,27 +4816,28 @@ async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGr
|
|
|
4292
4816
|
import {
|
|
4293
4817
|
collection as collection7,
|
|
4294
4818
|
doc as doc9,
|
|
4295
|
-
|
|
4296
|
-
|
|
4819
|
+
Timestamp as Timestamp12,
|
|
4820
|
+
getDoc as getDoc13,
|
|
4821
|
+
addDoc as addDoc2
|
|
4297
4822
|
} from "firebase/firestore";
|
|
4298
|
-
async function addReview(db, clinicId, review) {
|
|
4299
|
-
const
|
|
4300
|
-
|
|
4823
|
+
async function addReview(db, clinicId, review, app) {
|
|
4824
|
+
const clinicRef = doc9(db, "clinics", clinicId);
|
|
4825
|
+
const clinicSnap = await getDoc13(clinicRef);
|
|
4826
|
+
if (!clinicSnap.exists()) {
|
|
4301
4827
|
throw new Error("Clinic not found");
|
|
4302
4828
|
}
|
|
4829
|
+
const clinic = clinicSnap.data();
|
|
4303
4830
|
const now = Timestamp12.now();
|
|
4304
4831
|
const reviewData = {
|
|
4832
|
+
...review,
|
|
4305
4833
|
id: doc9(collection7(db, "clinic_reviews")).id,
|
|
4306
4834
|
clinicId,
|
|
4307
|
-
patientId: review.patientId,
|
|
4308
|
-
rating: review.rating,
|
|
4309
|
-
comment: review.comment,
|
|
4310
4835
|
createdAt: now,
|
|
4311
4836
|
updatedAt: now,
|
|
4312
4837
|
isVerified: false
|
|
4313
4838
|
};
|
|
4314
4839
|
clinicReviewSchema.parse(reviewData);
|
|
4315
|
-
await
|
|
4840
|
+
await addDoc2(collection7(db, "clinic_reviews"), reviewData);
|
|
4316
4841
|
const newRating = clinic.rating ? {
|
|
4317
4842
|
average: (clinic.rating.average * clinic.rating.count + review.rating) / (clinic.rating.count + 1),
|
|
4318
4843
|
count: clinic.rating.count + 1
|
|
@@ -4328,28 +4853,24 @@ async function addReview(db, clinicId, review) {
|
|
|
4328
4853
|
...clinic.reviewsInfo,
|
|
4329
4854
|
{
|
|
4330
4855
|
id: reviewData.id,
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
// This should be fetched from patient service
|
|
4336
|
-
patientPhoto: "",
|
|
4337
|
-
// This should be fetched from patient service
|
|
4338
|
-
createdAt: now,
|
|
4339
|
-
updatedAt: now
|
|
4856
|
+
patientId: reviewData.patientId,
|
|
4857
|
+
rating: reviewData.rating,
|
|
4858
|
+
comment: reviewData.comment,
|
|
4859
|
+
createdAt: reviewData.createdAt
|
|
4340
4860
|
}
|
|
4341
4861
|
]
|
|
4342
4862
|
},
|
|
4343
|
-
|
|
4344
|
-
//
|
|
4345
|
-
|
|
4346
|
-
//
|
|
4863
|
+
"system",
|
|
4864
|
+
// System update, no admin ID needed
|
|
4865
|
+
null,
|
|
4866
|
+
// No clinic admin service needed for system updates
|
|
4867
|
+
app
|
|
4347
4868
|
);
|
|
4348
4869
|
return reviewData;
|
|
4349
4870
|
}
|
|
4350
4871
|
|
|
4351
4872
|
// src/services/clinic/utils/tag.utils.ts
|
|
4352
|
-
async function addTags(db, clinicId, adminId, newTags, clinicAdminService) {
|
|
4873
|
+
async function addTags(db, clinicId, adminId, newTags, clinicAdminService, app) {
|
|
4353
4874
|
const clinic = await getClinic(db, clinicId);
|
|
4354
4875
|
if (!clinic) {
|
|
4355
4876
|
throw new Error("Clinic not found");
|
|
@@ -4358,7 +4879,8 @@ async function addTags(db, clinicId, adminId, newTags, clinicAdminService) {
|
|
|
4358
4879
|
if (!admin) {
|
|
4359
4880
|
throw new Error("Admin not found");
|
|
4360
4881
|
}
|
|
4361
|
-
|
|
4882
|
+
const hasPermission = admin.isGroupOwner && admin.clinicGroupId === clinic.clinicGroupId || admin.clinicsManaged.includes(clinicId) && clinic.admins && clinic.admins.includes(adminId);
|
|
4883
|
+
if (!hasPermission) {
|
|
4362
4884
|
throw new Error("Admin does not have permission to update this clinic");
|
|
4363
4885
|
}
|
|
4364
4886
|
const updatedTags = [.../* @__PURE__ */ new Set([...clinic.tags, ...newTags.tags || []])];
|
|
@@ -4369,10 +4891,11 @@ async function addTags(db, clinicId, adminId, newTags, clinicAdminService) {
|
|
|
4369
4891
|
tags: updatedTags
|
|
4370
4892
|
},
|
|
4371
4893
|
adminId,
|
|
4372
|
-
clinicAdminService
|
|
4894
|
+
clinicAdminService,
|
|
4895
|
+
app
|
|
4373
4896
|
);
|
|
4374
4897
|
}
|
|
4375
|
-
async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminService) {
|
|
4898
|
+
async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminService, app) {
|
|
4376
4899
|
const clinic = await getClinic(db, clinicId);
|
|
4377
4900
|
if (!clinic) {
|
|
4378
4901
|
throw new Error("Clinic not found");
|
|
@@ -4381,14 +4904,12 @@ async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminServic
|
|
|
4381
4904
|
if (!admin) {
|
|
4382
4905
|
throw new Error("Admin not found");
|
|
4383
4906
|
}
|
|
4384
|
-
|
|
4907
|
+
const hasPermission = admin.isGroupOwner && admin.clinicGroupId === clinic.clinicGroupId || admin.clinicsManaged.includes(clinicId) && clinic.admins && clinic.admins.includes(adminId);
|
|
4908
|
+
if (!hasPermission) {
|
|
4385
4909
|
throw new Error("Admin does not have permission to update this clinic");
|
|
4386
4910
|
}
|
|
4387
4911
|
const updatedTags = clinic.tags.filter(
|
|
4388
|
-
(tag) =>
|
|
4389
|
-
var _a;
|
|
4390
|
-
return !((_a = tagsToRemove.tags) == null ? void 0 : _a.includes(tag));
|
|
4391
|
-
}
|
|
4912
|
+
(tag) => !tagsToRemove.tags || !tagsToRemove.tags.includes(tag)
|
|
4392
4913
|
);
|
|
4393
4914
|
return updateClinic(
|
|
4394
4915
|
db,
|
|
@@ -4397,7 +4918,8 @@ async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminServic
|
|
|
4397
4918
|
tags: updatedTags
|
|
4398
4919
|
},
|
|
4399
4920
|
adminId,
|
|
4400
|
-
clinicAdminService
|
|
4921
|
+
clinicAdminService,
|
|
4922
|
+
app
|
|
4401
4923
|
);
|
|
4402
4924
|
}
|
|
4403
4925
|
|
|
@@ -4472,7 +4994,8 @@ var ClinicService = class extends BaseService {
|
|
|
4472
4994
|
data,
|
|
4473
4995
|
creatorAdminId,
|
|
4474
4996
|
this.clinicGroupService,
|
|
4475
|
-
this.clinicAdminService
|
|
4997
|
+
this.clinicAdminService,
|
|
4998
|
+
this.app
|
|
4476
4999
|
);
|
|
4477
5000
|
}
|
|
4478
5001
|
/**
|
|
@@ -4507,14 +5030,15 @@ var ClinicService = class extends BaseService {
|
|
|
4507
5030
|
clinicId,
|
|
4508
5031
|
data,
|
|
4509
5032
|
adminId,
|
|
4510
|
-
this.clinicAdminService
|
|
5033
|
+
this.clinicAdminService,
|
|
5034
|
+
this.app
|
|
4511
5035
|
);
|
|
4512
5036
|
}
|
|
4513
5037
|
/**
|
|
4514
5038
|
* Dodaje recenziju klinici
|
|
4515
5039
|
*/
|
|
4516
5040
|
async addReview(clinicId, review) {
|
|
4517
|
-
return addReview(this.db, clinicId, review);
|
|
5041
|
+
return addReview(this.db, clinicId, review, this.app);
|
|
4518
5042
|
}
|
|
4519
5043
|
/**
|
|
4520
5044
|
* Deaktivira kliniku
|
|
@@ -4536,7 +5060,8 @@ var ClinicService = class extends BaseService {
|
|
|
4536
5060
|
clinicId,
|
|
4537
5061
|
adminId,
|
|
4538
5062
|
newTags,
|
|
4539
|
-
this.clinicAdminService
|
|
5063
|
+
this.clinicAdminService,
|
|
5064
|
+
this.app
|
|
4540
5065
|
);
|
|
4541
5066
|
}
|
|
4542
5067
|
/**
|
|
@@ -4548,7 +5073,8 @@ var ClinicService = class extends BaseService {
|
|
|
4548
5073
|
clinicId,
|
|
4549
5074
|
adminId,
|
|
4550
5075
|
tagsToRemove,
|
|
4551
|
-
this.clinicAdminService
|
|
5076
|
+
this.clinicAdminService,
|
|
5077
|
+
this.app
|
|
4552
5078
|
);
|
|
4553
5079
|
}
|
|
4554
5080
|
/**
|
|
@@ -4583,12 +5109,21 @@ var ClinicService = class extends BaseService {
|
|
|
4583
5109
|
* @returns The created clinic
|
|
4584
5110
|
*/
|
|
4585
5111
|
async createClinicBranch(clinicGroupId, setupData, adminId) {
|
|
5112
|
+
var _a, _b;
|
|
5113
|
+
console.log("[CLINIC_SERVICE] Starting clinic branch creation", {
|
|
5114
|
+
clinicGroupId,
|
|
5115
|
+
adminId
|
|
5116
|
+
});
|
|
4586
5117
|
const clinicGroup = await this.clinicGroupService.getClinicGroup(
|
|
4587
5118
|
clinicGroupId
|
|
4588
5119
|
);
|
|
4589
5120
|
if (!clinicGroup) {
|
|
5121
|
+
console.error("[CLINIC_SERVICE] Clinic group not found", {
|
|
5122
|
+
clinicGroupId
|
|
5123
|
+
});
|
|
4590
5124
|
throw new Error(`Clinic group with ID ${clinicGroupId} not found`);
|
|
4591
5125
|
}
|
|
5126
|
+
console.log("[CLINIC_SERVICE] Clinic group verified");
|
|
4592
5127
|
const createClinicData = {
|
|
4593
5128
|
clinicGroupId,
|
|
4594
5129
|
name: setupData.name,
|
|
@@ -4597,8 +5132,8 @@ var ClinicService = class extends BaseService {
|
|
|
4597
5132
|
contactInfo: setupData.contactInfo,
|
|
4598
5133
|
workingHours: setupData.workingHours,
|
|
4599
5134
|
tags: setupData.tags,
|
|
4600
|
-
photos: setupData.photos,
|
|
4601
|
-
photosWithTags: setupData.photosWithTags,
|
|
5135
|
+
photos: setupData.photos || [],
|
|
5136
|
+
photosWithTags: setupData.photosWithTags || [],
|
|
4602
5137
|
doctors: [],
|
|
4603
5138
|
services: [],
|
|
4604
5139
|
admins: [adminId],
|
|
@@ -4607,7 +5142,17 @@ var ClinicService = class extends BaseService {
|
|
|
4607
5142
|
logo: setupData.logo,
|
|
4608
5143
|
featuredPhotos: setupData.featuredPhotos || []
|
|
4609
5144
|
};
|
|
5145
|
+
console.log("[CLINIC_SERVICE] Creating clinic branch with data", {
|
|
5146
|
+
name: createClinicData.name,
|
|
5147
|
+
hasLogo: !!createClinicData.logo,
|
|
5148
|
+
photosCount: createClinicData.photos.length,
|
|
5149
|
+
featuredPhotosCount: ((_a = createClinicData.featuredPhotos) == null ? void 0 : _a.length) || 0,
|
|
5150
|
+
photosWithTagsCount: ((_b = createClinicData.photosWithTags) == null ? void 0 : _b.length) || 0
|
|
5151
|
+
});
|
|
4610
5152
|
const clinic = await this.createClinic(createClinicData, adminId);
|
|
5153
|
+
console.log("[CLINIC_SERVICE] Clinic branch created successfully", {
|
|
5154
|
+
clinicId: clinic.id
|
|
5155
|
+
});
|
|
4611
5156
|
return clinic;
|
|
4612
5157
|
}
|
|
4613
5158
|
};
|
|
@@ -4729,12 +5274,38 @@ var AuthService = class extends BaseService {
|
|
|
4729
5274
|
"Clinic group data is required when creating a new group"
|
|
4730
5275
|
);
|
|
4731
5276
|
}
|
|
5277
|
+
console.log("[AUTH] Creating clinic admin first (without group)");
|
|
5278
|
+
const createClinicAdminData = {
|
|
5279
|
+
userRef: firebaseUser.uid,
|
|
5280
|
+
isGroupOwner: true,
|
|
5281
|
+
clinicsManaged: [],
|
|
5282
|
+
contactInfo: contactPerson,
|
|
5283
|
+
roleTitle: data.title,
|
|
5284
|
+
isActive: true
|
|
5285
|
+
// No clinicGroupId yet
|
|
5286
|
+
};
|
|
5287
|
+
let adminProfile;
|
|
5288
|
+
try {
|
|
5289
|
+
adminProfile = await clinicAdminService.createClinicAdmin(
|
|
5290
|
+
createClinicAdminData
|
|
5291
|
+
);
|
|
5292
|
+
console.log("[AUTH] Clinic admin created successfully", {
|
|
5293
|
+
adminId: adminProfile.id
|
|
5294
|
+
});
|
|
5295
|
+
} catch (adminCreationError) {
|
|
5296
|
+
console.error(
|
|
5297
|
+
"[AUTH] Clinic admin creation failed:",
|
|
5298
|
+
adminCreationError
|
|
5299
|
+
);
|
|
5300
|
+
throw adminCreationError;
|
|
5301
|
+
}
|
|
4732
5302
|
const createClinicGroupData = {
|
|
4733
5303
|
name: data.clinicGroupData.name,
|
|
4734
5304
|
hqLocation: data.clinicGroupData.hqLocation,
|
|
4735
5305
|
contactInfo: data.clinicGroupData.contactInfo,
|
|
4736
5306
|
contactPerson,
|
|
4737
|
-
ownerId:
|
|
5307
|
+
ownerId: adminProfile.id,
|
|
5308
|
+
// Use admin profile ID, not user UID
|
|
4738
5309
|
isActive: true,
|
|
4739
5310
|
logo: data.clinicGroupData.logo || null,
|
|
4740
5311
|
subscriptionModel: data.clinicGroupData.subscriptionModel || "no_subscription" /* NO_SUBSCRIPTION */
|
|
@@ -4742,13 +5313,24 @@ var AuthService = class extends BaseService {
|
|
|
4742
5313
|
console.log("[AUTH] Clinic group data prepared", {
|
|
4743
5314
|
groupName: createClinicGroupData.name
|
|
4744
5315
|
});
|
|
5316
|
+
let clinicGroup;
|
|
4745
5317
|
try {
|
|
4746
|
-
await clinicGroupService.createClinicGroup(
|
|
5318
|
+
clinicGroup = await clinicGroupService.createClinicGroup(
|
|
4747
5319
|
createClinicGroupData,
|
|
4748
|
-
|
|
4749
|
-
|
|
5320
|
+
adminProfile.id,
|
|
5321
|
+
// Use admin profile ID, not user UID
|
|
5322
|
+
false
|
|
5323
|
+
// This is not a default group since we're providing complete data
|
|
4750
5324
|
);
|
|
4751
|
-
console.log("[AUTH] Clinic group created successfully"
|
|
5325
|
+
console.log("[AUTH] Clinic group created successfully", {
|
|
5326
|
+
groupId: clinicGroup.id
|
|
5327
|
+
});
|
|
5328
|
+
console.log("[AUTH] Updating admin with clinic group ID");
|
|
5329
|
+
await clinicAdminService.updateClinicAdmin(adminProfile.id, {
|
|
5330
|
+
// Use admin profile ID, not user UID
|
|
5331
|
+
clinicGroupId: clinicGroup.id
|
|
5332
|
+
});
|
|
5333
|
+
console.log("[AUTH] Admin updated with clinic group ID successfully");
|
|
4752
5334
|
} catch (groupCreationError) {
|
|
4753
5335
|
console.error(
|
|
4754
5336
|
"[AUTH] Clinic group creation failed:",
|
|
@@ -4821,9 +5403,14 @@ var AuthService = class extends BaseService {
|
|
|
4821
5403
|
roleTitle: data.title,
|
|
4822
5404
|
isActive: true
|
|
4823
5405
|
};
|
|
5406
|
+
let adminProfile;
|
|
4824
5407
|
try {
|
|
4825
|
-
await clinicAdminService.createClinicAdmin(
|
|
4826
|
-
|
|
5408
|
+
adminProfile = await clinicAdminService.createClinicAdmin(
|
|
5409
|
+
createClinicAdminData
|
|
5410
|
+
);
|
|
5411
|
+
console.log("[AUTH] Clinic admin created successfully", {
|
|
5412
|
+
adminId: adminProfile.id
|
|
5413
|
+
});
|
|
4827
5414
|
} catch (adminCreationError) {
|
|
4828
5415
|
console.error(
|
|
4829
5416
|
"[AUTH] Clinic admin creation failed:",
|
|
@@ -5132,7 +5719,7 @@ var AuthService = class extends BaseService {
|
|
|
5132
5719
|
import {
|
|
5133
5720
|
collection as collection10,
|
|
5134
5721
|
doc as doc11,
|
|
5135
|
-
getDoc as
|
|
5722
|
+
getDoc as getDoc15,
|
|
5136
5723
|
getDocs as getDocs9,
|
|
5137
5724
|
query as query9,
|
|
5138
5725
|
where as where9,
|
|
@@ -5140,8 +5727,8 @@ import {
|
|
|
5140
5727
|
deleteDoc as deleteDoc6,
|
|
5141
5728
|
orderBy,
|
|
5142
5729
|
Timestamp as Timestamp14,
|
|
5143
|
-
addDoc,
|
|
5144
|
-
writeBatch as
|
|
5730
|
+
addDoc as addDoc3,
|
|
5731
|
+
writeBatch as writeBatch3
|
|
5145
5732
|
} from "firebase/firestore";
|
|
5146
5733
|
|
|
5147
5734
|
// src/types/notifications/index.ts
|
|
@@ -5178,7 +5765,7 @@ var NotificationService = class extends BaseService {
|
|
|
5178
5765
|
isRead: false,
|
|
5179
5766
|
userRole: notification.userRole || "patient" /* PATIENT */
|
|
5180
5767
|
};
|
|
5181
|
-
const docRef = await
|
|
5768
|
+
const docRef = await addDoc3(notificationsRef, notificationData);
|
|
5182
5769
|
return {
|
|
5183
5770
|
...notificationData,
|
|
5184
5771
|
id: docRef.id
|
|
@@ -5193,7 +5780,7 @@ var NotificationService = class extends BaseService {
|
|
|
5193
5780
|
NOTIFICATIONS_COLLECTION,
|
|
5194
5781
|
notificationId
|
|
5195
5782
|
);
|
|
5196
|
-
const notificationDoc = await
|
|
5783
|
+
const notificationDoc = await getDoc15(notificationRef);
|
|
5197
5784
|
if (!notificationDoc.exists()) {
|
|
5198
5785
|
return null;
|
|
5199
5786
|
}
|
|
@@ -5252,7 +5839,7 @@ var NotificationService = class extends BaseService {
|
|
|
5252
5839
|
*/
|
|
5253
5840
|
async markAllAsRead(userId) {
|
|
5254
5841
|
const notifications = await this.getUnreadNotifications(userId);
|
|
5255
|
-
const batch =
|
|
5842
|
+
const batch = writeBatch3(this.db);
|
|
5256
5843
|
notifications.forEach((notification) => {
|
|
5257
5844
|
const notificationRef = doc11(
|
|
5258
5845
|
this.db,
|
|
@@ -5328,7 +5915,7 @@ var NotificationService = class extends BaseService {
|
|
|
5328
5915
|
import {
|
|
5329
5916
|
collection as collection11,
|
|
5330
5917
|
doc as doc12,
|
|
5331
|
-
getDoc as
|
|
5918
|
+
getDoc as getDoc16,
|
|
5332
5919
|
getDocs as getDocs10,
|
|
5333
5920
|
setDoc as setDoc13,
|
|
5334
5921
|
updateDoc as updateDoc14,
|
|
@@ -5384,7 +5971,7 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
5384
5971
|
*/
|
|
5385
5972
|
async getTemplateById(templateId) {
|
|
5386
5973
|
const docRef = doc12(this.collectionRef, templateId);
|
|
5387
|
-
const docSnap = await
|
|
5974
|
+
const docSnap = await getDoc16(docRef);
|
|
5388
5975
|
if (!docSnap.exists()) {
|
|
5389
5976
|
return null;
|
|
5390
5977
|
}
|
|
@@ -5523,7 +6110,7 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
5523
6110
|
import {
|
|
5524
6111
|
collection as collection12,
|
|
5525
6112
|
doc as doc13,
|
|
5526
|
-
getDoc as
|
|
6113
|
+
getDoc as getDoc17,
|
|
5527
6114
|
getDocs as getDocs11,
|
|
5528
6115
|
setDoc as setDoc14,
|
|
5529
6116
|
updateDoc as updateDoc15,
|
|
@@ -5580,7 +6167,7 @@ var FilledDocumentService = class extends BaseService {
|
|
|
5580
6167
|
*/
|
|
5581
6168
|
async getFilledDocumentById(documentId) {
|
|
5582
6169
|
const docRef = doc13(this.collectionRef, documentId);
|
|
5583
|
-
const docSnap = await
|
|
6170
|
+
const docSnap = await getDoc17(docRef);
|
|
5584
6171
|
if (!docSnap.exists()) {
|
|
5585
6172
|
return null;
|
|
5586
6173
|
}
|