@blackcode_sa/metaestetics-api 1.4.6 → 1.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +374 -69
- package/dist/index.mjs +374 -69
- package/package.json +1 -1
- package/src/services/auth.service.ts +138 -28
- package/src/services/clinic/utils/admin.utils.ts +155 -34
- package/src/services/clinic/utils/clinic-group.utils.ts +99 -12
|
@@ -108,24 +108,58 @@ export class AuthService extends BaseService {
|
|
|
108
108
|
*/
|
|
109
109
|
async signUpClinicAdmin(data: ClinicAdminSignupData): Promise<User> {
|
|
110
110
|
try {
|
|
111
|
+
console.log("[AUTH] Starting clinic admin signup process", {
|
|
112
|
+
email: data.email,
|
|
113
|
+
});
|
|
114
|
+
|
|
111
115
|
// Validate data
|
|
112
|
-
|
|
116
|
+
try {
|
|
117
|
+
await clinicAdminSignupSchema.parseAsync(data);
|
|
118
|
+
console.log("[AUTH] Clinic admin signup data validation passed");
|
|
119
|
+
} catch (validationError) {
|
|
120
|
+
console.error(
|
|
121
|
+
"[AUTH] Validation error in signUpClinicAdmin:",
|
|
122
|
+
validationError
|
|
123
|
+
);
|
|
124
|
+
throw validationError;
|
|
125
|
+
}
|
|
113
126
|
|
|
114
127
|
// Create Firebase user
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
128
|
+
console.log("[AUTH] Creating Firebase user");
|
|
129
|
+
let firebaseUser;
|
|
130
|
+
try {
|
|
131
|
+
const result = await createUserWithEmailAndPassword(
|
|
132
|
+
this.auth,
|
|
133
|
+
data.email,
|
|
134
|
+
data.password
|
|
135
|
+
);
|
|
136
|
+
firebaseUser = result.user;
|
|
137
|
+
console.log("[AUTH] Firebase user created successfully", {
|
|
138
|
+
uid: firebaseUser.uid,
|
|
139
|
+
});
|
|
140
|
+
} catch (firebaseError) {
|
|
141
|
+
console.error("[AUTH] Firebase user creation failed:", firebaseError);
|
|
142
|
+
throw firebaseError;
|
|
143
|
+
}
|
|
120
144
|
|
|
121
145
|
// Create user with CLINIC_ADMIN role
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
146
|
+
console.log("[AUTH] Creating user with CLINIC_ADMIN role");
|
|
147
|
+
let user;
|
|
148
|
+
try {
|
|
149
|
+
user = await this.userService.createUser(
|
|
150
|
+
firebaseUser,
|
|
151
|
+
[UserRole.CLINIC_ADMIN],
|
|
152
|
+
{
|
|
153
|
+
skipProfileCreation: true,
|
|
154
|
+
}
|
|
155
|
+
);
|
|
156
|
+
console.log("[AUTH] User with CLINIC_ADMIN role created successfully", {
|
|
157
|
+
userId: user.uid,
|
|
158
|
+
});
|
|
159
|
+
} catch (userCreationError) {
|
|
160
|
+
console.error("[AUTH] User creation failed:", userCreationError);
|
|
161
|
+
throw userCreationError;
|
|
162
|
+
}
|
|
129
163
|
|
|
130
164
|
// Create contact person object
|
|
131
165
|
const contactPerson: ContactPerson = {
|
|
@@ -135,8 +169,10 @@ export class AuthService extends BaseService {
|
|
|
135
169
|
email: data.email,
|
|
136
170
|
phoneNumber: data.phoneNumber,
|
|
137
171
|
};
|
|
172
|
+
console.log("[AUTH] Contact person object created");
|
|
138
173
|
|
|
139
174
|
// Initialize services
|
|
175
|
+
console.log("[AUTH] Initializing clinic services");
|
|
140
176
|
const clinicAdminService = new ClinicAdminService(
|
|
141
177
|
this.db,
|
|
142
178
|
this.auth,
|
|
@@ -158,10 +194,15 @@ export class AuthService extends BaseService {
|
|
|
158
194
|
|
|
159
195
|
// Set services to resolve circular dependencies
|
|
160
196
|
clinicAdminService.setServices(clinicGroupService, clinicService);
|
|
197
|
+
console.log(
|
|
198
|
+
"[AUTH] Services initialized and circular dependencies resolved"
|
|
199
|
+
);
|
|
161
200
|
|
|
162
201
|
if (data.isCreatingNewGroup) {
|
|
202
|
+
console.log("[AUTH] Creating new clinic group flow");
|
|
163
203
|
// Create new clinic group
|
|
164
204
|
if (!data.clinicGroupData) {
|
|
205
|
+
console.error("[AUTH] Clinic group data is missing");
|
|
165
206
|
throw new Error(
|
|
166
207
|
"Clinic group data is required when creating a new group"
|
|
167
208
|
);
|
|
@@ -180,22 +221,40 @@ export class AuthService extends BaseService {
|
|
|
180
221
|
data.clinicGroupData.subscriptionModel ||
|
|
181
222
|
SubscriptionModel.NO_SUBSCRIPTION,
|
|
182
223
|
};
|
|
224
|
+
console.log("[AUTH] Clinic group data prepared", {
|
|
225
|
+
groupName: createClinicGroupData.name,
|
|
226
|
+
});
|
|
183
227
|
|
|
184
228
|
// Create clinic group
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
229
|
+
try {
|
|
230
|
+
await clinicGroupService.createClinicGroup(
|
|
231
|
+
createClinicGroupData,
|
|
232
|
+
firebaseUser.uid,
|
|
233
|
+
true
|
|
234
|
+
);
|
|
235
|
+
console.log("[AUTH] Clinic group created successfully");
|
|
236
|
+
} catch (groupCreationError) {
|
|
237
|
+
console.error(
|
|
238
|
+
"[AUTH] Clinic group creation failed:",
|
|
239
|
+
groupCreationError
|
|
240
|
+
);
|
|
241
|
+
throw groupCreationError;
|
|
242
|
+
}
|
|
190
243
|
} else {
|
|
244
|
+
console.log("[AUTH] Joining existing clinic group flow");
|
|
191
245
|
// Join existing clinic group with token
|
|
192
246
|
if (!data.inviteToken) {
|
|
247
|
+
console.error("[AUTH] Invite token is missing");
|
|
193
248
|
throw new Error(
|
|
194
249
|
"Invite token is required when joining an existing group"
|
|
195
250
|
);
|
|
196
251
|
}
|
|
252
|
+
console.log("[AUTH] Invite token provided", {
|
|
253
|
+
token: data.inviteToken,
|
|
254
|
+
});
|
|
197
255
|
|
|
198
256
|
// Find the token in the database
|
|
257
|
+
console.log("[AUTH] Searching for token in clinic groups");
|
|
199
258
|
const groupsRef = collection(this.db, CLINIC_GROUPS_COLLECTION);
|
|
200
259
|
const q = query(groupsRef);
|
|
201
260
|
const querySnapshot = await getDocs(q);
|
|
@@ -203,29 +262,56 @@ export class AuthService extends BaseService {
|
|
|
203
262
|
let foundGroup: ClinicGroup | null = null;
|
|
204
263
|
let foundToken: AdminToken | null = null;
|
|
205
264
|
|
|
265
|
+
console.log(
|
|
266
|
+
"[AUTH] Found",
|
|
267
|
+
querySnapshot.size,
|
|
268
|
+
"clinic groups to check"
|
|
269
|
+
);
|
|
206
270
|
for (const docSnapshot of querySnapshot.docs) {
|
|
207
271
|
const group = docSnapshot.data() as ClinicGroup;
|
|
272
|
+
console.log("[AUTH] Checking group", {
|
|
273
|
+
groupId: group.id,
|
|
274
|
+
groupName: group.name,
|
|
275
|
+
});
|
|
208
276
|
|
|
209
277
|
// Find the token in the group's tokens
|
|
210
|
-
const token = group.adminTokens.find(
|
|
211
|
-
|
|
278
|
+
const token = group.adminTokens.find((t) => {
|
|
279
|
+
const isMatch =
|
|
212
280
|
t.token === data.inviteToken &&
|
|
213
281
|
t.status === AdminTokenStatus.ACTIVE &&
|
|
214
|
-
new Date(t.expiresAt.toDate()) > new Date()
|
|
215
|
-
|
|
282
|
+
new Date(t.expiresAt.toDate()) > new Date();
|
|
283
|
+
|
|
284
|
+
console.log("[AUTH] Checking token", {
|
|
285
|
+
tokenId: t.id,
|
|
286
|
+
tokenMatch: t.token === data.inviteToken,
|
|
287
|
+
tokenStatus: t.status,
|
|
288
|
+
tokenActive: t.status === AdminTokenStatus.ACTIVE,
|
|
289
|
+
tokenExpiry: new Date(t.expiresAt.toDate()),
|
|
290
|
+
tokenExpired: new Date(t.expiresAt.toDate()) <= new Date(),
|
|
291
|
+
isMatch,
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
return isMatch;
|
|
295
|
+
});
|
|
216
296
|
|
|
217
297
|
if (token) {
|
|
218
298
|
foundGroup = group;
|
|
219
299
|
foundToken = token;
|
|
300
|
+
console.log("[AUTH] Found matching token in group", {
|
|
301
|
+
groupId: group.id,
|
|
302
|
+
tokenId: token.id,
|
|
303
|
+
});
|
|
220
304
|
break;
|
|
221
305
|
}
|
|
222
306
|
}
|
|
223
307
|
|
|
224
308
|
if (!foundGroup || !foundToken) {
|
|
309
|
+
console.error("[AUTH] No valid token found in any clinic group");
|
|
225
310
|
throw new Error("Invalid or expired invite token");
|
|
226
311
|
}
|
|
227
312
|
|
|
228
313
|
// Create clinic admin
|
|
314
|
+
console.log("[AUTH] Creating clinic admin");
|
|
229
315
|
const createClinicAdminData: CreateClinicAdminData = {
|
|
230
316
|
userRef: firebaseUser.uid,
|
|
231
317
|
clinicGroupId: foundGroup.id,
|
|
@@ -236,27 +322,51 @@ export class AuthService extends BaseService {
|
|
|
236
322
|
isActive: true,
|
|
237
323
|
};
|
|
238
324
|
|
|
239
|
-
|
|
325
|
+
try {
|
|
326
|
+
await clinicAdminService.createClinicAdmin(createClinicAdminData);
|
|
327
|
+
console.log("[AUTH] Clinic admin created successfully");
|
|
328
|
+
} catch (adminCreationError) {
|
|
329
|
+
console.error(
|
|
330
|
+
"[AUTH] Clinic admin creation failed:",
|
|
331
|
+
adminCreationError
|
|
332
|
+
);
|
|
333
|
+
throw adminCreationError;
|
|
334
|
+
}
|
|
240
335
|
|
|
241
336
|
// Mark token as used
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
337
|
+
try {
|
|
338
|
+
await clinicGroupService.verifyAndUseAdminToken(
|
|
339
|
+
foundGroup.id,
|
|
340
|
+
data.inviteToken,
|
|
341
|
+
firebaseUser.uid
|
|
342
|
+
);
|
|
343
|
+
console.log("[AUTH] Token marked as used successfully");
|
|
344
|
+
} catch (tokenUseError) {
|
|
345
|
+
console.error("[AUTH] Failed to mark token as used:", tokenUseError);
|
|
346
|
+
throw tokenUseError;
|
|
347
|
+
}
|
|
247
348
|
}
|
|
248
349
|
|
|
350
|
+
console.log("[AUTH] Clinic admin signup completed successfully", {
|
|
351
|
+
userId: user.uid,
|
|
352
|
+
});
|
|
249
353
|
return user;
|
|
250
354
|
} catch (error) {
|
|
251
355
|
if (error instanceof z.ZodError) {
|
|
356
|
+
console.error(
|
|
357
|
+
"[AUTH] Zod validation error in signUpClinicAdmin:",
|
|
358
|
+
JSON.stringify(error.errors, null, 2)
|
|
359
|
+
);
|
|
252
360
|
throw AUTH_ERRORS.VALIDATION_ERROR;
|
|
253
361
|
}
|
|
254
362
|
|
|
255
363
|
const firebaseError = error as FirebaseError;
|
|
256
364
|
if (firebaseError.code === FirebaseErrorCode.EMAIL_ALREADY_IN_USE) {
|
|
365
|
+
console.error("[AUTH] Email already in use:", data.email);
|
|
257
366
|
throw AUTH_ERRORS.EMAIL_ALREADY_EXISTS;
|
|
258
367
|
}
|
|
259
368
|
|
|
369
|
+
console.error("[AUTH] Unhandled error in signUpClinicAdmin:", error);
|
|
260
370
|
throw error;
|
|
261
371
|
}
|
|
262
372
|
}
|
|
@@ -38,21 +38,55 @@ export async function createClinicAdmin(
|
|
|
38
38
|
data: CreateClinicAdminData,
|
|
39
39
|
clinicGroupService: any
|
|
40
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
|
+
|
|
41
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
|
+
|
|
42
55
|
const validatedData = createClinicAdminSchema.parse(data);
|
|
43
56
|
|
|
44
57
|
// Proveravamo da li korisnik već ima admin profil
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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;
|
|
51
79
|
}
|
|
52
80
|
|
|
53
81
|
// Ako je owner, kreiramo default grupu ako nije prosleđen groupId
|
|
54
82
|
let clinicGroupId = validatedData.clinicGroupId;
|
|
83
|
+
console.log("[CLINIC_ADMIN] Checking clinic group situation", {
|
|
84
|
+
isGroupOwner: validatedData.isGroupOwner,
|
|
85
|
+
hasGroupId: !!clinicGroupId,
|
|
86
|
+
});
|
|
87
|
+
|
|
55
88
|
if (validatedData.isGroupOwner && !clinicGroupId) {
|
|
89
|
+
console.log("[CLINIC_ADMIN] Creating default group for owner");
|
|
56
90
|
// Kreiramo default grupu
|
|
57
91
|
const defaultGroup: CreateDefaultClinicGroupData = {
|
|
58
92
|
name: `${validatedData.contactInfo.firstName}'s Group`,
|
|
@@ -60,7 +94,7 @@ export async function createClinicAdmin(
|
|
|
60
94
|
contactPerson: validatedData.contactInfo,
|
|
61
95
|
contactInfo: {
|
|
62
96
|
email: validatedData.contactInfo.email,
|
|
63
|
-
phoneNumber: validatedData.contactInfo.phoneNumber,
|
|
97
|
+
phoneNumber: validatedData.contactInfo.phoneNumber || "",
|
|
64
98
|
},
|
|
65
99
|
hqLocation: {
|
|
66
100
|
address: "",
|
|
@@ -72,37 +106,77 @@ export async function createClinicAdmin(
|
|
|
72
106
|
},
|
|
73
107
|
isActive: true,
|
|
74
108
|
};
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
109
|
+
console.log("[CLINIC_ADMIN] Default group data prepared", {
|
|
110
|
+
groupName: defaultGroup.name,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
const clinicGroup = await clinicGroupService.createClinicGroup(
|
|
115
|
+
defaultGroup,
|
|
116
|
+
validatedData.userRef,
|
|
117
|
+
true
|
|
118
|
+
);
|
|
119
|
+
clinicGroupId = clinicGroup.id;
|
|
120
|
+
console.log("[CLINIC_ADMIN] Default group created successfully", {
|
|
121
|
+
groupId: clinicGroupId,
|
|
122
|
+
});
|
|
123
|
+
} catch (groupCreationError) {
|
|
124
|
+
console.error(
|
|
125
|
+
"[CLINIC_ADMIN] Error creating default group:",
|
|
126
|
+
groupCreationError
|
|
127
|
+
);
|
|
128
|
+
throw groupCreationError;
|
|
129
|
+
}
|
|
82
130
|
}
|
|
83
131
|
// Ako nije owner a nemamo groupId, to je greška
|
|
84
132
|
else if (!validatedData.isGroupOwner && !clinicGroupId) {
|
|
133
|
+
console.error("[CLINIC_ADMIN] Missing clinic group ID for non-owner admin");
|
|
85
134
|
throw new Error("Clinic group ID is required for non-owner admins");
|
|
86
135
|
}
|
|
87
136
|
// Ako nije owner a imamo groupId, proverimo da li grupa postoji
|
|
88
137
|
else if (!validatedData.isGroupOwner && clinicGroupId) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
138
|
+
console.log("[CLINIC_ADMIN] Checking if specified clinic group exists", {
|
|
139
|
+
groupId: clinicGroupId,
|
|
140
|
+
});
|
|
141
|
+
try {
|
|
142
|
+
const groupExists = await checkClinicGroupExists(
|
|
143
|
+
db,
|
|
144
|
+
clinicGroupId,
|
|
145
|
+
clinicGroupService
|
|
146
|
+
);
|
|
147
|
+
if (!groupExists) {
|
|
148
|
+
console.error("[CLINIC_ADMIN] Specified clinic group does not exist", {
|
|
149
|
+
groupId: clinicGroupId,
|
|
150
|
+
});
|
|
151
|
+
throw new Error("Specified clinic group does not exist");
|
|
152
|
+
}
|
|
153
|
+
console.log("[CLINIC_ADMIN] Specified clinic group exists");
|
|
154
|
+
} catch (groupCheckError) {
|
|
155
|
+
console.error(
|
|
156
|
+
"[CLINIC_ADMIN] Error checking if clinic group exists:",
|
|
157
|
+
groupCheckError
|
|
158
|
+
);
|
|
159
|
+
throw groupCheckError;
|
|
96
160
|
}
|
|
97
161
|
}
|
|
98
162
|
|
|
163
|
+
console.log("[CLINIC_ADMIN] Preparing admin data object");
|
|
164
|
+
|
|
165
|
+
// Ensure clinicGroupId is not undefined
|
|
166
|
+
if (!clinicGroupId) {
|
|
167
|
+
console.error(
|
|
168
|
+
"[CLINIC_ADMIN] clinicGroupId is undefined, which should not happen at this point"
|
|
169
|
+
);
|
|
170
|
+
throw new Error("clinicGroupId is required but was undefined");
|
|
171
|
+
}
|
|
172
|
+
|
|
99
173
|
const adminData: Omit<ClinicAdmin, "createdAt" | "updatedAt"> & {
|
|
100
174
|
createdAt: ReturnType<typeof serverTimestamp>;
|
|
101
175
|
updatedAt: ReturnType<typeof serverTimestamp>;
|
|
102
176
|
} = {
|
|
103
177
|
id: validatedData.userRef,
|
|
104
178
|
userRef: validatedData.userRef,
|
|
105
|
-
clinicGroupId: clinicGroupId
|
|
179
|
+
clinicGroupId: clinicGroupId,
|
|
106
180
|
isGroupOwner: validatedData.isGroupOwner,
|
|
107
181
|
clinicsManaged: [], // Uvek krećemo od prazne liste
|
|
108
182
|
clinicsManagedInfo: [], // Empty array for clinic info
|
|
@@ -114,27 +188,74 @@ export async function createClinicAdmin(
|
|
|
114
188
|
};
|
|
115
189
|
|
|
116
190
|
// Validacija kompletnog objekta
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
191
|
+
console.log("[CLINIC_ADMIN] Validating complete admin object");
|
|
192
|
+
try {
|
|
193
|
+
clinicAdminSchema.parse({
|
|
194
|
+
...adminData,
|
|
195
|
+
createdAt: Timestamp.now(),
|
|
196
|
+
updatedAt: Timestamp.now(),
|
|
197
|
+
});
|
|
198
|
+
console.log("[CLINIC_ADMIN] Admin object validation passed");
|
|
199
|
+
} catch (schemaError) {
|
|
200
|
+
console.error(
|
|
201
|
+
"[CLINIC_ADMIN] Admin object validation failed:",
|
|
202
|
+
JSON.stringify(schemaError, null, 2)
|
|
203
|
+
);
|
|
204
|
+
throw schemaError;
|
|
205
|
+
}
|
|
122
206
|
|
|
123
207
|
// Čuvamo u Firestore
|
|
124
|
-
|
|
208
|
+
console.log("[CLINIC_ADMIN] Saving admin to Firestore", {
|
|
209
|
+
adminId: adminData.id,
|
|
210
|
+
});
|
|
211
|
+
try {
|
|
212
|
+
await setDoc(doc(db, CLINIC_ADMINS_COLLECTION, adminData.id), adminData);
|
|
213
|
+
console.log("[CLINIC_ADMIN] Admin saved successfully");
|
|
214
|
+
} catch (firestoreError) {
|
|
215
|
+
console.error(
|
|
216
|
+
"[CLINIC_ADMIN] Error saving admin to Firestore:",
|
|
217
|
+
firestoreError
|
|
218
|
+
);
|
|
219
|
+
throw firestoreError;
|
|
220
|
+
}
|
|
125
221
|
|
|
126
222
|
// Dodajemo admina u grupu
|
|
127
223
|
if (clinicGroupId) {
|
|
128
|
-
|
|
224
|
+
console.log("[CLINIC_ADMIN] Adding admin to clinic group", {
|
|
225
|
+
adminId: adminData.id,
|
|
226
|
+
groupId: clinicGroupId,
|
|
227
|
+
});
|
|
228
|
+
try {
|
|
229
|
+
await clinicGroupService.addAdminToGroup(clinicGroupId, adminData.id);
|
|
230
|
+
console.log("[CLINIC_ADMIN] Admin added to group successfully");
|
|
231
|
+
} catch (addToGroupError) {
|
|
232
|
+
console.error(
|
|
233
|
+
"[CLINIC_ADMIN] Error adding admin to group:",
|
|
234
|
+
addToGroupError
|
|
235
|
+
);
|
|
236
|
+
throw addToGroupError;
|
|
237
|
+
}
|
|
129
238
|
}
|
|
130
239
|
|
|
131
240
|
// Vraćamo kreirani objekat
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
241
|
+
console.log("[CLINIC_ADMIN] Retrieving created admin");
|
|
242
|
+
try {
|
|
243
|
+
const createdAdmin = await getClinicAdmin(db, adminData.id);
|
|
244
|
+
if (!createdAdmin) {
|
|
245
|
+
console.error("[CLINIC_ADMIN] Failed to retrieve created admin");
|
|
246
|
+
throw new Error("Failed to retrieve created admin");
|
|
247
|
+
}
|
|
248
|
+
console.log("[CLINIC_ADMIN] Admin creation completed successfully", {
|
|
249
|
+
adminId: createdAdmin.id,
|
|
250
|
+
});
|
|
251
|
+
return createdAdmin;
|
|
252
|
+
} catch (retrieveError) {
|
|
253
|
+
console.error(
|
|
254
|
+
"[CLINIC_ADMIN] Error retrieving created admin:",
|
|
255
|
+
retrieveError
|
|
256
|
+
);
|
|
257
|
+
throw retrieveError;
|
|
135
258
|
}
|
|
136
|
-
|
|
137
|
-
return createdAdmin;
|
|
138
259
|
}
|
|
139
260
|
|
|
140
261
|
/**
|
|
@@ -59,24 +59,65 @@ export async function createClinicGroup(
|
|
|
59
59
|
isDefault: boolean = false,
|
|
60
60
|
clinicAdminService: any
|
|
61
61
|
): Promise<ClinicGroup> {
|
|
62
|
+
console.log("[CLINIC_GROUP] Starting clinic group creation", {
|
|
63
|
+
ownerId,
|
|
64
|
+
isDefault,
|
|
65
|
+
});
|
|
66
|
+
console.log("[CLINIC_GROUP] Input data:", JSON.stringify(data, null, 2));
|
|
67
|
+
|
|
62
68
|
// Validacija podataka
|
|
69
|
+
try {
|
|
70
|
+
const validatedData = createClinicGroupSchema.parse(data);
|
|
71
|
+
console.log("[CLINIC_GROUP] Data validation passed");
|
|
72
|
+
} catch (validationError) {
|
|
73
|
+
console.error("[CLINIC_GROUP] Data validation failed:", validationError);
|
|
74
|
+
throw validationError;
|
|
75
|
+
}
|
|
76
|
+
|
|
63
77
|
const validatedData = createClinicGroupSchema.parse(data);
|
|
64
78
|
|
|
65
79
|
// Proveravamo da li owner postoji i da li je clinic admin
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
80
|
+
try {
|
|
81
|
+
console.log("[CLINIC_GROUP] Checking if owner exists", { ownerId });
|
|
82
|
+
const owner = await clinicAdminService.getClinicAdmin(ownerId);
|
|
83
|
+
if (!owner) {
|
|
84
|
+
console.error("[CLINIC_GROUP] Owner not found or is not a clinic admin", {
|
|
85
|
+
ownerId,
|
|
86
|
+
});
|
|
87
|
+
throw new Error("Owner not found or is not a clinic admin");
|
|
88
|
+
}
|
|
89
|
+
console.log("[CLINIC_GROUP] Owner verified as clinic admin");
|
|
90
|
+
} catch (ownerError) {
|
|
91
|
+
console.error("[CLINIC_GROUP] Error verifying owner:", ownerError);
|
|
92
|
+
throw ownerError;
|
|
69
93
|
}
|
|
70
94
|
|
|
71
95
|
// Generišemo geohash za lokaciju
|
|
96
|
+
console.log("[CLINIC_GROUP] Generating geohash for location");
|
|
72
97
|
if (validatedData.hqLocation) {
|
|
73
|
-
|
|
74
|
-
validatedData.hqLocation.
|
|
75
|
-
|
|
76
|
-
|
|
98
|
+
try {
|
|
99
|
+
validatedData.hqLocation.geohash = geohashForLocation([
|
|
100
|
+
validatedData.hqLocation.latitude,
|
|
101
|
+
validatedData.hqLocation.longitude,
|
|
102
|
+
]);
|
|
103
|
+
console.log("[CLINIC_GROUP] Geohash generated successfully", {
|
|
104
|
+
geohash: validatedData.hqLocation.geohash,
|
|
105
|
+
});
|
|
106
|
+
} catch (geohashError) {
|
|
107
|
+
console.error("[CLINIC_GROUP] Error generating geohash:", geohashError);
|
|
108
|
+
throw geohashError;
|
|
109
|
+
}
|
|
77
110
|
}
|
|
78
111
|
|
|
79
112
|
const now = Timestamp.now();
|
|
113
|
+
console.log("[CLINIC_GROUP] Preparing clinic group data object");
|
|
114
|
+
|
|
115
|
+
// Log the logo value to debug null vs undefined issue
|
|
116
|
+
console.log("[CLINIC_GROUP] Logo value:", {
|
|
117
|
+
logoValue: validatedData.logo,
|
|
118
|
+
logoType: validatedData.logo === null ? "null" : typeof validatedData.logo,
|
|
119
|
+
});
|
|
120
|
+
|
|
80
121
|
const groupData: ClinicGroup = {
|
|
81
122
|
...validatedData,
|
|
82
123
|
id: doc(collection(db, CLINIC_GROUPS_COLLECTION)).id,
|
|
@@ -107,22 +148,68 @@ export async function createClinicGroup(
|
|
|
107
148
|
|
|
108
149
|
try {
|
|
109
150
|
// Validiramo kompletan objekat
|
|
110
|
-
|
|
151
|
+
console.log("[CLINIC_GROUP] Validating complete clinic group object");
|
|
152
|
+
try {
|
|
153
|
+
clinicGroupSchema.parse(groupData);
|
|
154
|
+
console.log("[CLINIC_GROUP] Clinic group validation passed");
|
|
155
|
+
} catch (schemaError) {
|
|
156
|
+
console.error(
|
|
157
|
+
"[CLINIC_GROUP] Clinic group validation failed:",
|
|
158
|
+
JSON.stringify(schemaError, null, 2)
|
|
159
|
+
);
|
|
160
|
+
throw schemaError;
|
|
161
|
+
}
|
|
111
162
|
|
|
112
163
|
// Čuvamo u Firestore
|
|
113
|
-
|
|
164
|
+
console.log("[CLINIC_GROUP] Saving clinic group to Firestore", {
|
|
165
|
+
groupId: groupData.id,
|
|
166
|
+
});
|
|
167
|
+
try {
|
|
168
|
+
await setDoc(doc(db, CLINIC_GROUPS_COLLECTION, groupData.id), groupData);
|
|
169
|
+
console.log("[CLINIC_GROUP] Clinic group saved successfully");
|
|
170
|
+
} catch (firestoreError) {
|
|
171
|
+
console.error(
|
|
172
|
+
"[CLINIC_GROUP] Error saving to Firestore:",
|
|
173
|
+
firestoreError
|
|
174
|
+
);
|
|
175
|
+
throw firestoreError;
|
|
176
|
+
}
|
|
114
177
|
|
|
115
178
|
// Ažuriramo clinic admin profil vlasnika
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
isGroupOwner: true,
|
|
179
|
+
console.log("[CLINIC_GROUP] Updating clinic admin profile for owner", {
|
|
180
|
+
ownerId,
|
|
119
181
|
});
|
|
182
|
+
try {
|
|
183
|
+
await clinicAdminService.updateClinicAdmin(ownerId, {
|
|
184
|
+
clinicGroupId: groupData.id,
|
|
185
|
+
isGroupOwner: true,
|
|
186
|
+
});
|
|
187
|
+
console.log("[CLINIC_GROUP] Clinic admin profile updated successfully");
|
|
188
|
+
} catch (updateError) {
|
|
189
|
+
console.error(
|
|
190
|
+
"[CLINIC_GROUP] Error updating clinic admin profile:",
|
|
191
|
+
updateError
|
|
192
|
+
);
|
|
193
|
+
throw updateError;
|
|
194
|
+
}
|
|
120
195
|
|
|
196
|
+
console.log("[CLINIC_GROUP] Clinic group creation completed successfully", {
|
|
197
|
+
groupId: groupData.id,
|
|
198
|
+
groupName: groupData.name,
|
|
199
|
+
});
|
|
121
200
|
return groupData;
|
|
122
201
|
} catch (error) {
|
|
123
202
|
if (error instanceof z.ZodError) {
|
|
203
|
+
console.error(
|
|
204
|
+
"[CLINIC_GROUP] Zod validation error:",
|
|
205
|
+
JSON.stringify(error.errors, null, 2)
|
|
206
|
+
);
|
|
124
207
|
throw new Error("Invalid clinic group data: " + error.message);
|
|
125
208
|
}
|
|
209
|
+
console.error(
|
|
210
|
+
"[CLINIC_GROUP] Unhandled error in createClinicGroup:",
|
|
211
|
+
error
|
|
212
|
+
);
|
|
126
213
|
throw error;
|
|
127
214
|
}
|
|
128
215
|
}
|