@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.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
@@ -3819,23 +3831,49 @@ async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdm
3819
3831
  }
3820
3832
  const now = import_firestore15.Timestamp.now();
3821
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;
3822
3835
  console.log("[CLINIC_GROUP] Logo value:", {
3823
3836
  logoValue: validatedData.logo,
3824
3837
  logoType: validatedData.logo === null ? "null" : typeof validatedData.logo
3825
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 });
3826
3847
  const groupData = {
3827
3848
  ...validatedData,
3828
- 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
3829
3853
  description: isDefault ? void 0 : validatedData.description || void 0,
3830
3854
  hqLocation: {
3831
- ...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,
3832
3861
  geohash: validatedData.hqLocation.geohash || void 0
3833
3862
  },
3834
3863
  contactInfo: {
3835
- ...validatedData.contactInfo,
3864
+ email: validatedData.contactInfo.email || "",
3865
+ phoneNumber: validatedData.contactInfo.phoneNumber || "",
3836
3866
  alternativePhoneNumber: isDefault ? void 0 : validatedData.contactInfo.alternativePhoneNumber || void 0,
3837
3867
  website: isDefault ? void 0 : validatedData.contactInfo.website || void 0
3838
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 */,
3839
3877
  clinics: [],
3840
3878
  clinicsInfo: [],
3841
3879
  admins: [ownerId],
@@ -3923,35 +3961,75 @@ async function getAllActiveGroups(db) {
3923
3961
  const querySnapshot = await (0, import_firestore15.getDocs)(q);
3924
3962
  return querySnapshot.docs.map((doc14) => doc14.data());
3925
3963
  }
3926
- async function updateClinicGroup(db, groupId, data) {
3964
+ async function updateClinicGroup(db, groupId, data, app) {
3965
+ console.log("[CLINIC_GROUP] Updating clinic group", { groupId });
3927
3966
  const group = await getClinicGroup(db, groupId);
3928
3967
  if (!group) {
3968
+ console.error("[CLINIC_GROUP] Clinic group not found", { groupId });
3929
3969
  throw new Error("Clinic group not found");
3930
3970
  }
3931
- const updatedData = {
3932
- ...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,
3933
3990
  updatedAt: import_firestore15.Timestamp.now()
3934
3991
  };
3992
+ console.log("[CLINIC_GROUP] Updating clinic group in Firestore");
3935
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");
3936
3995
  const updatedGroup = await getClinicGroup(db, groupId);
3937
3996
  if (!updatedGroup) {
3997
+ console.error("[CLINIC_GROUP] Failed to retrieve updated clinic group");
3938
3998
  throw new Error("Failed to retrieve updated clinic group");
3939
3999
  }
3940
4000
  return updatedGroup;
3941
4001
  }
3942
- async function addAdminToGroup(db, groupId, adminId) {
3943
- const group = await getClinicGroup(db, groupId);
3944
- if (!group) {
3945
- throw new Error("Clinic group not found");
3946
- }
3947
- if (group.admins.includes(adminId)) {
3948
- 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;
3949
4030
  }
3950
- await updateClinicGroup(db, groupId, {
3951
- admins: [...group.admins, adminId]
3952
- });
3953
4031
  }
3954
- async function removeAdminFromGroup(db, groupId, adminId) {
4032
+ async function removeAdminFromGroup(db, groupId, adminId, app) {
3955
4033
  const group = await getClinicGroup(db, groupId);
3956
4034
  if (!group) {
3957
4035
  throw new Error("Clinic group not found");
@@ -3962,21 +4040,30 @@ async function removeAdminFromGroup(db, groupId, adminId) {
3962
4040
  if (!group.admins.includes(adminId)) {
3963
4041
  return;
3964
4042
  }
3965
- await updateClinicGroup(db, groupId, {
3966
- admins: group.admins.filter((id) => id !== adminId)
3967
- });
4043
+ await updateClinicGroup(
4044
+ db,
4045
+ groupId,
4046
+ {
4047
+ admins: group.admins.filter((id) => id !== adminId)
4048
+ },
4049
+ app
4050
+ );
3968
4051
  }
3969
- async function deactivateClinicGroup(db, groupId) {
4052
+ async function deactivateClinicGroup(db, groupId, app) {
3970
4053
  const group = await getClinicGroup(db, groupId);
3971
4054
  if (!group) {
3972
4055
  throw new Error("Clinic group not found");
3973
4056
  }
3974
- await (0, import_firestore15.updateDoc)((0, import_firestore15.doc)(db, CLINIC_GROUPS_COLLECTION, groupId), {
3975
- isActive: false,
3976
- updatedAt: import_firestore15.Timestamp.now()
3977
- });
4057
+ await updateClinicGroup(
4058
+ db,
4059
+ groupId,
4060
+ {
4061
+ isActive: false
4062
+ },
4063
+ app
4064
+ );
3978
4065
  }
3979
- async function createAdminToken(db, groupId, creatorAdminId, data) {
4066
+ async function createAdminToken(db, groupId, creatorAdminId, app, data) {
3980
4067
  const group = await getClinicGroup(db, groupId);
3981
4068
  if (!group) {
3982
4069
  throw new Error("Clinic group not found");
@@ -3997,12 +4084,17 @@ async function createAdminToken(db, groupId, creatorAdminId, data) {
3997
4084
  createdAt: now,
3998
4085
  expiresAt
3999
4086
  };
4000
- await updateClinicGroup(db, groupId, {
4001
- adminTokens: [...group.adminTokens, token]
4002
- });
4087
+ await updateClinicGroup(
4088
+ db,
4089
+ groupId,
4090
+ {
4091
+ adminTokens: [...group.adminTokens, token]
4092
+ },
4093
+ app
4094
+ );
4003
4095
  return token;
4004
4096
  }
4005
- async function verifyAndUseAdminToken(db, groupId, token, userRef) {
4097
+ async function verifyAndUseAdminToken(db, groupId, token, userRef, app) {
4006
4098
  const group = await getClinicGroup(db, groupId);
4007
4099
  if (!group) {
4008
4100
  throw new Error("Clinic group not found");
@@ -4019,9 +4111,14 @@ async function verifyAndUseAdminToken(db, groupId, token, userRef) {
4019
4111
  const updatedTokens2 = group.adminTokens.map(
4020
4112
  (t) => t.id === adminToken.id ? { ...t, status: "expired" /* EXPIRED */ } : t
4021
4113
  );
4022
- await updateClinicGroup(db, groupId, {
4023
- adminTokens: updatedTokens2
4024
- });
4114
+ await updateClinicGroup(
4115
+ db,
4116
+ groupId,
4117
+ {
4118
+ adminTokens: updatedTokens2
4119
+ },
4120
+ app
4121
+ );
4025
4122
  throw new Error("Admin token has expired");
4026
4123
  }
4027
4124
  const updatedTokens = group.adminTokens.map(
@@ -4031,12 +4128,17 @@ async function verifyAndUseAdminToken(db, groupId, token, userRef) {
4031
4128
  usedByUserRef: userRef
4032
4129
  } : t
4033
4130
  );
4034
- await updateClinicGroup(db, groupId, {
4035
- adminTokens: updatedTokens
4036
- });
4131
+ await updateClinicGroup(
4132
+ db,
4133
+ groupId,
4134
+ {
4135
+ adminTokens: updatedTokens
4136
+ },
4137
+ app
4138
+ );
4037
4139
  return true;
4038
4140
  }
4039
- async function deleteAdminToken(db, groupId, tokenId, adminId) {
4141
+ async function deleteAdminToken(db, groupId, tokenId, adminId, app) {
4040
4142
  const group = await getClinicGroup(db, groupId);
4041
4143
  if (!group) {
4042
4144
  throw new Error("Clinic group not found");
@@ -4045,11 +4147,16 @@ async function deleteAdminToken(db, groupId, tokenId, adminId) {
4045
4147
  throw new Error("Admin does not belong to this clinic group");
4046
4148
  }
4047
4149
  const updatedTokens = group.adminTokens.filter((t) => t.id !== tokenId);
4048
- await updateClinicGroup(db, groupId, {
4049
- adminTokens: updatedTokens
4050
- });
4150
+ await updateClinicGroup(
4151
+ db,
4152
+ groupId,
4153
+ {
4154
+ adminTokens: updatedTokens
4155
+ },
4156
+ app
4157
+ );
4051
4158
  }
4052
- async function getActiveAdminTokens(db, groupId, adminId) {
4159
+ async function getActiveAdminTokens(db, groupId, adminId, app) {
4053
4160
  const group = await getClinicGroup(db, groupId);
4054
4161
  if (!group) {
4055
4162
  throw new Error("Clinic group not found");
@@ -4075,7 +4182,8 @@ var ClinicGroupService = class extends BaseService {
4075
4182
  data,
4076
4183
  ownerId,
4077
4184
  isDefault,
4078
- this.clinicAdminService
4185
+ this.clinicAdminService,
4186
+ this.app
4079
4187
  );
4080
4188
  }
4081
4189
  /**
@@ -4094,25 +4202,35 @@ var ClinicGroupService = class extends BaseService {
4094
4202
  * Ažurira grupaciju klinika
4095
4203
  */
4096
4204
  async updateClinicGroup(groupId, data) {
4097
- return updateClinicGroup(this.db, groupId, data);
4205
+ return updateClinicGroup(this.db, groupId, data, this.app);
4098
4206
  }
4099
4207
  /**
4100
4208
  * Dodaje admina u grupaciju
4101
4209
  */
4102
4210
  async addAdminToGroup(groupId, adminId) {
4103
- return addAdminToGroup(this.db, groupId, adminId);
4211
+ return addAdminToGroup(
4212
+ this.db,
4213
+ groupId,
4214
+ adminId,
4215
+ this.app
4216
+ );
4104
4217
  }
4105
4218
  /**
4106
4219
  * Uklanja admina iz grupacije
4107
4220
  */
4108
4221
  async removeAdminFromGroup(groupId, adminId) {
4109
- return removeAdminFromGroup(this.db, groupId, adminId);
4222
+ return removeAdminFromGroup(
4223
+ this.db,
4224
+ groupId,
4225
+ adminId,
4226
+ this.app
4227
+ );
4110
4228
  }
4111
4229
  /**
4112
4230
  * Deaktivira grupaciju klinika
4113
4231
  */
4114
4232
  async deactivateClinicGroup(groupId) {
4115
- return deactivateClinicGroup(this.db, groupId);
4233
+ return deactivateClinicGroup(this.db, groupId, this.app);
4116
4234
  }
4117
4235
  /**
4118
4236
  * Sets up additional clinic group information after initial creation
@@ -4122,18 +4240,45 @@ var ClinicGroupService = class extends BaseService {
4122
4240
  * @returns The updated clinic group
4123
4241
  */
4124
4242
  async setupClinicGroup(groupId, setupData) {
4243
+ console.log("[CLINIC_GROUP] Setting up clinic group", { groupId });
4125
4244
  const clinicGroup = await this.getClinicGroup(groupId);
4126
4245
  if (!clinicGroup) {
4246
+ console.error("[CLINIC_GROUP] Clinic group not found", { groupId });
4127
4247
  throw new Error(`Clinic group with ID ${groupId} not found`);
4128
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
+ }
4129
4273
  const updateData = {
4130
4274
  languages: setupData.languages,
4131
4275
  practiceType: setupData.practiceType,
4132
4276
  description: setupData.description,
4133
- logo: setupData.logo,
4277
+ logo: logoUrl,
4134
4278
  calendarSyncEnabled: setupData.calendarSyncEnabled,
4135
4279
  autoConfirmAppointments: setupData.autoConfirmAppointments
4136
4280
  };
4281
+ console.log("[CLINIC_GROUP] Updating clinic group with setup data");
4137
4282
  return this.updateClinicGroup(groupId, updateData);
4138
4283
  }
4139
4284
  /**
@@ -4144,6 +4289,7 @@ var ClinicGroupService = class extends BaseService {
4144
4289
  this.db,
4145
4290
  groupId,
4146
4291
  creatorAdminId,
4292
+ this.app,
4147
4293
  data
4148
4294
  );
4149
4295
  }
@@ -4155,7 +4301,8 @@ var ClinicGroupService = class extends BaseService {
4155
4301
  this.db,
4156
4302
  groupId,
4157
4303
  token,
4158
- userRef
4304
+ userRef,
4305
+ this.app
4159
4306
  );
4160
4307
  }
4161
4308
  /**
@@ -4166,14 +4313,20 @@ var ClinicGroupService = class extends BaseService {
4166
4313
  this.db,
4167
4314
  groupId,
4168
4315
  tokenId,
4169
- adminId
4316
+ adminId,
4317
+ this.app
4170
4318
  );
4171
4319
  }
4172
4320
  /**
4173
4321
  * Dohvata aktivne admin tokene
4174
4322
  */
4175
4323
  async getActiveAdminTokens(groupId, adminId) {
4176
- return getActiveAdminTokens(this.db, groupId, adminId);
4324
+ return getActiveAdminTokens(
4325
+ this.db,
4326
+ groupId,
4327
+ adminId,
4328
+ this.app
4329
+ );
4177
4330
  }
4178
4331
  };
4179
4332
 
@@ -4181,44 +4334,193 @@ var ClinicGroupService = class extends BaseService {
4181
4334
  var import_firestore16 = require("firebase/firestore");
4182
4335
  var import_geofire_common3 = require("geofire-common");
4183
4336
  var import_zod14 = require("zod");
4184
- async function createClinic(db, data, creatorAdminId, clinicGroupService, clinicAdminService) {
4185
- const validatedData = createClinicSchema.parse(data);
4186
- const admin = await clinicAdminService.getClinicAdmin(creatorAdminId);
4187
- if (!admin) {
4188
- 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;
4189
4347
  }
4190
- if (admin.clinicGroupId !== validatedData.clinicGroupId) {
4191
- 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;
4192
4367
  }
4193
- const group = await clinicGroupService.getClinicGroup(
4194
- validatedData.clinicGroupId
4195
- );
4196
- if (!group) {
4197
- 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;
4198
4383
  }
4384
+ console.log("[CLINIC] Generating geohash for location");
4199
4385
  if (validatedData.location) {
4200
- validatedData.location.geohash = (0, import_geofire_common3.geohashForLocation)([
4201
- validatedData.location.latitude,
4202
- validatedData.location.longitude
4203
- ]);
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
+ }
4204
4497
  }
4205
4498
  const now = import_firestore16.Timestamp.now();
4499
+ console.log("[CLINIC] Preparing clinic data object");
4206
4500
  const clinicData = {
4207
4501
  ...validatedData,
4208
- id: (0, import_firestore16.doc)((0, import_firestore16.collection)(db, CLINICS_COLLECTION)).id,
4502
+ id: clinicId,
4209
4503
  description: validatedData.description || void 0,
4210
4504
  location: {
4211
- ...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,
4212
4511
  geohash: validatedData.location.geohash || void 0
4213
4512
  },
4214
4513
  contactInfo: {
4215
- ...validatedData.contactInfo,
4514
+ email: validatedData.contactInfo.email || "",
4515
+ phoneNumber: validatedData.contactInfo.phoneNumber || "",
4216
4516
  alternativePhoneNumber: validatedData.contactInfo.alternativePhoneNumber || void 0,
4217
4517
  website: validatedData.contactInfo.website || void 0
4218
4518
  },
4519
+ logo: logoUrl || void 0,
4219
4520
  tags: validatedData.tags || [],
4220
- featuredPhotos: [],
4221
- photos: validatedData.photos || [],
4521
+ featuredPhotos: processedFeaturedPhotos || [],
4522
+ photos: processedPhotos || [],
4523
+ photosWithTags: processedPhotosWithTags,
4222
4524
  doctors: [],
4223
4525
  doctorsInfo: [],
4224
4526
  services: [],
@@ -4233,17 +4535,73 @@ async function createClinic(db, data, creatorAdminId, clinicGroupService, clinic
4233
4535
  isVerified: false
4234
4536
  };
4235
4537
  try {
4236
- clinicSchema.parse(clinicData);
4237
- await (0, import_firestore16.setDoc)((0, import_firestore16.doc)(db, CLINICS_COLLECTION, clinicData.id), clinicData);
4238
- await clinicGroupService.updateClinicGroup(validatedData.clinicGroupId, {
4239
- 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
4240
4594
  });
4241
- await clinicAdminService.addClinicToManaged(creatorAdminId, clinicData.id);
4242
4595
  return clinicData;
4243
4596
  } catch (error) {
4244
4597
  if (error instanceof import_zod14.z.ZodError) {
4598
+ console.error(
4599
+ "[CLINIC] Zod validation error:",
4600
+ JSON.stringify(error.errors, null, 2)
4601
+ );
4245
4602
  throw new Error("Invalid clinic data: " + error.message);
4246
4603
  }
4604
+ console.error("[CLINIC] Unhandled error in createClinic:", error);
4247
4605
  throw error;
4248
4606
  }
4249
4607
  }
@@ -4264,27 +4622,177 @@ async function getClinicsByGroup(db, groupId) {
4264
4622
  const querySnapshot = await (0, import_firestore16.getDocs)(q);
4265
4623
  return querySnapshot.docs.map((doc14) => doc14.data());
4266
4624
  }
4267
- 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 });
4268
4627
  const clinic = await getClinic(db, clinicId);
4269
4628
  if (!clinic) {
4629
+ console.error("[CLINIC] Clinic not found", { clinicId });
4270
4630
  throw new Error("Clinic not found");
4271
4631
  }
4272
- const admin = await clinicAdminService.getClinicAdmin(adminId);
4273
- if (!admin) {
4274
- 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
+ }
4275
4676
  }
4276
- if (!admin.isGroupOwner && !admin.clinicsManaged.includes(clinicId)) {
4277
- 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
+ }
4278
4708
  }
4279
- const updatedData = {
4280
- ...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,
4281
4780
  updatedAt: import_firestore16.Timestamp.now()
4282
4781
  };
4283
- 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
+ }
4284
4790
  const updatedClinic = await getClinic(db, clinicId);
4285
4791
  if (!updatedClinic) {
4792
+ console.error("[CLINIC] Failed to retrieve updated clinic");
4286
4793
  throw new Error("Failed to retrieve updated clinic");
4287
4794
  }
4795
+ console.log("[CLINIC] Clinic update completed successfully");
4288
4796
  return updatedClinic;
4289
4797
  }
4290
4798
  async function deactivateClinic(db, clinicId, adminId, clinicAdminService) {
@@ -4296,7 +4804,8 @@ async function deactivateClinic(db, clinicId, adminId, clinicAdminService) {
4296
4804
  if (!admin) {
4297
4805
  throw new Error("Admin not found");
4298
4806
  }
4299
- 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) {
4300
4809
  throw new Error("Admin does not have permission to deactivate this clinic");
4301
4810
  }
4302
4811
  await (0, import_firestore16.updateDoc)((0, import_firestore16.doc)(db, CLINICS_COLLECTION, clinicId), {
@@ -4339,24 +4848,24 @@ async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGr
4339
4848
 
4340
4849
  // src/services/clinic/utils/review.utils.ts
4341
4850
  var import_firestore17 = require("firebase/firestore");
4342
- async function addReview(db, clinicId, review) {
4343
- const clinic = await getClinic(db, clinicId);
4344
- 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()) {
4345
4855
  throw new Error("Clinic not found");
4346
4856
  }
4857
+ const clinic = clinicSnap.data();
4347
4858
  const now = import_firestore17.Timestamp.now();
4348
4859
  const reviewData = {
4860
+ ...review,
4349
4861
  id: (0, import_firestore17.doc)((0, import_firestore17.collection)(db, "clinic_reviews")).id,
4350
4862
  clinicId,
4351
- patientId: review.patientId,
4352
- rating: review.rating,
4353
- comment: review.comment,
4354
4863
  createdAt: now,
4355
4864
  updatedAt: now,
4356
4865
  isVerified: false
4357
4866
  };
4358
4867
  clinicReviewSchema.parse(reviewData);
4359
- 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);
4360
4869
  const newRating = clinic.rating ? {
4361
4870
  average: (clinic.rating.average * clinic.rating.count + review.rating) / (clinic.rating.count + 1),
4362
4871
  count: clinic.rating.count + 1
@@ -4372,28 +4881,24 @@ async function addReview(db, clinicId, review) {
4372
4881
  ...clinic.reviewsInfo,
4373
4882
  {
4374
4883
  id: reviewData.id,
4375
- rating: review.rating,
4376
- text: review.comment,
4377
- patientId: review.patientId,
4378
- patientName: "Patient",
4379
- // This should be fetched from patient service
4380
- patientPhoto: "",
4381
- // This should be fetched from patient service
4382
- createdAt: now,
4383
- updatedAt: now
4884
+ patientId: reviewData.patientId,
4885
+ rating: reviewData.rating,
4886
+ comment: reviewData.comment,
4887
+ createdAt: reviewData.createdAt
4384
4888
  }
4385
4889
  ]
4386
4890
  },
4387
- clinic.admins[0],
4388
- // Using the first admin for the update
4389
- { getClinicAdmin: async (id) => ({ isGroupOwner: true }) }
4390
- // 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
4391
4896
  );
4392
4897
  return reviewData;
4393
4898
  }
4394
4899
 
4395
4900
  // src/services/clinic/utils/tag.utils.ts
4396
- async function addTags(db, clinicId, adminId, newTags, clinicAdminService) {
4901
+ async function addTags(db, clinicId, adminId, newTags, clinicAdminService, app) {
4397
4902
  const clinic = await getClinic(db, clinicId);
4398
4903
  if (!clinic) {
4399
4904
  throw new Error("Clinic not found");
@@ -4402,7 +4907,8 @@ async function addTags(db, clinicId, adminId, newTags, clinicAdminService) {
4402
4907
  if (!admin) {
4403
4908
  throw new Error("Admin not found");
4404
4909
  }
4405
- 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) {
4406
4912
  throw new Error("Admin does not have permission to update this clinic");
4407
4913
  }
4408
4914
  const updatedTags = [.../* @__PURE__ */ new Set([...clinic.tags, ...newTags.tags || []])];
@@ -4413,10 +4919,11 @@ async function addTags(db, clinicId, adminId, newTags, clinicAdminService) {
4413
4919
  tags: updatedTags
4414
4920
  },
4415
4921
  adminId,
4416
- clinicAdminService
4922
+ clinicAdminService,
4923
+ app
4417
4924
  );
4418
4925
  }
4419
- async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminService) {
4926
+ async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminService, app) {
4420
4927
  const clinic = await getClinic(db, clinicId);
4421
4928
  if (!clinic) {
4422
4929
  throw new Error("Clinic not found");
@@ -4425,14 +4932,12 @@ async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminServic
4425
4932
  if (!admin) {
4426
4933
  throw new Error("Admin not found");
4427
4934
  }
4428
- 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) {
4429
4937
  throw new Error("Admin does not have permission to update this clinic");
4430
4938
  }
4431
4939
  const updatedTags = clinic.tags.filter(
4432
- (tag) => {
4433
- var _a;
4434
- return !((_a = tagsToRemove.tags) == null ? void 0 : _a.includes(tag));
4435
- }
4940
+ (tag) => !tagsToRemove.tags || !tagsToRemove.tags.includes(tag)
4436
4941
  );
4437
4942
  return updateClinic(
4438
4943
  db,
@@ -4441,7 +4946,8 @@ async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminServic
4441
4946
  tags: updatedTags
4442
4947
  },
4443
4948
  adminId,
4444
- clinicAdminService
4949
+ clinicAdminService,
4950
+ app
4445
4951
  );
4446
4952
  }
4447
4953
 
@@ -4511,7 +5017,8 @@ var ClinicService = class extends BaseService {
4511
5017
  data,
4512
5018
  creatorAdminId,
4513
5019
  this.clinicGroupService,
4514
- this.clinicAdminService
5020
+ this.clinicAdminService,
5021
+ this.app
4515
5022
  );
4516
5023
  }
4517
5024
  /**
@@ -4546,14 +5053,15 @@ var ClinicService = class extends BaseService {
4546
5053
  clinicId,
4547
5054
  data,
4548
5055
  adminId,
4549
- this.clinicAdminService
5056
+ this.clinicAdminService,
5057
+ this.app
4550
5058
  );
4551
5059
  }
4552
5060
  /**
4553
5061
  * Dodaje recenziju klinici
4554
5062
  */
4555
5063
  async addReview(clinicId, review) {
4556
- return addReview(this.db, clinicId, review);
5064
+ return addReview(this.db, clinicId, review, this.app);
4557
5065
  }
4558
5066
  /**
4559
5067
  * Deaktivira kliniku
@@ -4575,7 +5083,8 @@ var ClinicService = class extends BaseService {
4575
5083
  clinicId,
4576
5084
  adminId,
4577
5085
  newTags,
4578
- this.clinicAdminService
5086
+ this.clinicAdminService,
5087
+ this.app
4579
5088
  );
4580
5089
  }
4581
5090
  /**
@@ -4587,7 +5096,8 @@ var ClinicService = class extends BaseService {
4587
5096
  clinicId,
4588
5097
  adminId,
4589
5098
  tagsToRemove,
4590
- this.clinicAdminService
5099
+ this.clinicAdminService,
5100
+ this.app
4591
5101
  );
4592
5102
  }
4593
5103
  /**
@@ -4622,12 +5132,21 @@ var ClinicService = class extends BaseService {
4622
5132
  * @returns The created clinic
4623
5133
  */
4624
5134
  async createClinicBranch(clinicGroupId, setupData, adminId) {
5135
+ var _a, _b;
5136
+ console.log("[CLINIC_SERVICE] Starting clinic branch creation", {
5137
+ clinicGroupId,
5138
+ adminId
5139
+ });
4625
5140
  const clinicGroup = await this.clinicGroupService.getClinicGroup(
4626
5141
  clinicGroupId
4627
5142
  );
4628
5143
  if (!clinicGroup) {
5144
+ console.error("[CLINIC_SERVICE] Clinic group not found", {
5145
+ clinicGroupId
5146
+ });
4629
5147
  throw new Error(`Clinic group with ID ${clinicGroupId} not found`);
4630
5148
  }
5149
+ console.log("[CLINIC_SERVICE] Clinic group verified");
4631
5150
  const createClinicData = {
4632
5151
  clinicGroupId,
4633
5152
  name: setupData.name,
@@ -4636,8 +5155,8 @@ var ClinicService = class extends BaseService {
4636
5155
  contactInfo: setupData.contactInfo,
4637
5156
  workingHours: setupData.workingHours,
4638
5157
  tags: setupData.tags,
4639
- photos: setupData.photos,
4640
- photosWithTags: setupData.photosWithTags,
5158
+ photos: setupData.photos || [],
5159
+ photosWithTags: setupData.photosWithTags || [],
4641
5160
  doctors: [],
4642
5161
  services: [],
4643
5162
  admins: [adminId],
@@ -4646,7 +5165,17 @@ var ClinicService = class extends BaseService {
4646
5165
  logo: setupData.logo,
4647
5166
  featuredPhotos: setupData.featuredPhotos || []
4648
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
+ });
4649
5175
  const clinic = await this.createClinic(createClinicData, adminId);
5176
+ console.log("[CLINIC_SERVICE] Clinic branch created successfully", {
5177
+ clinicId: clinic.id
5178
+ });
4650
5179
  return clinic;
4651
5180
  }
4652
5181
  };
@@ -4768,7 +5297,7 @@ var AuthService = class extends BaseService {
4768
5297
  "Clinic group data is required when creating a new group"
4769
5298
  );
4770
5299
  }
4771
- console.log("[AUTH] Creating clinic admin first");
5300
+ console.log("[AUTH] Creating clinic admin first (without group)");
4772
5301
  const createClinicAdminData = {
4773
5302
  userRef: firebaseUser.uid,
4774
5303
  isGroupOwner: true,
@@ -4776,10 +5305,16 @@ var AuthService = class extends BaseService {
4776
5305
  contactInfo: contactPerson,
4777
5306
  roleTitle: data.title,
4778
5307
  isActive: true
5308
+ // No clinicGroupId yet
4779
5309
  };
5310
+ let adminProfile;
4780
5311
  try {
4781
- await clinicAdminService.createClinicAdmin(createClinicAdminData);
4782
- console.log("[AUTH] Clinic admin created successfully");
5312
+ adminProfile = await clinicAdminService.createClinicAdmin(
5313
+ createClinicAdminData
5314
+ );
5315
+ console.log("[AUTH] Clinic admin created successfully", {
5316
+ adminId: adminProfile.id
5317
+ });
4783
5318
  } catch (adminCreationError) {
4784
5319
  console.error(
4785
5320
  "[AUTH] Clinic admin creation failed:",
@@ -4792,7 +5327,8 @@ var AuthService = class extends BaseService {
4792
5327
  hqLocation: data.clinicGroupData.hqLocation,
4793
5328
  contactInfo: data.clinicGroupData.contactInfo,
4794
5329
  contactPerson,
4795
- ownerId: firebaseUser.uid,
5330
+ ownerId: adminProfile.id,
5331
+ // Use admin profile ID, not user UID
4796
5332
  isActive: true,
4797
5333
  logo: data.clinicGroupData.logo || null,
4798
5334
  subscriptionModel: data.clinicGroupData.subscriptionModel || "no_subscription" /* NO_SUBSCRIPTION */
@@ -4800,13 +5336,24 @@ var AuthService = class extends BaseService {
4800
5336
  console.log("[AUTH] Clinic group data prepared", {
4801
5337
  groupName: createClinicGroupData.name
4802
5338
  });
5339
+ let clinicGroup;
4803
5340
  try {
4804
- await clinicGroupService.createClinicGroup(
5341
+ clinicGroup = await clinicGroupService.createClinicGroup(
4805
5342
  createClinicGroupData,
4806
- firebaseUser.uid,
4807
- 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
4808
5347
  );
4809
- 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");
4810
5357
  } catch (groupCreationError) {
4811
5358
  console.error(
4812
5359
  "[AUTH] Clinic group creation failed:",
@@ -4879,9 +5426,14 @@ var AuthService = class extends BaseService {
4879
5426
  roleTitle: data.title,
4880
5427
  isActive: true
4881
5428
  };
5429
+ let adminProfile;
4882
5430
  try {
4883
- await clinicAdminService.createClinicAdmin(createClinicAdminData);
4884
- 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
+ });
4885
5437
  } catch (adminCreationError) {
4886
5438
  console.error(
4887
5439
  "[AUTH] Clinic admin creation failed:",