@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.js CHANGED
@@ -2447,7 +2447,7 @@ var clinicGroupSchema = import_zod9.z.object({
2447
2447
  admins: import_zod9.z.array(import_zod9.z.string()),
2448
2448
  adminsInfo: import_zod9.z.array(adminInfoSchema),
2449
2449
  adminTokens: import_zod9.z.array(adminTokenSchema),
2450
- ownerId: import_zod9.z.string(),
2450
+ ownerId: import_zod9.z.string().nullable(),
2451
2451
  createdAt: import_zod9.z.instanceof(Date).or(import_zod9.z.instanceof(import_firestore10.Timestamp)),
2452
2452
  // Timestamp
2453
2453
  updatedAt: import_zod9.z.instanceof(Date).or(import_zod9.z.instanceof(import_firestore10.Timestamp)),
@@ -2523,7 +2523,7 @@ var createClinicGroupSchema = import_zod9.z.object({
2523
2523
  hqLocation: clinicLocationSchema,
2524
2524
  contactInfo: clinicContactInfoSchema,
2525
2525
  contactPerson: contactPersonSchema,
2526
- ownerId: import_zod9.z.string(),
2526
+ ownerId: import_zod9.z.string().nullable(),
2527
2527
  isActive: import_zod9.z.boolean(),
2528
2528
  logo: import_zod9.z.string().optional().nullable(),
2529
2529
  practiceType: import_zod9.z.nativeEnum(PracticeType).optional(),
@@ -2557,7 +2557,7 @@ var createClinicSchema = import_zod9.z.object({
2557
2557
  });
2558
2558
  var createDefaultClinicGroupSchema = import_zod9.z.object({
2559
2559
  name: import_zod9.z.string(),
2560
- ownerId: import_zod9.z.string(),
2560
+ ownerId: import_zod9.z.string().nullable(),
2561
2561
  contactPerson: contactPersonSchema,
2562
2562
  contactInfo: clinicContactInfoSchema,
2563
2563
  hqLocation: clinicLocationSchema,
@@ -2655,45 +2655,7 @@ async function createClinicAdmin(db, data, clinicGroupService) {
2655
2655
  hasGroupId: !!clinicGroupId
2656
2656
  });
2657
2657
  if (validatedData.isGroupOwner && !clinicGroupId) {
2658
- console.log("[CLINIC_ADMIN] Creating default group for owner");
2659
- const defaultGroup = {
2660
- name: `${validatedData.contactInfo.firstName}'s Group`,
2661
- ownerId: validatedData.userRef,
2662
- contactPerson: validatedData.contactInfo,
2663
- contactInfo: {
2664
- email: validatedData.contactInfo.email,
2665
- phoneNumber: validatedData.contactInfo.phoneNumber || ""
2666
- },
2667
- hqLocation: {
2668
- address: "",
2669
- city: "",
2670
- country: "",
2671
- postalCode: "",
2672
- latitude: 0,
2673
- longitude: 0
2674
- },
2675
- isActive: true
2676
- };
2677
- console.log("[CLINIC_ADMIN] Default group data prepared", {
2678
- groupName: defaultGroup.name
2679
- });
2680
- try {
2681
- const clinicGroup = await clinicGroupService.createClinicGroup(
2682
- defaultGroup,
2683
- validatedData.userRef,
2684
- true
2685
- );
2686
- clinicGroupId = clinicGroup.id;
2687
- console.log("[CLINIC_ADMIN] Default group created successfully", {
2688
- groupId: clinicGroupId
2689
- });
2690
- } catch (groupCreationError) {
2691
- console.error(
2692
- "[CLINIC_ADMIN] Error creating default group:",
2693
- groupCreationError
2694
- );
2695
- throw groupCreationError;
2696
- }
2658
+ console.log("[CLINIC_ADMIN] Owner will be assigned to group later");
2697
2659
  } else if (!validatedData.isGroupOwner && !clinicGroupId) {
2698
2660
  console.error("[CLINIC_ADMIN] Missing clinic group ID for non-owner admin");
2699
2661
  throw new Error("Clinic group ID is required for non-owner admins");
@@ -2723,16 +2685,12 @@ async function createClinicAdmin(db, data, clinicGroupService) {
2723
2685
  }
2724
2686
  }
2725
2687
  console.log("[CLINIC_ADMIN] Preparing admin data object");
2726
- if (!clinicGroupId) {
2727
- console.error(
2728
- "[CLINIC_ADMIN] clinicGroupId is undefined, which should not happen at this point"
2729
- );
2730
- throw new Error("clinicGroupId is required but was undefined");
2731
- }
2732
2688
  const adminData = {
2733
- id: validatedData.userRef,
2689
+ id: (0, import_firestore11.doc)((0, import_firestore11.collection)(db, CLINIC_ADMINS_COLLECTION)).id,
2690
+ // Generate a new ID for the admin document
2734
2691
  userRef: validatedData.userRef,
2735
- clinicGroupId,
2692
+ clinicGroupId: clinicGroupId || "",
2693
+ // Empty string for now if no group ID
2736
2694
  isGroupOwner: validatedData.isGroupOwner,
2737
2695
  clinicsManaged: [],
2738
2696
  // Uvek krećemo od prazne liste
@@ -3756,6 +3714,59 @@ var UserService = class extends BaseService {
3756
3714
  var import_firestore15 = require("firebase/firestore");
3757
3715
  var import_geofire_common2 = require("geofire-common");
3758
3716
  var import_zod13 = require("zod");
3717
+
3718
+ // src/services/clinic/utils/photos.utils.ts
3719
+ var import_storage3 = require("firebase/storage");
3720
+ async function uploadPhoto(photo, entityType, entityId, photoType, app, fileName) {
3721
+ if (!photo || typeof photo !== "string" || !photo.startsWith("data:")) {
3722
+ return photo;
3723
+ }
3724
+ try {
3725
+ console.log(
3726
+ `[PHOTO_UTILS] Uploading ${photoType} for ${entityType}/${entityId}`
3727
+ );
3728
+ const storage = (0, import_storage3.getStorage)(app);
3729
+ const storageFileName = fileName || `${photoType}-${Date.now()}`;
3730
+ const storageRef = (0, import_storage3.ref)(
3731
+ storage,
3732
+ `${entityType}/${entityId}/${storageFileName}`
3733
+ );
3734
+ const base64Data = photo.split(",")[1];
3735
+ const contentType = photo.split(";")[0].split(":")[1];
3736
+ const byteCharacters = atob(base64Data);
3737
+ const byteArrays = [];
3738
+ for (let i = 0; i < byteCharacters.length; i++) {
3739
+ byteArrays.push(byteCharacters.charCodeAt(i));
3740
+ }
3741
+ const blob = new Blob([new Uint8Array(byteArrays)], { type: contentType });
3742
+ await (0, import_storage3.uploadBytes)(storageRef, blob, { contentType });
3743
+ const downloadUrl = await (0, import_storage3.getDownloadURL)(storageRef);
3744
+ console.log(`[PHOTO_UTILS] ${photoType} uploaded successfully`, {
3745
+ downloadUrl
3746
+ });
3747
+ return downloadUrl;
3748
+ } catch (error) {
3749
+ console.error(`[PHOTO_UTILS] Error uploading ${photoType}:`, error);
3750
+ return null;
3751
+ }
3752
+ }
3753
+ async function uploadMultiplePhotos(photos, entityType, entityId, photoType, app) {
3754
+ if (!photos || !Array.isArray(photos) || photos.length === 0) {
3755
+ return [];
3756
+ }
3757
+ const uploadPromises = photos.map(
3758
+ (photo, index) => uploadPhoto(photo, entityType, entityId, `${photoType}-${index}`, app)
3759
+ );
3760
+ try {
3761
+ const results = await Promise.all(uploadPromises);
3762
+ return results.filter((url) => url !== null);
3763
+ } catch (error) {
3764
+ console.error(`[PHOTO_UTILS] Error uploading multiple photos:`, error);
3765
+ return photos.filter((photo) => !photo.startsWith("data:"));
3766
+ }
3767
+ }
3768
+
3769
+ // src/services/clinic/utils/clinic-group.utils.ts
3759
3770
  function generateId() {
3760
3771
  const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
3761
3772
  const timestamp = Date.now().toString(36);
@@ -3765,7 +3776,8 @@ function generateId() {
3765
3776
  ).join("");
3766
3777
  return `${randomPart}-${timestamp}`;
3767
3778
  }
3768
- async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdminService) {
3779
+ async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdminService, app) {
3780
+ var _a, _b, _c, _d, _e;
3769
3781
  console.log("[CLINIC_GROUP] Starting clinic group creation", {
3770
3782
  ownerId,
3771
3783
  isDefault
@@ -3781,14 +3793,23 @@ async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdm
3781
3793
  const validatedData = createClinicGroupSchema.parse(data);
3782
3794
  try {
3783
3795
  console.log("[CLINIC_GROUP] Checking if owner exists", { ownerId });
3784
- const owner = await clinicAdminService.getClinicAdmin(ownerId);
3785
- if (!owner) {
3786
- console.error("[CLINIC_GROUP] Owner not found or is not a clinic admin", {
3787
- ownerId
3788
- });
3789
- throw new Error("Owner not found or is not a clinic admin");
3796
+ if (isDefault) {
3797
+ console.log(
3798
+ "[CLINIC_GROUP] Skipping owner verification for default group creation"
3799
+ );
3800
+ } else {
3801
+ const owner = await clinicAdminService.getClinicAdmin(ownerId);
3802
+ if (!owner) {
3803
+ console.error(
3804
+ "[CLINIC_GROUP] Owner not found or is not a clinic admin",
3805
+ {
3806
+ ownerId
3807
+ }
3808
+ );
3809
+ throw new Error("Owner not found or is not a clinic admin");
3810
+ }
3811
+ console.log("[CLINIC_GROUP] Owner verified as clinic admin");
3790
3812
  }
3791
- console.log("[CLINIC_GROUP] Owner verified as clinic admin");
3792
3813
  } catch (ownerError) {
3793
3814
  console.error("[CLINIC_GROUP] Error verifying owner:", ownerError);
3794
3815
  throw ownerError;
@@ -3810,23 +3831,49 @@ async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdm
3810
3831
  }
3811
3832
  const now = import_firestore15.Timestamp.now();
3812
3833
  console.log("[CLINIC_GROUP] Preparing clinic group data object");
3834
+ const groupId = (0, import_firestore15.doc)((0, import_firestore15.collection)(db, CLINIC_GROUPS_COLLECTION)).id;
3813
3835
  console.log("[CLINIC_GROUP] Logo value:", {
3814
3836
  logoValue: validatedData.logo,
3815
3837
  logoType: validatedData.logo === null ? "null" : typeof validatedData.logo
3816
3838
  });
3839
+ let logoUrl = await uploadPhoto(
3840
+ validatedData.logo || null,
3841
+ "clinic-groups",
3842
+ groupId,
3843
+ "logo",
3844
+ app
3845
+ );
3846
+ console.log("[CLINIC_GROUP] Logo processed", { logoUrl });
3817
3847
  const groupData = {
3818
3848
  ...validatedData,
3819
- id: (0, import_firestore15.doc)((0, import_firestore15.collection)(db, CLINIC_GROUPS_COLLECTION)).id,
3849
+ id: groupId,
3850
+ name: validatedData.name,
3851
+ logo: logoUrl,
3852
+ // Use the uploaded logo URL or the original value
3820
3853
  description: isDefault ? void 0 : validatedData.description || void 0,
3821
3854
  hqLocation: {
3822
- ...validatedData.hqLocation,
3855
+ address: validatedData.hqLocation.address || "",
3856
+ city: validatedData.hqLocation.city || "",
3857
+ country: validatedData.hqLocation.country || "",
3858
+ postalCode: validatedData.hqLocation.postalCode || "",
3859
+ latitude: validatedData.hqLocation.latitude || 0,
3860
+ longitude: validatedData.hqLocation.longitude || 0,
3823
3861
  geohash: validatedData.hqLocation.geohash || void 0
3824
3862
  },
3825
3863
  contactInfo: {
3826
- ...validatedData.contactInfo,
3864
+ email: validatedData.contactInfo.email || "",
3865
+ phoneNumber: validatedData.contactInfo.phoneNumber || "",
3827
3866
  alternativePhoneNumber: isDefault ? void 0 : validatedData.contactInfo.alternativePhoneNumber || void 0,
3828
3867
  website: isDefault ? void 0 : validatedData.contactInfo.website || void 0
3829
3868
  },
3869
+ contactPerson: {
3870
+ firstName: ((_a = validatedData.contactPerson) == null ? void 0 : _a.firstName) || "",
3871
+ lastName: ((_b = validatedData.contactPerson) == null ? void 0 : _b.lastName) || "",
3872
+ email: ((_c = validatedData.contactPerson) == null ? void 0 : _c.email) || "",
3873
+ title: ((_d = validatedData.contactPerson) == null ? void 0 : _d.title) || null,
3874
+ phoneNumber: ((_e = validatedData.contactPerson) == null ? void 0 : _e.phoneNumber) || null
3875
+ },
3876
+ subscriptionModel: validatedData.subscriptionModel || "no_subscription" /* NO_SUBSCRIPTION */,
3830
3877
  clinics: [],
3831
3878
  clinicsInfo: [],
3832
3879
  admins: [ownerId],
@@ -3914,35 +3961,75 @@ async function getAllActiveGroups(db) {
3914
3961
  const querySnapshot = await (0, import_firestore15.getDocs)(q);
3915
3962
  return querySnapshot.docs.map((doc14) => doc14.data());
3916
3963
  }
3917
- async function updateClinicGroup(db, groupId, data) {
3964
+ async function updateClinicGroup(db, groupId, data, app) {
3965
+ console.log("[CLINIC_GROUP] Updating clinic group", { groupId });
3918
3966
  const group = await getClinicGroup(db, groupId);
3919
3967
  if (!group) {
3968
+ console.error("[CLINIC_GROUP] Clinic group not found", { groupId });
3920
3969
  throw new Error("Clinic group not found");
3921
3970
  }
3922
- const updatedData = {
3923
- ...data,
3971
+ let updatedData = { ...data };
3972
+ if (data.logo && typeof data.logo === "string" && data.logo.startsWith("data:")) {
3973
+ console.log("[CLINIC_GROUP] Processing logo for update");
3974
+ try {
3975
+ const logoUrl = await uploadPhoto(
3976
+ data.logo,
3977
+ "clinic-groups",
3978
+ groupId,
3979
+ "logo",
3980
+ app
3981
+ );
3982
+ console.log("[CLINIC_GROUP] Logo processed for update", { logoUrl });
3983
+ updatedData.logo = logoUrl;
3984
+ } catch (error) {
3985
+ console.error("[CLINIC_GROUP] Error processing logo for update:", error);
3986
+ }
3987
+ }
3988
+ updatedData = {
3989
+ ...updatedData,
3924
3990
  updatedAt: import_firestore15.Timestamp.now()
3925
3991
  };
3992
+ console.log("[CLINIC_GROUP] Updating clinic group in Firestore");
3926
3993
  await (0, import_firestore15.updateDoc)((0, import_firestore15.doc)(db, CLINIC_GROUPS_COLLECTION, groupId), updatedData);
3994
+ console.log("[CLINIC_GROUP] Clinic group updated successfully");
3927
3995
  const updatedGroup = await getClinicGroup(db, groupId);
3928
3996
  if (!updatedGroup) {
3997
+ console.error("[CLINIC_GROUP] Failed to retrieve updated clinic group");
3929
3998
  throw new Error("Failed to retrieve updated clinic group");
3930
3999
  }
3931
4000
  return updatedGroup;
3932
4001
  }
3933
- async function addAdminToGroup(db, groupId, adminId) {
3934
- const group = await getClinicGroup(db, groupId);
3935
- if (!group) {
3936
- throw new Error("Clinic group not found");
3937
- }
3938
- if (group.admins.includes(adminId)) {
3939
- return;
4002
+ async function addAdminToGroup(db, groupId, adminId, app) {
4003
+ console.log("[CLINIC_GROUP] Adding admin to group", { groupId, adminId });
4004
+ try {
4005
+ const group = await getClinicGroup(db, groupId);
4006
+ if (!group) {
4007
+ console.error("[CLINIC_GROUP] Clinic group not found", { groupId });
4008
+ throw new Error("Clinic group not found");
4009
+ }
4010
+ if (group.admins.includes(adminId)) {
4011
+ console.log("[CLINIC_GROUP] Admin is already in the group", {
4012
+ adminId,
4013
+ groupId
4014
+ });
4015
+ return;
4016
+ }
4017
+ console.log("[CLINIC_GROUP] Updating group with new admin");
4018
+ await updateClinicGroup(
4019
+ db,
4020
+ groupId,
4021
+ {
4022
+ admins: [...group.admins, adminId]
4023
+ },
4024
+ app
4025
+ );
4026
+ console.log("[CLINIC_GROUP] Admin added to group successfully");
4027
+ } catch (error) {
4028
+ console.error("[CLINIC_GROUP] Error adding admin to group:", error);
4029
+ throw error;
3940
4030
  }
3941
- await updateClinicGroup(db, groupId, {
3942
- admins: [...group.admins, adminId]
3943
- });
3944
4031
  }
3945
- async function removeAdminFromGroup(db, groupId, adminId) {
4032
+ async function removeAdminFromGroup(db, groupId, adminId, app) {
3946
4033
  const group = await getClinicGroup(db, groupId);
3947
4034
  if (!group) {
3948
4035
  throw new Error("Clinic group not found");
@@ -3953,21 +4040,30 @@ async function removeAdminFromGroup(db, groupId, adminId) {
3953
4040
  if (!group.admins.includes(adminId)) {
3954
4041
  return;
3955
4042
  }
3956
- await updateClinicGroup(db, groupId, {
3957
- admins: group.admins.filter((id) => id !== adminId)
3958
- });
4043
+ await updateClinicGroup(
4044
+ db,
4045
+ groupId,
4046
+ {
4047
+ admins: group.admins.filter((id) => id !== adminId)
4048
+ },
4049
+ app
4050
+ );
3959
4051
  }
3960
- async function deactivateClinicGroup(db, groupId) {
4052
+ async function deactivateClinicGroup(db, groupId, app) {
3961
4053
  const group = await getClinicGroup(db, groupId);
3962
4054
  if (!group) {
3963
4055
  throw new Error("Clinic group not found");
3964
4056
  }
3965
- await (0, import_firestore15.updateDoc)((0, import_firestore15.doc)(db, CLINIC_GROUPS_COLLECTION, groupId), {
3966
- isActive: false,
3967
- updatedAt: import_firestore15.Timestamp.now()
3968
- });
4057
+ await updateClinicGroup(
4058
+ db,
4059
+ groupId,
4060
+ {
4061
+ isActive: false
4062
+ },
4063
+ app
4064
+ );
3969
4065
  }
3970
- async function createAdminToken(db, groupId, creatorAdminId, data) {
4066
+ async function createAdminToken(db, groupId, creatorAdminId, app, data) {
3971
4067
  const group = await getClinicGroup(db, groupId);
3972
4068
  if (!group) {
3973
4069
  throw new Error("Clinic group not found");
@@ -3988,12 +4084,17 @@ async function createAdminToken(db, groupId, creatorAdminId, data) {
3988
4084
  createdAt: now,
3989
4085
  expiresAt
3990
4086
  };
3991
- await updateClinicGroup(db, groupId, {
3992
- adminTokens: [...group.adminTokens, token]
3993
- });
4087
+ await updateClinicGroup(
4088
+ db,
4089
+ groupId,
4090
+ {
4091
+ adminTokens: [...group.adminTokens, token]
4092
+ },
4093
+ app
4094
+ );
3994
4095
  return token;
3995
4096
  }
3996
- async function verifyAndUseAdminToken(db, groupId, token, userRef) {
4097
+ async function verifyAndUseAdminToken(db, groupId, token, userRef, app) {
3997
4098
  const group = await getClinicGroup(db, groupId);
3998
4099
  if (!group) {
3999
4100
  throw new Error("Clinic group not found");
@@ -4010,9 +4111,14 @@ async function verifyAndUseAdminToken(db, groupId, token, userRef) {
4010
4111
  const updatedTokens2 = group.adminTokens.map(
4011
4112
  (t) => t.id === adminToken.id ? { ...t, status: "expired" /* EXPIRED */ } : t
4012
4113
  );
4013
- await updateClinicGroup(db, groupId, {
4014
- adminTokens: updatedTokens2
4015
- });
4114
+ await updateClinicGroup(
4115
+ db,
4116
+ groupId,
4117
+ {
4118
+ adminTokens: updatedTokens2
4119
+ },
4120
+ app
4121
+ );
4016
4122
  throw new Error("Admin token has expired");
4017
4123
  }
4018
4124
  const updatedTokens = group.adminTokens.map(
@@ -4022,12 +4128,17 @@ async function verifyAndUseAdminToken(db, groupId, token, userRef) {
4022
4128
  usedByUserRef: userRef
4023
4129
  } : t
4024
4130
  );
4025
- await updateClinicGroup(db, groupId, {
4026
- adminTokens: updatedTokens
4027
- });
4131
+ await updateClinicGroup(
4132
+ db,
4133
+ groupId,
4134
+ {
4135
+ adminTokens: updatedTokens
4136
+ },
4137
+ app
4138
+ );
4028
4139
  return true;
4029
4140
  }
4030
- async function deleteAdminToken(db, groupId, tokenId, adminId) {
4141
+ async function deleteAdminToken(db, groupId, tokenId, adminId, app) {
4031
4142
  const group = await getClinicGroup(db, groupId);
4032
4143
  if (!group) {
4033
4144
  throw new Error("Clinic group not found");
@@ -4036,11 +4147,16 @@ async function deleteAdminToken(db, groupId, tokenId, adminId) {
4036
4147
  throw new Error("Admin does not belong to this clinic group");
4037
4148
  }
4038
4149
  const updatedTokens = group.adminTokens.filter((t) => t.id !== tokenId);
4039
- await updateClinicGroup(db, groupId, {
4040
- adminTokens: updatedTokens
4041
- });
4150
+ await updateClinicGroup(
4151
+ db,
4152
+ groupId,
4153
+ {
4154
+ adminTokens: updatedTokens
4155
+ },
4156
+ app
4157
+ );
4042
4158
  }
4043
- async function getActiveAdminTokens(db, groupId, adminId) {
4159
+ async function getActiveAdminTokens(db, groupId, adminId, app) {
4044
4160
  const group = await getClinicGroup(db, groupId);
4045
4161
  if (!group) {
4046
4162
  throw new Error("Clinic group not found");
@@ -4066,7 +4182,8 @@ var ClinicGroupService = class extends BaseService {
4066
4182
  data,
4067
4183
  ownerId,
4068
4184
  isDefault,
4069
- this.clinicAdminService
4185
+ this.clinicAdminService,
4186
+ this.app
4070
4187
  );
4071
4188
  }
4072
4189
  /**
@@ -4085,25 +4202,35 @@ var ClinicGroupService = class extends BaseService {
4085
4202
  * Ažurira grupaciju klinika
4086
4203
  */
4087
4204
  async updateClinicGroup(groupId, data) {
4088
- return updateClinicGroup(this.db, groupId, data);
4205
+ return updateClinicGroup(this.db, groupId, data, this.app);
4089
4206
  }
4090
4207
  /**
4091
4208
  * Dodaje admina u grupaciju
4092
4209
  */
4093
4210
  async addAdminToGroup(groupId, adminId) {
4094
- return addAdminToGroup(this.db, groupId, adminId);
4211
+ return addAdminToGroup(
4212
+ this.db,
4213
+ groupId,
4214
+ adminId,
4215
+ this.app
4216
+ );
4095
4217
  }
4096
4218
  /**
4097
4219
  * Uklanja admina iz grupacije
4098
4220
  */
4099
4221
  async removeAdminFromGroup(groupId, adminId) {
4100
- return removeAdminFromGroup(this.db, groupId, adminId);
4222
+ return removeAdminFromGroup(
4223
+ this.db,
4224
+ groupId,
4225
+ adminId,
4226
+ this.app
4227
+ );
4101
4228
  }
4102
4229
  /**
4103
4230
  * Deaktivira grupaciju klinika
4104
4231
  */
4105
4232
  async deactivateClinicGroup(groupId) {
4106
- return deactivateClinicGroup(this.db, groupId);
4233
+ return deactivateClinicGroup(this.db, groupId, this.app);
4107
4234
  }
4108
4235
  /**
4109
4236
  * Sets up additional clinic group information after initial creation
@@ -4113,18 +4240,45 @@ var ClinicGroupService = class extends BaseService {
4113
4240
  * @returns The updated clinic group
4114
4241
  */
4115
4242
  async setupClinicGroup(groupId, setupData) {
4243
+ console.log("[CLINIC_GROUP] Setting up clinic group", { groupId });
4116
4244
  const clinicGroup = await this.getClinicGroup(groupId);
4117
4245
  if (!clinicGroup) {
4246
+ console.error("[CLINIC_GROUP] Clinic group not found", { groupId });
4118
4247
  throw new Error(`Clinic group with ID ${groupId} not found`);
4119
4248
  }
4249
+ let logoUrl = setupData.logo;
4250
+ if (logoUrl && typeof logoUrl === "string" && logoUrl.startsWith("data:")) {
4251
+ console.log("[CLINIC_GROUP] Processing logo in setupClinicGroup");
4252
+ try {
4253
+ const uploadedLogoUrl = await uploadPhoto(
4254
+ logoUrl,
4255
+ "clinic-groups",
4256
+ groupId,
4257
+ "logo",
4258
+ this.app
4259
+ );
4260
+ console.log("[CLINIC_GROUP] Logo processed in setupClinicGroup", {
4261
+ uploadedLogoUrl
4262
+ });
4263
+ if (uploadedLogoUrl !== null) {
4264
+ logoUrl = uploadedLogoUrl;
4265
+ }
4266
+ } catch (error) {
4267
+ console.error(
4268
+ "[CLINIC_GROUP] Error processing logo in setupClinicGroup:",
4269
+ error
4270
+ );
4271
+ }
4272
+ }
4120
4273
  const updateData = {
4121
4274
  languages: setupData.languages,
4122
4275
  practiceType: setupData.practiceType,
4123
4276
  description: setupData.description,
4124
- logo: setupData.logo,
4277
+ logo: logoUrl,
4125
4278
  calendarSyncEnabled: setupData.calendarSyncEnabled,
4126
4279
  autoConfirmAppointments: setupData.autoConfirmAppointments
4127
4280
  };
4281
+ console.log("[CLINIC_GROUP] Updating clinic group with setup data");
4128
4282
  return this.updateClinicGroup(groupId, updateData);
4129
4283
  }
4130
4284
  /**
@@ -4135,6 +4289,7 @@ var ClinicGroupService = class extends BaseService {
4135
4289
  this.db,
4136
4290
  groupId,
4137
4291
  creatorAdminId,
4292
+ this.app,
4138
4293
  data
4139
4294
  );
4140
4295
  }
@@ -4146,7 +4301,8 @@ var ClinicGroupService = class extends BaseService {
4146
4301
  this.db,
4147
4302
  groupId,
4148
4303
  token,
4149
- userRef
4304
+ userRef,
4305
+ this.app
4150
4306
  );
4151
4307
  }
4152
4308
  /**
@@ -4157,14 +4313,20 @@ var ClinicGroupService = class extends BaseService {
4157
4313
  this.db,
4158
4314
  groupId,
4159
4315
  tokenId,
4160
- adminId
4316
+ adminId,
4317
+ this.app
4161
4318
  );
4162
4319
  }
4163
4320
  /**
4164
4321
  * Dohvata aktivne admin tokene
4165
4322
  */
4166
4323
  async getActiveAdminTokens(groupId, adminId) {
4167
- return getActiveAdminTokens(this.db, groupId, adminId);
4324
+ return getActiveAdminTokens(
4325
+ this.db,
4326
+ groupId,
4327
+ adminId,
4328
+ this.app
4329
+ );
4168
4330
  }
4169
4331
  };
4170
4332
 
@@ -4172,44 +4334,193 @@ var ClinicGroupService = class extends BaseService {
4172
4334
  var import_firestore16 = require("firebase/firestore");
4173
4335
  var import_geofire_common3 = require("geofire-common");
4174
4336
  var import_zod14 = require("zod");
4175
- async function createClinic(db, data, creatorAdminId, clinicGroupService, clinicAdminService) {
4176
- const validatedData = createClinicSchema.parse(data);
4177
- const admin = await clinicAdminService.getClinicAdmin(creatorAdminId);
4178
- if (!admin) {
4179
- throw new Error("Admin not found");
4337
+ async function createClinic(db, data, creatorAdminId, clinicGroupService, clinicAdminService, app) {
4338
+ var _a;
4339
+ console.log("[CLINIC] Starting clinic creation", { creatorAdminId });
4340
+ console.log("[CLINIC] Input data:", JSON.stringify(data, null, 2));
4341
+ try {
4342
+ const validatedData2 = createClinicSchema.parse(data);
4343
+ console.log("[CLINIC] Data validation passed");
4344
+ } catch (validationError) {
4345
+ console.error("[CLINIC] Data validation failed:", validationError);
4346
+ throw validationError;
4180
4347
  }
4181
- if (admin.clinicGroupId !== validatedData.clinicGroupId) {
4182
- throw new Error("Admin does not belong to this clinic group");
4348
+ const validatedData = createClinicSchema.parse(data);
4349
+ try {
4350
+ console.log("[CLINIC] Checking if admin exists and belongs to group");
4351
+ const admin = await clinicAdminService.getClinicAdmin(creatorAdminId);
4352
+ if (!admin) {
4353
+ console.error("[CLINIC] Admin not found", { creatorAdminId });
4354
+ throw new Error("Admin not found");
4355
+ }
4356
+ if (admin.clinicGroupId !== validatedData.clinicGroupId) {
4357
+ console.error("[CLINIC] Admin does not belong to this clinic group", {
4358
+ adminGroupId: admin.clinicGroupId,
4359
+ requestedGroupId: validatedData.clinicGroupId
4360
+ });
4361
+ throw new Error("Admin does not belong to this clinic group");
4362
+ }
4363
+ console.log("[CLINIC] Admin verified");
4364
+ } catch (adminError) {
4365
+ console.error("[CLINIC] Error verifying admin:", adminError);
4366
+ throw adminError;
4183
4367
  }
4184
- const group = await clinicGroupService.getClinicGroup(
4185
- validatedData.clinicGroupId
4186
- );
4187
- if (!group) {
4188
- throw new Error("Clinic group not found");
4368
+ try {
4369
+ console.log("[CLINIC] Checking if clinic group exists");
4370
+ const group = await clinicGroupService.getClinicGroup(
4371
+ validatedData.clinicGroupId
4372
+ );
4373
+ if (!group) {
4374
+ console.error("[CLINIC] Clinic group not found", {
4375
+ groupId: validatedData.clinicGroupId
4376
+ });
4377
+ throw new Error("Clinic group not found");
4378
+ }
4379
+ console.log("[CLINIC] Clinic group verified");
4380
+ } catch (groupError) {
4381
+ console.error("[CLINIC] Error verifying clinic group:", groupError);
4382
+ throw groupError;
4189
4383
  }
4384
+ console.log("[CLINIC] Generating geohash for location");
4190
4385
  if (validatedData.location) {
4191
- validatedData.location.geohash = (0, import_geofire_common3.geohashForLocation)([
4192
- validatedData.location.latitude,
4193
- validatedData.location.longitude
4194
- ]);
4386
+ try {
4387
+ validatedData.location.geohash = (0, import_geofire_common3.geohashForLocation)([
4388
+ validatedData.location.latitude,
4389
+ validatedData.location.longitude
4390
+ ]);
4391
+ console.log("[CLINIC] Geohash generated successfully", {
4392
+ geohash: validatedData.location.geohash
4393
+ });
4394
+ } catch (geohashError) {
4395
+ console.error("[CLINIC] Error generating geohash:", geohashError);
4396
+ throw geohashError;
4397
+ }
4398
+ }
4399
+ const clinicId = (0, import_firestore16.doc)((0, import_firestore16.collection)(db, CLINICS_COLLECTION)).id;
4400
+ console.log("[CLINIC] Generated clinic ID:", clinicId);
4401
+ console.log("[CLINIC] Processing photos");
4402
+ let logoUrl = null;
4403
+ if (validatedData.logo) {
4404
+ console.log("[CLINIC] Processing logo");
4405
+ try {
4406
+ logoUrl = await uploadPhoto(
4407
+ validatedData.logo,
4408
+ "clinics",
4409
+ clinicId,
4410
+ "logo",
4411
+ app
4412
+ );
4413
+ console.log("[CLINIC] Logo processed", { logoUrl });
4414
+ } catch (logoError) {
4415
+ console.error("[CLINIC] Error processing logo:", logoError);
4416
+ }
4417
+ }
4418
+ let processedPhotos = [];
4419
+ if (validatedData.photos && validatedData.photos.length > 0) {
4420
+ console.log("[CLINIC] Processing regular photos");
4421
+ try {
4422
+ processedPhotos = await uploadMultiplePhotos(
4423
+ validatedData.photos,
4424
+ "clinics",
4425
+ clinicId,
4426
+ "photo",
4427
+ app
4428
+ );
4429
+ console.log("[CLINIC] Regular photos processed", {
4430
+ count: processedPhotos.length
4431
+ });
4432
+ } catch (photosError) {
4433
+ console.error("[CLINIC] Error processing regular photos:", photosError);
4434
+ processedPhotos = validatedData.photos.filter(
4435
+ (photo) => !photo.startsWith("data:")
4436
+ );
4437
+ }
4438
+ }
4439
+ let processedFeaturedPhotos = [];
4440
+ if (validatedData.featuredPhotos && validatedData.featuredPhotos.length > 0) {
4441
+ console.log("[CLINIC] Processing featured photos");
4442
+ try {
4443
+ processedFeaturedPhotos = await uploadMultiplePhotos(
4444
+ validatedData.featuredPhotos,
4445
+ "clinics",
4446
+ clinicId,
4447
+ "featured",
4448
+ app
4449
+ );
4450
+ console.log("[CLINIC] Featured photos processed", {
4451
+ count: processedFeaturedPhotos.length
4452
+ });
4453
+ } catch (featuredError) {
4454
+ console.error(
4455
+ "[CLINIC] Error processing featured photos:",
4456
+ featuredError
4457
+ );
4458
+ processedFeaturedPhotos = validatedData.featuredPhotos.filter(
4459
+ (photo) => !photo.startsWith("data:")
4460
+ );
4461
+ }
4462
+ }
4463
+ let processedPhotosWithTags = validatedData.photosWithTags || [];
4464
+ if (processedPhotosWithTags.length > 0) {
4465
+ console.log("[CLINIC] Processing photos with tags");
4466
+ try {
4467
+ const updatedPhotosWithTags = [];
4468
+ for (const photoWithTag of processedPhotosWithTags) {
4469
+ if (photoWithTag.url && photoWithTag.url.startsWith("data:")) {
4470
+ const uploadedUrl = await uploadPhoto(
4471
+ photoWithTag.url,
4472
+ "clinics",
4473
+ clinicId,
4474
+ `tagged-${photoWithTag.tag}`,
4475
+ app
4476
+ );
4477
+ if (uploadedUrl) {
4478
+ updatedPhotosWithTags.push({
4479
+ url: uploadedUrl,
4480
+ tag: photoWithTag.tag
4481
+ });
4482
+ }
4483
+ } else {
4484
+ updatedPhotosWithTags.push(photoWithTag);
4485
+ }
4486
+ }
4487
+ processedPhotosWithTags = updatedPhotosWithTags;
4488
+ console.log("[CLINIC] Photos with tags processed", {
4489
+ count: processedPhotosWithTags.length
4490
+ });
4491
+ } catch (tagsError) {
4492
+ console.error("[CLINIC] Error processing photos with tags:", tagsError);
4493
+ processedPhotosWithTags = ((_a = validatedData.photosWithTags) == null ? void 0 : _a.filter(
4494
+ (photo) => !photo.url.startsWith("data:")
4495
+ )) || [];
4496
+ }
4195
4497
  }
4196
4498
  const now = import_firestore16.Timestamp.now();
4499
+ console.log("[CLINIC] Preparing clinic data object");
4197
4500
  const clinicData = {
4198
4501
  ...validatedData,
4199
- id: (0, import_firestore16.doc)((0, import_firestore16.collection)(db, CLINICS_COLLECTION)).id,
4502
+ id: clinicId,
4200
4503
  description: validatedData.description || void 0,
4201
4504
  location: {
4202
- ...validatedData.location,
4505
+ address: validatedData.location.address || "",
4506
+ city: validatedData.location.city || "",
4507
+ country: validatedData.location.country || "",
4508
+ postalCode: validatedData.location.postalCode || "",
4509
+ latitude: validatedData.location.latitude || 0,
4510
+ longitude: validatedData.location.longitude || 0,
4203
4511
  geohash: validatedData.location.geohash || void 0
4204
4512
  },
4205
4513
  contactInfo: {
4206
- ...validatedData.contactInfo,
4514
+ email: validatedData.contactInfo.email || "",
4515
+ phoneNumber: validatedData.contactInfo.phoneNumber || "",
4207
4516
  alternativePhoneNumber: validatedData.contactInfo.alternativePhoneNumber || void 0,
4208
4517
  website: validatedData.contactInfo.website || void 0
4209
4518
  },
4519
+ logo: logoUrl || void 0,
4210
4520
  tags: validatedData.tags || [],
4211
- featuredPhotos: [],
4212
- photos: validatedData.photos || [],
4521
+ featuredPhotos: processedFeaturedPhotos || [],
4522
+ photos: processedPhotos || [],
4523
+ photosWithTags: processedPhotosWithTags,
4213
4524
  doctors: [],
4214
4525
  doctorsInfo: [],
4215
4526
  services: [],
@@ -4224,17 +4535,73 @@ async function createClinic(db, data, creatorAdminId, clinicGroupService, clinic
4224
4535
  isVerified: false
4225
4536
  };
4226
4537
  try {
4227
- clinicSchema.parse(clinicData);
4228
- await (0, import_firestore16.setDoc)((0, import_firestore16.doc)(db, CLINICS_COLLECTION, clinicData.id), clinicData);
4229
- await clinicGroupService.updateClinicGroup(validatedData.clinicGroupId, {
4230
- clinics: [...group.clinics, clinicData.id]
4538
+ console.log("[CLINIC] Validating complete clinic object");
4539
+ try {
4540
+ clinicSchema.parse(clinicData);
4541
+ console.log("[CLINIC] Clinic validation passed");
4542
+ } catch (schemaError) {
4543
+ console.error(
4544
+ "[CLINIC] Clinic validation failed:",
4545
+ JSON.stringify(schemaError, null, 2)
4546
+ );
4547
+ throw schemaError;
4548
+ }
4549
+ console.log("[CLINIC] Saving clinic to Firestore", {
4550
+ clinicId: clinicData.id
4551
+ });
4552
+ try {
4553
+ await (0, import_firestore16.setDoc)((0, import_firestore16.doc)(db, CLINICS_COLLECTION, clinicData.id), clinicData);
4554
+ console.log("[CLINIC] Clinic saved successfully");
4555
+ } catch (firestoreError) {
4556
+ console.error("[CLINIC] Error saving to Firestore:", firestoreError);
4557
+ throw firestoreError;
4558
+ }
4559
+ console.log("[CLINIC] Adding clinic to clinic group");
4560
+ try {
4561
+ const group = await clinicGroupService.getClinicGroup(
4562
+ validatedData.clinicGroupId
4563
+ );
4564
+ if (group) {
4565
+ await clinicGroupService.updateClinicGroup(
4566
+ validatedData.clinicGroupId,
4567
+ {
4568
+ clinics: [...group.clinics, clinicData.id]
4569
+ }
4570
+ );
4571
+ console.log("[CLINIC] Clinic added to group successfully");
4572
+ }
4573
+ } catch (groupUpdateError) {
4574
+ console.error("[CLINIC] Error adding clinic to group:", groupUpdateError);
4575
+ }
4576
+ console.log("[CLINIC] Adding clinic to admin's managed clinics");
4577
+ try {
4578
+ await clinicAdminService.addClinicToManaged(
4579
+ creatorAdminId,
4580
+ clinicData.id
4581
+ );
4582
+ console.log(
4583
+ "[CLINIC] Clinic added to admin's managed clinics successfully"
4584
+ );
4585
+ } catch (adminUpdateError) {
4586
+ console.error(
4587
+ "[CLINIC] Error adding clinic to admin's managed clinics:",
4588
+ adminUpdateError
4589
+ );
4590
+ }
4591
+ console.log("[CLINIC] Clinic creation completed successfully", {
4592
+ clinicId: clinicData.id,
4593
+ clinicName: clinicData.name
4231
4594
  });
4232
- await clinicAdminService.addClinicToManaged(creatorAdminId, clinicData.id);
4233
4595
  return clinicData;
4234
4596
  } catch (error) {
4235
4597
  if (error instanceof import_zod14.z.ZodError) {
4598
+ console.error(
4599
+ "[CLINIC] Zod validation error:",
4600
+ JSON.stringify(error.errors, null, 2)
4601
+ );
4236
4602
  throw new Error("Invalid clinic data: " + error.message);
4237
4603
  }
4604
+ console.error("[CLINIC] Unhandled error in createClinic:", error);
4238
4605
  throw error;
4239
4606
  }
4240
4607
  }
@@ -4255,27 +4622,177 @@ async function getClinicsByGroup(db, groupId) {
4255
4622
  const querySnapshot = await (0, import_firestore16.getDocs)(q);
4256
4623
  return querySnapshot.docs.map((doc14) => doc14.data());
4257
4624
  }
4258
- async function updateClinic(db, clinicId, data, adminId, clinicAdminService) {
4625
+ async function updateClinic(db, clinicId, data, adminId, clinicAdminService, app) {
4626
+ console.log("[CLINIC] Starting clinic update", { clinicId, adminId });
4259
4627
  const clinic = await getClinic(db, clinicId);
4260
4628
  if (!clinic) {
4629
+ console.error("[CLINIC] Clinic not found", { clinicId });
4261
4630
  throw new Error("Clinic not found");
4262
4631
  }
4263
- const admin = await clinicAdminService.getClinicAdmin(adminId);
4264
- if (!admin) {
4265
- throw new Error("Admin not found");
4632
+ try {
4633
+ console.log("[CLINIC] Checking admin permissions");
4634
+ const admin = await clinicAdminService.getClinicAdmin(adminId);
4635
+ if (!admin) {
4636
+ console.error("[CLINIC] Admin not found", { adminId });
4637
+ throw new Error("Admin not found");
4638
+ }
4639
+ const hasPermission = admin.isGroupOwner && admin.clinicGroupId === clinic.clinicGroupId || admin.clinicsManaged.includes(clinicId) && clinic.admins && clinic.admins.includes(adminId);
4640
+ if (!hasPermission) {
4641
+ console.error(
4642
+ "[CLINIC] Admin does not have permission to update this clinic",
4643
+ {
4644
+ adminId,
4645
+ clinicId,
4646
+ isGroupOwner: admin.isGroupOwner,
4647
+ clinicsManaged: admin.clinicsManaged,
4648
+ isClinicAdmin: clinic.admins && clinic.admins.includes(adminId)
4649
+ }
4650
+ );
4651
+ throw new Error("Admin does not have permission to update this clinic");
4652
+ }
4653
+ console.log("[CLINIC] Admin permissions verified");
4654
+ } catch (adminError) {
4655
+ console.error("[CLINIC] Error verifying admin permissions:", adminError);
4656
+ throw adminError;
4657
+ }
4658
+ let updatedData = { ...data };
4659
+ if (data.logo && typeof data.logo === "string" && data.logo.startsWith("data:")) {
4660
+ console.log("[CLINIC] Processing logo update");
4661
+ try {
4662
+ const logoUrl = await uploadPhoto(
4663
+ data.logo,
4664
+ "clinics",
4665
+ clinicId,
4666
+ "logo",
4667
+ app
4668
+ );
4669
+ console.log("[CLINIC] Logo update processed", { logoUrl });
4670
+ if (logoUrl !== null) {
4671
+ updatedData.logo = logoUrl;
4672
+ }
4673
+ } catch (logoError) {
4674
+ console.error("[CLINIC] Error processing logo update:", logoError);
4675
+ }
4266
4676
  }
4267
- if (!admin.isGroupOwner && !admin.clinicsManaged.includes(clinicId)) {
4268
- throw new Error("Admin does not have permission to update this clinic");
4677
+ if (data.photos && data.photos.length > 0) {
4678
+ console.log("[CLINIC] Processing regular photos update");
4679
+ try {
4680
+ const dataUrlPhotos = data.photos.filter(
4681
+ (photo) => typeof photo === "string" && photo.startsWith("data:")
4682
+ );
4683
+ const existingPhotos = data.photos.filter(
4684
+ (photo) => typeof photo === "string" && !photo.startsWith("data:")
4685
+ );
4686
+ if (dataUrlPhotos.length > 0) {
4687
+ const uploadedPhotos = await uploadMultiplePhotos(
4688
+ dataUrlPhotos,
4689
+ "clinics",
4690
+ clinicId,
4691
+ "photo",
4692
+ app
4693
+ );
4694
+ console.log("[CLINIC] Regular photos update processed", {
4695
+ count: uploadedPhotos.length
4696
+ });
4697
+ updatedData.photos = [...existingPhotos, ...uploadedPhotos];
4698
+ }
4699
+ } catch (photosError) {
4700
+ console.error(
4701
+ "[CLINIC] Error processing regular photos update:",
4702
+ photosError
4703
+ );
4704
+ updatedData.photos = data.photos.filter(
4705
+ (photo) => typeof photo === "string" && !photo.startsWith("data:")
4706
+ );
4707
+ }
4269
4708
  }
4270
- const updatedData = {
4271
- ...data,
4709
+ if (data.featuredPhotos && data.featuredPhotos.length > 0) {
4710
+ console.log("[CLINIC] Processing featured photos update");
4711
+ try {
4712
+ const dataUrlPhotos = data.featuredPhotos.filter(
4713
+ (photo) => typeof photo === "string" && photo.startsWith("data:")
4714
+ );
4715
+ const existingPhotos = data.featuredPhotos.filter(
4716
+ (photo) => typeof photo === "string" && !photo.startsWith("data:")
4717
+ );
4718
+ if (dataUrlPhotos.length > 0) {
4719
+ const uploadedPhotos = await uploadMultiplePhotos(
4720
+ dataUrlPhotos,
4721
+ "clinics",
4722
+ clinicId,
4723
+ "featured",
4724
+ app
4725
+ );
4726
+ console.log("[CLINIC] Featured photos update processed", {
4727
+ count: uploadedPhotos.length
4728
+ });
4729
+ updatedData.featuredPhotos = [...existingPhotos, ...uploadedPhotos];
4730
+ }
4731
+ } catch (featuredError) {
4732
+ console.error(
4733
+ "[CLINIC] Error processing featured photos update:",
4734
+ featuredError
4735
+ );
4736
+ updatedData.featuredPhotos = data.featuredPhotos.filter(
4737
+ (photo) => typeof photo === "string" && !photo.startsWith("data:")
4738
+ );
4739
+ }
4740
+ }
4741
+ if (data.photosWithTags && data.photosWithTags.length > 0) {
4742
+ console.log("[CLINIC] Processing photos with tags update");
4743
+ try {
4744
+ const updatedPhotosWithTags = [];
4745
+ for (const photoWithTag of data.photosWithTags) {
4746
+ if (photoWithTag.url && photoWithTag.url.startsWith("data:")) {
4747
+ const uploadedUrl = await uploadPhoto(
4748
+ photoWithTag.url,
4749
+ "clinics",
4750
+ clinicId,
4751
+ `tagged-${photoWithTag.tag}`,
4752
+ app
4753
+ );
4754
+ if (uploadedUrl) {
4755
+ updatedPhotosWithTags.push({
4756
+ url: uploadedUrl,
4757
+ tag: photoWithTag.tag
4758
+ });
4759
+ }
4760
+ } else {
4761
+ updatedPhotosWithTags.push(photoWithTag);
4762
+ }
4763
+ }
4764
+ updatedData.photosWithTags = updatedPhotosWithTags;
4765
+ console.log("[CLINIC] Photos with tags update processed", {
4766
+ count: updatedPhotosWithTags.length
4767
+ });
4768
+ } catch (tagsError) {
4769
+ console.error(
4770
+ "[CLINIC] Error processing photos with tags update:",
4771
+ tagsError
4772
+ );
4773
+ updatedData.photosWithTags = data.photosWithTags.filter(
4774
+ (photo) => !photo.url.startsWith("data:")
4775
+ );
4776
+ }
4777
+ }
4778
+ updatedData = {
4779
+ ...updatedData,
4272
4780
  updatedAt: import_firestore16.Timestamp.now()
4273
4781
  };
4274
- await (0, import_firestore16.updateDoc)((0, import_firestore16.doc)(db, CLINICS_COLLECTION, clinicId), updatedData);
4782
+ console.log("[CLINIC] Updating clinic in Firestore");
4783
+ try {
4784
+ await (0, import_firestore16.updateDoc)((0, import_firestore16.doc)(db, CLINICS_COLLECTION, clinicId), updatedData);
4785
+ console.log("[CLINIC] Clinic updated successfully");
4786
+ } catch (updateError) {
4787
+ console.error("[CLINIC] Error updating clinic in Firestore:", updateError);
4788
+ throw updateError;
4789
+ }
4275
4790
  const updatedClinic = await getClinic(db, clinicId);
4276
4791
  if (!updatedClinic) {
4792
+ console.error("[CLINIC] Failed to retrieve updated clinic");
4277
4793
  throw new Error("Failed to retrieve updated clinic");
4278
4794
  }
4795
+ console.log("[CLINIC] Clinic update completed successfully");
4279
4796
  return updatedClinic;
4280
4797
  }
4281
4798
  async function deactivateClinic(db, clinicId, adminId, clinicAdminService) {
@@ -4287,7 +4804,8 @@ async function deactivateClinic(db, clinicId, adminId, clinicAdminService) {
4287
4804
  if (!admin) {
4288
4805
  throw new Error("Admin not found");
4289
4806
  }
4290
- if (!admin.isGroupOwner && !admin.clinicsManaged.includes(clinicId)) {
4807
+ const hasPermission = admin.isGroupOwner && admin.clinicGroupId === clinic.clinicGroupId || admin.clinicsManaged.includes(clinicId) && clinic.admins && clinic.admins.includes(adminId);
4808
+ if (!hasPermission) {
4291
4809
  throw new Error("Admin does not have permission to deactivate this clinic");
4292
4810
  }
4293
4811
  await (0, import_firestore16.updateDoc)((0, import_firestore16.doc)(db, CLINICS_COLLECTION, clinicId), {
@@ -4330,24 +4848,24 @@ async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGr
4330
4848
 
4331
4849
  // src/services/clinic/utils/review.utils.ts
4332
4850
  var import_firestore17 = require("firebase/firestore");
4333
- async function addReview(db, clinicId, review) {
4334
- const clinic = await getClinic(db, clinicId);
4335
- if (!clinic) {
4851
+ async function addReview(db, clinicId, review, app) {
4852
+ const clinicRef = (0, import_firestore17.doc)(db, "clinics", clinicId);
4853
+ const clinicSnap = await (0, import_firestore17.getDoc)(clinicRef);
4854
+ if (!clinicSnap.exists()) {
4336
4855
  throw new Error("Clinic not found");
4337
4856
  }
4857
+ const clinic = clinicSnap.data();
4338
4858
  const now = import_firestore17.Timestamp.now();
4339
4859
  const reviewData = {
4860
+ ...review,
4340
4861
  id: (0, import_firestore17.doc)((0, import_firestore17.collection)(db, "clinic_reviews")).id,
4341
4862
  clinicId,
4342
- patientId: review.patientId,
4343
- rating: review.rating,
4344
- comment: review.comment,
4345
4863
  createdAt: now,
4346
4864
  updatedAt: now,
4347
4865
  isVerified: false
4348
4866
  };
4349
4867
  clinicReviewSchema.parse(reviewData);
4350
- await (0, import_firestore17.setDoc)((0, import_firestore17.doc)(db, "clinic_reviews", reviewData.id), reviewData);
4868
+ await (0, import_firestore17.addDoc)((0, import_firestore17.collection)(db, "clinic_reviews"), reviewData);
4351
4869
  const newRating = clinic.rating ? {
4352
4870
  average: (clinic.rating.average * clinic.rating.count + review.rating) / (clinic.rating.count + 1),
4353
4871
  count: clinic.rating.count + 1
@@ -4363,28 +4881,24 @@ async function addReview(db, clinicId, review) {
4363
4881
  ...clinic.reviewsInfo,
4364
4882
  {
4365
4883
  id: reviewData.id,
4366
- rating: review.rating,
4367
- text: review.comment,
4368
- patientId: review.patientId,
4369
- patientName: "Patient",
4370
- // This should be fetched from patient service
4371
- patientPhoto: "",
4372
- // This should be fetched from patient service
4373
- createdAt: now,
4374
- updatedAt: now
4884
+ patientId: reviewData.patientId,
4885
+ rating: reviewData.rating,
4886
+ comment: reviewData.comment,
4887
+ createdAt: reviewData.createdAt
4375
4888
  }
4376
4889
  ]
4377
4890
  },
4378
- clinic.admins[0],
4379
- // Using the first admin for the update
4380
- { getClinicAdmin: async (id) => ({ isGroupOwner: true }) }
4381
- // Mock admin service
4891
+ "system",
4892
+ // System update, no admin ID needed
4893
+ null,
4894
+ // No clinic admin service needed for system updates
4895
+ app
4382
4896
  );
4383
4897
  return reviewData;
4384
4898
  }
4385
4899
 
4386
4900
  // src/services/clinic/utils/tag.utils.ts
4387
- async function addTags(db, clinicId, adminId, newTags, clinicAdminService) {
4901
+ async function addTags(db, clinicId, adminId, newTags, clinicAdminService, app) {
4388
4902
  const clinic = await getClinic(db, clinicId);
4389
4903
  if (!clinic) {
4390
4904
  throw new Error("Clinic not found");
@@ -4393,7 +4907,8 @@ async function addTags(db, clinicId, adminId, newTags, clinicAdminService) {
4393
4907
  if (!admin) {
4394
4908
  throw new Error("Admin not found");
4395
4909
  }
4396
- if (!admin.isGroupOwner && !admin.clinicsManaged.includes(clinicId)) {
4910
+ const hasPermission = admin.isGroupOwner && admin.clinicGroupId === clinic.clinicGroupId || admin.clinicsManaged.includes(clinicId) && clinic.admins && clinic.admins.includes(adminId);
4911
+ if (!hasPermission) {
4397
4912
  throw new Error("Admin does not have permission to update this clinic");
4398
4913
  }
4399
4914
  const updatedTags = [.../* @__PURE__ */ new Set([...clinic.tags, ...newTags.tags || []])];
@@ -4404,10 +4919,11 @@ async function addTags(db, clinicId, adminId, newTags, clinicAdminService) {
4404
4919
  tags: updatedTags
4405
4920
  },
4406
4921
  adminId,
4407
- clinicAdminService
4922
+ clinicAdminService,
4923
+ app
4408
4924
  );
4409
4925
  }
4410
- async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminService) {
4926
+ async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminService, app) {
4411
4927
  const clinic = await getClinic(db, clinicId);
4412
4928
  if (!clinic) {
4413
4929
  throw new Error("Clinic not found");
@@ -4416,14 +4932,12 @@ async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminServic
4416
4932
  if (!admin) {
4417
4933
  throw new Error("Admin not found");
4418
4934
  }
4419
- if (!admin.isGroupOwner && !admin.clinicsManaged.includes(clinicId)) {
4935
+ const hasPermission = admin.isGroupOwner && admin.clinicGroupId === clinic.clinicGroupId || admin.clinicsManaged.includes(clinicId) && clinic.admins && clinic.admins.includes(adminId);
4936
+ if (!hasPermission) {
4420
4937
  throw new Error("Admin does not have permission to update this clinic");
4421
4938
  }
4422
4939
  const updatedTags = clinic.tags.filter(
4423
- (tag) => {
4424
- var _a;
4425
- return !((_a = tagsToRemove.tags) == null ? void 0 : _a.includes(tag));
4426
- }
4940
+ (tag) => !tagsToRemove.tags || !tagsToRemove.tags.includes(tag)
4427
4941
  );
4428
4942
  return updateClinic(
4429
4943
  db,
@@ -4432,7 +4946,8 @@ async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminServic
4432
4946
  tags: updatedTags
4433
4947
  },
4434
4948
  adminId,
4435
- clinicAdminService
4949
+ clinicAdminService,
4950
+ app
4436
4951
  );
4437
4952
  }
4438
4953
 
@@ -4502,7 +5017,8 @@ var ClinicService = class extends BaseService {
4502
5017
  data,
4503
5018
  creatorAdminId,
4504
5019
  this.clinicGroupService,
4505
- this.clinicAdminService
5020
+ this.clinicAdminService,
5021
+ this.app
4506
5022
  );
4507
5023
  }
4508
5024
  /**
@@ -4537,14 +5053,15 @@ var ClinicService = class extends BaseService {
4537
5053
  clinicId,
4538
5054
  data,
4539
5055
  adminId,
4540
- this.clinicAdminService
5056
+ this.clinicAdminService,
5057
+ this.app
4541
5058
  );
4542
5059
  }
4543
5060
  /**
4544
5061
  * Dodaje recenziju klinici
4545
5062
  */
4546
5063
  async addReview(clinicId, review) {
4547
- return addReview(this.db, clinicId, review);
5064
+ return addReview(this.db, clinicId, review, this.app);
4548
5065
  }
4549
5066
  /**
4550
5067
  * Deaktivira kliniku
@@ -4566,7 +5083,8 @@ var ClinicService = class extends BaseService {
4566
5083
  clinicId,
4567
5084
  adminId,
4568
5085
  newTags,
4569
- this.clinicAdminService
5086
+ this.clinicAdminService,
5087
+ this.app
4570
5088
  );
4571
5089
  }
4572
5090
  /**
@@ -4578,7 +5096,8 @@ var ClinicService = class extends BaseService {
4578
5096
  clinicId,
4579
5097
  adminId,
4580
5098
  tagsToRemove,
4581
- this.clinicAdminService
5099
+ this.clinicAdminService,
5100
+ this.app
4582
5101
  );
4583
5102
  }
4584
5103
  /**
@@ -4613,12 +5132,21 @@ var ClinicService = class extends BaseService {
4613
5132
  * @returns The created clinic
4614
5133
  */
4615
5134
  async createClinicBranch(clinicGroupId, setupData, adminId) {
5135
+ var _a, _b;
5136
+ console.log("[CLINIC_SERVICE] Starting clinic branch creation", {
5137
+ clinicGroupId,
5138
+ adminId
5139
+ });
4616
5140
  const clinicGroup = await this.clinicGroupService.getClinicGroup(
4617
5141
  clinicGroupId
4618
5142
  );
4619
5143
  if (!clinicGroup) {
5144
+ console.error("[CLINIC_SERVICE] Clinic group not found", {
5145
+ clinicGroupId
5146
+ });
4620
5147
  throw new Error(`Clinic group with ID ${clinicGroupId} not found`);
4621
5148
  }
5149
+ console.log("[CLINIC_SERVICE] Clinic group verified");
4622
5150
  const createClinicData = {
4623
5151
  clinicGroupId,
4624
5152
  name: setupData.name,
@@ -4627,8 +5155,8 @@ var ClinicService = class extends BaseService {
4627
5155
  contactInfo: setupData.contactInfo,
4628
5156
  workingHours: setupData.workingHours,
4629
5157
  tags: setupData.tags,
4630
- photos: setupData.photos,
4631
- photosWithTags: setupData.photosWithTags,
5158
+ photos: setupData.photos || [],
5159
+ photosWithTags: setupData.photosWithTags || [],
4632
5160
  doctors: [],
4633
5161
  services: [],
4634
5162
  admins: [adminId],
@@ -4637,7 +5165,17 @@ var ClinicService = class extends BaseService {
4637
5165
  logo: setupData.logo,
4638
5166
  featuredPhotos: setupData.featuredPhotos || []
4639
5167
  };
5168
+ console.log("[CLINIC_SERVICE] Creating clinic branch with data", {
5169
+ name: createClinicData.name,
5170
+ hasLogo: !!createClinicData.logo,
5171
+ photosCount: createClinicData.photos.length,
5172
+ featuredPhotosCount: ((_a = createClinicData.featuredPhotos) == null ? void 0 : _a.length) || 0,
5173
+ photosWithTagsCount: ((_b = createClinicData.photosWithTags) == null ? void 0 : _b.length) || 0
5174
+ });
4640
5175
  const clinic = await this.createClinic(createClinicData, adminId);
5176
+ console.log("[CLINIC_SERVICE] Clinic branch created successfully", {
5177
+ clinicId: clinic.id
5178
+ });
4641
5179
  return clinic;
4642
5180
  }
4643
5181
  };
@@ -4759,12 +5297,38 @@ var AuthService = class extends BaseService {
4759
5297
  "Clinic group data is required when creating a new group"
4760
5298
  );
4761
5299
  }
5300
+ console.log("[AUTH] Creating clinic admin first (without group)");
5301
+ const createClinicAdminData = {
5302
+ userRef: firebaseUser.uid,
5303
+ isGroupOwner: true,
5304
+ clinicsManaged: [],
5305
+ contactInfo: contactPerson,
5306
+ roleTitle: data.title,
5307
+ isActive: true
5308
+ // No clinicGroupId yet
5309
+ };
5310
+ let adminProfile;
5311
+ try {
5312
+ adminProfile = await clinicAdminService.createClinicAdmin(
5313
+ createClinicAdminData
5314
+ );
5315
+ console.log("[AUTH] Clinic admin created successfully", {
5316
+ adminId: adminProfile.id
5317
+ });
5318
+ } catch (adminCreationError) {
5319
+ console.error(
5320
+ "[AUTH] Clinic admin creation failed:",
5321
+ adminCreationError
5322
+ );
5323
+ throw adminCreationError;
5324
+ }
4762
5325
  const createClinicGroupData = {
4763
5326
  name: data.clinicGroupData.name,
4764
5327
  hqLocation: data.clinicGroupData.hqLocation,
4765
5328
  contactInfo: data.clinicGroupData.contactInfo,
4766
5329
  contactPerson,
4767
- ownerId: firebaseUser.uid,
5330
+ ownerId: adminProfile.id,
5331
+ // Use admin profile ID, not user UID
4768
5332
  isActive: true,
4769
5333
  logo: data.clinicGroupData.logo || null,
4770
5334
  subscriptionModel: data.clinicGroupData.subscriptionModel || "no_subscription" /* NO_SUBSCRIPTION */
@@ -4772,13 +5336,24 @@ var AuthService = class extends BaseService {
4772
5336
  console.log("[AUTH] Clinic group data prepared", {
4773
5337
  groupName: createClinicGroupData.name
4774
5338
  });
5339
+ let clinicGroup;
4775
5340
  try {
4776
- await clinicGroupService.createClinicGroup(
5341
+ clinicGroup = await clinicGroupService.createClinicGroup(
4777
5342
  createClinicGroupData,
4778
- firebaseUser.uid,
4779
- true
5343
+ adminProfile.id,
5344
+ // Use admin profile ID, not user UID
5345
+ false
5346
+ // This is not a default group since we're providing complete data
4780
5347
  );
4781
- console.log("[AUTH] Clinic group created successfully");
5348
+ console.log("[AUTH] Clinic group created successfully", {
5349
+ groupId: clinicGroup.id
5350
+ });
5351
+ console.log("[AUTH] Updating admin with clinic group ID");
5352
+ await clinicAdminService.updateClinicAdmin(adminProfile.id, {
5353
+ // Use admin profile ID, not user UID
5354
+ clinicGroupId: clinicGroup.id
5355
+ });
5356
+ console.log("[AUTH] Admin updated with clinic group ID successfully");
4782
5357
  } catch (groupCreationError) {
4783
5358
  console.error(
4784
5359
  "[AUTH] Clinic group creation failed:",
@@ -4851,9 +5426,14 @@ var AuthService = class extends BaseService {
4851
5426
  roleTitle: data.title,
4852
5427
  isActive: true
4853
5428
  };
5429
+ let adminProfile;
4854
5430
  try {
4855
- await clinicAdminService.createClinicAdmin(createClinicAdminData);
4856
- console.log("[AUTH] Clinic admin created successfully");
5431
+ adminProfile = await clinicAdminService.createClinicAdmin(
5432
+ createClinicAdminData
5433
+ );
5434
+ console.log("[AUTH] Clinic admin created successfully", {
5435
+ adminId: adminProfile.id
5436
+ });
4857
5437
  } catch (adminCreationError) {
4858
5438
  console.error(
4859
5439
  "[AUTH] Clinic admin creation failed:",