@dataclouder/ngx-lessons 0.0.26 → 0.0.28

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.
@@ -1,9 +1,11 @@
1
1
  import { ChangeDetectorRef, EventEmitter, OnInit, Type, QueryList, OnDestroy } from '@angular/core';
2
2
  import { NgComponentOutlet } from '@angular/common';
3
3
  import { ActivatedRoute, Router } from '@angular/router';
4
- import { ICustomFilter, PaginationBase, ToastAlertsAbstractService } from '@dataclouder/ngx-core';
4
+ import { Subscription } from 'rxjs';
5
+ import { ICustomFilter, PaginationBase, PColumn, ToastAlertsAbstractService } from '@dataclouder/ngx-core';
5
6
  import { LessonsAbstractService } from '../../lesson-mini-components/components/lessons.clases';
6
7
  import { DcLessonCardComponent } from '../dc-lesson-card/dc-lesson-card.component';
8
+ import { MenuItem } from 'node_modules/primeng/api/menuitem';
7
9
  import * as i0 from "@angular/core";
8
10
  export declare class DCLessonListComponent extends PaginationBase implements OnInit, OnDestroy {
9
11
  private cdr;
@@ -14,14 +16,17 @@ export declare class DCLessonListComponent extends PaginationBase implements OnI
14
16
  isAdmin: boolean;
15
17
  customCardComponent?: Type<DcLessonCardComponent>;
16
18
  customFilters: ICustomFilter[];
19
+ viewType: 'table' | 'card';
20
+ actions: MenuItem[];
17
21
  onTakeLesson: EventEmitter<any>;
18
22
  onEditLesson: EventEmitter<any>;
19
23
  onRemoveLesson: EventEmitter<any>;
20
24
  qr: EventEmitter<any>;
21
25
  onNewLesson: EventEmitter<any>;
26
+ columns: PColumn[];
22
27
  outlets: QueryList<NgComponentOutlet>;
23
28
  cardComponent: Type<DcLessonCardComponent>;
24
- private cardEventSubs;
29
+ cardEventSubs: Subscription[];
25
30
  lessons: any[];
26
31
  isLoadingLessons: boolean;
27
32
  constructor(cdr: ChangeDetectorRef, router: Router, route: ActivatedRoute, lessonsService: LessonsAbstractService, toastrService: ToastAlertsAbstractService);
@@ -33,13 +38,17 @@ export declare class DCLessonListComponent extends PaginationBase implements OnI
33
38
  getPaginatedLessons(paginator: any): Promise<void>;
34
39
  goToLessonDetails(id: string): void;
35
40
  search(searchText: string): void;
36
- generateQR(lesson: any): void;
37
- takeLesson(lesson: any): void;
38
- editLesson(lesson: any): void;
39
- removeLesson(lesson: any): void;
41
+ private generateQR;
42
+ private takeLesson;
43
+ private editLesson;
44
+ private removeLesson;
40
45
  newLesson(): void;
41
46
  filterChanged(filters: any): void;
42
47
  protected loadData(): Promise<void>;
48
+ doAction(event: {
49
+ item: any;
50
+ action: MenuItem;
51
+ }): void;
43
52
  static ɵfac: i0.ɵɵFactoryDeclaration<DCLessonListComponent, never>;
44
- static ɵcmp: i0.ɵɵComponentDeclaration<DCLessonListComponent, "dc-lesson-list", never, { "isAdmin": { "alias": "isAdmin"; "required": false; }; "customCardComponent": { "alias": "customCardComponent"; "required": false; }; "customFilters": { "alias": "customFilters"; "required": false; }; }, { "onTakeLesson": "onTakeLesson"; "onEditLesson": "onEditLesson"; "onRemoveLesson": "onRemoveLesson"; "qr": "qr"; "onNewLesson": "onNewLesson"; }, never, never, true, never>;
53
+ static ɵcmp: i0.ɵɵComponentDeclaration<DCLessonListComponent, "dc-lesson-list", never, { "isAdmin": { "alias": "isAdmin"; "required": false; }; "customCardComponent": { "alias": "customCardComponent"; "required": false; }; "customFilters": { "alias": "customFilters"; "required": false; }; "viewType": { "alias": "viewType"; "required": false; }; "actions": { "alias": "actions"; "required": false; }; }, { "onTakeLesson": "onTakeLesson"; "onEditLesson": "onEditLesson"; "onRemoveLesson": "onRemoveLesson"; "qr": "qr"; "onNewLesson": "onNewLesson"; }, never, never, true, never>;
45
54
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dataclouder/ngx-lessons",
3
- "version": "0.0.26",
3
+ "version": "0.0.28",
4
4
  "peerDependencies": {
5
5
  "@angular/common": ">=18.0.0",
6
6
  "@angular/core": ">=18.0.0",
@@ -7,38 +7,29 @@
7
7
  direction="down-left"
8
8
  [buttonProps]="{ severity: 'primary', rounded: true, outlined: true, raised: true }" />
9
9
 
10
- <div class="blog-card">
11
- <div class="meta">
12
- <div class="photo" [style.backgroundImage]="'url(' + coverUrl + ')'"></div>
13
- <ul class="details">
14
- <li class="author">
15
- <a>{{ lesson.authorEmail }}</a>
16
- </li>
17
- <li class="date">{{ lesson.createdDate | date : 'dd/MM/yyyy' }}</li>
18
- <li class="tags">
19
- <ul>
20
- <li *ngFor="let tag of lesson.tags">
21
- <a>{{ tag }}</a>
22
- </li>
23
- </ul>
24
- </li>
25
- </ul>
26
- </div>
10
+ <p-card>
11
+ <div class="lesson-card">
12
+ <div class="photo">
13
+ <img [src]="coverUrl" alt="" />
14
+ </div>
27
15
 
28
- <div class="description">
29
- <h1>{{ lesson.title }}</h1>
30
- <p>{{ lesson.description }}</p>
31
- <div class="card-footer">
32
- <div class="status-tags">
33
- <span class="level-tag">Nivel {{ lesson.level }}</span>
34
- <span *ngIf="lesson.taken?.status == 'passed'" class="status-tag success">Tomada</span>
35
- <span *ngIf="lesson.taken?.status == 'failed'" class="status-tag danger">Fallida</span>
36
- </div>
16
+ <span class="date">{{ lesson.createdDate | date : 'dd/MM/yyyy' }}</span>
17
+
18
+ <div class="description">
19
+ <h1>{{ lesson.title }}</h1>
20
+ <p>{{ lesson.description }}</p>
21
+ <div class="card-footer">
22
+ <div class="status-tags">
23
+ <span class="level-tag">Nivel {{ lesson.level }}</span>
24
+ <span *ngIf="lesson.taken?.status == 'passed'" class="status-tag success">Tomada</span>
25
+ <span *ngIf="lesson.taken?.status == 'failed'" class="status-tag danger">Fallida</span>
26
+ </div>
37
27
 
38
- <div class="actions">
39
- <p-button label="Tomar lección" (onClick)="eventCard(eventType.Take)" severity="primary"> </p-button>
28
+ <div class="actions">
29
+ <p-button label="Tomar lección" (onClick)="eventCard(eventType.Take)" severity="primary"> </p-button>
30
+ </div>
40
31
  </div>
41
32
  </div>
42
33
  </div>
43
- </div>
34
+ </p-card>
44
35
  </div>
@@ -1,235 +1,107 @@
1
1
  .card-container {
2
2
  position: relative;
3
+ margin-bottom: 20px;
4
+ margin-left: 10px;
3
5
  }
4
6
 
5
- .dial-button{
6
- position: absolute; top: 10px; right: 20px;
7
+ .dial-button {
8
+ position: absolute;
9
+ top: 10px;
10
+ right: 20px;
7
11
  z-index: 10;
8
-
9
12
  }
10
13
 
11
- .blog-card {
14
+ .lesson-card {
12
15
  position: relative;
13
- display: flex;
14
- flex-direction: row;
15
- background: #fff;
16
- border-radius: 12px;
17
- background: rgba(255, 255, 255, 0.1);
18
- border-radius: 12px;
16
+ border-radius: 0.5rem;
17
+ height: 100%;
18
+ }
19
19
 
20
- box-shadow: 0 0 20px var(--primary-color);
21
- margin: 1rem;
22
- overflow: hidden;
23
- transition: all 0.3s ease;
24
-
25
- &:hover {
26
- box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
27
- transform: translateY(-2px);
20
+ .lesson-card .photo {
21
+ position: absolute;
22
+ top: 0;
23
+ left: 0;
24
+ right: 0;
25
+ bottom: 0;
26
+ z-index: 1;
28
27
 
29
- &:before {
30
- opacity: 1;
31
- box-shadow: 0 0 15px var(--blue-color);
32
- }
28
+ img {
29
+ width: 100%;
30
+ height: 100%;
31
+ object-fit: cover;
32
+ object-position: center;
33
33
  }
34
+ }
34
35
 
35
- .meta {
36
- position: relative;
37
- flex: 1;
38
- max-width: 300px;
39
-
40
- .photo {
41
- position: absolute;
42
- top: 0;
43
- right: 0;
44
- bottom: 0;
45
- left: 0;
46
- background-size: cover;
47
- background-position: center;
48
-
49
- &::before {
50
- content: "";
51
- position: absolute;
52
- top: 0;
53
- right: 0;
54
- bottom: 0;
55
- left: 0;
56
- background: rgba(0, 0, 0, 0.3);
57
- }
58
- }
36
+ .description {
37
+ position: relative;
38
+ z-index: 2;
39
+ padding: 1.5rem;
40
+ color: white;
41
+ background: linear-gradient(to bottom, rgba(0, 0, 0, 0.4) 0%, rgba(0, 0, 0, 0.8) 100%);
42
+ height: 100%;
43
+ display: flex;
44
+ flex-direction: column;
59
45
 
60
- .details {
61
- position: relative;
62
- z-index: 1;
63
- list-style: none;
64
- padding: 1rem;
65
- color: #fff;
66
-
67
- li {
68
- margin-bottom: 0.5rem;
69
-
70
- &.author a {
71
- color: #fff;
72
- font-weight: bold;
73
- }
74
-
75
- &.date {
76
- font-size: 0.9rem;
77
- opacity: 0.8;
78
- }
79
-
80
- &.tags ul {
81
- list-style: none;
82
- padding: 0;
83
- display: flex;
84
- flex-wrap: wrap;
85
- gap: 0.5rem;
86
-
87
- li a {
88
- color: #fff;
89
- font-size: 0.8rem;
90
- opacity: 0.8;
91
- }
92
- }
93
- }
94
- }
46
+ h1 {
47
+ margin-top: 0;
48
+ margin-bottom: 0.5rem;
49
+ font-size: 1.5rem;
95
50
  }
96
51
 
97
- .description {
98
- flex: 2;
99
- padding: 1.5rem;
100
- background: #fff;
101
-
102
- h1 {
103
- margin: 0 0 1rem;
104
- font-size: 1.5rem;
105
- color: #333;
106
- }
107
-
108
- p {
109
- color: #666;
110
- line-height: 1.5;
111
- margin-bottom: 1rem;
112
- }
52
+ p {
53
+ margin-bottom: 1rem;
54
+ flex-grow: 1;
55
+ }
56
+ }
113
57
 
114
- .card-footer {
115
- display: flex;
116
- justify-content: space-between;
117
- align-items: center;
118
- margin-top: 1rem;
119
-
120
- .status-tags {
121
- display: flex;
122
- gap: 0.5rem;
123
-
124
- .level-tag {
125
- background: #e0e7ff;
126
- color: #4338ca;
127
- padding: 0.3rem 0.8rem;
128
- border-radius: 4px;
129
- font-size: 0.9rem;
130
- }
131
-
132
- .status-tag {
133
- padding: 0.3rem 0.8rem;
134
- border-radius: 4px;
135
- font-size: 0.9rem;
136
-
137
- &.success {
138
- background: #dcfce7;
139
- color: #166534;
140
- }
141
-
142
- &.danger {
143
- background: #fee2e2;
144
- color: #991b1b;
145
- }
146
- }
147
- }
58
+ .date {
59
+ position: absolute;
60
+ top: 1rem;
61
+ left: 1rem;
62
+ z-index: 3;
63
+ background-color: rgba(0, 0, 0, 0.7);
64
+ color: white;
65
+ padding: 0.3rem 0.6rem;
66
+ border-radius: 0.25rem;
67
+ font-size: 0.8rem;
68
+ }
148
69
 
149
- .actions {
150
- display: flex;
151
- align-items: center;
152
- gap: 1rem;
153
-
154
- .admin-actions {
155
- display: flex;
156
- gap: 0.5rem;
157
-
158
- .icon-button {
159
- background: none;
160
- border: none;
161
- padding: 0.5rem;
162
- cursor: pointer;
163
- border-radius: 4px;
164
- transition: background 0.2s;
165
-
166
- &.edit {
167
- color: #4338ca;
168
- &:hover { background: #e0e7ff; }
169
- }
170
-
171
- &.delete {
172
- color: #dc2626;
173
- &:hover { background: #fee2e2; }
174
- }
175
- }
176
- }
70
+ .card-footer {
71
+ display: flex;
72
+ justify-content: space-between;
73
+ align-items: center;
74
+ margin-top: auto;
75
+ }
177
76
 
178
- .take-lesson {
179
- background: #4338ca;
180
- color: white;
181
- border: none;
182
- padding: 0.5rem 1rem;
183
- border-radius: 4px;
184
- cursor: pointer;
185
- transition: background 0.2s;
186
-
187
- &:hover {
188
- background: #3730a3;
189
- }
190
- }
191
- }
192
- }
77
+ .status-tags {
78
+ display: flex;
79
+ gap: 0.5rem;
80
+
81
+ .level-tag,
82
+ .status-tag {
83
+ padding: 0.3rem 0.6rem;
84
+ border-radius: 0.25rem;
85
+ font-size: 0.8rem;
193
86
  }
194
- }
195
87
 
196
- @media (max-width: 768px) {
197
- .blog-card {
198
- flex-direction: column;
199
-
200
- .meta {
201
- max-width: 100%;
202
- min-height: 200px;
203
- }
88
+ .level-tag {
89
+ background-color: rgba(255, 255, 255, 0.2);
204
90
  }
205
- }
206
91
 
207
- span[class^="p-"] {
208
- position: absolute;
209
- top: 10px;
210
- right: 10px;
211
- cursor: pointer;
212
- z-index: 30;
213
- }
92
+ .status-tag {
93
+ &.success {
94
+ background-color: rgba(40, 167, 69, 0.7);
95
+ }
214
96
 
215
- .blog-card.glow-effect {
216
- &:before {
217
- content: '';
218
- position: absolute;
219
- top: -5px;
220
- left: -5px;
221
- right: -5px;
222
- bottom: -5px;
223
- border-radius: 12px;
224
- background: rgba(255, 255, 255, 0.1);
225
- z-index: -2;
226
- transition: all 0.3s ease;
227
- opacity: 0.5;
228
- box-shadow: 0 0 45px rgba(0, 123, 255, 0.689);
97
+ &.danger {
98
+ background-color: rgba(220, 53, 69, 0.7);
99
+ }
229
100
  }
101
+ }
230
102
 
231
- &:hover:before {
232
- opacity: 1;
233
- box-shadow: 0 0 60px rgba(0, 123, 255, 0.8);
103
+ .actions {
104
+ ::ng-deep .p-button {
105
+ font-size: 0.9rem;
234
106
  }
235
107
  }
@@ -6,6 +6,7 @@ import { PopoverModule } from 'primeng/popover';
6
6
 
7
7
  import { SpeedDialModule } from 'primeng/speeddial';
8
8
  import { MenuItem } from 'primeng/api';
9
+ import { CardModule } from 'primeng/card';
9
10
 
10
11
  import { ILesson, ILessonWithTaken } from '../../lesson-mini-components/components/lessons.clases';
11
12
 
@@ -20,7 +21,7 @@ enum EventCard {
20
21
  templateUrl: './dc-lesson-card.component.html',
21
22
  styleUrls: ['./dc-lesson-card.component.scss'],
22
23
  standalone: true,
23
- imports: [NgFor, NgIf, DatePipe, ButtonModule, PopoverModule, SpeedDialModule],
24
+ imports: [NgFor, NgIf, DatePipe, ButtonModule, PopoverModule, SpeedDialModule, CardModule],
24
25
  })
25
26
  export class DcLessonCardComponent implements OnInit {
26
27
  @Input() lesson: ILessonWithTaken | ILesson | any;
@@ -1,5 +1,8 @@
1
1
  <dc-filter-bar [customFilters]="customFilters" (onSearch)="search($event)" (onFilterChange)="filterChanged($event)" (onNew)="newLesson()"></dc-filter-bar>
2
2
 
3
+ @if(viewType === 'table') {
4
+ <app-quick-table [columns]="columns" [tableData]="lessons" [actions]="actions" (onAction)="doAction($event)"></app-quick-table>
5
+ } @else {
3
6
  <div class="lesson-list-container">
4
7
  @if (!isLoadingLessons && lessons?.length > 0) { @for (lesson of lessons; track lesson._id) {
5
8
  <ng-container
@@ -14,6 +17,7 @@
14
17
  <p>No se encontraron lecciones disponibles</p>
15
18
  }
16
19
  </div>
20
+ }
17
21
 
18
22
  <p-paginator
19
23
  currentPageReportTemplate="{{ totalRecords }} lecciones"
@@ -5,10 +5,32 @@ import { NgComponentOutlet } from '@angular/common';
5
5
  import { ActivatedRoute, Router, RouterModule } from '@angular/router';
6
6
 
7
7
  import { Subscription } from 'rxjs';
8
- import { DCFilterBarComponent, ICustomFilter, PaginationBase, TOAST_ALERTS_TOKEN, ToastAlertsAbstractService } from '@dataclouder/ngx-core';
8
+ import {
9
+ DCFilterBarComponent,
10
+ ICustomFilter,
11
+ PaginationBase,
12
+ PColumn,
13
+ QuickTableComponent,
14
+ TOAST_ALERTS_TOKEN,
15
+ ToastAlertsAbstractService,
16
+ } from '@dataclouder/ngx-core';
9
17
 
10
18
  import { LESSONS_TOKEN, LessonsAbstractService } from '../../lesson-mini-components/components/lessons.clases';
11
19
  import { DcLessonCardComponent } from '../dc-lesson-card/dc-lesson-card.component';
20
+ import { MenuItem } from 'node_modules/primeng/api/menuitem';
21
+
22
+ const tableViewColumns: PColumn[] = [
23
+ { field: 'media.images[0].url', header: 'Image', type: 'image' },
24
+ { field: 'title', header: 'Título' },
25
+ { field: 'description', header: 'Descripción' },
26
+ ];
27
+
28
+ const TableViewActions: MenuItem[] = [
29
+ { title: 'select', label: 'Select', icon: 'pi pi-check', severity: 'primary' },
30
+ { title: 'qr', label: 'QR', icon: 'pi pi-qrcode', severity: 'info' },
31
+ { title: 'edit', label: 'Edit', icon: 'pi pi-pencil', severity: 'info' },
32
+ { title: 'delete', label: 'Delete', icon: 'pi pi-trash', severity: 'danger' },
33
+ ];
12
34
 
13
35
  const returnProperties: Record<string, 0 | 1> = { id: 1, title: 1, assets: 1 };
14
36
 
@@ -17,21 +39,28 @@ const returnProperties: Record<string, 0 | 1> = { id: 1, title: 1, assets: 1 };
17
39
  templateUrl: './dc-lesson-list.component.html',
18
40
  styleUrls: ['./dc-lesson-list.component.scss'],
19
41
  standalone: true,
20
- imports: [CommonModule, RouterModule, DCFilterBarComponent, PaginatorModule, NgComponentOutlet],
42
+ imports: [CommonModule, RouterModule, DCFilterBarComponent, PaginatorModule, NgComponentOutlet, QuickTableComponent],
21
43
  })
22
44
  export class DCLessonListComponent extends PaginationBase implements OnInit, OnDestroy {
23
45
  @Input() public isAdmin: boolean = false;
24
46
  @Input() public customCardComponent?: Type<DcLessonCardComponent>;
25
47
  @Input() public customFilters: ICustomFilter[] = [];
48
+ @Input() public viewType: 'table' | 'card' = 'card';
49
+
50
+ @Input() public override actions: MenuItem[] = TableViewActions;
51
+
26
52
  @Output() public onTakeLesson: EventEmitter<any> = new EventEmitter();
27
53
  @Output() public onEditLesson: EventEmitter<any> = new EventEmitter();
28
54
  @Output() public onRemoveLesson: EventEmitter<any> = new EventEmitter();
29
55
  @Output() public qr: EventEmitter<any> = new EventEmitter();
30
56
  @Output() public onNewLesson: EventEmitter<any> = new EventEmitter();
57
+
58
+ public override columns: PColumn[] = tableViewColumns;
59
+
31
60
  @ViewChildren('outlet') outlets!: QueryList<NgComponentOutlet>;
32
61
 
33
62
  public cardComponent: Type<DcLessonCardComponent> = null;
34
- private cardEventSubs: Subscription[] = [];
63
+ public cardEventSubs: Subscription[] = [];
35
64
 
36
65
  public lessons: any[] = [];
37
66
  public isLoadingLessons = false;
@@ -119,19 +148,19 @@ export class DCLessonListComponent extends PaginationBase implements OnInit, OnD
119
148
  this.getPaginatedLessons(this.filterConfig);
120
149
  }
121
150
 
122
- public generateQR(lesson: any) {
151
+ private generateQR(lesson: any) {
123
152
  this.qr.emit(lesson);
124
153
  }
125
154
 
126
- public takeLesson(lesson: any) {
155
+ private takeLesson(lesson: any) {
127
156
  this.onTakeLesson.emit(lesson);
128
157
  }
129
158
 
130
- public editLesson(lesson: any) {
159
+ private editLesson(lesson: any) {
131
160
  this.onEditLesson.emit(lesson);
132
161
  }
133
162
 
134
- public removeLesson(lesson: any) {
163
+ private removeLesson(lesson: any) {
135
164
  const response = confirm('¿Estás seguro de querer eliminar esta lección?');
136
165
  if (response) {
137
166
  this.lessonsService.deleteLesson(lesson._id);
@@ -156,4 +185,16 @@ export class DCLessonListComponent extends PaginationBase implements OnInit, OnD
156
185
  protected override loadData(): Promise<void> {
157
186
  return this.getPaginatedLessons(this.filterConfig);
158
187
  }
188
+
189
+ public override doAction(event: { item: any; action: MenuItem }) {
190
+ if (event.action.label === 'Select') {
191
+ this.takeLesson(event.item);
192
+ } else if (event.action.label === 'QR') {
193
+ this.generateQR(event.item);
194
+ } else if (event.action.label === 'Edit') {
195
+ this.editLesson(event.item);
196
+ } else if (event.action.label === 'Delete') {
197
+ this.removeLesson(event.item);
198
+ }
199
+ }
159
200
  }