@blackcode_sa/metaestetics-api 1.14.34 → 1.14.37
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 +9 -18
- package/dist/admin/index.d.ts +9 -18
- package/dist/backoffice/index.d.mts +41 -54
- package/dist/backoffice/index.d.ts +41 -54
- package/dist/backoffice/index.js +23 -38
- package/dist/backoffice/index.mjs +23 -38
- package/dist/index.d.mts +21 -34
- package/dist/index.d.ts +21 -34
- package/dist/index.js +23 -38
- package/dist/index.mjs +23 -38
- package/package.json +1 -1
- package/src/backoffice/services/brand.service.ts +4 -17
- package/src/backoffice/services/product.service.ts +12 -17
- package/src/backoffice/services/technology.service.ts +3 -1
- package/src/backoffice/types/brand.types.ts +0 -2
- package/src/backoffice/types/product.types.ts +18 -28
package/dist/index.js
CHANGED
|
@@ -23359,13 +23359,12 @@ var BrandService = class extends BaseService {
|
|
|
23359
23359
|
return { id: docRef.id, ...newBrand };
|
|
23360
23360
|
}
|
|
23361
23361
|
/**
|
|
23362
|
-
* Gets a paginated list of active brands, optionally filtered by name
|
|
23362
|
+
* Gets a paginated list of active brands, optionally filtered by name.
|
|
23363
23363
|
* @param rowsPerPage - The number of brands to fetch.
|
|
23364
23364
|
* @param searchTerm - An optional string to filter brand names by (starts-with search).
|
|
23365
23365
|
* @param lastVisible - An optional document snapshot to use as a cursor for pagination.
|
|
23366
|
-
* @param category - An optional category to filter brands by.
|
|
23367
23366
|
*/
|
|
23368
|
-
async getAll(rowsPerPage, searchTerm, lastVisible
|
|
23367
|
+
async getAll(rowsPerPage, searchTerm, lastVisible) {
|
|
23369
23368
|
const constraints = [
|
|
23370
23369
|
(0, import_firestore61.where)("isActive", "==", true),
|
|
23371
23370
|
(0, import_firestore61.orderBy)("name_lowercase")
|
|
@@ -23377,9 +23376,6 @@ var BrandService = class extends BaseService {
|
|
|
23377
23376
|
(0, import_firestore61.where)("name_lowercase", "<=", lowercasedSearchTerm + "\uF8FF")
|
|
23378
23377
|
);
|
|
23379
23378
|
}
|
|
23380
|
-
if (category) {
|
|
23381
|
-
constraints.push((0, import_firestore61.where)("category", "==", category));
|
|
23382
|
-
}
|
|
23383
23379
|
if (lastVisible) {
|
|
23384
23380
|
constraints.push((0, import_firestore61.startAfter)(lastVisible));
|
|
23385
23381
|
}
|
|
@@ -23396,11 +23392,10 @@ var BrandService = class extends BaseService {
|
|
|
23396
23392
|
return { brands, lastVisible: newLastVisible };
|
|
23397
23393
|
}
|
|
23398
23394
|
/**
|
|
23399
|
-
* Gets the total count of active brands, optionally filtered by name
|
|
23395
|
+
* Gets the total count of active brands, optionally filtered by name.
|
|
23400
23396
|
* @param searchTerm - An optional string to filter brand names by (starts-with search).
|
|
23401
|
-
* @param category - An optional category to filter brands by.
|
|
23402
23397
|
*/
|
|
23403
|
-
async getBrandsCount(searchTerm
|
|
23398
|
+
async getBrandsCount(searchTerm) {
|
|
23404
23399
|
const constraints = [(0, import_firestore61.where)("isActive", "==", true)];
|
|
23405
23400
|
if (searchTerm) {
|
|
23406
23401
|
const lowercasedSearchTerm = searchTerm.toLowerCase();
|
|
@@ -23409,9 +23404,6 @@ var BrandService = class extends BaseService {
|
|
|
23409
23404
|
(0, import_firestore61.where)("name_lowercase", "<=", lowercasedSearchTerm + "\uF8FF")
|
|
23410
23405
|
);
|
|
23411
23406
|
}
|
|
23412
|
-
if (category) {
|
|
23413
|
-
constraints.push((0, import_firestore61.where)("category", "==", category));
|
|
23414
|
-
}
|
|
23415
23407
|
const q = (0, import_firestore61.query)(this.getBrandsRef(), ...constraints);
|
|
23416
23408
|
const snapshot = await (0, import_firestore61.getCountFromServer)(q);
|
|
23417
23409
|
return snapshot.data().count;
|
|
@@ -23481,7 +23473,6 @@ var BrandService = class extends BaseService {
|
|
|
23481
23473
|
"id",
|
|
23482
23474
|
"name",
|
|
23483
23475
|
"manufacturer",
|
|
23484
|
-
"category",
|
|
23485
23476
|
"website",
|
|
23486
23477
|
"description",
|
|
23487
23478
|
"isActive"
|
|
@@ -23512,15 +23503,14 @@ var BrandService = class extends BaseService {
|
|
|
23512
23503
|
return includeBom ? "\uFEFF" + csvBody : csvBody;
|
|
23513
23504
|
}
|
|
23514
23505
|
brandToCsvRow(brand) {
|
|
23515
|
-
var _a, _b, _c, _d, _e, _f
|
|
23506
|
+
var _a, _b, _c, _d, _e, _f;
|
|
23516
23507
|
const values = [
|
|
23517
23508
|
(_a = brand.id) != null ? _a : "",
|
|
23518
23509
|
(_b = brand.name) != null ? _b : "",
|
|
23519
23510
|
(_c = brand.manufacturer) != null ? _c : "",
|
|
23520
|
-
(_d = brand.
|
|
23521
|
-
(_e = brand.
|
|
23522
|
-
(_f = brand.
|
|
23523
|
-
String((_g = brand.isActive) != null ? _g : "")
|
|
23511
|
+
(_d = brand.website) != null ? _d : "",
|
|
23512
|
+
(_e = brand.description) != null ? _e : "",
|
|
23513
|
+
String((_f = brand.isActive) != null ? _f : "")
|
|
23524
23514
|
];
|
|
23525
23515
|
return values.map((v) => this.formatCsvValue(v)).join(",");
|
|
23526
23516
|
}
|
|
@@ -24946,7 +24936,8 @@ var TechnologyService = class extends BaseService {
|
|
|
24946
24936
|
const products = await this.getAssignedProducts(technologyId);
|
|
24947
24937
|
const byBrand = {};
|
|
24948
24938
|
products.forEach((product) => {
|
|
24949
|
-
|
|
24939
|
+
const brandName = product.brandName || "Unknown";
|
|
24940
|
+
byBrand[brandName] = (byBrand[brandName] || 0) + 1;
|
|
24950
24941
|
});
|
|
24951
24942
|
return {
|
|
24952
24943
|
totalAssigned: products.length,
|
|
@@ -25277,11 +25268,10 @@ var ProductService = class extends BaseService {
|
|
|
25277
25268
|
/**
|
|
25278
25269
|
* Creates a new product in the top-level collection
|
|
25279
25270
|
*/
|
|
25280
|
-
async createTopLevel(
|
|
25271
|
+
async createTopLevel(product, technologyIds = []) {
|
|
25281
25272
|
const now = /* @__PURE__ */ new Date();
|
|
25282
25273
|
const newProduct = {
|
|
25283
25274
|
...product,
|
|
25284
|
-
brandId,
|
|
25285
25275
|
assignedTechnologyIds: technologyIds,
|
|
25286
25276
|
createdAt: now,
|
|
25287
25277
|
updatedAt: now,
|
|
@@ -25294,11 +25284,14 @@ var ProductService = class extends BaseService {
|
|
|
25294
25284
|
* Gets all products from the top-level collection
|
|
25295
25285
|
*/
|
|
25296
25286
|
async getAllTopLevel(options) {
|
|
25297
|
-
const { rowsPerPage, lastVisible, brandId } = options;
|
|
25287
|
+
const { rowsPerPage, lastVisible, brandId, category } = options;
|
|
25298
25288
|
const constraints = [(0, import_firestore65.where)("isActive", "==", true), (0, import_firestore65.orderBy)("name")];
|
|
25299
25289
|
if (brandId) {
|
|
25300
25290
|
constraints.push((0, import_firestore65.where)("brandId", "==", brandId));
|
|
25301
25291
|
}
|
|
25292
|
+
if (category) {
|
|
25293
|
+
constraints.push((0, import_firestore65.where)("category", "==", category));
|
|
25294
|
+
}
|
|
25302
25295
|
if (lastVisible) {
|
|
25303
25296
|
constraints.push((0, import_firestore65.startAfter)(lastVisible));
|
|
25304
25297
|
}
|
|
@@ -25439,14 +25432,10 @@ var ProductService = class extends BaseService {
|
|
|
25439
25432
|
"name",
|
|
25440
25433
|
"brandId",
|
|
25441
25434
|
"brandName",
|
|
25435
|
+
"category",
|
|
25442
25436
|
"assignedTechnologyIds",
|
|
25443
25437
|
"description",
|
|
25444
|
-
"
|
|
25445
|
-
"dosage",
|
|
25446
|
-
"composition",
|
|
25447
|
-
"indications",
|
|
25448
|
-
"contraindications",
|
|
25449
|
-
"warnings",
|
|
25438
|
+
"metadata",
|
|
25450
25439
|
"isActive"
|
|
25451
25440
|
];
|
|
25452
25441
|
const rows = [];
|
|
@@ -25475,21 +25464,17 @@ var ProductService = class extends BaseService {
|
|
|
25475
25464
|
return includeBom ? "\uFEFF" + csvBody : csvBody;
|
|
25476
25465
|
}
|
|
25477
25466
|
productToCsvRow(product) {
|
|
25478
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i
|
|
25467
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
25479
25468
|
const values = [
|
|
25480
25469
|
(_a = product.id) != null ? _a : "",
|
|
25481
25470
|
(_b = product.name) != null ? _b : "",
|
|
25482
25471
|
(_c = product.brandId) != null ? _c : "",
|
|
25483
25472
|
(_d = product.brandName) != null ? _d : "",
|
|
25484
|
-
(
|
|
25485
|
-
(_g = product.
|
|
25486
|
-
(_h = product.
|
|
25487
|
-
|
|
25488
|
-
(
|
|
25489
|
-
(_l = (_k = product.indications) == null ? void 0 : _k.join(";")) != null ? _l : "",
|
|
25490
|
-
(_n = (_m = product.contraindications) == null ? void 0 : _m.map((c) => c.name).join(";")) != null ? _n : "",
|
|
25491
|
-
(_p = (_o = product.warnings) == null ? void 0 : _o.join(";")) != null ? _p : "",
|
|
25492
|
-
String((_q = product.isActive) != null ? _q : "")
|
|
25473
|
+
(_e = product.category) != null ? _e : "",
|
|
25474
|
+
(_g = (_f = product.assignedTechnologyIds) == null ? void 0 : _f.join(";")) != null ? _g : "",
|
|
25475
|
+
(_h = product.description) != null ? _h : "",
|
|
25476
|
+
product.metadata ? JSON.stringify(product.metadata) : "",
|
|
25477
|
+
String((_i = product.isActive) != null ? _i : "")
|
|
25493
25478
|
];
|
|
25494
25479
|
return values.map((v) => this.formatCsvValue(v)).join(",");
|
|
25495
25480
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -23618,13 +23618,12 @@ var BrandService = class extends BaseService {
|
|
|
23618
23618
|
return { id: docRef.id, ...newBrand };
|
|
23619
23619
|
}
|
|
23620
23620
|
/**
|
|
23621
|
-
* Gets a paginated list of active brands, optionally filtered by name
|
|
23621
|
+
* Gets a paginated list of active brands, optionally filtered by name.
|
|
23622
23622
|
* @param rowsPerPage - The number of brands to fetch.
|
|
23623
23623
|
* @param searchTerm - An optional string to filter brand names by (starts-with search).
|
|
23624
23624
|
* @param lastVisible - An optional document snapshot to use as a cursor for pagination.
|
|
23625
|
-
* @param category - An optional category to filter brands by.
|
|
23626
23625
|
*/
|
|
23627
|
-
async getAll(rowsPerPage, searchTerm, lastVisible
|
|
23626
|
+
async getAll(rowsPerPage, searchTerm, lastVisible) {
|
|
23628
23627
|
const constraints = [
|
|
23629
23628
|
where35("isActive", "==", true),
|
|
23630
23629
|
orderBy19("name_lowercase")
|
|
@@ -23636,9 +23635,6 @@ var BrandService = class extends BaseService {
|
|
|
23636
23635
|
where35("name_lowercase", "<=", lowercasedSearchTerm + "\uF8FF")
|
|
23637
23636
|
);
|
|
23638
23637
|
}
|
|
23639
|
-
if (category) {
|
|
23640
|
-
constraints.push(where35("category", "==", category));
|
|
23641
|
-
}
|
|
23642
23638
|
if (lastVisible) {
|
|
23643
23639
|
constraints.push(startAfter15(lastVisible));
|
|
23644
23640
|
}
|
|
@@ -23655,11 +23651,10 @@ var BrandService = class extends BaseService {
|
|
|
23655
23651
|
return { brands, lastVisible: newLastVisible };
|
|
23656
23652
|
}
|
|
23657
23653
|
/**
|
|
23658
|
-
* Gets the total count of active brands, optionally filtered by name
|
|
23654
|
+
* Gets the total count of active brands, optionally filtered by name.
|
|
23659
23655
|
* @param searchTerm - An optional string to filter brand names by (starts-with search).
|
|
23660
|
-
* @param category - An optional category to filter brands by.
|
|
23661
23656
|
*/
|
|
23662
|
-
async getBrandsCount(searchTerm
|
|
23657
|
+
async getBrandsCount(searchTerm) {
|
|
23663
23658
|
const constraints = [where35("isActive", "==", true)];
|
|
23664
23659
|
if (searchTerm) {
|
|
23665
23660
|
const lowercasedSearchTerm = searchTerm.toLowerCase();
|
|
@@ -23668,9 +23663,6 @@ var BrandService = class extends BaseService {
|
|
|
23668
23663
|
where35("name_lowercase", "<=", lowercasedSearchTerm + "\uF8FF")
|
|
23669
23664
|
);
|
|
23670
23665
|
}
|
|
23671
|
-
if (category) {
|
|
23672
|
-
constraints.push(where35("category", "==", category));
|
|
23673
|
-
}
|
|
23674
23666
|
const q = query35(this.getBrandsRef(), ...constraints);
|
|
23675
23667
|
const snapshot = await getCountFromServer3(q);
|
|
23676
23668
|
return snapshot.data().count;
|
|
@@ -23740,7 +23732,6 @@ var BrandService = class extends BaseService {
|
|
|
23740
23732
|
"id",
|
|
23741
23733
|
"name",
|
|
23742
23734
|
"manufacturer",
|
|
23743
|
-
"category",
|
|
23744
23735
|
"website",
|
|
23745
23736
|
"description",
|
|
23746
23737
|
"isActive"
|
|
@@ -23771,15 +23762,14 @@ var BrandService = class extends BaseService {
|
|
|
23771
23762
|
return includeBom ? "\uFEFF" + csvBody : csvBody;
|
|
23772
23763
|
}
|
|
23773
23764
|
brandToCsvRow(brand) {
|
|
23774
|
-
var _a, _b, _c, _d, _e, _f
|
|
23765
|
+
var _a, _b, _c, _d, _e, _f;
|
|
23775
23766
|
const values = [
|
|
23776
23767
|
(_a = brand.id) != null ? _a : "",
|
|
23777
23768
|
(_b = brand.name) != null ? _b : "",
|
|
23778
23769
|
(_c = brand.manufacturer) != null ? _c : "",
|
|
23779
|
-
(_d = brand.
|
|
23780
|
-
(_e = brand.
|
|
23781
|
-
(_f = brand.
|
|
23782
|
-
String((_g = brand.isActive) != null ? _g : "")
|
|
23770
|
+
(_d = brand.website) != null ? _d : "",
|
|
23771
|
+
(_e = brand.description) != null ? _e : "",
|
|
23772
|
+
String((_f = brand.isActive) != null ? _f : "")
|
|
23783
23773
|
];
|
|
23784
23774
|
return values.map((v) => this.formatCsvValue(v)).join(",");
|
|
23785
23775
|
}
|
|
@@ -25247,7 +25237,8 @@ var TechnologyService = class extends BaseService {
|
|
|
25247
25237
|
const products = await this.getAssignedProducts(technologyId);
|
|
25248
25238
|
const byBrand = {};
|
|
25249
25239
|
products.forEach((product) => {
|
|
25250
|
-
|
|
25240
|
+
const brandName = product.brandName || "Unknown";
|
|
25241
|
+
byBrand[brandName] = (byBrand[brandName] || 0) + 1;
|
|
25251
25242
|
});
|
|
25252
25243
|
return {
|
|
25253
25244
|
totalAssigned: products.length,
|
|
@@ -25594,11 +25585,10 @@ var ProductService = class extends BaseService {
|
|
|
25594
25585
|
/**
|
|
25595
25586
|
* Creates a new product in the top-level collection
|
|
25596
25587
|
*/
|
|
25597
|
-
async createTopLevel(
|
|
25588
|
+
async createTopLevel(product, technologyIds = []) {
|
|
25598
25589
|
const now = /* @__PURE__ */ new Date();
|
|
25599
25590
|
const newProduct = {
|
|
25600
25591
|
...product,
|
|
25601
|
-
brandId,
|
|
25602
25592
|
assignedTechnologyIds: technologyIds,
|
|
25603
25593
|
createdAt: now,
|
|
25604
25594
|
updatedAt: now,
|
|
@@ -25611,11 +25601,14 @@ var ProductService = class extends BaseService {
|
|
|
25611
25601
|
* Gets all products from the top-level collection
|
|
25612
25602
|
*/
|
|
25613
25603
|
async getAllTopLevel(options) {
|
|
25614
|
-
const { rowsPerPage, lastVisible, brandId } = options;
|
|
25604
|
+
const { rowsPerPage, lastVisible, brandId, category } = options;
|
|
25615
25605
|
const constraints = [where39("isActive", "==", true), orderBy23("name")];
|
|
25616
25606
|
if (brandId) {
|
|
25617
25607
|
constraints.push(where39("brandId", "==", brandId));
|
|
25618
25608
|
}
|
|
25609
|
+
if (category) {
|
|
25610
|
+
constraints.push(where39("category", "==", category));
|
|
25611
|
+
}
|
|
25619
25612
|
if (lastVisible) {
|
|
25620
25613
|
constraints.push(startAfter19(lastVisible));
|
|
25621
25614
|
}
|
|
@@ -25756,14 +25749,10 @@ var ProductService = class extends BaseService {
|
|
|
25756
25749
|
"name",
|
|
25757
25750
|
"brandId",
|
|
25758
25751
|
"brandName",
|
|
25752
|
+
"category",
|
|
25759
25753
|
"assignedTechnologyIds",
|
|
25760
25754
|
"description",
|
|
25761
|
-
"
|
|
25762
|
-
"dosage",
|
|
25763
|
-
"composition",
|
|
25764
|
-
"indications",
|
|
25765
|
-
"contraindications",
|
|
25766
|
-
"warnings",
|
|
25755
|
+
"metadata",
|
|
25767
25756
|
"isActive"
|
|
25768
25757
|
];
|
|
25769
25758
|
const rows = [];
|
|
@@ -25792,21 +25781,17 @@ var ProductService = class extends BaseService {
|
|
|
25792
25781
|
return includeBom ? "\uFEFF" + csvBody : csvBody;
|
|
25793
25782
|
}
|
|
25794
25783
|
productToCsvRow(product) {
|
|
25795
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i
|
|
25784
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
25796
25785
|
const values = [
|
|
25797
25786
|
(_a = product.id) != null ? _a : "",
|
|
25798
25787
|
(_b = product.name) != null ? _b : "",
|
|
25799
25788
|
(_c = product.brandId) != null ? _c : "",
|
|
25800
25789
|
(_d = product.brandName) != null ? _d : "",
|
|
25801
|
-
(
|
|
25802
|
-
(_g = product.
|
|
25803
|
-
(_h = product.
|
|
25804
|
-
|
|
25805
|
-
(
|
|
25806
|
-
(_l = (_k = product.indications) == null ? void 0 : _k.join(";")) != null ? _l : "",
|
|
25807
|
-
(_n = (_m = product.contraindications) == null ? void 0 : _m.map((c) => c.name).join(";")) != null ? _n : "",
|
|
25808
|
-
(_p = (_o = product.warnings) == null ? void 0 : _o.join(";")) != null ? _p : "",
|
|
25809
|
-
String((_q = product.isActive) != null ? _q : "")
|
|
25790
|
+
(_e = product.category) != null ? _e : "",
|
|
25791
|
+
(_g = (_f = product.assignedTechnologyIds) == null ? void 0 : _f.join(";")) != null ? _g : "",
|
|
25792
|
+
(_h = product.description) != null ? _h : "",
|
|
25793
|
+
product.metadata ? JSON.stringify(product.metadata) : "",
|
|
25794
|
+
String((_i = product.isActive) != null ? _i : "")
|
|
25810
25795
|
];
|
|
25811
25796
|
return values.map((v) => this.formatCsvValue(v)).join(",");
|
|
25812
25797
|
}
|
package/package.json
CHANGED
|
@@ -46,17 +46,15 @@ export class BrandService extends BaseService {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
|
-
* Gets a paginated list of active brands, optionally filtered by name
|
|
49
|
+
* Gets a paginated list of active brands, optionally filtered by name.
|
|
50
50
|
* @param rowsPerPage - The number of brands to fetch.
|
|
51
51
|
* @param searchTerm - An optional string to filter brand names by (starts-with search).
|
|
52
52
|
* @param lastVisible - An optional document snapshot to use as a cursor for pagination.
|
|
53
|
-
* @param category - An optional category to filter brands by.
|
|
54
53
|
*/
|
|
55
54
|
async getAll(
|
|
56
55
|
rowsPerPage: number,
|
|
57
56
|
searchTerm?: string,
|
|
58
|
-
lastVisible?: any
|
|
59
|
-
category?: string
|
|
57
|
+
lastVisible?: any
|
|
60
58
|
) {
|
|
61
59
|
const constraints: QueryConstraint[] = [
|
|
62
60
|
where("isActive", "==", true),
|
|
@@ -71,10 +69,6 @@ export class BrandService extends BaseService {
|
|
|
71
69
|
);
|
|
72
70
|
}
|
|
73
71
|
|
|
74
|
-
if (category) {
|
|
75
|
-
constraints.push(where("category", "==", category));
|
|
76
|
-
}
|
|
77
|
-
|
|
78
72
|
if (lastVisible) {
|
|
79
73
|
constraints.push(startAfter(lastVisible));
|
|
80
74
|
}
|
|
@@ -97,11 +91,10 @@ export class BrandService extends BaseService {
|
|
|
97
91
|
}
|
|
98
92
|
|
|
99
93
|
/**
|
|
100
|
-
* Gets the total count of active brands, optionally filtered by name
|
|
94
|
+
* Gets the total count of active brands, optionally filtered by name.
|
|
101
95
|
* @param searchTerm - An optional string to filter brand names by (starts-with search).
|
|
102
|
-
* @param category - An optional category to filter brands by.
|
|
103
96
|
*/
|
|
104
|
-
async getBrandsCount(searchTerm?: string
|
|
97
|
+
async getBrandsCount(searchTerm?: string) {
|
|
105
98
|
const constraints: QueryConstraint[] = [where("isActive", "==", true)];
|
|
106
99
|
|
|
107
100
|
if (searchTerm) {
|
|
@@ -112,10 +105,6 @@ export class BrandService extends BaseService {
|
|
|
112
105
|
);
|
|
113
106
|
}
|
|
114
107
|
|
|
115
|
-
if (category) {
|
|
116
|
-
constraints.push(where("category", "==", category));
|
|
117
|
-
}
|
|
118
|
-
|
|
119
108
|
const q = query(this.getBrandsRef(), ...constraints);
|
|
120
109
|
const snapshot = await getCountFromServer(q);
|
|
121
110
|
return snapshot.data().count;
|
|
@@ -199,7 +188,6 @@ export class BrandService extends BaseService {
|
|
|
199
188
|
"id",
|
|
200
189
|
"name",
|
|
201
190
|
"manufacturer",
|
|
202
|
-
"category",
|
|
203
191
|
"website",
|
|
204
192
|
"description",
|
|
205
193
|
"isActive",
|
|
@@ -246,7 +234,6 @@ export class BrandService extends BaseService {
|
|
|
246
234
|
brand.id ?? "",
|
|
247
235
|
brand.name ?? "",
|
|
248
236
|
brand.manufacturer ?? "",
|
|
249
|
-
brand.category ?? "",
|
|
250
237
|
brand.website ?? "",
|
|
251
238
|
brand.description ?? "",
|
|
252
239
|
String(brand.isActive ?? ""),
|
|
@@ -268,14 +268,12 @@ export class ProductService extends BaseService implements IProductService {
|
|
|
268
268
|
* Creates a new product in the top-level collection
|
|
269
269
|
*/
|
|
270
270
|
async createTopLevel(
|
|
271
|
-
|
|
272
|
-
product: Omit<Product, 'id' | 'createdAt' | 'updatedAt' | 'brandId' | 'assignedTechnologyIds'>,
|
|
271
|
+
product: Omit<Product, 'id' | 'createdAt' | 'updatedAt' | 'assignedTechnologyIds'>,
|
|
273
272
|
technologyIds: string[] = [],
|
|
274
273
|
): Promise<Product> {
|
|
275
274
|
const now = new Date();
|
|
276
275
|
const newProduct: Omit<Product, 'id'> = {
|
|
277
276
|
...product,
|
|
278
|
-
brandId,
|
|
279
277
|
assignedTechnologyIds: technologyIds,
|
|
280
278
|
createdAt: now,
|
|
281
279
|
updatedAt: now,
|
|
@@ -293,8 +291,9 @@ export class ProductService extends BaseService implements IProductService {
|
|
|
293
291
|
rowsPerPage: number;
|
|
294
292
|
lastVisible?: any;
|
|
295
293
|
brandId?: string;
|
|
294
|
+
category?: string;
|
|
296
295
|
}): Promise<{ products: Product[]; lastVisible: any }> {
|
|
297
|
-
const { rowsPerPage, lastVisible, brandId } = options;
|
|
296
|
+
const { rowsPerPage, lastVisible, brandId, category } = options;
|
|
298
297
|
|
|
299
298
|
const constraints: QueryConstraint[] = [where('isActive', '==', true), orderBy('name')];
|
|
300
299
|
|
|
@@ -302,6 +301,10 @@ export class ProductService extends BaseService implements IProductService {
|
|
|
302
301
|
constraints.push(where('brandId', '==', brandId));
|
|
303
302
|
}
|
|
304
303
|
|
|
304
|
+
if (category) {
|
|
305
|
+
constraints.push(where('category', '==', category));
|
|
306
|
+
}
|
|
307
|
+
|
|
305
308
|
if (lastVisible) {
|
|
306
309
|
constraints.push(startAfter(lastVisible));
|
|
307
310
|
}
|
|
@@ -340,7 +343,7 @@ export class ProductService extends BaseService implements IProductService {
|
|
|
340
343
|
*/
|
|
341
344
|
async updateTopLevel(
|
|
342
345
|
productId: string,
|
|
343
|
-
product: Partial<Omit<Product, 'id' | 'createdAt'
|
|
346
|
+
product: Partial<Omit<Product, 'id' | 'createdAt'>>,
|
|
344
347
|
): Promise<Product | null> {
|
|
345
348
|
const updateData = {
|
|
346
349
|
...product,
|
|
@@ -468,14 +471,10 @@ export class ProductService extends BaseService implements IProductService {
|
|
|
468
471
|
"name",
|
|
469
472
|
"brandId",
|
|
470
473
|
"brandName",
|
|
474
|
+
"category",
|
|
471
475
|
"assignedTechnologyIds",
|
|
472
476
|
"description",
|
|
473
|
-
"
|
|
474
|
-
"dosage",
|
|
475
|
-
"composition",
|
|
476
|
-
"indications",
|
|
477
|
-
"contraindications",
|
|
478
|
-
"warnings",
|
|
477
|
+
"metadata",
|
|
479
478
|
"isActive",
|
|
480
479
|
];
|
|
481
480
|
|
|
@@ -521,14 +520,10 @@ export class ProductService extends BaseService implements IProductService {
|
|
|
521
520
|
product.name ?? "",
|
|
522
521
|
product.brandId ?? "",
|
|
523
522
|
product.brandName ?? "",
|
|
523
|
+
product.category ?? "",
|
|
524
524
|
product.assignedTechnologyIds?.join(";") ?? "",
|
|
525
525
|
product.description ?? "",
|
|
526
|
-
product.
|
|
527
|
-
product.dosage ?? "",
|
|
528
|
-
product.composition ?? "",
|
|
529
|
-
product.indications?.join(";") ?? "",
|
|
530
|
-
product.contraindications?.map(c => c.name).join(";") ?? "",
|
|
531
|
-
product.warnings?.join(";") ?? "",
|
|
526
|
+
product.metadata ? JSON.stringify(product.metadata) : "",
|
|
532
527
|
String(product.isActive ?? ""),
|
|
533
528
|
];
|
|
534
529
|
return values.map((v) => this.formatCsvValue(v)).join(",");
|
|
@@ -979,7 +979,9 @@ export class TechnologyService extends BaseService implements ITechnologyService
|
|
|
979
979
|
|
|
980
980
|
const byBrand: Record<string, number> = {};
|
|
981
981
|
products.forEach(product => {
|
|
982
|
-
|
|
982
|
+
// Use brandName for grouping stats
|
|
983
|
+
const brandName = product.brandName || 'Unknown';
|
|
984
|
+
byBrand[brandName] = (byBrand[brandName] || 0) + 1;
|
|
983
985
|
});
|
|
984
986
|
|
|
985
987
|
return {
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
* @property manufacturer - Naziv proizvođača
|
|
8
8
|
* @property description - Detaljan opis brenda i njegovih proizvoda
|
|
9
9
|
* @property website - Web stranica brenda
|
|
10
|
-
* @property category - Kategorija brenda (npr. "laser", "peeling", "injectables") - za filtriranje
|
|
11
10
|
* @property isActive - Da li je brend aktivan u sistemu
|
|
12
11
|
* @property createdAt - Datum kreiranja
|
|
13
12
|
* @property updatedAt - Datum poslednjeg ažuriranja
|
|
@@ -22,7 +21,6 @@ export interface Brand {
|
|
|
22
21
|
isActive: boolean;
|
|
23
22
|
website?: string;
|
|
24
23
|
description?: string;
|
|
25
|
-
category?: string;
|
|
26
24
|
}
|
|
27
25
|
|
|
28
26
|
/**
|
|
@@ -1,21 +1,14 @@
|
|
|
1
|
-
import type { ContraindicationDynamic } from './admin-constants.types';
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Product used in procedures
|
|
5
|
-
*
|
|
3
|
+
* Simplified structure with only essential fields and flexible metadata
|
|
6
4
|
*
|
|
7
5
|
* @property id - Unique identifier of the product
|
|
8
6
|
* @property name - Name of the product
|
|
9
|
-
* @property brandId -
|
|
10
|
-
* @property brandName -
|
|
7
|
+
* @property brandId - Reference to the Brand document ID
|
|
8
|
+
* @property brandName - Display name of the brand (denormalized for performance)
|
|
9
|
+
* @property description - Detailed description of the product
|
|
11
10
|
* @property assignedTechnologyIds - Array of technology IDs this product is assigned to
|
|
12
|
-
* @property
|
|
13
|
-
* @property technicalDetails - Technical details and specifications
|
|
14
|
-
* @property warnings - List of warnings related to product use
|
|
15
|
-
* @property dosage - Dosage information (if applicable)
|
|
16
|
-
* @property composition - Product composition
|
|
17
|
-
* @property indications - List of indications for use
|
|
18
|
-
* @property contraindications - List of contraindications
|
|
11
|
+
* @property metadata - Flexible key-value pairs for additional product information
|
|
19
12
|
* @property isActive - Whether the product is active in the system
|
|
20
13
|
* @property createdAt - Creation date
|
|
21
14
|
* @property updatedAt - Last update date
|
|
@@ -23,23 +16,21 @@ import type { ContraindicationDynamic } from './admin-constants.types';
|
|
|
23
16
|
export interface Product {
|
|
24
17
|
id?: string;
|
|
25
18
|
name: string;
|
|
26
|
-
brandId: string;
|
|
27
|
-
brandName: string;
|
|
19
|
+
brandId: string; // Reference to Brand document
|
|
20
|
+
brandName: string; // Denormalized brand name for display
|
|
21
|
+
description: string;
|
|
22
|
+
category?: string; // "Injectables", "Laser Devices", "Skincare", etc.
|
|
28
23
|
|
|
29
|
-
//
|
|
24
|
+
// Technology assignment tracking
|
|
30
25
|
assignedTechnologyIds?: string[];
|
|
31
26
|
|
|
32
|
-
//
|
|
27
|
+
// Flexible metadata for any additional information
|
|
28
|
+
metadata?: Record<string, string | number | boolean>;
|
|
29
|
+
|
|
30
|
+
// System fields
|
|
31
|
+
isActive: boolean;
|
|
33
32
|
createdAt: Date;
|
|
34
33
|
updatedAt: Date;
|
|
35
|
-
isActive: boolean;
|
|
36
|
-
description?: string;
|
|
37
|
-
technicalDetails?: string;
|
|
38
|
-
warnings?: string[];
|
|
39
|
-
dosage?: string;
|
|
40
|
-
composition?: string;
|
|
41
|
-
indications?: string[];
|
|
42
|
-
contraindications?: ContraindicationDynamic[];
|
|
43
34
|
|
|
44
35
|
// LEGACY FIELDS: Only present in technology subcollections (/technologies/{id}/products/)
|
|
45
36
|
// These fields are synced by Cloud Functions for backward compatibility
|
|
@@ -72,13 +63,11 @@ export interface IProductService {
|
|
|
72
63
|
|
|
73
64
|
/**
|
|
74
65
|
* Creates a new product in the top-level collection
|
|
75
|
-
* @param brandId - ID of the brand that manufactures this product
|
|
76
66
|
* @param product - Product data
|
|
77
67
|
* @param technologyIds - Optional array of technology IDs to assign this product to
|
|
78
68
|
*/
|
|
79
69
|
createTopLevel(
|
|
80
|
-
|
|
81
|
-
product: Omit<Product, 'id' | 'createdAt' | 'updatedAt' | 'brandId' | 'assignedTechnologyIds'>,
|
|
70
|
+
product: Omit<Product, 'id' | 'createdAt' | 'updatedAt' | 'assignedTechnologyIds'>,
|
|
82
71
|
technologyIds?: string[],
|
|
83
72
|
): Promise<Product>;
|
|
84
73
|
|
|
@@ -90,6 +79,7 @@ export interface IProductService {
|
|
|
90
79
|
rowsPerPage: number;
|
|
91
80
|
lastVisible?: any;
|
|
92
81
|
brandId?: string;
|
|
82
|
+
category?: string;
|
|
93
83
|
}): Promise<{ products: Product[]; lastVisible: any }>;
|
|
94
84
|
|
|
95
85
|
/**
|
|
@@ -105,7 +95,7 @@ export interface IProductService {
|
|
|
105
95
|
*/
|
|
106
96
|
updateTopLevel(
|
|
107
97
|
productId: string,
|
|
108
|
-
product: Partial<Omit<Product, 'id' | 'createdAt'
|
|
98
|
+
product: Partial<Omit<Product, 'id' | 'createdAt'>>,
|
|
109
99
|
): Promise<Product | null>;
|
|
110
100
|
|
|
111
101
|
/**
|