@blackcode_sa/metaestetics-api 1.4.1 → 1.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -56,6 +56,11 @@ import {
56
56
  verifyPasswordResetCode,
57
57
  confirmPasswordReset
58
58
  } from "firebase/auth";
59
+ import {
60
+ collection as collection9,
61
+ query as query8,
62
+ getDocs as getDocs8
63
+ } from "firebase/firestore";
59
64
 
60
65
  // src/types/documentation-templates/index.ts
61
66
  var DocumentElementType = /* @__PURE__ */ ((DocumentElementType2) => {
@@ -116,7 +121,7 @@ var DOCUMENTATION_TEMPLATES_COLLECTION = "documentation-templates";
116
121
  var FILLED_DOCUMENTS_COLLECTION = "filled-documents";
117
122
 
118
123
  // src/services/auth.service.ts
119
- import { z as z13 } from "zod";
124
+ import { z as z15 } from "zod";
120
125
 
121
126
  // src/validations/schemas.ts
122
127
  import { z as z2 } from "zod";
@@ -546,7 +551,7 @@ import {
546
551
  where as where4,
547
552
  updateDoc as updateDoc9,
548
553
  deleteDoc as deleteDoc3,
549
- Timestamp as Timestamp8,
554
+ Timestamp as Timestamp9,
550
555
  setDoc as setDoc8,
551
556
  serverTimestamp as serverTimestamp10
552
557
  } from "firebase/firestore";
@@ -1271,9 +1276,9 @@ var addAllergyUtil = async (db, patientId, data, userRef) => {
1271
1276
  var updateAllergyUtil = async (db, patientId, data, userRef) => {
1272
1277
  const validatedData = updateAllergySchema.parse(data);
1273
1278
  const { allergyIndex, ...updateData } = validatedData;
1274
- const doc13 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1275
- if (!doc13.exists()) throw new Error("Medical info not found");
1276
- const medicalInfo = doc13.data();
1279
+ const doc14 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1280
+ if (!doc14.exists()) throw new Error("Medical info not found");
1281
+ const medicalInfo = doc14.data();
1277
1282
  if (allergyIndex >= medicalInfo.allergies.length) {
1278
1283
  throw new Error("Invalid allergy index");
1279
1284
  }
@@ -1289,9 +1294,9 @@ var updateAllergyUtil = async (db, patientId, data, userRef) => {
1289
1294
  });
1290
1295
  };
1291
1296
  var removeAllergyUtil = async (db, patientId, allergyIndex, userRef) => {
1292
- const doc13 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1293
- if (!doc13.exists()) throw new Error("Medical info not found");
1294
- const medicalInfo = doc13.data();
1297
+ const doc14 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1298
+ if (!doc14.exists()) throw new Error("Medical info not found");
1299
+ const medicalInfo = doc14.data();
1295
1300
  if (allergyIndex >= medicalInfo.allergies.length) {
1296
1301
  throw new Error("Invalid allergy index");
1297
1302
  }
@@ -1316,9 +1321,9 @@ var addBlockingConditionUtil = async (db, patientId, data, userRef) => {
1316
1321
  var updateBlockingConditionUtil = async (db, patientId, data, userRef) => {
1317
1322
  const validatedData = updateBlockingConditionSchema.parse(data);
1318
1323
  const { conditionIndex, ...updateData } = validatedData;
1319
- const doc13 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1320
- if (!doc13.exists()) throw new Error("Medical info not found");
1321
- const medicalInfo = doc13.data();
1324
+ const doc14 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1325
+ if (!doc14.exists()) throw new Error("Medical info not found");
1326
+ const medicalInfo = doc14.data();
1322
1327
  if (conditionIndex >= medicalInfo.blockingConditions.length) {
1323
1328
  throw new Error("Invalid blocking condition index");
1324
1329
  }
@@ -1334,9 +1339,9 @@ var updateBlockingConditionUtil = async (db, patientId, data, userRef) => {
1334
1339
  });
1335
1340
  };
1336
1341
  var removeBlockingConditionUtil = async (db, patientId, conditionIndex, userRef) => {
1337
- const doc13 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1338
- if (!doc13.exists()) throw new Error("Medical info not found");
1339
- const medicalInfo = doc13.data();
1342
+ const doc14 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1343
+ if (!doc14.exists()) throw new Error("Medical info not found");
1344
+ const medicalInfo = doc14.data();
1340
1345
  if (conditionIndex >= medicalInfo.blockingConditions.length) {
1341
1346
  throw new Error("Invalid blocking condition index");
1342
1347
  }
@@ -1361,9 +1366,9 @@ var addContraindicationUtil = async (db, patientId, data, userRef) => {
1361
1366
  var updateContraindicationUtil = async (db, patientId, data, userRef) => {
1362
1367
  const validatedData = updateContraindicationSchema.parse(data);
1363
1368
  const { contraindicationIndex, ...updateData } = validatedData;
1364
- const doc13 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1365
- if (!doc13.exists()) throw new Error("Medical info not found");
1366
- const medicalInfo = doc13.data();
1369
+ const doc14 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1370
+ if (!doc14.exists()) throw new Error("Medical info not found");
1371
+ const medicalInfo = doc14.data();
1367
1372
  if (contraindicationIndex >= medicalInfo.contraindications.length) {
1368
1373
  throw new Error("Invalid contraindication index");
1369
1374
  }
@@ -1379,9 +1384,9 @@ var updateContraindicationUtil = async (db, patientId, data, userRef) => {
1379
1384
  });
1380
1385
  };
1381
1386
  var removeContraindicationUtil = async (db, patientId, contraindicationIndex, userRef) => {
1382
- const doc13 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1383
- if (!doc13.exists()) throw new Error("Medical info not found");
1384
- const medicalInfo = doc13.data();
1387
+ const doc14 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1388
+ if (!doc14.exists()) throw new Error("Medical info not found");
1389
+ const medicalInfo = doc14.data();
1385
1390
  if (contraindicationIndex >= medicalInfo.contraindications.length) {
1386
1391
  throw new Error("Invalid contraindication index");
1387
1392
  }
@@ -1406,9 +1411,9 @@ var addMedicationUtil = async (db, patientId, data, userRef) => {
1406
1411
  var updateMedicationUtil = async (db, patientId, data, userRef) => {
1407
1412
  const validatedData = updateMedicationSchema.parse(data);
1408
1413
  const { medicationIndex, ...updateData } = validatedData;
1409
- const doc13 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1410
- if (!doc13.exists()) throw new Error("Medical info not found");
1411
- const medicalInfo = doc13.data();
1414
+ const doc14 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1415
+ if (!doc14.exists()) throw new Error("Medical info not found");
1416
+ const medicalInfo = doc14.data();
1412
1417
  if (medicationIndex >= medicalInfo.currentMedications.length) {
1413
1418
  throw new Error("Invalid medication index");
1414
1419
  }
@@ -1424,9 +1429,9 @@ var updateMedicationUtil = async (db, patientId, data, userRef) => {
1424
1429
  });
1425
1430
  };
1426
1431
  var removeMedicationUtil = async (db, patientId, medicationIndex, userRef) => {
1427
- const doc13 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1428
- if (!doc13.exists()) throw new Error("Medical info not found");
1429
- const medicalInfo = doc13.data();
1432
+ const doc14 = await getDoc3(getMedicalInfoDocRef(db, patientId));
1433
+ if (!doc14.exists()) throw new Error("Medical info not found");
1434
+ const medicalInfo = doc14.data();
1430
1435
  if (medicationIndex >= medicalInfo.currentMedications.length) {
1431
1436
  throw new Error("Invalid medication index");
1432
1437
  }
@@ -2083,20 +2088,42 @@ import {
2083
2088
  updateDoc as updateDoc7,
2084
2089
  setDoc as setDoc6,
2085
2090
  deleteDoc,
2086
- Timestamp as Timestamp5,
2091
+ Timestamp as Timestamp6,
2087
2092
  serverTimestamp as serverTimestamp8
2088
2093
  } from "firebase/firestore";
2089
2094
 
2090
- // src/types/clinic/index.ts
2091
- var CLINIC_GROUPS_COLLECTION = "clinic_groups";
2092
- var CLINIC_ADMINS_COLLECTION = "clinic_admins";
2093
- var CLINICS_COLLECTION = "clinics";
2094
- var AdminTokenStatus = /* @__PURE__ */ ((AdminTokenStatus2) => {
2095
- AdminTokenStatus2["ACTIVE"] = "active";
2096
- AdminTokenStatus2["USED"] = "used";
2097
- AdminTokenStatus2["EXPIRED"] = "expired";
2098
- return AdminTokenStatus2;
2099
- })(AdminTokenStatus || {});
2095
+ // src/types/clinic/preferences.types.ts
2096
+ var PracticeType = /* @__PURE__ */ ((PracticeType2) => {
2097
+ PracticeType2["GENERAL_PRACTICE"] = "general_practice";
2098
+ PracticeType2["DENTAL"] = "dental";
2099
+ PracticeType2["DERMATOLOGY"] = "dermatology";
2100
+ PracticeType2["CARDIOLOGY"] = "cardiology";
2101
+ PracticeType2["ORTHOPEDICS"] = "orthopedics";
2102
+ PracticeType2["GYNECOLOGY"] = "gynecology";
2103
+ PracticeType2["PEDIATRICS"] = "pediatrics";
2104
+ PracticeType2["OPHTHALMOLOGY"] = "ophthalmology";
2105
+ PracticeType2["NEUROLOGY"] = "neurology";
2106
+ PracticeType2["PSYCHIATRY"] = "psychiatry";
2107
+ PracticeType2["UROLOGY"] = "urology";
2108
+ PracticeType2["ONCOLOGY"] = "oncology";
2109
+ PracticeType2["ENDOCRINOLOGY"] = "endocrinology";
2110
+ PracticeType2["GASTROENTEROLOGY"] = "gastroenterology";
2111
+ PracticeType2["PULMONOLOGY"] = "pulmonology";
2112
+ PracticeType2["RHEUMATOLOGY"] = "rheumatology";
2113
+ PracticeType2["PHYSICAL_THERAPY"] = "physical_therapy";
2114
+ PracticeType2["NUTRITION"] = "nutrition";
2115
+ PracticeType2["ALTERNATIVE_MEDICINE"] = "alternative_medicine";
2116
+ PracticeType2["OTHER"] = "other";
2117
+ return PracticeType2;
2118
+ })(PracticeType || {});
2119
+ var Language = /* @__PURE__ */ ((Language2) => {
2120
+ Language2["ENGLISH"] = "english";
2121
+ Language2["GERMAN"] = "german";
2122
+ Language2["ITALIAN"] = "italian";
2123
+ Language2["FRENCH"] = "french";
2124
+ Language2["SPANISH"] = "spanish";
2125
+ return Language2;
2126
+ })(Language || {});
2100
2127
  var ClinicTag = /* @__PURE__ */ ((ClinicTag4) => {
2101
2128
  ClinicTag4["PARKING"] = "parking";
2102
2129
  ClinicTag4["WIFI"] = "wifi";
@@ -2147,8 +2174,27 @@ var ClinicTag = /* @__PURE__ */ ((ClinicTag4) => {
2147
2174
  return ClinicTag4;
2148
2175
  })(ClinicTag || {});
2149
2176
 
2177
+ // src/types/clinic/index.ts
2178
+ var CLINIC_GROUPS_COLLECTION = "clinic_groups";
2179
+ var CLINIC_ADMINS_COLLECTION = "clinic_admins";
2180
+ var CLINICS_COLLECTION = "clinics";
2181
+ var AdminTokenStatus = /* @__PURE__ */ ((AdminTokenStatus2) => {
2182
+ AdminTokenStatus2["ACTIVE"] = "active";
2183
+ AdminTokenStatus2["USED"] = "used";
2184
+ AdminTokenStatus2["EXPIRED"] = "expired";
2185
+ return AdminTokenStatus2;
2186
+ })(AdminTokenStatus || {});
2187
+ var SubscriptionModel = /* @__PURE__ */ ((SubscriptionModel2) => {
2188
+ SubscriptionModel2["NO_SUBSCRIPTION"] = "no_subscription";
2189
+ SubscriptionModel2["BASIC"] = "basic";
2190
+ SubscriptionModel2["PREMIUM"] = "premium";
2191
+ SubscriptionModel2["ENTERPRISE"] = "enterprise";
2192
+ return SubscriptionModel2;
2193
+ })(SubscriptionModel || {});
2194
+
2150
2195
  // src/validations/clinic.schema.ts
2151
2196
  import { z as z9 } from "zod";
2197
+ import { Timestamp as Timestamp5 } from "firebase/firestore";
2152
2198
 
2153
2199
  // src/backoffice/types/static/procedure-family.types.ts
2154
2200
  var ProcedureFamily = /* @__PURE__ */ ((ProcedureFamily2) => {
@@ -2200,8 +2246,8 @@ var Currency = /* @__PURE__ */ ((Currency2) => {
2200
2246
  var clinicContactInfoSchema = z9.object({
2201
2247
  email: z9.string().email(),
2202
2248
  phoneNumber: z9.string(),
2203
- alternativePhoneNumber: z9.string().nullable(),
2204
- website: z9.string().nullable()
2249
+ alternativePhoneNumber: z9.string().nullable().optional(),
2250
+ website: z9.string().nullable().optional()
2205
2251
  });
2206
2252
  var clinicLocationSchema = z9.object({
2207
2253
  address: z9.string(),
@@ -2210,20 +2256,26 @@ var clinicLocationSchema = z9.object({
2210
2256
  postalCode: z9.string(),
2211
2257
  latitude: z9.number().min(-90).max(90),
2212
2258
  longitude: z9.number().min(-180).max(180),
2213
- geohash: z9.string().nullable()
2259
+ geohash: z9.string().nullable().optional()
2214
2260
  });
2215
2261
  var workingHoursTimeSchema = z9.object({
2216
2262
  open: z9.string(),
2217
- close: z9.string()
2263
+ close: z9.string(),
2264
+ breaks: z9.array(
2265
+ z9.object({
2266
+ start: z9.string(),
2267
+ end: z9.string()
2268
+ })
2269
+ ).optional()
2218
2270
  });
2219
2271
  var workingHoursSchema = z9.object({
2220
- monday: workingHoursTimeSchema,
2221
- tuesday: workingHoursTimeSchema,
2222
- wednesday: workingHoursTimeSchema,
2223
- thursday: workingHoursTimeSchema,
2224
- friday: workingHoursTimeSchema,
2225
- saturday: workingHoursTimeSchema,
2226
- sunday: workingHoursTimeSchema
2272
+ monday: workingHoursTimeSchema.nullable(),
2273
+ tuesday: workingHoursTimeSchema.nullable(),
2274
+ wednesday: workingHoursTimeSchema.nullable(),
2275
+ thursday: workingHoursTimeSchema.nullable(),
2276
+ friday: workingHoursTimeSchema.nullable(),
2277
+ saturday: workingHoursTimeSchema.nullable(),
2278
+ sunday: workingHoursTimeSchema.nullable()
2227
2279
  });
2228
2280
  var clinicTagsSchema = z9.object({
2229
2281
  tags: z9.array(z9.nativeEnum(ClinicTag))
@@ -2244,14 +2296,14 @@ var clinicInfoSchema = z9.object({
2244
2296
  id: z9.string(),
2245
2297
  featuredPhoto: z9.string(),
2246
2298
  name: z9.string(),
2247
- description: z9.string().nullable(),
2299
+ description: z9.string().nullable().optional(),
2248
2300
  location: clinicLocationSchema,
2249
2301
  contactInfo: clinicContactInfoSchema
2250
2302
  });
2251
2303
  var doctorInfoSchema = z9.object({
2252
2304
  id: z9.string(),
2253
2305
  name: z9.string(),
2254
- description: z9.string().nullable(),
2306
+ description: z9.string().nullable().optional(),
2255
2307
  photo: z9.string(),
2256
2308
  rating: z9.number().min(0).max(5),
2257
2309
  services: z9.array(z9.string())
@@ -2259,7 +2311,7 @@ var doctorInfoSchema = z9.object({
2259
2311
  var serviceInfoSchema = z9.object({
2260
2312
  id: z9.string(),
2261
2313
  name: z9.string(),
2262
- description: z9.string().nullable(),
2314
+ description: z9.string().nullable().optional(),
2263
2315
  photo: z9.string(),
2264
2316
  procedureFamily: z9.nativeEnum(ProcedureFamily),
2265
2317
  category: z9.string(),
@@ -2280,9 +2332,9 @@ var reviewInfoSchema = z9.object({
2280
2332
  patientId: z9.string(),
2281
2333
  patientName: z9.string(),
2282
2334
  patientPhoto: z9.string(),
2283
- createdAt: z9.date(),
2335
+ createdAt: z9.instanceof(Date).or(z9.instanceof(Timestamp5)),
2284
2336
  // Timestamp
2285
- updatedAt: z9.date()
2337
+ updatedAt: z9.instanceof(Date).or(z9.instanceof(Timestamp5))
2286
2338
  // Timestamp
2287
2339
  });
2288
2340
  var clinicAdminSchema = z9.object({
@@ -2294,8 +2346,8 @@ var clinicAdminSchema = z9.object({
2294
2346
  clinicsManagedInfo: z9.array(clinicInfoSchema),
2295
2347
  contactInfo: contactPersonSchema,
2296
2348
  roleTitle: z9.string(),
2297
- createdAt: z9.date(),
2298
- updatedAt: z9.date(),
2349
+ createdAt: z9.instanceof(Date).or(z9.instanceof(Timestamp5)),
2350
+ updatedAt: z9.instanceof(Date).or(z9.instanceof(Timestamp5)),
2299
2351
  isActive: z9.boolean()
2300
2352
  });
2301
2353
  var adminTokenSchema = z9.object({
@@ -2303,9 +2355,9 @@ var adminTokenSchema = z9.object({
2303
2355
  token: z9.string(),
2304
2356
  status: z9.nativeEnum(AdminTokenStatus),
2305
2357
  usedByUserRef: z9.string().optional(),
2306
- createdAt: z9.date(),
2358
+ createdAt: z9.instanceof(Date).or(z9.instanceof(Timestamp5)),
2307
2359
  // Timestamp
2308
- expiresAt: z9.date()
2360
+ expiresAt: z9.instanceof(Date).or(z9.instanceof(Timestamp5))
2309
2361
  // Timestamp
2310
2362
  });
2311
2363
  var createAdminTokenSchema = z9.object({
@@ -2314,7 +2366,7 @@ var createAdminTokenSchema = z9.object({
2314
2366
  var clinicGroupSchema = z9.object({
2315
2367
  id: z9.string(),
2316
2368
  name: z9.string(),
2317
- description: z9.string().nullable(),
2369
+ description: z9.string().nullable().optional(),
2318
2370
  hqLocation: clinicLocationSchema,
2319
2371
  contactInfo: clinicContactInfoSchema,
2320
2372
  contactPerson: contactPersonSchema,
@@ -2324,11 +2376,17 @@ var clinicGroupSchema = z9.object({
2324
2376
  adminsInfo: z9.array(adminInfoSchema),
2325
2377
  adminTokens: z9.array(adminTokenSchema),
2326
2378
  ownerId: z9.string(),
2327
- createdAt: z9.date(),
2379
+ createdAt: z9.instanceof(Date).or(z9.instanceof(Timestamp5)),
2328
2380
  // Timestamp
2329
- updatedAt: z9.date(),
2381
+ updatedAt: z9.instanceof(Date).or(z9.instanceof(Timestamp5)),
2330
2382
  // Timestamp
2331
- isActive: z9.boolean()
2383
+ isActive: z9.boolean(),
2384
+ logo: z9.string().optional(),
2385
+ practiceType: z9.nativeEnum(PracticeType).optional(),
2386
+ languages: z9.array(z9.nativeEnum(Language)).optional(),
2387
+ subscriptionModel: z9.nativeEnum(SubscriptionModel),
2388
+ calendarSyncEnabled: z9.boolean().optional(),
2389
+ autoConfirmAppointments: z9.boolean().optional()
2332
2390
  });
2333
2391
  var clinicReviewSchema = z9.object({
2334
2392
  id: z9.string(),
@@ -2336,9 +2394,9 @@ var clinicReviewSchema = z9.object({
2336
2394
  patientId: z9.string(),
2337
2395
  rating: z9.number().min(1).max(5),
2338
2396
  comment: z9.string(),
2339
- createdAt: z9.date(),
2397
+ createdAt: z9.instanceof(Date).or(z9.instanceof(Timestamp5)),
2340
2398
  // Timestamp
2341
- updatedAt: z9.date(),
2399
+ updatedAt: z9.instanceof(Date).or(z9.instanceof(Timestamp5)),
2342
2400
  // Timestamp
2343
2401
  isVerified: z9.boolean()
2344
2402
  });
@@ -2346,13 +2404,19 @@ var clinicSchema = z9.object({
2346
2404
  id: z9.string(),
2347
2405
  clinicGroupId: z9.string(),
2348
2406
  name: z9.string(),
2349
- description: z9.string().nullable(),
2407
+ description: z9.string().nullable().optional(),
2350
2408
  location: clinicLocationSchema,
2351
2409
  contactInfo: clinicContactInfoSchema,
2352
2410
  workingHours: workingHoursSchema,
2353
2411
  tags: z9.array(z9.nativeEnum(ClinicTag)),
2354
2412
  featuredPhotos: z9.array(z9.string()),
2355
2413
  photos: z9.array(z9.string()),
2414
+ photosWithTags: z9.array(
2415
+ z9.object({
2416
+ url: z9.string(),
2417
+ tag: z9.string()
2418
+ })
2419
+ ).optional(),
2356
2420
  doctors: z9.array(z9.string()),
2357
2421
  doctorsInfo: z9.array(doctorInfoSchema),
2358
2422
  services: z9.array(z9.string()),
@@ -2364,12 +2428,13 @@ var clinicSchema = z9.object({
2364
2428
  count: z9.number().min(0)
2365
2429
  }).nullable(),
2366
2430
  admins: z9.array(z9.string()),
2367
- createdAt: z9.date(),
2431
+ createdAt: z9.instanceof(Date).or(z9.instanceof(Timestamp5)),
2368
2432
  // Timestamp
2369
- updatedAt: z9.date(),
2433
+ updatedAt: z9.instanceof(Date).or(z9.instanceof(Timestamp5)),
2370
2434
  // Timestamp
2371
2435
  isActive: z9.boolean(),
2372
- isVerified: z9.boolean()
2436
+ isVerified: z9.boolean(),
2437
+ logo: z9.string().optional()
2373
2438
  });
2374
2439
  var createClinicAdminSchema = z9.object({
2375
2440
  userRef: z9.string(),
@@ -2382,39 +2447,99 @@ var createClinicAdminSchema = z9.object({
2382
2447
  });
2383
2448
  var createClinicGroupSchema = z9.object({
2384
2449
  name: z9.string(),
2385
- description: z9.string().nullable(),
2450
+ description: z9.string().optional(),
2386
2451
  hqLocation: clinicLocationSchema,
2387
2452
  contactInfo: clinicContactInfoSchema,
2388
2453
  contactPerson: contactPersonSchema,
2389
2454
  ownerId: z9.string(),
2390
- isActive: z9.boolean()
2455
+ isActive: z9.boolean(),
2456
+ logo: z9.string().optional(),
2457
+ practiceType: z9.nativeEnum(PracticeType).optional(),
2458
+ languages: z9.array(z9.nativeEnum(Language)).optional(),
2459
+ subscriptionModel: z9.nativeEnum(SubscriptionModel).optional().default("no_subscription" /* NO_SUBSCRIPTION */),
2460
+ calendarSyncEnabled: z9.boolean().optional(),
2461
+ autoConfirmAppointments: z9.boolean().optional()
2391
2462
  });
2392
2463
  var createClinicSchema = z9.object({
2393
2464
  clinicGroupId: z9.string(),
2394
2465
  name: z9.string(),
2395
- description: z9.string().nullable(),
2466
+ description: z9.string().optional(),
2396
2467
  location: clinicLocationSchema,
2397
2468
  contactInfo: clinicContactInfoSchema,
2398
2469
  workingHours: workingHoursSchema,
2399
2470
  tags: z9.array(z9.nativeEnum(ClinicTag)),
2400
2471
  photos: z9.array(z9.string()),
2472
+ photosWithTags: z9.array(
2473
+ z9.object({
2474
+ url: z9.string(),
2475
+ tag: z9.string()
2476
+ })
2477
+ ).optional(),
2401
2478
  doctors: z9.array(z9.string()),
2402
2479
  services: z9.array(z9.string()),
2403
2480
  admins: z9.array(z9.string()),
2404
2481
  isActive: z9.boolean(),
2405
- isVerified: z9.boolean()
2482
+ isVerified: z9.boolean(),
2483
+ logo: z9.string().optional(),
2484
+ featuredPhotos: z9.array(z9.string()).optional()
2406
2485
  });
2407
2486
  var createDefaultClinicGroupSchema = z9.object({
2408
2487
  name: z9.string(),
2409
2488
  ownerId: z9.string(),
2410
2489
  contactPerson: contactPersonSchema,
2411
- contactInfo: z9.object({
2412
- email: z9.string().email(),
2413
- phoneNumber: z9.string()
2414
- }),
2490
+ contactInfo: clinicContactInfoSchema,
2415
2491
  hqLocation: clinicLocationSchema,
2416
- isActive: z9.boolean()
2492
+ isActive: z9.boolean(),
2493
+ logo: z9.string().optional(),
2494
+ practiceType: z9.nativeEnum(PracticeType).optional(),
2495
+ languages: z9.array(z9.nativeEnum(Language)).optional(),
2496
+ subscriptionModel: z9.nativeEnum(SubscriptionModel).optional().default("no_subscription" /* NO_SUBSCRIPTION */)
2497
+ });
2498
+ var clinicAdminSignupSchema = z9.object({
2499
+ email: z9.string().email(),
2500
+ password: z9.string().min(8),
2501
+ firstName: z9.string(),
2502
+ lastName: z9.string(),
2503
+ title: z9.string(),
2504
+ phoneNumber: z9.string(),
2505
+ isCreatingNewGroup: z9.boolean(),
2506
+ inviteToken: z9.string().optional(),
2507
+ clinicGroupData: z9.object({
2508
+ name: z9.string(),
2509
+ hqLocation: clinicLocationSchema,
2510
+ logo: z9.string().optional(),
2511
+ contactInfo: clinicContactInfoSchema,
2512
+ subscriptionModel: z9.nativeEnum(SubscriptionModel).optional().default("no_subscription" /* NO_SUBSCRIPTION */)
2513
+ }).optional()
2514
+ });
2515
+ var clinicGroupSetupSchema = z9.object({
2516
+ languages: z9.array(z9.nativeEnum(Language)),
2517
+ practiceType: z9.nativeEnum(PracticeType),
2518
+ description: z9.string(),
2519
+ logo: z9.string(),
2520
+ calendarSyncEnabled: z9.boolean(),
2521
+ autoConfirmAppointments: z9.boolean()
2522
+ });
2523
+ var clinicBranchSetupSchema = z9.object({
2524
+ name: z9.string(),
2525
+ location: clinicLocationSchema,
2526
+ description: z9.string().optional(),
2527
+ contactInfo: clinicContactInfoSchema,
2528
+ workingHours: workingHoursSchema,
2529
+ tags: z9.array(z9.nativeEnum(ClinicTag)),
2530
+ logo: z9.string().optional(),
2531
+ photos: z9.array(z9.string()),
2532
+ photosWithTags: z9.array(
2533
+ z9.object({
2534
+ url: z9.string(),
2535
+ tag: z9.string()
2536
+ })
2537
+ ).optional(),
2538
+ featuredPhotos: z9.array(z9.string()).optional()
2417
2539
  });
2540
+ var updateClinicAdminSchema = createClinicAdminSchema.partial();
2541
+ var updateClinicGroupSchema = createClinicGroupSchema.partial();
2542
+ var updateClinicSchema = createClinicSchema.partial();
2418
2543
 
2419
2544
  // src/services/clinic/utils/admin.utils.ts
2420
2545
  async function createClinicAdmin(db, data, clinicGroupService) {
@@ -2481,8 +2606,8 @@ async function createClinicAdmin(db, data, clinicGroupService) {
2481
2606
  };
2482
2607
  clinicAdminSchema.parse({
2483
2608
  ...adminData,
2484
- createdAt: Timestamp5.now(),
2485
- updatedAt: Timestamp5.now()
2609
+ createdAt: Timestamp6.now(),
2610
+ updatedAt: Timestamp6.now()
2486
2611
  });
2487
2612
  await setDoc6(doc4(db, CLINIC_ADMINS_COLLECTION, adminData.id), adminData);
2488
2613
  if (clinicGroupId) {
@@ -2523,7 +2648,7 @@ async function getClinicAdminsByGroup(db, clinicGroupId) {
2523
2648
  where2("clinicGroupId", "==", clinicGroupId)
2524
2649
  );
2525
2650
  const querySnapshot = await getDocs2(q);
2526
- return querySnapshot.docs.map((doc13) => doc13.data());
2651
+ return querySnapshot.docs.map((doc14) => doc14.data());
2527
2652
  }
2528
2653
  async function updateClinicAdmin(db, adminId, data) {
2529
2654
  const admin = await getClinicAdmin(db, adminId);
@@ -2797,7 +2922,7 @@ import {
2797
2922
  updateDoc as updateDoc8,
2798
2923
  setDoc as setDoc7,
2799
2924
  deleteDoc as deleteDoc2,
2800
- Timestamp as Timestamp7,
2925
+ Timestamp as Timestamp8,
2801
2926
  serverTimestamp as serverTimestamp9
2802
2927
  } from "firebase/firestore";
2803
2928
 
@@ -2806,7 +2931,7 @@ var PRACTITIONERS_COLLECTION = "practitioners";
2806
2931
 
2807
2932
  // src/validations/practitioner.schema.ts
2808
2933
  import { z as z10 } from "zod";
2809
- import { Timestamp as Timestamp6 } from "firebase/firestore";
2934
+ import { Timestamp as Timestamp7 } from "firebase/firestore";
2810
2935
 
2811
2936
  // src/backoffice/types/static/certification.types.ts
2812
2937
  var CertificationLevel = /* @__PURE__ */ ((CertificationLevel2) => {
@@ -2839,7 +2964,7 @@ var practitionerBasicInfoSchema = z10.object({
2839
2964
  title: z10.string().min(2).max(100),
2840
2965
  email: z10.string().email(),
2841
2966
  phoneNumber: z10.string().regex(/^\+?[1-9]\d{1,14}$/, "Invalid phone number"),
2842
- dateOfBirth: z10.instanceof(Timestamp6),
2967
+ dateOfBirth: z10.instanceof(Timestamp7),
2843
2968
  gender: z10.enum(["male", "female", "other"]),
2844
2969
  profileImageUrl: z10.string().url().optional(),
2845
2970
  bio: z10.string().max(1e3).optional(),
@@ -2850,8 +2975,8 @@ var practitionerCertificationSchema = z10.object({
2850
2975
  specialties: z10.array(z10.nativeEnum(CertificationSpecialty)),
2851
2976
  licenseNumber: z10.string().min(3).max(50),
2852
2977
  issuingAuthority: z10.string().min(2).max(100),
2853
- issueDate: z10.instanceof(Timestamp6),
2854
- expiryDate: z10.instanceof(Timestamp6).optional(),
2978
+ issueDate: z10.instanceof(Timestamp7),
2979
+ expiryDate: z10.instanceof(Timestamp7).optional(),
2855
2980
  verificationStatus: z10.enum(["pending", "verified", "rejected"])
2856
2981
  });
2857
2982
  var timeSlotSchema = z10.object({
@@ -2868,8 +2993,8 @@ var practitionerWorkingHoursSchema = z10.object({
2868
2993
  friday: timeSlotSchema,
2869
2994
  saturday: timeSlotSchema,
2870
2995
  sunday: timeSlotSchema,
2871
- createdAt: z10.instanceof(Timestamp6),
2872
- updatedAt: z10.instanceof(Timestamp6)
2996
+ createdAt: z10.instanceof(Timestamp7),
2997
+ updatedAt: z10.instanceof(Timestamp7)
2873
2998
  });
2874
2999
  var practitionerReviewSchema = z10.object({
2875
3000
  id: z10.string().min(1),
@@ -2878,8 +3003,8 @@ var practitionerReviewSchema = z10.object({
2878
3003
  clinicId: z10.string().min(1),
2879
3004
  rating: z10.number().min(1).max(5),
2880
3005
  comment: z10.string().max(1e3),
2881
- createdAt: z10.instanceof(Timestamp6),
2882
- updatedAt: z10.instanceof(Timestamp6),
3006
+ createdAt: z10.instanceof(Timestamp7),
3007
+ updatedAt: z10.instanceof(Timestamp7),
2883
3008
  isVerified: z10.boolean()
2884
3009
  });
2885
3010
  var practitionerClinicProceduresSchema = z10.object({
@@ -2887,8 +3012,8 @@ var practitionerClinicProceduresSchema = z10.object({
2887
3012
  clinicId: z10.string().min(1),
2888
3013
  procedures: z10.array(z10.string()).min(1),
2889
3014
  isActive: z10.boolean(),
2890
- createdAt: z10.instanceof(Timestamp6),
2891
- updatedAt: z10.instanceof(Timestamp6)
3015
+ createdAt: z10.instanceof(Timestamp7),
3016
+ updatedAt: z10.instanceof(Timestamp7)
2892
3017
  });
2893
3018
  var practitionerSchema = z10.object({
2894
3019
  id: z10.string().min(1),
@@ -2898,8 +3023,8 @@ var practitionerSchema = z10.object({
2898
3023
  clinics: z10.array(z10.string()),
2899
3024
  isActive: z10.boolean(),
2900
3025
  isVerified: z10.boolean(),
2901
- createdAt: z10.instanceof(Timestamp6),
2902
- updatedAt: z10.instanceof(Timestamp6)
3026
+ createdAt: z10.instanceof(Timestamp7),
3027
+ updatedAt: z10.instanceof(Timestamp7)
2903
3028
  });
2904
3029
  var createPractitionerSchema = z10.object({
2905
3030
  userRef: z10.string().min(1),
@@ -2962,8 +3087,8 @@ var PractitionerService = class extends BaseService {
2962
3087
  };
2963
3088
  practitionerSchema.parse({
2964
3089
  ...practitionerData,
2965
- createdAt: Timestamp7.now(),
2966
- updatedAt: Timestamp7.now()
3090
+ createdAt: Timestamp8.now(),
3091
+ updatedAt: Timestamp8.now()
2967
3092
  });
2968
3093
  await setDoc7(
2969
3094
  doc5(this.db, PRACTITIONERS_COLLECTION, practitionerData.id),
@@ -3017,7 +3142,7 @@ var PractitionerService = class extends BaseService {
3017
3142
  where3("isActive", "==", true)
3018
3143
  );
3019
3144
  const querySnapshot = await getDocs3(q);
3020
- return querySnapshot.docs.map((doc13) => doc13.data());
3145
+ return querySnapshot.docs.map((doc14) => doc14.data());
3021
3146
  }
3022
3147
  /**
3023
3148
  * Ažurira profil zdravstvenog radnika
@@ -3048,7 +3173,7 @@ var PractitionerService = class extends BaseService {
3048
3173
  practitionerSchema.parse({
3049
3174
  ...practitionerDoc.data(),
3050
3175
  ...data,
3051
- updatedAt: Timestamp7.now()
3176
+ updatedAt: Timestamp8.now()
3052
3177
  });
3053
3178
  await updateDoc8(practitionerRef, updateData);
3054
3179
  const updatedPractitioner = await this.getPractitioner(practitionerId);
@@ -3245,7 +3370,7 @@ var UserService = class extends BaseService {
3245
3370
  email: "",
3246
3371
  phoneNumber: "",
3247
3372
  title: "",
3248
- dateOfBirth: Timestamp8.now(),
3373
+ dateOfBirth: Timestamp9.now(),
3249
3374
  gender: "other",
3250
3375
  languages: ["Serbian"]
3251
3376
  },
@@ -3254,7 +3379,7 @@ var UserService = class extends BaseService {
3254
3379
  specialties: [],
3255
3380
  licenseNumber: "",
3256
3381
  issuingAuthority: "",
3257
- issueDate: Timestamp8.now(),
3382
+ issueDate: Timestamp9.now(),
3258
3383
  verificationStatus: "pending"
3259
3384
  },
3260
3385
  isActive: true,
@@ -3294,7 +3419,7 @@ var UserService = class extends BaseService {
3294
3419
  ];
3295
3420
  const q = query4(collection4(this.db, USERS_COLLECTION), ...constraints);
3296
3421
  const querySnapshot = await getDocs4(q);
3297
- const users = querySnapshot.docs.map((doc13) => doc13.data());
3422
+ const users = querySnapshot.docs.map((doc14) => doc14.data());
3298
3423
  return Promise.all(users.map((userData) => userSchema.parse(userData)));
3299
3424
  }
3300
3425
  /**
@@ -3448,486 +3573,347 @@ var UserService = class extends BaseService {
3448
3573
  }
3449
3574
  };
3450
3575
 
3451
- // src/services/auth.service.ts
3452
- var AuthService = class extends BaseService {
3453
- constructor(db, auth, app, userService) {
3454
- super(db, auth, app);
3455
- this.googleProvider = new GoogleAuthProvider();
3456
- this.facebookProvider = new FacebookAuthProvider();
3457
- this.appleProvider = new OAuthProvider("apple.com");
3458
- if (!userService) {
3459
- userService = new UserService(db, auth, app);
3576
+ // src/services/clinic/utils/clinic-group.utils.ts
3577
+ import {
3578
+ collection as collection5,
3579
+ doc as doc7,
3580
+ getDoc as getDoc11,
3581
+ getDocs as getDocs5,
3582
+ query as query5,
3583
+ where as where5,
3584
+ updateDoc as updateDoc10,
3585
+ setDoc as setDoc9,
3586
+ Timestamp as Timestamp10
3587
+ } from "firebase/firestore";
3588
+ import { geohashForLocation as geohashForLocation2 } from "geofire-common";
3589
+ import { z as z13 } from "zod";
3590
+ function generateId() {
3591
+ const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
3592
+ const timestamp = Date.now().toString(36);
3593
+ const randomPart = Array.from(
3594
+ { length: 12 },
3595
+ () => chars.charAt(Math.floor(Math.random() * chars.length))
3596
+ ).join("");
3597
+ return `${randomPart}-${timestamp}`;
3598
+ }
3599
+ async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdminService) {
3600
+ const validatedData = createClinicGroupSchema.parse(data);
3601
+ const owner = await clinicAdminService.getClinicAdmin(ownerId);
3602
+ if (!owner) {
3603
+ throw new Error("Owner not found or is not a clinic admin");
3604
+ }
3605
+ if (validatedData.hqLocation) {
3606
+ validatedData.hqLocation.geohash = geohashForLocation2([
3607
+ validatedData.hqLocation.latitude,
3608
+ validatedData.hqLocation.longitude
3609
+ ]);
3610
+ }
3611
+ const now = Timestamp10.now();
3612
+ const groupData = {
3613
+ ...validatedData,
3614
+ id: doc7(collection5(db, CLINIC_GROUPS_COLLECTION)).id,
3615
+ description: isDefault ? void 0 : validatedData.description || void 0,
3616
+ hqLocation: {
3617
+ ...validatedData.hqLocation,
3618
+ geohash: validatedData.hqLocation.geohash || void 0
3619
+ },
3620
+ contactInfo: {
3621
+ ...validatedData.contactInfo,
3622
+ alternativePhoneNumber: isDefault ? void 0 : validatedData.contactInfo.alternativePhoneNumber || void 0,
3623
+ website: isDefault ? void 0 : validatedData.contactInfo.website || void 0
3624
+ },
3625
+ clinics: [],
3626
+ clinicsInfo: [],
3627
+ admins: [ownerId],
3628
+ adminsInfo: [],
3629
+ adminTokens: [],
3630
+ ownerId,
3631
+ createdAt: now,
3632
+ updatedAt: now,
3633
+ isActive: true
3634
+ };
3635
+ try {
3636
+ clinicGroupSchema.parse(groupData);
3637
+ await setDoc9(doc7(db, CLINIC_GROUPS_COLLECTION, groupData.id), groupData);
3638
+ await clinicAdminService.updateClinicAdmin(ownerId, {
3639
+ clinicGroupId: groupData.id,
3640
+ isGroupOwner: true
3641
+ });
3642
+ return groupData;
3643
+ } catch (error) {
3644
+ if (error instanceof z13.ZodError) {
3645
+ throw new Error("Invalid clinic group data: " + error.message);
3460
3646
  }
3461
- this.userService = userService;
3647
+ throw error;
3462
3648
  }
3463
- /**
3464
- * Registruje novog korisnika sa email-om i lozinkom
3465
- */
3466
- async signUp(email, password, initialRole = "patient" /* PATIENT */) {
3467
- const { user: firebaseUser } = await createUserWithEmailAndPassword(
3468
- this.auth,
3469
- email,
3470
- password
3471
- );
3472
- return this.userService.createUser(firebaseUser, [initialRole]);
3649
+ }
3650
+ async function getClinicGroup(db, groupId) {
3651
+ const docRef = doc7(db, CLINIC_GROUPS_COLLECTION, groupId);
3652
+ const docSnap = await getDoc11(docRef);
3653
+ if (docSnap.exists()) {
3654
+ return docSnap.data();
3473
3655
  }
3474
- /**
3475
- * Prijavljuje korisnika sa email-om i lozinkom
3476
- */
3477
- async signIn(email, password) {
3478
- const { user: firebaseUser } = await signInWithEmailAndPassword(
3479
- this.auth,
3480
- email,
3481
- password
3482
- );
3483
- return this.userService.getOrCreateUser(firebaseUser);
3656
+ return null;
3657
+ }
3658
+ async function getAllActiveGroups(db) {
3659
+ const q = query5(
3660
+ collection5(db, CLINIC_GROUPS_COLLECTION),
3661
+ where5("isActive", "==", true)
3662
+ );
3663
+ const querySnapshot = await getDocs5(q);
3664
+ return querySnapshot.docs.map((doc14) => doc14.data());
3665
+ }
3666
+ async function updateClinicGroup(db, groupId, data) {
3667
+ const group = await getClinicGroup(db, groupId);
3668
+ if (!group) {
3669
+ throw new Error("Clinic group not found");
3484
3670
  }
3485
- /**
3486
- * Prijavljuje korisnika sa Facebook-om
3487
- */
3488
- async signInWithFacebook() {
3489
- const provider = new FacebookAuthProvider();
3490
- const { user: firebaseUser } = await signInWithPopup(this.auth, provider);
3491
- return this.userService.getOrCreateUser(firebaseUser);
3671
+ const updatedData = {
3672
+ ...data,
3673
+ updatedAt: Timestamp10.now()
3674
+ };
3675
+ await updateDoc10(doc7(db, CLINIC_GROUPS_COLLECTION, groupId), updatedData);
3676
+ const updatedGroup = await getClinicGroup(db, groupId);
3677
+ if (!updatedGroup) {
3678
+ throw new Error("Failed to retrieve updated clinic group");
3492
3679
  }
3493
- /**
3494
- * Prijavljuje korisnika sa Google nalogom
3495
- */
3496
- async signInWithGoogle(initialRole = "patient" /* PATIENT */) {
3497
- const { user: firebaseUser } = await signInWithPopup(
3498
- this.auth,
3499
- this.googleProvider
3500
- );
3501
- return this.userService.getOrCreateUser(firebaseUser);
3680
+ return updatedGroup;
3681
+ }
3682
+ async function addAdminToGroup(db, groupId, adminId) {
3683
+ const group = await getClinicGroup(db, groupId);
3684
+ if (!group) {
3685
+ throw new Error("Clinic group not found");
3502
3686
  }
3503
- /**
3504
- * Prijavljuje korisnika sa Apple-om
3505
- */
3506
- async signInWithApple() {
3507
- const provider = new OAuthProvider("apple.com");
3508
- const { user: firebaseUser } = await signInWithPopup(this.auth, provider);
3509
- return this.userService.getOrCreateUser(firebaseUser);
3687
+ if (group.admins.includes(adminId)) {
3688
+ return;
3510
3689
  }
3511
- /**
3512
- * Prijavljuje korisnika anonimno
3513
- */
3514
- async signInAnonymously() {
3515
- const { user: firebaseUser } = await firebaseSignInAnonymously(this.auth);
3516
- return this.userService.getOrCreateUser(firebaseUser);
3690
+ await updateClinicGroup(db, groupId, {
3691
+ admins: [...group.admins, adminId]
3692
+ });
3693
+ }
3694
+ async function removeAdminFromGroup(db, groupId, adminId) {
3695
+ const group = await getClinicGroup(db, groupId);
3696
+ if (!group) {
3697
+ throw new Error("Clinic group not found");
3517
3698
  }
3518
- /**
3519
- * Odjavljuje trenutnog korisnika
3520
- */
3521
- async signOut() {
3522
- await firebaseSignOut(this.auth);
3699
+ if (group.ownerId === adminId) {
3700
+ throw new Error("Cannot remove the owner from the group");
3523
3701
  }
3524
- /**
3525
- * Vraća trenutno prijavljenog korisnika
3526
- */
3527
- async getCurrentUser() {
3528
- const firebaseUser = this.auth.currentUser;
3529
- if (!firebaseUser) return null;
3530
- return this.userService.getUserById(firebaseUser.uid);
3702
+ if (!group.admins.includes(adminId)) {
3703
+ return;
3531
3704
  }
3532
- /**
3533
- * Registruje callback za promene stanja autentifikacije
3534
- */
3535
- onAuthStateChange(callback) {
3536
- return onAuthStateChanged(this.auth, callback);
3705
+ await updateClinicGroup(db, groupId, {
3706
+ admins: group.admins.filter((id) => id !== adminId)
3707
+ });
3708
+ }
3709
+ async function deactivateClinicGroup(db, groupId) {
3710
+ const group = await getClinicGroup(db, groupId);
3711
+ if (!group) {
3712
+ throw new Error("Clinic group not found");
3537
3713
  }
3538
- async upgradeAnonymousUser(email, password) {
3539
- try {
3540
- await emailSchema.parseAsync(email);
3541
- await passwordSchema.parseAsync(password);
3542
- const currentUser = this.auth.currentUser;
3543
- if (!currentUser) {
3544
- throw AUTH_ERRORS.NOT_AUTHENTICATED;
3545
- }
3546
- if (!currentUser.isAnonymous) {
3547
- throw new AuthError(
3548
- "User is not anonymous",
3549
- "AUTH/NOT_ANONYMOUS_USER",
3550
- 400
3551
- );
3552
- }
3553
- const credential = EmailAuthProvider.credential(email, password);
3554
- await linkWithCredential(currentUser, credential);
3555
- return await this.userService.upgradeAnonymousUser(
3556
- currentUser.uid,
3557
- email
3558
- );
3559
- } catch (error) {
3560
- if (error instanceof z13.ZodError) {
3561
- throw AUTH_ERRORS.VALIDATION_ERROR;
3562
- }
3563
- const firebaseError = error;
3564
- if (firebaseError.code === "auth/email-already-in-use" /* EMAIL_ALREADY_IN_USE */) {
3565
- throw AUTH_ERRORS.EMAIL_ALREADY_EXISTS;
3566
- }
3567
- throw error;
3568
- }
3714
+ await updateDoc10(doc7(db, CLINIC_GROUPS_COLLECTION, groupId), {
3715
+ isActive: false,
3716
+ updatedAt: Timestamp10.now()
3717
+ });
3718
+ }
3719
+ async function createAdminToken(db, groupId, creatorAdminId, data) {
3720
+ const group = await getClinicGroup(db, groupId);
3721
+ if (!group) {
3722
+ throw new Error("Clinic group not found");
3569
3723
  }
3570
- /**
3571
- * Upgrades an anonymous user to a regular user by signing in with a Google account.
3572
- *
3573
- * @throws {AuthError} If the user is not anonymous.
3574
- * @throws {AuthError} If the user is not authenticated.
3575
- * @throws {AuthError} If the popup window is closed by the user.
3576
- * @throws {FirebaseError} If any other Firebase error occurs.
3577
- *
3578
- * @returns {Promise<User>} The upgraded user.
3579
- */
3580
- async upgradeAnonymousUserWithGoogle() {
3581
- try {
3582
- const currentUser = this.auth.currentUser;
3583
- if (!currentUser) {
3584
- throw AUTH_ERRORS.NOT_AUTHENTICATED;
3585
- }
3586
- if (!currentUser.isAnonymous) {
3587
- throw new AuthError(
3588
- "User is not anonymous",
3589
- "AUTH/NOT_ANONYMOUS_USER",
3590
- 400
3591
- );
3592
- }
3593
- const userCredential = await signInWithPopup(
3594
- this.auth,
3595
- this.googleProvider
3596
- );
3597
- if (!userCredential) throw AUTH_ERRORS.INVALID_CREDENTIAL;
3598
- return await this.userService.upgradeAnonymousUser(
3599
- currentUser.uid,
3600
- userCredential.user.email
3601
- );
3602
- } catch (error) {
3603
- const firebaseError = error;
3604
- if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
3605
- throw AUTH_ERRORS.POPUP_CLOSED;
3606
- }
3607
- throw error;
3608
- }
3724
+ if (!group.admins.includes(creatorAdminId)) {
3725
+ throw new Error("Admin does not belong to this clinic group");
3609
3726
  }
3610
- async upgradeAnonymousUserWithFacebook() {
3611
- try {
3612
- const currentUser = this.auth.currentUser;
3613
- if (!currentUser) {
3614
- throw AUTH_ERRORS.NOT_AUTHENTICATED;
3615
- }
3616
- if (!currentUser.isAnonymous) {
3617
- throw new AuthError(
3618
- "User is not anonymous",
3619
- "AUTH/NOT_ANONYMOUS_USER",
3620
- 400
3621
- );
3622
- }
3623
- this.facebookProvider.addScope("email");
3624
- const userCredential = await signInWithPopup(
3625
- this.auth,
3626
- this.facebookProvider
3627
- );
3628
- if (!userCredential) throw AUTH_ERRORS.INVALID_CREDENTIAL;
3629
- return await this.userService.upgradeAnonymousUser(
3630
- currentUser.uid,
3631
- userCredential.user.email
3632
- );
3633
- } catch (error) {
3634
- const firebaseError = error;
3635
- if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
3636
- throw AUTH_ERRORS.POPUP_CLOSED;
3637
- }
3638
- throw error;
3639
- }
3727
+ const now = Timestamp10.now();
3728
+ const expiresInDays = (data == null ? void 0 : data.expiresInDays) || 7;
3729
+ const expiresAt = new Timestamp10(
3730
+ now.seconds + expiresInDays * 24 * 60 * 60,
3731
+ now.nanoseconds
3732
+ );
3733
+ const token = {
3734
+ id: generateId(),
3735
+ token: generateId(),
3736
+ status: "active" /* ACTIVE */,
3737
+ createdAt: now,
3738
+ expiresAt
3739
+ };
3740
+ await updateClinicGroup(db, groupId, {
3741
+ adminTokens: [...group.adminTokens, token]
3742
+ });
3743
+ return token;
3744
+ }
3745
+ async function verifyAndUseAdminToken(db, groupId, token, userRef) {
3746
+ const group = await getClinicGroup(db, groupId);
3747
+ if (!group) {
3748
+ throw new Error("Clinic group not found");
3640
3749
  }
3641
- async upgradeAnonymousUserWithApple() {
3642
- try {
3643
- const currentUser = this.auth.currentUser;
3644
- if (!currentUser) {
3645
- throw AUTH_ERRORS.NOT_AUTHENTICATED;
3646
- }
3647
- if (!currentUser.isAnonymous) {
3648
- throw new AuthError(
3649
- "User is not anonymous",
3650
- "AUTH/NOT_ANONYMOUS_USER",
3651
- 400
3652
- );
3653
- }
3654
- this.appleProvider.addScope("email");
3655
- this.appleProvider.addScope("name");
3656
- const userCredential = await signInWithPopup(
3657
- this.auth,
3658
- this.appleProvider
3659
- );
3660
- if (!userCredential) throw AUTH_ERRORS.INVALID_CREDENTIAL;
3661
- return await this.userService.upgradeAnonymousUser(
3662
- currentUser.uid,
3663
- userCredential.user.email
3664
- );
3665
- } catch (error) {
3666
- const firebaseError = error;
3667
- if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
3668
- throw AUTH_ERRORS.POPUP_CLOSED;
3669
- }
3670
- throw error;
3671
- }
3750
+ const adminToken = group.adminTokens.find((t) => t.token === token);
3751
+ if (!adminToken) {
3752
+ throw new Error("Admin token not found");
3753
+ }
3754
+ if (adminToken.status !== "active" /* ACTIVE */) {
3755
+ throw new Error("Admin token is not active");
3756
+ }
3757
+ const now = Timestamp10.now();
3758
+ if (adminToken.expiresAt.seconds < now.seconds) {
3759
+ const updatedTokens2 = group.adminTokens.map(
3760
+ (t) => t.id === adminToken.id ? { ...t, status: "expired" /* EXPIRED */ } : t
3761
+ );
3762
+ await updateClinicGroup(db, groupId, {
3763
+ adminTokens: updatedTokens2
3764
+ });
3765
+ throw new Error("Admin token has expired");
3766
+ }
3767
+ const updatedTokens = group.adminTokens.map(
3768
+ (t) => t.id === adminToken.id ? {
3769
+ ...t,
3770
+ status: "used" /* USED */,
3771
+ usedByUserRef: userRef
3772
+ } : t
3773
+ );
3774
+ await updateClinicGroup(db, groupId, {
3775
+ adminTokens: updatedTokens
3776
+ });
3777
+ return true;
3778
+ }
3779
+ async function deleteAdminToken(db, groupId, tokenId, adminId) {
3780
+ const group = await getClinicGroup(db, groupId);
3781
+ if (!group) {
3782
+ throw new Error("Clinic group not found");
3783
+ }
3784
+ if (!group.admins.includes(adminId)) {
3785
+ throw new Error("Admin does not belong to this clinic group");
3786
+ }
3787
+ const updatedTokens = group.adminTokens.filter((t) => t.id !== tokenId);
3788
+ await updateClinicGroup(db, groupId, {
3789
+ adminTokens: updatedTokens
3790
+ });
3791
+ }
3792
+ async function getActiveAdminTokens(db, groupId, adminId) {
3793
+ const group = await getClinicGroup(db, groupId);
3794
+ if (!group) {
3795
+ throw new Error("Clinic group not found");
3796
+ }
3797
+ if (!group.admins.includes(adminId)) {
3798
+ throw new Error("Admin does not belong to this clinic group");
3799
+ }
3800
+ return group.adminTokens.filter((t) => t.status === "active" /* ACTIVE */);
3801
+ }
3802
+
3803
+ // src/services/clinic/clinic-group.service.ts
3804
+ var ClinicGroupService = class extends BaseService {
3805
+ constructor(db, auth, app, clinicAdminService) {
3806
+ super(db, auth, app);
3807
+ this.clinicAdminService = clinicAdminService;
3672
3808
  }
3673
3809
  /**
3674
- * Šalje email za resetovanje lozinke korisniku
3675
- * @param email Email adresa korisnika
3676
- * @returns Promise koji se razrešava kada je email poslat
3810
+ * Kreira novu grupaciju klinika
3677
3811
  */
3678
- async sendPasswordResetEmail(email) {
3679
- try {
3680
- await emailSchema.parseAsync(email);
3681
- await sendPasswordResetEmail(this.auth, email);
3682
- } catch (error) {
3683
- if (error instanceof z13.ZodError) {
3684
- throw AUTH_ERRORS.VALIDATION_ERROR;
3685
- }
3686
- const firebaseError = error;
3687
- if (firebaseError.code === "auth/user-not-found" /* USER_NOT_FOUND */) {
3688
- throw AUTH_ERRORS.USER_NOT_FOUND;
3689
- }
3690
- throw error;
3691
- }
3812
+ async createClinicGroup(data, ownerId, isDefault = false) {
3813
+ return createClinicGroup(
3814
+ this.db,
3815
+ data,
3816
+ ownerId,
3817
+ isDefault,
3818
+ this.clinicAdminService
3819
+ );
3692
3820
  }
3693
3821
  /**
3694
- * Verifikuje kod za resetovanje lozinke iz email linka
3695
- * @param oobCode Kod iz URL-a za resetovanje lozinke
3696
- * @returns Promise koji se razrešava sa email adresom korisnika ako je kod validan
3822
+ * Dohvata grupaciju klinika po ID-u
3697
3823
  */
3698
- async verifyPasswordResetCode(oobCode) {
3699
- try {
3700
- return await verifyPasswordResetCode(this.auth, oobCode);
3701
- } catch (error) {
3702
- const firebaseError = error;
3703
- if (firebaseError.code === "auth/expired-action-code" /* EXPIRED_ACTION_CODE */) {
3704
- throw AUTH_ERRORS.EXPIRED_ACTION_CODE;
3705
- } else if (firebaseError.code === "auth/invalid-action-code" /* INVALID_ACTION_CODE */) {
3706
- throw AUTH_ERRORS.INVALID_ACTION_CODE;
3707
- }
3708
- throw error;
3709
- }
3824
+ async getClinicGroup(groupId) {
3825
+ return getClinicGroup(this.db, groupId);
3710
3826
  }
3711
3827
  /**
3712
- * Potvrđuje resetovanje lozinke i postavlja novu lozinku
3713
- * @param oobCode Kod iz URL-a za resetovanje lozinke
3714
- * @param newPassword Nova lozinka
3715
- * @returns Promise koji se razrešava kada je lozinka promenjena
3828
+ * Dohvata sve aktivne grupacije klinika
3716
3829
  */
3717
- async confirmPasswordReset(oobCode, newPassword) {
3718
- try {
3719
- await passwordSchema.parseAsync(newPassword);
3720
- await confirmPasswordReset(this.auth, oobCode, newPassword);
3721
- } catch (error) {
3722
- if (error instanceof z13.ZodError) {
3723
- throw AUTH_ERRORS.VALIDATION_ERROR;
3724
- }
3725
- const firebaseError = error;
3726
- if (firebaseError.code === "auth/expired-action-code" /* EXPIRED_ACTION_CODE */) {
3727
- throw AUTH_ERRORS.EXPIRED_ACTION_CODE;
3728
- } else if (firebaseError.code === "auth/invalid-action-code" /* INVALID_ACTION_CODE */) {
3729
- throw AUTH_ERRORS.INVALID_ACTION_CODE;
3730
- } else if (firebaseError.code === "auth/weak-password" /* WEAK_PASSWORD */) {
3731
- throw AUTH_ERRORS.WEAK_PASSWORD;
3732
- }
3733
- throw error;
3734
- }
3735
- }
3736
- };
3737
-
3738
- // src/services/notifications/notification.service.ts
3739
- import {
3740
- collection as collection5,
3741
- doc as doc7,
3742
- getDoc as getDoc11,
3743
- getDocs as getDocs5,
3744
- query as query5,
3745
- where as where5,
3746
- updateDoc as updateDoc10,
3747
- deleteDoc as deleteDoc4,
3748
- orderBy,
3749
- Timestamp as Timestamp9,
3750
- addDoc,
3751
- writeBatch as writeBatch2
3752
- } from "firebase/firestore";
3753
-
3754
- // src/types/notifications/index.ts
3755
- var NotificationType = /* @__PURE__ */ ((NotificationType3) => {
3756
- NotificationType3["PRE_REQUIREMENT"] = "preRequirement";
3757
- NotificationType3["POST_REQUIREMENT"] = "postRequirement";
3758
- NotificationType3["APPOINTMENT_REMINDER"] = "appointmentReminder";
3759
- NotificationType3["APPOINTMENT_NOTIFICATION"] = "appointmentNotification";
3760
- return NotificationType3;
3761
- })(NotificationType || {});
3762
- var NOTIFICATIONS_COLLECTION = "notifications";
3763
- var NotificationStatus = /* @__PURE__ */ ((NotificationStatus2) => {
3764
- NotificationStatus2["PENDING"] = "pending";
3765
- NotificationStatus2["SENT"] = "sent";
3766
- NotificationStatus2["FAILED"] = "failed";
3767
- NotificationStatus2["CANCELLED"] = "cancelled";
3768
- NotificationStatus2["PARTIAL_SUCCESS"] = "partialSuccess";
3769
- return NotificationStatus2;
3770
- })(NotificationStatus || {});
3771
-
3772
- // src/services/notifications/notification.service.ts
3773
- var NotificationService = class extends BaseService {
3774
- /**
3775
- * Kreira novu notifikaciju
3776
- */
3777
- async createNotification(notification) {
3778
- const notificationsRef = collection5(this.db, NOTIFICATIONS_COLLECTION);
3779
- const now = Timestamp9.now();
3780
- const notificationData = {
3781
- ...notification,
3782
- createdAt: now,
3783
- updatedAt: now,
3784
- status: "pending" /* PENDING */,
3785
- isRead: false,
3786
- userRole: notification.userRole || "patient" /* PATIENT */
3787
- };
3788
- const docRef = await addDoc(notificationsRef, notificationData);
3789
- return {
3790
- ...notificationData,
3791
- id: docRef.id
3792
- };
3830
+ async getAllActiveGroups() {
3831
+ return getAllActiveGroups(this.db);
3793
3832
  }
3794
3833
  /**
3795
- * Dohvata notifikaciju po ID-u
3834
+ * Ažurira grupaciju klinika
3796
3835
  */
3797
- async getNotification(notificationId) {
3798
- const notificationRef = doc7(
3799
- this.db,
3800
- NOTIFICATIONS_COLLECTION,
3801
- notificationId
3802
- );
3803
- const notificationDoc = await getDoc11(notificationRef);
3804
- if (!notificationDoc.exists()) {
3805
- return null;
3806
- }
3807
- return {
3808
- id: notificationDoc.id,
3809
- ...notificationDoc.data()
3810
- };
3836
+ async updateClinicGroup(groupId, data) {
3837
+ return updateClinicGroup(this.db, groupId, data);
3811
3838
  }
3812
3839
  /**
3813
- * Dohvata sve notifikacije za korisnika
3840
+ * Dodaje admina u grupaciju
3814
3841
  */
3815
- async getUserNotifications(userId) {
3816
- const q = query5(
3817
- collection5(this.db, NOTIFICATIONS_COLLECTION),
3818
- where5("userId", "==", userId),
3819
- orderBy("notificationTime", "desc")
3820
- );
3821
- const querySnapshot = await getDocs5(q);
3822
- return querySnapshot.docs.map((doc13) => ({
3823
- id: doc13.id,
3824
- ...doc13.data()
3825
- }));
3842
+ async addAdminToGroup(groupId, adminId) {
3843
+ return addAdminToGroup(this.db, groupId, adminId);
3826
3844
  }
3827
3845
  /**
3828
- * Dohvata nepročitane notifikacije za korisnika
3846
+ * Uklanja admina iz grupacije
3829
3847
  */
3830
- async getUnreadNotifications(userId) {
3831
- const q = query5(
3832
- collection5(this.db, NOTIFICATIONS_COLLECTION),
3833
- where5("userId", "==", userId),
3834
- where5("isRead", "==", false),
3835
- orderBy("notificationTime", "desc")
3836
- );
3837
- const querySnapshot = await getDocs5(q);
3838
- return querySnapshot.docs.map((doc13) => ({
3839
- id: doc13.id,
3840
- ...doc13.data()
3841
- }));
3848
+ async removeAdminFromGroup(groupId, adminId) {
3849
+ return removeAdminFromGroup(this.db, groupId, adminId);
3842
3850
  }
3843
3851
  /**
3844
- * Označava notifikaciju kao pročitanu
3852
+ * Deaktivira grupaciju klinika
3845
3853
  */
3846
- async markAsRead(notificationId) {
3847
- const notificationRef = doc7(
3848
- this.db,
3849
- NOTIFICATIONS_COLLECTION,
3850
- notificationId
3851
- );
3852
- await updateDoc10(notificationRef, {
3853
- isRead: true,
3854
- updatedAt: Timestamp9.now()
3855
- });
3854
+ async deactivateClinicGroup(groupId) {
3855
+ return deactivateClinicGroup(this.db, groupId);
3856
3856
  }
3857
3857
  /**
3858
- * Označava sve notifikacije korisnika kao pročitane
3858
+ * Sets up additional clinic group information after initial creation
3859
+ *
3860
+ * @param groupId - The ID of the clinic group to set up
3861
+ * @param setupData - The setup data for the clinic group
3862
+ * @returns The updated clinic group
3859
3863
  */
3860
- async markAllAsRead(userId) {
3861
- const notifications = await this.getUnreadNotifications(userId);
3862
- const batch = writeBatch2(this.db);
3863
- notifications.forEach((notification) => {
3864
- const notificationRef = doc7(
3865
- this.db,
3866
- NOTIFICATIONS_COLLECTION,
3867
- notification.id
3868
- );
3869
- batch.update(notificationRef, {
3870
- isRead: true,
3871
- updatedAt: Timestamp9.now()
3872
- });
3873
- });
3874
- await batch.commit();
3864
+ async setupClinicGroup(groupId, setupData) {
3865
+ const clinicGroup = await this.getClinicGroup(groupId);
3866
+ if (!clinicGroup) {
3867
+ throw new Error(`Clinic group with ID ${groupId} not found`);
3868
+ }
3869
+ const updateData = {
3870
+ languages: setupData.languages,
3871
+ practiceType: setupData.practiceType,
3872
+ description: setupData.description,
3873
+ logo: setupData.logo,
3874
+ calendarSyncEnabled: setupData.calendarSyncEnabled,
3875
+ autoConfirmAppointments: setupData.autoConfirmAppointments
3876
+ };
3877
+ return this.updateClinicGroup(groupId, updateData);
3875
3878
  }
3876
3879
  /**
3877
- * Ažurira status notifikacije
3880
+ * Kreira admin token za grupaciju
3878
3881
  */
3879
- async updateNotificationStatus(notificationId, status) {
3880
- const notificationRef = doc7(
3882
+ async createAdminToken(groupId, creatorAdminId, data) {
3883
+ return createAdminToken(
3881
3884
  this.db,
3882
- NOTIFICATIONS_COLLECTION,
3883
- notificationId
3885
+ groupId,
3886
+ creatorAdminId,
3887
+ data
3884
3888
  );
3885
- await updateDoc10(notificationRef, {
3886
- status,
3887
- updatedAt: Timestamp9.now()
3888
- });
3889
3889
  }
3890
3890
  /**
3891
- * Briše notifikaciju
3891
+ * Verifikuje i koristi admin token
3892
3892
  */
3893
- async deleteNotification(notificationId) {
3894
- const notificationRef = doc7(
3893
+ async verifyAndUseAdminToken(groupId, token, userRef) {
3894
+ return verifyAndUseAdminToken(
3895
3895
  this.db,
3896
- NOTIFICATIONS_COLLECTION,
3897
- notificationId
3896
+ groupId,
3897
+ token,
3898
+ userRef
3898
3899
  );
3899
- await deleteDoc4(notificationRef);
3900
3900
  }
3901
3901
  /**
3902
- * Dohvata notifikacije po tipu
3902
+ * Briše admin token
3903
3903
  */
3904
- async getNotificationsByType(userId, type) {
3905
- const q = query5(
3906
- collection5(this.db, NOTIFICATIONS_COLLECTION),
3907
- where5("userId", "==", userId),
3908
- where5("notificationType", "==", type),
3909
- orderBy("notificationTime", "desc")
3904
+ async deleteAdminToken(groupId, tokenId, adminId) {
3905
+ return deleteAdminToken(
3906
+ this.db,
3907
+ groupId,
3908
+ tokenId,
3909
+ adminId
3910
3910
  );
3911
- const querySnapshot = await getDocs5(q);
3912
- return querySnapshot.docs.map((doc13) => ({
3913
- id: doc13.id,
3914
- ...doc13.data()
3915
- }));
3916
3911
  }
3917
3912
  /**
3918
- * Dohvata notifikacije za određeni termin
3913
+ * Dohvata aktivne admin tokene
3919
3914
  */
3920
- async getAppointmentNotifications(appointmentId) {
3921
- const q = query5(
3922
- collection5(this.db, NOTIFICATIONS_COLLECTION),
3923
- where5("appointmentId", "==", appointmentId),
3924
- orderBy("notificationTime", "desc")
3925
- );
3926
- const querySnapshot = await getDocs5(q);
3927
- return querySnapshot.docs.map((doc13) => ({
3928
- id: doc13.id,
3929
- ...doc13.data()
3930
- }));
3915
+ async getActiveAdminTokens(groupId, adminId) {
3916
+ return getActiveAdminTokens(this.db, groupId, adminId);
3931
3917
  }
3932
3918
  };
3933
3919
 
@@ -3940,10 +3926,10 @@ import {
3940
3926
  query as query6,
3941
3927
  where as where6,
3942
3928
  updateDoc as updateDoc11,
3943
- setDoc as setDoc9,
3944
- Timestamp as Timestamp10
3929
+ setDoc as setDoc10,
3930
+ Timestamp as Timestamp11
3945
3931
  } from "firebase/firestore";
3946
- import { geohashForLocation as geohashForLocation2 } from "geofire-common";
3932
+ import { geohashForLocation as geohashForLocation3 } from "geofire-common";
3947
3933
  import { z as z14 } from "zod";
3948
3934
  async function createClinic(db, data, creatorAdminId, clinicGroupService, clinicAdminService) {
3949
3935
  const validatedData = createClinicSchema.parse(data);
@@ -3961,12 +3947,12 @@ async function createClinic(db, data, creatorAdminId, clinicGroupService, clinic
3961
3947
  throw new Error("Clinic group not found");
3962
3948
  }
3963
3949
  if (validatedData.location) {
3964
- validatedData.location.geohash = geohashForLocation2([
3950
+ validatedData.location.geohash = geohashForLocation3([
3965
3951
  validatedData.location.latitude,
3966
3952
  validatedData.location.longitude
3967
3953
  ]);
3968
3954
  }
3969
- const now = Timestamp10.now();
3955
+ const now = Timestamp11.now();
3970
3956
  const clinicData = {
3971
3957
  ...validatedData,
3972
3958
  id: doc8(collection6(db, CLINICS_COLLECTION)).id,
@@ -3998,7 +3984,7 @@ async function createClinic(db, data, creatorAdminId, clinicGroupService, clinic
3998
3984
  };
3999
3985
  try {
4000
3986
  clinicSchema.parse(clinicData);
4001
- await setDoc9(doc8(db, CLINICS_COLLECTION, clinicData.id), clinicData);
3987
+ await setDoc10(doc8(db, CLINICS_COLLECTION, clinicData.id), clinicData);
4002
3988
  await clinicGroupService.updateClinicGroup(validatedData.clinicGroupId, {
4003
3989
  clinics: [...group.clinics, clinicData.id]
4004
3990
  });
@@ -4026,7 +4012,7 @@ async function getClinicsByGroup(db, groupId) {
4026
4012
  where6("isActive", "==", true)
4027
4013
  );
4028
4014
  const querySnapshot = await getDocs6(q);
4029
- return querySnapshot.docs.map((doc13) => doc13.data());
4015
+ return querySnapshot.docs.map((doc14) => doc14.data());
4030
4016
  }
4031
4017
  async function updateClinic(db, clinicId, data, adminId, clinicAdminService) {
4032
4018
  const clinic = await getClinic(db, clinicId);
@@ -4042,7 +4028,7 @@ async function updateClinic(db, clinicId, data, adminId, clinicAdminService) {
4042
4028
  }
4043
4029
  const updatedData = {
4044
4030
  ...data,
4045
- updatedAt: Timestamp10.now()
4031
+ updatedAt: Timestamp11.now()
4046
4032
  };
4047
4033
  await updateDoc11(doc8(db, CLINICS_COLLECTION, clinicId), updatedData);
4048
4034
  const updatedClinic = await getClinic(db, clinicId);
@@ -4065,7 +4051,7 @@ async function deactivateClinic(db, clinicId, adminId, clinicAdminService) {
4065
4051
  }
4066
4052
  await updateDoc11(doc8(db, CLINICS_COLLECTION, clinicId), {
4067
4053
  isActive: false,
4068
- updatedAt: Timestamp10.now()
4054
+ updatedAt: Timestamp11.now()
4069
4055
  });
4070
4056
  }
4071
4057
  async function getClinicsByAdmin(db, adminId, options = {}, clinicAdminService, clinicGroupService) {
@@ -4089,7 +4075,7 @@ async function getClinicsByAdmin(db, adminId, options = {}, clinicAdminService,
4089
4075
  }
4090
4076
  const q = query6(collection6(db, CLINICS_COLLECTION), ...constraints);
4091
4077
  const querySnapshot = await getDocs6(q);
4092
- return querySnapshot.docs.map((doc13) => doc13.data());
4078
+ return querySnapshot.docs.map((doc14) => doc14.data());
4093
4079
  }
4094
4080
  async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGroupService) {
4095
4081
  return getClinicsByAdmin(
@@ -4105,15 +4091,15 @@ async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGr
4105
4091
  import {
4106
4092
  collection as collection7,
4107
4093
  doc as doc9,
4108
- setDoc as setDoc10,
4109
- Timestamp as Timestamp11
4094
+ setDoc as setDoc11,
4095
+ Timestamp as Timestamp12
4110
4096
  } from "firebase/firestore";
4111
4097
  async function addReview(db, clinicId, review) {
4112
4098
  const clinic = await getClinic(db, clinicId);
4113
4099
  if (!clinic) {
4114
4100
  throw new Error("Clinic not found");
4115
4101
  }
4116
- const now = Timestamp11.now();
4102
+ const now = Timestamp12.now();
4117
4103
  const reviewData = {
4118
4104
  id: doc9(collection7(db, "clinic_reviews")).id,
4119
4105
  clinicId,
@@ -4125,7 +4111,7 @@ async function addReview(db, clinicId, review) {
4125
4111
  isVerified: false
4126
4112
  };
4127
4113
  clinicReviewSchema.parse(reviewData);
4128
- await setDoc10(doc9(db, "clinic_reviews", reviewData.id), reviewData);
4114
+ await setDoc11(doc9(db, "clinic_reviews", reviewData.id), reviewData);
4129
4115
  const newRating = clinic.rating ? {
4130
4116
  average: (clinic.rating.average * clinic.rating.count + review.rating) / (clinic.rating.count + 1),
4131
4117
  count: clinic.rating.count + 1
@@ -4244,8 +4230,8 @@ async function findClinicsInRadius(db, center, radiusInKm, filters) {
4244
4230
  }
4245
4231
  const q = query7(collection8(db, CLINICS_COLLECTION), ...constraints);
4246
4232
  const querySnapshot = await getDocs7(q);
4247
- for (const doc13 of querySnapshot.docs) {
4248
- const clinic = doc13.data();
4233
+ for (const doc14 of querySnapshot.docs) {
4234
+ const clinic = doc14.data();
4249
4235
  const distance = distanceBetween(
4250
4236
  [center.latitude, center.longitude],
4251
4237
  [clinic.location.latitude, clinic.location.longitude]
@@ -4387,341 +4373,656 @@ var ClinicService = class extends BaseService {
4387
4373
  this.clinicGroupService
4388
4374
  );
4389
4375
  }
4376
+ /**
4377
+ * Creates a new clinic branch for a clinic group
4378
+ *
4379
+ * @param clinicGroupId - The ID of the clinic group
4380
+ * @param setupData - The setup data for the clinic branch
4381
+ * @param adminId - The ID of the admin creating the branch
4382
+ * @returns The created clinic
4383
+ */
4384
+ async createClinicBranch(clinicGroupId, setupData, adminId) {
4385
+ const clinicGroup = await this.clinicGroupService.getClinicGroup(
4386
+ clinicGroupId
4387
+ );
4388
+ if (!clinicGroup) {
4389
+ throw new Error(`Clinic group with ID ${clinicGroupId} not found`);
4390
+ }
4391
+ const createClinicData = {
4392
+ clinicGroupId,
4393
+ name: setupData.name,
4394
+ description: setupData.description,
4395
+ location: setupData.location,
4396
+ contactInfo: setupData.contactInfo,
4397
+ workingHours: setupData.workingHours,
4398
+ tags: setupData.tags,
4399
+ photos: setupData.photos,
4400
+ photosWithTags: setupData.photosWithTags,
4401
+ doctors: [],
4402
+ services: [],
4403
+ admins: [adminId],
4404
+ isActive: true,
4405
+ isVerified: false,
4406
+ logo: setupData.logo,
4407
+ featuredPhotos: setupData.featuredPhotos || []
4408
+ };
4409
+ const clinic = await this.createClinic(createClinicData, adminId);
4410
+ return clinic;
4411
+ }
4390
4412
  };
4391
4413
 
4392
- // src/services/clinic/utils/clinic-group.utils.ts
4393
- import {
4394
- collection as collection9,
4395
- doc as doc10,
4396
- getDoc as getDoc13,
4397
- getDocs as getDocs8,
4398
- query as query8,
4399
- where as where8,
4400
- updateDoc as updateDoc12,
4401
- setDoc as setDoc11,
4402
- Timestamp as Timestamp12
4403
- } from "firebase/firestore";
4404
- import { geohashForLocation as geohashForLocation3 } from "geofire-common";
4405
- import { z as z15 } from "zod";
4406
- function generateId() {
4407
- const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
4408
- const timestamp = Date.now().toString(36);
4409
- const randomPart = Array.from(
4410
- { length: 12 },
4411
- () => chars.charAt(Math.floor(Math.random() * chars.length))
4412
- ).join("");
4413
- return `${randomPart}-${timestamp}`;
4414
- }
4415
- async function createClinicGroup(db, data, ownerId, isDefault = false, clinicAdminService) {
4416
- const validatedData = createClinicGroupSchema.parse(data);
4417
- const owner = await clinicAdminService.getClinicAdmin(ownerId);
4418
- if (!owner) {
4419
- throw new Error("Owner not found or is not a clinic admin");
4414
+ // src/services/auth.service.ts
4415
+ var AuthService = class extends BaseService {
4416
+ constructor(db, auth, app, userService) {
4417
+ super(db, auth, app);
4418
+ this.googleProvider = new GoogleAuthProvider();
4419
+ this.facebookProvider = new FacebookAuthProvider();
4420
+ this.appleProvider = new OAuthProvider("apple.com");
4421
+ if (!userService) {
4422
+ userService = new UserService(db, auth, app);
4423
+ }
4424
+ this.userService = userService;
4420
4425
  }
4421
- if (validatedData.hqLocation) {
4422
- validatedData.hqLocation.geohash = geohashForLocation3([
4423
- validatedData.hqLocation.latitude,
4424
- validatedData.hqLocation.longitude
4425
- ]);
4426
+ /**
4427
+ * Registruje novog korisnika sa email-om i lozinkom
4428
+ */
4429
+ async signUp(email, password, initialRole = "patient" /* PATIENT */) {
4430
+ const { user: firebaseUser } = await createUserWithEmailAndPassword(
4431
+ this.auth,
4432
+ email,
4433
+ password
4434
+ );
4435
+ return this.userService.createUser(firebaseUser, [initialRole]);
4426
4436
  }
4427
- const now = Timestamp12.now();
4428
- const groupData = {
4429
- ...validatedData,
4430
- id: doc10(collection9(db, CLINIC_GROUPS_COLLECTION)).id,
4431
- description: isDefault ? void 0 : validatedData.description || void 0,
4432
- hqLocation: {
4433
- ...validatedData.hqLocation,
4434
- geohash: validatedData.hqLocation.geohash || void 0
4435
- },
4436
- contactInfo: {
4437
- ...validatedData.contactInfo,
4438
- alternativePhoneNumber: isDefault ? void 0 : validatedData.contactInfo.alternativePhoneNumber || void 0,
4439
- website: isDefault ? void 0 : validatedData.contactInfo.website || void 0
4440
- },
4441
- clinics: [],
4442
- clinicsInfo: [],
4443
- admins: [ownerId],
4444
- adminsInfo: [],
4445
- adminTokens: [],
4446
- ownerId,
4447
- createdAt: now,
4448
- updatedAt: now,
4449
- isActive: true
4450
- };
4451
- try {
4452
- clinicGroupSchema.parse(groupData);
4453
- await setDoc11(doc10(db, CLINIC_GROUPS_COLLECTION, groupData.id), groupData);
4454
- await clinicAdminService.updateClinicAdmin(ownerId, {
4455
- clinicGroupId: groupData.id,
4456
- isGroupOwner: true
4457
- });
4458
- return groupData;
4459
- } catch (error) {
4460
- if (error instanceof z15.ZodError) {
4461
- throw new Error("Invalid clinic group data: " + error.message);
4437
+ /**
4438
+ * Registers a new clinic admin user with email and password
4439
+ * Can either create a new clinic group or join an existing one with a token
4440
+ *
4441
+ * @param data - Clinic admin signup data
4442
+ * @returns The created user
4443
+ */
4444
+ async signUpClinicAdmin(data) {
4445
+ try {
4446
+ await clinicAdminSignupSchema.parseAsync(data);
4447
+ const { user: firebaseUser } = await createUserWithEmailAndPassword(
4448
+ this.auth,
4449
+ data.email,
4450
+ data.password
4451
+ );
4452
+ const user = await this.userService.createUser(firebaseUser, [
4453
+ "clinic_admin" /* CLINIC_ADMIN */
4454
+ ]);
4455
+ const contactPerson = {
4456
+ firstName: data.firstName,
4457
+ lastName: data.lastName,
4458
+ title: data.title,
4459
+ email: data.email,
4460
+ phoneNumber: data.phoneNumber
4461
+ };
4462
+ const clinicAdminService = new ClinicAdminService(
4463
+ this.db,
4464
+ this.auth,
4465
+ this.app
4466
+ );
4467
+ const clinicGroupService = new ClinicGroupService(
4468
+ this.db,
4469
+ this.auth,
4470
+ this.app,
4471
+ clinicAdminService
4472
+ );
4473
+ const clinicService = new ClinicService(
4474
+ this.db,
4475
+ this.auth,
4476
+ this.app,
4477
+ clinicGroupService,
4478
+ clinicAdminService
4479
+ );
4480
+ clinicAdminService.setServices(clinicGroupService, clinicService);
4481
+ if (data.isCreatingNewGroup) {
4482
+ if (!data.clinicGroupData) {
4483
+ throw new Error(
4484
+ "Clinic group data is required when creating a new group"
4485
+ );
4486
+ }
4487
+ const createClinicGroupData = {
4488
+ name: data.clinicGroupData.name,
4489
+ hqLocation: data.clinicGroupData.hqLocation,
4490
+ contactInfo: data.clinicGroupData.contactInfo,
4491
+ contactPerson,
4492
+ ownerId: firebaseUser.uid,
4493
+ isActive: true,
4494
+ logo: data.clinicGroupData.logo,
4495
+ subscriptionModel: data.clinicGroupData.subscriptionModel || "no_subscription" /* NO_SUBSCRIPTION */
4496
+ };
4497
+ await clinicGroupService.createClinicGroup(
4498
+ createClinicGroupData,
4499
+ firebaseUser.uid,
4500
+ true
4501
+ );
4502
+ } else {
4503
+ if (!data.inviteToken) {
4504
+ throw new Error(
4505
+ "Invite token is required when joining an existing group"
4506
+ );
4507
+ }
4508
+ const groupsRef = collection9(this.db, CLINIC_GROUPS_COLLECTION);
4509
+ const q = query8(groupsRef);
4510
+ const querySnapshot = await getDocs8(q);
4511
+ let foundGroup = null;
4512
+ let foundToken = null;
4513
+ for (const docSnapshot of querySnapshot.docs) {
4514
+ const group = docSnapshot.data();
4515
+ const token = group.adminTokens.find(
4516
+ (t) => t.token === data.inviteToken && t.status === "active" /* ACTIVE */ && new Date(t.expiresAt.toDate()) > /* @__PURE__ */ new Date()
4517
+ );
4518
+ if (token) {
4519
+ foundGroup = group;
4520
+ foundToken = token;
4521
+ break;
4522
+ }
4523
+ }
4524
+ if (!foundGroup || !foundToken) {
4525
+ throw new Error("Invalid or expired invite token");
4526
+ }
4527
+ const createClinicAdminData = {
4528
+ userRef: firebaseUser.uid,
4529
+ clinicGroupId: foundGroup.id,
4530
+ isGroupOwner: false,
4531
+ clinicsManaged: [],
4532
+ contactInfo: contactPerson,
4533
+ roleTitle: data.title,
4534
+ isActive: true
4535
+ };
4536
+ await clinicAdminService.createClinicAdmin(createClinicAdminData);
4537
+ await clinicGroupService.verifyAndUseAdminToken(
4538
+ foundGroup.id,
4539
+ data.inviteToken,
4540
+ firebaseUser.uid
4541
+ );
4542
+ }
4543
+ return user;
4544
+ } catch (error) {
4545
+ if (error instanceof z15.ZodError) {
4546
+ throw AUTH_ERRORS.VALIDATION_ERROR;
4547
+ }
4548
+ const firebaseError = error;
4549
+ if (firebaseError.code === "auth/email-already-in-use" /* EMAIL_ALREADY_IN_USE */) {
4550
+ throw AUTH_ERRORS.EMAIL_ALREADY_EXISTS;
4551
+ }
4552
+ throw error;
4462
4553
  }
4463
- throw error;
4464
- }
4465
- }
4466
- async function getClinicGroup(db, groupId) {
4467
- const docRef = doc10(db, CLINIC_GROUPS_COLLECTION, groupId);
4468
- const docSnap = await getDoc13(docRef);
4469
- if (docSnap.exists()) {
4470
- return docSnap.data();
4471
- }
4472
- return null;
4473
- }
4474
- async function getAllActiveGroups(db) {
4475
- const q = query8(
4476
- collection9(db, CLINIC_GROUPS_COLLECTION),
4477
- where8("isActive", "==", true)
4478
- );
4479
- const querySnapshot = await getDocs8(q);
4480
- return querySnapshot.docs.map((doc13) => doc13.data());
4481
- }
4482
- async function updateClinicGroup(db, groupId, data) {
4483
- const group = await getClinicGroup(db, groupId);
4484
- if (!group) {
4485
- throw new Error("Clinic group not found");
4486
- }
4487
- const updatedData = {
4488
- ...data,
4489
- updatedAt: Timestamp12.now()
4490
- };
4491
- await updateDoc12(doc10(db, CLINIC_GROUPS_COLLECTION, groupId), updatedData);
4492
- const updatedGroup = await getClinicGroup(db, groupId);
4493
- if (!updatedGroup) {
4494
- throw new Error("Failed to retrieve updated clinic group");
4495
- }
4496
- return updatedGroup;
4497
- }
4498
- async function addAdminToGroup(db, groupId, adminId) {
4499
- const group = await getClinicGroup(db, groupId);
4500
- if (!group) {
4501
- throw new Error("Clinic group not found");
4502
- }
4503
- if (group.admins.includes(adminId)) {
4504
- return;
4505
- }
4506
- await updateClinicGroup(db, groupId, {
4507
- admins: [...group.admins, adminId]
4508
- });
4509
- }
4510
- async function removeAdminFromGroup(db, groupId, adminId) {
4511
- const group = await getClinicGroup(db, groupId);
4512
- if (!group) {
4513
- throw new Error("Clinic group not found");
4514
4554
  }
4515
- if (group.ownerId === adminId) {
4516
- throw new Error("Cannot remove the owner from the group");
4517
- }
4518
- if (!group.admins.includes(adminId)) {
4519
- return;
4555
+ /**
4556
+ * Prijavljuje korisnika sa email-om i lozinkom
4557
+ */
4558
+ async signIn(email, password) {
4559
+ const { user: firebaseUser } = await signInWithEmailAndPassword(
4560
+ this.auth,
4561
+ email,
4562
+ password
4563
+ );
4564
+ return this.userService.getOrCreateUser(firebaseUser);
4520
4565
  }
4521
- await updateClinicGroup(db, groupId, {
4522
- admins: group.admins.filter((id) => id !== adminId)
4523
- });
4524
- }
4525
- async function deactivateClinicGroup(db, groupId) {
4526
- const group = await getClinicGroup(db, groupId);
4527
- if (!group) {
4528
- throw new Error("Clinic group not found");
4566
+ /**
4567
+ * Prijavljuje korisnika sa Facebook-om
4568
+ */
4569
+ async signInWithFacebook() {
4570
+ const provider = new FacebookAuthProvider();
4571
+ const { user: firebaseUser } = await signInWithPopup(this.auth, provider);
4572
+ return this.userService.getOrCreateUser(firebaseUser);
4529
4573
  }
4530
- await updateDoc12(doc10(db, CLINIC_GROUPS_COLLECTION, groupId), {
4531
- isActive: false,
4532
- updatedAt: Timestamp12.now()
4533
- });
4534
- }
4535
- async function createAdminToken(db, groupId, creatorAdminId, data) {
4536
- const group = await getClinicGroup(db, groupId);
4537
- if (!group) {
4538
- throw new Error("Clinic group not found");
4574
+ /**
4575
+ * Prijavljuje korisnika sa Google nalogom
4576
+ */
4577
+ async signInWithGoogle(initialRole = "patient" /* PATIENT */) {
4578
+ const { user: firebaseUser } = await signInWithPopup(
4579
+ this.auth,
4580
+ this.googleProvider
4581
+ );
4582
+ return this.userService.getOrCreateUser(firebaseUser);
4539
4583
  }
4540
- if (!group.admins.includes(creatorAdminId)) {
4541
- throw new Error("Admin does not belong to this clinic group");
4584
+ /**
4585
+ * Prijavljuje korisnika sa Apple-om
4586
+ */
4587
+ async signInWithApple() {
4588
+ const provider = new OAuthProvider("apple.com");
4589
+ const { user: firebaseUser } = await signInWithPopup(this.auth, provider);
4590
+ return this.userService.getOrCreateUser(firebaseUser);
4542
4591
  }
4543
- const now = Timestamp12.now();
4544
- const expiresInDays = (data == null ? void 0 : data.expiresInDays) || 7;
4545
- const expiresAt = new Timestamp12(
4546
- now.seconds + expiresInDays * 24 * 60 * 60,
4547
- now.nanoseconds
4548
- );
4549
- const token = {
4550
- id: generateId(),
4551
- token: generateId(),
4552
- status: "active" /* ACTIVE */,
4553
- createdAt: now,
4554
- expiresAt
4555
- };
4556
- await updateClinicGroup(db, groupId, {
4557
- adminTokens: [...group.adminTokens, token]
4558
- });
4559
- return token;
4560
- }
4561
- async function verifyAndUseAdminToken(db, groupId, token, userRef) {
4562
- const group = await getClinicGroup(db, groupId);
4563
- if (!group) {
4564
- throw new Error("Clinic group not found");
4592
+ /**
4593
+ * Prijavljuje korisnika anonimno
4594
+ */
4595
+ async signInAnonymously() {
4596
+ const { user: firebaseUser } = await firebaseSignInAnonymously(this.auth);
4597
+ return this.userService.getOrCreateUser(firebaseUser);
4565
4598
  }
4566
- const adminToken = group.adminTokens.find((t) => t.token === token);
4567
- if (!adminToken) {
4568
- throw new Error("Admin token not found");
4599
+ /**
4600
+ * Odjavljuje trenutnog korisnika
4601
+ */
4602
+ async signOut() {
4603
+ await firebaseSignOut(this.auth);
4569
4604
  }
4570
- if (adminToken.status !== "active" /* ACTIVE */) {
4571
- throw new Error("Admin token is not active");
4605
+ /**
4606
+ * Vraća trenutno prijavljenog korisnika
4607
+ */
4608
+ async getCurrentUser() {
4609
+ const firebaseUser = this.auth.currentUser;
4610
+ if (!firebaseUser) return null;
4611
+ return this.userService.getUserById(firebaseUser.uid);
4572
4612
  }
4573
- const now = Timestamp12.now();
4574
- if (adminToken.expiresAt.seconds < now.seconds) {
4575
- const updatedTokens2 = group.adminTokens.map(
4576
- (t) => t.id === adminToken.id ? { ...t, status: "expired" /* EXPIRED */ } : t
4577
- );
4578
- await updateClinicGroup(db, groupId, {
4579
- adminTokens: updatedTokens2
4580
- });
4581
- throw new Error("Admin token has expired");
4613
+ /**
4614
+ * Registruje callback za promene stanja autentifikacije
4615
+ */
4616
+ onAuthStateChange(callback) {
4617
+ return onAuthStateChanged(this.auth, callback);
4582
4618
  }
4583
- const updatedTokens = group.adminTokens.map(
4584
- (t) => t.id === adminToken.id ? {
4585
- ...t,
4586
- status: "used" /* USED */,
4587
- usedByUserRef: userRef
4588
- } : t
4589
- );
4590
- await updateClinicGroup(db, groupId, {
4591
- adminTokens: updatedTokens
4592
- });
4593
- return true;
4594
- }
4595
- async function deleteAdminToken(db, groupId, tokenId, adminId) {
4596
- const group = await getClinicGroup(db, groupId);
4597
- if (!group) {
4598
- throw new Error("Clinic group not found");
4619
+ async upgradeAnonymousUser(email, password) {
4620
+ try {
4621
+ await emailSchema.parseAsync(email);
4622
+ await passwordSchema.parseAsync(password);
4623
+ const currentUser = this.auth.currentUser;
4624
+ if (!currentUser) {
4625
+ throw AUTH_ERRORS.NOT_AUTHENTICATED;
4626
+ }
4627
+ if (!currentUser.isAnonymous) {
4628
+ throw new AuthError(
4629
+ "User is not anonymous",
4630
+ "AUTH/NOT_ANONYMOUS_USER",
4631
+ 400
4632
+ );
4633
+ }
4634
+ const credential = EmailAuthProvider.credential(email, password);
4635
+ await linkWithCredential(currentUser, credential);
4636
+ return await this.userService.upgradeAnonymousUser(
4637
+ currentUser.uid,
4638
+ email
4639
+ );
4640
+ } catch (error) {
4641
+ if (error instanceof z15.ZodError) {
4642
+ throw AUTH_ERRORS.VALIDATION_ERROR;
4643
+ }
4644
+ const firebaseError = error;
4645
+ if (firebaseError.code === "auth/email-already-in-use" /* EMAIL_ALREADY_IN_USE */) {
4646
+ throw AUTH_ERRORS.EMAIL_ALREADY_EXISTS;
4647
+ }
4648
+ throw error;
4649
+ }
4599
4650
  }
4600
- if (!group.admins.includes(adminId)) {
4601
- throw new Error("Admin does not belong to this clinic group");
4651
+ /**
4652
+ * Upgrades an anonymous user to a regular user by signing in with a Google account.
4653
+ *
4654
+ * @throws {AuthError} If the user is not anonymous.
4655
+ * @throws {AuthError} If the user is not authenticated.
4656
+ * @throws {AuthError} If the popup window is closed by the user.
4657
+ * @throws {FirebaseError} If any other Firebase error occurs.
4658
+ *
4659
+ * @returns {Promise<User>} The upgraded user.
4660
+ */
4661
+ async upgradeAnonymousUserWithGoogle() {
4662
+ try {
4663
+ const currentUser = this.auth.currentUser;
4664
+ if (!currentUser) {
4665
+ throw AUTH_ERRORS.NOT_AUTHENTICATED;
4666
+ }
4667
+ if (!currentUser.isAnonymous) {
4668
+ throw new AuthError(
4669
+ "User is not anonymous",
4670
+ "AUTH/NOT_ANONYMOUS_USER",
4671
+ 400
4672
+ );
4673
+ }
4674
+ const userCredential = await signInWithPopup(
4675
+ this.auth,
4676
+ this.googleProvider
4677
+ );
4678
+ if (!userCredential) throw AUTH_ERRORS.INVALID_CREDENTIAL;
4679
+ return await this.userService.upgradeAnonymousUser(
4680
+ currentUser.uid,
4681
+ userCredential.user.email
4682
+ );
4683
+ } catch (error) {
4684
+ const firebaseError = error;
4685
+ if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
4686
+ throw AUTH_ERRORS.POPUP_CLOSED;
4687
+ }
4688
+ throw error;
4689
+ }
4602
4690
  }
4603
- const updatedTokens = group.adminTokens.filter((t) => t.id !== tokenId);
4604
- await updateClinicGroup(db, groupId, {
4605
- adminTokens: updatedTokens
4606
- });
4607
- }
4608
- async function getActiveAdminTokens(db, groupId, adminId) {
4609
- const group = await getClinicGroup(db, groupId);
4610
- if (!group) {
4611
- throw new Error("Clinic group not found");
4691
+ async upgradeAnonymousUserWithFacebook() {
4692
+ try {
4693
+ const currentUser = this.auth.currentUser;
4694
+ if (!currentUser) {
4695
+ throw AUTH_ERRORS.NOT_AUTHENTICATED;
4696
+ }
4697
+ if (!currentUser.isAnonymous) {
4698
+ throw new AuthError(
4699
+ "User is not anonymous",
4700
+ "AUTH/NOT_ANONYMOUS_USER",
4701
+ 400
4702
+ );
4703
+ }
4704
+ this.facebookProvider.addScope("email");
4705
+ const userCredential = await signInWithPopup(
4706
+ this.auth,
4707
+ this.facebookProvider
4708
+ );
4709
+ if (!userCredential) throw AUTH_ERRORS.INVALID_CREDENTIAL;
4710
+ return await this.userService.upgradeAnonymousUser(
4711
+ currentUser.uid,
4712
+ userCredential.user.email
4713
+ );
4714
+ } catch (error) {
4715
+ const firebaseError = error;
4716
+ if (firebaseError.code === "auth/popup-closed-by-user" /* POPUP_CLOSED_BY_USER */) {
4717
+ throw AUTH_ERRORS.POPUP_CLOSED;
4718
+ }
4719
+ throw error;
4720
+ }
4612
4721
  }
4613
- if (!group.admins.includes(adminId)) {
4614
- throw new Error("Admin does not belong to this clinic group");
4722
+ async upgradeAnonymousUserWithApple() {
4723
+ try {
4724
+ const currentUser = this.auth.currentUser;
4725
+ if (!currentUser) {
4726
+ throw AUTH_ERRORS.NOT_AUTHENTICATED;
4727
+ }
4728
+ if (!currentUser.isAnonymous) {
4729
+ throw new AuthError(
4730
+ "User is not anonymous",
4731
+ "AUTH/NOT_ANONYMOUS_USER",
4732
+ 400
4733
+ );
4734
+ }
4735
+ this.appleProvider.addScope("email");
4736
+ this.appleProvider.addScope("name");
4737
+ const userCredential = await signInWithPopup(
4738
+ this.auth,
4739
+ this.appleProvider
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
+ }
4615
4753
  }
4616
- return group.adminTokens.filter((t) => t.status === "active" /* ACTIVE */);
4617
- }
4618
-
4619
- // src/services/clinic/clinic-group.service.ts
4620
- var ClinicGroupService = class extends BaseService {
4621
- constructor(db, auth, app, clinicAdminService) {
4622
- super(db, auth, app);
4623
- this.clinicAdminService = clinicAdminService;
4754
+ /**
4755
+ * Šalje email za resetovanje lozinke korisniku
4756
+ * @param email Email adresa korisnika
4757
+ * @returns Promise koji se razrešava kada je email poslat
4758
+ */
4759
+ async sendPasswordResetEmail(email) {
4760
+ try {
4761
+ await emailSchema.parseAsync(email);
4762
+ await sendPasswordResetEmail(this.auth, email);
4763
+ } catch (error) {
4764
+ if (error instanceof z15.ZodError) {
4765
+ throw AUTH_ERRORS.VALIDATION_ERROR;
4766
+ }
4767
+ const firebaseError = error;
4768
+ if (firebaseError.code === "auth/user-not-found" /* USER_NOT_FOUND */) {
4769
+ throw AUTH_ERRORS.USER_NOT_FOUND;
4770
+ }
4771
+ throw error;
4772
+ }
4624
4773
  }
4625
4774
  /**
4626
- * Kreira novu grupaciju klinika
4775
+ * Verifikuje kod za resetovanje lozinke iz email linka
4776
+ * @param oobCode Kod iz URL-a za resetovanje lozinke
4777
+ * @returns Promise koji se razrešava sa email adresom korisnika ako je kod validan
4627
4778
  */
4628
- async createClinicGroup(data, ownerId, isDefault = false) {
4629
- return createClinicGroup(
4630
- this.db,
4631
- data,
4632
- ownerId,
4633
- isDefault,
4634
- this.clinicAdminService
4635
- );
4779
+ async verifyPasswordResetCode(oobCode) {
4780
+ try {
4781
+ return await verifyPasswordResetCode(this.auth, oobCode);
4782
+ } catch (error) {
4783
+ const firebaseError = error;
4784
+ if (firebaseError.code === "auth/expired-action-code" /* EXPIRED_ACTION_CODE */) {
4785
+ throw AUTH_ERRORS.EXPIRED_ACTION_CODE;
4786
+ } else if (firebaseError.code === "auth/invalid-action-code" /* INVALID_ACTION_CODE */) {
4787
+ throw AUTH_ERRORS.INVALID_ACTION_CODE;
4788
+ }
4789
+ throw error;
4790
+ }
4636
4791
  }
4637
4792
  /**
4638
- * Dohvata grupaciju klinika po ID-u
4793
+ * Potvrđuje resetovanje lozinke i postavlja novu lozinku
4794
+ * @param oobCode Kod iz URL-a za resetovanje lozinke
4795
+ * @param newPassword Nova lozinka
4796
+ * @returns Promise koji se razrešava kada je lozinka promenjena
4639
4797
  */
4640
- async getClinicGroup(groupId) {
4641
- return getClinicGroup(this.db, groupId);
4798
+ async confirmPasswordReset(oobCode, newPassword) {
4799
+ try {
4800
+ await passwordSchema.parseAsync(newPassword);
4801
+ await confirmPasswordReset(this.auth, oobCode, newPassword);
4802
+ } catch (error) {
4803
+ if (error instanceof z15.ZodError) {
4804
+ throw AUTH_ERRORS.VALIDATION_ERROR;
4805
+ }
4806
+ const firebaseError = error;
4807
+ if (firebaseError.code === "auth/expired-action-code" /* EXPIRED_ACTION_CODE */) {
4808
+ throw AUTH_ERRORS.EXPIRED_ACTION_CODE;
4809
+ } else if (firebaseError.code === "auth/invalid-action-code" /* INVALID_ACTION_CODE */) {
4810
+ throw AUTH_ERRORS.INVALID_ACTION_CODE;
4811
+ } else if (firebaseError.code === "auth/weak-password" /* WEAK_PASSWORD */) {
4812
+ throw AUTH_ERRORS.WEAK_PASSWORD;
4813
+ }
4814
+ throw error;
4815
+ }
4642
4816
  }
4817
+ };
4818
+
4819
+ // src/services/notifications/notification.service.ts
4820
+ import {
4821
+ collection as collection10,
4822
+ doc as doc11,
4823
+ getDoc as getDoc14,
4824
+ getDocs as getDocs9,
4825
+ query as query9,
4826
+ where as where9,
4827
+ updateDoc as updateDoc13,
4828
+ deleteDoc as deleteDoc6,
4829
+ orderBy,
4830
+ Timestamp as Timestamp14,
4831
+ addDoc,
4832
+ writeBatch as writeBatch2
4833
+ } from "firebase/firestore";
4834
+
4835
+ // src/types/notifications/index.ts
4836
+ var NotificationType = /* @__PURE__ */ ((NotificationType3) => {
4837
+ NotificationType3["PRE_REQUIREMENT"] = "preRequirement";
4838
+ NotificationType3["POST_REQUIREMENT"] = "postRequirement";
4839
+ NotificationType3["APPOINTMENT_REMINDER"] = "appointmentReminder";
4840
+ NotificationType3["APPOINTMENT_NOTIFICATION"] = "appointmentNotification";
4841
+ return NotificationType3;
4842
+ })(NotificationType || {});
4843
+ var NOTIFICATIONS_COLLECTION = "notifications";
4844
+ var NotificationStatus = /* @__PURE__ */ ((NotificationStatus2) => {
4845
+ NotificationStatus2["PENDING"] = "pending";
4846
+ NotificationStatus2["SENT"] = "sent";
4847
+ NotificationStatus2["FAILED"] = "failed";
4848
+ NotificationStatus2["CANCELLED"] = "cancelled";
4849
+ NotificationStatus2["PARTIAL_SUCCESS"] = "partialSuccess";
4850
+ return NotificationStatus2;
4851
+ })(NotificationStatus || {});
4852
+
4853
+ // src/services/notifications/notification.service.ts
4854
+ var NotificationService = class extends BaseService {
4643
4855
  /**
4644
- * Dohvata sve aktivne grupacije klinika
4856
+ * Kreira novu notifikaciju
4645
4857
  */
4646
- async getAllActiveGroups() {
4647
- return getAllActiveGroups(this.db);
4858
+ async createNotification(notification) {
4859
+ const notificationsRef = collection10(this.db, NOTIFICATIONS_COLLECTION);
4860
+ const now = Timestamp14.now();
4861
+ const notificationData = {
4862
+ ...notification,
4863
+ createdAt: now,
4864
+ updatedAt: now,
4865
+ status: "pending" /* PENDING */,
4866
+ isRead: false,
4867
+ userRole: notification.userRole || "patient" /* PATIENT */
4868
+ };
4869
+ const docRef = await addDoc(notificationsRef, notificationData);
4870
+ return {
4871
+ ...notificationData,
4872
+ id: docRef.id
4873
+ };
4648
4874
  }
4649
4875
  /**
4650
- * Ažurira grupaciju klinika
4876
+ * Dohvata notifikaciju po ID-u
4651
4877
  */
4652
- async updateClinicGroup(groupId, data) {
4653
- return updateClinicGroup(this.db, groupId, data);
4878
+ async getNotification(notificationId) {
4879
+ const notificationRef = doc11(
4880
+ this.db,
4881
+ NOTIFICATIONS_COLLECTION,
4882
+ notificationId
4883
+ );
4884
+ const notificationDoc = await getDoc14(notificationRef);
4885
+ if (!notificationDoc.exists()) {
4886
+ return null;
4887
+ }
4888
+ return {
4889
+ id: notificationDoc.id,
4890
+ ...notificationDoc.data()
4891
+ };
4654
4892
  }
4655
4893
  /**
4656
- * Dodaje admina u grupaciju
4894
+ * Dohvata sve notifikacije za korisnika
4657
4895
  */
4658
- async addAdminToGroup(groupId, adminId) {
4659
- return addAdminToGroup(this.db, groupId, adminId);
4896
+ async getUserNotifications(userId) {
4897
+ const q = query9(
4898
+ collection10(this.db, NOTIFICATIONS_COLLECTION),
4899
+ where9("userId", "==", userId),
4900
+ orderBy("notificationTime", "desc")
4901
+ );
4902
+ const querySnapshot = await getDocs9(q);
4903
+ return querySnapshot.docs.map((doc14) => ({
4904
+ id: doc14.id,
4905
+ ...doc14.data()
4906
+ }));
4660
4907
  }
4661
4908
  /**
4662
- * Uklanja admina iz grupacije
4909
+ * Dohvata nepročitane notifikacije za korisnika
4663
4910
  */
4664
- async removeAdminFromGroup(groupId, adminId) {
4665
- return removeAdminFromGroup(this.db, groupId, adminId);
4911
+ async getUnreadNotifications(userId) {
4912
+ const q = query9(
4913
+ collection10(this.db, NOTIFICATIONS_COLLECTION),
4914
+ where9("userId", "==", userId),
4915
+ where9("isRead", "==", false),
4916
+ orderBy("notificationTime", "desc")
4917
+ );
4918
+ const querySnapshot = await getDocs9(q);
4919
+ return querySnapshot.docs.map((doc14) => ({
4920
+ id: doc14.id,
4921
+ ...doc14.data()
4922
+ }));
4666
4923
  }
4667
4924
  /**
4668
- * Deaktivira grupaciju klinika
4925
+ * Označava notifikaciju kao pročitanu
4669
4926
  */
4670
- async deactivateClinicGroup(groupId) {
4671
- return deactivateClinicGroup(this.db, groupId);
4927
+ async markAsRead(notificationId) {
4928
+ const notificationRef = doc11(
4929
+ this.db,
4930
+ NOTIFICATIONS_COLLECTION,
4931
+ notificationId
4932
+ );
4933
+ await updateDoc13(notificationRef, {
4934
+ isRead: true,
4935
+ updatedAt: Timestamp14.now()
4936
+ });
4672
4937
  }
4673
4938
  /**
4674
- * Kreira admin token za grupaciju
4939
+ * Označava sve notifikacije korisnika kao pročitane
4675
4940
  */
4676
- async createAdminToken(groupId, creatorAdminId, data) {
4677
- return createAdminToken(
4941
+ async markAllAsRead(userId) {
4942
+ const notifications = await this.getUnreadNotifications(userId);
4943
+ const batch = writeBatch2(this.db);
4944
+ notifications.forEach((notification) => {
4945
+ const notificationRef = doc11(
4946
+ this.db,
4947
+ NOTIFICATIONS_COLLECTION,
4948
+ notification.id
4949
+ );
4950
+ batch.update(notificationRef, {
4951
+ isRead: true,
4952
+ updatedAt: Timestamp14.now()
4953
+ });
4954
+ });
4955
+ await batch.commit();
4956
+ }
4957
+ /**
4958
+ * Ažurira status notifikacije
4959
+ */
4960
+ async updateNotificationStatus(notificationId, status) {
4961
+ const notificationRef = doc11(
4678
4962
  this.db,
4679
- groupId,
4680
- creatorAdminId,
4681
- data
4963
+ NOTIFICATIONS_COLLECTION,
4964
+ notificationId
4682
4965
  );
4966
+ await updateDoc13(notificationRef, {
4967
+ status,
4968
+ updatedAt: Timestamp14.now()
4969
+ });
4683
4970
  }
4684
4971
  /**
4685
- * Verifikuje i koristi admin token
4972
+ * Briše notifikaciju
4686
4973
  */
4687
- async verifyAndUseAdminToken(groupId, token, userRef) {
4688
- return verifyAndUseAdminToken(
4974
+ async deleteNotification(notificationId) {
4975
+ const notificationRef = doc11(
4689
4976
  this.db,
4690
- groupId,
4691
- token,
4692
- userRef
4977
+ NOTIFICATIONS_COLLECTION,
4978
+ notificationId
4693
4979
  );
4980
+ await deleteDoc6(notificationRef);
4694
4981
  }
4695
4982
  /**
4696
- * Briše admin token
4983
+ * Dohvata notifikacije po tipu
4697
4984
  */
4698
- async deleteAdminToken(groupId, tokenId, adminId) {
4699
- return deleteAdminToken(
4700
- this.db,
4701
- groupId,
4702
- tokenId,
4703
- adminId
4985
+ async getNotificationsByType(userId, type) {
4986
+ const q = query9(
4987
+ collection10(this.db, NOTIFICATIONS_COLLECTION),
4988
+ where9("userId", "==", userId),
4989
+ where9("notificationType", "==", type),
4990
+ orderBy("notificationTime", "desc")
4704
4991
  );
4992
+ const querySnapshot = await getDocs9(q);
4993
+ return querySnapshot.docs.map((doc14) => ({
4994
+ id: doc14.id,
4995
+ ...doc14.data()
4996
+ }));
4705
4997
  }
4706
4998
  /**
4707
- * Dohvata aktivne admin tokene
4999
+ * Dohvata notifikacije za određeni termin
4708
5000
  */
4709
- async getActiveAdminTokens(groupId, adminId) {
4710
- return getActiveAdminTokens(this.db, groupId, adminId);
5001
+ async getAppointmentNotifications(appointmentId) {
5002
+ const q = query9(
5003
+ collection10(this.db, NOTIFICATIONS_COLLECTION),
5004
+ where9("appointmentId", "==", appointmentId),
5005
+ orderBy("notificationTime", "desc")
5006
+ );
5007
+ const querySnapshot = await getDocs9(q);
5008
+ return querySnapshot.docs.map((doc14) => ({
5009
+ id: doc14.id,
5010
+ ...doc14.data()
5011
+ }));
4711
5012
  }
4712
5013
  };
4713
5014
 
4714
5015
  // src/services/documentation-templates/documentation-template.service.ts
4715
5016
  import {
4716
- collection as collection10,
4717
- doc as doc11,
4718
- getDoc as getDoc14,
4719
- getDocs as getDocs9,
4720
- setDoc as setDoc12,
4721
- updateDoc as updateDoc13,
5017
+ collection as collection11,
5018
+ doc as doc12,
5019
+ getDoc as getDoc15,
5020
+ getDocs as getDocs10,
5021
+ setDoc as setDoc13,
5022
+ updateDoc as updateDoc14,
4722
5023
  deleteDoc as deleteDoc7,
4723
- query as query9,
4724
- where as where9,
5024
+ query as query10,
5025
+ where as where10,
4725
5026
  orderBy as orderBy2,
4726
5027
  limit,
4727
5028
  startAfter
@@ -4729,7 +5030,7 @@ import {
4729
5030
  var DocumentationTemplateService = class extends BaseService {
4730
5031
  constructor() {
4731
5032
  super(...arguments);
4732
- this.collectionRef = collection10(
5033
+ this.collectionRef = collection11(
4733
5034
  this.db,
4734
5035
  DOCUMENTATION_TEMPLATES_COLLECTION
4735
5036
  );
@@ -4760,8 +5061,8 @@ var DocumentationTemplateService = class extends BaseService {
4760
5061
  isActive: true,
4761
5062
  tags: validatedData.tags || []
4762
5063
  };
4763
- const docRef = doc11(this.collectionRef, templateId);
4764
- await setDoc12(docRef, template);
5064
+ const docRef = doc12(this.collectionRef, templateId);
5065
+ await setDoc13(docRef, template);
4765
5066
  return template;
4766
5067
  }
4767
5068
  /**
@@ -4770,8 +5071,8 @@ var DocumentationTemplateService = class extends BaseService {
4770
5071
  * @returns The template or null if not found
4771
5072
  */
4772
5073
  async getTemplateById(templateId) {
4773
- const docRef = doc11(this.collectionRef, templateId);
4774
- const docSnap = await getDoc14(docRef);
5074
+ const docRef = doc12(this.collectionRef, templateId);
5075
+ const docSnap = await getDoc15(docRef);
4775
5076
  if (!docSnap.exists()) {
4776
5077
  return null;
4777
5078
  }
@@ -4802,8 +5103,8 @@ var DocumentationTemplateService = class extends BaseService {
4802
5103
  updatedAt: Date.now(),
4803
5104
  version: template.version + 1
4804
5105
  };
4805
- const docRef = doc11(this.collectionRef, templateId);
4806
- await updateDoc13(docRef, updateData);
5106
+ const docRef = doc12(this.collectionRef, templateId);
5107
+ await updateDoc14(docRef, updateData);
4807
5108
  return {
4808
5109
  ...template,
4809
5110
  ...updateData
@@ -4814,7 +5115,7 @@ var DocumentationTemplateService = class extends BaseService {
4814
5115
  * @param templateId - ID of the template to delete
4815
5116
  */
4816
5117
  async deleteTemplate(templateId) {
4817
- const docRef = doc11(this.collectionRef, templateId);
5118
+ const docRef = doc12(this.collectionRef, templateId);
4818
5119
  await deleteDoc7(docRef);
4819
5120
  }
4820
5121
  /**
@@ -4824,21 +5125,21 @@ var DocumentationTemplateService = class extends BaseService {
4824
5125
  * @returns Array of templates and the last document for pagination
4825
5126
  */
4826
5127
  async getActiveTemplates(pageSize = 20, lastDoc) {
4827
- let q = query9(
5128
+ let q = query10(
4828
5129
  this.collectionRef,
4829
- where9("isActive", "==", true),
5130
+ where10("isActive", "==", true),
4830
5131
  orderBy2("updatedAt", "desc"),
4831
5132
  limit(pageSize)
4832
5133
  );
4833
5134
  if (lastDoc) {
4834
- q = query9(q, startAfter(lastDoc));
5135
+ q = query10(q, startAfter(lastDoc));
4835
5136
  }
4836
- const querySnapshot = await getDocs9(q);
5137
+ const querySnapshot = await getDocs10(q);
4837
5138
  const templates = [];
4838
5139
  let lastVisible = null;
4839
- querySnapshot.forEach((doc13) => {
4840
- templates.push(doc13.data());
4841
- lastVisible = doc13;
5140
+ querySnapshot.forEach((doc14) => {
5141
+ templates.push(doc14.data());
5142
+ lastVisible = doc14;
4842
5143
  });
4843
5144
  return {
4844
5145
  templates,
@@ -4853,22 +5154,22 @@ var DocumentationTemplateService = class extends BaseService {
4853
5154
  * @returns Array of templates and the last document for pagination
4854
5155
  */
4855
5156
  async getTemplatesByTags(tags, pageSize = 20, lastDoc) {
4856
- let q = query9(
5157
+ let q = query10(
4857
5158
  this.collectionRef,
4858
- where9("isActive", "==", true),
4859
- where9("tags", "array-contains-any", tags),
5159
+ where10("isActive", "==", true),
5160
+ where10("tags", "array-contains-any", tags),
4860
5161
  orderBy2("updatedAt", "desc"),
4861
5162
  limit(pageSize)
4862
5163
  );
4863
5164
  if (lastDoc) {
4864
- q = query9(q, startAfter(lastDoc));
5165
+ q = query10(q, startAfter(lastDoc));
4865
5166
  }
4866
- const querySnapshot = await getDocs9(q);
5167
+ const querySnapshot = await getDocs10(q);
4867
5168
  const templates = [];
4868
5169
  let lastVisible = null;
4869
- querySnapshot.forEach((doc13) => {
4870
- templates.push(doc13.data());
4871
- lastVisible = doc13;
5170
+ querySnapshot.forEach((doc14) => {
5171
+ templates.push(doc14.data());
5172
+ lastVisible = doc14;
4872
5173
  });
4873
5174
  return {
4874
5175
  templates,
@@ -4883,21 +5184,21 @@ var DocumentationTemplateService = class extends BaseService {
4883
5184
  * @returns Array of templates and the last document for pagination
4884
5185
  */
4885
5186
  async getTemplatesByCreator(userId, pageSize = 20, lastDoc) {
4886
- let q = query9(
5187
+ let q = query10(
4887
5188
  this.collectionRef,
4888
- where9("createdBy", "==", userId),
5189
+ where10("createdBy", "==", userId),
4889
5190
  orderBy2("updatedAt", "desc"),
4890
5191
  limit(pageSize)
4891
5192
  );
4892
5193
  if (lastDoc) {
4893
- q = query9(q, startAfter(lastDoc));
5194
+ q = query10(q, startAfter(lastDoc));
4894
5195
  }
4895
- const querySnapshot = await getDocs9(q);
5196
+ const querySnapshot = await getDocs10(q);
4896
5197
  const templates = [];
4897
5198
  let lastVisible = null;
4898
- querySnapshot.forEach((doc13) => {
4899
- templates.push(doc13.data());
4900
- lastVisible = doc13;
5199
+ querySnapshot.forEach((doc14) => {
5200
+ templates.push(doc14.data());
5201
+ lastVisible = doc14;
4901
5202
  });
4902
5203
  return {
4903
5204
  templates,
@@ -4908,14 +5209,14 @@ var DocumentationTemplateService = class extends BaseService {
4908
5209
 
4909
5210
  // src/services/documentation-templates/filled-document.service.ts
4910
5211
  import {
4911
- collection as collection11,
4912
- doc as doc12,
4913
- getDoc as getDoc15,
4914
- getDocs as getDocs10,
4915
- setDoc as setDoc13,
4916
- updateDoc as updateDoc14,
4917
- query as query10,
4918
- where as where10,
5212
+ collection as collection12,
5213
+ doc as doc13,
5214
+ getDoc as getDoc16,
5215
+ getDocs as getDocs11,
5216
+ setDoc as setDoc14,
5217
+ updateDoc as updateDoc15,
5218
+ query as query11,
5219
+ where as where11,
4919
5220
  orderBy as orderBy3,
4920
5221
  limit as limit2,
4921
5222
  startAfter as startAfter2
@@ -4923,7 +5224,7 @@ import {
4923
5224
  var FilledDocumentService = class extends BaseService {
4924
5225
  constructor(...args) {
4925
5226
  super(...args);
4926
- this.collectionRef = collection11(
5227
+ this.collectionRef = collection12(
4927
5228
  this.db,
4928
5229
  FILLED_DOCUMENTS_COLLECTION
4929
5230
  );
@@ -4956,8 +5257,8 @@ var FilledDocumentService = class extends BaseService {
4956
5257
  values: {},
4957
5258
  status: "draft" /* DRAFT */
4958
5259
  };
4959
- const docRef = doc12(this.collectionRef, documentId);
4960
- await setDoc13(docRef, filledDocument);
5260
+ const docRef = doc13(this.collectionRef, documentId);
5261
+ await setDoc14(docRef, filledDocument);
4961
5262
  return filledDocument;
4962
5263
  }
4963
5264
  /**
@@ -4966,8 +5267,8 @@ var FilledDocumentService = class extends BaseService {
4966
5267
  * @returns The filled document or null if not found
4967
5268
  */
4968
5269
  async getFilledDocumentById(documentId) {
4969
- const docRef = doc12(this.collectionRef, documentId);
4970
- const docSnap = await getDoc15(docRef);
5270
+ const docRef = doc13(this.collectionRef, documentId);
5271
+ const docSnap = await getDoc16(docRef);
4971
5272
  if (!docSnap.exists()) {
4972
5273
  return null;
4973
5274
  }
@@ -4995,8 +5296,8 @@ var FilledDocumentService = class extends BaseService {
4995
5296
  if (status) {
4996
5297
  updateData.status = status;
4997
5298
  }
4998
- const docRef = doc12(this.collectionRef, documentId);
4999
- await updateDoc14(docRef, updateData);
5299
+ const docRef = doc13(this.collectionRef, documentId);
5300
+ await updateDoc15(docRef, updateData);
5000
5301
  return {
5001
5302
  ...filledDocument,
5002
5303
  ...updateData
@@ -5010,21 +5311,21 @@ var FilledDocumentService = class extends BaseService {
5010
5311
  * @returns Array of filled documents and the last document for pagination
5011
5312
  */
5012
5313
  async getFilledDocumentsByPatient(patientId, pageSize = 20, lastDoc) {
5013
- let q = query10(
5314
+ let q = query11(
5014
5315
  this.collectionRef,
5015
- where10("patientId", "==", patientId),
5316
+ where11("patientId", "==", patientId),
5016
5317
  orderBy3("updatedAt", "desc"),
5017
5318
  limit2(pageSize)
5018
5319
  );
5019
5320
  if (lastDoc) {
5020
- q = query10(q, startAfter2(lastDoc));
5321
+ q = query11(q, startAfter2(lastDoc));
5021
5322
  }
5022
- const querySnapshot = await getDocs10(q);
5323
+ const querySnapshot = await getDocs11(q);
5023
5324
  const documents = [];
5024
5325
  let lastVisible = null;
5025
- querySnapshot.forEach((doc13) => {
5026
- documents.push(doc13.data());
5027
- lastVisible = doc13;
5326
+ querySnapshot.forEach((doc14) => {
5327
+ documents.push(doc14.data());
5328
+ lastVisible = doc14;
5028
5329
  });
5029
5330
  return {
5030
5331
  documents,
@@ -5039,21 +5340,21 @@ var FilledDocumentService = class extends BaseService {
5039
5340
  * @returns Array of filled documents and the last document for pagination
5040
5341
  */
5041
5342
  async getFilledDocumentsByPractitioner(practitionerId, pageSize = 20, lastDoc) {
5042
- let q = query10(
5343
+ let q = query11(
5043
5344
  this.collectionRef,
5044
- where10("practitionerId", "==", practitionerId),
5345
+ where11("practitionerId", "==", practitionerId),
5045
5346
  orderBy3("updatedAt", "desc"),
5046
5347
  limit2(pageSize)
5047
5348
  );
5048
5349
  if (lastDoc) {
5049
- q = query10(q, startAfter2(lastDoc));
5350
+ q = query11(q, startAfter2(lastDoc));
5050
5351
  }
5051
- const querySnapshot = await getDocs10(q);
5352
+ const querySnapshot = await getDocs11(q);
5052
5353
  const documents = [];
5053
5354
  let lastVisible = null;
5054
- querySnapshot.forEach((doc13) => {
5055
- documents.push(doc13.data());
5056
- lastVisible = doc13;
5355
+ querySnapshot.forEach((doc14) => {
5356
+ documents.push(doc14.data());
5357
+ lastVisible = doc14;
5057
5358
  });
5058
5359
  return {
5059
5360
  documents,
@@ -5068,21 +5369,21 @@ var FilledDocumentService = class extends BaseService {
5068
5369
  * @returns Array of filled documents and the last document for pagination
5069
5370
  */
5070
5371
  async getFilledDocumentsByClinic(clinicId, pageSize = 20, lastDoc) {
5071
- let q = query10(
5372
+ let q = query11(
5072
5373
  this.collectionRef,
5073
- where10("clinicId", "==", clinicId),
5374
+ where11("clinicId", "==", clinicId),
5074
5375
  orderBy3("updatedAt", "desc"),
5075
5376
  limit2(pageSize)
5076
5377
  );
5077
5378
  if (lastDoc) {
5078
- q = query10(q, startAfter2(lastDoc));
5379
+ q = query11(q, startAfter2(lastDoc));
5079
5380
  }
5080
- const querySnapshot = await getDocs10(q);
5381
+ const querySnapshot = await getDocs11(q);
5081
5382
  const documents = [];
5082
5383
  let lastVisible = null;
5083
- querySnapshot.forEach((doc13) => {
5084
- documents.push(doc13.data());
5085
- lastVisible = doc13;
5384
+ querySnapshot.forEach((doc14) => {
5385
+ documents.push(doc14.data());
5386
+ lastVisible = doc14;
5086
5387
  });
5087
5388
  return {
5088
5389
  documents,
@@ -5097,21 +5398,21 @@ var FilledDocumentService = class extends BaseService {
5097
5398
  * @returns Array of filled documents and the last document for pagination
5098
5399
  */
5099
5400
  async getFilledDocumentsByTemplate(templateId, pageSize = 20, lastDoc) {
5100
- let q = query10(
5401
+ let q = query11(
5101
5402
  this.collectionRef,
5102
- where10("templateId", "==", templateId),
5403
+ where11("templateId", "==", templateId),
5103
5404
  orderBy3("updatedAt", "desc"),
5104
5405
  limit2(pageSize)
5105
5406
  );
5106
5407
  if (lastDoc) {
5107
- q = query10(q, startAfter2(lastDoc));
5408
+ q = query11(q, startAfter2(lastDoc));
5108
5409
  }
5109
- const querySnapshot = await getDocs10(q);
5410
+ const querySnapshot = await getDocs11(q);
5110
5411
  const documents = [];
5111
5412
  let lastVisible = null;
5112
- querySnapshot.forEach((doc13) => {
5113
- documents.push(doc13.data());
5114
- lastVisible = doc13;
5413
+ querySnapshot.forEach((doc14) => {
5414
+ documents.push(doc14.data());
5415
+ lastVisible = doc14;
5115
5416
  });
5116
5417
  return {
5117
5418
  documents,
@@ -5126,21 +5427,21 @@ var FilledDocumentService = class extends BaseService {
5126
5427
  * @returns Array of filled documents and the last document for pagination
5127
5428
  */
5128
5429
  async getFilledDocumentsByStatus(status, pageSize = 20, lastDoc) {
5129
- let q = query10(
5430
+ let q = query11(
5130
5431
  this.collectionRef,
5131
- where10("status", "==", status),
5432
+ where11("status", "==", status),
5132
5433
  orderBy3("updatedAt", "desc"),
5133
5434
  limit2(pageSize)
5134
5435
  );
5135
5436
  if (lastDoc) {
5136
- q = query10(q, startAfter2(lastDoc));
5437
+ q = query11(q, startAfter2(lastDoc));
5137
5438
  }
5138
- const querySnapshot = await getDocs10(q);
5439
+ const querySnapshot = await getDocs11(q);
5139
5440
  const documents = [];
5140
5441
  let lastVisible = null;
5141
- querySnapshot.forEach((doc13) => {
5142
- documents.push(doc13.data());
5143
- lastVisible = doc13;
5442
+ querySnapshot.forEach((doc14) => {
5443
+ documents.push(doc14.data());
5444
+ lastVisible = doc14;
5144
5445
  });
5145
5446
  return {
5146
5447
  documents,
@@ -5265,8 +5566,11 @@ export {
5265
5566
  blockingConditionSchema,
5266
5567
  clinicAdminOptionsSchema,
5267
5568
  clinicAdminSchema,
5569
+ clinicAdminSignupSchema,
5570
+ clinicBranchSetupSchema,
5268
5571
  clinicContactInfoSchema,
5269
5572
  clinicGroupSchema,
5573
+ clinicGroupSetupSchema,
5270
5574
  clinicInfoSchema,
5271
5575
  clinicLocationSchema,
5272
5576
  clinicReviewSchema,
@@ -5321,6 +5625,9 @@ export {
5321
5625
  timestampSchema,
5322
5626
  updateAllergySchema,
5323
5627
  updateBlockingConditionSchema,
5628
+ updateClinicAdminSchema,
5629
+ updateClinicGroupSchema,
5630
+ updateClinicSchema,
5324
5631
  updateContraindicationSchema,
5325
5632
  updateDocumentTemplateSchema,
5326
5633
  updateMedicationSchema,