@blackcode_sa/metaestetics-api 1.13.5 → 1.13.6
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/admin/index.d.mts +20 -1
- package/dist/admin/index.d.ts +20 -1
- package/dist/admin/index.js +217 -1
- package/dist/admin/index.mjs +217 -1
- package/package.json +121 -121
- package/src/__mocks__/firstore.ts +10 -10
- package/src/admin/aggregation/README.md +79 -79
- package/src/admin/aggregation/appointment/README.md +128 -128
- package/src/admin/aggregation/appointment/appointment.aggregation.service.ts +1984 -1984
- package/src/admin/aggregation/appointment/index.ts +1 -1
- package/src/admin/aggregation/clinic/README.md +52 -52
- package/src/admin/aggregation/clinic/clinic.aggregation.service.ts +966 -703
- package/src/admin/aggregation/clinic/index.ts +1 -1
- package/src/admin/aggregation/forms/README.md +13 -13
- package/src/admin/aggregation/forms/filled-forms.aggregation.service.ts +322 -322
- package/src/admin/aggregation/forms/index.ts +1 -1
- package/src/admin/aggregation/index.ts +8 -8
- package/src/admin/aggregation/patient/README.md +27 -27
- package/src/admin/aggregation/patient/index.ts +1 -1
- package/src/admin/aggregation/patient/patient.aggregation.service.ts +141 -141
- package/src/admin/aggregation/practitioner/README.md +42 -42
- package/src/admin/aggregation/practitioner/index.ts +1 -1
- package/src/admin/aggregation/practitioner/practitioner.aggregation.service.ts +433 -433
- package/src/admin/aggregation/practitioner-invite/index.ts +1 -1
- package/src/admin/aggregation/practitioner-invite/practitioner-invite.aggregation.service.ts +961 -961
- package/src/admin/aggregation/procedure/README.md +43 -43
- package/src/admin/aggregation/procedure/index.ts +1 -1
- package/src/admin/aggregation/procedure/procedure.aggregation.service.ts +702 -702
- package/src/admin/aggregation/reviews/index.ts +1 -1
- package/src/admin/aggregation/reviews/reviews.aggregation.service.ts +689 -689
- package/src/admin/analytics/analytics.admin.service.ts +278 -278
- package/src/admin/analytics/index.ts +2 -2
- package/src/admin/booking/README.md +125 -125
- package/src/admin/booking/booking.admin.ts +1037 -1037
- package/src/admin/booking/booking.calculator.ts +712 -712
- package/src/admin/booking/booking.types.ts +59 -59
- package/src/admin/booking/index.ts +3 -3
- package/src/admin/booking/timezones-problem.md +185 -185
- package/src/admin/calendar/README.md +7 -7
- package/src/admin/calendar/calendar.admin.service.ts +345 -345
- package/src/admin/calendar/index.ts +1 -1
- package/src/admin/documentation-templates/document-manager.admin.ts +260 -260
- package/src/admin/documentation-templates/index.ts +1 -1
- package/src/admin/free-consultation/free-consultation-utils.admin.ts +148 -148
- package/src/admin/free-consultation/index.ts +1 -1
- package/src/admin/index.ts +81 -81
- package/src/admin/logger/index.ts +78 -78
- package/src/admin/mailing/README.md +95 -95
- package/src/admin/mailing/appointment/appointment.mailing.service.ts +732 -732
- package/src/admin/mailing/appointment/index.ts +1 -1
- package/src/admin/mailing/appointment/templates/patient/appointment-confirmed.html +40 -40
- package/src/admin/mailing/base.mailing.service.ts +208 -208
- package/src/admin/mailing/index.ts +3 -3
- package/src/admin/mailing/practitionerInvite/existing-practitioner-invite.mailing.ts +611 -611
- package/src/admin/mailing/practitionerInvite/index.ts +2 -2
- package/src/admin/mailing/practitionerInvite/practitionerInvite.mailing.ts +395 -395
- package/src/admin/mailing/practitionerInvite/templates/existing-practitioner-invitation.template.ts +155 -155
- package/src/admin/mailing/practitionerInvite/templates/invitation.template.ts +101 -101
- package/src/admin/mailing/practitionerInvite/templates/invite-accepted-notification.template.ts +228 -228
- package/src/admin/mailing/practitionerInvite/templates/invite-rejected-notification.template.ts +242 -242
- package/src/admin/notifications/index.ts +1 -1
- package/src/admin/notifications/notifications.admin.ts +710 -710
- package/src/admin/requirements/README.md +128 -128
- package/src/admin/requirements/index.ts +1 -1
- package/src/admin/requirements/patient-requirements.admin.service.ts +475 -475
- package/src/admin/users/index.ts +1 -1
- package/src/admin/users/user-profile.admin.ts +405 -405
- package/src/backoffice/constants/certification.constants.ts +13 -13
- package/src/backoffice/constants/index.ts +1 -1
- package/src/backoffice/errors/backoffice.errors.ts +181 -181
- package/src/backoffice/errors/index.ts +1 -1
- package/src/backoffice/expo-safe/README.md +26 -26
- package/src/backoffice/expo-safe/index.ts +41 -41
- package/src/backoffice/index.ts +5 -5
- package/src/backoffice/services/FIXES_README.md +102 -102
- package/src/backoffice/services/README.md +57 -57
- package/src/backoffice/services/analytics.service.proposal.md +863 -863
- package/src/backoffice/services/analytics.service.summary.md +143 -143
- package/src/backoffice/services/brand.service.ts +256 -256
- package/src/backoffice/services/category.service.ts +384 -384
- package/src/backoffice/services/constants.service.ts +385 -385
- package/src/backoffice/services/documentation-template.service.ts +202 -202
- package/src/backoffice/services/index.ts +10 -10
- package/src/backoffice/services/migrate-products.ts +116 -116
- package/src/backoffice/services/product.service.ts +553 -553
- package/src/backoffice/services/requirement.service.ts +235 -235
- package/src/backoffice/services/subcategory.service.ts +461 -461
- package/src/backoffice/services/technology.service.ts +1151 -1151
- package/src/backoffice/types/README.md +12 -12
- package/src/backoffice/types/admin-constants.types.ts +69 -69
- package/src/backoffice/types/brand.types.ts +29 -29
- package/src/backoffice/types/category.types.ts +67 -67
- package/src/backoffice/types/documentation-templates.types.ts +28 -28
- package/src/backoffice/types/index.ts +10 -10
- package/src/backoffice/types/procedure-product.types.ts +38 -38
- package/src/backoffice/types/product.types.ts +240 -240
- package/src/backoffice/types/requirement.types.ts +63 -63
- package/src/backoffice/types/static/README.md +18 -18
- package/src/backoffice/types/static/blocking-condition.types.ts +21 -21
- package/src/backoffice/types/static/certification.types.ts +37 -37
- package/src/backoffice/types/static/contraindication.types.ts +19 -19
- package/src/backoffice/types/static/index.ts +6 -6
- package/src/backoffice/types/static/pricing.types.ts +16 -16
- package/src/backoffice/types/static/procedure-family.types.ts +14 -14
- package/src/backoffice/types/static/treatment-benefit.types.ts +22 -22
- package/src/backoffice/types/subcategory.types.ts +34 -34
- package/src/backoffice/types/technology.types.ts +168 -168
- package/src/backoffice/validations/index.ts +1 -1
- package/src/backoffice/validations/schemas.ts +164 -164
- package/src/config/__mocks__/firebase.ts +99 -99
- package/src/config/firebase.ts +78 -78
- package/src/config/index.ts +9 -9
- package/src/errors/auth.error.ts +6 -6
- package/src/errors/auth.errors.ts +200 -200
- package/src/errors/clinic.errors.ts +32 -32
- package/src/errors/firebase.errors.ts +47 -47
- package/src/errors/user.errors.ts +99 -99
- package/src/index.backup.ts +407 -407
- package/src/index.ts +6 -6
- package/src/locales/en.ts +31 -31
- package/src/recommender/admin/index.ts +1 -1
- package/src/recommender/admin/services/recommender.service.admin.ts +5 -5
- package/src/recommender/front/index.ts +1 -1
- package/src/recommender/front/services/onboarding.service.ts +5 -5
- package/src/recommender/front/services/recommender.service.ts +3 -3
- package/src/recommender/index.ts +1 -1
- package/src/services/PATIENTAUTH.MD +197 -197
- package/src/services/README.md +106 -106
- package/src/services/__tests__/auth/auth.mock.test.ts +17 -17
- package/src/services/__tests__/auth/auth.setup.ts +293 -293
- package/src/services/__tests__/auth.service.test.ts +346 -346
- package/src/services/__tests__/base.service.test.ts +77 -77
- package/src/services/__tests__/user.service.test.ts +528 -528
- package/src/services/analytics/ARCHITECTURE.md +199 -199
- package/src/services/analytics/CLOUD_FUNCTIONS.md +225 -225
- package/src/services/analytics/GROUPED_ANALYTICS.md +501 -501
- package/src/services/analytics/QUICK_START.md +393 -393
- package/src/services/analytics/README.md +304 -304
- package/src/services/analytics/SUMMARY.md +141 -141
- package/src/services/analytics/TRENDS.md +380 -380
- package/src/services/analytics/USAGE_GUIDE.md +518 -518
- package/src/services/analytics/analytics-cloud.service.ts +222 -222
- package/src/services/analytics/analytics.service.ts +2142 -2142
- package/src/services/analytics/index.ts +4 -4
- package/src/services/analytics/review-analytics.service.ts +941 -941
- package/src/services/analytics/utils/appointment-filtering.utils.ts +138 -138
- package/src/services/analytics/utils/cost-calculation.utils.ts +182 -182
- package/src/services/analytics/utils/grouping.utils.ts +434 -434
- package/src/services/analytics/utils/stored-analytics.utils.ts +347 -347
- package/src/services/analytics/utils/time-calculation.utils.ts +186 -186
- package/src/services/analytics/utils/trend-calculation.utils.ts +200 -200
- package/src/services/appointment/README.md +17 -17
- package/src/services/appointment/appointment.service.ts +2558 -2558
- package/src/services/appointment/index.ts +1 -1
- package/src/services/appointment/utils/appointment.utils.ts +552 -552
- package/src/services/appointment/utils/extended-procedure.utils.ts +314 -314
- package/src/services/appointment/utils/form-initialization.utils.ts +225 -225
- package/src/services/appointment/utils/recommended-procedure.utils.ts +195 -195
- package/src/services/appointment/utils/zone-management.utils.ts +353 -353
- package/src/services/appointment/utils/zone-photo.utils.ts +152 -152
- package/src/services/auth/auth.service.ts +989 -989
- package/src/services/auth/auth.v2.service.ts +961 -961
- package/src/services/auth/index.ts +7 -7
- package/src/services/auth/utils/error.utils.ts +90 -90
- package/src/services/auth/utils/firebase.utils.ts +49 -49
- package/src/services/auth/utils/index.ts +21 -21
- package/src/services/auth/utils/practitioner.utils.ts +125 -125
- package/src/services/base.service.ts +41 -41
- package/src/services/calendar/calendar.service.ts +1077 -1077
- package/src/services/calendar/calendar.v2.service.ts +1683 -1683
- package/src/services/calendar/calendar.v3.service.ts +313 -313
- package/src/services/calendar/externalCalendar.service.ts +178 -178
- package/src/services/calendar/index.ts +5 -5
- package/src/services/calendar/synced-calendars.service.ts +743 -743
- package/src/services/calendar/utils/appointment.utils.ts +265 -265
- package/src/services/calendar/utils/calendar-event.utils.ts +646 -646
- package/src/services/calendar/utils/clinic.utils.ts +237 -237
- package/src/services/calendar/utils/docs.utils.ts +157 -157
- package/src/services/calendar/utils/google-calendar.utils.ts +697 -697
- package/src/services/calendar/utils/index.ts +8 -8
- package/src/services/calendar/utils/patient.utils.ts +198 -198
- package/src/services/calendar/utils/practitioner.utils.ts +221 -221
- package/src/services/calendar/utils/synced-calendar.utils.ts +472 -472
- package/src/services/clinic/README.md +204 -204
- package/src/services/clinic/__tests__/clinic-admin.service.test.ts +287 -287
- package/src/services/clinic/__tests__/clinic-group.service.test.ts +352 -352
- package/src/services/clinic/__tests__/clinic.service.test.ts +354 -354
- package/src/services/clinic/billing-transactions.service.ts +217 -217
- package/src/services/clinic/clinic-admin.service.ts +202 -202
- package/src/services/clinic/clinic-group.service.ts +310 -310
- package/src/services/clinic/clinic.service.ts +708 -708
- package/src/services/clinic/index.ts +5 -5
- package/src/services/clinic/practitioner-invite.service.ts +519 -519
- package/src/services/clinic/utils/admin.utils.ts +551 -551
- package/src/services/clinic/utils/clinic-group.utils.ts +646 -646
- package/src/services/clinic/utils/clinic.utils.ts +949 -949
- package/src/services/clinic/utils/filter.utils.d.ts +23 -23
- package/src/services/clinic/utils/filter.utils.ts +446 -446
- package/src/services/clinic/utils/index.ts +11 -11
- package/src/services/clinic/utils/photos.utils.ts +188 -188
- package/src/services/clinic/utils/search.utils.ts +84 -84
- package/src/services/clinic/utils/tag.utils.ts +124 -124
- package/src/services/documentation-templates/documentation-template.service.ts +537 -537
- package/src/services/documentation-templates/filled-document.service.ts +587 -587
- package/src/services/documentation-templates/index.ts +2 -2
- package/src/services/index.ts +14 -14
- package/src/services/media/index.ts +1 -1
- package/src/services/media/media.service.ts +418 -418
- package/src/services/notifications/__tests__/notification.service.test.ts +242 -242
- package/src/services/notifications/index.ts +1 -1
- package/src/services/notifications/notification.service.ts +215 -215
- package/src/services/patient/README.md +48 -48
- package/src/services/patient/To-Do.md +43 -43
- package/src/services/patient/__tests__/patient.service.test.ts +294 -294
- package/src/services/patient/index.ts +2 -2
- package/src/services/patient/patient.service.ts +883 -883
- package/src/services/patient/patientRequirements.service.ts +285 -285
- package/src/services/patient/utils/aesthetic-analysis.utils.ts +176 -176
- package/src/services/patient/utils/clinic.utils.ts +80 -80
- package/src/services/patient/utils/docs.utils.ts +142 -142
- package/src/services/patient/utils/index.ts +9 -9
- package/src/services/patient/utils/location.utils.ts +126 -126
- package/src/services/patient/utils/medical-stuff.utils.ts +143 -143
- package/src/services/patient/utils/medical.utils.ts +458 -458
- package/src/services/patient/utils/practitioner.utils.ts +260 -260
- package/src/services/patient/utils/profile.utils.ts +510 -510
- package/src/services/patient/utils/sensitive.utils.ts +260 -260
- package/src/services/patient/utils/token.utils.ts +211 -211
- package/src/services/practitioner/README.md +145 -145
- package/src/services/practitioner/index.ts +1 -1
- package/src/services/practitioner/practitioner.service.ts +1742 -1742
- package/src/services/procedure/README.md +163 -163
- package/src/services/procedure/index.ts +1 -1
- package/src/services/procedure/procedure.service.ts +2200 -2200
- package/src/services/reviews/index.ts +1 -1
- package/src/services/reviews/reviews.service.ts +734 -734
- package/src/services/user/index.ts +1 -1
- package/src/services/user/user.service.ts +489 -489
- package/src/services/user/user.v2.service.ts +466 -466
- package/src/types/analytics/analytics.types.ts +597 -597
- package/src/types/analytics/grouped-analytics.types.ts +173 -173
- package/src/types/analytics/index.ts +4 -4
- package/src/types/analytics/stored-analytics.types.ts +137 -137
- package/src/types/appointment/index.ts +480 -480
- package/src/types/calendar/index.ts +258 -258
- package/src/types/calendar/synced-calendar.types.ts +66 -66
- package/src/types/clinic/index.ts +498 -498
- package/src/types/clinic/practitioner-invite.types.ts +91 -91
- package/src/types/clinic/preferences.types.ts +159 -159
- package/src/types/clinic/to-do +3 -3
- package/src/types/documentation-templates/index.ts +308 -308
- package/src/types/index.ts +47 -47
- package/src/types/notifications/README.md +77 -77
- package/src/types/notifications/index.ts +286 -286
- package/src/types/patient/aesthetic-analysis.types.ts +66 -66
- package/src/types/patient/allergies.ts +58 -58
- package/src/types/patient/index.ts +275 -275
- package/src/types/patient/medical-info.types.ts +152 -152
- package/src/types/patient/patient-requirements.ts +92 -92
- package/src/types/patient/token.types.ts +61 -61
- package/src/types/practitioner/index.ts +206 -206
- package/src/types/procedure/index.ts +181 -181
- package/src/types/profile/index.ts +39 -39
- package/src/types/reviews/index.ts +132 -132
- package/src/types/tz-lookup.d.ts +4 -4
- package/src/types/user/index.ts +38 -38
- package/src/utils/TIMESTAMPS.md +176 -176
- package/src/utils/TimestampUtils.ts +241 -241
- package/src/utils/index.ts +1 -1
- package/src/validations/appointment.schema.ts +574 -574
- package/src/validations/calendar.schema.ts +225 -225
- package/src/validations/clinic.schema.ts +494 -494
- package/src/validations/common.schema.ts +25 -25
- package/src/validations/documentation-templates/index.ts +1 -1
- package/src/validations/documentation-templates/template.schema.ts +220 -220
- package/src/validations/documentation-templates.schema.ts +10 -10
- package/src/validations/index.ts +20 -20
- package/src/validations/media.schema.ts +10 -10
- package/src/validations/notification.schema.ts +90 -90
- package/src/validations/patient/aesthetic-analysis.schema.ts +55 -55
- package/src/validations/patient/medical-info.schema.ts +125 -125
- package/src/validations/patient/patient-requirements.schema.ts +84 -84
- package/src/validations/patient/token.schema.ts +29 -29
- package/src/validations/patient.schema.ts +217 -217
- package/src/validations/practitioner.schema.ts +222 -222
- package/src/validations/procedure-product.schema.ts +41 -41
- package/src/validations/procedure.schema.ts +124 -124
- package/src/validations/profile-info.schema.ts +41 -41
- package/src/validations/reviews.schema.ts +195 -195
- package/src/validations/schemas.ts +104 -104
- package/src/validations/shared.schema.ts +78 -78
|
@@ -1,551 +1,551 @@
|
|
|
1
|
-
import {
|
|
2
|
-
collection,
|
|
3
|
-
doc,
|
|
4
|
-
getDoc,
|
|
5
|
-
getDocs,
|
|
6
|
-
query,
|
|
7
|
-
where,
|
|
8
|
-
updateDoc,
|
|
9
|
-
setDoc,
|
|
10
|
-
deleteDoc,
|
|
11
|
-
Timestamp,
|
|
12
|
-
Firestore,
|
|
13
|
-
serverTimestamp,
|
|
14
|
-
FieldValue,
|
|
15
|
-
} from "firebase/firestore";
|
|
16
|
-
import {
|
|
17
|
-
ClinicAdmin,
|
|
18
|
-
CreateClinicAdminData,
|
|
19
|
-
UpdateClinicAdminData,
|
|
20
|
-
CLINIC_ADMINS_COLLECTION,
|
|
21
|
-
CreateDefaultClinicGroupData,
|
|
22
|
-
} from "../../../types/clinic";
|
|
23
|
-
import {
|
|
24
|
-
clinicAdminSchema,
|
|
25
|
-
createClinicAdminSchema,
|
|
26
|
-
} from "../../../validations/clinic.schema";
|
|
27
|
-
import { z } from "zod";
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Creates a new clinic admin
|
|
31
|
-
* @param db - Firestore database instance
|
|
32
|
-
* @param data - Admin data
|
|
33
|
-
* @param clinicGroupService - Service for clinic group operations
|
|
34
|
-
* @returns The created clinic admin
|
|
35
|
-
*/
|
|
36
|
-
export async function createClinicAdmin(
|
|
37
|
-
db: Firestore,
|
|
38
|
-
data: CreateClinicAdminData,
|
|
39
|
-
clinicGroupService: any
|
|
40
|
-
): Promise<ClinicAdmin> {
|
|
41
|
-
console.log("[CLINIC_ADMIN] Starting clinic admin creation", {
|
|
42
|
-
userRef: data.userRef,
|
|
43
|
-
});
|
|
44
|
-
console.log("[CLINIC_ADMIN] Input data:", JSON.stringify(data, null, 2));
|
|
45
|
-
|
|
46
|
-
// Validacija podataka
|
|
47
|
-
try {
|
|
48
|
-
const validatedData = createClinicAdminSchema.parse(data);
|
|
49
|
-
console.log("[CLINIC_ADMIN] Data validation passed");
|
|
50
|
-
} catch (validationError) {
|
|
51
|
-
console.error("[CLINIC_ADMIN] Data validation failed:", validationError);
|
|
52
|
-
throw validationError;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const validatedData = createClinicAdminSchema.parse(data);
|
|
56
|
-
|
|
57
|
-
// Proveravamo da li korisnik već ima admin profil
|
|
58
|
-
console.log("[CLINIC_ADMIN] Checking if user already has an admin profile", {
|
|
59
|
-
userRef: validatedData.userRef,
|
|
60
|
-
});
|
|
61
|
-
try {
|
|
62
|
-
const existingAdmin = await getClinicAdminByUserRef(
|
|
63
|
-
db,
|
|
64
|
-
validatedData.userRef
|
|
65
|
-
);
|
|
66
|
-
if (existingAdmin) {
|
|
67
|
-
console.error("[CLINIC_ADMIN] User already has an admin profile", {
|
|
68
|
-
adminId: existingAdmin.id,
|
|
69
|
-
});
|
|
70
|
-
throw new Error("User already has an admin profile");
|
|
71
|
-
}
|
|
72
|
-
console.log("[CLINIC_ADMIN] User does not have an existing admin profile");
|
|
73
|
-
} catch (error: any) {
|
|
74
|
-
if (error.message === "User already has an admin profile") {
|
|
75
|
-
throw error;
|
|
76
|
-
}
|
|
77
|
-
console.error("[CLINIC_ADMIN] Error checking for existing admin:", error);
|
|
78
|
-
throw error;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Ako je owner, kreiramo default grupu ako nije prosleđen groupId
|
|
82
|
-
let clinicGroupId = validatedData.clinicGroupId;
|
|
83
|
-
console.log("[CLINIC_ADMIN] Checking clinic group situation", {
|
|
84
|
-
isGroupOwner: validatedData.isGroupOwner,
|
|
85
|
-
hasGroupId: !!clinicGroupId,
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
// For owners creating a new group, we'll set the group ID later
|
|
89
|
-
if (validatedData.isGroupOwner && !clinicGroupId) {
|
|
90
|
-
console.log("[CLINIC_ADMIN] Owner will be assigned to group later");
|
|
91
|
-
// Skip creating default group here - will be done in auth service
|
|
92
|
-
}
|
|
93
|
-
// Ako nije owner a nemamo groupId, to je greška
|
|
94
|
-
else if (!validatedData.isGroupOwner && !clinicGroupId) {
|
|
95
|
-
console.error("[CLINIC_ADMIN] Missing clinic group ID for non-owner admin");
|
|
96
|
-
throw new Error("Clinic group ID is required for non-owner admins");
|
|
97
|
-
}
|
|
98
|
-
// Ako nije owner a imamo groupId, proverimo da li grupa postoji
|
|
99
|
-
else if (!validatedData.isGroupOwner && clinicGroupId) {
|
|
100
|
-
console.log("[CLINIC_ADMIN] Checking if specified clinic group exists", {
|
|
101
|
-
groupId: clinicGroupId,
|
|
102
|
-
});
|
|
103
|
-
try {
|
|
104
|
-
const groupExists = await checkClinicGroupExists(
|
|
105
|
-
db,
|
|
106
|
-
clinicGroupId,
|
|
107
|
-
clinicGroupService
|
|
108
|
-
);
|
|
109
|
-
if (!groupExists) {
|
|
110
|
-
console.error("[CLINIC_ADMIN] Specified clinic group does not exist", {
|
|
111
|
-
groupId: clinicGroupId,
|
|
112
|
-
});
|
|
113
|
-
throw new Error("Specified clinic group does not exist");
|
|
114
|
-
}
|
|
115
|
-
console.log("[CLINIC_ADMIN] Specified clinic group exists");
|
|
116
|
-
} catch (groupCheckError) {
|
|
117
|
-
console.error(
|
|
118
|
-
"[CLINIC_ADMIN] Error checking if clinic group exists:",
|
|
119
|
-
groupCheckError
|
|
120
|
-
);
|
|
121
|
-
throw groupCheckError;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
console.log("[CLINIC_ADMIN] Preparing admin data object");
|
|
126
|
-
|
|
127
|
-
// Allow creating admin without a clinic group for owners
|
|
128
|
-
const adminData: Omit<ClinicAdmin, "createdAt" | "updatedAt"> & {
|
|
129
|
-
createdAt: ReturnType<typeof serverTimestamp>;
|
|
130
|
-
updatedAt: ReturnType<typeof serverTimestamp>;
|
|
131
|
-
} = {
|
|
132
|
-
id: doc(collection(db, CLINIC_ADMINS_COLLECTION)).id, // Generate a new ID for the admin document
|
|
133
|
-
userRef: validatedData.userRef,
|
|
134
|
-
clinicGroupId: clinicGroupId || "", // Empty string for now if no group ID
|
|
135
|
-
isGroupOwner: validatedData.isGroupOwner,
|
|
136
|
-
clinicsManaged: [], // Uvek krećemo od prazne liste
|
|
137
|
-
clinicsManagedInfo: [], // Empty array for clinic info
|
|
138
|
-
contactInfo: validatedData.contactInfo,
|
|
139
|
-
roleTitle: validatedData.roleTitle,
|
|
140
|
-
isActive: validatedData.isActive,
|
|
141
|
-
createdAt: serverTimestamp(),
|
|
142
|
-
updatedAt: serverTimestamp(),
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
// Validacija kompletnog objekta
|
|
146
|
-
console.log("[CLINIC_ADMIN] Validating complete admin object");
|
|
147
|
-
try {
|
|
148
|
-
clinicAdminSchema.parse({
|
|
149
|
-
...adminData,
|
|
150
|
-
createdAt: Timestamp.now(),
|
|
151
|
-
updatedAt: Timestamp.now(),
|
|
152
|
-
});
|
|
153
|
-
console.log("[CLINIC_ADMIN] Admin object validation passed");
|
|
154
|
-
} catch (schemaError) {
|
|
155
|
-
console.error(
|
|
156
|
-
"[CLINIC_ADMIN] Admin object validation failed:",
|
|
157
|
-
JSON.stringify(schemaError, null, 2)
|
|
158
|
-
);
|
|
159
|
-
throw schemaError;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Čuvamo u Firestore
|
|
163
|
-
console.log("[CLINIC_ADMIN] Saving admin to Firestore", {
|
|
164
|
-
adminId: adminData.id,
|
|
165
|
-
});
|
|
166
|
-
try {
|
|
167
|
-
await setDoc(doc(db, CLINIC_ADMINS_COLLECTION, adminData.id), adminData);
|
|
168
|
-
console.log("[CLINIC_ADMIN] Admin saved successfully");
|
|
169
|
-
} catch (firestoreError) {
|
|
170
|
-
console.error(
|
|
171
|
-
"[CLINIC_ADMIN] Error saving admin to Firestore:",
|
|
172
|
-
firestoreError
|
|
173
|
-
);
|
|
174
|
-
throw firestoreError;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Dodajemo admina u grupu
|
|
178
|
-
if (clinicGroupId) {
|
|
179
|
-
console.log("[CLINIC_ADMIN] Adding admin to clinic group", {
|
|
180
|
-
adminId: adminData.id,
|
|
181
|
-
groupId: clinicGroupId,
|
|
182
|
-
});
|
|
183
|
-
try {
|
|
184
|
-
await clinicGroupService.addAdminToGroup(clinicGroupId, adminData.id);
|
|
185
|
-
console.log("[CLINIC_ADMIN] Admin added to group successfully");
|
|
186
|
-
} catch (addToGroupError) {
|
|
187
|
-
console.error(
|
|
188
|
-
"[CLINIC_ADMIN] Error adding admin to group:",
|
|
189
|
-
addToGroupError
|
|
190
|
-
);
|
|
191
|
-
throw addToGroupError;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// Vraćamo kreirani objekat
|
|
196
|
-
console.log("[CLINIC_ADMIN] Retrieving created admin");
|
|
197
|
-
try {
|
|
198
|
-
const createdAdmin = await getClinicAdmin(db, adminData.id);
|
|
199
|
-
if (!createdAdmin) {
|
|
200
|
-
console.error("[CLINIC_ADMIN] Failed to retrieve created admin");
|
|
201
|
-
throw new Error("Failed to retrieve created admin");
|
|
202
|
-
}
|
|
203
|
-
console.log("[CLINIC_ADMIN] Admin creation completed successfully", {
|
|
204
|
-
adminId: createdAdmin.id,
|
|
205
|
-
});
|
|
206
|
-
return createdAdmin;
|
|
207
|
-
} catch (retrieveError) {
|
|
208
|
-
console.error(
|
|
209
|
-
"[CLINIC_ADMIN] Error retrieving created admin:",
|
|
210
|
-
retrieveError
|
|
211
|
-
);
|
|
212
|
-
throw retrieveError;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Checks if a clinic group exists
|
|
218
|
-
* @param db - Firestore database instance
|
|
219
|
-
* @param groupId - ID of the clinic group
|
|
220
|
-
* @param clinicGroupService - Service for clinic group operations
|
|
221
|
-
* @returns Whether the clinic group exists
|
|
222
|
-
*/
|
|
223
|
-
export async function checkClinicGroupExists(
|
|
224
|
-
db: Firestore,
|
|
225
|
-
groupId: string,
|
|
226
|
-
clinicGroupService: any
|
|
227
|
-
): Promise<boolean> {
|
|
228
|
-
const group = await clinicGroupService.getClinicGroup(groupId);
|
|
229
|
-
return !!group;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Gets a clinic admin by ID
|
|
234
|
-
* @param db - Firestore database instance
|
|
235
|
-
* @param adminId - ID of the admin
|
|
236
|
-
* @returns The clinic admin or null if not found
|
|
237
|
-
*/
|
|
238
|
-
export async function getClinicAdmin(
|
|
239
|
-
db: Firestore,
|
|
240
|
-
adminId: string
|
|
241
|
-
): Promise<ClinicAdmin | null> {
|
|
242
|
-
const docRef = doc(db, CLINIC_ADMINS_COLLECTION, adminId);
|
|
243
|
-
const docSnap = await getDoc(docRef);
|
|
244
|
-
|
|
245
|
-
if (docSnap.exists()) {
|
|
246
|
-
return docSnap.data() as ClinicAdmin;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
return null;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Gets a clinic admin by user reference
|
|
254
|
-
* @param db - Firestore database instance
|
|
255
|
-
* @param userRef - User reference
|
|
256
|
-
* @returns The clinic admin or null if not found
|
|
257
|
-
*/
|
|
258
|
-
export async function getClinicAdminByUserRef(
|
|
259
|
-
db: Firestore,
|
|
260
|
-
userRef: string
|
|
261
|
-
): Promise<ClinicAdmin | null> {
|
|
262
|
-
const q = query(
|
|
263
|
-
collection(db, CLINIC_ADMINS_COLLECTION),
|
|
264
|
-
where("userRef", "==", userRef)
|
|
265
|
-
);
|
|
266
|
-
|
|
267
|
-
const querySnapshot = await getDocs(q);
|
|
268
|
-
if (querySnapshot.empty) {
|
|
269
|
-
return null;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
return querySnapshot.docs[0].data() as ClinicAdmin;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Gets all clinic admins in a group
|
|
277
|
-
* @param db - Firestore database instance
|
|
278
|
-
* @param clinicGroupId - ID of the clinic group
|
|
279
|
-
* @returns Array of clinic admins in the group
|
|
280
|
-
*/
|
|
281
|
-
export async function getClinicAdminsByGroup(
|
|
282
|
-
db: Firestore,
|
|
283
|
-
clinicGroupId: string
|
|
284
|
-
): Promise<ClinicAdmin[]> {
|
|
285
|
-
const q = query(
|
|
286
|
-
collection(db, CLINIC_ADMINS_COLLECTION),
|
|
287
|
-
where("clinicGroupId", "==", clinicGroupId)
|
|
288
|
-
);
|
|
289
|
-
|
|
290
|
-
const querySnapshot = await getDocs(q);
|
|
291
|
-
return querySnapshot.docs.map((doc) => doc.data() as ClinicAdmin);
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* Updates a clinic admin
|
|
296
|
-
* @param db - Firestore database instance
|
|
297
|
-
* @param adminId - ID of the admin to update
|
|
298
|
-
* @param data - Data to update
|
|
299
|
-
* @returns The updated clinic admin
|
|
300
|
-
*/
|
|
301
|
-
export async function updateClinicAdmin(
|
|
302
|
-
db: Firestore,
|
|
303
|
-
adminId: string,
|
|
304
|
-
data: UpdateClinicAdminData
|
|
305
|
-
): Promise<ClinicAdmin> {
|
|
306
|
-
const admin = await getClinicAdmin(db, adminId);
|
|
307
|
-
if (!admin) {
|
|
308
|
-
throw new Error("Clinic admin not found");
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// Ažuriramo podatke
|
|
312
|
-
const updatedData = {
|
|
313
|
-
...data,
|
|
314
|
-
updatedAt: serverTimestamp(),
|
|
315
|
-
};
|
|
316
|
-
|
|
317
|
-
await updateDoc(doc(db, CLINIC_ADMINS_COLLECTION, adminId), updatedData);
|
|
318
|
-
|
|
319
|
-
// Vraćamo ažurirane podatke
|
|
320
|
-
const updatedAdmin = await getClinicAdmin(db, adminId);
|
|
321
|
-
if (!updatedAdmin) {
|
|
322
|
-
throw new Error("Failed to retrieve updated admin");
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
return updatedAdmin;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* Deletes a clinic admin
|
|
330
|
-
* @param db - Firestore database instance
|
|
331
|
-
* @param adminId - ID of the admin to delete
|
|
332
|
-
*/
|
|
333
|
-
export async function deleteClinicAdmin(
|
|
334
|
-
db: Firestore,
|
|
335
|
-
adminId: string
|
|
336
|
-
): Promise<void> {
|
|
337
|
-
const admin = await getClinicAdmin(db, adminId);
|
|
338
|
-
if (!admin) {
|
|
339
|
-
throw new Error("Clinic admin not found");
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
await deleteDoc(doc(db, CLINIC_ADMINS_COLLECTION, adminId));
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
/**
|
|
346
|
-
* Adds a clinic to an admin's managed clinics
|
|
347
|
-
* @param db - Firestore database instance
|
|
348
|
-
* @param adminId - ID of the admin
|
|
349
|
-
* @param clinicId - ID of the clinic to add
|
|
350
|
-
* @param requesterId - ID of the admin making the request
|
|
351
|
-
* @param clinicService - Service for clinic operations
|
|
352
|
-
*/
|
|
353
|
-
export async function addClinicToManaged(
|
|
354
|
-
db: Firestore,
|
|
355
|
-
adminId: string,
|
|
356
|
-
clinicId: string,
|
|
357
|
-
requesterId?: string,
|
|
358
|
-
clinicService?: any
|
|
359
|
-
): Promise<void> {
|
|
360
|
-
const admin = await getClinicAdmin(db, adminId);
|
|
361
|
-
if (!admin) {
|
|
362
|
-
throw new Error("Clinic admin not found");
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
// Ako je prosleđen requester, proveravamo da li ima prava
|
|
366
|
-
if (requesterId && requesterId !== adminId) {
|
|
367
|
-
const requester = await getClinicAdmin(db, requesterId);
|
|
368
|
-
if (!requester) {
|
|
369
|
-
throw new Error("Requester admin not found");
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// Samo owner grupe može da dodaje klinike drugim adminima
|
|
373
|
-
if (
|
|
374
|
-
!requester.isGroupOwner ||
|
|
375
|
-
requester.clinicGroupId !== admin.clinicGroupId
|
|
376
|
-
) {
|
|
377
|
-
throw new Error("Only group owner can add clinics to other admins");
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
// Proveravamo da li klinika već postoji u listi
|
|
382
|
-
if (admin.clinicsManaged.includes(clinicId)) {
|
|
383
|
-
return; // Klinika je već u listi
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// Ažuriramo listu klinika
|
|
387
|
-
await updateClinicAdmin(db, adminId, {
|
|
388
|
-
clinicsManaged: [...admin.clinicsManaged, clinicId],
|
|
389
|
-
});
|
|
390
|
-
|
|
391
|
-
// Ako imamo clinicService, dohvatamo info o klinici i dodajemo ga u clinicsManagedInfo
|
|
392
|
-
if (clinicService) {
|
|
393
|
-
const clinic = await clinicService.getClinic(clinicId);
|
|
394
|
-
if (clinic) {
|
|
395
|
-
await updateClinicAdmin(db, adminId, {
|
|
396
|
-
clinicsManagedInfo: [
|
|
397
|
-
...admin.clinicsManagedInfo,
|
|
398
|
-
{
|
|
399
|
-
id: clinic.id,
|
|
400
|
-
featuredPhoto: clinic.featuredPhotos[0] || "",
|
|
401
|
-
name: clinic.name,
|
|
402
|
-
description: clinic.description,
|
|
403
|
-
location: clinic.location,
|
|
404
|
-
contactInfo: clinic.contactInfo,
|
|
405
|
-
},
|
|
406
|
-
],
|
|
407
|
-
});
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* Removes a clinic from an admin's managed clinics
|
|
414
|
-
* @param db - Firestore database instance
|
|
415
|
-
* @param adminId - ID of the admin
|
|
416
|
-
* @param clinicId - ID of the clinic to remove
|
|
417
|
-
* @param requesterId - ID of the admin making the request
|
|
418
|
-
*/
|
|
419
|
-
export async function removeClinicFromManaged(
|
|
420
|
-
db: Firestore,
|
|
421
|
-
adminId: string,
|
|
422
|
-
clinicId: string,
|
|
423
|
-
requesterId?: string
|
|
424
|
-
): Promise<void> {
|
|
425
|
-
const admin = await getClinicAdmin(db, adminId);
|
|
426
|
-
if (!admin) {
|
|
427
|
-
throw new Error("Clinic admin not found");
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
// Ako je prosleđen requester, proveravamo da li ima prava
|
|
431
|
-
if (requesterId && requesterId !== adminId) {
|
|
432
|
-
const requester = await getClinicAdmin(db, requesterId);
|
|
433
|
-
if (!requester) {
|
|
434
|
-
throw new Error("Requester admin not found");
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
// Samo owner grupe može da uklanja klinike drugim adminima
|
|
438
|
-
if (
|
|
439
|
-
!requester.isGroupOwner ||
|
|
440
|
-
requester.clinicGroupId !== admin.clinicGroupId
|
|
441
|
-
) {
|
|
442
|
-
throw new Error("Only group owner can remove clinics from other admins");
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
// Proveravamo da li klinika postoji u listi
|
|
447
|
-
if (!admin.clinicsManaged.includes(clinicId)) {
|
|
448
|
-
return; // Klinika nije u listi
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
// Ažuriramo listu klinika
|
|
452
|
-
await updateClinicAdmin(db, adminId, {
|
|
453
|
-
clinicsManaged: admin.clinicsManaged.filter((id) => id !== clinicId),
|
|
454
|
-
clinicsManagedInfo: admin.clinicsManagedInfo.filter(
|
|
455
|
-
(info) => info.id !== clinicId
|
|
456
|
-
),
|
|
457
|
-
});
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
/**
|
|
461
|
-
* Gets clinics managed by an admin
|
|
462
|
-
* @param db - Firestore database instance
|
|
463
|
-
* @param adminId - ID of the admin
|
|
464
|
-
* @param clinicService - Service for clinic operations
|
|
465
|
-
* @returns Array of clinics managed by the admin
|
|
466
|
-
*/
|
|
467
|
-
export async function getManagedClinics(
|
|
468
|
-
db: Firestore,
|
|
469
|
-
adminId: string,
|
|
470
|
-
clinicService: any
|
|
471
|
-
): Promise<any[]> {
|
|
472
|
-
const admin = await getClinicAdmin(db, adminId);
|
|
473
|
-
if (!admin) {
|
|
474
|
-
throw new Error("Clinic admin not found");
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
if (admin.clinicsManaged.length === 0) {
|
|
478
|
-
return [];
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
return clinicService.getClinicsByAdmin(adminId);
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
/**
|
|
485
|
-
* Gets active clinics managed by an admin
|
|
486
|
-
* @param db - Firestore database instance
|
|
487
|
-
* @param adminId - ID of the admin
|
|
488
|
-
* @param clinicService - Service for clinic operations
|
|
489
|
-
* @returns Array of active clinics managed by the admin
|
|
490
|
-
*/
|
|
491
|
-
export async function getActiveManagedClinics(
|
|
492
|
-
db: Firestore,
|
|
493
|
-
adminId: string,
|
|
494
|
-
clinicService: any
|
|
495
|
-
): Promise<any[]> {
|
|
496
|
-
const admin = await getClinicAdmin(db, adminId);
|
|
497
|
-
if (!admin) {
|
|
498
|
-
throw new Error("Clinic admin not found");
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
if (admin.clinicsManaged.length === 0) {
|
|
502
|
-
return [];
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
return clinicService.getActiveClinicsByAdmin(adminId);
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
/**
|
|
509
|
-
* Syncs an admin's managed clinics info
|
|
510
|
-
* @param db - Firestore database instance
|
|
511
|
-
* @param adminId - ID of the admin
|
|
512
|
-
* @param clinicService - Service for clinic operations
|
|
513
|
-
*/
|
|
514
|
-
export async function syncOwnerClinics(
|
|
515
|
-
db: Firestore,
|
|
516
|
-
adminId: string,
|
|
517
|
-
clinicService: any,
|
|
518
|
-
clinicGroupService: any
|
|
519
|
-
): Promise<void> {
|
|
520
|
-
const admin = await getClinicAdmin(db, adminId);
|
|
521
|
-
if (!admin) {
|
|
522
|
-
throw new Error("Clinic admin not found");
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
// Samo za vlasnike grupa
|
|
526
|
-
if (!admin.isGroupOwner) {
|
|
527
|
-
return;
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
// Dohvatamo grupu
|
|
531
|
-
const group = await clinicGroupService.getClinicGroup(admin.clinicGroupId);
|
|
532
|
-
if (!group) {
|
|
533
|
-
throw new Error("Clinic group not found");
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
// Dohvatamo sve klinike grupe
|
|
537
|
-
const clinics = await clinicService.getClinicsByGroup(admin.clinicGroupId);
|
|
538
|
-
|
|
539
|
-
// Ažuriramo listu klinika
|
|
540
|
-
await updateClinicAdmin(db, adminId, {
|
|
541
|
-
clinicsManaged: clinics.map((clinic: any) => clinic.id),
|
|
542
|
-
clinicsManagedInfo: clinics.map((clinic: any) => ({
|
|
543
|
-
id: clinic.id,
|
|
544
|
-
featuredPhoto: clinic.featuredPhotos[0] || "",
|
|
545
|
-
name: clinic.name,
|
|
546
|
-
description: clinic.description,
|
|
547
|
-
location: clinic.location,
|
|
548
|
-
contactInfo: clinic.contactInfo,
|
|
549
|
-
})),
|
|
550
|
-
});
|
|
551
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
collection,
|
|
3
|
+
doc,
|
|
4
|
+
getDoc,
|
|
5
|
+
getDocs,
|
|
6
|
+
query,
|
|
7
|
+
where,
|
|
8
|
+
updateDoc,
|
|
9
|
+
setDoc,
|
|
10
|
+
deleteDoc,
|
|
11
|
+
Timestamp,
|
|
12
|
+
Firestore,
|
|
13
|
+
serverTimestamp,
|
|
14
|
+
FieldValue,
|
|
15
|
+
} from "firebase/firestore";
|
|
16
|
+
import {
|
|
17
|
+
ClinicAdmin,
|
|
18
|
+
CreateClinicAdminData,
|
|
19
|
+
UpdateClinicAdminData,
|
|
20
|
+
CLINIC_ADMINS_COLLECTION,
|
|
21
|
+
CreateDefaultClinicGroupData,
|
|
22
|
+
} from "../../../types/clinic";
|
|
23
|
+
import {
|
|
24
|
+
clinicAdminSchema,
|
|
25
|
+
createClinicAdminSchema,
|
|
26
|
+
} from "../../../validations/clinic.schema";
|
|
27
|
+
import { z } from "zod";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Creates a new clinic admin
|
|
31
|
+
* @param db - Firestore database instance
|
|
32
|
+
* @param data - Admin data
|
|
33
|
+
* @param clinicGroupService - Service for clinic group operations
|
|
34
|
+
* @returns The created clinic admin
|
|
35
|
+
*/
|
|
36
|
+
export async function createClinicAdmin(
|
|
37
|
+
db: Firestore,
|
|
38
|
+
data: CreateClinicAdminData,
|
|
39
|
+
clinicGroupService: any
|
|
40
|
+
): Promise<ClinicAdmin> {
|
|
41
|
+
console.log("[CLINIC_ADMIN] Starting clinic admin creation", {
|
|
42
|
+
userRef: data.userRef,
|
|
43
|
+
});
|
|
44
|
+
console.log("[CLINIC_ADMIN] Input data:", JSON.stringify(data, null, 2));
|
|
45
|
+
|
|
46
|
+
// Validacija podataka
|
|
47
|
+
try {
|
|
48
|
+
const validatedData = createClinicAdminSchema.parse(data);
|
|
49
|
+
console.log("[CLINIC_ADMIN] Data validation passed");
|
|
50
|
+
} catch (validationError) {
|
|
51
|
+
console.error("[CLINIC_ADMIN] Data validation failed:", validationError);
|
|
52
|
+
throw validationError;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const validatedData = createClinicAdminSchema.parse(data);
|
|
56
|
+
|
|
57
|
+
// Proveravamo da li korisnik već ima admin profil
|
|
58
|
+
console.log("[CLINIC_ADMIN] Checking if user already has an admin profile", {
|
|
59
|
+
userRef: validatedData.userRef,
|
|
60
|
+
});
|
|
61
|
+
try {
|
|
62
|
+
const existingAdmin = await getClinicAdminByUserRef(
|
|
63
|
+
db,
|
|
64
|
+
validatedData.userRef
|
|
65
|
+
);
|
|
66
|
+
if (existingAdmin) {
|
|
67
|
+
console.error("[CLINIC_ADMIN] User already has an admin profile", {
|
|
68
|
+
adminId: existingAdmin.id,
|
|
69
|
+
});
|
|
70
|
+
throw new Error("User already has an admin profile");
|
|
71
|
+
}
|
|
72
|
+
console.log("[CLINIC_ADMIN] User does not have an existing admin profile");
|
|
73
|
+
} catch (error: any) {
|
|
74
|
+
if (error.message === "User already has an admin profile") {
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
console.error("[CLINIC_ADMIN] Error checking for existing admin:", error);
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Ako je owner, kreiramo default grupu ako nije prosleđen groupId
|
|
82
|
+
let clinicGroupId = validatedData.clinicGroupId;
|
|
83
|
+
console.log("[CLINIC_ADMIN] Checking clinic group situation", {
|
|
84
|
+
isGroupOwner: validatedData.isGroupOwner,
|
|
85
|
+
hasGroupId: !!clinicGroupId,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// For owners creating a new group, we'll set the group ID later
|
|
89
|
+
if (validatedData.isGroupOwner && !clinicGroupId) {
|
|
90
|
+
console.log("[CLINIC_ADMIN] Owner will be assigned to group later");
|
|
91
|
+
// Skip creating default group here - will be done in auth service
|
|
92
|
+
}
|
|
93
|
+
// Ako nije owner a nemamo groupId, to je greška
|
|
94
|
+
else if (!validatedData.isGroupOwner && !clinicGroupId) {
|
|
95
|
+
console.error("[CLINIC_ADMIN] Missing clinic group ID for non-owner admin");
|
|
96
|
+
throw new Error("Clinic group ID is required for non-owner admins");
|
|
97
|
+
}
|
|
98
|
+
// Ako nije owner a imamo groupId, proverimo da li grupa postoji
|
|
99
|
+
else if (!validatedData.isGroupOwner && clinicGroupId) {
|
|
100
|
+
console.log("[CLINIC_ADMIN] Checking if specified clinic group exists", {
|
|
101
|
+
groupId: clinicGroupId,
|
|
102
|
+
});
|
|
103
|
+
try {
|
|
104
|
+
const groupExists = await checkClinicGroupExists(
|
|
105
|
+
db,
|
|
106
|
+
clinicGroupId,
|
|
107
|
+
clinicGroupService
|
|
108
|
+
);
|
|
109
|
+
if (!groupExists) {
|
|
110
|
+
console.error("[CLINIC_ADMIN] Specified clinic group does not exist", {
|
|
111
|
+
groupId: clinicGroupId,
|
|
112
|
+
});
|
|
113
|
+
throw new Error("Specified clinic group does not exist");
|
|
114
|
+
}
|
|
115
|
+
console.log("[CLINIC_ADMIN] Specified clinic group exists");
|
|
116
|
+
} catch (groupCheckError) {
|
|
117
|
+
console.error(
|
|
118
|
+
"[CLINIC_ADMIN] Error checking if clinic group exists:",
|
|
119
|
+
groupCheckError
|
|
120
|
+
);
|
|
121
|
+
throw groupCheckError;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
console.log("[CLINIC_ADMIN] Preparing admin data object");
|
|
126
|
+
|
|
127
|
+
// Allow creating admin without a clinic group for owners
|
|
128
|
+
const adminData: Omit<ClinicAdmin, "createdAt" | "updatedAt"> & {
|
|
129
|
+
createdAt: ReturnType<typeof serverTimestamp>;
|
|
130
|
+
updatedAt: ReturnType<typeof serverTimestamp>;
|
|
131
|
+
} = {
|
|
132
|
+
id: doc(collection(db, CLINIC_ADMINS_COLLECTION)).id, // Generate a new ID for the admin document
|
|
133
|
+
userRef: validatedData.userRef,
|
|
134
|
+
clinicGroupId: clinicGroupId || "", // Empty string for now if no group ID
|
|
135
|
+
isGroupOwner: validatedData.isGroupOwner,
|
|
136
|
+
clinicsManaged: [], // Uvek krećemo od prazne liste
|
|
137
|
+
clinicsManagedInfo: [], // Empty array for clinic info
|
|
138
|
+
contactInfo: validatedData.contactInfo,
|
|
139
|
+
roleTitle: validatedData.roleTitle,
|
|
140
|
+
isActive: validatedData.isActive,
|
|
141
|
+
createdAt: serverTimestamp(),
|
|
142
|
+
updatedAt: serverTimestamp(),
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// Validacija kompletnog objekta
|
|
146
|
+
console.log("[CLINIC_ADMIN] Validating complete admin object");
|
|
147
|
+
try {
|
|
148
|
+
clinicAdminSchema.parse({
|
|
149
|
+
...adminData,
|
|
150
|
+
createdAt: Timestamp.now(),
|
|
151
|
+
updatedAt: Timestamp.now(),
|
|
152
|
+
});
|
|
153
|
+
console.log("[CLINIC_ADMIN] Admin object validation passed");
|
|
154
|
+
} catch (schemaError) {
|
|
155
|
+
console.error(
|
|
156
|
+
"[CLINIC_ADMIN] Admin object validation failed:",
|
|
157
|
+
JSON.stringify(schemaError, null, 2)
|
|
158
|
+
);
|
|
159
|
+
throw schemaError;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Čuvamo u Firestore
|
|
163
|
+
console.log("[CLINIC_ADMIN] Saving admin to Firestore", {
|
|
164
|
+
adminId: adminData.id,
|
|
165
|
+
});
|
|
166
|
+
try {
|
|
167
|
+
await setDoc(doc(db, CLINIC_ADMINS_COLLECTION, adminData.id), adminData);
|
|
168
|
+
console.log("[CLINIC_ADMIN] Admin saved successfully");
|
|
169
|
+
} catch (firestoreError) {
|
|
170
|
+
console.error(
|
|
171
|
+
"[CLINIC_ADMIN] Error saving admin to Firestore:",
|
|
172
|
+
firestoreError
|
|
173
|
+
);
|
|
174
|
+
throw firestoreError;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Dodajemo admina u grupu
|
|
178
|
+
if (clinicGroupId) {
|
|
179
|
+
console.log("[CLINIC_ADMIN] Adding admin to clinic group", {
|
|
180
|
+
adminId: adminData.id,
|
|
181
|
+
groupId: clinicGroupId,
|
|
182
|
+
});
|
|
183
|
+
try {
|
|
184
|
+
await clinicGroupService.addAdminToGroup(clinicGroupId, adminData.id);
|
|
185
|
+
console.log("[CLINIC_ADMIN] Admin added to group successfully");
|
|
186
|
+
} catch (addToGroupError) {
|
|
187
|
+
console.error(
|
|
188
|
+
"[CLINIC_ADMIN] Error adding admin to group:",
|
|
189
|
+
addToGroupError
|
|
190
|
+
);
|
|
191
|
+
throw addToGroupError;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Vraćamo kreirani objekat
|
|
196
|
+
console.log("[CLINIC_ADMIN] Retrieving created admin");
|
|
197
|
+
try {
|
|
198
|
+
const createdAdmin = await getClinicAdmin(db, adminData.id);
|
|
199
|
+
if (!createdAdmin) {
|
|
200
|
+
console.error("[CLINIC_ADMIN] Failed to retrieve created admin");
|
|
201
|
+
throw new Error("Failed to retrieve created admin");
|
|
202
|
+
}
|
|
203
|
+
console.log("[CLINIC_ADMIN] Admin creation completed successfully", {
|
|
204
|
+
adminId: createdAdmin.id,
|
|
205
|
+
});
|
|
206
|
+
return createdAdmin;
|
|
207
|
+
} catch (retrieveError) {
|
|
208
|
+
console.error(
|
|
209
|
+
"[CLINIC_ADMIN] Error retrieving created admin:",
|
|
210
|
+
retrieveError
|
|
211
|
+
);
|
|
212
|
+
throw retrieveError;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Checks if a clinic group exists
|
|
218
|
+
* @param db - Firestore database instance
|
|
219
|
+
* @param groupId - ID of the clinic group
|
|
220
|
+
* @param clinicGroupService - Service for clinic group operations
|
|
221
|
+
* @returns Whether the clinic group exists
|
|
222
|
+
*/
|
|
223
|
+
export async function checkClinicGroupExists(
|
|
224
|
+
db: Firestore,
|
|
225
|
+
groupId: string,
|
|
226
|
+
clinicGroupService: any
|
|
227
|
+
): Promise<boolean> {
|
|
228
|
+
const group = await clinicGroupService.getClinicGroup(groupId);
|
|
229
|
+
return !!group;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Gets a clinic admin by ID
|
|
234
|
+
* @param db - Firestore database instance
|
|
235
|
+
* @param adminId - ID of the admin
|
|
236
|
+
* @returns The clinic admin or null if not found
|
|
237
|
+
*/
|
|
238
|
+
export async function getClinicAdmin(
|
|
239
|
+
db: Firestore,
|
|
240
|
+
adminId: string
|
|
241
|
+
): Promise<ClinicAdmin | null> {
|
|
242
|
+
const docRef = doc(db, CLINIC_ADMINS_COLLECTION, adminId);
|
|
243
|
+
const docSnap = await getDoc(docRef);
|
|
244
|
+
|
|
245
|
+
if (docSnap.exists()) {
|
|
246
|
+
return docSnap.data() as ClinicAdmin;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Gets a clinic admin by user reference
|
|
254
|
+
* @param db - Firestore database instance
|
|
255
|
+
* @param userRef - User reference
|
|
256
|
+
* @returns The clinic admin or null if not found
|
|
257
|
+
*/
|
|
258
|
+
export async function getClinicAdminByUserRef(
|
|
259
|
+
db: Firestore,
|
|
260
|
+
userRef: string
|
|
261
|
+
): Promise<ClinicAdmin | null> {
|
|
262
|
+
const q = query(
|
|
263
|
+
collection(db, CLINIC_ADMINS_COLLECTION),
|
|
264
|
+
where("userRef", "==", userRef)
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
const querySnapshot = await getDocs(q);
|
|
268
|
+
if (querySnapshot.empty) {
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return querySnapshot.docs[0].data() as ClinicAdmin;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Gets all clinic admins in a group
|
|
277
|
+
* @param db - Firestore database instance
|
|
278
|
+
* @param clinicGroupId - ID of the clinic group
|
|
279
|
+
* @returns Array of clinic admins in the group
|
|
280
|
+
*/
|
|
281
|
+
export async function getClinicAdminsByGroup(
|
|
282
|
+
db: Firestore,
|
|
283
|
+
clinicGroupId: string
|
|
284
|
+
): Promise<ClinicAdmin[]> {
|
|
285
|
+
const q = query(
|
|
286
|
+
collection(db, CLINIC_ADMINS_COLLECTION),
|
|
287
|
+
where("clinicGroupId", "==", clinicGroupId)
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
const querySnapshot = await getDocs(q);
|
|
291
|
+
return querySnapshot.docs.map((doc) => doc.data() as ClinicAdmin);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Updates a clinic admin
|
|
296
|
+
* @param db - Firestore database instance
|
|
297
|
+
* @param adminId - ID of the admin to update
|
|
298
|
+
* @param data - Data to update
|
|
299
|
+
* @returns The updated clinic admin
|
|
300
|
+
*/
|
|
301
|
+
export async function updateClinicAdmin(
|
|
302
|
+
db: Firestore,
|
|
303
|
+
adminId: string,
|
|
304
|
+
data: UpdateClinicAdminData
|
|
305
|
+
): Promise<ClinicAdmin> {
|
|
306
|
+
const admin = await getClinicAdmin(db, adminId);
|
|
307
|
+
if (!admin) {
|
|
308
|
+
throw new Error("Clinic admin not found");
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Ažuriramo podatke
|
|
312
|
+
const updatedData = {
|
|
313
|
+
...data,
|
|
314
|
+
updatedAt: serverTimestamp(),
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
await updateDoc(doc(db, CLINIC_ADMINS_COLLECTION, adminId), updatedData);
|
|
318
|
+
|
|
319
|
+
// Vraćamo ažurirane podatke
|
|
320
|
+
const updatedAdmin = await getClinicAdmin(db, adminId);
|
|
321
|
+
if (!updatedAdmin) {
|
|
322
|
+
throw new Error("Failed to retrieve updated admin");
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return updatedAdmin;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Deletes a clinic admin
|
|
330
|
+
* @param db - Firestore database instance
|
|
331
|
+
* @param adminId - ID of the admin to delete
|
|
332
|
+
*/
|
|
333
|
+
export async function deleteClinicAdmin(
|
|
334
|
+
db: Firestore,
|
|
335
|
+
adminId: string
|
|
336
|
+
): Promise<void> {
|
|
337
|
+
const admin = await getClinicAdmin(db, adminId);
|
|
338
|
+
if (!admin) {
|
|
339
|
+
throw new Error("Clinic admin not found");
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
await deleteDoc(doc(db, CLINIC_ADMINS_COLLECTION, adminId));
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Adds a clinic to an admin's managed clinics
|
|
347
|
+
* @param db - Firestore database instance
|
|
348
|
+
* @param adminId - ID of the admin
|
|
349
|
+
* @param clinicId - ID of the clinic to add
|
|
350
|
+
* @param requesterId - ID of the admin making the request
|
|
351
|
+
* @param clinicService - Service for clinic operations
|
|
352
|
+
*/
|
|
353
|
+
export async function addClinicToManaged(
|
|
354
|
+
db: Firestore,
|
|
355
|
+
adminId: string,
|
|
356
|
+
clinicId: string,
|
|
357
|
+
requesterId?: string,
|
|
358
|
+
clinicService?: any
|
|
359
|
+
): Promise<void> {
|
|
360
|
+
const admin = await getClinicAdmin(db, adminId);
|
|
361
|
+
if (!admin) {
|
|
362
|
+
throw new Error("Clinic admin not found");
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Ako je prosleđen requester, proveravamo da li ima prava
|
|
366
|
+
if (requesterId && requesterId !== adminId) {
|
|
367
|
+
const requester = await getClinicAdmin(db, requesterId);
|
|
368
|
+
if (!requester) {
|
|
369
|
+
throw new Error("Requester admin not found");
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Samo owner grupe može da dodaje klinike drugim adminima
|
|
373
|
+
if (
|
|
374
|
+
!requester.isGroupOwner ||
|
|
375
|
+
requester.clinicGroupId !== admin.clinicGroupId
|
|
376
|
+
) {
|
|
377
|
+
throw new Error("Only group owner can add clinics to other admins");
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Proveravamo da li klinika već postoji u listi
|
|
382
|
+
if (admin.clinicsManaged.includes(clinicId)) {
|
|
383
|
+
return; // Klinika je već u listi
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Ažuriramo listu klinika
|
|
387
|
+
await updateClinicAdmin(db, adminId, {
|
|
388
|
+
clinicsManaged: [...admin.clinicsManaged, clinicId],
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
// Ako imamo clinicService, dohvatamo info o klinici i dodajemo ga u clinicsManagedInfo
|
|
392
|
+
if (clinicService) {
|
|
393
|
+
const clinic = await clinicService.getClinic(clinicId);
|
|
394
|
+
if (clinic) {
|
|
395
|
+
await updateClinicAdmin(db, adminId, {
|
|
396
|
+
clinicsManagedInfo: [
|
|
397
|
+
...admin.clinicsManagedInfo,
|
|
398
|
+
{
|
|
399
|
+
id: clinic.id,
|
|
400
|
+
featuredPhoto: clinic.featuredPhotos[0] || "",
|
|
401
|
+
name: clinic.name,
|
|
402
|
+
description: clinic.description,
|
|
403
|
+
location: clinic.location,
|
|
404
|
+
contactInfo: clinic.contactInfo,
|
|
405
|
+
},
|
|
406
|
+
],
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Removes a clinic from an admin's managed clinics
|
|
414
|
+
* @param db - Firestore database instance
|
|
415
|
+
* @param adminId - ID of the admin
|
|
416
|
+
* @param clinicId - ID of the clinic to remove
|
|
417
|
+
* @param requesterId - ID of the admin making the request
|
|
418
|
+
*/
|
|
419
|
+
export async function removeClinicFromManaged(
|
|
420
|
+
db: Firestore,
|
|
421
|
+
adminId: string,
|
|
422
|
+
clinicId: string,
|
|
423
|
+
requesterId?: string
|
|
424
|
+
): Promise<void> {
|
|
425
|
+
const admin = await getClinicAdmin(db, adminId);
|
|
426
|
+
if (!admin) {
|
|
427
|
+
throw new Error("Clinic admin not found");
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// Ako je prosleđen requester, proveravamo da li ima prava
|
|
431
|
+
if (requesterId && requesterId !== adminId) {
|
|
432
|
+
const requester = await getClinicAdmin(db, requesterId);
|
|
433
|
+
if (!requester) {
|
|
434
|
+
throw new Error("Requester admin not found");
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// Samo owner grupe može da uklanja klinike drugim adminima
|
|
438
|
+
if (
|
|
439
|
+
!requester.isGroupOwner ||
|
|
440
|
+
requester.clinicGroupId !== admin.clinicGroupId
|
|
441
|
+
) {
|
|
442
|
+
throw new Error("Only group owner can remove clinics from other admins");
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Proveravamo da li klinika postoji u listi
|
|
447
|
+
if (!admin.clinicsManaged.includes(clinicId)) {
|
|
448
|
+
return; // Klinika nije u listi
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Ažuriramo listu klinika
|
|
452
|
+
await updateClinicAdmin(db, adminId, {
|
|
453
|
+
clinicsManaged: admin.clinicsManaged.filter((id) => id !== clinicId),
|
|
454
|
+
clinicsManagedInfo: admin.clinicsManagedInfo.filter(
|
|
455
|
+
(info) => info.id !== clinicId
|
|
456
|
+
),
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Gets clinics managed by an admin
|
|
462
|
+
* @param db - Firestore database instance
|
|
463
|
+
* @param adminId - ID of the admin
|
|
464
|
+
* @param clinicService - Service for clinic operations
|
|
465
|
+
* @returns Array of clinics managed by the admin
|
|
466
|
+
*/
|
|
467
|
+
export async function getManagedClinics(
|
|
468
|
+
db: Firestore,
|
|
469
|
+
adminId: string,
|
|
470
|
+
clinicService: any
|
|
471
|
+
): Promise<any[]> {
|
|
472
|
+
const admin = await getClinicAdmin(db, adminId);
|
|
473
|
+
if (!admin) {
|
|
474
|
+
throw new Error("Clinic admin not found");
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
if (admin.clinicsManaged.length === 0) {
|
|
478
|
+
return [];
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
return clinicService.getClinicsByAdmin(adminId);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Gets active clinics managed by an admin
|
|
486
|
+
* @param db - Firestore database instance
|
|
487
|
+
* @param adminId - ID of the admin
|
|
488
|
+
* @param clinicService - Service for clinic operations
|
|
489
|
+
* @returns Array of active clinics managed by the admin
|
|
490
|
+
*/
|
|
491
|
+
export async function getActiveManagedClinics(
|
|
492
|
+
db: Firestore,
|
|
493
|
+
adminId: string,
|
|
494
|
+
clinicService: any
|
|
495
|
+
): Promise<any[]> {
|
|
496
|
+
const admin = await getClinicAdmin(db, adminId);
|
|
497
|
+
if (!admin) {
|
|
498
|
+
throw new Error("Clinic admin not found");
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
if (admin.clinicsManaged.length === 0) {
|
|
502
|
+
return [];
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
return clinicService.getActiveClinicsByAdmin(adminId);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Syncs an admin's managed clinics info
|
|
510
|
+
* @param db - Firestore database instance
|
|
511
|
+
* @param adminId - ID of the admin
|
|
512
|
+
* @param clinicService - Service for clinic operations
|
|
513
|
+
*/
|
|
514
|
+
export async function syncOwnerClinics(
|
|
515
|
+
db: Firestore,
|
|
516
|
+
adminId: string,
|
|
517
|
+
clinicService: any,
|
|
518
|
+
clinicGroupService: any
|
|
519
|
+
): Promise<void> {
|
|
520
|
+
const admin = await getClinicAdmin(db, adminId);
|
|
521
|
+
if (!admin) {
|
|
522
|
+
throw new Error("Clinic admin not found");
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// Samo za vlasnike grupa
|
|
526
|
+
if (!admin.isGroupOwner) {
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// Dohvatamo grupu
|
|
531
|
+
const group = await clinicGroupService.getClinicGroup(admin.clinicGroupId);
|
|
532
|
+
if (!group) {
|
|
533
|
+
throw new Error("Clinic group not found");
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Dohvatamo sve klinike grupe
|
|
537
|
+
const clinics = await clinicService.getClinicsByGroup(admin.clinicGroupId);
|
|
538
|
+
|
|
539
|
+
// Ažuriramo listu klinika
|
|
540
|
+
await updateClinicAdmin(db, adminId, {
|
|
541
|
+
clinicsManaged: clinics.map((clinic: any) => clinic.id),
|
|
542
|
+
clinicsManagedInfo: clinics.map((clinic: any) => ({
|
|
543
|
+
id: clinic.id,
|
|
544
|
+
featuredPhoto: clinic.featuredPhotos[0] || "",
|
|
545
|
+
name: clinic.name,
|
|
546
|
+
description: clinic.description,
|
|
547
|
+
location: clinic.location,
|
|
548
|
+
contactInfo: clinic.contactInfo,
|
|
549
|
+
})),
|
|
550
|
+
});
|
|
551
|
+
}
|