tt-entities 0.0.38 → 0.0.40

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.
@@ -0,0 +1,121 @@
1
+ import {
2
+ Model,
3
+ Table,
4
+ Column,
5
+ DataType,
6
+ ForeignKey,
7
+ BelongsTo,
8
+ } from 'sequelize-typescript';
9
+
10
+ // ── Where the banner appears ──────────────────────────────────────────────────
11
+ export enum BannerPlacement {
12
+ HOME = 'home', // horizontal list on the home page
13
+ CATEGORY = 'category', // top of a specific category page
14
+ BRAND = 'brand', // top of a specific brand page
15
+ SEARCH = 'search', // search results page
16
+ CUSTOM = 'custom', // any future placement — identified by placementKey
17
+ }
18
+
19
+ export enum BannerStatus {
20
+ ACTIVE = 'active',
21
+ INACTIVE = 'inactive',
22
+ DRAFT = 'draft',
23
+ }
24
+
25
+ // ── Filter shape stored in the JSON column ────────────────────────────────────
26
+ // All fields are optional — any combination is valid.
27
+ // An empty object {} means "show everything" (no filter).
28
+ export interface BannerFilters {
29
+ categoryIds?: number[]; // products/bundles in these categories
30
+ brandIds?: number[]; // products belonging to these brands
31
+ tagSlugs?: string[]; // products tagged with any of these slugs
32
+ types?: ('product' | 'bundle')[]; // limit to only products or only bundles
33
+ isFeatured?: boolean; // only featured items
34
+ minPrice?: number;
35
+ maxPrice?: number;
36
+ // Future: collectionId, promotionId, etc.
37
+ }
38
+
39
+ @Table
40
+ export class Banner extends Model {
41
+ // ── Identity ────────────────────────────────────────────────────────────────
42
+ @Column({ allowNull: false })
43
+ declare titleEn: string;
44
+
45
+ @Column({ allowNull: false })
46
+ declare titleAr: string;
47
+
48
+ @Column({ type: DataType.TEXT, allowNull: true })
49
+ declare subtitleEn: string | null;
50
+
51
+ @Column({ type: DataType.TEXT, allowNull: true })
52
+ declare subtitleAr: string | null;
53
+
54
+ // ── Media ───────────────────────────────────────────────────────────────────
55
+ @Column({ allowNull: false })
56
+ declare coverImage: string; // S3 URL
57
+
58
+ @Column({ allowNull: true })
59
+ declare coverImageMobile: string | null; // optional separate mobile crop
60
+
61
+ // ── Placement ───────────────────────────────────────────────────────────────
62
+ // WHERE this banner appears
63
+ @Column({
64
+ type: DataType.ENUM(...Object.values(BannerPlacement)),
65
+ allowNull: false,
66
+ defaultValue: BannerPlacement.HOME,
67
+ })
68
+ declare placement: BannerPlacement;
69
+
70
+ // For placement=category → placementRefId = categoryId
71
+ // For placement=brand → placementRefId = brandId
72
+ // For placement=home/search/custom → null
73
+ @Column({ allowNull: true })
74
+ declare placementRefId?: number;
75
+
76
+ // Human-readable key for custom placements (e.g. "ramadan_sale", "checkout_top")
77
+ @Column({ allowNull: true })
78
+ declare placementKey?: string;
79
+
80
+ // ── Catalog filters (what products/bundles appear INSIDE the banner) ─────────
81
+ // Stored as JSON — resolved at runtime via CatalogListService
82
+ @Column({
83
+ type: DataType.JSON,
84
+ allowNull: false,
85
+ defaultValue: {},
86
+ })
87
+ declare filters: BannerFilters;
88
+
89
+ // Max number of items to return inside the banner (null = use API default)
90
+ @Column({ allowNull: true })
91
+ declare itemLimit?: number;
92
+
93
+ // ── CTA (optional tap action on the banner cover itself) ─────────────────────
94
+ @Column({ allowNull: true })
95
+ declare ctaLabelEn?: string;
96
+
97
+ @Column({ allowNull: true })
98
+ declare ctaLabelAr?: string;
99
+
100
+ // Deep link or web URL the cover image taps to
101
+ @Column({ allowNull: true })
102
+ declare ctaUrl?: string;
103
+
104
+ // ── Scheduling ───────────────────────────────────────────────────────────────
105
+ @Column({ type: DataType.DATE, allowNull: true })
106
+ declare startDate?: Date; // null = show immediately
107
+
108
+ @Column({ type: DataType.DATE, allowNull: true })
109
+ declare endDate?: Date; // null = show indefinitely
110
+
111
+ // ── Display ─────────────────────────────────────────────────────────────────
112
+ @Column({ defaultValue: 0 })
113
+ declare sortOrder: number;
114
+
115
+ @Column({
116
+ type: DataType.ENUM(...Object.values(BannerStatus)),
117
+ allowNull: false,
118
+ defaultValue: BannerStatus.DRAFT,
119
+ })
120
+ declare status: BannerStatus;
121
+ }
@@ -10,6 +10,8 @@ export enum FavoriteCatalogItemType {
10
10
  }
11
11
 
12
12
  @Table({
13
+ paranoid: false, // hard delete only — soft delete breaks the unique constraint on re-add
14
+ timestamps: true, // keeps createdAt / updatedAt, no deletedAt column
13
15
  indexes: [
14
16
  {
15
17
  // Prevent duplicate favorites for the same item
@@ -11,6 +11,7 @@ import { ApiKey } from './entities/apikey.entity';
11
11
  import { UserAddress } from './entities/user-address.entity';
12
12
  import { UserFavorite } from './entities/user-favorite.entity';
13
13
  import { UserFavoriteCatalog } from './entities/user-favorite-catalog.entity';
14
+ import { Banner } from './entities/banner.entity';
14
15
 
15
16
  // ─── Catalogue ────────────────────────────────────────────────────────────────
16
17
  import { Category } from './entities/category.entity';
@@ -92,6 +93,12 @@ export {
92
93
  UserFavoriteCatalog,
93
94
  FavoriteCatalogItemType,
94
95
  } from './entities/user-favorite-catalog.entity';
96
+ export {
97
+ Banner,
98
+ BannerPlacement,
99
+ BannerStatus,
100
+ BannerFilters,
101
+ } from './entities/banner.entity';
95
102
 
96
103
  // ─── Catalogue ────────────────────────────────────────────────────────────────
97
104
  export { Category } from './entities/category.entity';
@@ -267,5 +274,8 @@ export function getDbModels(): ModelCtor[] {
267
274
  OrderStatusHistory,
268
275
  UserTransaction,
269
276
  PurchaseOrderOrderItem,
277
+
278
+ // Banners
279
+ Banner,
270
280
  ];
271
281
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tt-entities",
3
- "version": "0.0.38",
3
+ "version": "0.0.40",
4
4
  "description": "Tatayab entities library",
5
5
  "main": "dist/libs/tatayab-entities-library/index.js",
6
6
  "types": "dist/libs/tatayab-entities-library/index.d.ts",