@blackcode_sa/metaestetics-api 1.5.2 → 1.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist/backoffice/index.d.mts +1306 -63
  2. package/dist/backoffice/index.d.ts +1306 -63
  3. package/dist/backoffice/index.js +35 -26
  4. package/dist/backoffice/index.mjs +35 -26
  5. package/dist/index.d.mts +30 -16
  6. package/dist/index.d.ts +30 -16
  7. package/dist/index.js +81 -1
  8. package/dist/index.mjs +81 -1
  9. package/package.json +1 -1
  10. package/src/backoffice/services/brand.service.ts +2 -4
  11. package/src/backoffice/services/category.service.ts +2 -7
  12. package/src/backoffice/services/product.service.ts +5 -7
  13. package/src/backoffice/services/requirement.service.ts +6 -7
  14. package/src/backoffice/services/subcategory.service.ts +11 -8
  15. package/src/backoffice/services/technology.service.ts +6 -11
  16. package/src/backoffice/types/brand.types.ts +5 -0
  17. package/src/backoffice/types/category.types.ts +5 -0
  18. package/src/backoffice/types/documentation-templates.types.ts +4 -0
  19. package/src/backoffice/types/product.types.ts +5 -0
  20. package/src/backoffice/types/requirement.types.ts +5 -0
  21. package/src/backoffice/types/subcategory.types.ts +5 -0
  22. package/src/backoffice/types/technology.types.ts +10 -0
  23. package/src/backoffice/validations/schemas.ts +2 -0
  24. package/src/errors/auth.errors.ts +7 -0
  25. package/src/services/auth.service.ts +94 -0
  26. package/src/services/documentation-templates/documentation-template.service.ts +4 -1
  27. package/src/services/procedure/procedure.service.ts +238 -0
  28. package/src/types/documentation-templates/index.ts +5 -0
  29. package/src/types/index.ts +3 -3
  30. package/src/types/procedure/index.ts +104 -0
  31. package/src/validations/procedure.schema.ts +58 -0
  32. package/src/validations/schemas.ts +9 -3
package/dist/index.mjs CHANGED
@@ -288,8 +288,11 @@ var passwordSchema = z2.string().min(8, "Password must be at least 8 characters"
288
288
  var userRoleSchema = z2.nativeEnum(UserRole);
289
289
  var userRolesSchema = z2.array(userRoleSchema).min(1, "User must have at least one role").max(3, "User cannot have more than 3 roles");
290
290
  var timestampSchema = z2.custom((data) => {
291
+ if (data && typeof data === "object" && "isEqual" in data) {
292
+ return true;
293
+ }
291
294
  return data && typeof data === "object" && "toDate" in data && "seconds" in data && "nanoseconds" in data;
292
- }, "Must be a Timestamp object");
295
+ }, "Must be a Timestamp object or serverTimestamp");
293
296
  var clinicAdminOptionsSchema = z2.object({
294
297
  isGroupOwner: z2.boolean(),
295
298
  groupToken: z2.string().optional(),
@@ -451,6 +454,12 @@ var AUTH_ERRORS = {
451
454
  "AUTH/INVALID_CREDENTIAL",
452
455
  401
453
456
  ),
457
+ // Resource not found
458
+ NOT_FOUND: new AuthError(
459
+ "The requested resource was not found",
460
+ "AUTH/NOT_FOUND",
461
+ 404
462
+ ),
454
463
  // Detailed password validation errors
455
464
  PASSWORD_LENGTH_ERROR: new AuthError(
456
465
  "Password must be at least 8 characters long",
@@ -5797,6 +5806,77 @@ var AuthService = class extends BaseService {
5797
5806
  );
5798
5807
  return this.userService.getOrCreateUser(firebaseUser);
5799
5808
  }
5809
+ /**
5810
+ * Prijavljuje korisnika sa email-om i lozinkom samo za clinic_admin role
5811
+ * @param email - Email korisnika
5812
+ * @param password - Lozinka korisnika
5813
+ * @returns Objekat koji sadrži korisnika, admin profil i grupu klinika
5814
+ * @throws {AUTH_ERRORS.INVALID_ROLE} Ako korisnik nema clinic_admin rolu
5815
+ * @throws {AUTH_ERRORS.NOT_FOUND} Ako admin profil nije pronađen
5816
+ */
5817
+ async signInClinicAdmin(email, password) {
5818
+ var _a;
5819
+ try {
5820
+ const clinicAdminService = new ClinicAdminService(
5821
+ this.db,
5822
+ this.auth,
5823
+ this.app
5824
+ );
5825
+ const clinicGroupService = new ClinicGroupService(
5826
+ this.db,
5827
+ this.auth,
5828
+ this.app,
5829
+ clinicAdminService
5830
+ );
5831
+ const clinicService = new ClinicService(
5832
+ this.db,
5833
+ this.auth,
5834
+ this.app,
5835
+ clinicGroupService,
5836
+ clinicAdminService
5837
+ );
5838
+ clinicAdminService.setServices(clinicGroupService, clinicService);
5839
+ const { user: firebaseUser } = await signInWithEmailAndPassword(
5840
+ this.auth,
5841
+ email,
5842
+ password
5843
+ );
5844
+ const user = await this.userService.getOrCreateUser(firebaseUser);
5845
+ if (!((_a = user.roles) == null ? void 0 : _a.includes("clinic_admin" /* CLINIC_ADMIN */))) {
5846
+ console.error("[AUTH] User is not a clinic admin:", user.uid);
5847
+ throw AUTH_ERRORS.INVALID_ROLE;
5848
+ }
5849
+ if (!user.adminProfile) {
5850
+ console.error("[AUTH] User has no admin profile:", user.uid);
5851
+ throw AUTH_ERRORS.NOT_FOUND;
5852
+ }
5853
+ const adminProfile = await clinicAdminService.getClinicAdmin(
5854
+ user.adminProfile
5855
+ );
5856
+ if (!adminProfile) {
5857
+ console.error("[AUTH] Admin profile not found:", user.adminProfile);
5858
+ throw AUTH_ERRORS.NOT_FOUND;
5859
+ }
5860
+ const clinicGroup = await clinicGroupService.getClinicGroup(
5861
+ adminProfile.clinicGroupId
5862
+ );
5863
+ if (!clinicGroup) {
5864
+ console.error(
5865
+ "[AUTH] Clinic group not found:",
5866
+ adminProfile.clinicGroupId
5867
+ );
5868
+ throw AUTH_ERRORS.NOT_FOUND;
5869
+ }
5870
+ return {
5871
+ user,
5872
+ clinicAdmin: adminProfile,
5873
+ clinicGroup
5874
+ };
5875
+ } catch (error) {
5876
+ console.error("[AUTH] Error in signInClinicAdmin:", error);
5877
+ throw error;
5878
+ }
5879
+ }
5800
5880
  /**
5801
5881
  * Prijavljuje korisnika sa Facebook-om
5802
5882
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@blackcode_sa/metaestetics-api",
3
3
  "private": false,
4
- "version": "1.5.2",
4
+ "version": "1.5.4",
5
5
  "description": "Firebase authentication service with anonymous upgrade support",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.mjs",
@@ -8,14 +8,12 @@ import {
8
8
  updateDoc,
9
9
  where,
10
10
  } from "firebase/firestore";
11
- import { Brand } from "../types/brand.types";
11
+ import { Brand, BRANDS_COLLECTION } from "../types/brand.types";
12
12
  import { BaseService } from "../../services/base.service";
13
13
 
14
- const COLLECTION = "backoffice_brands";
15
-
16
14
  export class BrandService extends BaseService {
17
15
  private get brandsRef() {
18
- return collection(this.db, COLLECTION);
16
+ return collection(this.db, BRANDS_COLLECTION);
19
17
  }
20
18
 
21
19
  async create(brand: Omit<Brand, "id" | "createdAt" | "updatedAt">) {
@@ -8,15 +8,10 @@ import {
8
8
  updateDoc,
9
9
  where,
10
10
  } from "firebase/firestore";
11
- import { Category } from "../types/category.types";
11
+ import { Category, CATEGORIES_COLLECTION } from "../types/category.types";
12
12
  import { BaseService } from "../../services/base.service";
13
13
  import { ProcedureFamily } from "../types/static/procedure-family.types";
14
14
 
15
- /**
16
- * Kolekcija u Firestore bazi gde se čuvaju kategorije
17
- */
18
- const COLLECTION = "backoffice_categories";
19
-
20
15
  /**
21
16
  * Servis za upravljanje kategorijama procedura.
22
17
  * Kategorije su prvi nivo organizacije nakon procedure family (aesthetics/surgery).
@@ -35,7 +30,7 @@ export class CategoryService extends BaseService {
35
30
  * Referenca na Firestore kolekciju kategorija
36
31
  */
37
32
  private get categoriesRef() {
38
- return collection(this.db, COLLECTION);
33
+ return collection(this.db, CATEGORIES_COLLECTION);
39
34
  }
40
35
 
41
36
  /**
@@ -9,14 +9,12 @@ import {
9
9
  updateDoc,
10
10
  where,
11
11
  } from "firebase/firestore";
12
- import { Product } from "../types/product.types";
12
+ import { Product, PRODUCTS_COLLECTION } from "../types/product.types";
13
13
  import { BaseService } from "../../services/base.service";
14
-
15
- const CATEGORIES_COLLECTION = "backoffice_categories";
16
- const SUBCATEGORIES_COLLECTION = "subcategories";
17
- const TECHNOLOGIES_COLLECTION = "technologies";
18
- const PRODUCTS_COLLECTION = "products";
19
- const BRANDS_COLLECTION = "backoffice_brands";
14
+ import { CATEGORIES_COLLECTION } from "../types/category.types";
15
+ import { BRANDS_COLLECTION } from "../types/brand.types";
16
+ import { SUBCATEGORIES_COLLECTION } from "../types/subcategory.types";
17
+ import { TECHNOLOGIES_COLLECTION } from "../types/technology.types";
20
18
 
21
19
  export class ProductService extends BaseService {
22
20
  private getProductsRefByTechnology(
@@ -8,14 +8,13 @@ import {
8
8
  updateDoc,
9
9
  where,
10
10
  } from "firebase/firestore";
11
- import { Requirement, RequirementType } from "../types/requirement.types";
11
+ import {
12
+ Requirement,
13
+ RequirementType,
14
+ REQUIREMENTS_COLLECTION,
15
+ } from "../types/requirement.types";
12
16
  import { BaseService } from "../../services/base.service";
13
17
 
14
- /**
15
- * Kolekcija u Firestore bazi gde se čuvaju globalni zahtevi
16
- */
17
- const COLLECTION = "backoffice_requirements";
18
-
19
18
  /**
20
19
  * Servis za upravljanje globalnim zahtevima.
21
20
  * Zahtevi se mogu kreirati globalno i zatim povezati sa različitim tehnologijama.
@@ -42,7 +41,7 @@ export class RequirementService extends BaseService {
42
41
  * Referenca na Firestore kolekciju zahteva
43
42
  */
44
43
  private get requirementsRef() {
45
- return collection(this.db, COLLECTION);
44
+ return collection(this.db, REQUIREMENTS_COLLECTION);
46
45
  }
47
46
 
48
47
  /**
@@ -8,14 +8,12 @@ import {
8
8
  updateDoc,
9
9
  where,
10
10
  } from "firebase/firestore";
11
- import { Subcategory } from "../types/subcategory.types";
11
+ import {
12
+ Subcategory,
13
+ SUBCATEGORIES_COLLECTION,
14
+ } from "../types/subcategory.types";
12
15
  import { BaseService } from "../../services/base.service";
13
-
14
- /**
15
- * Kolekcije u Firestore bazi
16
- */
17
- const COLLECTION = "backoffice_categories";
18
- const SUB_COLLECTION = "subcategories";
16
+ import { CATEGORIES_COLLECTION } from "../types/category.types";
19
17
 
20
18
  /**
21
19
  * Servis za upravljanje podkategorijama procedura.
@@ -36,7 +34,12 @@ export class SubcategoryService extends BaseService {
36
34
  * @param categoryId - ID roditeljske kategorije
37
35
  */
38
36
  private getSubcategoriesRef(categoryId: string) {
39
- return collection(this.db, COLLECTION, categoryId, SUB_COLLECTION);
37
+ return collection(
38
+ this.db,
39
+ CATEGORIES_COLLECTION,
40
+ categoryId,
41
+ SUBCATEGORIES_COLLECTION
42
+ );
40
43
  }
41
44
 
42
45
  /**
@@ -11,7 +11,7 @@ import {
11
11
  arrayRemove,
12
12
  Firestore,
13
13
  } from "firebase/firestore";
14
- import { Technology } from "../types/technology.types";
14
+ import { Technology, TECHNOLOGIES_COLLECTION } from "../types/technology.types";
15
15
  import { Requirement, RequirementType } from "../types/requirement.types";
16
16
  import { BlockingCondition } from "../types/static/blocking-condition.types";
17
17
  import { Contraindication } from "../types/static/contraindication.types";
@@ -22,13 +22,8 @@ import {
22
22
  CertificationRequirement,
23
23
  } from "../types/static/certification.types";
24
24
  import { BaseService } from "../../services/base.service";
25
-
26
- /**
27
- * Kolekcije u Firestore bazi
28
- */
29
- const COLLECTION = "backoffice_categories";
30
- const SUB_COLLECTION_SUBCATEGORIES = "subcategories";
31
- const SUB_COLLECTION_TECHNOLOGIES = "technologies";
25
+ import { SUBCATEGORIES_COLLECTION } from "../types/subcategory.types";
26
+ import { CATEGORIES_COLLECTION } from "../types/category.types";
32
27
 
33
28
  /**
34
29
  * Default vrednosti za sertifikaciju
@@ -68,11 +63,11 @@ export class TechnologyService extends BaseService {
68
63
  private getTechnologiesRef(categoryId: string, subcategoryId: string) {
69
64
  return collection(
70
65
  this.db,
71
- COLLECTION,
66
+ CATEGORIES_COLLECTION,
72
67
  categoryId,
73
- SUB_COLLECTION_SUBCATEGORIES,
68
+ SUBCATEGORIES_COLLECTION,
74
69
  subcategoryId,
75
- SUB_COLLECTION_TECHNOLOGIES
70
+ TECHNOLOGIES_COLLECTION
76
71
  );
77
72
  }
78
73
 
@@ -21,3 +21,8 @@ export interface Brand {
21
21
  website?: string;
22
22
  description?: string;
23
23
  }
24
+
25
+ /**
26
+ * Kolekcija u Firestore bazi gde se čuvaju brendovi
27
+ */
28
+ export const BRANDS_COLLECTION = "brands";
@@ -29,3 +29,8 @@ export interface Category {
29
29
  /** Flag koji označava da li je kategorija aktivna */
30
30
  isActive: boolean;
31
31
  }
32
+
33
+ /**
34
+ * Kolekcija u Firestore bazi gde se čuvaju kategorije
35
+ */
36
+ export const CATEGORIES_COLLECTION = "backoffice_categories";
@@ -7,6 +7,8 @@ import {
7
7
  HeadingLevel,
8
8
  ListType,
9
9
  DynamicVariable,
10
+ DOCUMENTATION_TEMPLATES_COLLECTION,
11
+ FILLED_DOCUMENTS_COLLECTION,
10
12
  } from "../../types/documentation-templates";
11
13
 
12
14
  /**
@@ -22,3 +24,5 @@ export {
22
24
  ListType,
23
25
  DynamicVariable,
24
26
  };
27
+
28
+ export { DOCUMENTATION_TEMPLATES_COLLECTION, FILLED_DOCUMENTS_COLLECTION };
@@ -33,3 +33,8 @@ export interface Product {
33
33
  indications?: string[];
34
34
  contraindications?: string[];
35
35
  }
36
+
37
+ /**
38
+ * Kolekcija u Firestore bazi gde se čuvaju proizvodi
39
+ */
40
+ export const PRODUCTS_COLLECTION = "products";
@@ -56,3 +56,8 @@ export interface Requirement {
56
56
  createdAt: Date;
57
57
  updatedAt: Date;
58
58
  }
59
+
60
+ /**
61
+ * Kolekcija u Firestore bazi gde se čuvaju globalni zahtevi
62
+ */
63
+ export const REQUIREMENTS_COLLECTION = "backoffice_requirements";
@@ -27,3 +27,8 @@ export interface Subcategory {
27
27
  /** Datum poslednjeg ažuriranja podkategorije */
28
28
  updatedAt: Date;
29
29
  }
30
+
31
+ /**
32
+ * Kolekcija u Firestore bazi gde se čuvaju podkategorije
33
+ */
34
+ export const SUBCATEGORIES_COLLECTION = "subcategories";
@@ -3,6 +3,7 @@ import { BlockingCondition } from "./static/blocking-condition.types";
3
3
  import { Contraindication } from "./static/contraindication.types";
4
4
  import { TreatmentBenefit } from "./static/treatment-benefit.types";
5
5
  import { CertificationRequirement } from "./static/certification.types";
6
+ import { DocumentTemplate } from "../../types/documentation-templates";
6
7
 
7
8
  /**
8
9
  * Zahtevi koji su povezani sa tehnologijom
@@ -29,6 +30,7 @@ export interface TechnologyRequirements {
29
30
  * @property contraindications - List of conditions requiring special attention
30
31
  * @property benefits - List of expected benefits from the procedure
31
32
  * @property certificationRequirement - Required certification level and specialties
33
+ * @property documentationTemplates - List of documentation templates required for this technology
32
34
  * @property isActive - Whether the technology is active in the system
33
35
  * @property createdAt - Creation date
34
36
  * @property updatedAt - Last update date
@@ -66,6 +68,9 @@ export interface Technology {
66
68
  /** Potrebna sertifikacija za korišćenje tehnologije */
67
69
  certificationRequirement: CertificationRequirement;
68
70
 
71
+ /** Dokumentacioni šabloni potrebni za ovu tehnologiju */
72
+ documentationTemplates?: DocumentTemplate[];
73
+
69
74
  /** Da li je tehnologija trenutno aktivna */
70
75
  isActive: boolean;
71
76
 
@@ -75,3 +80,8 @@ export interface Technology {
75
80
  /** Datum poslednjeg ažuriranja */
76
81
  updatedAt: Date;
77
82
  }
83
+
84
+ /**
85
+ * Kolekcija u Firestore bazi gde se čuvaju tehnologije
86
+ */
87
+ export const TECHNOLOGIES_COLLECTION = "technologies";
@@ -13,6 +13,7 @@ import {
13
13
  HeadingLevel,
14
14
  ListType,
15
15
  } from "../types/documentation-templates.types";
16
+ import { documentTemplateSchema } from "../../validations/documentation-templates.schema";
16
17
 
17
18
  /**
18
19
  * Base validation schemas for enums
@@ -87,6 +88,7 @@ export const technologySchema = z.object({
87
88
  }),
88
89
  blockingConditions: z.array(blockingConditionSchema),
89
90
  contraindications: z.array(contraindicationSchema),
91
+ documentationTemplates: z.array(documentTemplateSchema),
90
92
  benefits: z.array(treatmentBenefitSchema),
91
93
  certificationRequirement: certificationRequirementSchema,
92
94
  isActive: z.boolean().default(true),
@@ -134,6 +134,13 @@ export const AUTH_ERRORS = {
134
134
  401
135
135
  ),
136
136
 
137
+ // Resource not found
138
+ NOT_FOUND: new AuthError(
139
+ "The requested resource was not found",
140
+ "AUTH/NOT_FOUND",
141
+ 404
142
+ ),
143
+
137
144
  // Detailed password validation errors
138
145
  PASSWORD_LENGTH_ERROR: new AuthError(
139
146
  "Password must be at least 8 characters long",
@@ -471,6 +471,100 @@ export class AuthService extends BaseService {
471
471
  return this.userService.getOrCreateUser(firebaseUser);
472
472
  }
473
473
 
474
+ /**
475
+ * Prijavljuje korisnika sa email-om i lozinkom samo za clinic_admin role
476
+ * @param email - Email korisnika
477
+ * @param password - Lozinka korisnika
478
+ * @returns Objekat koji sadrži korisnika, admin profil i grupu klinika
479
+ * @throws {AUTH_ERRORS.INVALID_ROLE} Ako korisnik nema clinic_admin rolu
480
+ * @throws {AUTH_ERRORS.NOT_FOUND} Ako admin profil nije pronađen
481
+ */
482
+ async signInClinicAdmin(
483
+ email: string,
484
+ password: string
485
+ ): Promise<{
486
+ user: User;
487
+ clinicAdmin: ClinicAdmin;
488
+ clinicGroup: ClinicGroup;
489
+ }> {
490
+ try {
491
+ // Initialize required services
492
+ const clinicAdminService = new ClinicAdminService(
493
+ this.db,
494
+ this.auth,
495
+ this.app
496
+ );
497
+ const clinicGroupService = new ClinicGroupService(
498
+ this.db,
499
+ this.auth,
500
+ this.app,
501
+ clinicAdminService
502
+ );
503
+ const clinicService = new ClinicService(
504
+ this.db,
505
+ this.auth,
506
+ this.app,
507
+ clinicGroupService,
508
+ clinicAdminService
509
+ );
510
+
511
+ // Set services to resolve circular dependencies
512
+ clinicAdminService.setServices(clinicGroupService, clinicService);
513
+
514
+ // Sign in with email/password
515
+ const { user: firebaseUser } = await signInWithEmailAndPassword(
516
+ this.auth,
517
+ email,
518
+ password
519
+ );
520
+
521
+ // Get or create user
522
+ const user = await this.userService.getOrCreateUser(firebaseUser);
523
+
524
+ // Check if user has clinic_admin role
525
+ if (!user.roles?.includes(UserRole.CLINIC_ADMIN)) {
526
+ console.error("[AUTH] User is not a clinic admin:", user.uid);
527
+ throw AUTH_ERRORS.INVALID_ROLE;
528
+ }
529
+
530
+ // Check and get admin profile
531
+ if (!user.adminProfile) {
532
+ console.error("[AUTH] User has no admin profile:", user.uid);
533
+ throw AUTH_ERRORS.NOT_FOUND;
534
+ }
535
+
536
+ // Get clinic admin profile
537
+ const adminProfile = await clinicAdminService.getClinicAdmin(
538
+ user.adminProfile
539
+ );
540
+ if (!adminProfile) {
541
+ console.error("[AUTH] Admin profile not found:", user.adminProfile);
542
+ throw AUTH_ERRORS.NOT_FOUND;
543
+ }
544
+
545
+ // Get clinic group
546
+ const clinicGroup = await clinicGroupService.getClinicGroup(
547
+ adminProfile.clinicGroupId
548
+ );
549
+ if (!clinicGroup) {
550
+ console.error(
551
+ "[AUTH] Clinic group not found:",
552
+ adminProfile.clinicGroupId
553
+ );
554
+ throw AUTH_ERRORS.NOT_FOUND;
555
+ }
556
+
557
+ return {
558
+ user,
559
+ clinicAdmin: adminProfile,
560
+ clinicGroup,
561
+ };
562
+ } catch (error) {
563
+ console.error("[AUTH] Error in signInClinicAdmin:", error);
564
+ throw error;
565
+ }
566
+ }
567
+
474
568
  /**
475
569
  * Prijavljuje korisnika sa Facebook-om
476
570
  */
@@ -21,9 +21,12 @@ import {
21
21
  CreateDocumentTemplateData,
22
22
  DocumentElement,
23
23
  DocumentTemplate,
24
- DOCUMENTATION_TEMPLATES_COLLECTION,
25
24
  UpdateDocumentTemplateData,
26
25
  } from "../../types";
26
+ import {
27
+ FILLED_DOCUMENTS_COLLECTION,
28
+ DOCUMENTATION_TEMPLATES_COLLECTION,
29
+ } from "../../types";
27
30
  import {
28
31
  createDocumentTemplateSchema,
29
32
  updateDocumentTemplateSchema,