@blackcode_sa/metaestetics-api 1.4.2 → 1.4.4

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