@blackcode_sa/metaestetics-api 1.4.8 → 1.4.10

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