@blackcode_sa/metaestetics-api 1.12.8 → 1.12.11

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 CHANGED
@@ -1190,24 +1190,18 @@ var AppointmentService = class extends BaseService {
1190
1190
  `[APPOINTMENT_SERVICE] Getting available booking slots via HTTP for clinic: ${clinicId}, practitioner: ${practitionerId}, procedure: ${procedureId}`
1191
1191
  );
1192
1192
  if (!clinicId || !practitionerId || !procedureId || !startDate || !endDate) {
1193
- throw new Error(
1194
- "Missing required parameters for booking slots calculation"
1195
- );
1193
+ throw new Error("Missing required parameters for booking slots calculation");
1196
1194
  }
1197
1195
  if (endDate <= startDate) {
1198
1196
  throw new Error("End date must be after start date");
1199
1197
  }
1200
1198
  const currentUser = this.auth.currentUser;
1201
1199
  if (!currentUser) {
1202
- throw new Error(
1203
- "User must be authenticated to get available booking slots"
1204
- );
1200
+ throw new Error("User must be authenticated to get available booking slots");
1205
1201
  }
1206
1202
  const functionUrl = `https://europe-west6-metaestetics.cloudfunctions.net/bookingApi/getAvailableBookingSlots`;
1207
1203
  const idToken = await currentUser.getIdToken();
1208
- console.log(
1209
- `[APPOINTMENT_SERVICE] Got user token, user ID: ${currentUser.uid}`
1210
- );
1204
+ console.log(`[APPOINTMENT_SERVICE] Got user token, user ID: ${currentUser.uid}`);
1211
1205
  const requestData = {
1212
1206
  clinicId,
1213
1207
  practitionerId,
@@ -1218,9 +1212,7 @@ var AppointmentService = class extends BaseService {
1218
1212
  end: endDate.getTime()
1219
1213
  }
1220
1214
  };
1221
- console.log(
1222
- `[APPOINTMENT_SERVICE] Making fetch request to ${functionUrl}`
1223
- );
1215
+ console.log(`[APPOINTMENT_SERVICE] Making fetch request to ${functionUrl}`);
1224
1216
  const response = await fetch(functionUrl, {
1225
1217
  method: "POST",
1226
1218
  mode: "cors",
@@ -1242,9 +1234,7 @@ var AppointmentService = class extends BaseService {
1242
1234
  );
1243
1235
  if (!response.ok) {
1244
1236
  const errorText = await response.text();
1245
- console.error(
1246
- `[APPOINTMENT_SERVICE] Error response details: ${errorText}`
1247
- );
1237
+ console.error(`[APPOINTMENT_SERVICE] Error response details: ${errorText}`);
1248
1238
  throw new Error(
1249
1239
  `Failed to get available booking slots: ${response.status} ${response.statusText} - ${errorText}`
1250
1240
  );
@@ -1252,24 +1242,15 @@ var AppointmentService = class extends BaseService {
1252
1242
  const result = await response.json();
1253
1243
  console.log(`[APPOINTMENT_SERVICE] Response parsed successfully`, result);
1254
1244
  if (!result.success) {
1255
- throw new Error(
1256
- result.error || "Failed to get available booking slots"
1257
- );
1245
+ throw new Error(result.error || "Failed to get available booking slots");
1258
1246
  }
1259
- const slots = result.availableSlots.map(
1260
- (slot) => ({
1261
- start: new Date(slot.start)
1262
- })
1263
- );
1264
- console.log(
1265
- `[APPOINTMENT_SERVICE] Found ${slots.length} available booking slots via HTTP`
1266
- );
1247
+ const slots = result.availableSlots.map((slot) => ({
1248
+ start: new Date(slot.start)
1249
+ }));
1250
+ console.log(`[APPOINTMENT_SERVICE] Found ${slots.length} available booking slots via HTTP`);
1267
1251
  return slots;
1268
1252
  } catch (error) {
1269
- console.error(
1270
- "[APPOINTMENT_SERVICE] Error getting available booking slots via HTTP:",
1271
- error
1272
- );
1253
+ console.error("[APPOINTMENT_SERVICE] Error getting available booking slots via HTTP:", error);
1273
1254
  throw error;
1274
1255
  }
1275
1256
  }
@@ -1281,9 +1262,7 @@ var AppointmentService = class extends BaseService {
1281
1262
  */
1282
1263
  async createAppointmentHttp(data) {
1283
1264
  try {
1284
- console.log(
1285
- "[APPOINTMENT_SERVICE] Creating appointment via cloud function"
1286
- );
1265
+ console.log("[APPOINTMENT_SERVICE] Creating appointment via cloud function");
1287
1266
  const currentUser = this.auth.currentUser;
1288
1267
  if (!currentUser) {
1289
1268
  throw new Error("User must be authenticated to create an appointment");
@@ -1297,9 +1276,7 @@ var AppointmentService = class extends BaseService {
1297
1276
  appointmentEndTime: data.appointmentEndTime.toMillis ? data.appointmentEndTime.toMillis() : new Date(data.appointmentEndTime).getTime(),
1298
1277
  patientNotes: (data == null ? void 0 : data.patientNotes) || null
1299
1278
  };
1300
- console.log(
1301
- `[APPOINTMENT_SERVICE] Making fetch request to ${functionUrl}`
1302
- );
1279
+ console.log(`[APPOINTMENT_SERVICE] Making fetch request to ${functionUrl}`);
1303
1280
  const response = await fetch(functionUrl, {
1304
1281
  method: "POST",
1305
1282
  mode: "cors",
@@ -1318,9 +1295,7 @@ var AppointmentService = class extends BaseService {
1318
1295
  );
1319
1296
  if (!response.ok) {
1320
1297
  const errorText = await response.text();
1321
- console.error(
1322
- `[APPOINTMENT_SERVICE] Error response details: ${errorText}`
1323
- );
1298
+ console.error(`[APPOINTMENT_SERVICE] Error response details: ${errorText}`);
1324
1299
  throw new Error(
1325
1300
  `Failed to create appointment: ${response.status} ${response.statusText} - ${errorText}`
1326
1301
  );
@@ -1330,25 +1305,16 @@ var AppointmentService = class extends BaseService {
1330
1305
  throw new Error(result.error || "Failed to create appointment");
1331
1306
  }
1332
1307
  if (result.appointmentData) {
1333
- console.log(
1334
- `[APPOINTMENT_SERVICE] Appointment created with ID: ${result.appointmentId}`
1335
- );
1308
+ console.log(`[APPOINTMENT_SERVICE] Appointment created with ID: ${result.appointmentId}`);
1336
1309
  return result.appointmentData;
1337
1310
  }
1338
- const createdAppointment = await this.getAppointmentById(
1339
- result.appointmentId
1340
- );
1311
+ const createdAppointment = await this.getAppointmentById(result.appointmentId);
1341
1312
  if (!createdAppointment) {
1342
- throw new Error(
1343
- `Failed to retrieve created appointment with ID: ${result.appointmentId}`
1344
- );
1313
+ throw new Error(`Failed to retrieve created appointment with ID: ${result.appointmentId}`);
1345
1314
  }
1346
1315
  return createdAppointment;
1347
1316
  } catch (error) {
1348
- console.error(
1349
- "[APPOINTMENT_SERVICE] Error creating appointment via cloud function:",
1350
- error
1351
- );
1317
+ console.error("[APPOINTMENT_SERVICE] Error creating appointment via cloud function:", error);
1352
1318
  throw error;
1353
1319
  }
1354
1320
  }
@@ -1360,19 +1326,14 @@ var AppointmentService = class extends BaseService {
1360
1326
  */
1361
1327
  async getAppointmentById(appointmentId) {
1362
1328
  try {
1363
- console.log(
1364
- `[APPOINTMENT_SERVICE] Getting appointment with ID: ${appointmentId}`
1365
- );
1329
+ console.log(`[APPOINTMENT_SERVICE] Getting appointment with ID: ${appointmentId}`);
1366
1330
  const appointment = await getAppointmentByIdUtil(this.db, appointmentId);
1367
1331
  console.log(
1368
1332
  `[APPOINTMENT_SERVICE] Appointment ${appointmentId} ${appointment ? "found" : "not found"}`
1369
1333
  );
1370
1334
  return appointment;
1371
1335
  } catch (error) {
1372
- console.error(
1373
- `[APPOINTMENT_SERVICE] Error getting appointment ${appointmentId}:`,
1374
- error
1375
- );
1336
+ console.error(`[APPOINTMENT_SERVICE] Error getting appointment ${appointmentId}:`, error);
1376
1337
  throw error;
1377
1338
  }
1378
1339
  }
@@ -1385,24 +1346,13 @@ var AppointmentService = class extends BaseService {
1385
1346
  */
1386
1347
  async updateAppointment(appointmentId, data) {
1387
1348
  try {
1388
- console.log(
1389
- `[APPOINTMENT_SERVICE] Updating appointment with ID: ${appointmentId}`
1390
- );
1349
+ console.log(`[APPOINTMENT_SERVICE] Updating appointment with ID: ${appointmentId}`);
1391
1350
  const validatedData = await updateAppointmentSchema.parseAsync(data);
1392
- const updatedAppointment = await updateAppointmentUtil(
1393
- this.db,
1394
- appointmentId,
1395
- validatedData
1396
- );
1397
- console.log(
1398
- `[APPOINTMENT_SERVICE] Appointment ${appointmentId} updated successfully`
1399
- );
1351
+ const updatedAppointment = await updateAppointmentUtil(this.db, appointmentId, validatedData);
1352
+ console.log(`[APPOINTMENT_SERVICE] Appointment ${appointmentId} updated successfully`);
1400
1353
  return updatedAppointment;
1401
1354
  } catch (error) {
1402
- console.error(
1403
- `[APPOINTMENT_SERVICE] Error updating appointment ${appointmentId}:`,
1404
- error
1405
- );
1355
+ console.error(`[APPOINTMENT_SERVICE] Error updating appointment ${appointmentId}:`, error);
1406
1356
  throw error;
1407
1357
  }
1408
1358
  }
@@ -1414,21 +1364,13 @@ var AppointmentService = class extends BaseService {
1414
1364
  */
1415
1365
  async searchAppointments(params) {
1416
1366
  try {
1417
- console.log(
1418
- "[APPOINTMENT_SERVICE] Searching appointments with params:",
1419
- params
1420
- );
1367
+ console.log("[APPOINTMENT_SERVICE] Searching appointments with params:", params);
1421
1368
  await searchAppointmentsSchema.parseAsync(params);
1422
1369
  const result = await searchAppointmentsUtil(this.db, params);
1423
- console.log(
1424
- `[APPOINTMENT_SERVICE] Found ${result.appointments.length} appointments`
1425
- );
1370
+ console.log(`[APPOINTMENT_SERVICE] Found ${result.appointments.length} appointments`);
1426
1371
  return result;
1427
1372
  } catch (error) {
1428
- console.error(
1429
- "[APPOINTMENT_SERVICE] Error searching appointments:",
1430
- error
1431
- );
1373
+ console.error("[APPOINTMENT_SERVICE] Error searching appointments:", error);
1432
1374
  throw error;
1433
1375
  }
1434
1376
  }
@@ -1440,9 +1382,7 @@ var AppointmentService = class extends BaseService {
1440
1382
  * @returns Found appointments and the last document for pagination
1441
1383
  */
1442
1384
  async getPatientAppointments(patientId, options) {
1443
- console.log(
1444
- `[APPOINTMENT_SERVICE] Getting appointments for patient: ${patientId}`
1445
- );
1385
+ console.log(`[APPOINTMENT_SERVICE] Getting appointments for patient: ${patientId}`);
1446
1386
  const searchParams = {
1447
1387
  patientId,
1448
1388
  startDate: options == null ? void 0 : options.startDate,
@@ -1461,9 +1401,7 @@ var AppointmentService = class extends BaseService {
1461
1401
  * @returns Found appointments and the last document for pagination
1462
1402
  */
1463
1403
  async getPractitionerAppointments(practitionerId, options) {
1464
- console.log(
1465
- `[APPOINTMENT_SERVICE] Getting appointments for practitioner: ${practitionerId}`
1466
- );
1404
+ console.log(`[APPOINTMENT_SERVICE] Getting appointments for practitioner: ${practitionerId}`);
1467
1405
  const searchParams = {
1468
1406
  practitionerId,
1469
1407
  startDate: options == null ? void 0 : options.startDate,
@@ -1482,9 +1420,7 @@ var AppointmentService = class extends BaseService {
1482
1420
  * @returns Found appointments and the last document for pagination
1483
1421
  */
1484
1422
  async getClinicAppointments(clinicBranchId, options) {
1485
- console.log(
1486
- `[APPOINTMENT_SERVICE] Getting appointments for clinic: ${clinicBranchId}`
1487
- );
1423
+ console.log(`[APPOINTMENT_SERVICE] Getting appointments for clinic: ${clinicBranchId}`);
1488
1424
  const searchParams = {
1489
1425
  clinicBranchId,
1490
1426
  practitionerId: options == null ? void 0 : options.practitionerId,
@@ -1535,68 +1471,42 @@ var AppointmentService = class extends BaseService {
1535
1471
  * Confirms a PENDING appointment by an Admin/Clinic.
1536
1472
  */
1537
1473
  async confirmAppointmentAdmin(appointmentId) {
1538
- console.log(
1539
- `[APPOINTMENT_SERVICE] Admin confirming appointment: ${appointmentId}`
1540
- );
1474
+ console.log(`[APPOINTMENT_SERVICE] Admin confirming appointment: ${appointmentId}`);
1541
1475
  const appointment = await this.getAppointmentById(appointmentId);
1542
- if (!appointment)
1543
- throw new Error(`Appointment ${appointmentId} not found.`);
1476
+ if (!appointment) throw new Error(`Appointment ${appointmentId} not found.`);
1544
1477
  if (appointment.status !== "pending" /* PENDING */) {
1545
- throw new Error(
1546
- `Appointment ${appointmentId} is not in PENDING state to be confirmed.`
1547
- );
1478
+ throw new Error(`Appointment ${appointmentId} is not in PENDING state to be confirmed.`);
1548
1479
  }
1549
- return this.updateAppointmentStatus(
1550
- appointmentId,
1551
- "confirmed" /* CONFIRMED */
1552
- );
1480
+ return this.updateAppointmentStatus(appointmentId, "confirmed" /* CONFIRMED */);
1553
1481
  }
1554
1482
  /**
1555
1483
  * Cancels an appointment by the User (Patient).
1556
1484
  */
1557
1485
  async cancelAppointmentUser(appointmentId, reason) {
1558
- console.log(
1559
- `[APPOINTMENT_SERVICE] User canceling appointment: ${appointmentId}`
1560
- );
1561
- return this.updateAppointmentStatus(
1562
- appointmentId,
1563
- "canceled_patient" /* CANCELED_PATIENT */,
1564
- {
1565
- cancellationReason: reason,
1566
- canceledBy: "patient"
1567
- }
1568
- );
1486
+ console.log(`[APPOINTMENT_SERVICE] User canceling appointment: ${appointmentId}`);
1487
+ return this.updateAppointmentStatus(appointmentId, "canceled_patient" /* CANCELED_PATIENT */, {
1488
+ cancellationReason: reason,
1489
+ canceledBy: "patient"
1490
+ });
1569
1491
  }
1570
1492
  /**
1571
1493
  * Cancels an appointment by an Admin/Clinic.
1572
1494
  */
1573
1495
  async cancelAppointmentAdmin(appointmentId, reason) {
1574
- console.log(
1575
- `[APPOINTMENT_SERVICE] Admin canceling appointment: ${appointmentId}`
1576
- );
1577
- return this.updateAppointmentStatus(
1578
- appointmentId,
1579
- "canceled_clinic" /* CANCELED_CLINIC */,
1580
- {
1581
- cancellationReason: reason,
1582
- canceledBy: "clinic"
1583
- }
1584
- );
1496
+ console.log(`[APPOINTMENT_SERVICE] Admin canceling appointment: ${appointmentId}`);
1497
+ return this.updateAppointmentStatus(appointmentId, "canceled_clinic" /* CANCELED_CLINIC */, {
1498
+ cancellationReason: reason,
1499
+ canceledBy: "clinic"
1500
+ });
1585
1501
  }
1586
1502
  /**
1587
1503
  * Admin proposes to reschedule an appointment.
1588
1504
  * Sets status to RESCHEDULED_BY_CLINIC and updates times.
1589
1505
  */
1590
1506
  async rescheduleAppointmentAdmin(params) {
1591
- console.log(
1592
- `[APPOINTMENT_SERVICE] Admin rescheduling appointment: ${params.appointmentId}`
1593
- );
1594
- const validatedParams = await rescheduleAppointmentSchema.parseAsync(
1595
- params
1596
- );
1597
- const startTimestamp = this.convertToTimestamp(
1598
- validatedParams.newStartTime
1599
- );
1507
+ console.log(`[APPOINTMENT_SERVICE] Admin rescheduling appointment: ${params.appointmentId}`);
1508
+ const validatedParams = await rescheduleAppointmentSchema.parseAsync(params);
1509
+ const startTimestamp = this.convertToTimestamp(validatedParams.newStartTime);
1600
1510
  const endTimestamp = this.convertToTimestamp(validatedParams.newEndTime);
1601
1511
  if (endTimestamp.toMillis() <= startTimestamp.toMillis()) {
1602
1512
  throw new Error("New end time must be after new start time.");
@@ -1639,48 +1549,31 @@ var AppointmentService = class extends BaseService {
1639
1549
  if (value && typeof value.seconds === "number") {
1640
1550
  return new import_firestore2.Timestamp(value.seconds, value.nanoseconds || 0);
1641
1551
  }
1642
- throw new Error(
1643
- `Invalid timestamp format: ${typeof value}, value: ${JSON.stringify(
1644
- value
1645
- )}`
1646
- );
1552
+ throw new Error(`Invalid timestamp format: ${typeof value}, value: ${JSON.stringify(value)}`);
1647
1553
  }
1648
1554
  /**
1649
1555
  * User confirms a reschedule proposed by the clinic.
1650
1556
  * Status changes from RESCHEDULED_BY_CLINIC to CONFIRMED.
1651
1557
  */
1652
1558
  async rescheduleAppointmentConfirmUser(appointmentId) {
1653
- console.log(
1654
- `[APPOINTMENT_SERVICE] User confirming reschedule for: ${appointmentId}`
1655
- );
1559
+ console.log(`[APPOINTMENT_SERVICE] User confirming reschedule for: ${appointmentId}`);
1656
1560
  const appointment = await this.getAppointmentById(appointmentId);
1657
- if (!appointment)
1658
- throw new Error(`Appointment ${appointmentId} not found.`);
1561
+ if (!appointment) throw new Error(`Appointment ${appointmentId} not found.`);
1659
1562
  if (appointment.status !== "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
1660
- throw new Error(
1661
- `Appointment ${appointmentId} is not in RESCHEDULED_BY_CLINIC state.`
1662
- );
1563
+ throw new Error(`Appointment ${appointmentId} is not in RESCHEDULED_BY_CLINIC state.`);
1663
1564
  }
1664
- return this.updateAppointmentStatus(
1665
- appointmentId,
1666
- "confirmed" /* CONFIRMED */
1667
- );
1565
+ return this.updateAppointmentStatus(appointmentId, "confirmed" /* CONFIRMED */);
1668
1566
  }
1669
1567
  /**
1670
1568
  * User rejects a reschedule proposed by the clinic.
1671
1569
  * Status changes from RESCHEDULED_BY_CLINIC to CANCELED_PATIENT_RESCHEDULED.
1672
1570
  */
1673
1571
  async rescheduleAppointmentRejectUser(appointmentId, reason) {
1674
- console.log(
1675
- `[APPOINTMENT_SERVICE] User rejecting reschedule for: ${appointmentId}`
1676
- );
1572
+ console.log(`[APPOINTMENT_SERVICE] User rejecting reschedule for: ${appointmentId}`);
1677
1573
  const appointment = await this.getAppointmentById(appointmentId);
1678
- if (!appointment)
1679
- throw new Error(`Appointment ${appointmentId} not found.`);
1574
+ if (!appointment) throw new Error(`Appointment ${appointmentId} not found.`);
1680
1575
  if (appointment.status !== "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
1681
- throw new Error(
1682
- `Appointment ${appointmentId} is not in RESCHEDULED_BY_CLINIC state.`
1683
- );
1576
+ throw new Error(`Appointment ${appointmentId} is not in RESCHEDULED_BY_CLINIC state.`);
1684
1577
  }
1685
1578
  return this.updateAppointmentStatus(
1686
1579
  appointmentId,
@@ -1696,17 +1589,12 @@ var AppointmentService = class extends BaseService {
1696
1589
  * Requires all pending user forms to be completed.
1697
1590
  */
1698
1591
  async checkInPatientAdmin(appointmentId) {
1699
- console.log(
1700
- `[APPOINTMENT_SERVICE] Admin checking in patient for: ${appointmentId}`
1701
- );
1592
+ console.log(`[APPOINTMENT_SERVICE] Admin checking in patient for: ${appointmentId}`);
1702
1593
  const appointment = await this.getAppointmentById(appointmentId);
1703
- if (!appointment)
1704
- throw new Error(`Appointment ${appointmentId} not found.`);
1594
+ if (!appointment) throw new Error(`Appointment ${appointmentId} not found.`);
1705
1595
  if (appointment.pendingUserFormsIds && appointment.pendingUserFormsIds.length > 0) {
1706
1596
  throw new Error(
1707
- `Cannot check in: Patient has ${appointment.pendingUserFormsIds.length} pending required form(s). IDs: ${appointment.pendingUserFormsIds.join(
1708
- ", "
1709
- )}`
1597
+ `Cannot check in: Patient has ${appointment.pendingUserFormsIds.length} pending required form(s). IDs: ${appointment.pendingUserFormsIds.join(", ")}`
1710
1598
  );
1711
1599
  }
1712
1600
  if (appointment.status !== "confirmed" /* CONFIRMED */ && appointment.status !== "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
@@ -1714,25 +1602,17 @@ var AppointmentService = class extends BaseService {
1714
1602
  `Checking in appointment ${appointmentId} with status ${appointment.status}. Ensure this is intended.`
1715
1603
  );
1716
1604
  }
1717
- return this.updateAppointmentStatus(
1718
- appointmentId,
1719
- "checked_in" /* CHECKED_IN */
1720
- );
1605
+ return this.updateAppointmentStatus(appointmentId, "checked_in" /* CHECKED_IN */);
1721
1606
  }
1722
1607
  /**
1723
1608
  * Doctor starts the appointment procedure.
1724
1609
  */
1725
1610
  async startAppointmentDoctor(appointmentId) {
1726
- console.log(
1727
- `[APPOINTMENT_SERVICE] Doctor starting appointment: ${appointmentId}`
1728
- );
1611
+ console.log(`[APPOINTMENT_SERVICE] Doctor starting appointment: ${appointmentId}`);
1729
1612
  const appointment = await this.getAppointmentById(appointmentId);
1730
- if (!appointment)
1731
- throw new Error(`Appointment ${appointmentId} not found.`);
1613
+ if (!appointment) throw new Error(`Appointment ${appointmentId} not found.`);
1732
1614
  if (appointment.status !== "checked_in" /* CHECKED_IN */) {
1733
- throw new Error(
1734
- `Appointment ${appointmentId} must be CHECKED_IN to start.`
1735
- );
1615
+ throw new Error(`Appointment ${appointmentId} must be CHECKED_IN to start.`);
1736
1616
  }
1737
1617
  const updateData = {
1738
1618
  status: "in_progress" /* IN_PROGRESS */,
@@ -1746,24 +1626,18 @@ var AppointmentService = class extends BaseService {
1746
1626
  * Doctor completes and finalizes the appointment.
1747
1627
  */
1748
1628
  async completeAppointmentDoctor(appointmentId, finalizationNotes, actualDurationMinutesInput) {
1749
- console.log(
1750
- `[APPOINTMENT_SERVICE] Doctor completing appointment: ${appointmentId}`
1751
- );
1629
+ console.log(`[APPOINTMENT_SERVICE] Doctor completing appointment: ${appointmentId}`);
1752
1630
  const currentUser = this.auth.currentUser;
1753
- if (!currentUser)
1754
- throw new Error("Authentication required to complete appointment.");
1631
+ if (!currentUser) throw new Error("Authentication required to complete appointment.");
1755
1632
  const appointment = await this.getAppointmentById(appointmentId);
1756
- if (!appointment)
1757
- throw new Error(`Appointment ${appointmentId} not found.`);
1633
+ if (!appointment) throw new Error(`Appointment ${appointmentId} not found.`);
1758
1634
  let calculatedDurationMinutes = actualDurationMinutesInput;
1759
1635
  const procedureCompletionTime = import_firestore2.Timestamp.now();
1760
1636
  if (calculatedDurationMinutes === void 0 && appointment.procedureActualStartTime) {
1761
1637
  const startTimeMillis = appointment.procedureActualStartTime.toMillis();
1762
1638
  const endTimeMillis = procedureCompletionTime.toMillis();
1763
1639
  if (endTimeMillis > startTimeMillis) {
1764
- calculatedDurationMinutes = Math.round(
1765
- (endTimeMillis - startTimeMillis) / 6e4
1766
- );
1640
+ calculatedDurationMinutes = Math.round((endTimeMillis - startTimeMillis) / 6e4);
1767
1641
  }
1768
1642
  }
1769
1643
  const updateData = {
@@ -1787,31 +1661,22 @@ var AppointmentService = class extends BaseService {
1787
1661
  * Admin marks an appointment as No-Show.
1788
1662
  */
1789
1663
  async markNoShowAdmin(appointmentId) {
1790
- console.log(
1791
- `[APPOINTMENT_SERVICE] Admin marking no-show for: ${appointmentId}`
1792
- );
1664
+ console.log(`[APPOINTMENT_SERVICE] Admin marking no-show for: ${appointmentId}`);
1793
1665
  const appointment = await this.getAppointmentById(appointmentId);
1794
- if (!appointment)
1795
- throw new Error(`Appointment ${appointmentId} not found.`);
1666
+ if (!appointment) throw new Error(`Appointment ${appointmentId} not found.`);
1796
1667
  if (import_firestore2.Timestamp.now().toMillis() < appointment.appointmentStartTime.toMillis()) {
1797
1668
  throw new Error("Cannot mark no-show before appointment start time.");
1798
1669
  }
1799
- return this.updateAppointmentStatus(
1800
- appointmentId,
1801
- "no_show" /* NO_SHOW */,
1802
- {
1803
- cancellationReason: "Patient did not show up for the appointment.",
1804
- canceledBy: "clinic"
1805
- }
1806
- );
1670
+ return this.updateAppointmentStatus(appointmentId, "no_show" /* NO_SHOW */, {
1671
+ cancellationReason: "Patient did not show up for the appointment.",
1672
+ canceledBy: "clinic"
1673
+ });
1807
1674
  }
1808
1675
  /**
1809
1676
  * Adds a media item to an appointment.
1810
1677
  */
1811
1678
  async addMediaToAppointment(appointmentId, mediaItemData) {
1812
- console.log(
1813
- `[APPOINTMENT_SERVICE] Adding media to appointment ${appointmentId}`
1814
- );
1679
+ console.log(`[APPOINTMENT_SERVICE] Adding media to appointment ${appointmentId}`);
1815
1680
  const currentUser = this.auth.currentUser;
1816
1681
  if (!currentUser) throw new Error("Authentication required.");
1817
1682
  const newMediaItem = {
@@ -1851,9 +1716,7 @@ var AppointmentService = class extends BaseService {
1851
1716
  * Adds or updates review information for an appointment.
1852
1717
  */
1853
1718
  async addReviewToAppointment(appointmentId, reviewData) {
1854
- console.log(
1855
- `[APPOINTMENT_SERVICE] Adding review to appointment ${appointmentId}`
1856
- );
1719
+ console.log(`[APPOINTMENT_SERVICE] Adding review to appointment ${appointmentId}`);
1857
1720
  const newReviewInfo = {
1858
1721
  ...reviewData,
1859
1722
  reviewId: this.generateId(),
@@ -1887,9 +1750,7 @@ var AppointmentService = class extends BaseService {
1887
1750
  * @returns The updated appointment
1888
1751
  */
1889
1752
  async updateInternalNotes(appointmentId, notes) {
1890
- console.log(
1891
- `[APPOINTMENT_SERVICE] Updating internal notes for appointment: ${appointmentId}`
1892
- );
1753
+ console.log(`[APPOINTMENT_SERVICE] Updating internal notes for appointment: ${appointmentId}`);
1893
1754
  const updateData = {
1894
1755
  internalNotes: notes
1895
1756
  };
@@ -1905,9 +1766,7 @@ var AppointmentService = class extends BaseService {
1905
1766
  */
1906
1767
  async getUpcomingPatientAppointments(patientId, options) {
1907
1768
  try {
1908
- console.log(
1909
- `[APPOINTMENT_SERVICE] Getting upcoming appointments for patient: ${patientId}`
1910
- );
1769
+ console.log(`[APPOINTMENT_SERVICE] Getting upcoming appointments for patient: ${patientId}`);
1911
1770
  const effectiveStartDate = (options == null ? void 0 : options.startDate) || /* @__PURE__ */ new Date();
1912
1771
  const upcomingStatuses = [
1913
1772
  "pending" /* PENDING */,
@@ -1919,21 +1778,9 @@ var AppointmentService = class extends BaseService {
1919
1778
  const constraints = [];
1920
1779
  constraints.push((0, import_firestore2.where)("patientId", "==", patientId));
1921
1780
  constraints.push((0, import_firestore2.where)("status", "in", upcomingStatuses));
1922
- constraints.push(
1923
- (0, import_firestore2.where)(
1924
- "appointmentStartTime",
1925
- ">=",
1926
- import_firestore2.Timestamp.fromDate(effectiveStartDate)
1927
- )
1928
- );
1781
+ constraints.push((0, import_firestore2.where)("appointmentStartTime", ">=", import_firestore2.Timestamp.fromDate(effectiveStartDate)));
1929
1782
  if (options == null ? void 0 : options.endDate) {
1930
- constraints.push(
1931
- (0, import_firestore2.where)(
1932
- "appointmentStartTime",
1933
- "<=",
1934
- import_firestore2.Timestamp.fromDate(options.endDate)
1935
- )
1936
- );
1783
+ constraints.push((0, import_firestore2.where)("appointmentStartTime", "<=", import_firestore2.Timestamp.fromDate(options.endDate)));
1937
1784
  }
1938
1785
  constraints.push((0, import_firestore2.orderBy)("appointmentStartTime", "asc"));
1939
1786
  if (options == null ? void 0 : options.limit) {
@@ -1942,14 +1789,9 @@ var AppointmentService = class extends BaseService {
1942
1789
  if (options == null ? void 0 : options.startAfter) {
1943
1790
  constraints.push((0, import_firestore2.startAfter)(options.startAfter));
1944
1791
  }
1945
- const q = (0, import_firestore2.query)(
1946
- (0, import_firestore2.collection)(this.db, APPOINTMENTS_COLLECTION),
1947
- ...constraints
1948
- );
1792
+ const q = (0, import_firestore2.query)((0, import_firestore2.collection)(this.db, APPOINTMENTS_COLLECTION), ...constraints);
1949
1793
  const querySnapshot = await (0, import_firestore2.getDocs)(q);
1950
- const appointments = querySnapshot.docs.map(
1951
- (doc38) => doc38.data()
1952
- );
1794
+ const appointments = querySnapshot.docs.map((doc38) => doc38.data());
1953
1795
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
1954
1796
  console.log(
1955
1797
  `[APPOINTMENT_SERVICE] Found ${appointments.length} upcoming appointments for patient ${patientId}`
@@ -1974,9 +1816,7 @@ var AppointmentService = class extends BaseService {
1974
1816
  */
1975
1817
  async getPastPatientAppointments(patientId, options) {
1976
1818
  try {
1977
- console.log(
1978
- `[APPOINTMENT_SERVICE] Getting past appointments for patient: ${patientId}`
1979
- );
1819
+ console.log(`[APPOINTMENT_SERVICE] Getting past appointments for patient: ${patientId}`);
1980
1820
  const effectiveEndDate = (options == null ? void 0 : options.endDate) || /* @__PURE__ */ new Date();
1981
1821
  const pastStatuses = ["completed" /* COMPLETED */];
1982
1822
  if (options == null ? void 0 : options.showCanceled) {
@@ -1994,20 +1834,10 @@ var AppointmentService = class extends BaseService {
1994
1834
  constraints.push((0, import_firestore2.where)("status", "in", pastStatuses));
1995
1835
  if (options == null ? void 0 : options.startDate) {
1996
1836
  constraints.push(
1997
- (0, import_firestore2.where)(
1998
- "appointmentStartTime",
1999
- ">=",
2000
- import_firestore2.Timestamp.fromDate(options.startDate)
2001
- )
1837
+ (0, import_firestore2.where)("appointmentStartTime", ">=", import_firestore2.Timestamp.fromDate(options.startDate))
2002
1838
  );
2003
1839
  }
2004
- constraints.push(
2005
- (0, import_firestore2.where)(
2006
- "appointmentStartTime",
2007
- "<=",
2008
- import_firestore2.Timestamp.fromDate(effectiveEndDate)
2009
- )
2010
- );
1840
+ constraints.push((0, import_firestore2.where)("appointmentStartTime", "<=", import_firestore2.Timestamp.fromDate(effectiveEndDate)));
2011
1841
  constraints.push((0, import_firestore2.orderBy)("appointmentStartTime", "desc"));
2012
1842
  if (options == null ? void 0 : options.limit) {
2013
1843
  constraints.push((0, import_firestore2.limit)(options.limit));
@@ -2015,14 +1845,9 @@ var AppointmentService = class extends BaseService {
2015
1845
  if (options == null ? void 0 : options.startAfter) {
2016
1846
  constraints.push((0, import_firestore2.startAfter)(options.startAfter));
2017
1847
  }
2018
- const q = (0, import_firestore2.query)(
2019
- (0, import_firestore2.collection)(this.db, APPOINTMENTS_COLLECTION),
2020
- ...constraints
2021
- );
1848
+ const q = (0, import_firestore2.query)((0, import_firestore2.collection)(this.db, APPOINTMENTS_COLLECTION), ...constraints);
2022
1849
  const querySnapshot = await (0, import_firestore2.getDocs)(q);
2023
- const appointments = querySnapshot.docs.map(
2024
- (doc38) => doc38.data()
2025
- );
1850
+ const appointments = querySnapshot.docs.map((doc38) => doc38.data());
2026
1851
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
2027
1852
  console.log(
2028
1853
  `[APPOINTMENT_SERVICE] Found ${appointments.length} past appointments for patient ${patientId}`
@@ -2036,6 +1861,46 @@ var AppointmentService = class extends BaseService {
2036
1861
  throw error;
2037
1862
  }
2038
1863
  }
1864
+ /**
1865
+ * Counts completed appointments for a patient with optional clinic filtering.
1866
+ *
1867
+ * @param patientId ID of the patient.
1868
+ * @param clinicBranchId Optional ID of the clinic branch to either include or exclude.
1869
+ * @param excludeClinic Optional boolean. If true (default), excludes the specified clinic. If false, includes only that clinic.
1870
+ * @returns The count of completed appointments.
1871
+ */
1872
+ async countCompletedAppointments(patientId, clinicBranchId, excludeClinic = true) {
1873
+ try {
1874
+ console.log(
1875
+ `[APPOINTMENT_SERVICE] Counting completed appointments for patient: ${patientId}`,
1876
+ { clinicBranchId, excludeClinic }
1877
+ );
1878
+ const constraints = [
1879
+ (0, import_firestore2.where)("patientId", "==", patientId),
1880
+ (0, import_firestore2.where)("status", "==", "completed" /* COMPLETED */)
1881
+ ];
1882
+ if (clinicBranchId) {
1883
+ if (excludeClinic) {
1884
+ constraints.push((0, import_firestore2.where)("clinicBranchId", "!=", clinicBranchId));
1885
+ } else {
1886
+ constraints.push((0, import_firestore2.where)("clinicBranchId", "==", clinicBranchId));
1887
+ }
1888
+ }
1889
+ const q = (0, import_firestore2.query)((0, import_firestore2.collection)(this.db, APPOINTMENTS_COLLECTION), ...constraints);
1890
+ const snapshot = await (0, import_firestore2.getCountFromServer)(q);
1891
+ const count = snapshot.data().count;
1892
+ console.log(
1893
+ `[APPOINTMENT_SERVICE] Found ${count} completed appointments for patient ${patientId}`
1894
+ );
1895
+ return count;
1896
+ } catch (error) {
1897
+ console.error(
1898
+ `[APPOINTMENT_SERVICE] Error counting completed appointments for patient ${patientId}:`,
1899
+ error
1900
+ );
1901
+ throw error;
1902
+ }
1903
+ }
2039
1904
  };
2040
1905
 
2041
1906
  // src/services/auth/auth.service.ts
@@ -9909,19 +9774,13 @@ var AuthService = class extends BaseService {
9909
9774
  constructor(db, auth, app, userService) {
9910
9775
  super(db, auth, app);
9911
9776
  this.googleProvider = new import_auth7.GoogleAuthProvider();
9912
- this.facebookProvider = new import_auth7.FacebookAuthProvider();
9913
- this.appleProvider = new import_auth7.OAuthProvider("apple.com");
9914
9777
  this.userService = userService || new UserService(db, auth, app);
9915
9778
  }
9916
9779
  /**
9917
9780
  * Registruje novog korisnika sa email-om i lozinkom
9918
9781
  */
9919
9782
  async signUp(email, password, initialRole = "patient" /* PATIENT */, options) {
9920
- const { user: firebaseUser } = await (0, import_auth7.createUserWithEmailAndPassword)(
9921
- this.auth,
9922
- email,
9923
- password
9924
- );
9783
+ const { user: firebaseUser } = await (0, import_auth7.createUserWithEmailAndPassword)(this.auth, email, password);
9925
9784
  return this.userService.createUser(firebaseUser, [initialRole], options);
9926
9785
  }
9927
9786
  /**
@@ -9940,20 +9799,13 @@ var AuthService = class extends BaseService {
9940
9799
  await clinicAdminSignupSchema.parseAsync(data);
9941
9800
  console.log("[AUTH] Clinic admin signup data validation passed");
9942
9801
  } catch (validationError) {
9943
- console.error(
9944
- "[AUTH] Validation error in signUpClinicAdmin:",
9945
- validationError
9946
- );
9802
+ console.error("[AUTH] Validation error in signUpClinicAdmin:", validationError);
9947
9803
  throw validationError;
9948
9804
  }
9949
9805
  console.log("[AUTH] Creating Firebase user");
9950
9806
  let firebaseUser;
9951
9807
  try {
9952
- const result = await (0, import_auth7.createUserWithEmailAndPassword)(
9953
- this.auth,
9954
- data.email,
9955
- data.password
9956
- );
9808
+ const result = await (0, import_auth7.createUserWithEmailAndPassword)(this.auth, data.email, data.password);
9957
9809
  firebaseUser = result.user;
9958
9810
  console.log("[AUTH] Firebase user created successfully", {
9959
9811
  uid: firebaseUser.uid
@@ -9965,13 +9817,9 @@ var AuthService = class extends BaseService {
9965
9817
  console.log("[AUTH] Creating user with CLINIC_ADMIN role");
9966
9818
  let user;
9967
9819
  try {
9968
- user = await this.userService.createUser(
9969
- firebaseUser,
9970
- ["clinic_admin" /* CLINIC_ADMIN */],
9971
- {
9972
- skipProfileCreation: true
9973
- }
9974
- );
9820
+ user = await this.userService.createUser(firebaseUser, ["clinic_admin" /* CLINIC_ADMIN */], {
9821
+ skipProfileCreation: true
9822
+ });
9975
9823
  console.log("[AUTH] User with CLINIC_ADMIN role created successfully", {
9976
9824
  userId: user.uid
9977
9825
  });
@@ -9988,11 +9836,7 @@ var AuthService = class extends BaseService {
9988
9836
  };
9989
9837
  console.log("[AUTH] Contact person object created");
9990
9838
  console.log("[AUTH] Initializing clinic services");
9991
- const clinicAdminService = new ClinicAdminService(
9992
- this.db,
9993
- this.auth,
9994
- this.app
9995
- );
9839
+ const clinicAdminService = new ClinicAdminService(this.db, this.auth, this.app);
9996
9840
  const clinicGroupService = new ClinicGroupService(
9997
9841
  this.db,
9998
9842
  this.auth,
@@ -10009,18 +9853,14 @@ var AuthService = class extends BaseService {
10009
9853
  mediaService
10010
9854
  );
10011
9855
  clinicAdminService.setServices(clinicGroupService, clinicService);
10012
- console.log(
10013
- "[AUTH] Services initialized and circular dependencies resolved"
10014
- );
9856
+ console.log("[AUTH] Services initialized and circular dependencies resolved");
10015
9857
  let clinicGroup = null;
10016
9858
  let adminProfile = null;
10017
9859
  if (data.isCreatingNewGroup) {
10018
9860
  console.log("[AUTH] Creating new clinic group flow");
10019
9861
  if (!data.clinicGroupData) {
10020
9862
  console.error("[AUTH] Clinic group data is missing");
10021
- throw new Error(
10022
- "Clinic group data is required when creating a new group"
10023
- );
9863
+ throw new Error("Clinic group data is required when creating a new group");
10024
9864
  }
10025
9865
  console.log("[AUTH] Creating clinic admin first (without group)");
10026
9866
  const createClinicAdminData = {
@@ -10033,17 +9873,12 @@ var AuthService = class extends BaseService {
10033
9873
  // No clinicGroupId yet
10034
9874
  };
10035
9875
  try {
10036
- adminProfile = await clinicAdminService.createClinicAdmin(
10037
- createClinicAdminData
10038
- );
9876
+ adminProfile = await clinicAdminService.createClinicAdmin(createClinicAdminData);
10039
9877
  console.log("[AUTH] Clinic admin created successfully", {
10040
9878
  adminId: adminProfile.id
10041
9879
  });
10042
9880
  } catch (adminCreationError) {
10043
- console.error(
10044
- "[AUTH] Clinic admin creation failed:",
10045
- adminCreationError
10046
- );
9881
+ console.error("[AUTH] Clinic admin creation failed:", adminCreationError);
10047
9882
  throw adminCreationError;
10048
9883
  }
10049
9884
  try {
@@ -10051,14 +9886,9 @@ var AuthService = class extends BaseService {
10051
9886
  user = await this.userService.updateUser(firebaseUser.uid, {
10052
9887
  adminProfile: adminProfile.id
10053
9888
  });
10054
- console.log(
10055
- "[AUTH] User updated with admin profile reference successfully"
10056
- );
9889
+ console.log("[AUTH] User updated with admin profile reference successfully");
10057
9890
  } catch (userUpdateError) {
10058
- console.error(
10059
- "[AUTH] Failed to update user with admin profile:",
10060
- userUpdateError
10061
- );
9891
+ console.error("[AUTH] Failed to update user with admin profile:", userUpdateError);
10062
9892
  throw userUpdateError;
10063
9893
  }
10064
9894
  const createClinicGroupData = {
@@ -10096,23 +9926,16 @@ var AuthService = class extends BaseService {
10096
9926
  clinicGroupId: clinicGroup.id
10097
9927
  });
10098
9928
  console.log("[AUTH] Admin updated with clinic group ID successfully");
10099
- adminProfile = await clinicAdminService.getClinicAdmin(
10100
- adminProfile.id
10101
- );
9929
+ adminProfile = await clinicAdminService.getClinicAdmin(adminProfile.id);
10102
9930
  } catch (groupCreationError) {
10103
- console.error(
10104
- "[AUTH] Clinic group creation failed:",
10105
- groupCreationError
10106
- );
9931
+ console.error("[AUTH] Clinic group creation failed:", groupCreationError);
10107
9932
  throw groupCreationError;
10108
9933
  }
10109
9934
  } else {
10110
9935
  console.log("[AUTH] Joining existing clinic group flow");
10111
9936
  if (!data.inviteToken) {
10112
9937
  console.error("[AUTH] Invite token is missing");
10113
- throw new Error(
10114
- "Invite token is required when joining an existing group"
10115
- );
9938
+ throw new Error("Invite token is required when joining an existing group");
10116
9939
  }
10117
9940
  console.log("[AUTH] Invite token provided", {
10118
9941
  token: data.inviteToken
@@ -10123,11 +9946,7 @@ var AuthService = class extends BaseService {
10123
9946
  const querySnapshot = await (0, import_firestore29.getDocs)(q);
10124
9947
  let foundGroup = null;
10125
9948
  let foundToken = null;
10126
- console.log(
10127
- "[AUTH] Found",
10128
- querySnapshot.size,
10129
- "clinic groups to check"
10130
- );
9949
+ console.log("[AUTH] Found", querySnapshot.size, "clinic groups to check");
10131
9950
  for (const docSnapshot of querySnapshot.docs) {
10132
9951
  const group = docSnapshot.data();
10133
9952
  console.log("[AUTH] Checking group", {
@@ -10173,17 +9992,12 @@ var AuthService = class extends BaseService {
10173
9992
  isActive: true
10174
9993
  };
10175
9994
  try {
10176
- adminProfile = await clinicAdminService.createClinicAdmin(
10177
- createClinicAdminData
10178
- );
9995
+ adminProfile = await clinicAdminService.createClinicAdmin(createClinicAdminData);
10179
9996
  console.log("[AUTH] Clinic admin created successfully", {
10180
9997
  adminId: adminProfile.id
10181
9998
  });
10182
9999
  } catch (adminCreationError) {
10183
- console.error(
10184
- "[AUTH] Clinic admin creation failed:",
10185
- adminCreationError
10186
- );
10000
+ console.error("[AUTH] Clinic admin creation failed:", adminCreationError);
10187
10001
  throw adminCreationError;
10188
10002
  }
10189
10003
  try {
@@ -10204,9 +10018,7 @@ var AuthService = class extends BaseService {
10204
10018
  clinicAdminId: (adminProfile == null ? void 0 : adminProfile.id) || "unknown"
10205
10019
  });
10206
10020
  if (!clinicGroup || !adminProfile) {
10207
- throw new Error(
10208
- "Failed to create or retrieve clinic group or admin profile"
10209
- );
10021
+ throw new Error("Failed to create or retrieve clinic group or admin profile");
10210
10022
  }
10211
10023
  return {
10212
10024
  user,
@@ -10234,11 +10046,7 @@ var AuthService = class extends BaseService {
10234
10046
  * Prijavljuje korisnika sa email-om i lozinkom
10235
10047
  */
10236
10048
  async signIn(email, password) {
10237
- const { user: firebaseUser } = await (0, import_auth7.signInWithEmailAndPassword)(
10238
- this.auth,
10239
- email,
10240
- password
10241
- );
10049
+ const { user: firebaseUser } = await (0, import_auth7.signInWithEmailAndPassword)(this.auth, email, password);
10242
10050
  return this.userService.getOrCreateUser(firebaseUser);
10243
10051
  }
10244
10052
  /**
@@ -10252,11 +10060,7 @@ var AuthService = class extends BaseService {
10252
10060
  async signInClinicAdmin(email, password) {
10253
10061
  var _a;
10254
10062
  try {
10255
- const clinicAdminService = new ClinicAdminService(
10256
- this.db,
10257
- this.auth,
10258
- this.app
10259
- );
10063
+ const clinicAdminService = new ClinicAdminService(this.db, this.auth, this.app);
10260
10064
  const clinicGroupService = new ClinicGroupService(
10261
10065
  this.db,
10262
10066
  this.auth,
@@ -10273,11 +10077,7 @@ var AuthService = class extends BaseService {
10273
10077
  mediaService
10274
10078
  );
10275
10079
  clinicAdminService.setServices(clinicGroupService, clinicService);
10276
- const { user: firebaseUser } = await (0, import_auth7.signInWithEmailAndPassword)(
10277
- this.auth,
10278
- email,
10279
- password
10280
- );
10080
+ const { user: firebaseUser } = await (0, import_auth7.signInWithEmailAndPassword)(this.auth, email, password);
10281
10081
  const user = await this.userService.getOrCreateUser(firebaseUser);
10282
10082
  if (!((_a = user.roles) == null ? void 0 : _a.includes("clinic_admin" /* CLINIC_ADMIN */))) {
10283
10083
  console.error("[AUTH] User is not a clinic admin:", user.uid);
@@ -10287,21 +10087,14 @@ var AuthService = class extends BaseService {
10287
10087
  console.error("[AUTH] User has no admin profile:", user.uid);
10288
10088
  throw AUTH_ERRORS.NOT_FOUND;
10289
10089
  }
10290
- const adminProfile = await clinicAdminService.getClinicAdmin(
10291
- user.adminProfile
10292
- );
10090
+ const adminProfile = await clinicAdminService.getClinicAdmin(user.adminProfile);
10293
10091
  if (!adminProfile) {
10294
10092
  console.error("[AUTH] Admin profile not found:", user.adminProfile);
10295
10093
  throw AUTH_ERRORS.NOT_FOUND;
10296
10094
  }
10297
- const clinicGroup = await clinicGroupService.getClinicGroup(
10298
- adminProfile.clinicGroupId
10299
- );
10095
+ const clinicGroup = await clinicGroupService.getClinicGroup(adminProfile.clinicGroupId);
10300
10096
  if (!clinicGroup) {
10301
- console.error(
10302
- "[AUTH] Clinic group not found:",
10303
- adminProfile.clinicGroupId
10304
- );
10097
+ console.error("[AUTH] Clinic group not found:", adminProfile.clinicGroupId);
10305
10098
  throw AUTH_ERRORS.NOT_FOUND;
10306
10099
  }
10307
10100
  return {
@@ -10314,39 +10107,6 @@ var AuthService = class extends BaseService {
10314
10107
  throw error;
10315
10108
  }
10316
10109
  }
10317
- /**
10318
- * Prijavljuje korisnika sa Facebook-om
10319
- */
10320
- async signInWithFacebook() {
10321
- const provider = new import_auth7.FacebookAuthProvider();
10322
- const { user: firebaseUser } = await (0, import_auth7.signInWithPopup)(this.auth, provider);
10323
- return this.userService.getOrCreateUser(firebaseUser);
10324
- }
10325
- /**
10326
- * Prijavljuje korisnika sa Google nalogom
10327
- */
10328
- async signInWithGoogle(initialRole = "patient" /* PATIENT */, options) {
10329
- const { user: firebaseUser } = await (0, import_auth7.signInWithPopup)(
10330
- this.auth,
10331
- this.googleProvider
10332
- );
10333
- const existingUser = await this.userService.getUserByEmail(
10334
- firebaseUser.email
10335
- );
10336
- if (existingUser) {
10337
- await this.userService.updateUserLoginTimestamp(existingUser.uid);
10338
- return existingUser;
10339
- }
10340
- return this.userService.createUser(firebaseUser, [initialRole], options);
10341
- }
10342
- /**
10343
- * Prijavljuje korisnika sa Apple-om
10344
- */
10345
- async signInWithApple() {
10346
- const provider = new import_auth7.OAuthProvider("apple.com");
10347
- const { user: firebaseUser } = await (0, import_auth7.signInWithPopup)(this.auth, provider);
10348
- return this.userService.getOrCreateUser(firebaseUser);
10349
- }
10350
10110
  /**
10351
10111
  * Prijavljuje korisnika anonimno
10352
10112
  */
@@ -10383,18 +10143,11 @@ var AuthService = class extends BaseService {
10383
10143
  throw AUTH_ERRORS.NOT_AUTHENTICATED;
10384
10144
  }
10385
10145
  if (!currentUser.isAnonymous) {
10386
- throw new AuthError(
10387
- "User is not anonymous",
10388
- "AUTH/NOT_ANONYMOUS_USER",
10389
- 400
10390
- );
10146
+ throw new AuthError("User is not anonymous", "AUTH/NOT_ANONYMOUS_USER", 400);
10391
10147
  }
10392
10148
  const credential = import_auth7.EmailAuthProvider.credential(email, password);
10393
10149
  await (0, import_auth7.linkWithCredential)(currentUser, credential);
10394
- return await this.userService.upgradeAnonymousUser(
10395
- currentUser.uid,
10396
- email
10397
- );
10150
+ return await this.userService.upgradeAnonymousUser(currentUser.uid, email);
10398
10151
  } catch (error) {
10399
10152
  if (error instanceof import_zod23.z.ZodError) {
10400
10153
  throw AUTH_ERRORS.VALIDATION_ERROR;
@@ -10406,109 +10159,6 @@ var AuthService = class extends BaseService {
10406
10159
  throw error;
10407
10160
  }
10408
10161
  }
10409
- /**
10410
- * Upgrades an anonymous user to a regular user by signing in with a Google account.
10411
- *
10412
- * @throws {AuthError} If the user is not anonymous.
10413
- * @throws {AuthError} If the user is not authenticated.
10414
- * @throws {AuthError} If the popup window is closed by the user.
10415
- * @throws {FirebaseError} If any other Firebase error occurs.
10416
- *
10417
- * @returns {Promise<User>} The upgraded user.
10418
- */
10419
- async upgradeAnonymousUserWithGoogle() {
10420
- try {
10421
- const currentUser = this.auth.currentUser;
10422
- if (!currentUser) {
10423
- throw AUTH_ERRORS.NOT_AUTHENTICATED;
10424
- }
10425
- if (!currentUser.isAnonymous) {
10426
- throw new AuthError(
10427
- "User is not anonymous",
10428
- "AUTH/NOT_ANONYMOUS_USER",
10429
- 400
10430
- );
10431
- }
10432
- const userCredential = await (0, import_auth7.signInWithPopup)(
10433
- this.auth,
10434
- this.googleProvider
10435
- );
10436
- if (!userCredential) throw AUTH_ERRORS.INVALID_CREDENTIAL;
10437
- return await this.userService.upgradeAnonymousUser(
10438
- currentUser.uid,
10439
- userCredential.user.email
10440
- );
10441
- } catch (error) {
10442
- const firebaseError = error;
10443
- if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
10444
- throw AUTH_ERRORS.POPUP_CLOSED;
10445
- }
10446
- throw error;
10447
- }
10448
- }
10449
- async upgradeAnonymousUserWithFacebook() {
10450
- try {
10451
- const currentUser = this.auth.currentUser;
10452
- if (!currentUser) {
10453
- throw AUTH_ERRORS.NOT_AUTHENTICATED;
10454
- }
10455
- if (!currentUser.isAnonymous) {
10456
- throw new AuthError(
10457
- "User is not anonymous",
10458
- "AUTH/NOT_ANONYMOUS_USER",
10459
- 400
10460
- );
10461
- }
10462
- this.facebookProvider.addScope("email");
10463
- const userCredential = await (0, import_auth7.signInWithPopup)(
10464
- this.auth,
10465
- this.facebookProvider
10466
- );
10467
- if (!userCredential) throw AUTH_ERRORS.INVALID_CREDENTIAL;
10468
- return await this.userService.upgradeAnonymousUser(
10469
- currentUser.uid,
10470
- userCredential.user.email
10471
- );
10472
- } catch (error) {
10473
- const firebaseError = error;
10474
- if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
10475
- throw AUTH_ERRORS.POPUP_CLOSED;
10476
- }
10477
- throw error;
10478
- }
10479
- }
10480
- async upgradeAnonymousUserWithApple() {
10481
- try {
10482
- const currentUser = this.auth.currentUser;
10483
- if (!currentUser) {
10484
- throw AUTH_ERRORS.NOT_AUTHENTICATED;
10485
- }
10486
- if (!currentUser.isAnonymous) {
10487
- throw new AuthError(
10488
- "User is not anonymous",
10489
- "AUTH/NOT_ANONYMOUS_USER",
10490
- 400
10491
- );
10492
- }
10493
- this.appleProvider.addScope("email");
10494
- this.appleProvider.addScope("name");
10495
- const userCredential = await (0, import_auth7.signInWithPopup)(
10496
- this.auth,
10497
- this.appleProvider
10498
- );
10499
- if (!userCredential) throw AUTH_ERRORS.INVALID_CREDENTIAL;
10500
- return await this.userService.upgradeAnonymousUser(
10501
- currentUser.uid,
10502
- userCredential.user.email
10503
- );
10504
- } catch (error) {
10505
- const firebaseError = error;
10506
- if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
10507
- throw AUTH_ERRORS.POPUP_CLOSED;
10508
- }
10509
- throw error;
10510
- }
10511
- }
10512
10162
  /**
10513
10163
  * Šalje email za resetovanje lozinke korisniku
10514
10164
  * @param email Email adresa korisnika
@@ -10589,11 +10239,7 @@ var AuthService = class extends BaseService {
10589
10239
  await this.validateSignupData(data);
10590
10240
  console.log("[AUTH] Creating Firebase user");
10591
10241
  try {
10592
- const result = await (0, import_auth7.createUserWithEmailAndPassword)(
10593
- this.auth,
10594
- data.email,
10595
- data.password
10596
- );
10242
+ const result = await (0, import_auth7.createUserWithEmailAndPassword)(this.auth, data.email, data.password);
10597
10243
  firebaseUser = result.user;
10598
10244
  console.log("[AUTH] Firebase user created successfully", {
10599
10245
  uid: firebaseUser.uid
@@ -10603,64 +10249,43 @@ var AuthService = class extends BaseService {
10603
10249
  throw handleFirebaseError(firebaseError);
10604
10250
  }
10605
10251
  console.log("[AUTH] Starting Firestore transaction");
10606
- const transactionResult = await (0, import_firestore29.runTransaction)(
10607
- this.db,
10608
- async (transaction) => {
10609
- console.log(
10610
- "[AUTH] Transaction started - creating user and practitioner"
10611
- );
10612
- const practitionerService = new PractitionerService(
10613
- this.db,
10614
- this.auth,
10615
- this.app
10616
- );
10617
- console.log("[AUTH] Creating user document");
10618
- const user = await this.userService.createUser(
10619
- firebaseUser,
10620
- ["practitioner" /* PRACTITIONER */],
10621
- { skipProfileCreation: true }
10252
+ const transactionResult = await (0, import_firestore29.runTransaction)(this.db, async (transaction) => {
10253
+ console.log("[AUTH] Transaction started - creating user and practitioner");
10254
+ const practitionerService = new PractitionerService(this.db, this.auth, this.app);
10255
+ console.log("[AUTH] Creating user document");
10256
+ const user = await this.userService.createUser(firebaseUser, ["practitioner" /* PRACTITIONER */], {
10257
+ skipProfileCreation: true
10258
+ });
10259
+ let practitioner;
10260
+ if (data.token) {
10261
+ console.log("[AUTH] Claiming existing practitioner profile with token");
10262
+ const claimedPractitioner = await practitionerService.validateTokenAndClaimProfile(
10263
+ data.token,
10264
+ firebaseUser.uid
10622
10265
  );
10623
- let practitioner;
10624
- if (data.token) {
10625
- console.log(
10626
- "[AUTH] Claiming existing practitioner profile with token"
10627
- );
10628
- const claimedPractitioner = await practitionerService.validateTokenAndClaimProfile(
10629
- data.token,
10630
- firebaseUser.uid
10631
- );
10632
- if (!claimedPractitioner) {
10633
- throw new Error("Invalid or expired invitation token");
10634
- }
10635
- practitioner = claimedPractitioner;
10636
- } else {
10637
- console.log("[AUTH] Creating new practitioner profile");
10638
- const practitionerData = buildPractitionerData(
10639
- data,
10640
- firebaseUser.uid
10641
- );
10642
- practitioner = await practitionerService.createPractitioner(
10643
- practitionerData
10644
- );
10266
+ if (!claimedPractitioner) {
10267
+ throw new Error("Invalid or expired invitation token");
10645
10268
  }
10646
- console.log("[AUTH] Linking practitioner to user");
10647
- await this.userService.updateUser(firebaseUser.uid, {
10648
- practitionerProfile: practitioner.id
10649
- });
10650
- console.log("[AUTH] Transaction operations completed successfully");
10651
- return { user, practitioner };
10269
+ practitioner = claimedPractitioner;
10270
+ } else {
10271
+ console.log("[AUTH] Creating new practitioner profile");
10272
+ const practitionerData = buildPractitionerData(data, firebaseUser.uid);
10273
+ practitioner = await practitionerService.createPractitioner(practitionerData);
10652
10274
  }
10653
- );
10275
+ console.log("[AUTH] Linking practitioner to user");
10276
+ await this.userService.updateUser(firebaseUser.uid, {
10277
+ practitionerProfile: practitioner.id
10278
+ });
10279
+ console.log("[AUTH] Transaction operations completed successfully");
10280
+ return { user, practitioner };
10281
+ });
10654
10282
  console.log("[AUTH] Atomic practitioner signup completed successfully", {
10655
10283
  userId: transactionResult.user.uid,
10656
10284
  practitionerId: transactionResult.practitioner.id
10657
10285
  });
10658
10286
  return transactionResult;
10659
10287
  } catch (error) {
10660
- console.error(
10661
- "[AUTH] Atomic signup failed, initiating cleanup...",
10662
- error
10663
- );
10288
+ console.error("[AUTH] Atomic signup failed, initiating cleanup...", error);
10664
10289
  if (firebaseUser) {
10665
10290
  await cleanupFirebaseUser(firebaseUser);
10666
10291
  }
@@ -10683,14 +10308,8 @@ var AuthService = class extends BaseService {
10683
10308
  }
10684
10309
  console.log("[AUTH] Email availability confirmed");
10685
10310
  if (data.token) {
10686
- const practitionerService = new PractitionerService(
10687
- this.db,
10688
- this.auth,
10689
- this.app
10690
- );
10691
- const isValidToken = await practitionerService.validateToken(
10692
- data.token
10693
- );
10311
+ const practitionerService = new PractitionerService(this.db, this.auth, this.app);
10312
+ const isValidToken = await practitionerService.validateToken(data.token);
10694
10313
  if (!isValidToken) {
10695
10314
  console.log("[AUTH] Invalid token provided:", data.token);
10696
10315
  throw new Error("Invalid or expired invitation token");
@@ -10721,16 +10340,8 @@ var AuthService = class extends BaseService {
10721
10340
  console.log("[AUTH] Starting practitioner signin process", {
10722
10341
  email
10723
10342
  });
10724
- const practitionerService = new PractitionerService(
10725
- this.db,
10726
- this.auth,
10727
- this.app
10728
- );
10729
- const { user: firebaseUser } = await (0, import_auth7.signInWithEmailAndPassword)(
10730
- this.auth,
10731
- email,
10732
- password
10733
- );
10343
+ const practitionerService = new PractitionerService(this.db, this.auth, this.app);
10344
+ const { user: firebaseUser } = await (0, import_auth7.signInWithEmailAndPassword)(this.auth, email, password);
10734
10345
  const user = await this.userService.getOrCreateUser(firebaseUser);
10735
10346
  console.log("[AUTH] User retrieved", { uid: user.uid });
10736
10347
  if (!((_a = user.roles) == null ? void 0 : _a.includes("practitioner" /* PRACTITIONER */))) {
@@ -10741,14 +10352,9 @@ var AuthService = class extends BaseService {
10741
10352
  console.error("[AUTH] User has no practitioner profile:", user.uid);
10742
10353
  throw AUTH_ERRORS.NOT_FOUND;
10743
10354
  }
10744
- const practitioner = await practitionerService.getPractitioner(
10745
- user.practitionerProfile
10746
- );
10355
+ const practitioner = await practitionerService.getPractitioner(user.practitionerProfile);
10747
10356
  if (!practitioner) {
10748
- console.error(
10749
- "[AUTH] Practitioner profile not found:",
10750
- user.practitionerProfile
10751
- );
10357
+ console.error("[AUTH] Practitioner profile not found:", user.practitionerProfile);
10752
10358
  throw AUTH_ERRORS.NOT_FOUND;
10753
10359
  }
10754
10360
  console.log("[AUTH] Practitioner signin completed successfully", {
@@ -10764,6 +10370,194 @@ var AuthService = class extends BaseService {
10764
10370
  throw error;
10765
10371
  }
10766
10372
  }
10373
+ /**
10374
+ * Signs in a user with a Google ID token from a mobile client.
10375
+ * If the user does not exist, a new user is created.
10376
+ * @param idToken - The Google ID token obtained from the mobile app.
10377
+ * @param initialRole - The role to assign to the user if they are being created.
10378
+ * @returns The signed-in or newly created user.
10379
+ */
10380
+ async signInWithGoogleIdToken(idToken, initialRole = "patient" /* PATIENT */) {
10381
+ try {
10382
+ console.log("[AUTH] Signing in with Google ID Token");
10383
+ const credential = import_auth7.GoogleAuthProvider.credential(idToken);
10384
+ const { user: firebaseUser } = await (0, import_auth7.signInWithCredential)(this.auth, credential);
10385
+ console.log("[AUTH] Firebase user signed in:", firebaseUser.uid);
10386
+ const existingUser = await this.userService.getUserById(firebaseUser.uid);
10387
+ if (existingUser) {
10388
+ console.log("[AUTH] Existing user found, returning profile:", existingUser.uid);
10389
+ return existingUser;
10390
+ }
10391
+ console.log("[AUTH] No existing user found, creating new profile for:", firebaseUser.uid);
10392
+ return this.userService.createUser(firebaseUser, [initialRole]);
10393
+ } catch (error) {
10394
+ console.error("[AUTH] Error in signInWithGoogleIdToken:", error);
10395
+ throw handleFirebaseError(error);
10396
+ }
10397
+ }
10398
+ /**
10399
+ * Signs in a user with a Google authorization code from a mobile client.
10400
+ * This method directly exchanges the authorization code for tokens using Google's OAuth2 API
10401
+ * with the platform-specific client ID (no client secret needed for native apps).
10402
+ * @param authorizationCode - The Google authorization code obtained from the mobile app.
10403
+ * @param redirectUri - The redirect URI used in the OAuth flow.
10404
+ * @param platform - The platform (ios/android) to determine which client ID to use.
10405
+ * @param initialRole - The role to assign to the user if they are being created.
10406
+ * @returns The signed-in or newly created user.
10407
+ */
10408
+ async signInWithGoogleAuthCode(authorizationCode, redirectUri, platform, initialRole = "patient" /* PATIENT */) {
10409
+ try {
10410
+ console.log("[AUTH] Signing in with Google authorization code (native flow)");
10411
+ console.log("[AUTH] Platform:", platform);
10412
+ console.log("[AUTH] Redirect URI:", redirectUri);
10413
+ console.log("[AUTH] Code length:", authorizationCode.length);
10414
+ const clientId = platform === "ios" ? process.env.GOOGLE_IOS_CLIENT_ID : process.env.GOOGLE_ANDROID_CLIENT_ID;
10415
+ if (!clientId) {
10416
+ throw new Error(
10417
+ `Missing Google ${platform.toUpperCase()} client ID in environment variables`
10418
+ );
10419
+ }
10420
+ console.log("[AUTH] Using client ID:", `${clientId.substring(0, 20)}...`);
10421
+ const tokenEndpoint = "https://oauth2.googleapis.com/token";
10422
+ const params = new URLSearchParams({
10423
+ client_id: clientId,
10424
+ code: authorizationCode,
10425
+ grant_type: "authorization_code",
10426
+ redirect_uri: redirectUri
10427
+ // For native apps, we don't include client_secret
10428
+ });
10429
+ console.log("[AUTH] Making request to Google token endpoint...");
10430
+ const response = await fetch(tokenEndpoint, {
10431
+ method: "POST",
10432
+ headers: {
10433
+ "Content-Type": "application/x-www-form-urlencoded"
10434
+ },
10435
+ body: params.toString()
10436
+ });
10437
+ if (!response.ok) {
10438
+ const errorText = await response.text();
10439
+ console.error("[AUTH] Google token exchange failed:", {
10440
+ status: response.status,
10441
+ statusText: response.statusText,
10442
+ error: errorText
10443
+ });
10444
+ throw new Error(`Google token exchange failed: ${response.status} - ${errorText}`);
10445
+ }
10446
+ const tokenData = await response.json();
10447
+ console.log("[AUTH] Token exchange response received:", {
10448
+ hasIdToken: !!tokenData.id_token,
10449
+ hasAccessToken: !!tokenData.access_token,
10450
+ hasRefreshToken: !!tokenData.refresh_token
10451
+ });
10452
+ if (!tokenData.id_token) {
10453
+ console.error("[AUTH] No ID token in response:", tokenData);
10454
+ throw new Error("No ID token received from Google token exchange");
10455
+ }
10456
+ console.log("[AUTH] Successfully obtained ID token from Google");
10457
+ console.log("[AUTH] ID token length:", tokenData.id_token.length);
10458
+ return await this.signInWithGoogleIdToken(tokenData.id_token, initialRole);
10459
+ } catch (error) {
10460
+ console.error("[AUTH] Error in signInWithGoogleAuthCode:", error);
10461
+ throw handleFirebaseError(error);
10462
+ }
10463
+ }
10464
+ /**
10465
+ * Links a Google account to the currently signed-in user using an ID token.
10466
+ * This is used to upgrade an anonymous user or to allow an existing user
10467
+ * to sign in with Google in the future.
10468
+ * @param idToken - The Google ID token obtained from the mobile app.
10469
+ * @returns The updated user profile.
10470
+ */
10471
+ async linkGoogleAccount(idToken) {
10472
+ try {
10473
+ console.log("[AUTH] Linking Google account with ID Token");
10474
+ const currentUser = this.auth.currentUser;
10475
+ if (!currentUser) {
10476
+ throw AUTH_ERRORS.NOT_AUTHENTICATED;
10477
+ }
10478
+ const wasAnonymous = currentUser.isAnonymous;
10479
+ console.log(`[AUTH] Current user is ${wasAnonymous ? "anonymous" : "not anonymous"}`);
10480
+ const credential = import_auth7.GoogleAuthProvider.credential(idToken);
10481
+ const userCredential = await (0, import_auth7.linkWithCredential)(currentUser, credential);
10482
+ const linkedFirebaseUser = userCredential.user;
10483
+ console.log("[AUTH] Google account linked successfully to user:", linkedFirebaseUser.uid);
10484
+ if (wasAnonymous) {
10485
+ console.log("[AUTH] Upgrading anonymous user profile");
10486
+ return await this.userService.upgradeAnonymousUser(
10487
+ linkedFirebaseUser.uid,
10488
+ linkedFirebaseUser.email
10489
+ );
10490
+ }
10491
+ return await this.userService.getUserById(linkedFirebaseUser.uid);
10492
+ } catch (error) {
10493
+ console.error("[AUTH] Error in linkGoogleAccount:", error);
10494
+ throw handleFirebaseError(error);
10495
+ }
10496
+ }
10497
+ /**
10498
+ * Links a Google account to the currently signed-in user using an authorization code.
10499
+ * This method directly exchanges the authorization code for tokens using Google's OAuth2 API
10500
+ * with the platform-specific client ID, then links the Google account to the current user.
10501
+ * @param authorizationCode - The Google authorization code obtained from the mobile app.
10502
+ * @param redirectUri - The redirect URI used in the OAuth flow.
10503
+ * @param platform - The platform (ios/android) to determine which client ID to use.
10504
+ * @returns The updated user profile.
10505
+ */
10506
+ async linkGoogleAccountWithAuthCode(authorizationCode, redirectUri, platform) {
10507
+ try {
10508
+ console.log("[AUTH] Linking Google account with authorization code (native flow)");
10509
+ console.log("[AUTH] Platform:", platform);
10510
+ console.log("[AUTH] Redirect URI:", redirectUri);
10511
+ console.log("[AUTH] Code length:", authorizationCode.length);
10512
+ const clientId = platform === "ios" ? process.env.GOOGLE_IOS_CLIENT_ID : process.env.GOOGLE_ANDROID_CLIENT_ID;
10513
+ if (!clientId) {
10514
+ throw new Error(
10515
+ `Missing Google ${platform.toUpperCase()} client ID in environment variables`
10516
+ );
10517
+ }
10518
+ console.log("[AUTH] Using client ID:", `${clientId.substring(0, 20)}...`);
10519
+ const tokenEndpoint = "https://oauth2.googleapis.com/token";
10520
+ const params = new URLSearchParams({
10521
+ client_id: clientId,
10522
+ code: authorizationCode,
10523
+ grant_type: "authorization_code",
10524
+ redirect_uri: redirectUri
10525
+ });
10526
+ console.log("[AUTH] Making request to Google token endpoint...");
10527
+ const response = await fetch(tokenEndpoint, {
10528
+ method: "POST",
10529
+ headers: {
10530
+ "Content-Type": "application/x-www-form-urlencoded"
10531
+ },
10532
+ body: params.toString()
10533
+ });
10534
+ if (!response.ok) {
10535
+ const errorText = await response.text();
10536
+ console.error("[AUTH] Google token exchange failed:", {
10537
+ status: response.status,
10538
+ statusText: response.statusText,
10539
+ error: errorText
10540
+ });
10541
+ throw new Error(`Google token exchange failed: ${response.status} - ${errorText}`);
10542
+ }
10543
+ const tokenData = await response.json();
10544
+ console.log("[AUTH] Token exchange response received:", {
10545
+ hasIdToken: !!tokenData.id_token,
10546
+ hasAccessToken: !!tokenData.access_token,
10547
+ hasRefreshToken: !!tokenData.refresh_token
10548
+ });
10549
+ if (!tokenData.id_token) {
10550
+ console.error("[AUTH] No ID token in response:", tokenData);
10551
+ throw new Error("No ID token received from Google token exchange");
10552
+ }
10553
+ console.log("[AUTH] Successfully obtained ID token from Google");
10554
+ console.log("[AUTH] ID token length:", tokenData.id_token.length);
10555
+ return await this.linkGoogleAccount(tokenData.id_token);
10556
+ } catch (error) {
10557
+ console.error("[AUTH] Error in linkGoogleAccountWithAuthCode:", error);
10558
+ throw handleFirebaseError(error);
10559
+ }
10560
+ }
10767
10561
  };
10768
10562
 
10769
10563
  // src/services/calendar/calendar.v2.service.ts