@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/admin/index.js +30 -9
- package/dist/admin/index.mjs +30 -9
- package/dist/index.d.mts +49 -32
- package/dist/index.d.ts +49 -32
- package/dist/index.js +376 -582
- package/dist/index.mjs +390 -597
- package/package.json +1 -1
- package/src/admin/aggregation/forms/README.md +13 -0
- package/src/admin/aggregation/forms/filled-forms.aggregation.service.ts +71 -51
- package/src/services/appointment/README.md +17 -0
- package/src/services/appointment/appointment.service.ts +233 -386
- package/src/services/auth/auth.service.ts +422 -466
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
|
|
|
@@ -1071,24 +1072,18 @@ var AppointmentService = class extends BaseService {
|
|
|
1071
1072
|
`[APPOINTMENT_SERVICE] Getting available booking slots via HTTP for clinic: ${clinicId}, practitioner: ${practitionerId}, procedure: ${procedureId}`
|
|
1072
1073
|
);
|
|
1073
1074
|
if (!clinicId || !practitionerId || !procedureId || !startDate || !endDate) {
|
|
1074
|
-
throw new Error(
|
|
1075
|
-
"Missing required parameters for booking slots calculation"
|
|
1076
|
-
);
|
|
1075
|
+
throw new Error("Missing required parameters for booking slots calculation");
|
|
1077
1076
|
}
|
|
1078
1077
|
if (endDate <= startDate) {
|
|
1079
1078
|
throw new Error("End date must be after start date");
|
|
1080
1079
|
}
|
|
1081
1080
|
const currentUser = this.auth.currentUser;
|
|
1082
1081
|
if (!currentUser) {
|
|
1083
|
-
throw new Error(
|
|
1084
|
-
"User must be authenticated to get available booking slots"
|
|
1085
|
-
);
|
|
1082
|
+
throw new Error("User must be authenticated to get available booking slots");
|
|
1086
1083
|
}
|
|
1087
1084
|
const functionUrl = `https://europe-west6-metaestetics.cloudfunctions.net/bookingApi/getAvailableBookingSlots`;
|
|
1088
1085
|
const idToken = await currentUser.getIdToken();
|
|
1089
|
-
console.log(
|
|
1090
|
-
`[APPOINTMENT_SERVICE] Got user token, user ID: ${currentUser.uid}`
|
|
1091
|
-
);
|
|
1086
|
+
console.log(`[APPOINTMENT_SERVICE] Got user token, user ID: ${currentUser.uid}`);
|
|
1092
1087
|
const requestData = {
|
|
1093
1088
|
clinicId,
|
|
1094
1089
|
practitionerId,
|
|
@@ -1099,9 +1094,7 @@ var AppointmentService = class extends BaseService {
|
|
|
1099
1094
|
end: endDate.getTime()
|
|
1100
1095
|
}
|
|
1101
1096
|
};
|
|
1102
|
-
console.log(
|
|
1103
|
-
`[APPOINTMENT_SERVICE] Making fetch request to ${functionUrl}`
|
|
1104
|
-
);
|
|
1097
|
+
console.log(`[APPOINTMENT_SERVICE] Making fetch request to ${functionUrl}`);
|
|
1105
1098
|
const response = await fetch(functionUrl, {
|
|
1106
1099
|
method: "POST",
|
|
1107
1100
|
mode: "cors",
|
|
@@ -1123,9 +1116,7 @@ var AppointmentService = class extends BaseService {
|
|
|
1123
1116
|
);
|
|
1124
1117
|
if (!response.ok) {
|
|
1125
1118
|
const errorText = await response.text();
|
|
1126
|
-
console.error(
|
|
1127
|
-
`[APPOINTMENT_SERVICE] Error response details: ${errorText}`
|
|
1128
|
-
);
|
|
1119
|
+
console.error(`[APPOINTMENT_SERVICE] Error response details: ${errorText}`);
|
|
1129
1120
|
throw new Error(
|
|
1130
1121
|
`Failed to get available booking slots: ${response.status} ${response.statusText} - ${errorText}`
|
|
1131
1122
|
);
|
|
@@ -1133,24 +1124,15 @@ var AppointmentService = class extends BaseService {
|
|
|
1133
1124
|
const result = await response.json();
|
|
1134
1125
|
console.log(`[APPOINTMENT_SERVICE] Response parsed successfully`, result);
|
|
1135
1126
|
if (!result.success) {
|
|
1136
|
-
throw new Error(
|
|
1137
|
-
result.error || "Failed to get available booking slots"
|
|
1138
|
-
);
|
|
1127
|
+
throw new Error(result.error || "Failed to get available booking slots");
|
|
1139
1128
|
}
|
|
1140
|
-
const slots = result.availableSlots.map(
|
|
1141
|
-
(slot)
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
);
|
|
1145
|
-
console.log(
|
|
1146
|
-
`[APPOINTMENT_SERVICE] Found ${slots.length} available booking slots via HTTP`
|
|
1147
|
-
);
|
|
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`);
|
|
1148
1133
|
return slots;
|
|
1149
1134
|
} catch (error) {
|
|
1150
|
-
console.error(
|
|
1151
|
-
"[APPOINTMENT_SERVICE] Error getting available booking slots via HTTP:",
|
|
1152
|
-
error
|
|
1153
|
-
);
|
|
1135
|
+
console.error("[APPOINTMENT_SERVICE] Error getting available booking slots via HTTP:", error);
|
|
1154
1136
|
throw error;
|
|
1155
1137
|
}
|
|
1156
1138
|
}
|
|
@@ -1162,9 +1144,7 @@ var AppointmentService = class extends BaseService {
|
|
|
1162
1144
|
*/
|
|
1163
1145
|
async createAppointmentHttp(data) {
|
|
1164
1146
|
try {
|
|
1165
|
-
console.log(
|
|
1166
|
-
"[APPOINTMENT_SERVICE] Creating appointment via cloud function"
|
|
1167
|
-
);
|
|
1147
|
+
console.log("[APPOINTMENT_SERVICE] Creating appointment via cloud function");
|
|
1168
1148
|
const currentUser = this.auth.currentUser;
|
|
1169
1149
|
if (!currentUser) {
|
|
1170
1150
|
throw new Error("User must be authenticated to create an appointment");
|
|
@@ -1178,9 +1158,7 @@ var AppointmentService = class extends BaseService {
|
|
|
1178
1158
|
appointmentEndTime: data.appointmentEndTime.toMillis ? data.appointmentEndTime.toMillis() : new Date(data.appointmentEndTime).getTime(),
|
|
1179
1159
|
patientNotes: (data == null ? void 0 : data.patientNotes) || null
|
|
1180
1160
|
};
|
|
1181
|
-
console.log(
|
|
1182
|
-
`[APPOINTMENT_SERVICE] Making fetch request to ${functionUrl}`
|
|
1183
|
-
);
|
|
1161
|
+
console.log(`[APPOINTMENT_SERVICE] Making fetch request to ${functionUrl}`);
|
|
1184
1162
|
const response = await fetch(functionUrl, {
|
|
1185
1163
|
method: "POST",
|
|
1186
1164
|
mode: "cors",
|
|
@@ -1199,9 +1177,7 @@ var AppointmentService = class extends BaseService {
|
|
|
1199
1177
|
);
|
|
1200
1178
|
if (!response.ok) {
|
|
1201
1179
|
const errorText = await response.text();
|
|
1202
|
-
console.error(
|
|
1203
|
-
`[APPOINTMENT_SERVICE] Error response details: ${errorText}`
|
|
1204
|
-
);
|
|
1180
|
+
console.error(`[APPOINTMENT_SERVICE] Error response details: ${errorText}`);
|
|
1205
1181
|
throw new Error(
|
|
1206
1182
|
`Failed to create appointment: ${response.status} ${response.statusText} - ${errorText}`
|
|
1207
1183
|
);
|
|
@@ -1211,25 +1187,16 @@ var AppointmentService = class extends BaseService {
|
|
|
1211
1187
|
throw new Error(result.error || "Failed to create appointment");
|
|
1212
1188
|
}
|
|
1213
1189
|
if (result.appointmentData) {
|
|
1214
|
-
console.log(
|
|
1215
|
-
`[APPOINTMENT_SERVICE] Appointment created with ID: ${result.appointmentId}`
|
|
1216
|
-
);
|
|
1190
|
+
console.log(`[APPOINTMENT_SERVICE] Appointment created with ID: ${result.appointmentId}`);
|
|
1217
1191
|
return result.appointmentData;
|
|
1218
1192
|
}
|
|
1219
|
-
const createdAppointment = await this.getAppointmentById(
|
|
1220
|
-
result.appointmentId
|
|
1221
|
-
);
|
|
1193
|
+
const createdAppointment = await this.getAppointmentById(result.appointmentId);
|
|
1222
1194
|
if (!createdAppointment) {
|
|
1223
|
-
throw new Error(
|
|
1224
|
-
`Failed to retrieve created appointment with ID: ${result.appointmentId}`
|
|
1225
|
-
);
|
|
1195
|
+
throw new Error(`Failed to retrieve created appointment with ID: ${result.appointmentId}`);
|
|
1226
1196
|
}
|
|
1227
1197
|
return createdAppointment;
|
|
1228
1198
|
} catch (error) {
|
|
1229
|
-
console.error(
|
|
1230
|
-
"[APPOINTMENT_SERVICE] Error creating appointment via cloud function:",
|
|
1231
|
-
error
|
|
1232
|
-
);
|
|
1199
|
+
console.error("[APPOINTMENT_SERVICE] Error creating appointment via cloud function:", error);
|
|
1233
1200
|
throw error;
|
|
1234
1201
|
}
|
|
1235
1202
|
}
|
|
@@ -1241,19 +1208,14 @@ var AppointmentService = class extends BaseService {
|
|
|
1241
1208
|
*/
|
|
1242
1209
|
async getAppointmentById(appointmentId) {
|
|
1243
1210
|
try {
|
|
1244
|
-
console.log(
|
|
1245
|
-
`[APPOINTMENT_SERVICE] Getting appointment with ID: ${appointmentId}`
|
|
1246
|
-
);
|
|
1211
|
+
console.log(`[APPOINTMENT_SERVICE] Getting appointment with ID: ${appointmentId}`);
|
|
1247
1212
|
const appointment = await getAppointmentByIdUtil(this.db, appointmentId);
|
|
1248
1213
|
console.log(
|
|
1249
1214
|
`[APPOINTMENT_SERVICE] Appointment ${appointmentId} ${appointment ? "found" : "not found"}`
|
|
1250
1215
|
);
|
|
1251
1216
|
return appointment;
|
|
1252
1217
|
} catch (error) {
|
|
1253
|
-
console.error(
|
|
1254
|
-
`[APPOINTMENT_SERVICE] Error getting appointment ${appointmentId}:`,
|
|
1255
|
-
error
|
|
1256
|
-
);
|
|
1218
|
+
console.error(`[APPOINTMENT_SERVICE] Error getting appointment ${appointmentId}:`, error);
|
|
1257
1219
|
throw error;
|
|
1258
1220
|
}
|
|
1259
1221
|
}
|
|
@@ -1266,24 +1228,13 @@ var AppointmentService = class extends BaseService {
|
|
|
1266
1228
|
*/
|
|
1267
1229
|
async updateAppointment(appointmentId, data) {
|
|
1268
1230
|
try {
|
|
1269
|
-
console.log(
|
|
1270
|
-
`[APPOINTMENT_SERVICE] Updating appointment with ID: ${appointmentId}`
|
|
1271
|
-
);
|
|
1231
|
+
console.log(`[APPOINTMENT_SERVICE] Updating appointment with ID: ${appointmentId}`);
|
|
1272
1232
|
const validatedData = await updateAppointmentSchema.parseAsync(data);
|
|
1273
|
-
const updatedAppointment = await updateAppointmentUtil(
|
|
1274
|
-
|
|
1275
|
-
appointmentId,
|
|
1276
|
-
validatedData
|
|
1277
|
-
);
|
|
1278
|
-
console.log(
|
|
1279
|
-
`[APPOINTMENT_SERVICE] Appointment ${appointmentId} updated successfully`
|
|
1280
|
-
);
|
|
1233
|
+
const updatedAppointment = await updateAppointmentUtil(this.db, appointmentId, validatedData);
|
|
1234
|
+
console.log(`[APPOINTMENT_SERVICE] Appointment ${appointmentId} updated successfully`);
|
|
1281
1235
|
return updatedAppointment;
|
|
1282
1236
|
} catch (error) {
|
|
1283
|
-
console.error(
|
|
1284
|
-
`[APPOINTMENT_SERVICE] Error updating appointment ${appointmentId}:`,
|
|
1285
|
-
error
|
|
1286
|
-
);
|
|
1237
|
+
console.error(`[APPOINTMENT_SERVICE] Error updating appointment ${appointmentId}:`, error);
|
|
1287
1238
|
throw error;
|
|
1288
1239
|
}
|
|
1289
1240
|
}
|
|
@@ -1295,21 +1246,13 @@ var AppointmentService = class extends BaseService {
|
|
|
1295
1246
|
*/
|
|
1296
1247
|
async searchAppointments(params) {
|
|
1297
1248
|
try {
|
|
1298
|
-
console.log(
|
|
1299
|
-
"[APPOINTMENT_SERVICE] Searching appointments with params:",
|
|
1300
|
-
params
|
|
1301
|
-
);
|
|
1249
|
+
console.log("[APPOINTMENT_SERVICE] Searching appointments with params:", params);
|
|
1302
1250
|
await searchAppointmentsSchema.parseAsync(params);
|
|
1303
1251
|
const result = await searchAppointmentsUtil(this.db, params);
|
|
1304
|
-
console.log(
|
|
1305
|
-
`[APPOINTMENT_SERVICE] Found ${result.appointments.length} appointments`
|
|
1306
|
-
);
|
|
1252
|
+
console.log(`[APPOINTMENT_SERVICE] Found ${result.appointments.length} appointments`);
|
|
1307
1253
|
return result;
|
|
1308
1254
|
} catch (error) {
|
|
1309
|
-
console.error(
|
|
1310
|
-
"[APPOINTMENT_SERVICE] Error searching appointments:",
|
|
1311
|
-
error
|
|
1312
|
-
);
|
|
1255
|
+
console.error("[APPOINTMENT_SERVICE] Error searching appointments:", error);
|
|
1313
1256
|
throw error;
|
|
1314
1257
|
}
|
|
1315
1258
|
}
|
|
@@ -1321,9 +1264,7 @@ var AppointmentService = class extends BaseService {
|
|
|
1321
1264
|
* @returns Found appointments and the last document for pagination
|
|
1322
1265
|
*/
|
|
1323
1266
|
async getPatientAppointments(patientId, options) {
|
|
1324
|
-
console.log(
|
|
1325
|
-
`[APPOINTMENT_SERVICE] Getting appointments for patient: ${patientId}`
|
|
1326
|
-
);
|
|
1267
|
+
console.log(`[APPOINTMENT_SERVICE] Getting appointments for patient: ${patientId}`);
|
|
1327
1268
|
const searchParams = {
|
|
1328
1269
|
patientId,
|
|
1329
1270
|
startDate: options == null ? void 0 : options.startDate,
|
|
@@ -1342,9 +1283,7 @@ var AppointmentService = class extends BaseService {
|
|
|
1342
1283
|
* @returns Found appointments and the last document for pagination
|
|
1343
1284
|
*/
|
|
1344
1285
|
async getPractitionerAppointments(practitionerId, options) {
|
|
1345
|
-
console.log(
|
|
1346
|
-
`[APPOINTMENT_SERVICE] Getting appointments for practitioner: ${practitionerId}`
|
|
1347
|
-
);
|
|
1286
|
+
console.log(`[APPOINTMENT_SERVICE] Getting appointments for practitioner: ${practitionerId}`);
|
|
1348
1287
|
const searchParams = {
|
|
1349
1288
|
practitionerId,
|
|
1350
1289
|
startDate: options == null ? void 0 : options.startDate,
|
|
@@ -1363,9 +1302,7 @@ var AppointmentService = class extends BaseService {
|
|
|
1363
1302
|
* @returns Found appointments and the last document for pagination
|
|
1364
1303
|
*/
|
|
1365
1304
|
async getClinicAppointments(clinicBranchId, options) {
|
|
1366
|
-
console.log(
|
|
1367
|
-
`[APPOINTMENT_SERVICE] Getting appointments for clinic: ${clinicBranchId}`
|
|
1368
|
-
);
|
|
1305
|
+
console.log(`[APPOINTMENT_SERVICE] Getting appointments for clinic: ${clinicBranchId}`);
|
|
1369
1306
|
const searchParams = {
|
|
1370
1307
|
clinicBranchId,
|
|
1371
1308
|
practitionerId: options == null ? void 0 : options.practitionerId,
|
|
@@ -1416,68 +1353,42 @@ var AppointmentService = class extends BaseService {
|
|
|
1416
1353
|
* Confirms a PENDING appointment by an Admin/Clinic.
|
|
1417
1354
|
*/
|
|
1418
1355
|
async confirmAppointmentAdmin(appointmentId) {
|
|
1419
|
-
console.log(
|
|
1420
|
-
`[APPOINTMENT_SERVICE] Admin confirming appointment: ${appointmentId}`
|
|
1421
|
-
);
|
|
1356
|
+
console.log(`[APPOINTMENT_SERVICE] Admin confirming appointment: ${appointmentId}`);
|
|
1422
1357
|
const appointment = await this.getAppointmentById(appointmentId);
|
|
1423
|
-
if (!appointment)
|
|
1424
|
-
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
1358
|
+
if (!appointment) throw new Error(`Appointment ${appointmentId} not found.`);
|
|
1425
1359
|
if (appointment.status !== "pending" /* PENDING */) {
|
|
1426
|
-
throw new Error(
|
|
1427
|
-
`Appointment ${appointmentId} is not in PENDING state to be confirmed.`
|
|
1428
|
-
);
|
|
1360
|
+
throw new Error(`Appointment ${appointmentId} is not in PENDING state to be confirmed.`);
|
|
1429
1361
|
}
|
|
1430
|
-
return this.updateAppointmentStatus(
|
|
1431
|
-
appointmentId,
|
|
1432
|
-
"confirmed" /* CONFIRMED */
|
|
1433
|
-
);
|
|
1362
|
+
return this.updateAppointmentStatus(appointmentId, "confirmed" /* CONFIRMED */);
|
|
1434
1363
|
}
|
|
1435
1364
|
/**
|
|
1436
1365
|
* Cancels an appointment by the User (Patient).
|
|
1437
1366
|
*/
|
|
1438
1367
|
async cancelAppointmentUser(appointmentId, reason) {
|
|
1439
|
-
console.log(
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
"canceled_patient" /* CANCELED_PATIENT */,
|
|
1445
|
-
{
|
|
1446
|
-
cancellationReason: reason,
|
|
1447
|
-
canceledBy: "patient"
|
|
1448
|
-
}
|
|
1449
|
-
);
|
|
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
|
+
});
|
|
1450
1373
|
}
|
|
1451
1374
|
/**
|
|
1452
1375
|
* Cancels an appointment by an Admin/Clinic.
|
|
1453
1376
|
*/
|
|
1454
1377
|
async cancelAppointmentAdmin(appointmentId, reason) {
|
|
1455
|
-
console.log(
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
"canceled_clinic" /* CANCELED_CLINIC */,
|
|
1461
|
-
{
|
|
1462
|
-
cancellationReason: reason,
|
|
1463
|
-
canceledBy: "clinic"
|
|
1464
|
-
}
|
|
1465
|
-
);
|
|
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
|
+
});
|
|
1466
1383
|
}
|
|
1467
1384
|
/**
|
|
1468
1385
|
* Admin proposes to reschedule an appointment.
|
|
1469
1386
|
* Sets status to RESCHEDULED_BY_CLINIC and updates times.
|
|
1470
1387
|
*/
|
|
1471
1388
|
async rescheduleAppointmentAdmin(params) {
|
|
1472
|
-
console.log(
|
|
1473
|
-
|
|
1474
|
-
);
|
|
1475
|
-
const validatedParams = await rescheduleAppointmentSchema.parseAsync(
|
|
1476
|
-
params
|
|
1477
|
-
);
|
|
1478
|
-
const startTimestamp = this.convertToTimestamp(
|
|
1479
|
-
validatedParams.newStartTime
|
|
1480
|
-
);
|
|
1389
|
+
console.log(`[APPOINTMENT_SERVICE] Admin rescheduling appointment: ${params.appointmentId}`);
|
|
1390
|
+
const validatedParams = await rescheduleAppointmentSchema.parseAsync(params);
|
|
1391
|
+
const startTimestamp = this.convertToTimestamp(validatedParams.newStartTime);
|
|
1481
1392
|
const endTimestamp = this.convertToTimestamp(validatedParams.newEndTime);
|
|
1482
1393
|
if (endTimestamp.toMillis() <= startTimestamp.toMillis()) {
|
|
1483
1394
|
throw new Error("New end time must be after new start time.");
|
|
@@ -1520,48 +1431,31 @@ var AppointmentService = class extends BaseService {
|
|
|
1520
1431
|
if (value && typeof value.seconds === "number") {
|
|
1521
1432
|
return new Timestamp2(value.seconds, value.nanoseconds || 0);
|
|
1522
1433
|
}
|
|
1523
|
-
throw new Error(
|
|
1524
|
-
`Invalid timestamp format: ${typeof value}, value: ${JSON.stringify(
|
|
1525
|
-
value
|
|
1526
|
-
)}`
|
|
1527
|
-
);
|
|
1434
|
+
throw new Error(`Invalid timestamp format: ${typeof value}, value: ${JSON.stringify(value)}`);
|
|
1528
1435
|
}
|
|
1529
1436
|
/**
|
|
1530
1437
|
* User confirms a reschedule proposed by the clinic.
|
|
1531
1438
|
* Status changes from RESCHEDULED_BY_CLINIC to CONFIRMED.
|
|
1532
1439
|
*/
|
|
1533
1440
|
async rescheduleAppointmentConfirmUser(appointmentId) {
|
|
1534
|
-
console.log(
|
|
1535
|
-
`[APPOINTMENT_SERVICE] User confirming reschedule for: ${appointmentId}`
|
|
1536
|
-
);
|
|
1441
|
+
console.log(`[APPOINTMENT_SERVICE] User confirming reschedule for: ${appointmentId}`);
|
|
1537
1442
|
const appointment = await this.getAppointmentById(appointmentId);
|
|
1538
|
-
if (!appointment)
|
|
1539
|
-
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
1443
|
+
if (!appointment) throw new Error(`Appointment ${appointmentId} not found.`);
|
|
1540
1444
|
if (appointment.status !== "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
|
|
1541
|
-
throw new Error(
|
|
1542
|
-
`Appointment ${appointmentId} is not in RESCHEDULED_BY_CLINIC state.`
|
|
1543
|
-
);
|
|
1445
|
+
throw new Error(`Appointment ${appointmentId} is not in RESCHEDULED_BY_CLINIC state.`);
|
|
1544
1446
|
}
|
|
1545
|
-
return this.updateAppointmentStatus(
|
|
1546
|
-
appointmentId,
|
|
1547
|
-
"confirmed" /* CONFIRMED */
|
|
1548
|
-
);
|
|
1447
|
+
return this.updateAppointmentStatus(appointmentId, "confirmed" /* CONFIRMED */);
|
|
1549
1448
|
}
|
|
1550
1449
|
/**
|
|
1551
1450
|
* User rejects a reschedule proposed by the clinic.
|
|
1552
1451
|
* Status changes from RESCHEDULED_BY_CLINIC to CANCELED_PATIENT_RESCHEDULED.
|
|
1553
1452
|
*/
|
|
1554
1453
|
async rescheduleAppointmentRejectUser(appointmentId, reason) {
|
|
1555
|
-
console.log(
|
|
1556
|
-
`[APPOINTMENT_SERVICE] User rejecting reschedule for: ${appointmentId}`
|
|
1557
|
-
);
|
|
1454
|
+
console.log(`[APPOINTMENT_SERVICE] User rejecting reschedule for: ${appointmentId}`);
|
|
1558
1455
|
const appointment = await this.getAppointmentById(appointmentId);
|
|
1559
|
-
if (!appointment)
|
|
1560
|
-
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
1456
|
+
if (!appointment) throw new Error(`Appointment ${appointmentId} not found.`);
|
|
1561
1457
|
if (appointment.status !== "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
|
|
1562
|
-
throw new Error(
|
|
1563
|
-
`Appointment ${appointmentId} is not in RESCHEDULED_BY_CLINIC state.`
|
|
1564
|
-
);
|
|
1458
|
+
throw new Error(`Appointment ${appointmentId} is not in RESCHEDULED_BY_CLINIC state.`);
|
|
1565
1459
|
}
|
|
1566
1460
|
return this.updateAppointmentStatus(
|
|
1567
1461
|
appointmentId,
|
|
@@ -1577,17 +1471,12 @@ var AppointmentService = class extends BaseService {
|
|
|
1577
1471
|
* Requires all pending user forms to be completed.
|
|
1578
1472
|
*/
|
|
1579
1473
|
async checkInPatientAdmin(appointmentId) {
|
|
1580
|
-
console.log(
|
|
1581
|
-
`[APPOINTMENT_SERVICE] Admin checking in patient for: ${appointmentId}`
|
|
1582
|
-
);
|
|
1474
|
+
console.log(`[APPOINTMENT_SERVICE] Admin checking in patient for: ${appointmentId}`);
|
|
1583
1475
|
const appointment = await this.getAppointmentById(appointmentId);
|
|
1584
|
-
if (!appointment)
|
|
1585
|
-
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
1476
|
+
if (!appointment) throw new Error(`Appointment ${appointmentId} not found.`);
|
|
1586
1477
|
if (appointment.pendingUserFormsIds && appointment.pendingUserFormsIds.length > 0) {
|
|
1587
1478
|
throw new Error(
|
|
1588
|
-
`Cannot check in: Patient has ${appointment.pendingUserFormsIds.length} pending required form(s). IDs: ${appointment.pendingUserFormsIds.join(
|
|
1589
|
-
", "
|
|
1590
|
-
)}`
|
|
1479
|
+
`Cannot check in: Patient has ${appointment.pendingUserFormsIds.length} pending required form(s). IDs: ${appointment.pendingUserFormsIds.join(", ")}`
|
|
1591
1480
|
);
|
|
1592
1481
|
}
|
|
1593
1482
|
if (appointment.status !== "confirmed" /* CONFIRMED */ && appointment.status !== "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */) {
|
|
@@ -1595,25 +1484,17 @@ var AppointmentService = class extends BaseService {
|
|
|
1595
1484
|
`Checking in appointment ${appointmentId} with status ${appointment.status}. Ensure this is intended.`
|
|
1596
1485
|
);
|
|
1597
1486
|
}
|
|
1598
|
-
return this.updateAppointmentStatus(
|
|
1599
|
-
appointmentId,
|
|
1600
|
-
"checked_in" /* CHECKED_IN */
|
|
1601
|
-
);
|
|
1487
|
+
return this.updateAppointmentStatus(appointmentId, "checked_in" /* CHECKED_IN */);
|
|
1602
1488
|
}
|
|
1603
1489
|
/**
|
|
1604
1490
|
* Doctor starts the appointment procedure.
|
|
1605
1491
|
*/
|
|
1606
1492
|
async startAppointmentDoctor(appointmentId) {
|
|
1607
|
-
console.log(
|
|
1608
|
-
`[APPOINTMENT_SERVICE] Doctor starting appointment: ${appointmentId}`
|
|
1609
|
-
);
|
|
1493
|
+
console.log(`[APPOINTMENT_SERVICE] Doctor starting appointment: ${appointmentId}`);
|
|
1610
1494
|
const appointment = await this.getAppointmentById(appointmentId);
|
|
1611
|
-
if (!appointment)
|
|
1612
|
-
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
1495
|
+
if (!appointment) throw new Error(`Appointment ${appointmentId} not found.`);
|
|
1613
1496
|
if (appointment.status !== "checked_in" /* CHECKED_IN */) {
|
|
1614
|
-
throw new Error(
|
|
1615
|
-
`Appointment ${appointmentId} must be CHECKED_IN to start.`
|
|
1616
|
-
);
|
|
1497
|
+
throw new Error(`Appointment ${appointmentId} must be CHECKED_IN to start.`);
|
|
1617
1498
|
}
|
|
1618
1499
|
const updateData = {
|
|
1619
1500
|
status: "in_progress" /* IN_PROGRESS */,
|
|
@@ -1627,24 +1508,18 @@ var AppointmentService = class extends BaseService {
|
|
|
1627
1508
|
* Doctor completes and finalizes the appointment.
|
|
1628
1509
|
*/
|
|
1629
1510
|
async completeAppointmentDoctor(appointmentId, finalizationNotes, actualDurationMinutesInput) {
|
|
1630
|
-
console.log(
|
|
1631
|
-
`[APPOINTMENT_SERVICE] Doctor completing appointment: ${appointmentId}`
|
|
1632
|
-
);
|
|
1511
|
+
console.log(`[APPOINTMENT_SERVICE] Doctor completing appointment: ${appointmentId}`);
|
|
1633
1512
|
const currentUser = this.auth.currentUser;
|
|
1634
|
-
if (!currentUser)
|
|
1635
|
-
throw new Error("Authentication required to complete appointment.");
|
|
1513
|
+
if (!currentUser) throw new Error("Authentication required to complete appointment.");
|
|
1636
1514
|
const appointment = await this.getAppointmentById(appointmentId);
|
|
1637
|
-
if (!appointment)
|
|
1638
|
-
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
1515
|
+
if (!appointment) throw new Error(`Appointment ${appointmentId} not found.`);
|
|
1639
1516
|
let calculatedDurationMinutes = actualDurationMinutesInput;
|
|
1640
1517
|
const procedureCompletionTime = Timestamp2.now();
|
|
1641
1518
|
if (calculatedDurationMinutes === void 0 && appointment.procedureActualStartTime) {
|
|
1642
1519
|
const startTimeMillis = appointment.procedureActualStartTime.toMillis();
|
|
1643
1520
|
const endTimeMillis = procedureCompletionTime.toMillis();
|
|
1644
1521
|
if (endTimeMillis > startTimeMillis) {
|
|
1645
|
-
calculatedDurationMinutes = Math.round(
|
|
1646
|
-
(endTimeMillis - startTimeMillis) / 6e4
|
|
1647
|
-
);
|
|
1522
|
+
calculatedDurationMinutes = Math.round((endTimeMillis - startTimeMillis) / 6e4);
|
|
1648
1523
|
}
|
|
1649
1524
|
}
|
|
1650
1525
|
const updateData = {
|
|
@@ -1668,31 +1543,22 @@ var AppointmentService = class extends BaseService {
|
|
|
1668
1543
|
* Admin marks an appointment as No-Show.
|
|
1669
1544
|
*/
|
|
1670
1545
|
async markNoShowAdmin(appointmentId) {
|
|
1671
|
-
console.log(
|
|
1672
|
-
`[APPOINTMENT_SERVICE] Admin marking no-show for: ${appointmentId}`
|
|
1673
|
-
);
|
|
1546
|
+
console.log(`[APPOINTMENT_SERVICE] Admin marking no-show for: ${appointmentId}`);
|
|
1674
1547
|
const appointment = await this.getAppointmentById(appointmentId);
|
|
1675
|
-
if (!appointment)
|
|
1676
|
-
throw new Error(`Appointment ${appointmentId} not found.`);
|
|
1548
|
+
if (!appointment) throw new Error(`Appointment ${appointmentId} not found.`);
|
|
1677
1549
|
if (Timestamp2.now().toMillis() < appointment.appointmentStartTime.toMillis()) {
|
|
1678
1550
|
throw new Error("Cannot mark no-show before appointment start time.");
|
|
1679
1551
|
}
|
|
1680
|
-
return this.updateAppointmentStatus(
|
|
1681
|
-
|
|
1682
|
-
"
|
|
1683
|
-
|
|
1684
|
-
cancellationReason: "Patient did not show up for the appointment.",
|
|
1685
|
-
canceledBy: "clinic"
|
|
1686
|
-
}
|
|
1687
|
-
);
|
|
1552
|
+
return this.updateAppointmentStatus(appointmentId, "no_show" /* NO_SHOW */, {
|
|
1553
|
+
cancellationReason: "Patient did not show up for the appointment.",
|
|
1554
|
+
canceledBy: "clinic"
|
|
1555
|
+
});
|
|
1688
1556
|
}
|
|
1689
1557
|
/**
|
|
1690
1558
|
* Adds a media item to an appointment.
|
|
1691
1559
|
*/
|
|
1692
1560
|
async addMediaToAppointment(appointmentId, mediaItemData) {
|
|
1693
|
-
console.log(
|
|
1694
|
-
`[APPOINTMENT_SERVICE] Adding media to appointment ${appointmentId}`
|
|
1695
|
-
);
|
|
1561
|
+
console.log(`[APPOINTMENT_SERVICE] Adding media to appointment ${appointmentId}`);
|
|
1696
1562
|
const currentUser = this.auth.currentUser;
|
|
1697
1563
|
if (!currentUser) throw new Error("Authentication required.");
|
|
1698
1564
|
const newMediaItem = {
|
|
@@ -1732,9 +1598,7 @@ var AppointmentService = class extends BaseService {
|
|
|
1732
1598
|
* Adds or updates review information for an appointment.
|
|
1733
1599
|
*/
|
|
1734
1600
|
async addReviewToAppointment(appointmentId, reviewData) {
|
|
1735
|
-
console.log(
|
|
1736
|
-
`[APPOINTMENT_SERVICE] Adding review to appointment ${appointmentId}`
|
|
1737
|
-
);
|
|
1601
|
+
console.log(`[APPOINTMENT_SERVICE] Adding review to appointment ${appointmentId}`);
|
|
1738
1602
|
const newReviewInfo = {
|
|
1739
1603
|
...reviewData,
|
|
1740
1604
|
reviewId: this.generateId(),
|
|
@@ -1768,9 +1632,7 @@ var AppointmentService = class extends BaseService {
|
|
|
1768
1632
|
* @returns The updated appointment
|
|
1769
1633
|
*/
|
|
1770
1634
|
async updateInternalNotes(appointmentId, notes) {
|
|
1771
|
-
console.log(
|
|
1772
|
-
`[APPOINTMENT_SERVICE] Updating internal notes for appointment: ${appointmentId}`
|
|
1773
|
-
);
|
|
1635
|
+
console.log(`[APPOINTMENT_SERVICE] Updating internal notes for appointment: ${appointmentId}`);
|
|
1774
1636
|
const updateData = {
|
|
1775
1637
|
internalNotes: notes
|
|
1776
1638
|
};
|
|
@@ -1786,9 +1648,7 @@ var AppointmentService = class extends BaseService {
|
|
|
1786
1648
|
*/
|
|
1787
1649
|
async getUpcomingPatientAppointments(patientId, options) {
|
|
1788
1650
|
try {
|
|
1789
|
-
console.log(
|
|
1790
|
-
`[APPOINTMENT_SERVICE] Getting upcoming appointments for patient: ${patientId}`
|
|
1791
|
-
);
|
|
1651
|
+
console.log(`[APPOINTMENT_SERVICE] Getting upcoming appointments for patient: ${patientId}`);
|
|
1792
1652
|
const effectiveStartDate = (options == null ? void 0 : options.startDate) || /* @__PURE__ */ new Date();
|
|
1793
1653
|
const upcomingStatuses = [
|
|
1794
1654
|
"pending" /* PENDING */,
|
|
@@ -1800,21 +1660,9 @@ var AppointmentService = class extends BaseService {
|
|
|
1800
1660
|
const constraints = [];
|
|
1801
1661
|
constraints.push(where2("patientId", "==", patientId));
|
|
1802
1662
|
constraints.push(where2("status", "in", upcomingStatuses));
|
|
1803
|
-
constraints.push(
|
|
1804
|
-
where2(
|
|
1805
|
-
"appointmentStartTime",
|
|
1806
|
-
">=",
|
|
1807
|
-
Timestamp2.fromDate(effectiveStartDate)
|
|
1808
|
-
)
|
|
1809
|
-
);
|
|
1663
|
+
constraints.push(where2("appointmentStartTime", ">=", Timestamp2.fromDate(effectiveStartDate)));
|
|
1810
1664
|
if (options == null ? void 0 : options.endDate) {
|
|
1811
|
-
constraints.push(
|
|
1812
|
-
where2(
|
|
1813
|
-
"appointmentStartTime",
|
|
1814
|
-
"<=",
|
|
1815
|
-
Timestamp2.fromDate(options.endDate)
|
|
1816
|
-
)
|
|
1817
|
-
);
|
|
1665
|
+
constraints.push(where2("appointmentStartTime", "<=", Timestamp2.fromDate(options.endDate)));
|
|
1818
1666
|
}
|
|
1819
1667
|
constraints.push(orderBy2("appointmentStartTime", "asc"));
|
|
1820
1668
|
if (options == null ? void 0 : options.limit) {
|
|
@@ -1823,14 +1671,9 @@ var AppointmentService = class extends BaseService {
|
|
|
1823
1671
|
if (options == null ? void 0 : options.startAfter) {
|
|
1824
1672
|
constraints.push(startAfter2(options.startAfter));
|
|
1825
1673
|
}
|
|
1826
|
-
const q = query2(
|
|
1827
|
-
collection2(this.db, APPOINTMENTS_COLLECTION),
|
|
1828
|
-
...constraints
|
|
1829
|
-
);
|
|
1674
|
+
const q = query2(collection2(this.db, APPOINTMENTS_COLLECTION), ...constraints);
|
|
1830
1675
|
const querySnapshot = await getDocs2(q);
|
|
1831
|
-
const appointments = querySnapshot.docs.map(
|
|
1832
|
-
(doc38) => doc38.data()
|
|
1833
|
-
);
|
|
1676
|
+
const appointments = querySnapshot.docs.map((doc38) => doc38.data());
|
|
1834
1677
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
1835
1678
|
console.log(
|
|
1836
1679
|
`[APPOINTMENT_SERVICE] Found ${appointments.length} upcoming appointments for patient ${patientId}`
|
|
@@ -1855,9 +1698,7 @@ var AppointmentService = class extends BaseService {
|
|
|
1855
1698
|
*/
|
|
1856
1699
|
async getPastPatientAppointments(patientId, options) {
|
|
1857
1700
|
try {
|
|
1858
|
-
console.log(
|
|
1859
|
-
`[APPOINTMENT_SERVICE] Getting past appointments for patient: ${patientId}`
|
|
1860
|
-
);
|
|
1701
|
+
console.log(`[APPOINTMENT_SERVICE] Getting past appointments for patient: ${patientId}`);
|
|
1861
1702
|
const effectiveEndDate = (options == null ? void 0 : options.endDate) || /* @__PURE__ */ new Date();
|
|
1862
1703
|
const pastStatuses = ["completed" /* COMPLETED */];
|
|
1863
1704
|
if (options == null ? void 0 : options.showCanceled) {
|
|
@@ -1875,20 +1716,10 @@ var AppointmentService = class extends BaseService {
|
|
|
1875
1716
|
constraints.push(where2("status", "in", pastStatuses));
|
|
1876
1717
|
if (options == null ? void 0 : options.startDate) {
|
|
1877
1718
|
constraints.push(
|
|
1878
|
-
where2(
|
|
1879
|
-
"appointmentStartTime",
|
|
1880
|
-
">=",
|
|
1881
|
-
Timestamp2.fromDate(options.startDate)
|
|
1882
|
-
)
|
|
1719
|
+
where2("appointmentStartTime", ">=", Timestamp2.fromDate(options.startDate))
|
|
1883
1720
|
);
|
|
1884
1721
|
}
|
|
1885
|
-
constraints.push(
|
|
1886
|
-
where2(
|
|
1887
|
-
"appointmentStartTime",
|
|
1888
|
-
"<=",
|
|
1889
|
-
Timestamp2.fromDate(effectiveEndDate)
|
|
1890
|
-
)
|
|
1891
|
-
);
|
|
1722
|
+
constraints.push(where2("appointmentStartTime", "<=", Timestamp2.fromDate(effectiveEndDate)));
|
|
1892
1723
|
constraints.push(orderBy2("appointmentStartTime", "desc"));
|
|
1893
1724
|
if (options == null ? void 0 : options.limit) {
|
|
1894
1725
|
constraints.push(limit2(options.limit));
|
|
@@ -1896,14 +1727,9 @@ var AppointmentService = class extends BaseService {
|
|
|
1896
1727
|
if (options == null ? void 0 : options.startAfter) {
|
|
1897
1728
|
constraints.push(startAfter2(options.startAfter));
|
|
1898
1729
|
}
|
|
1899
|
-
const q = query2(
|
|
1900
|
-
collection2(this.db, APPOINTMENTS_COLLECTION),
|
|
1901
|
-
...constraints
|
|
1902
|
-
);
|
|
1730
|
+
const q = query2(collection2(this.db, APPOINTMENTS_COLLECTION), ...constraints);
|
|
1903
1731
|
const querySnapshot = await getDocs2(q);
|
|
1904
|
-
const appointments = querySnapshot.docs.map(
|
|
1905
|
-
(doc38) => doc38.data()
|
|
1906
|
-
);
|
|
1732
|
+
const appointments = querySnapshot.docs.map((doc38) => doc38.data());
|
|
1907
1733
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
1908
1734
|
console.log(
|
|
1909
1735
|
`[APPOINTMENT_SERVICE] Found ${appointments.length} past appointments for patient ${patientId}`
|
|
@@ -1917,6 +1743,46 @@ var AppointmentService = class extends BaseService {
|
|
|
1917
1743
|
throw error;
|
|
1918
1744
|
}
|
|
1919
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
|
+
}
|
|
1920
1786
|
};
|
|
1921
1787
|
|
|
1922
1788
|
// src/services/auth/auth.service.ts
|
|
@@ -1926,15 +1792,13 @@ import {
|
|
|
1926
1792
|
signInAnonymously as firebaseSignInAnonymously,
|
|
1927
1793
|
signOut as firebaseSignOut,
|
|
1928
1794
|
GoogleAuthProvider,
|
|
1929
|
-
FacebookAuthProvider,
|
|
1930
|
-
OAuthProvider,
|
|
1931
|
-
signInWithPopup,
|
|
1932
1795
|
linkWithCredential,
|
|
1933
1796
|
EmailAuthProvider,
|
|
1934
1797
|
onAuthStateChanged,
|
|
1935
1798
|
sendPasswordResetEmail,
|
|
1936
1799
|
verifyPasswordResetCode,
|
|
1937
|
-
confirmPasswordReset
|
|
1800
|
+
confirmPasswordReset,
|
|
1801
|
+
signInWithCredential
|
|
1938
1802
|
} from "firebase/auth";
|
|
1939
1803
|
import {
|
|
1940
1804
|
collection as collection18,
|
|
@@ -10014,19 +9878,13 @@ var AuthService = class extends BaseService {
|
|
|
10014
9878
|
constructor(db, auth, app, userService) {
|
|
10015
9879
|
super(db, auth, app);
|
|
10016
9880
|
this.googleProvider = new GoogleAuthProvider();
|
|
10017
|
-
this.facebookProvider = new FacebookAuthProvider();
|
|
10018
|
-
this.appleProvider = new OAuthProvider("apple.com");
|
|
10019
9881
|
this.userService = userService || new UserService(db, auth, app);
|
|
10020
9882
|
}
|
|
10021
9883
|
/**
|
|
10022
9884
|
* Registruje novog korisnika sa email-om i lozinkom
|
|
10023
9885
|
*/
|
|
10024
9886
|
async signUp(email, password, initialRole = "patient" /* PATIENT */, options) {
|
|
10025
|
-
const { user: firebaseUser } = await createUserWithEmailAndPassword(
|
|
10026
|
-
this.auth,
|
|
10027
|
-
email,
|
|
10028
|
-
password
|
|
10029
|
-
);
|
|
9887
|
+
const { user: firebaseUser } = await createUserWithEmailAndPassword(this.auth, email, password);
|
|
10030
9888
|
return this.userService.createUser(firebaseUser, [initialRole], options);
|
|
10031
9889
|
}
|
|
10032
9890
|
/**
|
|
@@ -10045,20 +9903,13 @@ var AuthService = class extends BaseService {
|
|
|
10045
9903
|
await clinicAdminSignupSchema.parseAsync(data);
|
|
10046
9904
|
console.log("[AUTH] Clinic admin signup data validation passed");
|
|
10047
9905
|
} catch (validationError) {
|
|
10048
|
-
console.error(
|
|
10049
|
-
"[AUTH] Validation error in signUpClinicAdmin:",
|
|
10050
|
-
validationError
|
|
10051
|
-
);
|
|
9906
|
+
console.error("[AUTH] Validation error in signUpClinicAdmin:", validationError);
|
|
10052
9907
|
throw validationError;
|
|
10053
9908
|
}
|
|
10054
9909
|
console.log("[AUTH] Creating Firebase user");
|
|
10055
9910
|
let firebaseUser;
|
|
10056
9911
|
try {
|
|
10057
|
-
const result = await createUserWithEmailAndPassword(
|
|
10058
|
-
this.auth,
|
|
10059
|
-
data.email,
|
|
10060
|
-
data.password
|
|
10061
|
-
);
|
|
9912
|
+
const result = await createUserWithEmailAndPassword(this.auth, data.email, data.password);
|
|
10062
9913
|
firebaseUser = result.user;
|
|
10063
9914
|
console.log("[AUTH] Firebase user created successfully", {
|
|
10064
9915
|
uid: firebaseUser.uid
|
|
@@ -10070,13 +9921,9 @@ var AuthService = class extends BaseService {
|
|
|
10070
9921
|
console.log("[AUTH] Creating user with CLINIC_ADMIN role");
|
|
10071
9922
|
let user;
|
|
10072
9923
|
try {
|
|
10073
|
-
user = await this.userService.createUser(
|
|
10074
|
-
|
|
10075
|
-
|
|
10076
|
-
{
|
|
10077
|
-
skipProfileCreation: true
|
|
10078
|
-
}
|
|
10079
|
-
);
|
|
9924
|
+
user = await this.userService.createUser(firebaseUser, ["clinic_admin" /* CLINIC_ADMIN */], {
|
|
9925
|
+
skipProfileCreation: true
|
|
9926
|
+
});
|
|
10080
9927
|
console.log("[AUTH] User with CLINIC_ADMIN role created successfully", {
|
|
10081
9928
|
userId: user.uid
|
|
10082
9929
|
});
|
|
@@ -10093,11 +9940,7 @@ var AuthService = class extends BaseService {
|
|
|
10093
9940
|
};
|
|
10094
9941
|
console.log("[AUTH] Contact person object created");
|
|
10095
9942
|
console.log("[AUTH] Initializing clinic services");
|
|
10096
|
-
const clinicAdminService = new ClinicAdminService(
|
|
10097
|
-
this.db,
|
|
10098
|
-
this.auth,
|
|
10099
|
-
this.app
|
|
10100
|
-
);
|
|
9943
|
+
const clinicAdminService = new ClinicAdminService(this.db, this.auth, this.app);
|
|
10101
9944
|
const clinicGroupService = new ClinicGroupService(
|
|
10102
9945
|
this.db,
|
|
10103
9946
|
this.auth,
|
|
@@ -10114,18 +9957,14 @@ var AuthService = class extends BaseService {
|
|
|
10114
9957
|
mediaService
|
|
10115
9958
|
);
|
|
10116
9959
|
clinicAdminService.setServices(clinicGroupService, clinicService);
|
|
10117
|
-
console.log(
|
|
10118
|
-
"[AUTH] Services initialized and circular dependencies resolved"
|
|
10119
|
-
);
|
|
9960
|
+
console.log("[AUTH] Services initialized and circular dependencies resolved");
|
|
10120
9961
|
let clinicGroup = null;
|
|
10121
9962
|
let adminProfile = null;
|
|
10122
9963
|
if (data.isCreatingNewGroup) {
|
|
10123
9964
|
console.log("[AUTH] Creating new clinic group flow");
|
|
10124
9965
|
if (!data.clinicGroupData) {
|
|
10125
9966
|
console.error("[AUTH] Clinic group data is missing");
|
|
10126
|
-
throw new Error(
|
|
10127
|
-
"Clinic group data is required when creating a new group"
|
|
10128
|
-
);
|
|
9967
|
+
throw new Error("Clinic group data is required when creating a new group");
|
|
10129
9968
|
}
|
|
10130
9969
|
console.log("[AUTH] Creating clinic admin first (without group)");
|
|
10131
9970
|
const createClinicAdminData = {
|
|
@@ -10138,17 +9977,12 @@ var AuthService = class extends BaseService {
|
|
|
10138
9977
|
// No clinicGroupId yet
|
|
10139
9978
|
};
|
|
10140
9979
|
try {
|
|
10141
|
-
adminProfile = await clinicAdminService.createClinicAdmin(
|
|
10142
|
-
createClinicAdminData
|
|
10143
|
-
);
|
|
9980
|
+
adminProfile = await clinicAdminService.createClinicAdmin(createClinicAdminData);
|
|
10144
9981
|
console.log("[AUTH] Clinic admin created successfully", {
|
|
10145
9982
|
adminId: adminProfile.id
|
|
10146
9983
|
});
|
|
10147
9984
|
} catch (adminCreationError) {
|
|
10148
|
-
console.error(
|
|
10149
|
-
"[AUTH] Clinic admin creation failed:",
|
|
10150
|
-
adminCreationError
|
|
10151
|
-
);
|
|
9985
|
+
console.error("[AUTH] Clinic admin creation failed:", adminCreationError);
|
|
10152
9986
|
throw adminCreationError;
|
|
10153
9987
|
}
|
|
10154
9988
|
try {
|
|
@@ -10156,14 +9990,9 @@ var AuthService = class extends BaseService {
|
|
|
10156
9990
|
user = await this.userService.updateUser(firebaseUser.uid, {
|
|
10157
9991
|
adminProfile: adminProfile.id
|
|
10158
9992
|
});
|
|
10159
|
-
console.log(
|
|
10160
|
-
"[AUTH] User updated with admin profile reference successfully"
|
|
10161
|
-
);
|
|
9993
|
+
console.log("[AUTH] User updated with admin profile reference successfully");
|
|
10162
9994
|
} catch (userUpdateError) {
|
|
10163
|
-
console.error(
|
|
10164
|
-
"[AUTH] Failed to update user with admin profile:",
|
|
10165
|
-
userUpdateError
|
|
10166
|
-
);
|
|
9995
|
+
console.error("[AUTH] Failed to update user with admin profile:", userUpdateError);
|
|
10167
9996
|
throw userUpdateError;
|
|
10168
9997
|
}
|
|
10169
9998
|
const createClinicGroupData = {
|
|
@@ -10201,23 +10030,16 @@ var AuthService = class extends BaseService {
|
|
|
10201
10030
|
clinicGroupId: clinicGroup.id
|
|
10202
10031
|
});
|
|
10203
10032
|
console.log("[AUTH] Admin updated with clinic group ID successfully");
|
|
10204
|
-
adminProfile = await clinicAdminService.getClinicAdmin(
|
|
10205
|
-
adminProfile.id
|
|
10206
|
-
);
|
|
10033
|
+
adminProfile = await clinicAdminService.getClinicAdmin(adminProfile.id);
|
|
10207
10034
|
} catch (groupCreationError) {
|
|
10208
|
-
console.error(
|
|
10209
|
-
"[AUTH] Clinic group creation failed:",
|
|
10210
|
-
groupCreationError
|
|
10211
|
-
);
|
|
10035
|
+
console.error("[AUTH] Clinic group creation failed:", groupCreationError);
|
|
10212
10036
|
throw groupCreationError;
|
|
10213
10037
|
}
|
|
10214
10038
|
} else {
|
|
10215
10039
|
console.log("[AUTH] Joining existing clinic group flow");
|
|
10216
10040
|
if (!data.inviteToken) {
|
|
10217
10041
|
console.error("[AUTH] Invite token is missing");
|
|
10218
|
-
throw new Error(
|
|
10219
|
-
"Invite token is required when joining an existing group"
|
|
10220
|
-
);
|
|
10042
|
+
throw new Error("Invite token is required when joining an existing group");
|
|
10221
10043
|
}
|
|
10222
10044
|
console.log("[AUTH] Invite token provided", {
|
|
10223
10045
|
token: data.inviteToken
|
|
@@ -10228,11 +10050,7 @@ var AuthService = class extends BaseService {
|
|
|
10228
10050
|
const querySnapshot = await getDocs18(q);
|
|
10229
10051
|
let foundGroup = null;
|
|
10230
10052
|
let foundToken = null;
|
|
10231
|
-
console.log(
|
|
10232
|
-
"[AUTH] Found",
|
|
10233
|
-
querySnapshot.size,
|
|
10234
|
-
"clinic groups to check"
|
|
10235
|
-
);
|
|
10053
|
+
console.log("[AUTH] Found", querySnapshot.size, "clinic groups to check");
|
|
10236
10054
|
for (const docSnapshot of querySnapshot.docs) {
|
|
10237
10055
|
const group = docSnapshot.data();
|
|
10238
10056
|
console.log("[AUTH] Checking group", {
|
|
@@ -10278,17 +10096,12 @@ var AuthService = class extends BaseService {
|
|
|
10278
10096
|
isActive: true
|
|
10279
10097
|
};
|
|
10280
10098
|
try {
|
|
10281
|
-
adminProfile = await clinicAdminService.createClinicAdmin(
|
|
10282
|
-
createClinicAdminData
|
|
10283
|
-
);
|
|
10099
|
+
adminProfile = await clinicAdminService.createClinicAdmin(createClinicAdminData);
|
|
10284
10100
|
console.log("[AUTH] Clinic admin created successfully", {
|
|
10285
10101
|
adminId: adminProfile.id
|
|
10286
10102
|
});
|
|
10287
10103
|
} catch (adminCreationError) {
|
|
10288
|
-
console.error(
|
|
10289
|
-
"[AUTH] Clinic admin creation failed:",
|
|
10290
|
-
adminCreationError
|
|
10291
|
-
);
|
|
10104
|
+
console.error("[AUTH] Clinic admin creation failed:", adminCreationError);
|
|
10292
10105
|
throw adminCreationError;
|
|
10293
10106
|
}
|
|
10294
10107
|
try {
|
|
@@ -10309,9 +10122,7 @@ var AuthService = class extends BaseService {
|
|
|
10309
10122
|
clinicAdminId: (adminProfile == null ? void 0 : adminProfile.id) || "unknown"
|
|
10310
10123
|
});
|
|
10311
10124
|
if (!clinicGroup || !adminProfile) {
|
|
10312
|
-
throw new Error(
|
|
10313
|
-
"Failed to create or retrieve clinic group or admin profile"
|
|
10314
|
-
);
|
|
10125
|
+
throw new Error("Failed to create or retrieve clinic group or admin profile");
|
|
10315
10126
|
}
|
|
10316
10127
|
return {
|
|
10317
10128
|
user,
|
|
@@ -10339,11 +10150,7 @@ var AuthService = class extends BaseService {
|
|
|
10339
10150
|
* Prijavljuje korisnika sa email-om i lozinkom
|
|
10340
10151
|
*/
|
|
10341
10152
|
async signIn(email, password) {
|
|
10342
|
-
const { user: firebaseUser } = await signInWithEmailAndPassword(
|
|
10343
|
-
this.auth,
|
|
10344
|
-
email,
|
|
10345
|
-
password
|
|
10346
|
-
);
|
|
10153
|
+
const { user: firebaseUser } = await signInWithEmailAndPassword(this.auth, email, password);
|
|
10347
10154
|
return this.userService.getOrCreateUser(firebaseUser);
|
|
10348
10155
|
}
|
|
10349
10156
|
/**
|
|
@@ -10357,11 +10164,7 @@ var AuthService = class extends BaseService {
|
|
|
10357
10164
|
async signInClinicAdmin(email, password) {
|
|
10358
10165
|
var _a;
|
|
10359
10166
|
try {
|
|
10360
|
-
const clinicAdminService = new ClinicAdminService(
|
|
10361
|
-
this.db,
|
|
10362
|
-
this.auth,
|
|
10363
|
-
this.app
|
|
10364
|
-
);
|
|
10167
|
+
const clinicAdminService = new ClinicAdminService(this.db, this.auth, this.app);
|
|
10365
10168
|
const clinicGroupService = new ClinicGroupService(
|
|
10366
10169
|
this.db,
|
|
10367
10170
|
this.auth,
|
|
@@ -10378,11 +10181,7 @@ var AuthService = class extends BaseService {
|
|
|
10378
10181
|
mediaService
|
|
10379
10182
|
);
|
|
10380
10183
|
clinicAdminService.setServices(clinicGroupService, clinicService);
|
|
10381
|
-
const { user: firebaseUser } = await signInWithEmailAndPassword(
|
|
10382
|
-
this.auth,
|
|
10383
|
-
email,
|
|
10384
|
-
password
|
|
10385
|
-
);
|
|
10184
|
+
const { user: firebaseUser } = await signInWithEmailAndPassword(this.auth, email, password);
|
|
10386
10185
|
const user = await this.userService.getOrCreateUser(firebaseUser);
|
|
10387
10186
|
if (!((_a = user.roles) == null ? void 0 : _a.includes("clinic_admin" /* CLINIC_ADMIN */))) {
|
|
10388
10187
|
console.error("[AUTH] User is not a clinic admin:", user.uid);
|
|
@@ -10392,21 +10191,14 @@ var AuthService = class extends BaseService {
|
|
|
10392
10191
|
console.error("[AUTH] User has no admin profile:", user.uid);
|
|
10393
10192
|
throw AUTH_ERRORS.NOT_FOUND;
|
|
10394
10193
|
}
|
|
10395
|
-
const adminProfile = await clinicAdminService.getClinicAdmin(
|
|
10396
|
-
user.adminProfile
|
|
10397
|
-
);
|
|
10194
|
+
const adminProfile = await clinicAdminService.getClinicAdmin(user.adminProfile);
|
|
10398
10195
|
if (!adminProfile) {
|
|
10399
10196
|
console.error("[AUTH] Admin profile not found:", user.adminProfile);
|
|
10400
10197
|
throw AUTH_ERRORS.NOT_FOUND;
|
|
10401
10198
|
}
|
|
10402
|
-
const clinicGroup = await clinicGroupService.getClinicGroup(
|
|
10403
|
-
adminProfile.clinicGroupId
|
|
10404
|
-
);
|
|
10199
|
+
const clinicGroup = await clinicGroupService.getClinicGroup(adminProfile.clinicGroupId);
|
|
10405
10200
|
if (!clinicGroup) {
|
|
10406
|
-
console.error(
|
|
10407
|
-
"[AUTH] Clinic group not found:",
|
|
10408
|
-
adminProfile.clinicGroupId
|
|
10409
|
-
);
|
|
10201
|
+
console.error("[AUTH] Clinic group not found:", adminProfile.clinicGroupId);
|
|
10410
10202
|
throw AUTH_ERRORS.NOT_FOUND;
|
|
10411
10203
|
}
|
|
10412
10204
|
return {
|
|
@@ -10419,39 +10211,6 @@ var AuthService = class extends BaseService {
|
|
|
10419
10211
|
throw error;
|
|
10420
10212
|
}
|
|
10421
10213
|
}
|
|
10422
|
-
/**
|
|
10423
|
-
* Prijavljuje korisnika sa Facebook-om
|
|
10424
|
-
*/
|
|
10425
|
-
async signInWithFacebook() {
|
|
10426
|
-
const provider = new FacebookAuthProvider();
|
|
10427
|
-
const { user: firebaseUser } = await signInWithPopup(this.auth, provider);
|
|
10428
|
-
return this.userService.getOrCreateUser(firebaseUser);
|
|
10429
|
-
}
|
|
10430
|
-
/**
|
|
10431
|
-
* Prijavljuje korisnika sa Google nalogom
|
|
10432
|
-
*/
|
|
10433
|
-
async signInWithGoogle(initialRole = "patient" /* PATIENT */, options) {
|
|
10434
|
-
const { user: firebaseUser } = await signInWithPopup(
|
|
10435
|
-
this.auth,
|
|
10436
|
-
this.googleProvider
|
|
10437
|
-
);
|
|
10438
|
-
const existingUser = await this.userService.getUserByEmail(
|
|
10439
|
-
firebaseUser.email
|
|
10440
|
-
);
|
|
10441
|
-
if (existingUser) {
|
|
10442
|
-
await this.userService.updateUserLoginTimestamp(existingUser.uid);
|
|
10443
|
-
return existingUser;
|
|
10444
|
-
}
|
|
10445
|
-
return this.userService.createUser(firebaseUser, [initialRole], options);
|
|
10446
|
-
}
|
|
10447
|
-
/**
|
|
10448
|
-
* Prijavljuje korisnika sa Apple-om
|
|
10449
|
-
*/
|
|
10450
|
-
async signInWithApple() {
|
|
10451
|
-
const provider = new OAuthProvider("apple.com");
|
|
10452
|
-
const { user: firebaseUser } = await signInWithPopup(this.auth, provider);
|
|
10453
|
-
return this.userService.getOrCreateUser(firebaseUser);
|
|
10454
|
-
}
|
|
10455
10214
|
/**
|
|
10456
10215
|
* Prijavljuje korisnika anonimno
|
|
10457
10216
|
*/
|
|
@@ -10488,18 +10247,11 @@ var AuthService = class extends BaseService {
|
|
|
10488
10247
|
throw AUTH_ERRORS.NOT_AUTHENTICATED;
|
|
10489
10248
|
}
|
|
10490
10249
|
if (!currentUser.isAnonymous) {
|
|
10491
|
-
throw new AuthError(
|
|
10492
|
-
"User is not anonymous",
|
|
10493
|
-
"AUTH/NOT_ANONYMOUS_USER",
|
|
10494
|
-
400
|
|
10495
|
-
);
|
|
10250
|
+
throw new AuthError("User is not anonymous", "AUTH/NOT_ANONYMOUS_USER", 400);
|
|
10496
10251
|
}
|
|
10497
10252
|
const credential = EmailAuthProvider.credential(email, password);
|
|
10498
10253
|
await linkWithCredential(currentUser, credential);
|
|
10499
|
-
return await this.userService.upgradeAnonymousUser(
|
|
10500
|
-
currentUser.uid,
|
|
10501
|
-
email
|
|
10502
|
-
);
|
|
10254
|
+
return await this.userService.upgradeAnonymousUser(currentUser.uid, email);
|
|
10503
10255
|
} catch (error) {
|
|
10504
10256
|
if (error instanceof z23.ZodError) {
|
|
10505
10257
|
throw AUTH_ERRORS.VALIDATION_ERROR;
|
|
@@ -10511,109 +10263,6 @@ var AuthService = class extends BaseService {
|
|
|
10511
10263
|
throw error;
|
|
10512
10264
|
}
|
|
10513
10265
|
}
|
|
10514
|
-
/**
|
|
10515
|
-
* Upgrades an anonymous user to a regular user by signing in with a Google account.
|
|
10516
|
-
*
|
|
10517
|
-
* @throws {AuthError} If the user is not anonymous.
|
|
10518
|
-
* @throws {AuthError} If the user is not authenticated.
|
|
10519
|
-
* @throws {AuthError} If the popup window is closed by the user.
|
|
10520
|
-
* @throws {FirebaseError} If any other Firebase error occurs.
|
|
10521
|
-
*
|
|
10522
|
-
* @returns {Promise<User>} The upgraded user.
|
|
10523
|
-
*/
|
|
10524
|
-
async upgradeAnonymousUserWithGoogle() {
|
|
10525
|
-
try {
|
|
10526
|
-
const currentUser = this.auth.currentUser;
|
|
10527
|
-
if (!currentUser) {
|
|
10528
|
-
throw AUTH_ERRORS.NOT_AUTHENTICATED;
|
|
10529
|
-
}
|
|
10530
|
-
if (!currentUser.isAnonymous) {
|
|
10531
|
-
throw new AuthError(
|
|
10532
|
-
"User is not anonymous",
|
|
10533
|
-
"AUTH/NOT_ANONYMOUS_USER",
|
|
10534
|
-
400
|
|
10535
|
-
);
|
|
10536
|
-
}
|
|
10537
|
-
const userCredential = await signInWithPopup(
|
|
10538
|
-
this.auth,
|
|
10539
|
-
this.googleProvider
|
|
10540
|
-
);
|
|
10541
|
-
if (!userCredential) throw AUTH_ERRORS.INVALID_CREDENTIAL;
|
|
10542
|
-
return await this.userService.upgradeAnonymousUser(
|
|
10543
|
-
currentUser.uid,
|
|
10544
|
-
userCredential.user.email
|
|
10545
|
-
);
|
|
10546
|
-
} catch (error) {
|
|
10547
|
-
const firebaseError = error;
|
|
10548
|
-
if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
|
|
10549
|
-
throw AUTH_ERRORS.POPUP_CLOSED;
|
|
10550
|
-
}
|
|
10551
|
-
throw error;
|
|
10552
|
-
}
|
|
10553
|
-
}
|
|
10554
|
-
async upgradeAnonymousUserWithFacebook() {
|
|
10555
|
-
try {
|
|
10556
|
-
const currentUser = this.auth.currentUser;
|
|
10557
|
-
if (!currentUser) {
|
|
10558
|
-
throw AUTH_ERRORS.NOT_AUTHENTICATED;
|
|
10559
|
-
}
|
|
10560
|
-
if (!currentUser.isAnonymous) {
|
|
10561
|
-
throw new AuthError(
|
|
10562
|
-
"User is not anonymous",
|
|
10563
|
-
"AUTH/NOT_ANONYMOUS_USER",
|
|
10564
|
-
400
|
|
10565
|
-
);
|
|
10566
|
-
}
|
|
10567
|
-
this.facebookProvider.addScope("email");
|
|
10568
|
-
const userCredential = await signInWithPopup(
|
|
10569
|
-
this.auth,
|
|
10570
|
-
this.facebookProvider
|
|
10571
|
-
);
|
|
10572
|
-
if (!userCredential) throw AUTH_ERRORS.INVALID_CREDENTIAL;
|
|
10573
|
-
return await this.userService.upgradeAnonymousUser(
|
|
10574
|
-
currentUser.uid,
|
|
10575
|
-
userCredential.user.email
|
|
10576
|
-
);
|
|
10577
|
-
} catch (error) {
|
|
10578
|
-
const firebaseError = error;
|
|
10579
|
-
if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
|
|
10580
|
-
throw AUTH_ERRORS.POPUP_CLOSED;
|
|
10581
|
-
}
|
|
10582
|
-
throw error;
|
|
10583
|
-
}
|
|
10584
|
-
}
|
|
10585
|
-
async upgradeAnonymousUserWithApple() {
|
|
10586
|
-
try {
|
|
10587
|
-
const currentUser = this.auth.currentUser;
|
|
10588
|
-
if (!currentUser) {
|
|
10589
|
-
throw AUTH_ERRORS.NOT_AUTHENTICATED;
|
|
10590
|
-
}
|
|
10591
|
-
if (!currentUser.isAnonymous) {
|
|
10592
|
-
throw new AuthError(
|
|
10593
|
-
"User is not anonymous",
|
|
10594
|
-
"AUTH/NOT_ANONYMOUS_USER",
|
|
10595
|
-
400
|
|
10596
|
-
);
|
|
10597
|
-
}
|
|
10598
|
-
this.appleProvider.addScope("email");
|
|
10599
|
-
this.appleProvider.addScope("name");
|
|
10600
|
-
const userCredential = await signInWithPopup(
|
|
10601
|
-
this.auth,
|
|
10602
|
-
this.appleProvider
|
|
10603
|
-
);
|
|
10604
|
-
if (!userCredential) throw AUTH_ERRORS.INVALID_CREDENTIAL;
|
|
10605
|
-
return await this.userService.upgradeAnonymousUser(
|
|
10606
|
-
currentUser.uid,
|
|
10607
|
-
userCredential.user.email
|
|
10608
|
-
);
|
|
10609
|
-
} catch (error) {
|
|
10610
|
-
const firebaseError = error;
|
|
10611
|
-
if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
|
|
10612
|
-
throw AUTH_ERRORS.POPUP_CLOSED;
|
|
10613
|
-
}
|
|
10614
|
-
throw error;
|
|
10615
|
-
}
|
|
10616
|
-
}
|
|
10617
10266
|
/**
|
|
10618
10267
|
* Šalje email za resetovanje lozinke korisniku
|
|
10619
10268
|
* @param email Email adresa korisnika
|
|
@@ -10694,11 +10343,7 @@ var AuthService = class extends BaseService {
|
|
|
10694
10343
|
await this.validateSignupData(data);
|
|
10695
10344
|
console.log("[AUTH] Creating Firebase user");
|
|
10696
10345
|
try {
|
|
10697
|
-
const result = await createUserWithEmailAndPassword(
|
|
10698
|
-
this.auth,
|
|
10699
|
-
data.email,
|
|
10700
|
-
data.password
|
|
10701
|
-
);
|
|
10346
|
+
const result = await createUserWithEmailAndPassword(this.auth, data.email, data.password);
|
|
10702
10347
|
firebaseUser = result.user;
|
|
10703
10348
|
console.log("[AUTH] Firebase user created successfully", {
|
|
10704
10349
|
uid: firebaseUser.uid
|
|
@@ -10708,64 +10353,43 @@ var AuthService = class extends BaseService {
|
|
|
10708
10353
|
throw handleFirebaseError(firebaseError);
|
|
10709
10354
|
}
|
|
10710
10355
|
console.log("[AUTH] Starting Firestore transaction");
|
|
10711
|
-
const transactionResult = await runTransaction(
|
|
10712
|
-
|
|
10713
|
-
|
|
10714
|
-
|
|
10715
|
-
|
|
10716
|
-
|
|
10717
|
-
|
|
10718
|
-
|
|
10719
|
-
|
|
10720
|
-
|
|
10721
|
-
|
|
10722
|
-
|
|
10723
|
-
|
|
10724
|
-
firebaseUser,
|
|
10725
|
-
["practitioner" /* PRACTITIONER */],
|
|
10726
|
-
{ 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
|
|
10727
10369
|
);
|
|
10728
|
-
|
|
10729
|
-
|
|
10730
|
-
console.log(
|
|
10731
|
-
"[AUTH] Claiming existing practitioner profile with token"
|
|
10732
|
-
);
|
|
10733
|
-
const claimedPractitioner = await practitionerService.validateTokenAndClaimProfile(
|
|
10734
|
-
data.token,
|
|
10735
|
-
firebaseUser.uid
|
|
10736
|
-
);
|
|
10737
|
-
if (!claimedPractitioner) {
|
|
10738
|
-
throw new Error("Invalid or expired invitation token");
|
|
10739
|
-
}
|
|
10740
|
-
practitioner = claimedPractitioner;
|
|
10741
|
-
} else {
|
|
10742
|
-
console.log("[AUTH] Creating new practitioner profile");
|
|
10743
|
-
const practitionerData = buildPractitionerData(
|
|
10744
|
-
data,
|
|
10745
|
-
firebaseUser.uid
|
|
10746
|
-
);
|
|
10747
|
-
practitioner = await practitionerService.createPractitioner(
|
|
10748
|
-
practitionerData
|
|
10749
|
-
);
|
|
10370
|
+
if (!claimedPractitioner) {
|
|
10371
|
+
throw new Error("Invalid or expired invitation token");
|
|
10750
10372
|
}
|
|
10751
|
-
|
|
10752
|
-
|
|
10753
|
-
|
|
10754
|
-
|
|
10755
|
-
|
|
10756
|
-
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);
|
|
10757
10378
|
}
|
|
10758
|
-
|
|
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
|
+
});
|
|
10759
10386
|
console.log("[AUTH] Atomic practitioner signup completed successfully", {
|
|
10760
10387
|
userId: transactionResult.user.uid,
|
|
10761
10388
|
practitionerId: transactionResult.practitioner.id
|
|
10762
10389
|
});
|
|
10763
10390
|
return transactionResult;
|
|
10764
10391
|
} catch (error) {
|
|
10765
|
-
console.error(
|
|
10766
|
-
"[AUTH] Atomic signup failed, initiating cleanup...",
|
|
10767
|
-
error
|
|
10768
|
-
);
|
|
10392
|
+
console.error("[AUTH] Atomic signup failed, initiating cleanup...", error);
|
|
10769
10393
|
if (firebaseUser) {
|
|
10770
10394
|
await cleanupFirebaseUser(firebaseUser);
|
|
10771
10395
|
}
|
|
@@ -10788,14 +10412,8 @@ var AuthService = class extends BaseService {
|
|
|
10788
10412
|
}
|
|
10789
10413
|
console.log("[AUTH] Email availability confirmed");
|
|
10790
10414
|
if (data.token) {
|
|
10791
|
-
const practitionerService = new PractitionerService(
|
|
10792
|
-
|
|
10793
|
-
this.auth,
|
|
10794
|
-
this.app
|
|
10795
|
-
);
|
|
10796
|
-
const isValidToken = await practitionerService.validateToken(
|
|
10797
|
-
data.token
|
|
10798
|
-
);
|
|
10415
|
+
const practitionerService = new PractitionerService(this.db, this.auth, this.app);
|
|
10416
|
+
const isValidToken = await practitionerService.validateToken(data.token);
|
|
10799
10417
|
if (!isValidToken) {
|
|
10800
10418
|
console.log("[AUTH] Invalid token provided:", data.token);
|
|
10801
10419
|
throw new Error("Invalid or expired invitation token");
|
|
@@ -10826,16 +10444,8 @@ var AuthService = class extends BaseService {
|
|
|
10826
10444
|
console.log("[AUTH] Starting practitioner signin process", {
|
|
10827
10445
|
email
|
|
10828
10446
|
});
|
|
10829
|
-
const practitionerService = new PractitionerService(
|
|
10830
|
-
|
|
10831
|
-
this.auth,
|
|
10832
|
-
this.app
|
|
10833
|
-
);
|
|
10834
|
-
const { user: firebaseUser } = await signInWithEmailAndPassword(
|
|
10835
|
-
this.auth,
|
|
10836
|
-
email,
|
|
10837
|
-
password
|
|
10838
|
-
);
|
|
10447
|
+
const practitionerService = new PractitionerService(this.db, this.auth, this.app);
|
|
10448
|
+
const { user: firebaseUser } = await signInWithEmailAndPassword(this.auth, email, password);
|
|
10839
10449
|
const user = await this.userService.getOrCreateUser(firebaseUser);
|
|
10840
10450
|
console.log("[AUTH] User retrieved", { uid: user.uid });
|
|
10841
10451
|
if (!((_a = user.roles) == null ? void 0 : _a.includes("practitioner" /* PRACTITIONER */))) {
|
|
@@ -10846,14 +10456,9 @@ var AuthService = class extends BaseService {
|
|
|
10846
10456
|
console.error("[AUTH] User has no practitioner profile:", user.uid);
|
|
10847
10457
|
throw AUTH_ERRORS.NOT_FOUND;
|
|
10848
10458
|
}
|
|
10849
|
-
const practitioner = await practitionerService.getPractitioner(
|
|
10850
|
-
user.practitionerProfile
|
|
10851
|
-
);
|
|
10459
|
+
const practitioner = await practitionerService.getPractitioner(user.practitionerProfile);
|
|
10852
10460
|
if (!practitioner) {
|
|
10853
|
-
console.error(
|
|
10854
|
-
"[AUTH] Practitioner profile not found:",
|
|
10855
|
-
user.practitionerProfile
|
|
10856
|
-
);
|
|
10461
|
+
console.error("[AUTH] Practitioner profile not found:", user.practitionerProfile);
|
|
10857
10462
|
throw AUTH_ERRORS.NOT_FOUND;
|
|
10858
10463
|
}
|
|
10859
10464
|
console.log("[AUTH] Practitioner signin completed successfully", {
|
|
@@ -10869,6 +10474,194 @@ var AuthService = class extends BaseService {
|
|
|
10869
10474
|
throw error;
|
|
10870
10475
|
}
|
|
10871
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
|
+
* Signs in a user with a Google authorization code from a mobile client.
|
|
10504
|
+
* This method directly exchanges the authorization code for tokens using Google's OAuth2 API
|
|
10505
|
+
* with the platform-specific client ID (no client secret needed for native apps).
|
|
10506
|
+
* @param authorizationCode - The Google authorization code obtained from the mobile app.
|
|
10507
|
+
* @param redirectUri - The redirect URI used in the OAuth flow.
|
|
10508
|
+
* @param platform - The platform (ios/android) to determine which client ID to use.
|
|
10509
|
+
* @param initialRole - The role to assign to the user if they are being created.
|
|
10510
|
+
* @returns The signed-in or newly created user.
|
|
10511
|
+
*/
|
|
10512
|
+
async signInWithGoogleAuthCode(authorizationCode, redirectUri, platform, initialRole = "patient" /* PATIENT */) {
|
|
10513
|
+
try {
|
|
10514
|
+
console.log("[AUTH] Signing in with Google authorization code (native flow)");
|
|
10515
|
+
console.log("[AUTH] Platform:", platform);
|
|
10516
|
+
console.log("[AUTH] Redirect URI:", redirectUri);
|
|
10517
|
+
console.log("[AUTH] Code length:", authorizationCode.length);
|
|
10518
|
+
const clientId = platform === "ios" ? process.env.GOOGLE_IOS_CLIENT_ID : process.env.GOOGLE_ANDROID_CLIENT_ID;
|
|
10519
|
+
if (!clientId) {
|
|
10520
|
+
throw new Error(
|
|
10521
|
+
`Missing Google ${platform.toUpperCase()} client ID in environment variables`
|
|
10522
|
+
);
|
|
10523
|
+
}
|
|
10524
|
+
console.log("[AUTH] Using client ID:", `${clientId.substring(0, 20)}...`);
|
|
10525
|
+
const tokenEndpoint = "https://oauth2.googleapis.com/token";
|
|
10526
|
+
const params = new URLSearchParams({
|
|
10527
|
+
client_id: clientId,
|
|
10528
|
+
code: authorizationCode,
|
|
10529
|
+
grant_type: "authorization_code",
|
|
10530
|
+
redirect_uri: redirectUri
|
|
10531
|
+
// For native apps, we don't include client_secret
|
|
10532
|
+
});
|
|
10533
|
+
console.log("[AUTH] Making request to Google token endpoint...");
|
|
10534
|
+
const response = await fetch(tokenEndpoint, {
|
|
10535
|
+
method: "POST",
|
|
10536
|
+
headers: {
|
|
10537
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
10538
|
+
},
|
|
10539
|
+
body: params.toString()
|
|
10540
|
+
});
|
|
10541
|
+
if (!response.ok) {
|
|
10542
|
+
const errorText = await response.text();
|
|
10543
|
+
console.error("[AUTH] Google token exchange failed:", {
|
|
10544
|
+
status: response.status,
|
|
10545
|
+
statusText: response.statusText,
|
|
10546
|
+
error: errorText
|
|
10547
|
+
});
|
|
10548
|
+
throw new Error(`Google token exchange failed: ${response.status} - ${errorText}`);
|
|
10549
|
+
}
|
|
10550
|
+
const tokenData = await response.json();
|
|
10551
|
+
console.log("[AUTH] Token exchange response received:", {
|
|
10552
|
+
hasIdToken: !!tokenData.id_token,
|
|
10553
|
+
hasAccessToken: !!tokenData.access_token,
|
|
10554
|
+
hasRefreshToken: !!tokenData.refresh_token
|
|
10555
|
+
});
|
|
10556
|
+
if (!tokenData.id_token) {
|
|
10557
|
+
console.error("[AUTH] No ID token in response:", tokenData);
|
|
10558
|
+
throw new Error("No ID token received from Google token exchange");
|
|
10559
|
+
}
|
|
10560
|
+
console.log("[AUTH] Successfully obtained ID token from Google");
|
|
10561
|
+
console.log("[AUTH] ID token length:", tokenData.id_token.length);
|
|
10562
|
+
return await this.signInWithGoogleIdToken(tokenData.id_token, initialRole);
|
|
10563
|
+
} catch (error) {
|
|
10564
|
+
console.error("[AUTH] Error in signInWithGoogleAuthCode:", error);
|
|
10565
|
+
throw handleFirebaseError(error);
|
|
10566
|
+
}
|
|
10567
|
+
}
|
|
10568
|
+
/**
|
|
10569
|
+
* Links a Google account to the currently signed-in user using an ID token.
|
|
10570
|
+
* This is used to upgrade an anonymous user or to allow an existing user
|
|
10571
|
+
* to sign in with Google in the future.
|
|
10572
|
+
* @param idToken - The Google ID token obtained from the mobile app.
|
|
10573
|
+
* @returns The updated user profile.
|
|
10574
|
+
*/
|
|
10575
|
+
async linkGoogleAccount(idToken) {
|
|
10576
|
+
try {
|
|
10577
|
+
console.log("[AUTH] Linking Google account with ID Token");
|
|
10578
|
+
const currentUser = this.auth.currentUser;
|
|
10579
|
+
if (!currentUser) {
|
|
10580
|
+
throw AUTH_ERRORS.NOT_AUTHENTICATED;
|
|
10581
|
+
}
|
|
10582
|
+
const wasAnonymous = currentUser.isAnonymous;
|
|
10583
|
+
console.log(`[AUTH] Current user is ${wasAnonymous ? "anonymous" : "not anonymous"}`);
|
|
10584
|
+
const credential = GoogleAuthProvider.credential(idToken);
|
|
10585
|
+
const userCredential = await linkWithCredential(currentUser, credential);
|
|
10586
|
+
const linkedFirebaseUser = userCredential.user;
|
|
10587
|
+
console.log("[AUTH] Google account linked successfully to user:", linkedFirebaseUser.uid);
|
|
10588
|
+
if (wasAnonymous) {
|
|
10589
|
+
console.log("[AUTH] Upgrading anonymous user profile");
|
|
10590
|
+
return await this.userService.upgradeAnonymousUser(
|
|
10591
|
+
linkedFirebaseUser.uid,
|
|
10592
|
+
linkedFirebaseUser.email
|
|
10593
|
+
);
|
|
10594
|
+
}
|
|
10595
|
+
return await this.userService.getUserById(linkedFirebaseUser.uid);
|
|
10596
|
+
} catch (error) {
|
|
10597
|
+
console.error("[AUTH] Error in linkGoogleAccount:", error);
|
|
10598
|
+
throw handleFirebaseError(error);
|
|
10599
|
+
}
|
|
10600
|
+
}
|
|
10601
|
+
/**
|
|
10602
|
+
* Links a Google account to the currently signed-in user using an authorization code.
|
|
10603
|
+
* This method directly exchanges the authorization code for tokens using Google's OAuth2 API
|
|
10604
|
+
* with the platform-specific client ID, then links the Google account to the current user.
|
|
10605
|
+
* @param authorizationCode - The Google authorization code obtained from the mobile app.
|
|
10606
|
+
* @param redirectUri - The redirect URI used in the OAuth flow.
|
|
10607
|
+
* @param platform - The platform (ios/android) to determine which client ID to use.
|
|
10608
|
+
* @returns The updated user profile.
|
|
10609
|
+
*/
|
|
10610
|
+
async linkGoogleAccountWithAuthCode(authorizationCode, redirectUri, platform) {
|
|
10611
|
+
try {
|
|
10612
|
+
console.log("[AUTH] Linking Google account with authorization code (native flow)");
|
|
10613
|
+
console.log("[AUTH] Platform:", platform);
|
|
10614
|
+
console.log("[AUTH] Redirect URI:", redirectUri);
|
|
10615
|
+
console.log("[AUTH] Code length:", authorizationCode.length);
|
|
10616
|
+
const clientId = platform === "ios" ? process.env.GOOGLE_IOS_CLIENT_ID : process.env.GOOGLE_ANDROID_CLIENT_ID;
|
|
10617
|
+
if (!clientId) {
|
|
10618
|
+
throw new Error(
|
|
10619
|
+
`Missing Google ${platform.toUpperCase()} client ID in environment variables`
|
|
10620
|
+
);
|
|
10621
|
+
}
|
|
10622
|
+
console.log("[AUTH] Using client ID:", `${clientId.substring(0, 20)}...`);
|
|
10623
|
+
const tokenEndpoint = "https://oauth2.googleapis.com/token";
|
|
10624
|
+
const params = new URLSearchParams({
|
|
10625
|
+
client_id: clientId,
|
|
10626
|
+
code: authorizationCode,
|
|
10627
|
+
grant_type: "authorization_code",
|
|
10628
|
+
redirect_uri: redirectUri
|
|
10629
|
+
});
|
|
10630
|
+
console.log("[AUTH] Making request to Google token endpoint...");
|
|
10631
|
+
const response = await fetch(tokenEndpoint, {
|
|
10632
|
+
method: "POST",
|
|
10633
|
+
headers: {
|
|
10634
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
10635
|
+
},
|
|
10636
|
+
body: params.toString()
|
|
10637
|
+
});
|
|
10638
|
+
if (!response.ok) {
|
|
10639
|
+
const errorText = await response.text();
|
|
10640
|
+
console.error("[AUTH] Google token exchange failed:", {
|
|
10641
|
+
status: response.status,
|
|
10642
|
+
statusText: response.statusText,
|
|
10643
|
+
error: errorText
|
|
10644
|
+
});
|
|
10645
|
+
throw new Error(`Google token exchange failed: ${response.status} - ${errorText}`);
|
|
10646
|
+
}
|
|
10647
|
+
const tokenData = await response.json();
|
|
10648
|
+
console.log("[AUTH] Token exchange response received:", {
|
|
10649
|
+
hasIdToken: !!tokenData.id_token,
|
|
10650
|
+
hasAccessToken: !!tokenData.access_token,
|
|
10651
|
+
hasRefreshToken: !!tokenData.refresh_token
|
|
10652
|
+
});
|
|
10653
|
+
if (!tokenData.id_token) {
|
|
10654
|
+
console.error("[AUTH] No ID token in response:", tokenData);
|
|
10655
|
+
throw new Error("No ID token received from Google token exchange");
|
|
10656
|
+
}
|
|
10657
|
+
console.log("[AUTH] Successfully obtained ID token from Google");
|
|
10658
|
+
console.log("[AUTH] ID token length:", tokenData.id_token.length);
|
|
10659
|
+
return await this.linkGoogleAccount(tokenData.id_token);
|
|
10660
|
+
} catch (error) {
|
|
10661
|
+
console.error("[AUTH] Error in linkGoogleAccountWithAuthCode:", error);
|
|
10662
|
+
throw handleFirebaseError(error);
|
|
10663
|
+
}
|
|
10664
|
+
}
|
|
10872
10665
|
};
|
|
10873
10666
|
|
|
10874
10667
|
// src/services/calendar/calendar.v2.service.ts
|
|
@@ -14197,7 +13990,7 @@ import {
|
|
|
14197
13990
|
limit as limit13,
|
|
14198
13991
|
startAfter as startAfter11
|
|
14199
13992
|
} from "firebase/firestore";
|
|
14200
|
-
import { getCountFromServer } from "firebase/firestore";
|
|
13993
|
+
import { getCountFromServer as getCountFromServer2 } from "firebase/firestore";
|
|
14201
13994
|
var DocumentationTemplateService = class extends BaseService {
|
|
14202
13995
|
constructor(...args) {
|
|
14203
13996
|
super(...args);
|
|
@@ -14455,7 +14248,7 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
14455
14248
|
constraints.push(where26("sortingOrder", "==", sortingOrder));
|
|
14456
14249
|
}
|
|
14457
14250
|
const q = query26(this.collectionRef, ...constraints.filter((c) => c));
|
|
14458
|
-
const snapshot = await
|
|
14251
|
+
const snapshot = await getCountFromServer2(q);
|
|
14459
14252
|
return snapshot.data().count;
|
|
14460
14253
|
}
|
|
14461
14254
|
/**
|
|
@@ -16840,7 +16633,7 @@ import {
|
|
|
16840
16633
|
limit as limit17,
|
|
16841
16634
|
orderBy as orderBy19,
|
|
16842
16635
|
startAfter as startAfter15,
|
|
16843
|
-
getCountFromServer as
|
|
16636
|
+
getCountFromServer as getCountFromServer3
|
|
16844
16637
|
} from "firebase/firestore";
|
|
16845
16638
|
|
|
16846
16639
|
// src/backoffice/types/brand.types.ts
|
|
@@ -16916,7 +16709,7 @@ var BrandService = class extends BaseService {
|
|
|
16916
16709
|
);
|
|
16917
16710
|
}
|
|
16918
16711
|
const q = query32(this.getBrandsRef(), ...constraints);
|
|
16919
|
-
const snapshot = await
|
|
16712
|
+
const snapshot = await getCountFromServer3(q);
|
|
16920
16713
|
return snapshot.data().count;
|
|
16921
16714
|
}
|
|
16922
16715
|
/**
|
|
@@ -16978,7 +16771,7 @@ import {
|
|
|
16978
16771
|
addDoc as addDoc4,
|
|
16979
16772
|
collection as collection33,
|
|
16980
16773
|
doc as doc33,
|
|
16981
|
-
getCountFromServer as
|
|
16774
|
+
getCountFromServer as getCountFromServer4,
|
|
16982
16775
|
getDoc as getDoc35,
|
|
16983
16776
|
getDocs as getDocs33,
|
|
16984
16777
|
limit as limit18,
|
|
@@ -17030,7 +16823,7 @@ var CategoryService = class extends BaseService {
|
|
|
17030
16823
|
where33("family", "==", family),
|
|
17031
16824
|
where33("isActive", "==", active)
|
|
17032
16825
|
);
|
|
17033
|
-
const snapshot = await
|
|
16826
|
+
const snapshot = await getCountFromServer4(q);
|
|
17034
16827
|
counts[family] = snapshot.data().count;
|
|
17035
16828
|
}
|
|
17036
16829
|
return counts;
|
|
@@ -17171,7 +16964,7 @@ import {
|
|
|
17171
16964
|
collectionGroup as collectionGroup2,
|
|
17172
16965
|
deleteDoc as deleteDoc20,
|
|
17173
16966
|
doc as doc34,
|
|
17174
|
-
getCountFromServer as
|
|
16967
|
+
getCountFromServer as getCountFromServer5,
|
|
17175
16968
|
getDoc as getDoc36,
|
|
17176
16969
|
getDocs as getDocs34,
|
|
17177
16970
|
limit as limit19,
|
|
@@ -17234,7 +17027,7 @@ var SubcategoryService = class extends BaseService {
|
|
|
17234
17027
|
const categoryId = categoryDoc.id;
|
|
17235
17028
|
const subcategoriesRef = this.getSubcategoriesRef(categoryId);
|
|
17236
17029
|
const q = query34(subcategoriesRef, where34("isActive", "==", active));
|
|
17237
|
-
const snapshot = await
|
|
17030
|
+
const snapshot = await getCountFromServer5(q);
|
|
17238
17031
|
counts[categoryId] = snapshot.data().count;
|
|
17239
17032
|
}
|
|
17240
17033
|
return counts;
|
|
@@ -18036,7 +17829,7 @@ import {
|
|
|
18036
17829
|
limit as limit21,
|
|
18037
17830
|
orderBy as orderBy23,
|
|
18038
17831
|
startAfter as startAfter19,
|
|
18039
|
-
getCountFromServer as
|
|
17832
|
+
getCountFromServer as getCountFromServer7
|
|
18040
17833
|
} from "firebase/firestore";
|
|
18041
17834
|
|
|
18042
17835
|
// src/backoffice/types/product.types.ts
|
|
@@ -18115,7 +17908,7 @@ var ProductService = class extends BaseService {
|
|
|
18115
17908
|
constraints.push(where36("technologyId", "==", technologyId));
|
|
18116
17909
|
}
|
|
18117
17910
|
const q = query36(collectionGroup3(this.db, PRODUCTS_COLLECTION), ...constraints);
|
|
18118
|
-
const snapshot = await
|
|
17911
|
+
const snapshot = await getCountFromServer7(q);
|
|
18119
17912
|
return snapshot.data().count;
|
|
18120
17913
|
}
|
|
18121
17914
|
/**
|