@blackcode_sa/metaestetics-api 1.4.6 → 1.4.8

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.
@@ -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
- await clinicAdminSignupSchema.parseAsync(data);
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
- const { user: firebaseUser } = await createUserWithEmailAndPassword(
116
- this.auth,
117
- data.email,
118
- data.password
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
- const user = await this.userService.createUser(
123
- firebaseUser,
124
- [UserRole.CLINIC_ADMIN],
125
- {
126
- skipProfileCreation: true,
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,16 +194,43 @@ 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
  );
168
209
  }
169
210
 
170
- // Create clinic group
211
+ // First create the clinic admin
212
+ console.log("[AUTH] Creating clinic admin first");
213
+ const createClinicAdminData: CreateClinicAdminData = {
214
+ userRef: firebaseUser.uid,
215
+ isGroupOwner: true,
216
+ clinicsManaged: [],
217
+ contactInfo: contactPerson,
218
+ roleTitle: data.title,
219
+ isActive: true,
220
+ };
221
+
222
+ try {
223
+ await clinicAdminService.createClinicAdmin(createClinicAdminData);
224
+ console.log("[AUTH] Clinic admin created successfully");
225
+ } catch (adminCreationError) {
226
+ console.error(
227
+ "[AUTH] Clinic admin creation failed:",
228
+ adminCreationError
229
+ );
230
+ throw adminCreationError;
231
+ }
232
+
233
+ // Then create clinic group
171
234
  const createClinicGroupData: CreateClinicGroupData = {
172
235
  name: data.clinicGroupData.name,
173
236
  hqLocation: data.clinicGroupData.hqLocation,
@@ -180,22 +243,40 @@ export class AuthService extends BaseService {
180
243
  data.clinicGroupData.subscriptionModel ||
181
244
  SubscriptionModel.NO_SUBSCRIPTION,
182
245
  };
246
+ console.log("[AUTH] Clinic group data prepared", {
247
+ groupName: createClinicGroupData.name,
248
+ });
183
249
 
184
250
  // Create clinic group
185
- await clinicGroupService.createClinicGroup(
186
- createClinicGroupData,
187
- firebaseUser.uid,
188
- true
189
- );
251
+ try {
252
+ await clinicGroupService.createClinicGroup(
253
+ createClinicGroupData,
254
+ firebaseUser.uid,
255
+ true
256
+ );
257
+ console.log("[AUTH] Clinic group created successfully");
258
+ } catch (groupCreationError) {
259
+ console.error(
260
+ "[AUTH] Clinic group creation failed:",
261
+ groupCreationError
262
+ );
263
+ throw groupCreationError;
264
+ }
190
265
  } else {
266
+ console.log("[AUTH] Joining existing clinic group flow");
191
267
  // Join existing clinic group with token
192
268
  if (!data.inviteToken) {
269
+ console.error("[AUTH] Invite token is missing");
193
270
  throw new Error(
194
271
  "Invite token is required when joining an existing group"
195
272
  );
196
273
  }
274
+ console.log("[AUTH] Invite token provided", {
275
+ token: data.inviteToken,
276
+ });
197
277
 
198
278
  // Find the token in the database
279
+ console.log("[AUTH] Searching for token in clinic groups");
199
280
  const groupsRef = collection(this.db, CLINIC_GROUPS_COLLECTION);
200
281
  const q = query(groupsRef);
201
282
  const querySnapshot = await getDocs(q);
@@ -203,29 +284,56 @@ export class AuthService extends BaseService {
203
284
  let foundGroup: ClinicGroup | null = null;
204
285
  let foundToken: AdminToken | null = null;
205
286
 
287
+ console.log(
288
+ "[AUTH] Found",
289
+ querySnapshot.size,
290
+ "clinic groups to check"
291
+ );
206
292
  for (const docSnapshot of querySnapshot.docs) {
207
293
  const group = docSnapshot.data() as ClinicGroup;
294
+ console.log("[AUTH] Checking group", {
295
+ groupId: group.id,
296
+ groupName: group.name,
297
+ });
208
298
 
209
299
  // Find the token in the group's tokens
210
- const token = group.adminTokens.find(
211
- (t) =>
300
+ const token = group.adminTokens.find((t) => {
301
+ const isMatch =
212
302
  t.token === data.inviteToken &&
213
303
  t.status === AdminTokenStatus.ACTIVE &&
214
- new Date(t.expiresAt.toDate()) > new Date()
215
- );
304
+ new Date(t.expiresAt.toDate()) > new Date();
305
+
306
+ console.log("[AUTH] Checking token", {
307
+ tokenId: t.id,
308
+ tokenMatch: t.token === data.inviteToken,
309
+ tokenStatus: t.status,
310
+ tokenActive: t.status === AdminTokenStatus.ACTIVE,
311
+ tokenExpiry: new Date(t.expiresAt.toDate()),
312
+ tokenExpired: new Date(t.expiresAt.toDate()) <= new Date(),
313
+ isMatch,
314
+ });
315
+
316
+ return isMatch;
317
+ });
216
318
 
217
319
  if (token) {
218
320
  foundGroup = group;
219
321
  foundToken = token;
322
+ console.log("[AUTH] Found matching token in group", {
323
+ groupId: group.id,
324
+ tokenId: token.id,
325
+ });
220
326
  break;
221
327
  }
222
328
  }
223
329
 
224
330
  if (!foundGroup || !foundToken) {
331
+ console.error("[AUTH] No valid token found in any clinic group");
225
332
  throw new Error("Invalid or expired invite token");
226
333
  }
227
334
 
228
335
  // Create clinic admin
336
+ console.log("[AUTH] Creating clinic admin");
229
337
  const createClinicAdminData: CreateClinicAdminData = {
230
338
  userRef: firebaseUser.uid,
231
339
  clinicGroupId: foundGroup.id,
@@ -236,27 +344,51 @@ export class AuthService extends BaseService {
236
344
  isActive: true,
237
345
  };
238
346
 
239
- await clinicAdminService.createClinicAdmin(createClinicAdminData);
347
+ try {
348
+ await clinicAdminService.createClinicAdmin(createClinicAdminData);
349
+ console.log("[AUTH] Clinic admin created successfully");
350
+ } catch (adminCreationError) {
351
+ console.error(
352
+ "[AUTH] Clinic admin creation failed:",
353
+ adminCreationError
354
+ );
355
+ throw adminCreationError;
356
+ }
240
357
 
241
358
  // Mark token as used
242
- await clinicGroupService.verifyAndUseAdminToken(
243
- foundGroup.id,
244
- data.inviteToken,
245
- firebaseUser.uid
246
- );
359
+ try {
360
+ await clinicGroupService.verifyAndUseAdminToken(
361
+ foundGroup.id,
362
+ data.inviteToken,
363
+ firebaseUser.uid
364
+ );
365
+ console.log("[AUTH] Token marked as used successfully");
366
+ } catch (tokenUseError) {
367
+ console.error("[AUTH] Failed to mark token as used:", tokenUseError);
368
+ throw tokenUseError;
369
+ }
247
370
  }
248
371
 
372
+ console.log("[AUTH] Clinic admin signup completed successfully", {
373
+ userId: user.uid,
374
+ });
249
375
  return user;
250
376
  } catch (error) {
251
377
  if (error instanceof z.ZodError) {
378
+ console.error(
379
+ "[AUTH] Zod validation error in signUpClinicAdmin:",
380
+ JSON.stringify(error.errors, null, 2)
381
+ );
252
382
  throw AUTH_ERRORS.VALIDATION_ERROR;
253
383
  }
254
384
 
255
385
  const firebaseError = error as FirebaseError;
256
386
  if (firebaseError.code === FirebaseErrorCode.EMAIL_ALREADY_IN_USE) {
387
+ console.error("[AUTH] Email already in use:", data.email);
257
388
  throw AUTH_ERRORS.EMAIL_ALREADY_EXISTS;
258
389
  }
259
390
 
391
+ console.error("[AUTH] Unhandled error in signUpClinicAdmin:", error);
260
392
  throw error;
261
393
  }
262
394
  }
@@ -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
- const existingAdmin = await getClinicAdminByUserRef(
46
- db,
47
- validatedData.userRef
48
- );
49
- if (existingAdmin) {
50
- throw new Error("User already has an admin profile");
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
- const clinicGroup = await clinicGroupService.createClinicGroup(
77
- defaultGroup,
78
- validatedData.userRef,
79
- true
80
- );
81
- clinicGroupId = clinicGroup.id;
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
- const groupExists = await checkClinicGroupExists(
90
- db,
91
- clinicGroupId,
92
- clinicGroupService
93
- );
94
- if (!groupExists) {
95
- throw new Error("Specified clinic group does not exist");
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
- clinicAdminSchema.parse({
118
- ...adminData,
119
- createdAt: Timestamp.now(),
120
- updatedAt: Timestamp.now(),
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
- await setDoc(doc(db, CLINIC_ADMINS_COLLECTION, adminData.id), adminData);
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
- await clinicGroupService.addAdminToGroup(clinicGroupId, adminData.id);
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
- const createdAdmin = await getClinicAdmin(db, adminData.id);
133
- if (!createdAdmin) {
134
- throw new Error("Failed to retrieve created admin");
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
  /**