diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index a905d84..2960ef1 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -49,6 +49,13 @@ export const routes: Routes = [ loadComponent: () => import('./features/catalog/categories/categories').then((m) => m.CategoriesPageComponent), }, + { + path: 'catalog/manufacturers', + loadComponent: () => + import('./features/catalog/manufacturer/manufacturers').then( + (m) => m.ManufacturersPageComponent, + ), + }, { path: 'compatibility/:sub', loadComponent: () => import('./features/placeholder').then((m) => m.PlaceholderPageComponent), diff --git a/src/app/core/models/catetories/categories-default-query.ts b/src/app/core/models/catetories/categories-default-query.ts index 5c421cf..83e880d 100644 --- a/src/app/core/models/catetories/categories-default-query.ts +++ b/src/app/core/models/catetories/categories-default-query.ts @@ -1,6 +1,6 @@ export interface CategoryDefaultQuery { page: number | null; - name: string | null; + search: string | null; active: boolean | null; per_page: number | null; parent_id: string | null; diff --git a/src/app/core/models/manufactureres/manufacturer-request.model.ts b/src/app/core/models/manufactureres/manufacturer-request.model.ts new file mode 100644 index 0000000..2b13f15 --- /dev/null +++ b/src/app/core/models/manufactureres/manufacturer-request.model.ts @@ -0,0 +1,7 @@ +export interface ManufacturerRequest { + name: string; + slug: string; + website: string; + active: boolean; + image: string | File | null; +} diff --git a/src/app/core/models/manufactureres/manufacturer-response.model.ts b/src/app/core/models/manufactureres/manufacturer-response.model.ts index 7698c91..15c1646 100644 --- a/src/app/core/models/manufactureres/manufacturer-response.model.ts +++ b/src/app/core/models/manufactureres/manufacturer-response.model.ts @@ -1,4 +1,4 @@ -export interface ManufacturerResponse { +export interface ManufacturerResponse extends Record { id: string; name: string; slug: string; diff --git a/src/app/core/services/manufacture-service.ts b/src/app/core/services/manufacture-service.ts index a8417c3..b65090f 100644 --- a/src/app/core/services/manufacture-service.ts +++ b/src/app/core/services/manufacture-service.ts @@ -8,6 +8,7 @@ import { GeneralOptionQuery } from '../models/generals/general-option-query.mode import { ManufacturerOption } from '../models/manufactureres/manufaturer-options.model'; import { getAllResponse } from '../models/generals/general-responses-list.model'; import { GeneralOption } from '../models/generals/general-options-response.model'; +import { ManufacturerRequest } from '../models/manufactureres/manufacturer-request.model'; @Injectable({ providedIn: 'root', @@ -17,8 +18,11 @@ export class ManufacturerService { private api = environment.apiUrl; private flag = 'manufacturer'; - getAll() { - return this.http.get>(`${this.api}/${this.flag}`); + getAll(filters: Partial) { + const params = buildHttpParams(filters); + return this.http.get>(`${this.api}/${this.flag}`, { + params, + }); } getOptions(filters: GeneralOptionQuery) { @@ -37,4 +41,19 @@ export class ManufacturerService { `${this.api}/${this.flag}/product/${productId}`, ); } + + createManufacturer(data: ManufacturerRequest) { + return this.http.post>(`${this.api}/${this.flag}`, data); + } + + updateManufacturer(id: string, data: ManufacturerRequest) { + return this.http.put>( + `${this.api}/${this.flag}/${id}`, + data, + ); + } + + deleteManufacturer(id: string) { + return this.http.delete>(`${this.api}/${this.flag}/${id}`); + } } diff --git a/src/app/features/catalog/categories/categories.ts b/src/app/features/catalog/categories/categories.ts index 8aac353..b9ceddd 100644 --- a/src/app/features/catalog/categories/categories.ts +++ b/src/app/features/catalog/categories/categories.ts @@ -3,10 +3,14 @@ import { Component, computed, inject, + OnDestroy, OnInit, signal, } from '@angular/core'; import { Router } from '@angular/router'; +import { Subject, Subscription } from 'rxjs'; +import { debounceTime, distinctUntilChanged } from 'rxjs/operators'; + import { PageHeaderComponent } from '../../../design-system/page-header/page-header'; import { ToolbarComponent } from '../../../design-system/toolbar/toolbar'; import { SearchInputComponent } from '../../../design-system/input/search-input'; @@ -43,18 +47,22 @@ import { initialValuesPagination } from '../../../design-system/pagination/utils templateUrl: './categories.html', styleUrl: './categories.css', }) -export class CategoriesPageComponent implements OnInit { +export class CategoriesPageComponent implements OnInit, OnDestroy { private router = inject(Router); private toastService = inject(ToastService); private readonly categoryService = inject(CategoryService); - private readonly perPage = signal(25); + private readonly perPage = signal(10); private readonly currentPage = signal(1); readonly loading = signal(false); readonly searchQuery = signal(''); readonly selectedStatus = signal(''); + // Subject para gerenciar o debounce da digitação no campo de busca + private searchSubject = new Subject(); + private searchSubscription?: Subscription; + // Category Form Drawer State readonly isFormOpen = signal(false); readonly formMode = signal<'create' | 'edit' | 'view'>('create'); @@ -82,7 +90,7 @@ export class CategoriesPageComponent implements OnInit { readonly totalItens = signal(0); query: CategoryDefaultQuery = { - name: null, + search: null, active: null, parent_id: null, page: this.currentPage(), @@ -90,7 +98,25 @@ export class CategoriesPageComponent implements OnInit { }; ngOnInit(): void { + // 1. Busca inicial this.getPaginationAllCategories(this.query); + + // 2. Inscrição para escutar a busca com debounce de 400ms + this.searchSubscription = this.searchSubject + .pipe(debounceTime(400), distinctUntilChanged()) + .subscribe((queryText) => { + this.currentPage.set(1); + this.query = { + ...this.query, + search: queryText || null, + page: 1, + }; + this.getPaginationAllCategories(this.query); + }); + } + + ngOnDestroy(): void { + this.searchSubscription?.unsubscribe(); } getPaginationAllCategories(filters: CategoryDefaultQuery): void { @@ -111,30 +137,24 @@ export class CategoriesPageComponent implements OnInit { }); } - readonly filteredCategories = computed(() => { - const q = this.searchQuery().toLowerCase().trim(); - const st = this.selectedStatus(); - - return this.allCategories().filter((c) => { - const matchesQ = - !q || - c.name.toLowerCase().includes(q) || - c.slug.toLowerCase().includes(q) || - (c.description || '').toLowerCase().includes(q); - const matchesSt = !st || (st === 'active' ? c.active : !c.active); - return matchesQ && matchesSt; - }); - }); - onSearchChange(query: string): void { - this.query = { ...this.query, name: query }; this.searchQuery.set(query); - this.getPaginationAllCategories(this.query); + this.searchSubject.next(query); } onStatusChange(status: string): void { - this.query = { ...this.query, active: status === 'active' }; + let activeValue: boolean | null = null; + if (status === 'active') activeValue = true; + if (status === 'inactive') activeValue = false; + this.selectedStatus.set(status); + this.currentPage.set(1); + + this.query = { + ...this.query, + active: activeValue, + page: 1, + }; this.getPaginationAllCategories(this.query); } @@ -165,13 +185,16 @@ export class CategoriesPageComponent implements OnInit { resetFilters(): void { this.searchQuery.set(''); this.selectedStatus.set(''); + this.currentPage.set(1); + this.query = { - name: null, + search: null, active: null, parent_id: null, - page: this.currentPage(), + page: 1, per_page: this.perPage(), }; + this.getPaginationAllCategories(this.query); this.toastService.info('Filtros limpos', 'Todos os parâmetros de busca foram resetados.'); } diff --git a/src/app/features/catalog/manufacturer/manufacturer-form/manufacturer-form.ts b/src/app/features/catalog/manufacturer/manufacturer-form/manufacturer-form.ts index bcc73c3..2655c06 100644 --- a/src/app/features/catalog/manufacturer/manufacturer-form/manufacturer-form.ts +++ b/src/app/features/catalog/manufacturer/manufacturer-form/manufacturer-form.ts @@ -6,32 +6,24 @@ import { signal, computed, effect, - inject + inject, } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ButtonComponent } from '../../../../design-system/button/button'; import { AppIconComponent } from '../../../../design-system/icon/app-icon'; import { DrawerComponent } from '../../../../design-system/drawer/drawer'; -import { ManufacturerService } from '../../../../core/services/manufacturer'; import { ToastService } from '../../../../core/services/toast'; -import { - Manufacturer, - CreateManufacturerPayload, - UpdateManufacturerPayload -} from '../../../../core/models/manufacturer'; +import { ManufacturerRequest } from '../../../../core/models/manufactureres/manufacturer-request.model'; +import { ManufacturerService } from '../../../../core/services/manufacture-service'; +import { ManufacturerResponse } from '../../../../core/models/manufactureres/manufacturer-response.model'; @Component({ selector: 'app-manufacturer-form', standalone: true, - imports: [ - CommonModule, - ButtonComponent, - AppIconComponent, - DrawerComponent - ], + imports: [CommonModule, ButtonComponent, AppIconComponent, DrawerComponent], changeDetection: ChangeDetectionStrategy.OnPush, templateUrl: './manufacturer-form.html', - styleUrl: './manufacturer-form.css' + styleUrl: './manufacturer-form.css', }) export class ManufacturerFormComponent { private manufacturerService = inject(ManufacturerService); @@ -39,10 +31,10 @@ export class ManufacturerFormComponent { readonly isOpen = input(false); readonly mode = input<'create' | 'edit' | 'view'>('create'); - readonly manufacturer = input(null); + readonly manufacturer = input(null); readonly closeForm = output(); - readonly manufacturerSaved = output(); + readonly manufacturerSaved = output(); // Reactive State Signals readonly isSubmitting = signal(false); @@ -230,28 +222,31 @@ export class ManufacturerFormComponent { } if (!this.validateForm()) { - this.toastService.error('Formulário Inválido', 'Corrija os campos indicados antes de salvar.'); + this.toastService.error( + 'Formulário Inválido', + 'Corrija os campos indicados antes de salvar.', + ); return; } this.isSubmitting.set(true); - const payload: CreateManufacturerPayload | UpdateManufacturerPayload = { + const payload: ManufacturerRequest = { name: this.name().trim(), slug: this.slug().trim(), - image: this.image().trim() || null, - website: this.website().trim() || null, - active: this.active() + image: this.image().trim(), + website: this.website().trim(), + active: this.active(), }; if (this.mode() === 'edit' && this.manufacturer()?.id) { const id = this.manufacturer()!.id; - this.manufacturerService.update(id, payload).subscribe({ + this.manufacturerService.updateManufacturer(id, payload).subscribe({ next: (response) => { this.isSubmitting.set(false); this.toastService.success( 'Fabricante Atualizado', - `O fabricante "${response.data.name}" foi salvo com sucesso.` + `O fabricante "${response.data.name}" foi salvo com sucesso.`, ); this.manufacturerSaved.emit(response.data); this.close(); @@ -269,15 +264,15 @@ export class ManufacturerFormComponent { } this.formErrors.set(serverErrors); } - } + }, }); } else { - this.manufacturerService.create(payload as CreateManufacturerPayload).subscribe({ + this.manufacturerService.createManufacturer(payload).subscribe({ next: (response) => { this.isSubmitting.set(false); this.toastService.success( 'Fabricante Criado', - `O fabricante "${response.data.name}" foi cadastrado com sucesso.` + `O fabricante "${response.data.name}" foi cadastrado com sucesso.`, ); this.manufacturerSaved.emit(response.data); this.close(); @@ -295,7 +290,7 @@ export class ManufacturerFormComponent { } this.formErrors.set(serverErrors); } - } + }, }); } } diff --git a/src/app/features/catalog/manufacturer/manufacturers.html b/src/app/features/catalog/manufacturer/manufacturers.html index f33405c..0fb7fd8 100644 --- a/src/app/features/catalog/manufacturer/manufacturers.html +++ b/src/app/features/catalog/manufacturer/manufacturers.html @@ -16,38 +16,62 @@
-
+
-
+
- Total de Fabricantes - {{ totalCount() }} cadastrados + + Total de Fabricantes + + + {{ totalCount() }} cadastrados +
-
+
-
+
- Fabricantes Ativos - {{ activeCount() }} marcas ativas + + Fabricantes Ativos + + + {{ activeCount() }} marcas ativas +
-
+
-
+
- Com Website Oficial - {{ withWebsiteCount() }} verificados + + Com Website Oficial + + + {{ withWebsiteCount() }} verificados +
@@ -65,11 +89,7 @@
@@ -85,20 +105,13 @@
- - +
diff --git a/src/app/features/catalog/manufacturer/manufacturers.ts b/src/app/features/catalog/manufacturer/manufacturers.ts index 82f1d14..44c9b60 100644 --- a/src/app/features/catalog/manufacturer/manufacturers.ts +++ b/src/app/features/catalog/manufacturer/manufacturers.ts @@ -1,18 +1,36 @@ -import { Component, ChangeDetectionStrategy, signal, computed, inject, OnInit } from '@angular/core'; -import { PageHeaderComponent } from '../../design-system/page-header/page-header'; -import { ToolbarComponent } from '../../design-system/toolbar/toolbar'; -import { SearchInputComponent } from '../../design-system/input/search-input'; -import { SelectComponent } from '../../design-system/select/select'; -import { ButtonComponent } from '../../design-system/button/button'; -import { DataTableComponent } from '../../design-system/data-table/data-table'; -import { PaginationComponent } from '../../design-system/pagination/pagination'; -import { ConfirmDialogComponent } from '../../design-system/dialog/confirm-dialog'; -import { AppIconComponent } from '../../design-system/icon/app-icon'; -import { ManufacturerFormComponent } from './components/manufacturer-form/manufacturer-form'; -import { ToastService } from '../../core/services/toast'; -import { ManufacturerService } from '../../core/services/manufacturer'; -import { Manufacturer } from '../../core/models/manufacturer'; -import { TableColumn, TableAction } from '../../core/models/table-config'; +import { + Component, + ChangeDetectionStrategy, + signal, + computed, + inject, + OnInit, + OnDestroy, +} from '@angular/core'; +import { Subject, Subscription } from 'rxjs'; +import { debounceTime, distinctUntilChanged } from 'rxjs/operators'; + +import { PageHeaderComponent } from '../../../design-system/page-header/page-header'; +import { ToolbarComponent } from '../../../design-system/toolbar/toolbar'; +import { SearchInputComponent } from '../../../design-system/input/search-input'; +import { SelectComponent } from '../../../design-system/select/select'; +import { ButtonComponent } from '../../../design-system/button/button'; +import { DataTableComponent } from '../../../design-system/data-table/data-table'; +import { PaginationComponent } from '../../../design-system/pagination/pagination'; +import { ConfirmDialogComponent } from '../../../design-system/dialog/confirm-dialog'; +import { AppIconComponent } from '../../../design-system/icon/app-icon'; +import { ManufacturerFormComponent } from './manufacturer-form/manufacturer-form'; +import { ToastService } from '../../../core/services/toast'; +import { ManufacturerService } from '../../../core/services/manufacture-service'; +import { ManufacturerResponse } from '../../../core/models/manufactureres/manufacturer-response.model'; +import { TableAction, TableColumn } from '../../../core/models/list-table/list-table.model'; +import { + manufacturerTableActions, + manufacturerTableColumns, +} from '../../../utils/manufacturer-table-collums'; +import { PaginationMeta } from '../../../core/models/pagination/pagination.model'; +import { initialValuesPagination } from '../../../design-system/pagination/utils/initial-values'; +import { GeneralOptionQuery } from '../../../core/models/generals/general-option-query.model'; @Component({ selector: 'app-manufacturers-page', @@ -27,13 +45,13 @@ import { TableColumn, TableAction } from '../../core/models/table-config'; PaginationComponent, ConfirmDialogComponent, AppIconComponent, - ManufacturerFormComponent + ManufacturerFormComponent, ], changeDetection: ChangeDetectionStrategy.OnPush, templateUrl: './manufacturers.html', - styleUrl: './manufacturers.css' + styleUrl: './manufacturers.css', }) -export class ManufacturersPageComponent implements OnInit { +export class ManufacturersPageComponent implements OnInit, OnDestroy { private toastService = inject(ToastService); private manufacturerService = inject(ManufacturerService); @@ -41,162 +59,145 @@ export class ManufacturersPageComponent implements OnInit { readonly searchQuery = signal(''); readonly selectedStatus = signal(''); readonly currentPage = signal(1); - readonly pageSize = signal(10); - readonly totalItems = signal(0); + readonly perPage = signal(10); + + // Subject para gerenciar a busca com atraso (debounce) + private searchSubject = new Subject(); + private searchSubscription?: Subscription; // Form Drawer State readonly isFormOpen = signal(false); readonly formMode = signal<'create' | 'edit' | 'view'>('create'); - readonly selectedManufacturer = signal(null); + readonly selectedManufacturer = signal(null); // Delete Dialog State readonly deleteDialogOpen = signal(false); - readonly selectedManufacturerForDelete = signal(null); + readonly selectedManufacturerForDelete = signal(null); readonly isDeleting = signal(false); - readonly allManufacturers = signal([]); - - readonly columns: TableColumn[] = [ - { - key: 'image', - header: 'Logo', - width: '70px', - align: 'center', - type: 'icon', - iconGetter: () => 'building' - }, - { key: 'name', header: 'Fabricante / Marca' }, - { key: 'slug', header: 'Slug / URL', width: '160px' }, - { - key: 'website', - header: 'Website Oficial', - width: '240px', - valueGetter: (m: Manufacturer) => m.website || '—' - }, - { - key: 'active', - header: 'Status', - width: '120px', - align: 'center', - type: 'badge', - badgeConfig: (m: Manufacturer) => ({ - text: m.active ? 'Ativo' : 'Inativo', - variant: m.active ? 'success' : 'neutral' - }) - }, - { - key: 'created_at', - header: 'Criado em', - width: '120px', - align: 'center', - type: 'date' - } - ]; - - readonly actions: TableAction[] = [ - { - id: 'view', - label: 'Visualizar', - icon: 'eye', - colorClass: 'text-gray-400 hover:text-[#5A8DEE] hover:bg-gray-100 dark:hover:bg-slate-700', - title: 'Visualizar Detalhes', - handler: (m) => this.viewManufacturer(m) - }, - { - id: 'edit', - label: 'Editar', - icon: 'edit', - colorClass: 'text-gray-400 hover:text-[#4F8A6B] hover:bg-gray-100 dark:hover:bg-slate-700', - title: 'Editar Fabricante', - handler: (m) => this.editManufacturer(m) - }, - { - id: 'delete', - label: 'Excluir', - icon: 'trash-2', - colorClass: 'text-gray-400 hover:text-[#D66A6A] hover:bg-gray-100 dark:hover:bg-slate-700', - title: 'Excluir Fabricante', - handler: (m) => this.confirmDelete(m) - } - ]; + readonly allManufacturers = signal([]); + + readonly columns: TableColumn[] = manufacturerTableColumns; + readonly actions: TableAction[] = manufacturerTableActions; + + readonly pagination = signal(initialValuesPagination); + + query: Partial = { + active: null, + page: this.currentPage(), + per_page: this.perPage(), + }; // Quick KPI Signals readonly totalCount = computed(() => this.allManufacturers().length); - readonly activeCount = computed(() => this.allManufacturers().filter(m => m.active).length); - readonly withWebsiteCount = computed(() => this.allManufacturers().filter(m => !!m.website).length); + readonly activeCount = computed(() => this.allManufacturers().filter((m) => m.active).length); + readonly withWebsiteCount = computed( + () => this.allManufacturers().filter((m) => !!m.website).length, + ); ngOnInit(): void { - this.loadManufacturers(); + // Busca inicial de dados + this.loadManufacturers(this.query); + + // Inscrição no Subject com debounceTime (400ms) + this.searchSubscription = this.searchSubject + .pipe(debounceTime(400), distinctUntilChanged()) + .subscribe((queryText) => { + this.currentPage.set(1); + this.query = { + ...this.query, + search: queryText, + page: 1, + }; + this.loadManufacturers(this.query); + }); + } + + ngOnDestroy(): void { + this.searchSubscription?.unsubscribe(); } - loadManufacturers(): void { + loadManufacturers(query: Partial): void { this.loading.set(true); - this.manufacturerService.getAll().subscribe({ + this.manufacturerService.getAll(query).subscribe({ next: (response) => { this.allManufacturers.set(response.data); - if (response.meta) { - this.totalItems.set(response.meta.total); - this.currentPage.set(response.meta.current_page); - this.pageSize.set(response.meta.per_page); - } else { - this.totalItems.set(response.data.length); - } + this.pagination.set(response.meta); this.loading.set(false); }, error: (error) => { this.loading.set(false); - this.toastService.error('Erro ao buscar fabricantes', error.message || 'Falha ao carregar lista de fabricantes.'); - } + this.toastService.error( + 'Erro ao buscar fabricantes', + error.message || 'Falha ao carregar lista de fabricantes.', + ); + }, }); } - readonly filteredManufacturers = computed(() => { - const q = this.searchQuery().toLowerCase().trim(); - const st = this.selectedStatus(); - - return this.allManufacturers().filter(m => { - const matchesQ = - !q || - m.name.toLowerCase().includes(q) || - m.slug.toLowerCase().includes(q) || - (m.website || '').toLowerCase().includes(q); - - const matchesSt = !st || (st === 'active' ? m.active : !m.active); - return matchesQ && matchesSt; - }); - }); - - readonly paginatedManufacturers = computed(() => { - const all = this.filteredManufacturers(); - const page = this.currentPage(); - const size = this.pageSize(); - const start = (page - 1) * size; - return all.slice(start, start + size); - }); + onActionClick(event: { actionId: string; row: ManufacturerResponse }): void { + switch (event.actionId) { + case 'view': + this.viewManufacturer(event.row); + break; + case 'edit': + this.editManufacturer(event.row); + break; + case 'delete': + this.confirmDelete(event.row); + break; + } + } + // Chamado a cada digitação do input de busca onSearchChange(query: string): void { this.searchQuery.set(query); - this.currentPage.set(1); + this.searchSubject.next(query); } + // Filtro por status onStatusChange(status: string): void { + let activeValue: boolean | null = null; + if (status === 'active') activeValue = true; + if (status === 'inactive') activeValue = false; + this.selectedStatus.set(status); this.currentPage.set(1); + + this.query = { + ...this.query, + active: activeValue, + page: 1, + }; + this.loadManufacturers(this.query); } onPageChange(page: number): void { this.currentPage.set(page); + this.query = { ...this.query, page }; + this.loadManufacturers(this.query); } onPageSizeChange(size: number): void { - this.pageSize.set(size); + this.perPage.set(size); this.currentPage.set(1); + this.query = { ...this.query, per_page: size, page: 1 }; + this.loadManufacturers(this.query); } resetFilters(): void { this.searchQuery.set(''); this.selectedStatus.set(''); this.currentPage.set(1); + + this.query = { + active: null, + search: '', + page: 1, + per_page: this.perPage(), + }; + + this.loadManufacturers(this.query); this.toastService.info('Filtros limpos', 'Todos os parâmetros de busca foram resetados.'); } @@ -206,13 +207,13 @@ export class ManufacturersPageComponent implements OnInit { this.isFormOpen.set(true); } - editManufacturer(mfr: Manufacturer): void { + editManufacturer(mfr: ManufacturerResponse): void { this.selectedManufacturer.set(mfr); this.formMode.set('edit'); this.isFormOpen.set(true); } - viewManufacturer(mfr: Manufacturer): void { + viewManufacturer(mfr: ManufacturerResponse): void { this.selectedManufacturer.set(mfr); this.formMode.set('view'); this.isFormOpen.set(true); @@ -224,10 +225,10 @@ export class ManufacturersPageComponent implements OnInit { } onManufacturerSaved(): void { - this.loadManufacturers(); + this.loadManufacturers(this.query); } - confirmDelete(mfr: Manufacturer): void { + confirmDelete(mfr: ManufacturerResponse): void { this.selectedManufacturerForDelete.set(mfr); this.deleteDialogOpen.set(true); } @@ -237,21 +238,31 @@ export class ManufacturersPageComponent implements OnInit { if (!mfr) return; this.isDeleting.set(true); - this.manufacturerService.delete(mfr.id).subscribe({ + this.manufacturerService.deleteManufacturer(mfr.id).subscribe({ next: () => { this.isDeleting.set(false); this.deleteDialogOpen.set(false); - this.allManufacturers.update(list => list.filter(m => m.id !== mfr.id)); + this.allManufacturers.update((list) => list.filter((m) => m.id !== mfr.id)); this.toastService.success( 'Fabricante Excluído', - `O fabricante "${mfr.name}" foi removido com sucesso.` + `O fabricante "${mfr.name}" foi removido com sucesso.`, ); }, error: (err) => { this.isDeleting.set(false); this.deleteDialogOpen.set(false); this.toastService.error('Erro ao excluir', err.message || 'Falha ao remover fabricante.'); - } + }, }); } + + onPaginationChange(meta: PaginationMeta): void { + this.pagination.set(meta); + this.query = { + ...this.query, + page: meta.current_page, + per_page: meta.per_page, + }; + this.loadManufacturers(this.query); + } } diff --git a/src/app/utils/manufacturer-table-collums.ts b/src/app/utils/manufacturer-table-collums.ts new file mode 100644 index 0000000..df80b90 --- /dev/null +++ b/src/app/utils/manufacturer-table-collums.ts @@ -0,0 +1,63 @@ +import { TableAction, TableColumn } from '../core/models/list-table/list-table.model'; +import { ManufacturerResponse } from '../core/models/manufactureres/manufacturer-response.model'; + +export const manufacturerTableColumns: TableColumn[] = [ + { + key: 'image', + header: 'Logo', + width: '70px', + align: 'center', + type: 'icon', + iconGetter: () => 'building', + }, + { key: 'name', header: 'Fabricante / Marca' }, + { key: 'slug', header: 'Slug / URL', width: '160px' }, + { + key: 'website', + header: 'Website Oficial', + width: '240px', + valueGetter: (m: ManufacturerResponse) => m.website || '—', + }, + { + key: 'active', + header: 'Status', + width: '120px', + align: 'center', + type: 'badge', + badgeConfig: (m: ManufacturerResponse) => ({ + text: m.active ? 'Ativo' : 'Inativo', + variant: m.active ? 'success' : 'neutral', + }), + }, + { + key: 'created_at', + header: 'Criado em', + width: '120px', + align: 'center', + type: 'date', + }, +]; + +export const manufacturerTableActions: TableAction[] = [ + { + id: 'view', + label: 'Visualizar', + icon: 'eye', + colorClass: 'text-gray-400 hover:text-[#5A8DEE] hover:bg-gray-100 dark:hover:bg-slate-700', + title: 'Visualizar Detalhes', + }, + { + id: 'edit', + label: 'Editar', + icon: 'edit', + colorClass: 'text-gray-400 hover:text-[#4F8A6B] hover:bg-gray-100 dark:hover:bg-slate-700', + title: 'Editar Fabricante', + }, + { + id: 'delete', + label: 'Excluir', + icon: 'trash-2', + colorClass: 'text-gray-400 hover:text-[#D66A6A] hover:bg-gray-100 dark:hover:bg-slate-700', + title: 'Excluir Fabricante', + }, +];