@blackcode_sa/metaestetics-api 1.12.7 → 1.12.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -10,7 +10,8 @@ import {
10
10
  query as query2,
11
11
  limit as limit2,
12
12
  startAfter as startAfter2,
13
- getDocs as getDocs2
13
+ getDocs as getDocs2,
14
+ getCountFromServer
14
15
  } from "firebase/firestore";
15
16
  import { getFunctions } from "firebase/functions";
16
17
 
@@ -675,49 +676,67 @@ var Language = /* @__PURE__ */ ((Language2) => {
675
676
  var ClinicTag = /* @__PURE__ */ ((ClinicTag6) => {
676
677
  ClinicTag6["PARKING"] = "parking";
677
678
  ClinicTag6["WIFI"] = "wifi";
678
- ClinicTag6["WHEELCHAIR_ACCESS"] = "wheelchair_access";
679
- ClinicTag6["CAFE"] = "cafe";
680
- ClinicTag6["PHARMACY"] = "pharmacy";
681
- ClinicTag6["WAITING_ROOM"] = "waiting_room";
679
+ ClinicTag6["LUXURY_WAITING"] = "luxury_waiting";
680
+ ClinicTag6["REFRESHMENTS"] = "refreshments";
681
+ ClinicTag6["PRIVATE_ROOMS"] = "private_rooms";
682
+ ClinicTag6["RECOVERY_AREA"] = "recovery_area";
682
683
  ClinicTag6["CARD_PAYMENT"] = "card_payment";
683
- ClinicTag6["INSURANCE"] = "insurance";
684
- ClinicTag6["CHILDREN_AREA"] = "children_area";
685
- ClinicTag6["TV"] = "tv";
686
- ClinicTag6["AIR_CONDITIONING"] = "air_conditioning";
687
- ClinicTag6["WATER_DISPENSER"] = "water_dispenser";
688
- ClinicTag6["VENDING_MACHINE"] = "vending_machine";
689
- ClinicTag6["ELEVATOR"] = "elevator";
690
- ClinicTag6["RAMP"] = "ramp";
691
- ClinicTag6["HANDICAP_PARKING"] = "handicap_parking";
692
- ClinicTag6["BRAILLE"] = "braille";
693
- ClinicTag6["SIGN_LANGUAGE"] = "sign_language";
694
- ClinicTag6["EMERGENCY_SERVICE"] = "emergency_service";
695
- ClinicTag6["LAB"] = "lab";
696
- ClinicTag6["XRAY"] = "xray";
697
- ClinicTag6["ULTRASOUND"] = "ultrasound";
698
- ClinicTag6["DENTAL"] = "dental";
699
- ClinicTag6["PEDIATRIC"] = "pediatric";
700
- ClinicTag6["GYNECOLOGY"] = "gynecology";
701
- ClinicTag6["CARDIOLOGY"] = "cardiology";
702
- ClinicTag6["DERMATOLOGY"] = "dermatology";
703
- ClinicTag6["ORTHOPEDIC"] = "orthopedic";
704
- ClinicTag6["OPHTHALMOLOGY"] = "ophthalmology";
705
- ClinicTag6["TELEMEDICINE"] = "telemedicine";
706
- ClinicTag6["HOME_VISITS"] = "home_visits";
684
+ ClinicTag6["FINANCING"] = "financing";
685
+ ClinicTag6["FREE_CONSULTATION"] = "free_consultation";
686
+ ClinicTag6["VIRTUAL_CONSULTATION"] = "virtual_consultation";
687
+ ClinicTag6["BEFORE_AFTER_PHOTOS"] = "before_after_photos";
688
+ ClinicTag6["AFTERCARE_SUPPORT"] = "aftercare_support";
689
+ ClinicTag6["BOTOX"] = "botox";
690
+ ClinicTag6["DERMAL_FILLERS"] = "dermal_fillers";
691
+ ClinicTag6["LASER_HAIR_REMOVAL"] = "laser_hair_removal";
692
+ ClinicTag6["LASER_SKIN_RESURFACING"] = "laser_skin_resurfacing";
693
+ ClinicTag6["CHEMICAL_PEELS"] = "chemical_peels";
694
+ ClinicTag6["MICRONEEDLING"] = "microneedling";
695
+ ClinicTag6["COOLSCULPTING"] = "coolsculpting";
696
+ ClinicTag6["THREAD_LIFT"] = "thread_lift";
697
+ ClinicTag6["LIP_ENHANCEMENT"] = "lip_enhancement";
698
+ ClinicTag6["RHINOPLASTY"] = "rhinoplasty";
699
+ ClinicTag6["SKIN_TIGHTENING"] = "skin_tightening";
700
+ ClinicTag6["FAT_DISSOLVING"] = "fat_dissolving";
701
+ ClinicTag6["PRP_TREATMENT"] = "prp_treatment";
702
+ ClinicTag6["HYDRAFACIAL"] = "hydrafacial";
703
+ ClinicTag6["IPL_PHOTOFACIAL"] = "ipl_photofacial";
704
+ ClinicTag6["BODY_CONTOURING"] = "body_contouring";
705
+ ClinicTag6["FACELIFT"] = "facelift";
706
+ ClinicTag6["RHINOPLASTY_SURGICAL"] = "rhinoplasty_surgical";
707
+ ClinicTag6["BREAST_AUGMENTATION"] = "breast_augmentation";
708
+ ClinicTag6["BREAST_REDUCTION"] = "breast_reduction";
709
+ ClinicTag6["BREAST_LIFT"] = "breast_lift";
710
+ ClinicTag6["TUMMY_TUCK"] = "tummy_tuck";
711
+ ClinicTag6["LIPOSUCTION"] = "liposuction";
712
+ ClinicTag6["BBL"] = "bbl";
713
+ ClinicTag6["MOMMY_MAKEOVER"] = "mommy_makeover";
714
+ ClinicTag6["ARM_LIFT"] = "arm_lift";
715
+ ClinicTag6["THIGH_LIFT"] = "thigh_lift";
716
+ ClinicTag6["EYELID_SURGERY"] = "eyelid_surgery";
717
+ ClinicTag6["BROW_LIFT"] = "brow_lift";
718
+ ClinicTag6["NECK_LIFT"] = "neck_lift";
719
+ ClinicTag6["OTOPLASTY"] = "otoplasty";
720
+ ClinicTag6["LABIAPLASTY"] = "labiaplasty";
707
721
  ClinicTag6["ONLINE_BOOKING"] = "online_booking";
708
722
  ClinicTag6["MOBILE_APP"] = "mobile_app";
709
723
  ClinicTag6["SMS_NOTIFICATIONS"] = "sms_notifications";
710
724
  ClinicTag6["EMAIL_NOTIFICATIONS"] = "email_notifications";
725
+ ClinicTag6["VIRTUAL_TRY_ON"] = "virtual_try_on";
726
+ ClinicTag6["SKIN_ANALYSIS"] = "skin_analysis";
727
+ ClinicTag6["TREATMENT_TRACKING"] = "treatment_tracking";
728
+ ClinicTag6["LOYALTY_PROGRAM"] = "loyalty_program";
711
729
  ClinicTag6["ENGLISH"] = "english";
712
- ClinicTag6["SERBIAN"] = "serbian";
713
730
  ClinicTag6["GERMAN"] = "german";
714
- ClinicTag6["RUSSIAN"] = "russian";
715
- ClinicTag6["CHINESE"] = "chinese";
716
- ClinicTag6["SPANISH"] = "spanish";
717
731
  ClinicTag6["FRENCH"] = "french";
732
+ ClinicTag6["SPANISH"] = "spanish";
733
+ ClinicTag6["ITALIAN"] = "italian";
734
+ ClinicTag6["DUTCH"] = "dutch";
735
+ ClinicTag6["RUSSIAN"] = "russian";
736
+ ClinicTag6["PORTUGUESE"] = "portuguese";
718
737
  ClinicTag6["OPEN_24_7"] = "open_24_7";
719
738
  ClinicTag6["WEEKEND_HOURS"] = "weekend_hours";
720
- ClinicTag6["NIGHT_SHIFT"] = "night_shift";
739
+ ClinicTag6["EXTENDED_HOURS"] = "extended_hours";
721
740
  ClinicTag6["HOLIDAY_HOURS"] = "holiday_hours";
722
741
  return ClinicTag6;
723
742
  })(ClinicTag || {});
@@ -1053,24 +1072,18 @@ var AppointmentService = class extends BaseService {
1053
1072
  `[APPOINTMENT_SERVICE] Getting available booking slots via HTTP for clinic: ${clinicId}, practitioner: ${practitionerId}, procedure: ${procedureId}`
1054
1073
  );
1055
1074
  if (!clinicId || !practitionerId || !procedureId || !startDate || !endDate) {
1056
- throw new Error(
1057
- "Missing required parameters for booking slots calculation"
1058
- );
1075
+ throw new Error("Missing required parameters for booking slots calculation");
1059
1076
  }
1060
1077
  if (endDate <= startDate) {
1061
1078
  throw new Error("End date must be after start date");
1062
1079
  }
1063
1080
  const currentUser = this.auth.currentUser;
1064
1081
  if (!currentUser) {
1065
- throw new Error(
1066
- "User must be authenticated to get available booking slots"
1067
- );
1082
+ throw new Error("User must be authenticated to get available booking slots");
1068
1083
  }
1069
1084
  const functionUrl = `https://europe-west6-metaestetics.cloudfunctions.net/bookingApi/getAvailableBookingSlots`;
1070
1085
  const idToken = await currentUser.getIdToken();
1071
- console.log(
1072
- `[APPOINTMENT_SERVICE] Got user token, user ID: ${currentUser.uid}`
1073
- );
1086
+ console.log(`[APPOINTMENT_SERVICE] Got user token, user ID: ${currentUser.uid}`);
1074
1087
  const requestData = {
1075
1088
  clinicId,
1076
1089
  practitionerId,
@@ -1081,9 +1094,7 @@ var AppointmentService = class extends BaseService {
1081
1094
  end: endDate.getTime()
1082
1095
  }
1083
1096
  };
1084
- console.log(
1085
- `[APPOINTMENT_SERVICE] Making fetch request to ${functionUrl}`
1086
- );
1097
+ console.log(`[APPOINTMENT_SERVICE] Making fetch request to ${functionUrl}`);
1087
1098
  const response = await fetch(functionUrl, {
1088
1099
  method: "POST",
1089
1100
  mode: "cors",
@@ -1105,9 +1116,7 @@ var AppointmentService = class extends BaseService {
1105
1116
  );
1106
1117
  if (!response.ok) {
1107
1118
  const errorText = await response.text();
1108
- console.error(
1109
- `[APPOINTMENT_SERVICE] Error response details: ${errorText}`
1110
- );
1119
+ console.error(`[APPOINTMENT_SERVICE] Error response details: ${errorText}`);
1111
1120
  throw new Error(
1112
1121
  `Failed to get available booking slots: ${response.status} ${response.statusText} - ${errorText}`
1113
1122
  );
@@ -1115,24 +1124,15 @@ var AppointmentService = class extends BaseService {
1115
1124
  const result = await response.json();
1116
1125
  console.log(`[APPOINTMENT_SERVICE] Response parsed successfully`, result);
1117
1126
  if (!result.success) {
1118
- throw new Error(
1119
- result.error || "Failed to get available booking slots"
1120
- );
1127
+ throw new Error(result.error || "Failed to get available booking slots");
1121
1128
  }
1122
- const slots = result.availableSlots.map(
1123
- (slot) => ({
1124
- start: new Date(slot.start)
1125
- })
1126
- );
1127
- console.log(
1128
- `[APPOINTMENT_SERVICE] Found ${slots.length} available booking slots via HTTP`
1129
- );
1129
+ const slots = result.availableSlots.map((slot) => ({
1130
+ start: new Date(slot.start)
1131
+ }));
1132
+ console.log(`[APPOINTMENT_SERVICE] Found ${slots.length} available booking slots via HTTP`);
1130
1133
  return slots;
1131
1134
  } catch (error) {
1132
- console.error(
1133
- "[APPOINTMENT_SERVICE] Error getting available booking slots via HTTP:",
1134
- error
1135
- );
1135
+ console.error("[APPOINTMENT_SERVICE] Error getting available booking slots via HTTP:", error);
1136
1136
  throw error;
1137
1137
  }
1138
1138
  }
@@ -1144,9 +1144,7 @@ var AppointmentService = class extends BaseService {
1144
1144
  */
1145
1145
  async createAppointmentHttp(data) {
1146
1146
  try {
1147
- console.log(
1148
- "[APPOINTMENT_SERVICE] Creating appointment via cloud function"
1149
- );
1147
+ console.log("[APPOINTMENT_SERVICE] Creating appointment via cloud function");
1150
1148
  const currentUser = this.auth.currentUser;
1151
1149
  if (!currentUser) {
1152
1150
  throw new Error("User must be authenticated to create an appointment");
@@ -1160,9 +1158,7 @@ var AppointmentService = class extends BaseService {
1160
1158
  appointmentEndTime: data.appointmentEndTime.toMillis ? data.appointmentEndTime.toMillis() : new Date(data.appointmentEndTime).getTime(),
1161
1159
  patientNotes: (data == null ? void 0 : data.patientNotes) || null
1162
1160
  };
1163
- console.log(
1164
- `[APPOINTMENT_SERVICE] Making fetch request to ${functionUrl}`
1165
- );
1161
+ console.log(`[APPOINTMENT_SERVICE] Making fetch request to ${functionUrl}`);
1166
1162
  const response = await fetch(functionUrl, {
1167
1163
  method: "POST",
1168
1164
  mode: "cors",
@@ -1181,9 +1177,7 @@ var AppointmentService = class extends BaseService {
1181
1177
  );
1182
1178
  if (!response.ok) {
1183
1179
  const errorText = await response.text();
1184
- console.error(
1185
- `[APPOINTMENT_SERVICE] Error response details: ${errorText}`
1186
- );
1180
+ console.error(`[APPOINTMENT_SERVICE] Error response details: ${errorText}`);
1187
1181
  throw new Error(
1188
1182
  `Failed to create appointment: ${response.status} ${response.statusText} - ${errorText}`
1189
1183
  );
@@ -1193,25 +1187,16 @@ var AppointmentService = class extends BaseService {
1193
1187
  throw new Error(result.error || "Failed to create appointment");
1194
1188
  }
1195
1189
  if (result.appointmentData) {
1196
- console.log(
1197
- `[APPOINTMENT_SERVICE] Appointment created with ID: ${result.appointmentId}`
1198
- );
1190
+ console.log(`[APPOINTMENT_SERVICE] Appointment created with ID: ${result.appointmentId}`);
1199
1191
  return result.appointmentData;
1200
1192
  }
1201
- const createdAppointment = await this.getAppointmentById(
1202
- result.appointmentId
1203
- );
1193
+ const createdAppointment = await this.getAppointmentById(result.appointmentId);
1204
1194
  if (!createdAppointment) {
1205
- throw new Error(
1206
- `Failed to retrieve created appointment with ID: ${result.appointmentId}`
1207
- );
1195
+ throw new Error(`Failed to retrieve created appointment with ID: ${result.appointmentId}`);
1208
1196
  }
1209
1197
  return createdAppointment;
1210
1198
  } catch (error) {
1211
- console.error(
1212
- "[APPOINTMENT_SERVICE] Error creating appointment via cloud function:",
1213
- error
1214
- );
1199
+ console.error("[APPOINTMENT_SERVICE] Error creating appointment via cloud function:", error);
1215
1200
  throw error;
1216
1201
  }
1217
1202
  }
@@ -1223,19 +1208,14 @@ var AppointmentService = class extends BaseService {
1223
1208
  */
1224
1209
  async getAppointmentById(appointmentId) {
1225
1210
  try {
1226
- console.log(
1227
- `[APPOINTMENT_SERVICE] Getting appointment with ID: ${appointmentId}`
1228
- );
1211
+ console.log(`[APPOINTMENT_SERVICE] Getting appointment with ID: ${appointmentId}`);
1229
1212
  const appointment = await getAppointmentByIdUtil(this.db, appointmentId);
1230
1213
  console.log(
1231
1214
  `[APPOINTMENT_SERVICE] Appointment ${appointmentId} ${appointment ? "found" : "not found"}`
1232
1215
  );
1233
1216
  return appointment;
1234
1217
  } catch (error) {
1235
- console.error(
1236
- `[APPOINTMENT_SERVICE] Error getting appointment ${appointmentId}:`,
1237
- error
1238
- );
1218
+ console.error(`[APPOINTMENT_SERVICE] Error getting appointment ${appointmentId}:`, error);
1239
1219
  throw error;
1240
1220
  }
1241
1221
  }
@@ -1248,24 +1228,13 @@ var AppointmentService = class extends BaseService {
1248
1228
  */
1249
1229
  async updateAppointment(appointmentId, data) {
1250
1230
  try {
1251
- console.log(
1252
- `[APPOINTMENT_SERVICE] Updating appointment with ID: ${appointmentId}`
1253
- );
1231
+ console.log(`[APPOINTMENT_SERVICE] Updating appointment with ID: ${appointmentId}`);
1254
1232
  const validatedData = await updateAppointmentSchema.parseAsync(data);
1255
- const updatedAppointment = await updateAppointmentUtil(
1256
- this.db,
1257
- appointmentId,
1258
- validatedData
1259
- );
1260
- console.log(
1261
- `[APPOINTMENT_SERVICE] Appointment ${appointmentId} updated successfully`
1262
- );
1233
+ const updatedAppointment = await updateAppointmentUtil(this.db, appointmentId, validatedData);
1234
+ console.log(`[APPOINTMENT_SERVICE] Appointment ${appointmentId} updated successfully`);
1263
1235
  return updatedAppointment;
1264
1236
  } catch (error) {
1265
- console.error(
1266
- `[APPOINTMENT_SERVICE] Error updating appointment ${appointmentId}:`,
1267
- error
1268
- );
1237
+ console.error(`[APPOINTMENT_SERVICE] Error updating appointment ${appointmentId}:`, error);
1269
1238
  throw error;
1270
1239
  }
1271
1240
  }
@@ -1277,21 +1246,13 @@ var AppointmentService = class extends BaseService {
1277
1246
  */
1278
1247
  async searchAppointments(params) {
1279
1248
  try {
1280
- console.log(
1281
- "[APPOINTMENT_SERVICE] Searching appointments with params:",
1282
- params
1283
- );
1249
+ console.log("[APPOINTMENT_SERVICE] Searching appointments with params:", params);
1284
1250
  await searchAppointmentsSchema.parseAsync(params);
1285
1251
  const result = await searchAppointmentsUtil(this.db, params);
1286
- console.log(
1287
- `[APPOINTMENT_SERVICE] Found ${result.appointments.length} appointments`
1288
- );
1252
+ console.log(`[APPOINTMENT_SERVICE] Found ${result.appointments.length} appointments`);
1289
1253
  return result;
1290
1254
  } catch (error) {
1291
- console.error(
1292
- "[APPOINTMENT_SERVICE] Error searching appointments:",
1293
- error
1294
- );
1255
+ console.error("[APPOINTMENT_SERVICE] Error searching appointments:", error);
1295
1256
  throw error;
1296
1257
  }
1297
1258
  }
@@ -1303,9 +1264,7 @@ var AppointmentService = class extends BaseService {
1303
1264
  * @returns Found appointments and the last document for pagination
1304
1265
  */
1305
1266
  async getPatientAppointments(patientId, options) {
1306
- console.log(
1307
- `[APPOINTMENT_SERVICE] Getting appointments for patient: ${patientId}`
1308
- );
1267
+ console.log(`[APPOINTMENT_SERVICE] Getting appointments for patient: ${patientId}`);
1309
1268
  const searchParams = {
1310
1269
  patientId,
1311
1270
  startDate: options == null ? void 0 : options.startDate,
@@ -1324,9 +1283,7 @@ var AppointmentService = class extends BaseService {
1324
1283
  * @returns Found appointments and the last document for pagination
1325
1284
  */
1326
1285
  async getPractitionerAppointments(practitionerId, options) {
1327
- console.log(
1328
- `[APPOINTMENT_SERVICE] Getting appointments for practitioner: ${practitionerId}`
1329
- );
1286
+ console.log(`[APPOINTMENT_SERVICE] Getting appointments for practitioner: ${practitionerId}`);
1330
1287
  const searchParams = {
1331
1288
  practitionerId,
1332
1289
  startDate: options == null ? void 0 : options.startDate,
@@ -1345,9 +1302,7 @@ var AppointmentService = class extends BaseService {
1345
1302
  * @returns Found appointments and the last document for pagination
1346
1303
  */
1347
1304
  async getClinicAppointments(clinicBranchId, options) {
1348
- console.log(
1349
- `[APPOINTMENT_SERVICE] Getting appointments for clinic: ${clinicBranchId}`
1350
- );
1305
+ console.log(`[APPOINTMENT_SERVICE] Getting appointments for clinic: ${clinicBranchId}`);
1351
1306
  const searchParams = {
1352
1307
  clinicBranchId,
1353
1308
  practitionerId: options == null ? void 0 : options.practitionerId,
@@ -1398,68 +1353,42 @@ var AppointmentService = class extends BaseService {
1398
1353
  * Confirms a PENDING appointment by an Admin/Clinic.
1399
1354
  */
1400
1355
  async confirmAppointmentAdmin(appointmentId) {
1401
- console.log(
1402
- `[APPOINTMENT_SERVICE] Admin confirming appointment: ${appointmentId}`
1403
- );
1356
+ console.log(`[APPOINTMENT_SERVICE] Admin confirming appointment: ${appointmentId}`);
1404
1357
  const appointment = await this.getAppointmentById(appointmentId);
1405
- if (!appointment)
1406
- throw new Error(`Appointment ${appointmentId} not found.`);
1358
+ if (!appointment) throw new Error(`Appointment ${appointmentId} not found.`);
1407
1359
  if (appointment.status !== "pending" /* PENDING */) {
1408
- throw new Error(
1409
- `Appointment ${appointmentId} is not in PENDING state to be confirmed.`
1410
- );
1360
+ throw new Error(`Appointment ${appointmentId} is not in PENDING state to be confirmed.`);
1411
1361
  }
1412
- return this.updateAppointmentStatus(
1413
- appointmentId,
1414
- "confirmed" /* CONFIRMED */
1415
- );
1362
+ return this.updateAppointmentStatus(appointmentId, "confirmed" /* CONFIRMED */);
1416
1363
  }
1417
1364
  /**
1418
1365
  * Cancels an appointment by the User (Patient).
1419
1366
  */
1420
1367
  async cancelAppointmentUser(appointmentId, reason) {
1421
- console.log(
1422
- `[APPOINTMENT_SERVICE] User canceling appointment: ${appointmentId}`
1423
- );
1424
- return this.updateAppointmentStatus(
1425
- appointmentId,
1426
- "canceled_patient" /* CANCELED_PATIENT */,
1427
- {
1428
- cancellationReason: reason,
1429
- canceledBy: "patient"
1430
- }
1431
- );
1368
+ console.log(`[APPOINTMENT_SERVICE] User canceling appointment: ${appointmentId}`);
1369
+ return this.updateAppointmentStatus(appointmentId, "canceled_patient" /* CANCELED_PATIENT */, {
1370
+ cancellationReason: reason,
1371
+ canceledBy: "patient"
1372
+ });
1432
1373
  }
1433
1374
  /**
1434
1375
  * Cancels an appointment by an Admin/Clinic.
1435
1376
  */
1436
1377
  async cancelAppointmentAdmin(appointmentId, reason) {
1437
- console.log(
1438
- `[APPOINTMENT_SERVICE] Admin canceling appointment: ${appointmentId}`
1439
- );
1440
- return this.updateAppointmentStatus(
1441
- appointmentId,
1442
- "canceled_clinic" /* CANCELED_CLINIC */,
1443
- {
1444
- cancellationReason: reason,
1445
- canceledBy: "clinic"
1446
- }
1447
- );
1378
+ console.log(`[APPOINTMENT_SERVICE] Admin canceling appointment: ${appointmentId}`);
1379
+ return this.updateAppointmentStatus(appointmentId, "canceled_clinic" /* CANCELED_CLINIC */, {
1380
+ cancellationReason: reason,
1381
+ canceledBy: "clinic"
1382
+ });
1448
1383
  }
1449
1384
  /**
1450
1385
  * Admin proposes to reschedule an appointment.
1451
1386
  * Sets status to RESCHEDULED_BY_CLINIC and updates times.
1452
1387
  */
1453
1388
  async rescheduleAppointmentAdmin(params) {
1454
- console.log(
1455
- `[APPOINTMENT_SERVICE] Admin rescheduling appointment: ${params.appointmentId}`
1456
- );
1457
- const validatedParams = await rescheduleAppointmentSchema.parseAsync(
1458
- params
1459
- );
1460
- const startTimestamp = this.convertToTimestamp(
1461
- validatedParams.newStartTime
1462
- );
1389
+ console.log(`[APPOINTMENT_SERVICE] Admin rescheduling appointment: ${params.appointmentId}`);
1390
+ const validatedParams = await rescheduleAppointmentSchema.parseAsync(params);
1391
+ const startTimestamp = this.convertToTimestamp(validatedParams.newStartTime);
1463
1392
  const endTimestamp = this.convertToTimestamp(validatedParams.newEndTime);
1464
1393
  if (endTimestamp.toMillis() <= startTimestamp.toMillis()) {
1465
1394
  throw new Error("New end time must be after new start time.");
@@ -1502,48 +1431,31 @@ var AppointmentService = class extends BaseService {
1502
1431
  if (value && typeof value.seconds === "number") {
1503
1432
  return new Timestamp2(value.seconds, value.nanoseconds || 0);
1504
1433
  }
1505
- throw new Error(
1506
- `Invalid timestamp format: ${typeof value}, value: ${JSON.stringify(
1507
- value
1508
- )}`
1509
- );
1434
+ throw new Error(`Invalid timestamp format: ${typeof value}, value: ${JSON.stringify(value)}`);
1510
1435
  }
1511
1436
  /**
1512
1437
  * User confirms a reschedule proposed by the clinic.
1513
1438
  * Status changes from RESCHEDULED_BY_CLINIC to CONFIRMED.
1514
1439
  */
1515
1440
  async rescheduleAppointmentConfirmUser(appointmentId) {
1516
- console.log(
1517
- `[APPOINTMENT_SERVICE] User confirming reschedule for: ${appointmentId}`
1518
- );
1441
+ console.log(`[APPOINTMENT_SERVICE] User confirming reschedule for: ${appointmentId}`);
1519
1442
  const appointment = await this.getAppointmentById(appointmentId);
1520
- if (!appointment)
1521
- throw new Error(`Appointment ${appointmentId} not found.`);
1443
+ if (!appointment) throw new Error(`Appointment ${appointmentId} not found.`);
1522
1444
  if (appointment.status !== "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
1523
- throw new Error(
1524
- `Appointment ${appointmentId} is not in RESCHEDULED_BY_CLINIC state.`
1525
- );
1445
+ throw new Error(`Appointment ${appointmentId} is not in RESCHEDULED_BY_CLINIC state.`);
1526
1446
  }
1527
- return this.updateAppointmentStatus(
1528
- appointmentId,
1529
- "confirmed" /* CONFIRMED */
1530
- );
1447
+ return this.updateAppointmentStatus(appointmentId, "confirmed" /* CONFIRMED */);
1531
1448
  }
1532
1449
  /**
1533
1450
  * User rejects a reschedule proposed by the clinic.
1534
1451
  * Status changes from RESCHEDULED_BY_CLINIC to CANCELED_PATIENT_RESCHEDULED.
1535
1452
  */
1536
1453
  async rescheduleAppointmentRejectUser(appointmentId, reason) {
1537
- console.log(
1538
- `[APPOINTMENT_SERVICE] User rejecting reschedule for: ${appointmentId}`
1539
- );
1454
+ console.log(`[APPOINTMENT_SERVICE] User rejecting reschedule for: ${appointmentId}`);
1540
1455
  const appointment = await this.getAppointmentById(appointmentId);
1541
- if (!appointment)
1542
- throw new Error(`Appointment ${appointmentId} not found.`);
1456
+ if (!appointment) throw new Error(`Appointment ${appointmentId} not found.`);
1543
1457
  if (appointment.status !== "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
1544
- throw new Error(
1545
- `Appointment ${appointmentId} is not in RESCHEDULED_BY_CLINIC state.`
1546
- );
1458
+ throw new Error(`Appointment ${appointmentId} is not in RESCHEDULED_BY_CLINIC state.`);
1547
1459
  }
1548
1460
  return this.updateAppointmentStatus(
1549
1461
  appointmentId,
@@ -1559,17 +1471,12 @@ var AppointmentService = class extends BaseService {
1559
1471
  * Requires all pending user forms to be completed.
1560
1472
  */
1561
1473
  async checkInPatientAdmin(appointmentId) {
1562
- console.log(
1563
- `[APPOINTMENT_SERVICE] Admin checking in patient for: ${appointmentId}`
1564
- );
1474
+ console.log(`[APPOINTMENT_SERVICE] Admin checking in patient for: ${appointmentId}`);
1565
1475
  const appointment = await this.getAppointmentById(appointmentId);
1566
- if (!appointment)
1567
- throw new Error(`Appointment ${appointmentId} not found.`);
1476
+ if (!appointment) throw new Error(`Appointment ${appointmentId} not found.`);
1568
1477
  if (appointment.pendingUserFormsIds && appointment.pendingUserFormsIds.length > 0) {
1569
1478
  throw new Error(
1570
- `Cannot check in: Patient has ${appointment.pendingUserFormsIds.length} pending required form(s). IDs: ${appointment.pendingUserFormsIds.join(
1571
- ", "
1572
- )}`
1479
+ `Cannot check in: Patient has ${appointment.pendingUserFormsIds.length} pending required form(s). IDs: ${appointment.pendingUserFormsIds.join(", ")}`
1573
1480
  );
1574
1481
  }
1575
1482
  if (appointment.status !== "confirmed" /* CONFIRMED */ && appointment.status !== "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
@@ -1577,25 +1484,17 @@ var AppointmentService = class extends BaseService {
1577
1484
  `Checking in appointment ${appointmentId} with status ${appointment.status}. Ensure this is intended.`
1578
1485
  );
1579
1486
  }
1580
- return this.updateAppointmentStatus(
1581
- appointmentId,
1582
- "checked_in" /* CHECKED_IN */
1583
- );
1487
+ return this.updateAppointmentStatus(appointmentId, "checked_in" /* CHECKED_IN */);
1584
1488
  }
1585
1489
  /**
1586
1490
  * Doctor starts the appointment procedure.
1587
1491
  */
1588
1492
  async startAppointmentDoctor(appointmentId) {
1589
- console.log(
1590
- `[APPOINTMENT_SERVICE] Doctor starting appointment: ${appointmentId}`
1591
- );
1493
+ console.log(`[APPOINTMENT_SERVICE] Doctor starting appointment: ${appointmentId}`);
1592
1494
  const appointment = await this.getAppointmentById(appointmentId);
1593
- if (!appointment)
1594
- throw new Error(`Appointment ${appointmentId} not found.`);
1495
+ if (!appointment) throw new Error(`Appointment ${appointmentId} not found.`);
1595
1496
  if (appointment.status !== "checked_in" /* CHECKED_IN */) {
1596
- throw new Error(
1597
- `Appointment ${appointmentId} must be CHECKED_IN to start.`
1598
- );
1497
+ throw new Error(`Appointment ${appointmentId} must be CHECKED_IN to start.`);
1599
1498
  }
1600
1499
  const updateData = {
1601
1500
  status: "in_progress" /* IN_PROGRESS */,
@@ -1609,24 +1508,18 @@ var AppointmentService = class extends BaseService {
1609
1508
  * Doctor completes and finalizes the appointment.
1610
1509
  */
1611
1510
  async completeAppointmentDoctor(appointmentId, finalizationNotes, actualDurationMinutesInput) {
1612
- console.log(
1613
- `[APPOINTMENT_SERVICE] Doctor completing appointment: ${appointmentId}`
1614
- );
1511
+ console.log(`[APPOINTMENT_SERVICE] Doctor completing appointment: ${appointmentId}`);
1615
1512
  const currentUser = this.auth.currentUser;
1616
- if (!currentUser)
1617
- throw new Error("Authentication required to complete appointment.");
1513
+ if (!currentUser) throw new Error("Authentication required to complete appointment.");
1618
1514
  const appointment = await this.getAppointmentById(appointmentId);
1619
- if (!appointment)
1620
- throw new Error(`Appointment ${appointmentId} not found.`);
1515
+ if (!appointment) throw new Error(`Appointment ${appointmentId} not found.`);
1621
1516
  let calculatedDurationMinutes = actualDurationMinutesInput;
1622
1517
  const procedureCompletionTime = Timestamp2.now();
1623
1518
  if (calculatedDurationMinutes === void 0 && appointment.procedureActualStartTime) {
1624
1519
  const startTimeMillis = appointment.procedureActualStartTime.toMillis();
1625
1520
  const endTimeMillis = procedureCompletionTime.toMillis();
1626
1521
  if (endTimeMillis > startTimeMillis) {
1627
- calculatedDurationMinutes = Math.round(
1628
- (endTimeMillis - startTimeMillis) / 6e4
1629
- );
1522
+ calculatedDurationMinutes = Math.round((endTimeMillis - startTimeMillis) / 6e4);
1630
1523
  }
1631
1524
  }
1632
1525
  const updateData = {
@@ -1650,31 +1543,22 @@ var AppointmentService = class extends BaseService {
1650
1543
  * Admin marks an appointment as No-Show.
1651
1544
  */
1652
1545
  async markNoShowAdmin(appointmentId) {
1653
- console.log(
1654
- `[APPOINTMENT_SERVICE] Admin marking no-show for: ${appointmentId}`
1655
- );
1546
+ console.log(`[APPOINTMENT_SERVICE] Admin marking no-show for: ${appointmentId}`);
1656
1547
  const appointment = await this.getAppointmentById(appointmentId);
1657
- if (!appointment)
1658
- throw new Error(`Appointment ${appointmentId} not found.`);
1548
+ if (!appointment) throw new Error(`Appointment ${appointmentId} not found.`);
1659
1549
  if (Timestamp2.now().toMillis() < appointment.appointmentStartTime.toMillis()) {
1660
1550
  throw new Error("Cannot mark no-show before appointment start time.");
1661
1551
  }
1662
- return this.updateAppointmentStatus(
1663
- appointmentId,
1664
- "no_show" /* NO_SHOW */,
1665
- {
1666
- cancellationReason: "Patient did not show up for the appointment.",
1667
- canceledBy: "clinic"
1668
- }
1669
- );
1552
+ return this.updateAppointmentStatus(appointmentId, "no_show" /* NO_SHOW */, {
1553
+ cancellationReason: "Patient did not show up for the appointment.",
1554
+ canceledBy: "clinic"
1555
+ });
1670
1556
  }
1671
1557
  /**
1672
1558
  * Adds a media item to an appointment.
1673
1559
  */
1674
1560
  async addMediaToAppointment(appointmentId, mediaItemData) {
1675
- console.log(
1676
- `[APPOINTMENT_SERVICE] Adding media to appointment ${appointmentId}`
1677
- );
1561
+ console.log(`[APPOINTMENT_SERVICE] Adding media to appointment ${appointmentId}`);
1678
1562
  const currentUser = this.auth.currentUser;
1679
1563
  if (!currentUser) throw new Error("Authentication required.");
1680
1564
  const newMediaItem = {
@@ -1714,9 +1598,7 @@ var AppointmentService = class extends BaseService {
1714
1598
  * Adds or updates review information for an appointment.
1715
1599
  */
1716
1600
  async addReviewToAppointment(appointmentId, reviewData) {
1717
- console.log(
1718
- `[APPOINTMENT_SERVICE] Adding review to appointment ${appointmentId}`
1719
- );
1601
+ console.log(`[APPOINTMENT_SERVICE] Adding review to appointment ${appointmentId}`);
1720
1602
  const newReviewInfo = {
1721
1603
  ...reviewData,
1722
1604
  reviewId: this.generateId(),
@@ -1750,9 +1632,7 @@ var AppointmentService = class extends BaseService {
1750
1632
  * @returns The updated appointment
1751
1633
  */
1752
1634
  async updateInternalNotes(appointmentId, notes) {
1753
- console.log(
1754
- `[APPOINTMENT_SERVICE] Updating internal notes for appointment: ${appointmentId}`
1755
- );
1635
+ console.log(`[APPOINTMENT_SERVICE] Updating internal notes for appointment: ${appointmentId}`);
1756
1636
  const updateData = {
1757
1637
  internalNotes: notes
1758
1638
  };
@@ -1768,9 +1648,7 @@ var AppointmentService = class extends BaseService {
1768
1648
  */
1769
1649
  async getUpcomingPatientAppointments(patientId, options) {
1770
1650
  try {
1771
- console.log(
1772
- `[APPOINTMENT_SERVICE] Getting upcoming appointments for patient: ${patientId}`
1773
- );
1651
+ console.log(`[APPOINTMENT_SERVICE] Getting upcoming appointments for patient: ${patientId}`);
1774
1652
  const effectiveStartDate = (options == null ? void 0 : options.startDate) || /* @__PURE__ */ new Date();
1775
1653
  const upcomingStatuses = [
1776
1654
  "pending" /* PENDING */,
@@ -1782,21 +1660,9 @@ var AppointmentService = class extends BaseService {
1782
1660
  const constraints = [];
1783
1661
  constraints.push(where2("patientId", "==", patientId));
1784
1662
  constraints.push(where2("status", "in", upcomingStatuses));
1785
- constraints.push(
1786
- where2(
1787
- "appointmentStartTime",
1788
- ">=",
1789
- Timestamp2.fromDate(effectiveStartDate)
1790
- )
1791
- );
1663
+ constraints.push(where2("appointmentStartTime", ">=", Timestamp2.fromDate(effectiveStartDate)));
1792
1664
  if (options == null ? void 0 : options.endDate) {
1793
- constraints.push(
1794
- where2(
1795
- "appointmentStartTime",
1796
- "<=",
1797
- Timestamp2.fromDate(options.endDate)
1798
- )
1799
- );
1665
+ constraints.push(where2("appointmentStartTime", "<=", Timestamp2.fromDate(options.endDate)));
1800
1666
  }
1801
1667
  constraints.push(orderBy2("appointmentStartTime", "asc"));
1802
1668
  if (options == null ? void 0 : options.limit) {
@@ -1805,14 +1671,9 @@ var AppointmentService = class extends BaseService {
1805
1671
  if (options == null ? void 0 : options.startAfter) {
1806
1672
  constraints.push(startAfter2(options.startAfter));
1807
1673
  }
1808
- const q = query2(
1809
- collection2(this.db, APPOINTMENTS_COLLECTION),
1810
- ...constraints
1811
- );
1674
+ const q = query2(collection2(this.db, APPOINTMENTS_COLLECTION), ...constraints);
1812
1675
  const querySnapshot = await getDocs2(q);
1813
- const appointments = querySnapshot.docs.map(
1814
- (doc38) => doc38.data()
1815
- );
1676
+ const appointments = querySnapshot.docs.map((doc38) => doc38.data());
1816
1677
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
1817
1678
  console.log(
1818
1679
  `[APPOINTMENT_SERVICE] Found ${appointments.length} upcoming appointments for patient ${patientId}`
@@ -1837,9 +1698,7 @@ var AppointmentService = class extends BaseService {
1837
1698
  */
1838
1699
  async getPastPatientAppointments(patientId, options) {
1839
1700
  try {
1840
- console.log(
1841
- `[APPOINTMENT_SERVICE] Getting past appointments for patient: ${patientId}`
1842
- );
1701
+ console.log(`[APPOINTMENT_SERVICE] Getting past appointments for patient: ${patientId}`);
1843
1702
  const effectiveEndDate = (options == null ? void 0 : options.endDate) || /* @__PURE__ */ new Date();
1844
1703
  const pastStatuses = ["completed" /* COMPLETED */];
1845
1704
  if (options == null ? void 0 : options.showCanceled) {
@@ -1857,20 +1716,10 @@ var AppointmentService = class extends BaseService {
1857
1716
  constraints.push(where2("status", "in", pastStatuses));
1858
1717
  if (options == null ? void 0 : options.startDate) {
1859
1718
  constraints.push(
1860
- where2(
1861
- "appointmentStartTime",
1862
- ">=",
1863
- Timestamp2.fromDate(options.startDate)
1864
- )
1719
+ where2("appointmentStartTime", ">=", Timestamp2.fromDate(options.startDate))
1865
1720
  );
1866
1721
  }
1867
- constraints.push(
1868
- where2(
1869
- "appointmentStartTime",
1870
- "<=",
1871
- Timestamp2.fromDate(effectiveEndDate)
1872
- )
1873
- );
1722
+ constraints.push(where2("appointmentStartTime", "<=", Timestamp2.fromDate(effectiveEndDate)));
1874
1723
  constraints.push(orderBy2("appointmentStartTime", "desc"));
1875
1724
  if (options == null ? void 0 : options.limit) {
1876
1725
  constraints.push(limit2(options.limit));
@@ -1878,14 +1727,9 @@ var AppointmentService = class extends BaseService {
1878
1727
  if (options == null ? void 0 : options.startAfter) {
1879
1728
  constraints.push(startAfter2(options.startAfter));
1880
1729
  }
1881
- const q = query2(
1882
- collection2(this.db, APPOINTMENTS_COLLECTION),
1883
- ...constraints
1884
- );
1730
+ const q = query2(collection2(this.db, APPOINTMENTS_COLLECTION), ...constraints);
1885
1731
  const querySnapshot = await getDocs2(q);
1886
- const appointments = querySnapshot.docs.map(
1887
- (doc38) => doc38.data()
1888
- );
1732
+ const appointments = querySnapshot.docs.map((doc38) => doc38.data());
1889
1733
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
1890
1734
  console.log(
1891
1735
  `[APPOINTMENT_SERVICE] Found ${appointments.length} past appointments for patient ${patientId}`
@@ -1899,6 +1743,46 @@ var AppointmentService = class extends BaseService {
1899
1743
  throw error;
1900
1744
  }
1901
1745
  }
1746
+ /**
1747
+ * Counts completed appointments for a patient with optional clinic filtering.
1748
+ *
1749
+ * @param patientId ID of the patient.
1750
+ * @param clinicBranchId Optional ID of the clinic branch to either include or exclude.
1751
+ * @param excludeClinic Optional boolean. If true (default), excludes the specified clinic. If false, includes only that clinic.
1752
+ * @returns The count of completed appointments.
1753
+ */
1754
+ async countCompletedAppointments(patientId, clinicBranchId, excludeClinic = true) {
1755
+ try {
1756
+ console.log(
1757
+ `[APPOINTMENT_SERVICE] Counting completed appointments for patient: ${patientId}`,
1758
+ { clinicBranchId, excludeClinic }
1759
+ );
1760
+ const constraints = [
1761
+ where2("patientId", "==", patientId),
1762
+ where2("status", "==", "completed" /* COMPLETED */)
1763
+ ];
1764
+ if (clinicBranchId) {
1765
+ if (excludeClinic) {
1766
+ constraints.push(where2("clinicBranchId", "!=", clinicBranchId));
1767
+ } else {
1768
+ constraints.push(where2("clinicBranchId", "==", clinicBranchId));
1769
+ }
1770
+ }
1771
+ const q = query2(collection2(this.db, APPOINTMENTS_COLLECTION), ...constraints);
1772
+ const snapshot = await getCountFromServer(q);
1773
+ const count = snapshot.data().count;
1774
+ console.log(
1775
+ `[APPOINTMENT_SERVICE] Found ${count} completed appointments for patient ${patientId}`
1776
+ );
1777
+ return count;
1778
+ } catch (error) {
1779
+ console.error(
1780
+ `[APPOINTMENT_SERVICE] Error counting completed appointments for patient ${patientId}:`,
1781
+ error
1782
+ );
1783
+ throw error;
1784
+ }
1785
+ }
1902
1786
  };
1903
1787
 
1904
1788
  // src/services/auth/auth.service.ts
@@ -1908,15 +1792,13 @@ import {
1908
1792
  signInAnonymously as firebaseSignInAnonymously,
1909
1793
  signOut as firebaseSignOut,
1910
1794
  GoogleAuthProvider,
1911
- FacebookAuthProvider,
1912
- OAuthProvider,
1913
- signInWithPopup,
1914
1795
  linkWithCredential,
1915
1796
  EmailAuthProvider,
1916
1797
  onAuthStateChanged,
1917
1798
  sendPasswordResetEmail,
1918
1799
  verifyPasswordResetCode,
1919
- confirmPasswordReset
1800
+ confirmPasswordReset,
1801
+ signInWithCredential
1920
1802
  } from "firebase/auth";
1921
1803
  import {
1922
1804
  collection as collection18,
@@ -7929,7 +7811,10 @@ var BillingTransactionsService = class extends BaseService {
7929
7811
  "subscription_reactivated" /* SUBSCRIPTION_REACTIVATED */,
7930
7812
  "subscription_deleted" /* SUBSCRIPTION_DELETED */
7931
7813
  ];
7932
- const constraints = [where12("type", "in", subscriptionTypes), orderBy5("timestamp", "desc")];
7814
+ const constraints = [
7815
+ where12("type", "in", subscriptionTypes),
7816
+ orderBy5("timestamp", "desc")
7817
+ ];
7933
7818
  if (startAfterDoc) {
7934
7819
  constraints.push(startAfter7(startAfterDoc));
7935
7820
  }
@@ -9993,19 +9878,13 @@ var AuthService = class extends BaseService {
9993
9878
  constructor(db, auth, app, userService) {
9994
9879
  super(db, auth, app);
9995
9880
  this.googleProvider = new GoogleAuthProvider();
9996
- this.facebookProvider = new FacebookAuthProvider();
9997
- this.appleProvider = new OAuthProvider("apple.com");
9998
9881
  this.userService = userService || new UserService(db, auth, app);
9999
9882
  }
10000
9883
  /**
10001
9884
  * Registruje novog korisnika sa email-om i lozinkom
10002
9885
  */
10003
9886
  async signUp(email, password, initialRole = "patient" /* PATIENT */, options) {
10004
- const { user: firebaseUser } = await createUserWithEmailAndPassword(
10005
- this.auth,
10006
- email,
10007
- password
10008
- );
9887
+ const { user: firebaseUser } = await createUserWithEmailAndPassword(this.auth, email, password);
10009
9888
  return this.userService.createUser(firebaseUser, [initialRole], options);
10010
9889
  }
10011
9890
  /**
@@ -10024,20 +9903,13 @@ var AuthService = class extends BaseService {
10024
9903
  await clinicAdminSignupSchema.parseAsync(data);
10025
9904
  console.log("[AUTH] Clinic admin signup data validation passed");
10026
9905
  } catch (validationError) {
10027
- console.error(
10028
- "[AUTH] Validation error in signUpClinicAdmin:",
10029
- validationError
10030
- );
9906
+ console.error("[AUTH] Validation error in signUpClinicAdmin:", validationError);
10031
9907
  throw validationError;
10032
9908
  }
10033
9909
  console.log("[AUTH] Creating Firebase user");
10034
9910
  let firebaseUser;
10035
9911
  try {
10036
- const result = await createUserWithEmailAndPassword(
10037
- this.auth,
10038
- data.email,
10039
- data.password
10040
- );
9912
+ const result = await createUserWithEmailAndPassword(this.auth, data.email, data.password);
10041
9913
  firebaseUser = result.user;
10042
9914
  console.log("[AUTH] Firebase user created successfully", {
10043
9915
  uid: firebaseUser.uid
@@ -10049,13 +9921,9 @@ var AuthService = class extends BaseService {
10049
9921
  console.log("[AUTH] Creating user with CLINIC_ADMIN role");
10050
9922
  let user;
10051
9923
  try {
10052
- user = await this.userService.createUser(
10053
- firebaseUser,
10054
- ["clinic_admin" /* CLINIC_ADMIN */],
10055
- {
10056
- skipProfileCreation: true
10057
- }
10058
- );
9924
+ user = await this.userService.createUser(firebaseUser, ["clinic_admin" /* CLINIC_ADMIN */], {
9925
+ skipProfileCreation: true
9926
+ });
10059
9927
  console.log("[AUTH] User with CLINIC_ADMIN role created successfully", {
10060
9928
  userId: user.uid
10061
9929
  });
@@ -10072,11 +9940,7 @@ var AuthService = class extends BaseService {
10072
9940
  };
10073
9941
  console.log("[AUTH] Contact person object created");
10074
9942
  console.log("[AUTH] Initializing clinic services");
10075
- const clinicAdminService = new ClinicAdminService(
10076
- this.db,
10077
- this.auth,
10078
- this.app
10079
- );
9943
+ const clinicAdminService = new ClinicAdminService(this.db, this.auth, this.app);
10080
9944
  const clinicGroupService = new ClinicGroupService(
10081
9945
  this.db,
10082
9946
  this.auth,
@@ -10093,18 +9957,14 @@ var AuthService = class extends BaseService {
10093
9957
  mediaService
10094
9958
  );
10095
9959
  clinicAdminService.setServices(clinicGroupService, clinicService);
10096
- console.log(
10097
- "[AUTH] Services initialized and circular dependencies resolved"
10098
- );
9960
+ console.log("[AUTH] Services initialized and circular dependencies resolved");
10099
9961
  let clinicGroup = null;
10100
9962
  let adminProfile = null;
10101
9963
  if (data.isCreatingNewGroup) {
10102
9964
  console.log("[AUTH] Creating new clinic group flow");
10103
9965
  if (!data.clinicGroupData) {
10104
9966
  console.error("[AUTH] Clinic group data is missing");
10105
- throw new Error(
10106
- "Clinic group data is required when creating a new group"
10107
- );
9967
+ throw new Error("Clinic group data is required when creating a new group");
10108
9968
  }
10109
9969
  console.log("[AUTH] Creating clinic admin first (without group)");
10110
9970
  const createClinicAdminData = {
@@ -10117,17 +9977,12 @@ var AuthService = class extends BaseService {
10117
9977
  // No clinicGroupId yet
10118
9978
  };
10119
9979
  try {
10120
- adminProfile = await clinicAdminService.createClinicAdmin(
10121
- createClinicAdminData
10122
- );
9980
+ adminProfile = await clinicAdminService.createClinicAdmin(createClinicAdminData);
10123
9981
  console.log("[AUTH] Clinic admin created successfully", {
10124
9982
  adminId: adminProfile.id
10125
9983
  });
10126
9984
  } catch (adminCreationError) {
10127
- console.error(
10128
- "[AUTH] Clinic admin creation failed:",
10129
- adminCreationError
10130
- );
9985
+ console.error("[AUTH] Clinic admin creation failed:", adminCreationError);
10131
9986
  throw adminCreationError;
10132
9987
  }
10133
9988
  try {
@@ -10135,14 +9990,9 @@ var AuthService = class extends BaseService {
10135
9990
  user = await this.userService.updateUser(firebaseUser.uid, {
10136
9991
  adminProfile: adminProfile.id
10137
9992
  });
10138
- console.log(
10139
- "[AUTH] User updated with admin profile reference successfully"
10140
- );
9993
+ console.log("[AUTH] User updated with admin profile reference successfully");
10141
9994
  } catch (userUpdateError) {
10142
- console.error(
10143
- "[AUTH] Failed to update user with admin profile:",
10144
- userUpdateError
10145
- );
9995
+ console.error("[AUTH] Failed to update user with admin profile:", userUpdateError);
10146
9996
  throw userUpdateError;
10147
9997
  }
10148
9998
  const createClinicGroupData = {
@@ -10180,23 +10030,16 @@ var AuthService = class extends BaseService {
10180
10030
  clinicGroupId: clinicGroup.id
10181
10031
  });
10182
10032
  console.log("[AUTH] Admin updated with clinic group ID successfully");
10183
- adminProfile = await clinicAdminService.getClinicAdmin(
10184
- adminProfile.id
10185
- );
10033
+ adminProfile = await clinicAdminService.getClinicAdmin(adminProfile.id);
10186
10034
  } catch (groupCreationError) {
10187
- console.error(
10188
- "[AUTH] Clinic group creation failed:",
10189
- groupCreationError
10190
- );
10035
+ console.error("[AUTH] Clinic group creation failed:", groupCreationError);
10191
10036
  throw groupCreationError;
10192
10037
  }
10193
10038
  } else {
10194
10039
  console.log("[AUTH] Joining existing clinic group flow");
10195
10040
  if (!data.inviteToken) {
10196
10041
  console.error("[AUTH] Invite token is missing");
10197
- throw new Error(
10198
- "Invite token is required when joining an existing group"
10199
- );
10042
+ throw new Error("Invite token is required when joining an existing group");
10200
10043
  }
10201
10044
  console.log("[AUTH] Invite token provided", {
10202
10045
  token: data.inviteToken
@@ -10207,11 +10050,7 @@ var AuthService = class extends BaseService {
10207
10050
  const querySnapshot = await getDocs18(q);
10208
10051
  let foundGroup = null;
10209
10052
  let foundToken = null;
10210
- console.log(
10211
- "[AUTH] Found",
10212
- querySnapshot.size,
10213
- "clinic groups to check"
10214
- );
10053
+ console.log("[AUTH] Found", querySnapshot.size, "clinic groups to check");
10215
10054
  for (const docSnapshot of querySnapshot.docs) {
10216
10055
  const group = docSnapshot.data();
10217
10056
  console.log("[AUTH] Checking group", {
@@ -10257,17 +10096,12 @@ var AuthService = class extends BaseService {
10257
10096
  isActive: true
10258
10097
  };
10259
10098
  try {
10260
- adminProfile = await clinicAdminService.createClinicAdmin(
10261
- createClinicAdminData
10262
- );
10099
+ adminProfile = await clinicAdminService.createClinicAdmin(createClinicAdminData);
10263
10100
  console.log("[AUTH] Clinic admin created successfully", {
10264
10101
  adminId: adminProfile.id
10265
10102
  });
10266
10103
  } catch (adminCreationError) {
10267
- console.error(
10268
- "[AUTH] Clinic admin creation failed:",
10269
- adminCreationError
10270
- );
10104
+ console.error("[AUTH] Clinic admin creation failed:", adminCreationError);
10271
10105
  throw adminCreationError;
10272
10106
  }
10273
10107
  try {
@@ -10288,9 +10122,7 @@ var AuthService = class extends BaseService {
10288
10122
  clinicAdminId: (adminProfile == null ? void 0 : adminProfile.id) || "unknown"
10289
10123
  });
10290
10124
  if (!clinicGroup || !adminProfile) {
10291
- throw new Error(
10292
- "Failed to create or retrieve clinic group or admin profile"
10293
- );
10125
+ throw new Error("Failed to create or retrieve clinic group or admin profile");
10294
10126
  }
10295
10127
  return {
10296
10128
  user,
@@ -10318,11 +10150,7 @@ var AuthService = class extends BaseService {
10318
10150
  * Prijavljuje korisnika sa email-om i lozinkom
10319
10151
  */
10320
10152
  async signIn(email, password) {
10321
- const { user: firebaseUser } = await signInWithEmailAndPassword(
10322
- this.auth,
10323
- email,
10324
- password
10325
- );
10153
+ const { user: firebaseUser } = await signInWithEmailAndPassword(this.auth, email, password);
10326
10154
  return this.userService.getOrCreateUser(firebaseUser);
10327
10155
  }
10328
10156
  /**
@@ -10336,11 +10164,7 @@ var AuthService = class extends BaseService {
10336
10164
  async signInClinicAdmin(email, password) {
10337
10165
  var _a;
10338
10166
  try {
10339
- const clinicAdminService = new ClinicAdminService(
10340
- this.db,
10341
- this.auth,
10342
- this.app
10343
- );
10167
+ const clinicAdminService = new ClinicAdminService(this.db, this.auth, this.app);
10344
10168
  const clinicGroupService = new ClinicGroupService(
10345
10169
  this.db,
10346
10170
  this.auth,
@@ -10357,11 +10181,7 @@ var AuthService = class extends BaseService {
10357
10181
  mediaService
10358
10182
  );
10359
10183
  clinicAdminService.setServices(clinicGroupService, clinicService);
10360
- const { user: firebaseUser } = await signInWithEmailAndPassword(
10361
- this.auth,
10362
- email,
10363
- password
10364
- );
10184
+ const { user: firebaseUser } = await signInWithEmailAndPassword(this.auth, email, password);
10365
10185
  const user = await this.userService.getOrCreateUser(firebaseUser);
10366
10186
  if (!((_a = user.roles) == null ? void 0 : _a.includes("clinic_admin" /* CLINIC_ADMIN */))) {
10367
10187
  console.error("[AUTH] User is not a clinic admin:", user.uid);
@@ -10371,21 +10191,14 @@ var AuthService = class extends BaseService {
10371
10191
  console.error("[AUTH] User has no admin profile:", user.uid);
10372
10192
  throw AUTH_ERRORS.NOT_FOUND;
10373
10193
  }
10374
- const adminProfile = await clinicAdminService.getClinicAdmin(
10375
- user.adminProfile
10376
- );
10194
+ const adminProfile = await clinicAdminService.getClinicAdmin(user.adminProfile);
10377
10195
  if (!adminProfile) {
10378
10196
  console.error("[AUTH] Admin profile not found:", user.adminProfile);
10379
10197
  throw AUTH_ERRORS.NOT_FOUND;
10380
10198
  }
10381
- const clinicGroup = await clinicGroupService.getClinicGroup(
10382
- adminProfile.clinicGroupId
10383
- );
10199
+ const clinicGroup = await clinicGroupService.getClinicGroup(adminProfile.clinicGroupId);
10384
10200
  if (!clinicGroup) {
10385
- console.error(
10386
- "[AUTH] Clinic group not found:",
10387
- adminProfile.clinicGroupId
10388
- );
10201
+ console.error("[AUTH] Clinic group not found:", adminProfile.clinicGroupId);
10389
10202
  throw AUTH_ERRORS.NOT_FOUND;
10390
10203
  }
10391
10204
  return {
@@ -10398,39 +10211,6 @@ var AuthService = class extends BaseService {
10398
10211
  throw error;
10399
10212
  }
10400
10213
  }
10401
- /**
10402
- * Prijavljuje korisnika sa Facebook-om
10403
- */
10404
- async signInWithFacebook() {
10405
- const provider = new FacebookAuthProvider();
10406
- const { user: firebaseUser } = await signInWithPopup(this.auth, provider);
10407
- return this.userService.getOrCreateUser(firebaseUser);
10408
- }
10409
- /**
10410
- * Prijavljuje korisnika sa Google nalogom
10411
- */
10412
- async signInWithGoogle(initialRole = "patient" /* PATIENT */, options) {
10413
- const { user: firebaseUser } = await signInWithPopup(
10414
- this.auth,
10415
- this.googleProvider
10416
- );
10417
- const existingUser = await this.userService.getUserByEmail(
10418
- firebaseUser.email
10419
- );
10420
- if (existingUser) {
10421
- await this.userService.updateUserLoginTimestamp(existingUser.uid);
10422
- return existingUser;
10423
- }
10424
- return this.userService.createUser(firebaseUser, [initialRole], options);
10425
- }
10426
- /**
10427
- * Prijavljuje korisnika sa Apple-om
10428
- */
10429
- async signInWithApple() {
10430
- const provider = new OAuthProvider("apple.com");
10431
- const { user: firebaseUser } = await signInWithPopup(this.auth, provider);
10432
- return this.userService.getOrCreateUser(firebaseUser);
10433
- }
10434
10214
  /**
10435
10215
  * Prijavljuje korisnika anonimno
10436
10216
  */
@@ -10467,18 +10247,11 @@ var AuthService = class extends BaseService {
10467
10247
  throw AUTH_ERRORS.NOT_AUTHENTICATED;
10468
10248
  }
10469
10249
  if (!currentUser.isAnonymous) {
10470
- throw new AuthError(
10471
- "User is not anonymous",
10472
- "AUTH/NOT_ANONYMOUS_USER",
10473
- 400
10474
- );
10250
+ throw new AuthError("User is not anonymous", "AUTH/NOT_ANONYMOUS_USER", 400);
10475
10251
  }
10476
10252
  const credential = EmailAuthProvider.credential(email, password);
10477
10253
  await linkWithCredential(currentUser, credential);
10478
- return await this.userService.upgradeAnonymousUser(
10479
- currentUser.uid,
10480
- email
10481
- );
10254
+ return await this.userService.upgradeAnonymousUser(currentUser.uid, email);
10482
10255
  } catch (error) {
10483
10256
  if (error instanceof z23.ZodError) {
10484
10257
  throw AUTH_ERRORS.VALIDATION_ERROR;
@@ -10490,109 +10263,6 @@ var AuthService = class extends BaseService {
10490
10263
  throw error;
10491
10264
  }
10492
10265
  }
10493
- /**
10494
- * Upgrades an anonymous user to a regular user by signing in with a Google account.
10495
- *
10496
- * @throws {AuthError} If the user is not anonymous.
10497
- * @throws {AuthError} If the user is not authenticated.
10498
- * @throws {AuthError} If the popup window is closed by the user.
10499
- * @throws {FirebaseError} If any other Firebase error occurs.
10500
- *
10501
- * @returns {Promise<User>} The upgraded user.
10502
- */
10503
- async upgradeAnonymousUserWithGoogle() {
10504
- try {
10505
- const currentUser = this.auth.currentUser;
10506
- if (!currentUser) {
10507
- throw AUTH_ERRORS.NOT_AUTHENTICATED;
10508
- }
10509
- if (!currentUser.isAnonymous) {
10510
- throw new AuthError(
10511
- "User is not anonymous",
10512
- "AUTH/NOT_ANONYMOUS_USER",
10513
- 400
10514
- );
10515
- }
10516
- const userCredential = await signInWithPopup(
10517
- this.auth,
10518
- this.googleProvider
10519
- );
10520
- if (!userCredential) throw AUTH_ERRORS.INVALID_CREDENTIAL;
10521
- return await this.userService.upgradeAnonymousUser(
10522
- currentUser.uid,
10523
- userCredential.user.email
10524
- );
10525
- } catch (error) {
10526
- const firebaseError = error;
10527
- if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
10528
- throw AUTH_ERRORS.POPUP_CLOSED;
10529
- }
10530
- throw error;
10531
- }
10532
- }
10533
- async upgradeAnonymousUserWithFacebook() {
10534
- try {
10535
- const currentUser = this.auth.currentUser;
10536
- if (!currentUser) {
10537
- throw AUTH_ERRORS.NOT_AUTHENTICATED;
10538
- }
10539
- if (!currentUser.isAnonymous) {
10540
- throw new AuthError(
10541
- "User is not anonymous",
10542
- "AUTH/NOT_ANONYMOUS_USER",
10543
- 400
10544
- );
10545
- }
10546
- this.facebookProvider.addScope("email");
10547
- const userCredential = await signInWithPopup(
10548
- this.auth,
10549
- this.facebookProvider
10550
- );
10551
- if (!userCredential) throw AUTH_ERRORS.INVALID_CREDENTIAL;
10552
- return await this.userService.upgradeAnonymousUser(
10553
- currentUser.uid,
10554
- userCredential.user.email
10555
- );
10556
- } catch (error) {
10557
- const firebaseError = error;
10558
- if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
10559
- throw AUTH_ERRORS.POPUP_CLOSED;
10560
- }
10561
- throw error;
10562
- }
10563
- }
10564
- async upgradeAnonymousUserWithApple() {
10565
- try {
10566
- const currentUser = this.auth.currentUser;
10567
- if (!currentUser) {
10568
- throw AUTH_ERRORS.NOT_AUTHENTICATED;
10569
- }
10570
- if (!currentUser.isAnonymous) {
10571
- throw new AuthError(
10572
- "User is not anonymous",
10573
- "AUTH/NOT_ANONYMOUS_USER",
10574
- 400
10575
- );
10576
- }
10577
- this.appleProvider.addScope("email");
10578
- this.appleProvider.addScope("name");
10579
- const userCredential = await signInWithPopup(
10580
- this.auth,
10581
- this.appleProvider
10582
- );
10583
- if (!userCredential) throw AUTH_ERRORS.INVALID_CREDENTIAL;
10584
- return await this.userService.upgradeAnonymousUser(
10585
- currentUser.uid,
10586
- userCredential.user.email
10587
- );
10588
- } catch (error) {
10589
- const firebaseError = error;
10590
- if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
10591
- throw AUTH_ERRORS.POPUP_CLOSED;
10592
- }
10593
- throw error;
10594
- }
10595
- }
10596
10266
  /**
10597
10267
  * Šalje email za resetovanje lozinke korisniku
10598
10268
  * @param email Email adresa korisnika
@@ -10673,11 +10343,7 @@ var AuthService = class extends BaseService {
10673
10343
  await this.validateSignupData(data);
10674
10344
  console.log("[AUTH] Creating Firebase user");
10675
10345
  try {
10676
- const result = await createUserWithEmailAndPassword(
10677
- this.auth,
10678
- data.email,
10679
- data.password
10680
- );
10346
+ const result = await createUserWithEmailAndPassword(this.auth, data.email, data.password);
10681
10347
  firebaseUser = result.user;
10682
10348
  console.log("[AUTH] Firebase user created successfully", {
10683
10349
  uid: firebaseUser.uid
@@ -10687,64 +10353,43 @@ var AuthService = class extends BaseService {
10687
10353
  throw handleFirebaseError(firebaseError);
10688
10354
  }
10689
10355
  console.log("[AUTH] Starting Firestore transaction");
10690
- const transactionResult = await runTransaction(
10691
- this.db,
10692
- async (transaction) => {
10693
- console.log(
10694
- "[AUTH] Transaction started - creating user and practitioner"
10695
- );
10696
- const practitionerService = new PractitionerService(
10697
- this.db,
10698
- this.auth,
10699
- this.app
10700
- );
10701
- console.log("[AUTH] Creating user document");
10702
- const user = await this.userService.createUser(
10703
- firebaseUser,
10704
- ["practitioner" /* PRACTITIONER */],
10705
- { skipProfileCreation: true }
10356
+ const transactionResult = await runTransaction(this.db, async (transaction) => {
10357
+ console.log("[AUTH] Transaction started - creating user and practitioner");
10358
+ const practitionerService = new PractitionerService(this.db, this.auth, this.app);
10359
+ console.log("[AUTH] Creating user document");
10360
+ const user = await this.userService.createUser(firebaseUser, ["practitioner" /* PRACTITIONER */], {
10361
+ skipProfileCreation: true
10362
+ });
10363
+ let practitioner;
10364
+ if (data.token) {
10365
+ console.log("[AUTH] Claiming existing practitioner profile with token");
10366
+ const claimedPractitioner = await practitionerService.validateTokenAndClaimProfile(
10367
+ data.token,
10368
+ firebaseUser.uid
10706
10369
  );
10707
- let practitioner;
10708
- if (data.token) {
10709
- console.log(
10710
- "[AUTH] Claiming existing practitioner profile with token"
10711
- );
10712
- const claimedPractitioner = await practitionerService.validateTokenAndClaimProfile(
10713
- data.token,
10714
- firebaseUser.uid
10715
- );
10716
- if (!claimedPractitioner) {
10717
- throw new Error("Invalid or expired invitation token");
10718
- }
10719
- practitioner = claimedPractitioner;
10720
- } else {
10721
- console.log("[AUTH] Creating new practitioner profile");
10722
- const practitionerData = buildPractitionerData(
10723
- data,
10724
- firebaseUser.uid
10725
- );
10726
- practitioner = await practitionerService.createPractitioner(
10727
- practitionerData
10728
- );
10370
+ if (!claimedPractitioner) {
10371
+ throw new Error("Invalid or expired invitation token");
10729
10372
  }
10730
- console.log("[AUTH] Linking practitioner to user");
10731
- await this.userService.updateUser(firebaseUser.uid, {
10732
- practitionerProfile: practitioner.id
10733
- });
10734
- console.log("[AUTH] Transaction operations completed successfully");
10735
- return { user, practitioner };
10373
+ practitioner = claimedPractitioner;
10374
+ } else {
10375
+ console.log("[AUTH] Creating new practitioner profile");
10376
+ const practitionerData = buildPractitionerData(data, firebaseUser.uid);
10377
+ practitioner = await practitionerService.createPractitioner(practitionerData);
10736
10378
  }
10737
- );
10379
+ console.log("[AUTH] Linking practitioner to user");
10380
+ await this.userService.updateUser(firebaseUser.uid, {
10381
+ practitionerProfile: practitioner.id
10382
+ });
10383
+ console.log("[AUTH] Transaction operations completed successfully");
10384
+ return { user, practitioner };
10385
+ });
10738
10386
  console.log("[AUTH] Atomic practitioner signup completed successfully", {
10739
10387
  userId: transactionResult.user.uid,
10740
10388
  practitionerId: transactionResult.practitioner.id
10741
10389
  });
10742
10390
  return transactionResult;
10743
10391
  } catch (error) {
10744
- console.error(
10745
- "[AUTH] Atomic signup failed, initiating cleanup...",
10746
- error
10747
- );
10392
+ console.error("[AUTH] Atomic signup failed, initiating cleanup...", error);
10748
10393
  if (firebaseUser) {
10749
10394
  await cleanupFirebaseUser(firebaseUser);
10750
10395
  }
@@ -10767,14 +10412,8 @@ var AuthService = class extends BaseService {
10767
10412
  }
10768
10413
  console.log("[AUTH] Email availability confirmed");
10769
10414
  if (data.token) {
10770
- const practitionerService = new PractitionerService(
10771
- this.db,
10772
- this.auth,
10773
- this.app
10774
- );
10775
- const isValidToken = await practitionerService.validateToken(
10776
- data.token
10777
- );
10415
+ const practitionerService = new PractitionerService(this.db, this.auth, this.app);
10416
+ const isValidToken = await practitionerService.validateToken(data.token);
10778
10417
  if (!isValidToken) {
10779
10418
  console.log("[AUTH] Invalid token provided:", data.token);
10780
10419
  throw new Error("Invalid or expired invitation token");
@@ -10805,16 +10444,8 @@ var AuthService = class extends BaseService {
10805
10444
  console.log("[AUTH] Starting practitioner signin process", {
10806
10445
  email
10807
10446
  });
10808
- const practitionerService = new PractitionerService(
10809
- this.db,
10810
- this.auth,
10811
- this.app
10812
- );
10813
- const { user: firebaseUser } = await signInWithEmailAndPassword(
10814
- this.auth,
10815
- email,
10816
- password
10817
- );
10447
+ const practitionerService = new PractitionerService(this.db, this.auth, this.app);
10448
+ const { user: firebaseUser } = await signInWithEmailAndPassword(this.auth, email, password);
10818
10449
  const user = await this.userService.getOrCreateUser(firebaseUser);
10819
10450
  console.log("[AUTH] User retrieved", { uid: user.uid });
10820
10451
  if (!((_a = user.roles) == null ? void 0 : _a.includes("practitioner" /* PRACTITIONER */))) {
@@ -10825,14 +10456,9 @@ var AuthService = class extends BaseService {
10825
10456
  console.error("[AUTH] User has no practitioner profile:", user.uid);
10826
10457
  throw AUTH_ERRORS.NOT_FOUND;
10827
10458
  }
10828
- const practitioner = await practitionerService.getPractitioner(
10829
- user.practitionerProfile
10830
- );
10459
+ const practitioner = await practitionerService.getPractitioner(user.practitionerProfile);
10831
10460
  if (!practitioner) {
10832
- console.error(
10833
- "[AUTH] Practitioner profile not found:",
10834
- user.practitionerProfile
10835
- );
10461
+ console.error("[AUTH] Practitioner profile not found:", user.practitionerProfile);
10836
10462
  throw AUTH_ERRORS.NOT_FOUND;
10837
10463
  }
10838
10464
  console.log("[AUTH] Practitioner signin completed successfully", {
@@ -10848,6 +10474,64 @@ var AuthService = class extends BaseService {
10848
10474
  throw error;
10849
10475
  }
10850
10476
  }
10477
+ /**
10478
+ * Signs in a user with a Google ID token from a mobile client.
10479
+ * If the user does not exist, a new user is created.
10480
+ * @param idToken - The Google ID token obtained from the mobile app.
10481
+ * @param initialRole - The role to assign to the user if they are being created.
10482
+ * @returns The signed-in or newly created user.
10483
+ */
10484
+ async signInWithGoogleIdToken(idToken, initialRole = "patient" /* PATIENT */) {
10485
+ try {
10486
+ console.log("[AUTH] Signing in with Google ID Token");
10487
+ const credential = GoogleAuthProvider.credential(idToken);
10488
+ const { user: firebaseUser } = await signInWithCredential(this.auth, credential);
10489
+ console.log("[AUTH] Firebase user signed in:", firebaseUser.uid);
10490
+ const existingUser = await this.userService.getUserById(firebaseUser.uid);
10491
+ if (existingUser) {
10492
+ console.log("[AUTH] Existing user found, returning profile:", existingUser.uid);
10493
+ return existingUser;
10494
+ }
10495
+ console.log("[AUTH] No existing user found, creating new profile for:", firebaseUser.uid);
10496
+ return this.userService.createUser(firebaseUser, [initialRole]);
10497
+ } catch (error) {
10498
+ console.error("[AUTH] Error in signInWithGoogleIdToken:", error);
10499
+ throw handleFirebaseError(error);
10500
+ }
10501
+ }
10502
+ /**
10503
+ * Links a Google account to the currently signed-in user using an ID token.
10504
+ * This is used to upgrade an anonymous user or to allow an existing user
10505
+ * to sign in with Google in the future.
10506
+ * @param idToken - The Google ID token obtained from the mobile app.
10507
+ * @returns The updated user profile.
10508
+ */
10509
+ async linkGoogleAccount(idToken) {
10510
+ try {
10511
+ console.log("[AUTH] Linking Google account with ID Token");
10512
+ const currentUser = this.auth.currentUser;
10513
+ if (!currentUser) {
10514
+ throw AUTH_ERRORS.NOT_AUTHENTICATED;
10515
+ }
10516
+ const wasAnonymous = currentUser.isAnonymous;
10517
+ console.log(`[AUTH] Current user is ${wasAnonymous ? "anonymous" : "not anonymous"}`);
10518
+ const credential = GoogleAuthProvider.credential(idToken);
10519
+ const userCredential = await linkWithCredential(currentUser, credential);
10520
+ const linkedFirebaseUser = userCredential.user;
10521
+ console.log("[AUTH] Google account linked successfully to user:", linkedFirebaseUser.uid);
10522
+ if (wasAnonymous) {
10523
+ console.log("[AUTH] Upgrading anonymous user profile");
10524
+ return await this.userService.upgradeAnonymousUser(
10525
+ linkedFirebaseUser.uid,
10526
+ linkedFirebaseUser.email
10527
+ );
10528
+ }
10529
+ return await this.userService.getUserById(linkedFirebaseUser.uid);
10530
+ } catch (error) {
10531
+ console.error("[AUTH] Error in linkGoogleAccount:", error);
10532
+ throw handleFirebaseError(error);
10533
+ }
10534
+ }
10851
10535
  };
10852
10536
 
10853
10537
  // src/services/calendar/calendar.v2.service.ts
@@ -14176,7 +13860,7 @@ import {
14176
13860
  limit as limit13,
14177
13861
  startAfter as startAfter11
14178
13862
  } from "firebase/firestore";
14179
- import { getCountFromServer } from "firebase/firestore";
13863
+ import { getCountFromServer as getCountFromServer2 } from "firebase/firestore";
14180
13864
  var DocumentationTemplateService = class extends BaseService {
14181
13865
  constructor(...args) {
14182
13866
  super(...args);
@@ -14434,7 +14118,7 @@ var DocumentationTemplateService = class extends BaseService {
14434
14118
  constraints.push(where26("sortingOrder", "==", sortingOrder));
14435
14119
  }
14436
14120
  const q = query26(this.collectionRef, ...constraints.filter((c) => c));
14437
- const snapshot = await getCountFromServer(q);
14121
+ const snapshot = await getCountFromServer2(q);
14438
14122
  return snapshot.data().count;
14439
14123
  }
14440
14124
  /**
@@ -16819,7 +16503,7 @@ import {
16819
16503
  limit as limit17,
16820
16504
  orderBy as orderBy19,
16821
16505
  startAfter as startAfter15,
16822
- getCountFromServer as getCountFromServer2
16506
+ getCountFromServer as getCountFromServer3
16823
16507
  } from "firebase/firestore";
16824
16508
 
16825
16509
  // src/backoffice/types/brand.types.ts
@@ -16895,7 +16579,7 @@ var BrandService = class extends BaseService {
16895
16579
  );
16896
16580
  }
16897
16581
  const q = query32(this.getBrandsRef(), ...constraints);
16898
- const snapshot = await getCountFromServer2(q);
16582
+ const snapshot = await getCountFromServer3(q);
16899
16583
  return snapshot.data().count;
16900
16584
  }
16901
16585
  /**
@@ -16957,7 +16641,7 @@ import {
16957
16641
  addDoc as addDoc4,
16958
16642
  collection as collection33,
16959
16643
  doc as doc33,
16960
- getCountFromServer as getCountFromServer3,
16644
+ getCountFromServer as getCountFromServer4,
16961
16645
  getDoc as getDoc35,
16962
16646
  getDocs as getDocs33,
16963
16647
  limit as limit18,
@@ -17009,7 +16693,7 @@ var CategoryService = class extends BaseService {
17009
16693
  where33("family", "==", family),
17010
16694
  where33("isActive", "==", active)
17011
16695
  );
17012
- const snapshot = await getCountFromServer3(q);
16696
+ const snapshot = await getCountFromServer4(q);
17013
16697
  counts[family] = snapshot.data().count;
17014
16698
  }
17015
16699
  return counts;
@@ -17150,7 +16834,7 @@ import {
17150
16834
  collectionGroup as collectionGroup2,
17151
16835
  deleteDoc as deleteDoc20,
17152
16836
  doc as doc34,
17153
- getCountFromServer as getCountFromServer4,
16837
+ getCountFromServer as getCountFromServer5,
17154
16838
  getDoc as getDoc36,
17155
16839
  getDocs as getDocs34,
17156
16840
  limit as limit19,
@@ -17213,7 +16897,7 @@ var SubcategoryService = class extends BaseService {
17213
16897
  const categoryId = categoryDoc.id;
17214
16898
  const subcategoriesRef = this.getSubcategoriesRef(categoryId);
17215
16899
  const q = query34(subcategoriesRef, where34("isActive", "==", active));
17216
- const snapshot = await getCountFromServer4(q);
16900
+ const snapshot = await getCountFromServer5(q);
17217
16901
  counts[categoryId] = snapshot.data().count;
17218
16902
  }
17219
16903
  return counts;
@@ -18015,7 +17699,7 @@ import {
18015
17699
  limit as limit21,
18016
17700
  orderBy as orderBy23,
18017
17701
  startAfter as startAfter19,
18018
- getCountFromServer as getCountFromServer6
17702
+ getCountFromServer as getCountFromServer7
18019
17703
  } from "firebase/firestore";
18020
17704
 
18021
17705
  // src/backoffice/types/product.types.ts
@@ -18094,7 +17778,7 @@ var ProductService = class extends BaseService {
18094
17778
  constraints.push(where36("technologyId", "==", technologyId));
18095
17779
  }
18096
17780
  const q = query36(collectionGroup3(this.db, PRODUCTS_COLLECTION), ...constraints);
18097
- const snapshot = await getCountFromServer6(q);
17781
+ const snapshot = await getCountFromServer7(q);
18098
17782
  return snapshot.data().count;
18099
17783
  }
18100
17784
  /**