@blackcode_sa/metaestetics-api 1.4.8 → 1.4.9

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.
@@ -12,6 +12,7 @@ import {
12
12
  Firestore,
13
13
  serverTimestamp,
14
14
  } from "firebase/firestore";
15
+ import { getStorage, ref, uploadBytes, getDownloadURL } from "firebase/storage";
15
16
  import {
16
17
  ClinicGroup,
17
18
  CreateClinicGroupData,
@@ -19,6 +20,7 @@ import {
19
20
  AdminToken,
20
21
  AdminTokenStatus,
21
22
  CreateAdminTokenData,
23
+ SubscriptionModel,
22
24
  } from "../../../types/clinic";
23
25
  import { geohashForLocation } from "geofire-common";
24
26
  import {
@@ -26,6 +28,8 @@ import {
26
28
  createClinicGroupSchema,
27
29
  } from "../../../validations/clinic.schema";
28
30
  import { z } from "zod";
31
+ import { uploadPhoto } from "./photos.utils";
32
+ import { FirebaseApp } from "firebase/app";
29
33
 
30
34
  /**
31
35
  * Generates a unique ID for documents
@@ -50,6 +54,7 @@ function generateId(): string {
50
54
  * @param ownerId - ID of the owner
51
55
  * @param isDefault - Whether this is a default group
52
56
  * @param clinicAdminService - Service for clinic admin operations
57
+ * @param app - Firebase app instance
53
58
  * @returns The created clinic group
54
59
  */
55
60
  export async function createClinicGroup(
@@ -57,7 +62,8 @@ export async function createClinicGroup(
57
62
  data: CreateClinicGroupData,
58
63
  ownerId: string,
59
64
  isDefault: boolean = false,
60
- clinicAdminService: any
65
+ clinicAdminService: any,
66
+ app: FirebaseApp
61
67
  ): Promise<ClinicGroup> {
62
68
  console.log("[CLINIC_GROUP] Starting clinic group creation", {
63
69
  ownerId,
@@ -122,22 +128,43 @@ export async function createClinicGroup(
122
128
  const now = Timestamp.now();
123
129
  console.log("[CLINIC_GROUP] Preparing clinic group data object");
124
130
 
131
+ // Generate a unique ID for the clinic group
132
+ const groupId = doc(collection(db, CLINIC_GROUPS_COLLECTION)).id;
133
+
125
134
  // Log the logo value to debug null vs undefined issue
126
135
  console.log("[CLINIC_GROUP] Logo value:", {
127
136
  logoValue: validatedData.logo,
128
137
  logoType: validatedData.logo === null ? "null" : typeof validatedData.logo,
129
138
  });
130
139
 
140
+ // Handle logo upload if provided
141
+ let logoUrl = await uploadPhoto(
142
+ validatedData.logo || null,
143
+ "clinic-groups",
144
+ groupId,
145
+ "logo",
146
+ app
147
+ );
148
+ console.log("[CLINIC_GROUP] Logo processed", { logoUrl });
149
+
131
150
  const groupData: ClinicGroup = {
132
151
  ...validatedData,
133
- id: doc(collection(db, CLINIC_GROUPS_COLLECTION)).id,
152
+ id: groupId,
153
+ name: validatedData.name,
154
+ logo: logoUrl, // Use the uploaded logo URL or the original value
134
155
  description: isDefault ? undefined : validatedData.description || undefined,
135
156
  hqLocation: {
136
- ...validatedData.hqLocation,
157
+ address: validatedData.hqLocation.address || "",
158
+ city: validatedData.hqLocation.city || "",
159
+ country: validatedData.hqLocation.country || "",
160
+ postalCode: validatedData.hqLocation.postalCode || "",
161
+ latitude: validatedData.hqLocation.latitude || 0,
162
+ longitude: validatedData.hqLocation.longitude || 0,
137
163
  geohash: validatedData.hqLocation.geohash || undefined,
138
164
  },
139
165
  contactInfo: {
140
- ...validatedData.contactInfo,
166
+ email: validatedData.contactInfo.email || "",
167
+ phoneNumber: validatedData.contactInfo.phoneNumber || "",
141
168
  alternativePhoneNumber: isDefault
142
169
  ? undefined
143
170
  : validatedData.contactInfo.alternativePhoneNumber || undefined,
@@ -145,6 +172,15 @@ export async function createClinicGroup(
145
172
  ? undefined
146
173
  : validatedData.contactInfo.website || undefined,
147
174
  },
175
+ contactPerson: {
176
+ firstName: validatedData.contactPerson?.firstName || "",
177
+ lastName: validatedData.contactPerson?.lastName || "",
178
+ email: validatedData.contactPerson?.email || "",
179
+ title: validatedData.contactPerson?.title || null,
180
+ phoneNumber: validatedData.contactPerson?.phoneNumber || null,
181
+ },
182
+ subscriptionModel:
183
+ validatedData.subscriptionModel || SubscriptionModel.NO_SUBSCRIPTION,
148
184
  clinics: [],
149
185
  clinicsInfo: [],
150
186
  admins: [ownerId],
@@ -266,29 +302,64 @@ export async function getAllActiveGroups(
266
302
  * @param db - Firestore database instance
267
303
  * @param groupId - ID of the clinic group
268
304
  * @param data - Data to update
305
+ * @param app - Firebase app instance
269
306
  * @returns The updated clinic group
270
307
  */
271
308
  export async function updateClinicGroup(
272
309
  db: Firestore,
273
310
  groupId: string,
274
- data: Partial<ClinicGroup>
311
+ data: Partial<ClinicGroup>,
312
+ app: FirebaseApp
275
313
  ): Promise<ClinicGroup> {
314
+ console.log("[CLINIC_GROUP] Updating clinic group", { groupId });
315
+
276
316
  const group = await getClinicGroup(db, groupId);
277
317
  if (!group) {
318
+ console.error("[CLINIC_GROUP] Clinic group not found", { groupId });
278
319
  throw new Error("Clinic group not found");
279
320
  }
280
321
 
281
- // Ažuriramo podatke
282
- const updatedData = {
283
- ...data,
322
+ // Process logo if it's a data URL
323
+ let updatedData = { ...data };
324
+
325
+ if (
326
+ data.logo &&
327
+ typeof data.logo === "string" &&
328
+ data.logo.startsWith("data:")
329
+ ) {
330
+ console.log("[CLINIC_GROUP] Processing logo for update");
331
+ try {
332
+ const logoUrl = await uploadPhoto(
333
+ data.logo,
334
+ "clinic-groups",
335
+ groupId,
336
+ "logo",
337
+ app
338
+ );
339
+ console.log("[CLINIC_GROUP] Logo processed for update", { logoUrl });
340
+
341
+ // Replace the data URL with the uploaded URL
342
+ updatedData.logo = logoUrl;
343
+ } catch (error) {
344
+ console.error("[CLINIC_GROUP] Error processing logo for update:", error);
345
+ // Continue with update even if logo upload fails
346
+ }
347
+ }
348
+
349
+ // Add timestamp
350
+ updatedData = {
351
+ ...updatedData,
284
352
  updatedAt: Timestamp.now(),
285
353
  };
286
354
 
355
+ console.log("[CLINIC_GROUP] Updating clinic group in Firestore");
287
356
  await updateDoc(doc(db, CLINIC_GROUPS_COLLECTION, groupId), updatedData);
357
+ console.log("[CLINIC_GROUP] Clinic group updated successfully");
288
358
 
289
- // Vraćamo ažurirane podatke
359
+ // Return updated data
290
360
  const updatedGroup = await getClinicGroup(db, groupId);
291
361
  if (!updatedGroup) {
362
+ console.error("[CLINIC_GROUP] Failed to retrieve updated clinic group");
292
363
  throw new Error("Failed to retrieve updated clinic group");
293
364
  }
294
365
 
@@ -299,25 +370,46 @@ export async function updateClinicGroup(
299
370
  * Adds an admin to a clinic group
300
371
  * @param db - Firestore database instance
301
372
  * @param groupId - ID of the clinic group
302
- * @param adminId - ID of the admin to add
373
+ * @param adminId - ID of the admin to add (this is the admin document ID, not the user UID)
374
+ * @param app - Firebase app instance
303
375
  */
304
376
  export async function addAdminToGroup(
305
377
  db: Firestore,
306
378
  groupId: string,
307
- adminId: string
379
+ adminId: string,
380
+ app: FirebaseApp
308
381
  ): Promise<void> {
309
- const group = await getClinicGroup(db, groupId);
310
- if (!group) {
311
- throw new Error("Clinic group not found");
312
- }
382
+ console.log("[CLINIC_GROUP] Adding admin to group", { groupId, adminId });
313
383
 
314
- if (group.admins.includes(adminId)) {
315
- return; // Admin is already in the group
316
- }
384
+ try {
385
+ const group = await getClinicGroup(db, groupId);
386
+ if (!group) {
387
+ console.error("[CLINIC_GROUP] Clinic group not found", { groupId });
388
+ throw new Error("Clinic group not found");
389
+ }
317
390
 
318
- await updateClinicGroup(db, groupId, {
319
- admins: [...group.admins, adminId],
320
- });
391
+ if (group.admins.includes(adminId)) {
392
+ console.log("[CLINIC_GROUP] Admin is already in the group", {
393
+ adminId,
394
+ groupId,
395
+ });
396
+ return; // Admin is already in the group
397
+ }
398
+
399
+ console.log("[CLINIC_GROUP] Updating group with new admin");
400
+ await updateClinicGroup(
401
+ db,
402
+ groupId,
403
+ {
404
+ admins: [...group.admins, adminId],
405
+ },
406
+ app
407
+ );
408
+ console.log("[CLINIC_GROUP] Admin added to group successfully");
409
+ } catch (error) {
410
+ console.error("[CLINIC_GROUP] Error adding admin to group:", error);
411
+ throw error;
412
+ }
321
413
  }
322
414
 
323
415
  /**
@@ -325,11 +417,13 @@ export async function addAdminToGroup(
325
417
  * @param db - Firestore database instance
326
418
  * @param groupId - ID of the clinic group
327
419
  * @param adminId - ID of the admin to remove
420
+ * @param app - Firebase app instance
328
421
  */
329
422
  export async function removeAdminFromGroup(
330
423
  db: Firestore,
331
424
  groupId: string,
332
- adminId: string
425
+ adminId: string,
426
+ app: FirebaseApp
333
427
  ): Promise<void> {
334
428
  const group = await getClinicGroup(db, groupId);
335
429
  if (!group) {
@@ -344,29 +438,40 @@ export async function removeAdminFromGroup(
344
438
  return; // Admin is not in the group
345
439
  }
346
440
 
347
- await updateClinicGroup(db, groupId, {
348
- admins: group.admins.filter((id) => id !== adminId),
349
- });
441
+ await updateClinicGroup(
442
+ db,
443
+ groupId,
444
+ {
445
+ admins: group.admins.filter((id) => id !== adminId),
446
+ },
447
+ app
448
+ );
350
449
  }
351
450
 
352
451
  /**
353
452
  * Deactivates a clinic group
354
453
  * @param db - Firestore database instance
355
454
  * @param groupId - ID of the clinic group
455
+ * @param app - Firebase app instance
356
456
  */
357
457
  export async function deactivateClinicGroup(
358
458
  db: Firestore,
359
- groupId: string
459
+ groupId: string,
460
+ app: FirebaseApp
360
461
  ): Promise<void> {
361
462
  const group = await getClinicGroup(db, groupId);
362
463
  if (!group) {
363
464
  throw new Error("Clinic group not found");
364
465
  }
365
466
 
366
- await updateDoc(doc(db, CLINIC_GROUPS_COLLECTION, groupId), {
367
- isActive: false,
368
- updatedAt: Timestamp.now(),
369
- });
467
+ await updateClinicGroup(
468
+ db,
469
+ groupId,
470
+ {
471
+ isActive: false,
472
+ },
473
+ app
474
+ );
370
475
  }
371
476
 
372
477
  /**
@@ -374,6 +479,7 @@ export async function deactivateClinicGroup(
374
479
  * @param db - Firestore database instance
375
480
  * @param groupId - ID of the clinic group
376
481
  * @param creatorAdminId - ID of the admin creating the token
482
+ * @param app - Firebase app instance
377
483
  * @param data - Token data
378
484
  * @returns The created admin token
379
485
  */
@@ -381,6 +487,7 @@ export async function createAdminToken(
381
487
  db: Firestore,
382
488
  groupId: string,
383
489
  creatorAdminId: string,
490
+ app: FirebaseApp,
384
491
  data?: CreateAdminTokenData
385
492
  ): Promise<AdminToken> {
386
493
  const group = await getClinicGroup(db, groupId);
@@ -409,9 +516,14 @@ export async function createAdminToken(
409
516
  };
410
517
 
411
518
  // Dodajemo token u grupu
412
- await updateClinicGroup(db, groupId, {
413
- adminTokens: [...group.adminTokens, token],
414
- });
519
+ await updateClinicGroup(
520
+ db,
521
+ groupId,
522
+ {
523
+ adminTokens: [...group.adminTokens, token],
524
+ },
525
+ app
526
+ );
415
527
 
416
528
  return token;
417
529
  }
@@ -422,13 +534,15 @@ export async function createAdminToken(
422
534
  * @param groupId - ID of the clinic group
423
535
  * @param token - Token to verify
424
536
  * @param userRef - User reference
537
+ * @param app - Firebase app instance
425
538
  * @returns Whether the token was successfully used
426
539
  */
427
540
  export async function verifyAndUseAdminToken(
428
541
  db: Firestore,
429
542
  groupId: string,
430
543
  token: string,
431
- userRef: string
544
+ userRef: string,
545
+ app: FirebaseApp
432
546
  ): Promise<boolean> {
433
547
  const group = await getClinicGroup(db, groupId);
434
548
  if (!group) {
@@ -451,9 +565,14 @@ export async function verifyAndUseAdminToken(
451
565
  t.id === adminToken.id ? { ...t, status: AdminTokenStatus.EXPIRED } : t
452
566
  );
453
567
 
454
- await updateClinicGroup(db, groupId, {
455
- adminTokens: updatedTokens,
456
- });
568
+ await updateClinicGroup(
569
+ db,
570
+ groupId,
571
+ {
572
+ adminTokens: updatedTokens,
573
+ },
574
+ app
575
+ );
457
576
 
458
577
  throw new Error("Admin token has expired");
459
578
  }
@@ -469,9 +588,14 @@ export async function verifyAndUseAdminToken(
469
588
  : t
470
589
  );
471
590
 
472
- await updateClinicGroup(db, groupId, {
473
- adminTokens: updatedTokens,
474
- });
591
+ await updateClinicGroup(
592
+ db,
593
+ groupId,
594
+ {
595
+ adminTokens: updatedTokens,
596
+ },
597
+ app
598
+ );
475
599
 
476
600
  return true;
477
601
  }
@@ -482,12 +606,14 @@ export async function verifyAndUseAdminToken(
482
606
  * @param groupId - ID of the clinic group
483
607
  * @param tokenId - ID of the token to delete
484
608
  * @param adminId - ID of the admin making the deletion
609
+ * @param app - Firebase app instance
485
610
  */
486
611
  export async function deleteAdminToken(
487
612
  db: Firestore,
488
613
  groupId: string,
489
614
  tokenId: string,
490
- adminId: string
615
+ adminId: string,
616
+ app: FirebaseApp
491
617
  ): Promise<void> {
492
618
  const group = await getClinicGroup(db, groupId);
493
619
  if (!group) {
@@ -502,9 +628,14 @@ export async function deleteAdminToken(
502
628
  // Uklanjamo token
503
629
  const updatedTokens = group.adminTokens.filter((t) => t.id !== tokenId);
504
630
 
505
- await updateClinicGroup(db, groupId, {
506
- adminTokens: updatedTokens,
507
- });
631
+ await updateClinicGroup(
632
+ db,
633
+ groupId,
634
+ {
635
+ adminTokens: updatedTokens,
636
+ },
637
+ app
638
+ );
508
639
  }
509
640
 
510
641
  /**
@@ -512,12 +643,14 @@ export async function deleteAdminToken(
512
643
  * @param db - Firestore database instance
513
644
  * @param groupId - ID of the clinic group
514
645
  * @param adminId - ID of the admin requesting the tokens
646
+ * @param app - Firebase app instance (not used but included for consistency)
515
647
  * @returns Array of active admin tokens
516
648
  */
517
649
  export async function getActiveAdminTokens(
518
650
  db: Firestore,
519
651
  groupId: string,
520
- adminId: string
652
+ adminId: string,
653
+ app: FirebaseApp
521
654
  ): Promise<AdminToken[]> {
522
655
  const group = await getClinicGroup(db, groupId);
523
656
  if (!group) {