@blackcode_sa/metaestetics-api 1.8.0 → 1.8.1

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 (40) hide show
  1. package/dist/admin/index.d.mts +956 -848
  2. package/dist/admin/index.d.ts +956 -848
  3. package/dist/admin/index.js +7215 -6757
  4. package/dist/admin/index.mjs +7215 -6754
  5. package/dist/backoffice/index.d.mts +1418 -1418
  6. package/dist/backoffice/index.d.ts +1418 -1418
  7. package/dist/backoffice/index.js +1464 -1454
  8. package/dist/backoffice/index.mjs +1509 -1499
  9. package/dist/index.d.mts +5565 -5565
  10. package/dist/index.d.ts +5565 -5565
  11. package/dist/index.js +9229 -9225
  12. package/dist/index.mjs +9324 -9320
  13. package/package.json +1 -1
  14. package/src/admin/aggregation/appointment/index.ts +1 -0
  15. package/src/admin/aggregation/clinic/index.ts +1 -0
  16. package/src/admin/aggregation/forms/index.ts +1 -0
  17. package/src/admin/aggregation/index.ts +8 -0
  18. package/src/admin/aggregation/patient/index.ts +1 -0
  19. package/src/admin/aggregation/practitioner/index.ts +1 -0
  20. package/src/admin/aggregation/practitioner-invite/index.ts +1 -0
  21. package/src/admin/aggregation/procedure/index.ts +1 -0
  22. package/src/admin/aggregation/reviews/index.ts +1 -0
  23. package/src/admin/booking/index.ts +1 -1
  24. package/src/admin/calendar/index.ts +1 -0
  25. package/src/admin/documentation-templates/index.ts +1 -0
  26. package/src/admin/free-consultation/index.ts +1 -0
  27. package/src/admin/index.ts +18 -120
  28. package/src/admin/mailing/appointment/index.ts +1 -0
  29. package/src/admin/mailing/index.ts +1 -2
  30. package/src/admin/mailing/practitionerInvite/index.ts +1 -0
  31. package/src/admin/notifications/index.ts +1 -0
  32. package/src/admin/requirements/index.ts +1 -0
  33. package/src/admin/users/index.ts +1 -0
  34. package/src/admin/users/user-profile.admin.ts +1 -0
  35. package/src/backoffice/constants/index.ts +1 -0
  36. package/src/backoffice/errors/index.ts +1 -0
  37. package/src/backoffice/index.ts +5 -14
  38. package/src/backoffice/services/index.ts +7 -0
  39. package/src/backoffice/validations/index.ts +1 -0
  40. package/src/services/index.ts +12 -14
@@ -32,7 +32,7 @@ __export(index_exports, {
32
32
  CircularReferenceError: () => CircularReferenceError,
33
33
  Contraindication: () => Contraindication,
34
34
  ContraindicationError: () => ContraindicationError,
35
- DEFAULT_CERTIFICATION_REQUIREMENT: () => DEFAULT_CERTIFICATION_REQUIREMENT,
35
+ DEFAULT_CERTIFICATION_REQUIREMENT: () => DEFAULT_CERTIFICATION_REQUIREMENT2,
36
36
  DocumentElementType: () => DocumentElementType,
37
37
  DocumentationTemplateService: () => DocumentationTemplateService2,
38
38
  DynamicVariable: () => DynamicVariable,
@@ -90,371 +90,310 @@ __export(index_exports, {
90
90
  });
91
91
  module.exports = __toCommonJS(index_exports);
92
92
 
93
+ // src/backoffice/services/brand.service.ts
94
+ var import_firestore = require("firebase/firestore");
95
+
93
96
  // src/backoffice/types/brand.types.ts
94
97
  var BRANDS_COLLECTION = "brands";
95
98
 
96
- // src/backoffice/types/category.types.ts
97
- var CATEGORIES_COLLECTION = "backoffice_categories";
98
-
99
- // src/backoffice/types/product.types.ts
100
- var PRODUCTS_COLLECTION = "products";
101
-
102
- // src/backoffice/types/requirement.types.ts
103
- var TimeUnit = /* @__PURE__ */ ((TimeUnit2) => {
104
- TimeUnit2["HOURS"] = "hours";
105
- TimeUnit2["DAYS"] = "days";
106
- return TimeUnit2;
107
- })(TimeUnit || {});
108
- var RequirementType = /* @__PURE__ */ ((RequirementType3) => {
109
- RequirementType3["PRE"] = "pre";
110
- RequirementType3["POST"] = "post";
111
- return RequirementType3;
112
- })(RequirementType || {});
113
- var REQUIREMENTS_COLLECTION = "backoffice_requirements";
114
-
115
- // src/backoffice/types/subcategory.types.ts
116
- var SUBCATEGORIES_COLLECTION = "subcategories";
117
-
118
- // src/backoffice/types/technology.types.ts
119
- var TECHNOLOGIES_COLLECTION = "technologies";
120
-
121
- // src/backoffice/types/static/blocking-condition.types.ts
122
- var BlockingCondition = /* @__PURE__ */ ((BlockingCondition2) => {
123
- BlockingCondition2["PREGNANCY"] = "pregnancy";
124
- BlockingCondition2["BREASTFEEDING"] = "breastfeeding";
125
- BlockingCondition2["ACTIVE_INFECTION"] = "active_infection";
126
- BlockingCondition2["SKIN_CONDITION"] = "skin_condition";
127
- BlockingCondition2["AUTOIMMUNE_DISEASE"] = "autoimmune_disease";
128
- BlockingCondition2["BLOOD_THINNERS"] = "blood_thinners";
129
- BlockingCondition2["RECENT_SURGERY"] = "recent_surgery";
130
- BlockingCondition2["DIABETES"] = "diabetes";
131
- BlockingCondition2["HEART_CONDITION"] = "heart_condition";
132
- BlockingCondition2["HIGH_BLOOD_PRESSURE"] = "high_blood_pressure";
133
- BlockingCondition2["KELOID_SCARRING"] = "keloid_scarring";
134
- BlockingCondition2["METAL_IMPLANTS"] = "metal_implants";
135
- BlockingCondition2["PACEMAKER"] = "pacemaker";
136
- BlockingCondition2["CANCER"] = "cancer";
137
- BlockingCondition2["EPILEPSY"] = "epilepsy";
138
- return BlockingCondition2;
139
- })(BlockingCondition || {});
140
-
141
- // src/backoffice/types/static/certification.types.ts
142
- var CertificationLevel = /* @__PURE__ */ ((CertificationLevel2) => {
143
- CertificationLevel2["AESTHETICIAN"] = "aesthetician";
144
- CertificationLevel2["NURSE_ASSISTANT"] = "nurse_assistant";
145
- CertificationLevel2["NURSE"] = "nurse";
146
- CertificationLevel2["NURSE_PRACTITIONER"] = "nurse_practitioner";
147
- CertificationLevel2["PHYSICIAN_ASSISTANT"] = "physician_assistant";
148
- CertificationLevel2["DOCTOR"] = "doctor";
149
- CertificationLevel2["SPECIALIST"] = "specialist";
150
- CertificationLevel2["PLASTIC_SURGEON"] = "plastic_surgeon";
151
- return CertificationLevel2;
152
- })(CertificationLevel || {});
153
- var CertificationSpecialty = /* @__PURE__ */ ((CertificationSpecialty3) => {
154
- CertificationSpecialty3["LASER"] = "laser";
155
- CertificationSpecialty3["INJECTABLES"] = "injectables";
156
- CertificationSpecialty3["CHEMICAL_PEELS"] = "chemical_peels";
157
- CertificationSpecialty3["MICRODERMABRASION"] = "microdermabrasion";
158
- CertificationSpecialty3["BODY_CONTOURING"] = "body_contouring";
159
- CertificationSpecialty3["SKIN_CARE"] = "skin_care";
160
- CertificationSpecialty3["WOUND_CARE"] = "wound_care";
161
- CertificationSpecialty3["ANESTHESIA"] = "anesthesia";
162
- return CertificationSpecialty3;
163
- })(CertificationSpecialty || {});
164
-
165
- // src/backoffice/types/static/contraindication.types.ts
166
- var Contraindication = /* @__PURE__ */ ((Contraindication2) => {
167
- Contraindication2["SENSITIVE_SKIN"] = "sensitive_skin";
168
- Contraindication2["RECENT_TANNING"] = "recent_tanning";
169
- Contraindication2["RECENT_BOTOX"] = "recent_botox";
170
- Contraindication2["RECENT_FILLERS"] = "recent_fillers";
171
- Contraindication2["SKIN_ALLERGIES"] = "skin_allergies";
172
- Contraindication2["MEDICATIONS"] = "medications";
173
- Contraindication2["RECENT_CHEMICAL_PEEL"] = "recent_chemical_peel";
174
- Contraindication2["RECENT_LASER"] = "recent_laser";
175
- Contraindication2["SKIN_INFLAMMATION"] = "skin_inflammation";
176
- Contraindication2["OPEN_WOUNDS"] = "open_wounds";
177
- Contraindication2["HERPES_SIMPLEX"] = "herpes_simplex";
178
- Contraindication2["COLD_SORES"] = "cold_sores";
179
- return Contraindication2;
180
- })(Contraindication || {});
181
-
182
- // src/backoffice/types/static/procedure-family.types.ts
183
- var ProcedureFamily = /* @__PURE__ */ ((ProcedureFamily2) => {
184
- ProcedureFamily2["AESTHETICS"] = "aesthetics";
185
- ProcedureFamily2["SURGERY"] = "surgery";
186
- return ProcedureFamily2;
187
- })(ProcedureFamily || {});
188
-
189
- // src/backoffice/types/static/treatment-benefit.types.ts
190
- var TreatmentBenefit = /* @__PURE__ */ ((TreatmentBenefit2) => {
191
- TreatmentBenefit2["WRINKLE_REDUCTION"] = "wrinkle_reduction";
192
- TreatmentBenefit2["SKIN_TIGHTENING"] = "skin_tightening";
193
- TreatmentBenefit2["COLLAGEN_PRODUCTION"] = "collagen_production";
194
- TreatmentBenefit2["ACNE_REDUCTION"] = "acne_reduction";
195
- TreatmentBenefit2["SCAR_REDUCTION"] = "scar_reduction";
196
- TreatmentBenefit2["PIGMENTATION_IMPROVEMENT"] = "pigmentation_improvement";
197
- TreatmentBenefit2["HAIR_REMOVAL"] = "hair_removal";
198
- TreatmentBenefit2["MUSCLE_TONING"] = "muscle_toning";
199
- TreatmentBenefit2["FAT_REDUCTION"] = "fat_reduction";
200
- TreatmentBenefit2["CELLULITE_REDUCTION"] = "cellulite_reduction";
201
- TreatmentBenefit2["SKIN_REJUVENATION"] = "skin_rejuvenation";
202
- TreatmentBenefit2["PORE_REDUCTION"] = "pore_reduction";
203
- TreatmentBenefit2["TEXTURE_IMPROVEMENT"] = "texture_improvement";
204
- TreatmentBenefit2["HYDRATION_BOOST"] = "hydration_boost";
205
- TreatmentBenefit2["CIRCULATION_IMPROVEMENT"] = "circulation_improvement";
206
- return TreatmentBenefit2;
207
- })(TreatmentBenefit || {});
208
-
209
- // src/types/documentation-templates/index.ts
210
- var DOCUMENTATION_TEMPLATES_COLLECTION = "documentation-templates";
211
- var DocumentElementType = /* @__PURE__ */ ((DocumentElementType2) => {
212
- DocumentElementType2["HEADING"] = "heading";
213
- DocumentElementType2["PARAGRAPH"] = "paragraph";
214
- DocumentElementType2["LIST"] = "list";
215
- DocumentElementType2["DYNAMIC_TEXT"] = "dynamic_text";
216
- DocumentElementType2["BINARY_CHOICE"] = "binary_choice";
217
- DocumentElementType2["MULTIPLE_CHOICE"] = "multiple_choice";
218
- DocumentElementType2["SINGLE_CHOICE"] = "single_choice";
219
- DocumentElementType2["RATING_SCALE"] = "rating_scale";
220
- DocumentElementType2["TEXT_INPUT"] = "text_input";
221
- DocumentElementType2["DATE_PICKER"] = "date_picker";
222
- DocumentElementType2["SIGNATURE"] = "signature";
223
- DocumentElementType2["DITIGAL_SIGNATURE"] = "digital_signature";
224
- DocumentElementType2["FILE_UPLOAD"] = "file_upload";
225
- return DocumentElementType2;
226
- })(DocumentElementType || {});
227
- var ListType = /* @__PURE__ */ ((ListType2) => {
228
- ListType2["ORDERED"] = "ordered";
229
- ListType2["UNORDERED"] = "unordered";
230
- return ListType2;
231
- })(ListType || {});
232
- var HeadingLevel = /* @__PURE__ */ ((HeadingLevel2) => {
233
- HeadingLevel2["H1"] = "h1";
234
- HeadingLevel2["H2"] = "h2";
235
- HeadingLevel2["H3"] = "h3";
236
- HeadingLevel2["H4"] = "h4";
237
- HeadingLevel2["H5"] = "h5";
238
- HeadingLevel2["H6"] = "h6";
239
- return HeadingLevel2;
240
- })(HeadingLevel || {});
241
- var DynamicVariable = /* @__PURE__ */ ((DynamicVariable2) => {
242
- DynamicVariable2["PATIENT_NAME"] = "$[PATIENT_NAME]";
243
- DynamicVariable2["DOCTOR_NAME"] = "$[DOCTOR_NAME]";
244
- DynamicVariable2["CLINIC_NAME"] = "$[CLINIC_NAME]";
245
- DynamicVariable2["PATIENT_BIRTHDAY"] = "$[PATIENT_BIRTHDAY]";
246
- DynamicVariable2["APPOINTMENT_DATE"] = "$[APPOINTMENT_DATE]";
247
- DynamicVariable2["CURRENT_DATE"] = "$[CURRENT_DATE]";
248
- DynamicVariable2["PROCEDURE_NAME"] = "$[PROCEDURE_NAME]";
249
- DynamicVariable2["PROCEDURE_DESCRIPTION"] = "$[PROCEDURE_DESCRIPTION]";
250
- DynamicVariable2["PROCEDURE_COST"] = "$[PROCEDURE_COST]";
251
- DynamicVariable2["PROCEDURE_DURATION"] = "$[PROCEDURE_DURATION]";
252
- DynamicVariable2["PROCEDURE_RISK"] = "$[PROCEDURE_RISK]";
253
- return DynamicVariable2;
254
- })(DynamicVariable || {});
255
- var FilledDocumentStatus = /* @__PURE__ */ ((FilledDocumentStatus2) => {
256
- FilledDocumentStatus2["DRAFT"] = "draft";
257
- FilledDocumentStatus2["SKIPPED"] = "skipped";
258
- FilledDocumentStatus2["PENDING"] = "pending";
259
- FilledDocumentStatus2["COMPLETED"] = "completed";
260
- FilledDocumentStatus2["SIGNED"] = "signed";
261
- FilledDocumentStatus2["REJECTED"] = "rejected";
262
- return FilledDocumentStatus2;
263
- })(FilledDocumentStatus || {});
264
-
265
- // src/backoffice/constants/certification.constants.ts
266
- var DEFAULT_CERTIFICATION_REQUIREMENT = {
267
- minimumLevel: "aesthetician" /* AESTHETICIAN */,
268
- requiredSpecialties: []
269
- };
270
-
271
- // src/backoffice/errors/backoffice.errors.ts
272
- var BackofficeError = class extends Error {
273
- constructor(message) {
274
- super(message);
275
- this.name = "BackofficeError";
99
+ // src/services/base.service.ts
100
+ var import_storage = require("firebase/storage");
101
+ var BaseService = class {
102
+ constructor(db, auth, app) {
103
+ this.db = db;
104
+ this.auth = auth;
105
+ this.app = app;
106
+ this.storage = (0, import_storage.getStorage)(app);
276
107
  }
277
- };
278
- var CategoryError = class extends BackofficeError {
279
- constructor(message) {
280
- super(message);
281
- this.name = "CategoryError";
108
+ /**
109
+ * Generiše jedinstveni ID za dokumente
110
+ * Format: xxxxxxxxxxxx-timestamp
111
+ * Gde je x random karakter (broj ili slovo)
112
+ */
113
+ generateId() {
114
+ const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
115
+ const timestamp = Date.now().toString(36);
116
+ const randomPart = Array.from(
117
+ { length: 12 },
118
+ () => chars.charAt(Math.floor(Math.random() * chars.length))
119
+ ).join("");
120
+ return `${randomPart}-${timestamp}`;
282
121
  }
283
122
  };
284
- var CategoryNotFoundError = class extends CategoryError {
285
- constructor(id) {
286
- super(`Kategorija sa ID-em ${id} nije prona\u0111ena`);
287
- this.name = "CategoryNotFoundError";
123
+
124
+ // src/backoffice/services/brand.service.ts
125
+ var BrandService = class extends BaseService {
126
+ /**
127
+ * Gets reference to brands collection
128
+ */
129
+ getBrandsRef() {
130
+ return (0, import_firestore.collection)(this.db, BRANDS_COLLECTION);
288
131
  }
289
- };
290
- var InvalidCategoryDataError = class extends CategoryError {
291
- constructor(message) {
292
- super(`Neva\u017Ee\u0107i podaci za kategoriju: ${message}`);
293
- this.name = "InvalidCategoryDataError";
132
+ /**
133
+ * Creates a new brand
134
+ */
135
+ async create(brand) {
136
+ const now = /* @__PURE__ */ new Date();
137
+ const newBrand = {
138
+ ...brand,
139
+ createdAt: now,
140
+ updatedAt: now,
141
+ isActive: true
142
+ };
143
+ const docRef = await (0, import_firestore.addDoc)(this.getBrandsRef(), newBrand);
144
+ return { id: docRef.id, ...newBrand };
294
145
  }
295
- };
296
- var SubcategoryError = class extends BackofficeError {
297
- constructor(message) {
298
- super(message);
299
- this.name = "SubcategoryError";
146
+ /**
147
+ * Gets all active brands
148
+ */
149
+ async getAll() {
150
+ const q = (0, import_firestore.query)(this.getBrandsRef(), (0, import_firestore.where)("isActive", "==", true));
151
+ const snapshot = await (0, import_firestore.getDocs)(q);
152
+ return snapshot.docs.map(
153
+ (doc10) => ({
154
+ id: doc10.id,
155
+ ...doc10.data()
156
+ })
157
+ );
300
158
  }
301
- };
302
- var SubcategoryNotFoundError = class extends SubcategoryError {
303
- constructor(id) {
304
- super(`Podkategorija sa ID-em ${id} nije prona\u0111ena`);
305
- this.name = "SubcategoryNotFoundError";
306
- }
307
- };
308
- var InvalidSubcategoryDataError = class extends SubcategoryError {
309
- constructor(message) {
310
- super(`Neva\u017Ee\u0107i podaci za podkategoriju: ${message}`);
311
- this.name = "InvalidSubcategoryDataError";
312
- }
313
- };
314
- var TechnologyError = class extends BackofficeError {
315
- constructor(message) {
316
- super(message);
317
- this.name = "TechnologyError";
318
- }
319
- };
320
- var TechnologyNotFoundError = class extends TechnologyError {
321
- constructor(id) {
322
- super(`Tehnologija sa ID-em ${id} nije prona\u0111ena`);
323
- this.name = "TechnologyNotFoundError";
324
- }
325
- };
326
- var InvalidTechnologyDataError = class extends TechnologyError {
327
- constructor(message) {
328
- super(`Neva\u017Ee\u0107i podaci za tehnologiju: ${message}`);
329
- this.name = "InvalidTechnologyDataError";
330
- }
331
- };
332
- var RequirementError = class extends BackofficeError {
333
- constructor(message) {
334
- super(message);
335
- this.name = "RequirementError";
336
- }
337
- };
338
- var RequirementNotFoundError = class extends RequirementError {
339
- constructor(id) {
340
- super(`Zahtev sa ID-em ${id} nije prona\u0111en`);
341
- this.name = "RequirementNotFoundError";
342
- }
343
- };
344
- var InvalidRequirementDataError = class extends RequirementError {
345
- constructor(message) {
346
- super(`Neva\u017Ee\u0107i podaci za zahtev: ${message}`);
347
- this.name = "InvalidRequirementDataError";
348
- }
349
- };
350
- var InvalidTimeframeError = class extends RequirementError {
351
- constructor(message) {
352
- super(`Invalid timeframe: ${message}`);
353
- this.name = "InvalidTimeframeError";
159
+ /**
160
+ * Updates a brand
161
+ */
162
+ async update(brandId, brand) {
163
+ const updateData = {
164
+ ...brand,
165
+ updatedAt: /* @__PURE__ */ new Date()
166
+ };
167
+ const docRef = (0, import_firestore.doc)(this.getBrandsRef(), brandId);
168
+ await (0, import_firestore.updateDoc)(docRef, updateData);
169
+ return this.getById(brandId);
354
170
  }
355
- };
356
- var RelationshipError = class extends BackofficeError {
357
- constructor(message) {
358
- super(message);
359
- this.name = "RelationshipError";
171
+ /**
172
+ * Soft deletes a brand
173
+ */
174
+ async delete(brandId) {
175
+ await this.update(brandId, {
176
+ isActive: false
177
+ });
360
178
  }
361
- };
362
- var InvalidHierarchyError = class extends RelationshipError {
363
- constructor(message) {
364
- super(`Invalid hierarchy: ${message}`);
365
- this.name = "InvalidHierarchyError";
179
+ /**
180
+ * Gets a brand by ID
181
+ */
182
+ async getById(brandId) {
183
+ const docRef = (0, import_firestore.doc)(this.getBrandsRef(), brandId);
184
+ const docSnap = await (0, import_firestore.getDoc)(docRef);
185
+ if (!docSnap.exists()) return null;
186
+ return {
187
+ id: docSnap.id,
188
+ ...docSnap.data()
189
+ };
366
190
  }
367
191
  };
368
- var CircularReferenceError = class extends RelationshipError {
369
- constructor(message) {
370
- super(`Circular reference detected: ${message}`);
371
- this.name = "CircularReferenceError";
192
+
193
+ // src/backoffice/services/category.service.ts
194
+ var import_firestore2 = require("firebase/firestore");
195
+
196
+ // src/backoffice/types/category.types.ts
197
+ var CATEGORIES_COLLECTION = "backoffice_categories";
198
+
199
+ // src/backoffice/services/category.service.ts
200
+ var CategoryService = class extends BaseService {
201
+ /**
202
+ * Referenca na Firestore kolekciju kategorija
203
+ */
204
+ get categoriesRef() {
205
+ return (0, import_firestore2.collection)(this.db, CATEGORIES_COLLECTION);
372
206
  }
373
- };
374
- var BlockingConditionError = class extends BackofficeError {
375
- constructor(message) {
376
- super(message);
377
- this.name = "BlockingConditionError";
207
+ /**
208
+ * Kreira novu kategoriju u sistemu
209
+ * @param category - Podaci za novu kategoriju
210
+ * @returns Kreirana kategorija sa generisanim ID-em
211
+ */
212
+ async create(category) {
213
+ const now = /* @__PURE__ */ new Date();
214
+ const newCategory = {
215
+ ...category,
216
+ createdAt: now,
217
+ updatedAt: now,
218
+ isActive: true
219
+ };
220
+ const docRef = await (0, import_firestore2.addDoc)(this.categoriesRef, newCategory);
221
+ return { id: docRef.id, ...newCategory };
378
222
  }
379
- };
380
- var InvalidBlockingConditionError = class extends BlockingConditionError {
381
- constructor(condition) {
382
- super(`Neva\u017Ee\u0107i blokiraju\u0107i uslov: ${condition}`);
383
- this.name = "InvalidBlockingConditionError";
223
+ /**
224
+ * Vraća sve aktivne kategorije
225
+ * @returns Lista aktivnih kategorija
226
+ */
227
+ async getAll() {
228
+ const q = (0, import_firestore2.query)(this.categoriesRef, (0, import_firestore2.where)("isActive", "==", true));
229
+ const snapshot = await (0, import_firestore2.getDocs)(q);
230
+ return snapshot.docs.map(
231
+ (doc10) => ({
232
+ id: doc10.id,
233
+ ...doc10.data()
234
+ })
235
+ );
384
236
  }
385
- };
386
- var ContraindicationError = class extends BackofficeError {
387
- constructor(message) {
388
- super(message);
389
- this.name = "ContraindicationError";
237
+ /**
238
+ * Vraća sve aktivne kategorije za određenu familiju procedura
239
+ * @param family - Familija procedura (aesthetics/surgery)
240
+ * @returns Lista kategorija koje pripadaju traženoj familiji
241
+ */
242
+ async getAllByFamily(family) {
243
+ const q = (0, import_firestore2.query)(
244
+ this.categoriesRef,
245
+ (0, import_firestore2.where)("family", "==", family),
246
+ (0, import_firestore2.where)("isActive", "==", true)
247
+ );
248
+ const snapshot = await (0, import_firestore2.getDocs)(q);
249
+ return snapshot.docs.map(
250
+ (doc10) => ({
251
+ id: doc10.id,
252
+ ...doc10.data()
253
+ })
254
+ );
390
255
  }
391
- };
392
- var InvalidContraindicationError = class extends ContraindicationError {
393
- constructor(contraindication) {
394
- super(`Neva\u017Ee\u0107a kontraindikacija: ${contraindication}`);
395
- this.name = "InvalidContraindicationError";
256
+ /**
257
+ * Ažurira postojeću kategoriju
258
+ * @param id - ID kategorije koja se ažurira
259
+ * @param category - Novi podaci za kategoriju
260
+ * @returns Ažurirana kategorija
261
+ */
262
+ async update(id, category) {
263
+ const updateData = {
264
+ ...category,
265
+ updatedAt: /* @__PURE__ */ new Date()
266
+ };
267
+ const docRef = (0, import_firestore2.doc)(this.categoriesRef, id);
268
+ await (0, import_firestore2.updateDoc)(docRef, updateData);
269
+ return this.getById(id);
396
270
  }
397
- };
398
- var TreatmentBenefitError = class extends BackofficeError {
399
- constructor(message) {
400
- super(message);
401
- this.name = "TreatmentBenefitError";
271
+ /**
272
+ * Soft delete kategorije (postavlja isActive na false)
273
+ * @param id - ID kategorije koja se briše
274
+ */
275
+ async delete(id) {
276
+ await this.update(id, { isActive: false });
402
277
  }
403
- };
404
- var InvalidTreatmentBenefitError = class extends TreatmentBenefitError {
405
- constructor(benefit) {
406
- super(`Neva\u017Ee\u0107i benefit tretmana: ${benefit}`);
407
- this.name = "InvalidTreatmentBenefitError";
278
+ /**
279
+ * Vraća kategoriju po ID-u
280
+ * @param id - ID tražene kategorije
281
+ * @returns Kategorija ili null ako ne postoji
282
+ */
283
+ async getById(id) {
284
+ const docRef = (0, import_firestore2.doc)(this.categoriesRef, id);
285
+ const docSnap = await (0, import_firestore2.getDoc)(docRef);
286
+ if (!docSnap.exists()) return null;
287
+ return {
288
+ id: docSnap.id,
289
+ ...docSnap.data()
290
+ };
408
291
  }
409
292
  };
410
293
 
411
- // src/backoffice/validations/schemas.ts
412
- var import_zod2 = require("zod");
294
+ // src/services/documentation-templates/documentation-template.service.ts
295
+ var import_firestore3 = require("firebase/firestore");
413
296
 
414
- // src/validations/documentation-templates/template.schema.ts
415
- var import_zod = require("zod");
416
- var baseElementSchema = import_zod.z.object({
417
- id: import_zod.z.string().optional(),
418
- // Make id optional so we can omit it later
419
- type: import_zod.z.nativeEnum(DocumentElementType),
420
- required: import_zod.z.boolean().optional()
421
- });
422
- var headingElementSchema = baseElementSchema.extend({
423
- type: import_zod.z.literal("heading" /* HEADING */),
424
- text: import_zod.z.string().min(1).max(200),
425
- level: import_zod.z.nativeEnum(HeadingLevel)
426
- });
427
- var paragraphElementSchema = baseElementSchema.extend({
428
- type: import_zod.z.literal("paragraph" /* PARAGRAPH */),
429
- text: import_zod.z.string().min(1).max(5e3)
430
- });
431
- var listElementSchema = baseElementSchema.extend({
432
- type: import_zod.z.literal("list" /* LIST */),
433
- items: import_zod.z.array(import_zod.z.string().min(1).max(500)).min(1).max(100),
434
- listType: import_zod.z.nativeEnum(ListType)
435
- });
436
- var dynamicTextElementSchema = baseElementSchema.extend({
437
- type: import_zod.z.literal("dynamic_text" /* DYNAMIC_TEXT */),
438
- text: import_zod.z.string().min(1).max(5e3)
439
- });
440
- var binaryChoiceElementSchema = baseElementSchema.extend({
441
- type: import_zod.z.literal("binary_choice" /* BINARY_CHOICE */),
442
- question: import_zod.z.string().min(1).max(500),
443
- defaultValue: import_zod.z.boolean().optional()
444
- });
445
- var multipleChoiceElementSchema = baseElementSchema.extend({
446
- type: import_zod.z.literal("multiple_choice" /* MULTIPLE_CHOICE */),
447
- question: import_zod.z.string().min(1).max(500),
448
- options: import_zod.z.array(import_zod.z.string().min(1).max(200)).min(2).max(50),
449
- defaultValues: import_zod.z.array(import_zod.z.string()).optional()
450
- });
451
- var singleChoiceElementSchema = baseElementSchema.extend({
452
- type: import_zod.z.literal("single_choice" /* SINGLE_CHOICE */),
453
- question: import_zod.z.string().min(1).max(500),
454
- options: import_zod.z.array(import_zod.z.string().min(1).max(200)).min(2).max(50),
455
- defaultValue: import_zod.z.string().optional()
456
- });
457
- var ratingScaleElementSchema = baseElementSchema.extend({
297
+ // src/types/documentation-templates/index.ts
298
+ var DOCUMENTATION_TEMPLATES_COLLECTION = "documentation-templates";
299
+ var DocumentElementType = /* @__PURE__ */ ((DocumentElementType2) => {
300
+ DocumentElementType2["HEADING"] = "heading";
301
+ DocumentElementType2["PARAGRAPH"] = "paragraph";
302
+ DocumentElementType2["LIST"] = "list";
303
+ DocumentElementType2["DYNAMIC_TEXT"] = "dynamic_text";
304
+ DocumentElementType2["BINARY_CHOICE"] = "binary_choice";
305
+ DocumentElementType2["MULTIPLE_CHOICE"] = "multiple_choice";
306
+ DocumentElementType2["SINGLE_CHOICE"] = "single_choice";
307
+ DocumentElementType2["RATING_SCALE"] = "rating_scale";
308
+ DocumentElementType2["TEXT_INPUT"] = "text_input";
309
+ DocumentElementType2["DATE_PICKER"] = "date_picker";
310
+ DocumentElementType2["SIGNATURE"] = "signature";
311
+ DocumentElementType2["DITIGAL_SIGNATURE"] = "digital_signature";
312
+ DocumentElementType2["FILE_UPLOAD"] = "file_upload";
313
+ return DocumentElementType2;
314
+ })(DocumentElementType || {});
315
+ var ListType = /* @__PURE__ */ ((ListType2) => {
316
+ ListType2["ORDERED"] = "ordered";
317
+ ListType2["UNORDERED"] = "unordered";
318
+ return ListType2;
319
+ })(ListType || {});
320
+ var HeadingLevel = /* @__PURE__ */ ((HeadingLevel2) => {
321
+ HeadingLevel2["H1"] = "h1";
322
+ HeadingLevel2["H2"] = "h2";
323
+ HeadingLevel2["H3"] = "h3";
324
+ HeadingLevel2["H4"] = "h4";
325
+ HeadingLevel2["H5"] = "h5";
326
+ HeadingLevel2["H6"] = "h6";
327
+ return HeadingLevel2;
328
+ })(HeadingLevel || {});
329
+ var DynamicVariable = /* @__PURE__ */ ((DynamicVariable2) => {
330
+ DynamicVariable2["PATIENT_NAME"] = "$[PATIENT_NAME]";
331
+ DynamicVariable2["DOCTOR_NAME"] = "$[DOCTOR_NAME]";
332
+ DynamicVariable2["CLINIC_NAME"] = "$[CLINIC_NAME]";
333
+ DynamicVariable2["PATIENT_BIRTHDAY"] = "$[PATIENT_BIRTHDAY]";
334
+ DynamicVariable2["APPOINTMENT_DATE"] = "$[APPOINTMENT_DATE]";
335
+ DynamicVariable2["CURRENT_DATE"] = "$[CURRENT_DATE]";
336
+ DynamicVariable2["PROCEDURE_NAME"] = "$[PROCEDURE_NAME]";
337
+ DynamicVariable2["PROCEDURE_DESCRIPTION"] = "$[PROCEDURE_DESCRIPTION]";
338
+ DynamicVariable2["PROCEDURE_COST"] = "$[PROCEDURE_COST]";
339
+ DynamicVariable2["PROCEDURE_DURATION"] = "$[PROCEDURE_DURATION]";
340
+ DynamicVariable2["PROCEDURE_RISK"] = "$[PROCEDURE_RISK]";
341
+ return DynamicVariable2;
342
+ })(DynamicVariable || {});
343
+ var FilledDocumentStatus = /* @__PURE__ */ ((FilledDocumentStatus2) => {
344
+ FilledDocumentStatus2["DRAFT"] = "draft";
345
+ FilledDocumentStatus2["SKIPPED"] = "skipped";
346
+ FilledDocumentStatus2["PENDING"] = "pending";
347
+ FilledDocumentStatus2["COMPLETED"] = "completed";
348
+ FilledDocumentStatus2["SIGNED"] = "signed";
349
+ FilledDocumentStatus2["REJECTED"] = "rejected";
350
+ return FilledDocumentStatus2;
351
+ })(FilledDocumentStatus || {});
352
+
353
+ // src/validations/documentation-templates/template.schema.ts
354
+ var import_zod = require("zod");
355
+ var baseElementSchema = import_zod.z.object({
356
+ id: import_zod.z.string().optional(),
357
+ // Make id optional so we can omit it later
358
+ type: import_zod.z.nativeEnum(DocumentElementType),
359
+ required: import_zod.z.boolean().optional()
360
+ });
361
+ var headingElementSchema = baseElementSchema.extend({
362
+ type: import_zod.z.literal("heading" /* HEADING */),
363
+ text: import_zod.z.string().min(1).max(200),
364
+ level: import_zod.z.nativeEnum(HeadingLevel)
365
+ });
366
+ var paragraphElementSchema = baseElementSchema.extend({
367
+ type: import_zod.z.literal("paragraph" /* PARAGRAPH */),
368
+ text: import_zod.z.string().min(1).max(5e3)
369
+ });
370
+ var listElementSchema = baseElementSchema.extend({
371
+ type: import_zod.z.literal("list" /* LIST */),
372
+ items: import_zod.z.array(import_zod.z.string().min(1).max(500)).min(1).max(100),
373
+ listType: import_zod.z.nativeEnum(ListType)
374
+ });
375
+ var dynamicTextElementSchema = baseElementSchema.extend({
376
+ type: import_zod.z.literal("dynamic_text" /* DYNAMIC_TEXT */),
377
+ text: import_zod.z.string().min(1).max(5e3)
378
+ });
379
+ var binaryChoiceElementSchema = baseElementSchema.extend({
380
+ type: import_zod.z.literal("binary_choice" /* BINARY_CHOICE */),
381
+ question: import_zod.z.string().min(1).max(500),
382
+ defaultValue: import_zod.z.boolean().optional()
383
+ });
384
+ var multipleChoiceElementSchema = baseElementSchema.extend({
385
+ type: import_zod.z.literal("multiple_choice" /* MULTIPLE_CHOICE */),
386
+ question: import_zod.z.string().min(1).max(500),
387
+ options: import_zod.z.array(import_zod.z.string().min(1).max(200)).min(2).max(50),
388
+ defaultValues: import_zod.z.array(import_zod.z.string()).optional()
389
+ });
390
+ var singleChoiceElementSchema = baseElementSchema.extend({
391
+ type: import_zod.z.literal("single_choice" /* SINGLE_CHOICE */),
392
+ question: import_zod.z.string().min(1).max(500),
393
+ options: import_zod.z.array(import_zod.z.string().min(1).max(200)).min(2).max(50),
394
+ defaultValue: import_zod.z.string().optional()
395
+ });
396
+ var ratingScaleElementSchema = baseElementSchema.extend({
458
397
  type: import_zod.z.literal("rating_scale" /* RATING_SCALE */),
459
398
  question: import_zod.z.string().min(1).max(500),
460
399
  min: import_zod.z.number().int().min(0).max(10),
@@ -585,392 +524,440 @@ var updateFilledDocumentDataSchema = import_zod.z.object({
585
524
  status: filledDocumentStatusSchema.optional()
586
525
  });
587
526
 
588
- // src/backoffice/validations/schemas.ts
589
- var blockingConditionSchema = import_zod2.z.nativeEnum(BlockingCondition);
590
- var contraindicationSchema = import_zod2.z.nativeEnum(Contraindication);
591
- var treatmentBenefitSchema = import_zod2.z.nativeEnum(TreatmentBenefit);
592
- var procedureFamilySchema = import_zod2.z.nativeEnum(ProcedureFamily);
593
- var timeUnitSchema = import_zod2.z.nativeEnum(TimeUnit);
594
- var requirementTypeSchema = import_zod2.z.nativeEnum(RequirementType);
595
- var certificationLevelSchema = import_zod2.z.nativeEnum(CertificationLevel);
596
- var certificationSpecialtySchema = import_zod2.z.nativeEnum(
597
- CertificationSpecialty
598
- );
599
- var certificationRequirementSchema = import_zod2.z.object({
600
- minimumLevel: certificationLevelSchema,
601
- requiredSpecialties: import_zod2.z.array(certificationSpecialtySchema).max(5, "Maximum 5 specialties allowed").optional()
602
- });
603
- var timeframeSchema = import_zod2.z.object({
604
- duration: import_zod2.z.number().min(1, "Duration must be positive"),
605
- unit: timeUnitSchema,
606
- notifyAt: import_zod2.z.array(import_zod2.z.number()).min(1, "At least one notification point is required")
607
- });
608
- var requirementSchema = import_zod2.z.object({
609
- name: import_zod2.z.string().min(1, "Name is required").max(100, "Name is too long"),
610
- description: import_zod2.z.string().min(1, "Description is required"),
611
- type: requirementTypeSchema,
612
- timeframe: timeframeSchema,
613
- importance: import_zod2.z.enum(["low", "medium", "high"]),
614
- isActive: import_zod2.z.boolean().default(true)
615
- });
616
- var technologyRequirementsSchema = import_zod2.z.object({
617
- pre: import_zod2.z.array(requirementSchema),
618
- post: import_zod2.z.array(requirementSchema)
619
- });
620
- var technologySchema = import_zod2.z.object({
621
- name: import_zod2.z.string().min(1, "Name is required").max(100, "Name is too long"),
622
- description: import_zod2.z.string().max(1e3, "Description is too long").optional(),
623
- technicalDetails: import_zod2.z.string().max(2e3, "Technical details are too long").optional(),
624
- family: procedureFamilySchema,
625
- categoryId: import_zod2.z.string().min(1, "Category ID is required"),
626
- subcategoryId: import_zod2.z.string().min(1, "Subcategory ID is required"),
627
- requirements: technologyRequirementsSchema.default({
628
- pre: [],
629
- post: []
630
- }),
631
- blockingConditions: import_zod2.z.array(blockingConditionSchema),
632
- contraindications: import_zod2.z.array(contraindicationSchema),
633
- documentationTemplates: import_zod2.z.array(documentTemplateSchema),
634
- benefits: import_zod2.z.array(treatmentBenefitSchema),
635
- certificationRequirement: certificationRequirementSchema,
636
- isActive: import_zod2.z.boolean().default(true)
637
- });
638
- var categorySchema = import_zod2.z.object({
639
- name: import_zod2.z.string().min(1, "Name is required").max(100, "Name is too long"),
640
- description: import_zod2.z.string().optional(),
641
- family: procedureFamilySchema,
642
- isActive: import_zod2.z.boolean().default(true)
643
- });
644
- var subcategorySchema = import_zod2.z.object({
645
- name: import_zod2.z.string().min(1, "Name is required").max(100, "Name is too long"),
646
- description: import_zod2.z.string().optional(),
647
- categoryId: import_zod2.z.string().min(1, "Category ID is required"),
648
- isActive: import_zod2.z.boolean().default(true)
649
- });
650
- var categoryUpdateSchema = categorySchema.partial();
651
- var subcategoryUpdateSchema = subcategorySchema.partial();
652
- var technologyUpdateSchema = technologySchema.partial();
653
- var requirementUpdateSchema = requirementSchema.partial();
654
-
655
- // src/backoffice/services/category.service.ts
656
- var import_firestore = require("firebase/firestore");
657
-
658
- // src/services/base.service.ts
659
- var import_storage = require("firebase/storage");
660
- var BaseService = class {
661
- constructor(db, auth, app) {
662
- this.db = db;
663
- this.auth = auth;
664
- this.app = app;
665
- this.storage = (0, import_storage.getStorage)(app);
666
- }
667
- /**
668
- * Generiše jedinstveni ID za dokumente
669
- * Format: xxxxxxxxxxxx-timestamp
670
- * Gde je x random karakter (broj ili slovo)
671
- */
672
- generateId() {
673
- const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
674
- const timestamp = Date.now().toString(36);
675
- const randomPart = Array.from(
676
- { length: 12 },
677
- () => chars.charAt(Math.floor(Math.random() * chars.length))
678
- ).join("");
679
- return `${randomPart}-${timestamp}`;
680
- }
681
- };
682
-
683
- // src/backoffice/services/category.service.ts
684
- var CategoryService = class extends BaseService {
685
- /**
686
- * Referenca na Firestore kolekciju kategorija
687
- */
688
- get categoriesRef() {
689
- return (0, import_firestore.collection)(this.db, CATEGORIES_COLLECTION);
527
+ // src/services/documentation-templates/documentation-template.service.ts
528
+ var DocumentationTemplateService = class extends BaseService {
529
+ constructor() {
530
+ super(...arguments);
531
+ this.collectionRef = (0, import_firestore3.collection)(
532
+ this.db,
533
+ DOCUMENTATION_TEMPLATES_COLLECTION
534
+ );
690
535
  }
691
536
  /**
692
- * Kreira novu kategoriju u sistemu
693
- * @param category - Podaci za novu kategoriju
694
- * @returns Kreirana kategorija sa generisanim ID-em
537
+ * Create a new document template
538
+ * @param data - Template data
539
+ * @param userId - ID of the user creating the template
540
+ * @returns The created template
695
541
  */
696
- async create(category) {
697
- const now = /* @__PURE__ */ new Date();
698
- const newCategory = {
699
- ...category,
542
+ async createTemplate(data, userId) {
543
+ const validatedData = createDocumentTemplateSchema.parse(data);
544
+ const templateId = this.generateId();
545
+ const elementsWithIds = validatedData.elements.map((element) => ({
546
+ ...element,
547
+ id: this.generateId()
548
+ }));
549
+ const now = Date.now();
550
+ const template = {
551
+ id: templateId,
552
+ title: validatedData.title,
553
+ description: validatedData.description,
554
+ elements: elementsWithIds,
700
555
  createdAt: now,
701
556
  updatedAt: now,
702
- isActive: true
557
+ createdBy: userId,
558
+ version: 1,
559
+ isActive: true,
560
+ tags: validatedData.tags || [],
561
+ isUserForm: validatedData.isUserForm || false,
562
+ isRequired: validatedData.isRequired || false,
563
+ sortingOrder: validatedData.sortingOrder || 0
703
564
  };
704
- const docRef = await (0, import_firestore.addDoc)(this.categoriesRef, newCategory);
705
- return { id: docRef.id, ...newCategory };
565
+ const docRef = (0, import_firestore3.doc)(this.collectionRef, templateId);
566
+ await (0, import_firestore3.setDoc)(docRef, template);
567
+ return template;
706
568
  }
707
569
  /**
708
- * Vraća sve aktivne kategorije
709
- * @returns Lista aktivnih kategorija
570
+ * Get a document template by ID
571
+ * @param templateId - ID of the template to retrieve
572
+ * @param version - Optional version number to retrieve (defaults to latest version)
573
+ * @returns The template or null if not found
710
574
  */
711
- async getAll() {
712
- const q = (0, import_firestore.query)(this.categoriesRef, (0, import_firestore.where)("isActive", "==", true));
713
- const snapshot = await (0, import_firestore.getDocs)(q);
714
- return snapshot.docs.map(
715
- (doc10) => ({
716
- id: doc10.id,
717
- ...doc10.data()
718
- })
719
- );
575
+ async getTemplateById(templateId, version) {
576
+ const docRef = (0, import_firestore3.doc)(this.collectionRef, templateId);
577
+ const docSnap = await (0, import_firestore3.getDoc)(docRef);
578
+ if (!docSnap.exists()) {
579
+ return null;
580
+ }
581
+ const currentTemplate = docSnap.data();
582
+ if (version === void 0) {
583
+ return currentTemplate;
584
+ }
585
+ if (currentTemplate.version === version) {
586
+ return currentTemplate;
587
+ }
588
+ try {
589
+ const versionTemplate = await this.getTemplateVersion(
590
+ templateId,
591
+ version
592
+ );
593
+ if (versionTemplate) {
594
+ return versionTemplate;
595
+ }
596
+ } catch (error) {
597
+ console.error(`Error getting template version ${version}:`, error);
598
+ }
599
+ return null;
720
600
  }
721
601
  /**
722
- * Vraća sve aktivne kategorije za određenu familiju procedura
723
- * @param family - Familija procedura (aesthetics/surgery)
724
- * @returns Lista kategorija koje pripadaju traženoj familiji
602
+ * Update an existing document template
603
+ * @param templateId - ID of the template to update
604
+ * @param data - Updated template data
605
+ * @returns The updated template
725
606
  */
726
- async getAllByFamily(family) {
727
- const q = (0, import_firestore.query)(
728
- this.categoriesRef,
729
- (0, import_firestore.where)("family", "==", family),
730
- (0, import_firestore.where)("isActive", "==", true)
607
+ async updateTemplate(templateId, data) {
608
+ var _a, _b, _c;
609
+ const validatedData = updateDocumentTemplateSchema.parse(data);
610
+ console.log("Validated data", validatedData);
611
+ const template = await this.getTemplateById(templateId);
612
+ if (!template) {
613
+ throw new Error(`Template with ID ${templateId} not found`);
614
+ }
615
+ const versionsCollectionRef = (0, import_firestore3.collection)(
616
+ this.db,
617
+ `${DOCUMENTATION_TEMPLATES_COLLECTION}/${templateId}/versions`
731
618
  );
732
- const snapshot = await (0, import_firestore.getDocs)(q);
733
- return snapshot.docs.map(
734
- (doc10) => ({
735
- id: doc10.id,
736
- ...doc10.data()
737
- })
619
+ const versionDocRef = (0, import_firestore3.doc)(
620
+ versionsCollectionRef,
621
+ template.version.toString()
738
622
  );
739
- }
740
- /**
741
- * Ažurira postojeću kategoriju
742
- * @param id - ID kategorije koja se ažurira
743
- * @param category - Novi podaci za kategoriju
744
- * @returns Ažurirana kategorija
745
- */
746
- async update(id, category) {
747
- const updateData = {
748
- ...category,
749
- updatedAt: /* @__PURE__ */ new Date()
623
+ await (0, import_firestore3.setDoc)(versionDocRef, template);
624
+ let updatedElements = template.elements;
625
+ if (validatedData.elements) {
626
+ updatedElements = validatedData.elements.map((element) => ({
627
+ ...element,
628
+ id: element.id || this.generateId()
629
+ }));
630
+ }
631
+ const updatePayload = {
632
+ elements: updatedElements,
633
+ updatedAt: Date.now(),
634
+ version: template.version + 1
750
635
  };
751
- const docRef = (0, import_firestore.doc)(this.categoriesRef, id);
752
- await (0, import_firestore.updateDoc)(docRef, updateData);
753
- return this.getById(id);
754
- }
755
- /**
756
- * Soft delete kategorije (postavlja isActive na false)
757
- * @param id - ID kategorije koja se briše
758
- */
759
- async delete(id) {
760
- await this.update(id, { isActive: false });
636
+ if (validatedData.title !== void 0)
637
+ updatePayload.title = validatedData.title;
638
+ if (validatedData.description !== void 0)
639
+ updatePayload.description = validatedData.description;
640
+ if (validatedData.isActive !== void 0)
641
+ updatePayload.isActive = validatedData.isActive;
642
+ if (validatedData.tags !== void 0)
643
+ updatePayload.tags = validatedData.tags;
644
+ updatePayload.isUserForm = (_a = validatedData.isUserForm) != null ? _a : false;
645
+ updatePayload.isRequired = (_b = validatedData.isRequired) != null ? _b : false;
646
+ updatePayload.sortingOrder = (_c = validatedData.sortingOrder) != null ? _c : 0;
647
+ const docRef = (0, import_firestore3.doc)(this.collectionRef, templateId);
648
+ console.log("Update payload", updatePayload);
649
+ await (0, import_firestore3.updateDoc)(docRef, updatePayload);
650
+ return { ...template, ...updatePayload };
761
651
  }
762
652
  /**
763
- * Vraća kategoriju po ID-u
764
- * @param id - ID tražene kategorije
765
- * @returns Kategorija ili null ako ne postoji
653
+ * Get a specific version of a template
654
+ * @param templateId - ID of the template
655
+ * @param versionNumber - Version number to retrieve
656
+ * @returns The template version or null if not found
766
657
  */
767
- async getById(id) {
768
- const docRef = (0, import_firestore.doc)(this.categoriesRef, id);
769
- const docSnap = await (0, import_firestore.getDoc)(docRef);
770
- if (!docSnap.exists()) return null;
771
- return {
772
- id: docSnap.id,
773
- ...docSnap.data()
774
- };
658
+ async getTemplateVersion(templateId, versionNumber) {
659
+ const versionDocRef = (0, import_firestore3.doc)(
660
+ this.db,
661
+ `${DOCUMENTATION_TEMPLATES_COLLECTION}/${templateId}/versions/${versionNumber}`
662
+ );
663
+ const versionDocSnap = await (0, import_firestore3.getDoc)(versionDocRef);
664
+ if (!versionDocSnap.exists()) {
665
+ return null;
666
+ }
667
+ return versionDocSnap.data();
775
668
  }
776
- };
777
-
778
- // src/backoffice/services/subcategory.service.ts
779
- var import_firestore2 = require("firebase/firestore");
780
- var SubcategoryService = class extends BaseService {
781
669
  /**
782
- * Vraća referencu na Firestore kolekciju podkategorija za određenu kategoriju
783
- * @param categoryId - ID roditeljske kategorije
670
+ * Get all versions of a template
671
+ * @param templateId - ID of the template
672
+ * @returns Array of template versions
784
673
  */
785
- getSubcategoriesRef(categoryId) {
786
- return (0, import_firestore2.collection)(
674
+ async getTemplateOldVersions(templateId) {
675
+ const versionsCollectionRef = (0, import_firestore3.collection)(
787
676
  this.db,
788
- CATEGORIES_COLLECTION,
789
- categoryId,
790
- SUBCATEGORIES_COLLECTION
677
+ `${DOCUMENTATION_TEMPLATES_COLLECTION}/${templateId}/versions`
791
678
  );
679
+ const q = (0, import_firestore3.query)(versionsCollectionRef, (0, import_firestore3.orderBy)("version", "desc"));
680
+ const querySnapshot = await (0, import_firestore3.getDocs)(q);
681
+ const versions = [];
682
+ querySnapshot.forEach((doc10) => {
683
+ versions.push(doc10.data());
684
+ });
685
+ return versions;
792
686
  }
793
687
  /**
794
- * Kreira novu podkategoriju u okviru kategorije
795
- * @param categoryId - ID kategorije kojoj će pripadati nova podkategorija
796
- * @param subcategory - Podaci za novu podkategoriju
797
- * @returns Kreirana podkategorija sa generisanim ID-em
688
+ * Delete a document template
689
+ * @param templateId - ID of the template to delete
798
690
  */
799
- async create(categoryId, subcategory) {
800
- const now = /* @__PURE__ */ new Date();
801
- const newSubcategory = {
802
- ...subcategory,
803
- categoryId,
804
- createdAt: now,
805
- updatedAt: now,
806
- isActive: true
807
- };
808
- const docRef = await (0, import_firestore2.addDoc)(
809
- this.getSubcategoriesRef(categoryId),
810
- newSubcategory
811
- );
812
- return { id: docRef.id, ...newSubcategory };
691
+ async deleteTemplate(templateId) {
692
+ const docRef = (0, import_firestore3.doc)(this.collectionRef, templateId);
693
+ await (0, import_firestore3.deleteDoc)(docRef);
813
694
  }
814
695
  /**
815
- * Vraća sve aktivne podkategorije za određenu kategoriju
816
- * @param categoryId - ID kategorije čije podkategorije tražimo
817
- * @returns Lista aktivnih podkategorija
696
+ * Get all active templates
697
+ * @param pageSize - Number of templates to retrieve
698
+ * @param lastDoc - Last document from previous page for pagination
699
+ * @returns Array of templates and the last document for pagination
818
700
  */
819
- async getAllByCategoryId(categoryId) {
820
- const q = (0, import_firestore2.query)(
821
- this.getSubcategoriesRef(categoryId),
822
- (0, import_firestore2.where)("isActive", "==", true)
823
- );
824
- const snapshot = await (0, import_firestore2.getDocs)(q);
825
- return snapshot.docs.map(
826
- (doc10) => ({
827
- id: doc10.id,
828
- ...doc10.data()
829
- })
701
+ async getActiveTemplates(pageSize = 20, lastDoc) {
702
+ let q = (0, import_firestore3.query)(
703
+ this.collectionRef,
704
+ (0, import_firestore3.where)("isActive", "==", true),
705
+ (0, import_firestore3.orderBy)("updatedAt", "desc"),
706
+ (0, import_firestore3.limit)(pageSize)
830
707
  );
708
+ if (lastDoc) {
709
+ q = (0, import_firestore3.query)(q, (0, import_firestore3.startAfter)(lastDoc));
710
+ }
711
+ const querySnapshot = await (0, import_firestore3.getDocs)(q);
712
+ const templates = [];
713
+ let lastVisible = null;
714
+ querySnapshot.forEach((doc10) => {
715
+ templates.push(doc10.data());
716
+ lastVisible = doc10;
717
+ });
718
+ return {
719
+ templates,
720
+ lastDoc: lastVisible
721
+ };
831
722
  }
832
723
  /**
833
- * Ažurira postojeću podkategoriju
834
- * @param categoryId - ID kategorije kojoj pripada podkategorija
835
- * @param subcategoryId - ID podkategorije koja se ažurira
836
- * @param subcategory - Novi podaci za podkategoriju
837
- * @returns Ažurirana podkategorija
724
+ * Get templates by tags
725
+ * @param tags - Tags to filter by
726
+ * @param pageSize - Number of templates to retrieve
727
+ * @param lastDoc - Last document from previous page for pagination
728
+ * @returns Array of templates and the last document for pagination
838
729
  */
839
- async update(categoryId, subcategoryId, subcategory) {
840
- const updateData = {
841
- ...subcategory,
842
- updatedAt: /* @__PURE__ */ new Date()
730
+ async getTemplatesByTags(tags, pageSize = 20, lastDoc) {
731
+ let q = (0, import_firestore3.query)(
732
+ this.collectionRef,
733
+ (0, import_firestore3.where)("isActive", "==", true),
734
+ (0, import_firestore3.where)("tags", "array-contains-any", tags),
735
+ (0, import_firestore3.orderBy)("updatedAt", "desc"),
736
+ (0, import_firestore3.limit)(pageSize)
737
+ );
738
+ if (lastDoc) {
739
+ q = (0, import_firestore3.query)(q, (0, import_firestore3.startAfter)(lastDoc));
740
+ }
741
+ const querySnapshot = await (0, import_firestore3.getDocs)(q);
742
+ const templates = [];
743
+ let lastVisible = null;
744
+ querySnapshot.forEach((doc10) => {
745
+ templates.push(doc10.data());
746
+ lastVisible = doc10;
747
+ });
748
+ return {
749
+ templates,
750
+ lastDoc: lastVisible
843
751
  };
844
- const docRef = (0, import_firestore2.doc)(this.getSubcategoriesRef(categoryId), subcategoryId);
845
- await (0, import_firestore2.updateDoc)(docRef, updateData);
846
- return this.getById(categoryId, subcategoryId);
847
752
  }
848
753
  /**
849
- * Soft delete podkategorije (postavlja isActive na false)
850
- * @param categoryId - ID kategorije kojoj pripada podkategorija
851
- * @param subcategoryId - ID podkategorije koja se briše
754
+ * Get templates created by a specific user
755
+ * @param userId - ID of the user who created the templates
756
+ * @param pageSize - Number of templates to retrieve
757
+ * @param lastDoc - Last document from previous page for pagination
758
+ * @returns Array of templates and the last document for pagination
852
759
  */
853
- async delete(categoryId, subcategoryId) {
854
- await this.update(categoryId, subcategoryId, { isActive: false });
760
+ async getTemplatesByCreator(userId, pageSize = 20, lastDoc) {
761
+ let q = (0, import_firestore3.query)(
762
+ this.collectionRef,
763
+ (0, import_firestore3.where)("createdBy", "==", userId),
764
+ (0, import_firestore3.orderBy)("updatedAt", "desc"),
765
+ (0, import_firestore3.limit)(pageSize)
766
+ );
767
+ if (lastDoc) {
768
+ q = (0, import_firestore3.query)(q, (0, import_firestore3.startAfter)(lastDoc));
769
+ }
770
+ const querySnapshot = await (0, import_firestore3.getDocs)(q);
771
+ const templates = [];
772
+ let lastVisible = null;
773
+ querySnapshot.forEach((doc10) => {
774
+ templates.push(doc10.data());
775
+ lastVisible = doc10;
776
+ });
777
+ return {
778
+ templates,
779
+ lastDoc: lastVisible
780
+ };
855
781
  }
856
782
  /**
857
- * Vraća podkategoriju po ID-u
858
- * @param categoryId - ID kategorije kojoj pripada podkategorija
859
- * @param subcategoryId - ID tražene podkategorije
860
- * @returns Podkategorija ili null ako ne postoji
783
+ * Get all templates for selection with optional filtering
784
+ * @param options - Filtering options
785
+ * @returns Array of templates
861
786
  */
862
- async getById(categoryId, subcategoryId) {
863
- const docRef = (0, import_firestore2.doc)(this.getSubcategoriesRef(categoryId), subcategoryId);
864
- const docSnap = await (0, import_firestore2.getDoc)(docRef);
865
- if (!docSnap.exists()) return null;
866
- return {
867
- id: docSnap.id,
868
- ...docSnap.data()
869
- };
787
+ async getAllTemplatesForSelection(options) {
788
+ let q = (0, import_firestore3.query)(
789
+ this.collectionRef,
790
+ (0, import_firestore3.where)("isActive", "==", true),
791
+ (0, import_firestore3.orderBy)("updatedAt", "desc")
792
+ );
793
+ if ((options == null ? void 0 : options.isUserForm) !== void 0) {
794
+ q = (0, import_firestore3.query)(q, (0, import_firestore3.where)("isUserForm", "==", options.isUserForm));
795
+ }
796
+ if ((options == null ? void 0 : options.isRequired) !== void 0) {
797
+ q = (0, import_firestore3.query)(q, (0, import_firestore3.where)("isRequired", "==", options.isRequired));
798
+ }
799
+ const querySnapshot = await (0, import_firestore3.getDocs)(q);
800
+ const templates = [];
801
+ querySnapshot.forEach((doc10) => {
802
+ templates.push(doc10.data());
803
+ });
804
+ return templates;
870
805
  }
871
806
  };
872
807
 
873
- // src/backoffice/services/technology.service.ts
874
- var import_firestore3 = require("firebase/firestore");
875
- var DEFAULT_CERTIFICATION_REQUIREMENT2 = {
876
- minimumLevel: "aesthetician" /* AESTHETICIAN */,
877
- requiredSpecialties: []
878
- };
879
- var TechnologyService = class extends BaseService {
808
+ // src/services/documentation-templates/filled-document.service.ts
809
+ var import_firestore6 = require("firebase/firestore");
810
+
811
+ // src/services/media/media.service.ts
812
+ var import_firestore4 = require("firebase/firestore");
813
+ var import_storage2 = require("firebase/storage");
814
+ var import_firestore5 = require("firebase/firestore");
815
+
816
+ // src/backoffice/services/documentation-template.service.ts
817
+ var DocumentationTemplateService2 = class {
880
818
  /**
881
- * Vraća referencu na Firestore kolekciju tehnologija
819
+ * Constructor for DocumentationTemplateService
820
+ * @param db - Firestore instance
821
+ * @param auth - Firebase Auth instance
822
+ * @param app - Firebase App instance
882
823
  */
883
- getTechnologiesRef() {
884
- return (0, import_firestore3.collection)(this.db, TECHNOLOGIES_COLLECTION);
824
+ constructor(db, auth, app) {
825
+ this.apiService = new DocumentationTemplateService(db, auth, app);
885
826
  }
886
827
  /**
887
- * Kreira novu tehnologiju
888
- * @param technology - Podaci za novu tehnologiju
889
- * @returns Kreirana tehnologija sa generisanim ID-em
828
+ * Create a new document template
829
+ * @param data - Template data
830
+ * @param userId - ID of the user creating the template
831
+ * @returns The created template
890
832
  */
891
- async create(technology) {
892
- const now = /* @__PURE__ */ new Date();
893
- const newTechnology = {
894
- ...technology,
895
- createdAt: now,
896
- updatedAt: now,
897
- isActive: true,
898
- requirements: technology.requirements || {
899
- pre: [],
900
- post: []
901
- },
902
- blockingConditions: technology.blockingConditions || [],
903
- contraindications: technology.contraindications || [],
904
- benefits: technology.benefits || [],
905
- certificationRequirement: technology.certificationRequirement || DEFAULT_CERTIFICATION_REQUIREMENT2
906
- };
907
- const docRef = await (0, import_firestore3.addDoc)(this.getTechnologiesRef(), newTechnology);
908
- return { id: docRef.id, ...newTechnology };
833
+ async createTemplate(data, userId) {
834
+ return this.apiService.createTemplate(data, userId);
909
835
  }
910
836
  /**
911
- * Vraća sve aktivne tehnologije
912
- * @returns Lista aktivnih tehnologija
837
+ * Get a document template by ID
838
+ * @param templateId - ID of the template to retrieve
839
+ * @param version - Optional version number to retrieve (defaults to latest version)
840
+ * @returns The template or null if not found
913
841
  */
914
- async getAll() {
915
- const q = (0, import_firestore3.query)(this.getTechnologiesRef(), (0, import_firestore3.where)("isActive", "==", true));
916
- const snapshot = await (0, import_firestore3.getDocs)(q);
917
- return snapshot.docs.map(
918
- (doc10) => ({
919
- id: doc10.id,
920
- ...doc10.data()
921
- })
922
- );
842
+ async getTemplateById(templateId, version) {
843
+ return this.apiService.getTemplateById(templateId, version);
923
844
  }
924
845
  /**
925
- * Vraća sve aktivne tehnologije za određenu familiju
926
- * @param family - Familija procedura
927
- * @returns Lista aktivnih tehnologija
846
+ * Update an existing document template
847
+ * @param templateId - ID of the template to update
848
+ * @param data - Updated template data
849
+ * @returns The updated template
928
850
  */
929
- async getAllByFamily(family) {
930
- const q = (0, import_firestore3.query)(
931
- this.getTechnologiesRef(),
932
- (0, import_firestore3.where)("isActive", "==", true),
933
- (0, import_firestore3.where)("family", "==", family)
934
- );
935
- const snapshot = await (0, import_firestore3.getDocs)(q);
936
- return snapshot.docs.map(
937
- (doc10) => ({
938
- id: doc10.id,
939
- ...doc10.data()
940
- })
941
- );
851
+ async updateTemplate(templateId, data) {
852
+ return this.apiService.updateTemplate(templateId, data);
942
853
  }
943
854
  /**
944
- * Vraća sve aktivne tehnologije za određenu kategoriju
945
- * @param categoryId - ID kategorije
946
- * @returns Lista aktivnih tehnologija
855
+ * Delete a document template
856
+ * @param templateId - ID of the template to delete
947
857
  */
948
- async getAllByCategoryId(categoryId) {
949
- const q = (0, import_firestore3.query)(
950
- this.getTechnologiesRef(),
951
- (0, import_firestore3.where)("isActive", "==", true),
952
- (0, import_firestore3.where)("categoryId", "==", categoryId)
858
+ async deleteTemplate(templateId) {
859
+ return this.apiService.deleteTemplate(templateId);
860
+ }
861
+ /**
862
+ * Get all active templates
863
+ * @param pageSize - Number of templates to retrieve
864
+ * @param lastDoc - Last document from previous page for pagination
865
+ * @returns Array of templates and the last document for pagination
866
+ */
867
+ async getActiveTemplates(pageSize = 20, lastDoc) {
868
+ return this.apiService.getActiveTemplates(pageSize, lastDoc);
869
+ }
870
+ /**
871
+ * Get templates by tags
872
+ * @param tags - Tags to filter by
873
+ * @param pageSize - Number of templates to retrieve
874
+ * @param lastDoc - Last document from previous page for pagination
875
+ * @returns Array of templates and the last document for pagination
876
+ */
877
+ async getTemplatesByTags(tags, pageSize = 20, lastDoc) {
878
+ return this.apiService.getTemplatesByTags(tags, pageSize, lastDoc);
879
+ }
880
+ /**
881
+ * Get templates created by a specific user
882
+ * @param userId - ID of the user who created the templates
883
+ * @param pageSize - Number of templates to retrieve
884
+ * @param lastDoc - Last document from previous page for pagination
885
+ * @returns Array of templates and the last document for pagination
886
+ */
887
+ async getTemplatesByCreator(userId, pageSize = 20, lastDoc) {
888
+ return this.apiService.getTemplatesByCreator(userId, pageSize, lastDoc);
889
+ }
890
+ /**
891
+ * Get a specific version of a template
892
+ * @param templateId - ID of the template
893
+ * @param versionNumber - Version number to retrieve
894
+ * @returns The template version or null if not found
895
+ */
896
+ async getTemplateVersion(templateId, versionNumber) {
897
+ return this.apiService.getTemplateVersion(templateId, versionNumber);
898
+ }
899
+ /**
900
+ * Get all versions of a template
901
+ * @param templateId - ID of the template
902
+ * @returns Array of template versions
903
+ */
904
+ async getTemplateVersions(templateId) {
905
+ return this.apiService.getTemplateOldVersions(templateId);
906
+ }
907
+ };
908
+
909
+ // src/backoffice/services/product.service.ts
910
+ var import_firestore7 = require("firebase/firestore");
911
+
912
+ // src/backoffice/types/product.types.ts
913
+ var PRODUCTS_COLLECTION = "products";
914
+
915
+ // src/backoffice/types/technology.types.ts
916
+ var TECHNOLOGIES_COLLECTION = "technologies";
917
+
918
+ // src/backoffice/services/product.service.ts
919
+ var ProductService = class extends BaseService {
920
+ /**
921
+ * Gets reference to products collection under a technology
922
+ * @param technologyId - ID of the technology
923
+ * @returns Firestore collection reference
924
+ */
925
+ getProductsRef(technologyId) {
926
+ return (0, import_firestore7.collection)(
927
+ this.db,
928
+ TECHNOLOGIES_COLLECTION,
929
+ technologyId,
930
+ PRODUCTS_COLLECTION
953
931
  );
954
- const snapshot = await (0, import_firestore3.getDocs)(q);
955
- return snapshot.docs.map(
956
- (doc10) => ({
957
- id: doc10.id,
958
- ...doc10.data()
959
- })
932
+ }
933
+ /**
934
+ * Creates a new product under technology
935
+ */
936
+ async create(technologyId, brandId, product) {
937
+ const now = /* @__PURE__ */ new Date();
938
+ const newProduct = {
939
+ ...product,
940
+ brandId,
941
+ technologyId,
942
+ createdAt: now,
943
+ updatedAt: now,
944
+ isActive: true
945
+ };
946
+ const productRef = await (0, import_firestore7.addDoc)(
947
+ this.getProductsRef(technologyId),
948
+ newProduct
960
949
  );
950
+ return { id: productRef.id, ...newProduct };
961
951
  }
962
952
  /**
963
- * Vraća sve aktivne tehnologije za određenu podkategoriju
964
- * @param subcategoryId - ID podkategorije
965
- * @returns Lista aktivnih tehnologija
953
+ * Gets all products for a technology
966
954
  */
967
- async getAllBySubcategoryId(subcategoryId) {
968
- const q = (0, import_firestore3.query)(
969
- this.getTechnologiesRef(),
970
- (0, import_firestore3.where)("isActive", "==", true),
971
- (0, import_firestore3.where)("subcategoryId", "==", subcategoryId)
955
+ async getAllByTechnology(technologyId) {
956
+ const q = (0, import_firestore7.query)(
957
+ this.getProductsRef(technologyId),
958
+ (0, import_firestore7.where)("isActive", "==", true)
972
959
  );
973
- const snapshot = await (0, import_firestore3.getDocs)(q);
960
+ const snapshot = await (0, import_firestore7.getDocs)(q);
974
961
  return snapshot.docs.map(
975
962
  (doc10) => ({
976
963
  id: doc10.id,
@@ -979,348 +966,345 @@ var TechnologyService = class extends BaseService {
979
966
  );
980
967
  }
981
968
  /**
982
- * Ažurira postojeću tehnologiju
983
- * @param technologyId - ID tehnologije
984
- * @param technology - Novi podaci za tehnologiju
985
- * @returns Ažurirana tehnologija
969
+ * Gets all products for a brand by filtering through all technologies
986
970
  */
987
- async update(technologyId, technology) {
971
+ async getAllByBrand(brandId) {
972
+ const allTechnologiesRef = (0, import_firestore7.collection)(this.db, TECHNOLOGIES_COLLECTION);
973
+ const technologiesSnapshot = await (0, import_firestore7.getDocs)(allTechnologiesRef);
974
+ const products = [];
975
+ for (const techDoc of technologiesSnapshot.docs) {
976
+ const q = (0, import_firestore7.query)(
977
+ this.getProductsRef(techDoc.id),
978
+ (0, import_firestore7.where)("brandId", "==", brandId),
979
+ (0, import_firestore7.where)("isActive", "==", true)
980
+ );
981
+ const snapshot = await (0, import_firestore7.getDocs)(q);
982
+ products.push(
983
+ ...snapshot.docs.map(
984
+ (doc10) => ({
985
+ id: doc10.id,
986
+ ...doc10.data()
987
+ })
988
+ )
989
+ );
990
+ }
991
+ return products;
992
+ }
993
+ /**
994
+ * Updates a product
995
+ */
996
+ async update(technologyId, productId, product) {
988
997
  const updateData = {
989
- ...technology,
998
+ ...product,
990
999
  updatedAt: /* @__PURE__ */ new Date()
991
1000
  };
992
- const docRef = (0, import_firestore3.doc)(this.getTechnologiesRef(), technologyId);
993
- await (0, import_firestore3.updateDoc)(docRef, updateData);
994
- return this.getById(technologyId);
1001
+ const docRef = (0, import_firestore7.doc)(this.getProductsRef(technologyId), productId);
1002
+ await (0, import_firestore7.updateDoc)(docRef, updateData);
1003
+ return this.getById(technologyId, productId);
995
1004
  }
996
1005
  /**
997
- * Soft delete tehnologije (postavlja isActive na false)
998
- * @param technologyId - ID tehnologije koja se briše
1006
+ * Soft deletes a product
999
1007
  */
1000
- async delete(technologyId) {
1001
- await this.update(technologyId, {
1008
+ async delete(technologyId, productId) {
1009
+ await this.update(technologyId, productId, {
1002
1010
  isActive: false
1003
1011
  });
1004
1012
  }
1005
1013
  /**
1006
- * Vraća tehnologiju po ID-u
1007
- * @param technologyId - ID tražene tehnologije
1008
- * @returns Tehnologija ili null ako ne postoji
1014
+ * Gets a product by ID
1009
1015
  */
1010
- async getById(technologyId) {
1011
- const docRef = (0, import_firestore3.doc)(this.getTechnologiesRef(), technologyId);
1012
- const docSnap = await (0, import_firestore3.getDoc)(docRef);
1016
+ async getById(technologyId, productId) {
1017
+ const docRef = (0, import_firestore7.doc)(this.getProductsRef(technologyId), productId);
1018
+ const docSnap = await (0, import_firestore7.getDoc)(docRef);
1013
1019
  if (!docSnap.exists()) return null;
1014
1020
  return {
1015
1021
  id: docSnap.id,
1016
1022
  ...docSnap.data()
1017
1023
  };
1018
1024
  }
1025
+ };
1026
+
1027
+ // src/backoffice/services/requirement.service.ts
1028
+ var import_firestore8 = require("firebase/firestore");
1029
+
1030
+ // src/backoffice/types/requirement.types.ts
1031
+ var TimeUnit = /* @__PURE__ */ ((TimeUnit2) => {
1032
+ TimeUnit2["HOURS"] = "hours";
1033
+ TimeUnit2["DAYS"] = "days";
1034
+ return TimeUnit2;
1035
+ })(TimeUnit || {});
1036
+ var RequirementType = /* @__PURE__ */ ((RequirementType3) => {
1037
+ RequirementType3["PRE"] = "pre";
1038
+ RequirementType3["POST"] = "post";
1039
+ return RequirementType3;
1040
+ })(RequirementType || {});
1041
+ var REQUIREMENTS_COLLECTION = "backoffice_requirements";
1042
+
1043
+ // src/backoffice/services/requirement.service.ts
1044
+ var RequirementService = class extends BaseService {
1019
1045
  /**
1020
- * Dodaje novi zahtev tehnologiji
1021
- * @param technologyId - ID tehnologije
1022
- * @param requirement - Zahtev koji se dodaje
1023
- * @returns Ažurirana tehnologija sa novim zahtevom
1046
+ * Referenca na Firestore kolekciju zahteva
1024
1047
  */
1025
- async addRequirement(technologyId, requirement) {
1026
- const docRef = (0, import_firestore3.doc)(this.getTechnologiesRef(), technologyId);
1027
- const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
1028
- await (0, import_firestore3.updateDoc)(docRef, {
1029
- [requirementType]: (0, import_firestore3.arrayUnion)(requirement),
1030
- updatedAt: /* @__PURE__ */ new Date()
1031
- });
1032
- return this.getById(technologyId);
1048
+ get requirementsRef() {
1049
+ return (0, import_firestore8.collection)(this.db, REQUIREMENTS_COLLECTION);
1033
1050
  }
1034
1051
  /**
1035
- * Uklanja zahtev iz tehnologije
1036
- * @param technologyId - ID tehnologije
1037
- * @param requirement - Zahtev koji se uklanja
1038
- * @returns Ažurirana tehnologija bez uklonjenog zahteva
1052
+ * Kreira novi globalni zahtev
1053
+ * @param requirement - Podaci za novi zahtev
1054
+ * @returns Kreirani zahtev sa generisanim ID-em
1039
1055
  */
1040
- async removeRequirement(technologyId, requirement) {
1041
- const docRef = (0, import_firestore3.doc)(this.getTechnologiesRef(), technologyId);
1042
- const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
1043
- await (0, import_firestore3.updateDoc)(docRef, {
1044
- [requirementType]: (0, import_firestore3.arrayRemove)(requirement),
1045
- updatedAt: /* @__PURE__ */ new Date()
1046
- });
1047
- return this.getById(technologyId);
1056
+ async create(requirement) {
1057
+ const now = /* @__PURE__ */ new Date();
1058
+ const newRequirement = {
1059
+ ...requirement,
1060
+ createdAt: now,
1061
+ updatedAt: now,
1062
+ isActive: true
1063
+ };
1064
+ const docRef = await (0, import_firestore8.addDoc)(this.requirementsRef, newRequirement);
1065
+ return { id: docRef.id, ...newRequirement };
1048
1066
  }
1049
1067
  /**
1050
- * Vraća sve zahteve za tehnologiju
1051
- * @param technologyId - ID tehnologije
1052
- * @param type - Opcioni filter za tip zahteva (pre/post)
1053
- * @returns Lista zahteva
1068
+ * Vraća sve aktivne zahteve
1069
+ * @returns Lista aktivnih zahteva
1054
1070
  */
1055
- async getRequirements(technologyId, type) {
1056
- const technology = await this.getById(technologyId);
1057
- if (!technology || !technology.requirements) return [];
1058
- if (type) {
1059
- return technology.requirements[type];
1060
- }
1061
- return [...technology.requirements.pre, ...technology.requirements.post];
1071
+ async getAll() {
1072
+ const q = (0, import_firestore8.query)(this.requirementsRef, (0, import_firestore8.where)("isActive", "==", true));
1073
+ const snapshot = await (0, import_firestore8.getDocs)(q);
1074
+ return snapshot.docs.map(
1075
+ (doc10) => ({
1076
+ id: doc10.id,
1077
+ ...doc10.data()
1078
+ })
1079
+ );
1062
1080
  }
1063
1081
  /**
1064
- * Ažurira postojeći zahtev
1065
- * @param technologyId - ID tehnologije
1066
- * @param oldRequirement - Stari zahtev koji se menja
1067
- * @param newRequirement - Novi zahtev koji zamenjuje stari
1068
- * @returns Ažurirana tehnologija
1082
+ * Vraća sve aktivne zahteve određenog tipa
1083
+ * @param type - Tip zahteva (pre/post)
1084
+ * @returns Lista zahteva određenog tipa
1069
1085
  */
1070
- async updateRequirement(technologyId, oldRequirement, newRequirement) {
1071
- await this.removeRequirement(technologyId, oldRequirement);
1072
- return this.addRequirement(technologyId, newRequirement);
1086
+ async getAllByType(type) {
1087
+ const q = (0, import_firestore8.query)(
1088
+ this.requirementsRef,
1089
+ (0, import_firestore8.where)("type", "==", type),
1090
+ (0, import_firestore8.where)("isActive", "==", true)
1091
+ );
1092
+ const snapshot = await (0, import_firestore8.getDocs)(q);
1093
+ return snapshot.docs.map(
1094
+ (doc10) => ({
1095
+ id: doc10.id,
1096
+ ...doc10.data()
1097
+ })
1098
+ );
1073
1099
  }
1074
1100
  /**
1075
- * Dodaje blokirajući uslov tehnologiji
1076
- * @param technologyId - ID tehnologije
1077
- * @param condition - Blokirajući uslov koji se dodaje
1078
- * @returns Ažurirana tehnologija
1101
+ * Ažurira postojeći zahtev
1102
+ * @param id - ID zahteva koji se ažurira
1103
+ * @param requirement - Novi podaci za zahtev
1104
+ * @returns Ažurirani zahtev
1079
1105
  */
1080
- async addBlockingCondition(technologyId, condition) {
1081
- const docRef = (0, import_firestore3.doc)(this.getTechnologiesRef(), technologyId);
1082
- await (0, import_firestore3.updateDoc)(docRef, {
1083
- blockingConditions: (0, import_firestore3.arrayUnion)(condition),
1106
+ async update(id, requirement) {
1107
+ const updateData = {
1108
+ ...requirement,
1084
1109
  updatedAt: /* @__PURE__ */ new Date()
1085
- });
1086
- return this.getById(technologyId);
1110
+ };
1111
+ const docRef = (0, import_firestore8.doc)(this.requirementsRef, id);
1112
+ await (0, import_firestore8.updateDoc)(docRef, updateData);
1113
+ return this.getById(id);
1087
1114
  }
1088
1115
  /**
1089
- * Uklanja blokirajući uslov iz tehnologije
1090
- * @param technologyId - ID tehnologije
1091
- * @param condition - Blokirajući uslov koji se uklanja
1092
- * @returns Ažurirana tehnologija
1116
+ * Soft delete zahteva (postavlja isActive na false)
1117
+ * @param id - ID zahteva koji se briše
1093
1118
  */
1094
- async removeBlockingCondition(technologyId, condition) {
1095
- const docRef = (0, import_firestore3.doc)(this.getTechnologiesRef(), technologyId);
1096
- await (0, import_firestore3.updateDoc)(docRef, {
1097
- blockingConditions: (0, import_firestore3.arrayRemove)(condition),
1098
- updatedAt: /* @__PURE__ */ new Date()
1099
- });
1100
- return this.getById(technologyId);
1119
+ async delete(id) {
1120
+ await this.update(id, { isActive: false });
1101
1121
  }
1102
1122
  /**
1103
- * Dodaje kontraindikaciju tehnologiji
1104
- * @param technologyId - ID tehnologije
1105
- * @param contraindication - Kontraindikacija koja se dodaje
1106
- * @returns Ažurirana tehnologija
1123
+ * Vraća zahtev po ID-u
1124
+ * @param id - ID traženog zahteva
1125
+ * @returns Zahtev ili null ako ne postoji
1107
1126
  */
1108
- async addContraindication(technologyId, contraindication) {
1109
- const docRef = (0, import_firestore3.doc)(this.getTechnologiesRef(), technologyId);
1110
- await (0, import_firestore3.updateDoc)(docRef, {
1111
- contraindications: (0, import_firestore3.arrayUnion)(contraindication),
1112
- updatedAt: /* @__PURE__ */ new Date()
1113
- });
1114
- return this.getById(technologyId);
1127
+ async getById(id) {
1128
+ const docRef = (0, import_firestore8.doc)(this.requirementsRef, id);
1129
+ const docSnap = await (0, import_firestore8.getDoc)(docRef);
1130
+ if (!docSnap.exists()) return null;
1131
+ return {
1132
+ id: docSnap.id,
1133
+ ...docSnap.data()
1134
+ };
1115
1135
  }
1136
+ };
1137
+
1138
+ // src/backoffice/services/subcategory.service.ts
1139
+ var import_firestore9 = require("firebase/firestore");
1140
+
1141
+ // src/backoffice/types/subcategory.types.ts
1142
+ var SUBCATEGORIES_COLLECTION = "subcategories";
1143
+
1144
+ // src/backoffice/services/subcategory.service.ts
1145
+ var SubcategoryService = class extends BaseService {
1116
1146
  /**
1117
- * Uklanja kontraindikaciju iz tehnologije
1118
- * @param technologyId - ID tehnologije
1119
- * @param contraindication - Kontraindikacija koja se uklanja
1120
- * @returns Ažurirana tehnologija
1147
+ * Vraća referencu na Firestore kolekciju podkategorija za određenu kategoriju
1148
+ * @param categoryId - ID roditeljske kategorije
1121
1149
  */
1122
- async removeContraindication(technologyId, contraindication) {
1123
- const docRef = (0, import_firestore3.doc)(this.getTechnologiesRef(), technologyId);
1124
- await (0, import_firestore3.updateDoc)(docRef, {
1125
- contraindications: (0, import_firestore3.arrayRemove)(contraindication),
1126
- updatedAt: /* @__PURE__ */ new Date()
1127
- });
1128
- return this.getById(technologyId);
1150
+ getSubcategoriesRef(categoryId) {
1151
+ return (0, import_firestore9.collection)(
1152
+ this.db,
1153
+ CATEGORIES_COLLECTION,
1154
+ categoryId,
1155
+ SUBCATEGORIES_COLLECTION
1156
+ );
1129
1157
  }
1130
1158
  /**
1131
- * Dodaje benefit tehnologiji
1132
- * @param technologyId - ID tehnologije
1133
- * @param benefit - Benefit koji se dodaje
1134
- * @returns Ažurirana tehnologija
1159
+ * Kreira novu podkategoriju u okviru kategorije
1160
+ * @param categoryId - ID kategorije kojoj će pripadati nova podkategorija
1161
+ * @param subcategory - Podaci za novu podkategoriju
1162
+ * @returns Kreirana podkategorija sa generisanim ID-em
1135
1163
  */
1136
- async addBenefit(technologyId, benefit) {
1137
- const docRef = (0, import_firestore3.doc)(this.getTechnologiesRef(), technologyId);
1138
- await (0, import_firestore3.updateDoc)(docRef, {
1139
- benefits: (0, import_firestore3.arrayUnion)(benefit),
1140
- updatedAt: /* @__PURE__ */ new Date()
1141
- });
1142
- return this.getById(technologyId);
1164
+ async create(categoryId, subcategory) {
1165
+ const now = /* @__PURE__ */ new Date();
1166
+ const newSubcategory = {
1167
+ ...subcategory,
1168
+ categoryId,
1169
+ createdAt: now,
1170
+ updatedAt: now,
1171
+ isActive: true
1172
+ };
1173
+ const docRef = await (0, import_firestore9.addDoc)(
1174
+ this.getSubcategoriesRef(categoryId),
1175
+ newSubcategory
1176
+ );
1177
+ return { id: docRef.id, ...newSubcategory };
1143
1178
  }
1144
1179
  /**
1145
- * Uklanja benefit iz tehnologije
1146
- * @param technologyId - ID tehnologije
1147
- * @param benefit - Benefit koji se uklanja
1148
- * @returns Ažurirana tehnologija
1180
+ * Vraća sve aktivne podkategorije za određenu kategoriju
1181
+ * @param categoryId - ID kategorije čije podkategorije tražimo
1182
+ * @returns Lista aktivnih podkategorija
1149
1183
  */
1150
- async removeBenefit(technologyId, benefit) {
1151
- const docRef = (0, import_firestore3.doc)(this.getTechnologiesRef(), technologyId);
1152
- await (0, import_firestore3.updateDoc)(docRef, {
1153
- benefits: (0, import_firestore3.arrayRemove)(benefit),
1154
- updatedAt: /* @__PURE__ */ new Date()
1155
- });
1156
- return this.getById(technologyId);
1184
+ async getAllByCategoryId(categoryId) {
1185
+ const q = (0, import_firestore9.query)(
1186
+ this.getSubcategoriesRef(categoryId),
1187
+ (0, import_firestore9.where)("isActive", "==", true)
1188
+ );
1189
+ const snapshot = await (0, import_firestore9.getDocs)(q);
1190
+ return snapshot.docs.map(
1191
+ (doc10) => ({
1192
+ id: doc10.id,
1193
+ ...doc10.data()
1194
+ })
1195
+ );
1157
1196
  }
1158
1197
  /**
1159
- * Vraća sve blokirajuće uslove za tehnologiju
1160
- * @param technologyId - ID tehnologije
1161
- * @returns Lista blokirajućih uslova
1198
+ * Ažurira postojeću podkategoriju
1199
+ * @param categoryId - ID kategorije kojoj pripada podkategorija
1200
+ * @param subcategoryId - ID podkategorije koja se ažurira
1201
+ * @param subcategory - Novi podaci za podkategoriju
1202
+ * @returns Ažurirana podkategorija
1162
1203
  */
1163
- async getBlockingConditions(technologyId) {
1164
- const technology = await this.getById(technologyId);
1165
- return (technology == null ? void 0 : technology.blockingConditions) || [];
1204
+ async update(categoryId, subcategoryId, subcategory) {
1205
+ const updateData = {
1206
+ ...subcategory,
1207
+ updatedAt: /* @__PURE__ */ new Date()
1208
+ };
1209
+ const docRef = (0, import_firestore9.doc)(this.getSubcategoriesRef(categoryId), subcategoryId);
1210
+ await (0, import_firestore9.updateDoc)(docRef, updateData);
1211
+ return this.getById(categoryId, subcategoryId);
1166
1212
  }
1167
1213
  /**
1168
- * Vraća sve kontraindikacije za tehnologiju
1169
- * @param technologyId - ID tehnologije
1170
- * @returns Lista kontraindikacija
1214
+ * Soft delete podkategorije (postavlja isActive na false)
1215
+ * @param categoryId - ID kategorije kojoj pripada podkategorija
1216
+ * @param subcategoryId - ID podkategorije koja se briše
1171
1217
  */
1172
- async getContraindications(technologyId) {
1173
- const technology = await this.getById(technologyId);
1174
- return (technology == null ? void 0 : technology.contraindications) || [];
1218
+ async delete(categoryId, subcategoryId) {
1219
+ await this.update(categoryId, subcategoryId, { isActive: false });
1175
1220
  }
1176
1221
  /**
1177
- * Vraća sve benefite za tehnologiju
1178
- * @param technologyId - ID tehnologije
1179
- * @returns Lista benefita
1222
+ * Vraća podkategoriju po ID-u
1223
+ * @param categoryId - ID kategorije kojoj pripada podkategorija
1224
+ * @param subcategoryId - ID tražene podkategorije
1225
+ * @returns Podkategorija ili null ako ne postoji
1180
1226
  */
1181
- async getBenefits(technologyId) {
1182
- const technology = await this.getById(technologyId);
1183
- return (technology == null ? void 0 : technology.benefits) || [];
1184
- }
1185
- /**
1186
- * Ažurira zahteve sertifikacije za tehnologiju
1187
- * @param technologyId - ID tehnologije
1188
- * @param certificationRequirement - Novi zahtevi sertifikacije
1189
- * @returns Ažurirana tehnologija
1190
- */
1191
- async updateCertificationRequirement(technologyId, certificationRequirement) {
1192
- const docRef = (0, import_firestore3.doc)(this.getTechnologiesRef(), technologyId);
1193
- await (0, import_firestore3.updateDoc)(docRef, {
1194
- certificationRequirement,
1195
- updatedAt: /* @__PURE__ */ new Date()
1196
- });
1197
- return this.getById(technologyId);
1198
- }
1199
- /**
1200
- * Vraća zahteve sertifikacije za tehnologiju
1201
- * @param technologyId - ID tehnologije
1202
- * @returns Zahtevi sertifikacije ili null ako tehnologija ne postoji
1203
- */
1204
- async getCertificationRequirement(technologyId) {
1205
- const technology = await this.getById(technologyId);
1206
- return (technology == null ? void 0 : technology.certificationRequirement) || null;
1207
- }
1208
- /**
1209
- * Proverava da li doktor ima odgovarajuću sertifikaciju za izvođenje tehnologije
1210
- *
1211
- * @param requiredCertification - Zahtevana sertifikacija za tehnologiju
1212
- * @param practitionerCertification - Sertifikacija zdravstvenog radnika
1213
- * @returns true ako zdravstveni radnik ima odgovarajuću sertifikaciju, false ako nema
1214
- *
1215
- * @example
1216
- * const isValid = technologyService.validateCertification(
1217
- * {
1218
- * minimumLevel: CertificationLevel.DOCTOR,
1219
- * requiredSpecialties: [CertificationSpecialty.INJECTABLES]
1220
- * },
1221
- * {
1222
- * level: CertificationLevel.SPECIALIST,
1223
- * specialties: [CertificationSpecialty.INJECTABLES, CertificationSpecialty.LASER]
1224
- * }
1225
- * );
1226
- */
1227
- validateCertification(requiredCertification, practitionerCertification) {
1228
- const doctorLevel = Object.values(CertificationLevel).indexOf(
1229
- practitionerCertification.level
1230
- );
1231
- const requiredLevel = Object.values(CertificationLevel).indexOf(
1232
- requiredCertification.minimumLevel
1233
- );
1234
- if (doctorLevel < requiredLevel) return false;
1235
- const requiredSpecialties = requiredCertification.requiredSpecialties || [];
1236
- if (requiredSpecialties.length > 0) {
1237
- const doctorSpecialties = practitionerCertification.specialties;
1238
- const hasAllRequiredSpecialties = requiredSpecialties.every(
1239
- (requiredSpecialty) => doctorSpecialties.includes(requiredSpecialty)
1240
- );
1241
- if (!hasAllRequiredSpecialties) return false;
1242
- }
1243
- return true;
1244
- }
1245
- /**
1246
- * Vraća sve tehnologije koje je zdravstveni radnik sertifikovan da izvodi
1247
- * zajedno sa listama dozvoljenih familija, kategorija i podkategorija
1248
- *
1249
- * @param practitioner - Profil zdravstvenog radnika
1250
- * @returns Objekat koji sadrži:
1251
- * - technologies: Lista tehnologija koje zdravstveni radnik može da izvodi
1252
- * - families: Lista familija procedura koje zdravstveni radnik može da izvodi
1253
- * - categories: Lista ID-eva kategorija koje zdravstveni radnik može da izvodi
1254
- * - subcategories: Lista ID-eva podkategorija koje zdravstveni radnik može da izvodi
1255
- *
1256
- * @example
1257
- * const practitioner = {
1258
- * certification: {
1259
- * level: CertificationLevel.DOCTOR,
1260
- * specialties: [CertificationSpecialty.INJECTABLES]
1261
- * }
1262
- * };
1263
- * const allowedTechnologies = await technologyService.getAllowedTechnologies(practitioner);
1264
- * console.log(allowedTechnologies.families); // [ProcedureFamily.AESTHETICS]
1265
- * console.log(allowedTechnologies.categories); // ["category1", "category2"]
1266
- * console.log(allowedTechnologies.subcategories); // ["subcategory1", "subcategory2"]
1267
- */
1268
- async getAllowedTechnologies(practitioner) {
1269
- const allTechnologies = await this.getAll();
1270
- const allowedTechnologies = allTechnologies.filter(
1271
- (technology) => this.validateCertification(
1272
- technology.certificationRequirement,
1273
- practitioner.certification
1274
- )
1275
- );
1276
- const families = [...new Set(allowedTechnologies.map((t) => t.family))];
1277
- const categories = [
1278
- ...new Set(allowedTechnologies.map((t) => t.categoryId))
1279
- ];
1280
- const subcategories = [
1281
- ...new Set(allowedTechnologies.map((t) => t.subcategoryId))
1282
- ];
1283
- return {
1284
- technologies: allowedTechnologies,
1285
- families,
1286
- categories,
1287
- subcategories
1288
- };
1227
+ async getById(categoryId, subcategoryId) {
1228
+ const docRef = (0, import_firestore9.doc)(this.getSubcategoriesRef(categoryId), subcategoryId);
1229
+ const docSnap = await (0, import_firestore9.getDoc)(docRef);
1230
+ if (!docSnap.exists()) return null;
1231
+ return {
1232
+ id: docSnap.id,
1233
+ ...docSnap.data()
1234
+ };
1289
1235
  }
1290
1236
  };
1291
1237
 
1292
- // src/backoffice/services/requirement.service.ts
1293
- var import_firestore4 = require("firebase/firestore");
1294
- var RequirementService = class extends BaseService {
1238
+ // src/backoffice/services/technology.service.ts
1239
+ var import_firestore10 = require("firebase/firestore");
1240
+
1241
+ // src/backoffice/types/static/certification.types.ts
1242
+ var CertificationLevel = /* @__PURE__ */ ((CertificationLevel2) => {
1243
+ CertificationLevel2["AESTHETICIAN"] = "aesthetician";
1244
+ CertificationLevel2["NURSE_ASSISTANT"] = "nurse_assistant";
1245
+ CertificationLevel2["NURSE"] = "nurse";
1246
+ CertificationLevel2["NURSE_PRACTITIONER"] = "nurse_practitioner";
1247
+ CertificationLevel2["PHYSICIAN_ASSISTANT"] = "physician_assistant";
1248
+ CertificationLevel2["DOCTOR"] = "doctor";
1249
+ CertificationLevel2["SPECIALIST"] = "specialist";
1250
+ CertificationLevel2["PLASTIC_SURGEON"] = "plastic_surgeon";
1251
+ return CertificationLevel2;
1252
+ })(CertificationLevel || {});
1253
+ var CertificationSpecialty = /* @__PURE__ */ ((CertificationSpecialty3) => {
1254
+ CertificationSpecialty3["LASER"] = "laser";
1255
+ CertificationSpecialty3["INJECTABLES"] = "injectables";
1256
+ CertificationSpecialty3["CHEMICAL_PEELS"] = "chemical_peels";
1257
+ CertificationSpecialty3["MICRODERMABRASION"] = "microdermabrasion";
1258
+ CertificationSpecialty3["BODY_CONTOURING"] = "body_contouring";
1259
+ CertificationSpecialty3["SKIN_CARE"] = "skin_care";
1260
+ CertificationSpecialty3["WOUND_CARE"] = "wound_care";
1261
+ CertificationSpecialty3["ANESTHESIA"] = "anesthesia";
1262
+ return CertificationSpecialty3;
1263
+ })(CertificationSpecialty || {});
1264
+
1265
+ // src/backoffice/services/technology.service.ts
1266
+ var DEFAULT_CERTIFICATION_REQUIREMENT = {
1267
+ minimumLevel: "aesthetician" /* AESTHETICIAN */,
1268
+ requiredSpecialties: []
1269
+ };
1270
+ var TechnologyService = class extends BaseService {
1295
1271
  /**
1296
- * Referenca na Firestore kolekciju zahteva
1272
+ * Vraća referencu na Firestore kolekciju tehnologija
1297
1273
  */
1298
- get requirementsRef() {
1299
- return (0, import_firestore4.collection)(this.db, REQUIREMENTS_COLLECTION);
1274
+ getTechnologiesRef() {
1275
+ return (0, import_firestore10.collection)(this.db, TECHNOLOGIES_COLLECTION);
1300
1276
  }
1301
1277
  /**
1302
- * Kreira novi globalni zahtev
1303
- * @param requirement - Podaci za novi zahtev
1304
- * @returns Kreirani zahtev sa generisanim ID-em
1278
+ * Kreira novu tehnologiju
1279
+ * @param technology - Podaci za novu tehnologiju
1280
+ * @returns Kreirana tehnologija sa generisanim ID-em
1305
1281
  */
1306
- async create(requirement) {
1282
+ async create(technology) {
1307
1283
  const now = /* @__PURE__ */ new Date();
1308
- const newRequirement = {
1309
- ...requirement,
1284
+ const newTechnology = {
1285
+ ...technology,
1310
1286
  createdAt: now,
1311
1287
  updatedAt: now,
1312
- isActive: true
1288
+ isActive: true,
1289
+ requirements: technology.requirements || {
1290
+ pre: [],
1291
+ post: []
1292
+ },
1293
+ blockingConditions: technology.blockingConditions || [],
1294
+ contraindications: technology.contraindications || [],
1295
+ benefits: technology.benefits || [],
1296
+ certificationRequirement: technology.certificationRequirement || DEFAULT_CERTIFICATION_REQUIREMENT
1313
1297
  };
1314
- const docRef = await (0, import_firestore4.addDoc)(this.requirementsRef, newRequirement);
1315
- return { id: docRef.id, ...newRequirement };
1298
+ const docRef = await (0, import_firestore10.addDoc)(this.getTechnologiesRef(), newTechnology);
1299
+ return { id: docRef.id, ...newTechnology };
1316
1300
  }
1317
1301
  /**
1318
- * Vraća sve aktivne zahteve
1319
- * @returns Lista aktivnih zahteva
1302
+ * Vraća sve aktivne tehnologije
1303
+ * @returns Lista aktivnih tehnologija
1320
1304
  */
1321
1305
  async getAll() {
1322
- const q = (0, import_firestore4.query)(this.requirementsRef, (0, import_firestore4.where)("isActive", "==", true));
1323
- const snapshot = await (0, import_firestore4.getDocs)(q);
1306
+ const q = (0, import_firestore10.query)(this.getTechnologiesRef(), (0, import_firestore10.where)("isActive", "==", true));
1307
+ const snapshot = await (0, import_firestore10.getDocs)(q);
1324
1308
  return snapshot.docs.map(
1325
1309
  (doc10) => ({
1326
1310
  id: doc10.id,
@@ -1329,17 +1313,17 @@ var RequirementService = class extends BaseService {
1329
1313
  );
1330
1314
  }
1331
1315
  /**
1332
- * Vraća sve aktivne zahteve određenog tipa
1333
- * @param type - Tip zahteva (pre/post)
1334
- * @returns Lista zahteva određenog tipa
1316
+ * Vraća sve aktivne tehnologije za određenu familiju
1317
+ * @param family - Familija procedura
1318
+ * @returns Lista aktivnih tehnologija
1335
1319
  */
1336
- async getAllByType(type) {
1337
- const q = (0, import_firestore4.query)(
1338
- this.requirementsRef,
1339
- (0, import_firestore4.where)("type", "==", type),
1340
- (0, import_firestore4.where)("isActive", "==", true)
1320
+ async getAllByFamily(family) {
1321
+ const q = (0, import_firestore10.query)(
1322
+ this.getTechnologiesRef(),
1323
+ (0, import_firestore10.where)("isActive", "==", true),
1324
+ (0, import_firestore10.where)("family", "==", family)
1341
1325
  );
1342
- const snapshot = await (0, import_firestore4.getDocs)(q);
1326
+ const snapshot = await (0, import_firestore10.getDocs)(q);
1343
1327
  return snapshot.docs.map(
1344
1328
  (doc10) => ({
1345
1329
  id: doc10.id,
@@ -1348,603 +1332,629 @@ var RequirementService = class extends BaseService {
1348
1332
  );
1349
1333
  }
1350
1334
  /**
1351
- * Ažurira postojeći zahtev
1352
- * @param id - ID zahteva koji se ažurira
1353
- * @param requirement - Novi podaci za zahtev
1354
- * @returns Ažurirani zahtev
1335
+ * Vraća sve aktivne tehnologije za određenu kategoriju
1336
+ * @param categoryId - ID kategorije
1337
+ * @returns Lista aktivnih tehnologija
1355
1338
  */
1356
- async update(id, requirement) {
1339
+ async getAllByCategoryId(categoryId) {
1340
+ const q = (0, import_firestore10.query)(
1341
+ this.getTechnologiesRef(),
1342
+ (0, import_firestore10.where)("isActive", "==", true),
1343
+ (0, import_firestore10.where)("categoryId", "==", categoryId)
1344
+ );
1345
+ const snapshot = await (0, import_firestore10.getDocs)(q);
1346
+ return snapshot.docs.map(
1347
+ (doc10) => ({
1348
+ id: doc10.id,
1349
+ ...doc10.data()
1350
+ })
1351
+ );
1352
+ }
1353
+ /**
1354
+ * Vraća sve aktivne tehnologije za određenu podkategoriju
1355
+ * @param subcategoryId - ID podkategorije
1356
+ * @returns Lista aktivnih tehnologija
1357
+ */
1358
+ async getAllBySubcategoryId(subcategoryId) {
1359
+ const q = (0, import_firestore10.query)(
1360
+ this.getTechnologiesRef(),
1361
+ (0, import_firestore10.where)("isActive", "==", true),
1362
+ (0, import_firestore10.where)("subcategoryId", "==", subcategoryId)
1363
+ );
1364
+ const snapshot = await (0, import_firestore10.getDocs)(q);
1365
+ return snapshot.docs.map(
1366
+ (doc10) => ({
1367
+ id: doc10.id,
1368
+ ...doc10.data()
1369
+ })
1370
+ );
1371
+ }
1372
+ /**
1373
+ * Ažurira postojeću tehnologiju
1374
+ * @param technologyId - ID tehnologije
1375
+ * @param technology - Novi podaci za tehnologiju
1376
+ * @returns Ažurirana tehnologija
1377
+ */
1378
+ async update(technologyId, technology) {
1357
1379
  const updateData = {
1358
- ...requirement,
1380
+ ...technology,
1359
1381
  updatedAt: /* @__PURE__ */ new Date()
1360
1382
  };
1361
- const docRef = (0, import_firestore4.doc)(this.requirementsRef, id);
1362
- await (0, import_firestore4.updateDoc)(docRef, updateData);
1363
- return this.getById(id);
1383
+ const docRef = (0, import_firestore10.doc)(this.getTechnologiesRef(), technologyId);
1384
+ await (0, import_firestore10.updateDoc)(docRef, updateData);
1385
+ return this.getById(technologyId);
1364
1386
  }
1365
1387
  /**
1366
- * Soft delete zahteva (postavlja isActive na false)
1367
- * @param id - ID zahteva koji se briše
1388
+ * Soft delete tehnologije (postavlja isActive na false)
1389
+ * @param technologyId - ID tehnologije koja se briše
1368
1390
  */
1369
- async delete(id) {
1370
- await this.update(id, { isActive: false });
1391
+ async delete(technologyId) {
1392
+ await this.update(technologyId, {
1393
+ isActive: false
1394
+ });
1371
1395
  }
1372
1396
  /**
1373
- * Vraća zahtev po ID-u
1374
- * @param id - ID traženog zahteva
1375
- * @returns Zahtev ili null ako ne postoji
1397
+ * Vraća tehnologiju po ID-u
1398
+ * @param technologyId - ID tražene tehnologije
1399
+ * @returns Tehnologija ili null ako ne postoji
1376
1400
  */
1377
- async getById(id) {
1378
- const docRef = (0, import_firestore4.doc)(this.requirementsRef, id);
1379
- const docSnap = await (0, import_firestore4.getDoc)(docRef);
1401
+ async getById(technologyId) {
1402
+ const docRef = (0, import_firestore10.doc)(this.getTechnologiesRef(), technologyId);
1403
+ const docSnap = await (0, import_firestore10.getDoc)(docRef);
1380
1404
  if (!docSnap.exists()) return null;
1381
1405
  return {
1382
1406
  id: docSnap.id,
1383
1407
  ...docSnap.data()
1384
1408
  };
1385
1409
  }
1386
- };
1387
-
1388
- // src/backoffice/services/brand.service.ts
1389
- var import_firestore5 = require("firebase/firestore");
1390
- var BrandService = class extends BaseService {
1391
1410
  /**
1392
- * Gets reference to brands collection
1411
+ * Dodaje novi zahtev tehnologiji
1412
+ * @param technologyId - ID tehnologije
1413
+ * @param requirement - Zahtev koji se dodaje
1414
+ * @returns Ažurirana tehnologija sa novim zahtevom
1393
1415
  */
1394
- getBrandsRef() {
1395
- return (0, import_firestore5.collection)(this.db, BRANDS_COLLECTION);
1416
+ async addRequirement(technologyId, requirement) {
1417
+ const docRef = (0, import_firestore10.doc)(this.getTechnologiesRef(), technologyId);
1418
+ const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
1419
+ await (0, import_firestore10.updateDoc)(docRef, {
1420
+ [requirementType]: (0, import_firestore10.arrayUnion)(requirement),
1421
+ updatedAt: /* @__PURE__ */ new Date()
1422
+ });
1423
+ return this.getById(technologyId);
1396
1424
  }
1397
1425
  /**
1398
- * Creates a new brand
1426
+ * Uklanja zahtev iz tehnologije
1427
+ * @param technologyId - ID tehnologije
1428
+ * @param requirement - Zahtev koji se uklanja
1429
+ * @returns Ažurirana tehnologija bez uklonjenog zahteva
1399
1430
  */
1400
- async create(brand) {
1401
- const now = /* @__PURE__ */ new Date();
1402
- const newBrand = {
1403
- ...brand,
1404
- createdAt: now,
1405
- updatedAt: now,
1406
- isActive: true
1407
- };
1408
- const docRef = await (0, import_firestore5.addDoc)(this.getBrandsRef(), newBrand);
1409
- return { id: docRef.id, ...newBrand };
1431
+ async removeRequirement(technologyId, requirement) {
1432
+ const docRef = (0, import_firestore10.doc)(this.getTechnologiesRef(), technologyId);
1433
+ const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
1434
+ await (0, import_firestore10.updateDoc)(docRef, {
1435
+ [requirementType]: (0, import_firestore10.arrayRemove)(requirement),
1436
+ updatedAt: /* @__PURE__ */ new Date()
1437
+ });
1438
+ return this.getById(technologyId);
1410
1439
  }
1411
1440
  /**
1412
- * Gets all active brands
1441
+ * Vraća sve zahteve za tehnologiju
1442
+ * @param technologyId - ID tehnologije
1443
+ * @param type - Opcioni filter za tip zahteva (pre/post)
1444
+ * @returns Lista zahteva
1413
1445
  */
1414
- async getAll() {
1415
- const q = (0, import_firestore5.query)(this.getBrandsRef(), (0, import_firestore5.where)("isActive", "==", true));
1416
- const snapshot = await (0, import_firestore5.getDocs)(q);
1417
- return snapshot.docs.map(
1418
- (doc10) => ({
1419
- id: doc10.id,
1420
- ...doc10.data()
1421
- })
1422
- );
1446
+ async getRequirements(technologyId, type) {
1447
+ const technology = await this.getById(technologyId);
1448
+ if (!technology || !technology.requirements) return [];
1449
+ if (type) {
1450
+ return technology.requirements[type];
1451
+ }
1452
+ return [...technology.requirements.pre, ...technology.requirements.post];
1423
1453
  }
1424
1454
  /**
1425
- * Updates a brand
1455
+ * Ažurira postojeći zahtev
1456
+ * @param technologyId - ID tehnologije
1457
+ * @param oldRequirement - Stari zahtev koji se menja
1458
+ * @param newRequirement - Novi zahtev koji zamenjuje stari
1459
+ * @returns Ažurirana tehnologija
1426
1460
  */
1427
- async update(brandId, brand) {
1428
- const updateData = {
1429
- ...brand,
1430
- updatedAt: /* @__PURE__ */ new Date()
1431
- };
1432
- const docRef = (0, import_firestore5.doc)(this.getBrandsRef(), brandId);
1433
- await (0, import_firestore5.updateDoc)(docRef, updateData);
1434
- return this.getById(brandId);
1461
+ async updateRequirement(technologyId, oldRequirement, newRequirement) {
1462
+ await this.removeRequirement(technologyId, oldRequirement);
1463
+ return this.addRequirement(technologyId, newRequirement);
1435
1464
  }
1436
1465
  /**
1437
- * Soft deletes a brand
1466
+ * Dodaje blokirajući uslov tehnologiji
1467
+ * @param technologyId - ID tehnologije
1468
+ * @param condition - Blokirajući uslov koji se dodaje
1469
+ * @returns Ažurirana tehnologija
1438
1470
  */
1439
- async delete(brandId) {
1440
- await this.update(brandId, {
1441
- isActive: false
1471
+ async addBlockingCondition(technologyId, condition) {
1472
+ const docRef = (0, import_firestore10.doc)(this.getTechnologiesRef(), technologyId);
1473
+ await (0, import_firestore10.updateDoc)(docRef, {
1474
+ blockingConditions: (0, import_firestore10.arrayUnion)(condition),
1475
+ updatedAt: /* @__PURE__ */ new Date()
1442
1476
  });
1477
+ return this.getById(technologyId);
1443
1478
  }
1444
1479
  /**
1445
- * Gets a brand by ID
1480
+ * Uklanja blokirajući uslov iz tehnologije
1481
+ * @param technologyId - ID tehnologije
1482
+ * @param condition - Blokirajući uslov koji se uklanja
1483
+ * @returns Ažurirana tehnologija
1446
1484
  */
1447
- async getById(brandId) {
1448
- const docRef = (0, import_firestore5.doc)(this.getBrandsRef(), brandId);
1449
- const docSnap = await (0, import_firestore5.getDoc)(docRef);
1450
- if (!docSnap.exists()) return null;
1451
- return {
1452
- id: docSnap.id,
1453
- ...docSnap.data()
1454
- };
1485
+ async removeBlockingCondition(technologyId, condition) {
1486
+ const docRef = (0, import_firestore10.doc)(this.getTechnologiesRef(), technologyId);
1487
+ await (0, import_firestore10.updateDoc)(docRef, {
1488
+ blockingConditions: (0, import_firestore10.arrayRemove)(condition),
1489
+ updatedAt: /* @__PURE__ */ new Date()
1490
+ });
1491
+ return this.getById(technologyId);
1455
1492
  }
1456
- };
1457
-
1458
- // src/backoffice/services/product.service.ts
1459
- var import_firestore6 = require("firebase/firestore");
1460
- var ProductService = class extends BaseService {
1461
1493
  /**
1462
- * Gets reference to products collection under a technology
1463
- * @param technologyId - ID of the technology
1464
- * @returns Firestore collection reference
1494
+ * Dodaje kontraindikaciju tehnologiji
1495
+ * @param technologyId - ID tehnologije
1496
+ * @param contraindication - Kontraindikacija koja se dodaje
1497
+ * @returns Ažurirana tehnologija
1465
1498
  */
1466
- getProductsRef(technologyId) {
1467
- return (0, import_firestore6.collection)(
1468
- this.db,
1469
- TECHNOLOGIES_COLLECTION,
1470
- technologyId,
1471
- PRODUCTS_COLLECTION
1472
- );
1499
+ async addContraindication(technologyId, contraindication) {
1500
+ const docRef = (0, import_firestore10.doc)(this.getTechnologiesRef(), technologyId);
1501
+ await (0, import_firestore10.updateDoc)(docRef, {
1502
+ contraindications: (0, import_firestore10.arrayUnion)(contraindication),
1503
+ updatedAt: /* @__PURE__ */ new Date()
1504
+ });
1505
+ return this.getById(technologyId);
1473
1506
  }
1474
1507
  /**
1475
- * Creates a new product under technology
1508
+ * Uklanja kontraindikaciju iz tehnologije
1509
+ * @param technologyId - ID tehnologije
1510
+ * @param contraindication - Kontraindikacija koja se uklanja
1511
+ * @returns Ažurirana tehnologija
1476
1512
  */
1477
- async create(technologyId, brandId, product) {
1478
- const now = /* @__PURE__ */ new Date();
1479
- const newProduct = {
1480
- ...product,
1481
- brandId,
1482
- technologyId,
1483
- createdAt: now,
1484
- updatedAt: now,
1485
- isActive: true
1486
- };
1487
- const productRef = await (0, import_firestore6.addDoc)(
1488
- this.getProductsRef(technologyId),
1489
- newProduct
1490
- );
1491
- return { id: productRef.id, ...newProduct };
1513
+ async removeContraindication(technologyId, contraindication) {
1514
+ const docRef = (0, import_firestore10.doc)(this.getTechnologiesRef(), technologyId);
1515
+ await (0, import_firestore10.updateDoc)(docRef, {
1516
+ contraindications: (0, import_firestore10.arrayRemove)(contraindication),
1517
+ updatedAt: /* @__PURE__ */ new Date()
1518
+ });
1519
+ return this.getById(technologyId);
1492
1520
  }
1493
1521
  /**
1494
- * Gets all products for a technology
1522
+ * Dodaje benefit tehnologiji
1523
+ * @param technologyId - ID tehnologije
1524
+ * @param benefit - Benefit koji se dodaje
1525
+ * @returns Ažurirana tehnologija
1495
1526
  */
1496
- async getAllByTechnology(technologyId) {
1497
- const q = (0, import_firestore6.query)(
1498
- this.getProductsRef(technologyId),
1499
- (0, import_firestore6.where)("isActive", "==", true)
1500
- );
1501
- const snapshot = await (0, import_firestore6.getDocs)(q);
1502
- return snapshot.docs.map(
1503
- (doc10) => ({
1504
- id: doc10.id,
1505
- ...doc10.data()
1506
- })
1507
- );
1527
+ async addBenefit(technologyId, benefit) {
1528
+ const docRef = (0, import_firestore10.doc)(this.getTechnologiesRef(), technologyId);
1529
+ await (0, import_firestore10.updateDoc)(docRef, {
1530
+ benefits: (0, import_firestore10.arrayUnion)(benefit),
1531
+ updatedAt: /* @__PURE__ */ new Date()
1532
+ });
1533
+ return this.getById(technologyId);
1508
1534
  }
1509
1535
  /**
1510
- * Gets all products for a brand by filtering through all technologies
1536
+ * Uklanja benefit iz tehnologije
1537
+ * @param technologyId - ID tehnologije
1538
+ * @param benefit - Benefit koji se uklanja
1539
+ * @returns Ažurirana tehnologija
1511
1540
  */
1512
- async getAllByBrand(brandId) {
1513
- const allTechnologiesRef = (0, import_firestore6.collection)(this.db, TECHNOLOGIES_COLLECTION);
1514
- const technologiesSnapshot = await (0, import_firestore6.getDocs)(allTechnologiesRef);
1515
- const products = [];
1516
- for (const techDoc of technologiesSnapshot.docs) {
1517
- const q = (0, import_firestore6.query)(
1518
- this.getProductsRef(techDoc.id),
1519
- (0, import_firestore6.where)("brandId", "==", brandId),
1520
- (0, import_firestore6.where)("isActive", "==", true)
1521
- );
1522
- const snapshot = await (0, import_firestore6.getDocs)(q);
1523
- products.push(
1524
- ...snapshot.docs.map(
1525
- (doc10) => ({
1526
- id: doc10.id,
1527
- ...doc10.data()
1528
- })
1529
- )
1530
- );
1531
- }
1532
- return products;
1541
+ async removeBenefit(technologyId, benefit) {
1542
+ const docRef = (0, import_firestore10.doc)(this.getTechnologiesRef(), technologyId);
1543
+ await (0, import_firestore10.updateDoc)(docRef, {
1544
+ benefits: (0, import_firestore10.arrayRemove)(benefit),
1545
+ updatedAt: /* @__PURE__ */ new Date()
1546
+ });
1547
+ return this.getById(technologyId);
1533
1548
  }
1534
1549
  /**
1535
- * Updates a product
1550
+ * Vraća sve blokirajuće uslove za tehnologiju
1551
+ * @param technologyId - ID tehnologije
1552
+ * @returns Lista blokirajućih uslova
1536
1553
  */
1537
- async update(technologyId, productId, product) {
1538
- const updateData = {
1539
- ...product,
1540
- updatedAt: /* @__PURE__ */ new Date()
1541
- };
1542
- const docRef = (0, import_firestore6.doc)(this.getProductsRef(technologyId), productId);
1543
- await (0, import_firestore6.updateDoc)(docRef, updateData);
1544
- return this.getById(technologyId, productId);
1554
+ async getBlockingConditions(technologyId) {
1555
+ const technology = await this.getById(technologyId);
1556
+ return (technology == null ? void 0 : technology.blockingConditions) || [];
1545
1557
  }
1546
1558
  /**
1547
- * Soft deletes a product
1559
+ * Vraća sve kontraindikacije za tehnologiju
1560
+ * @param technologyId - ID tehnologije
1561
+ * @returns Lista kontraindikacija
1548
1562
  */
1549
- async delete(technologyId, productId) {
1550
- await this.update(technologyId, productId, {
1551
- isActive: false
1552
- });
1563
+ async getContraindications(technologyId) {
1564
+ const technology = await this.getById(technologyId);
1565
+ return (technology == null ? void 0 : technology.contraindications) || [];
1553
1566
  }
1554
1567
  /**
1555
- * Gets a product by ID
1568
+ * Vraća sve benefite za tehnologiju
1569
+ * @param technologyId - ID tehnologije
1570
+ * @returns Lista benefita
1556
1571
  */
1557
- async getById(technologyId, productId) {
1558
- const docRef = (0, import_firestore6.doc)(this.getProductsRef(technologyId), productId);
1559
- const docSnap = await (0, import_firestore6.getDoc)(docRef);
1560
- if (!docSnap.exists()) return null;
1561
- return {
1562
- id: docSnap.id,
1563
- ...docSnap.data()
1564
- };
1565
- }
1566
- };
1567
-
1568
- // src/services/documentation-templates/documentation-template.service.ts
1569
- var import_firestore7 = require("firebase/firestore");
1570
- var DocumentationTemplateService = class extends BaseService {
1571
- constructor() {
1572
- super(...arguments);
1573
- this.collectionRef = (0, import_firestore7.collection)(
1574
- this.db,
1575
- DOCUMENTATION_TEMPLATES_COLLECTION
1576
- );
1572
+ async getBenefits(technologyId) {
1573
+ const technology = await this.getById(technologyId);
1574
+ return (technology == null ? void 0 : technology.benefits) || [];
1577
1575
  }
1578
1576
  /**
1579
- * Create a new document template
1580
- * @param data - Template data
1581
- * @param userId - ID of the user creating the template
1582
- * @returns The created template
1577
+ * Ažurira zahteve sertifikacije za tehnologiju
1578
+ * @param technologyId - ID tehnologije
1579
+ * @param certificationRequirement - Novi zahtevi sertifikacije
1580
+ * @returns Ažurirana tehnologija
1583
1581
  */
1584
- async createTemplate(data, userId) {
1585
- const validatedData = createDocumentTemplateSchema.parse(data);
1586
- const templateId = this.generateId();
1587
- const elementsWithIds = validatedData.elements.map((element) => ({
1588
- ...element,
1589
- id: this.generateId()
1590
- }));
1591
- const now = Date.now();
1592
- const template = {
1593
- id: templateId,
1594
- title: validatedData.title,
1595
- description: validatedData.description,
1596
- elements: elementsWithIds,
1597
- createdAt: now,
1598
- updatedAt: now,
1599
- createdBy: userId,
1600
- version: 1,
1601
- isActive: true,
1602
- tags: validatedData.tags || [],
1603
- isUserForm: validatedData.isUserForm || false,
1604
- isRequired: validatedData.isRequired || false,
1605
- sortingOrder: validatedData.sortingOrder || 0
1606
- };
1607
- const docRef = (0, import_firestore7.doc)(this.collectionRef, templateId);
1608
- await (0, import_firestore7.setDoc)(docRef, template);
1609
- return template;
1582
+ async updateCertificationRequirement(technologyId, certificationRequirement) {
1583
+ const docRef = (0, import_firestore10.doc)(this.getTechnologiesRef(), technologyId);
1584
+ await (0, import_firestore10.updateDoc)(docRef, {
1585
+ certificationRequirement,
1586
+ updatedAt: /* @__PURE__ */ new Date()
1587
+ });
1588
+ return this.getById(technologyId);
1610
1589
  }
1611
1590
  /**
1612
- * Get a document template by ID
1613
- * @param templateId - ID of the template to retrieve
1614
- * @param version - Optional version number to retrieve (defaults to latest version)
1615
- * @returns The template or null if not found
1616
- */
1617
- async getTemplateById(templateId, version) {
1618
- const docRef = (0, import_firestore7.doc)(this.collectionRef, templateId);
1619
- const docSnap = await (0, import_firestore7.getDoc)(docRef);
1620
- if (!docSnap.exists()) {
1621
- return null;
1622
- }
1623
- const currentTemplate = docSnap.data();
1624
- if (version === void 0) {
1625
- return currentTemplate;
1626
- }
1627
- if (currentTemplate.version === version) {
1628
- return currentTemplate;
1629
- }
1630
- try {
1631
- const versionTemplate = await this.getTemplateVersion(
1632
- templateId,
1633
- version
1634
- );
1635
- if (versionTemplate) {
1636
- return versionTemplate;
1637
- }
1638
- } catch (error) {
1639
- console.error(`Error getting template version ${version}:`, error);
1640
- }
1641
- return null;
1591
+ * Vraća zahteve sertifikacije za tehnologiju
1592
+ * @param technologyId - ID tehnologije
1593
+ * @returns Zahtevi sertifikacije ili null ako tehnologija ne postoji
1594
+ */
1595
+ async getCertificationRequirement(technologyId) {
1596
+ const technology = await this.getById(technologyId);
1597
+ return (technology == null ? void 0 : technology.certificationRequirement) || null;
1642
1598
  }
1643
1599
  /**
1644
- * Update an existing document template
1645
- * @param templateId - ID of the template to update
1646
- * @param data - Updated template data
1647
- * @returns The updated template
1600
+ * Proverava da li doktor ima odgovarajuću sertifikaciju za izvođenje tehnologije
1601
+ *
1602
+ * @param requiredCertification - Zahtevana sertifikacija za tehnologiju
1603
+ * @param practitionerCertification - Sertifikacija zdravstvenog radnika
1604
+ * @returns true ako zdravstveni radnik ima odgovarajuću sertifikaciju, false ako nema
1605
+ *
1606
+ * @example
1607
+ * const isValid = technologyService.validateCertification(
1608
+ * {
1609
+ * minimumLevel: CertificationLevel.DOCTOR,
1610
+ * requiredSpecialties: [CertificationSpecialty.INJECTABLES]
1611
+ * },
1612
+ * {
1613
+ * level: CertificationLevel.SPECIALIST,
1614
+ * specialties: [CertificationSpecialty.INJECTABLES, CertificationSpecialty.LASER]
1615
+ * }
1616
+ * );
1648
1617
  */
1649
- async updateTemplate(templateId, data) {
1650
- var _a, _b, _c;
1651
- const validatedData = updateDocumentTemplateSchema.parse(data);
1652
- console.log("Validated data", validatedData);
1653
- const template = await this.getTemplateById(templateId);
1654
- if (!template) {
1655
- throw new Error(`Template with ID ${templateId} not found`);
1656
- }
1657
- const versionsCollectionRef = (0, import_firestore7.collection)(
1658
- this.db,
1659
- `${DOCUMENTATION_TEMPLATES_COLLECTION}/${templateId}/versions`
1618
+ validateCertification(requiredCertification, practitionerCertification) {
1619
+ const doctorLevel = Object.values(CertificationLevel).indexOf(
1620
+ practitionerCertification.level
1660
1621
  );
1661
- const versionDocRef = (0, import_firestore7.doc)(
1662
- versionsCollectionRef,
1663
- template.version.toString()
1622
+ const requiredLevel = Object.values(CertificationLevel).indexOf(
1623
+ requiredCertification.minimumLevel
1664
1624
  );
1665
- await (0, import_firestore7.setDoc)(versionDocRef, template);
1666
- let updatedElements = template.elements;
1667
- if (validatedData.elements) {
1668
- updatedElements = validatedData.elements.map((element) => ({
1669
- ...element,
1670
- id: element.id || this.generateId()
1671
- }));
1625
+ if (doctorLevel < requiredLevel) return false;
1626
+ const requiredSpecialties = requiredCertification.requiredSpecialties || [];
1627
+ if (requiredSpecialties.length > 0) {
1628
+ const doctorSpecialties = practitionerCertification.specialties;
1629
+ const hasAllRequiredSpecialties = requiredSpecialties.every(
1630
+ (requiredSpecialty) => doctorSpecialties.includes(requiredSpecialty)
1631
+ );
1632
+ if (!hasAllRequiredSpecialties) return false;
1672
1633
  }
1673
- const updatePayload = {
1674
- elements: updatedElements,
1675
- updatedAt: Date.now(),
1676
- version: template.version + 1
1677
- };
1678
- if (validatedData.title !== void 0)
1679
- updatePayload.title = validatedData.title;
1680
- if (validatedData.description !== void 0)
1681
- updatePayload.description = validatedData.description;
1682
- if (validatedData.isActive !== void 0)
1683
- updatePayload.isActive = validatedData.isActive;
1684
- if (validatedData.tags !== void 0)
1685
- updatePayload.tags = validatedData.tags;
1686
- updatePayload.isUserForm = (_a = validatedData.isUserForm) != null ? _a : false;
1687
- updatePayload.isRequired = (_b = validatedData.isRequired) != null ? _b : false;
1688
- updatePayload.sortingOrder = (_c = validatedData.sortingOrder) != null ? _c : 0;
1689
- const docRef = (0, import_firestore7.doc)(this.collectionRef, templateId);
1690
- console.log("Update payload", updatePayload);
1691
- await (0, import_firestore7.updateDoc)(docRef, updatePayload);
1692
- return { ...template, ...updatePayload };
1634
+ return true;
1693
1635
  }
1694
1636
  /**
1695
- * Get a specific version of a template
1696
- * @param templateId - ID of the template
1697
- * @param versionNumber - Version number to retrieve
1698
- * @returns The template version or null if not found
1637
+ * Vraća sve tehnologije koje je zdravstveni radnik sertifikovan da izvodi
1638
+ * zajedno sa listama dozvoljenih familija, kategorija i podkategorija
1639
+ *
1640
+ * @param practitioner - Profil zdravstvenog radnika
1641
+ * @returns Objekat koji sadrži:
1642
+ * - technologies: Lista tehnologija koje zdravstveni radnik može da izvodi
1643
+ * - families: Lista familija procedura koje zdravstveni radnik može da izvodi
1644
+ * - categories: Lista ID-eva kategorija koje zdravstveni radnik može da izvodi
1645
+ * - subcategories: Lista ID-eva podkategorija koje zdravstveni radnik može da izvodi
1646
+ *
1647
+ * @example
1648
+ * const practitioner = {
1649
+ * certification: {
1650
+ * level: CertificationLevel.DOCTOR,
1651
+ * specialties: [CertificationSpecialty.INJECTABLES]
1652
+ * }
1653
+ * };
1654
+ * const allowedTechnologies = await technologyService.getAllowedTechnologies(practitioner);
1655
+ * console.log(allowedTechnologies.families); // [ProcedureFamily.AESTHETICS]
1656
+ * console.log(allowedTechnologies.categories); // ["category1", "category2"]
1657
+ * console.log(allowedTechnologies.subcategories); // ["subcategory1", "subcategory2"]
1699
1658
  */
1700
- async getTemplateVersion(templateId, versionNumber) {
1701
- const versionDocRef = (0, import_firestore7.doc)(
1702
- this.db,
1703
- `${DOCUMENTATION_TEMPLATES_COLLECTION}/${templateId}/versions/${versionNumber}`
1659
+ async getAllowedTechnologies(practitioner) {
1660
+ const allTechnologies = await this.getAll();
1661
+ const allowedTechnologies = allTechnologies.filter(
1662
+ (technology) => this.validateCertification(
1663
+ technology.certificationRequirement,
1664
+ practitioner.certification
1665
+ )
1704
1666
  );
1705
- const versionDocSnap = await (0, import_firestore7.getDoc)(versionDocRef);
1706
- if (!versionDocSnap.exists()) {
1707
- return null;
1708
- }
1709
- return versionDocSnap.data();
1667
+ const families = [...new Set(allowedTechnologies.map((t) => t.family))];
1668
+ const categories = [
1669
+ ...new Set(allowedTechnologies.map((t) => t.categoryId))
1670
+ ];
1671
+ const subcategories = [
1672
+ ...new Set(allowedTechnologies.map((t) => t.subcategoryId))
1673
+ ];
1674
+ return {
1675
+ technologies: allowedTechnologies,
1676
+ families,
1677
+ categories,
1678
+ subcategories
1679
+ };
1710
1680
  }
1711
- /**
1712
- * Get all versions of a template
1713
- * @param templateId - ID of the template
1714
- * @returns Array of template versions
1715
- */
1716
- async getTemplateOldVersions(templateId) {
1717
- const versionsCollectionRef = (0, import_firestore7.collection)(
1718
- this.db,
1719
- `${DOCUMENTATION_TEMPLATES_COLLECTION}/${templateId}/versions`
1720
- );
1721
- const q = (0, import_firestore7.query)(versionsCollectionRef, (0, import_firestore7.orderBy)("version", "desc"));
1722
- const querySnapshot = await (0, import_firestore7.getDocs)(q);
1723
- const versions = [];
1724
- querySnapshot.forEach((doc10) => {
1725
- versions.push(doc10.data());
1726
- });
1727
- return versions;
1681
+ };
1682
+
1683
+ // src/backoffice/types/static/blocking-condition.types.ts
1684
+ var BlockingCondition = /* @__PURE__ */ ((BlockingCondition2) => {
1685
+ BlockingCondition2["PREGNANCY"] = "pregnancy";
1686
+ BlockingCondition2["BREASTFEEDING"] = "breastfeeding";
1687
+ BlockingCondition2["ACTIVE_INFECTION"] = "active_infection";
1688
+ BlockingCondition2["SKIN_CONDITION"] = "skin_condition";
1689
+ BlockingCondition2["AUTOIMMUNE_DISEASE"] = "autoimmune_disease";
1690
+ BlockingCondition2["BLOOD_THINNERS"] = "blood_thinners";
1691
+ BlockingCondition2["RECENT_SURGERY"] = "recent_surgery";
1692
+ BlockingCondition2["DIABETES"] = "diabetes";
1693
+ BlockingCondition2["HEART_CONDITION"] = "heart_condition";
1694
+ BlockingCondition2["HIGH_BLOOD_PRESSURE"] = "high_blood_pressure";
1695
+ BlockingCondition2["KELOID_SCARRING"] = "keloid_scarring";
1696
+ BlockingCondition2["METAL_IMPLANTS"] = "metal_implants";
1697
+ BlockingCondition2["PACEMAKER"] = "pacemaker";
1698
+ BlockingCondition2["CANCER"] = "cancer";
1699
+ BlockingCondition2["EPILEPSY"] = "epilepsy";
1700
+ return BlockingCondition2;
1701
+ })(BlockingCondition || {});
1702
+
1703
+ // src/backoffice/types/static/contraindication.types.ts
1704
+ var Contraindication = /* @__PURE__ */ ((Contraindication2) => {
1705
+ Contraindication2["SENSITIVE_SKIN"] = "sensitive_skin";
1706
+ Contraindication2["RECENT_TANNING"] = "recent_tanning";
1707
+ Contraindication2["RECENT_BOTOX"] = "recent_botox";
1708
+ Contraindication2["RECENT_FILLERS"] = "recent_fillers";
1709
+ Contraindication2["SKIN_ALLERGIES"] = "skin_allergies";
1710
+ Contraindication2["MEDICATIONS"] = "medications";
1711
+ Contraindication2["RECENT_CHEMICAL_PEEL"] = "recent_chemical_peel";
1712
+ Contraindication2["RECENT_LASER"] = "recent_laser";
1713
+ Contraindication2["SKIN_INFLAMMATION"] = "skin_inflammation";
1714
+ Contraindication2["OPEN_WOUNDS"] = "open_wounds";
1715
+ Contraindication2["HERPES_SIMPLEX"] = "herpes_simplex";
1716
+ Contraindication2["COLD_SORES"] = "cold_sores";
1717
+ return Contraindication2;
1718
+ })(Contraindication || {});
1719
+
1720
+ // src/backoffice/types/static/procedure-family.types.ts
1721
+ var ProcedureFamily = /* @__PURE__ */ ((ProcedureFamily2) => {
1722
+ ProcedureFamily2["AESTHETICS"] = "aesthetics";
1723
+ ProcedureFamily2["SURGERY"] = "surgery";
1724
+ return ProcedureFamily2;
1725
+ })(ProcedureFamily || {});
1726
+
1727
+ // src/backoffice/types/static/treatment-benefit.types.ts
1728
+ var TreatmentBenefit = /* @__PURE__ */ ((TreatmentBenefit2) => {
1729
+ TreatmentBenefit2["WRINKLE_REDUCTION"] = "wrinkle_reduction";
1730
+ TreatmentBenefit2["SKIN_TIGHTENING"] = "skin_tightening";
1731
+ TreatmentBenefit2["COLLAGEN_PRODUCTION"] = "collagen_production";
1732
+ TreatmentBenefit2["ACNE_REDUCTION"] = "acne_reduction";
1733
+ TreatmentBenefit2["SCAR_REDUCTION"] = "scar_reduction";
1734
+ TreatmentBenefit2["PIGMENTATION_IMPROVEMENT"] = "pigmentation_improvement";
1735
+ TreatmentBenefit2["HAIR_REMOVAL"] = "hair_removal";
1736
+ TreatmentBenefit2["MUSCLE_TONING"] = "muscle_toning";
1737
+ TreatmentBenefit2["FAT_REDUCTION"] = "fat_reduction";
1738
+ TreatmentBenefit2["CELLULITE_REDUCTION"] = "cellulite_reduction";
1739
+ TreatmentBenefit2["SKIN_REJUVENATION"] = "skin_rejuvenation";
1740
+ TreatmentBenefit2["PORE_REDUCTION"] = "pore_reduction";
1741
+ TreatmentBenefit2["TEXTURE_IMPROVEMENT"] = "texture_improvement";
1742
+ TreatmentBenefit2["HYDRATION_BOOST"] = "hydration_boost";
1743
+ TreatmentBenefit2["CIRCULATION_IMPROVEMENT"] = "circulation_improvement";
1744
+ return TreatmentBenefit2;
1745
+ })(TreatmentBenefit || {});
1746
+
1747
+ // src/backoffice/validations/schemas.ts
1748
+ var import_zod2 = require("zod");
1749
+ var blockingConditionSchema = import_zod2.z.nativeEnum(BlockingCondition);
1750
+ var contraindicationSchema = import_zod2.z.nativeEnum(Contraindication);
1751
+ var treatmentBenefitSchema = import_zod2.z.nativeEnum(TreatmentBenefit);
1752
+ var procedureFamilySchema = import_zod2.z.nativeEnum(ProcedureFamily);
1753
+ var timeUnitSchema = import_zod2.z.nativeEnum(TimeUnit);
1754
+ var requirementTypeSchema = import_zod2.z.nativeEnum(RequirementType);
1755
+ var certificationLevelSchema = import_zod2.z.nativeEnum(CertificationLevel);
1756
+ var certificationSpecialtySchema = import_zod2.z.nativeEnum(
1757
+ CertificationSpecialty
1758
+ );
1759
+ var certificationRequirementSchema = import_zod2.z.object({
1760
+ minimumLevel: certificationLevelSchema,
1761
+ requiredSpecialties: import_zod2.z.array(certificationSpecialtySchema).max(5, "Maximum 5 specialties allowed").optional()
1762
+ });
1763
+ var timeframeSchema = import_zod2.z.object({
1764
+ duration: import_zod2.z.number().min(1, "Duration must be positive"),
1765
+ unit: timeUnitSchema,
1766
+ notifyAt: import_zod2.z.array(import_zod2.z.number()).min(1, "At least one notification point is required")
1767
+ });
1768
+ var requirementSchema = import_zod2.z.object({
1769
+ name: import_zod2.z.string().min(1, "Name is required").max(100, "Name is too long"),
1770
+ description: import_zod2.z.string().min(1, "Description is required"),
1771
+ type: requirementTypeSchema,
1772
+ timeframe: timeframeSchema,
1773
+ importance: import_zod2.z.enum(["low", "medium", "high"]),
1774
+ isActive: import_zod2.z.boolean().default(true)
1775
+ });
1776
+ var technologyRequirementsSchema = import_zod2.z.object({
1777
+ pre: import_zod2.z.array(requirementSchema),
1778
+ post: import_zod2.z.array(requirementSchema)
1779
+ });
1780
+ var technologySchema = import_zod2.z.object({
1781
+ name: import_zod2.z.string().min(1, "Name is required").max(100, "Name is too long"),
1782
+ description: import_zod2.z.string().max(1e3, "Description is too long").optional(),
1783
+ technicalDetails: import_zod2.z.string().max(2e3, "Technical details are too long").optional(),
1784
+ family: procedureFamilySchema,
1785
+ categoryId: import_zod2.z.string().min(1, "Category ID is required"),
1786
+ subcategoryId: import_zod2.z.string().min(1, "Subcategory ID is required"),
1787
+ requirements: technologyRequirementsSchema.default({
1788
+ pre: [],
1789
+ post: []
1790
+ }),
1791
+ blockingConditions: import_zod2.z.array(blockingConditionSchema),
1792
+ contraindications: import_zod2.z.array(contraindicationSchema),
1793
+ documentationTemplates: import_zod2.z.array(documentTemplateSchema),
1794
+ benefits: import_zod2.z.array(treatmentBenefitSchema),
1795
+ certificationRequirement: certificationRequirementSchema,
1796
+ isActive: import_zod2.z.boolean().default(true)
1797
+ });
1798
+ var categorySchema = import_zod2.z.object({
1799
+ name: import_zod2.z.string().min(1, "Name is required").max(100, "Name is too long"),
1800
+ description: import_zod2.z.string().optional(),
1801
+ family: procedureFamilySchema,
1802
+ isActive: import_zod2.z.boolean().default(true)
1803
+ });
1804
+ var subcategorySchema = import_zod2.z.object({
1805
+ name: import_zod2.z.string().min(1, "Name is required").max(100, "Name is too long"),
1806
+ description: import_zod2.z.string().optional(),
1807
+ categoryId: import_zod2.z.string().min(1, "Category ID is required"),
1808
+ isActive: import_zod2.z.boolean().default(true)
1809
+ });
1810
+ var categoryUpdateSchema = categorySchema.partial();
1811
+ var subcategoryUpdateSchema = subcategorySchema.partial();
1812
+ var technologyUpdateSchema = technologySchema.partial();
1813
+ var requirementUpdateSchema = requirementSchema.partial();
1814
+
1815
+ // src/backoffice/constants/certification.constants.ts
1816
+ var DEFAULT_CERTIFICATION_REQUIREMENT2 = {
1817
+ minimumLevel: "aesthetician" /* AESTHETICIAN */,
1818
+ requiredSpecialties: []
1819
+ };
1820
+
1821
+ // src/backoffice/errors/backoffice.errors.ts
1822
+ var BackofficeError = class extends Error {
1823
+ constructor(message) {
1824
+ super(message);
1825
+ this.name = "BackofficeError";
1826
+ }
1827
+ };
1828
+ var CategoryError = class extends BackofficeError {
1829
+ constructor(message) {
1830
+ super(message);
1831
+ this.name = "CategoryError";
1832
+ }
1833
+ };
1834
+ var CategoryNotFoundError = class extends CategoryError {
1835
+ constructor(id) {
1836
+ super(`Kategorija sa ID-em ${id} nije prona\u0111ena`);
1837
+ this.name = "CategoryNotFoundError";
1838
+ }
1839
+ };
1840
+ var InvalidCategoryDataError = class extends CategoryError {
1841
+ constructor(message) {
1842
+ super(`Neva\u017Ee\u0107i podaci za kategoriju: ${message}`);
1843
+ this.name = "InvalidCategoryDataError";
1844
+ }
1845
+ };
1846
+ var SubcategoryError = class extends BackofficeError {
1847
+ constructor(message) {
1848
+ super(message);
1849
+ this.name = "SubcategoryError";
1850
+ }
1851
+ };
1852
+ var SubcategoryNotFoundError = class extends SubcategoryError {
1853
+ constructor(id) {
1854
+ super(`Podkategorija sa ID-em ${id} nije prona\u0111ena`);
1855
+ this.name = "SubcategoryNotFoundError";
1856
+ }
1857
+ };
1858
+ var InvalidSubcategoryDataError = class extends SubcategoryError {
1859
+ constructor(message) {
1860
+ super(`Neva\u017Ee\u0107i podaci za podkategoriju: ${message}`);
1861
+ this.name = "InvalidSubcategoryDataError";
1862
+ }
1863
+ };
1864
+ var TechnologyError = class extends BackofficeError {
1865
+ constructor(message) {
1866
+ super(message);
1867
+ this.name = "TechnologyError";
1728
1868
  }
1729
- /**
1730
- * Delete a document template
1731
- * @param templateId - ID of the template to delete
1732
- */
1733
- async deleteTemplate(templateId) {
1734
- const docRef = (0, import_firestore7.doc)(this.collectionRef, templateId);
1735
- await (0, import_firestore7.deleteDoc)(docRef);
1869
+ };
1870
+ var TechnologyNotFoundError = class extends TechnologyError {
1871
+ constructor(id) {
1872
+ super(`Tehnologija sa ID-em ${id} nije prona\u0111ena`);
1873
+ this.name = "TechnologyNotFoundError";
1736
1874
  }
1737
- /**
1738
- * Get all active templates
1739
- * @param pageSize - Number of templates to retrieve
1740
- * @param lastDoc - Last document from previous page for pagination
1741
- * @returns Array of templates and the last document for pagination
1742
- */
1743
- async getActiveTemplates(pageSize = 20, lastDoc) {
1744
- let q = (0, import_firestore7.query)(
1745
- this.collectionRef,
1746
- (0, import_firestore7.where)("isActive", "==", true),
1747
- (0, import_firestore7.orderBy)("updatedAt", "desc"),
1748
- (0, import_firestore7.limit)(pageSize)
1749
- );
1750
- if (lastDoc) {
1751
- q = (0, import_firestore7.query)(q, (0, import_firestore7.startAfter)(lastDoc));
1752
- }
1753
- const querySnapshot = await (0, import_firestore7.getDocs)(q);
1754
- const templates = [];
1755
- let lastVisible = null;
1756
- querySnapshot.forEach((doc10) => {
1757
- templates.push(doc10.data());
1758
- lastVisible = doc10;
1759
- });
1760
- return {
1761
- templates,
1762
- lastDoc: lastVisible
1763
- };
1875
+ };
1876
+ var InvalidTechnologyDataError = class extends TechnologyError {
1877
+ constructor(message) {
1878
+ super(`Neva\u017Ee\u0107i podaci za tehnologiju: ${message}`);
1879
+ this.name = "InvalidTechnologyDataError";
1764
1880
  }
1765
- /**
1766
- * Get templates by tags
1767
- * @param tags - Tags to filter by
1768
- * @param pageSize - Number of templates to retrieve
1769
- * @param lastDoc - Last document from previous page for pagination
1770
- * @returns Array of templates and the last document for pagination
1771
- */
1772
- async getTemplatesByTags(tags, pageSize = 20, lastDoc) {
1773
- let q = (0, import_firestore7.query)(
1774
- this.collectionRef,
1775
- (0, import_firestore7.where)("isActive", "==", true),
1776
- (0, import_firestore7.where)("tags", "array-contains-any", tags),
1777
- (0, import_firestore7.orderBy)("updatedAt", "desc"),
1778
- (0, import_firestore7.limit)(pageSize)
1779
- );
1780
- if (lastDoc) {
1781
- q = (0, import_firestore7.query)(q, (0, import_firestore7.startAfter)(lastDoc));
1782
- }
1783
- const querySnapshot = await (0, import_firestore7.getDocs)(q);
1784
- const templates = [];
1785
- let lastVisible = null;
1786
- querySnapshot.forEach((doc10) => {
1787
- templates.push(doc10.data());
1788
- lastVisible = doc10;
1789
- });
1790
- return {
1791
- templates,
1792
- lastDoc: lastVisible
1793
- };
1881
+ };
1882
+ var RequirementError = class extends BackofficeError {
1883
+ constructor(message) {
1884
+ super(message);
1885
+ this.name = "RequirementError";
1794
1886
  }
1795
- /**
1796
- * Get templates created by a specific user
1797
- * @param userId - ID of the user who created the templates
1798
- * @param pageSize - Number of templates to retrieve
1799
- * @param lastDoc - Last document from previous page for pagination
1800
- * @returns Array of templates and the last document for pagination
1801
- */
1802
- async getTemplatesByCreator(userId, pageSize = 20, lastDoc) {
1803
- let q = (0, import_firestore7.query)(
1804
- this.collectionRef,
1805
- (0, import_firestore7.where)("createdBy", "==", userId),
1806
- (0, import_firestore7.orderBy)("updatedAt", "desc"),
1807
- (0, import_firestore7.limit)(pageSize)
1808
- );
1809
- if (lastDoc) {
1810
- q = (0, import_firestore7.query)(q, (0, import_firestore7.startAfter)(lastDoc));
1811
- }
1812
- const querySnapshot = await (0, import_firestore7.getDocs)(q);
1813
- const templates = [];
1814
- let lastVisible = null;
1815
- querySnapshot.forEach((doc10) => {
1816
- templates.push(doc10.data());
1817
- lastVisible = doc10;
1818
- });
1819
- return {
1820
- templates,
1821
- lastDoc: lastVisible
1822
- };
1887
+ };
1888
+ var RequirementNotFoundError = class extends RequirementError {
1889
+ constructor(id) {
1890
+ super(`Zahtev sa ID-em ${id} nije prona\u0111en`);
1891
+ this.name = "RequirementNotFoundError";
1823
1892
  }
1824
- /**
1825
- * Get all templates for selection with optional filtering
1826
- * @param options - Filtering options
1827
- * @returns Array of templates
1828
- */
1829
- async getAllTemplatesForSelection(options) {
1830
- let q = (0, import_firestore7.query)(
1831
- this.collectionRef,
1832
- (0, import_firestore7.where)("isActive", "==", true),
1833
- (0, import_firestore7.orderBy)("updatedAt", "desc")
1834
- );
1835
- if ((options == null ? void 0 : options.isUserForm) !== void 0) {
1836
- q = (0, import_firestore7.query)(q, (0, import_firestore7.where)("isUserForm", "==", options.isUserForm));
1837
- }
1838
- if ((options == null ? void 0 : options.isRequired) !== void 0) {
1839
- q = (0, import_firestore7.query)(q, (0, import_firestore7.where)("isRequired", "==", options.isRequired));
1840
- }
1841
- const querySnapshot = await (0, import_firestore7.getDocs)(q);
1842
- const templates = [];
1843
- querySnapshot.forEach((doc10) => {
1844
- templates.push(doc10.data());
1845
- });
1846
- return templates;
1893
+ };
1894
+ var InvalidRequirementDataError = class extends RequirementError {
1895
+ constructor(message) {
1896
+ super(`Neva\u017Ee\u0107i podaci za zahtev: ${message}`);
1897
+ this.name = "InvalidRequirementDataError";
1847
1898
  }
1848
1899
  };
1849
-
1850
- // src/services/documentation-templates/filled-document.service.ts
1851
- var import_firestore10 = require("firebase/firestore");
1852
-
1853
- // src/services/media/media.service.ts
1854
- var import_firestore8 = require("firebase/firestore");
1855
- var import_storage2 = require("firebase/storage");
1856
- var import_firestore9 = require("firebase/firestore");
1857
-
1858
- // src/backoffice/services/documentation-template.service.ts
1859
- var DocumentationTemplateService2 = class {
1860
- /**
1861
- * Constructor for DocumentationTemplateService
1862
- * @param db - Firestore instance
1863
- * @param auth - Firebase Auth instance
1864
- * @param app - Firebase App instance
1865
- */
1866
- constructor(db, auth, app) {
1867
- this.apiService = new DocumentationTemplateService(db, auth, app);
1900
+ var InvalidTimeframeError = class extends RequirementError {
1901
+ constructor(message) {
1902
+ super(`Invalid timeframe: ${message}`);
1903
+ this.name = "InvalidTimeframeError";
1868
1904
  }
1869
- /**
1870
- * Create a new document template
1871
- * @param data - Template data
1872
- * @param userId - ID of the user creating the template
1873
- * @returns The created template
1874
- */
1875
- async createTemplate(data, userId) {
1876
- return this.apiService.createTemplate(data, userId);
1905
+ };
1906
+ var RelationshipError = class extends BackofficeError {
1907
+ constructor(message) {
1908
+ super(message);
1909
+ this.name = "RelationshipError";
1877
1910
  }
1878
- /**
1879
- * Get a document template by ID
1880
- * @param templateId - ID of the template to retrieve
1881
- * @param version - Optional version number to retrieve (defaults to latest version)
1882
- * @returns The template or null if not found
1883
- */
1884
- async getTemplateById(templateId, version) {
1885
- return this.apiService.getTemplateById(templateId, version);
1911
+ };
1912
+ var InvalidHierarchyError = class extends RelationshipError {
1913
+ constructor(message) {
1914
+ super(`Invalid hierarchy: ${message}`);
1915
+ this.name = "InvalidHierarchyError";
1886
1916
  }
1887
- /**
1888
- * Update an existing document template
1889
- * @param templateId - ID of the template to update
1890
- * @param data - Updated template data
1891
- * @returns The updated template
1892
- */
1893
- async updateTemplate(templateId, data) {
1894
- return this.apiService.updateTemplate(templateId, data);
1917
+ };
1918
+ var CircularReferenceError = class extends RelationshipError {
1919
+ constructor(message) {
1920
+ super(`Circular reference detected: ${message}`);
1921
+ this.name = "CircularReferenceError";
1895
1922
  }
1896
- /**
1897
- * Delete a document template
1898
- * @param templateId - ID of the template to delete
1899
- */
1900
- async deleteTemplate(templateId) {
1901
- return this.apiService.deleteTemplate(templateId);
1923
+ };
1924
+ var BlockingConditionError = class extends BackofficeError {
1925
+ constructor(message) {
1926
+ super(message);
1927
+ this.name = "BlockingConditionError";
1902
1928
  }
1903
- /**
1904
- * Get all active templates
1905
- * @param pageSize - Number of templates to retrieve
1906
- * @param lastDoc - Last document from previous page for pagination
1907
- * @returns Array of templates and the last document for pagination
1908
- */
1909
- async getActiveTemplates(pageSize = 20, lastDoc) {
1910
- return this.apiService.getActiveTemplates(pageSize, lastDoc);
1929
+ };
1930
+ var InvalidBlockingConditionError = class extends BlockingConditionError {
1931
+ constructor(condition) {
1932
+ super(`Neva\u017Ee\u0107i blokiraju\u0107i uslov: ${condition}`);
1933
+ this.name = "InvalidBlockingConditionError";
1911
1934
  }
1912
- /**
1913
- * Get templates by tags
1914
- * @param tags - Tags to filter by
1915
- * @param pageSize - Number of templates to retrieve
1916
- * @param lastDoc - Last document from previous page for pagination
1917
- * @returns Array of templates and the last document for pagination
1918
- */
1919
- async getTemplatesByTags(tags, pageSize = 20, lastDoc) {
1920
- return this.apiService.getTemplatesByTags(tags, pageSize, lastDoc);
1935
+ };
1936
+ var ContraindicationError = class extends BackofficeError {
1937
+ constructor(message) {
1938
+ super(message);
1939
+ this.name = "ContraindicationError";
1921
1940
  }
1922
- /**
1923
- * Get templates created by a specific user
1924
- * @param userId - ID of the user who created the templates
1925
- * @param pageSize - Number of templates to retrieve
1926
- * @param lastDoc - Last document from previous page for pagination
1927
- * @returns Array of templates and the last document for pagination
1928
- */
1929
- async getTemplatesByCreator(userId, pageSize = 20, lastDoc) {
1930
- return this.apiService.getTemplatesByCreator(userId, pageSize, lastDoc);
1941
+ };
1942
+ var InvalidContraindicationError = class extends ContraindicationError {
1943
+ constructor(contraindication) {
1944
+ super(`Neva\u017Ee\u0107a kontraindikacija: ${contraindication}`);
1945
+ this.name = "InvalidContraindicationError";
1931
1946
  }
1932
- /**
1933
- * Get a specific version of a template
1934
- * @param templateId - ID of the template
1935
- * @param versionNumber - Version number to retrieve
1936
- * @returns The template version or null if not found
1937
- */
1938
- async getTemplateVersion(templateId, versionNumber) {
1939
- return this.apiService.getTemplateVersion(templateId, versionNumber);
1947
+ };
1948
+ var TreatmentBenefitError = class extends BackofficeError {
1949
+ constructor(message) {
1950
+ super(message);
1951
+ this.name = "TreatmentBenefitError";
1940
1952
  }
1941
- /**
1942
- * Get all versions of a template
1943
- * @param templateId - ID of the template
1944
- * @returns Array of template versions
1945
- */
1946
- async getTemplateVersions(templateId) {
1947
- return this.apiService.getTemplateOldVersions(templateId);
1953
+ };
1954
+ var InvalidTreatmentBenefitError = class extends TreatmentBenefitError {
1955
+ constructor(benefit) {
1956
+ super(`Neva\u017Ee\u0107i benefit tretmana: ${benefit}`);
1957
+ this.name = "InvalidTreatmentBenefitError";
1948
1958
  }
1949
1959
  };
1950
1960
  // Annotate the CommonJS export names for ESM import in node: