@blackcode_sa/metaestetics-api 1.11.2 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/index.d.mts +331 -318
- package/dist/admin/index.d.ts +331 -318
- package/dist/backoffice/index.d.mts +1166 -430
- package/dist/backoffice/index.d.ts +1166 -430
- package/dist/backoffice/index.js +1128 -245
- package/dist/backoffice/index.mjs +1119 -209
- package/dist/index.d.mts +4429 -4034
- package/dist/index.d.ts +4429 -4034
- package/dist/index.js +1644 -666
- package/dist/index.mjs +1408 -402
- package/package.json +1 -1
- package/src/backoffice/expo-safe/index.ts +3 -0
- package/src/backoffice/services/README.md +40 -0
- package/src/backoffice/services/brand.service.ts +85 -6
- package/src/backoffice/services/category.service.ts +92 -10
- package/src/backoffice/services/constants.service.ts +308 -0
- package/src/backoffice/services/documentation-template.service.ts +56 -2
- package/src/backoffice/services/index.ts +1 -0
- package/src/backoffice/services/product.service.ts +126 -5
- package/src/backoffice/services/requirement.service.ts +13 -0
- package/src/backoffice/services/subcategory.service.ts +184 -13
- package/src/backoffice/services/technology.service.ts +344 -129
- package/src/backoffice/types/admin-constants.types.ts +69 -0
- package/src/backoffice/types/brand.types.ts +1 -0
- package/src/backoffice/types/index.ts +1 -0
- package/src/backoffice/types/product.types.ts +31 -4
- package/src/backoffice/types/static/contraindication.types.ts +1 -0
- package/src/backoffice/types/static/treatment-benefit.types.ts +1 -0
- package/src/backoffice/types/technology.types.ts +113 -4
- package/src/backoffice/validations/schemas.ts +35 -9
- package/src/services/appointment/appointment.service.ts +0 -5
- package/src/services/appointment/utils/appointment.utils.ts +124 -113
- package/src/services/base.service.ts +10 -3
- package/src/services/documentation-templates/documentation-template.service.ts +116 -0
- package/src/services/media/media.service.ts +2 -2
- package/src/services/procedure/procedure.service.ts +436 -234
- package/src/types/appointment/index.ts +4 -3
- package/src/types/clinic/index.ts +1 -6
- package/src/types/patient/medical-info.types.ts +3 -3
- package/src/types/procedure/index.ts +20 -17
- package/src/validations/appointment.schema.ts +1 -0
- package/src/validations/clinic.schema.ts +1 -6
- package/src/validations/patient/medical-info.schema.ts +7 -2
- package/src/backoffice/services/__tests__/brand.service.test.ts +0 -196
- package/src/backoffice/services/__tests__/category.service.test.ts +0 -201
- package/src/backoffice/services/__tests__/product.service.test.ts +0 -358
- package/src/backoffice/services/__tests__/requirement.service.test.ts +0 -226
- package/src/backoffice/services/__tests__/subcategory.service.test.ts +0 -181
- package/src/backoffice/services/__tests__/technology.service.test.ts +0 -1097
package/dist/backoffice/index.js
CHANGED
|
@@ -32,6 +32,7 @@ __export(index_exports, {
|
|
|
32
32
|
CertificationLevel: () => CertificationLevel,
|
|
33
33
|
CertificationSpecialty: () => CertificationSpecialty,
|
|
34
34
|
CircularReferenceError: () => CircularReferenceError,
|
|
35
|
+
ConstantsService: () => ConstantsService,
|
|
35
36
|
Contraindication: () => Contraindication,
|
|
36
37
|
ContraindicationError: () => ContraindicationError,
|
|
37
38
|
Currency: () => Currency,
|
|
@@ -79,6 +80,7 @@ __export(index_exports, {
|
|
|
79
80
|
certificationLevelSchema: () => certificationLevelSchema,
|
|
80
81
|
certificationRequirementSchema: () => certificationRequirementSchema,
|
|
81
82
|
certificationSpecialtySchema: () => certificationSpecialtySchema,
|
|
83
|
+
contraindicationDynamicSchema: () => contraindicationDynamicSchema,
|
|
82
84
|
contraindicationSchemaBackoffice: () => contraindicationSchemaBackoffice,
|
|
83
85
|
createDocumentTemplateSchema: () => createDocumentTemplateSchema,
|
|
84
86
|
documentElementSchema: () => documentElementSchema,
|
|
@@ -95,6 +97,7 @@ __export(index_exports, {
|
|
|
95
97
|
technologyUpdateSchema: () => technologyUpdateSchema,
|
|
96
98
|
timeUnitSchemaBackoffice: () => timeUnitSchemaBackoffice,
|
|
97
99
|
timeframeSchema: () => timeframeSchema,
|
|
100
|
+
treatmentBenefitDynamicSchema: () => treatmentBenefitDynamicSchema,
|
|
98
101
|
treatmentBenefitSchemaBackoffice: () => treatmentBenefitSchemaBackoffice,
|
|
99
102
|
updateDocumentTemplateSchema: () => updateDocumentTemplateSchema
|
|
100
103
|
});
|
|
@@ -109,11 +112,13 @@ var BRANDS_COLLECTION = "brands";
|
|
|
109
112
|
// src/services/base.service.ts
|
|
110
113
|
var import_storage = require("firebase/storage");
|
|
111
114
|
var BaseService = class {
|
|
112
|
-
constructor(db, auth, app) {
|
|
115
|
+
constructor(db, auth, app, storage) {
|
|
113
116
|
this.db = db;
|
|
114
117
|
this.auth = auth;
|
|
115
118
|
this.app = app;
|
|
116
|
-
|
|
119
|
+
if (app) {
|
|
120
|
+
this.storage = storage || (0, import_storage.getStorage)(app);
|
|
121
|
+
}
|
|
117
122
|
}
|
|
118
123
|
/**
|
|
119
124
|
* Generiše jedinstveni ID za dokumente
|
|
@@ -146,6 +151,7 @@ var BrandService = class extends BaseService {
|
|
|
146
151
|
const now = /* @__PURE__ */ new Date();
|
|
147
152
|
const newBrand = {
|
|
148
153
|
...brand,
|
|
154
|
+
name_lowercase: brand.name.toLowerCase(),
|
|
149
155
|
createdAt: now,
|
|
150
156
|
updatedAt: now,
|
|
151
157
|
isActive: true
|
|
@@ -154,15 +160,69 @@ var BrandService = class extends BaseService {
|
|
|
154
160
|
return { id: docRef.id, ...newBrand };
|
|
155
161
|
}
|
|
156
162
|
/**
|
|
157
|
-
* Gets
|
|
163
|
+
* Gets a paginated list of active brands, optionally filtered by name.
|
|
164
|
+
* @param rowsPerPage - The number of brands to fetch.
|
|
165
|
+
* @param searchTerm - An optional string to filter brand names by (starts-with search).
|
|
166
|
+
* @param lastVisible - An optional document snapshot to use as a cursor for pagination.
|
|
158
167
|
*/
|
|
159
|
-
async getAll() {
|
|
160
|
-
const
|
|
168
|
+
async getAll(rowsPerPage, searchTerm, lastVisible) {
|
|
169
|
+
const constraints = [
|
|
170
|
+
(0, import_firestore.where)("isActive", "==", true),
|
|
171
|
+
(0, import_firestore.orderBy)("name_lowercase")
|
|
172
|
+
];
|
|
173
|
+
if (searchTerm) {
|
|
174
|
+
const lowercasedSearchTerm = searchTerm.toLowerCase();
|
|
175
|
+
constraints.push((0, import_firestore.where)("name_lowercase", ">=", lowercasedSearchTerm));
|
|
176
|
+
constraints.push(
|
|
177
|
+
(0, import_firestore.where)("name_lowercase", "<=", lowercasedSearchTerm + "\uF8FF")
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
if (lastVisible) {
|
|
181
|
+
constraints.push((0, import_firestore.startAfter)(lastVisible));
|
|
182
|
+
}
|
|
183
|
+
constraints.push((0, import_firestore.limit)(rowsPerPage));
|
|
184
|
+
const q = (0, import_firestore.query)(this.getBrandsRef(), ...constraints);
|
|
185
|
+
const snapshot = await (0, import_firestore.getDocs)(q);
|
|
186
|
+
const brands = snapshot.docs.map(
|
|
187
|
+
(doc11) => ({
|
|
188
|
+
id: doc11.id,
|
|
189
|
+
...doc11.data()
|
|
190
|
+
})
|
|
191
|
+
);
|
|
192
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
193
|
+
return { brands, lastVisible: newLastVisible };
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Gets the total count of active brands, optionally filtered by name.
|
|
197
|
+
* @param searchTerm - An optional string to filter brand names by (starts-with search).
|
|
198
|
+
*/
|
|
199
|
+
async getBrandsCount(searchTerm) {
|
|
200
|
+
const constraints = [(0, import_firestore.where)("isActive", "==", true)];
|
|
201
|
+
if (searchTerm) {
|
|
202
|
+
const lowercasedSearchTerm = searchTerm.toLowerCase();
|
|
203
|
+
constraints.push((0, import_firestore.where)("name_lowercase", ">=", lowercasedSearchTerm));
|
|
204
|
+
constraints.push(
|
|
205
|
+
(0, import_firestore.where)("name_lowercase", "<=", lowercasedSearchTerm + "\uF8FF")
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
const q = (0, import_firestore.query)(this.getBrandsRef(), ...constraints);
|
|
209
|
+
const snapshot = await (0, import_firestore.getCountFromServer)(q);
|
|
210
|
+
return snapshot.data().count;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Gets all active brands for filter dropdowns (not paginated).
|
|
214
|
+
*/
|
|
215
|
+
async getAllForFilter() {
|
|
216
|
+
const q = (0, import_firestore.query)(
|
|
217
|
+
this.getBrandsRef(),
|
|
218
|
+
(0, import_firestore.where)("isActive", "==", true),
|
|
219
|
+
(0, import_firestore.orderBy)("name")
|
|
220
|
+
);
|
|
161
221
|
const snapshot = await (0, import_firestore.getDocs)(q);
|
|
162
222
|
return snapshot.docs.map(
|
|
163
|
-
(
|
|
164
|
-
id:
|
|
165
|
-
...
|
|
223
|
+
(doc11) => ({
|
|
224
|
+
id: doc11.id,
|
|
225
|
+
...doc11.data()
|
|
166
226
|
})
|
|
167
227
|
);
|
|
168
228
|
}
|
|
@@ -174,6 +234,9 @@ var BrandService = class extends BaseService {
|
|
|
174
234
|
...brand,
|
|
175
235
|
updatedAt: /* @__PURE__ */ new Date()
|
|
176
236
|
};
|
|
237
|
+
if (brand.name) {
|
|
238
|
+
updateData.name_lowercase = brand.name.toLowerCase();
|
|
239
|
+
}
|
|
177
240
|
const docRef = (0, import_firestore.doc)(this.getBrandsRef(), brandId);
|
|
178
241
|
await (0, import_firestore.updateDoc)(docRef, updateData);
|
|
179
242
|
return this.getById(brandId);
|
|
@@ -206,6 +269,13 @@ var import_firestore2 = require("firebase/firestore");
|
|
|
206
269
|
// src/backoffice/types/category.types.ts
|
|
207
270
|
var CATEGORIES_COLLECTION = "backoffice_categories";
|
|
208
271
|
|
|
272
|
+
// src/backoffice/types/static/procedure-family.types.ts
|
|
273
|
+
var ProcedureFamily = /* @__PURE__ */ ((ProcedureFamily2) => {
|
|
274
|
+
ProcedureFamily2["AESTHETICS"] = "aesthetics";
|
|
275
|
+
ProcedureFamily2["SURGERY"] = "surgery";
|
|
276
|
+
return ProcedureFamily2;
|
|
277
|
+
})(ProcedureFamily || {});
|
|
278
|
+
|
|
209
279
|
// src/backoffice/services/category.service.ts
|
|
210
280
|
var CategoryService = class extends BaseService {
|
|
211
281
|
/**
|
|
@@ -231,37 +301,87 @@ var CategoryService = class extends BaseService {
|
|
|
231
301
|
return { id: docRef.id, ...newCategory };
|
|
232
302
|
}
|
|
233
303
|
/**
|
|
234
|
-
*
|
|
235
|
-
* @
|
|
304
|
+
* Returns counts of categories for each family.
|
|
305
|
+
* @param active - Whether to count active or inactive categories.
|
|
306
|
+
* @returns A record mapping family to category count.
|
|
236
307
|
*/
|
|
237
|
-
async
|
|
308
|
+
async getCategoryCounts(active = true) {
|
|
309
|
+
const counts = {};
|
|
310
|
+
const families = Object.values(ProcedureFamily);
|
|
311
|
+
for (const family of families) {
|
|
312
|
+
const q = (0, import_firestore2.query)(
|
|
313
|
+
this.categoriesRef,
|
|
314
|
+
(0, import_firestore2.where)("family", "==", family),
|
|
315
|
+
(0, import_firestore2.where)("isActive", "==", active)
|
|
316
|
+
);
|
|
317
|
+
const snapshot = await (0, import_firestore2.getCountFromServer)(q);
|
|
318
|
+
counts[family] = snapshot.data().count;
|
|
319
|
+
}
|
|
320
|
+
return counts;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Vraća sve kategorije za potrebe filtera (bez paginacije)
|
|
324
|
+
* @returns Lista svih aktivnih kategorija
|
|
325
|
+
*/
|
|
326
|
+
async getAllForFilter() {
|
|
238
327
|
const q = (0, import_firestore2.query)(this.categoriesRef, (0, import_firestore2.where)("isActive", "==", true));
|
|
239
328
|
const snapshot = await (0, import_firestore2.getDocs)(q);
|
|
240
329
|
return snapshot.docs.map(
|
|
241
|
-
(
|
|
242
|
-
id:
|
|
243
|
-
...
|
|
330
|
+
(doc11) => ({
|
|
331
|
+
id: doc11.id,
|
|
332
|
+
...doc11.data()
|
|
244
333
|
})
|
|
245
334
|
);
|
|
246
335
|
}
|
|
247
336
|
/**
|
|
248
|
-
* Vraća sve
|
|
337
|
+
* Vraća sve kategorije sa paginacijom
|
|
338
|
+
* @param options - Pagination and filter options
|
|
339
|
+
* @returns Lista kategorija i poslednji vidljiv dokument
|
|
340
|
+
*/
|
|
341
|
+
async getAll(options = {}) {
|
|
342
|
+
const { active = true, limit: queryLimit = 10, lastVisible } = options;
|
|
343
|
+
const constraints = [
|
|
344
|
+
(0, import_firestore2.where)("isActive", "==", active),
|
|
345
|
+
(0, import_firestore2.orderBy)("name"),
|
|
346
|
+
queryLimit ? (0, import_firestore2.limit)(queryLimit) : void 0,
|
|
347
|
+
lastVisible ? (0, import_firestore2.startAfter)(lastVisible) : void 0
|
|
348
|
+
].filter((c) => !!c);
|
|
349
|
+
const q = (0, import_firestore2.query)(this.categoriesRef, ...constraints);
|
|
350
|
+
const snapshot = await (0, import_firestore2.getDocs)(q);
|
|
351
|
+
const categories = snapshot.docs.map(
|
|
352
|
+
(doc11) => ({
|
|
353
|
+
id: doc11.id,
|
|
354
|
+
...doc11.data()
|
|
355
|
+
})
|
|
356
|
+
);
|
|
357
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
358
|
+
return { categories, lastVisible: newLastVisible };
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Vraća sve aktivne kategorije za određenu familiju procedura sa paginacijom
|
|
249
362
|
* @param family - Familija procedura (aesthetics/surgery)
|
|
363
|
+
* @param options - Pagination options
|
|
250
364
|
* @returns Lista kategorija koje pripadaju traženoj familiji
|
|
251
365
|
*/
|
|
252
|
-
async getAllByFamily(family) {
|
|
253
|
-
const
|
|
254
|
-
|
|
366
|
+
async getAllByFamily(family, options = {}) {
|
|
367
|
+
const { active = true, limit: queryLimit = 10, lastVisible } = options;
|
|
368
|
+
const constraints = [
|
|
255
369
|
(0, import_firestore2.where)("family", "==", family),
|
|
256
|
-
(0, import_firestore2.where)("isActive", "==",
|
|
257
|
-
|
|
370
|
+
(0, import_firestore2.where)("isActive", "==", active),
|
|
371
|
+
(0, import_firestore2.orderBy)("name"),
|
|
372
|
+
queryLimit ? (0, import_firestore2.limit)(queryLimit) : void 0,
|
|
373
|
+
lastVisible ? (0, import_firestore2.startAfter)(lastVisible) : void 0
|
|
374
|
+
].filter((c) => !!c);
|
|
375
|
+
const q = (0, import_firestore2.query)(this.categoriesRef, ...constraints);
|
|
258
376
|
const snapshot = await (0, import_firestore2.getDocs)(q);
|
|
259
|
-
|
|
260
|
-
(
|
|
261
|
-
id:
|
|
262
|
-
...
|
|
377
|
+
const categories = snapshot.docs.map(
|
|
378
|
+
(doc11) => ({
|
|
379
|
+
id: doc11.id,
|
|
380
|
+
...doc11.data()
|
|
263
381
|
})
|
|
264
382
|
);
|
|
383
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
384
|
+
return { categories, lastVisible: newLastVisible };
|
|
265
385
|
}
|
|
266
386
|
/**
|
|
267
387
|
* Ažurira postojeću kategoriju
|
|
@@ -285,6 +405,13 @@ var CategoryService = class extends BaseService {
|
|
|
285
405
|
async delete(id) {
|
|
286
406
|
await this.update(id, { isActive: false });
|
|
287
407
|
}
|
|
408
|
+
/**
|
|
409
|
+
* Reactivates a category by setting its isActive flag to true.
|
|
410
|
+
* @param id - The ID of the category to reactivate.
|
|
411
|
+
*/
|
|
412
|
+
async reactivate(id) {
|
|
413
|
+
await this.update(id, { isActive: true });
|
|
414
|
+
}
|
|
288
415
|
/**
|
|
289
416
|
* Vraća kategoriju po ID-u
|
|
290
417
|
* @param id - ID tražene kategorije
|
|
@@ -536,9 +663,10 @@ var updateFilledDocumentDataSchema = import_zod.z.object({
|
|
|
536
663
|
});
|
|
537
664
|
|
|
538
665
|
// src/services/documentation-templates/documentation-template.service.ts
|
|
666
|
+
var import_firestore4 = require("firebase/firestore");
|
|
539
667
|
var DocumentationTemplateService = class extends BaseService {
|
|
540
|
-
constructor() {
|
|
541
|
-
super(...
|
|
668
|
+
constructor(...args) {
|
|
669
|
+
super(...args);
|
|
542
670
|
this.collectionRef = (0, import_firestore3.collection)(
|
|
543
671
|
this.db,
|
|
544
672
|
DOCUMENTATION_TEMPLATES_COLLECTION
|
|
@@ -690,8 +818,8 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
690
818
|
const q = (0, import_firestore3.query)(versionsCollectionRef, (0, import_firestore3.orderBy)("version", "desc"));
|
|
691
819
|
const querySnapshot = await (0, import_firestore3.getDocs)(q);
|
|
692
820
|
const versions = [];
|
|
693
|
-
querySnapshot.forEach((
|
|
694
|
-
versions.push(
|
|
821
|
+
querySnapshot.forEach((doc11) => {
|
|
822
|
+
versions.push(doc11.data());
|
|
695
823
|
});
|
|
696
824
|
return versions;
|
|
697
825
|
}
|
|
@@ -722,15 +850,97 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
722
850
|
const querySnapshot = await (0, import_firestore3.getDocs)(q);
|
|
723
851
|
const templates = [];
|
|
724
852
|
let lastVisible = null;
|
|
725
|
-
querySnapshot.forEach((
|
|
726
|
-
templates.push(
|
|
727
|
-
lastVisible =
|
|
853
|
+
querySnapshot.forEach((doc11) => {
|
|
854
|
+
templates.push(doc11.data());
|
|
855
|
+
lastVisible = doc11;
|
|
728
856
|
});
|
|
729
857
|
return {
|
|
730
858
|
templates,
|
|
731
859
|
lastDoc: lastVisible
|
|
732
860
|
};
|
|
733
861
|
}
|
|
862
|
+
/**
|
|
863
|
+
* Get all active templates with optional filters and pagination.
|
|
864
|
+
* @param options - Options for filtering and pagination.
|
|
865
|
+
* @returns A promise that resolves to the templates and the last visible document.
|
|
866
|
+
*/
|
|
867
|
+
async getTemplates(options) {
|
|
868
|
+
const {
|
|
869
|
+
pageSize = 20,
|
|
870
|
+
lastDoc,
|
|
871
|
+
isUserForm,
|
|
872
|
+
isRequired,
|
|
873
|
+
sortingOrder
|
|
874
|
+
} = options;
|
|
875
|
+
const constraints = [
|
|
876
|
+
(0, import_firestore3.where)("isActive", "==", true),
|
|
877
|
+
(0, import_firestore3.orderBy)("sortingOrder", "asc"),
|
|
878
|
+
(0, import_firestore3.orderBy)("title", "asc"),
|
|
879
|
+
(0, import_firestore3.limit)(pageSize)
|
|
880
|
+
];
|
|
881
|
+
if (isUserForm !== void 0) {
|
|
882
|
+
constraints.push((0, import_firestore3.where)("isUserForm", "==", isUserForm));
|
|
883
|
+
}
|
|
884
|
+
if (isRequired !== void 0) {
|
|
885
|
+
constraints.push((0, import_firestore3.where)("isRequired", "==", isRequired));
|
|
886
|
+
}
|
|
887
|
+
if (sortingOrder !== void 0) {
|
|
888
|
+
constraints.push((0, import_firestore3.where)("sortingOrder", "==", sortingOrder));
|
|
889
|
+
}
|
|
890
|
+
if (lastDoc) {
|
|
891
|
+
constraints.push((0, import_firestore3.startAfter)(lastDoc));
|
|
892
|
+
}
|
|
893
|
+
const q = (0, import_firestore3.query)(this.collectionRef, ...constraints.filter((c) => c));
|
|
894
|
+
const querySnapshot = await (0, import_firestore3.getDocs)(q);
|
|
895
|
+
const templates = [];
|
|
896
|
+
let lastVisible = null;
|
|
897
|
+
querySnapshot.forEach((doc11) => {
|
|
898
|
+
templates.push(doc11.data());
|
|
899
|
+
lastVisible = doc11;
|
|
900
|
+
});
|
|
901
|
+
return {
|
|
902
|
+
templates,
|
|
903
|
+
lastDoc: lastVisible
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* Get the total count of active templates with optional filters.
|
|
908
|
+
* @param options - Options for filtering.
|
|
909
|
+
* @returns A promise that resolves to the total count of templates.
|
|
910
|
+
*/
|
|
911
|
+
async getTemplatesCount(options) {
|
|
912
|
+
const { isUserForm, isRequired, sortingOrder } = options;
|
|
913
|
+
const constraints = [(0, import_firestore3.where)("isActive", "==", true)];
|
|
914
|
+
if (isUserForm !== void 0) {
|
|
915
|
+
constraints.push((0, import_firestore3.where)("isUserForm", "==", isUserForm));
|
|
916
|
+
}
|
|
917
|
+
if (isRequired !== void 0) {
|
|
918
|
+
constraints.push((0, import_firestore3.where)("isRequired", "==", isRequired));
|
|
919
|
+
}
|
|
920
|
+
if (sortingOrder !== void 0) {
|
|
921
|
+
constraints.push((0, import_firestore3.where)("sortingOrder", "==", sortingOrder));
|
|
922
|
+
}
|
|
923
|
+
const q = (0, import_firestore3.query)(this.collectionRef, ...constraints.filter((c) => c));
|
|
924
|
+
const snapshot = await (0, import_firestore4.getCountFromServer)(q);
|
|
925
|
+
return snapshot.data().count;
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* Get all active templates without pagination for filtering purposes.
|
|
929
|
+
* @returns A promise that resolves to an array of all active templates.
|
|
930
|
+
*/
|
|
931
|
+
async getAllActiveTemplates() {
|
|
932
|
+
const q = (0, import_firestore3.query)(
|
|
933
|
+
this.collectionRef,
|
|
934
|
+
(0, import_firestore3.where)("isActive", "==", true),
|
|
935
|
+
(0, import_firestore3.orderBy)("title", "asc")
|
|
936
|
+
);
|
|
937
|
+
const querySnapshot = await (0, import_firestore3.getDocs)(q);
|
|
938
|
+
const templates = [];
|
|
939
|
+
querySnapshot.forEach((doc11) => {
|
|
940
|
+
templates.push(doc11.data());
|
|
941
|
+
});
|
|
942
|
+
return templates;
|
|
943
|
+
}
|
|
734
944
|
/**
|
|
735
945
|
* Get templates by tags
|
|
736
946
|
* @param tags - Tags to filter by
|
|
@@ -752,9 +962,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
752
962
|
const querySnapshot = await (0, import_firestore3.getDocs)(q);
|
|
753
963
|
const templates = [];
|
|
754
964
|
let lastVisible = null;
|
|
755
|
-
querySnapshot.forEach((
|
|
756
|
-
templates.push(
|
|
757
|
-
lastVisible =
|
|
965
|
+
querySnapshot.forEach((doc11) => {
|
|
966
|
+
templates.push(doc11.data());
|
|
967
|
+
lastVisible = doc11;
|
|
758
968
|
});
|
|
759
969
|
return {
|
|
760
970
|
templates,
|
|
@@ -781,9 +991,9 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
781
991
|
const querySnapshot = await (0, import_firestore3.getDocs)(q);
|
|
782
992
|
const templates = [];
|
|
783
993
|
let lastVisible = null;
|
|
784
|
-
querySnapshot.forEach((
|
|
785
|
-
templates.push(
|
|
786
|
-
lastVisible =
|
|
994
|
+
querySnapshot.forEach((doc11) => {
|
|
995
|
+
templates.push(doc11.data());
|
|
996
|
+
lastVisible = doc11;
|
|
787
997
|
});
|
|
788
998
|
return {
|
|
789
999
|
templates,
|
|
@@ -809,20 +1019,20 @@ var DocumentationTemplateService = class extends BaseService {
|
|
|
809
1019
|
}
|
|
810
1020
|
const querySnapshot = await (0, import_firestore3.getDocs)(q);
|
|
811
1021
|
const templates = [];
|
|
812
|
-
querySnapshot.forEach((
|
|
813
|
-
templates.push(
|
|
1022
|
+
querySnapshot.forEach((doc11) => {
|
|
1023
|
+
templates.push(doc11.data());
|
|
814
1024
|
});
|
|
815
1025
|
return templates;
|
|
816
1026
|
}
|
|
817
1027
|
};
|
|
818
1028
|
|
|
819
1029
|
// src/services/documentation-templates/filled-document.service.ts
|
|
820
|
-
var
|
|
1030
|
+
var import_firestore7 = require("firebase/firestore");
|
|
821
1031
|
|
|
822
1032
|
// src/services/media/media.service.ts
|
|
823
|
-
var import_firestore4 = require("firebase/firestore");
|
|
824
|
-
var import_storage2 = require("firebase/storage");
|
|
825
1033
|
var import_firestore5 = require("firebase/firestore");
|
|
1034
|
+
var import_storage2 = require("firebase/storage");
|
|
1035
|
+
var import_firestore6 = require("firebase/firestore");
|
|
826
1036
|
|
|
827
1037
|
// src/backoffice/services/documentation-template.service.ts
|
|
828
1038
|
var DocumentationTemplateServiceBackoffice = class {
|
|
@@ -832,8 +1042,8 @@ var DocumentationTemplateServiceBackoffice = class {
|
|
|
832
1042
|
* @param auth - Firebase Auth instance
|
|
833
1043
|
* @param app - Firebase App instance
|
|
834
1044
|
*/
|
|
835
|
-
constructor(
|
|
836
|
-
this.apiService = new DocumentationTemplateService(
|
|
1045
|
+
constructor(...args) {
|
|
1046
|
+
this.apiService = new DocumentationTemplateService(...args);
|
|
837
1047
|
}
|
|
838
1048
|
/**
|
|
839
1049
|
* Create a new document template
|
|
@@ -878,6 +1088,40 @@ var DocumentationTemplateServiceBackoffice = class {
|
|
|
878
1088
|
async getActiveTemplates(pageSize = 20, lastDoc) {
|
|
879
1089
|
return this.apiService.getActiveTemplates(pageSize, lastDoc);
|
|
880
1090
|
}
|
|
1091
|
+
/**
|
|
1092
|
+
* Get all active templates with optional filters and pagination.
|
|
1093
|
+
* @param options - Options for filtering and pagination.
|
|
1094
|
+
* @returns A promise that resolves to the templates and the last visible document.
|
|
1095
|
+
*/
|
|
1096
|
+
async getTemplates(options) {
|
|
1097
|
+
return this.apiService.getTemplates(options);
|
|
1098
|
+
}
|
|
1099
|
+
/**
|
|
1100
|
+
* Get the total count of active templates with optional filters.
|
|
1101
|
+
* @param options - Options for filtering.
|
|
1102
|
+
* @returns A promise that resolves to the total count of templates.
|
|
1103
|
+
*/
|
|
1104
|
+
async getTemplatesCount(options) {
|
|
1105
|
+
return this.apiService.getTemplatesCount(options);
|
|
1106
|
+
}
|
|
1107
|
+
/**
|
|
1108
|
+
* Get all active templates without pagination for filtering purposes.
|
|
1109
|
+
* @returns A promise that resolves to an array of all active templates.
|
|
1110
|
+
*/
|
|
1111
|
+
async getAllActiveTemplates() {
|
|
1112
|
+
return this.apiService.getAllActiveTemplates();
|
|
1113
|
+
}
|
|
1114
|
+
/**
|
|
1115
|
+
* Searches for active templates by title.
|
|
1116
|
+
* @param title - The title to search for.
|
|
1117
|
+
* @returns A list of templates that match the search criteria.
|
|
1118
|
+
*/
|
|
1119
|
+
async search(title) {
|
|
1120
|
+
const { templates } = await this.apiService.getActiveTemplates(1e3);
|
|
1121
|
+
return templates.filter(
|
|
1122
|
+
(t) => t.title.toLowerCase().includes(title.toLowerCase())
|
|
1123
|
+
);
|
|
1124
|
+
}
|
|
881
1125
|
/**
|
|
882
1126
|
* Get templates by tags
|
|
883
1127
|
* @param tags - Tags to filter by
|
|
@@ -918,7 +1162,7 @@ var DocumentationTemplateServiceBackoffice = class {
|
|
|
918
1162
|
};
|
|
919
1163
|
|
|
920
1164
|
// src/backoffice/services/product.service.ts
|
|
921
|
-
var
|
|
1165
|
+
var import_firestore8 = require("firebase/firestore");
|
|
922
1166
|
|
|
923
1167
|
// src/backoffice/types/product.types.ts
|
|
924
1168
|
var PRODUCTS_COLLECTION = "products";
|
|
@@ -934,7 +1178,7 @@ var ProductService = class extends BaseService {
|
|
|
934
1178
|
* @returns Firestore collection reference
|
|
935
1179
|
*/
|
|
936
1180
|
getProductsRef(technologyId) {
|
|
937
|
-
return (0,
|
|
1181
|
+
return (0, import_firestore8.collection)(
|
|
938
1182
|
this.db,
|
|
939
1183
|
TECHNOLOGIES_COLLECTION,
|
|
940
1184
|
technologyId,
|
|
@@ -954,47 +1198,129 @@ var ProductService = class extends BaseService {
|
|
|
954
1198
|
updatedAt: now,
|
|
955
1199
|
isActive: true
|
|
956
1200
|
};
|
|
957
|
-
const productRef = await (0,
|
|
1201
|
+
const productRef = await (0, import_firestore8.addDoc)(
|
|
958
1202
|
this.getProductsRef(technologyId),
|
|
959
1203
|
newProduct
|
|
960
1204
|
);
|
|
961
1205
|
return { id: productRef.id, ...newProduct };
|
|
962
1206
|
}
|
|
963
1207
|
/**
|
|
964
|
-
* Gets all products
|
|
1208
|
+
* Gets a paginated list of all products, with optional filters.
|
|
1209
|
+
* This uses a collectionGroup query to search across all technologies.
|
|
965
1210
|
*/
|
|
966
|
-
async
|
|
967
|
-
const
|
|
968
|
-
|
|
969
|
-
|
|
1211
|
+
async getAll(options) {
|
|
1212
|
+
const {
|
|
1213
|
+
rowsPerPage,
|
|
1214
|
+
lastVisible,
|
|
1215
|
+
categoryId,
|
|
1216
|
+
subcategoryId,
|
|
1217
|
+
technologyId
|
|
1218
|
+
} = options;
|
|
1219
|
+
const constraints = [
|
|
1220
|
+
(0, import_firestore8.where)("isActive", "==", true),
|
|
1221
|
+
(0, import_firestore8.orderBy)("name")
|
|
1222
|
+
];
|
|
1223
|
+
if (categoryId) {
|
|
1224
|
+
constraints.push((0, import_firestore8.where)("categoryId", "==", categoryId));
|
|
1225
|
+
}
|
|
1226
|
+
if (subcategoryId) {
|
|
1227
|
+
constraints.push((0, import_firestore8.where)("subcategoryId", "==", subcategoryId));
|
|
1228
|
+
}
|
|
1229
|
+
if (technologyId) {
|
|
1230
|
+
constraints.push((0, import_firestore8.where)("technologyId", "==", technologyId));
|
|
1231
|
+
}
|
|
1232
|
+
if (lastVisible) {
|
|
1233
|
+
constraints.push((0, import_firestore8.startAfter)(lastVisible));
|
|
1234
|
+
}
|
|
1235
|
+
constraints.push((0, import_firestore8.limit)(rowsPerPage));
|
|
1236
|
+
const q = (0, import_firestore8.query)(
|
|
1237
|
+
(0, import_firestore8.collectionGroup)(this.db, PRODUCTS_COLLECTION),
|
|
1238
|
+
...constraints
|
|
970
1239
|
);
|
|
971
|
-
const snapshot = await (0,
|
|
972
|
-
|
|
973
|
-
(
|
|
974
|
-
id:
|
|
975
|
-
...
|
|
1240
|
+
const snapshot = await (0, import_firestore8.getDocs)(q);
|
|
1241
|
+
const products = snapshot.docs.map(
|
|
1242
|
+
(doc11) => ({
|
|
1243
|
+
id: doc11.id,
|
|
1244
|
+
...doc11.data()
|
|
976
1245
|
})
|
|
977
1246
|
);
|
|
1247
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
1248
|
+
return { products, lastVisible: newLastVisible };
|
|
1249
|
+
}
|
|
1250
|
+
/**
|
|
1251
|
+
* Gets the total count of active products, with optional filters.
|
|
1252
|
+
*/
|
|
1253
|
+
async getProductsCount(options) {
|
|
1254
|
+
const { categoryId, subcategoryId, technologyId } = options;
|
|
1255
|
+
const constraints = [(0, import_firestore8.where)("isActive", "==", true)];
|
|
1256
|
+
if (categoryId) {
|
|
1257
|
+
constraints.push((0, import_firestore8.where)("categoryId", "==", categoryId));
|
|
1258
|
+
}
|
|
1259
|
+
if (subcategoryId) {
|
|
1260
|
+
constraints.push((0, import_firestore8.where)("subcategoryId", "==", subcategoryId));
|
|
1261
|
+
}
|
|
1262
|
+
if (technologyId) {
|
|
1263
|
+
constraints.push((0, import_firestore8.where)("technologyId", "==", technologyId));
|
|
1264
|
+
}
|
|
1265
|
+
const q = (0, import_firestore8.query)(
|
|
1266
|
+
(0, import_firestore8.collectionGroup)(this.db, PRODUCTS_COLLECTION),
|
|
1267
|
+
...constraints
|
|
1268
|
+
);
|
|
1269
|
+
const snapshot = await (0, import_firestore8.getCountFromServer)(q);
|
|
1270
|
+
return snapshot.data().count;
|
|
1271
|
+
}
|
|
1272
|
+
/**
|
|
1273
|
+
* Gets counts of active products grouped by category, subcategory, and technology.
|
|
1274
|
+
* This uses a single collectionGroup query for efficiency.
|
|
1275
|
+
*/
|
|
1276
|
+
async getProductCounts() {
|
|
1277
|
+
const q = (0, import_firestore8.query)(
|
|
1278
|
+
(0, import_firestore8.collectionGroup)(this.db, PRODUCTS_COLLECTION),
|
|
1279
|
+
(0, import_firestore8.where)("isActive", "==", true)
|
|
1280
|
+
);
|
|
1281
|
+
const snapshot = await (0, import_firestore8.getDocs)(q);
|
|
1282
|
+
const counts = {
|
|
1283
|
+
byCategory: {},
|
|
1284
|
+
bySubcategory: {},
|
|
1285
|
+
byTechnology: {}
|
|
1286
|
+
};
|
|
1287
|
+
if (snapshot.empty) {
|
|
1288
|
+
return counts;
|
|
1289
|
+
}
|
|
1290
|
+
snapshot.docs.forEach((doc11) => {
|
|
1291
|
+
const product = doc11.data();
|
|
1292
|
+
const { categoryId, subcategoryId, technologyId } = product;
|
|
1293
|
+
if (categoryId) {
|
|
1294
|
+
counts.byCategory[categoryId] = (counts.byCategory[categoryId] || 0) + 1;
|
|
1295
|
+
}
|
|
1296
|
+
if (subcategoryId) {
|
|
1297
|
+
counts.bySubcategory[subcategoryId] = (counts.bySubcategory[subcategoryId] || 0) + 1;
|
|
1298
|
+
}
|
|
1299
|
+
if (technologyId) {
|
|
1300
|
+
counts.byTechnology[technologyId] = (counts.byTechnology[technologyId] || 0) + 1;
|
|
1301
|
+
}
|
|
1302
|
+
});
|
|
1303
|
+
return counts;
|
|
978
1304
|
}
|
|
979
1305
|
/**
|
|
980
1306
|
* Gets all products for a brand by filtering through all technologies
|
|
981
1307
|
*/
|
|
982
1308
|
async getAllByBrand(brandId) {
|
|
983
|
-
const allTechnologiesRef = (0,
|
|
984
|
-
const technologiesSnapshot = await (0,
|
|
1309
|
+
const allTechnologiesRef = (0, import_firestore8.collection)(this.db, TECHNOLOGIES_COLLECTION);
|
|
1310
|
+
const technologiesSnapshot = await (0, import_firestore8.getDocs)(allTechnologiesRef);
|
|
985
1311
|
const products = [];
|
|
986
1312
|
for (const techDoc of technologiesSnapshot.docs) {
|
|
987
|
-
const q = (0,
|
|
1313
|
+
const q = (0, import_firestore8.query)(
|
|
988
1314
|
this.getProductsRef(techDoc.id),
|
|
989
|
-
(0,
|
|
990
|
-
(0,
|
|
1315
|
+
(0, import_firestore8.where)("brandId", "==", brandId),
|
|
1316
|
+
(0, import_firestore8.where)("isActive", "==", true)
|
|
991
1317
|
);
|
|
992
|
-
const snapshot = await (0,
|
|
1318
|
+
const snapshot = await (0, import_firestore8.getDocs)(q);
|
|
993
1319
|
products.push(
|
|
994
1320
|
...snapshot.docs.map(
|
|
995
|
-
(
|
|
996
|
-
id:
|
|
997
|
-
...
|
|
1321
|
+
(doc11) => ({
|
|
1322
|
+
id: doc11.id,
|
|
1323
|
+
...doc11.data()
|
|
998
1324
|
})
|
|
999
1325
|
)
|
|
1000
1326
|
);
|
|
@@ -1009,8 +1335,8 @@ var ProductService = class extends BaseService {
|
|
|
1009
1335
|
...product,
|
|
1010
1336
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1011
1337
|
};
|
|
1012
|
-
const docRef = (0,
|
|
1013
|
-
await (0,
|
|
1338
|
+
const docRef = (0, import_firestore8.doc)(this.getProductsRef(technologyId), productId);
|
|
1339
|
+
await (0, import_firestore8.updateDoc)(docRef, updateData);
|
|
1014
1340
|
return this.getById(technologyId, productId);
|
|
1015
1341
|
}
|
|
1016
1342
|
/**
|
|
@@ -1025,8 +1351,8 @@ var ProductService = class extends BaseService {
|
|
|
1025
1351
|
* Gets a product by ID
|
|
1026
1352
|
*/
|
|
1027
1353
|
async getById(technologyId, productId) {
|
|
1028
|
-
const docRef = (0,
|
|
1029
|
-
const docSnap = await (0,
|
|
1354
|
+
const docRef = (0, import_firestore8.doc)(this.getProductsRef(technologyId), productId);
|
|
1355
|
+
const docSnap = await (0, import_firestore8.getDoc)(docRef);
|
|
1030
1356
|
if (!docSnap.exists()) return null;
|
|
1031
1357
|
return {
|
|
1032
1358
|
id: docSnap.id,
|
|
@@ -1036,7 +1362,7 @@ var ProductService = class extends BaseService {
|
|
|
1036
1362
|
};
|
|
1037
1363
|
|
|
1038
1364
|
// src/backoffice/services/requirement.service.ts
|
|
1039
|
-
var
|
|
1365
|
+
var import_firestore9 = require("firebase/firestore");
|
|
1040
1366
|
|
|
1041
1367
|
// src/backoffice/types/requirement.types.ts
|
|
1042
1368
|
var TimeUnit = /* @__PURE__ */ ((TimeUnit2) => {
|
|
@@ -1057,7 +1383,7 @@ var RequirementService = class extends BaseService {
|
|
|
1057
1383
|
* Referenca na Firestore kolekciju zahteva
|
|
1058
1384
|
*/
|
|
1059
1385
|
get requirementsRef() {
|
|
1060
|
-
return (0,
|
|
1386
|
+
return (0, import_firestore9.collection)(this.db, REQUIREMENTS_COLLECTION);
|
|
1061
1387
|
}
|
|
1062
1388
|
/**
|
|
1063
1389
|
* Kreira novi globalni zahtev
|
|
@@ -1072,7 +1398,7 @@ var RequirementService = class extends BaseService {
|
|
|
1072
1398
|
updatedAt: now,
|
|
1073
1399
|
isActive: true
|
|
1074
1400
|
};
|
|
1075
|
-
const docRef = await (0,
|
|
1401
|
+
const docRef = await (0, import_firestore9.addDoc)(this.requirementsRef, newRequirement);
|
|
1076
1402
|
return { id: docRef.id, ...newRequirement };
|
|
1077
1403
|
}
|
|
1078
1404
|
/**
|
|
@@ -1080,12 +1406,12 @@ var RequirementService = class extends BaseService {
|
|
|
1080
1406
|
* @returns Lista aktivnih zahteva
|
|
1081
1407
|
*/
|
|
1082
1408
|
async getAll() {
|
|
1083
|
-
const q = (0,
|
|
1084
|
-
const snapshot = await (0,
|
|
1409
|
+
const q = (0, import_firestore9.query)(this.requirementsRef, (0, import_firestore9.where)("isActive", "==", true));
|
|
1410
|
+
const snapshot = await (0, import_firestore9.getDocs)(q);
|
|
1085
1411
|
return snapshot.docs.map(
|
|
1086
|
-
(
|
|
1087
|
-
id:
|
|
1088
|
-
...
|
|
1412
|
+
(doc11) => ({
|
|
1413
|
+
id: doc11.id,
|
|
1414
|
+
...doc11.data()
|
|
1089
1415
|
})
|
|
1090
1416
|
);
|
|
1091
1417
|
}
|
|
@@ -1095,19 +1421,31 @@ var RequirementService = class extends BaseService {
|
|
|
1095
1421
|
* @returns Lista zahteva određenog tipa
|
|
1096
1422
|
*/
|
|
1097
1423
|
async getAllByType(type) {
|
|
1098
|
-
const q = (0,
|
|
1424
|
+
const q = (0, import_firestore9.query)(
|
|
1099
1425
|
this.requirementsRef,
|
|
1100
|
-
(0,
|
|
1101
|
-
(0,
|
|
1426
|
+
(0, import_firestore9.where)("type", "==", type),
|
|
1427
|
+
(0, import_firestore9.where)("isActive", "==", true)
|
|
1102
1428
|
);
|
|
1103
|
-
const snapshot = await (0,
|
|
1429
|
+
const snapshot = await (0, import_firestore9.getDocs)(q);
|
|
1104
1430
|
return snapshot.docs.map(
|
|
1105
|
-
(
|
|
1106
|
-
id:
|
|
1107
|
-
...
|
|
1431
|
+
(doc11) => ({
|
|
1432
|
+
id: doc11.id,
|
|
1433
|
+
...doc11.data()
|
|
1108
1434
|
})
|
|
1109
1435
|
);
|
|
1110
1436
|
}
|
|
1437
|
+
/**
|
|
1438
|
+
* Searches for requirements by name.
|
|
1439
|
+
* @param name - The name to search for.
|
|
1440
|
+
* @param type - The type of requirement (pre/post).
|
|
1441
|
+
* @returns A list of requirements that match the search criteria.
|
|
1442
|
+
*/
|
|
1443
|
+
async search(name, type) {
|
|
1444
|
+
const requirements = await this.getAllByType(type);
|
|
1445
|
+
return requirements.filter(
|
|
1446
|
+
(r) => r.name.toLowerCase().includes(name.toLowerCase())
|
|
1447
|
+
);
|
|
1448
|
+
}
|
|
1111
1449
|
/**
|
|
1112
1450
|
* Ažurira postojeći zahtev
|
|
1113
1451
|
* @param id - ID zahteva koji se ažurira
|
|
@@ -1119,8 +1457,8 @@ var RequirementService = class extends BaseService {
|
|
|
1119
1457
|
...requirement,
|
|
1120
1458
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1121
1459
|
};
|
|
1122
|
-
const docRef = (0,
|
|
1123
|
-
await (0,
|
|
1460
|
+
const docRef = (0, import_firestore9.doc)(this.requirementsRef, id);
|
|
1461
|
+
await (0, import_firestore9.updateDoc)(docRef, updateData);
|
|
1124
1462
|
return this.getById(id);
|
|
1125
1463
|
}
|
|
1126
1464
|
/**
|
|
@@ -1136,8 +1474,8 @@ var RequirementService = class extends BaseService {
|
|
|
1136
1474
|
* @returns Zahtev ili null ako ne postoji
|
|
1137
1475
|
*/
|
|
1138
1476
|
async getById(id) {
|
|
1139
|
-
const docRef = (0,
|
|
1140
|
-
const docSnap = await (0,
|
|
1477
|
+
const docRef = (0, import_firestore9.doc)(this.requirementsRef, id);
|
|
1478
|
+
const docSnap = await (0, import_firestore9.getDoc)(docRef);
|
|
1141
1479
|
if (!docSnap.exists()) return null;
|
|
1142
1480
|
return {
|
|
1143
1481
|
id: docSnap.id,
|
|
@@ -1147,7 +1485,7 @@ var RequirementService = class extends BaseService {
|
|
|
1147
1485
|
};
|
|
1148
1486
|
|
|
1149
1487
|
// src/backoffice/services/subcategory.service.ts
|
|
1150
|
-
var
|
|
1488
|
+
var import_firestore10 = require("firebase/firestore");
|
|
1151
1489
|
|
|
1152
1490
|
// src/backoffice/types/subcategory.types.ts
|
|
1153
1491
|
var SUBCATEGORIES_COLLECTION = "subcategories";
|
|
@@ -1159,7 +1497,7 @@ var SubcategoryService = class extends BaseService {
|
|
|
1159
1497
|
* @param categoryId - ID roditeljske kategorije
|
|
1160
1498
|
*/
|
|
1161
1499
|
getSubcategoriesRef(categoryId) {
|
|
1162
|
-
return (0,
|
|
1500
|
+
return (0, import_firestore10.collection)(
|
|
1163
1501
|
this.db,
|
|
1164
1502
|
CATEGORIES_COLLECTION,
|
|
1165
1503
|
categoryId,
|
|
@@ -1181,27 +1519,117 @@ var SubcategoryService = class extends BaseService {
|
|
|
1181
1519
|
updatedAt: now,
|
|
1182
1520
|
isActive: true
|
|
1183
1521
|
};
|
|
1184
|
-
const docRef = await (0,
|
|
1522
|
+
const docRef = await (0, import_firestore10.addDoc)(
|
|
1185
1523
|
this.getSubcategoriesRef(categoryId),
|
|
1186
1524
|
newSubcategory
|
|
1187
1525
|
);
|
|
1188
1526
|
return { id: docRef.id, ...newSubcategory };
|
|
1189
1527
|
}
|
|
1190
1528
|
/**
|
|
1191
|
-
*
|
|
1529
|
+
* Returns counts of subcategories for all categories.
|
|
1530
|
+
* @param active - Whether to count active or inactive subcategories.
|
|
1531
|
+
* @returns A record mapping category ID to subcategory count.
|
|
1532
|
+
*/
|
|
1533
|
+
async getSubcategoryCounts(active = true) {
|
|
1534
|
+
const categoriesRef = (0, import_firestore10.collection)(this.db, CATEGORIES_COLLECTION);
|
|
1535
|
+
const categoriesSnapshot = await (0, import_firestore10.getDocs)(categoriesRef);
|
|
1536
|
+
const counts = {};
|
|
1537
|
+
for (const categoryDoc of categoriesSnapshot.docs) {
|
|
1538
|
+
const categoryId = categoryDoc.id;
|
|
1539
|
+
const subcategoriesRef = this.getSubcategoriesRef(categoryId);
|
|
1540
|
+
const q = (0, import_firestore10.query)(subcategoriesRef, (0, import_firestore10.where)("isActive", "==", active));
|
|
1541
|
+
const snapshot = await (0, import_firestore10.getCountFromServer)(q);
|
|
1542
|
+
counts[categoryId] = snapshot.data().count;
|
|
1543
|
+
}
|
|
1544
|
+
return counts;
|
|
1545
|
+
}
|
|
1546
|
+
/**
|
|
1547
|
+
* Vraća sve aktivne podkategorije za određenu kategoriju sa paginacijom
|
|
1192
1548
|
* @param categoryId - ID kategorije čije podkategorije tražimo
|
|
1193
|
-
* @
|
|
1549
|
+
* @param options - Pagination options
|
|
1550
|
+
* @returns Lista aktivnih podkategorija i poslednji vidljiv dokument
|
|
1551
|
+
*/
|
|
1552
|
+
async getAllByCategoryId(categoryId, options = {}) {
|
|
1553
|
+
const { active = true, limit: queryLimit = 10, lastVisible } = options;
|
|
1554
|
+
const constraints = [
|
|
1555
|
+
(0, import_firestore10.where)("isActive", "==", active),
|
|
1556
|
+
(0, import_firestore10.orderBy)("name"),
|
|
1557
|
+
queryLimit ? (0, import_firestore10.limit)(queryLimit) : void 0,
|
|
1558
|
+
lastVisible ? (0, import_firestore10.startAfter)(lastVisible) : void 0
|
|
1559
|
+
].filter((c) => !!c);
|
|
1560
|
+
const q = (0, import_firestore10.query)(this.getSubcategoriesRef(categoryId), ...constraints);
|
|
1561
|
+
const querySnapshot = await (0, import_firestore10.getDocs)(q);
|
|
1562
|
+
const subcategories = querySnapshot.docs.map(
|
|
1563
|
+
(doc11) => ({
|
|
1564
|
+
id: doc11.id,
|
|
1565
|
+
...doc11.data()
|
|
1566
|
+
})
|
|
1567
|
+
);
|
|
1568
|
+
const newLastVisible = querySnapshot.docs[querySnapshot.docs.length - 1];
|
|
1569
|
+
return { subcategories, lastVisible: newLastVisible };
|
|
1570
|
+
}
|
|
1571
|
+
/**
|
|
1572
|
+
* Vraća sve podkategorije sa paginacijom koristeći collection group query.
|
|
1573
|
+
* NOTE: This query requires a composite index in Firestore on the 'subcategories' collection group.
|
|
1574
|
+
* The index should be on 'isActive' (ascending) and 'name' (ascending).
|
|
1575
|
+
* Firestore will provide a link to create this index in the console error if it's missing.
|
|
1576
|
+
* @param options - Pagination options
|
|
1577
|
+
* @returns Lista podkategorija i poslednji vidljiv dokument
|
|
1578
|
+
*/
|
|
1579
|
+
async getAll(options = {}) {
|
|
1580
|
+
const { active = true, limit: queryLimit = 10, lastVisible } = options;
|
|
1581
|
+
const constraints = [
|
|
1582
|
+
(0, import_firestore10.where)("isActive", "==", active),
|
|
1583
|
+
(0, import_firestore10.orderBy)("name"),
|
|
1584
|
+
queryLimit ? (0, import_firestore10.limit)(queryLimit) : void 0,
|
|
1585
|
+
lastVisible ? (0, import_firestore10.startAfter)(lastVisible) : void 0
|
|
1586
|
+
].filter((c) => !!c);
|
|
1587
|
+
const q = (0, import_firestore10.query)(
|
|
1588
|
+
(0, import_firestore10.collectionGroup)(this.db, SUBCATEGORIES_COLLECTION),
|
|
1589
|
+
...constraints
|
|
1590
|
+
);
|
|
1591
|
+
const querySnapshot = await (0, import_firestore10.getDocs)(q);
|
|
1592
|
+
const subcategories = querySnapshot.docs.map(
|
|
1593
|
+
(doc11) => ({
|
|
1594
|
+
id: doc11.id,
|
|
1595
|
+
...doc11.data()
|
|
1596
|
+
})
|
|
1597
|
+
);
|
|
1598
|
+
const newLastVisible = querySnapshot.docs[querySnapshot.docs.length - 1];
|
|
1599
|
+
return { subcategories, lastVisible: newLastVisible };
|
|
1600
|
+
}
|
|
1601
|
+
/**
|
|
1602
|
+
* Vraća sve subkategorije za određenu kategoriju za potrebe filtera (bez paginacije)
|
|
1603
|
+
* @param categoryId - ID kategorije čije subkategorije tražimo
|
|
1604
|
+
* @returns Lista svih aktivnih subkategorija
|
|
1194
1605
|
*/
|
|
1195
|
-
async
|
|
1196
|
-
const q = (0,
|
|
1606
|
+
async getAllForFilterByCategoryId(categoryId) {
|
|
1607
|
+
const q = (0, import_firestore10.query)(
|
|
1197
1608
|
this.getSubcategoriesRef(categoryId),
|
|
1198
|
-
(0,
|
|
1609
|
+
(0, import_firestore10.where)("isActive", "==", true)
|
|
1199
1610
|
);
|
|
1200
|
-
const
|
|
1201
|
-
return
|
|
1202
|
-
(
|
|
1203
|
-
id:
|
|
1204
|
-
...
|
|
1611
|
+
const querySnapshot = await (0, import_firestore10.getDocs)(q);
|
|
1612
|
+
return querySnapshot.docs.map(
|
|
1613
|
+
(doc11) => ({
|
|
1614
|
+
id: doc11.id,
|
|
1615
|
+
...doc11.data()
|
|
1616
|
+
})
|
|
1617
|
+
);
|
|
1618
|
+
}
|
|
1619
|
+
/**
|
|
1620
|
+
* Vraća sve subkategorije za potrebe filtera (bez paginacije)
|
|
1621
|
+
* @returns Lista svih aktivnih subkategorija
|
|
1622
|
+
*/
|
|
1623
|
+
async getAllForFilter() {
|
|
1624
|
+
const q = (0, import_firestore10.query)(
|
|
1625
|
+
(0, import_firestore10.collectionGroup)(this.db, SUBCATEGORIES_COLLECTION),
|
|
1626
|
+
(0, import_firestore10.where)("isActive", "==", true)
|
|
1627
|
+
);
|
|
1628
|
+
const querySnapshot = await (0, import_firestore10.getDocs)(q);
|
|
1629
|
+
return querySnapshot.docs.map(
|
|
1630
|
+
(doc11) => ({
|
|
1631
|
+
id: doc11.id,
|
|
1632
|
+
...doc11.data()
|
|
1205
1633
|
})
|
|
1206
1634
|
);
|
|
1207
1635
|
}
|
|
@@ -1213,13 +1641,42 @@ var SubcategoryService = class extends BaseService {
|
|
|
1213
1641
|
* @returns Ažurirana podkategorija
|
|
1214
1642
|
*/
|
|
1215
1643
|
async update(categoryId, subcategoryId, subcategory) {
|
|
1216
|
-
const
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1644
|
+
const newCategoryId = subcategory.categoryId;
|
|
1645
|
+
if (newCategoryId && newCategoryId !== categoryId) {
|
|
1646
|
+
const oldDocRef = (0, import_firestore10.doc)(
|
|
1647
|
+
this.getSubcategoriesRef(categoryId),
|
|
1648
|
+
subcategoryId
|
|
1649
|
+
);
|
|
1650
|
+
const docSnap = await (0, import_firestore10.getDoc)(oldDocRef);
|
|
1651
|
+
if (!docSnap.exists()) {
|
|
1652
|
+
throw new Error("Subcategory to update does not exist.");
|
|
1653
|
+
}
|
|
1654
|
+
const existingData = docSnap.data();
|
|
1655
|
+
const newData = {
|
|
1656
|
+
...existingData,
|
|
1657
|
+
...subcategory,
|
|
1658
|
+
categoryId: newCategoryId,
|
|
1659
|
+
// Ensure categoryId is updated
|
|
1660
|
+
createdAt: existingData.createdAt,
|
|
1661
|
+
// Preserve original creation date
|
|
1662
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1663
|
+
};
|
|
1664
|
+
const newDocRef = (0, import_firestore10.doc)(
|
|
1665
|
+
this.getSubcategoriesRef(newCategoryId),
|
|
1666
|
+
subcategoryId
|
|
1667
|
+
);
|
|
1668
|
+
await (0, import_firestore10.setDoc)(newDocRef, newData);
|
|
1669
|
+
await (0, import_firestore10.deleteDoc)(oldDocRef);
|
|
1670
|
+
return { id: subcategoryId, ...newData };
|
|
1671
|
+
} else {
|
|
1672
|
+
const updateData = {
|
|
1673
|
+
...subcategory,
|
|
1674
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1675
|
+
};
|
|
1676
|
+
const docRef = (0, import_firestore10.doc)(this.getSubcategoriesRef(categoryId), subcategoryId);
|
|
1677
|
+
await (0, import_firestore10.updateDoc)(docRef, updateData);
|
|
1678
|
+
return this.getById(categoryId, subcategoryId);
|
|
1679
|
+
}
|
|
1223
1680
|
}
|
|
1224
1681
|
/**
|
|
1225
1682
|
* Soft delete podkategorije (postavlja isActive na false)
|
|
@@ -1229,6 +1686,14 @@ var SubcategoryService = class extends BaseService {
|
|
|
1229
1686
|
async delete(categoryId, subcategoryId) {
|
|
1230
1687
|
await this.update(categoryId, subcategoryId, { isActive: false });
|
|
1231
1688
|
}
|
|
1689
|
+
/**
|
|
1690
|
+
* Reactivates a subcategory by setting its isActive flag to true.
|
|
1691
|
+
* @param categoryId - The ID of the category to which the subcategory belongs.
|
|
1692
|
+
* @param subcategoryId - The ID of the subcategory to reactivate.
|
|
1693
|
+
*/
|
|
1694
|
+
async reactivate(categoryId, subcategoryId) {
|
|
1695
|
+
await this.update(categoryId, subcategoryId, { isActive: true });
|
|
1696
|
+
}
|
|
1232
1697
|
/**
|
|
1233
1698
|
* Vraća podkategoriju po ID-u
|
|
1234
1699
|
* @param categoryId - ID kategorije kojoj pripada podkategorija
|
|
@@ -1236,8 +1701,8 @@ var SubcategoryService = class extends BaseService {
|
|
|
1236
1701
|
* @returns Podkategorija ili null ako ne postoji
|
|
1237
1702
|
*/
|
|
1238
1703
|
async getById(categoryId, subcategoryId) {
|
|
1239
|
-
const docRef = (0,
|
|
1240
|
-
const docSnap = await (0,
|
|
1704
|
+
const docRef = (0, import_firestore10.doc)(this.getSubcategoriesRef(categoryId), subcategoryId);
|
|
1705
|
+
const docSnap = await (0, import_firestore10.getDoc)(docRef);
|
|
1241
1706
|
if (!docSnap.exists()) return null;
|
|
1242
1707
|
return {
|
|
1243
1708
|
id: docSnap.id,
|
|
@@ -1247,7 +1712,7 @@ var SubcategoryService = class extends BaseService {
|
|
|
1247
1712
|
};
|
|
1248
1713
|
|
|
1249
1714
|
// src/backoffice/services/technology.service.ts
|
|
1250
|
-
var
|
|
1715
|
+
var import_firestore11 = require("firebase/firestore");
|
|
1251
1716
|
|
|
1252
1717
|
// src/backoffice/types/static/certification.types.ts
|
|
1253
1718
|
var CertificationLevel = /* @__PURE__ */ ((CertificationLevel2) => {
|
|
@@ -1280,138 +1745,186 @@ var DEFAULT_CERTIFICATION_REQUIREMENT = {
|
|
|
1280
1745
|
};
|
|
1281
1746
|
var TechnologyService = class extends BaseService {
|
|
1282
1747
|
/**
|
|
1283
|
-
*
|
|
1748
|
+
* Reference to the Firestore collection of technologies.
|
|
1284
1749
|
*/
|
|
1285
|
-
|
|
1286
|
-
return (0,
|
|
1750
|
+
get technologiesRef() {
|
|
1751
|
+
return (0, import_firestore11.collection)(this.db, TECHNOLOGIES_COLLECTION);
|
|
1287
1752
|
}
|
|
1288
1753
|
/**
|
|
1289
|
-
*
|
|
1290
|
-
* @param technology -
|
|
1291
|
-
* @returns
|
|
1754
|
+
* Creates a new technology.
|
|
1755
|
+
* @param technology - Data for the new technology.
|
|
1756
|
+
* @returns The created technology with its generated ID.
|
|
1292
1757
|
*/
|
|
1293
1758
|
async create(technology) {
|
|
1294
1759
|
const now = /* @__PURE__ */ new Date();
|
|
1295
1760
|
const newTechnology = {
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
post: []
|
|
1303
|
-
},
|
|
1761
|
+
name: technology.name,
|
|
1762
|
+
description: technology.description,
|
|
1763
|
+
family: technology.family,
|
|
1764
|
+
categoryId: technology.categoryId,
|
|
1765
|
+
subcategoryId: technology.subcategoryId,
|
|
1766
|
+
requirements: technology.requirements || { pre: [], post: [] },
|
|
1304
1767
|
blockingConditions: technology.blockingConditions || [],
|
|
1305
1768
|
contraindications: technology.contraindications || [],
|
|
1306
1769
|
benefits: technology.benefits || [],
|
|
1307
|
-
certificationRequirement: technology.certificationRequirement || DEFAULT_CERTIFICATION_REQUIREMENT
|
|
1770
|
+
certificationRequirement: technology.certificationRequirement || DEFAULT_CERTIFICATION_REQUIREMENT,
|
|
1771
|
+
documentationTemplates: technology.documentationTemplates || [],
|
|
1772
|
+
isActive: true,
|
|
1773
|
+
createdAt: now,
|
|
1774
|
+
updatedAt: now
|
|
1308
1775
|
};
|
|
1309
|
-
|
|
1776
|
+
if (technology.technicalDetails) {
|
|
1777
|
+
newTechnology.technicalDetails = technology.technicalDetails;
|
|
1778
|
+
}
|
|
1779
|
+
const docRef = await (0, import_firestore11.addDoc)(this.technologiesRef, newTechnology);
|
|
1310
1780
|
return { id: docRef.id, ...newTechnology };
|
|
1311
1781
|
}
|
|
1312
1782
|
/**
|
|
1313
|
-
*
|
|
1314
|
-
* @
|
|
1783
|
+
* Returns counts of technologies for each subcategory.
|
|
1784
|
+
* @param active - Whether to count active or inactive technologies.
|
|
1785
|
+
* @returns A record mapping subcategory ID to technology count.
|
|
1315
1786
|
*/
|
|
1316
|
-
async
|
|
1317
|
-
const q = (0,
|
|
1318
|
-
const snapshot = await (0,
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1787
|
+
async getTechnologyCounts(active = true) {
|
|
1788
|
+
const q = (0, import_firestore11.query)(this.technologiesRef, (0, import_firestore11.where)("isActive", "==", active));
|
|
1789
|
+
const snapshot = await (0, import_firestore11.getDocs)(q);
|
|
1790
|
+
const counts = {};
|
|
1791
|
+
snapshot.docs.forEach((doc11) => {
|
|
1792
|
+
const tech = doc11.data();
|
|
1793
|
+
counts[tech.subcategoryId] = (counts[tech.subcategoryId] || 0) + 1;
|
|
1794
|
+
});
|
|
1795
|
+
return counts;
|
|
1325
1796
|
}
|
|
1326
1797
|
/**
|
|
1327
|
-
*
|
|
1328
|
-
* @param
|
|
1329
|
-
* @returns
|
|
1798
|
+
* Returns counts of technologies for each category.
|
|
1799
|
+
* @param active - Whether to count active or inactive technologies.
|
|
1800
|
+
* @returns A record mapping category ID to technology count.
|
|
1330
1801
|
*/
|
|
1331
|
-
async
|
|
1332
|
-
const q = (0,
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1802
|
+
async getTechnologyCountsByCategory(active = true) {
|
|
1803
|
+
const q = (0, import_firestore11.query)(this.technologiesRef, (0, import_firestore11.where)("isActive", "==", active));
|
|
1804
|
+
const snapshot = await (0, import_firestore11.getDocs)(q);
|
|
1805
|
+
const counts = {};
|
|
1806
|
+
snapshot.docs.forEach((doc11) => {
|
|
1807
|
+
const tech = doc11.data();
|
|
1808
|
+
counts[tech.categoryId] = (counts[tech.categoryId] || 0) + 1;
|
|
1809
|
+
});
|
|
1810
|
+
return counts;
|
|
1811
|
+
}
|
|
1812
|
+
/**
|
|
1813
|
+
* Returns all technologies with pagination.
|
|
1814
|
+
* @param options - Pagination and filter options.
|
|
1815
|
+
* @returns A list of technologies and the last visible document.
|
|
1816
|
+
*/
|
|
1817
|
+
async getAll(options = {}) {
|
|
1818
|
+
const { active = true, limit: queryLimit = 10, lastVisible } = options;
|
|
1819
|
+
const constraints = [
|
|
1820
|
+
(0, import_firestore11.where)("isActive", "==", active),
|
|
1821
|
+
(0, import_firestore11.orderBy)("name"),
|
|
1822
|
+
queryLimit ? (0, import_firestore11.limit)(queryLimit) : void 0,
|
|
1823
|
+
lastVisible ? (0, import_firestore11.startAfter)(lastVisible) : void 0
|
|
1824
|
+
].filter((c) => !!c);
|
|
1825
|
+
const q = (0, import_firestore11.query)(this.technologiesRef, ...constraints);
|
|
1826
|
+
const snapshot = await (0, import_firestore11.getDocs)(q);
|
|
1827
|
+
const technologies = snapshot.docs.map(
|
|
1828
|
+
(doc11) => ({
|
|
1829
|
+
id: doc11.id,
|
|
1830
|
+
...doc11.data()
|
|
1342
1831
|
})
|
|
1343
1832
|
);
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
*
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1833
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
1834
|
+
return { technologies, lastVisible: newLastVisible };
|
|
1835
|
+
}
|
|
1836
|
+
/**
|
|
1837
|
+
* Returns all technologies for a specific category with pagination.
|
|
1838
|
+
* @param categoryId - The ID of the category.
|
|
1839
|
+
* @param options - Pagination options.
|
|
1840
|
+
* @returns A list of technologies for the specified category.
|
|
1841
|
+
*/
|
|
1842
|
+
async getAllByCategoryId(categoryId, options = {}) {
|
|
1843
|
+
const { active = true, limit: queryLimit = 10, lastVisible } = options;
|
|
1844
|
+
const constraints = [
|
|
1845
|
+
(0, import_firestore11.where)("categoryId", "==", categoryId),
|
|
1846
|
+
(0, import_firestore11.where)("isActive", "==", active),
|
|
1847
|
+
(0, import_firestore11.orderBy)("name"),
|
|
1848
|
+
queryLimit ? (0, import_firestore11.limit)(queryLimit) : void 0,
|
|
1849
|
+
lastVisible ? (0, import_firestore11.startAfter)(lastVisible) : void 0
|
|
1850
|
+
].filter((c) => !!c);
|
|
1851
|
+
const q = (0, import_firestore11.query)(this.technologiesRef, ...constraints);
|
|
1852
|
+
const snapshot = await (0, import_firestore11.getDocs)(q);
|
|
1853
|
+
const technologies = snapshot.docs.map(
|
|
1854
|
+
(doc11) => ({
|
|
1855
|
+
id: doc11.id,
|
|
1856
|
+
...doc11.data()
|
|
1857
|
+
})
|
|
1355
1858
|
);
|
|
1356
|
-
const
|
|
1357
|
-
return
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1859
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
1860
|
+
return { technologies, lastVisible: newLastVisible };
|
|
1861
|
+
}
|
|
1862
|
+
/**
|
|
1863
|
+
* Returns all technologies for a specific subcategory with pagination.
|
|
1864
|
+
* @param subcategoryId - The ID of the subcategory.
|
|
1865
|
+
* @param options - Pagination options.
|
|
1866
|
+
* @returns A list of technologies for the specified subcategory.
|
|
1867
|
+
*/
|
|
1868
|
+
async getAllBySubcategoryId(subcategoryId, options = {}) {
|
|
1869
|
+
const { active = true, limit: queryLimit = 10, lastVisible } = options;
|
|
1870
|
+
const constraints = [
|
|
1871
|
+
(0, import_firestore11.where)("subcategoryId", "==", subcategoryId),
|
|
1872
|
+
(0, import_firestore11.where)("isActive", "==", active),
|
|
1873
|
+
(0, import_firestore11.orderBy)("name"),
|
|
1874
|
+
queryLimit ? (0, import_firestore11.limit)(queryLimit) : void 0,
|
|
1875
|
+
lastVisible ? (0, import_firestore11.startAfter)(lastVisible) : void 0
|
|
1876
|
+
].filter((c) => !!c);
|
|
1877
|
+
const q = (0, import_firestore11.query)(this.technologiesRef, ...constraints);
|
|
1878
|
+
const snapshot = await (0, import_firestore11.getDocs)(q);
|
|
1879
|
+
const technologies = snapshot.docs.map(
|
|
1880
|
+
(doc11) => ({
|
|
1881
|
+
id: doc11.id,
|
|
1882
|
+
...doc11.data()
|
|
1361
1883
|
})
|
|
1362
1884
|
);
|
|
1885
|
+
const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
|
|
1886
|
+
return { technologies, lastVisible: newLastVisible };
|
|
1363
1887
|
}
|
|
1364
1888
|
/**
|
|
1365
|
-
*
|
|
1366
|
-
* @param
|
|
1367
|
-
* @
|
|
1889
|
+
* Updates an existing technology.
|
|
1890
|
+
* @param id - The ID of the technology to update.
|
|
1891
|
+
* @param technology - New data for the technology.
|
|
1892
|
+
* @returns The updated technology.
|
|
1368
1893
|
*/
|
|
1369
|
-
async
|
|
1370
|
-
const
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
})
|
|
1381
|
-
);
|
|
1894
|
+
async update(id, technology) {
|
|
1895
|
+
const updateData = { ...technology };
|
|
1896
|
+
Object.keys(updateData).forEach((key) => {
|
|
1897
|
+
if (updateData[key] === void 0) {
|
|
1898
|
+
delete updateData[key];
|
|
1899
|
+
}
|
|
1900
|
+
});
|
|
1901
|
+
updateData.updatedAt = /* @__PURE__ */ new Date();
|
|
1902
|
+
const docRef = (0, import_firestore11.doc)(this.technologiesRef, id);
|
|
1903
|
+
await (0, import_firestore11.updateDoc)(docRef, updateData);
|
|
1904
|
+
return this.getById(id);
|
|
1382
1905
|
}
|
|
1383
1906
|
/**
|
|
1384
|
-
*
|
|
1385
|
-
* @param
|
|
1386
|
-
* @param technology - Novi podaci za tehnologiju
|
|
1387
|
-
* @returns Ažurirana tehnologija
|
|
1907
|
+
* Soft deletes a technology.
|
|
1908
|
+
* @param id - The ID of the technology to delete.
|
|
1388
1909
|
*/
|
|
1389
|
-
async
|
|
1390
|
-
|
|
1391
|
-
...technology,
|
|
1392
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
1393
|
-
};
|
|
1394
|
-
const docRef = (0, import_firestore10.doc)(this.getTechnologiesRef(), technologyId);
|
|
1395
|
-
await (0, import_firestore10.updateDoc)(docRef, updateData);
|
|
1396
|
-
return this.getById(technologyId);
|
|
1910
|
+
async delete(id) {
|
|
1911
|
+
await this.update(id, { isActive: false });
|
|
1397
1912
|
}
|
|
1398
1913
|
/**
|
|
1399
|
-
*
|
|
1400
|
-
* @param
|
|
1914
|
+
* Reactivates a technology.
|
|
1915
|
+
* @param id - The ID of the technology to reactivate.
|
|
1401
1916
|
*/
|
|
1402
|
-
async
|
|
1403
|
-
await this.update(
|
|
1404
|
-
isActive: false
|
|
1405
|
-
});
|
|
1917
|
+
async reactivate(id) {
|
|
1918
|
+
await this.update(id, { isActive: true });
|
|
1406
1919
|
}
|
|
1407
1920
|
/**
|
|
1408
|
-
*
|
|
1409
|
-
* @param
|
|
1410
|
-
* @returns
|
|
1921
|
+
* Returns a technology by its ID.
|
|
1922
|
+
* @param id - The ID of the requested technology.
|
|
1923
|
+
* @returns The technology or null if it doesn't exist.
|
|
1411
1924
|
*/
|
|
1412
|
-
async getById(
|
|
1413
|
-
const docRef = (0,
|
|
1414
|
-
const docSnap = await (0,
|
|
1925
|
+
async getById(id) {
|
|
1926
|
+
const docRef = (0, import_firestore11.doc)(this.technologiesRef, id);
|
|
1927
|
+
const docSnap = await (0, import_firestore11.getDoc)(docRef);
|
|
1415
1928
|
if (!docSnap.exists()) return null;
|
|
1416
1929
|
return {
|
|
1417
1930
|
id: docSnap.id,
|
|
@@ -1425,10 +1938,10 @@ var TechnologyService = class extends BaseService {
|
|
|
1425
1938
|
* @returns Ažurirana tehnologija sa novim zahtevom
|
|
1426
1939
|
*/
|
|
1427
1940
|
async addRequirement(technologyId, requirement) {
|
|
1428
|
-
const docRef = (0,
|
|
1941
|
+
const docRef = (0, import_firestore11.doc)(this.technologiesRef, technologyId);
|
|
1429
1942
|
const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
|
|
1430
|
-
await (0,
|
|
1431
|
-
[requirementType]: (0,
|
|
1943
|
+
await (0, import_firestore11.updateDoc)(docRef, {
|
|
1944
|
+
[requirementType]: (0, import_firestore11.arrayUnion)(requirement),
|
|
1432
1945
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1433
1946
|
});
|
|
1434
1947
|
return this.getById(technologyId);
|
|
@@ -1440,10 +1953,10 @@ var TechnologyService = class extends BaseService {
|
|
|
1440
1953
|
* @returns Ažurirana tehnologija bez uklonjenog zahteva
|
|
1441
1954
|
*/
|
|
1442
1955
|
async removeRequirement(technologyId, requirement) {
|
|
1443
|
-
const docRef = (0,
|
|
1956
|
+
const docRef = (0, import_firestore11.doc)(this.technologiesRef, technologyId);
|
|
1444
1957
|
const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
|
|
1445
|
-
await (0,
|
|
1446
|
-
[requirementType]: (0,
|
|
1958
|
+
await (0, import_firestore11.updateDoc)(docRef, {
|
|
1959
|
+
[requirementType]: (0, import_firestore11.arrayRemove)(requirement),
|
|
1447
1960
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1448
1961
|
});
|
|
1449
1962
|
return this.getById(technologyId);
|
|
@@ -1480,9 +1993,9 @@ var TechnologyService = class extends BaseService {
|
|
|
1480
1993
|
* @returns Ažurirana tehnologija
|
|
1481
1994
|
*/
|
|
1482
1995
|
async addBlockingCondition(technologyId, condition) {
|
|
1483
|
-
const docRef = (0,
|
|
1484
|
-
await (0,
|
|
1485
|
-
blockingConditions: (0,
|
|
1996
|
+
const docRef = (0, import_firestore11.doc)(this.technologiesRef, technologyId);
|
|
1997
|
+
await (0, import_firestore11.updateDoc)(docRef, {
|
|
1998
|
+
blockingConditions: (0, import_firestore11.arrayUnion)(condition),
|
|
1486
1999
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1487
2000
|
});
|
|
1488
2001
|
return this.getById(technologyId);
|
|
@@ -1494,9 +2007,9 @@ var TechnologyService = class extends BaseService {
|
|
|
1494
2007
|
* @returns Ažurirana tehnologija
|
|
1495
2008
|
*/
|
|
1496
2009
|
async removeBlockingCondition(technologyId, condition) {
|
|
1497
|
-
const docRef = (0,
|
|
1498
|
-
await (0,
|
|
1499
|
-
blockingConditions: (0,
|
|
2010
|
+
const docRef = (0, import_firestore11.doc)(this.technologiesRef, technologyId);
|
|
2011
|
+
await (0, import_firestore11.updateDoc)(docRef, {
|
|
2012
|
+
blockingConditions: (0, import_firestore11.arrayRemove)(condition),
|
|
1500
2013
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1501
2014
|
});
|
|
1502
2015
|
return this.getById(technologyId);
|
|
@@ -1508,9 +2021,17 @@ var TechnologyService = class extends BaseService {
|
|
|
1508
2021
|
* @returns Ažurirana tehnologija
|
|
1509
2022
|
*/
|
|
1510
2023
|
async addContraindication(technologyId, contraindication) {
|
|
1511
|
-
const docRef = (0,
|
|
1512
|
-
await (
|
|
1513
|
-
|
|
2024
|
+
const docRef = (0, import_firestore11.doc)(this.technologiesRef, technologyId);
|
|
2025
|
+
const technology = await this.getById(technologyId);
|
|
2026
|
+
if (!technology) {
|
|
2027
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
2028
|
+
}
|
|
2029
|
+
const existingContraindications = technology.contraindications || [];
|
|
2030
|
+
if (existingContraindications.some((c) => c.id === contraindication.id)) {
|
|
2031
|
+
return technology;
|
|
2032
|
+
}
|
|
2033
|
+
await (0, import_firestore11.updateDoc)(docRef, {
|
|
2034
|
+
contraindications: [...existingContraindications, contraindication],
|
|
1514
2035
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1515
2036
|
});
|
|
1516
2037
|
return this.getById(technologyId);
|
|
@@ -1522,9 +2043,45 @@ var TechnologyService = class extends BaseService {
|
|
|
1522
2043
|
* @returns Ažurirana tehnologija
|
|
1523
2044
|
*/
|
|
1524
2045
|
async removeContraindication(technologyId, contraindication) {
|
|
1525
|
-
const docRef = (0,
|
|
1526
|
-
await (
|
|
1527
|
-
|
|
2046
|
+
const docRef = (0, import_firestore11.doc)(this.technologiesRef, technologyId);
|
|
2047
|
+
const technology = await this.getById(technologyId);
|
|
2048
|
+
if (!technology) {
|
|
2049
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
2050
|
+
}
|
|
2051
|
+
const updatedContraindications = (technology.contraindications || []).filter((c) => c.id !== contraindication.id);
|
|
2052
|
+
await (0, import_firestore11.updateDoc)(docRef, {
|
|
2053
|
+
contraindications: updatedContraindications,
|
|
2054
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
2055
|
+
});
|
|
2056
|
+
return this.getById(technologyId);
|
|
2057
|
+
}
|
|
2058
|
+
/**
|
|
2059
|
+
* Updates an existing contraindication in a technology's list.
|
|
2060
|
+
* If the contraindication does not exist, it will not be added.
|
|
2061
|
+
* @param technologyId - ID of the technology
|
|
2062
|
+
* @param contraindication - The updated contraindication object
|
|
2063
|
+
* @returns The updated technology
|
|
2064
|
+
*/
|
|
2065
|
+
async updateContraindication(technologyId, contraindication) {
|
|
2066
|
+
const docRef = (0, import_firestore11.doc)(this.technologiesRef, technologyId);
|
|
2067
|
+
const technology = await this.getById(technologyId);
|
|
2068
|
+
if (!technology) {
|
|
2069
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
2070
|
+
}
|
|
2071
|
+
const contraindications = technology.contraindications || [];
|
|
2072
|
+
const index = contraindications.findIndex(
|
|
2073
|
+
(c) => c.id === contraindication.id
|
|
2074
|
+
);
|
|
2075
|
+
if (index === -1) {
|
|
2076
|
+
console.warn(
|
|
2077
|
+
`Contraindication with id ${contraindication.id} not found for technology ${technologyId}. No update performed.`
|
|
2078
|
+
);
|
|
2079
|
+
return technology;
|
|
2080
|
+
}
|
|
2081
|
+
const updatedContraindications = [...contraindications];
|
|
2082
|
+
updatedContraindications[index] = contraindication;
|
|
2083
|
+
await (0, import_firestore11.updateDoc)(docRef, {
|
|
2084
|
+
contraindications: updatedContraindications,
|
|
1528
2085
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1529
2086
|
});
|
|
1530
2087
|
return this.getById(technologyId);
|
|
@@ -1536,9 +2093,17 @@ var TechnologyService = class extends BaseService {
|
|
|
1536
2093
|
* @returns Ažurirana tehnologija
|
|
1537
2094
|
*/
|
|
1538
2095
|
async addBenefit(technologyId, benefit) {
|
|
1539
|
-
const docRef = (0,
|
|
1540
|
-
await (
|
|
1541
|
-
|
|
2096
|
+
const docRef = (0, import_firestore11.doc)(this.technologiesRef, technologyId);
|
|
2097
|
+
const technology = await this.getById(technologyId);
|
|
2098
|
+
if (!technology) {
|
|
2099
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
2100
|
+
}
|
|
2101
|
+
const existingBenefits = technology.benefits || [];
|
|
2102
|
+
if (existingBenefits.some((b) => b.id === benefit.id)) {
|
|
2103
|
+
return technology;
|
|
2104
|
+
}
|
|
2105
|
+
await (0, import_firestore11.updateDoc)(docRef, {
|
|
2106
|
+
benefits: [...existingBenefits, benefit],
|
|
1542
2107
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1543
2108
|
});
|
|
1544
2109
|
return this.getById(technologyId);
|
|
@@ -1550,9 +2115,45 @@ var TechnologyService = class extends BaseService {
|
|
|
1550
2115
|
* @returns Ažurirana tehnologija
|
|
1551
2116
|
*/
|
|
1552
2117
|
async removeBenefit(technologyId, benefit) {
|
|
1553
|
-
const docRef = (0,
|
|
1554
|
-
await (
|
|
1555
|
-
|
|
2118
|
+
const docRef = (0, import_firestore11.doc)(this.technologiesRef, technologyId);
|
|
2119
|
+
const technology = await this.getById(technologyId);
|
|
2120
|
+
if (!technology) {
|
|
2121
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
2122
|
+
}
|
|
2123
|
+
const updatedBenefits = (technology.benefits || []).filter(
|
|
2124
|
+
(b) => b.id !== benefit.id
|
|
2125
|
+
);
|
|
2126
|
+
await (0, import_firestore11.updateDoc)(docRef, {
|
|
2127
|
+
benefits: updatedBenefits,
|
|
2128
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
2129
|
+
});
|
|
2130
|
+
return this.getById(technologyId);
|
|
2131
|
+
}
|
|
2132
|
+
/**
|
|
2133
|
+
* Updates an existing benefit in a technology's list.
|
|
2134
|
+
* If the benefit does not exist, it will not be added.
|
|
2135
|
+
* @param technologyId - ID of the technology
|
|
2136
|
+
* @param benefit - The updated benefit object
|
|
2137
|
+
* @returns The updated technology
|
|
2138
|
+
*/
|
|
2139
|
+
async updateBenefit(technologyId, benefit) {
|
|
2140
|
+
const docRef = (0, import_firestore11.doc)(this.technologiesRef, technologyId);
|
|
2141
|
+
const technology = await this.getById(technologyId);
|
|
2142
|
+
if (!technology) {
|
|
2143
|
+
throw new Error(`Technology with id ${technologyId} not found`);
|
|
2144
|
+
}
|
|
2145
|
+
const benefits = technology.benefits || [];
|
|
2146
|
+
const index = benefits.findIndex((b) => b.id === benefit.id);
|
|
2147
|
+
if (index === -1) {
|
|
2148
|
+
console.warn(
|
|
2149
|
+
`Benefit with id ${benefit.id} not found for technology ${technologyId}. No update performed.`
|
|
2150
|
+
);
|
|
2151
|
+
return technology;
|
|
2152
|
+
}
|
|
2153
|
+
const updatedBenefits = [...benefits];
|
|
2154
|
+
updatedBenefits[index] = benefit;
|
|
2155
|
+
await (0, import_firestore11.updateDoc)(docRef, {
|
|
2156
|
+
benefits: updatedBenefits,
|
|
1556
2157
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1557
2158
|
});
|
|
1558
2159
|
return this.getById(technologyId);
|
|
@@ -1591,8 +2192,8 @@ var TechnologyService = class extends BaseService {
|
|
|
1591
2192
|
* @returns Ažurirana tehnologija
|
|
1592
2193
|
*/
|
|
1593
2194
|
async updateCertificationRequirement(technologyId, certificationRequirement) {
|
|
1594
|
-
const docRef = (0,
|
|
1595
|
-
await (0,
|
|
2195
|
+
const docRef = (0, import_firestore11.doc)(this.technologiesRef, technologyId);
|
|
2196
|
+
await (0, import_firestore11.updateDoc)(docRef, {
|
|
1596
2197
|
certificationRequirement,
|
|
1597
2198
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1598
2199
|
});
|
|
@@ -1669,7 +2270,7 @@ var TechnologyService = class extends BaseService {
|
|
|
1669
2270
|
*/
|
|
1670
2271
|
async getAllowedTechnologies(practitioner) {
|
|
1671
2272
|
const allTechnologies = await this.getAll();
|
|
1672
|
-
const allowedTechnologies = allTechnologies.filter(
|
|
2273
|
+
const allowedTechnologies = allTechnologies.technologies.filter(
|
|
1673
2274
|
(technology) => this.validateCertification(
|
|
1674
2275
|
technology.certificationRequirement,
|
|
1675
2276
|
practitioner.certification
|
|
@@ -1689,6 +2290,276 @@ var TechnologyService = class extends BaseService {
|
|
|
1689
2290
|
subcategories
|
|
1690
2291
|
};
|
|
1691
2292
|
}
|
|
2293
|
+
/**
|
|
2294
|
+
* Gets all active technologies for a subcategory for filter dropdowns.
|
|
2295
|
+
* @param categoryId - The ID of the parent category.
|
|
2296
|
+
* @param subcategoryId - The ID of the subcategory.
|
|
2297
|
+
*/
|
|
2298
|
+
async getAllForFilterBySubcategoryId(categoryId, subcategoryId) {
|
|
2299
|
+
const q = (0, import_firestore11.query)(
|
|
2300
|
+
(0, import_firestore11.collection)(this.db, TECHNOLOGIES_COLLECTION),
|
|
2301
|
+
(0, import_firestore11.where)("isActive", "==", true),
|
|
2302
|
+
(0, import_firestore11.where)("categoryId", "==", categoryId),
|
|
2303
|
+
(0, import_firestore11.where)("subcategoryId", "==", subcategoryId),
|
|
2304
|
+
(0, import_firestore11.orderBy)("name")
|
|
2305
|
+
);
|
|
2306
|
+
const snapshot = await (0, import_firestore11.getDocs)(q);
|
|
2307
|
+
return snapshot.docs.map(
|
|
2308
|
+
(doc11) => ({
|
|
2309
|
+
id: doc11.id,
|
|
2310
|
+
...doc11.data()
|
|
2311
|
+
})
|
|
2312
|
+
);
|
|
2313
|
+
}
|
|
2314
|
+
/**
|
|
2315
|
+
* Gets all active technologies for filter dropdowns.
|
|
2316
|
+
*/
|
|
2317
|
+
async getAllForFilter() {
|
|
2318
|
+
const q = (0, import_firestore11.query)(
|
|
2319
|
+
(0, import_firestore11.collection)(this.db, TECHNOLOGIES_COLLECTION),
|
|
2320
|
+
(0, import_firestore11.where)("isActive", "==", true),
|
|
2321
|
+
(0, import_firestore11.orderBy)("name")
|
|
2322
|
+
);
|
|
2323
|
+
const snapshot = await (0, import_firestore11.getDocs)(q);
|
|
2324
|
+
return snapshot.docs.map(
|
|
2325
|
+
(doc11) => ({
|
|
2326
|
+
id: doc11.id,
|
|
2327
|
+
...doc11.data()
|
|
2328
|
+
})
|
|
2329
|
+
);
|
|
2330
|
+
}
|
|
2331
|
+
};
|
|
2332
|
+
|
|
2333
|
+
// src/backoffice/services/constants.service.ts
|
|
2334
|
+
var import_firestore12 = require("firebase/firestore");
|
|
2335
|
+
var ADMIN_CONSTANTS_COLLECTION = "admin-constants";
|
|
2336
|
+
var TREATMENT_BENEFITS_DOC = "treatment-benefits";
|
|
2337
|
+
var CONTRAINDICATIONS_DOC = "contraindications";
|
|
2338
|
+
var ConstantsService = class extends BaseService {
|
|
2339
|
+
/**
|
|
2340
|
+
* @description Gets the reference to the document holding treatment benefits.
|
|
2341
|
+
* @private
|
|
2342
|
+
* @type {DocumentReference}
|
|
2343
|
+
*/
|
|
2344
|
+
get treatmentBenefitsDocRef() {
|
|
2345
|
+
return (0, import_firestore12.doc)(this.db, ADMIN_CONSTANTS_COLLECTION, TREATMENT_BENEFITS_DOC);
|
|
2346
|
+
}
|
|
2347
|
+
/**
|
|
2348
|
+
* @description Gets the reference to the document holding contraindications.
|
|
2349
|
+
* @private
|
|
2350
|
+
* @type {DocumentReference}
|
|
2351
|
+
*/
|
|
2352
|
+
get contraindicationsDocRef() {
|
|
2353
|
+
return (0, import_firestore12.doc)(this.db, ADMIN_CONSTANTS_COLLECTION, CONTRAINDICATIONS_DOC);
|
|
2354
|
+
}
|
|
2355
|
+
// =================================================================
|
|
2356
|
+
// Treatment Benefits
|
|
2357
|
+
// =================================================================
|
|
2358
|
+
/**
|
|
2359
|
+
* @description Retrieves all treatment benefits without pagination.
|
|
2360
|
+
* @returns {Promise<TreatmentBenefitDynamic[]>} An array of all treatment benefits.
|
|
2361
|
+
*/
|
|
2362
|
+
async getAllBenefitsForFilter() {
|
|
2363
|
+
const docSnap = await (0, import_firestore12.getDoc)(this.treatmentBenefitsDocRef);
|
|
2364
|
+
if (!docSnap.exists()) {
|
|
2365
|
+
return [];
|
|
2366
|
+
}
|
|
2367
|
+
return docSnap.data().benefits;
|
|
2368
|
+
}
|
|
2369
|
+
/**
|
|
2370
|
+
* @description Retrieves a paginated list of treatment benefits.
|
|
2371
|
+
* @param {{ page: number; limit: number }} options - Pagination options.
|
|
2372
|
+
* @returns {Promise<{ benefits: TreatmentBenefitDynamic[]; total: number }>} A paginated list of benefits and the total count.
|
|
2373
|
+
*/
|
|
2374
|
+
async getAllBenefits(options) {
|
|
2375
|
+
const allBenefits = await this.getAllBenefitsForFilter();
|
|
2376
|
+
const { page, limit: limit9 } = options;
|
|
2377
|
+
const startIndex = page * limit9;
|
|
2378
|
+
const endIndex = startIndex + limit9;
|
|
2379
|
+
const paginatedBenefits = allBenefits.slice(startIndex, endIndex);
|
|
2380
|
+
return { benefits: paginatedBenefits, total: allBenefits.length };
|
|
2381
|
+
}
|
|
2382
|
+
/**
|
|
2383
|
+
* @description Adds a new treatment benefit.
|
|
2384
|
+
* @param {Omit<TreatmentBenefitDynamic, "id">} benefit - The treatment benefit to add, without an ID.
|
|
2385
|
+
* @returns {Promise<TreatmentBenefitDynamic>} The newly created treatment benefit with its generated ID.
|
|
2386
|
+
*/
|
|
2387
|
+
async addTreatmentBenefit(benefit) {
|
|
2388
|
+
const newBenefit = {
|
|
2389
|
+
id: this.generateId(),
|
|
2390
|
+
...benefit
|
|
2391
|
+
};
|
|
2392
|
+
const docSnap = await (0, import_firestore12.getDoc)(this.treatmentBenefitsDocRef);
|
|
2393
|
+
if (!docSnap.exists()) {
|
|
2394
|
+
await (0, import_firestore12.setDoc)(this.treatmentBenefitsDocRef, { benefits: [newBenefit] });
|
|
2395
|
+
} else {
|
|
2396
|
+
await (0, import_firestore12.updateDoc)(this.treatmentBenefitsDocRef, {
|
|
2397
|
+
benefits: (0, import_firestore12.arrayUnion)(newBenefit)
|
|
2398
|
+
});
|
|
2399
|
+
}
|
|
2400
|
+
return newBenefit;
|
|
2401
|
+
}
|
|
2402
|
+
/**
|
|
2403
|
+
* @description Retrieves a single treatment benefit by its ID.
|
|
2404
|
+
* @param {string} benefitId - The ID of the treatment benefit to retrieve.
|
|
2405
|
+
* @returns {Promise<TreatmentBenefitDynamic | undefined>} The found treatment benefit or undefined.
|
|
2406
|
+
*/
|
|
2407
|
+
async getBenefitById(benefitId) {
|
|
2408
|
+
const benefits = await this.getAllBenefitsForFilter();
|
|
2409
|
+
return benefits.find((b) => b.id === benefitId);
|
|
2410
|
+
}
|
|
2411
|
+
/**
|
|
2412
|
+
* @description Searches for treatment benefits by name (case-insensitive).
|
|
2413
|
+
* @param {string} searchTerm - The term to search for in the benefit names.
|
|
2414
|
+
* @returns {Promise<TreatmentBenefitDynamic[]>} An array of matching treatment benefits.
|
|
2415
|
+
*/
|
|
2416
|
+
async searchBenefitsByName(searchTerm) {
|
|
2417
|
+
const benefits = await this.getAllBenefitsForFilter();
|
|
2418
|
+
const normalizedSearchTerm = searchTerm.toLowerCase();
|
|
2419
|
+
return benefits.filter(
|
|
2420
|
+
(b) => b.name.toLowerCase().includes(normalizedSearchTerm)
|
|
2421
|
+
);
|
|
2422
|
+
}
|
|
2423
|
+
/**
|
|
2424
|
+
* @description Updates an existing treatment benefit.
|
|
2425
|
+
* @param {TreatmentBenefitDynamic} benefit - The treatment benefit with updated data. Its ID must match an existing benefit.
|
|
2426
|
+
* @returns {Promise<TreatmentBenefitDynamic>} The updated treatment benefit.
|
|
2427
|
+
* @throws {Error} If the treatment benefit is not found.
|
|
2428
|
+
*/
|
|
2429
|
+
async updateTreatmentBenefit(benefit) {
|
|
2430
|
+
const benefits = await this.getAllBenefitsForFilter();
|
|
2431
|
+
const benefitIndex = benefits.findIndex((b) => b.id === benefit.id);
|
|
2432
|
+
if (benefitIndex === -1) {
|
|
2433
|
+
throw new Error("Treatment benefit not found.");
|
|
2434
|
+
}
|
|
2435
|
+
benefits[benefitIndex] = benefit;
|
|
2436
|
+
await (0, import_firestore12.updateDoc)(this.treatmentBenefitsDocRef, { benefits });
|
|
2437
|
+
return benefit;
|
|
2438
|
+
}
|
|
2439
|
+
/**
|
|
2440
|
+
* @description Deletes a treatment benefit by its ID.
|
|
2441
|
+
* @param {string} benefitId - The ID of the treatment benefit to delete.
|
|
2442
|
+
* @returns {Promise<void>}
|
|
2443
|
+
*/
|
|
2444
|
+
async deleteTreatmentBenefit(benefitId) {
|
|
2445
|
+
const benefits = await this.getAllBenefitsForFilter();
|
|
2446
|
+
const benefitToRemove = benefits.find((b) => b.id === benefitId);
|
|
2447
|
+
if (!benefitToRemove) {
|
|
2448
|
+
return;
|
|
2449
|
+
}
|
|
2450
|
+
await (0, import_firestore12.updateDoc)(this.treatmentBenefitsDocRef, {
|
|
2451
|
+
benefits: (0, import_firestore12.arrayRemove)(benefitToRemove)
|
|
2452
|
+
});
|
|
2453
|
+
}
|
|
2454
|
+
// =================================================================
|
|
2455
|
+
// Contraindications
|
|
2456
|
+
// =================================================================
|
|
2457
|
+
/**
|
|
2458
|
+
* @description Retrieves all contraindications without pagination.
|
|
2459
|
+
* @returns {Promise<ContraindicationDynamic[]>} An array of all contraindications.
|
|
2460
|
+
*/
|
|
2461
|
+
async getAllContraindicationsForFilter() {
|
|
2462
|
+
const docSnap = await (0, import_firestore12.getDoc)(this.contraindicationsDocRef);
|
|
2463
|
+
if (!docSnap.exists()) {
|
|
2464
|
+
return [];
|
|
2465
|
+
}
|
|
2466
|
+
return docSnap.data().contraindications;
|
|
2467
|
+
}
|
|
2468
|
+
/**
|
|
2469
|
+
* @description Retrieves a paginated list of contraindications.
|
|
2470
|
+
* @param {{ page: number; limit: number }} options - Pagination options.
|
|
2471
|
+
* @returns {Promise<{ contraindications: ContraindicationDynamic[]; total: number }>} A paginated list and the total count.
|
|
2472
|
+
*/
|
|
2473
|
+
async getAllContraindications(options) {
|
|
2474
|
+
const allContraindications = await this.getAllContraindicationsForFilter();
|
|
2475
|
+
const { page, limit: limit9 } = options;
|
|
2476
|
+
const startIndex = page * limit9;
|
|
2477
|
+
const endIndex = startIndex + limit9;
|
|
2478
|
+
const paginatedContraindications = allContraindications.slice(
|
|
2479
|
+
startIndex,
|
|
2480
|
+
endIndex
|
|
2481
|
+
);
|
|
2482
|
+
return {
|
|
2483
|
+
contraindications: paginatedContraindications,
|
|
2484
|
+
total: allContraindications.length
|
|
2485
|
+
};
|
|
2486
|
+
}
|
|
2487
|
+
/**
|
|
2488
|
+
* @description Adds a new contraindication.
|
|
2489
|
+
* @param {Omit<ContraindicationDynamic, "id">} contraindication - The contraindication to add, without an ID.
|
|
2490
|
+
* @returns {Promise<ContraindicationDynamic>} The newly created contraindication with its generated ID.
|
|
2491
|
+
*/
|
|
2492
|
+
async addContraindication(contraindication) {
|
|
2493
|
+
const newContraindication = {
|
|
2494
|
+
id: this.generateId(),
|
|
2495
|
+
...contraindication
|
|
2496
|
+
};
|
|
2497
|
+
const docSnap = await (0, import_firestore12.getDoc)(this.contraindicationsDocRef);
|
|
2498
|
+
if (!docSnap.exists()) {
|
|
2499
|
+
await (0, import_firestore12.setDoc)(this.contraindicationsDocRef, {
|
|
2500
|
+
contraindications: [newContraindication]
|
|
2501
|
+
});
|
|
2502
|
+
} else {
|
|
2503
|
+
await (0, import_firestore12.updateDoc)(this.contraindicationsDocRef, {
|
|
2504
|
+
contraindications: (0, import_firestore12.arrayUnion)(newContraindication)
|
|
2505
|
+
});
|
|
2506
|
+
}
|
|
2507
|
+
return newContraindication;
|
|
2508
|
+
}
|
|
2509
|
+
/**
|
|
2510
|
+
* @description Retrieves a single contraindication by its ID.
|
|
2511
|
+
* @param {string} contraindicationId - The ID of the contraindication to retrieve.
|
|
2512
|
+
* @returns {Promise<ContraindicationDynamic | undefined>} The found contraindication or undefined.
|
|
2513
|
+
*/
|
|
2514
|
+
async getContraindicationById(contraindicationId) {
|
|
2515
|
+
const contraindications = await this.getAllContraindicationsForFilter();
|
|
2516
|
+
return contraindications.find((c) => c.id === contraindicationId);
|
|
2517
|
+
}
|
|
2518
|
+
/**
|
|
2519
|
+
* @description Searches for contraindications by name (case-insensitive).
|
|
2520
|
+
* @param {string} searchTerm - The term to search for in the contraindication names.
|
|
2521
|
+
* @returns {Promise<ContraindicationDynamic[]>} An array of matching contraindications.
|
|
2522
|
+
*/
|
|
2523
|
+
async searchContraindicationsByName(searchTerm) {
|
|
2524
|
+
const contraindications = await this.getAllContraindicationsForFilter();
|
|
2525
|
+
const normalizedSearchTerm = searchTerm.toLowerCase();
|
|
2526
|
+
return contraindications.filter(
|
|
2527
|
+
(c) => c.name.toLowerCase().includes(normalizedSearchTerm)
|
|
2528
|
+
);
|
|
2529
|
+
}
|
|
2530
|
+
/**
|
|
2531
|
+
* @description Updates an existing contraindication.
|
|
2532
|
+
* @param {ContraindicationDynamic} contraindication - The contraindication with updated data. Its ID must match an existing one.
|
|
2533
|
+
* @returns {Promise<ContraindicationDynamic>} The updated contraindication.
|
|
2534
|
+
* @throws {Error} If the contraindication is not found.
|
|
2535
|
+
*/
|
|
2536
|
+
async updateContraindication(contraindication) {
|
|
2537
|
+
const contraindications = await this.getAllContraindicationsForFilter();
|
|
2538
|
+
const index = contraindications.findIndex(
|
|
2539
|
+
(c) => c.id === contraindication.id
|
|
2540
|
+
);
|
|
2541
|
+
if (index === -1) {
|
|
2542
|
+
throw new Error("Contraindication not found.");
|
|
2543
|
+
}
|
|
2544
|
+
contraindications[index] = contraindication;
|
|
2545
|
+
await (0, import_firestore12.updateDoc)(this.contraindicationsDocRef, { contraindications });
|
|
2546
|
+
return contraindication;
|
|
2547
|
+
}
|
|
2548
|
+
/**
|
|
2549
|
+
* @description Deletes a contraindication by its ID.
|
|
2550
|
+
* @param {string} contraindicationId - The ID of the contraindication to delete.
|
|
2551
|
+
* @returns {Promise<void>}
|
|
2552
|
+
*/
|
|
2553
|
+
async deleteContraindication(contraindicationId) {
|
|
2554
|
+
const contraindications = await this.getAllContraindicationsForFilter();
|
|
2555
|
+
const toRemove = contraindications.find((c) => c.id === contraindicationId);
|
|
2556
|
+
if (!toRemove) {
|
|
2557
|
+
return;
|
|
2558
|
+
}
|
|
2559
|
+
await (0, import_firestore12.updateDoc)(this.contraindicationsDocRef, {
|
|
2560
|
+
contraindications: (0, import_firestore12.arrayRemove)(toRemove)
|
|
2561
|
+
});
|
|
2562
|
+
}
|
|
1692
2563
|
};
|
|
1693
2564
|
|
|
1694
2565
|
// src/backoffice/types/static/blocking-condition.types.ts
|
|
@@ -1747,13 +2618,6 @@ var Currency = /* @__PURE__ */ ((Currency2) => {
|
|
|
1747
2618
|
return Currency2;
|
|
1748
2619
|
})(Currency || {});
|
|
1749
2620
|
|
|
1750
|
-
// src/backoffice/types/static/procedure-family.types.ts
|
|
1751
|
-
var ProcedureFamily = /* @__PURE__ */ ((ProcedureFamily2) => {
|
|
1752
|
-
ProcedureFamily2["AESTHETICS"] = "aesthetics";
|
|
1753
|
-
ProcedureFamily2["SURGERY"] = "surgery";
|
|
1754
|
-
return ProcedureFamily2;
|
|
1755
|
-
})(ProcedureFamily || {});
|
|
1756
|
-
|
|
1757
2621
|
// src/backoffice/types/static/treatment-benefit.types.ts
|
|
1758
2622
|
var TreatmentBenefit = /* @__PURE__ */ ((TreatmentBenefit2) => {
|
|
1759
2623
|
TreatmentBenefit2["WRINKLE_REDUCTION"] = "wrinkle_reduction";
|
|
@@ -1776,9 +2640,25 @@ var TreatmentBenefit = /* @__PURE__ */ ((TreatmentBenefit2) => {
|
|
|
1776
2640
|
|
|
1777
2641
|
// src/backoffice/validations/schemas.ts
|
|
1778
2642
|
var import_zod2 = require("zod");
|
|
2643
|
+
var contraindicationDynamicSchema = import_zod2.z.object({
|
|
2644
|
+
id: import_zod2.z.string().min(1, "Contraindication ID is required").regex(
|
|
2645
|
+
/^[a-z0-9_]+$/,
|
|
2646
|
+
"ID must be in snake_case (lowercase, numbers, and underscores only)"
|
|
2647
|
+
),
|
|
2648
|
+
name: import_zod2.z.string().min(1, "Contraindication name is required"),
|
|
2649
|
+
description: import_zod2.z.string().optional()
|
|
2650
|
+
});
|
|
2651
|
+
var treatmentBenefitDynamicSchema = import_zod2.z.object({
|
|
2652
|
+
id: import_zod2.z.string().min(1, "Benefit ID is required").regex(
|
|
2653
|
+
/^[a-z0-9_]+$/,
|
|
2654
|
+
"ID must be in snake_case (lowercase, numbers, and underscores only)"
|
|
2655
|
+
),
|
|
2656
|
+
name: import_zod2.z.string().min(1, "Benefit name is required"),
|
|
2657
|
+
description: import_zod2.z.string().optional()
|
|
2658
|
+
});
|
|
1779
2659
|
var blockingConditionSchemaBackoffice = import_zod2.z.nativeEnum(BlockingCondition);
|
|
1780
|
-
var contraindicationSchemaBackoffice =
|
|
1781
|
-
var treatmentBenefitSchemaBackoffice =
|
|
2660
|
+
var contraindicationSchemaBackoffice = contraindicationDynamicSchema;
|
|
2661
|
+
var treatmentBenefitSchemaBackoffice = treatmentBenefitDynamicSchema;
|
|
1782
2662
|
var procedureFamilySchemaBackoffice = import_zod2.z.nativeEnum(ProcedureFamily);
|
|
1783
2663
|
var timeUnitSchemaBackoffice = import_zod2.z.nativeEnum(TimeUnit);
|
|
1784
2664
|
var requirementTypeSchema = import_zod2.z.nativeEnum(RequirementType);
|
|
@@ -2001,6 +2881,7 @@ var InvalidTreatmentBenefitError = class extends TreatmentBenefitError {
|
|
|
2001
2881
|
CertificationLevel,
|
|
2002
2882
|
CertificationSpecialty,
|
|
2003
2883
|
CircularReferenceError,
|
|
2884
|
+
ConstantsService,
|
|
2004
2885
|
Contraindication,
|
|
2005
2886
|
ContraindicationError,
|
|
2006
2887
|
Currency,
|
|
@@ -2048,6 +2929,7 @@ var InvalidTreatmentBenefitError = class extends TreatmentBenefitError {
|
|
|
2048
2929
|
certificationLevelSchema,
|
|
2049
2930
|
certificationRequirementSchema,
|
|
2050
2931
|
certificationSpecialtySchema,
|
|
2932
|
+
contraindicationDynamicSchema,
|
|
2051
2933
|
contraindicationSchemaBackoffice,
|
|
2052
2934
|
createDocumentTemplateSchema,
|
|
2053
2935
|
documentElementSchema,
|
|
@@ -2064,6 +2946,7 @@ var InvalidTreatmentBenefitError = class extends TreatmentBenefitError {
|
|
|
2064
2946
|
technologyUpdateSchema,
|
|
2065
2947
|
timeUnitSchemaBackoffice,
|
|
2066
2948
|
timeframeSchema,
|
|
2949
|
+
treatmentBenefitDynamicSchema,
|
|
2067
2950
|
treatmentBenefitSchemaBackoffice,
|
|
2068
2951
|
updateDocumentTemplateSchema
|
|
2069
2952
|
});
|