@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.mjs CHANGED
@@ -2375,7 +2375,7 @@ var clinicGroupSchema = z9.object({
2375
2375
  admins: z9.array(z9.string()),
2376
2376
  adminsInfo: z9.array(adminInfoSchema),
2377
2377
  adminTokens: z9.array(adminTokenSchema),
2378
- ownerId: z9.string(),
2378
+ ownerId: z9.string().nullable(),
2379
2379
  createdAt: z9.instanceof(Date).or(z9.instanceof(Timestamp5)),
2380
2380
  // Timestamp
2381
2381
  updatedAt: z9.instanceof(Date).or(z9.instanceof(Timestamp5)),
@@ -2386,7 +2386,8 @@ var clinicGroupSchema = z9.object({
2386
2386
  languages: z9.array(z9.nativeEnum(Language)).optional(),
2387
2387
  subscriptionModel: z9.nativeEnum(SubscriptionModel),
2388
2388
  calendarSyncEnabled: z9.boolean().optional(),
2389
- autoConfirmAppointments: z9.boolean().optional()
2389
+ autoConfirmAppointments: z9.boolean().optional(),
2390
+ businessIdentificationNumber: z9.string().optional().nullable()
2390
2391
  });
2391
2392
  var clinicReviewSchema = z9.object({
2392
2393
  id: z9.string(),
@@ -2451,14 +2452,15 @@ var createClinicGroupSchema = z9.object({
2451
2452
  hqLocation: clinicLocationSchema,
2452
2453
  contactInfo: clinicContactInfoSchema,
2453
2454
  contactPerson: contactPersonSchema,
2454
- ownerId: z9.string(),
2455
+ ownerId: z9.string().nullable(),
2455
2456
  isActive: z9.boolean(),
2456
2457
  logo: z9.string().optional().nullable(),
2457
2458
  practiceType: z9.nativeEnum(PracticeType).optional(),
2458
2459
  languages: z9.array(z9.nativeEnum(Language)).optional(),
2459
2460
  subscriptionModel: z9.nativeEnum(SubscriptionModel).optional().default("no_subscription" /* NO_SUBSCRIPTION */),
2460
2461
  calendarSyncEnabled: z9.boolean().optional(),
2461
- autoConfirmAppointments: z9.boolean().optional()
2462
+ autoConfirmAppointments: z9.boolean().optional(),
2463
+ businessIdentificationNumber: z9.string().optional().nullable()
2462
2464
  });
2463
2465
  var createClinicSchema = z9.object({
2464
2466
  clinicGroupId: z9.string(),
@@ -2485,7 +2487,7 @@ var createClinicSchema = z9.object({
2485
2487
  });
2486
2488
  var createDefaultClinicGroupSchema = z9.object({
2487
2489
  name: z9.string(),
2488
- ownerId: z9.string(),
2490
+ ownerId: z9.string().nullable(),
2489
2491
  contactPerson: contactPersonSchema,
2490
2492
  contactInfo: clinicContactInfoSchema,
2491
2493
  hqLocation: clinicLocationSchema,
@@ -2518,7 +2520,8 @@ var clinicGroupSetupSchema = z9.object({
2518
2520
  description: z9.string(),
2519
2521
  logo: z9.string(),
2520
2522
  calendarSyncEnabled: z9.boolean(),
2521
- autoConfirmAppointments: z9.boolean()
2523
+ autoConfirmAppointments: z9.boolean(),
2524
+ businessIdentificationNumber: z9.string().optional().nullable()
2522
2525
  });
2523
2526
  var clinicBranchSetupSchema = z9.object({
2524
2527
  name: z9.string(),
@@ -2583,45 +2586,7 @@ async function createClinicAdmin(db, data, clinicGroupService) {
2583
2586
  hasGroupId: !!clinicGroupId
2584
2587
  });
2585
2588
  if (validatedData.isGroupOwner && !clinicGroupId) {
2586
- console.log("[CLINIC_ADMIN] Creating default group for owner");
2587
- const defaultGroup = {
2588
- name: `${validatedData.contactInfo.firstName}'s Group`,
2589
- ownerId: validatedData.userRef,
2590
- contactPerson: validatedData.contactInfo,
2591
- contactInfo: {
2592
- email: validatedData.contactInfo.email,
2593
- phoneNumber: validatedData.contactInfo.phoneNumber || ""
2594
- },
2595
- hqLocation: {
2596
- address: "",
2597
- city: "",
2598
- country: "",
2599
- postalCode: "",
2600
- latitude: 0,
2601
- longitude: 0
2602
- },
2603
- isActive: true
2604
- };
2605
- console.log("[CLINIC_ADMIN] Default group data prepared", {
2606
- groupName: defaultGroup.name
2607
- });
2608
- try {
2609
- const clinicGroup = await clinicGroupService.createClinicGroup(
2610
- defaultGroup,
2611
- validatedData.userRef,
2612
- true
2613
- );
2614
- clinicGroupId = clinicGroup.id;
2615
- console.log("[CLINIC_ADMIN] Default group created successfully", {
2616
- groupId: clinicGroupId
2617
- });
2618
- } catch (groupCreationError) {
2619
- console.error(
2620
- "[CLINIC_ADMIN] Error creating default group:",
2621
- groupCreationError
2622
- );
2623
- throw groupCreationError;
2624
- }
2589
+ console.log("[CLINIC_ADMIN] Owner will be assigned to group later");
2625
2590
  } else if (!validatedData.isGroupOwner && !clinicGroupId) {
2626
2591
  console.error("[CLINIC_ADMIN] Missing clinic group ID for non-owner admin");
2627
2592
  throw new Error("Clinic group ID is required for non-owner admins");
@@ -2651,16 +2616,12 @@ async function createClinicAdmin(db, data, clinicGroupService) {
2651
2616
  }
2652
2617
  }
2653
2618
  console.log("[CLINIC_ADMIN] Preparing admin data object");
2654
- if (!clinicGroupId) {
2655
- console.error(
2656
- "[CLINIC_ADMIN] clinicGroupId is undefined, which should not happen at this point"
2657
- );
2658
- throw new Error("clinicGroupId is required but was undefined");
2659
- }
2660
2619
  const adminData = {
2661
- id: validatedData.userRef,
2620
+ id: doc4(collection2(db, CLINIC_ADMINS_COLLECTION)).id,
2621
+ // Generate a new ID for the admin document
2662
2622
  userRef: validatedData.userRef,
2663
- clinicGroupId,
2623
+ clinicGroupId: clinicGroupId || "",
2624
+ // Empty string for now if no group ID
2664
2625
  isGroupOwner: validatedData.isGroupOwner,
2665
2626
  clinicsManaged: [],
2666
2627
  // Uvek krećemo od prazne liste
@@ -3706,6 +3667,65 @@ import {
3706
3667
  } from "firebase/firestore";
3707
3668
  import { geohashForLocation as geohashForLocation2 } from "geofire-common";
3708
3669
  import { z as z13 } from "zod";
3670
+
3671
+ // src/services/clinic/utils/photos.utils.ts
3672
+ import {
3673
+ getStorage as getStorage2,
3674
+ ref as ref2,
3675
+ uploadBytes as uploadBytes2,
3676
+ getDownloadURL as getDownloadURL2,
3677
+ deleteObject as deleteObject2
3678
+ } from "firebase/storage";
3679
+ async function uploadPhoto(photo, entityType, entityId, photoType, app, fileName) {
3680
+ if (!photo || typeof photo !== "string" || !photo.startsWith("data:")) {
3681
+ return photo;
3682
+ }
3683
+ try {
3684
+ console.log(
3685
+ `[PHOTO_UTILS] Uploading ${photoType} for ${entityType}/${entityId}`
3686
+ );
3687
+ const storage = getStorage2(app);
3688
+ const storageFileName = fileName || `${photoType}-${Date.now()}`;
3689
+ const storageRef = ref2(
3690
+ storage,
3691
+ `${entityType}/${entityId}/${storageFileName}`
3692
+ );
3693
+ const base64Data = photo.split(",")[1];
3694
+ const contentType = photo.split(";")[0].split(":")[1];
3695
+ const byteCharacters = atob(base64Data);
3696
+ const byteArrays = [];
3697
+ for (let i = 0; i < byteCharacters.length; i++) {
3698
+ byteArrays.push(byteCharacters.charCodeAt(i));
3699
+ }
3700
+ const blob = new Blob([new Uint8Array(byteArrays)], { type: contentType });
3701
+ await uploadBytes2(storageRef, blob, { contentType });
3702
+ const downloadUrl = await getDownloadURL2(storageRef);
3703
+ console.log(`[PHOTO_UTILS] ${photoType} uploaded successfully`, {
3704
+ downloadUrl
3705
+ });
3706
+ return downloadUrl;
3707
+ } catch (error) {
3708
+ console.error(`[PHOTO_UTILS] Error uploading ${photoType}:`, error);
3709
+ return null;
3710
+ }
3711
+ }
3712
+ async function uploadMultiplePhotos(photos, entityType, entityId, photoType, app) {
3713
+ if (!photos || !Array.isArray(photos) || photos.length === 0) {
3714
+ return [];
3715
+ }
3716
+ const uploadPromises = photos.map(
3717
+ (photo, index) => uploadPhoto(photo, entityType, entityId, `${photoType}-${index}`, app)
3718
+ );
3719
+ try {
3720
+ const results = await Promise.all(uploadPromises);
3721
+ return results.filter((url) => url !== null);
3722
+ } catch (error) {
3723
+ console.error(`[PHOTO_UTILS] Error uploading multiple photos:`, error);
3724
+ return photos.filter((photo) => !photo.startsWith("data:"));
3725
+ }
3726
+ }
3727
+
3728
+ // src/services/clinic/utils/clinic-group.utils.ts
3709
3729
  function generateId() {
3710
3730
  const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
3711
3731
  const timestamp = Date.now().toString(36);
@@ -3715,7 +3735,8 @@ function generateId() {
3715
3735
  ).join("");
3716
3736
  return `${randomPart}-${timestamp}`;
3717
3737
  }
3718
- async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdminService) {
3738
+ async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdminService, app) {
3739
+ var _a, _b, _c, _d, _e;
3719
3740
  console.log("[CLINIC_GROUP] Starting clinic group creation", {
3720
3741
  ownerId,
3721
3742
  isDefault
@@ -3769,23 +3790,49 @@ async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdm
3769
3790
  }
3770
3791
  const now = Timestamp10.now();
3771
3792
  console.log("[CLINIC_GROUP] Preparing clinic group data object");
3793
+ const groupId = doc7(collection5(db, CLINIC_GROUPS_COLLECTION)).id;
3772
3794
  console.log("[CLINIC_GROUP] Logo value:", {
3773
3795
  logoValue: validatedData.logo,
3774
3796
  logoType: validatedData.logo === null ? "null" : typeof validatedData.logo
3775
3797
  });
3798
+ let logoUrl = await uploadPhoto(
3799
+ validatedData.logo || null,
3800
+ "clinic-groups",
3801
+ groupId,
3802
+ "logo",
3803
+ app
3804
+ );
3805
+ console.log("[CLINIC_GROUP] Logo processed", { logoUrl });
3776
3806
  const groupData = {
3777
3807
  ...validatedData,
3778
- id: doc7(collection5(db, CLINIC_GROUPS_COLLECTION)).id,
3808
+ id: groupId,
3809
+ name: validatedData.name,
3810
+ logo: logoUrl,
3811
+ // Use the uploaded logo URL or the original value
3779
3812
  description: isDefault ? void 0 : validatedData.description || void 0,
3780
3813
  hqLocation: {
3781
- ...validatedData.hqLocation,
3814
+ address: validatedData.hqLocation.address || "",
3815
+ city: validatedData.hqLocation.city || "",
3816
+ country: validatedData.hqLocation.country || "",
3817
+ postalCode: validatedData.hqLocation.postalCode || "",
3818
+ latitude: validatedData.hqLocation.latitude || 0,
3819
+ longitude: validatedData.hqLocation.longitude || 0,
3782
3820
  geohash: validatedData.hqLocation.geohash || void 0
3783
3821
  },
3784
3822
  contactInfo: {
3785
- ...validatedData.contactInfo,
3823
+ email: validatedData.contactInfo.email || "",
3824
+ phoneNumber: validatedData.contactInfo.phoneNumber || "",
3786
3825
  alternativePhoneNumber: isDefault ? void 0 : validatedData.contactInfo.alternativePhoneNumber || void 0,
3787
3826
  website: isDefault ? void 0 : validatedData.contactInfo.website || void 0
3788
3827
  },
3828
+ contactPerson: {
3829
+ firstName: ((_a = validatedData.contactPerson) == null ? void 0 : _a.firstName) || "",
3830
+ lastName: ((_b = validatedData.contactPerson) == null ? void 0 : _b.lastName) || "",
3831
+ email: ((_c = validatedData.contactPerson) == null ? void 0 : _c.email) || "",
3832
+ title: ((_d = validatedData.contactPerson) == null ? void 0 : _d.title) || null,
3833
+ phoneNumber: ((_e = validatedData.contactPerson) == null ? void 0 : _e.phoneNumber) || null
3834
+ },
3835
+ subscriptionModel: validatedData.subscriptionModel || "no_subscription" /* NO_SUBSCRIPTION */,
3789
3836
  clinics: [],
3790
3837
  clinicsInfo: [],
3791
3838
  admins: [ownerId],
@@ -3873,35 +3920,75 @@ async function getAllActiveGroups(db) {
3873
3920
  const querySnapshot = await getDocs5(q);
3874
3921
  return querySnapshot.docs.map((doc14) => doc14.data());
3875
3922
  }
3876
- async function updateClinicGroup(db, groupId, data) {
3923
+ async function updateClinicGroup(db, groupId, data, app) {
3924
+ console.log("[CLINIC_GROUP] Updating clinic group", { groupId });
3877
3925
  const group = await getClinicGroup(db, groupId);
3878
3926
  if (!group) {
3927
+ console.error("[CLINIC_GROUP] Clinic group not found", { groupId });
3879
3928
  throw new Error("Clinic group not found");
3880
3929
  }
3881
- const updatedData = {
3882
- ...data,
3930
+ let updatedData = { ...data };
3931
+ if (data.logo && typeof data.logo === "string" && data.logo.startsWith("data:")) {
3932
+ console.log("[CLINIC_GROUP] Processing logo for update");
3933
+ try {
3934
+ const logoUrl = await uploadPhoto(
3935
+ data.logo,
3936
+ "clinic-groups",
3937
+ groupId,
3938
+ "logo",
3939
+ app
3940
+ );
3941
+ console.log("[CLINIC_GROUP] Logo processed for update", { logoUrl });
3942
+ updatedData.logo = logoUrl;
3943
+ } catch (error) {
3944
+ console.error("[CLINIC_GROUP] Error processing logo for update:", error);
3945
+ }
3946
+ }
3947
+ updatedData = {
3948
+ ...updatedData,
3883
3949
  updatedAt: Timestamp10.now()
3884
3950
  };
3951
+ console.log("[CLINIC_GROUP] Updating clinic group in Firestore");
3885
3952
  await updateDoc10(doc7(db, CLINIC_GROUPS_COLLECTION, groupId), updatedData);
3953
+ console.log("[CLINIC_GROUP] Clinic group updated successfully");
3886
3954
  const updatedGroup = await getClinicGroup(db, groupId);
3887
3955
  if (!updatedGroup) {
3956
+ console.error("[CLINIC_GROUP] Failed to retrieve updated clinic group");
3888
3957
  throw new Error("Failed to retrieve updated clinic group");
3889
3958
  }
3890
3959
  return updatedGroup;
3891
3960
  }
3892
- async function addAdminToGroup(db, groupId, adminId) {
3893
- const group = await getClinicGroup(db, groupId);
3894
- if (!group) {
3895
- throw new Error("Clinic group not found");
3896
- }
3897
- if (group.admins.includes(adminId)) {
3898
- return;
3961
+ async function addAdminToGroup(db, groupId, adminId, app) {
3962
+ console.log("[CLINIC_GROUP] Adding admin to group", { groupId, adminId });
3963
+ try {
3964
+ const group = await getClinicGroup(db, groupId);
3965
+ if (!group) {
3966
+ console.error("[CLINIC_GROUP] Clinic group not found", { groupId });
3967
+ throw new Error("Clinic group not found");
3968
+ }
3969
+ if (group.admins.includes(adminId)) {
3970
+ console.log("[CLINIC_GROUP] Admin is already in the group", {
3971
+ adminId,
3972
+ groupId
3973
+ });
3974
+ return;
3975
+ }
3976
+ console.log("[CLINIC_GROUP] Updating group with new admin");
3977
+ await updateClinicGroup(
3978
+ db,
3979
+ groupId,
3980
+ {
3981
+ admins: [...group.admins, adminId]
3982
+ },
3983
+ app
3984
+ );
3985
+ console.log("[CLINIC_GROUP] Admin added to group successfully");
3986
+ } catch (error) {
3987
+ console.error("[CLINIC_GROUP] Error adding admin to group:", error);
3988
+ throw error;
3899
3989
  }
3900
- await updateClinicGroup(db, groupId, {
3901
- admins: [...group.admins, adminId]
3902
- });
3903
3990
  }
3904
- async function removeAdminFromGroup(db, groupId, adminId) {
3991
+ async function removeAdminFromGroup(db, groupId, adminId, app) {
3905
3992
  const group = await getClinicGroup(db, groupId);
3906
3993
  if (!group) {
3907
3994
  throw new Error("Clinic group not found");
@@ -3912,21 +3999,30 @@ async function removeAdminFromGroup(db, groupId, adminId) {
3912
3999
  if (!group.admins.includes(adminId)) {
3913
4000
  return;
3914
4001
  }
3915
- await updateClinicGroup(db, groupId, {
3916
- admins: group.admins.filter((id) => id !== adminId)
3917
- });
4002
+ await updateClinicGroup(
4003
+ db,
4004
+ groupId,
4005
+ {
4006
+ admins: group.admins.filter((id) => id !== adminId)
4007
+ },
4008
+ app
4009
+ );
3918
4010
  }
3919
- async function deactivateClinicGroup(db, groupId) {
4011
+ async function deactivateClinicGroup(db, groupId, app) {
3920
4012
  const group = await getClinicGroup(db, groupId);
3921
4013
  if (!group) {
3922
4014
  throw new Error("Clinic group not found");
3923
4015
  }
3924
- await updateDoc10(doc7(db, CLINIC_GROUPS_COLLECTION, groupId), {
3925
- isActive: false,
3926
- updatedAt: Timestamp10.now()
3927
- });
4016
+ await updateClinicGroup(
4017
+ db,
4018
+ groupId,
4019
+ {
4020
+ isActive: false
4021
+ },
4022
+ app
4023
+ );
3928
4024
  }
3929
- async function createAdminToken(db, groupId, creatorAdminId, data) {
4025
+ async function createAdminToken(db, groupId, creatorAdminId, app, data) {
3930
4026
  const group = await getClinicGroup(db, groupId);
3931
4027
  if (!group) {
3932
4028
  throw new Error("Clinic group not found");
@@ -3947,12 +4043,17 @@ async function createAdminToken(db, groupId, creatorAdminId, data) {
3947
4043
  createdAt: now,
3948
4044
  expiresAt
3949
4045
  };
3950
- await updateClinicGroup(db, groupId, {
3951
- adminTokens: [...group.adminTokens, token]
3952
- });
4046
+ await updateClinicGroup(
4047
+ db,
4048
+ groupId,
4049
+ {
4050
+ adminTokens: [...group.adminTokens, token]
4051
+ },
4052
+ app
4053
+ );
3953
4054
  return token;
3954
4055
  }
3955
- async function verifyAndUseAdminToken(db, groupId, token, userRef) {
4056
+ async function verifyAndUseAdminToken(db, groupId, token, userRef, app) {
3956
4057
  const group = await getClinicGroup(db, groupId);
3957
4058
  if (!group) {
3958
4059
  throw new Error("Clinic group not found");
@@ -3969,9 +4070,14 @@ async function verifyAndUseAdminToken(db, groupId, token, userRef) {
3969
4070
  const updatedTokens2 = group.adminTokens.map(
3970
4071
  (t) => t.id === adminToken.id ? { ...t, status: "expired" /* EXPIRED */ } : t
3971
4072
  );
3972
- await updateClinicGroup(db, groupId, {
3973
- adminTokens: updatedTokens2
3974
- });
4073
+ await updateClinicGroup(
4074
+ db,
4075
+ groupId,
4076
+ {
4077
+ adminTokens: updatedTokens2
4078
+ },
4079
+ app
4080
+ );
3975
4081
  throw new Error("Admin token has expired");
3976
4082
  }
3977
4083
  const updatedTokens = group.adminTokens.map(
@@ -3981,12 +4087,17 @@ async function verifyAndUseAdminToken(db, groupId, token, userRef) {
3981
4087
  usedByUserRef: userRef
3982
4088
  } : t
3983
4089
  );
3984
- await updateClinicGroup(db, groupId, {
3985
- adminTokens: updatedTokens
3986
- });
4090
+ await updateClinicGroup(
4091
+ db,
4092
+ groupId,
4093
+ {
4094
+ adminTokens: updatedTokens
4095
+ },
4096
+ app
4097
+ );
3987
4098
  return true;
3988
4099
  }
3989
- async function deleteAdminToken(db, groupId, tokenId, adminId) {
4100
+ async function deleteAdminToken(db, groupId, tokenId, adminId, app) {
3990
4101
  const group = await getClinicGroup(db, groupId);
3991
4102
  if (!group) {
3992
4103
  throw new Error("Clinic group not found");
@@ -3995,11 +4106,16 @@ async function deleteAdminToken(db, groupId, tokenId, adminId) {
3995
4106
  throw new Error("Admin does not belong to this clinic group");
3996
4107
  }
3997
4108
  const updatedTokens = group.adminTokens.filter((t) => t.id !== tokenId);
3998
- await updateClinicGroup(db, groupId, {
3999
- adminTokens: updatedTokens
4000
- });
4109
+ await updateClinicGroup(
4110
+ db,
4111
+ groupId,
4112
+ {
4113
+ adminTokens: updatedTokens
4114
+ },
4115
+ app
4116
+ );
4001
4117
  }
4002
- async function getActiveAdminTokens(db, groupId, adminId) {
4118
+ async function getActiveAdminTokens(db, groupId, adminId, app) {
4003
4119
  const group = await getClinicGroup(db, groupId);
4004
4120
  if (!group) {
4005
4121
  throw new Error("Clinic group not found");
@@ -4025,7 +4141,8 @@ var ClinicGroupService = class extends BaseService {
4025
4141
  data,
4026
4142
  ownerId,
4027
4143
  isDefault,
4028
- this.clinicAdminService
4144
+ this.clinicAdminService,
4145
+ this.app
4029
4146
  );
4030
4147
  }
4031
4148
  /**
@@ -4044,25 +4161,35 @@ var ClinicGroupService = class extends BaseService {
4044
4161
  * Ažurira grupaciju klinika
4045
4162
  */
4046
4163
  async updateClinicGroup(groupId, data) {
4047
- return updateClinicGroup(this.db, groupId, data);
4164
+ return updateClinicGroup(this.db, groupId, data, this.app);
4048
4165
  }
4049
4166
  /**
4050
4167
  * Dodaje admina u grupaciju
4051
4168
  */
4052
4169
  async addAdminToGroup(groupId, adminId) {
4053
- return addAdminToGroup(this.db, groupId, adminId);
4170
+ return addAdminToGroup(
4171
+ this.db,
4172
+ groupId,
4173
+ adminId,
4174
+ this.app
4175
+ );
4054
4176
  }
4055
4177
  /**
4056
4178
  * Uklanja admina iz grupacije
4057
4179
  */
4058
4180
  async removeAdminFromGroup(groupId, adminId) {
4059
- return removeAdminFromGroup(this.db, groupId, adminId);
4181
+ return removeAdminFromGroup(
4182
+ this.db,
4183
+ groupId,
4184
+ adminId,
4185
+ this.app
4186
+ );
4060
4187
  }
4061
4188
  /**
4062
4189
  * Deaktivira grupaciju klinika
4063
4190
  */
4064
4191
  async deactivateClinicGroup(groupId) {
4065
- return deactivateClinicGroup(this.db, groupId);
4192
+ return deactivateClinicGroup(this.db, groupId, this.app);
4066
4193
  }
4067
4194
  /**
4068
4195
  * Sets up additional clinic group information after initial creation
@@ -4072,18 +4199,45 @@ var ClinicGroupService = class extends BaseService {
4072
4199
  * @returns The updated clinic group
4073
4200
  */
4074
4201
  async setupClinicGroup(groupId, setupData) {
4202
+ console.log("[CLINIC_GROUP] Setting up clinic group", { groupId });
4075
4203
  const clinicGroup = await this.getClinicGroup(groupId);
4076
4204
  if (!clinicGroup) {
4205
+ console.error("[CLINIC_GROUP] Clinic group not found", { groupId });
4077
4206
  throw new Error(`Clinic group with ID ${groupId} not found`);
4078
4207
  }
4208
+ let logoUrl = setupData.logo;
4209
+ if (logoUrl && typeof logoUrl === "string" && logoUrl.startsWith("data:")) {
4210
+ console.log("[CLINIC_GROUP] Processing logo in setupClinicGroup");
4211
+ try {
4212
+ const uploadedLogoUrl = await uploadPhoto(
4213
+ logoUrl,
4214
+ "clinic-groups",
4215
+ groupId,
4216
+ "logo",
4217
+ this.app
4218
+ );
4219
+ console.log("[CLINIC_GROUP] Logo processed in setupClinicGroup", {
4220
+ uploadedLogoUrl
4221
+ });
4222
+ if (uploadedLogoUrl !== null) {
4223
+ logoUrl = uploadedLogoUrl;
4224
+ }
4225
+ } catch (error) {
4226
+ console.error(
4227
+ "[CLINIC_GROUP] Error processing logo in setupClinicGroup:",
4228
+ error
4229
+ );
4230
+ }
4231
+ }
4079
4232
  const updateData = {
4080
4233
  languages: setupData.languages,
4081
4234
  practiceType: setupData.practiceType,
4082
4235
  description: setupData.description,
4083
- logo: setupData.logo,
4236
+ logo: logoUrl,
4084
4237
  calendarSyncEnabled: setupData.calendarSyncEnabled,
4085
4238
  autoConfirmAppointments: setupData.autoConfirmAppointments
4086
4239
  };
4240
+ console.log("[CLINIC_GROUP] Updating clinic group with setup data");
4087
4241
  return this.updateClinicGroup(groupId, updateData);
4088
4242
  }
4089
4243
  /**
@@ -4094,6 +4248,7 @@ var ClinicGroupService = class extends BaseService {
4094
4248
  this.db,
4095
4249
  groupId,
4096
4250
  creatorAdminId,
4251
+ this.app,
4097
4252
  data
4098
4253
  );
4099
4254
  }
@@ -4105,7 +4260,8 @@ var ClinicGroupService = class extends BaseService {
4105
4260
  this.db,
4106
4261
  groupId,
4107
4262
  token,
4108
- userRef
4263
+ userRef,
4264
+ this.app
4109
4265
  );
4110
4266
  }
4111
4267
  /**
@@ -4116,14 +4272,20 @@ var ClinicGroupService = class extends BaseService {
4116
4272
  this.db,
4117
4273
  groupId,
4118
4274
  tokenId,
4119
- adminId
4275
+ adminId,
4276
+ this.app
4120
4277
  );
4121
4278
  }
4122
4279
  /**
4123
4280
  * Dohvata aktivne admin tokene
4124
4281
  */
4125
4282
  async getActiveAdminTokens(groupId, adminId) {
4126
- return getActiveAdminTokens(this.db, groupId, adminId);
4283
+ return getActiveAdminTokens(
4284
+ this.db,
4285
+ groupId,
4286
+ adminId,
4287
+ this.app
4288
+ );
4127
4289
  }
4128
4290
  };
4129
4291
 
@@ -4141,44 +4303,193 @@ import {
4141
4303
  } from "firebase/firestore";
4142
4304
  import { geohashForLocation as geohashForLocation3 } from "geofire-common";
4143
4305
  import { z as z14 } from "zod";
4144
- async function createClinic(db, data, creatorAdminId, clinicGroupService, clinicAdminService) {
4145
- const validatedData = createClinicSchema.parse(data);
4146
- const admin = await clinicAdminService.getClinicAdmin(creatorAdminId);
4147
- if (!admin) {
4148
- throw new Error("Admin not found");
4306
+ async function createClinic(db, data, creatorAdminId, clinicGroupService, clinicAdminService, app) {
4307
+ var _a;
4308
+ console.log("[CLINIC] Starting clinic creation", { creatorAdminId });
4309
+ console.log("[CLINIC] Input data:", JSON.stringify(data, null, 2));
4310
+ try {
4311
+ const validatedData2 = createClinicSchema.parse(data);
4312
+ console.log("[CLINIC] Data validation passed");
4313
+ } catch (validationError) {
4314
+ console.error("[CLINIC] Data validation failed:", validationError);
4315
+ throw validationError;
4149
4316
  }
4150
- if (admin.clinicGroupId !== validatedData.clinicGroupId) {
4151
- throw new Error("Admin does not belong to this clinic group");
4317
+ const validatedData = createClinicSchema.parse(data);
4318
+ try {
4319
+ console.log("[CLINIC] Checking if admin exists and belongs to group");
4320
+ const admin = await clinicAdminService.getClinicAdmin(creatorAdminId);
4321
+ if (!admin) {
4322
+ console.error("[CLINIC] Admin not found", { creatorAdminId });
4323
+ throw new Error("Admin not found");
4324
+ }
4325
+ if (admin.clinicGroupId !== validatedData.clinicGroupId) {
4326
+ console.error("[CLINIC] Admin does not belong to this clinic group", {
4327
+ adminGroupId: admin.clinicGroupId,
4328
+ requestedGroupId: validatedData.clinicGroupId
4329
+ });
4330
+ throw new Error("Admin does not belong to this clinic group");
4331
+ }
4332
+ console.log("[CLINIC] Admin verified");
4333
+ } catch (adminError) {
4334
+ console.error("[CLINIC] Error verifying admin:", adminError);
4335
+ throw adminError;
4152
4336
  }
4153
- const group = await clinicGroupService.getClinicGroup(
4154
- validatedData.clinicGroupId
4155
- );
4156
- if (!group) {
4157
- throw new Error("Clinic group not found");
4337
+ try {
4338
+ console.log("[CLINIC] Checking if clinic group exists");
4339
+ const group = await clinicGroupService.getClinicGroup(
4340
+ validatedData.clinicGroupId
4341
+ );
4342
+ if (!group) {
4343
+ console.error("[CLINIC] Clinic group not found", {
4344
+ groupId: validatedData.clinicGroupId
4345
+ });
4346
+ throw new Error("Clinic group not found");
4347
+ }
4348
+ console.log("[CLINIC] Clinic group verified");
4349
+ } catch (groupError) {
4350
+ console.error("[CLINIC] Error verifying clinic group:", groupError);
4351
+ throw groupError;
4158
4352
  }
4353
+ console.log("[CLINIC] Generating geohash for location");
4159
4354
  if (validatedData.location) {
4160
- validatedData.location.geohash = geohashForLocation3([
4161
- validatedData.location.latitude,
4162
- validatedData.location.longitude
4163
- ]);
4355
+ try {
4356
+ validatedData.location.geohash = geohashForLocation3([
4357
+ validatedData.location.latitude,
4358
+ validatedData.location.longitude
4359
+ ]);
4360
+ console.log("[CLINIC] Geohash generated successfully", {
4361
+ geohash: validatedData.location.geohash
4362
+ });
4363
+ } catch (geohashError) {
4364
+ console.error("[CLINIC] Error generating geohash:", geohashError);
4365
+ throw geohashError;
4366
+ }
4367
+ }
4368
+ const clinicId = doc8(collection6(db, CLINICS_COLLECTION)).id;
4369
+ console.log("[CLINIC] Generated clinic ID:", clinicId);
4370
+ console.log("[CLINIC] Processing photos");
4371
+ let logoUrl = null;
4372
+ if (validatedData.logo) {
4373
+ console.log("[CLINIC] Processing logo");
4374
+ try {
4375
+ logoUrl = await uploadPhoto(
4376
+ validatedData.logo,
4377
+ "clinics",
4378
+ clinicId,
4379
+ "logo",
4380
+ app
4381
+ );
4382
+ console.log("[CLINIC] Logo processed", { logoUrl });
4383
+ } catch (logoError) {
4384
+ console.error("[CLINIC] Error processing logo:", logoError);
4385
+ }
4386
+ }
4387
+ let processedPhotos = [];
4388
+ if (validatedData.photos && validatedData.photos.length > 0) {
4389
+ console.log("[CLINIC] Processing regular photos");
4390
+ try {
4391
+ processedPhotos = await uploadMultiplePhotos(
4392
+ validatedData.photos,
4393
+ "clinics",
4394
+ clinicId,
4395
+ "photo",
4396
+ app
4397
+ );
4398
+ console.log("[CLINIC] Regular photos processed", {
4399
+ count: processedPhotos.length
4400
+ });
4401
+ } catch (photosError) {
4402
+ console.error("[CLINIC] Error processing regular photos:", photosError);
4403
+ processedPhotos = validatedData.photos.filter(
4404
+ (photo) => !photo.startsWith("data:")
4405
+ );
4406
+ }
4407
+ }
4408
+ let processedFeaturedPhotos = [];
4409
+ if (validatedData.featuredPhotos && validatedData.featuredPhotos.length > 0) {
4410
+ console.log("[CLINIC] Processing featured photos");
4411
+ try {
4412
+ processedFeaturedPhotos = await uploadMultiplePhotos(
4413
+ validatedData.featuredPhotos,
4414
+ "clinics",
4415
+ clinicId,
4416
+ "featured",
4417
+ app
4418
+ );
4419
+ console.log("[CLINIC] Featured photos processed", {
4420
+ count: processedFeaturedPhotos.length
4421
+ });
4422
+ } catch (featuredError) {
4423
+ console.error(
4424
+ "[CLINIC] Error processing featured photos:",
4425
+ featuredError
4426
+ );
4427
+ processedFeaturedPhotos = validatedData.featuredPhotos.filter(
4428
+ (photo) => !photo.startsWith("data:")
4429
+ );
4430
+ }
4431
+ }
4432
+ let processedPhotosWithTags = validatedData.photosWithTags || [];
4433
+ if (processedPhotosWithTags.length > 0) {
4434
+ console.log("[CLINIC] Processing photos with tags");
4435
+ try {
4436
+ const updatedPhotosWithTags = [];
4437
+ for (const photoWithTag of processedPhotosWithTags) {
4438
+ if (photoWithTag.url && photoWithTag.url.startsWith("data:")) {
4439
+ const uploadedUrl = await uploadPhoto(
4440
+ photoWithTag.url,
4441
+ "clinics",
4442
+ clinicId,
4443
+ `tagged-${photoWithTag.tag}`,
4444
+ app
4445
+ );
4446
+ if (uploadedUrl) {
4447
+ updatedPhotosWithTags.push({
4448
+ url: uploadedUrl,
4449
+ tag: photoWithTag.tag
4450
+ });
4451
+ }
4452
+ } else {
4453
+ updatedPhotosWithTags.push(photoWithTag);
4454
+ }
4455
+ }
4456
+ processedPhotosWithTags = updatedPhotosWithTags;
4457
+ console.log("[CLINIC] Photos with tags processed", {
4458
+ count: processedPhotosWithTags.length
4459
+ });
4460
+ } catch (tagsError) {
4461
+ console.error("[CLINIC] Error processing photos with tags:", tagsError);
4462
+ processedPhotosWithTags = ((_a = validatedData.photosWithTags) == null ? void 0 : _a.filter(
4463
+ (photo) => !photo.url.startsWith("data:")
4464
+ )) || [];
4465
+ }
4164
4466
  }
4165
4467
  const now = Timestamp11.now();
4468
+ console.log("[CLINIC] Preparing clinic data object");
4166
4469
  const clinicData = {
4167
4470
  ...validatedData,
4168
- id: doc8(collection6(db, CLINICS_COLLECTION)).id,
4471
+ id: clinicId,
4169
4472
  description: validatedData.description || void 0,
4170
4473
  location: {
4171
- ...validatedData.location,
4474
+ address: validatedData.location.address || "",
4475
+ city: validatedData.location.city || "",
4476
+ country: validatedData.location.country || "",
4477
+ postalCode: validatedData.location.postalCode || "",
4478
+ latitude: validatedData.location.latitude || 0,
4479
+ longitude: validatedData.location.longitude || 0,
4172
4480
  geohash: validatedData.location.geohash || void 0
4173
4481
  },
4174
4482
  contactInfo: {
4175
- ...validatedData.contactInfo,
4483
+ email: validatedData.contactInfo.email || "",
4484
+ phoneNumber: validatedData.contactInfo.phoneNumber || "",
4176
4485
  alternativePhoneNumber: validatedData.contactInfo.alternativePhoneNumber || void 0,
4177
4486
  website: validatedData.contactInfo.website || void 0
4178
4487
  },
4488
+ logo: logoUrl || void 0,
4179
4489
  tags: validatedData.tags || [],
4180
- featuredPhotos: [],
4181
- photos: validatedData.photos || [],
4490
+ featuredPhotos: processedFeaturedPhotos || [],
4491
+ photos: processedPhotos || [],
4492
+ photosWithTags: processedPhotosWithTags,
4182
4493
  doctors: [],
4183
4494
  doctorsInfo: [],
4184
4495
  services: [],
@@ -4193,17 +4504,73 @@ async function createClinic(db, data, creatorAdminId, clinicGroupService, clinic
4193
4504
  isVerified: false
4194
4505
  };
4195
4506
  try {
4196
- clinicSchema.parse(clinicData);
4197
- await setDoc10(doc8(db, CLINICS_COLLECTION, clinicData.id), clinicData);
4198
- await clinicGroupService.updateClinicGroup(validatedData.clinicGroupId, {
4199
- clinics: [...group.clinics, clinicData.id]
4507
+ console.log("[CLINIC] Validating complete clinic object");
4508
+ try {
4509
+ clinicSchema.parse(clinicData);
4510
+ console.log("[CLINIC] Clinic validation passed");
4511
+ } catch (schemaError) {
4512
+ console.error(
4513
+ "[CLINIC] Clinic validation failed:",
4514
+ JSON.stringify(schemaError, null, 2)
4515
+ );
4516
+ throw schemaError;
4517
+ }
4518
+ console.log("[CLINIC] Saving clinic to Firestore", {
4519
+ clinicId: clinicData.id
4520
+ });
4521
+ try {
4522
+ await setDoc10(doc8(db, CLINICS_COLLECTION, clinicData.id), clinicData);
4523
+ console.log("[CLINIC] Clinic saved successfully");
4524
+ } catch (firestoreError) {
4525
+ console.error("[CLINIC] Error saving to Firestore:", firestoreError);
4526
+ throw firestoreError;
4527
+ }
4528
+ console.log("[CLINIC] Adding clinic to clinic group");
4529
+ try {
4530
+ const group = await clinicGroupService.getClinicGroup(
4531
+ validatedData.clinicGroupId
4532
+ );
4533
+ if (group) {
4534
+ await clinicGroupService.updateClinicGroup(
4535
+ validatedData.clinicGroupId,
4536
+ {
4537
+ clinics: [...group.clinics, clinicData.id]
4538
+ }
4539
+ );
4540
+ console.log("[CLINIC] Clinic added to group successfully");
4541
+ }
4542
+ } catch (groupUpdateError) {
4543
+ console.error("[CLINIC] Error adding clinic to group:", groupUpdateError);
4544
+ }
4545
+ console.log("[CLINIC] Adding clinic to admin's managed clinics");
4546
+ try {
4547
+ await clinicAdminService.addClinicToManaged(
4548
+ creatorAdminId,
4549
+ clinicData.id
4550
+ );
4551
+ console.log(
4552
+ "[CLINIC] Clinic added to admin's managed clinics successfully"
4553
+ );
4554
+ } catch (adminUpdateError) {
4555
+ console.error(
4556
+ "[CLINIC] Error adding clinic to admin's managed clinics:",
4557
+ adminUpdateError
4558
+ );
4559
+ }
4560
+ console.log("[CLINIC] Clinic creation completed successfully", {
4561
+ clinicId: clinicData.id,
4562
+ clinicName: clinicData.name
4200
4563
  });
4201
- await clinicAdminService.addClinicToManaged(creatorAdminId, clinicData.id);
4202
4564
  return clinicData;
4203
4565
  } catch (error) {
4204
4566
  if (error instanceof z14.ZodError) {
4567
+ console.error(
4568
+ "[CLINIC] Zod validation error:",
4569
+ JSON.stringify(error.errors, null, 2)
4570
+ );
4205
4571
  throw new Error("Invalid clinic data: " + error.message);
4206
4572
  }
4573
+ console.error("[CLINIC] Unhandled error in createClinic:", error);
4207
4574
  throw error;
4208
4575
  }
4209
4576
  }
@@ -4224,27 +4591,177 @@ async function getClinicsByGroup(db, groupId) {
4224
4591
  const querySnapshot = await getDocs6(q);
4225
4592
  return querySnapshot.docs.map((doc14) => doc14.data());
4226
4593
  }
4227
- async function updateClinic(db, clinicId, data, adminId, clinicAdminService) {
4594
+ async function updateClinic(db, clinicId, data, adminId, clinicAdminService, app) {
4595
+ console.log("[CLINIC] Starting clinic update", { clinicId, adminId });
4228
4596
  const clinic = await getClinic(db, clinicId);
4229
4597
  if (!clinic) {
4598
+ console.error("[CLINIC] Clinic not found", { clinicId });
4230
4599
  throw new Error("Clinic not found");
4231
4600
  }
4232
- const admin = await clinicAdminService.getClinicAdmin(adminId);
4233
- if (!admin) {
4234
- throw new Error("Admin not found");
4601
+ try {
4602
+ console.log("[CLINIC] Checking admin permissions");
4603
+ const admin = await clinicAdminService.getClinicAdmin(adminId);
4604
+ if (!admin) {
4605
+ console.error("[CLINIC] Admin not found", { adminId });
4606
+ throw new Error("Admin not found");
4607
+ }
4608
+ const hasPermission = admin.isGroupOwner && admin.clinicGroupId === clinic.clinicGroupId || admin.clinicsManaged.includes(clinicId) && clinic.admins && clinic.admins.includes(adminId);
4609
+ if (!hasPermission) {
4610
+ console.error(
4611
+ "[CLINIC] Admin does not have permission to update this clinic",
4612
+ {
4613
+ adminId,
4614
+ clinicId,
4615
+ isGroupOwner: admin.isGroupOwner,
4616
+ clinicsManaged: admin.clinicsManaged,
4617
+ isClinicAdmin: clinic.admins && clinic.admins.includes(adminId)
4618
+ }
4619
+ );
4620
+ throw new Error("Admin does not have permission to update this clinic");
4621
+ }
4622
+ console.log("[CLINIC] Admin permissions verified");
4623
+ } catch (adminError) {
4624
+ console.error("[CLINIC] Error verifying admin permissions:", adminError);
4625
+ throw adminError;
4626
+ }
4627
+ let updatedData = { ...data };
4628
+ if (data.logo && typeof data.logo === "string" && data.logo.startsWith("data:")) {
4629
+ console.log("[CLINIC] Processing logo update");
4630
+ try {
4631
+ const logoUrl = await uploadPhoto(
4632
+ data.logo,
4633
+ "clinics",
4634
+ clinicId,
4635
+ "logo",
4636
+ app
4637
+ );
4638
+ console.log("[CLINIC] Logo update processed", { logoUrl });
4639
+ if (logoUrl !== null) {
4640
+ updatedData.logo = logoUrl;
4641
+ }
4642
+ } catch (logoError) {
4643
+ console.error("[CLINIC] Error processing logo update:", logoError);
4644
+ }
4235
4645
  }
4236
- if (!admin.isGroupOwner && !admin.clinicsManaged.includes(clinicId)) {
4237
- throw new Error("Admin does not have permission to update this clinic");
4646
+ if (data.photos && data.photos.length > 0) {
4647
+ console.log("[CLINIC] Processing regular photos update");
4648
+ try {
4649
+ const dataUrlPhotos = data.photos.filter(
4650
+ (photo) => typeof photo === "string" && photo.startsWith("data:")
4651
+ );
4652
+ const existingPhotos = data.photos.filter(
4653
+ (photo) => typeof photo === "string" && !photo.startsWith("data:")
4654
+ );
4655
+ if (dataUrlPhotos.length > 0) {
4656
+ const uploadedPhotos = await uploadMultiplePhotos(
4657
+ dataUrlPhotos,
4658
+ "clinics",
4659
+ clinicId,
4660
+ "photo",
4661
+ app
4662
+ );
4663
+ console.log("[CLINIC] Regular photos update processed", {
4664
+ count: uploadedPhotos.length
4665
+ });
4666
+ updatedData.photos = [...existingPhotos, ...uploadedPhotos];
4667
+ }
4668
+ } catch (photosError) {
4669
+ console.error(
4670
+ "[CLINIC] Error processing regular photos update:",
4671
+ photosError
4672
+ );
4673
+ updatedData.photos = data.photos.filter(
4674
+ (photo) => typeof photo === "string" && !photo.startsWith("data:")
4675
+ );
4676
+ }
4238
4677
  }
4239
- const updatedData = {
4240
- ...data,
4678
+ if (data.featuredPhotos && data.featuredPhotos.length > 0) {
4679
+ console.log("[CLINIC] Processing featured photos update");
4680
+ try {
4681
+ const dataUrlPhotos = data.featuredPhotos.filter(
4682
+ (photo) => typeof photo === "string" && photo.startsWith("data:")
4683
+ );
4684
+ const existingPhotos = data.featuredPhotos.filter(
4685
+ (photo) => typeof photo === "string" && !photo.startsWith("data:")
4686
+ );
4687
+ if (dataUrlPhotos.length > 0) {
4688
+ const uploadedPhotos = await uploadMultiplePhotos(
4689
+ dataUrlPhotos,
4690
+ "clinics",
4691
+ clinicId,
4692
+ "featured",
4693
+ app
4694
+ );
4695
+ console.log("[CLINIC] Featured photos update processed", {
4696
+ count: uploadedPhotos.length
4697
+ });
4698
+ updatedData.featuredPhotos = [...existingPhotos, ...uploadedPhotos];
4699
+ }
4700
+ } catch (featuredError) {
4701
+ console.error(
4702
+ "[CLINIC] Error processing featured photos update:",
4703
+ featuredError
4704
+ );
4705
+ updatedData.featuredPhotos = data.featuredPhotos.filter(
4706
+ (photo) => typeof photo === "string" && !photo.startsWith("data:")
4707
+ );
4708
+ }
4709
+ }
4710
+ if (data.photosWithTags && data.photosWithTags.length > 0) {
4711
+ console.log("[CLINIC] Processing photos with tags update");
4712
+ try {
4713
+ const updatedPhotosWithTags = [];
4714
+ for (const photoWithTag of data.photosWithTags) {
4715
+ if (photoWithTag.url && photoWithTag.url.startsWith("data:")) {
4716
+ const uploadedUrl = await uploadPhoto(
4717
+ photoWithTag.url,
4718
+ "clinics",
4719
+ clinicId,
4720
+ `tagged-${photoWithTag.tag}`,
4721
+ app
4722
+ );
4723
+ if (uploadedUrl) {
4724
+ updatedPhotosWithTags.push({
4725
+ url: uploadedUrl,
4726
+ tag: photoWithTag.tag
4727
+ });
4728
+ }
4729
+ } else {
4730
+ updatedPhotosWithTags.push(photoWithTag);
4731
+ }
4732
+ }
4733
+ updatedData.photosWithTags = updatedPhotosWithTags;
4734
+ console.log("[CLINIC] Photos with tags update processed", {
4735
+ count: updatedPhotosWithTags.length
4736
+ });
4737
+ } catch (tagsError) {
4738
+ console.error(
4739
+ "[CLINIC] Error processing photos with tags update:",
4740
+ tagsError
4741
+ );
4742
+ updatedData.photosWithTags = data.photosWithTags.filter(
4743
+ (photo) => !photo.url.startsWith("data:")
4744
+ );
4745
+ }
4746
+ }
4747
+ updatedData = {
4748
+ ...updatedData,
4241
4749
  updatedAt: Timestamp11.now()
4242
4750
  };
4243
- await updateDoc11(doc8(db, CLINICS_COLLECTION, clinicId), updatedData);
4751
+ console.log("[CLINIC] Updating clinic in Firestore");
4752
+ try {
4753
+ await updateDoc11(doc8(db, CLINICS_COLLECTION, clinicId), updatedData);
4754
+ console.log("[CLINIC] Clinic updated successfully");
4755
+ } catch (updateError) {
4756
+ console.error("[CLINIC] Error updating clinic in Firestore:", updateError);
4757
+ throw updateError;
4758
+ }
4244
4759
  const updatedClinic = await getClinic(db, clinicId);
4245
4760
  if (!updatedClinic) {
4761
+ console.error("[CLINIC] Failed to retrieve updated clinic");
4246
4762
  throw new Error("Failed to retrieve updated clinic");
4247
4763
  }
4764
+ console.log("[CLINIC] Clinic update completed successfully");
4248
4765
  return updatedClinic;
4249
4766
  }
4250
4767
  async function deactivateClinic(db, clinicId, adminId, clinicAdminService) {
@@ -4256,7 +4773,8 @@ async function deactivateClinic(db, clinicId, adminId, clinicAdminService) {
4256
4773
  if (!admin) {
4257
4774
  throw new Error("Admin not found");
4258
4775
  }
4259
- if (!admin.isGroupOwner && !admin.clinicsManaged.includes(clinicId)) {
4776
+ const hasPermission = admin.isGroupOwner && admin.clinicGroupId === clinic.clinicGroupId || admin.clinicsManaged.includes(clinicId) && clinic.admins && clinic.admins.includes(adminId);
4777
+ if (!hasPermission) {
4260
4778
  throw new Error("Admin does not have permission to deactivate this clinic");
4261
4779
  }
4262
4780
  await updateDoc11(doc8(db, CLINICS_COLLECTION, clinicId), {
@@ -4301,27 +4819,28 @@ async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGr
4301
4819
  import {
4302
4820
  collection as collection7,
4303
4821
  doc as doc9,
4304
- setDoc as setDoc11,
4305
- Timestamp as Timestamp12
4822
+ Timestamp as Timestamp12,
4823
+ getDoc as getDoc13,
4824
+ addDoc as addDoc2
4306
4825
  } from "firebase/firestore";
4307
- async function addReview(db, clinicId, review) {
4308
- const clinic = await getClinic(db, clinicId);
4309
- if (!clinic) {
4826
+ async function addReview(db, clinicId, review, app) {
4827
+ const clinicRef = doc9(db, "clinics", clinicId);
4828
+ const clinicSnap = await getDoc13(clinicRef);
4829
+ if (!clinicSnap.exists()) {
4310
4830
  throw new Error("Clinic not found");
4311
4831
  }
4832
+ const clinic = clinicSnap.data();
4312
4833
  const now = Timestamp12.now();
4313
4834
  const reviewData = {
4835
+ ...review,
4314
4836
  id: doc9(collection7(db, "clinic_reviews")).id,
4315
4837
  clinicId,
4316
- patientId: review.patientId,
4317
- rating: review.rating,
4318
- comment: review.comment,
4319
4838
  createdAt: now,
4320
4839
  updatedAt: now,
4321
4840
  isVerified: false
4322
4841
  };
4323
4842
  clinicReviewSchema.parse(reviewData);
4324
- await setDoc11(doc9(db, "clinic_reviews", reviewData.id), reviewData);
4843
+ await addDoc2(collection7(db, "clinic_reviews"), reviewData);
4325
4844
  const newRating = clinic.rating ? {
4326
4845
  average: (clinic.rating.average * clinic.rating.count + review.rating) / (clinic.rating.count + 1),
4327
4846
  count: clinic.rating.count + 1
@@ -4337,28 +4856,24 @@ async function addReview(db, clinicId, review) {
4337
4856
  ...clinic.reviewsInfo,
4338
4857
  {
4339
4858
  id: reviewData.id,
4340
- rating: review.rating,
4341
- text: review.comment,
4342
- patientId: review.patientId,
4343
- patientName: "Patient",
4344
- // This should be fetched from patient service
4345
- patientPhoto: "",
4346
- // This should be fetched from patient service
4347
- createdAt: now,
4348
- updatedAt: now
4859
+ patientId: reviewData.patientId,
4860
+ rating: reviewData.rating,
4861
+ comment: reviewData.comment,
4862
+ createdAt: reviewData.createdAt
4349
4863
  }
4350
4864
  ]
4351
4865
  },
4352
- clinic.admins[0],
4353
- // Using the first admin for the update
4354
- { getClinicAdmin: async (id) => ({ isGroupOwner: true }) }
4355
- // Mock admin service
4866
+ "system",
4867
+ // System update, no admin ID needed
4868
+ null,
4869
+ // No clinic admin service needed for system updates
4870
+ app
4356
4871
  );
4357
4872
  return reviewData;
4358
4873
  }
4359
4874
 
4360
4875
  // src/services/clinic/utils/tag.utils.ts
4361
- async function addTags(db, clinicId, adminId, newTags, clinicAdminService) {
4876
+ async function addTags(db, clinicId, adminId, newTags, clinicAdminService, app) {
4362
4877
  const clinic = await getClinic(db, clinicId);
4363
4878
  if (!clinic) {
4364
4879
  throw new Error("Clinic not found");
@@ -4367,7 +4882,8 @@ async function addTags(db, clinicId, adminId, newTags, clinicAdminService) {
4367
4882
  if (!admin) {
4368
4883
  throw new Error("Admin not found");
4369
4884
  }
4370
- if (!admin.isGroupOwner && !admin.clinicsManaged.includes(clinicId)) {
4885
+ const hasPermission = admin.isGroupOwner && admin.clinicGroupId === clinic.clinicGroupId || admin.clinicsManaged.includes(clinicId) && clinic.admins && clinic.admins.includes(adminId);
4886
+ if (!hasPermission) {
4371
4887
  throw new Error("Admin does not have permission to update this clinic");
4372
4888
  }
4373
4889
  const updatedTags = [.../* @__PURE__ */ new Set([...clinic.tags, ...newTags.tags || []])];
@@ -4378,10 +4894,11 @@ async function addTags(db, clinicId, adminId, newTags, clinicAdminService) {
4378
4894
  tags: updatedTags
4379
4895
  },
4380
4896
  adminId,
4381
- clinicAdminService
4897
+ clinicAdminService,
4898
+ app
4382
4899
  );
4383
4900
  }
4384
- async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminService) {
4901
+ async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminService, app) {
4385
4902
  const clinic = await getClinic(db, clinicId);
4386
4903
  if (!clinic) {
4387
4904
  throw new Error("Clinic not found");
@@ -4390,14 +4907,12 @@ async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminServic
4390
4907
  if (!admin) {
4391
4908
  throw new Error("Admin not found");
4392
4909
  }
4393
- 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) {
4394
4912
  throw new Error("Admin does not have permission to update this clinic");
4395
4913
  }
4396
4914
  const updatedTags = clinic.tags.filter(
4397
- (tag) => {
4398
- var _a;
4399
- return !((_a = tagsToRemove.tags) == null ? void 0 : _a.includes(tag));
4400
- }
4915
+ (tag) => !tagsToRemove.tags || !tagsToRemove.tags.includes(tag)
4401
4916
  );
4402
4917
  return updateClinic(
4403
4918
  db,
@@ -4406,7 +4921,8 @@ async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminServic
4406
4921
  tags: updatedTags
4407
4922
  },
4408
4923
  adminId,
4409
- clinicAdminService
4924
+ clinicAdminService,
4925
+ app
4410
4926
  );
4411
4927
  }
4412
4928
 
@@ -4481,7 +4997,8 @@ var ClinicService = class extends BaseService {
4481
4997
  data,
4482
4998
  creatorAdminId,
4483
4999
  this.clinicGroupService,
4484
- this.clinicAdminService
5000
+ this.clinicAdminService,
5001
+ this.app
4485
5002
  );
4486
5003
  }
4487
5004
  /**
@@ -4516,14 +5033,15 @@ var ClinicService = class extends BaseService {
4516
5033
  clinicId,
4517
5034
  data,
4518
5035
  adminId,
4519
- this.clinicAdminService
5036
+ this.clinicAdminService,
5037
+ this.app
4520
5038
  );
4521
5039
  }
4522
5040
  /**
4523
5041
  * Dodaje recenziju klinici
4524
5042
  */
4525
5043
  async addReview(clinicId, review) {
4526
- return addReview(this.db, clinicId, review);
5044
+ return addReview(this.db, clinicId, review, this.app);
4527
5045
  }
4528
5046
  /**
4529
5047
  * Deaktivira kliniku
@@ -4545,7 +5063,8 @@ var ClinicService = class extends BaseService {
4545
5063
  clinicId,
4546
5064
  adminId,
4547
5065
  newTags,
4548
- this.clinicAdminService
5066
+ this.clinicAdminService,
5067
+ this.app
4549
5068
  );
4550
5069
  }
4551
5070
  /**
@@ -4557,7 +5076,8 @@ var ClinicService = class extends BaseService {
4557
5076
  clinicId,
4558
5077
  adminId,
4559
5078
  tagsToRemove,
4560
- this.clinicAdminService
5079
+ this.clinicAdminService,
5080
+ this.app
4561
5081
  );
4562
5082
  }
4563
5083
  /**
@@ -4592,12 +5112,21 @@ var ClinicService = class extends BaseService {
4592
5112
  * @returns The created clinic
4593
5113
  */
4594
5114
  async createClinicBranch(clinicGroupId, setupData, adminId) {
5115
+ var _a, _b;
5116
+ console.log("[CLINIC_SERVICE] Starting clinic branch creation", {
5117
+ clinicGroupId,
5118
+ adminId
5119
+ });
4595
5120
  const clinicGroup = await this.clinicGroupService.getClinicGroup(
4596
5121
  clinicGroupId
4597
5122
  );
4598
5123
  if (!clinicGroup) {
5124
+ console.error("[CLINIC_SERVICE] Clinic group not found", {
5125
+ clinicGroupId
5126
+ });
4599
5127
  throw new Error(`Clinic group with ID ${clinicGroupId} not found`);
4600
5128
  }
5129
+ console.log("[CLINIC_SERVICE] Clinic group verified");
4601
5130
  const createClinicData = {
4602
5131
  clinicGroupId,
4603
5132
  name: setupData.name,
@@ -4606,8 +5135,8 @@ var ClinicService = class extends BaseService {
4606
5135
  contactInfo: setupData.contactInfo,
4607
5136
  workingHours: setupData.workingHours,
4608
5137
  tags: setupData.tags,
4609
- photos: setupData.photos,
4610
- photosWithTags: setupData.photosWithTags,
5138
+ photos: setupData.photos || [],
5139
+ photosWithTags: setupData.photosWithTags || [],
4611
5140
  doctors: [],
4612
5141
  services: [],
4613
5142
  admins: [adminId],
@@ -4616,7 +5145,17 @@ var ClinicService = class extends BaseService {
4616
5145
  logo: setupData.logo,
4617
5146
  featuredPhotos: setupData.featuredPhotos || []
4618
5147
  };
5148
+ console.log("[CLINIC_SERVICE] Creating clinic branch with data", {
5149
+ name: createClinicData.name,
5150
+ hasLogo: !!createClinicData.logo,
5151
+ photosCount: createClinicData.photos.length,
5152
+ featuredPhotosCount: ((_a = createClinicData.featuredPhotos) == null ? void 0 : _a.length) || 0,
5153
+ photosWithTagsCount: ((_b = createClinicData.photosWithTags) == null ? void 0 : _b.length) || 0
5154
+ });
4619
5155
  const clinic = await this.createClinic(createClinicData, adminId);
5156
+ console.log("[CLINIC_SERVICE] Clinic branch created successfully", {
5157
+ clinicId: clinic.id
5158
+ });
4620
5159
  return clinic;
4621
5160
  }
4622
5161
  };
@@ -4738,7 +5277,7 @@ var AuthService = class extends BaseService {
4738
5277
  "Clinic group data is required when creating a new group"
4739
5278
  );
4740
5279
  }
4741
- console.log("[AUTH] Creating clinic admin first");
5280
+ console.log("[AUTH] Creating clinic admin first (without group)");
4742
5281
  const createClinicAdminData = {
4743
5282
  userRef: firebaseUser.uid,
4744
5283
  isGroupOwner: true,
@@ -4746,10 +5285,16 @@ var AuthService = class extends BaseService {
4746
5285
  contactInfo: contactPerson,
4747
5286
  roleTitle: data.title,
4748
5287
  isActive: true
5288
+ // No clinicGroupId yet
4749
5289
  };
5290
+ let adminProfile;
4750
5291
  try {
4751
- await clinicAdminService.createClinicAdmin(createClinicAdminData);
4752
- console.log("[AUTH] Clinic admin created successfully");
5292
+ adminProfile = await clinicAdminService.createClinicAdmin(
5293
+ createClinicAdminData
5294
+ );
5295
+ console.log("[AUTH] Clinic admin created successfully", {
5296
+ adminId: adminProfile.id
5297
+ });
4753
5298
  } catch (adminCreationError) {
4754
5299
  console.error(
4755
5300
  "[AUTH] Clinic admin creation failed:",
@@ -4762,7 +5307,8 @@ var AuthService = class extends BaseService {
4762
5307
  hqLocation: data.clinicGroupData.hqLocation,
4763
5308
  contactInfo: data.clinicGroupData.contactInfo,
4764
5309
  contactPerson,
4765
- ownerId: firebaseUser.uid,
5310
+ ownerId: adminProfile.id,
5311
+ // Use admin profile ID, not user UID
4766
5312
  isActive: true,
4767
5313
  logo: data.clinicGroupData.logo || null,
4768
5314
  subscriptionModel: data.clinicGroupData.subscriptionModel || "no_subscription" /* NO_SUBSCRIPTION */
@@ -4770,13 +5316,24 @@ var AuthService = class extends BaseService {
4770
5316
  console.log("[AUTH] Clinic group data prepared", {
4771
5317
  groupName: createClinicGroupData.name
4772
5318
  });
5319
+ let clinicGroup;
4773
5320
  try {
4774
- await clinicGroupService.createClinicGroup(
5321
+ clinicGroup = await clinicGroupService.createClinicGroup(
4775
5322
  createClinicGroupData,
4776
- firebaseUser.uid,
4777
- true
5323
+ adminProfile.id,
5324
+ // Use admin profile ID, not user UID
5325
+ false
5326
+ // This is not a default group since we're providing complete data
4778
5327
  );
4779
- console.log("[AUTH] Clinic group created successfully");
5328
+ console.log("[AUTH] Clinic group created successfully", {
5329
+ groupId: clinicGroup.id
5330
+ });
5331
+ console.log("[AUTH] Updating admin with clinic group ID");
5332
+ await clinicAdminService.updateClinicAdmin(adminProfile.id, {
5333
+ // Use admin profile ID, not user UID
5334
+ clinicGroupId: clinicGroup.id
5335
+ });
5336
+ console.log("[AUTH] Admin updated with clinic group ID successfully");
4780
5337
  } catch (groupCreationError) {
4781
5338
  console.error(
4782
5339
  "[AUTH] Clinic group creation failed:",
@@ -4849,9 +5406,14 @@ var AuthService = class extends BaseService {
4849
5406
  roleTitle: data.title,
4850
5407
  isActive: true
4851
5408
  };
5409
+ let adminProfile;
4852
5410
  try {
4853
- await clinicAdminService.createClinicAdmin(createClinicAdminData);
4854
- console.log("[AUTH] Clinic admin created successfully");
5411
+ adminProfile = await clinicAdminService.createClinicAdmin(
5412
+ createClinicAdminData
5413
+ );
5414
+ console.log("[AUTH] Clinic admin created successfully", {
5415
+ adminId: adminProfile.id
5416
+ });
4855
5417
  } catch (adminCreationError) {
4856
5418
  console.error(
4857
5419
  "[AUTH] Clinic admin creation failed:",
@@ -5160,7 +5722,7 @@ var AuthService = class extends BaseService {
5160
5722
  import {
5161
5723
  collection as collection10,
5162
5724
  doc as doc11,
5163
- getDoc as getDoc14,
5725
+ getDoc as getDoc15,
5164
5726
  getDocs as getDocs9,
5165
5727
  query as query9,
5166
5728
  where as where9,
@@ -5168,8 +5730,8 @@ import {
5168
5730
  deleteDoc as deleteDoc6,
5169
5731
  orderBy,
5170
5732
  Timestamp as Timestamp14,
5171
- addDoc,
5172
- writeBatch as writeBatch2
5733
+ addDoc as addDoc3,
5734
+ writeBatch as writeBatch3
5173
5735
  } from "firebase/firestore";
5174
5736
 
5175
5737
  // src/types/notifications/index.ts
@@ -5206,7 +5768,7 @@ var NotificationService = class extends BaseService {
5206
5768
  isRead: false,
5207
5769
  userRole: notification.userRole || "patient" /* PATIENT */
5208
5770
  };
5209
- const docRef = await addDoc(notificationsRef, notificationData);
5771
+ const docRef = await addDoc3(notificationsRef, notificationData);
5210
5772
  return {
5211
5773
  ...notificationData,
5212
5774
  id: docRef.id
@@ -5221,7 +5783,7 @@ var NotificationService = class extends BaseService {
5221
5783
  NOTIFICATIONS_COLLECTION,
5222
5784
  notificationId
5223
5785
  );
5224
- const notificationDoc = await getDoc14(notificationRef);
5786
+ const notificationDoc = await getDoc15(notificationRef);
5225
5787
  if (!notificationDoc.exists()) {
5226
5788
  return null;
5227
5789
  }
@@ -5280,7 +5842,7 @@ var NotificationService = class extends BaseService {
5280
5842
  */
5281
5843
  async markAllAsRead(userId) {
5282
5844
  const notifications = await this.getUnreadNotifications(userId);
5283
- const batch = writeBatch2(this.db);
5845
+ const batch = writeBatch3(this.db);
5284
5846
  notifications.forEach((notification) => {
5285
5847
  const notificationRef = doc11(
5286
5848
  this.db,
@@ -5356,7 +5918,7 @@ var NotificationService = class extends BaseService {
5356
5918
  import {
5357
5919
  collection as collection11,
5358
5920
  doc as doc12,
5359
- getDoc as getDoc15,
5921
+ getDoc as getDoc16,
5360
5922
  getDocs as getDocs10,
5361
5923
  setDoc as setDoc13,
5362
5924
  updateDoc as updateDoc14,
@@ -5412,7 +5974,7 @@ var DocumentationTemplateService = class extends BaseService {
5412
5974
  */
5413
5975
  async getTemplateById(templateId) {
5414
5976
  const docRef = doc12(this.collectionRef, templateId);
5415
- const docSnap = await getDoc15(docRef);
5977
+ const docSnap = await getDoc16(docRef);
5416
5978
  if (!docSnap.exists()) {
5417
5979
  return null;
5418
5980
  }
@@ -5551,7 +6113,7 @@ var DocumentationTemplateService = class extends BaseService {
5551
6113
  import {
5552
6114
  collection as collection12,
5553
6115
  doc as doc13,
5554
- getDoc as getDoc16,
6116
+ getDoc as getDoc17,
5555
6117
  getDocs as getDocs11,
5556
6118
  setDoc as setDoc14,
5557
6119
  updateDoc as updateDoc15,
@@ -5608,7 +6170,7 @@ var FilledDocumentService = class extends BaseService {
5608
6170
  */
5609
6171
  async getFilledDocumentById(documentId) {
5610
6172
  const docRef = doc13(this.collectionRef, documentId);
5611
- const docSnap = await getDoc16(docRef);
6173
+ const docSnap = await getDoc17(docRef);
5612
6174
  if (!docSnap.exists()) {
5613
6175
  return null;
5614
6176
  }