@blackcode_sa/metaestetics-api 1.4.2 → 1.4.3
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.d.mts +2841 -407
- package/dist/index.d.ts +2841 -407
- package/dist/index.js +1279 -970
- package/dist/index.mjs +1200 -893
- package/package.json +1 -1
- package/src/services/auth.service.ts +173 -0
- package/src/services/clinic/clinic-group.service.ts +34 -0
- package/src/services/clinic/clinic.service.ts +53 -0
- package/src/types/clinic/index.ts +165 -100
- package/src/types/clinic/preferences.types.ts +101 -0
- package/src/validations/clinic.schema.ts +162 -34
package/dist/index.js
CHANGED
|
@@ -81,8 +81,11 @@ __export(index_exports, {
|
|
|
81
81
|
blockingConditionSchema: () => blockingConditionSchema,
|
|
82
82
|
clinicAdminOptionsSchema: () => clinicAdminOptionsSchema,
|
|
83
83
|
clinicAdminSchema: () => clinicAdminSchema,
|
|
84
|
+
clinicAdminSignupSchema: () => clinicAdminSignupSchema,
|
|
85
|
+
clinicBranchSetupSchema: () => clinicBranchSetupSchema,
|
|
84
86
|
clinicContactInfoSchema: () => clinicContactInfoSchema,
|
|
85
87
|
clinicGroupSchema: () => clinicGroupSchema,
|
|
88
|
+
clinicGroupSetupSchema: () => clinicGroupSetupSchema,
|
|
86
89
|
clinicInfoSchema: () => clinicInfoSchema,
|
|
87
90
|
clinicLocationSchema: () => clinicLocationSchema,
|
|
88
91
|
clinicReviewSchema: () => clinicReviewSchema,
|
|
@@ -137,6 +140,9 @@ __export(index_exports, {
|
|
|
137
140
|
timestampSchema: () => timestampSchema,
|
|
138
141
|
updateAllergySchema: () => updateAllergySchema,
|
|
139
142
|
updateBlockingConditionSchema: () => updateBlockingConditionSchema,
|
|
143
|
+
updateClinicAdminSchema: () => updateClinicAdminSchema,
|
|
144
|
+
updateClinicGroupSchema: () => updateClinicGroupSchema,
|
|
145
|
+
updateClinicSchema: () => updateClinicSchema,
|
|
140
146
|
updateContraindicationSchema: () => updateContraindicationSchema,
|
|
141
147
|
updateDocumentTemplateSchema: () => updateDocumentTemplateSchema,
|
|
142
148
|
updateMedicationSchema: () => updateMedicationSchema,
|
|
@@ -193,6 +199,7 @@ var getFirebaseApp = async () => {
|
|
|
193
199
|
|
|
194
200
|
// src/services/auth.service.ts
|
|
195
201
|
var import_auth5 = require("firebase/auth");
|
|
202
|
+
var import_firestore19 = require("firebase/firestore");
|
|
196
203
|
|
|
197
204
|
// src/types/documentation-templates/index.ts
|
|
198
205
|
var DocumentElementType = /* @__PURE__ */ ((DocumentElementType2) => {
|
|
@@ -253,7 +260,7 @@ var DOCUMENTATION_TEMPLATES_COLLECTION = "documentation-templates";
|
|
|
253
260
|
var FILLED_DOCUMENTS_COLLECTION = "filled-documents";
|
|
254
261
|
|
|
255
262
|
// src/services/auth.service.ts
|
|
256
|
-
var
|
|
263
|
+
var import_zod15 = require("zod");
|
|
257
264
|
|
|
258
265
|
// src/validations/schemas.ts
|
|
259
266
|
var import_zod2 = require("zod");
|
|
@@ -674,7 +681,7 @@ var BaseService = class {
|
|
|
674
681
|
};
|
|
675
682
|
|
|
676
683
|
// src/services/user.service.ts
|
|
677
|
-
var
|
|
684
|
+
var import_firestore14 = require("firebase/firestore");
|
|
678
685
|
|
|
679
686
|
// src/errors/user.errors.ts
|
|
680
687
|
var USER_ERRORS = {
|
|
@@ -1359,9 +1366,9 @@ var addAllergyUtil = async (db, patientId, data, userRef) => {
|
|
|
1359
1366
|
var updateAllergyUtil = async (db, patientId, data, userRef) => {
|
|
1360
1367
|
const validatedData = updateAllergySchema.parse(data);
|
|
1361
1368
|
const { allergyIndex, ...updateData } = validatedData;
|
|
1362
|
-
const
|
|
1363
|
-
if (!
|
|
1364
|
-
const medicalInfo =
|
|
1369
|
+
const doc14 = await (0, import_firestore5.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
1370
|
+
if (!doc14.exists()) throw new Error("Medical info not found");
|
|
1371
|
+
const medicalInfo = doc14.data();
|
|
1365
1372
|
if (allergyIndex >= medicalInfo.allergies.length) {
|
|
1366
1373
|
throw new Error("Invalid allergy index");
|
|
1367
1374
|
}
|
|
@@ -1377,9 +1384,9 @@ var updateAllergyUtil = async (db, patientId, data, userRef) => {
|
|
|
1377
1384
|
});
|
|
1378
1385
|
};
|
|
1379
1386
|
var removeAllergyUtil = async (db, patientId, allergyIndex, userRef) => {
|
|
1380
|
-
const
|
|
1381
|
-
if (!
|
|
1382
|
-
const medicalInfo =
|
|
1387
|
+
const doc14 = await (0, import_firestore5.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
1388
|
+
if (!doc14.exists()) throw new Error("Medical info not found");
|
|
1389
|
+
const medicalInfo = doc14.data();
|
|
1383
1390
|
if (allergyIndex >= medicalInfo.allergies.length) {
|
|
1384
1391
|
throw new Error("Invalid allergy index");
|
|
1385
1392
|
}
|
|
@@ -1404,9 +1411,9 @@ var addBlockingConditionUtil = async (db, patientId, data, userRef) => {
|
|
|
1404
1411
|
var updateBlockingConditionUtil = async (db, patientId, data, userRef) => {
|
|
1405
1412
|
const validatedData = updateBlockingConditionSchema.parse(data);
|
|
1406
1413
|
const { conditionIndex, ...updateData } = validatedData;
|
|
1407
|
-
const
|
|
1408
|
-
if (!
|
|
1409
|
-
const medicalInfo =
|
|
1414
|
+
const doc14 = await (0, import_firestore5.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
1415
|
+
if (!doc14.exists()) throw new Error("Medical info not found");
|
|
1416
|
+
const medicalInfo = doc14.data();
|
|
1410
1417
|
if (conditionIndex >= medicalInfo.blockingConditions.length) {
|
|
1411
1418
|
throw new Error("Invalid blocking condition index");
|
|
1412
1419
|
}
|
|
@@ -1422,9 +1429,9 @@ var updateBlockingConditionUtil = async (db, patientId, data, userRef) => {
|
|
|
1422
1429
|
});
|
|
1423
1430
|
};
|
|
1424
1431
|
var removeBlockingConditionUtil = async (db, patientId, conditionIndex, userRef) => {
|
|
1425
|
-
const
|
|
1426
|
-
if (!
|
|
1427
|
-
const medicalInfo =
|
|
1432
|
+
const doc14 = await (0, import_firestore5.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
1433
|
+
if (!doc14.exists()) throw new Error("Medical info not found");
|
|
1434
|
+
const medicalInfo = doc14.data();
|
|
1428
1435
|
if (conditionIndex >= medicalInfo.blockingConditions.length) {
|
|
1429
1436
|
throw new Error("Invalid blocking condition index");
|
|
1430
1437
|
}
|
|
@@ -1449,9 +1456,9 @@ var addContraindicationUtil = async (db, patientId, data, userRef) => {
|
|
|
1449
1456
|
var updateContraindicationUtil = async (db, patientId, data, userRef) => {
|
|
1450
1457
|
const validatedData = updateContraindicationSchema.parse(data);
|
|
1451
1458
|
const { contraindicationIndex, ...updateData } = validatedData;
|
|
1452
|
-
const
|
|
1453
|
-
if (!
|
|
1454
|
-
const medicalInfo =
|
|
1459
|
+
const doc14 = await (0, import_firestore5.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
1460
|
+
if (!doc14.exists()) throw new Error("Medical info not found");
|
|
1461
|
+
const medicalInfo = doc14.data();
|
|
1455
1462
|
if (contraindicationIndex >= medicalInfo.contraindications.length) {
|
|
1456
1463
|
throw new Error("Invalid contraindication index");
|
|
1457
1464
|
}
|
|
@@ -1467,9 +1474,9 @@ var updateContraindicationUtil = async (db, patientId, data, userRef) => {
|
|
|
1467
1474
|
});
|
|
1468
1475
|
};
|
|
1469
1476
|
var removeContraindicationUtil = async (db, patientId, contraindicationIndex, userRef) => {
|
|
1470
|
-
const
|
|
1471
|
-
if (!
|
|
1472
|
-
const medicalInfo =
|
|
1477
|
+
const doc14 = await (0, import_firestore5.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
1478
|
+
if (!doc14.exists()) throw new Error("Medical info not found");
|
|
1479
|
+
const medicalInfo = doc14.data();
|
|
1473
1480
|
if (contraindicationIndex >= medicalInfo.contraindications.length) {
|
|
1474
1481
|
throw new Error("Invalid contraindication index");
|
|
1475
1482
|
}
|
|
@@ -1494,9 +1501,9 @@ var addMedicationUtil = async (db, patientId, data, userRef) => {
|
|
|
1494
1501
|
var updateMedicationUtil = async (db, patientId, data, userRef) => {
|
|
1495
1502
|
const validatedData = updateMedicationSchema.parse(data);
|
|
1496
1503
|
const { medicationIndex, ...updateData } = validatedData;
|
|
1497
|
-
const
|
|
1498
|
-
if (!
|
|
1499
|
-
const medicalInfo =
|
|
1504
|
+
const doc14 = await (0, import_firestore5.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
1505
|
+
if (!doc14.exists()) throw new Error("Medical info not found");
|
|
1506
|
+
const medicalInfo = doc14.data();
|
|
1500
1507
|
if (medicationIndex >= medicalInfo.currentMedications.length) {
|
|
1501
1508
|
throw new Error("Invalid medication index");
|
|
1502
1509
|
}
|
|
@@ -1512,9 +1519,9 @@ var updateMedicationUtil = async (db, patientId, data, userRef) => {
|
|
|
1512
1519
|
});
|
|
1513
1520
|
};
|
|
1514
1521
|
var removeMedicationUtil = async (db, patientId, medicationIndex, userRef) => {
|
|
1515
|
-
const
|
|
1516
|
-
if (!
|
|
1517
|
-
const medicalInfo =
|
|
1522
|
+
const doc14 = await (0, import_firestore5.getDoc)(getMedicalInfoDocRef(db, patientId));
|
|
1523
|
+
if (!doc14.exists()) throw new Error("Medical info not found");
|
|
1524
|
+
const medicalInfo = doc14.data();
|
|
1518
1525
|
if (medicationIndex >= medicalInfo.currentMedications.length) {
|
|
1519
1526
|
throw new Error("Invalid medication index");
|
|
1520
1527
|
}
|
|
@@ -2150,18 +2157,40 @@ var PatientService = class extends BaseService {
|
|
|
2150
2157
|
};
|
|
2151
2158
|
|
|
2152
2159
|
// src/services/clinic/utils/admin.utils.ts
|
|
2153
|
-
var
|
|
2160
|
+
var import_firestore11 = require("firebase/firestore");
|
|
2154
2161
|
|
|
2155
|
-
// src/types/clinic/
|
|
2156
|
-
var
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2162
|
+
// src/types/clinic/preferences.types.ts
|
|
2163
|
+
var PracticeType = /* @__PURE__ */ ((PracticeType2) => {
|
|
2164
|
+
PracticeType2["GENERAL_PRACTICE"] = "general_practice";
|
|
2165
|
+
PracticeType2["DENTAL"] = "dental";
|
|
2166
|
+
PracticeType2["DERMATOLOGY"] = "dermatology";
|
|
2167
|
+
PracticeType2["CARDIOLOGY"] = "cardiology";
|
|
2168
|
+
PracticeType2["ORTHOPEDICS"] = "orthopedics";
|
|
2169
|
+
PracticeType2["GYNECOLOGY"] = "gynecology";
|
|
2170
|
+
PracticeType2["PEDIATRICS"] = "pediatrics";
|
|
2171
|
+
PracticeType2["OPHTHALMOLOGY"] = "ophthalmology";
|
|
2172
|
+
PracticeType2["NEUROLOGY"] = "neurology";
|
|
2173
|
+
PracticeType2["PSYCHIATRY"] = "psychiatry";
|
|
2174
|
+
PracticeType2["UROLOGY"] = "urology";
|
|
2175
|
+
PracticeType2["ONCOLOGY"] = "oncology";
|
|
2176
|
+
PracticeType2["ENDOCRINOLOGY"] = "endocrinology";
|
|
2177
|
+
PracticeType2["GASTROENTEROLOGY"] = "gastroenterology";
|
|
2178
|
+
PracticeType2["PULMONOLOGY"] = "pulmonology";
|
|
2179
|
+
PracticeType2["RHEUMATOLOGY"] = "rheumatology";
|
|
2180
|
+
PracticeType2["PHYSICAL_THERAPY"] = "physical_therapy";
|
|
2181
|
+
PracticeType2["NUTRITION"] = "nutrition";
|
|
2182
|
+
PracticeType2["ALTERNATIVE_MEDICINE"] = "alternative_medicine";
|
|
2183
|
+
PracticeType2["OTHER"] = "other";
|
|
2184
|
+
return PracticeType2;
|
|
2185
|
+
})(PracticeType || {});
|
|
2186
|
+
var Language = /* @__PURE__ */ ((Language2) => {
|
|
2187
|
+
Language2["ENGLISH"] = "english";
|
|
2188
|
+
Language2["GERMAN"] = "german";
|
|
2189
|
+
Language2["ITALIAN"] = "italian";
|
|
2190
|
+
Language2["FRENCH"] = "french";
|
|
2191
|
+
Language2["SPANISH"] = "spanish";
|
|
2192
|
+
return Language2;
|
|
2193
|
+
})(Language || {});
|
|
2165
2194
|
var ClinicTag = /* @__PURE__ */ ((ClinicTag4) => {
|
|
2166
2195
|
ClinicTag4["PARKING"] = "parking";
|
|
2167
2196
|
ClinicTag4["WIFI"] = "wifi";
|
|
@@ -2212,8 +2241,27 @@ var ClinicTag = /* @__PURE__ */ ((ClinicTag4) => {
|
|
|
2212
2241
|
return ClinicTag4;
|
|
2213
2242
|
})(ClinicTag || {});
|
|
2214
2243
|
|
|
2244
|
+
// src/types/clinic/index.ts
|
|
2245
|
+
var CLINIC_GROUPS_COLLECTION = "clinic_groups";
|
|
2246
|
+
var CLINIC_ADMINS_COLLECTION = "clinic_admins";
|
|
2247
|
+
var CLINICS_COLLECTION = "clinics";
|
|
2248
|
+
var AdminTokenStatus = /* @__PURE__ */ ((AdminTokenStatus2) => {
|
|
2249
|
+
AdminTokenStatus2["ACTIVE"] = "active";
|
|
2250
|
+
AdminTokenStatus2["USED"] = "used";
|
|
2251
|
+
AdminTokenStatus2["EXPIRED"] = "expired";
|
|
2252
|
+
return AdminTokenStatus2;
|
|
2253
|
+
})(AdminTokenStatus || {});
|
|
2254
|
+
var SubscriptionModel = /* @__PURE__ */ ((SubscriptionModel2) => {
|
|
2255
|
+
SubscriptionModel2["NO_SUBSCRIPTION"] = "no_subscription";
|
|
2256
|
+
SubscriptionModel2["BASIC"] = "basic";
|
|
2257
|
+
SubscriptionModel2["PREMIUM"] = "premium";
|
|
2258
|
+
SubscriptionModel2["ENTERPRISE"] = "enterprise";
|
|
2259
|
+
return SubscriptionModel2;
|
|
2260
|
+
})(SubscriptionModel || {});
|
|
2261
|
+
|
|
2215
2262
|
// src/validations/clinic.schema.ts
|
|
2216
2263
|
var import_zod9 = require("zod");
|
|
2264
|
+
var import_firestore10 = require("firebase/firestore");
|
|
2217
2265
|
|
|
2218
2266
|
// src/backoffice/types/static/procedure-family.types.ts
|
|
2219
2267
|
var ProcedureFamily = /* @__PURE__ */ ((ProcedureFamily2) => {
|
|
@@ -2265,8 +2313,8 @@ var Currency = /* @__PURE__ */ ((Currency2) => {
|
|
|
2265
2313
|
var clinicContactInfoSchema = import_zod9.z.object({
|
|
2266
2314
|
email: import_zod9.z.string().email(),
|
|
2267
2315
|
phoneNumber: import_zod9.z.string(),
|
|
2268
|
-
alternativePhoneNumber: import_zod9.z.string().nullable(),
|
|
2269
|
-
website: import_zod9.z.string().nullable()
|
|
2316
|
+
alternativePhoneNumber: import_zod9.z.string().nullable().optional(),
|
|
2317
|
+
website: import_zod9.z.string().nullable().optional()
|
|
2270
2318
|
});
|
|
2271
2319
|
var clinicLocationSchema = import_zod9.z.object({
|
|
2272
2320
|
address: import_zod9.z.string(),
|
|
@@ -2275,20 +2323,26 @@ var clinicLocationSchema = import_zod9.z.object({
|
|
|
2275
2323
|
postalCode: import_zod9.z.string(),
|
|
2276
2324
|
latitude: import_zod9.z.number().min(-90).max(90),
|
|
2277
2325
|
longitude: import_zod9.z.number().min(-180).max(180),
|
|
2278
|
-
geohash: import_zod9.z.string().nullable()
|
|
2326
|
+
geohash: import_zod9.z.string().nullable().optional()
|
|
2279
2327
|
});
|
|
2280
2328
|
var workingHoursTimeSchema = import_zod9.z.object({
|
|
2281
2329
|
open: import_zod9.z.string(),
|
|
2282
|
-
close: import_zod9.z.string()
|
|
2330
|
+
close: import_zod9.z.string(),
|
|
2331
|
+
breaks: import_zod9.z.array(
|
|
2332
|
+
import_zod9.z.object({
|
|
2333
|
+
start: import_zod9.z.string(),
|
|
2334
|
+
end: import_zod9.z.string()
|
|
2335
|
+
})
|
|
2336
|
+
).optional()
|
|
2283
2337
|
});
|
|
2284
2338
|
var workingHoursSchema = import_zod9.z.object({
|
|
2285
|
-
monday: workingHoursTimeSchema,
|
|
2286
|
-
tuesday: workingHoursTimeSchema,
|
|
2287
|
-
wednesday: workingHoursTimeSchema,
|
|
2288
|
-
thursday: workingHoursTimeSchema,
|
|
2289
|
-
friday: workingHoursTimeSchema,
|
|
2290
|
-
saturday: workingHoursTimeSchema,
|
|
2291
|
-
sunday: workingHoursTimeSchema
|
|
2339
|
+
monday: workingHoursTimeSchema.nullable(),
|
|
2340
|
+
tuesday: workingHoursTimeSchema.nullable(),
|
|
2341
|
+
wednesday: workingHoursTimeSchema.nullable(),
|
|
2342
|
+
thursday: workingHoursTimeSchema.nullable(),
|
|
2343
|
+
friday: workingHoursTimeSchema.nullable(),
|
|
2344
|
+
saturday: workingHoursTimeSchema.nullable(),
|
|
2345
|
+
sunday: workingHoursTimeSchema.nullable()
|
|
2292
2346
|
});
|
|
2293
2347
|
var clinicTagsSchema = import_zod9.z.object({
|
|
2294
2348
|
tags: import_zod9.z.array(import_zod9.z.nativeEnum(ClinicTag))
|
|
@@ -2309,14 +2363,14 @@ var clinicInfoSchema = import_zod9.z.object({
|
|
|
2309
2363
|
id: import_zod9.z.string(),
|
|
2310
2364
|
featuredPhoto: import_zod9.z.string(),
|
|
2311
2365
|
name: import_zod9.z.string(),
|
|
2312
|
-
description: import_zod9.z.string().nullable(),
|
|
2366
|
+
description: import_zod9.z.string().nullable().optional(),
|
|
2313
2367
|
location: clinicLocationSchema,
|
|
2314
2368
|
contactInfo: clinicContactInfoSchema
|
|
2315
2369
|
});
|
|
2316
2370
|
var doctorInfoSchema = import_zod9.z.object({
|
|
2317
2371
|
id: import_zod9.z.string(),
|
|
2318
2372
|
name: import_zod9.z.string(),
|
|
2319
|
-
description: import_zod9.z.string().nullable(),
|
|
2373
|
+
description: import_zod9.z.string().nullable().optional(),
|
|
2320
2374
|
photo: import_zod9.z.string(),
|
|
2321
2375
|
rating: import_zod9.z.number().min(0).max(5),
|
|
2322
2376
|
services: import_zod9.z.array(import_zod9.z.string())
|
|
@@ -2324,7 +2378,7 @@ var doctorInfoSchema = import_zod9.z.object({
|
|
|
2324
2378
|
var serviceInfoSchema = import_zod9.z.object({
|
|
2325
2379
|
id: import_zod9.z.string(),
|
|
2326
2380
|
name: import_zod9.z.string(),
|
|
2327
|
-
description: import_zod9.z.string().nullable(),
|
|
2381
|
+
description: import_zod9.z.string().nullable().optional(),
|
|
2328
2382
|
photo: import_zod9.z.string(),
|
|
2329
2383
|
procedureFamily: import_zod9.z.nativeEnum(ProcedureFamily),
|
|
2330
2384
|
category: import_zod9.z.string(),
|
|
@@ -2345,9 +2399,9 @@ var reviewInfoSchema = import_zod9.z.object({
|
|
|
2345
2399
|
patientId: import_zod9.z.string(),
|
|
2346
2400
|
patientName: import_zod9.z.string(),
|
|
2347
2401
|
patientPhoto: import_zod9.z.string(),
|
|
2348
|
-
createdAt: import_zod9.z.
|
|
2402
|
+
createdAt: import_zod9.z.instanceof(Date).or(import_zod9.z.instanceof(import_firestore10.Timestamp)),
|
|
2349
2403
|
// Timestamp
|
|
2350
|
-
updatedAt: import_zod9.z.
|
|
2404
|
+
updatedAt: import_zod9.z.instanceof(Date).or(import_zod9.z.instanceof(import_firestore10.Timestamp))
|
|
2351
2405
|
// Timestamp
|
|
2352
2406
|
});
|
|
2353
2407
|
var clinicAdminSchema = import_zod9.z.object({
|
|
@@ -2359,8 +2413,8 @@ var clinicAdminSchema = import_zod9.z.object({
|
|
|
2359
2413
|
clinicsManagedInfo: import_zod9.z.array(clinicInfoSchema),
|
|
2360
2414
|
contactInfo: contactPersonSchema,
|
|
2361
2415
|
roleTitle: import_zod9.z.string(),
|
|
2362
|
-
createdAt: import_zod9.z.
|
|
2363
|
-
updatedAt: import_zod9.z.
|
|
2416
|
+
createdAt: import_zod9.z.instanceof(Date).or(import_zod9.z.instanceof(import_firestore10.Timestamp)),
|
|
2417
|
+
updatedAt: import_zod9.z.instanceof(Date).or(import_zod9.z.instanceof(import_firestore10.Timestamp)),
|
|
2364
2418
|
isActive: import_zod9.z.boolean()
|
|
2365
2419
|
});
|
|
2366
2420
|
var adminTokenSchema = import_zod9.z.object({
|
|
@@ -2368,9 +2422,9 @@ var adminTokenSchema = import_zod9.z.object({
|
|
|
2368
2422
|
token: import_zod9.z.string(),
|
|
2369
2423
|
status: import_zod9.z.nativeEnum(AdminTokenStatus),
|
|
2370
2424
|
usedByUserRef: import_zod9.z.string().optional(),
|
|
2371
|
-
createdAt: import_zod9.z.
|
|
2425
|
+
createdAt: import_zod9.z.instanceof(Date).or(import_zod9.z.instanceof(import_firestore10.Timestamp)),
|
|
2372
2426
|
// Timestamp
|
|
2373
|
-
expiresAt: import_zod9.z.
|
|
2427
|
+
expiresAt: import_zod9.z.instanceof(Date).or(import_zod9.z.instanceof(import_firestore10.Timestamp))
|
|
2374
2428
|
// Timestamp
|
|
2375
2429
|
});
|
|
2376
2430
|
var createAdminTokenSchema = import_zod9.z.object({
|
|
@@ -2379,7 +2433,7 @@ var createAdminTokenSchema = import_zod9.z.object({
|
|
|
2379
2433
|
var clinicGroupSchema = import_zod9.z.object({
|
|
2380
2434
|
id: import_zod9.z.string(),
|
|
2381
2435
|
name: import_zod9.z.string(),
|
|
2382
|
-
description: import_zod9.z.string().nullable(),
|
|
2436
|
+
description: import_zod9.z.string().nullable().optional(),
|
|
2383
2437
|
hqLocation: clinicLocationSchema,
|
|
2384
2438
|
contactInfo: clinicContactInfoSchema,
|
|
2385
2439
|
contactPerson: contactPersonSchema,
|
|
@@ -2389,11 +2443,17 @@ var clinicGroupSchema = import_zod9.z.object({
|
|
|
2389
2443
|
adminsInfo: import_zod9.z.array(adminInfoSchema),
|
|
2390
2444
|
adminTokens: import_zod9.z.array(adminTokenSchema),
|
|
2391
2445
|
ownerId: import_zod9.z.string(),
|
|
2392
|
-
createdAt: import_zod9.z.
|
|
2446
|
+
createdAt: import_zod9.z.instanceof(Date).or(import_zod9.z.instanceof(import_firestore10.Timestamp)),
|
|
2393
2447
|
// Timestamp
|
|
2394
|
-
updatedAt: import_zod9.z.
|
|
2448
|
+
updatedAt: import_zod9.z.instanceof(Date).or(import_zod9.z.instanceof(import_firestore10.Timestamp)),
|
|
2395
2449
|
// Timestamp
|
|
2396
|
-
isActive: import_zod9.z.boolean()
|
|
2450
|
+
isActive: import_zod9.z.boolean(),
|
|
2451
|
+
logo: import_zod9.z.string().optional(),
|
|
2452
|
+
practiceType: import_zod9.z.nativeEnum(PracticeType).optional(),
|
|
2453
|
+
languages: import_zod9.z.array(import_zod9.z.nativeEnum(Language)).optional(),
|
|
2454
|
+
subscriptionModel: import_zod9.z.nativeEnum(SubscriptionModel),
|
|
2455
|
+
calendarSyncEnabled: import_zod9.z.boolean().optional(),
|
|
2456
|
+
autoConfirmAppointments: import_zod9.z.boolean().optional()
|
|
2397
2457
|
});
|
|
2398
2458
|
var clinicReviewSchema = import_zod9.z.object({
|
|
2399
2459
|
id: import_zod9.z.string(),
|
|
@@ -2401,9 +2461,9 @@ var clinicReviewSchema = import_zod9.z.object({
|
|
|
2401
2461
|
patientId: import_zod9.z.string(),
|
|
2402
2462
|
rating: import_zod9.z.number().min(1).max(5),
|
|
2403
2463
|
comment: import_zod9.z.string(),
|
|
2404
|
-
createdAt: import_zod9.z.
|
|
2464
|
+
createdAt: import_zod9.z.instanceof(Date).or(import_zod9.z.instanceof(import_firestore10.Timestamp)),
|
|
2405
2465
|
// Timestamp
|
|
2406
|
-
updatedAt: import_zod9.z.
|
|
2466
|
+
updatedAt: import_zod9.z.instanceof(Date).or(import_zod9.z.instanceof(import_firestore10.Timestamp)),
|
|
2407
2467
|
// Timestamp
|
|
2408
2468
|
isVerified: import_zod9.z.boolean()
|
|
2409
2469
|
});
|
|
@@ -2411,13 +2471,19 @@ var clinicSchema = import_zod9.z.object({
|
|
|
2411
2471
|
id: import_zod9.z.string(),
|
|
2412
2472
|
clinicGroupId: import_zod9.z.string(),
|
|
2413
2473
|
name: import_zod9.z.string(),
|
|
2414
|
-
description: import_zod9.z.string().nullable(),
|
|
2474
|
+
description: import_zod9.z.string().nullable().optional(),
|
|
2415
2475
|
location: clinicLocationSchema,
|
|
2416
2476
|
contactInfo: clinicContactInfoSchema,
|
|
2417
2477
|
workingHours: workingHoursSchema,
|
|
2418
2478
|
tags: import_zod9.z.array(import_zod9.z.nativeEnum(ClinicTag)),
|
|
2419
2479
|
featuredPhotos: import_zod9.z.array(import_zod9.z.string()),
|
|
2420
2480
|
photos: import_zod9.z.array(import_zod9.z.string()),
|
|
2481
|
+
photosWithTags: import_zod9.z.array(
|
|
2482
|
+
import_zod9.z.object({
|
|
2483
|
+
url: import_zod9.z.string(),
|
|
2484
|
+
tag: import_zod9.z.string()
|
|
2485
|
+
})
|
|
2486
|
+
).optional(),
|
|
2421
2487
|
doctors: import_zod9.z.array(import_zod9.z.string()),
|
|
2422
2488
|
doctorsInfo: import_zod9.z.array(doctorInfoSchema),
|
|
2423
2489
|
services: import_zod9.z.array(import_zod9.z.string()),
|
|
@@ -2429,12 +2495,13 @@ var clinicSchema = import_zod9.z.object({
|
|
|
2429
2495
|
count: import_zod9.z.number().min(0)
|
|
2430
2496
|
}).nullable(),
|
|
2431
2497
|
admins: import_zod9.z.array(import_zod9.z.string()),
|
|
2432
|
-
createdAt: import_zod9.z.
|
|
2498
|
+
createdAt: import_zod9.z.instanceof(Date).or(import_zod9.z.instanceof(import_firestore10.Timestamp)),
|
|
2433
2499
|
// Timestamp
|
|
2434
|
-
updatedAt: import_zod9.z.
|
|
2500
|
+
updatedAt: import_zod9.z.instanceof(Date).or(import_zod9.z.instanceof(import_firestore10.Timestamp)),
|
|
2435
2501
|
// Timestamp
|
|
2436
2502
|
isActive: import_zod9.z.boolean(),
|
|
2437
|
-
isVerified: import_zod9.z.boolean()
|
|
2503
|
+
isVerified: import_zod9.z.boolean(),
|
|
2504
|
+
logo: import_zod9.z.string().optional()
|
|
2438
2505
|
});
|
|
2439
2506
|
var createClinicAdminSchema = import_zod9.z.object({
|
|
2440
2507
|
userRef: import_zod9.z.string(),
|
|
@@ -2447,39 +2514,99 @@ var createClinicAdminSchema = import_zod9.z.object({
|
|
|
2447
2514
|
});
|
|
2448
2515
|
var createClinicGroupSchema = import_zod9.z.object({
|
|
2449
2516
|
name: import_zod9.z.string(),
|
|
2450
|
-
description: import_zod9.z.string().
|
|
2517
|
+
description: import_zod9.z.string().optional(),
|
|
2451
2518
|
hqLocation: clinicLocationSchema,
|
|
2452
2519
|
contactInfo: clinicContactInfoSchema,
|
|
2453
2520
|
contactPerson: contactPersonSchema,
|
|
2454
2521
|
ownerId: import_zod9.z.string(),
|
|
2455
|
-
isActive: import_zod9.z.boolean()
|
|
2522
|
+
isActive: import_zod9.z.boolean(),
|
|
2523
|
+
logo: import_zod9.z.string().optional(),
|
|
2524
|
+
practiceType: import_zod9.z.nativeEnum(PracticeType).optional(),
|
|
2525
|
+
languages: import_zod9.z.array(import_zod9.z.nativeEnum(Language)).optional(),
|
|
2526
|
+
subscriptionModel: import_zod9.z.nativeEnum(SubscriptionModel).optional().default("no_subscription" /* NO_SUBSCRIPTION */),
|
|
2527
|
+
calendarSyncEnabled: import_zod9.z.boolean().optional(),
|
|
2528
|
+
autoConfirmAppointments: import_zod9.z.boolean().optional()
|
|
2456
2529
|
});
|
|
2457
2530
|
var createClinicSchema = import_zod9.z.object({
|
|
2458
2531
|
clinicGroupId: import_zod9.z.string(),
|
|
2459
2532
|
name: import_zod9.z.string(),
|
|
2460
|
-
description: import_zod9.z.string().
|
|
2533
|
+
description: import_zod9.z.string().optional(),
|
|
2461
2534
|
location: clinicLocationSchema,
|
|
2462
2535
|
contactInfo: clinicContactInfoSchema,
|
|
2463
2536
|
workingHours: workingHoursSchema,
|
|
2464
2537
|
tags: import_zod9.z.array(import_zod9.z.nativeEnum(ClinicTag)),
|
|
2465
2538
|
photos: import_zod9.z.array(import_zod9.z.string()),
|
|
2539
|
+
photosWithTags: import_zod9.z.array(
|
|
2540
|
+
import_zod9.z.object({
|
|
2541
|
+
url: import_zod9.z.string(),
|
|
2542
|
+
tag: import_zod9.z.string()
|
|
2543
|
+
})
|
|
2544
|
+
).optional(),
|
|
2466
2545
|
doctors: import_zod9.z.array(import_zod9.z.string()),
|
|
2467
2546
|
services: import_zod9.z.array(import_zod9.z.string()),
|
|
2468
2547
|
admins: import_zod9.z.array(import_zod9.z.string()),
|
|
2469
2548
|
isActive: import_zod9.z.boolean(),
|
|
2470
|
-
isVerified: import_zod9.z.boolean()
|
|
2549
|
+
isVerified: import_zod9.z.boolean(),
|
|
2550
|
+
logo: import_zod9.z.string().optional(),
|
|
2551
|
+
featuredPhotos: import_zod9.z.array(import_zod9.z.string()).optional()
|
|
2471
2552
|
});
|
|
2472
2553
|
var createDefaultClinicGroupSchema = import_zod9.z.object({
|
|
2473
2554
|
name: import_zod9.z.string(),
|
|
2474
2555
|
ownerId: import_zod9.z.string(),
|
|
2475
2556
|
contactPerson: contactPersonSchema,
|
|
2476
|
-
contactInfo:
|
|
2477
|
-
email: import_zod9.z.string().email(),
|
|
2478
|
-
phoneNumber: import_zod9.z.string()
|
|
2479
|
-
}),
|
|
2557
|
+
contactInfo: clinicContactInfoSchema,
|
|
2480
2558
|
hqLocation: clinicLocationSchema,
|
|
2481
|
-
isActive: import_zod9.z.boolean()
|
|
2559
|
+
isActive: import_zod9.z.boolean(),
|
|
2560
|
+
logo: import_zod9.z.string().optional(),
|
|
2561
|
+
practiceType: import_zod9.z.nativeEnum(PracticeType).optional(),
|
|
2562
|
+
languages: import_zod9.z.array(import_zod9.z.nativeEnum(Language)).optional(),
|
|
2563
|
+
subscriptionModel: import_zod9.z.nativeEnum(SubscriptionModel).optional().default("no_subscription" /* NO_SUBSCRIPTION */)
|
|
2564
|
+
});
|
|
2565
|
+
var clinicAdminSignupSchema = import_zod9.z.object({
|
|
2566
|
+
email: import_zod9.z.string().email(),
|
|
2567
|
+
password: import_zod9.z.string().min(8),
|
|
2568
|
+
firstName: import_zod9.z.string(),
|
|
2569
|
+
lastName: import_zod9.z.string(),
|
|
2570
|
+
title: import_zod9.z.string(),
|
|
2571
|
+
phoneNumber: import_zod9.z.string(),
|
|
2572
|
+
isCreatingNewGroup: import_zod9.z.boolean(),
|
|
2573
|
+
inviteToken: import_zod9.z.string().optional(),
|
|
2574
|
+
clinicGroupData: import_zod9.z.object({
|
|
2575
|
+
name: import_zod9.z.string(),
|
|
2576
|
+
hqLocation: clinicLocationSchema,
|
|
2577
|
+
logo: import_zod9.z.string().optional(),
|
|
2578
|
+
contactInfo: clinicContactInfoSchema,
|
|
2579
|
+
subscriptionModel: import_zod9.z.nativeEnum(SubscriptionModel).optional().default("no_subscription" /* NO_SUBSCRIPTION */)
|
|
2580
|
+
}).optional()
|
|
2581
|
+
});
|
|
2582
|
+
var clinicGroupSetupSchema = import_zod9.z.object({
|
|
2583
|
+
languages: import_zod9.z.array(import_zod9.z.nativeEnum(Language)),
|
|
2584
|
+
practiceType: import_zod9.z.nativeEnum(PracticeType),
|
|
2585
|
+
description: import_zod9.z.string(),
|
|
2586
|
+
logo: import_zod9.z.string(),
|
|
2587
|
+
calendarSyncEnabled: import_zod9.z.boolean(),
|
|
2588
|
+
autoConfirmAppointments: import_zod9.z.boolean()
|
|
2589
|
+
});
|
|
2590
|
+
var clinicBranchSetupSchema = import_zod9.z.object({
|
|
2591
|
+
name: import_zod9.z.string(),
|
|
2592
|
+
location: clinicLocationSchema,
|
|
2593
|
+
description: import_zod9.z.string().optional(),
|
|
2594
|
+
contactInfo: clinicContactInfoSchema,
|
|
2595
|
+
workingHours: workingHoursSchema,
|
|
2596
|
+
tags: import_zod9.z.array(import_zod9.z.nativeEnum(ClinicTag)),
|
|
2597
|
+
logo: import_zod9.z.string().optional(),
|
|
2598
|
+
photos: import_zod9.z.array(import_zod9.z.string()),
|
|
2599
|
+
photosWithTags: import_zod9.z.array(
|
|
2600
|
+
import_zod9.z.object({
|
|
2601
|
+
url: import_zod9.z.string(),
|
|
2602
|
+
tag: import_zod9.z.string()
|
|
2603
|
+
})
|
|
2604
|
+
).optional(),
|
|
2605
|
+
featuredPhotos: import_zod9.z.array(import_zod9.z.string()).optional()
|
|
2482
2606
|
});
|
|
2607
|
+
var updateClinicAdminSchema = createClinicAdminSchema.partial();
|
|
2608
|
+
var updateClinicGroupSchema = createClinicGroupSchema.partial();
|
|
2609
|
+
var updateClinicSchema = createClinicSchema.partial();
|
|
2483
2610
|
|
|
2484
2611
|
// src/services/clinic/utils/admin.utils.ts
|
|
2485
2612
|
async function createClinicAdmin(db, data, clinicGroupService) {
|
|
@@ -2541,15 +2668,15 @@ async function createClinicAdmin(db, data, clinicGroupService) {
|
|
|
2541
2668
|
contactInfo: validatedData.contactInfo,
|
|
2542
2669
|
roleTitle: validatedData.roleTitle,
|
|
2543
2670
|
isActive: validatedData.isActive,
|
|
2544
|
-
createdAt: (0,
|
|
2545
|
-
updatedAt: (0,
|
|
2671
|
+
createdAt: (0, import_firestore11.serverTimestamp)(),
|
|
2672
|
+
updatedAt: (0, import_firestore11.serverTimestamp)()
|
|
2546
2673
|
};
|
|
2547
2674
|
clinicAdminSchema.parse({
|
|
2548
2675
|
...adminData,
|
|
2549
|
-
createdAt:
|
|
2550
|
-
updatedAt:
|
|
2676
|
+
createdAt: import_firestore11.Timestamp.now(),
|
|
2677
|
+
updatedAt: import_firestore11.Timestamp.now()
|
|
2551
2678
|
});
|
|
2552
|
-
await (0,
|
|
2679
|
+
await (0, import_firestore11.setDoc)((0, import_firestore11.doc)(db, CLINIC_ADMINS_COLLECTION, adminData.id), adminData);
|
|
2553
2680
|
if (clinicGroupId) {
|
|
2554
2681
|
await clinicGroupService.addAdminToGroup(clinicGroupId, adminData.id);
|
|
2555
2682
|
}
|
|
@@ -2564,31 +2691,31 @@ async function checkClinicGroupExists(db, groupId, clinicGroupService) {
|
|
|
2564
2691
|
return !!group;
|
|
2565
2692
|
}
|
|
2566
2693
|
async function getClinicAdmin(db, adminId) {
|
|
2567
|
-
const docRef = (0,
|
|
2568
|
-
const docSnap = await (0,
|
|
2694
|
+
const docRef = (0, import_firestore11.doc)(db, CLINIC_ADMINS_COLLECTION, adminId);
|
|
2695
|
+
const docSnap = await (0, import_firestore11.getDoc)(docRef);
|
|
2569
2696
|
if (docSnap.exists()) {
|
|
2570
2697
|
return docSnap.data();
|
|
2571
2698
|
}
|
|
2572
2699
|
return null;
|
|
2573
2700
|
}
|
|
2574
2701
|
async function getClinicAdminByUserRef(db, userRef) {
|
|
2575
|
-
const q = (0,
|
|
2576
|
-
(0,
|
|
2577
|
-
(0,
|
|
2702
|
+
const q = (0, import_firestore11.query)(
|
|
2703
|
+
(0, import_firestore11.collection)(db, CLINIC_ADMINS_COLLECTION),
|
|
2704
|
+
(0, import_firestore11.where)("userRef", "==", userRef)
|
|
2578
2705
|
);
|
|
2579
|
-
const querySnapshot = await (0,
|
|
2706
|
+
const querySnapshot = await (0, import_firestore11.getDocs)(q);
|
|
2580
2707
|
if (querySnapshot.empty) {
|
|
2581
2708
|
return null;
|
|
2582
2709
|
}
|
|
2583
2710
|
return querySnapshot.docs[0].data();
|
|
2584
2711
|
}
|
|
2585
2712
|
async function getClinicAdminsByGroup(db, clinicGroupId) {
|
|
2586
|
-
const q = (0,
|
|
2587
|
-
(0,
|
|
2588
|
-
(0,
|
|
2713
|
+
const q = (0, import_firestore11.query)(
|
|
2714
|
+
(0, import_firestore11.collection)(db, CLINIC_ADMINS_COLLECTION),
|
|
2715
|
+
(0, import_firestore11.where)("clinicGroupId", "==", clinicGroupId)
|
|
2589
2716
|
);
|
|
2590
|
-
const querySnapshot = await (0,
|
|
2591
|
-
return querySnapshot.docs.map((
|
|
2717
|
+
const querySnapshot = await (0, import_firestore11.getDocs)(q);
|
|
2718
|
+
return querySnapshot.docs.map((doc14) => doc14.data());
|
|
2592
2719
|
}
|
|
2593
2720
|
async function updateClinicAdmin(db, adminId, data) {
|
|
2594
2721
|
const admin = await getClinicAdmin(db, adminId);
|
|
@@ -2597,9 +2724,9 @@ async function updateClinicAdmin(db, adminId, data) {
|
|
|
2597
2724
|
}
|
|
2598
2725
|
const updatedData = {
|
|
2599
2726
|
...data,
|
|
2600
|
-
updatedAt: (0,
|
|
2727
|
+
updatedAt: (0, import_firestore11.serverTimestamp)()
|
|
2601
2728
|
};
|
|
2602
|
-
await (0,
|
|
2729
|
+
await (0, import_firestore11.updateDoc)((0, import_firestore11.doc)(db, CLINIC_ADMINS_COLLECTION, adminId), updatedData);
|
|
2603
2730
|
const updatedAdmin = await getClinicAdmin(db, adminId);
|
|
2604
2731
|
if (!updatedAdmin) {
|
|
2605
2732
|
throw new Error("Failed to retrieve updated admin");
|
|
@@ -2611,7 +2738,7 @@ async function deleteClinicAdmin(db, adminId) {
|
|
|
2611
2738
|
if (!admin) {
|
|
2612
2739
|
throw new Error("Clinic admin not found");
|
|
2613
2740
|
}
|
|
2614
|
-
await (0,
|
|
2741
|
+
await (0, import_firestore11.deleteDoc)((0, import_firestore11.doc)(db, CLINIC_ADMINS_COLLECTION, adminId));
|
|
2615
2742
|
}
|
|
2616
2743
|
async function addClinicToManaged(db, adminId, clinicId, requesterId, clinicService) {
|
|
2617
2744
|
const admin = await getClinicAdmin(db, adminId);
|
|
@@ -2852,14 +2979,14 @@ var ClinicAdminService = class extends BaseService {
|
|
|
2852
2979
|
};
|
|
2853
2980
|
|
|
2854
2981
|
// src/services/practitioner/practitioner.service.ts
|
|
2855
|
-
var
|
|
2982
|
+
var import_firestore13 = require("firebase/firestore");
|
|
2856
2983
|
|
|
2857
2984
|
// src/types/practitioner/index.ts
|
|
2858
2985
|
var PRACTITIONERS_COLLECTION = "practitioners";
|
|
2859
2986
|
|
|
2860
2987
|
// src/validations/practitioner.schema.ts
|
|
2861
2988
|
var import_zod10 = require("zod");
|
|
2862
|
-
var
|
|
2989
|
+
var import_firestore12 = require("firebase/firestore");
|
|
2863
2990
|
|
|
2864
2991
|
// src/backoffice/types/static/certification.types.ts
|
|
2865
2992
|
var CertificationLevel = /* @__PURE__ */ ((CertificationLevel2) => {
|
|
@@ -2892,7 +3019,7 @@ var practitionerBasicInfoSchema = import_zod10.z.object({
|
|
|
2892
3019
|
title: import_zod10.z.string().min(2).max(100),
|
|
2893
3020
|
email: import_zod10.z.string().email(),
|
|
2894
3021
|
phoneNumber: import_zod10.z.string().regex(/^\+?[1-9]\d{1,14}$/, "Invalid phone number"),
|
|
2895
|
-
dateOfBirth: import_zod10.z.instanceof(
|
|
3022
|
+
dateOfBirth: import_zod10.z.instanceof(import_firestore12.Timestamp),
|
|
2896
3023
|
gender: import_zod10.z.enum(["male", "female", "other"]),
|
|
2897
3024
|
profileImageUrl: import_zod10.z.string().url().optional(),
|
|
2898
3025
|
bio: import_zod10.z.string().max(1e3).optional(),
|
|
@@ -2903,8 +3030,8 @@ var practitionerCertificationSchema = import_zod10.z.object({
|
|
|
2903
3030
|
specialties: import_zod10.z.array(import_zod10.z.nativeEnum(CertificationSpecialty)),
|
|
2904
3031
|
licenseNumber: import_zod10.z.string().min(3).max(50),
|
|
2905
3032
|
issuingAuthority: import_zod10.z.string().min(2).max(100),
|
|
2906
|
-
issueDate: import_zod10.z.instanceof(
|
|
2907
|
-
expiryDate: import_zod10.z.instanceof(
|
|
3033
|
+
issueDate: import_zod10.z.instanceof(import_firestore12.Timestamp),
|
|
3034
|
+
expiryDate: import_zod10.z.instanceof(import_firestore12.Timestamp).optional(),
|
|
2908
3035
|
verificationStatus: import_zod10.z.enum(["pending", "verified", "rejected"])
|
|
2909
3036
|
});
|
|
2910
3037
|
var timeSlotSchema = import_zod10.z.object({
|
|
@@ -2921,8 +3048,8 @@ var practitionerWorkingHoursSchema = import_zod10.z.object({
|
|
|
2921
3048
|
friday: timeSlotSchema,
|
|
2922
3049
|
saturday: timeSlotSchema,
|
|
2923
3050
|
sunday: timeSlotSchema,
|
|
2924
|
-
createdAt: import_zod10.z.instanceof(
|
|
2925
|
-
updatedAt: import_zod10.z.instanceof(
|
|
3051
|
+
createdAt: import_zod10.z.instanceof(import_firestore12.Timestamp),
|
|
3052
|
+
updatedAt: import_zod10.z.instanceof(import_firestore12.Timestamp)
|
|
2926
3053
|
});
|
|
2927
3054
|
var practitionerReviewSchema = import_zod10.z.object({
|
|
2928
3055
|
id: import_zod10.z.string().min(1),
|
|
@@ -2931,8 +3058,8 @@ var practitionerReviewSchema = import_zod10.z.object({
|
|
|
2931
3058
|
clinicId: import_zod10.z.string().min(1),
|
|
2932
3059
|
rating: import_zod10.z.number().min(1).max(5),
|
|
2933
3060
|
comment: import_zod10.z.string().max(1e3),
|
|
2934
|
-
createdAt: import_zod10.z.instanceof(
|
|
2935
|
-
updatedAt: import_zod10.z.instanceof(
|
|
3061
|
+
createdAt: import_zod10.z.instanceof(import_firestore12.Timestamp),
|
|
3062
|
+
updatedAt: import_zod10.z.instanceof(import_firestore12.Timestamp),
|
|
2936
3063
|
isVerified: import_zod10.z.boolean()
|
|
2937
3064
|
});
|
|
2938
3065
|
var practitionerClinicProceduresSchema = import_zod10.z.object({
|
|
@@ -2940,8 +3067,8 @@ var practitionerClinicProceduresSchema = import_zod10.z.object({
|
|
|
2940
3067
|
clinicId: import_zod10.z.string().min(1),
|
|
2941
3068
|
procedures: import_zod10.z.array(import_zod10.z.string()).min(1),
|
|
2942
3069
|
isActive: import_zod10.z.boolean(),
|
|
2943
|
-
createdAt: import_zod10.z.instanceof(
|
|
2944
|
-
updatedAt: import_zod10.z.instanceof(
|
|
3070
|
+
createdAt: import_zod10.z.instanceof(import_firestore12.Timestamp),
|
|
3071
|
+
updatedAt: import_zod10.z.instanceof(import_firestore12.Timestamp)
|
|
2945
3072
|
});
|
|
2946
3073
|
var practitionerSchema = import_zod10.z.object({
|
|
2947
3074
|
id: import_zod10.z.string().min(1),
|
|
@@ -2951,8 +3078,8 @@ var practitionerSchema = import_zod10.z.object({
|
|
|
2951
3078
|
clinics: import_zod10.z.array(import_zod10.z.string()),
|
|
2952
3079
|
isActive: import_zod10.z.boolean(),
|
|
2953
3080
|
isVerified: import_zod10.z.boolean(),
|
|
2954
|
-
createdAt: import_zod10.z.instanceof(
|
|
2955
|
-
updatedAt: import_zod10.z.instanceof(
|
|
3081
|
+
createdAt: import_zod10.z.instanceof(import_firestore12.Timestamp),
|
|
3082
|
+
updatedAt: import_zod10.z.instanceof(import_firestore12.Timestamp)
|
|
2956
3083
|
});
|
|
2957
3084
|
var createPractitionerSchema = import_zod10.z.object({
|
|
2958
3085
|
userRef: import_zod10.z.string().min(1),
|
|
@@ -3010,16 +3137,16 @@ var PractitionerService = class extends BaseService {
|
|
|
3010
3137
|
clinics: validatedData.clinics || [],
|
|
3011
3138
|
isActive: validatedData.isActive,
|
|
3012
3139
|
isVerified: validatedData.isVerified,
|
|
3013
|
-
createdAt: (0,
|
|
3014
|
-
updatedAt: (0,
|
|
3140
|
+
createdAt: (0, import_firestore13.serverTimestamp)(),
|
|
3141
|
+
updatedAt: (0, import_firestore13.serverTimestamp)()
|
|
3015
3142
|
};
|
|
3016
3143
|
practitionerSchema.parse({
|
|
3017
3144
|
...practitionerData,
|
|
3018
|
-
createdAt:
|
|
3019
|
-
updatedAt:
|
|
3145
|
+
createdAt: import_firestore13.Timestamp.now(),
|
|
3146
|
+
updatedAt: import_firestore13.Timestamp.now()
|
|
3020
3147
|
});
|
|
3021
|
-
await (0,
|
|
3022
|
-
(0,
|
|
3148
|
+
await (0, import_firestore13.setDoc)(
|
|
3149
|
+
(0, import_firestore13.doc)(this.db, PRACTITIONERS_COLLECTION, practitionerData.id),
|
|
3023
3150
|
practitionerData
|
|
3024
3151
|
);
|
|
3025
3152
|
const savedPractitioner = await this.getPractitioner(practitionerData.id);
|
|
@@ -3038,8 +3165,8 @@ var PractitionerService = class extends BaseService {
|
|
|
3038
3165
|
* Dohvata zdravstvenog radnika po ID-u
|
|
3039
3166
|
*/
|
|
3040
3167
|
async getPractitioner(practitionerId) {
|
|
3041
|
-
const practitionerDoc = await (0,
|
|
3042
|
-
(0,
|
|
3168
|
+
const practitionerDoc = await (0, import_firestore13.getDoc)(
|
|
3169
|
+
(0, import_firestore13.doc)(this.db, PRACTITIONERS_COLLECTION, practitionerId)
|
|
3043
3170
|
);
|
|
3044
3171
|
if (!practitionerDoc.exists()) {
|
|
3045
3172
|
return null;
|
|
@@ -3050,11 +3177,11 @@ var PractitionerService = class extends BaseService {
|
|
|
3050
3177
|
* Dohvata zdravstvenog radnika po User ID-u
|
|
3051
3178
|
*/
|
|
3052
3179
|
async getPractitionerByUserRef(userRef) {
|
|
3053
|
-
const q = (0,
|
|
3054
|
-
(0,
|
|
3055
|
-
(0,
|
|
3180
|
+
const q = (0, import_firestore13.query)(
|
|
3181
|
+
(0, import_firestore13.collection)(this.db, PRACTITIONERS_COLLECTION),
|
|
3182
|
+
(0, import_firestore13.where)("userRef", "==", userRef)
|
|
3056
3183
|
);
|
|
3057
|
-
const querySnapshot = await (0,
|
|
3184
|
+
const querySnapshot = await (0, import_firestore13.getDocs)(q);
|
|
3058
3185
|
if (querySnapshot.empty) {
|
|
3059
3186
|
return null;
|
|
3060
3187
|
}
|
|
@@ -3064,24 +3191,24 @@ var PractitionerService = class extends BaseService {
|
|
|
3064
3191
|
* Dohvata sve zdravstvene radnike za određenu kliniku
|
|
3065
3192
|
*/
|
|
3066
3193
|
async getPractitionersByClinic(clinicId) {
|
|
3067
|
-
const q = (0,
|
|
3068
|
-
(0,
|
|
3069
|
-
(0,
|
|
3070
|
-
(0,
|
|
3194
|
+
const q = (0, import_firestore13.query)(
|
|
3195
|
+
(0, import_firestore13.collection)(this.db, PRACTITIONERS_COLLECTION),
|
|
3196
|
+
(0, import_firestore13.where)("clinics", "array-contains", clinicId),
|
|
3197
|
+
(0, import_firestore13.where)("isActive", "==", true)
|
|
3071
3198
|
);
|
|
3072
|
-
const querySnapshot = await (0,
|
|
3073
|
-
return querySnapshot.docs.map((
|
|
3199
|
+
const querySnapshot = await (0, import_firestore13.getDocs)(q);
|
|
3200
|
+
return querySnapshot.docs.map((doc14) => doc14.data());
|
|
3074
3201
|
}
|
|
3075
3202
|
/**
|
|
3076
3203
|
* Ažurira profil zdravstvenog radnika
|
|
3077
3204
|
*/
|
|
3078
3205
|
async updatePractitioner(practitionerId, data) {
|
|
3079
|
-
const practitionerRef = (0,
|
|
3206
|
+
const practitionerRef = (0, import_firestore13.doc)(
|
|
3080
3207
|
this.db,
|
|
3081
3208
|
PRACTITIONERS_COLLECTION,
|
|
3082
3209
|
practitionerId
|
|
3083
3210
|
);
|
|
3084
|
-
const practitionerDoc = await (0,
|
|
3211
|
+
const practitionerDoc = await (0, import_firestore13.getDoc)(practitionerRef);
|
|
3085
3212
|
if (!practitionerDoc.exists()) {
|
|
3086
3213
|
throw new Error("Practitioner not found");
|
|
3087
3214
|
}
|
|
@@ -3096,14 +3223,14 @@ var PractitionerService = class extends BaseService {
|
|
|
3096
3223
|
}
|
|
3097
3224
|
const updateData = {
|
|
3098
3225
|
...data,
|
|
3099
|
-
updatedAt: (0,
|
|
3226
|
+
updatedAt: (0, import_firestore13.serverTimestamp)()
|
|
3100
3227
|
};
|
|
3101
3228
|
practitionerSchema.parse({
|
|
3102
3229
|
...practitionerDoc.data(),
|
|
3103
3230
|
...data,
|
|
3104
|
-
updatedAt:
|
|
3231
|
+
updatedAt: import_firestore13.Timestamp.now()
|
|
3105
3232
|
});
|
|
3106
|
-
await (0,
|
|
3233
|
+
await (0, import_firestore13.updateDoc)(practitionerRef, updateData);
|
|
3107
3234
|
const updatedPractitioner = await this.getPractitioner(practitionerId);
|
|
3108
3235
|
if (!updatedPractitioner) {
|
|
3109
3236
|
throw new Error("Failed to retrieve updated practitioner profile");
|
|
@@ -3174,7 +3301,7 @@ var PractitionerService = class extends BaseService {
|
|
|
3174
3301
|
if (!practitioner) {
|
|
3175
3302
|
throw new Error("Practitioner not found");
|
|
3176
3303
|
}
|
|
3177
|
-
await (0,
|
|
3304
|
+
await (0, import_firestore13.deleteDoc)((0, import_firestore13.doc)(this.db, PRACTITIONERS_COLLECTION, practitionerId));
|
|
3178
3305
|
}
|
|
3179
3306
|
};
|
|
3180
3307
|
|
|
@@ -3213,17 +3340,17 @@ var UserService = class extends BaseService {
|
|
|
3213
3340
|
email: firebaseUser.email,
|
|
3214
3341
|
roles: roles.length > 0 ? roles : ["patient" /* PATIENT */],
|
|
3215
3342
|
isAnonymous: firebaseUser.isAnonymous,
|
|
3216
|
-
createdAt: (0,
|
|
3217
|
-
updatedAt: (0,
|
|
3218
|
-
lastLoginAt: (0,
|
|
3343
|
+
createdAt: (0, import_firestore14.serverTimestamp)(),
|
|
3344
|
+
updatedAt: (0, import_firestore14.serverTimestamp)(),
|
|
3345
|
+
lastLoginAt: (0, import_firestore14.serverTimestamp)()
|
|
3219
3346
|
};
|
|
3220
|
-
await (0,
|
|
3347
|
+
await (0, import_firestore14.setDoc)((0, import_firestore14.doc)(this.db, USERS_COLLECTION, userData.uid), userData);
|
|
3221
3348
|
const profiles = await this.createProfilesForRoles(
|
|
3222
3349
|
userData.uid,
|
|
3223
3350
|
roles,
|
|
3224
3351
|
options
|
|
3225
3352
|
);
|
|
3226
|
-
await (0,
|
|
3353
|
+
await (0, import_firestore14.updateDoc)((0, import_firestore14.doc)(this.db, USERS_COLLECTION, userData.uid), profiles);
|
|
3227
3354
|
return this.getUserById(userData.uid);
|
|
3228
3355
|
}
|
|
3229
3356
|
/**
|
|
@@ -3298,7 +3425,7 @@ var UserService = class extends BaseService {
|
|
|
3298
3425
|
email: "",
|
|
3299
3426
|
phoneNumber: "",
|
|
3300
3427
|
title: "",
|
|
3301
|
-
dateOfBirth:
|
|
3428
|
+
dateOfBirth: import_firestore14.Timestamp.now(),
|
|
3302
3429
|
gender: "other",
|
|
3303
3430
|
languages: ["Serbian"]
|
|
3304
3431
|
},
|
|
@@ -3307,7 +3434,7 @@ var UserService = class extends BaseService {
|
|
|
3307
3434
|
specialties: [],
|
|
3308
3435
|
licenseNumber: "",
|
|
3309
3436
|
issuingAuthority: "",
|
|
3310
|
-
issueDate:
|
|
3437
|
+
issueDate: import_firestore14.Timestamp.now(),
|
|
3311
3438
|
verificationStatus: "pending"
|
|
3312
3439
|
},
|
|
3313
3440
|
isActive: true,
|
|
@@ -3323,7 +3450,7 @@ var UserService = class extends BaseService {
|
|
|
3323
3450
|
* Dohvata korisnika po ID-u
|
|
3324
3451
|
*/
|
|
3325
3452
|
async getUserById(uid) {
|
|
3326
|
-
const userDoc = await (0,
|
|
3453
|
+
const userDoc = await (0, import_firestore14.getDoc)((0, import_firestore14.doc)(this.db, USERS_COLLECTION, uid));
|
|
3327
3454
|
if (!userDoc.exists()) {
|
|
3328
3455
|
throw USER_ERRORS.NOT_FOUND;
|
|
3329
3456
|
}
|
|
@@ -3334,53 +3461,53 @@ var UserService = class extends BaseService {
|
|
|
3334
3461
|
* Dohvata korisnika po email-u
|
|
3335
3462
|
*/
|
|
3336
3463
|
async getUserByEmail(email) {
|
|
3337
|
-
const usersRef = (0,
|
|
3338
|
-
const q = (0,
|
|
3339
|
-
const querySnapshot = await (0,
|
|
3464
|
+
const usersRef = (0, import_firestore14.collection)(this.db, USERS_COLLECTION);
|
|
3465
|
+
const q = (0, import_firestore14.query)(usersRef, (0, import_firestore14.where)("email", "==", email));
|
|
3466
|
+
const querySnapshot = await (0, import_firestore14.getDocs)(q);
|
|
3340
3467
|
if (querySnapshot.empty) return null;
|
|
3341
3468
|
const userData = querySnapshot.docs[0].data();
|
|
3342
3469
|
return userSchema.parse(userData);
|
|
3343
3470
|
}
|
|
3344
3471
|
async getUsersByRole(role) {
|
|
3345
3472
|
const constraints = [
|
|
3346
|
-
(0,
|
|
3473
|
+
(0, import_firestore14.where)("roles", "array-contains", role)
|
|
3347
3474
|
];
|
|
3348
|
-
const q = (0,
|
|
3349
|
-
const querySnapshot = await (0,
|
|
3350
|
-
const users = querySnapshot.docs.map((
|
|
3475
|
+
const q = (0, import_firestore14.query)((0, import_firestore14.collection)(this.db, USERS_COLLECTION), ...constraints);
|
|
3476
|
+
const querySnapshot = await (0, import_firestore14.getDocs)(q);
|
|
3477
|
+
const users = querySnapshot.docs.map((doc14) => doc14.data());
|
|
3351
3478
|
return Promise.all(users.map((userData) => userSchema.parse(userData)));
|
|
3352
3479
|
}
|
|
3353
3480
|
/**
|
|
3354
3481
|
* Ažurira timestamp poslednjeg logovanja
|
|
3355
3482
|
*/
|
|
3356
3483
|
async updateUserLoginTimestamp(uid) {
|
|
3357
|
-
const userRef = (0,
|
|
3358
|
-
const userDoc = await (0,
|
|
3484
|
+
const userRef = (0, import_firestore14.doc)(this.db, USERS_COLLECTION, uid);
|
|
3485
|
+
const userDoc = await (0, import_firestore14.getDoc)(userRef);
|
|
3359
3486
|
if (!userDoc.exists()) {
|
|
3360
3487
|
throw AUTH_ERRORS.USER_NOT_FOUND;
|
|
3361
3488
|
}
|
|
3362
|
-
await (0,
|
|
3363
|
-
lastLoginAt: (0,
|
|
3364
|
-
updatedAt: (0,
|
|
3489
|
+
await (0, import_firestore14.updateDoc)(userRef, {
|
|
3490
|
+
lastLoginAt: (0, import_firestore14.serverTimestamp)(),
|
|
3491
|
+
updatedAt: (0, import_firestore14.serverTimestamp)()
|
|
3365
3492
|
});
|
|
3366
3493
|
return this.getUserById(uid);
|
|
3367
3494
|
}
|
|
3368
3495
|
async upgradeAnonymousUser(uid, email) {
|
|
3369
|
-
const userRef = (0,
|
|
3370
|
-
const userDoc = await (0,
|
|
3496
|
+
const userRef = (0, import_firestore14.doc)(this.db, USERS_COLLECTION, uid);
|
|
3497
|
+
const userDoc = await (0, import_firestore14.getDoc)(userRef);
|
|
3371
3498
|
if (!userDoc.exists()) {
|
|
3372
3499
|
throw USER_ERRORS.NOT_FOUND;
|
|
3373
3500
|
}
|
|
3374
|
-
await (0,
|
|
3501
|
+
await (0, import_firestore14.updateDoc)(userRef, {
|
|
3375
3502
|
email,
|
|
3376
3503
|
isAnonymous: false,
|
|
3377
|
-
updatedAt: (0,
|
|
3504
|
+
updatedAt: (0, import_firestore14.serverTimestamp)()
|
|
3378
3505
|
});
|
|
3379
3506
|
return this.getUserById(uid);
|
|
3380
3507
|
}
|
|
3381
3508
|
async updateUser(uid, updates) {
|
|
3382
|
-
const userRef = (0,
|
|
3383
|
-
const userDoc = await (0,
|
|
3509
|
+
const userRef = (0, import_firestore14.doc)(this.db, USERS_COLLECTION, uid);
|
|
3510
|
+
const userDoc = await (0, import_firestore14.getDoc)(userRef);
|
|
3384
3511
|
if (!userDoc.exists()) {
|
|
3385
3512
|
throw USER_ERRORS.NOT_FOUND;
|
|
3386
3513
|
}
|
|
@@ -3389,7 +3516,7 @@ var UserService = class extends BaseService {
|
|
|
3389
3516
|
const updatedUser = {
|
|
3390
3517
|
...currentUser,
|
|
3391
3518
|
...updates,
|
|
3392
|
-
updatedAt: (0,
|
|
3519
|
+
updatedAt: (0, import_firestore14.serverTimestamp)()
|
|
3393
3520
|
};
|
|
3394
3521
|
updatedUser.roles.forEach((role) => {
|
|
3395
3522
|
switch (role) {
|
|
@@ -3411,9 +3538,9 @@ var UserService = class extends BaseService {
|
|
|
3411
3538
|
}
|
|
3412
3539
|
});
|
|
3413
3540
|
userSchema.parse(updatedUser);
|
|
3414
|
-
await (0,
|
|
3541
|
+
await (0, import_firestore14.updateDoc)(userRef, {
|
|
3415
3542
|
...updates,
|
|
3416
|
-
updatedAt: (0,
|
|
3543
|
+
updatedAt: (0, import_firestore14.serverTimestamp)()
|
|
3417
3544
|
});
|
|
3418
3545
|
return this.getUserById(uid);
|
|
3419
3546
|
} catch (error) {
|
|
@@ -3430,10 +3557,10 @@ var UserService = class extends BaseService {
|
|
|
3430
3557
|
const user = await this.getUserById(uid);
|
|
3431
3558
|
if (user.roles.includes(role)) return;
|
|
3432
3559
|
const profiles = await this.createProfilesForRoles(uid, [role], options);
|
|
3433
|
-
await (0,
|
|
3560
|
+
await (0, import_firestore14.updateDoc)((0, import_firestore14.doc)(this.db, USERS_COLLECTION, uid), {
|
|
3434
3561
|
roles: [...user.roles, role],
|
|
3435
3562
|
...profiles,
|
|
3436
|
-
updatedAt: (0,
|
|
3563
|
+
updatedAt: (0, import_firestore14.serverTimestamp)()
|
|
3437
3564
|
});
|
|
3438
3565
|
}
|
|
3439
3566
|
/**
|
|
@@ -3465,15 +3592,15 @@ var UserService = class extends BaseService {
|
|
|
3465
3592
|
}
|
|
3466
3593
|
break;
|
|
3467
3594
|
}
|
|
3468
|
-
await (0,
|
|
3595
|
+
await (0, import_firestore14.updateDoc)((0, import_firestore14.doc)(this.db, USERS_COLLECTION, uid), {
|
|
3469
3596
|
roles: user.roles.filter((r) => r !== role),
|
|
3470
|
-
updatedAt: (0,
|
|
3597
|
+
updatedAt: (0, import_firestore14.serverTimestamp)()
|
|
3471
3598
|
});
|
|
3472
3599
|
}
|
|
3473
3600
|
// Delete operations
|
|
3474
3601
|
async deleteUser(uid) {
|
|
3475
|
-
const userRef = (0,
|
|
3476
|
-
const userDoc = await (0,
|
|
3602
|
+
const userRef = (0, import_firestore14.doc)(this.db, USERS_COLLECTION, uid);
|
|
3603
|
+
const userDoc = await (0, import_firestore14.getDoc)(userRef);
|
|
3477
3604
|
if (!userDoc.exists()) {
|
|
3478
3605
|
throw USER_ERRORS.NOT_FOUND;
|
|
3479
3606
|
}
|
|
@@ -3494,486 +3621,350 @@ var UserService = class extends BaseService {
|
|
|
3494
3621
|
userData.adminProfile
|
|
3495
3622
|
);
|
|
3496
3623
|
}
|
|
3497
|
-
await (0,
|
|
3624
|
+
await (0, import_firestore14.deleteDoc)(userRef);
|
|
3498
3625
|
} catch (error) {
|
|
3499
3626
|
throw error;
|
|
3500
3627
|
}
|
|
3501
3628
|
}
|
|
3502
3629
|
};
|
|
3503
3630
|
|
|
3504
|
-
// src/services/
|
|
3505
|
-
var
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3631
|
+
// src/services/clinic/utils/clinic-group.utils.ts
|
|
3632
|
+
var import_firestore15 = require("firebase/firestore");
|
|
3633
|
+
var import_geofire_common2 = require("geofire-common");
|
|
3634
|
+
var import_zod13 = require("zod");
|
|
3635
|
+
function generateId() {
|
|
3636
|
+
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
3637
|
+
const timestamp = Date.now().toString(36);
|
|
3638
|
+
const randomPart = Array.from(
|
|
3639
|
+
{ length: 12 },
|
|
3640
|
+
() => chars.charAt(Math.floor(Math.random() * chars.length))
|
|
3641
|
+
).join("");
|
|
3642
|
+
return `${randomPart}-${timestamp}`;
|
|
3643
|
+
}
|
|
3644
|
+
async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdminService) {
|
|
3645
|
+
const validatedData = createClinicGroupSchema.parse(data);
|
|
3646
|
+
const owner = await clinicAdminService.getClinicAdmin(ownerId);
|
|
3647
|
+
if (!owner) {
|
|
3648
|
+
throw new Error("Owner not found or is not a clinic admin");
|
|
3649
|
+
}
|
|
3650
|
+
if (validatedData.hqLocation) {
|
|
3651
|
+
validatedData.hqLocation.geohash = (0, import_geofire_common2.geohashForLocation)([
|
|
3652
|
+
validatedData.hqLocation.latitude,
|
|
3653
|
+
validatedData.hqLocation.longitude
|
|
3654
|
+
]);
|
|
3655
|
+
}
|
|
3656
|
+
const now = import_firestore15.Timestamp.now();
|
|
3657
|
+
const groupData = {
|
|
3658
|
+
...validatedData,
|
|
3659
|
+
id: (0, import_firestore15.doc)((0, import_firestore15.collection)(db, CLINIC_GROUPS_COLLECTION)).id,
|
|
3660
|
+
description: isDefault ? void 0 : validatedData.description || void 0,
|
|
3661
|
+
hqLocation: {
|
|
3662
|
+
...validatedData.hqLocation,
|
|
3663
|
+
geohash: validatedData.hqLocation.geohash || void 0
|
|
3664
|
+
},
|
|
3665
|
+
contactInfo: {
|
|
3666
|
+
...validatedData.contactInfo,
|
|
3667
|
+
alternativePhoneNumber: isDefault ? void 0 : validatedData.contactInfo.alternativePhoneNumber || void 0,
|
|
3668
|
+
website: isDefault ? void 0 : validatedData.contactInfo.website || void 0
|
|
3669
|
+
},
|
|
3670
|
+
clinics: [],
|
|
3671
|
+
clinicsInfo: [],
|
|
3672
|
+
admins: [ownerId],
|
|
3673
|
+
adminsInfo: [],
|
|
3674
|
+
adminTokens: [],
|
|
3675
|
+
ownerId,
|
|
3676
|
+
createdAt: now,
|
|
3677
|
+
updatedAt: now,
|
|
3678
|
+
isActive: true
|
|
3679
|
+
};
|
|
3680
|
+
try {
|
|
3681
|
+
clinicGroupSchema.parse(groupData);
|
|
3682
|
+
await (0, import_firestore15.setDoc)((0, import_firestore15.doc)(db, CLINIC_GROUPS_COLLECTION, groupData.id), groupData);
|
|
3683
|
+
await clinicAdminService.updateClinicAdmin(ownerId, {
|
|
3684
|
+
clinicGroupId: groupData.id,
|
|
3685
|
+
isGroupOwner: true
|
|
3686
|
+
});
|
|
3687
|
+
return groupData;
|
|
3688
|
+
} catch (error) {
|
|
3689
|
+
if (error instanceof import_zod13.z.ZodError) {
|
|
3690
|
+
throw new Error("Invalid clinic group data: " + error.message);
|
|
3513
3691
|
}
|
|
3514
|
-
|
|
3692
|
+
throw error;
|
|
3515
3693
|
}
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
email,
|
|
3523
|
-
password
|
|
3524
|
-
);
|
|
3525
|
-
return this.userService.createUser(firebaseUser, [initialRole]);
|
|
3694
|
+
}
|
|
3695
|
+
async function getClinicGroup(db, groupId) {
|
|
3696
|
+
const docRef = (0, import_firestore15.doc)(db, CLINIC_GROUPS_COLLECTION, groupId);
|
|
3697
|
+
const docSnap = await (0, import_firestore15.getDoc)(docRef);
|
|
3698
|
+
if (docSnap.exists()) {
|
|
3699
|
+
return docSnap.data();
|
|
3526
3700
|
}
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3701
|
+
return null;
|
|
3702
|
+
}
|
|
3703
|
+
async function getAllActiveGroups(db) {
|
|
3704
|
+
const q = (0, import_firestore15.query)(
|
|
3705
|
+
(0, import_firestore15.collection)(db, CLINIC_GROUPS_COLLECTION),
|
|
3706
|
+
(0, import_firestore15.where)("isActive", "==", true)
|
|
3707
|
+
);
|
|
3708
|
+
const querySnapshot = await (0, import_firestore15.getDocs)(q);
|
|
3709
|
+
return querySnapshot.docs.map((doc14) => doc14.data());
|
|
3710
|
+
}
|
|
3711
|
+
async function updateClinicGroup(db, groupId, data) {
|
|
3712
|
+
const group = await getClinicGroup(db, groupId);
|
|
3713
|
+
if (!group) {
|
|
3714
|
+
throw new Error("Clinic group not found");
|
|
3537
3715
|
}
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3716
|
+
const updatedData = {
|
|
3717
|
+
...data,
|
|
3718
|
+
updatedAt: import_firestore15.Timestamp.now()
|
|
3719
|
+
};
|
|
3720
|
+
await (0, import_firestore15.updateDoc)((0, import_firestore15.doc)(db, CLINIC_GROUPS_COLLECTION, groupId), updatedData);
|
|
3721
|
+
const updatedGroup = await getClinicGroup(db, groupId);
|
|
3722
|
+
if (!updatedGroup) {
|
|
3723
|
+
throw new Error("Failed to retrieve updated clinic group");
|
|
3545
3724
|
}
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
this.googleProvider
|
|
3553
|
-
);
|
|
3554
|
-
return this.userService.getOrCreateUser(firebaseUser);
|
|
3725
|
+
return updatedGroup;
|
|
3726
|
+
}
|
|
3727
|
+
async function addAdminToGroup(db, groupId, adminId) {
|
|
3728
|
+
const group = await getClinicGroup(db, groupId);
|
|
3729
|
+
if (!group) {
|
|
3730
|
+
throw new Error("Clinic group not found");
|
|
3555
3731
|
}
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
*/
|
|
3559
|
-
async signInWithApple() {
|
|
3560
|
-
const provider = new import_auth5.OAuthProvider("apple.com");
|
|
3561
|
-
const { user: firebaseUser } = await (0, import_auth5.signInWithPopup)(this.auth, provider);
|
|
3562
|
-
return this.userService.getOrCreateUser(firebaseUser);
|
|
3732
|
+
if (group.admins.includes(adminId)) {
|
|
3733
|
+
return;
|
|
3563
3734
|
}
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3735
|
+
await updateClinicGroup(db, groupId, {
|
|
3736
|
+
admins: [...group.admins, adminId]
|
|
3737
|
+
});
|
|
3738
|
+
}
|
|
3739
|
+
async function removeAdminFromGroup(db, groupId, adminId) {
|
|
3740
|
+
const group = await getClinicGroup(db, groupId);
|
|
3741
|
+
if (!group) {
|
|
3742
|
+
throw new Error("Clinic group not found");
|
|
3570
3743
|
}
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
*/
|
|
3574
|
-
async signOut() {
|
|
3575
|
-
await (0, import_auth5.signOut)(this.auth);
|
|
3744
|
+
if (group.ownerId === adminId) {
|
|
3745
|
+
throw new Error("Cannot remove the owner from the group");
|
|
3576
3746
|
}
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
*/
|
|
3580
|
-
async getCurrentUser() {
|
|
3581
|
-
const firebaseUser = this.auth.currentUser;
|
|
3582
|
-
if (!firebaseUser) return null;
|
|
3583
|
-
return this.userService.getUserById(firebaseUser.uid);
|
|
3747
|
+
if (!group.admins.includes(adminId)) {
|
|
3748
|
+
return;
|
|
3584
3749
|
}
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3750
|
+
await updateClinicGroup(db, groupId, {
|
|
3751
|
+
admins: group.admins.filter((id) => id !== adminId)
|
|
3752
|
+
});
|
|
3753
|
+
}
|
|
3754
|
+
async function deactivateClinicGroup(db, groupId) {
|
|
3755
|
+
const group = await getClinicGroup(db, groupId);
|
|
3756
|
+
if (!group) {
|
|
3757
|
+
throw new Error("Clinic group not found");
|
|
3590
3758
|
}
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
throw new AuthError(
|
|
3601
|
-
"User is not anonymous",
|
|
3602
|
-
"AUTH/NOT_ANONYMOUS_USER",
|
|
3603
|
-
400
|
|
3604
|
-
);
|
|
3605
|
-
}
|
|
3606
|
-
const credential = import_auth5.EmailAuthProvider.credential(email, password);
|
|
3607
|
-
await (0, import_auth5.linkWithCredential)(currentUser, credential);
|
|
3608
|
-
return await this.userService.upgradeAnonymousUser(
|
|
3609
|
-
currentUser.uid,
|
|
3610
|
-
email
|
|
3611
|
-
);
|
|
3612
|
-
} catch (error) {
|
|
3613
|
-
if (error instanceof import_zod13.z.ZodError) {
|
|
3614
|
-
throw AUTH_ERRORS.VALIDATION_ERROR;
|
|
3615
|
-
}
|
|
3616
|
-
const firebaseError = error;
|
|
3617
|
-
if (firebaseError.code === "auth/email-already-in-use" /* EMAIL_ALREADY_IN_USE */) {
|
|
3618
|
-
throw AUTH_ERRORS.EMAIL_ALREADY_EXISTS;
|
|
3619
|
-
}
|
|
3620
|
-
throw error;
|
|
3621
|
-
}
|
|
3759
|
+
await (0, import_firestore15.updateDoc)((0, import_firestore15.doc)(db, CLINIC_GROUPS_COLLECTION, groupId), {
|
|
3760
|
+
isActive: false,
|
|
3761
|
+
updatedAt: import_firestore15.Timestamp.now()
|
|
3762
|
+
});
|
|
3763
|
+
}
|
|
3764
|
+
async function createAdminToken(db, groupId, creatorAdminId, data) {
|
|
3765
|
+
const group = await getClinicGroup(db, groupId);
|
|
3766
|
+
if (!group) {
|
|
3767
|
+
throw new Error("Clinic group not found");
|
|
3622
3768
|
}
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
*
|
|
3626
|
-
* @throws {AuthError} If the user is not anonymous.
|
|
3627
|
-
* @throws {AuthError} If the user is not authenticated.
|
|
3628
|
-
* @throws {AuthError} If the popup window is closed by the user.
|
|
3629
|
-
* @throws {FirebaseError} If any other Firebase error occurs.
|
|
3630
|
-
*
|
|
3631
|
-
* @returns {Promise<User>} The upgraded user.
|
|
3632
|
-
*/
|
|
3633
|
-
async upgradeAnonymousUserWithGoogle() {
|
|
3634
|
-
try {
|
|
3635
|
-
const currentUser = this.auth.currentUser;
|
|
3636
|
-
if (!currentUser) {
|
|
3637
|
-
throw AUTH_ERRORS.NOT_AUTHENTICATED;
|
|
3638
|
-
}
|
|
3639
|
-
if (!currentUser.isAnonymous) {
|
|
3640
|
-
throw new AuthError(
|
|
3641
|
-
"User is not anonymous",
|
|
3642
|
-
"AUTH/NOT_ANONYMOUS_USER",
|
|
3643
|
-
400
|
|
3644
|
-
);
|
|
3645
|
-
}
|
|
3646
|
-
const userCredential = await (0, import_auth5.signInWithPopup)(
|
|
3647
|
-
this.auth,
|
|
3648
|
-
this.googleProvider
|
|
3649
|
-
);
|
|
3650
|
-
if (!userCredential) throw AUTH_ERRORS.INVALID_CREDENTIAL;
|
|
3651
|
-
return await this.userService.upgradeAnonymousUser(
|
|
3652
|
-
currentUser.uid,
|
|
3653
|
-
userCredential.user.email
|
|
3654
|
-
);
|
|
3655
|
-
} catch (error) {
|
|
3656
|
-
const firebaseError = error;
|
|
3657
|
-
if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
|
|
3658
|
-
throw AUTH_ERRORS.POPUP_CLOSED;
|
|
3659
|
-
}
|
|
3660
|
-
throw error;
|
|
3661
|
-
}
|
|
3769
|
+
if (!group.admins.includes(creatorAdminId)) {
|
|
3770
|
+
throw new Error("Admin does not belong to this clinic group");
|
|
3662
3771
|
}
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
);
|
|
3686
|
-
} catch (error) {
|
|
3687
|
-
const firebaseError = error;
|
|
3688
|
-
if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
|
|
3689
|
-
throw AUTH_ERRORS.POPUP_CLOSED;
|
|
3690
|
-
}
|
|
3691
|
-
throw error;
|
|
3692
|
-
}
|
|
3772
|
+
const now = import_firestore15.Timestamp.now();
|
|
3773
|
+
const expiresInDays = (data == null ? void 0 : data.expiresInDays) || 7;
|
|
3774
|
+
const expiresAt = new import_firestore15.Timestamp(
|
|
3775
|
+
now.seconds + expiresInDays * 24 * 60 * 60,
|
|
3776
|
+
now.nanoseconds
|
|
3777
|
+
);
|
|
3778
|
+
const token = {
|
|
3779
|
+
id: generateId(),
|
|
3780
|
+
token: generateId(),
|
|
3781
|
+
status: "active" /* ACTIVE */,
|
|
3782
|
+
createdAt: now,
|
|
3783
|
+
expiresAt
|
|
3784
|
+
};
|
|
3785
|
+
await updateClinicGroup(db, groupId, {
|
|
3786
|
+
adminTokens: [...group.adminTokens, token]
|
|
3787
|
+
});
|
|
3788
|
+
return token;
|
|
3789
|
+
}
|
|
3790
|
+
async function verifyAndUseAdminToken(db, groupId, token, userRef) {
|
|
3791
|
+
const group = await getClinicGroup(db, groupId);
|
|
3792
|
+
if (!group) {
|
|
3793
|
+
throw new Error("Clinic group not found");
|
|
3693
3794
|
}
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
if (!currentUser) {
|
|
3698
|
-
throw AUTH_ERRORS.NOT_AUTHENTICATED;
|
|
3699
|
-
}
|
|
3700
|
-
if (!currentUser.isAnonymous) {
|
|
3701
|
-
throw new AuthError(
|
|
3702
|
-
"User is not anonymous",
|
|
3703
|
-
"AUTH/NOT_ANONYMOUS_USER",
|
|
3704
|
-
400
|
|
3705
|
-
);
|
|
3706
|
-
}
|
|
3707
|
-
this.appleProvider.addScope("email");
|
|
3708
|
-
this.appleProvider.addScope("name");
|
|
3709
|
-
const userCredential = await (0, import_auth5.signInWithPopup)(
|
|
3710
|
-
this.auth,
|
|
3711
|
-
this.appleProvider
|
|
3712
|
-
);
|
|
3713
|
-
if (!userCredential) throw AUTH_ERRORS.INVALID_CREDENTIAL;
|
|
3714
|
-
return await this.userService.upgradeAnonymousUser(
|
|
3715
|
-
currentUser.uid,
|
|
3716
|
-
userCredential.user.email
|
|
3717
|
-
);
|
|
3718
|
-
} catch (error) {
|
|
3719
|
-
const firebaseError = error;
|
|
3720
|
-
if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
|
|
3721
|
-
throw AUTH_ERRORS.POPUP_CLOSED;
|
|
3722
|
-
}
|
|
3723
|
-
throw error;
|
|
3724
|
-
}
|
|
3795
|
+
const adminToken = group.adminTokens.find((t) => t.token === token);
|
|
3796
|
+
if (!adminToken) {
|
|
3797
|
+
throw new Error("Admin token not found");
|
|
3725
3798
|
}
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
* @param email Email adresa korisnika
|
|
3729
|
-
* @returns Promise koji se razrešava kada je email poslat
|
|
3730
|
-
*/
|
|
3731
|
-
async sendPasswordResetEmail(email) {
|
|
3732
|
-
try {
|
|
3733
|
-
await emailSchema.parseAsync(email);
|
|
3734
|
-
await (0, import_auth5.sendPasswordResetEmail)(this.auth, email);
|
|
3735
|
-
} catch (error) {
|
|
3736
|
-
if (error instanceof import_zod13.z.ZodError) {
|
|
3737
|
-
throw AUTH_ERRORS.VALIDATION_ERROR;
|
|
3738
|
-
}
|
|
3739
|
-
const firebaseError = error;
|
|
3740
|
-
if (firebaseError.code === "auth/user-not-found" /* USER_NOT_FOUND */) {
|
|
3741
|
-
throw AUTH_ERRORS.USER_NOT_FOUND;
|
|
3742
|
-
}
|
|
3743
|
-
throw error;
|
|
3744
|
-
}
|
|
3799
|
+
if (adminToken.status !== "active" /* ACTIVE */) {
|
|
3800
|
+
throw new Error("Admin token is not active");
|
|
3745
3801
|
}
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
const firebaseError = error;
|
|
3756
|
-
if (firebaseError.code === "auth/expired-action-code" /* EXPIRED_ACTION_CODE */) {
|
|
3757
|
-
throw AUTH_ERRORS.EXPIRED_ACTION_CODE;
|
|
3758
|
-
} else if (firebaseError.code === "auth/invalid-action-code" /* INVALID_ACTION_CODE */) {
|
|
3759
|
-
throw AUTH_ERRORS.INVALID_ACTION_CODE;
|
|
3760
|
-
}
|
|
3761
|
-
throw error;
|
|
3762
|
-
}
|
|
3802
|
+
const now = import_firestore15.Timestamp.now();
|
|
3803
|
+
if (adminToken.expiresAt.seconds < now.seconds) {
|
|
3804
|
+
const updatedTokens2 = group.adminTokens.map(
|
|
3805
|
+
(t) => t.id === adminToken.id ? { ...t, status: "expired" /* EXPIRED */ } : t
|
|
3806
|
+
);
|
|
3807
|
+
await updateClinicGroup(db, groupId, {
|
|
3808
|
+
adminTokens: updatedTokens2
|
|
3809
|
+
});
|
|
3810
|
+
throw new Error("Admin token has expired");
|
|
3763
3811
|
}
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
throw AUTH_ERRORS.EXPIRED_ACTION_CODE;
|
|
3781
|
-
} else if (firebaseError.code === "auth/invalid-action-code" /* INVALID_ACTION_CODE */) {
|
|
3782
|
-
throw AUTH_ERRORS.INVALID_ACTION_CODE;
|
|
3783
|
-
} else if (firebaseError.code === "auth/weak-password" /* WEAK_PASSWORD */) {
|
|
3784
|
-
throw AUTH_ERRORS.WEAK_PASSWORD;
|
|
3785
|
-
}
|
|
3786
|
-
throw error;
|
|
3787
|
-
}
|
|
3812
|
+
const updatedTokens = group.adminTokens.map(
|
|
3813
|
+
(t) => t.id === adminToken.id ? {
|
|
3814
|
+
...t,
|
|
3815
|
+
status: "used" /* USED */,
|
|
3816
|
+
usedByUserRef: userRef
|
|
3817
|
+
} : t
|
|
3818
|
+
);
|
|
3819
|
+
await updateClinicGroup(db, groupId, {
|
|
3820
|
+
adminTokens: updatedTokens
|
|
3821
|
+
});
|
|
3822
|
+
return true;
|
|
3823
|
+
}
|
|
3824
|
+
async function deleteAdminToken(db, groupId, tokenId, adminId) {
|
|
3825
|
+
const group = await getClinicGroup(db, groupId);
|
|
3826
|
+
if (!group) {
|
|
3827
|
+
throw new Error("Clinic group not found");
|
|
3788
3828
|
}
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
}
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
NotificationStatus2["CANCELLED"] = "cancelled";
|
|
3808
|
-
NotificationStatus2["PARTIAL_SUCCESS"] = "partialSuccess";
|
|
3809
|
-
return NotificationStatus2;
|
|
3810
|
-
})(NotificationStatus || {});
|
|
3829
|
+
if (!group.admins.includes(adminId)) {
|
|
3830
|
+
throw new Error("Admin does not belong to this clinic group");
|
|
3831
|
+
}
|
|
3832
|
+
const updatedTokens = group.adminTokens.filter((t) => t.id !== tokenId);
|
|
3833
|
+
await updateClinicGroup(db, groupId, {
|
|
3834
|
+
adminTokens: updatedTokens
|
|
3835
|
+
});
|
|
3836
|
+
}
|
|
3837
|
+
async function getActiveAdminTokens(db, groupId, adminId) {
|
|
3838
|
+
const group = await getClinicGroup(db, groupId);
|
|
3839
|
+
if (!group) {
|
|
3840
|
+
throw new Error("Clinic group not found");
|
|
3841
|
+
}
|
|
3842
|
+
if (!group.admins.includes(adminId)) {
|
|
3843
|
+
throw new Error("Admin does not belong to this clinic group");
|
|
3844
|
+
}
|
|
3845
|
+
return group.adminTokens.filter((t) => t.status === "active" /* ACTIVE */);
|
|
3846
|
+
}
|
|
3811
3847
|
|
|
3812
|
-
// src/services/
|
|
3813
|
-
var
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
async createNotification(notification) {
|
|
3818
|
-
const notificationsRef = (0, import_firestore14.collection)(this.db, NOTIFICATIONS_COLLECTION);
|
|
3819
|
-
const now = import_firestore14.Timestamp.now();
|
|
3820
|
-
const notificationData = {
|
|
3821
|
-
...notification,
|
|
3822
|
-
createdAt: now,
|
|
3823
|
-
updatedAt: now,
|
|
3824
|
-
status: "pending" /* PENDING */,
|
|
3825
|
-
isRead: false,
|
|
3826
|
-
userRole: notification.userRole || "patient" /* PATIENT */
|
|
3827
|
-
};
|
|
3828
|
-
const docRef = await (0, import_firestore14.addDoc)(notificationsRef, notificationData);
|
|
3829
|
-
return {
|
|
3830
|
-
...notificationData,
|
|
3831
|
-
id: docRef.id
|
|
3832
|
-
};
|
|
3848
|
+
// src/services/clinic/clinic-group.service.ts
|
|
3849
|
+
var ClinicGroupService = class extends BaseService {
|
|
3850
|
+
constructor(db, auth, app, clinicAdminService) {
|
|
3851
|
+
super(db, auth, app);
|
|
3852
|
+
this.clinicAdminService = clinicAdminService;
|
|
3833
3853
|
}
|
|
3834
3854
|
/**
|
|
3835
|
-
*
|
|
3855
|
+
* Kreira novu grupaciju klinika
|
|
3836
3856
|
*/
|
|
3837
|
-
async
|
|
3838
|
-
|
|
3857
|
+
async createClinicGroup(data, ownerId, isDefault = false) {
|
|
3858
|
+
return createClinicGroup(
|
|
3839
3859
|
this.db,
|
|
3840
|
-
|
|
3841
|
-
|
|
3860
|
+
data,
|
|
3861
|
+
ownerId,
|
|
3862
|
+
isDefault,
|
|
3863
|
+
this.clinicAdminService
|
|
3842
3864
|
);
|
|
3843
|
-
const notificationDoc = await (0, import_firestore14.getDoc)(notificationRef);
|
|
3844
|
-
if (!notificationDoc.exists()) {
|
|
3845
|
-
return null;
|
|
3846
|
-
}
|
|
3847
|
-
return {
|
|
3848
|
-
id: notificationDoc.id,
|
|
3849
|
-
...notificationDoc.data()
|
|
3850
|
-
};
|
|
3851
3865
|
}
|
|
3852
3866
|
/**
|
|
3853
|
-
* Dohvata
|
|
3867
|
+
* Dohvata grupaciju klinika po ID-u
|
|
3868
|
+
*/
|
|
3869
|
+
async getClinicGroup(groupId) {
|
|
3870
|
+
return getClinicGroup(this.db, groupId);
|
|
3871
|
+
}
|
|
3872
|
+
/**
|
|
3873
|
+
* Dohvata sve aktivne grupacije klinika
|
|
3874
|
+
*/
|
|
3875
|
+
async getAllActiveGroups() {
|
|
3876
|
+
return getAllActiveGroups(this.db);
|
|
3877
|
+
}
|
|
3878
|
+
/**
|
|
3879
|
+
* Ažurira grupaciju klinika
|
|
3854
3880
|
*/
|
|
3855
|
-
async
|
|
3856
|
-
|
|
3857
|
-
(0, import_firestore14.collection)(this.db, NOTIFICATIONS_COLLECTION),
|
|
3858
|
-
(0, import_firestore14.where)("userId", "==", userId),
|
|
3859
|
-
(0, import_firestore14.orderBy)("notificationTime", "desc")
|
|
3860
|
-
);
|
|
3861
|
-
const querySnapshot = await (0, import_firestore14.getDocs)(q);
|
|
3862
|
-
return querySnapshot.docs.map((doc13) => ({
|
|
3863
|
-
id: doc13.id,
|
|
3864
|
-
...doc13.data()
|
|
3865
|
-
}));
|
|
3881
|
+
async updateClinicGroup(groupId, data) {
|
|
3882
|
+
return updateClinicGroup(this.db, groupId, data);
|
|
3866
3883
|
}
|
|
3867
3884
|
/**
|
|
3868
|
-
*
|
|
3885
|
+
* Dodaje admina u grupaciju
|
|
3869
3886
|
*/
|
|
3870
|
-
async
|
|
3871
|
-
|
|
3872
|
-
(0, import_firestore14.collection)(this.db, NOTIFICATIONS_COLLECTION),
|
|
3873
|
-
(0, import_firestore14.where)("userId", "==", userId),
|
|
3874
|
-
(0, import_firestore14.where)("isRead", "==", false),
|
|
3875
|
-
(0, import_firestore14.orderBy)("notificationTime", "desc")
|
|
3876
|
-
);
|
|
3877
|
-
const querySnapshot = await (0, import_firestore14.getDocs)(q);
|
|
3878
|
-
return querySnapshot.docs.map((doc13) => ({
|
|
3879
|
-
id: doc13.id,
|
|
3880
|
-
...doc13.data()
|
|
3881
|
-
}));
|
|
3887
|
+
async addAdminToGroup(groupId, adminId) {
|
|
3888
|
+
return addAdminToGroup(this.db, groupId, adminId);
|
|
3882
3889
|
}
|
|
3883
3890
|
/**
|
|
3884
|
-
*
|
|
3891
|
+
* Uklanja admina iz grupacije
|
|
3885
3892
|
*/
|
|
3886
|
-
async
|
|
3887
|
-
|
|
3888
|
-
this.db,
|
|
3889
|
-
NOTIFICATIONS_COLLECTION,
|
|
3890
|
-
notificationId
|
|
3891
|
-
);
|
|
3892
|
-
await (0, import_firestore14.updateDoc)(notificationRef, {
|
|
3893
|
-
isRead: true,
|
|
3894
|
-
updatedAt: import_firestore14.Timestamp.now()
|
|
3895
|
-
});
|
|
3893
|
+
async removeAdminFromGroup(groupId, adminId) {
|
|
3894
|
+
return removeAdminFromGroup(this.db, groupId, adminId);
|
|
3896
3895
|
}
|
|
3897
3896
|
/**
|
|
3898
|
-
*
|
|
3897
|
+
* Deaktivira grupaciju klinika
|
|
3899
3898
|
*/
|
|
3900
|
-
async
|
|
3901
|
-
|
|
3902
|
-
const batch = (0, import_firestore14.writeBatch)(this.db);
|
|
3903
|
-
notifications.forEach((notification) => {
|
|
3904
|
-
const notificationRef = (0, import_firestore14.doc)(
|
|
3905
|
-
this.db,
|
|
3906
|
-
NOTIFICATIONS_COLLECTION,
|
|
3907
|
-
notification.id
|
|
3908
|
-
);
|
|
3909
|
-
batch.update(notificationRef, {
|
|
3910
|
-
isRead: true,
|
|
3911
|
-
updatedAt: import_firestore14.Timestamp.now()
|
|
3912
|
-
});
|
|
3913
|
-
});
|
|
3914
|
-
await batch.commit();
|
|
3899
|
+
async deactivateClinicGroup(groupId) {
|
|
3900
|
+
return deactivateClinicGroup(this.db, groupId);
|
|
3915
3901
|
}
|
|
3916
3902
|
/**
|
|
3917
|
-
*
|
|
3903
|
+
* Sets up additional clinic group information after initial creation
|
|
3904
|
+
*
|
|
3905
|
+
* @param groupId - The ID of the clinic group to set up
|
|
3906
|
+
* @param setupData - The setup data for the clinic group
|
|
3907
|
+
* @returns The updated clinic group
|
|
3918
3908
|
*/
|
|
3919
|
-
async
|
|
3920
|
-
const
|
|
3909
|
+
async setupClinicGroup(groupId, setupData) {
|
|
3910
|
+
const clinicGroup = await this.getClinicGroup(groupId);
|
|
3911
|
+
if (!clinicGroup) {
|
|
3912
|
+
throw new Error(`Clinic group with ID ${groupId} not found`);
|
|
3913
|
+
}
|
|
3914
|
+
const updateData = {
|
|
3915
|
+
languages: setupData.languages,
|
|
3916
|
+
practiceType: setupData.practiceType,
|
|
3917
|
+
description: setupData.description,
|
|
3918
|
+
logo: setupData.logo,
|
|
3919
|
+
calendarSyncEnabled: setupData.calendarSyncEnabled,
|
|
3920
|
+
autoConfirmAppointments: setupData.autoConfirmAppointments
|
|
3921
|
+
};
|
|
3922
|
+
return this.updateClinicGroup(groupId, updateData);
|
|
3923
|
+
}
|
|
3924
|
+
/**
|
|
3925
|
+
* Kreira admin token za grupaciju
|
|
3926
|
+
*/
|
|
3927
|
+
async createAdminToken(groupId, creatorAdminId, data) {
|
|
3928
|
+
return createAdminToken(
|
|
3921
3929
|
this.db,
|
|
3922
|
-
|
|
3923
|
-
|
|
3930
|
+
groupId,
|
|
3931
|
+
creatorAdminId,
|
|
3932
|
+
data
|
|
3924
3933
|
);
|
|
3925
|
-
await (0, import_firestore14.updateDoc)(notificationRef, {
|
|
3926
|
-
status,
|
|
3927
|
-
updatedAt: import_firestore14.Timestamp.now()
|
|
3928
|
-
});
|
|
3929
3934
|
}
|
|
3930
3935
|
/**
|
|
3931
|
-
*
|
|
3936
|
+
* Verifikuje i koristi admin token
|
|
3932
3937
|
*/
|
|
3933
|
-
async
|
|
3934
|
-
|
|
3938
|
+
async verifyAndUseAdminToken(groupId, token, userRef) {
|
|
3939
|
+
return verifyAndUseAdminToken(
|
|
3935
3940
|
this.db,
|
|
3936
|
-
|
|
3937
|
-
|
|
3941
|
+
groupId,
|
|
3942
|
+
token,
|
|
3943
|
+
userRef
|
|
3938
3944
|
);
|
|
3939
|
-
await (0, import_firestore14.deleteDoc)(notificationRef);
|
|
3940
3945
|
}
|
|
3941
3946
|
/**
|
|
3942
|
-
*
|
|
3947
|
+
* Briše admin token
|
|
3943
3948
|
*/
|
|
3944
|
-
async
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3949
|
+
async deleteAdminToken(groupId, tokenId, adminId) {
|
|
3950
|
+
return deleteAdminToken(
|
|
3951
|
+
this.db,
|
|
3952
|
+
groupId,
|
|
3953
|
+
tokenId,
|
|
3954
|
+
adminId
|
|
3950
3955
|
);
|
|
3951
|
-
const querySnapshot = await (0, import_firestore14.getDocs)(q);
|
|
3952
|
-
return querySnapshot.docs.map((doc13) => ({
|
|
3953
|
-
id: doc13.id,
|
|
3954
|
-
...doc13.data()
|
|
3955
|
-
}));
|
|
3956
3956
|
}
|
|
3957
3957
|
/**
|
|
3958
|
-
* Dohvata
|
|
3958
|
+
* Dohvata aktivne admin tokene
|
|
3959
3959
|
*/
|
|
3960
|
-
async
|
|
3961
|
-
|
|
3962
|
-
(0, import_firestore14.collection)(this.db, NOTIFICATIONS_COLLECTION),
|
|
3963
|
-
(0, import_firestore14.where)("appointmentId", "==", appointmentId),
|
|
3964
|
-
(0, import_firestore14.orderBy)("notificationTime", "desc")
|
|
3965
|
-
);
|
|
3966
|
-
const querySnapshot = await (0, import_firestore14.getDocs)(q);
|
|
3967
|
-
return querySnapshot.docs.map((doc13) => ({
|
|
3968
|
-
id: doc13.id,
|
|
3969
|
-
...doc13.data()
|
|
3970
|
-
}));
|
|
3960
|
+
async getActiveAdminTokens(groupId, adminId) {
|
|
3961
|
+
return getActiveAdminTokens(this.db, groupId, adminId);
|
|
3971
3962
|
}
|
|
3972
3963
|
};
|
|
3973
3964
|
|
|
3974
3965
|
// src/services/clinic/utils/clinic.utils.ts
|
|
3975
|
-
var
|
|
3976
|
-
var
|
|
3966
|
+
var import_firestore16 = require("firebase/firestore");
|
|
3967
|
+
var import_geofire_common3 = require("geofire-common");
|
|
3977
3968
|
var import_zod14 = require("zod");
|
|
3978
3969
|
async function createClinic(db, data, creatorAdminId, clinicGroupService, clinicAdminService) {
|
|
3979
3970
|
const validatedData = createClinicSchema.parse(data);
|
|
@@ -3991,15 +3982,15 @@ async function createClinic(db, data, creatorAdminId, clinicGroupService, clinic
|
|
|
3991
3982
|
throw new Error("Clinic group not found");
|
|
3992
3983
|
}
|
|
3993
3984
|
if (validatedData.location) {
|
|
3994
|
-
validatedData.location.geohash = (0,
|
|
3985
|
+
validatedData.location.geohash = (0, import_geofire_common3.geohashForLocation)([
|
|
3995
3986
|
validatedData.location.latitude,
|
|
3996
3987
|
validatedData.location.longitude
|
|
3997
3988
|
]);
|
|
3998
3989
|
}
|
|
3999
|
-
const now =
|
|
3990
|
+
const now = import_firestore16.Timestamp.now();
|
|
4000
3991
|
const clinicData = {
|
|
4001
3992
|
...validatedData,
|
|
4002
|
-
id: (0,
|
|
3993
|
+
id: (0, import_firestore16.doc)((0, import_firestore16.collection)(db, CLINICS_COLLECTION)).id,
|
|
4003
3994
|
description: validatedData.description || void 0,
|
|
4004
3995
|
location: {
|
|
4005
3996
|
...validatedData.location,
|
|
@@ -4028,7 +4019,7 @@ async function createClinic(db, data, creatorAdminId, clinicGroupService, clinic
|
|
|
4028
4019
|
};
|
|
4029
4020
|
try {
|
|
4030
4021
|
clinicSchema.parse(clinicData);
|
|
4031
|
-
await (0,
|
|
4022
|
+
await (0, import_firestore16.setDoc)((0, import_firestore16.doc)(db, CLINICS_COLLECTION, clinicData.id), clinicData);
|
|
4032
4023
|
await clinicGroupService.updateClinicGroup(validatedData.clinicGroupId, {
|
|
4033
4024
|
clinics: [...group.clinics, clinicData.id]
|
|
4034
4025
|
});
|
|
@@ -4042,21 +4033,21 @@ async function createClinic(db, data, creatorAdminId, clinicGroupService, clinic
|
|
|
4042
4033
|
}
|
|
4043
4034
|
}
|
|
4044
4035
|
async function getClinic(db, clinicId) {
|
|
4045
|
-
const docRef = (0,
|
|
4046
|
-
const docSnap = await (0,
|
|
4036
|
+
const docRef = (0, import_firestore16.doc)(db, CLINICS_COLLECTION, clinicId);
|
|
4037
|
+
const docSnap = await (0, import_firestore16.getDoc)(docRef);
|
|
4047
4038
|
if (docSnap.exists()) {
|
|
4048
4039
|
return docSnap.data();
|
|
4049
4040
|
}
|
|
4050
4041
|
return null;
|
|
4051
4042
|
}
|
|
4052
4043
|
async function getClinicsByGroup(db, groupId) {
|
|
4053
|
-
const q = (0,
|
|
4054
|
-
(0,
|
|
4055
|
-
(0,
|
|
4056
|
-
(0,
|
|
4044
|
+
const q = (0, import_firestore16.query)(
|
|
4045
|
+
(0, import_firestore16.collection)(db, CLINICS_COLLECTION),
|
|
4046
|
+
(0, import_firestore16.where)("clinicGroupId", "==", groupId),
|
|
4047
|
+
(0, import_firestore16.where)("isActive", "==", true)
|
|
4057
4048
|
);
|
|
4058
|
-
const querySnapshot = await (0,
|
|
4059
|
-
return querySnapshot.docs.map((
|
|
4049
|
+
const querySnapshot = await (0, import_firestore16.getDocs)(q);
|
|
4050
|
+
return querySnapshot.docs.map((doc14) => doc14.data());
|
|
4060
4051
|
}
|
|
4061
4052
|
async function updateClinic(db, clinicId, data, adminId, clinicAdminService) {
|
|
4062
4053
|
const clinic = await getClinic(db, clinicId);
|
|
@@ -4072,9 +4063,9 @@ async function updateClinic(db, clinicId, data, adminId, clinicAdminService) {
|
|
|
4072
4063
|
}
|
|
4073
4064
|
const updatedData = {
|
|
4074
4065
|
...data,
|
|
4075
|
-
updatedAt:
|
|
4066
|
+
updatedAt: import_firestore16.Timestamp.now()
|
|
4076
4067
|
};
|
|
4077
|
-
await (0,
|
|
4068
|
+
await (0, import_firestore16.updateDoc)((0, import_firestore16.doc)(db, CLINICS_COLLECTION, clinicId), updatedData);
|
|
4078
4069
|
const updatedClinic = await getClinic(db, clinicId);
|
|
4079
4070
|
if (!updatedClinic) {
|
|
4080
4071
|
throw new Error("Failed to retrieve updated clinic");
|
|
@@ -4093,9 +4084,9 @@ async function deactivateClinic(db, clinicId, adminId, clinicAdminService) {
|
|
|
4093
4084
|
if (!admin.isGroupOwner && !admin.clinicsManaged.includes(clinicId)) {
|
|
4094
4085
|
throw new Error("Admin does not have permission to deactivate this clinic");
|
|
4095
4086
|
}
|
|
4096
|
-
await (0,
|
|
4087
|
+
await (0, import_firestore16.updateDoc)((0, import_firestore16.doc)(db, CLINICS_COLLECTION, clinicId), {
|
|
4097
4088
|
isActive: false,
|
|
4098
|
-
updatedAt:
|
|
4089
|
+
updatedAt: import_firestore16.Timestamp.now()
|
|
4099
4090
|
});
|
|
4100
4091
|
}
|
|
4101
4092
|
async function getClinicsByAdmin(db, adminId, options = {}, clinicAdminService, clinicGroupService) {
|
|
@@ -4113,13 +4104,13 @@ async function getClinicsByAdmin(db, adminId, options = {}, clinicAdminService,
|
|
|
4113
4104
|
if (clinicIds.length === 0) {
|
|
4114
4105
|
return [];
|
|
4115
4106
|
}
|
|
4116
|
-
const constraints = [(0,
|
|
4107
|
+
const constraints = [(0, import_firestore16.where)("id", "in", clinicIds)];
|
|
4117
4108
|
if (options.isActive !== void 0) {
|
|
4118
|
-
constraints.push((0,
|
|
4109
|
+
constraints.push((0, import_firestore16.where)("isActive", "==", options.isActive));
|
|
4119
4110
|
}
|
|
4120
|
-
const q = (0,
|
|
4121
|
-
const querySnapshot = await (0,
|
|
4122
|
-
return querySnapshot.docs.map((
|
|
4111
|
+
const q = (0, import_firestore16.query)((0, import_firestore16.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
4112
|
+
const querySnapshot = await (0, import_firestore16.getDocs)(q);
|
|
4113
|
+
return querySnapshot.docs.map((doc14) => doc14.data());
|
|
4123
4114
|
}
|
|
4124
4115
|
async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGroupService) {
|
|
4125
4116
|
return getClinicsByAdmin(
|
|
@@ -4132,15 +4123,15 @@ async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGr
|
|
|
4132
4123
|
}
|
|
4133
4124
|
|
|
4134
4125
|
// src/services/clinic/utils/review.utils.ts
|
|
4135
|
-
var
|
|
4126
|
+
var import_firestore17 = require("firebase/firestore");
|
|
4136
4127
|
async function addReview(db, clinicId, review) {
|
|
4137
4128
|
const clinic = await getClinic(db, clinicId);
|
|
4138
4129
|
if (!clinic) {
|
|
4139
4130
|
throw new Error("Clinic not found");
|
|
4140
4131
|
}
|
|
4141
|
-
const now =
|
|
4132
|
+
const now = import_firestore17.Timestamp.now();
|
|
4142
4133
|
const reviewData = {
|
|
4143
|
-
id: (0,
|
|
4134
|
+
id: (0, import_firestore17.doc)((0, import_firestore17.collection)(db, "clinic_reviews")).id,
|
|
4144
4135
|
clinicId,
|
|
4145
4136
|
patientId: review.patientId,
|
|
4146
4137
|
rating: review.rating,
|
|
@@ -4150,7 +4141,7 @@ async function addReview(db, clinicId, review) {
|
|
|
4150
4141
|
isVerified: false
|
|
4151
4142
|
};
|
|
4152
4143
|
clinicReviewSchema.parse(reviewData);
|
|
4153
|
-
await (0,
|
|
4144
|
+
await (0, import_firestore17.setDoc)((0, import_firestore17.doc)(db, "clinic_reviews", reviewData.id), reviewData);
|
|
4154
4145
|
const newRating = clinic.rating ? {
|
|
4155
4146
|
average: (clinic.rating.average * clinic.rating.count + review.rating) / (clinic.rating.count + 1),
|
|
4156
4147
|
count: clinic.rating.count + 1
|
|
@@ -4240,33 +4231,33 @@ async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminServic
|
|
|
4240
4231
|
}
|
|
4241
4232
|
|
|
4242
4233
|
// src/services/clinic/utils/search.utils.ts
|
|
4243
|
-
var
|
|
4244
|
-
var
|
|
4234
|
+
var import_firestore18 = require("firebase/firestore");
|
|
4235
|
+
var import_geofire_common4 = require("geofire-common");
|
|
4245
4236
|
async function findClinicsInRadius(db, center, radiusInKm, filters) {
|
|
4246
|
-
const bounds = (0,
|
|
4237
|
+
const bounds = (0, import_geofire_common4.geohashQueryBounds)(
|
|
4247
4238
|
[center.latitude, center.longitude],
|
|
4248
4239
|
radiusInKm * 1e3
|
|
4249
4240
|
);
|
|
4250
4241
|
const matchingDocs = [];
|
|
4251
4242
|
for (const b of bounds) {
|
|
4252
4243
|
const constraints = [
|
|
4253
|
-
(0,
|
|
4254
|
-
(0,
|
|
4255
|
-
(0,
|
|
4244
|
+
(0, import_firestore18.where)("location.geohash", ">=", b[0]),
|
|
4245
|
+
(0, import_firestore18.where)("location.geohash", "<=", b[1]),
|
|
4246
|
+
(0, import_firestore18.where)("isActive", "==", true)
|
|
4256
4247
|
];
|
|
4257
4248
|
if (filters == null ? void 0 : filters.services) {
|
|
4258
4249
|
constraints.push(
|
|
4259
|
-
(0,
|
|
4250
|
+
(0, import_firestore18.where)("services", "array-contains-any", filters.services)
|
|
4260
4251
|
);
|
|
4261
4252
|
}
|
|
4262
4253
|
if ((filters == null ? void 0 : filters.tags) && filters.tags.length > 0) {
|
|
4263
|
-
constraints.push((0,
|
|
4254
|
+
constraints.push((0, import_firestore18.where)("tags", "array-contains-any", filters.tags));
|
|
4264
4255
|
}
|
|
4265
|
-
const q = (0,
|
|
4266
|
-
const querySnapshot = await (0,
|
|
4267
|
-
for (const
|
|
4268
|
-
const clinic =
|
|
4269
|
-
const distance = (0,
|
|
4256
|
+
const q = (0, import_firestore18.query)((0, import_firestore18.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
4257
|
+
const querySnapshot = await (0, import_firestore18.getDocs)(q);
|
|
4258
|
+
for (const doc14 of querySnapshot.docs) {
|
|
4259
|
+
const clinic = doc14.data();
|
|
4260
|
+
const distance = (0, import_geofire_common4.distanceBetween)(
|
|
4270
4261
|
[center.latitude, center.longitude],
|
|
4271
4262
|
[clinic.location.latitude, clinic.location.longitude]
|
|
4272
4263
|
);
|
|
@@ -4277,11 +4268,11 @@ async function findClinicsInRadius(db, center, radiusInKm, filters) {
|
|
|
4277
4268
|
}
|
|
4278
4269
|
}
|
|
4279
4270
|
return matchingDocs.sort((a, b) => {
|
|
4280
|
-
const distanceA = (0,
|
|
4271
|
+
const distanceA = (0, import_geofire_common4.distanceBetween)(
|
|
4281
4272
|
[center.latitude, center.longitude],
|
|
4282
4273
|
[a.location.latitude, a.location.longitude]
|
|
4283
4274
|
);
|
|
4284
|
-
const distanceB = (0,
|
|
4275
|
+
const distanceB = (0, import_geofire_common4.distanceBetween)(
|
|
4285
4276
|
[center.latitude, center.longitude],
|
|
4286
4277
|
[b.location.latitude, b.location.longitude]
|
|
4287
4278
|
);
|
|
@@ -4407,326 +4398,638 @@ var ClinicService = class extends BaseService {
|
|
|
4407
4398
|
this.clinicGroupService
|
|
4408
4399
|
);
|
|
4409
4400
|
}
|
|
4401
|
+
/**
|
|
4402
|
+
* Creates a new clinic branch for a clinic group
|
|
4403
|
+
*
|
|
4404
|
+
* @param clinicGroupId - The ID of the clinic group
|
|
4405
|
+
* @param setupData - The setup data for the clinic branch
|
|
4406
|
+
* @param adminId - The ID of the admin creating the branch
|
|
4407
|
+
* @returns The created clinic
|
|
4408
|
+
*/
|
|
4409
|
+
async createClinicBranch(clinicGroupId, setupData, adminId) {
|
|
4410
|
+
const clinicGroup = await this.clinicGroupService.getClinicGroup(
|
|
4411
|
+
clinicGroupId
|
|
4412
|
+
);
|
|
4413
|
+
if (!clinicGroup) {
|
|
4414
|
+
throw new Error(`Clinic group with ID ${clinicGroupId} not found`);
|
|
4415
|
+
}
|
|
4416
|
+
const createClinicData = {
|
|
4417
|
+
clinicGroupId,
|
|
4418
|
+
name: setupData.name,
|
|
4419
|
+
description: setupData.description,
|
|
4420
|
+
location: setupData.location,
|
|
4421
|
+
contactInfo: setupData.contactInfo,
|
|
4422
|
+
workingHours: setupData.workingHours,
|
|
4423
|
+
tags: setupData.tags,
|
|
4424
|
+
photos: setupData.photos,
|
|
4425
|
+
photosWithTags: setupData.photosWithTags,
|
|
4426
|
+
doctors: [],
|
|
4427
|
+
services: [],
|
|
4428
|
+
admins: [adminId],
|
|
4429
|
+
isActive: true,
|
|
4430
|
+
isVerified: false,
|
|
4431
|
+
logo: setupData.logo,
|
|
4432
|
+
featuredPhotos: setupData.featuredPhotos || []
|
|
4433
|
+
};
|
|
4434
|
+
const clinic = await this.createClinic(createClinicData, adminId);
|
|
4435
|
+
return clinic;
|
|
4436
|
+
}
|
|
4410
4437
|
};
|
|
4411
4438
|
|
|
4412
|
-
// src/services/
|
|
4413
|
-
var
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
() => chars.charAt(Math.floor(Math.random() * chars.length))
|
|
4422
|
-
).join("");
|
|
4423
|
-
return `${randomPart}-${timestamp}`;
|
|
4424
|
-
}
|
|
4425
|
-
async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdminService) {
|
|
4426
|
-
const validatedData = createClinicGroupSchema.parse(data);
|
|
4427
|
-
const owner = await clinicAdminService.getClinicAdmin(ownerId);
|
|
4428
|
-
if (!owner) {
|
|
4429
|
-
throw new Error("Owner not found or is not a clinic admin");
|
|
4430
|
-
}
|
|
4431
|
-
if (validatedData.hqLocation) {
|
|
4432
|
-
validatedData.hqLocation.geohash = (0, import_geofire_common4.geohashForLocation)([
|
|
4433
|
-
validatedData.hqLocation.latitude,
|
|
4434
|
-
validatedData.hqLocation.longitude
|
|
4435
|
-
]);
|
|
4436
|
-
}
|
|
4437
|
-
const now = import_firestore18.Timestamp.now();
|
|
4438
|
-
const groupData = {
|
|
4439
|
-
...validatedData,
|
|
4440
|
-
id: (0, import_firestore18.doc)((0, import_firestore18.collection)(db, CLINIC_GROUPS_COLLECTION)).id,
|
|
4441
|
-
description: isDefault ? void 0 : validatedData.description || void 0,
|
|
4442
|
-
hqLocation: {
|
|
4443
|
-
...validatedData.hqLocation,
|
|
4444
|
-
geohash: validatedData.hqLocation.geohash || void 0
|
|
4445
|
-
},
|
|
4446
|
-
contactInfo: {
|
|
4447
|
-
...validatedData.contactInfo,
|
|
4448
|
-
alternativePhoneNumber: isDefault ? void 0 : validatedData.contactInfo.alternativePhoneNumber || void 0,
|
|
4449
|
-
website: isDefault ? void 0 : validatedData.contactInfo.website || void 0
|
|
4450
|
-
},
|
|
4451
|
-
clinics: [],
|
|
4452
|
-
clinicsInfo: [],
|
|
4453
|
-
admins: [ownerId],
|
|
4454
|
-
adminsInfo: [],
|
|
4455
|
-
adminTokens: [],
|
|
4456
|
-
ownerId,
|
|
4457
|
-
createdAt: now,
|
|
4458
|
-
updatedAt: now,
|
|
4459
|
-
isActive: true
|
|
4460
|
-
};
|
|
4461
|
-
try {
|
|
4462
|
-
clinicGroupSchema.parse(groupData);
|
|
4463
|
-
await (0, import_firestore18.setDoc)((0, import_firestore18.doc)(db, CLINIC_GROUPS_COLLECTION, groupData.id), groupData);
|
|
4464
|
-
await clinicAdminService.updateClinicAdmin(ownerId, {
|
|
4465
|
-
clinicGroupId: groupData.id,
|
|
4466
|
-
isGroupOwner: true
|
|
4467
|
-
});
|
|
4468
|
-
return groupData;
|
|
4469
|
-
} catch (error) {
|
|
4470
|
-
if (error instanceof import_zod15.z.ZodError) {
|
|
4471
|
-
throw new Error("Invalid clinic group data: " + error.message);
|
|
4439
|
+
// src/services/auth.service.ts
|
|
4440
|
+
var AuthService = class extends BaseService {
|
|
4441
|
+
constructor(db, auth, app, userService) {
|
|
4442
|
+
super(db, auth, app);
|
|
4443
|
+
this.googleProvider = new import_auth5.GoogleAuthProvider();
|
|
4444
|
+
this.facebookProvider = new import_auth5.FacebookAuthProvider();
|
|
4445
|
+
this.appleProvider = new import_auth5.OAuthProvider("apple.com");
|
|
4446
|
+
if (!userService) {
|
|
4447
|
+
userService = new UserService(db, auth, app);
|
|
4472
4448
|
}
|
|
4473
|
-
|
|
4474
|
-
}
|
|
4475
|
-
}
|
|
4476
|
-
async function getClinicGroup(db, groupId) {
|
|
4477
|
-
const docRef = (0, import_firestore18.doc)(db, CLINIC_GROUPS_COLLECTION, groupId);
|
|
4478
|
-
const docSnap = await (0, import_firestore18.getDoc)(docRef);
|
|
4479
|
-
if (docSnap.exists()) {
|
|
4480
|
-
return docSnap.data();
|
|
4481
|
-
}
|
|
4482
|
-
return null;
|
|
4483
|
-
}
|
|
4484
|
-
async function getAllActiveGroups(db) {
|
|
4485
|
-
const q = (0, import_firestore18.query)(
|
|
4486
|
-
(0, import_firestore18.collection)(db, CLINIC_GROUPS_COLLECTION),
|
|
4487
|
-
(0, import_firestore18.where)("isActive", "==", true)
|
|
4488
|
-
);
|
|
4489
|
-
const querySnapshot = await (0, import_firestore18.getDocs)(q);
|
|
4490
|
-
return querySnapshot.docs.map((doc13) => doc13.data());
|
|
4491
|
-
}
|
|
4492
|
-
async function updateClinicGroup(db, groupId, data) {
|
|
4493
|
-
const group = await getClinicGroup(db, groupId);
|
|
4494
|
-
if (!group) {
|
|
4495
|
-
throw new Error("Clinic group not found");
|
|
4496
|
-
}
|
|
4497
|
-
const updatedData = {
|
|
4498
|
-
...data,
|
|
4499
|
-
updatedAt: import_firestore18.Timestamp.now()
|
|
4500
|
-
};
|
|
4501
|
-
await (0, import_firestore18.updateDoc)((0, import_firestore18.doc)(db, CLINIC_GROUPS_COLLECTION, groupId), updatedData);
|
|
4502
|
-
const updatedGroup = await getClinicGroup(db, groupId);
|
|
4503
|
-
if (!updatedGroup) {
|
|
4504
|
-
throw new Error("Failed to retrieve updated clinic group");
|
|
4505
|
-
}
|
|
4506
|
-
return updatedGroup;
|
|
4507
|
-
}
|
|
4508
|
-
async function addAdminToGroup(db, groupId, adminId) {
|
|
4509
|
-
const group = await getClinicGroup(db, groupId);
|
|
4510
|
-
if (!group) {
|
|
4511
|
-
throw new Error("Clinic group not found");
|
|
4512
|
-
}
|
|
4513
|
-
if (group.admins.includes(adminId)) {
|
|
4514
|
-
return;
|
|
4515
|
-
}
|
|
4516
|
-
await updateClinicGroup(db, groupId, {
|
|
4517
|
-
admins: [...group.admins, adminId]
|
|
4518
|
-
});
|
|
4519
|
-
}
|
|
4520
|
-
async function removeAdminFromGroup(db, groupId, adminId) {
|
|
4521
|
-
const group = await getClinicGroup(db, groupId);
|
|
4522
|
-
if (!group) {
|
|
4523
|
-
throw new Error("Clinic group not found");
|
|
4449
|
+
this.userService = userService;
|
|
4524
4450
|
}
|
|
4525
|
-
|
|
4526
|
-
|
|
4451
|
+
/**
|
|
4452
|
+
* Registruje novog korisnika sa email-om i lozinkom
|
|
4453
|
+
*/
|
|
4454
|
+
async signUp(email, password, initialRole = "patient" /* PATIENT */) {
|
|
4455
|
+
const { user: firebaseUser } = await (0, import_auth5.createUserWithEmailAndPassword)(
|
|
4456
|
+
this.auth,
|
|
4457
|
+
email,
|
|
4458
|
+
password
|
|
4459
|
+
);
|
|
4460
|
+
return this.userService.createUser(firebaseUser, [initialRole]);
|
|
4527
4461
|
}
|
|
4528
|
-
|
|
4529
|
-
|
|
4462
|
+
/**
|
|
4463
|
+
* Registers a new clinic admin user with email and password
|
|
4464
|
+
* Can either create a new clinic group or join an existing one with a token
|
|
4465
|
+
*
|
|
4466
|
+
* @param data - Clinic admin signup data
|
|
4467
|
+
* @returns The created user
|
|
4468
|
+
*/
|
|
4469
|
+
async signUpClinicAdmin(data) {
|
|
4470
|
+
try {
|
|
4471
|
+
await clinicAdminSignupSchema.parseAsync(data);
|
|
4472
|
+
const { user: firebaseUser } = await (0, import_auth5.createUserWithEmailAndPassword)(
|
|
4473
|
+
this.auth,
|
|
4474
|
+
data.email,
|
|
4475
|
+
data.password
|
|
4476
|
+
);
|
|
4477
|
+
const user = await this.userService.createUser(firebaseUser, [
|
|
4478
|
+
"clinic_admin" /* CLINIC_ADMIN */
|
|
4479
|
+
]);
|
|
4480
|
+
const contactPerson = {
|
|
4481
|
+
firstName: data.firstName,
|
|
4482
|
+
lastName: data.lastName,
|
|
4483
|
+
title: data.title,
|
|
4484
|
+
email: data.email,
|
|
4485
|
+
phoneNumber: data.phoneNumber
|
|
4486
|
+
};
|
|
4487
|
+
const clinicAdminService = new ClinicAdminService(
|
|
4488
|
+
this.db,
|
|
4489
|
+
this.auth,
|
|
4490
|
+
this.app
|
|
4491
|
+
);
|
|
4492
|
+
const clinicGroupService = new ClinicGroupService(
|
|
4493
|
+
this.db,
|
|
4494
|
+
this.auth,
|
|
4495
|
+
this.app,
|
|
4496
|
+
clinicAdminService
|
|
4497
|
+
);
|
|
4498
|
+
const clinicService = new ClinicService(
|
|
4499
|
+
this.db,
|
|
4500
|
+
this.auth,
|
|
4501
|
+
this.app,
|
|
4502
|
+
clinicGroupService,
|
|
4503
|
+
clinicAdminService
|
|
4504
|
+
);
|
|
4505
|
+
clinicAdminService.setServices(clinicGroupService, clinicService);
|
|
4506
|
+
if (data.isCreatingNewGroup) {
|
|
4507
|
+
if (!data.clinicGroupData) {
|
|
4508
|
+
throw new Error(
|
|
4509
|
+
"Clinic group data is required when creating a new group"
|
|
4510
|
+
);
|
|
4511
|
+
}
|
|
4512
|
+
const createClinicGroupData = {
|
|
4513
|
+
name: data.clinicGroupData.name,
|
|
4514
|
+
hqLocation: data.clinicGroupData.hqLocation,
|
|
4515
|
+
contactInfo: data.clinicGroupData.contactInfo,
|
|
4516
|
+
contactPerson,
|
|
4517
|
+
ownerId: firebaseUser.uid,
|
|
4518
|
+
isActive: true,
|
|
4519
|
+
logo: data.clinicGroupData.logo,
|
|
4520
|
+
subscriptionModel: data.clinicGroupData.subscriptionModel || "no_subscription" /* NO_SUBSCRIPTION */
|
|
4521
|
+
};
|
|
4522
|
+
await clinicGroupService.createClinicGroup(
|
|
4523
|
+
createClinicGroupData,
|
|
4524
|
+
firebaseUser.uid,
|
|
4525
|
+
true
|
|
4526
|
+
);
|
|
4527
|
+
} else {
|
|
4528
|
+
if (!data.inviteToken) {
|
|
4529
|
+
throw new Error(
|
|
4530
|
+
"Invite token is required when joining an existing group"
|
|
4531
|
+
);
|
|
4532
|
+
}
|
|
4533
|
+
const groupsRef = (0, import_firestore19.collection)(this.db, CLINIC_GROUPS_COLLECTION);
|
|
4534
|
+
const q = (0, import_firestore19.query)(groupsRef);
|
|
4535
|
+
const querySnapshot = await (0, import_firestore19.getDocs)(q);
|
|
4536
|
+
let foundGroup = null;
|
|
4537
|
+
let foundToken = null;
|
|
4538
|
+
for (const docSnapshot of querySnapshot.docs) {
|
|
4539
|
+
const group = docSnapshot.data();
|
|
4540
|
+
const token = group.adminTokens.find(
|
|
4541
|
+
(t) => t.token === data.inviteToken && t.status === "active" /* ACTIVE */ && new Date(t.expiresAt.toDate()) > /* @__PURE__ */ new Date()
|
|
4542
|
+
);
|
|
4543
|
+
if (token) {
|
|
4544
|
+
foundGroup = group;
|
|
4545
|
+
foundToken = token;
|
|
4546
|
+
break;
|
|
4547
|
+
}
|
|
4548
|
+
}
|
|
4549
|
+
if (!foundGroup || !foundToken) {
|
|
4550
|
+
throw new Error("Invalid or expired invite token");
|
|
4551
|
+
}
|
|
4552
|
+
const createClinicAdminData = {
|
|
4553
|
+
userRef: firebaseUser.uid,
|
|
4554
|
+
clinicGroupId: foundGroup.id,
|
|
4555
|
+
isGroupOwner: false,
|
|
4556
|
+
clinicsManaged: [],
|
|
4557
|
+
contactInfo: contactPerson,
|
|
4558
|
+
roleTitle: data.title,
|
|
4559
|
+
isActive: true
|
|
4560
|
+
};
|
|
4561
|
+
await clinicAdminService.createClinicAdmin(createClinicAdminData);
|
|
4562
|
+
await clinicGroupService.verifyAndUseAdminToken(
|
|
4563
|
+
foundGroup.id,
|
|
4564
|
+
data.inviteToken,
|
|
4565
|
+
firebaseUser.uid
|
|
4566
|
+
);
|
|
4567
|
+
}
|
|
4568
|
+
return user;
|
|
4569
|
+
} catch (error) {
|
|
4570
|
+
if (error instanceof import_zod15.z.ZodError) {
|
|
4571
|
+
throw AUTH_ERRORS.VALIDATION_ERROR;
|
|
4572
|
+
}
|
|
4573
|
+
const firebaseError = error;
|
|
4574
|
+
if (firebaseError.code === "auth/email-already-in-use" /* EMAIL_ALREADY_IN_USE */) {
|
|
4575
|
+
throw AUTH_ERRORS.EMAIL_ALREADY_EXISTS;
|
|
4576
|
+
}
|
|
4577
|
+
throw error;
|
|
4578
|
+
}
|
|
4530
4579
|
}
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4580
|
+
/**
|
|
4581
|
+
* Prijavljuje korisnika sa email-om i lozinkom
|
|
4582
|
+
*/
|
|
4583
|
+
async signIn(email, password) {
|
|
4584
|
+
const { user: firebaseUser } = await (0, import_auth5.signInWithEmailAndPassword)(
|
|
4585
|
+
this.auth,
|
|
4586
|
+
email,
|
|
4587
|
+
password
|
|
4588
|
+
);
|
|
4589
|
+
return this.userService.getOrCreateUser(firebaseUser);
|
|
4539
4590
|
}
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
if (!group) {
|
|
4548
|
-
throw new Error("Clinic group not found");
|
|
4591
|
+
/**
|
|
4592
|
+
* Prijavljuje korisnika sa Facebook-om
|
|
4593
|
+
*/
|
|
4594
|
+
async signInWithFacebook() {
|
|
4595
|
+
const provider = new import_auth5.FacebookAuthProvider();
|
|
4596
|
+
const { user: firebaseUser } = await (0, import_auth5.signInWithPopup)(this.auth, provider);
|
|
4597
|
+
return this.userService.getOrCreateUser(firebaseUser);
|
|
4549
4598
|
}
|
|
4550
|
-
|
|
4551
|
-
|
|
4599
|
+
/**
|
|
4600
|
+
* Prijavljuje korisnika sa Google nalogom
|
|
4601
|
+
*/
|
|
4602
|
+
async signInWithGoogle(initialRole = "patient" /* PATIENT */) {
|
|
4603
|
+
const { user: firebaseUser } = await (0, import_auth5.signInWithPopup)(
|
|
4604
|
+
this.auth,
|
|
4605
|
+
this.googleProvider
|
|
4606
|
+
);
|
|
4607
|
+
return this.userService.getOrCreateUser(firebaseUser);
|
|
4552
4608
|
}
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
id: generateId(),
|
|
4561
|
-
token: generateId(),
|
|
4562
|
-
status: "active" /* ACTIVE */,
|
|
4563
|
-
createdAt: now,
|
|
4564
|
-
expiresAt
|
|
4565
|
-
};
|
|
4566
|
-
await updateClinicGroup(db, groupId, {
|
|
4567
|
-
adminTokens: [...group.adminTokens, token]
|
|
4568
|
-
});
|
|
4569
|
-
return token;
|
|
4570
|
-
}
|
|
4571
|
-
async function verifyAndUseAdminToken(db, groupId, token, userRef) {
|
|
4572
|
-
const group = await getClinicGroup(db, groupId);
|
|
4573
|
-
if (!group) {
|
|
4574
|
-
throw new Error("Clinic group not found");
|
|
4609
|
+
/**
|
|
4610
|
+
* Prijavljuje korisnika sa Apple-om
|
|
4611
|
+
*/
|
|
4612
|
+
async signInWithApple() {
|
|
4613
|
+
const provider = new import_auth5.OAuthProvider("apple.com");
|
|
4614
|
+
const { user: firebaseUser } = await (0, import_auth5.signInWithPopup)(this.auth, provider);
|
|
4615
|
+
return this.userService.getOrCreateUser(firebaseUser);
|
|
4575
4616
|
}
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4617
|
+
/**
|
|
4618
|
+
* Prijavljuje korisnika anonimno
|
|
4619
|
+
*/
|
|
4620
|
+
async signInAnonymously() {
|
|
4621
|
+
const { user: firebaseUser } = await (0, import_auth5.signInAnonymously)(this.auth);
|
|
4622
|
+
return this.userService.getOrCreateUser(firebaseUser);
|
|
4579
4623
|
}
|
|
4580
|
-
|
|
4581
|
-
|
|
4624
|
+
/**
|
|
4625
|
+
* Odjavljuje trenutnog korisnika
|
|
4626
|
+
*/
|
|
4627
|
+
async signOut() {
|
|
4628
|
+
await (0, import_auth5.signOut)(this.auth);
|
|
4582
4629
|
}
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
});
|
|
4591
|
-
throw new Error("Admin token has expired");
|
|
4630
|
+
/**
|
|
4631
|
+
* Vraća trenutno prijavljenog korisnika
|
|
4632
|
+
*/
|
|
4633
|
+
async getCurrentUser() {
|
|
4634
|
+
const firebaseUser = this.auth.currentUser;
|
|
4635
|
+
if (!firebaseUser) return null;
|
|
4636
|
+
return this.userService.getUserById(firebaseUser.uid);
|
|
4592
4637
|
}
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
} : t
|
|
4599
|
-
);
|
|
4600
|
-
await updateClinicGroup(db, groupId, {
|
|
4601
|
-
adminTokens: updatedTokens
|
|
4602
|
-
});
|
|
4603
|
-
return true;
|
|
4604
|
-
}
|
|
4605
|
-
async function deleteAdminToken(db, groupId, tokenId, adminId) {
|
|
4606
|
-
const group = await getClinicGroup(db, groupId);
|
|
4607
|
-
if (!group) {
|
|
4608
|
-
throw new Error("Clinic group not found");
|
|
4638
|
+
/**
|
|
4639
|
+
* Registruje callback za promene stanja autentifikacije
|
|
4640
|
+
*/
|
|
4641
|
+
onAuthStateChange(callback) {
|
|
4642
|
+
return (0, import_auth5.onAuthStateChanged)(this.auth, callback);
|
|
4609
4643
|
}
|
|
4610
|
-
|
|
4611
|
-
|
|
4644
|
+
async upgradeAnonymousUser(email, password) {
|
|
4645
|
+
try {
|
|
4646
|
+
await emailSchema.parseAsync(email);
|
|
4647
|
+
await passwordSchema.parseAsync(password);
|
|
4648
|
+
const currentUser = this.auth.currentUser;
|
|
4649
|
+
if (!currentUser) {
|
|
4650
|
+
throw AUTH_ERRORS.NOT_AUTHENTICATED;
|
|
4651
|
+
}
|
|
4652
|
+
if (!currentUser.isAnonymous) {
|
|
4653
|
+
throw new AuthError(
|
|
4654
|
+
"User is not anonymous",
|
|
4655
|
+
"AUTH/NOT_ANONYMOUS_USER",
|
|
4656
|
+
400
|
|
4657
|
+
);
|
|
4658
|
+
}
|
|
4659
|
+
const credential = import_auth5.EmailAuthProvider.credential(email, password);
|
|
4660
|
+
await (0, import_auth5.linkWithCredential)(currentUser, credential);
|
|
4661
|
+
return await this.userService.upgradeAnonymousUser(
|
|
4662
|
+
currentUser.uid,
|
|
4663
|
+
email
|
|
4664
|
+
);
|
|
4665
|
+
} catch (error) {
|
|
4666
|
+
if (error instanceof import_zod15.z.ZodError) {
|
|
4667
|
+
throw AUTH_ERRORS.VALIDATION_ERROR;
|
|
4668
|
+
}
|
|
4669
|
+
const firebaseError = error;
|
|
4670
|
+
if (firebaseError.code === "auth/email-already-in-use" /* EMAIL_ALREADY_IN_USE */) {
|
|
4671
|
+
throw AUTH_ERRORS.EMAIL_ALREADY_EXISTS;
|
|
4672
|
+
}
|
|
4673
|
+
throw error;
|
|
4674
|
+
}
|
|
4612
4675
|
}
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
}
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4676
|
+
/**
|
|
4677
|
+
* Upgrades an anonymous user to a regular user by signing in with a Google account.
|
|
4678
|
+
*
|
|
4679
|
+
* @throws {AuthError} If the user is not anonymous.
|
|
4680
|
+
* @throws {AuthError} If the user is not authenticated.
|
|
4681
|
+
* @throws {AuthError} If the popup window is closed by the user.
|
|
4682
|
+
* @throws {FirebaseError} If any other Firebase error occurs.
|
|
4683
|
+
*
|
|
4684
|
+
* @returns {Promise<User>} The upgraded user.
|
|
4685
|
+
*/
|
|
4686
|
+
async upgradeAnonymousUserWithGoogle() {
|
|
4687
|
+
try {
|
|
4688
|
+
const currentUser = this.auth.currentUser;
|
|
4689
|
+
if (!currentUser) {
|
|
4690
|
+
throw AUTH_ERRORS.NOT_AUTHENTICATED;
|
|
4691
|
+
}
|
|
4692
|
+
if (!currentUser.isAnonymous) {
|
|
4693
|
+
throw new AuthError(
|
|
4694
|
+
"User is not anonymous",
|
|
4695
|
+
"AUTH/NOT_ANONYMOUS_USER",
|
|
4696
|
+
400
|
|
4697
|
+
);
|
|
4698
|
+
}
|
|
4699
|
+
const userCredential = await (0, import_auth5.signInWithPopup)(
|
|
4700
|
+
this.auth,
|
|
4701
|
+
this.googleProvider
|
|
4702
|
+
);
|
|
4703
|
+
if (!userCredential) throw AUTH_ERRORS.INVALID_CREDENTIAL;
|
|
4704
|
+
return await this.userService.upgradeAnonymousUser(
|
|
4705
|
+
currentUser.uid,
|
|
4706
|
+
userCredential.user.email
|
|
4707
|
+
);
|
|
4708
|
+
} catch (error) {
|
|
4709
|
+
const firebaseError = error;
|
|
4710
|
+
if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
|
|
4711
|
+
throw AUTH_ERRORS.POPUP_CLOSED;
|
|
4712
|
+
}
|
|
4713
|
+
throw error;
|
|
4714
|
+
}
|
|
4622
4715
|
}
|
|
4623
|
-
|
|
4624
|
-
|
|
4716
|
+
async upgradeAnonymousUserWithFacebook() {
|
|
4717
|
+
try {
|
|
4718
|
+
const currentUser = this.auth.currentUser;
|
|
4719
|
+
if (!currentUser) {
|
|
4720
|
+
throw AUTH_ERRORS.NOT_AUTHENTICATED;
|
|
4721
|
+
}
|
|
4722
|
+
if (!currentUser.isAnonymous) {
|
|
4723
|
+
throw new AuthError(
|
|
4724
|
+
"User is not anonymous",
|
|
4725
|
+
"AUTH/NOT_ANONYMOUS_USER",
|
|
4726
|
+
400
|
|
4727
|
+
);
|
|
4728
|
+
}
|
|
4729
|
+
this.facebookProvider.addScope("email");
|
|
4730
|
+
const userCredential = await (0, import_auth5.signInWithPopup)(
|
|
4731
|
+
this.auth,
|
|
4732
|
+
this.facebookProvider
|
|
4733
|
+
);
|
|
4734
|
+
if (!userCredential) throw AUTH_ERRORS.INVALID_CREDENTIAL;
|
|
4735
|
+
return await this.userService.upgradeAnonymousUser(
|
|
4736
|
+
currentUser.uid,
|
|
4737
|
+
userCredential.user.email
|
|
4738
|
+
);
|
|
4739
|
+
} catch (error) {
|
|
4740
|
+
const firebaseError = error;
|
|
4741
|
+
if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
|
|
4742
|
+
throw AUTH_ERRORS.POPUP_CLOSED;
|
|
4743
|
+
}
|
|
4744
|
+
throw error;
|
|
4745
|
+
}
|
|
4625
4746
|
}
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4747
|
+
async upgradeAnonymousUserWithApple() {
|
|
4748
|
+
try {
|
|
4749
|
+
const currentUser = this.auth.currentUser;
|
|
4750
|
+
if (!currentUser) {
|
|
4751
|
+
throw AUTH_ERRORS.NOT_AUTHENTICATED;
|
|
4752
|
+
}
|
|
4753
|
+
if (!currentUser.isAnonymous) {
|
|
4754
|
+
throw new AuthError(
|
|
4755
|
+
"User is not anonymous",
|
|
4756
|
+
"AUTH/NOT_ANONYMOUS_USER",
|
|
4757
|
+
400
|
|
4758
|
+
);
|
|
4759
|
+
}
|
|
4760
|
+
this.appleProvider.addScope("email");
|
|
4761
|
+
this.appleProvider.addScope("name");
|
|
4762
|
+
const userCredential = await (0, import_auth5.signInWithPopup)(
|
|
4763
|
+
this.auth,
|
|
4764
|
+
this.appleProvider
|
|
4765
|
+
);
|
|
4766
|
+
if (!userCredential) throw AUTH_ERRORS.INVALID_CREDENTIAL;
|
|
4767
|
+
return await this.userService.upgradeAnonymousUser(
|
|
4768
|
+
currentUser.uid,
|
|
4769
|
+
userCredential.user.email
|
|
4770
|
+
);
|
|
4771
|
+
} catch (error) {
|
|
4772
|
+
const firebaseError = error;
|
|
4773
|
+
if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
|
|
4774
|
+
throw AUTH_ERRORS.POPUP_CLOSED;
|
|
4775
|
+
}
|
|
4776
|
+
throw error;
|
|
4777
|
+
}
|
|
4634
4778
|
}
|
|
4635
4779
|
/**
|
|
4636
|
-
*
|
|
4780
|
+
* Šalje email za resetovanje lozinke korisniku
|
|
4781
|
+
* @param email Email adresa korisnika
|
|
4782
|
+
* @returns Promise koji se razrešava kada je email poslat
|
|
4637
4783
|
*/
|
|
4638
|
-
async
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4784
|
+
async sendPasswordResetEmail(email) {
|
|
4785
|
+
try {
|
|
4786
|
+
await emailSchema.parseAsync(email);
|
|
4787
|
+
await (0, import_auth5.sendPasswordResetEmail)(this.auth, email);
|
|
4788
|
+
} catch (error) {
|
|
4789
|
+
if (error instanceof import_zod15.z.ZodError) {
|
|
4790
|
+
throw AUTH_ERRORS.VALIDATION_ERROR;
|
|
4791
|
+
}
|
|
4792
|
+
const firebaseError = error;
|
|
4793
|
+
if (firebaseError.code === "auth/user-not-found" /* USER_NOT_FOUND */) {
|
|
4794
|
+
throw AUTH_ERRORS.USER_NOT_FOUND;
|
|
4795
|
+
}
|
|
4796
|
+
throw error;
|
|
4797
|
+
}
|
|
4646
4798
|
}
|
|
4647
4799
|
/**
|
|
4648
|
-
*
|
|
4800
|
+
* Verifikuje kod za resetovanje lozinke iz email linka
|
|
4801
|
+
* @param oobCode Kod iz URL-a za resetovanje lozinke
|
|
4802
|
+
* @returns Promise koji se razrešava sa email adresom korisnika ako je kod validan
|
|
4649
4803
|
*/
|
|
4650
|
-
async
|
|
4651
|
-
|
|
4804
|
+
async verifyPasswordResetCode(oobCode) {
|
|
4805
|
+
try {
|
|
4806
|
+
return await (0, import_auth5.verifyPasswordResetCode)(this.auth, oobCode);
|
|
4807
|
+
} catch (error) {
|
|
4808
|
+
const firebaseError = error;
|
|
4809
|
+
if (firebaseError.code === "auth/expired-action-code" /* EXPIRED_ACTION_CODE */) {
|
|
4810
|
+
throw AUTH_ERRORS.EXPIRED_ACTION_CODE;
|
|
4811
|
+
} else if (firebaseError.code === "auth/invalid-action-code" /* INVALID_ACTION_CODE */) {
|
|
4812
|
+
throw AUTH_ERRORS.INVALID_ACTION_CODE;
|
|
4813
|
+
}
|
|
4814
|
+
throw error;
|
|
4815
|
+
}
|
|
4652
4816
|
}
|
|
4653
4817
|
/**
|
|
4654
|
-
*
|
|
4818
|
+
* Potvrđuje resetovanje lozinke i postavlja novu lozinku
|
|
4819
|
+
* @param oobCode Kod iz URL-a za resetovanje lozinke
|
|
4820
|
+
* @param newPassword Nova lozinka
|
|
4821
|
+
* @returns Promise koji se razrešava kada je lozinka promenjena
|
|
4655
4822
|
*/
|
|
4656
|
-
async
|
|
4657
|
-
|
|
4823
|
+
async confirmPasswordReset(oobCode, newPassword) {
|
|
4824
|
+
try {
|
|
4825
|
+
await passwordSchema.parseAsync(newPassword);
|
|
4826
|
+
await (0, import_auth5.confirmPasswordReset)(this.auth, oobCode, newPassword);
|
|
4827
|
+
} catch (error) {
|
|
4828
|
+
if (error instanceof import_zod15.z.ZodError) {
|
|
4829
|
+
throw AUTH_ERRORS.VALIDATION_ERROR;
|
|
4830
|
+
}
|
|
4831
|
+
const firebaseError = error;
|
|
4832
|
+
if (firebaseError.code === "auth/expired-action-code" /* EXPIRED_ACTION_CODE */) {
|
|
4833
|
+
throw AUTH_ERRORS.EXPIRED_ACTION_CODE;
|
|
4834
|
+
} else if (firebaseError.code === "auth/invalid-action-code" /* INVALID_ACTION_CODE */) {
|
|
4835
|
+
throw AUTH_ERRORS.INVALID_ACTION_CODE;
|
|
4836
|
+
} else if (firebaseError.code === "auth/weak-password" /* WEAK_PASSWORD */) {
|
|
4837
|
+
throw AUTH_ERRORS.WEAK_PASSWORD;
|
|
4838
|
+
}
|
|
4839
|
+
throw error;
|
|
4840
|
+
}
|
|
4658
4841
|
}
|
|
4842
|
+
};
|
|
4843
|
+
|
|
4844
|
+
// src/services/notifications/notification.service.ts
|
|
4845
|
+
var import_firestore20 = require("firebase/firestore");
|
|
4846
|
+
|
|
4847
|
+
// src/types/notifications/index.ts
|
|
4848
|
+
var NotificationType = /* @__PURE__ */ ((NotificationType3) => {
|
|
4849
|
+
NotificationType3["PRE_REQUIREMENT"] = "preRequirement";
|
|
4850
|
+
NotificationType3["POST_REQUIREMENT"] = "postRequirement";
|
|
4851
|
+
NotificationType3["APPOINTMENT_REMINDER"] = "appointmentReminder";
|
|
4852
|
+
NotificationType3["APPOINTMENT_NOTIFICATION"] = "appointmentNotification";
|
|
4853
|
+
return NotificationType3;
|
|
4854
|
+
})(NotificationType || {});
|
|
4855
|
+
var NOTIFICATIONS_COLLECTION = "notifications";
|
|
4856
|
+
var NotificationStatus = /* @__PURE__ */ ((NotificationStatus2) => {
|
|
4857
|
+
NotificationStatus2["PENDING"] = "pending";
|
|
4858
|
+
NotificationStatus2["SENT"] = "sent";
|
|
4859
|
+
NotificationStatus2["FAILED"] = "failed";
|
|
4860
|
+
NotificationStatus2["CANCELLED"] = "cancelled";
|
|
4861
|
+
NotificationStatus2["PARTIAL_SUCCESS"] = "partialSuccess";
|
|
4862
|
+
return NotificationStatus2;
|
|
4863
|
+
})(NotificationStatus || {});
|
|
4864
|
+
|
|
4865
|
+
// src/services/notifications/notification.service.ts
|
|
4866
|
+
var NotificationService = class extends BaseService {
|
|
4659
4867
|
/**
|
|
4660
|
-
*
|
|
4868
|
+
* Kreira novu notifikaciju
|
|
4661
4869
|
*/
|
|
4662
|
-
async
|
|
4663
|
-
|
|
4870
|
+
async createNotification(notification) {
|
|
4871
|
+
const notificationsRef = (0, import_firestore20.collection)(this.db, NOTIFICATIONS_COLLECTION);
|
|
4872
|
+
const now = import_firestore20.Timestamp.now();
|
|
4873
|
+
const notificationData = {
|
|
4874
|
+
...notification,
|
|
4875
|
+
createdAt: now,
|
|
4876
|
+
updatedAt: now,
|
|
4877
|
+
status: "pending" /* PENDING */,
|
|
4878
|
+
isRead: false,
|
|
4879
|
+
userRole: notification.userRole || "patient" /* PATIENT */
|
|
4880
|
+
};
|
|
4881
|
+
const docRef = await (0, import_firestore20.addDoc)(notificationsRef, notificationData);
|
|
4882
|
+
return {
|
|
4883
|
+
...notificationData,
|
|
4884
|
+
id: docRef.id
|
|
4885
|
+
};
|
|
4664
4886
|
}
|
|
4665
4887
|
/**
|
|
4666
|
-
*
|
|
4888
|
+
* Dohvata notifikaciju po ID-u
|
|
4667
4889
|
*/
|
|
4668
|
-
async
|
|
4669
|
-
|
|
4890
|
+
async getNotification(notificationId) {
|
|
4891
|
+
const notificationRef = (0, import_firestore20.doc)(
|
|
4892
|
+
this.db,
|
|
4893
|
+
NOTIFICATIONS_COLLECTION,
|
|
4894
|
+
notificationId
|
|
4895
|
+
);
|
|
4896
|
+
const notificationDoc = await (0, import_firestore20.getDoc)(notificationRef);
|
|
4897
|
+
if (!notificationDoc.exists()) {
|
|
4898
|
+
return null;
|
|
4899
|
+
}
|
|
4900
|
+
return {
|
|
4901
|
+
id: notificationDoc.id,
|
|
4902
|
+
...notificationDoc.data()
|
|
4903
|
+
};
|
|
4670
4904
|
}
|
|
4671
4905
|
/**
|
|
4672
|
-
*
|
|
4906
|
+
* Dohvata sve notifikacije za korisnika
|
|
4673
4907
|
*/
|
|
4674
|
-
async
|
|
4675
|
-
|
|
4908
|
+
async getUserNotifications(userId) {
|
|
4909
|
+
const q = (0, import_firestore20.query)(
|
|
4910
|
+
(0, import_firestore20.collection)(this.db, NOTIFICATIONS_COLLECTION),
|
|
4911
|
+
(0, import_firestore20.where)("userId", "==", userId),
|
|
4912
|
+
(0, import_firestore20.orderBy)("notificationTime", "desc")
|
|
4913
|
+
);
|
|
4914
|
+
const querySnapshot = await (0, import_firestore20.getDocs)(q);
|
|
4915
|
+
return querySnapshot.docs.map((doc14) => ({
|
|
4916
|
+
id: doc14.id,
|
|
4917
|
+
...doc14.data()
|
|
4918
|
+
}));
|
|
4676
4919
|
}
|
|
4677
4920
|
/**
|
|
4678
|
-
*
|
|
4921
|
+
* Dohvata nepročitane notifikacije za korisnika
|
|
4679
4922
|
*/
|
|
4680
|
-
async
|
|
4681
|
-
|
|
4923
|
+
async getUnreadNotifications(userId) {
|
|
4924
|
+
const q = (0, import_firestore20.query)(
|
|
4925
|
+
(0, import_firestore20.collection)(this.db, NOTIFICATIONS_COLLECTION),
|
|
4926
|
+
(0, import_firestore20.where)("userId", "==", userId),
|
|
4927
|
+
(0, import_firestore20.where)("isRead", "==", false),
|
|
4928
|
+
(0, import_firestore20.orderBy)("notificationTime", "desc")
|
|
4929
|
+
);
|
|
4930
|
+
const querySnapshot = await (0, import_firestore20.getDocs)(q);
|
|
4931
|
+
return querySnapshot.docs.map((doc14) => ({
|
|
4932
|
+
id: doc14.id,
|
|
4933
|
+
...doc14.data()
|
|
4934
|
+
}));
|
|
4682
4935
|
}
|
|
4683
4936
|
/**
|
|
4684
|
-
*
|
|
4937
|
+
* Označava notifikaciju kao pročitanu
|
|
4685
4938
|
*/
|
|
4686
|
-
async
|
|
4687
|
-
|
|
4939
|
+
async markAsRead(notificationId) {
|
|
4940
|
+
const notificationRef = (0, import_firestore20.doc)(
|
|
4688
4941
|
this.db,
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
data
|
|
4942
|
+
NOTIFICATIONS_COLLECTION,
|
|
4943
|
+
notificationId
|
|
4692
4944
|
);
|
|
4945
|
+
await (0, import_firestore20.updateDoc)(notificationRef, {
|
|
4946
|
+
isRead: true,
|
|
4947
|
+
updatedAt: import_firestore20.Timestamp.now()
|
|
4948
|
+
});
|
|
4693
4949
|
}
|
|
4694
4950
|
/**
|
|
4695
|
-
*
|
|
4951
|
+
* Označava sve notifikacije korisnika kao pročitane
|
|
4696
4952
|
*/
|
|
4697
|
-
async
|
|
4698
|
-
|
|
4953
|
+
async markAllAsRead(userId) {
|
|
4954
|
+
const notifications = await this.getUnreadNotifications(userId);
|
|
4955
|
+
const batch = (0, import_firestore20.writeBatch)(this.db);
|
|
4956
|
+
notifications.forEach((notification) => {
|
|
4957
|
+
const notificationRef = (0, import_firestore20.doc)(
|
|
4958
|
+
this.db,
|
|
4959
|
+
NOTIFICATIONS_COLLECTION,
|
|
4960
|
+
notification.id
|
|
4961
|
+
);
|
|
4962
|
+
batch.update(notificationRef, {
|
|
4963
|
+
isRead: true,
|
|
4964
|
+
updatedAt: import_firestore20.Timestamp.now()
|
|
4965
|
+
});
|
|
4966
|
+
});
|
|
4967
|
+
await batch.commit();
|
|
4968
|
+
}
|
|
4969
|
+
/**
|
|
4970
|
+
* Ažurira status notifikacije
|
|
4971
|
+
*/
|
|
4972
|
+
async updateNotificationStatus(notificationId, status) {
|
|
4973
|
+
const notificationRef = (0, import_firestore20.doc)(
|
|
4699
4974
|
this.db,
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
userRef
|
|
4975
|
+
NOTIFICATIONS_COLLECTION,
|
|
4976
|
+
notificationId
|
|
4703
4977
|
);
|
|
4978
|
+
await (0, import_firestore20.updateDoc)(notificationRef, {
|
|
4979
|
+
status,
|
|
4980
|
+
updatedAt: import_firestore20.Timestamp.now()
|
|
4981
|
+
});
|
|
4704
4982
|
}
|
|
4705
4983
|
/**
|
|
4706
|
-
* Briše
|
|
4984
|
+
* Briše notifikaciju
|
|
4707
4985
|
*/
|
|
4708
|
-
async
|
|
4709
|
-
|
|
4986
|
+
async deleteNotification(notificationId) {
|
|
4987
|
+
const notificationRef = (0, import_firestore20.doc)(
|
|
4710
4988
|
this.db,
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
adminId
|
|
4989
|
+
NOTIFICATIONS_COLLECTION,
|
|
4990
|
+
notificationId
|
|
4714
4991
|
);
|
|
4992
|
+
await (0, import_firestore20.deleteDoc)(notificationRef);
|
|
4715
4993
|
}
|
|
4716
4994
|
/**
|
|
4717
|
-
* Dohvata
|
|
4995
|
+
* Dohvata notifikacije po tipu
|
|
4718
4996
|
*/
|
|
4719
|
-
async
|
|
4720
|
-
|
|
4997
|
+
async getNotificationsByType(userId, type) {
|
|
4998
|
+
const q = (0, import_firestore20.query)(
|
|
4999
|
+
(0, import_firestore20.collection)(this.db, NOTIFICATIONS_COLLECTION),
|
|
5000
|
+
(0, import_firestore20.where)("userId", "==", userId),
|
|
5001
|
+
(0, import_firestore20.where)("notificationType", "==", type),
|
|
5002
|
+
(0, import_firestore20.orderBy)("notificationTime", "desc")
|
|
5003
|
+
);
|
|
5004
|
+
const querySnapshot = await (0, import_firestore20.getDocs)(q);
|
|
5005
|
+
return querySnapshot.docs.map((doc14) => ({
|
|
5006
|
+
id: doc14.id,
|
|
5007
|
+
...doc14.data()
|
|
5008
|
+
}));
|
|
5009
|
+
}
|
|
5010
|
+
/**
|
|
5011
|
+
* Dohvata notifikacije za određeni termin
|
|
5012
|
+
*/
|
|
5013
|
+
async getAppointmentNotifications(appointmentId) {
|
|
5014
|
+
const q = (0, import_firestore20.query)(
|
|
5015
|
+
(0, import_firestore20.collection)(this.db, NOTIFICATIONS_COLLECTION),
|
|
5016
|
+
(0, import_firestore20.where)("appointmentId", "==", appointmentId),
|
|
5017
|
+
(0, import_firestore20.orderBy)("notificationTime", "desc")
|
|
5018
|
+
);
|
|
5019
|
+
const querySnapshot = await (0, import_firestore20.getDocs)(q);
|
|
5020
|
+
return querySnapshot.docs.map((doc14) => ({
|
|
5021
|
+
id: doc14.id,
|
|
5022
|
+
...doc14.data()
|
|
5023
|
+
}));
|
|
4721
5024
|
}
|
|
4722
5025
|
};
|
|
4723
5026
|
|
|
4724
5027
|
// src/services/documentation-templates/documentation-template.service.ts
|
|
4725
|
-
var
|
|
5028
|
+
var import_firestore21 = require("firebase/firestore");
|
|
4726
5029
|
var DocumentationTemplateService = class extends BaseService {
|
|
4727
5030
|
constructor() {
|
|
4728
5031
|
super(...arguments);
|
|
4729
|
-
this.collectionRef = (0,
|
|
5032
|
+
this.collectionRef = (0, import_firestore21.collection)(
|
|
4730
5033
|
this.db,
|
|
4731
5034
|
DOCUMENTATION_TEMPLATES_COLLECTION
|
|
4732
5035
|
);
|
|
@@ -4757,8 +5060,8 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
4757
5060
|
isActive: true,
|
|
4758
5061
|
tags: validatedData.tags || []
|
|
4759
5062
|
};
|
|
4760
|
-
const docRef = (0,
|
|
4761
|
-
await (0,
|
|
5063
|
+
const docRef = (0, import_firestore21.doc)(this.collectionRef, templateId);
|
|
5064
|
+
await (0, import_firestore21.setDoc)(docRef, template);
|
|
4762
5065
|
return template;
|
|
4763
5066
|
}
|
|
4764
5067
|
/**
|
|
@@ -4767,8 +5070,8 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
4767
5070
|
* @returns The template or null if not found
|
|
4768
5071
|
*/
|
|
4769
5072
|
async getTemplateById(templateId) {
|
|
4770
|
-
const docRef = (0,
|
|
4771
|
-
const docSnap = await (0,
|
|
5073
|
+
const docRef = (0, import_firestore21.doc)(this.collectionRef, templateId);
|
|
5074
|
+
const docSnap = await (0, import_firestore21.getDoc)(docRef);
|
|
4772
5075
|
if (!docSnap.exists()) {
|
|
4773
5076
|
return null;
|
|
4774
5077
|
}
|
|
@@ -4799,8 +5102,8 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
4799
5102
|
updatedAt: Date.now(),
|
|
4800
5103
|
version: template.version + 1
|
|
4801
5104
|
};
|
|
4802
|
-
const docRef = (0,
|
|
4803
|
-
await (0,
|
|
5105
|
+
const docRef = (0, import_firestore21.doc)(this.collectionRef, templateId);
|
|
5106
|
+
await (0, import_firestore21.updateDoc)(docRef, updateData);
|
|
4804
5107
|
return {
|
|
4805
5108
|
...template,
|
|
4806
5109
|
...updateData
|
|
@@ -4811,8 +5114,8 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
4811
5114
|
* @param templateId - ID of the template to delete
|
|
4812
5115
|
*/
|
|
4813
5116
|
async deleteTemplate(templateId) {
|
|
4814
|
-
const docRef = (0,
|
|
4815
|
-
await (0,
|
|
5117
|
+
const docRef = (0, import_firestore21.doc)(this.collectionRef, templateId);
|
|
5118
|
+
await (0, import_firestore21.deleteDoc)(docRef);
|
|
4816
5119
|
}
|
|
4817
5120
|
/**
|
|
4818
5121
|
* Get all active templates
|
|
@@ -4821,21 +5124,21 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
4821
5124
|
* @returns Array of templates and the last document for pagination
|
|
4822
5125
|
*/
|
|
4823
5126
|
async getActiveTemplates(pageSize = 20, lastDoc) {
|
|
4824
|
-
let q = (0,
|
|
5127
|
+
let q = (0, import_firestore21.query)(
|
|
4825
5128
|
this.collectionRef,
|
|
4826
|
-
(0,
|
|
4827
|
-
(0,
|
|
4828
|
-
(0,
|
|
5129
|
+
(0, import_firestore21.where)("isActive", "==", true),
|
|
5130
|
+
(0, import_firestore21.orderBy)("updatedAt", "desc"),
|
|
5131
|
+
(0, import_firestore21.limit)(pageSize)
|
|
4829
5132
|
);
|
|
4830
5133
|
if (lastDoc) {
|
|
4831
|
-
q = (0,
|
|
5134
|
+
q = (0, import_firestore21.query)(q, (0, import_firestore21.startAfter)(lastDoc));
|
|
4832
5135
|
}
|
|
4833
|
-
const querySnapshot = await (0,
|
|
5136
|
+
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
4834
5137
|
const templates = [];
|
|
4835
5138
|
let lastVisible = null;
|
|
4836
|
-
querySnapshot.forEach((
|
|
4837
|
-
templates.push(
|
|
4838
|
-
lastVisible =
|
|
5139
|
+
querySnapshot.forEach((doc14) => {
|
|
5140
|
+
templates.push(doc14.data());
|
|
5141
|
+
lastVisible = doc14;
|
|
4839
5142
|
});
|
|
4840
5143
|
return {
|
|
4841
5144
|
templates,
|
|
@@ -4850,22 +5153,22 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
4850
5153
|
* @returns Array of templates and the last document for pagination
|
|
4851
5154
|
*/
|
|
4852
5155
|
async getTemplatesByTags(tags, pageSize = 20, lastDoc) {
|
|
4853
|
-
let q = (0,
|
|
5156
|
+
let q = (0, import_firestore21.query)(
|
|
4854
5157
|
this.collectionRef,
|
|
4855
|
-
(0,
|
|
4856
|
-
(0,
|
|
4857
|
-
(0,
|
|
4858
|
-
(0,
|
|
5158
|
+
(0, import_firestore21.where)("isActive", "==", true),
|
|
5159
|
+
(0, import_firestore21.where)("tags", "array-contains-any", tags),
|
|
5160
|
+
(0, import_firestore21.orderBy)("updatedAt", "desc"),
|
|
5161
|
+
(0, import_firestore21.limit)(pageSize)
|
|
4859
5162
|
);
|
|
4860
5163
|
if (lastDoc) {
|
|
4861
|
-
q = (0,
|
|
5164
|
+
q = (0, import_firestore21.query)(q, (0, import_firestore21.startAfter)(lastDoc));
|
|
4862
5165
|
}
|
|
4863
|
-
const querySnapshot = await (0,
|
|
5166
|
+
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
4864
5167
|
const templates = [];
|
|
4865
5168
|
let lastVisible = null;
|
|
4866
|
-
querySnapshot.forEach((
|
|
4867
|
-
templates.push(
|
|
4868
|
-
lastVisible =
|
|
5169
|
+
querySnapshot.forEach((doc14) => {
|
|
5170
|
+
templates.push(doc14.data());
|
|
5171
|
+
lastVisible = doc14;
|
|
4869
5172
|
});
|
|
4870
5173
|
return {
|
|
4871
5174
|
templates,
|
|
@@ -4880,21 +5183,21 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
4880
5183
|
* @returns Array of templates and the last document for pagination
|
|
4881
5184
|
*/
|
|
4882
5185
|
async getTemplatesByCreator(userId, pageSize = 20, lastDoc) {
|
|
4883
|
-
let q = (0,
|
|
5186
|
+
let q = (0, import_firestore21.query)(
|
|
4884
5187
|
this.collectionRef,
|
|
4885
|
-
(0,
|
|
4886
|
-
(0,
|
|
4887
|
-
(0,
|
|
5188
|
+
(0, import_firestore21.where)("createdBy", "==", userId),
|
|
5189
|
+
(0, import_firestore21.orderBy)("updatedAt", "desc"),
|
|
5190
|
+
(0, import_firestore21.limit)(pageSize)
|
|
4888
5191
|
);
|
|
4889
5192
|
if (lastDoc) {
|
|
4890
|
-
q = (0,
|
|
5193
|
+
q = (0, import_firestore21.query)(q, (0, import_firestore21.startAfter)(lastDoc));
|
|
4891
5194
|
}
|
|
4892
|
-
const querySnapshot = await (0,
|
|
5195
|
+
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
4893
5196
|
const templates = [];
|
|
4894
5197
|
let lastVisible = null;
|
|
4895
|
-
querySnapshot.forEach((
|
|
4896
|
-
templates.push(
|
|
4897
|
-
lastVisible =
|
|
5198
|
+
querySnapshot.forEach((doc14) => {
|
|
5199
|
+
templates.push(doc14.data());
|
|
5200
|
+
lastVisible = doc14;
|
|
4898
5201
|
});
|
|
4899
5202
|
return {
|
|
4900
5203
|
templates,
|
|
@@ -4904,11 +5207,11 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
4904
5207
|
};
|
|
4905
5208
|
|
|
4906
5209
|
// src/services/documentation-templates/filled-document.service.ts
|
|
4907
|
-
var
|
|
5210
|
+
var import_firestore22 = require("firebase/firestore");
|
|
4908
5211
|
var FilledDocumentService = class extends BaseService {
|
|
4909
5212
|
constructor(...args) {
|
|
4910
5213
|
super(...args);
|
|
4911
|
-
this.collectionRef = (0,
|
|
5214
|
+
this.collectionRef = (0, import_firestore22.collection)(
|
|
4912
5215
|
this.db,
|
|
4913
5216
|
FILLED_DOCUMENTS_COLLECTION
|
|
4914
5217
|
);
|
|
@@ -4941,8 +5244,8 @@ var FilledDocumentService = class extends BaseService {
|
|
|
4941
5244
|
values: {},
|
|
4942
5245
|
status: "draft" /* DRAFT */
|
|
4943
5246
|
};
|
|
4944
|
-
const docRef = (0,
|
|
4945
|
-
await (0,
|
|
5247
|
+
const docRef = (0, import_firestore22.doc)(this.collectionRef, documentId);
|
|
5248
|
+
await (0, import_firestore22.setDoc)(docRef, filledDocument);
|
|
4946
5249
|
return filledDocument;
|
|
4947
5250
|
}
|
|
4948
5251
|
/**
|
|
@@ -4951,8 +5254,8 @@ var FilledDocumentService = class extends BaseService {
|
|
|
4951
5254
|
* @returns The filled document or null if not found
|
|
4952
5255
|
*/
|
|
4953
5256
|
async getFilledDocumentById(documentId) {
|
|
4954
|
-
const docRef = (0,
|
|
4955
|
-
const docSnap = await (0,
|
|
5257
|
+
const docRef = (0, import_firestore22.doc)(this.collectionRef, documentId);
|
|
5258
|
+
const docSnap = await (0, import_firestore22.getDoc)(docRef);
|
|
4956
5259
|
if (!docSnap.exists()) {
|
|
4957
5260
|
return null;
|
|
4958
5261
|
}
|
|
@@ -4980,8 +5283,8 @@ var FilledDocumentService = class extends BaseService {
|
|
|
4980
5283
|
if (status) {
|
|
4981
5284
|
updateData.status = status;
|
|
4982
5285
|
}
|
|
4983
|
-
const docRef = (0,
|
|
4984
|
-
await (0,
|
|
5286
|
+
const docRef = (0, import_firestore22.doc)(this.collectionRef, documentId);
|
|
5287
|
+
await (0, import_firestore22.updateDoc)(docRef, updateData);
|
|
4985
5288
|
return {
|
|
4986
5289
|
...filledDocument,
|
|
4987
5290
|
...updateData
|
|
@@ -4995,21 +5298,21 @@ var FilledDocumentService = class extends BaseService {
|
|
|
4995
5298
|
* @returns Array of filled documents and the last document for pagination
|
|
4996
5299
|
*/
|
|
4997
5300
|
async getFilledDocumentsByPatient(patientId, pageSize = 20, lastDoc) {
|
|
4998
|
-
let q = (0,
|
|
5301
|
+
let q = (0, import_firestore22.query)(
|
|
4999
5302
|
this.collectionRef,
|
|
5000
|
-
(0,
|
|
5001
|
-
(0,
|
|
5002
|
-
(0,
|
|
5303
|
+
(0, import_firestore22.where)("patientId", "==", patientId),
|
|
5304
|
+
(0, import_firestore22.orderBy)("updatedAt", "desc"),
|
|
5305
|
+
(0, import_firestore22.limit)(pageSize)
|
|
5003
5306
|
);
|
|
5004
5307
|
if (lastDoc) {
|
|
5005
|
-
q = (0,
|
|
5308
|
+
q = (0, import_firestore22.query)(q, (0, import_firestore22.startAfter)(lastDoc));
|
|
5006
5309
|
}
|
|
5007
|
-
const querySnapshot = await (0,
|
|
5310
|
+
const querySnapshot = await (0, import_firestore22.getDocs)(q);
|
|
5008
5311
|
const documents = [];
|
|
5009
5312
|
let lastVisible = null;
|
|
5010
|
-
querySnapshot.forEach((
|
|
5011
|
-
documents.push(
|
|
5012
|
-
lastVisible =
|
|
5313
|
+
querySnapshot.forEach((doc14) => {
|
|
5314
|
+
documents.push(doc14.data());
|
|
5315
|
+
lastVisible = doc14;
|
|
5013
5316
|
});
|
|
5014
5317
|
return {
|
|
5015
5318
|
documents,
|
|
@@ -5024,21 +5327,21 @@ var FilledDocumentService = class extends BaseService {
|
|
|
5024
5327
|
* @returns Array of filled documents and the last document for pagination
|
|
5025
5328
|
*/
|
|
5026
5329
|
async getFilledDocumentsByPractitioner(practitionerId, pageSize = 20, lastDoc) {
|
|
5027
|
-
let q = (0,
|
|
5330
|
+
let q = (0, import_firestore22.query)(
|
|
5028
5331
|
this.collectionRef,
|
|
5029
|
-
(0,
|
|
5030
|
-
(0,
|
|
5031
|
-
(0,
|
|
5332
|
+
(0, import_firestore22.where)("practitionerId", "==", practitionerId),
|
|
5333
|
+
(0, import_firestore22.orderBy)("updatedAt", "desc"),
|
|
5334
|
+
(0, import_firestore22.limit)(pageSize)
|
|
5032
5335
|
);
|
|
5033
5336
|
if (lastDoc) {
|
|
5034
|
-
q = (0,
|
|
5337
|
+
q = (0, import_firestore22.query)(q, (0, import_firestore22.startAfter)(lastDoc));
|
|
5035
5338
|
}
|
|
5036
|
-
const querySnapshot = await (0,
|
|
5339
|
+
const querySnapshot = await (0, import_firestore22.getDocs)(q);
|
|
5037
5340
|
const documents = [];
|
|
5038
5341
|
let lastVisible = null;
|
|
5039
|
-
querySnapshot.forEach((
|
|
5040
|
-
documents.push(
|
|
5041
|
-
lastVisible =
|
|
5342
|
+
querySnapshot.forEach((doc14) => {
|
|
5343
|
+
documents.push(doc14.data());
|
|
5344
|
+
lastVisible = doc14;
|
|
5042
5345
|
});
|
|
5043
5346
|
return {
|
|
5044
5347
|
documents,
|
|
@@ -5053,21 +5356,21 @@ var FilledDocumentService = class extends BaseService {
|
|
|
5053
5356
|
* @returns Array of filled documents and the last document for pagination
|
|
5054
5357
|
*/
|
|
5055
5358
|
async getFilledDocumentsByClinic(clinicId, pageSize = 20, lastDoc) {
|
|
5056
|
-
let q = (0,
|
|
5359
|
+
let q = (0, import_firestore22.query)(
|
|
5057
5360
|
this.collectionRef,
|
|
5058
|
-
(0,
|
|
5059
|
-
(0,
|
|
5060
|
-
(0,
|
|
5361
|
+
(0, import_firestore22.where)("clinicId", "==", clinicId),
|
|
5362
|
+
(0, import_firestore22.orderBy)("updatedAt", "desc"),
|
|
5363
|
+
(0, import_firestore22.limit)(pageSize)
|
|
5061
5364
|
);
|
|
5062
5365
|
if (lastDoc) {
|
|
5063
|
-
q = (0,
|
|
5366
|
+
q = (0, import_firestore22.query)(q, (0, import_firestore22.startAfter)(lastDoc));
|
|
5064
5367
|
}
|
|
5065
|
-
const querySnapshot = await (0,
|
|
5368
|
+
const querySnapshot = await (0, import_firestore22.getDocs)(q);
|
|
5066
5369
|
const documents = [];
|
|
5067
5370
|
let lastVisible = null;
|
|
5068
|
-
querySnapshot.forEach((
|
|
5069
|
-
documents.push(
|
|
5070
|
-
lastVisible =
|
|
5371
|
+
querySnapshot.forEach((doc14) => {
|
|
5372
|
+
documents.push(doc14.data());
|
|
5373
|
+
lastVisible = doc14;
|
|
5071
5374
|
});
|
|
5072
5375
|
return {
|
|
5073
5376
|
documents,
|
|
@@ -5082,21 +5385,21 @@ var FilledDocumentService = class extends BaseService {
|
|
|
5082
5385
|
* @returns Array of filled documents and the last document for pagination
|
|
5083
5386
|
*/
|
|
5084
5387
|
async getFilledDocumentsByTemplate(templateId, pageSize = 20, lastDoc) {
|
|
5085
|
-
let q = (0,
|
|
5388
|
+
let q = (0, import_firestore22.query)(
|
|
5086
5389
|
this.collectionRef,
|
|
5087
|
-
(0,
|
|
5088
|
-
(0,
|
|
5089
|
-
(0,
|
|
5390
|
+
(0, import_firestore22.where)("templateId", "==", templateId),
|
|
5391
|
+
(0, import_firestore22.orderBy)("updatedAt", "desc"),
|
|
5392
|
+
(0, import_firestore22.limit)(pageSize)
|
|
5090
5393
|
);
|
|
5091
5394
|
if (lastDoc) {
|
|
5092
|
-
q = (0,
|
|
5395
|
+
q = (0, import_firestore22.query)(q, (0, import_firestore22.startAfter)(lastDoc));
|
|
5093
5396
|
}
|
|
5094
|
-
const querySnapshot = await (0,
|
|
5397
|
+
const querySnapshot = await (0, import_firestore22.getDocs)(q);
|
|
5095
5398
|
const documents = [];
|
|
5096
5399
|
let lastVisible = null;
|
|
5097
|
-
querySnapshot.forEach((
|
|
5098
|
-
documents.push(
|
|
5099
|
-
lastVisible =
|
|
5400
|
+
querySnapshot.forEach((doc14) => {
|
|
5401
|
+
documents.push(doc14.data());
|
|
5402
|
+
lastVisible = doc14;
|
|
5100
5403
|
});
|
|
5101
5404
|
return {
|
|
5102
5405
|
documents,
|
|
@@ -5111,21 +5414,21 @@ var FilledDocumentService = class extends BaseService {
|
|
|
5111
5414
|
* @returns Array of filled documents and the last document for pagination
|
|
5112
5415
|
*/
|
|
5113
5416
|
async getFilledDocumentsByStatus(status, pageSize = 20, lastDoc) {
|
|
5114
|
-
let q = (0,
|
|
5417
|
+
let q = (0, import_firestore22.query)(
|
|
5115
5418
|
this.collectionRef,
|
|
5116
|
-
(0,
|
|
5117
|
-
(0,
|
|
5118
|
-
(0,
|
|
5419
|
+
(0, import_firestore22.where)("status", "==", status),
|
|
5420
|
+
(0, import_firestore22.orderBy)("updatedAt", "desc"),
|
|
5421
|
+
(0, import_firestore22.limit)(pageSize)
|
|
5119
5422
|
);
|
|
5120
5423
|
if (lastDoc) {
|
|
5121
|
-
q = (0,
|
|
5424
|
+
q = (0, import_firestore22.query)(q, (0, import_firestore22.startAfter)(lastDoc));
|
|
5122
5425
|
}
|
|
5123
|
-
const querySnapshot = await (0,
|
|
5426
|
+
const querySnapshot = await (0, import_firestore22.getDocs)(q);
|
|
5124
5427
|
const documents = [];
|
|
5125
5428
|
let lastVisible = null;
|
|
5126
|
-
querySnapshot.forEach((
|
|
5127
|
-
documents.push(
|
|
5128
|
-
lastVisible =
|
|
5429
|
+
querySnapshot.forEach((doc14) => {
|
|
5430
|
+
documents.push(doc14.data());
|
|
5431
|
+
lastVisible = doc14;
|
|
5129
5432
|
});
|
|
5130
5433
|
return {
|
|
5131
5434
|
documents,
|
|
@@ -5251,8 +5554,11 @@ var notificationSchema = import_zod16.z.discriminatedUnion("notificationType", [
|
|
|
5251
5554
|
blockingConditionSchema,
|
|
5252
5555
|
clinicAdminOptionsSchema,
|
|
5253
5556
|
clinicAdminSchema,
|
|
5557
|
+
clinicAdminSignupSchema,
|
|
5558
|
+
clinicBranchSetupSchema,
|
|
5254
5559
|
clinicContactInfoSchema,
|
|
5255
5560
|
clinicGroupSchema,
|
|
5561
|
+
clinicGroupSetupSchema,
|
|
5256
5562
|
clinicInfoSchema,
|
|
5257
5563
|
clinicLocationSchema,
|
|
5258
5564
|
clinicReviewSchema,
|
|
@@ -5307,6 +5613,9 @@ var notificationSchema = import_zod16.z.discriminatedUnion("notificationType", [
|
|
|
5307
5613
|
timestampSchema,
|
|
5308
5614
|
updateAllergySchema,
|
|
5309
5615
|
updateBlockingConditionSchema,
|
|
5616
|
+
updateClinicAdminSchema,
|
|
5617
|
+
updateClinicGroupSchema,
|
|
5618
|
+
updateClinicSchema,
|
|
5310
5619
|
updateContraindicationSchema,
|
|
5311
5620
|
updateDocumentTemplateSchema,
|
|
5312
5621
|
updateMedicationSchema,
|