@blackcode_sa/metaestetics-api 1.4.1 → 1.4.3

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