@blackcode_sa/metaestetics-api 1.4.2 → 1.4.4
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 +2842 -407
- package/dist/index.d.ts +2842 -407
- package/dist/index.js +1285 -969
- package/dist/index.mjs +1207 -893
- package/package.json +1 -1
- package/src/services/auth.service.ts +177 -0
- package/src/services/clinic/clinic-group.service.ts +34 -0
- package/src/services/clinic/clinic.service.ts +53 -0
- package/src/services/user.service.ts +8 -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
|
/**
|
|
@@ -3262,6 +3389,9 @@ var UserService = class extends BaseService {
|
|
|
3262
3389
|
profiles.patientProfile = patientProfile.id;
|
|
3263
3390
|
break;
|
|
3264
3391
|
case "clinic_admin" /* CLINIC_ADMIN */:
|
|
3392
|
+
if (options == null ? void 0 : options.skipProfileCreation) {
|
|
3393
|
+
break;
|
|
3394
|
+
}
|
|
3265
3395
|
if (((_a = options == null ? void 0 : options.clinicAdminData) == null ? void 0 : _a.groupToken) && ((_b = options == null ? void 0 : options.clinicAdminData) == null ? void 0 : _b.groupId)) {
|
|
3266
3396
|
const isValid = await this.getClinicAdminService().getClinicGroupService().verifyAndUseAdminToken(
|
|
3267
3397
|
options.clinicAdminData.groupId,
|
|
@@ -3298,7 +3428,7 @@ var UserService = class extends BaseService {
|
|
|
3298
3428
|
email: "",
|
|
3299
3429
|
phoneNumber: "",
|
|
3300
3430
|
title: "",
|
|
3301
|
-
dateOfBirth:
|
|
3431
|
+
dateOfBirth: import_firestore14.Timestamp.now(),
|
|
3302
3432
|
gender: "other",
|
|
3303
3433
|
languages: ["Serbian"]
|
|
3304
3434
|
},
|
|
@@ -3307,7 +3437,7 @@ var UserService = class extends BaseService {
|
|
|
3307
3437
|
specialties: [],
|
|
3308
3438
|
licenseNumber: "",
|
|
3309
3439
|
issuingAuthority: "",
|
|
3310
|
-
issueDate:
|
|
3440
|
+
issueDate: import_firestore14.Timestamp.now(),
|
|
3311
3441
|
verificationStatus: "pending"
|
|
3312
3442
|
},
|
|
3313
3443
|
isActive: true,
|
|
@@ -3323,7 +3453,7 @@ var UserService = class extends BaseService {
|
|
|
3323
3453
|
* Dohvata korisnika po ID-u
|
|
3324
3454
|
*/
|
|
3325
3455
|
async getUserById(uid) {
|
|
3326
|
-
const userDoc = await (0,
|
|
3456
|
+
const userDoc = await (0, import_firestore14.getDoc)((0, import_firestore14.doc)(this.db, USERS_COLLECTION, uid));
|
|
3327
3457
|
if (!userDoc.exists()) {
|
|
3328
3458
|
throw USER_ERRORS.NOT_FOUND;
|
|
3329
3459
|
}
|
|
@@ -3334,53 +3464,53 @@ var UserService = class extends BaseService {
|
|
|
3334
3464
|
* Dohvata korisnika po email-u
|
|
3335
3465
|
*/
|
|
3336
3466
|
async getUserByEmail(email) {
|
|
3337
|
-
const usersRef = (0,
|
|
3338
|
-
const q = (0,
|
|
3339
|
-
const querySnapshot = await (0,
|
|
3467
|
+
const usersRef = (0, import_firestore14.collection)(this.db, USERS_COLLECTION);
|
|
3468
|
+
const q = (0, import_firestore14.query)(usersRef, (0, import_firestore14.where)("email", "==", email));
|
|
3469
|
+
const querySnapshot = await (0, import_firestore14.getDocs)(q);
|
|
3340
3470
|
if (querySnapshot.empty) return null;
|
|
3341
3471
|
const userData = querySnapshot.docs[0].data();
|
|
3342
3472
|
return userSchema.parse(userData);
|
|
3343
3473
|
}
|
|
3344
3474
|
async getUsersByRole(role) {
|
|
3345
3475
|
const constraints = [
|
|
3346
|
-
(0,
|
|
3476
|
+
(0, import_firestore14.where)("roles", "array-contains", role)
|
|
3347
3477
|
];
|
|
3348
|
-
const q = (0,
|
|
3349
|
-
const querySnapshot = await (0,
|
|
3350
|
-
const users = querySnapshot.docs.map((
|
|
3478
|
+
const q = (0, import_firestore14.query)((0, import_firestore14.collection)(this.db, USERS_COLLECTION), ...constraints);
|
|
3479
|
+
const querySnapshot = await (0, import_firestore14.getDocs)(q);
|
|
3480
|
+
const users = querySnapshot.docs.map((doc14) => doc14.data());
|
|
3351
3481
|
return Promise.all(users.map((userData) => userSchema.parse(userData)));
|
|
3352
3482
|
}
|
|
3353
3483
|
/**
|
|
3354
3484
|
* Ažurira timestamp poslednjeg logovanja
|
|
3355
3485
|
*/
|
|
3356
3486
|
async updateUserLoginTimestamp(uid) {
|
|
3357
|
-
const userRef = (0,
|
|
3358
|
-
const userDoc = await (0,
|
|
3487
|
+
const userRef = (0, import_firestore14.doc)(this.db, USERS_COLLECTION, uid);
|
|
3488
|
+
const userDoc = await (0, import_firestore14.getDoc)(userRef);
|
|
3359
3489
|
if (!userDoc.exists()) {
|
|
3360
3490
|
throw AUTH_ERRORS.USER_NOT_FOUND;
|
|
3361
3491
|
}
|
|
3362
|
-
await (0,
|
|
3363
|
-
lastLoginAt: (0,
|
|
3364
|
-
updatedAt: (0,
|
|
3492
|
+
await (0, import_firestore14.updateDoc)(userRef, {
|
|
3493
|
+
lastLoginAt: (0, import_firestore14.serverTimestamp)(),
|
|
3494
|
+
updatedAt: (0, import_firestore14.serverTimestamp)()
|
|
3365
3495
|
});
|
|
3366
3496
|
return this.getUserById(uid);
|
|
3367
3497
|
}
|
|
3368
3498
|
async upgradeAnonymousUser(uid, email) {
|
|
3369
|
-
const userRef = (0,
|
|
3370
|
-
const userDoc = await (0,
|
|
3499
|
+
const userRef = (0, import_firestore14.doc)(this.db, USERS_COLLECTION, uid);
|
|
3500
|
+
const userDoc = await (0, import_firestore14.getDoc)(userRef);
|
|
3371
3501
|
if (!userDoc.exists()) {
|
|
3372
3502
|
throw USER_ERRORS.NOT_FOUND;
|
|
3373
3503
|
}
|
|
3374
|
-
await (0,
|
|
3504
|
+
await (0, import_firestore14.updateDoc)(userRef, {
|
|
3375
3505
|
email,
|
|
3376
3506
|
isAnonymous: false,
|
|
3377
|
-
updatedAt: (0,
|
|
3507
|
+
updatedAt: (0, import_firestore14.serverTimestamp)()
|
|
3378
3508
|
});
|
|
3379
3509
|
return this.getUserById(uid);
|
|
3380
3510
|
}
|
|
3381
3511
|
async updateUser(uid, updates) {
|
|
3382
|
-
const userRef = (0,
|
|
3383
|
-
const userDoc = await (0,
|
|
3512
|
+
const userRef = (0, import_firestore14.doc)(this.db, USERS_COLLECTION, uid);
|
|
3513
|
+
const userDoc = await (0, import_firestore14.getDoc)(userRef);
|
|
3384
3514
|
if (!userDoc.exists()) {
|
|
3385
3515
|
throw USER_ERRORS.NOT_FOUND;
|
|
3386
3516
|
}
|
|
@@ -3389,7 +3519,7 @@ var UserService = class extends BaseService {
|
|
|
3389
3519
|
const updatedUser = {
|
|
3390
3520
|
...currentUser,
|
|
3391
3521
|
...updates,
|
|
3392
|
-
updatedAt: (0,
|
|
3522
|
+
updatedAt: (0, import_firestore14.serverTimestamp)()
|
|
3393
3523
|
};
|
|
3394
3524
|
updatedUser.roles.forEach((role) => {
|
|
3395
3525
|
switch (role) {
|
|
@@ -3411,9 +3541,9 @@ var UserService = class extends BaseService {
|
|
|
3411
3541
|
}
|
|
3412
3542
|
});
|
|
3413
3543
|
userSchema.parse(updatedUser);
|
|
3414
|
-
await (0,
|
|
3544
|
+
await (0, import_firestore14.updateDoc)(userRef, {
|
|
3415
3545
|
...updates,
|
|
3416
|
-
updatedAt: (0,
|
|
3546
|
+
updatedAt: (0, import_firestore14.serverTimestamp)()
|
|
3417
3547
|
});
|
|
3418
3548
|
return this.getUserById(uid);
|
|
3419
3549
|
} catch (error) {
|
|
@@ -3430,10 +3560,10 @@ var UserService = class extends BaseService {
|
|
|
3430
3560
|
const user = await this.getUserById(uid);
|
|
3431
3561
|
if (user.roles.includes(role)) return;
|
|
3432
3562
|
const profiles = await this.createProfilesForRoles(uid, [role], options);
|
|
3433
|
-
await (0,
|
|
3563
|
+
await (0, import_firestore14.updateDoc)((0, import_firestore14.doc)(this.db, USERS_COLLECTION, uid), {
|
|
3434
3564
|
roles: [...user.roles, role],
|
|
3435
3565
|
...profiles,
|
|
3436
|
-
updatedAt: (0,
|
|
3566
|
+
updatedAt: (0, import_firestore14.serverTimestamp)()
|
|
3437
3567
|
});
|
|
3438
3568
|
}
|
|
3439
3569
|
/**
|
|
@@ -3465,15 +3595,15 @@ var UserService = class extends BaseService {
|
|
|
3465
3595
|
}
|
|
3466
3596
|
break;
|
|
3467
3597
|
}
|
|
3468
|
-
await (0,
|
|
3598
|
+
await (0, import_firestore14.updateDoc)((0, import_firestore14.doc)(this.db, USERS_COLLECTION, uid), {
|
|
3469
3599
|
roles: user.roles.filter((r) => r !== role),
|
|
3470
|
-
updatedAt: (0,
|
|
3600
|
+
updatedAt: (0, import_firestore14.serverTimestamp)()
|
|
3471
3601
|
});
|
|
3472
3602
|
}
|
|
3473
3603
|
// Delete operations
|
|
3474
3604
|
async deleteUser(uid) {
|
|
3475
|
-
const userRef = (0,
|
|
3476
|
-
const userDoc = await (0,
|
|
3605
|
+
const userRef = (0, import_firestore14.doc)(this.db, USERS_COLLECTION, uid);
|
|
3606
|
+
const userDoc = await (0, import_firestore14.getDoc)(userRef);
|
|
3477
3607
|
if (!userDoc.exists()) {
|
|
3478
3608
|
throw USER_ERRORS.NOT_FOUND;
|
|
3479
3609
|
}
|
|
@@ -3494,486 +3624,350 @@ var UserService = class extends BaseService {
|
|
|
3494
3624
|
userData.adminProfile
|
|
3495
3625
|
);
|
|
3496
3626
|
}
|
|
3497
|
-
await (0,
|
|
3627
|
+
await (0, import_firestore14.deleteDoc)(userRef);
|
|
3498
3628
|
} catch (error) {
|
|
3499
3629
|
throw error;
|
|
3500
3630
|
}
|
|
3501
3631
|
}
|
|
3502
3632
|
};
|
|
3503
3633
|
|
|
3504
|
-
// src/services/
|
|
3505
|
-
var
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3634
|
+
// src/services/clinic/utils/clinic-group.utils.ts
|
|
3635
|
+
var import_firestore15 = require("firebase/firestore");
|
|
3636
|
+
var import_geofire_common2 = require("geofire-common");
|
|
3637
|
+
var import_zod13 = require("zod");
|
|
3638
|
+
function generateId() {
|
|
3639
|
+
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
3640
|
+
const timestamp = Date.now().toString(36);
|
|
3641
|
+
const randomPart = Array.from(
|
|
3642
|
+
{ length: 12 },
|
|
3643
|
+
() => chars.charAt(Math.floor(Math.random() * chars.length))
|
|
3644
|
+
).join("");
|
|
3645
|
+
return `${randomPart}-${timestamp}`;
|
|
3646
|
+
}
|
|
3647
|
+
async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdminService) {
|
|
3648
|
+
const validatedData = createClinicGroupSchema.parse(data);
|
|
3649
|
+
const owner = await clinicAdminService.getClinicAdmin(ownerId);
|
|
3650
|
+
if (!owner) {
|
|
3651
|
+
throw new Error("Owner not found or is not a clinic admin");
|
|
3652
|
+
}
|
|
3653
|
+
if (validatedData.hqLocation) {
|
|
3654
|
+
validatedData.hqLocation.geohash = (0, import_geofire_common2.geohashForLocation)([
|
|
3655
|
+
validatedData.hqLocation.latitude,
|
|
3656
|
+
validatedData.hqLocation.longitude
|
|
3657
|
+
]);
|
|
3658
|
+
}
|
|
3659
|
+
const now = import_firestore15.Timestamp.now();
|
|
3660
|
+
const groupData = {
|
|
3661
|
+
...validatedData,
|
|
3662
|
+
id: (0, import_firestore15.doc)((0, import_firestore15.collection)(db, CLINIC_GROUPS_COLLECTION)).id,
|
|
3663
|
+
description: isDefault ? void 0 : validatedData.description || void 0,
|
|
3664
|
+
hqLocation: {
|
|
3665
|
+
...validatedData.hqLocation,
|
|
3666
|
+
geohash: validatedData.hqLocation.geohash || void 0
|
|
3667
|
+
},
|
|
3668
|
+
contactInfo: {
|
|
3669
|
+
...validatedData.contactInfo,
|
|
3670
|
+
alternativePhoneNumber: isDefault ? void 0 : validatedData.contactInfo.alternativePhoneNumber || void 0,
|
|
3671
|
+
website: isDefault ? void 0 : validatedData.contactInfo.website || void 0
|
|
3672
|
+
},
|
|
3673
|
+
clinics: [],
|
|
3674
|
+
clinicsInfo: [],
|
|
3675
|
+
admins: [ownerId],
|
|
3676
|
+
adminsInfo: [],
|
|
3677
|
+
adminTokens: [],
|
|
3678
|
+
ownerId,
|
|
3679
|
+
createdAt: now,
|
|
3680
|
+
updatedAt: now,
|
|
3681
|
+
isActive: true
|
|
3682
|
+
};
|
|
3683
|
+
try {
|
|
3684
|
+
clinicGroupSchema.parse(groupData);
|
|
3685
|
+
await (0, import_firestore15.setDoc)((0, import_firestore15.doc)(db, CLINIC_GROUPS_COLLECTION, groupData.id), groupData);
|
|
3686
|
+
await clinicAdminService.updateClinicAdmin(ownerId, {
|
|
3687
|
+
clinicGroupId: groupData.id,
|
|
3688
|
+
isGroupOwner: true
|
|
3689
|
+
});
|
|
3690
|
+
return groupData;
|
|
3691
|
+
} catch (error) {
|
|
3692
|
+
if (error instanceof import_zod13.z.ZodError) {
|
|
3693
|
+
throw new Error("Invalid clinic group data: " + error.message);
|
|
3513
3694
|
}
|
|
3514
|
-
|
|
3695
|
+
throw error;
|
|
3515
3696
|
}
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
email,
|
|
3523
|
-
password
|
|
3524
|
-
);
|
|
3525
|
-
return this.userService.createUser(firebaseUser, [initialRole]);
|
|
3697
|
+
}
|
|
3698
|
+
async function getClinicGroup(db, groupId) {
|
|
3699
|
+
const docRef = (0, import_firestore15.doc)(db, CLINIC_GROUPS_COLLECTION, groupId);
|
|
3700
|
+
const docSnap = await (0, import_firestore15.getDoc)(docRef);
|
|
3701
|
+
if (docSnap.exists()) {
|
|
3702
|
+
return docSnap.data();
|
|
3526
3703
|
}
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3704
|
+
return null;
|
|
3705
|
+
}
|
|
3706
|
+
async function getAllActiveGroups(db) {
|
|
3707
|
+
const q = (0, import_firestore15.query)(
|
|
3708
|
+
(0, import_firestore15.collection)(db, CLINIC_GROUPS_COLLECTION),
|
|
3709
|
+
(0, import_firestore15.where)("isActive", "==", true)
|
|
3710
|
+
);
|
|
3711
|
+
const querySnapshot = await (0, import_firestore15.getDocs)(q);
|
|
3712
|
+
return querySnapshot.docs.map((doc14) => doc14.data());
|
|
3713
|
+
}
|
|
3714
|
+
async function updateClinicGroup(db, groupId, data) {
|
|
3715
|
+
const group = await getClinicGroup(db, groupId);
|
|
3716
|
+
if (!group) {
|
|
3717
|
+
throw new Error("Clinic group not found");
|
|
3537
3718
|
}
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3719
|
+
const updatedData = {
|
|
3720
|
+
...data,
|
|
3721
|
+
updatedAt: import_firestore15.Timestamp.now()
|
|
3722
|
+
};
|
|
3723
|
+
await (0, import_firestore15.updateDoc)((0, import_firestore15.doc)(db, CLINIC_GROUPS_COLLECTION, groupId), updatedData);
|
|
3724
|
+
const updatedGroup = await getClinicGroup(db, groupId);
|
|
3725
|
+
if (!updatedGroup) {
|
|
3726
|
+
throw new Error("Failed to retrieve updated clinic group");
|
|
3545
3727
|
}
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
this.googleProvider
|
|
3553
|
-
);
|
|
3554
|
-
return this.userService.getOrCreateUser(firebaseUser);
|
|
3728
|
+
return updatedGroup;
|
|
3729
|
+
}
|
|
3730
|
+
async function addAdminToGroup(db, groupId, adminId) {
|
|
3731
|
+
const group = await getClinicGroup(db, groupId);
|
|
3732
|
+
if (!group) {
|
|
3733
|
+
throw new Error("Clinic group not found");
|
|
3555
3734
|
}
|
|
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);
|
|
3735
|
+
if (group.admins.includes(adminId)) {
|
|
3736
|
+
return;
|
|
3563
3737
|
}
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3738
|
+
await updateClinicGroup(db, groupId, {
|
|
3739
|
+
admins: [...group.admins, adminId]
|
|
3740
|
+
});
|
|
3741
|
+
}
|
|
3742
|
+
async function removeAdminFromGroup(db, groupId, adminId) {
|
|
3743
|
+
const group = await getClinicGroup(db, groupId);
|
|
3744
|
+
if (!group) {
|
|
3745
|
+
throw new Error("Clinic group not found");
|
|
3570
3746
|
}
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
*/
|
|
3574
|
-
async signOut() {
|
|
3575
|
-
await (0, import_auth5.signOut)(this.auth);
|
|
3747
|
+
if (group.ownerId === adminId) {
|
|
3748
|
+
throw new Error("Cannot remove the owner from the group");
|
|
3576
3749
|
}
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
*/
|
|
3580
|
-
async getCurrentUser() {
|
|
3581
|
-
const firebaseUser = this.auth.currentUser;
|
|
3582
|
-
if (!firebaseUser) return null;
|
|
3583
|
-
return this.userService.getUserById(firebaseUser.uid);
|
|
3750
|
+
if (!group.admins.includes(adminId)) {
|
|
3751
|
+
return;
|
|
3584
3752
|
}
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3753
|
+
await updateClinicGroup(db, groupId, {
|
|
3754
|
+
admins: group.admins.filter((id) => id !== adminId)
|
|
3755
|
+
});
|
|
3756
|
+
}
|
|
3757
|
+
async function deactivateClinicGroup(db, groupId) {
|
|
3758
|
+
const group = await getClinicGroup(db, groupId);
|
|
3759
|
+
if (!group) {
|
|
3760
|
+
throw new Error("Clinic group not found");
|
|
3590
3761
|
}
|
|
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
|
-
}
|
|
3762
|
+
await (0, import_firestore15.updateDoc)((0, import_firestore15.doc)(db, CLINIC_GROUPS_COLLECTION, groupId), {
|
|
3763
|
+
isActive: false,
|
|
3764
|
+
updatedAt: import_firestore15.Timestamp.now()
|
|
3765
|
+
});
|
|
3766
|
+
}
|
|
3767
|
+
async function createAdminToken(db, groupId, creatorAdminId, data) {
|
|
3768
|
+
const group = await getClinicGroup(db, groupId);
|
|
3769
|
+
if (!group) {
|
|
3770
|
+
throw new Error("Clinic group not found");
|
|
3622
3771
|
}
|
|
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
|
-
}
|
|
3772
|
+
if (!group.admins.includes(creatorAdminId)) {
|
|
3773
|
+
throw new Error("Admin does not belong to this clinic group");
|
|
3662
3774
|
}
|
|
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
|
-
}
|
|
3775
|
+
const now = import_firestore15.Timestamp.now();
|
|
3776
|
+
const expiresInDays = (data == null ? void 0 : data.expiresInDays) || 7;
|
|
3777
|
+
const expiresAt = new import_firestore15.Timestamp(
|
|
3778
|
+
now.seconds + expiresInDays * 24 * 60 * 60,
|
|
3779
|
+
now.nanoseconds
|
|
3780
|
+
);
|
|
3781
|
+
const token = {
|
|
3782
|
+
id: generateId(),
|
|
3783
|
+
token: generateId(),
|
|
3784
|
+
status: "active" /* ACTIVE */,
|
|
3785
|
+
createdAt: now,
|
|
3786
|
+
expiresAt
|
|
3787
|
+
};
|
|
3788
|
+
await updateClinicGroup(db, groupId, {
|
|
3789
|
+
adminTokens: [...group.adminTokens, token]
|
|
3790
|
+
});
|
|
3791
|
+
return token;
|
|
3792
|
+
}
|
|
3793
|
+
async function verifyAndUseAdminToken(db, groupId, token, userRef) {
|
|
3794
|
+
const group = await getClinicGroup(db, groupId);
|
|
3795
|
+
if (!group) {
|
|
3796
|
+
throw new Error("Clinic group not found");
|
|
3693
3797
|
}
|
|
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
|
-
}
|
|
3798
|
+
const adminToken = group.adminTokens.find((t) => t.token === token);
|
|
3799
|
+
if (!adminToken) {
|
|
3800
|
+
throw new Error("Admin token not found");
|
|
3725
3801
|
}
|
|
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
|
-
}
|
|
3802
|
+
if (adminToken.status !== "active" /* ACTIVE */) {
|
|
3803
|
+
throw new Error("Admin token is not active");
|
|
3745
3804
|
}
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3805
|
+
const now = import_firestore15.Timestamp.now();
|
|
3806
|
+
if (adminToken.expiresAt.seconds < now.seconds) {
|
|
3807
|
+
const updatedTokens2 = group.adminTokens.map(
|
|
3808
|
+
(t) => t.id === adminToken.id ? { ...t, status: "expired" /* EXPIRED */ } : t
|
|
3809
|
+
);
|
|
3810
|
+
await updateClinicGroup(db, groupId, {
|
|
3811
|
+
adminTokens: updatedTokens2
|
|
3812
|
+
});
|
|
3813
|
+
throw new Error("Admin token has expired");
|
|
3814
|
+
}
|
|
3815
|
+
const updatedTokens = group.adminTokens.map(
|
|
3816
|
+
(t) => t.id === adminToken.id ? {
|
|
3817
|
+
...t,
|
|
3818
|
+
status: "used" /* USED */,
|
|
3819
|
+
usedByUserRef: userRef
|
|
3820
|
+
} : t
|
|
3821
|
+
);
|
|
3822
|
+
await updateClinicGroup(db, groupId, {
|
|
3823
|
+
adminTokens: updatedTokens
|
|
3824
|
+
});
|
|
3825
|
+
return true;
|
|
3826
|
+
}
|
|
3827
|
+
async function deleteAdminToken(db, groupId, tokenId, adminId) {
|
|
3828
|
+
const group = await getClinicGroup(db, groupId);
|
|
3829
|
+
if (!group) {
|
|
3830
|
+
throw new Error("Clinic group not found");
|
|
3831
|
+
}
|
|
3832
|
+
if (!group.admins.includes(adminId)) {
|
|
3833
|
+
throw new Error("Admin does not belong to this clinic group");
|
|
3834
|
+
}
|
|
3835
|
+
const updatedTokens = group.adminTokens.filter((t) => t.id !== tokenId);
|
|
3836
|
+
await updateClinicGroup(db, groupId, {
|
|
3837
|
+
adminTokens: updatedTokens
|
|
3838
|
+
});
|
|
3839
|
+
}
|
|
3840
|
+
async function getActiveAdminTokens(db, groupId, adminId) {
|
|
3841
|
+
const group = await getClinicGroup(db, groupId);
|
|
3842
|
+
if (!group) {
|
|
3843
|
+
throw new Error("Clinic group not found");
|
|
3844
|
+
}
|
|
3845
|
+
if (!group.admins.includes(adminId)) {
|
|
3846
|
+
throw new Error("Admin does not belong to this clinic group");
|
|
3847
|
+
}
|
|
3848
|
+
return group.adminTokens.filter((t) => t.status === "active" /* ACTIVE */);
|
|
3849
|
+
}
|
|
3850
|
+
|
|
3851
|
+
// src/services/clinic/clinic-group.service.ts
|
|
3852
|
+
var ClinicGroupService = class extends BaseService {
|
|
3853
|
+
constructor(db, auth, app, clinicAdminService) {
|
|
3854
|
+
super(db, auth, app);
|
|
3855
|
+
this.clinicAdminService = clinicAdminService;
|
|
3763
3856
|
}
|
|
3764
3857
|
/**
|
|
3765
|
-
*
|
|
3766
|
-
* @param oobCode Kod iz URL-a za resetovanje lozinke
|
|
3767
|
-
* @param newPassword Nova lozinka
|
|
3768
|
-
* @returns Promise koji se razrešava kada je lozinka promenjena
|
|
3858
|
+
* Kreira novu grupaciju klinika
|
|
3769
3859
|
*/
|
|
3770
|
-
async
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
const firebaseError = error;
|
|
3779
|
-
if (firebaseError.code === "auth/expired-action-code" /* EXPIRED_ACTION_CODE */) {
|
|
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
|
-
}
|
|
3860
|
+
async createClinicGroup(data, ownerId, isDefault = false) {
|
|
3861
|
+
return createClinicGroup(
|
|
3862
|
+
this.db,
|
|
3863
|
+
data,
|
|
3864
|
+
ownerId,
|
|
3865
|
+
isDefault,
|
|
3866
|
+
this.clinicAdminService
|
|
3867
|
+
);
|
|
3788
3868
|
}
|
|
3789
|
-
};
|
|
3790
|
-
|
|
3791
|
-
// src/services/notifications/notification.service.ts
|
|
3792
|
-
var import_firestore14 = require("firebase/firestore");
|
|
3793
|
-
|
|
3794
|
-
// src/types/notifications/index.ts
|
|
3795
|
-
var NotificationType = /* @__PURE__ */ ((NotificationType3) => {
|
|
3796
|
-
NotificationType3["PRE_REQUIREMENT"] = "preRequirement";
|
|
3797
|
-
NotificationType3["POST_REQUIREMENT"] = "postRequirement";
|
|
3798
|
-
NotificationType3["APPOINTMENT_REMINDER"] = "appointmentReminder";
|
|
3799
|
-
NotificationType3["APPOINTMENT_NOTIFICATION"] = "appointmentNotification";
|
|
3800
|
-
return NotificationType3;
|
|
3801
|
-
})(NotificationType || {});
|
|
3802
|
-
var NOTIFICATIONS_COLLECTION = "notifications";
|
|
3803
|
-
var NotificationStatus = /* @__PURE__ */ ((NotificationStatus2) => {
|
|
3804
|
-
NotificationStatus2["PENDING"] = "pending";
|
|
3805
|
-
NotificationStatus2["SENT"] = "sent";
|
|
3806
|
-
NotificationStatus2["FAILED"] = "failed";
|
|
3807
|
-
NotificationStatus2["CANCELLED"] = "cancelled";
|
|
3808
|
-
NotificationStatus2["PARTIAL_SUCCESS"] = "partialSuccess";
|
|
3809
|
-
return NotificationStatus2;
|
|
3810
|
-
})(NotificationStatus || {});
|
|
3811
|
-
|
|
3812
|
-
// src/services/notifications/notification.service.ts
|
|
3813
|
-
var NotificationService = class extends BaseService {
|
|
3814
3869
|
/**
|
|
3815
|
-
*
|
|
3870
|
+
* Dohvata grupaciju klinika po ID-u
|
|
3816
3871
|
*/
|
|
3817
|
-
async
|
|
3818
|
-
|
|
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
|
-
};
|
|
3872
|
+
async getClinicGroup(groupId) {
|
|
3873
|
+
return getClinicGroup(this.db, groupId);
|
|
3833
3874
|
}
|
|
3834
3875
|
/**
|
|
3835
|
-
* Dohvata
|
|
3876
|
+
* Dohvata sve aktivne grupacije klinika
|
|
3836
3877
|
*/
|
|
3837
|
-
async
|
|
3838
|
-
|
|
3839
|
-
this.db,
|
|
3840
|
-
NOTIFICATIONS_COLLECTION,
|
|
3841
|
-
notificationId
|
|
3842
|
-
);
|
|
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
|
-
};
|
|
3878
|
+
async getAllActiveGroups() {
|
|
3879
|
+
return getAllActiveGroups(this.db);
|
|
3851
3880
|
}
|
|
3852
3881
|
/**
|
|
3853
|
-
*
|
|
3882
|
+
* Ažurira grupaciju klinika
|
|
3854
3883
|
*/
|
|
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
|
-
}));
|
|
3884
|
+
async updateClinicGroup(groupId, data) {
|
|
3885
|
+
return updateClinicGroup(this.db, groupId, data);
|
|
3866
3886
|
}
|
|
3867
3887
|
/**
|
|
3868
|
-
*
|
|
3888
|
+
* Dodaje admina u grupaciju
|
|
3869
3889
|
*/
|
|
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
|
-
}));
|
|
3890
|
+
async addAdminToGroup(groupId, adminId) {
|
|
3891
|
+
return addAdminToGroup(this.db, groupId, adminId);
|
|
3882
3892
|
}
|
|
3883
3893
|
/**
|
|
3884
|
-
*
|
|
3894
|
+
* Uklanja admina iz grupacije
|
|
3885
3895
|
*/
|
|
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
|
-
});
|
|
3896
|
+
async removeAdminFromGroup(groupId, adminId) {
|
|
3897
|
+
return removeAdminFromGroup(this.db, groupId, adminId);
|
|
3896
3898
|
}
|
|
3897
3899
|
/**
|
|
3898
|
-
*
|
|
3900
|
+
* Deaktivira grupaciju klinika
|
|
3899
3901
|
*/
|
|
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();
|
|
3902
|
+
async deactivateClinicGroup(groupId) {
|
|
3903
|
+
return deactivateClinicGroup(this.db, groupId);
|
|
3915
3904
|
}
|
|
3916
3905
|
/**
|
|
3917
|
-
*
|
|
3906
|
+
* Sets up additional clinic group information after initial creation
|
|
3907
|
+
*
|
|
3908
|
+
* @param groupId - The ID of the clinic group to set up
|
|
3909
|
+
* @param setupData - The setup data for the clinic group
|
|
3910
|
+
* @returns The updated clinic group
|
|
3918
3911
|
*/
|
|
3919
|
-
async
|
|
3920
|
-
const
|
|
3912
|
+
async setupClinicGroup(groupId, setupData) {
|
|
3913
|
+
const clinicGroup = await this.getClinicGroup(groupId);
|
|
3914
|
+
if (!clinicGroup) {
|
|
3915
|
+
throw new Error(`Clinic group with ID ${groupId} not found`);
|
|
3916
|
+
}
|
|
3917
|
+
const updateData = {
|
|
3918
|
+
languages: setupData.languages,
|
|
3919
|
+
practiceType: setupData.practiceType,
|
|
3920
|
+
description: setupData.description,
|
|
3921
|
+
logo: setupData.logo,
|
|
3922
|
+
calendarSyncEnabled: setupData.calendarSyncEnabled,
|
|
3923
|
+
autoConfirmAppointments: setupData.autoConfirmAppointments
|
|
3924
|
+
};
|
|
3925
|
+
return this.updateClinicGroup(groupId, updateData);
|
|
3926
|
+
}
|
|
3927
|
+
/**
|
|
3928
|
+
* Kreira admin token za grupaciju
|
|
3929
|
+
*/
|
|
3930
|
+
async createAdminToken(groupId, creatorAdminId, data) {
|
|
3931
|
+
return createAdminToken(
|
|
3921
3932
|
this.db,
|
|
3922
|
-
|
|
3923
|
-
|
|
3933
|
+
groupId,
|
|
3934
|
+
creatorAdminId,
|
|
3935
|
+
data
|
|
3924
3936
|
);
|
|
3925
|
-
await (0, import_firestore14.updateDoc)(notificationRef, {
|
|
3926
|
-
status,
|
|
3927
|
-
updatedAt: import_firestore14.Timestamp.now()
|
|
3928
|
-
});
|
|
3929
3937
|
}
|
|
3930
3938
|
/**
|
|
3931
|
-
*
|
|
3939
|
+
* Verifikuje i koristi admin token
|
|
3932
3940
|
*/
|
|
3933
|
-
async
|
|
3934
|
-
|
|
3941
|
+
async verifyAndUseAdminToken(groupId, token, userRef) {
|
|
3942
|
+
return verifyAndUseAdminToken(
|
|
3935
3943
|
this.db,
|
|
3936
|
-
|
|
3937
|
-
|
|
3944
|
+
groupId,
|
|
3945
|
+
token,
|
|
3946
|
+
userRef
|
|
3938
3947
|
);
|
|
3939
|
-
await (0, import_firestore14.deleteDoc)(notificationRef);
|
|
3940
3948
|
}
|
|
3941
3949
|
/**
|
|
3942
|
-
*
|
|
3950
|
+
* Briše admin token
|
|
3943
3951
|
*/
|
|
3944
|
-
async
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3952
|
+
async deleteAdminToken(groupId, tokenId, adminId) {
|
|
3953
|
+
return deleteAdminToken(
|
|
3954
|
+
this.db,
|
|
3955
|
+
groupId,
|
|
3956
|
+
tokenId,
|
|
3957
|
+
adminId
|
|
3950
3958
|
);
|
|
3951
|
-
const querySnapshot = await (0, import_firestore14.getDocs)(q);
|
|
3952
|
-
return querySnapshot.docs.map((doc13) => ({
|
|
3953
|
-
id: doc13.id,
|
|
3954
|
-
...doc13.data()
|
|
3955
|
-
}));
|
|
3956
3959
|
}
|
|
3957
3960
|
/**
|
|
3958
|
-
* Dohvata
|
|
3961
|
+
* Dohvata aktivne admin tokene
|
|
3959
3962
|
*/
|
|
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
|
-
}));
|
|
3963
|
+
async getActiveAdminTokens(groupId, adminId) {
|
|
3964
|
+
return getActiveAdminTokens(this.db, groupId, adminId);
|
|
3971
3965
|
}
|
|
3972
3966
|
};
|
|
3973
3967
|
|
|
3974
3968
|
// src/services/clinic/utils/clinic.utils.ts
|
|
3975
|
-
var
|
|
3976
|
-
var
|
|
3969
|
+
var import_firestore16 = require("firebase/firestore");
|
|
3970
|
+
var import_geofire_common3 = require("geofire-common");
|
|
3977
3971
|
var import_zod14 = require("zod");
|
|
3978
3972
|
async function createClinic(db, data, creatorAdminId, clinicGroupService, clinicAdminService) {
|
|
3979
3973
|
const validatedData = createClinicSchema.parse(data);
|
|
@@ -3991,15 +3985,15 @@ async function createClinic(db, data, creatorAdminId, clinicGroupService, clinic
|
|
|
3991
3985
|
throw new Error("Clinic group not found");
|
|
3992
3986
|
}
|
|
3993
3987
|
if (validatedData.location) {
|
|
3994
|
-
validatedData.location.geohash = (0,
|
|
3988
|
+
validatedData.location.geohash = (0, import_geofire_common3.geohashForLocation)([
|
|
3995
3989
|
validatedData.location.latitude,
|
|
3996
3990
|
validatedData.location.longitude
|
|
3997
3991
|
]);
|
|
3998
3992
|
}
|
|
3999
|
-
const now =
|
|
3993
|
+
const now = import_firestore16.Timestamp.now();
|
|
4000
3994
|
const clinicData = {
|
|
4001
3995
|
...validatedData,
|
|
4002
|
-
id: (0,
|
|
3996
|
+
id: (0, import_firestore16.doc)((0, import_firestore16.collection)(db, CLINICS_COLLECTION)).id,
|
|
4003
3997
|
description: validatedData.description || void 0,
|
|
4004
3998
|
location: {
|
|
4005
3999
|
...validatedData.location,
|
|
@@ -4028,7 +4022,7 @@ async function createClinic(db, data, creatorAdminId, clinicGroupService, clinic
|
|
|
4028
4022
|
};
|
|
4029
4023
|
try {
|
|
4030
4024
|
clinicSchema.parse(clinicData);
|
|
4031
|
-
await (0,
|
|
4025
|
+
await (0, import_firestore16.setDoc)((0, import_firestore16.doc)(db, CLINICS_COLLECTION, clinicData.id), clinicData);
|
|
4032
4026
|
await clinicGroupService.updateClinicGroup(validatedData.clinicGroupId, {
|
|
4033
4027
|
clinics: [...group.clinics, clinicData.id]
|
|
4034
4028
|
});
|
|
@@ -4042,21 +4036,21 @@ async function createClinic(db, data, creatorAdminId, clinicGroupService, clinic
|
|
|
4042
4036
|
}
|
|
4043
4037
|
}
|
|
4044
4038
|
async function getClinic(db, clinicId) {
|
|
4045
|
-
const docRef = (0,
|
|
4046
|
-
const docSnap = await (0,
|
|
4039
|
+
const docRef = (0, import_firestore16.doc)(db, CLINICS_COLLECTION, clinicId);
|
|
4040
|
+
const docSnap = await (0, import_firestore16.getDoc)(docRef);
|
|
4047
4041
|
if (docSnap.exists()) {
|
|
4048
4042
|
return docSnap.data();
|
|
4049
4043
|
}
|
|
4050
4044
|
return null;
|
|
4051
4045
|
}
|
|
4052
4046
|
async function getClinicsByGroup(db, groupId) {
|
|
4053
|
-
const q = (0,
|
|
4054
|
-
(0,
|
|
4055
|
-
(0,
|
|
4056
|
-
(0,
|
|
4047
|
+
const q = (0, import_firestore16.query)(
|
|
4048
|
+
(0, import_firestore16.collection)(db, CLINICS_COLLECTION),
|
|
4049
|
+
(0, import_firestore16.where)("clinicGroupId", "==", groupId),
|
|
4050
|
+
(0, import_firestore16.where)("isActive", "==", true)
|
|
4057
4051
|
);
|
|
4058
|
-
const querySnapshot = await (0,
|
|
4059
|
-
return querySnapshot.docs.map((
|
|
4052
|
+
const querySnapshot = await (0, import_firestore16.getDocs)(q);
|
|
4053
|
+
return querySnapshot.docs.map((doc14) => doc14.data());
|
|
4060
4054
|
}
|
|
4061
4055
|
async function updateClinic(db, clinicId, data, adminId, clinicAdminService) {
|
|
4062
4056
|
const clinic = await getClinic(db, clinicId);
|
|
@@ -4072,9 +4066,9 @@ async function updateClinic(db, clinicId, data, adminId, clinicAdminService) {
|
|
|
4072
4066
|
}
|
|
4073
4067
|
const updatedData = {
|
|
4074
4068
|
...data,
|
|
4075
|
-
updatedAt:
|
|
4069
|
+
updatedAt: import_firestore16.Timestamp.now()
|
|
4076
4070
|
};
|
|
4077
|
-
await (0,
|
|
4071
|
+
await (0, import_firestore16.updateDoc)((0, import_firestore16.doc)(db, CLINICS_COLLECTION, clinicId), updatedData);
|
|
4078
4072
|
const updatedClinic = await getClinic(db, clinicId);
|
|
4079
4073
|
if (!updatedClinic) {
|
|
4080
4074
|
throw new Error("Failed to retrieve updated clinic");
|
|
@@ -4093,9 +4087,9 @@ async function deactivateClinic(db, clinicId, adminId, clinicAdminService) {
|
|
|
4093
4087
|
if (!admin.isGroupOwner && !admin.clinicsManaged.includes(clinicId)) {
|
|
4094
4088
|
throw new Error("Admin does not have permission to deactivate this clinic");
|
|
4095
4089
|
}
|
|
4096
|
-
await (0,
|
|
4090
|
+
await (0, import_firestore16.updateDoc)((0, import_firestore16.doc)(db, CLINICS_COLLECTION, clinicId), {
|
|
4097
4091
|
isActive: false,
|
|
4098
|
-
updatedAt:
|
|
4092
|
+
updatedAt: import_firestore16.Timestamp.now()
|
|
4099
4093
|
});
|
|
4100
4094
|
}
|
|
4101
4095
|
async function getClinicsByAdmin(db, adminId, options = {}, clinicAdminService, clinicGroupService) {
|
|
@@ -4113,13 +4107,13 @@ async function getClinicsByAdmin(db, adminId, options = {}, clinicAdminService,
|
|
|
4113
4107
|
if (clinicIds.length === 0) {
|
|
4114
4108
|
return [];
|
|
4115
4109
|
}
|
|
4116
|
-
const constraints = [(0,
|
|
4110
|
+
const constraints = [(0, import_firestore16.where)("id", "in", clinicIds)];
|
|
4117
4111
|
if (options.isActive !== void 0) {
|
|
4118
|
-
constraints.push((0,
|
|
4112
|
+
constraints.push((0, import_firestore16.where)("isActive", "==", options.isActive));
|
|
4119
4113
|
}
|
|
4120
|
-
const q = (0,
|
|
4121
|
-
const querySnapshot = await (0,
|
|
4122
|
-
return querySnapshot.docs.map((
|
|
4114
|
+
const q = (0, import_firestore16.query)((0, import_firestore16.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
4115
|
+
const querySnapshot = await (0, import_firestore16.getDocs)(q);
|
|
4116
|
+
return querySnapshot.docs.map((doc14) => doc14.data());
|
|
4123
4117
|
}
|
|
4124
4118
|
async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGroupService) {
|
|
4125
4119
|
return getClinicsByAdmin(
|
|
@@ -4132,15 +4126,15 @@ async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGr
|
|
|
4132
4126
|
}
|
|
4133
4127
|
|
|
4134
4128
|
// src/services/clinic/utils/review.utils.ts
|
|
4135
|
-
var
|
|
4129
|
+
var import_firestore17 = require("firebase/firestore");
|
|
4136
4130
|
async function addReview(db, clinicId, review) {
|
|
4137
4131
|
const clinic = await getClinic(db, clinicId);
|
|
4138
4132
|
if (!clinic) {
|
|
4139
4133
|
throw new Error("Clinic not found");
|
|
4140
4134
|
}
|
|
4141
|
-
const now =
|
|
4135
|
+
const now = import_firestore17.Timestamp.now();
|
|
4142
4136
|
const reviewData = {
|
|
4143
|
-
id: (0,
|
|
4137
|
+
id: (0, import_firestore17.doc)((0, import_firestore17.collection)(db, "clinic_reviews")).id,
|
|
4144
4138
|
clinicId,
|
|
4145
4139
|
patientId: review.patientId,
|
|
4146
4140
|
rating: review.rating,
|
|
@@ -4150,7 +4144,7 @@ async function addReview(db, clinicId, review) {
|
|
|
4150
4144
|
isVerified: false
|
|
4151
4145
|
};
|
|
4152
4146
|
clinicReviewSchema.parse(reviewData);
|
|
4153
|
-
await (0,
|
|
4147
|
+
await (0, import_firestore17.setDoc)((0, import_firestore17.doc)(db, "clinic_reviews", reviewData.id), reviewData);
|
|
4154
4148
|
const newRating = clinic.rating ? {
|
|
4155
4149
|
average: (clinic.rating.average * clinic.rating.count + review.rating) / (clinic.rating.count + 1),
|
|
4156
4150
|
count: clinic.rating.count + 1
|
|
@@ -4240,33 +4234,33 @@ async function removeTags(db, clinicId, adminId, tagsToRemove, clinicAdminServic
|
|
|
4240
4234
|
}
|
|
4241
4235
|
|
|
4242
4236
|
// src/services/clinic/utils/search.utils.ts
|
|
4243
|
-
var
|
|
4244
|
-
var
|
|
4237
|
+
var import_firestore18 = require("firebase/firestore");
|
|
4238
|
+
var import_geofire_common4 = require("geofire-common");
|
|
4245
4239
|
async function findClinicsInRadius(db, center, radiusInKm, filters) {
|
|
4246
|
-
const bounds = (0,
|
|
4240
|
+
const bounds = (0, import_geofire_common4.geohashQueryBounds)(
|
|
4247
4241
|
[center.latitude, center.longitude],
|
|
4248
4242
|
radiusInKm * 1e3
|
|
4249
4243
|
);
|
|
4250
4244
|
const matchingDocs = [];
|
|
4251
4245
|
for (const b of bounds) {
|
|
4252
4246
|
const constraints = [
|
|
4253
|
-
(0,
|
|
4254
|
-
(0,
|
|
4255
|
-
(0,
|
|
4247
|
+
(0, import_firestore18.where)("location.geohash", ">=", b[0]),
|
|
4248
|
+
(0, import_firestore18.where)("location.geohash", "<=", b[1]),
|
|
4249
|
+
(0, import_firestore18.where)("isActive", "==", true)
|
|
4256
4250
|
];
|
|
4257
4251
|
if (filters == null ? void 0 : filters.services) {
|
|
4258
4252
|
constraints.push(
|
|
4259
|
-
(0,
|
|
4253
|
+
(0, import_firestore18.where)("services", "array-contains-any", filters.services)
|
|
4260
4254
|
);
|
|
4261
4255
|
}
|
|
4262
4256
|
if ((filters == null ? void 0 : filters.tags) && filters.tags.length > 0) {
|
|
4263
|
-
constraints.push((0,
|
|
4257
|
+
constraints.push((0, import_firestore18.where)("tags", "array-contains-any", filters.tags));
|
|
4264
4258
|
}
|
|
4265
|
-
const q = (0,
|
|
4266
|
-
const querySnapshot = await (0,
|
|
4267
|
-
for (const
|
|
4268
|
-
const clinic =
|
|
4269
|
-
const distance = (0,
|
|
4259
|
+
const q = (0, import_firestore18.query)((0, import_firestore18.collection)(db, CLINICS_COLLECTION), ...constraints);
|
|
4260
|
+
const querySnapshot = await (0, import_firestore18.getDocs)(q);
|
|
4261
|
+
for (const doc14 of querySnapshot.docs) {
|
|
4262
|
+
const clinic = doc14.data();
|
|
4263
|
+
const distance = (0, import_geofire_common4.distanceBetween)(
|
|
4270
4264
|
[center.latitude, center.longitude],
|
|
4271
4265
|
[clinic.location.latitude, clinic.location.longitude]
|
|
4272
4266
|
);
|
|
@@ -4277,11 +4271,11 @@ async function findClinicsInRadius(db, center, radiusInKm, filters) {
|
|
|
4277
4271
|
}
|
|
4278
4272
|
}
|
|
4279
4273
|
return matchingDocs.sort((a, b) => {
|
|
4280
|
-
const distanceA = (0,
|
|
4274
|
+
const distanceA = (0, import_geofire_common4.distanceBetween)(
|
|
4281
4275
|
[center.latitude, center.longitude],
|
|
4282
4276
|
[a.location.latitude, a.location.longitude]
|
|
4283
4277
|
);
|
|
4284
|
-
const distanceB = (0,
|
|
4278
|
+
const distanceB = (0, import_geofire_common4.distanceBetween)(
|
|
4285
4279
|
[center.latitude, center.longitude],
|
|
4286
4280
|
[b.location.latitude, b.location.longitude]
|
|
4287
4281
|
);
|
|
@@ -4407,326 +4401,642 @@ var ClinicService = class extends BaseService {
|
|
|
4407
4401
|
this.clinicGroupService
|
|
4408
4402
|
);
|
|
4409
4403
|
}
|
|
4404
|
+
/**
|
|
4405
|
+
* Creates a new clinic branch for a clinic group
|
|
4406
|
+
*
|
|
4407
|
+
* @param clinicGroupId - The ID of the clinic group
|
|
4408
|
+
* @param setupData - The setup data for the clinic branch
|
|
4409
|
+
* @param adminId - The ID of the admin creating the branch
|
|
4410
|
+
* @returns The created clinic
|
|
4411
|
+
*/
|
|
4412
|
+
async createClinicBranch(clinicGroupId, setupData, adminId) {
|
|
4413
|
+
const clinicGroup = await this.clinicGroupService.getClinicGroup(
|
|
4414
|
+
clinicGroupId
|
|
4415
|
+
);
|
|
4416
|
+
if (!clinicGroup) {
|
|
4417
|
+
throw new Error(`Clinic group with ID ${clinicGroupId} not found`);
|
|
4418
|
+
}
|
|
4419
|
+
const createClinicData = {
|
|
4420
|
+
clinicGroupId,
|
|
4421
|
+
name: setupData.name,
|
|
4422
|
+
description: setupData.description,
|
|
4423
|
+
location: setupData.location,
|
|
4424
|
+
contactInfo: setupData.contactInfo,
|
|
4425
|
+
workingHours: setupData.workingHours,
|
|
4426
|
+
tags: setupData.tags,
|
|
4427
|
+
photos: setupData.photos,
|
|
4428
|
+
photosWithTags: setupData.photosWithTags,
|
|
4429
|
+
doctors: [],
|
|
4430
|
+
services: [],
|
|
4431
|
+
admins: [adminId],
|
|
4432
|
+
isActive: true,
|
|
4433
|
+
isVerified: false,
|
|
4434
|
+
logo: setupData.logo,
|
|
4435
|
+
featuredPhotos: setupData.featuredPhotos || []
|
|
4436
|
+
};
|
|
4437
|
+
const clinic = await this.createClinic(createClinicData, adminId);
|
|
4438
|
+
return clinic;
|
|
4439
|
+
}
|
|
4410
4440
|
};
|
|
4411
4441
|
|
|
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);
|
|
4442
|
+
// src/services/auth.service.ts
|
|
4443
|
+
var AuthService = class extends BaseService {
|
|
4444
|
+
constructor(db, auth, app, userService) {
|
|
4445
|
+
super(db, auth, app);
|
|
4446
|
+
this.googleProvider = new import_auth5.GoogleAuthProvider();
|
|
4447
|
+
this.facebookProvider = new import_auth5.FacebookAuthProvider();
|
|
4448
|
+
this.appleProvider = new import_auth5.OAuthProvider("apple.com");
|
|
4449
|
+
if (!userService) {
|
|
4450
|
+
userService = new UserService(db, auth, app);
|
|
4472
4451
|
}
|
|
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");
|
|
4452
|
+
this.userService = userService;
|
|
4524
4453
|
}
|
|
4525
|
-
|
|
4526
|
-
|
|
4454
|
+
/**
|
|
4455
|
+
* Registruje novog korisnika sa email-om i lozinkom
|
|
4456
|
+
*/
|
|
4457
|
+
async signUp(email, password, initialRole = "patient" /* PATIENT */) {
|
|
4458
|
+
const { user: firebaseUser } = await (0, import_auth5.createUserWithEmailAndPassword)(
|
|
4459
|
+
this.auth,
|
|
4460
|
+
email,
|
|
4461
|
+
password
|
|
4462
|
+
);
|
|
4463
|
+
return this.userService.createUser(firebaseUser, [initialRole]);
|
|
4527
4464
|
}
|
|
4528
|
-
|
|
4529
|
-
|
|
4465
|
+
/**
|
|
4466
|
+
* Registers a new clinic admin user with email and password
|
|
4467
|
+
* Can either create a new clinic group or join an existing one with a token
|
|
4468
|
+
*
|
|
4469
|
+
* @param data - Clinic admin signup data
|
|
4470
|
+
* @returns The created user
|
|
4471
|
+
*/
|
|
4472
|
+
async signUpClinicAdmin(data) {
|
|
4473
|
+
try {
|
|
4474
|
+
await clinicAdminSignupSchema.parseAsync(data);
|
|
4475
|
+
const { user: firebaseUser } = await (0, import_auth5.createUserWithEmailAndPassword)(
|
|
4476
|
+
this.auth,
|
|
4477
|
+
data.email,
|
|
4478
|
+
data.password
|
|
4479
|
+
);
|
|
4480
|
+
const user = await this.userService.createUser(
|
|
4481
|
+
firebaseUser,
|
|
4482
|
+
["clinic_admin" /* CLINIC_ADMIN */],
|
|
4483
|
+
{
|
|
4484
|
+
skipProfileCreation: true
|
|
4485
|
+
}
|
|
4486
|
+
);
|
|
4487
|
+
const contactPerson = {
|
|
4488
|
+
firstName: data.firstName,
|
|
4489
|
+
lastName: data.lastName,
|
|
4490
|
+
title: data.title,
|
|
4491
|
+
email: data.email,
|
|
4492
|
+
phoneNumber: data.phoneNumber
|
|
4493
|
+
};
|
|
4494
|
+
const clinicAdminService = new ClinicAdminService(
|
|
4495
|
+
this.db,
|
|
4496
|
+
this.auth,
|
|
4497
|
+
this.app
|
|
4498
|
+
);
|
|
4499
|
+
const clinicGroupService = new ClinicGroupService(
|
|
4500
|
+
this.db,
|
|
4501
|
+
this.auth,
|
|
4502
|
+
this.app,
|
|
4503
|
+
clinicAdminService
|
|
4504
|
+
);
|
|
4505
|
+
const clinicService = new ClinicService(
|
|
4506
|
+
this.db,
|
|
4507
|
+
this.auth,
|
|
4508
|
+
this.app,
|
|
4509
|
+
clinicGroupService,
|
|
4510
|
+
clinicAdminService
|
|
4511
|
+
);
|
|
4512
|
+
clinicAdminService.setServices(clinicGroupService, clinicService);
|
|
4513
|
+
if (data.isCreatingNewGroup) {
|
|
4514
|
+
if (!data.clinicGroupData) {
|
|
4515
|
+
throw new Error(
|
|
4516
|
+
"Clinic group data is required when creating a new group"
|
|
4517
|
+
);
|
|
4518
|
+
}
|
|
4519
|
+
const createClinicGroupData = {
|
|
4520
|
+
name: data.clinicGroupData.name,
|
|
4521
|
+
hqLocation: data.clinicGroupData.hqLocation,
|
|
4522
|
+
contactInfo: data.clinicGroupData.contactInfo,
|
|
4523
|
+
contactPerson,
|
|
4524
|
+
ownerId: firebaseUser.uid,
|
|
4525
|
+
isActive: true,
|
|
4526
|
+
logo: data.clinicGroupData.logo,
|
|
4527
|
+
subscriptionModel: data.clinicGroupData.subscriptionModel || "no_subscription" /* NO_SUBSCRIPTION */
|
|
4528
|
+
};
|
|
4529
|
+
await clinicGroupService.createClinicGroup(
|
|
4530
|
+
createClinicGroupData,
|
|
4531
|
+
firebaseUser.uid,
|
|
4532
|
+
true
|
|
4533
|
+
);
|
|
4534
|
+
} else {
|
|
4535
|
+
if (!data.inviteToken) {
|
|
4536
|
+
throw new Error(
|
|
4537
|
+
"Invite token is required when joining an existing group"
|
|
4538
|
+
);
|
|
4539
|
+
}
|
|
4540
|
+
const groupsRef = (0, import_firestore19.collection)(this.db, CLINIC_GROUPS_COLLECTION);
|
|
4541
|
+
const q = (0, import_firestore19.query)(groupsRef);
|
|
4542
|
+
const querySnapshot = await (0, import_firestore19.getDocs)(q);
|
|
4543
|
+
let foundGroup = null;
|
|
4544
|
+
let foundToken = null;
|
|
4545
|
+
for (const docSnapshot of querySnapshot.docs) {
|
|
4546
|
+
const group = docSnapshot.data();
|
|
4547
|
+
const token = group.adminTokens.find(
|
|
4548
|
+
(t) => t.token === data.inviteToken && t.status === "active" /* ACTIVE */ && new Date(t.expiresAt.toDate()) > /* @__PURE__ */ new Date()
|
|
4549
|
+
);
|
|
4550
|
+
if (token) {
|
|
4551
|
+
foundGroup = group;
|
|
4552
|
+
foundToken = token;
|
|
4553
|
+
break;
|
|
4554
|
+
}
|
|
4555
|
+
}
|
|
4556
|
+
if (!foundGroup || !foundToken) {
|
|
4557
|
+
throw new Error("Invalid or expired invite token");
|
|
4558
|
+
}
|
|
4559
|
+
const createClinicAdminData = {
|
|
4560
|
+
userRef: firebaseUser.uid,
|
|
4561
|
+
clinicGroupId: foundGroup.id,
|
|
4562
|
+
isGroupOwner: false,
|
|
4563
|
+
clinicsManaged: [],
|
|
4564
|
+
contactInfo: contactPerson,
|
|
4565
|
+
roleTitle: data.title,
|
|
4566
|
+
isActive: true
|
|
4567
|
+
};
|
|
4568
|
+
await clinicAdminService.createClinicAdmin(createClinicAdminData);
|
|
4569
|
+
await clinicGroupService.verifyAndUseAdminToken(
|
|
4570
|
+
foundGroup.id,
|
|
4571
|
+
data.inviteToken,
|
|
4572
|
+
firebaseUser.uid
|
|
4573
|
+
);
|
|
4574
|
+
}
|
|
4575
|
+
return user;
|
|
4576
|
+
} catch (error) {
|
|
4577
|
+
if (error instanceof import_zod15.z.ZodError) {
|
|
4578
|
+
throw AUTH_ERRORS.VALIDATION_ERROR;
|
|
4579
|
+
}
|
|
4580
|
+
const firebaseError = error;
|
|
4581
|
+
if (firebaseError.code === "auth/email-already-in-use" /* EMAIL_ALREADY_IN_USE */) {
|
|
4582
|
+
throw AUTH_ERRORS.EMAIL_ALREADY_EXISTS;
|
|
4583
|
+
}
|
|
4584
|
+
throw error;
|
|
4585
|
+
}
|
|
4530
4586
|
}
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4587
|
+
/**
|
|
4588
|
+
* Prijavljuje korisnika sa email-om i lozinkom
|
|
4589
|
+
*/
|
|
4590
|
+
async signIn(email, password) {
|
|
4591
|
+
const { user: firebaseUser } = await (0, import_auth5.signInWithEmailAndPassword)(
|
|
4592
|
+
this.auth,
|
|
4593
|
+
email,
|
|
4594
|
+
password
|
|
4595
|
+
);
|
|
4596
|
+
return this.userService.getOrCreateUser(firebaseUser);
|
|
4539
4597
|
}
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
if (!group) {
|
|
4548
|
-
throw new Error("Clinic group not found");
|
|
4598
|
+
/**
|
|
4599
|
+
* Prijavljuje korisnika sa Facebook-om
|
|
4600
|
+
*/
|
|
4601
|
+
async signInWithFacebook() {
|
|
4602
|
+
const provider = new import_auth5.FacebookAuthProvider();
|
|
4603
|
+
const { user: firebaseUser } = await (0, import_auth5.signInWithPopup)(this.auth, provider);
|
|
4604
|
+
return this.userService.getOrCreateUser(firebaseUser);
|
|
4549
4605
|
}
|
|
4550
|
-
|
|
4551
|
-
|
|
4606
|
+
/**
|
|
4607
|
+
* Prijavljuje korisnika sa Google nalogom
|
|
4608
|
+
*/
|
|
4609
|
+
async signInWithGoogle(initialRole = "patient" /* PATIENT */) {
|
|
4610
|
+
const { user: firebaseUser } = await (0, import_auth5.signInWithPopup)(
|
|
4611
|
+
this.auth,
|
|
4612
|
+
this.googleProvider
|
|
4613
|
+
);
|
|
4614
|
+
return this.userService.getOrCreateUser(firebaseUser);
|
|
4552
4615
|
}
|
|
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");
|
|
4616
|
+
/**
|
|
4617
|
+
* Prijavljuje korisnika sa Apple-om
|
|
4618
|
+
*/
|
|
4619
|
+
async signInWithApple() {
|
|
4620
|
+
const provider = new import_auth5.OAuthProvider("apple.com");
|
|
4621
|
+
const { user: firebaseUser } = await (0, import_auth5.signInWithPopup)(this.auth, provider);
|
|
4622
|
+
return this.userService.getOrCreateUser(firebaseUser);
|
|
4575
4623
|
}
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4624
|
+
/**
|
|
4625
|
+
* Prijavljuje korisnika anonimno
|
|
4626
|
+
*/
|
|
4627
|
+
async signInAnonymously() {
|
|
4628
|
+
const { user: firebaseUser } = await (0, import_auth5.signInAnonymously)(this.auth);
|
|
4629
|
+
return this.userService.getOrCreateUser(firebaseUser);
|
|
4579
4630
|
}
|
|
4580
|
-
|
|
4581
|
-
|
|
4631
|
+
/**
|
|
4632
|
+
* Odjavljuje trenutnog korisnika
|
|
4633
|
+
*/
|
|
4634
|
+
async signOut() {
|
|
4635
|
+
await (0, import_auth5.signOut)(this.auth);
|
|
4582
4636
|
}
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
});
|
|
4591
|
-
throw new Error("Admin token has expired");
|
|
4637
|
+
/**
|
|
4638
|
+
* Vraća trenutno prijavljenog korisnika
|
|
4639
|
+
*/
|
|
4640
|
+
async getCurrentUser() {
|
|
4641
|
+
const firebaseUser = this.auth.currentUser;
|
|
4642
|
+
if (!firebaseUser) return null;
|
|
4643
|
+
return this.userService.getUserById(firebaseUser.uid);
|
|
4592
4644
|
}
|
|
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");
|
|
4645
|
+
/**
|
|
4646
|
+
* Registruje callback za promene stanja autentifikacije
|
|
4647
|
+
*/
|
|
4648
|
+
onAuthStateChange(callback) {
|
|
4649
|
+
return (0, import_auth5.onAuthStateChanged)(this.auth, callback);
|
|
4609
4650
|
}
|
|
4610
|
-
|
|
4611
|
-
|
|
4651
|
+
async upgradeAnonymousUser(email, password) {
|
|
4652
|
+
try {
|
|
4653
|
+
await emailSchema.parseAsync(email);
|
|
4654
|
+
await passwordSchema.parseAsync(password);
|
|
4655
|
+
const currentUser = this.auth.currentUser;
|
|
4656
|
+
if (!currentUser) {
|
|
4657
|
+
throw AUTH_ERRORS.NOT_AUTHENTICATED;
|
|
4658
|
+
}
|
|
4659
|
+
if (!currentUser.isAnonymous) {
|
|
4660
|
+
throw new AuthError(
|
|
4661
|
+
"User is not anonymous",
|
|
4662
|
+
"AUTH/NOT_ANONYMOUS_USER",
|
|
4663
|
+
400
|
|
4664
|
+
);
|
|
4665
|
+
}
|
|
4666
|
+
const credential = import_auth5.EmailAuthProvider.credential(email, password);
|
|
4667
|
+
await (0, import_auth5.linkWithCredential)(currentUser, credential);
|
|
4668
|
+
return await this.userService.upgradeAnonymousUser(
|
|
4669
|
+
currentUser.uid,
|
|
4670
|
+
email
|
|
4671
|
+
);
|
|
4672
|
+
} catch (error) {
|
|
4673
|
+
if (error instanceof import_zod15.z.ZodError) {
|
|
4674
|
+
throw AUTH_ERRORS.VALIDATION_ERROR;
|
|
4675
|
+
}
|
|
4676
|
+
const firebaseError = error;
|
|
4677
|
+
if (firebaseError.code === "auth/email-already-in-use" /* EMAIL_ALREADY_IN_USE */) {
|
|
4678
|
+
throw AUTH_ERRORS.EMAIL_ALREADY_EXISTS;
|
|
4679
|
+
}
|
|
4680
|
+
throw error;
|
|
4681
|
+
}
|
|
4612
4682
|
}
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
}
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4683
|
+
/**
|
|
4684
|
+
* Upgrades an anonymous user to a regular user by signing in with a Google account.
|
|
4685
|
+
*
|
|
4686
|
+
* @throws {AuthError} If the user is not anonymous.
|
|
4687
|
+
* @throws {AuthError} If the user is not authenticated.
|
|
4688
|
+
* @throws {AuthError} If the popup window is closed by the user.
|
|
4689
|
+
* @throws {FirebaseError} If any other Firebase error occurs.
|
|
4690
|
+
*
|
|
4691
|
+
* @returns {Promise<User>} The upgraded user.
|
|
4692
|
+
*/
|
|
4693
|
+
async upgradeAnonymousUserWithGoogle() {
|
|
4694
|
+
try {
|
|
4695
|
+
const currentUser = this.auth.currentUser;
|
|
4696
|
+
if (!currentUser) {
|
|
4697
|
+
throw AUTH_ERRORS.NOT_AUTHENTICATED;
|
|
4698
|
+
}
|
|
4699
|
+
if (!currentUser.isAnonymous) {
|
|
4700
|
+
throw new AuthError(
|
|
4701
|
+
"User is not anonymous",
|
|
4702
|
+
"AUTH/NOT_ANONYMOUS_USER",
|
|
4703
|
+
400
|
|
4704
|
+
);
|
|
4705
|
+
}
|
|
4706
|
+
const userCredential = await (0, import_auth5.signInWithPopup)(
|
|
4707
|
+
this.auth,
|
|
4708
|
+
this.googleProvider
|
|
4709
|
+
);
|
|
4710
|
+
if (!userCredential) throw AUTH_ERRORS.INVALID_CREDENTIAL;
|
|
4711
|
+
return await this.userService.upgradeAnonymousUser(
|
|
4712
|
+
currentUser.uid,
|
|
4713
|
+
userCredential.user.email
|
|
4714
|
+
);
|
|
4715
|
+
} catch (error) {
|
|
4716
|
+
const firebaseError = error;
|
|
4717
|
+
if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
|
|
4718
|
+
throw AUTH_ERRORS.POPUP_CLOSED;
|
|
4719
|
+
}
|
|
4720
|
+
throw error;
|
|
4721
|
+
}
|
|
4622
4722
|
}
|
|
4623
|
-
|
|
4624
|
-
|
|
4723
|
+
async upgradeAnonymousUserWithFacebook() {
|
|
4724
|
+
try {
|
|
4725
|
+
const currentUser = this.auth.currentUser;
|
|
4726
|
+
if (!currentUser) {
|
|
4727
|
+
throw AUTH_ERRORS.NOT_AUTHENTICATED;
|
|
4728
|
+
}
|
|
4729
|
+
if (!currentUser.isAnonymous) {
|
|
4730
|
+
throw new AuthError(
|
|
4731
|
+
"User is not anonymous",
|
|
4732
|
+
"AUTH/NOT_ANONYMOUS_USER",
|
|
4733
|
+
400
|
|
4734
|
+
);
|
|
4735
|
+
}
|
|
4736
|
+
this.facebookProvider.addScope("email");
|
|
4737
|
+
const userCredential = await (0, import_auth5.signInWithPopup)(
|
|
4738
|
+
this.auth,
|
|
4739
|
+
this.facebookProvider
|
|
4740
|
+
);
|
|
4741
|
+
if (!userCredential) throw AUTH_ERRORS.INVALID_CREDENTIAL;
|
|
4742
|
+
return await this.userService.upgradeAnonymousUser(
|
|
4743
|
+
currentUser.uid,
|
|
4744
|
+
userCredential.user.email
|
|
4745
|
+
);
|
|
4746
|
+
} catch (error) {
|
|
4747
|
+
const firebaseError = error;
|
|
4748
|
+
if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
|
|
4749
|
+
throw AUTH_ERRORS.POPUP_CLOSED;
|
|
4750
|
+
}
|
|
4751
|
+
throw error;
|
|
4752
|
+
}
|
|
4625
4753
|
}
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4754
|
+
async upgradeAnonymousUserWithApple() {
|
|
4755
|
+
try {
|
|
4756
|
+
const currentUser = this.auth.currentUser;
|
|
4757
|
+
if (!currentUser) {
|
|
4758
|
+
throw AUTH_ERRORS.NOT_AUTHENTICATED;
|
|
4759
|
+
}
|
|
4760
|
+
if (!currentUser.isAnonymous) {
|
|
4761
|
+
throw new AuthError(
|
|
4762
|
+
"User is not anonymous",
|
|
4763
|
+
"AUTH/NOT_ANONYMOUS_USER",
|
|
4764
|
+
400
|
|
4765
|
+
);
|
|
4766
|
+
}
|
|
4767
|
+
this.appleProvider.addScope("email");
|
|
4768
|
+
this.appleProvider.addScope("name");
|
|
4769
|
+
const userCredential = await (0, import_auth5.signInWithPopup)(
|
|
4770
|
+
this.auth,
|
|
4771
|
+
this.appleProvider
|
|
4772
|
+
);
|
|
4773
|
+
if (!userCredential) throw AUTH_ERRORS.INVALID_CREDENTIAL;
|
|
4774
|
+
return await this.userService.upgradeAnonymousUser(
|
|
4775
|
+
currentUser.uid,
|
|
4776
|
+
userCredential.user.email
|
|
4777
|
+
);
|
|
4778
|
+
} catch (error) {
|
|
4779
|
+
const firebaseError = error;
|
|
4780
|
+
if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
|
|
4781
|
+
throw AUTH_ERRORS.POPUP_CLOSED;
|
|
4782
|
+
}
|
|
4783
|
+
throw error;
|
|
4784
|
+
}
|
|
4634
4785
|
}
|
|
4635
4786
|
/**
|
|
4636
|
-
*
|
|
4787
|
+
* Šalje email za resetovanje lozinke korisniku
|
|
4788
|
+
* @param email Email adresa korisnika
|
|
4789
|
+
* @returns Promise koji se razrešava kada je email poslat
|
|
4637
4790
|
*/
|
|
4638
|
-
async
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4791
|
+
async sendPasswordResetEmail(email) {
|
|
4792
|
+
try {
|
|
4793
|
+
await emailSchema.parseAsync(email);
|
|
4794
|
+
await (0, import_auth5.sendPasswordResetEmail)(this.auth, email);
|
|
4795
|
+
} catch (error) {
|
|
4796
|
+
if (error instanceof import_zod15.z.ZodError) {
|
|
4797
|
+
throw AUTH_ERRORS.VALIDATION_ERROR;
|
|
4798
|
+
}
|
|
4799
|
+
const firebaseError = error;
|
|
4800
|
+
if (firebaseError.code === "auth/user-not-found" /* USER_NOT_FOUND */) {
|
|
4801
|
+
throw AUTH_ERRORS.USER_NOT_FOUND;
|
|
4802
|
+
}
|
|
4803
|
+
throw error;
|
|
4804
|
+
}
|
|
4646
4805
|
}
|
|
4647
4806
|
/**
|
|
4648
|
-
*
|
|
4807
|
+
* Verifikuje kod za resetovanje lozinke iz email linka
|
|
4808
|
+
* @param oobCode Kod iz URL-a za resetovanje lozinke
|
|
4809
|
+
* @returns Promise koji se razrešava sa email adresom korisnika ako je kod validan
|
|
4649
4810
|
*/
|
|
4650
|
-
async
|
|
4651
|
-
|
|
4811
|
+
async verifyPasswordResetCode(oobCode) {
|
|
4812
|
+
try {
|
|
4813
|
+
return await (0, import_auth5.verifyPasswordResetCode)(this.auth, oobCode);
|
|
4814
|
+
} catch (error) {
|
|
4815
|
+
const firebaseError = error;
|
|
4816
|
+
if (firebaseError.code === "auth/expired-action-code" /* EXPIRED_ACTION_CODE */) {
|
|
4817
|
+
throw AUTH_ERRORS.EXPIRED_ACTION_CODE;
|
|
4818
|
+
} else if (firebaseError.code === "auth/invalid-action-code" /* INVALID_ACTION_CODE */) {
|
|
4819
|
+
throw AUTH_ERRORS.INVALID_ACTION_CODE;
|
|
4820
|
+
}
|
|
4821
|
+
throw error;
|
|
4822
|
+
}
|
|
4652
4823
|
}
|
|
4653
4824
|
/**
|
|
4654
|
-
*
|
|
4825
|
+
* Potvrđuje resetovanje lozinke i postavlja novu lozinku
|
|
4826
|
+
* @param oobCode Kod iz URL-a za resetovanje lozinke
|
|
4827
|
+
* @param newPassword Nova lozinka
|
|
4828
|
+
* @returns Promise koji se razrešava kada je lozinka promenjena
|
|
4655
4829
|
*/
|
|
4656
|
-
async
|
|
4657
|
-
|
|
4830
|
+
async confirmPasswordReset(oobCode, newPassword) {
|
|
4831
|
+
try {
|
|
4832
|
+
await passwordSchema.parseAsync(newPassword);
|
|
4833
|
+
await (0, import_auth5.confirmPasswordReset)(this.auth, oobCode, newPassword);
|
|
4834
|
+
} catch (error) {
|
|
4835
|
+
if (error instanceof import_zod15.z.ZodError) {
|
|
4836
|
+
throw AUTH_ERRORS.VALIDATION_ERROR;
|
|
4837
|
+
}
|
|
4838
|
+
const firebaseError = error;
|
|
4839
|
+
if (firebaseError.code === "auth/expired-action-code" /* EXPIRED_ACTION_CODE */) {
|
|
4840
|
+
throw AUTH_ERRORS.EXPIRED_ACTION_CODE;
|
|
4841
|
+
} else if (firebaseError.code === "auth/invalid-action-code" /* INVALID_ACTION_CODE */) {
|
|
4842
|
+
throw AUTH_ERRORS.INVALID_ACTION_CODE;
|
|
4843
|
+
} else if (firebaseError.code === "auth/weak-password" /* WEAK_PASSWORD */) {
|
|
4844
|
+
throw AUTH_ERRORS.WEAK_PASSWORD;
|
|
4845
|
+
}
|
|
4846
|
+
throw error;
|
|
4847
|
+
}
|
|
4658
4848
|
}
|
|
4849
|
+
};
|
|
4850
|
+
|
|
4851
|
+
// src/services/notifications/notification.service.ts
|
|
4852
|
+
var import_firestore20 = require("firebase/firestore");
|
|
4853
|
+
|
|
4854
|
+
// src/types/notifications/index.ts
|
|
4855
|
+
var NotificationType = /* @__PURE__ */ ((NotificationType3) => {
|
|
4856
|
+
NotificationType3["PRE_REQUIREMENT"] = "preRequirement";
|
|
4857
|
+
NotificationType3["POST_REQUIREMENT"] = "postRequirement";
|
|
4858
|
+
NotificationType3["APPOINTMENT_REMINDER"] = "appointmentReminder";
|
|
4859
|
+
NotificationType3["APPOINTMENT_NOTIFICATION"] = "appointmentNotification";
|
|
4860
|
+
return NotificationType3;
|
|
4861
|
+
})(NotificationType || {});
|
|
4862
|
+
var NOTIFICATIONS_COLLECTION = "notifications";
|
|
4863
|
+
var NotificationStatus = /* @__PURE__ */ ((NotificationStatus2) => {
|
|
4864
|
+
NotificationStatus2["PENDING"] = "pending";
|
|
4865
|
+
NotificationStatus2["SENT"] = "sent";
|
|
4866
|
+
NotificationStatus2["FAILED"] = "failed";
|
|
4867
|
+
NotificationStatus2["CANCELLED"] = "cancelled";
|
|
4868
|
+
NotificationStatus2["PARTIAL_SUCCESS"] = "partialSuccess";
|
|
4869
|
+
return NotificationStatus2;
|
|
4870
|
+
})(NotificationStatus || {});
|
|
4871
|
+
|
|
4872
|
+
// src/services/notifications/notification.service.ts
|
|
4873
|
+
var NotificationService = class extends BaseService {
|
|
4659
4874
|
/**
|
|
4660
|
-
*
|
|
4875
|
+
* Kreira novu notifikaciju
|
|
4661
4876
|
*/
|
|
4662
|
-
async
|
|
4663
|
-
|
|
4877
|
+
async createNotification(notification) {
|
|
4878
|
+
const notificationsRef = (0, import_firestore20.collection)(this.db, NOTIFICATIONS_COLLECTION);
|
|
4879
|
+
const now = import_firestore20.Timestamp.now();
|
|
4880
|
+
const notificationData = {
|
|
4881
|
+
...notification,
|
|
4882
|
+
createdAt: now,
|
|
4883
|
+
updatedAt: now,
|
|
4884
|
+
status: "pending" /* PENDING */,
|
|
4885
|
+
isRead: false,
|
|
4886
|
+
userRole: notification.userRole || "patient" /* PATIENT */
|
|
4887
|
+
};
|
|
4888
|
+
const docRef = await (0, import_firestore20.addDoc)(notificationsRef, notificationData);
|
|
4889
|
+
return {
|
|
4890
|
+
...notificationData,
|
|
4891
|
+
id: docRef.id
|
|
4892
|
+
};
|
|
4664
4893
|
}
|
|
4665
4894
|
/**
|
|
4666
|
-
*
|
|
4895
|
+
* Dohvata notifikaciju po ID-u
|
|
4667
4896
|
*/
|
|
4668
|
-
async
|
|
4669
|
-
|
|
4897
|
+
async getNotification(notificationId) {
|
|
4898
|
+
const notificationRef = (0, import_firestore20.doc)(
|
|
4899
|
+
this.db,
|
|
4900
|
+
NOTIFICATIONS_COLLECTION,
|
|
4901
|
+
notificationId
|
|
4902
|
+
);
|
|
4903
|
+
const notificationDoc = await (0, import_firestore20.getDoc)(notificationRef);
|
|
4904
|
+
if (!notificationDoc.exists()) {
|
|
4905
|
+
return null;
|
|
4906
|
+
}
|
|
4907
|
+
return {
|
|
4908
|
+
id: notificationDoc.id,
|
|
4909
|
+
...notificationDoc.data()
|
|
4910
|
+
};
|
|
4670
4911
|
}
|
|
4671
4912
|
/**
|
|
4672
|
-
*
|
|
4913
|
+
* Dohvata sve notifikacije za korisnika
|
|
4673
4914
|
*/
|
|
4674
|
-
async
|
|
4675
|
-
|
|
4915
|
+
async getUserNotifications(userId) {
|
|
4916
|
+
const q = (0, import_firestore20.query)(
|
|
4917
|
+
(0, import_firestore20.collection)(this.db, NOTIFICATIONS_COLLECTION),
|
|
4918
|
+
(0, import_firestore20.where)("userId", "==", userId),
|
|
4919
|
+
(0, import_firestore20.orderBy)("notificationTime", "desc")
|
|
4920
|
+
);
|
|
4921
|
+
const querySnapshot = await (0, import_firestore20.getDocs)(q);
|
|
4922
|
+
return querySnapshot.docs.map((doc14) => ({
|
|
4923
|
+
id: doc14.id,
|
|
4924
|
+
...doc14.data()
|
|
4925
|
+
}));
|
|
4676
4926
|
}
|
|
4677
4927
|
/**
|
|
4678
|
-
*
|
|
4928
|
+
* Dohvata nepročitane notifikacije za korisnika
|
|
4679
4929
|
*/
|
|
4680
|
-
async
|
|
4681
|
-
|
|
4930
|
+
async getUnreadNotifications(userId) {
|
|
4931
|
+
const q = (0, import_firestore20.query)(
|
|
4932
|
+
(0, import_firestore20.collection)(this.db, NOTIFICATIONS_COLLECTION),
|
|
4933
|
+
(0, import_firestore20.where)("userId", "==", userId),
|
|
4934
|
+
(0, import_firestore20.where)("isRead", "==", false),
|
|
4935
|
+
(0, import_firestore20.orderBy)("notificationTime", "desc")
|
|
4936
|
+
);
|
|
4937
|
+
const querySnapshot = await (0, import_firestore20.getDocs)(q);
|
|
4938
|
+
return querySnapshot.docs.map((doc14) => ({
|
|
4939
|
+
id: doc14.id,
|
|
4940
|
+
...doc14.data()
|
|
4941
|
+
}));
|
|
4682
4942
|
}
|
|
4683
4943
|
/**
|
|
4684
|
-
*
|
|
4944
|
+
* Označava notifikaciju kao pročitanu
|
|
4685
4945
|
*/
|
|
4686
|
-
async
|
|
4687
|
-
|
|
4946
|
+
async markAsRead(notificationId) {
|
|
4947
|
+
const notificationRef = (0, import_firestore20.doc)(
|
|
4688
4948
|
this.db,
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
data
|
|
4949
|
+
NOTIFICATIONS_COLLECTION,
|
|
4950
|
+
notificationId
|
|
4692
4951
|
);
|
|
4952
|
+
await (0, import_firestore20.updateDoc)(notificationRef, {
|
|
4953
|
+
isRead: true,
|
|
4954
|
+
updatedAt: import_firestore20.Timestamp.now()
|
|
4955
|
+
});
|
|
4693
4956
|
}
|
|
4694
4957
|
/**
|
|
4695
|
-
*
|
|
4958
|
+
* Označava sve notifikacije korisnika kao pročitane
|
|
4696
4959
|
*/
|
|
4697
|
-
async
|
|
4698
|
-
|
|
4960
|
+
async markAllAsRead(userId) {
|
|
4961
|
+
const notifications = await this.getUnreadNotifications(userId);
|
|
4962
|
+
const batch = (0, import_firestore20.writeBatch)(this.db);
|
|
4963
|
+
notifications.forEach((notification) => {
|
|
4964
|
+
const notificationRef = (0, import_firestore20.doc)(
|
|
4965
|
+
this.db,
|
|
4966
|
+
NOTIFICATIONS_COLLECTION,
|
|
4967
|
+
notification.id
|
|
4968
|
+
);
|
|
4969
|
+
batch.update(notificationRef, {
|
|
4970
|
+
isRead: true,
|
|
4971
|
+
updatedAt: import_firestore20.Timestamp.now()
|
|
4972
|
+
});
|
|
4973
|
+
});
|
|
4974
|
+
await batch.commit();
|
|
4975
|
+
}
|
|
4976
|
+
/**
|
|
4977
|
+
* Ažurira status notifikacije
|
|
4978
|
+
*/
|
|
4979
|
+
async updateNotificationStatus(notificationId, status) {
|
|
4980
|
+
const notificationRef = (0, import_firestore20.doc)(
|
|
4699
4981
|
this.db,
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
userRef
|
|
4982
|
+
NOTIFICATIONS_COLLECTION,
|
|
4983
|
+
notificationId
|
|
4703
4984
|
);
|
|
4985
|
+
await (0, import_firestore20.updateDoc)(notificationRef, {
|
|
4986
|
+
status,
|
|
4987
|
+
updatedAt: import_firestore20.Timestamp.now()
|
|
4988
|
+
});
|
|
4704
4989
|
}
|
|
4705
4990
|
/**
|
|
4706
|
-
* Briše
|
|
4991
|
+
* Briše notifikaciju
|
|
4707
4992
|
*/
|
|
4708
|
-
async
|
|
4709
|
-
|
|
4993
|
+
async deleteNotification(notificationId) {
|
|
4994
|
+
const notificationRef = (0, import_firestore20.doc)(
|
|
4710
4995
|
this.db,
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
adminId
|
|
4996
|
+
NOTIFICATIONS_COLLECTION,
|
|
4997
|
+
notificationId
|
|
4714
4998
|
);
|
|
4999
|
+
await (0, import_firestore20.deleteDoc)(notificationRef);
|
|
4715
5000
|
}
|
|
4716
5001
|
/**
|
|
4717
|
-
* Dohvata
|
|
5002
|
+
* Dohvata notifikacije po tipu
|
|
4718
5003
|
*/
|
|
4719
|
-
async
|
|
4720
|
-
|
|
5004
|
+
async getNotificationsByType(userId, type) {
|
|
5005
|
+
const q = (0, import_firestore20.query)(
|
|
5006
|
+
(0, import_firestore20.collection)(this.db, NOTIFICATIONS_COLLECTION),
|
|
5007
|
+
(0, import_firestore20.where)("userId", "==", userId),
|
|
5008
|
+
(0, import_firestore20.where)("notificationType", "==", type),
|
|
5009
|
+
(0, import_firestore20.orderBy)("notificationTime", "desc")
|
|
5010
|
+
);
|
|
5011
|
+
const querySnapshot = await (0, import_firestore20.getDocs)(q);
|
|
5012
|
+
return querySnapshot.docs.map((doc14) => ({
|
|
5013
|
+
id: doc14.id,
|
|
5014
|
+
...doc14.data()
|
|
5015
|
+
}));
|
|
5016
|
+
}
|
|
5017
|
+
/**
|
|
5018
|
+
* Dohvata notifikacije za određeni termin
|
|
5019
|
+
*/
|
|
5020
|
+
async getAppointmentNotifications(appointmentId) {
|
|
5021
|
+
const q = (0, import_firestore20.query)(
|
|
5022
|
+
(0, import_firestore20.collection)(this.db, NOTIFICATIONS_COLLECTION),
|
|
5023
|
+
(0, import_firestore20.where)("appointmentId", "==", appointmentId),
|
|
5024
|
+
(0, import_firestore20.orderBy)("notificationTime", "desc")
|
|
5025
|
+
);
|
|
5026
|
+
const querySnapshot = await (0, import_firestore20.getDocs)(q);
|
|
5027
|
+
return querySnapshot.docs.map((doc14) => ({
|
|
5028
|
+
id: doc14.id,
|
|
5029
|
+
...doc14.data()
|
|
5030
|
+
}));
|
|
4721
5031
|
}
|
|
4722
5032
|
};
|
|
4723
5033
|
|
|
4724
5034
|
// src/services/documentation-templates/documentation-template.service.ts
|
|
4725
|
-
var
|
|
5035
|
+
var import_firestore21 = require("firebase/firestore");
|
|
4726
5036
|
var DocumentationTemplateService = class extends BaseService {
|
|
4727
5037
|
constructor() {
|
|
4728
5038
|
super(...arguments);
|
|
4729
|
-
this.collectionRef = (0,
|
|
5039
|
+
this.collectionRef = (0, import_firestore21.collection)(
|
|
4730
5040
|
this.db,
|
|
4731
5041
|
DOCUMENTATION_TEMPLATES_COLLECTION
|
|
4732
5042
|
);
|
|
@@ -4757,8 +5067,8 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
4757
5067
|
isActive: true,
|
|
4758
5068
|
tags: validatedData.tags || []
|
|
4759
5069
|
};
|
|
4760
|
-
const docRef = (0,
|
|
4761
|
-
await (0,
|
|
5070
|
+
const docRef = (0, import_firestore21.doc)(this.collectionRef, templateId);
|
|
5071
|
+
await (0, import_firestore21.setDoc)(docRef, template);
|
|
4762
5072
|
return template;
|
|
4763
5073
|
}
|
|
4764
5074
|
/**
|
|
@@ -4767,8 +5077,8 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
4767
5077
|
* @returns The template or null if not found
|
|
4768
5078
|
*/
|
|
4769
5079
|
async getTemplateById(templateId) {
|
|
4770
|
-
const docRef = (0,
|
|
4771
|
-
const docSnap = await (0,
|
|
5080
|
+
const docRef = (0, import_firestore21.doc)(this.collectionRef, templateId);
|
|
5081
|
+
const docSnap = await (0, import_firestore21.getDoc)(docRef);
|
|
4772
5082
|
if (!docSnap.exists()) {
|
|
4773
5083
|
return null;
|
|
4774
5084
|
}
|
|
@@ -4799,8 +5109,8 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
4799
5109
|
updatedAt: Date.now(),
|
|
4800
5110
|
version: template.version + 1
|
|
4801
5111
|
};
|
|
4802
|
-
const docRef = (0,
|
|
4803
|
-
await (0,
|
|
5112
|
+
const docRef = (0, import_firestore21.doc)(this.collectionRef, templateId);
|
|
5113
|
+
await (0, import_firestore21.updateDoc)(docRef, updateData);
|
|
4804
5114
|
return {
|
|
4805
5115
|
...template,
|
|
4806
5116
|
...updateData
|
|
@@ -4811,8 +5121,8 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
4811
5121
|
* @param templateId - ID of the template to delete
|
|
4812
5122
|
*/
|
|
4813
5123
|
async deleteTemplate(templateId) {
|
|
4814
|
-
const docRef = (0,
|
|
4815
|
-
await (0,
|
|
5124
|
+
const docRef = (0, import_firestore21.doc)(this.collectionRef, templateId);
|
|
5125
|
+
await (0, import_firestore21.deleteDoc)(docRef);
|
|
4816
5126
|
}
|
|
4817
5127
|
/**
|
|
4818
5128
|
* Get all active templates
|
|
@@ -4821,21 +5131,21 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
4821
5131
|
* @returns Array of templates and the last document for pagination
|
|
4822
5132
|
*/
|
|
4823
5133
|
async getActiveTemplates(pageSize = 20, lastDoc) {
|
|
4824
|
-
let q = (0,
|
|
5134
|
+
let q = (0, import_firestore21.query)(
|
|
4825
5135
|
this.collectionRef,
|
|
4826
|
-
(0,
|
|
4827
|
-
(0,
|
|
4828
|
-
(0,
|
|
5136
|
+
(0, import_firestore21.where)("isActive", "==", true),
|
|
5137
|
+
(0, import_firestore21.orderBy)("updatedAt", "desc"),
|
|
5138
|
+
(0, import_firestore21.limit)(pageSize)
|
|
4829
5139
|
);
|
|
4830
5140
|
if (lastDoc) {
|
|
4831
|
-
q = (0,
|
|
5141
|
+
q = (0, import_firestore21.query)(q, (0, import_firestore21.startAfter)(lastDoc));
|
|
4832
5142
|
}
|
|
4833
|
-
const querySnapshot = await (0,
|
|
5143
|
+
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
4834
5144
|
const templates = [];
|
|
4835
5145
|
let lastVisible = null;
|
|
4836
|
-
querySnapshot.forEach((
|
|
4837
|
-
templates.push(
|
|
4838
|
-
lastVisible =
|
|
5146
|
+
querySnapshot.forEach((doc14) => {
|
|
5147
|
+
templates.push(doc14.data());
|
|
5148
|
+
lastVisible = doc14;
|
|
4839
5149
|
});
|
|
4840
5150
|
return {
|
|
4841
5151
|
templates,
|
|
@@ -4850,22 +5160,22 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
4850
5160
|
* @returns Array of templates and the last document for pagination
|
|
4851
5161
|
*/
|
|
4852
5162
|
async getTemplatesByTags(tags, pageSize = 20, lastDoc) {
|
|
4853
|
-
let q = (0,
|
|
5163
|
+
let q = (0, import_firestore21.query)(
|
|
4854
5164
|
this.collectionRef,
|
|
4855
|
-
(0,
|
|
4856
|
-
(0,
|
|
4857
|
-
(0,
|
|
4858
|
-
(0,
|
|
5165
|
+
(0, import_firestore21.where)("isActive", "==", true),
|
|
5166
|
+
(0, import_firestore21.where)("tags", "array-contains-any", tags),
|
|
5167
|
+
(0, import_firestore21.orderBy)("updatedAt", "desc"),
|
|
5168
|
+
(0, import_firestore21.limit)(pageSize)
|
|
4859
5169
|
);
|
|
4860
5170
|
if (lastDoc) {
|
|
4861
|
-
q = (0,
|
|
5171
|
+
q = (0, import_firestore21.query)(q, (0, import_firestore21.startAfter)(lastDoc));
|
|
4862
5172
|
}
|
|
4863
|
-
const querySnapshot = await (0,
|
|
5173
|
+
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
4864
5174
|
const templates = [];
|
|
4865
5175
|
let lastVisible = null;
|
|
4866
|
-
querySnapshot.forEach((
|
|
4867
|
-
templates.push(
|
|
4868
|
-
lastVisible =
|
|
5176
|
+
querySnapshot.forEach((doc14) => {
|
|
5177
|
+
templates.push(doc14.data());
|
|
5178
|
+
lastVisible = doc14;
|
|
4869
5179
|
});
|
|
4870
5180
|
return {
|
|
4871
5181
|
templates,
|
|
@@ -4880,21 +5190,21 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
4880
5190
|
* @returns Array of templates and the last document for pagination
|
|
4881
5191
|
*/
|
|
4882
5192
|
async getTemplatesByCreator(userId, pageSize = 20, lastDoc) {
|
|
4883
|
-
let q = (0,
|
|
5193
|
+
let q = (0, import_firestore21.query)(
|
|
4884
5194
|
this.collectionRef,
|
|
4885
|
-
(0,
|
|
4886
|
-
(0,
|
|
4887
|
-
(0,
|
|
5195
|
+
(0, import_firestore21.where)("createdBy", "==", userId),
|
|
5196
|
+
(0, import_firestore21.orderBy)("updatedAt", "desc"),
|
|
5197
|
+
(0, import_firestore21.limit)(pageSize)
|
|
4888
5198
|
);
|
|
4889
5199
|
if (lastDoc) {
|
|
4890
|
-
q = (0,
|
|
5200
|
+
q = (0, import_firestore21.query)(q, (0, import_firestore21.startAfter)(lastDoc));
|
|
4891
5201
|
}
|
|
4892
|
-
const querySnapshot = await (0,
|
|
5202
|
+
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
4893
5203
|
const templates = [];
|
|
4894
5204
|
let lastVisible = null;
|
|
4895
|
-
querySnapshot.forEach((
|
|
4896
|
-
templates.push(
|
|
4897
|
-
lastVisible =
|
|
5205
|
+
querySnapshot.forEach((doc14) => {
|
|
5206
|
+
templates.push(doc14.data());
|
|
5207
|
+
lastVisible = doc14;
|
|
4898
5208
|
});
|
|
4899
5209
|
return {
|
|
4900
5210
|
templates,
|
|
@@ -4904,11 +5214,11 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
4904
5214
|
};
|
|
4905
5215
|
|
|
4906
5216
|
// src/services/documentation-templates/filled-document.service.ts
|
|
4907
|
-
var
|
|
5217
|
+
var import_firestore22 = require("firebase/firestore");
|
|
4908
5218
|
var FilledDocumentService = class extends BaseService {
|
|
4909
5219
|
constructor(...args) {
|
|
4910
5220
|
super(...args);
|
|
4911
|
-
this.collectionRef = (0,
|
|
5221
|
+
this.collectionRef = (0, import_firestore22.collection)(
|
|
4912
5222
|
this.db,
|
|
4913
5223
|
FILLED_DOCUMENTS_COLLECTION
|
|
4914
5224
|
);
|
|
@@ -4941,8 +5251,8 @@ var FilledDocumentService = class extends BaseService {
|
|
|
4941
5251
|
values: {},
|
|
4942
5252
|
status: "draft" /* DRAFT */
|
|
4943
5253
|
};
|
|
4944
|
-
const docRef = (0,
|
|
4945
|
-
await (0,
|
|
5254
|
+
const docRef = (0, import_firestore22.doc)(this.collectionRef, documentId);
|
|
5255
|
+
await (0, import_firestore22.setDoc)(docRef, filledDocument);
|
|
4946
5256
|
return filledDocument;
|
|
4947
5257
|
}
|
|
4948
5258
|
/**
|
|
@@ -4951,8 +5261,8 @@ var FilledDocumentService = class extends BaseService {
|
|
|
4951
5261
|
* @returns The filled document or null if not found
|
|
4952
5262
|
*/
|
|
4953
5263
|
async getFilledDocumentById(documentId) {
|
|
4954
|
-
const docRef = (0,
|
|
4955
|
-
const docSnap = await (0,
|
|
5264
|
+
const docRef = (0, import_firestore22.doc)(this.collectionRef, documentId);
|
|
5265
|
+
const docSnap = await (0, import_firestore22.getDoc)(docRef);
|
|
4956
5266
|
if (!docSnap.exists()) {
|
|
4957
5267
|
return null;
|
|
4958
5268
|
}
|
|
@@ -4980,8 +5290,8 @@ var FilledDocumentService = class extends BaseService {
|
|
|
4980
5290
|
if (status) {
|
|
4981
5291
|
updateData.status = status;
|
|
4982
5292
|
}
|
|
4983
|
-
const docRef = (0,
|
|
4984
|
-
await (0,
|
|
5293
|
+
const docRef = (0, import_firestore22.doc)(this.collectionRef, documentId);
|
|
5294
|
+
await (0, import_firestore22.updateDoc)(docRef, updateData);
|
|
4985
5295
|
return {
|
|
4986
5296
|
...filledDocument,
|
|
4987
5297
|
...updateData
|
|
@@ -4995,21 +5305,21 @@ var FilledDocumentService = class extends BaseService {
|
|
|
4995
5305
|
* @returns Array of filled documents and the last document for pagination
|
|
4996
5306
|
*/
|
|
4997
5307
|
async getFilledDocumentsByPatient(patientId, pageSize = 20, lastDoc) {
|
|
4998
|
-
let q = (0,
|
|
5308
|
+
let q = (0, import_firestore22.query)(
|
|
4999
5309
|
this.collectionRef,
|
|
5000
|
-
(0,
|
|
5001
|
-
(0,
|
|
5002
|
-
(0,
|
|
5310
|
+
(0, import_firestore22.where)("patientId", "==", patientId),
|
|
5311
|
+
(0, import_firestore22.orderBy)("updatedAt", "desc"),
|
|
5312
|
+
(0, import_firestore22.limit)(pageSize)
|
|
5003
5313
|
);
|
|
5004
5314
|
if (lastDoc) {
|
|
5005
|
-
q = (0,
|
|
5315
|
+
q = (0, import_firestore22.query)(q, (0, import_firestore22.startAfter)(lastDoc));
|
|
5006
5316
|
}
|
|
5007
|
-
const querySnapshot = await (0,
|
|
5317
|
+
const querySnapshot = await (0, import_firestore22.getDocs)(q);
|
|
5008
5318
|
const documents = [];
|
|
5009
5319
|
let lastVisible = null;
|
|
5010
|
-
querySnapshot.forEach((
|
|
5011
|
-
documents.push(
|
|
5012
|
-
lastVisible =
|
|
5320
|
+
querySnapshot.forEach((doc14) => {
|
|
5321
|
+
documents.push(doc14.data());
|
|
5322
|
+
lastVisible = doc14;
|
|
5013
5323
|
});
|
|
5014
5324
|
return {
|
|
5015
5325
|
documents,
|
|
@@ -5024,21 +5334,21 @@ var FilledDocumentService = class extends BaseService {
|
|
|
5024
5334
|
* @returns Array of filled documents and the last document for pagination
|
|
5025
5335
|
*/
|
|
5026
5336
|
async getFilledDocumentsByPractitioner(practitionerId, pageSize = 20, lastDoc) {
|
|
5027
|
-
let q = (0,
|
|
5337
|
+
let q = (0, import_firestore22.query)(
|
|
5028
5338
|
this.collectionRef,
|
|
5029
|
-
(0,
|
|
5030
|
-
(0,
|
|
5031
|
-
(0,
|
|
5339
|
+
(0, import_firestore22.where)("practitionerId", "==", practitionerId),
|
|
5340
|
+
(0, import_firestore22.orderBy)("updatedAt", "desc"),
|
|
5341
|
+
(0, import_firestore22.limit)(pageSize)
|
|
5032
5342
|
);
|
|
5033
5343
|
if (lastDoc) {
|
|
5034
|
-
q = (0,
|
|
5344
|
+
q = (0, import_firestore22.query)(q, (0, import_firestore22.startAfter)(lastDoc));
|
|
5035
5345
|
}
|
|
5036
|
-
const querySnapshot = await (0,
|
|
5346
|
+
const querySnapshot = await (0, import_firestore22.getDocs)(q);
|
|
5037
5347
|
const documents = [];
|
|
5038
5348
|
let lastVisible = null;
|
|
5039
|
-
querySnapshot.forEach((
|
|
5040
|
-
documents.push(
|
|
5041
|
-
lastVisible =
|
|
5349
|
+
querySnapshot.forEach((doc14) => {
|
|
5350
|
+
documents.push(doc14.data());
|
|
5351
|
+
lastVisible = doc14;
|
|
5042
5352
|
});
|
|
5043
5353
|
return {
|
|
5044
5354
|
documents,
|
|
@@ -5053,21 +5363,21 @@ var FilledDocumentService = class extends BaseService {
|
|
|
5053
5363
|
* @returns Array of filled documents and the last document for pagination
|
|
5054
5364
|
*/
|
|
5055
5365
|
async getFilledDocumentsByClinic(clinicId, pageSize = 20, lastDoc) {
|
|
5056
|
-
let q = (0,
|
|
5366
|
+
let q = (0, import_firestore22.query)(
|
|
5057
5367
|
this.collectionRef,
|
|
5058
|
-
(0,
|
|
5059
|
-
(0,
|
|
5060
|
-
(0,
|
|
5368
|
+
(0, import_firestore22.where)("clinicId", "==", clinicId),
|
|
5369
|
+
(0, import_firestore22.orderBy)("updatedAt", "desc"),
|
|
5370
|
+
(0, import_firestore22.limit)(pageSize)
|
|
5061
5371
|
);
|
|
5062
5372
|
if (lastDoc) {
|
|
5063
|
-
q = (0,
|
|
5373
|
+
q = (0, import_firestore22.query)(q, (0, import_firestore22.startAfter)(lastDoc));
|
|
5064
5374
|
}
|
|
5065
|
-
const querySnapshot = await (0,
|
|
5375
|
+
const querySnapshot = await (0, import_firestore22.getDocs)(q);
|
|
5066
5376
|
const documents = [];
|
|
5067
5377
|
let lastVisible = null;
|
|
5068
|
-
querySnapshot.forEach((
|
|
5069
|
-
documents.push(
|
|
5070
|
-
lastVisible =
|
|
5378
|
+
querySnapshot.forEach((doc14) => {
|
|
5379
|
+
documents.push(doc14.data());
|
|
5380
|
+
lastVisible = doc14;
|
|
5071
5381
|
});
|
|
5072
5382
|
return {
|
|
5073
5383
|
documents,
|
|
@@ -5082,21 +5392,21 @@ var FilledDocumentService = class extends BaseService {
|
|
|
5082
5392
|
* @returns Array of filled documents and the last document for pagination
|
|
5083
5393
|
*/
|
|
5084
5394
|
async getFilledDocumentsByTemplate(templateId, pageSize = 20, lastDoc) {
|
|
5085
|
-
let q = (0,
|
|
5395
|
+
let q = (0, import_firestore22.query)(
|
|
5086
5396
|
this.collectionRef,
|
|
5087
|
-
(0,
|
|
5088
|
-
(0,
|
|
5089
|
-
(0,
|
|
5397
|
+
(0, import_firestore22.where)("templateId", "==", templateId),
|
|
5398
|
+
(0, import_firestore22.orderBy)("updatedAt", "desc"),
|
|
5399
|
+
(0, import_firestore22.limit)(pageSize)
|
|
5090
5400
|
);
|
|
5091
5401
|
if (lastDoc) {
|
|
5092
|
-
q = (0,
|
|
5402
|
+
q = (0, import_firestore22.query)(q, (0, import_firestore22.startAfter)(lastDoc));
|
|
5093
5403
|
}
|
|
5094
|
-
const querySnapshot = await (0,
|
|
5404
|
+
const querySnapshot = await (0, import_firestore22.getDocs)(q);
|
|
5095
5405
|
const documents = [];
|
|
5096
5406
|
let lastVisible = null;
|
|
5097
|
-
querySnapshot.forEach((
|
|
5098
|
-
documents.push(
|
|
5099
|
-
lastVisible =
|
|
5407
|
+
querySnapshot.forEach((doc14) => {
|
|
5408
|
+
documents.push(doc14.data());
|
|
5409
|
+
lastVisible = doc14;
|
|
5100
5410
|
});
|
|
5101
5411
|
return {
|
|
5102
5412
|
documents,
|
|
@@ -5111,21 +5421,21 @@ var FilledDocumentService = class extends BaseService {
|
|
|
5111
5421
|
* @returns Array of filled documents and the last document for pagination
|
|
5112
5422
|
*/
|
|
5113
5423
|
async getFilledDocumentsByStatus(status, pageSize = 20, lastDoc) {
|
|
5114
|
-
let q = (0,
|
|
5424
|
+
let q = (0, import_firestore22.query)(
|
|
5115
5425
|
this.collectionRef,
|
|
5116
|
-
(0,
|
|
5117
|
-
(0,
|
|
5118
|
-
(0,
|
|
5426
|
+
(0, import_firestore22.where)("status", "==", status),
|
|
5427
|
+
(0, import_firestore22.orderBy)("updatedAt", "desc"),
|
|
5428
|
+
(0, import_firestore22.limit)(pageSize)
|
|
5119
5429
|
);
|
|
5120
5430
|
if (lastDoc) {
|
|
5121
|
-
q = (0,
|
|
5431
|
+
q = (0, import_firestore22.query)(q, (0, import_firestore22.startAfter)(lastDoc));
|
|
5122
5432
|
}
|
|
5123
|
-
const querySnapshot = await (0,
|
|
5433
|
+
const querySnapshot = await (0, import_firestore22.getDocs)(q);
|
|
5124
5434
|
const documents = [];
|
|
5125
5435
|
let lastVisible = null;
|
|
5126
|
-
querySnapshot.forEach((
|
|
5127
|
-
documents.push(
|
|
5128
|
-
lastVisible =
|
|
5436
|
+
querySnapshot.forEach((doc14) => {
|
|
5437
|
+
documents.push(doc14.data());
|
|
5438
|
+
lastVisible = doc14;
|
|
5129
5439
|
});
|
|
5130
5440
|
return {
|
|
5131
5441
|
documents,
|
|
@@ -5251,8 +5561,11 @@ var notificationSchema = import_zod16.z.discriminatedUnion("notificationType", [
|
|
|
5251
5561
|
blockingConditionSchema,
|
|
5252
5562
|
clinicAdminOptionsSchema,
|
|
5253
5563
|
clinicAdminSchema,
|
|
5564
|
+
clinicAdminSignupSchema,
|
|
5565
|
+
clinicBranchSetupSchema,
|
|
5254
5566
|
clinicContactInfoSchema,
|
|
5255
5567
|
clinicGroupSchema,
|
|
5568
|
+
clinicGroupSetupSchema,
|
|
5256
5569
|
clinicInfoSchema,
|
|
5257
5570
|
clinicLocationSchema,
|
|
5258
5571
|
clinicReviewSchema,
|
|
@@ -5307,6 +5620,9 @@ var notificationSchema = import_zod16.z.discriminatedUnion("notificationType", [
|
|
|
5307
5620
|
timestampSchema,
|
|
5308
5621
|
updateAllergySchema,
|
|
5309
5622
|
updateBlockingConditionSchema,
|
|
5623
|
+
updateClinicAdminSchema,
|
|
5624
|
+
updateClinicGroupSchema,
|
|
5625
|
+
updateClinicSchema,
|
|
5310
5626
|
updateContraindicationSchema,
|
|
5311
5627
|
updateDocumentTemplateSchema,
|
|
5312
5628
|
updateMedicationSchema,
|