@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.
@@ -11,6 +11,8 @@ import {
11
11
  Timestamp,
12
12
  Firestore,
13
13
  QueryConstraint,
14
+ addDoc,
15
+ writeBatch,
14
16
  } from "firebase/firestore";
15
17
  import {
16
18
  Clinic,
@@ -19,6 +21,8 @@ import {
19
21
  ClinicReview,
20
22
  ClinicTag,
21
23
  ClinicGroup,
24
+ ClinicBranchSetupData,
25
+ ClinicLocation,
22
26
  } from "../../../types/clinic";
23
27
  import { geohashForLocation } from "geofire-common";
24
28
  import {
@@ -27,6 +31,12 @@ import {
27
31
  clinicReviewSchema,
28
32
  } from "../../../validations/clinic.schema";
29
33
  import { z } from "zod";
34
+ import { FirebaseApp } from "firebase/app";
35
+ import {
36
+ uploadPhoto,
37
+ uploadMultiplePhotos,
38
+ processEntityPhotos,
39
+ } from "./photos.utils";
30
40
 
31
41
  /**
32
42
  * Creates a new clinic
@@ -35,6 +45,7 @@ import { z } from "zod";
35
45
  * @param creatorAdminId - ID of the admin creating the clinic
36
46
  * @param clinicGroupService - Service for clinic group operations
37
47
  * @param clinicAdminService - Service for clinic admin operations
48
+ * @param app - Firebase app instance
38
49
  * @returns The created clinic
39
50
  */
40
51
  export async function createClinic(
@@ -42,55 +53,224 @@ export async function createClinic(
42
53
  data: CreateClinicData,
43
54
  creatorAdminId: string,
44
55
  clinicGroupService: any,
45
- clinicAdminService: any
56
+ clinicAdminService: any,
57
+ app: FirebaseApp
46
58
  ): Promise<Clinic> {
59
+ console.log("[CLINIC] Starting clinic creation", { creatorAdminId });
60
+ console.log("[CLINIC] Input data:", JSON.stringify(data, null, 2));
61
+
47
62
  // Validacija podataka
63
+ try {
64
+ const validatedData = createClinicSchema.parse(data);
65
+ console.log("[CLINIC] Data validation passed");
66
+ } catch (validationError) {
67
+ console.error("[CLINIC] Data validation failed:", validationError);
68
+ throw validationError;
69
+ }
70
+
48
71
  const validatedData = createClinicSchema.parse(data);
49
72
 
50
73
  // Proveravamo da li admin postoji i da li pripada grupi
51
- const admin = await clinicAdminService.getClinicAdmin(creatorAdminId);
52
- if (!admin) {
53
- throw new Error("Admin not found");
54
- }
74
+ try {
75
+ console.log("[CLINIC] Checking if admin exists and belongs to group");
76
+ const admin = await clinicAdminService.getClinicAdmin(creatorAdminId);
77
+ if (!admin) {
78
+ console.error("[CLINIC] Admin not found", { creatorAdminId });
79
+ throw new Error("Admin not found");
80
+ }
55
81
 
56
- if (admin.clinicGroupId !== validatedData.clinicGroupId) {
57
- throw new Error("Admin does not belong to this clinic group");
82
+ if (admin.clinicGroupId !== validatedData.clinicGroupId) {
83
+ console.error("[CLINIC] Admin does not belong to this clinic group", {
84
+ adminGroupId: admin.clinicGroupId,
85
+ requestedGroupId: validatedData.clinicGroupId,
86
+ });
87
+ throw new Error("Admin does not belong to this clinic group");
88
+ }
89
+ console.log("[CLINIC] Admin verified");
90
+ } catch (adminError) {
91
+ console.error("[CLINIC] Error verifying admin:", adminError);
92
+ throw adminError;
58
93
  }
59
94
 
60
95
  // Proveravamo da li grupa postoji
61
- const group = await clinicGroupService.getClinicGroup(
62
- validatedData.clinicGroupId
63
- );
64
- if (!group) {
65
- throw new Error("Clinic group not found");
96
+ try {
97
+ console.log("[CLINIC] Checking if clinic group exists");
98
+ const group = await clinicGroupService.getClinicGroup(
99
+ validatedData.clinicGroupId
100
+ );
101
+ if (!group) {
102
+ console.error("[CLINIC] Clinic group not found", {
103
+ groupId: validatedData.clinicGroupId,
104
+ });
105
+ throw new Error("Clinic group not found");
106
+ }
107
+ console.log("[CLINIC] Clinic group verified");
108
+ } catch (groupError) {
109
+ console.error("[CLINIC] Error verifying clinic group:", groupError);
110
+ throw groupError;
66
111
  }
67
112
 
68
113
  // Generišemo geohash za lokaciju
114
+ console.log("[CLINIC] Generating geohash for location");
69
115
  if (validatedData.location) {
70
- validatedData.location.geohash = geohashForLocation([
71
- validatedData.location.latitude,
72
- validatedData.location.longitude,
73
- ]);
116
+ try {
117
+ validatedData.location.geohash = geohashForLocation([
118
+ validatedData.location.latitude,
119
+ validatedData.location.longitude,
120
+ ]);
121
+ console.log("[CLINIC] Geohash generated successfully", {
122
+ geohash: validatedData.location.geohash,
123
+ });
124
+ } catch (geohashError) {
125
+ console.error("[CLINIC] Error generating geohash:", geohashError);
126
+ throw geohashError;
127
+ }
128
+ }
129
+
130
+ // Generate a unique ID for the clinic
131
+ const clinicId = doc(collection(db, CLINICS_COLLECTION)).id;
132
+ console.log("[CLINIC] Generated clinic ID:", clinicId);
133
+
134
+ // Process photos
135
+ console.log("[CLINIC] Processing photos");
136
+
137
+ // Handle logo upload if provided
138
+ let logoUrl = null;
139
+ if (validatedData.logo) {
140
+ console.log("[CLINIC] Processing logo");
141
+ try {
142
+ logoUrl = await uploadPhoto(
143
+ validatedData.logo,
144
+ "clinics",
145
+ clinicId,
146
+ "logo",
147
+ app
148
+ );
149
+ console.log("[CLINIC] Logo processed", { logoUrl });
150
+ } catch (logoError) {
151
+ console.error("[CLINIC] Error processing logo:", logoError);
152
+ // Continue with clinic creation even if logo upload fails
153
+ }
154
+ }
155
+
156
+ // Handle regular photos upload
157
+ let processedPhotos: string[] = [];
158
+ if (validatedData.photos && validatedData.photos.length > 0) {
159
+ console.log("[CLINIC] Processing regular photos");
160
+ try {
161
+ processedPhotos = await uploadMultiplePhotos(
162
+ validatedData.photos,
163
+ "clinics",
164
+ clinicId,
165
+ "photo",
166
+ app
167
+ );
168
+ console.log("[CLINIC] Regular photos processed", {
169
+ count: processedPhotos.length,
170
+ });
171
+ } catch (photosError) {
172
+ console.error("[CLINIC] Error processing regular photos:", photosError);
173
+ // Continue with clinic creation even if photos upload fails
174
+ processedPhotos = validatedData.photos.filter(
175
+ (photo) => !photo.startsWith("data:")
176
+ );
177
+ }
178
+ }
179
+
180
+ // Handle featured photos upload
181
+ let processedFeaturedPhotos: string[] = [];
182
+ if (validatedData.featuredPhotos && validatedData.featuredPhotos.length > 0) {
183
+ console.log("[CLINIC] Processing featured photos");
184
+ try {
185
+ processedFeaturedPhotos = await uploadMultiplePhotos(
186
+ validatedData.featuredPhotos,
187
+ "clinics",
188
+ clinicId,
189
+ "featured",
190
+ app
191
+ );
192
+ console.log("[CLINIC] Featured photos processed", {
193
+ count: processedFeaturedPhotos.length,
194
+ });
195
+ } catch (featuredError) {
196
+ console.error(
197
+ "[CLINIC] Error processing featured photos:",
198
+ featuredError
199
+ );
200
+ // Continue with clinic creation even if featured photos upload fails
201
+ processedFeaturedPhotos = validatedData.featuredPhotos.filter(
202
+ (photo) => !photo.startsWith("data:")
203
+ );
204
+ }
205
+ }
206
+
207
+ // Handle photos with tags
208
+ let processedPhotosWithTags = validatedData.photosWithTags || [];
209
+ if (processedPhotosWithTags.length > 0) {
210
+ console.log("[CLINIC] Processing photos with tags");
211
+ try {
212
+ const updatedPhotosWithTags = [];
213
+ for (const photoWithTag of processedPhotosWithTags) {
214
+ if (photoWithTag.url && photoWithTag.url.startsWith("data:")) {
215
+ const uploadedUrl = await uploadPhoto(
216
+ photoWithTag.url,
217
+ "clinics",
218
+ clinicId,
219
+ `tagged-${photoWithTag.tag}`,
220
+ app
221
+ );
222
+ if (uploadedUrl) {
223
+ updatedPhotosWithTags.push({
224
+ url: uploadedUrl,
225
+ tag: photoWithTag.tag,
226
+ });
227
+ }
228
+ } else {
229
+ updatedPhotosWithTags.push(photoWithTag);
230
+ }
231
+ }
232
+ processedPhotosWithTags = updatedPhotosWithTags;
233
+ console.log("[CLINIC] Photos with tags processed", {
234
+ count: processedPhotosWithTags.length,
235
+ });
236
+ } catch (tagsError) {
237
+ console.error("[CLINIC] Error processing photos with tags:", tagsError);
238
+ // Continue with clinic creation even if photos with tags upload fails
239
+ processedPhotosWithTags =
240
+ validatedData.photosWithTags?.filter(
241
+ (photo) => !photo.url.startsWith("data:")
242
+ ) || [];
243
+ }
74
244
  }
75
245
 
76
246
  const now = Timestamp.now();
247
+ console.log("[CLINIC] Preparing clinic data object");
248
+
77
249
  const clinicData: Clinic = {
78
250
  ...validatedData,
79
- id: doc(collection(db, CLINICS_COLLECTION)).id,
251
+ id: clinicId,
80
252
  description: validatedData.description || undefined,
81
253
  location: {
82
- ...validatedData.location,
254
+ address: validatedData.location.address || "",
255
+ city: validatedData.location.city || "",
256
+ country: validatedData.location.country || "",
257
+ postalCode: validatedData.location.postalCode || "",
258
+ latitude: validatedData.location.latitude || 0,
259
+ longitude: validatedData.location.longitude || 0,
83
260
  geohash: validatedData.location.geohash || undefined,
84
261
  },
85
262
  contactInfo: {
86
- ...validatedData.contactInfo,
263
+ email: validatedData.contactInfo.email || "",
264
+ phoneNumber: validatedData.contactInfo.phoneNumber || "",
87
265
  alternativePhoneNumber:
88
266
  validatedData.contactInfo.alternativePhoneNumber || undefined,
89
267
  website: validatedData.contactInfo.website || undefined,
90
268
  },
269
+ logo: logoUrl || undefined,
91
270
  tags: validatedData.tags || [],
92
- featuredPhotos: [],
93
- photos: validatedData.photos || [],
271
+ featuredPhotos: processedFeaturedPhotos || [],
272
+ photos: processedPhotos || [],
273
+ photosWithTags: processedPhotosWithTags,
94
274
  doctors: [],
95
275
  doctorsInfo: [],
96
276
  services: [],
@@ -107,24 +287,82 @@ export async function createClinic(
107
287
 
108
288
  try {
109
289
  // Validiramo kompletan objekat
110
- clinicSchema.parse(clinicData);
290
+ console.log("[CLINIC] Validating complete clinic object");
291
+ try {
292
+ clinicSchema.parse(clinicData);
293
+ console.log("[CLINIC] Clinic validation passed");
294
+ } catch (schemaError) {
295
+ console.error(
296
+ "[CLINIC] Clinic validation failed:",
297
+ JSON.stringify(schemaError, null, 2)
298
+ );
299
+ throw schemaError;
300
+ }
111
301
 
112
302
  // Čuvamo u Firestore
113
- await setDoc(doc(db, CLINICS_COLLECTION, clinicData.id), clinicData);
303
+ console.log("[CLINIC] Saving clinic to Firestore", {
304
+ clinicId: clinicData.id,
305
+ });
306
+ try {
307
+ await setDoc(doc(db, CLINICS_COLLECTION, clinicData.id), clinicData);
308
+ console.log("[CLINIC] Clinic saved successfully");
309
+ } catch (firestoreError) {
310
+ console.error("[CLINIC] Error saving to Firestore:", firestoreError);
311
+ throw firestoreError;
312
+ }
114
313
 
115
314
  // Dodajemo kliniku u grupaciju
116
- await clinicGroupService.updateClinicGroup(validatedData.clinicGroupId, {
117
- clinics: [...group.clinics, clinicData.id],
118
- });
315
+ console.log("[CLINIC] Adding clinic to clinic group");
316
+ try {
317
+ const group = await clinicGroupService.getClinicGroup(
318
+ validatedData.clinicGroupId
319
+ );
320
+ if (group) {
321
+ await clinicGroupService.updateClinicGroup(
322
+ validatedData.clinicGroupId,
323
+ {
324
+ clinics: [...group.clinics, clinicData.id],
325
+ }
326
+ );
327
+ console.log("[CLINIC] Clinic added to group successfully");
328
+ }
329
+ } catch (groupUpdateError) {
330
+ console.error("[CLINIC] Error adding clinic to group:", groupUpdateError);
331
+ // Continue even if adding to group fails
332
+ }
119
333
 
120
334
  // Dodajemo kliniku adminu koji ju je kreirao
121
- await clinicAdminService.addClinicToManaged(creatorAdminId, clinicData.id);
335
+ console.log("[CLINIC] Adding clinic to admin's managed clinics");
336
+ try {
337
+ await clinicAdminService.addClinicToManaged(
338
+ creatorAdminId,
339
+ clinicData.id
340
+ );
341
+ console.log(
342
+ "[CLINIC] Clinic added to admin's managed clinics successfully"
343
+ );
344
+ } catch (adminUpdateError) {
345
+ console.error(
346
+ "[CLINIC] Error adding clinic to admin's managed clinics:",
347
+ adminUpdateError
348
+ );
349
+ // Continue even if adding to admin fails
350
+ }
122
351
 
352
+ console.log("[CLINIC] Clinic creation completed successfully", {
353
+ clinicId: clinicData.id,
354
+ clinicName: clinicData.name,
355
+ });
123
356
  return clinicData;
124
357
  } catch (error) {
125
358
  if (error instanceof z.ZodError) {
359
+ console.error(
360
+ "[CLINIC] Zod validation error:",
361
+ JSON.stringify(error.errors, null, 2)
362
+ );
126
363
  throw new Error("Invalid clinic data: " + error.message);
127
364
  }
365
+ console.error("[CLINIC] Unhandled error in createClinic:", error);
128
366
  throw error;
129
367
  }
130
368
  }
@@ -176,6 +414,7 @@ export async function getClinicsByGroup(
176
414
  * @param data - Data to update
177
415
  * @param adminId - ID of the admin making the update
178
416
  * @param clinicAdminService - Service for clinic admin operations
417
+ * @param app - Firebase app instance
179
418
  * @returns The updated clinic
180
419
  */
181
420
  export async function updateClinic(
@@ -183,37 +422,231 @@ export async function updateClinic(
183
422
  clinicId: string,
184
423
  data: Partial<Clinic>,
185
424
  adminId: string,
186
- clinicAdminService: any
425
+ clinicAdminService: any,
426
+ app: FirebaseApp
187
427
  ): Promise<Clinic> {
428
+ console.log("[CLINIC] Starting clinic update", { clinicId, adminId });
429
+
188
430
  const clinic = await getClinic(db, clinicId);
189
431
  if (!clinic) {
432
+ console.error("[CLINIC] Clinic not found", { clinicId });
190
433
  throw new Error("Clinic not found");
191
434
  }
192
435
 
193
436
  // Proveravamo da li admin ima prava da ažurira kliniku
194
- const admin = await clinicAdminService.getClinicAdmin(adminId);
195
- if (!admin) {
196
- throw new Error("Admin not found");
437
+ try {
438
+ console.log("[CLINIC] Checking admin permissions");
439
+ const admin = await clinicAdminService.getClinicAdmin(adminId);
440
+ if (!admin) {
441
+ console.error("[CLINIC] Admin not found", { adminId });
442
+ throw new Error("Admin not found");
443
+ }
444
+
445
+ // Check if admin is either:
446
+ // 1. The owner of the clinic group, OR
447
+ // 2. Has this clinic in their managed clinics list, OR
448
+ // 3. Is listed in the clinic's admins array
449
+ const hasPermission =
450
+ (admin.isGroupOwner && admin.clinicGroupId === clinic.clinicGroupId) ||
451
+ (admin.clinicsManaged.includes(clinicId) &&
452
+ clinic.admins &&
453
+ clinic.admins.includes(adminId));
454
+
455
+ if (!hasPermission) {
456
+ console.error(
457
+ "[CLINIC] Admin does not have permission to update this clinic",
458
+ {
459
+ adminId,
460
+ clinicId,
461
+ isGroupOwner: admin.isGroupOwner,
462
+ clinicsManaged: admin.clinicsManaged,
463
+ isClinicAdmin: clinic.admins && clinic.admins.includes(adminId),
464
+ }
465
+ );
466
+ throw new Error("Admin does not have permission to update this clinic");
467
+ }
468
+ console.log("[CLINIC] Admin permissions verified");
469
+ } catch (adminError) {
470
+ console.error("[CLINIC] Error verifying admin permissions:", adminError);
471
+ throw adminError;
472
+ }
473
+
474
+ // Process photos in the update data
475
+ let updatedData = { ...data };
476
+
477
+ // Handle logo update if provided
478
+ if (
479
+ data.logo &&
480
+ typeof data.logo === "string" &&
481
+ data.logo.startsWith("data:")
482
+ ) {
483
+ console.log("[CLINIC] Processing logo update");
484
+ try {
485
+ const logoUrl = await uploadPhoto(
486
+ data.logo,
487
+ "clinics",
488
+ clinicId,
489
+ "logo",
490
+ app
491
+ );
492
+ console.log("[CLINIC] Logo update processed", { logoUrl });
493
+
494
+ if (logoUrl !== null) {
495
+ updatedData.logo = logoUrl;
496
+ }
497
+ } catch (logoError) {
498
+ console.error("[CLINIC] Error processing logo update:", logoError);
499
+ // Continue with update even if logo upload fails
500
+ }
501
+ }
502
+
503
+ // Handle regular photos update if provided
504
+ if (data.photos && data.photos.length > 0) {
505
+ console.log("[CLINIC] Processing regular photos update");
506
+ try {
507
+ // Filter out only data URLs that need to be uploaded
508
+ const dataUrlPhotos = data.photos.filter(
509
+ (photo) => typeof photo === "string" && photo.startsWith("data:")
510
+ );
511
+ const existingPhotos = data.photos.filter(
512
+ (photo) => typeof photo === "string" && !photo.startsWith("data:")
513
+ );
514
+
515
+ if (dataUrlPhotos.length > 0) {
516
+ const uploadedPhotos = await uploadMultiplePhotos(
517
+ dataUrlPhotos,
518
+ "clinics",
519
+ clinicId,
520
+ "photo",
521
+ app
522
+ );
523
+ console.log("[CLINIC] Regular photos update processed", {
524
+ count: uploadedPhotos.length,
525
+ });
526
+
527
+ // Combine existing photos with newly uploaded ones
528
+ updatedData.photos = [...existingPhotos, ...uploadedPhotos];
529
+ }
530
+ } catch (photosError) {
531
+ console.error(
532
+ "[CLINIC] Error processing regular photos update:",
533
+ photosError
534
+ );
535
+ // Continue with update even if photos upload fails
536
+ updatedData.photos = data.photos.filter(
537
+ (photo) => typeof photo === "string" && !photo.startsWith("data:")
538
+ );
539
+ }
197
540
  }
198
541
 
199
- if (!admin.isGroupOwner && !admin.clinicsManaged.includes(clinicId)) {
200
- throw new Error("Admin does not have permission to update this clinic");
542
+ // Handle featured photos update if provided
543
+ if (data.featuredPhotos && data.featuredPhotos.length > 0) {
544
+ console.log("[CLINIC] Processing featured photos update");
545
+ try {
546
+ // Filter out only data URLs that need to be uploaded
547
+ const dataUrlPhotos = data.featuredPhotos.filter(
548
+ (photo) => typeof photo === "string" && photo.startsWith("data:")
549
+ );
550
+ const existingPhotos = data.featuredPhotos.filter(
551
+ (photo) => typeof photo === "string" && !photo.startsWith("data:")
552
+ );
553
+
554
+ if (dataUrlPhotos.length > 0) {
555
+ const uploadedPhotos = await uploadMultiplePhotos(
556
+ dataUrlPhotos,
557
+ "clinics",
558
+ clinicId,
559
+ "featured",
560
+ app
561
+ );
562
+ console.log("[CLINIC] Featured photos update processed", {
563
+ count: uploadedPhotos.length,
564
+ });
565
+
566
+ // Combine existing photos with newly uploaded ones
567
+ updatedData.featuredPhotos = [...existingPhotos, ...uploadedPhotos];
568
+ }
569
+ } catch (featuredError) {
570
+ console.error(
571
+ "[CLINIC] Error processing featured photos update:",
572
+ featuredError
573
+ );
574
+ // Continue with update even if featured photos upload fails
575
+ updatedData.featuredPhotos = data.featuredPhotos.filter(
576
+ (photo) => typeof photo === "string" && !photo.startsWith("data:")
577
+ );
578
+ }
201
579
  }
202
580
 
203
- // Ažuriramo podatke
204
- const updatedData = {
205
- ...data,
581
+ // Handle photos with tags update if provided
582
+ if (data.photosWithTags && data.photosWithTags.length > 0) {
583
+ console.log("[CLINIC] Processing photos with tags update");
584
+ try {
585
+ const updatedPhotosWithTags = [];
586
+
587
+ // Process each photo with tag
588
+ for (const photoWithTag of data.photosWithTags) {
589
+ if (photoWithTag.url && photoWithTag.url.startsWith("data:")) {
590
+ // Upload new photo
591
+ const uploadedUrl = await uploadPhoto(
592
+ photoWithTag.url,
593
+ "clinics",
594
+ clinicId,
595
+ `tagged-${photoWithTag.tag}`,
596
+ app
597
+ );
598
+
599
+ if (uploadedUrl) {
600
+ updatedPhotosWithTags.push({
601
+ url: uploadedUrl,
602
+ tag: photoWithTag.tag,
603
+ });
604
+ }
605
+ } else {
606
+ // Keep existing photo
607
+ updatedPhotosWithTags.push(photoWithTag);
608
+ }
609
+ }
610
+
611
+ updatedData.photosWithTags = updatedPhotosWithTags;
612
+ console.log("[CLINIC] Photos with tags update processed", {
613
+ count: updatedPhotosWithTags.length,
614
+ });
615
+ } catch (tagsError) {
616
+ console.error(
617
+ "[CLINIC] Error processing photos with tags update:",
618
+ tagsError
619
+ );
620
+ // Continue with update even if photos with tags upload fails
621
+ updatedData.photosWithTags = data.photosWithTags.filter(
622
+ (photo) => !photo.url.startsWith("data:")
623
+ );
624
+ }
625
+ }
626
+
627
+ // Add timestamp
628
+ updatedData = {
629
+ ...updatedData,
206
630
  updatedAt: Timestamp.now(),
207
631
  };
208
632
 
209
- await updateDoc(doc(db, CLINICS_COLLECTION, clinicId), updatedData);
633
+ console.log("[CLINIC] Updating clinic in Firestore");
634
+ try {
635
+ await updateDoc(doc(db, CLINICS_COLLECTION, clinicId), updatedData);
636
+ console.log("[CLINIC] Clinic updated successfully");
637
+ } catch (updateError) {
638
+ console.error("[CLINIC] Error updating clinic in Firestore:", updateError);
639
+ throw updateError;
640
+ }
210
641
 
211
- // Vraćamo ažurirane podatke
642
+ // Return updated data
212
643
  const updatedClinic = await getClinic(db, clinicId);
213
644
  if (!updatedClinic) {
645
+ console.error("[CLINIC] Failed to retrieve updated clinic");
214
646
  throw new Error("Failed to retrieve updated clinic");
215
647
  }
216
648
 
649
+ console.log("[CLINIC] Clinic update completed successfully");
217
650
  return updatedClinic;
218
651
  }
219
652
 
@@ -241,7 +674,17 @@ export async function deactivateClinic(
241
674
  throw new Error("Admin not found");
242
675
  }
243
676
 
244
- if (!admin.isGroupOwner && !admin.clinicsManaged.includes(clinicId)) {
677
+ // Check if admin is either:
678
+ // 1. The owner of the clinic group, OR
679
+ // 2. Has this clinic in their managed clinics list, OR
680
+ // 3. Is listed in the clinic's admins array
681
+ const hasPermission =
682
+ (admin.isGroupOwner && admin.clinicGroupId === clinic.clinicGroupId) ||
683
+ (admin.clinicsManaged.includes(clinicId) &&
684
+ clinic.admins &&
685
+ clinic.admins.includes(adminId));
686
+
687
+ if (!hasPermission) {
245
688
  throw new Error("Admin does not have permission to deactivate this clinic");
246
689
  }
247
690