@blackcode_sa/metaestetics-api 1.4.8 → 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.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] Creating default group for owner");
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: validatedData.userRef,
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
@@ -3769,23 +3787,49 @@ async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdm
3769
3787
  }
3770
3788
  const now = Timestamp10.now();
3771
3789
  console.log("[CLINIC_GROUP] Preparing clinic group data object");
3790
+ const groupId = doc7(collection5(db, CLINIC_GROUPS_COLLECTION)).id;
3772
3791
  console.log("[CLINIC_GROUP] Logo value:", {
3773
3792
  logoValue: validatedData.logo,
3774
3793
  logoType: validatedData.logo === null ? "null" : typeof validatedData.logo
3775
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 });
3776
3803
  const groupData = {
3777
3804
  ...validatedData,
3778
- id: doc7(collection5(db, CLINIC_GROUPS_COLLECTION)).id,
3805
+ id: groupId,
3806
+ name: validatedData.name,
3807
+ logo: logoUrl,
3808
+ // Use the uploaded logo URL or the original value
3779
3809
  description: isDefault ? void 0 : validatedData.description || void 0,
3780
3810
  hqLocation: {
3781
- ...validatedData.hqLocation,
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,
3782
3817
  geohash: validatedData.hqLocation.geohash || void 0
3783
3818
  },
3784
3819
  contactInfo: {
3785
- ...validatedData.contactInfo,
3820
+ email: validatedData.contactInfo.email || "",
3821
+ phoneNumber: validatedData.contactInfo.phoneNumber || "",
3786
3822
  alternativePhoneNumber: isDefault ? void 0 : validatedData.contactInfo.alternativePhoneNumber || void 0,
3787
3823
  website: isDefault ? void 0 : validatedData.contactInfo.website || void 0
3788
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 */,
3789
3833
  clinics: [],
3790
3834
  clinicsInfo: [],
3791
3835
  admins: [ownerId],
@@ -3873,35 +3917,75 @@ async function getAllActiveGroups(db) {
3873
3917
  const querySnapshot = await getDocs5(q);
3874
3918
  return querySnapshot.docs.map((doc14) => doc14.data());
3875
3919
  }
3876
- async function updateClinicGroup(db, groupId, data) {
3920
+ async function updateClinicGroup(db, groupId, data, app) {
3921
+ console.log("[CLINIC_GROUP] Updating clinic group", { groupId });
3877
3922
  const group = await getClinicGroup(db, groupId);
3878
3923
  if (!group) {
3924
+ console.error("[CLINIC_GROUP] Clinic group not found", { groupId });
3879
3925
  throw new Error("Clinic group not found");
3880
3926
  }
3881
- const updatedData = {
3882
- ...data,
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,
3883
3946
  updatedAt: Timestamp10.now()
3884
3947
  };
3948
+ console.log("[CLINIC_GROUP] Updating clinic group in Firestore");
3885
3949
  await updateDoc10(doc7(db, CLINIC_GROUPS_COLLECTION, groupId), updatedData);
3950
+ console.log("[CLINIC_GROUP] Clinic group updated successfully");
3886
3951
  const updatedGroup = await getClinicGroup(db, groupId);
3887
3952
  if (!updatedGroup) {
3953
+ console.error("[CLINIC_GROUP] Failed to retrieve updated clinic group");
3888
3954
  throw new Error("Failed to retrieve updated clinic group");
3889
3955
  }
3890
3956
  return updatedGroup;
3891
3957
  }
3892
- async function addAdminToGroup(db, groupId, adminId) {
3893
- const group = await getClinicGroup(db, groupId);
3894
- if (!group) {
3895
- throw new Error("Clinic group not found");
3896
- }
3897
- if (group.admins.includes(adminId)) {
3898
- return;
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;
3899
3986
  }
3900
- await updateClinicGroup(db, groupId, {
3901
- admins: [...group.admins, adminId]
3902
- });
3903
3987
  }
3904
- async function removeAdminFromGroup(db, groupId, adminId) {
3988
+ async function removeAdminFromGroup(db, groupId, adminId, app) {
3905
3989
  const group = await getClinicGroup(db, groupId);
3906
3990
  if (!group) {
3907
3991
  throw new Error("Clinic group not found");
@@ -3912,21 +3996,30 @@ async function removeAdminFromGroup(db, groupId, adminId) {
3912
3996
  if (!group.admins.includes(adminId)) {
3913
3997
  return;
3914
3998
  }
3915
- await updateClinicGroup(db, groupId, {
3916
- admins: group.admins.filter((id) => id !== adminId)
3917
- });
3999
+ await updateClinicGroup(
4000
+ db,
4001
+ groupId,
4002
+ {
4003
+ admins: group.admins.filter((id) => id !== adminId)
4004
+ },
4005
+ app
4006
+ );
3918
4007
  }
3919
- async function deactivateClinicGroup(db, groupId) {
4008
+ async function deactivateClinicGroup(db, groupId, app) {
3920
4009
  const group = await getClinicGroup(db, groupId);
3921
4010
  if (!group) {
3922
4011
  throw new Error("Clinic group not found");
3923
4012
  }
3924
- await updateDoc10(doc7(db, CLINIC_GROUPS_COLLECTION, groupId), {
3925
- isActive: false,
3926
- updatedAt: Timestamp10.now()
3927
- });
4013
+ await updateClinicGroup(
4014
+ db,
4015
+ groupId,
4016
+ {
4017
+ isActive: false
4018
+ },
4019
+ app
4020
+ );
3928
4021
  }
3929
- async function createAdminToken(db, groupId, creatorAdminId, data) {
4022
+ async function createAdminToken(db, groupId, creatorAdminId, app, data) {
3930
4023
  const group = await getClinicGroup(db, groupId);
3931
4024
  if (!group) {
3932
4025
  throw new Error("Clinic group not found");
@@ -3947,12 +4040,17 @@ async function createAdminToken(db, groupId, creatorAdminId, data) {
3947
4040
  createdAt: now,
3948
4041
  expiresAt
3949
4042
  };
3950
- await updateClinicGroup(db, groupId, {
3951
- adminTokens: [...group.adminTokens, token]
3952
- });
4043
+ await updateClinicGroup(
4044
+ db,
4045
+ groupId,
4046
+ {
4047
+ adminTokens: [...group.adminTokens, token]
4048
+ },
4049
+ app
4050
+ );
3953
4051
  return token;
3954
4052
  }
3955
- async function verifyAndUseAdminToken(db, groupId, token, userRef) {
4053
+ async function verifyAndUseAdminToken(db, groupId, token, userRef, app) {
3956
4054
  const group = await getClinicGroup(db, groupId);
3957
4055
  if (!group) {
3958
4056
  throw new Error("Clinic group not found");
@@ -3969,9 +4067,14 @@ async function verifyAndUseAdminToken(db, groupId, token, userRef) {
3969
4067
  const updatedTokens2 = group.adminTokens.map(
3970
4068
  (t) => t.id === adminToken.id ? { ...t, status: "expired" /* EXPIRED */ } : t
3971
4069
  );
3972
- await updateClinicGroup(db, groupId, {
3973
- adminTokens: updatedTokens2
3974
- });
4070
+ await updateClinicGroup(
4071
+ db,
4072
+ groupId,
4073
+ {
4074
+ adminTokens: updatedTokens2
4075
+ },
4076
+ app
4077
+ );
3975
4078
  throw new Error("Admin token has expired");
3976
4079
  }
3977
4080
  const updatedTokens = group.adminTokens.map(
@@ -3981,12 +4084,17 @@ async function verifyAndUseAdminToken(db, groupId, token, userRef) {
3981
4084
  usedByUserRef: userRef
3982
4085
  } : t
3983
4086
  );
3984
- await updateClinicGroup(db, groupId, {
3985
- adminTokens: updatedTokens
3986
- });
4087
+ await updateClinicGroup(
4088
+ db,
4089
+ groupId,
4090
+ {
4091
+ adminTokens: updatedTokens
4092
+ },
4093
+ app
4094
+ );
3987
4095
  return true;
3988
4096
  }
3989
- async function deleteAdminToken(db, groupId, tokenId, adminId) {
4097
+ async function deleteAdminToken(db, groupId, tokenId, adminId, app) {
3990
4098
  const group = await getClinicGroup(db, groupId);
3991
4099
  if (!group) {
3992
4100
  throw new Error("Clinic group not found");
@@ -3995,11 +4103,16 @@ async function deleteAdminToken(db, groupId, tokenId, adminId) {
3995
4103
  throw new Error("Admin does not belong to this clinic group");
3996
4104
  }
3997
4105
  const updatedTokens = group.adminTokens.filter((t) => t.id !== tokenId);
3998
- await updateClinicGroup(db, groupId, {
3999
- adminTokens: updatedTokens
4000
- });
4106
+ await updateClinicGroup(
4107
+ db,
4108
+ groupId,
4109
+ {
4110
+ adminTokens: updatedTokens
4111
+ },
4112
+ app
4113
+ );
4001
4114
  }
4002
- async function getActiveAdminTokens(db, groupId, adminId) {
4115
+ async function getActiveAdminTokens(db, groupId, adminId, app) {
4003
4116
  const group = await getClinicGroup(db, groupId);
4004
4117
  if (!group) {
4005
4118
  throw new Error("Clinic group not found");
@@ -4025,7 +4138,8 @@ var ClinicGroupService = class extends BaseService {
4025
4138
  data,
4026
4139
  ownerId,
4027
4140
  isDefault,
4028
- this.clinicAdminService
4141
+ this.clinicAdminService,
4142
+ this.app
4029
4143
  );
4030
4144
  }
4031
4145
  /**
@@ -4044,25 +4158,35 @@ var ClinicGroupService = class extends BaseService {
4044
4158
  * Ažurira grupaciju klinika
4045
4159
  */
4046
4160
  async updateClinicGroup(groupId, data) {
4047
- return updateClinicGroup(this.db, groupId, data);
4161
+ return updateClinicGroup(this.db, groupId, data, this.app);
4048
4162
  }
4049
4163
  /**
4050
4164
  * Dodaje admina u grupaciju
4051
4165
  */
4052
4166
  async addAdminToGroup(groupId, adminId) {
4053
- return addAdminToGroup(this.db, groupId, adminId);
4167
+ return addAdminToGroup(
4168
+ this.db,
4169
+ groupId,
4170
+ adminId,
4171
+ this.app
4172
+ );
4054
4173
  }
4055
4174
  /**
4056
4175
  * Uklanja admina iz grupacije
4057
4176
  */
4058
4177
  async removeAdminFromGroup(groupId, adminId) {
4059
- return removeAdminFromGroup(this.db, groupId, adminId);
4178
+ return removeAdminFromGroup(
4179
+ this.db,
4180
+ groupId,
4181
+ adminId,
4182
+ this.app
4183
+ );
4060
4184
  }
4061
4185
  /**
4062
4186
  * Deaktivira grupaciju klinika
4063
4187
  */
4064
4188
  async deactivateClinicGroup(groupId) {
4065
- return deactivateClinicGroup(this.db, groupId);
4189
+ return deactivateClinicGroup(this.db, groupId, this.app);
4066
4190
  }
4067
4191
  /**
4068
4192
  * Sets up additional clinic group information after initial creation
@@ -4072,18 +4196,45 @@ var ClinicGroupService = class extends BaseService {
4072
4196
  * @returns The updated clinic group
4073
4197
  */
4074
4198
  async setupClinicGroup(groupId, setupData) {
4199
+ console.log("[CLINIC_GROUP] Setting up clinic group", { groupId });
4075
4200
  const clinicGroup = await this.getClinicGroup(groupId);
4076
4201
  if (!clinicGroup) {
4202
+ console.error("[CLINIC_GROUP] Clinic group not found", { groupId });
4077
4203
  throw new Error(`Clinic group with ID ${groupId} not found`);
4078
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
+ }
4079
4229
  const updateData = {
4080
4230
  languages: setupData.languages,
4081
4231
  practiceType: setupData.practiceType,
4082
4232
  description: setupData.description,
4083
- logo: setupData.logo,
4233
+ logo: logoUrl,
4084
4234
  calendarSyncEnabled: setupData.calendarSyncEnabled,
4085
4235
  autoConfirmAppointments: setupData.autoConfirmAppointments
4086
4236
  };
4237
+ console.log("[CLINIC_GROUP] Updating clinic group with setup data");
4087
4238
  return this.updateClinicGroup(groupId, updateData);
4088
4239
  }
4089
4240
  /**
@@ -4094,6 +4245,7 @@ var ClinicGroupService = class extends BaseService {
4094
4245
  this.db,
4095
4246
  groupId,
4096
4247
  creatorAdminId,
4248
+ this.app,
4097
4249
  data
4098
4250
  );
4099
4251
  }
@@ -4105,7 +4257,8 @@ var ClinicGroupService = class extends BaseService {
4105
4257
  this.db,
4106
4258
  groupId,
4107
4259
  token,
4108
- userRef
4260
+ userRef,
4261
+ this.app
4109
4262
  );
4110
4263
  }
4111
4264
  /**
@@ -4116,14 +4269,20 @@ var ClinicGroupService = class extends BaseService {
4116
4269
  this.db,
4117
4270
  groupId,
4118
4271
  tokenId,
4119
- adminId
4272
+ adminId,
4273
+ this.app
4120
4274
  );
4121
4275
  }
4122
4276
  /**
4123
4277
  * Dohvata aktivne admin tokene
4124
4278
  */
4125
4279
  async getActiveAdminTokens(groupId, adminId) {
4126
- return getActiveAdminTokens(this.db, groupId, adminId);
4280
+ return getActiveAdminTokens(
4281
+ this.db,
4282
+ groupId,
4283
+ adminId,
4284
+ this.app
4285
+ );
4127
4286
  }
4128
4287
  };
4129
4288
 
@@ -4141,44 +4300,193 @@ import {
4141
4300
  } from "firebase/firestore";
4142
4301
  import { geohashForLocation as geohashForLocation3 } from "geofire-common";
4143
4302
  import { z as z14 } from "zod";
4144
- async function createClinic(db, data, creatorAdminId, clinicGroupService, clinicAdminService) {
4145
- const validatedData = createClinicSchema.parse(data);
4146
- const admin = await clinicAdminService.getClinicAdmin(creatorAdminId);
4147
- if (!admin) {
4148
- throw new Error("Admin not found");
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;
4149
4313
  }
4150
- if (admin.clinicGroupId !== validatedData.clinicGroupId) {
4151
- throw new Error("Admin does not belong to this clinic group");
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;
4152
4333
  }
4153
- const group = await clinicGroupService.getClinicGroup(
4154
- validatedData.clinicGroupId
4155
- );
4156
- if (!group) {
4157
- throw new Error("Clinic group not found");
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;
4158
4349
  }
4350
+ console.log("[CLINIC] Generating geohash for location");
4159
4351
  if (validatedData.location) {
4160
- validatedData.location.geohash = geohashForLocation3([
4161
- validatedData.location.latitude,
4162
- validatedData.location.longitude
4163
- ]);
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
+ }
4164
4463
  }
4165
4464
  const now = Timestamp11.now();
4465
+ console.log("[CLINIC] Preparing clinic data object");
4166
4466
  const clinicData = {
4167
4467
  ...validatedData,
4168
- id: doc8(collection6(db, CLINICS_COLLECTION)).id,
4468
+ id: clinicId,
4169
4469
  description: validatedData.description || void 0,
4170
4470
  location: {
4171
- ...validatedData.location,
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,
4172
4477
  geohash: validatedData.location.geohash || void 0
4173
4478
  },
4174
4479
  contactInfo: {
4175
- ...validatedData.contactInfo,
4480
+ email: validatedData.contactInfo.email || "",
4481
+ phoneNumber: validatedData.contactInfo.phoneNumber || "",
4176
4482
  alternativePhoneNumber: validatedData.contactInfo.alternativePhoneNumber || void 0,
4177
4483
  website: validatedData.contactInfo.website || void 0
4178
4484
  },
4485
+ logo: logoUrl || void 0,
4179
4486
  tags: validatedData.tags || [],
4180
- featuredPhotos: [],
4181
- photos: validatedData.photos || [],
4487
+ featuredPhotos: processedFeaturedPhotos || [],
4488
+ photos: processedPhotos || [],
4489
+ photosWithTags: processedPhotosWithTags,
4182
4490
  doctors: [],
4183
4491
  doctorsInfo: [],
4184
4492
  services: [],
@@ -4193,17 +4501,73 @@ async function createClinic(db, data, creatorAdminId, clinicGroupService, clinic
4193
4501
  isVerified: false
4194
4502
  };
4195
4503
  try {
4196
- clinicSchema.parse(clinicData);
4197
- await setDoc10(doc8(db, CLINICS_COLLECTION, clinicData.id), clinicData);
4198
- await clinicGroupService.updateClinicGroup(validatedData.clinicGroupId, {
4199
- clinics: [...group.clinics, clinicData.id]
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
4200
4560
  });
4201
- await clinicAdminService.addClinicToManaged(creatorAdminId, clinicData.id);
4202
4561
  return clinicData;
4203
4562
  } catch (error) {
4204
4563
  if (error instanceof z14.ZodError) {
4564
+ console.error(
4565
+ "[CLINIC] Zod validation error:",
4566
+ JSON.stringify(error.errors, null, 2)
4567
+ );
4205
4568
  throw new Error("Invalid clinic data: " + error.message);
4206
4569
  }
4570
+ console.error("[CLINIC] Unhandled error in createClinic:", error);
4207
4571
  throw error;
4208
4572
  }
4209
4573
  }
@@ -4224,27 +4588,177 @@ async function getClinicsByGroup(db, groupId) {
4224
4588
  const querySnapshot = await getDocs6(q);
4225
4589
  return querySnapshot.docs.map((doc14) => doc14.data());
4226
4590
  }
4227
- 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 });
4228
4593
  const clinic = await getClinic(db, clinicId);
4229
4594
  if (!clinic) {
4595
+ console.error("[CLINIC] Clinic not found", { clinicId });
4230
4596
  throw new Error("Clinic not found");
4231
4597
  }
4232
- const admin = await clinicAdminService.getClinicAdmin(adminId);
4233
- if (!admin) {
4234
- throw new Error("Admin not found");
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
+ }
4235
4642
  }
4236
- if (!admin.isGroupOwner && !admin.clinicsManaged.includes(clinicId)) {
4237
- throw new Error("Admin does not have permission to update this clinic");
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
+ }
4238
4674
  }
4239
- const updatedData = {
4240
- ...data,
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,
4241
4746
  updatedAt: Timestamp11.now()
4242
4747
  };
4243
- await updateDoc11(doc8(db, CLINICS_COLLECTION, clinicId), updatedData);
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
+ }
4244
4756
  const updatedClinic = await getClinic(db, clinicId);
4245
4757
  if (!updatedClinic) {
4758
+ console.error("[CLINIC] Failed to retrieve updated clinic");
4246
4759
  throw new Error("Failed to retrieve updated clinic");
4247
4760
  }
4761
+ console.log("[CLINIC] Clinic update completed successfully");
4248
4762
  return updatedClinic;
4249
4763
  }
4250
4764
  async function deactivateClinic(db, clinicId, adminId, clinicAdminService) {
@@ -4256,7 +4770,8 @@ async function deactivateClinic(db, clinicId, adminId, clinicAdminService) {
4256
4770
  if (!admin) {
4257
4771
  throw new Error("Admin not found");
4258
4772
  }
4259
- if (!admin.isGroupOwner && !admin.clinicsManaged.includes(clinicId)) {
4773
+ const hasPermission = admin.isGroupOwner && admin.clinicGroupId === clinic.clinicGroupId || admin.clinicsManaged.includes(clinicId) && clinic.admins && clinic.admins.includes(adminId);
4774
+ if (!hasPermission) {
4260
4775
  throw new Error("Admin does not have permission to deactivate this clinic");
4261
4776
  }
4262
4777
  await updateDoc11(doc8(db, CLINICS_COLLECTION, clinicId), {
@@ -4301,27 +4816,28 @@ async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGr
4301
4816
  import {
4302
4817
  collection as collection7,
4303
4818
  doc as doc9,
4304
- setDoc as setDoc11,
4305
- Timestamp as Timestamp12
4819
+ Timestamp as Timestamp12,
4820
+ getDoc as getDoc13,
4821
+ addDoc as addDoc2
4306
4822
  } from "firebase/firestore";
4307
- async function addReview(db, clinicId, review) {
4308
- const clinic = await getClinic(db, clinicId);
4309
- if (!clinic) {
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()) {
4310
4827
  throw new Error("Clinic not found");
4311
4828
  }
4829
+ const clinic = clinicSnap.data();
4312
4830
  const now = Timestamp12.now();
4313
4831
  const reviewData = {
4832
+ ...review,
4314
4833
  id: doc9(collection7(db, "clinic_reviews")).id,
4315
4834
  clinicId,
4316
- patientId: review.patientId,
4317
- rating: review.rating,
4318
- comment: review.comment,
4319
4835
  createdAt: now,
4320
4836
  updatedAt: now,
4321
4837
  isVerified: false
4322
4838
  };
4323
4839
  clinicReviewSchema.parse(reviewData);
4324
- await setDoc11(doc9(db, "clinic_reviews", reviewData.id), reviewData);
4840
+ await addDoc2(collection7(db, "clinic_reviews"), reviewData);
4325
4841
  const newRating = clinic.rating ? {
4326
4842
  average: (clinic.rating.average * clinic.rating.count + review.rating) / (clinic.rating.count + 1),
4327
4843
  count: clinic.rating.count + 1
@@ -4337,28 +4853,24 @@ async function addReview(db, clinicId, review) {
4337
4853
  ...clinic.reviewsInfo,
4338
4854
  {
4339
4855
  id: reviewData.id,
4340
- rating: review.rating,
4341
- text: review.comment,
4342
- patientId: review.patientId,
4343
- patientName: "Patient",
4344
- // This should be fetched from patient service
4345
- patientPhoto: "",
4346
- // This should be fetched from patient service
4347
- createdAt: now,
4348
- updatedAt: now
4856
+ patientId: reviewData.patientId,
4857
+ rating: reviewData.rating,
4858
+ comment: reviewData.comment,
4859
+ createdAt: reviewData.createdAt
4349
4860
  }
4350
4861
  ]
4351
4862
  },
4352
- clinic.admins[0],
4353
- // Using the first admin for the update
4354
- { getClinicAdmin: async (id) => ({ isGroupOwner: true }) }
4355
- // Mock admin service
4863
+ "system",
4864
+ // System update, no admin ID needed
4865
+ null,
4866
+ // No clinic admin service needed for system updates
4867
+ app
4356
4868
  );
4357
4869
  return reviewData;
4358
4870
  }
4359
4871
 
4360
4872
  // src/services/clinic/utils/tag.utils.ts
4361
- async function addTags(db, clinicId, adminId, newTags, clinicAdminService) {
4873
+ async function addTags(db, clinicId, adminId, newTags, clinicAdminService, app) {
4362
4874
  const clinic = await getClinic(db, clinicId);
4363
4875
  if (!clinic) {
4364
4876
  throw new Error("Clinic not found");
@@ -4367,7 +4879,8 @@ async function addTags(db, clinicId, adminId, newTags, clinicAdminService) {
4367
4879
  if (!admin) {
4368
4880
  throw new Error("Admin not found");
4369
4881
  }
4370
- if (!admin.isGroupOwner && !admin.clinicsManaged.includes(clinicId)) {
4882
+ const hasPermission = admin.isGroupOwner && admin.clinicGroupId === clinic.clinicGroupId || admin.clinicsManaged.includes(clinicId) && clinic.admins && clinic.admins.includes(adminId);
4883
+ if (!hasPermission) {
4371
4884
  throw new Error("Admin does not have permission to update this clinic");
4372
4885
  }
4373
4886
  const updatedTags = [.../* @__PURE__ */ new Set([...clinic.tags, ...newTags.tags || []])];
@@ -4378,10 +4891,11 @@ async function addTags(db, clinicId, adminId, newTags, clinicAdminService) {
4378
4891
  tags: updatedTags
4379
4892
  },
4380
4893
  adminId,
4381
- clinicAdminService
4894
+ clinicAdminService,
4895
+ app
4382
4896
  );
4383
4897
  }
4384
- async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminService) {
4898
+ async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminService, app) {
4385
4899
  const clinic = await getClinic(db, clinicId);
4386
4900
  if (!clinic) {
4387
4901
  throw new Error("Clinic not found");
@@ -4390,14 +4904,12 @@ async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminServic
4390
4904
  if (!admin) {
4391
4905
  throw new Error("Admin not found");
4392
4906
  }
4393
- if (!admin.isGroupOwner && !admin.clinicsManaged.includes(clinicId)) {
4907
+ const hasPermission = admin.isGroupOwner && admin.clinicGroupId === clinic.clinicGroupId || admin.clinicsManaged.includes(clinicId) && clinic.admins && clinic.admins.includes(adminId);
4908
+ if (!hasPermission) {
4394
4909
  throw new Error("Admin does not have permission to update this clinic");
4395
4910
  }
4396
4911
  const updatedTags = clinic.tags.filter(
4397
- (tag) => {
4398
- var _a;
4399
- return !((_a = tagsToRemove.tags) == null ? void 0 : _a.includes(tag));
4400
- }
4912
+ (tag) => !tagsToRemove.tags || !tagsToRemove.tags.includes(tag)
4401
4913
  );
4402
4914
  return updateClinic(
4403
4915
  db,
@@ -4406,7 +4918,8 @@ async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminServic
4406
4918
  tags: updatedTags
4407
4919
  },
4408
4920
  adminId,
4409
- clinicAdminService
4921
+ clinicAdminService,
4922
+ app
4410
4923
  );
4411
4924
  }
4412
4925
 
@@ -4481,7 +4994,8 @@ var ClinicService = class extends BaseService {
4481
4994
  data,
4482
4995
  creatorAdminId,
4483
4996
  this.clinicGroupService,
4484
- this.clinicAdminService
4997
+ this.clinicAdminService,
4998
+ this.app
4485
4999
  );
4486
5000
  }
4487
5001
  /**
@@ -4516,14 +5030,15 @@ var ClinicService = class extends BaseService {
4516
5030
  clinicId,
4517
5031
  data,
4518
5032
  adminId,
4519
- this.clinicAdminService
5033
+ this.clinicAdminService,
5034
+ this.app
4520
5035
  );
4521
5036
  }
4522
5037
  /**
4523
5038
  * Dodaje recenziju klinici
4524
5039
  */
4525
5040
  async addReview(clinicId, review) {
4526
- return addReview(this.db, clinicId, review);
5041
+ return addReview(this.db, clinicId, review, this.app);
4527
5042
  }
4528
5043
  /**
4529
5044
  * Deaktivira kliniku
@@ -4545,7 +5060,8 @@ var ClinicService = class extends BaseService {
4545
5060
  clinicId,
4546
5061
  adminId,
4547
5062
  newTags,
4548
- this.clinicAdminService
5063
+ this.clinicAdminService,
5064
+ this.app
4549
5065
  );
4550
5066
  }
4551
5067
  /**
@@ -4557,7 +5073,8 @@ var ClinicService = class extends BaseService {
4557
5073
  clinicId,
4558
5074
  adminId,
4559
5075
  tagsToRemove,
4560
- this.clinicAdminService
5076
+ this.clinicAdminService,
5077
+ this.app
4561
5078
  );
4562
5079
  }
4563
5080
  /**
@@ -4592,12 +5109,21 @@ var ClinicService = class extends BaseService {
4592
5109
  * @returns The created clinic
4593
5110
  */
4594
5111
  async createClinicBranch(clinicGroupId, setupData, adminId) {
5112
+ var _a, _b;
5113
+ console.log("[CLINIC_SERVICE] Starting clinic branch creation", {
5114
+ clinicGroupId,
5115
+ adminId
5116
+ });
4595
5117
  const clinicGroup = await this.clinicGroupService.getClinicGroup(
4596
5118
  clinicGroupId
4597
5119
  );
4598
5120
  if (!clinicGroup) {
5121
+ console.error("[CLINIC_SERVICE] Clinic group not found", {
5122
+ clinicGroupId
5123
+ });
4599
5124
  throw new Error(`Clinic group with ID ${clinicGroupId} not found`);
4600
5125
  }
5126
+ console.log("[CLINIC_SERVICE] Clinic group verified");
4601
5127
  const createClinicData = {
4602
5128
  clinicGroupId,
4603
5129
  name: setupData.name,
@@ -4606,8 +5132,8 @@ var ClinicService = class extends BaseService {
4606
5132
  contactInfo: setupData.contactInfo,
4607
5133
  workingHours: setupData.workingHours,
4608
5134
  tags: setupData.tags,
4609
- photos: setupData.photos,
4610
- photosWithTags: setupData.photosWithTags,
5135
+ photos: setupData.photos || [],
5136
+ photosWithTags: setupData.photosWithTags || [],
4611
5137
  doctors: [],
4612
5138
  services: [],
4613
5139
  admins: [adminId],
@@ -4616,7 +5142,17 @@ var ClinicService = class extends BaseService {
4616
5142
  logo: setupData.logo,
4617
5143
  featuredPhotos: setupData.featuredPhotos || []
4618
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
+ });
4619
5152
  const clinic = await this.createClinic(createClinicData, adminId);
5153
+ console.log("[CLINIC_SERVICE] Clinic branch created successfully", {
5154
+ clinicId: clinic.id
5155
+ });
4620
5156
  return clinic;
4621
5157
  }
4622
5158
  };
@@ -4738,7 +5274,7 @@ var AuthService = class extends BaseService {
4738
5274
  "Clinic group data is required when creating a new group"
4739
5275
  );
4740
5276
  }
4741
- console.log("[AUTH] Creating clinic admin first");
5277
+ console.log("[AUTH] Creating clinic admin first (without group)");
4742
5278
  const createClinicAdminData = {
4743
5279
  userRef: firebaseUser.uid,
4744
5280
  isGroupOwner: true,
@@ -4746,10 +5282,16 @@ var AuthService = class extends BaseService {
4746
5282
  contactInfo: contactPerson,
4747
5283
  roleTitle: data.title,
4748
5284
  isActive: true
5285
+ // No clinicGroupId yet
4749
5286
  };
5287
+ let adminProfile;
4750
5288
  try {
4751
- await clinicAdminService.createClinicAdmin(createClinicAdminData);
4752
- console.log("[AUTH] Clinic admin created successfully");
5289
+ adminProfile = await clinicAdminService.createClinicAdmin(
5290
+ createClinicAdminData
5291
+ );
5292
+ console.log("[AUTH] Clinic admin created successfully", {
5293
+ adminId: adminProfile.id
5294
+ });
4753
5295
  } catch (adminCreationError) {
4754
5296
  console.error(
4755
5297
  "[AUTH] Clinic admin creation failed:",
@@ -4762,7 +5304,8 @@ var AuthService = class extends BaseService {
4762
5304
  hqLocation: data.clinicGroupData.hqLocation,
4763
5305
  contactInfo: data.clinicGroupData.contactInfo,
4764
5306
  contactPerson,
4765
- ownerId: firebaseUser.uid,
5307
+ ownerId: adminProfile.id,
5308
+ // Use admin profile ID, not user UID
4766
5309
  isActive: true,
4767
5310
  logo: data.clinicGroupData.logo || null,
4768
5311
  subscriptionModel: data.clinicGroupData.subscriptionModel || "no_subscription" /* NO_SUBSCRIPTION */
@@ -4770,13 +5313,24 @@ var AuthService = class extends BaseService {
4770
5313
  console.log("[AUTH] Clinic group data prepared", {
4771
5314
  groupName: createClinicGroupData.name
4772
5315
  });
5316
+ let clinicGroup;
4773
5317
  try {
4774
- await clinicGroupService.createClinicGroup(
5318
+ clinicGroup = await clinicGroupService.createClinicGroup(
4775
5319
  createClinicGroupData,
4776
- firebaseUser.uid,
4777
- true
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
4778
5324
  );
4779
- 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");
4780
5334
  } catch (groupCreationError) {
4781
5335
  console.error(
4782
5336
  "[AUTH] Clinic group creation failed:",
@@ -4849,9 +5403,14 @@ var AuthService = class extends BaseService {
4849
5403
  roleTitle: data.title,
4850
5404
  isActive: true
4851
5405
  };
5406
+ let adminProfile;
4852
5407
  try {
4853
- await clinicAdminService.createClinicAdmin(createClinicAdminData);
4854
- console.log("[AUTH] Clinic admin created successfully");
5408
+ adminProfile = await clinicAdminService.createClinicAdmin(
5409
+ createClinicAdminData
5410
+ );
5411
+ console.log("[AUTH] Clinic admin created successfully", {
5412
+ adminId: adminProfile.id
5413
+ });
4855
5414
  } catch (adminCreationError) {
4856
5415
  console.error(
4857
5416
  "[AUTH] Clinic admin creation failed:",
@@ -5160,7 +5719,7 @@ var AuthService = class extends BaseService {
5160
5719
  import {
5161
5720
  collection as collection10,
5162
5721
  doc as doc11,
5163
- getDoc as getDoc14,
5722
+ getDoc as getDoc15,
5164
5723
  getDocs as getDocs9,
5165
5724
  query as query9,
5166
5725
  where as where9,
@@ -5168,8 +5727,8 @@ import {
5168
5727
  deleteDoc as deleteDoc6,
5169
5728
  orderBy,
5170
5729
  Timestamp as Timestamp14,
5171
- addDoc,
5172
- writeBatch as writeBatch2
5730
+ addDoc as addDoc3,
5731
+ writeBatch as writeBatch3
5173
5732
  } from "firebase/firestore";
5174
5733
 
5175
5734
  // src/types/notifications/index.ts
@@ -5206,7 +5765,7 @@ var NotificationService = class extends BaseService {
5206
5765
  isRead: false,
5207
5766
  userRole: notification.userRole || "patient" /* PATIENT */
5208
5767
  };
5209
- const docRef = await addDoc(notificationsRef, notificationData);
5768
+ const docRef = await addDoc3(notificationsRef, notificationData);
5210
5769
  return {
5211
5770
  ...notificationData,
5212
5771
  id: docRef.id
@@ -5221,7 +5780,7 @@ var NotificationService = class extends BaseService {
5221
5780
  NOTIFICATIONS_COLLECTION,
5222
5781
  notificationId
5223
5782
  );
5224
- const notificationDoc = await getDoc14(notificationRef);
5783
+ const notificationDoc = await getDoc15(notificationRef);
5225
5784
  if (!notificationDoc.exists()) {
5226
5785
  return null;
5227
5786
  }
@@ -5280,7 +5839,7 @@ var NotificationService = class extends BaseService {
5280
5839
  */
5281
5840
  async markAllAsRead(userId) {
5282
5841
  const notifications = await this.getUnreadNotifications(userId);
5283
- const batch = writeBatch2(this.db);
5842
+ const batch = writeBatch3(this.db);
5284
5843
  notifications.forEach((notification) => {
5285
5844
  const notificationRef = doc11(
5286
5845
  this.db,
@@ -5356,7 +5915,7 @@ var NotificationService = class extends BaseService {
5356
5915
  import {
5357
5916
  collection as collection11,
5358
5917
  doc as doc12,
5359
- getDoc as getDoc15,
5918
+ getDoc as getDoc16,
5360
5919
  getDocs as getDocs10,
5361
5920
  setDoc as setDoc13,
5362
5921
  updateDoc as updateDoc14,
@@ -5412,7 +5971,7 @@ var DocumentationTemplateService = class extends BaseService {
5412
5971
  */
5413
5972
  async getTemplateById(templateId) {
5414
5973
  const docRef = doc12(this.collectionRef, templateId);
5415
- const docSnap = await getDoc15(docRef);
5974
+ const docSnap = await getDoc16(docRef);
5416
5975
  if (!docSnap.exists()) {
5417
5976
  return null;
5418
5977
  }
@@ -5551,7 +6110,7 @@ var DocumentationTemplateService = class extends BaseService {
5551
6110
  import {
5552
6111
  collection as collection12,
5553
6112
  doc as doc13,
5554
- getDoc as getDoc16,
6113
+ getDoc as getDoc17,
5555
6114
  getDocs as getDocs11,
5556
6115
  setDoc as setDoc14,
5557
6116
  updateDoc as updateDoc15,
@@ -5608,7 +6167,7 @@ var FilledDocumentService = class extends BaseService {
5608
6167
  */
5609
6168
  async getFilledDocumentById(documentId) {
5610
6169
  const docRef = doc13(this.collectionRef, documentId);
5611
- const docSnap = await getDoc16(docRef);
6170
+ const docSnap = await getDoc17(docRef);
5612
6171
  if (!docSnap.exists()) {
5613
6172
  return null;
5614
6173
  }