P O S Menu Component - Copy this Angular, Css Component to your project
dale mas estilos a este codigo import { Component, inject } from '@angular/core'; import { MatTableModule } from '@angular/material/table'; import { AsyncPipe, CommonModule } from '@angular/common'; import { MatCardModule } from '@angular/material/card'; import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatDialog, MatDialogModule } from '@angular/material/dialog'; import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar'; import { MatTooltipModule } from '@angular/material/tooltip'; import { Product } from '../../models/product.model'; import { MatTableDataSource } from '@angular/material/table'; import { InventoryService } from '../../services/inventory.service'; import { ProductDialogComponent } from './product-dialog.component'; import { ConfirmDialogComponent } from './confirm-dialog.component'; import { HttpErrorResponse } from '@angular/common/http'; @Component({ selector: 'app-inventory', standalone: true, imports: [ CommonModule, MatTableModule, AsyncPipe, MatCardModule, MatButtonModule, MatIconModule, MatInputModule, MatFormFieldModule, MatDialogModule, MatSnackBarModule, MatTooltipModule ], providers: [InventoryService], template: ` <div class="inventory-page"> <mat-card class="inventory-card"> <mat-card-header> <mat-card-title> <div class="header-content"> <mat-icon class="header-icon">inventory_2</mat-icon> <span>Gestión de Inventario</span> </div> </mat-card-title> </mat-card-header> <mat-card-content> <div class="table-container"> <div class="actions-row"> <mat-form-field appearance="outline" class="search-field"> <mat-label>Buscar producto</mat-label> <mat-icon matPrefix>search</mat-icon> <input matInput (keyup)="applyFilter($event)" placeholder="Nombre del producto"> </mat-form-field> <button mat-raised-button color="primary" class="add-button" (click)="openProductDialog()" matTooltip="Agregar nuevo producto"> <mat-icon>add</mat-icon> Nuevo Producto </button> </div> @if (dataSource.data.length === 0) { <div class="no-data"> <mat-icon>inventory</mat-icon> <p>No hay productos registrados</p> </div> } @else { <table mat-table [dataSource]="dataSource" class="mat-elevation-z8"> <ng-container matColumnDef="name"> <th mat-header-cell *matHeaderCellDef> Nombre </th> <td mat-cell *matCellDef="let product"> {{product.name}} </td> </ng-container> <ng-container matColumnDef="price"> <th mat-header-cell *matHeaderCellDef> Precio </th> <td mat-cell *matCellDef="let product" class="price-cell"> {{product.price | currency:'USD':'symbol':'1.2-2'}} </td> </ng-container> <ng-container matColumnDef="stock"> <th mat-header-cell *matHeaderCellDef> Inventario </th> <td mat-cell *matCellDef="let product"> <span [class]="getStockClass(product.stock)"> {{product.stock}} </span> </td> </ng-container> <ng-container matColumnDef="actions"> <th mat-header-cell *matHeaderCellDef> Acciones </th> <td mat-cell *matCellDef="let product" class="action-cell"> <button mat-icon-button color="primary" (click)="openProductDialog(product)" matTooltip="Editar producto" matTooltipPosition="above" matTooltipClass="custom-tooltip" [matTooltipShowDelay]="500"> <mat-icon>edit</mat-icon> </button> <button mat-icon-button color="warn" (click)="deleteProduct(product.id)" matTooltip="Eliminar producto" matTooltipPosition="above" matTooltipClass="custom-tooltip" [matTooltipShowDelay]="500"> <mat-icon>delete</mat-icon> </button> </td> </ng-container> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> </table> } </div> </mat-card-content> </mat-card> </div> `, styles: [` .inventory-page { padding: 20px; background-color: #f5f5f5; min-height: 100vh; } .inventory-card { margin: 0 auto; max-width: 1200px; border-radius: 8px; } .header-content { display: flex; align-items: center; gap: 12px; padding: 16px 0; } .header-icon { color: #1976d2; font-size: 32px; height: 32px; width: 32px; } .actions-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; gap: 16px; } .search-field { flex: 1; } .add-button { height: 48px; } .table-container { margin-top: 16px; } .no-data { text-align: center; padding: 40px; background: white; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .no-data mat-icon { font-size: 48px; width: 48px; height: 48px; color: #9e9e9e; margin-bottom: 16px; } .no-data p { color: #757575; font-size: 16px; margin: 0; } table { width: 100%; box-shadow: 0 2px 4px rgba(0,0,0,0.1); border-radius: 8px; overflow: hidden; } .mat-header-cell { background-color: #f5f5f5; color: #424242; font-weight: 600; font-size: 14px; padding: 16px; } .mat-cell { font-size: 14px; padding: 16px; } .price-cell { color: #1976d2; font-weight: 500; } .action-cell { display: flex; gap: 8px; } .stock-high { color: #4caf50; font-weight: 500; } .stock-medium { color: #ff9800; font-weight: 500; } .stock-low { color: #f44336; font-weight: 500; } tr.mat-row:hover { background-color: #f5f5f5; } @media (max-width: 768px) { .actions-row { flex-direction: column; } .search-field { width: 100%; } .add-button { width: 100%; } .mat-cell { padding: 12px; } } `] }) export class InventoryComponent { private inventoryService = inject(InventoryService); private dialog = inject(MatDialog); private snackBar = inject(MatSnackBar); dataSource = new MatTableDataSource<Product>([]); displayedColumns: string[] = ['name', 'price', 'stock', 'actions']; constructor() { this.loadProducts(); } loadProducts() { this.inventoryService.getProducts().subscribe({ next: (products) => { this.dataSource.data = products; }, error: (error) => { console.error('Error loading products:', error); this.showMessage('Error al cargar los productos', 'error'); } }); } applyFilter(event: Event) { const filterValue = (event.target as HTMLInputElement).value; this.dataSource.filter = filterValue.trim().toLowerCase(); } getStockClass(stock: number): string { if (stock > 20) return 'stock-high'; if (stock > 10) return 'stock-medium'; return 'stock-low'; } openProductDialog(product?: Product) { const dialogRef = this.dialog.open(ProductDialogComponent, { data: product }); dialogRef.afterClosed().subscribe(result => { if (result) { if (result.id) { this.updateProduct(result); } else { this.createProduct(result); } } }); } createProduct(product: Product) { this.inventoryService.addProduct(product).subscribe({ next: () => { this.loadProducts(); this.showMessage('Producto creado exitosamente'); }, error: () => this.showMessage('Error al crear el producto', 'error') }); } updateProduct(product: Product) { this.inventoryService.updateProduct(product.id, product).subscribe({ next: () => { this.loadProducts(); this.showMessage('Producto actualizado exitosamente'); }, error: () => this.showMessage('Error al actualizar el producto', 'error') }); } deleteProduct(id: number) { const dialogRef = this.dialog.open(ConfirmDialogComponent); dialogRef.afterClosed().subscribe(result => { if (result) { this.inventoryService.deleteProduct(id).subscribe({ next: () => { this.loadProducts(); this.showMessage('Producto eliminado exitosamente'); }, error: () => this.showMessage('Error al eliminar el producto', 'error') }); } }); } private showMessage(message: string, type: 'success' | 'error' = 'success') { this.snackBar.open(message, 'Cerrar', { duration: 3000, horizontalPosition: 'end', verticalPosition: 'top', panelClass: type === 'success' ? ['success-snackbar'] : ['error-snackbar'] }); } }