This commit is contained in:
tanshu committed 2026-08-29 21:09:42 +00:00
1 parent 10448e8b12
commit 85a063c1a7
132 files changed
+4377 -3348

No files matched your search

+16 -2
View File
@@ -1,6 +1,12 @@
import { LayoutModule } from '@angular/cdk/layout';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { ApplicationConfig, LOCALE_ID, importProvidersFrom, provideZonelessChangeDetection } from '@angular/core';
import {
ApplicationConfig,
LOCALE_ID,
importProvidersFrom,
isDevMode,
provideZonelessChangeDetection,
} from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { MomentDateAdapter } from '@angular/material-moment-adapter';
import { MatButtonModule } from '@angular/material/button';
@@ -24,6 +30,7 @@ import { dateFormat } from './app.environment';
import { routes } from './app.routes';
import { AuthService } from './auth/auth.service';
import { authInterceptor } from './core/auth.interceptor';
import { delayInterceptor } from './core/delay-interceptor';
import { jwtInterceptor } from './core/jwt.interceptor';
import { refreshInterceptor } from './core/refresh.interceptor';
@@ -49,7 +56,14 @@ export const appConfig: ApplicationConfig = {
),
{ provide: LOCALE_ID, useValue: 'en-IN' },
AuthService,
provideHttpClient(withInterceptors([refreshInterceptor, jwtInterceptor, authInterceptor])),
provideHttpClient(
withInterceptors([
authInterceptor,
jwtInterceptor,
refreshInterceptor,
...(isDevMode() ? [delayInterceptor] : []),
]),
),
provideRouter(
routes,
withRouterConfig({
@@ -1,86 +1,92 @@
<h2 class="row-container space-between">
<span>Beer Sale Report</span>
<button type="button" mat-icon-button (click)="exportCsv()">
<mat-icon>save_alt</mat-icon>
</button>
</h2>
@if (!infoResource.value() || !saleCategoriesResource.value()) {
<p>Loading...</p>
@if (infoResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (infoResource.error()) {
<app-error-state (retryAction)="infoResource.reload()" />
} @else {
<form class="flex-col">
<div class="row-container sm:max-lg:flex-col">
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Start Date</mat-label>
<input
matInput
[matDatepicker]="startDate"
(focus)="startDate.open()"
[formField]="form.startDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
<mat-datepicker #startDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Finish Date</mat-label>
<input
matInput
[matDatepicker]="finishDate"
(focus)="finishDate.open()"
[formField]="form.finishDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Sale Category</mat-label>
<mat-select [formField]="form.saleCategory">
@for (sc of saleCategories(); track sc) {
<mat-option [value]="sc.id">
{{ sc.name }}
</mat-option>
<h2 class="row-container space-between">
<span>Beer Sale Report</span>
<button type="button" mat-icon-button (click)="exportCsv()">
<mat-icon>save_alt</mat-icon>
</button>
</h2>
@if (!infoResource.value() || !saleCategoriesResource.value()) {
<p>Loading...</p>
} @else {
<form class="flex-col">
<div class="row-container sm:max-lg:flex-col">
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Start Date</mat-label>
<input
matInput
[matDatepicker]="startDate"
(focus)="startDate.open()"
[formField]="form.startDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
<mat-datepicker #startDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Finish Date</mat-label>
<input
matInput
[matDatepicker]="finishDate"
(focus)="finishDate.open()"
[formField]="form.finishDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Sale Category</mat-label>
<mat-select [formField]="form.saleCategory">
@for (sc of saleCategories(); track sc) {
<mat-option [value]="sc.id">
{{ sc.name }}
</mat-option>
}
</mat-select>
@for (error of form.saleCategory().errors(); track error) {
<mat-error>{{ error.message }}</mat-error>
}
</mat-select>
@for (error of form.saleCategory().errors(); track error) {
<mat-error>{{ error.message }}</mat-error>
}
</mat-form-field>
<button
type="button"
mat-raised-button
class="flex-auto basis-1-5"
color="primary"
[disabled]="form().invalid()"
(click)="show()"
>
Show
</button>
</div>
<div class="row-container sm:max-lg:flex-col">
<mat-checkbox class="flex-auto" [formField]="form.regular">Regular</mat-checkbox>
<mat-checkbox class="flex-auto" [formField]="form.happy">Happy Hour</mat-checkbox>
<mat-checkbox class="flex-auto" [formField]="form.staff">Staff Consumption</mat-checkbox>
<mat-checkbox class="flex-auto" [formField]="form.nc">No Charge</mat-checkbox>
</div>
</form>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Date Column -->
<ng-container matColumnDef="date">
<mat-header-cell *matHeaderCellDef>Time</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.date }}</mat-cell>
</ng-container>
<!-- Name Column -->
@for (col of info()?.headers ?? []; track col) {
<ng-container matColumnDef="{{ col }}">
<mat-header-cell *matHeaderCellDef class="right">{{ col }}</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row[col] | number: '1.2-2' }}</mat-cell>
</mat-form-field>
<button
type="button"
mat-raised-button
class="flex-auto basis-1-5"
color="primary"
[disabled]="form().invalid()"
(click)="show()"
>
Show
</button>
</div>
<div class="row-container sm:max-lg:flex-col">
<mat-checkbox class="flex-auto" [formField]="form.regular">Regular</mat-checkbox>
<mat-checkbox class="flex-auto" [formField]="form.happy">Happy Hour</mat-checkbox>
<mat-checkbox class="flex-auto" [formField]="form.staff">Staff Consumption</mat-checkbox>
<mat-checkbox class="flex-auto" [formField]="form.nc">No Charge</mat-checkbox>
</div>
</form>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Date Column -->
<ng-container matColumnDef="date">
<mat-header-cell *matHeaderCellDef>Time</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.date }}</mat-cell>
</ng-container>
}
<mat-header-row *matHeaderRowDef="displayedColumns()"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns()"></mat-row>
</mat-table>
<!-- Name Column -->
@for (col of info()?.headers ?? []; track col) {
<ng-container matColumnDef="{{ col }}">
<mat-header-cell *matHeaderCellDef class="right">{{ col }}</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row[col] | number: '1.2-2' }}</mat-cell>
</ng-container>
}
<mat-header-row *matHeaderRowDef="displayedColumns()"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns()"></mat-row>
</mat-table>
}
}
@@ -13,6 +13,8 @@ import { Router } from '@angular/router';
import moment from 'moment';
import { SaleCategoryService } from '../sale-category/sale-category.service';
import { ErrorStateComponent } from '../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../shared/skeleton-loader/skeleton-loader.component';
import { ToCsvService } from '../shared/to-csv.service';
import { BeerSaleExportHeaderInterface } from './beer-sale-export-header-interface';
import { BeerSaleReport } from './beer-sale-report';
@@ -43,6 +45,8 @@ export interface BeerSaleReportFormData {
MatSelectModule,
MatTableModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class BeerSaleReportComponent {
@@ -1,64 +1,70 @@
<h2 class="row-container space-between">
<span>Bill Settlement Report</span>
<button type="button" mat-icon-button (click)="exportCsv()">
<mat-icon>save_alt</mat-icon>
</button>
</h2>
@if (infoResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (infoResource.error()) {
<app-error-state (retryAction)="infoResource.reload()" />
} @else {
<h2 class="row-container space-between">
<span>Bill Settlement Report</span>
<button type="button" mat-icon-button (click)="exportCsv()">
<mat-icon>save_alt</mat-icon>
</button>
</h2>
<form class="flex-col">
<div class="row-container sm:max-lg:flex-col">
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Start Date</mat-label>
<input
matInput
[matDatepicker]="startDate"
(focus)="startDate.open()"
[formField]="form.startDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
<mat-datepicker #startDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Finish Date</mat-label>
<input
matInput
[matDatepicker]="finishDate"
(focus)="finishDate.open()"
[formField]="form.finishDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<button type="button" mat-raised-button class="flex-auto basis-1-5" color="primary" (click)="show()">Show</button>
</div>
</form>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Date Column -->
<ng-container matColumnDef="date">
<mat-header-cell *matHeaderCellDef>Time</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.date | localTime }}</mat-cell>
</ng-container>
<form class="flex-col">
<div class="row-container sm:max-lg:flex-col">
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Start Date</mat-label>
<input
matInput
[matDatepicker]="startDate"
(focus)="startDate.open()"
[formField]="form.startDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
<mat-datepicker #startDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Finish Date</mat-label>
<input
matInput
[matDatepicker]="finishDate"
(focus)="finishDate.open()"
[formField]="form.finishDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<button type="button" mat-raised-button class="flex-auto basis-1-5" color="primary" (click)="show()">Show</button>
</div>
</form>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Date Column -->
<ng-container matColumnDef="date">
<mat-header-cell *matHeaderCellDef>Time</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.date | localTime }}</mat-cell>
</ng-container>
<!-- Bill ID Column -->
<ng-container matColumnDef="billId">
<mat-header-cell *matHeaderCellDef class="right">Bill ID</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.billId }}</mat-cell>
</ng-container>
<!-- Bill ID Column -->
<ng-container matColumnDef="billId">
<mat-header-cell *matHeaderCellDef class="right">Bill ID</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.billId }}</mat-cell>
</ng-container>
<!-- Amount Column -->
<ng-container matColumnDef="amount">
<mat-header-cell *matHeaderCellDef class="right">Amount</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.amount | number: '1.2-2' }}</mat-cell>
</ng-container>
<!-- Amount Column -->
<ng-container matColumnDef="amount">
<mat-header-cell *matHeaderCellDef class="right">Amount</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.amount | number: '1.2-2' }}</mat-cell>
</ng-container>
<!-- Settlement Column -->
<ng-container matColumnDef="settlement">
<mat-header-cell *matHeaderCellDef class="right">Settlement</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.settlement }}</mat-cell>
</ng-container>
<!-- Settlement Column -->
<ng-container matColumnDef="settlement">
<mat-header-cell *matHeaderCellDef class="right">Settlement</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.settlement }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
}
@@ -10,7 +10,9 @@ import { MatTableModule } from '@angular/material/table';
import { Router } from '@angular/router';
import moment from 'moment';
import { ErrorStateComponent } from '../shared/error-state/error-state.component';
import { LocalTimePipe } from '../shared/local-time.pipe';
import { SkeletonLoaderComponent } from '../shared/skeleton-loader/skeleton-loader.component';
import { ToCsvService } from '../shared/to-csv.service';
import { BillSettlementReport } from './bill-settlement-report';
import { BillSettlementReportService } from './bill-settlement-report.service';
@@ -34,6 +36,8 @@ export interface BillSettlementReportFormData {
MatInputModule,
MatTableModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class BillSettlementReportComponent {
@@ -1,33 +1,39 @@
<h1 mat-dialog-title>Edit Bundle Item</h1>
@if (productsResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (productsResource.error()) {
<app-error-state (retryAction)="productsResource.reload()" />
} @else {
<h1 mat-dialog-title>Edit Bundle Item</h1>
<div mat-dialog-content>
<form>
<mat-form-field class="w-full">
<mat-label>Item</mat-label>
<input matInput type="text" [formField]="form.product" [matAutocomplete]="autoP" />
<mat-autocomplete #autoP="matAutocomplete" [displayWith]="displayFn">
@for (p of products(); track p) {
<mat-option [value]="p">{{ p.name }}</mat-option>
}
</mat-autocomplete>
</mat-form-field>
<div class="flex flex-row flex-wrap gap-3">
<mat-form-field class="flex-auto">
<mat-label>Quantity</mat-label>
<input matInput type="number" [formField]="form.quantity" />
<div mat-dialog-content>
<form>
<mat-form-field class="w-full">
<mat-label>Item</mat-label>
<input matInput type="text" [formField]="form.product" [matAutocomplete]="autoP" />
<mat-autocomplete #autoP="matAutocomplete" [displayWith]="displayFn">
@for (p of products(); track p) {
<mat-option [value]="p">{{ p.name }}</mat-option>
}
</mat-autocomplete>
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Sale Price</mat-label>
<input matInput type="number" [formField]="form.salePrice" />
</mat-form-field>
<mat-checkbox [formField]="form.printInBill" class="flex-auto">Print in Bill?</mat-checkbox>
</div>
</form>
</div>
<div class="flex flex-row flex-wrap gap-3">
<mat-form-field class="flex-auto">
<mat-label>Quantity</mat-label>
<input matInput type="number" [formField]="form.quantity" />
</mat-form-field>
<div mat-dialog-actions>
<button mat-raised-button color="warn" [mat-dialog-close]="false">Cancel</button>
<button type="button" mat-raised-button color="primary" (click)="accept()">Ok</button>
</div>
<mat-form-field class="flex-auto">
<mat-label>Sale Price</mat-label>
<input matInput type="number" [formField]="form.salePrice" />
</mat-form-field>
<mat-checkbox [formField]="form.printInBill" class="flex-auto">Print in Bill?</mat-checkbox>
</div>
</form>
</div>
<div mat-dialog-actions>
<button mat-raised-button color="warn" [mat-dialog-close]="false">Cancel</button>
<button type="button" mat-raised-button color="primary" (click)="accept()">Ok</button>
</div>
}
@@ -10,6 +10,8 @@ import { MatInputModule } from '@angular/material/input';
import { ProductQuery } from '../../core/product-query';
import { ProductService } from '../../product/product.service';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { BundleItem } from '../bundle';
export interface BundleDetailDialogFormData {
@@ -33,6 +35,8 @@ export interface BundleDetailDialogFormData {
MatFormFieldModule,
MatInputModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class BundleDetailDialogComponent {
@@ -1,149 +1,155 @@
<h2>Bundle</h2>
@if (itemResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (itemResource.error()) {
<app-error-state (retryAction)="itemResource.reload()" />
} @else {
<h2>Bundle</h2>
<form>
<div class="row-container">
<mat-form-field class="basis-3-4">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
<form>
<div class="row-container">
<mat-form-field class="basis-3-4">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
<mat-form-field class="basis-1-4">
<mat-label>Units</mat-label>
<input matInput [formField]="form.units" />
</mat-form-field>
<mat-form-field class="basis-1-4">
<mat-label>Units</mat-label>
<input matInput [formField]="form.units" />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Sale Price</mat-label>
<input matInput type="number" [value]="formModel().salePrice" readonly />
<mat-hint>Computed from bundle items</mat-hint>
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Menu Category</mat-label>
<mat-select [formField]="form.menuCategory">
@for (mc of menuCategories(); track mc) {
<mat-option [value]="mc">
{{ mc.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Sale Category</mat-label>
<mat-select [formField]="form.saleCategory">
@for (sc of saleCategories(); track sc) {
<mat-option [value]="sc">
{{ sc.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
<div class="row-container">
<span class="flex-auto"
>Sale Category is used for Tax Report and displaying in the right bill regimes. For the Sale Report, Discount
Report and Beer Sale Report, the Sale Category from the Bundle Items is used.</span
>
</div>
<div class="row-container">
<mat-checkbox [formField]="form.hasHappyHour" class="flex-auto">Has Happy Hour?</mat-checkbox>
<mat-checkbox [formField]="form.isNotAvailable" class="flex-auto">Not Available?</mat-checkbox>
</div>
<h2>Items</h2>
<div class="nutrition-grid">
<mat-form-field class="flex-auto">
<mat-label>Product</mat-label>
<input
type="text"
matInput
[formField]="form.addRow.sku"
[matAutocomplete]="autoItem"
[value]="displayFn(formModel().addRow.sku)"
/>
<mat-autocomplete #autoItem="matAutocomplete" [displayWith]="displayFn">
@for (p of itemProducts(); track p) {
<mat-option [value]="p">{{ p.name }}</mat-option>
}
</mat-autocomplete>
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Quantity</mat-label>
<input matInput type="number" [formField]="form.addRow.quantity" />
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Sale Price</mat-label>
<input matInput type="number" [formField]="form.addRow.salePrice" />
</mat-form-field>
<mat-checkbox [formField]="form.addRow.printInBill" class="basis-1-4">Print in Bill?</mat-checkbox>
<button type="button" mat-raised-button color="primary" (click)="addRow()" class="flex-auto">Add</button>
</div>
</form>
<div class="row-container wrapped">
<mat-table [dataSource]="formModel().items" aria-label="Bundle Items" class="flex-auto">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Item</mat-header-cell>
<mat-cell *matCellDef="let row">
{{ row.sku?.name }}
</mat-cell>
</ng-container>
<!-- Quantity Column -->
<ng-container matColumnDef="quantity">
<mat-header-cell *matHeaderCellDef class="right">Qty</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">
{{ row.quantity }}
</mat-cell>
</ng-container>
<!-- Sale Price Column -->
<ng-container matColumnDef="salePrice">
<mat-header-cell *matHeaderCellDef class="right">Sale Price</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">
{{ row.salePrice | currency: 'INR' }}
</mat-cell>
</ng-container>
<!-- Sale Price Column -->
<ng-container matColumnDef="printInBill">
<mat-header-cell *matHeaderCellDef class="right">Print in Bill</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">
<mat-icon>
{{ row.printInBill ? 'visibility' : 'visibility_off' }}
</mat-icon>
</mat-cell>
</ng-container>
<!-- Action Column -->
<ng-container matColumnDef="action">
<mat-header-cell *matHeaderCellDef class="center">Action</mat-header-cell>
<mat-cell *matCellDef="let row" class="center">
<button type="button" mat-icon-button tabindex="-1" (click)="editRow(row)">
<mat-icon>edit</mat-icon>
</button>
<button type="button" mat-icon-button tabindex="-1" color="warn" (click)="deleteRow(row)">
<mat-icon>delete</mat-icon>
</button>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Sale Price</mat-label>
<input matInput type="number" [value]="formModel().salePrice" readonly />
<mat-hint>Computed from bundle items</mat-hint>
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Menu Category</mat-label>
<mat-select [formField]="form.menuCategory">
@for (mc of menuCategories(); track mc) {
<mat-option [value]="mc">
{{ mc.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Sale Category</mat-label>
<mat-select [formField]="form.saleCategory">
@for (sc of saleCategories(); track sc) {
<mat-option [value]="sc">
{{ sc.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
<button type="button" mat-raised-button color="primary" (click)="save()">Save</button>
@if (!!item().id) {
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
}
</div>
<div class="row-container">
<span class="flex-auto"
>Sale Category is used for Tax Report and displaying in the right bill regimes. For the Sale Report, Discount
Report and Beer Sale Report, the Sale Category from the Bundle Items is used.</span
>
</div>
<div class="row-container">
<mat-checkbox [formField]="form.hasHappyHour" class="flex-auto">Has Happy Hour?</mat-checkbox>
<mat-checkbox [formField]="form.isNotAvailable" class="flex-auto">Not Available?</mat-checkbox>
</div>
<h2>Items</h2>
<div class="nutrition-grid">
<mat-form-field class="flex-auto">
<mat-label>Product</mat-label>
<input
type="text"
matInput
[formField]="form.addRow.sku"
[matAutocomplete]="autoItem"
[value]="displayFn(formModel().addRow.sku)"
/>
<mat-autocomplete #autoItem="matAutocomplete" [displayWith]="displayFn">
@for (p of itemProducts(); track p) {
<mat-option [value]="p">{{ p.name }}</mat-option>
}
</mat-autocomplete>
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Quantity</mat-label>
<input matInput type="number" [formField]="form.addRow.quantity" />
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Sale Price</mat-label>
<input matInput type="number" [formField]="form.addRow.salePrice" />
</mat-form-field>
<mat-checkbox [formField]="form.addRow.printInBill" class="basis-1-4">Print in Bill?</mat-checkbox>
<button type="button" mat-raised-button color="primary" (click)="addRow()" class="flex-auto">Add</button>
</div>
</form>
<div class="row-container wrapped">
<mat-table [dataSource]="formModel().items" aria-label="Bundle Items" class="flex-auto">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Item</mat-header-cell>
<mat-cell *matCellDef="let row">
{{ row.sku?.name }}
</mat-cell>
</ng-container>
<!-- Quantity Column -->
<ng-container matColumnDef="quantity">
<mat-header-cell *matHeaderCellDef class="right">Qty</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">
{{ row.quantity }}
</mat-cell>
</ng-container>
<!-- Sale Price Column -->
<ng-container matColumnDef="salePrice">
<mat-header-cell *matHeaderCellDef class="right">Sale Price</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">
{{ row.salePrice | currency: 'INR' }}
</mat-cell>
</ng-container>
<!-- Sale Price Column -->
<ng-container matColumnDef="printInBill">
<mat-header-cell *matHeaderCellDef class="right">Print in Bill</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">
<mat-icon>
{{ row.printInBill ? 'visibility' : 'visibility_off' }}
</mat-icon>
</mat-cell>
</ng-container>
<!-- Action Column -->
<ng-container matColumnDef="action">
<mat-header-cell *matHeaderCellDef class="center">Action</mat-header-cell>
<mat-cell *matCellDef="let row" class="center">
<button type="button" mat-icon-button tabindex="-1" (click)="editRow(row)">
<mat-icon>edit</mat-icon>
</button>
<button type="button" mat-icon-button tabindex="-1" color="warn" (click)="deleteRow(row)">
<mat-icon>delete</mat-icon>
</button>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
</div>
<div class="row-container">
<button type="button" mat-raised-button color="primary" (click)="save()">Save</button>
@if (!!item().id) {
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
}
</div>
}
@@ -21,6 +21,8 @@ import { MenuCategoryService } from '../../menu-category/menu-category.service';
import { ProductService } from '../../product/product.service';
import { SaleCategoryService } from '../../sale-category/sale-category.service';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { Bundle, BundleItem } from '../bundle';
import { BundleService } from '../bundle.service';
import { BundleDetailDialogComponent } from './bundle-detail-dialog.component';
@@ -58,6 +60,8 @@ export interface BundleDetailFormData {
MatSelectModule,
MatTableModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class BundleDetailComponent {
@@ -1,107 +1,113 @@
<h2 class="row-container space-between">
<span>Bundles</span>
<button type="button" mat-icon-button (click)="exportCsv()" [disabled]="!dataSource().length">
<mat-icon>save_alt</mat-icon>
</button>
<a mat-button [routerLink]="['/bundles', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
@if (listResource.isLoading()) {
<app-skeleton-loader type="table" [count]="5" />
} @else if (listResource.error()) {
<app-error-state (retryAction)="listResource.reload()" />
} @else {
<h2 class="row-container space-between">
<span>Bundles</span>
<button type="button" mat-icon-button (click)="exportCsv()" [disabled]="!dataSource().length">
<mat-icon>save_alt</mat-icon>
</button>
<a mat-button [routerLink]="['/bundles', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Filter</mat-label>
<input type="text" matInput [formField]="form.filter" autocomplete="off" />
</mat-form-field>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Filter</mat-label>
<input type="text" matInput [formField]="form.filter" autocomplete="off" />
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Menu Category</mat-label>
<mat-select [formField]="form.menuCategory">
<mat-option>-- All Bundles --</mat-option>
@for (mc of menuCategoriesResource.value(); track mc) {
<mat-option [value]="mc.id">
{{ mc.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
</form>
<mat-form-field class="flex-auto">
<mat-label>Menu Category</mat-label>
<mat-select [formField]="form.menuCategory">
<mat-option [value]="null">-- All Bundles --</mat-option>
@for (mc of menuCategoriesResource.value(); track mc) {
<mat-option [value]="mc.id">
{{ mc.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
</form>
<mat-table #table [dataSource]="dataSource()" aria-label="Bundles">
<!-- Name -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row">
<a [routerLink]="['/bundles', row.id]">{{ row.name }} ({{ row.units }})</a>
</mat-cell>
</ng-container>
<mat-table #table [dataSource]="dataSource()" aria-label="Bundles">
<!-- Name -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row">
<a [routerLink]="['/bundles', row.id]">{{ row.name }} ({{ row.units }})</a>
</mat-cell>
</ng-container>
<!-- Price -->
<ng-container matColumnDef="price">
<mat-header-cell *matHeaderCellDef class="right">Price</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">
{{ row.salePrice | currency: 'INR' }}
</mat-cell>
</ng-container>
<!-- Price -->
<ng-container matColumnDef="price">
<mat-header-cell *matHeaderCellDef class="right">Price</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">
{{ row.salePrice | currency: 'INR' }}
</mat-cell>
</ng-container>
<!-- Menu Category -->
<ng-container matColumnDef="menuCategory">
<mat-header-cell *matHeaderCellDef>Menu Category</mat-header-cell>
<mat-cell *matCellDef="let row">
{{ row.menuCategory?.name }}
</mat-cell>
</ng-container>
<!-- Menu Category -->
<ng-container matColumnDef="menuCategory">
<mat-header-cell *matHeaderCellDef>Menu Category</mat-header-cell>
<mat-cell *matCellDef="let row">
{{ row.menuCategory?.name }}
</mat-cell>
</ng-container>
<!-- Sale Category -->
<ng-container matColumnDef="saleCategory">
<mat-header-cell *matHeaderCellDef>Sale Category</mat-header-cell>
<mat-cell *matCellDef="let row">
{{ row.saleCategory?.name }}
</mat-cell>
</ng-container>
<!-- Sale Category -->
<ng-container matColumnDef="saleCategory">
<mat-header-cell *matHeaderCellDef>Sale Category</mat-header-cell>
<mat-cell *matCellDef="let row">
{{ row.saleCategory?.name }}
</mat-cell>
</ng-container>
<!-- Items -->
<ng-container matColumnDef="items">
<mat-header-cell *matHeaderCellDef>Items</mat-header-cell>
<mat-cell *matCellDef="let row">
<div class="items-list">
@for (item of row.items; track item) {
<mat-icon>
{{ item.printInBill ? 'visibility' : 'visibility_off' }}
</mat-icon>
<div class="item-name">
{{ item.sku?.name }} x {{ item.quantity }} @ {{ item.salePrice | currency: 'INR' }}
<!-- Items -->
<ng-container matColumnDef="items">
<mat-header-cell *matHeaderCellDef>Items</mat-header-cell>
<mat-cell *matCellDef="let row">
<div class="items-list">
@for (item of row.items; track item) {
<mat-icon>
{{ item.printInBill ? 'visibility' : 'visibility_off' }}
</mat-icon>
<div class="item-name">
{{ item.sku?.name }} x {{ item.quantity }} @ {{ item.salePrice | currency: 'INR' }}
</div>
}
</div>
</mat-cell>
</ng-container>
<!-- Info -->
<ng-container matColumnDef="info">
<mat-header-cell *matHeaderCellDef>Details</mat-header-cell>
<mat-cell *matCellDef="let row">
<div class="row-container">
<div>
<mat-icon>
{{ row.hasHappyHour ? 'sentiment_satisfied_alt' : 'sentiment_dissatisfied' }}
</mat-icon>
<b>{{ row.hasHappyHour ? 'Happy Hour' : 'Regular' }}</b>
</div>
}
</div>
</mat-cell>
</ng-container>
<!-- Info -->
<ng-container matColumnDef="info">
<mat-header-cell *matHeaderCellDef>Details</mat-header-cell>
<mat-cell *matCellDef="let row">
<div class="row-container">
<div>
<mat-icon>
{{ row.hasHappyHour ? 'sentiment_satisfied_alt' : 'sentiment_dissatisfied' }}
</mat-icon>
<b>{{ row.hasHappyHour ? 'Happy Hour' : 'Regular' }}</b>
<div>
<mat-icon>
{{ row.isNotAvailable ? 'pause' : 'play_arrow' }}
</mat-icon>
<b>{{ row.isNotAvailable ? 'Not Available' : 'Available' }}</b>
</div>
</div>
</mat-cell>
</ng-container>
<div>
<mat-icon>
{{ row.isNotAvailable ? 'pause' : 'play_arrow' }}
</mat-icon>
<b>{{ row.isNotAvailable ? 'Not Available' : 'Available' }}</b>
</div>
</div>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
}
@@ -11,6 +11,8 @@ import { MatTableModule } from '@angular/material/table';
import { RouterModule } from '@angular/router';
import { MenuCategoryService } from '../../menu-category/menu-category.service';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { ToCsvService } from '../../shared/to-csv.service';
import { Bundle } from '../bundle';
import { BundleService } from '../bundle.service';
@@ -35,6 +37,8 @@ export interface BundleListFormData {
MatTableModule,
FormField,
RouterModule,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class BundleListComponent {
@@ -48,7 +52,7 @@ export class BundleListComponent {
menuCategoryFilter = computed(() => this.formModel().menuCategory);
formModel = signal<BundleListFormData>({
menuCategory: '',
menuCategory: null,
filter: '',
});
@@ -1,68 +1,74 @@
<h2 class="row-container space-between">
<span>Cashier Report</span>
<span class="spacer"></span>
<button type="button" mat-icon-button [disabled]="!info().cashier.id" (click)="exportCsv()">
<mat-icon>save_alt</mat-icon>
</button>
<button type="button" mat-icon-button [disabled]="!info().cashier.id" (click)="print()">
<mat-icon>print</mat-icon>
</button>
</h2>
@if (infoResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (infoResource.error()) {
<app-error-state (retryAction)="infoResource.reload()" />
} @else {
<h2 class="row-container space-between">
<span>Cashier Report</span>
<span class="spacer"></span>
<button type="button" mat-icon-button [disabled]="!info().cashier.id" (click)="exportCsv()">
<mat-icon>save_alt</mat-icon>
</button>
<button type="button" mat-icon-button [disabled]="!info().cashier.id" (click)="print()">
<mat-icon>print</mat-icon>
</button>
</h2>
<form class="flex-col">
<div class="row-container sm:max-lg:flex-col">
<mat-form-field class="flex-auto">
<mat-label>Start Date</mat-label>
<input
matInput
[matDatepicker]="startDate"
(focus)="startDate.open()"
[formField]="form.startDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
<mat-datepicker #startDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Finish Date</mat-label>
<input
matInput
[matDatepicker]="finishDate"
(focus)="finishDate.open()"
[formField]="form.finishDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
</div>
<div class="row-container sm:max-lg:flex-col">
<mat-form-field class="flex-auto basis-4-5">
<mat-label>Cashier</mat-label>
<mat-select [formField]="form.cashier">
<mat-option>-- Cashier --</mat-option>
@for (ac of cashiers(); track ac) {
<mat-option [value]="ac.id">
{{ ac.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
<button type="button" mat-raised-button class="flex-auto basis-1-5" color="primary" (click)="show()">Show</button>
</div>
</form>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.name }}</mat-cell>
</ng-container>
<form class="flex-col">
<div class="row-container sm:max-lg:flex-col">
<mat-form-field class="flex-auto">
<mat-label>Start Date</mat-label>
<input
matInput
[matDatepicker]="startDate"
(focus)="startDate.open()"
[formField]="form.startDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
<mat-datepicker #startDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Finish Date</mat-label>
<input
matInput
[matDatepicker]="finishDate"
(focus)="finishDate.open()"
[formField]="form.finishDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
</div>
<div class="row-container sm:max-lg:flex-col">
<mat-form-field class="flex-auto basis-4-5">
<mat-label>Cashier</mat-label>
<mat-select [formField]="form.cashier">
<mat-option [value]="null">-- Cashier --</mat-option>
@for (ac of cashiers(); track ac) {
<mat-option [value]="ac.id">
{{ ac.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
<button type="button" mat-raised-button class="flex-auto basis-1-5" color="primary" (click)="show()">Show</button>
</div>
</form>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.name }}</mat-cell>
</ng-container>
<!-- Amount Column -->
<ng-container matColumnDef="amount">
<mat-header-cell *matHeaderCellDef class="right">Amount</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.amount | currency: 'INR' }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<!-- Amount Column -->
<ng-container matColumnDef="amount">
<mat-header-cell *matHeaderCellDef class="right">Amount</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.amount | currency: 'INR' }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
}
@@ -14,6 +14,8 @@ import { Router } from '@angular/router';
import moment from 'moment';
import { User } from '../core/user';
import { ErrorStateComponent } from '../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../shared/skeleton-loader/skeleton-loader.component';
import { ToCsvService } from '../shared/to-csv.service';
import { CashierReport } from './cashier-report';
import { CashierReportService } from './cashier-report.service';
@@ -39,6 +41,8 @@ export interface CashierReportFormData {
MatSelectModule,
MatTableModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class CashierReportComponent {
+7
View File
@@ -0,0 +1,7 @@
import { HttpInterceptorFn } from '@angular/common/http';
import { timer, switchMap } from 'rxjs';
export const delayInterceptor: HttpInterceptorFn = (req, next) => {
// Delay all requests by 1500ms to test loading states
return timer(1500).pipe(switchMap(() => next(req)));
};
@@ -1,41 +1,47 @@
<h2>Customer</h2>
<form class="flex-col">
@if (itemResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (itemResource.error()) {
<app-error-state (retryAction)="itemResource.reload()" />
} @else {
<h2>Customer</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Phone</mat-label>
<input matInput [formField]="form.phone" />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Address</mat-label>
<textarea matInput [formField]="form.address"> </textarea>
</mat-form-field>
</div>
<div class="row-container">
<mat-checkbox [formField]="form.printInBill">Print in Bill?</mat-checkbox>
</div>
<mat-divider></mat-divider>
<div class="discounts">
@for (r of item().discounts; track r; let i = $index) {
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Discount on {{ r.name }}</mat-label>
<input matInput type="number" [formField]="form.discounts[i].discount" />
<span matTextSuffix>%</span>
<mat-hint>Max {{ r.limit | percent: '1.2-2' }}</mat-hint>
</mat-form-field>
</div>
}
</div>
</form>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
<button type="button" mat-raised-button color="primary" class="" (click)="save()">Save</button>
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Phone</mat-label>
<input matInput [formField]="form.phone" />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Address</mat-label>
<textarea matInput [formField]="form.address"> </textarea>
</mat-form-field>
</div>
<div class="row-container">
<mat-checkbox [formField]="form.printInBill">Print in Bill?</mat-checkbox>
</div>
<mat-divider></mat-divider>
<div class="discounts">
@for (r of item().discounts; track r; let i = $index) {
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Discount on {{ r.name }}</mat-label>
<input matInput type="number" [formField]="form.discounts[i].discount" />
<span matTextSuffix>%</span>
<mat-hint>Max {{ r.limit | percent: '1.2-2' }}</mat-hint>
</mat-form-field>
</div>
}
</div>
</form>
<div class="row-container">
<button type="button" mat-raised-button color="primary" class="" (click)="save()">Save</button>
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
</div>
}
@@ -13,6 +13,8 @@ import { round } from 'mathjs';
import { Customer } from '../../core/customer';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { CustomerService } from '../customer.service';
export interface CustomerDetailFormData {
@@ -37,6 +39,8 @@ export interface CustomerDetailFormData {
MatInputModule,
PercentPipe,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class CustomerDetailComponent {
@@ -1,65 +1,71 @@
<h2 class="row-container space-between">
<span>Customers</span>
<a mat-button [routerLink]="['/customers', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Filter</mat-label>
<input type="text" matInput [formField]="form.filter" autocomplete="off" />
</mat-form-field>
</div>
</form>
<mat-table #table [dataSource]="dataSource().items" matSort (matSortChange)="sortData($event)" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/customers', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
@if (listResource.isLoading()) {
<app-skeleton-loader type="table" [count]="5" />
} @else if (listResource.error()) {
<app-error-state (retryAction)="listResource.reload()" />
} @else {
<h2 class="row-container space-between">
<span>Customers</span>
<a mat-button [routerLink]="['/customers', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Filter</mat-label>
<input type="text" matInput [formField]="form.filter" autocomplete="off" />
</mat-form-field>
</div>
</form>
<mat-table #table [dataSource]="dataSource().items" matSort (matSortChange)="sortData($event)" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/customers', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
<!-- Phone Column -->
<ng-container matColumnDef="phone">
<mat-header-cell *matHeaderCellDef mat-sort-header>Phone</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.phone }}</mat-cell>
</ng-container>
<!-- Phone Column -->
<ng-container matColumnDef="phone">
<mat-header-cell *matHeaderCellDef mat-sort-header>Phone</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.phone }}</mat-cell>
</ng-container>
<!-- Address Column -->
<ng-container matColumnDef="address">
<mat-header-cell *matHeaderCellDef mat-sort-header>Address</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.address }}</mat-cell>
</ng-container>
<!-- Address Column -->
<ng-container matColumnDef="address">
<mat-header-cell *matHeaderCellDef mat-sort-header>Address</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.address }}</mat-cell>
</ng-container>
<!-- Print In Bill Column -->
<ng-container matColumnDef="printInBill">
<mat-header-cell *matHeaderCellDef mat-sort-header>Print in Bill</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.printInBill }}</mat-cell>
</ng-container>
<!-- Print In Bill Column -->
<ng-container matColumnDef="printInBill">
<mat-header-cell *matHeaderCellDef mat-sort-header>Print in Bill</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.printInBill }}</mat-cell>
</ng-container>
<!-- Discounts Column -->
<ng-container matColumnDef="discounts">
<mat-header-cell *matHeaderCellDef>Discounts</mat-header-cell>
<mat-cell *matCellDef="let row">
<ul>
@for (discount of row.discounts; track discount) {
<li>{{ discount.name }} - {{ discount.discount | percent: '1.2-2' }}</li>
}
</ul>
</mat-cell>
</ng-container>
<!-- Discounts Column -->
<ng-container matColumnDef="discounts">
<mat-header-cell *matHeaderCellDef>Discounts</mat-header-cell>
<mat-cell *matCellDef="let row">
<ul>
@for (discount of row.discounts; track discount) {
<li>{{ discount.name }} - {{ discount.discount | percent: '1.2-2' }}</li>
}
</ul>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-paginator
#paginator
[length]="dataSource().total"
[pageIndex]="0"
[pageSize]="50"
[pageSizeOptions]="[25, 50, 100, 250, 5000]"
>
</mat-paginator>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-paginator
#paginator
[length]="dataSource().total"
[pageIndex]="0"
[pageSize]="50"
[pageSizeOptions]="[25, 50, 100, 250, 5000]"
>
</mat-paginator>
}
@@ -11,6 +11,8 @@ import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { Customer } from '../../core/customer';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { CustomerService } from '../customer.service';
export interface CustomerListFormData {
@@ -31,6 +33,8 @@ export interface CustomerListFormData {
MatPaginatorModule,
MatSortModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class CustomerListComponent {
@@ -1,34 +1,40 @@
<h2>Device</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" (keyup.enter)="save()" />
</mat-form-field>
@if (itemResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (itemResource.error()) {
<app-error-state (retryAction)="itemResource.reload()" />
} @else {
<h2>Device</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" (keyup.enter)="save()" />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Section</mat-label>
<mat-select [formField]="form.section">
@for (s of sections(); track s) {
<mat-option [value]="s.id">
{{ s.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
<div class="row-container">
<mat-checkbox [formField]="form.enabled" class="flex-auto">Enabled?</mat-checkbox>
</div>
</form>
<div class="row-container space-between">
<button type="button" mat-raised-button color="primary" class="" (click)="save()">Save</button>
@if (!!item().id) {
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
}
<div class="spacer"></div>
<span
>Created on <strong>{{ item().creationDate | localTime }}</strong></span
>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Section</mat-label>
<mat-select [formField]="form.section">
@for (s of sections(); track s) {
<mat-option [value]="s.id">
{{ s.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
<div class="row-container">
<mat-checkbox [formField]="form.enabled" class="flex-auto">Enabled?</mat-checkbox>
</div>
</form>
<div class="row-container space-between">
<button type="button" mat-raised-button color="primary" class="" (click)="save()">Save</button>
@if (!!item().id) {
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
}
<div class="spacer"></div>
<span
>Created on <strong>{{ item().creationDate | localTime }}</strong></span
>
</div>
}
@@ -14,7 +14,9 @@ import { Device } from '../../core/device';
import { Section } from '../../core/section';
import { SectionService } from '../../sections/section.service';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { LocalTimePipe } from '../../shared/local-time.pipe';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { DeviceService } from '../device.service';
export interface DeviceDetailFormData {
@@ -36,6 +38,8 @@ export interface DeviceDetailFormData {
MatOptionModule,
MatSelectModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class DeviceDetailComponent {
@@ -1,45 +1,51 @@
<h2 class="row-container space-between">
<span>Devices</span>
<a mat-button [routerLink]="['/devices', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/devices', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
@if (listResource.isLoading()) {
<app-skeleton-loader type="table" [count]="5" />
} @else if (listResource.error()) {
<app-error-state (retryAction)="listResource.reload()" />
} @else {
<h2 class="row-container space-between">
<span>Devices</span>
<a mat-button [routerLink]="['/devices', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/devices', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
<!-- Section Column -->
<ng-container matColumnDef="section">
<mat-header-cell *matHeaderCellDef>Section</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.section.name }}</mat-cell>
</ng-container>
<!-- Section Column -->
<ng-container matColumnDef="section">
<mat-header-cell *matHeaderCellDef>Section</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.section.name }}</mat-cell>
</ng-container>
<!-- Section Column -->
<ng-container matColumnDef="enabled">
<mat-header-cell *matHeaderCellDef>Enabled</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.enabled }}</mat-cell>
</ng-container>
<!-- Section Column -->
<ng-container matColumnDef="enabled">
<mat-header-cell *matHeaderCellDef>Enabled</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.enabled }}</mat-cell>
</ng-container>
<!-- Creation Date Column -->
<ng-container matColumnDef="creationDate">
<mat-header-cell *matHeaderCellDef>Created</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.creationDate | localTime }}</mat-cell>
</ng-container>
<!-- Creation Date Column -->
<ng-container matColumnDef="creationDate">
<mat-header-cell *matHeaderCellDef>Created</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.creationDate | localTime }}</mat-cell>
</ng-container>
<!-- Last Login Column -->
<ng-container matColumnDef="last">
<mat-header-cell *matHeaderCellDef>Last Login</mat-header-cell>
<mat-cell *matCellDef="let row"
>{{ row.lastUser }} &#64; {{ row.lastDate ? (row.lastDate | localTime) : 'Never' }}</mat-cell
>
</ng-container>
<!-- Last Login Column -->
<ng-container matColumnDef="last">
<mat-header-cell *matHeaderCellDef>Last Login</mat-header-cell>
<mat-cell *matCellDef="let row"
>{{ row.lastUser }} &#64; {{ row.lastDate ? (row.lastDate | localTime) : 'Never' }}</mat-cell
>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
}
@@ -4,13 +4,23 @@ import { MatIconModule } from '@angular/material/icon';
import { MatTableModule } from '@angular/material/table';
import { RouterLink } from '@angular/router';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { LocalTimePipe } from '../../shared/local-time.pipe';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { DeviceService } from '../device.service';
@Component({
selector: 'app-device-list',
templateUrl: './device-list.component.html',
styleUrls: ['./device-list.component.css'],
imports: [LocalTimePipe, MatButtonModule, MatIconModule, MatTableModule, RouterLink],
imports: [
LocalTimePipe,
MatButtonModule,
MatIconModule,
MatTableModule,
RouterLink,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class DeviceListComponent {
private deviceService = inject(DeviceService);
@@ -1,54 +1,60 @@
<h2 class="row-container space-between">
<span>Discount Report</span>
<span class="spacer"></span>
<button type="button" mat-icon-button (click)="exportCsv()">
<mat-icon>save_alt</mat-icon>
</button>
<button type="button" mat-icon-button (click)="print()">
<mat-icon>print</mat-icon>
</button>
</h2>
<form class="flex-col">
<div class="row-container sm:max-lg:flex-col">
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Start Date</mat-label>
<input
matInput
[matDatepicker]="startDate"
(focus)="startDate.open()"
[formField]="form.startDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
<mat-datepicker #startDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Finish Date</mat-label>
<input
matInput
[matDatepicker]="finishDate"
(focus)="finishDate.open()"
[formField]="form.finishDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<button type="button" mat-raised-button class="flex-auto basis-1-5" color="primary" (click)="show()">Show</button>
</div>
</form>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.name }}</mat-cell>
</ng-container>
@if (infoResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (infoResource.error()) {
<app-error-state (retryAction)="infoResource.reload()" />
} @else {
<h2 class="row-container space-between">
<span>Discount Report</span>
<span class="spacer"></span>
<button type="button" mat-icon-button (click)="exportCsv()">
<mat-icon>save_alt</mat-icon>
</button>
<button type="button" mat-icon-button (click)="print()">
<mat-icon>print</mat-icon>
</button>
</h2>
<form class="flex-col">
<div class="row-container sm:max-lg:flex-col">
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Start Date</mat-label>
<input
matInput
[matDatepicker]="startDate"
(focus)="startDate.open()"
[formField]="form.startDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
<mat-datepicker #startDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Finish Date</mat-label>
<input
matInput
[matDatepicker]="finishDate"
(focus)="finishDate.open()"
[formField]="form.finishDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<button type="button" mat-raised-button class="flex-auto basis-1-5" color="primary" (click)="show()">Show</button>
</div>
</form>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.name }}</mat-cell>
</ng-container>
<!-- Amount Column -->
<ng-container matColumnDef="amount">
<mat-header-cell *matHeaderCellDef class="right">Amount</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.amount | currency: 'INR' }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<!-- Amount Column -->
<ng-container matColumnDef="amount">
<mat-header-cell *matHeaderCellDef class="right">Amount</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.amount | currency: 'INR' }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
}
@@ -11,6 +11,8 @@ import { MatTableModule } from '@angular/material/table';
import { Router } from '@angular/router';
import moment from 'moment';
import { ErrorStateComponent } from '../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../shared/skeleton-loader/skeleton-loader.component';
import { ToCsvService } from '../shared/to-csv.service';
import { DiscountReport } from './discount-report';
import { DiscountReportService } from './discount-report.service';
@@ -33,6 +35,8 @@ export interface DiscountReportFormData {
MatInputModule,
MatTableModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class DiscountReportComponent {
@@ -1,70 +1,76 @@
<h2>Guest Details</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Phone</mat-label>
<input matInput type="text" [formField]="form.phone" [matAutocomplete]="auto" autocomplete="off" />
</mat-form-field>
<mat-autocomplete
#auto="matAutocomplete"
autoActiveFirstOption
[displayWith]="displayFn"
(optionSelected)="selected($event)"
>
@for (customer of customers(); track customer) {
<mat-option [value]="customer">{{ customer.name }} - {{ customer.phone }}</mat-option>
}
</mat-autocomplete>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Pax</mat-label>
<input matInput type="number" [formField]="form.pax" />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Address</mat-label>
<textarea matInput [formField]="form.address"></textarea>
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Notes</mat-label>
<textarea matInput [formField]="form.notes"></textarea>
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto basis-1-2">
<mat-label>Date</mat-label>
<input matInput [matDatepicker]="date" (focus)="date.open()" [formField]="form.date" autocomplete="off" />
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
<mat-datepicker #date></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto basis-1-2">
<mat-label>Time</mat-label>
<input
matInput
[matTimepicker]="time"
[formField]="form.time"
matTimepickerMin="12:00"
matTimepickerMax="23:45"
/>
<mat-timepicker-toggle matSuffix [for]="time"></mat-timepicker-toggle>
<mat-timepicker #time interval="15min"></mat-timepicker>
</mat-form-field>
</div>
</form>
@if (itemResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (itemResource.error()) {
<app-error-state (retryAction)="itemResource.reload()" />
} @else {
<h2>Guest Details</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Phone</mat-label>
<input matInput type="text" [formField]="form.phone" [matAutocomplete]="auto" autocomplete="off" />
</mat-form-field>
<mat-autocomplete
#auto="matAutocomplete"
autoActiveFirstOption
[displayWith]="displayFn"
(optionSelected)="selected($event)"
>
@for (customer of customers(); track customer) {
<mat-option [value]="customer">{{ customer.name }} - {{ customer.phone }}</mat-option>
}
</mat-autocomplete>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Pax</mat-label>
<input matInput type="number" [formField]="form.pax" />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Address</mat-label>
<textarea matInput [formField]="form.address"></textarea>
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Notes</mat-label>
<textarea matInput [formField]="form.notes"></textarea>
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto basis-1-2">
<mat-label>Date</mat-label>
<input matInput [matDatepicker]="date" (focus)="date.open()" [formField]="form.date" autocomplete="off" />
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
<mat-datepicker #date></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto basis-1-2">
<mat-label>Time</mat-label>
<input
matInput
[matTimepicker]="time"
[formField]="form.time"
matTimepickerMin="12:00"
matTimepickerMax="23:45"
/>
<mat-timepicker-toggle matSuffix [for]="time"></mat-timepicker-toggle>
<mat-timepicker #time interval="15min"></mat-timepicker>
</mat-form-field>
</div>
</form>
<div class="row-container">
<button type="button" mat-raised-button color="primary" class="" (click)="save()">Save</button>
@if (!!item().id) {
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
}
</div>
<div class="row-container">
<button type="button" mat-raised-button color="primary" class="" (click)="save()">Save</button>
@if (!!item().id) {
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
}
</div>
}
@@ -15,6 +15,8 @@ import moment from 'moment';
import { Customer } from '../../core/customer';
import { CustomerService } from '../../customers/customer.service';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { GuestBook, GuestBookType } from '../guest-book';
import { GuestBookService } from '../guest-book.service';
@@ -41,6 +43,8 @@ export interface GuestBookDetailFormData {
MatOptionModule,
MatTimepickerModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class GuestBookDetailComponent {
@@ -1,78 +1,83 @@
<h2 class="row-container space-between">
<span>Guest List</span>
<a mat-button [routerLink]="['/guest-book', 'new']" [queryParams]="{ t: 'booking' }">
<mat-icon>add_box</mat-icon>
Table Booking
</a>
<a mat-button [routerLink]="['/guest-book', 'new']" [queryParams]="{ t: 'walk_in' }">
<mat-icon>add_box</mat-icon>
Walk-in
</a>
</h2>
@if (listResource.isLoading()) {
<app-skeleton-loader type="table" [count]="5" />
} @else if (listResource.error()) {
<app-error-state (retryAction)="listResource.reload()" />
} @else {
<h2 class="row-container space-between">
<span>Guest List</span>
<a mat-button [routerLink]="['/guest-book', 'new']" [queryParams]="{ t: 'booking' }">
<mat-icon>add_box</mat-icon>
Table Booking
</a>
<a mat-button [routerLink]="['/guest-book', 'new']" [queryParams]="{ t: 'walk_in' }">
<mat-icon>add_box</mat-icon>
Walk-in
</a>
</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Date</mat-label>
<input matInput [matDatepicker]="date" (focus)="date.open()" [formField]="form.date" autocomplete="off" />
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
<mat-datepicker #date></mat-datepicker>
</mat-form-field>
</div>
</form>
<mat-table [dataSource]="dataSource()" aria-label="Elements">
<!-- SNo Column -->
<ng-container matColumnDef="sno">
<mat-header-cell *matHeaderCellDef>S. No / Total</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.serial }} / {{ row.count }}</mat-cell>
</ng-container>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Date</mat-label>
<input matInput [matDatepicker]="date" (focus)="date.open()" [formField]="form.date" autocomplete="off" />
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
<mat-datepicker #date></mat-datepicker>
</mat-form-field>
</div>
</form>
<mat-table [dataSource]="dataSource()" aria-label="Elements">
<!-- SNo Column -->
<ng-container matColumnDef="sno">
<mat-header-cell *matHeaderCellDef>S. No / Total</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.serial }} / {{ row.count }}</mat-cell>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/guest-book/', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/guest-book/', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
<!-- Phone Column -->
<ng-container matColumnDef="phone">
<mat-header-cell *matHeaderCellDef>Phone</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.phone }}</mat-cell>
</ng-container>
<!-- Phone Column -->
<ng-container matColumnDef="phone">
<mat-header-cell *matHeaderCellDef>Phone</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.phone }}</mat-cell>
</ng-container>
<!-- Pax Column -->
<ng-container matColumnDef="pax">
<mat-header-cell *matHeaderCellDef>Pax</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.pax }}</mat-cell>
</ng-container>
<!-- Pax Column -->
<ng-container matColumnDef="pax">
<mat-header-cell *matHeaderCellDef>Pax</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.pax }}</mat-cell>
</ng-container>
<!-- Time Column -->
<ng-container matColumnDef="date">
<mat-header-cell *matHeaderCellDef>Time</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.bookingDate | localTime }} // {{ row.arrivalDate | localTime }}</mat-cell>
</ng-container>
<!-- Time Column -->
<ng-container matColumnDef="date">
<mat-header-cell *matHeaderCellDef>Time</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.bookingDate | localTime }} // {{ row.arrivalDate | localTime }}</mat-cell>
</ng-container>
<!-- Action Column -->
<ng-container matColumnDef="action">
<mat-header-cell *matHeaderCellDef class="center">Action</mat-header-cell>
<mat-cell *matCellDef="let row" class="center">
@if (row.status === 'old' || (!row.tableId && !row.voucherId)) {
<button mat-icon-button [routerLink]="['/sales']" [queryParams]="{ guest: row.id }">
<mat-icon>chair</mat-icon>
</button>
}
@if (row.tableId) {
<button
mat-stroked-button
color="primary"
[routerLink]="['/sales', 'bill']"
[queryParams]="{ table: row.tableId, voucher: row.voucherId }"
>
{{ row.tableName }}
</button>
}
<!-- <button
<!-- Action Column -->
<ng-container matColumnDef="action">
<mat-header-cell *matHeaderCellDef class="center">Action</mat-header-cell>
<mat-cell *matCellDef="let row" class="center">
@if (row.status === 'old' || (!row.tableId && !row.voucherId)) {
<button mat-icon-button [routerLink]="['/sales']" [queryParams]="{ guest: row.id }">
<mat-icon>chair</mat-icon>
</button>
}
@if (row.tableId) {
<button
mat-stroked-button
color="primary"
[routerLink]="['/sales', 'bill']"
[queryParams]="{ table: row.tableId, voucher: row.voucherId }"
>
{{ row.tableName }}
</button>
}
<!-- <button
mat-stroked-button
color="primary"
[routerLink]="['/sales', 'bill']"
@@ -81,14 +86,15 @@
>
{{ row.tableName }}
</button> -->
</mat-cell>
</ng-container>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row
*matRowDef="let row; columns: displayedColumns"
[class.grey300]="row.status === 'booking'"
[class.accent]="row.status === 'running'"
[class.strong-accent]="row.status === 'printed'"
></mat-row>
</mat-table>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row
*matRowDef="let row; columns: displayedColumns"
[class.grey300]="row.status === 'booking'"
[class.accent]="row.status === 'running'"
[class.strong-accent]="row.status === 'printed'"
></mat-row>
</mat-table>
}
@@ -9,7 +9,9 @@ import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import moment from 'moment';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { LocalTimePipe } from '../../shared/local-time.pipe';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { GuestBookService } from '../guest-book.service';
export interface GuestBookListFormData {
@@ -31,6 +33,8 @@ export interface GuestBookListFormData {
MatTableModule,
FormField,
RouterLink,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class GuestBookListComponent {
@@ -1,23 +1,29 @@
<form class="flex-col">
@if (listResource.isLoading()) {
<app-skeleton-loader type="table" [count]="5" />
} @else if (listResource.error()) {
<app-error-state (retryAction)="listResource.reload()" />
} @else {
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Header / Footer</mat-label>
<mat-select [formField]="form.id" (selectionChange)="show($event)">
@for (s of list(); track s) {
<mat-option [value]="s.id">
{{ s.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Text</mat-label>
<textarea matInput matAutosizeMinRows="5" [formField]="form.text"></textarea>
</mat-form-field>
</div>
</form>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Header / Footer</mat-label>
<mat-select [formField]="form.id" (selectionChange)="show($event)">
@for (s of list(); track s) {
<mat-option [value]="s.id">
{{ s.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
<button type="button" mat-raised-button color="primary" (click)="save()">Save</button>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Text</mat-label>
<textarea matInput matAutosizeMinRows="5" [formField]="form.text"></textarea>
</mat-form-field>
</div>
</form>
<div class="row-container">
<button type="button" mat-raised-button color="primary" (click)="save()">Save</button>
</div>
}
@@ -9,6 +9,8 @@ import { MatSelectChange, MatSelectModule } from '@angular/material/select';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Router } from '@angular/router';
import { ErrorStateComponent } from '../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../shared/skeleton-loader/skeleton-loader.component';
import { HeaderFooter } from './header-footer';
import { HeaderFooterService } from './header-footer.service';
@@ -29,6 +31,8 @@ export interface HeaderFooterFormData {
MatOptionModule,
MatSelectModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class HeaderFooterComponent {
@@ -1,23 +1,29 @@
<h2>Menu Category</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
</div>
<div class="row-container">
<mat-checkbox [formField]="form.isActive">Is Active?</mat-checkbox>
</div>
</form>
@if (itemResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (itemResource.error()) {
<app-error-state (retryAction)="itemResource.reload()" />
} @else {
<h2>Menu Category</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
</div>
<div class="row-container">
<mat-checkbox [formField]="form.isActive">Is Active?</mat-checkbox>
</div>
</form>
<div class="row-container">
<button type="button" mat-raised-button [disabled]="item().isFixture" color="primary" class="" (click)="save()">
Save
</button>
@if (!!item().id) {
<button type="button" mat-raised-button [disabled]="item().isFixture" color="warn" (click)="confirmDelete()">
Delete
<div class="row-container">
<button type="button" mat-raised-button [disabled]="item().isFixture" color="primary" class="" (click)="save()">
Save
</button>
}
</div>
@if (!!item().id) {
<button type="button" mat-raised-button [disabled]="item().isFixture" color="warn" (click)="confirmDelete()">
Delete
</button>
}
</div>
}
@@ -10,6 +10,8 @@ import { Router } from '@angular/router';
import { MenuCategory } from '../../core/menu-category';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { MenuCategoryService } from '../menu-category.service';
export interface MenuCategoryDetailFormData {
@@ -21,7 +23,15 @@ export interface MenuCategoryDetailFormData {
selector: 'app-menu-category-detail',
templateUrl: './menu-category-detail.component.html',
styleUrls: ['./menu-category-detail.component.css'],
imports: [MatButtonModule, MatCheckboxModule, MatFormFieldModule, MatInputModule, FormField],
imports: [
MatButtonModule,
MatCheckboxModule,
MatFormFieldModule,
MatInputModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class MenuCategoryDetailComponent {
private router = inject(Router);
@@ -1,39 +1,45 @@
<h2 class="row-container space-between">
<span>Menu Categories</span>
<button type="button" mat-button (click)="updateSortOrder()">Update Order</button>
<a mat-button [routerLink]="['/menu-categories', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<mat-table
#table
cdkDropList
[dataSource]="dataSource()"
[cdkDropListData]="dataSource()"
aria-label="Elements"
(cdkDropListDropped)="dropTable($event)"
>
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/menu-categories', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
@if (listResource.isLoading()) {
<app-skeleton-loader type="table" [count]="5" />
} @else if (listResource.error()) {
<app-error-state (retryAction)="listResource.reload()" />
} @else {
<h2 class="row-container space-between">
<span>Menu Categories</span>
<button type="button" mat-button (click)="updateSortOrder()">Update Order</button>
<a mat-button [routerLink]="['/menu-categories', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<mat-table
#table
cdkDropList
[dataSource]="dataSource()"
[cdkDropListData]="dataSource()"
aria-label="Elements"
(cdkDropListDropped)="dropTable($event)"
>
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/menu-categories', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
<!-- Is Active Column -->
<ng-container matColumnDef="isActive">
<mat-header-cell *matHeaderCellDef>Active?</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.isActive }}</mat-cell>
</ng-container>
<!-- Is Active Column -->
<ng-container matColumnDef="isActive">
<mat-header-cell *matHeaderCellDef>Active?</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.isActive }}</mat-cell>
</ng-container>
<!-- Is Fixture Column -->
<ng-container matColumnDef="isFixture">
<mat-header-cell *matHeaderCellDef>Fixture?</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.isFixture }}</mat-cell>
</ng-container>
<!-- Is Fixture Column -->
<ng-container matColumnDef="isFixture">
<mat-header-cell *matHeaderCellDef>Fixture?</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.isFixture }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns" cdkDrag [cdkDragData]="row"></mat-row>
</mat-table>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns" cdkDrag [cdkDragData]="row"></mat-row>
</mat-table>
}
@@ -8,12 +8,22 @@ import { RouterLink } from '@angular/router';
import { firstValueFrom } from 'rxjs';
import { MenuCategory } from '../../core/menu-category';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { MenuCategoryService } from '../menu-category.service';
@Component({
selector: 'app-menu-category-list',
templateUrl: './menu-category-list.component.html',
styleUrls: ['./menu-category-list.component.css'],
imports: [DragDropModule, MatButtonModule, MatIconModule, MatTableModule, RouterLink],
imports: [
DragDropModule,
MatButtonModule,
MatIconModule,
MatTableModule,
RouterLink,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class MenuCategoryListComponent {
private snackBar = inject(MatSnackBar);
@@ -1,103 +1,109 @@
<h2 class="row-container space-between">
<span>Menu Engineering Report</span>
<span class="spacer"></span>
<button type="button" mat-icon-button (click)="exportCsv()">
<mat-icon>save_alt</mat-icon>
</button>
<button type="button" mat-icon-button (click)="print()">
<mat-icon>print</mat-icon>
</button>
</h2>
@if (infoResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (infoResource.error()) {
<app-error-state (retryAction)="infoResource.reload()" />
} @else {
<h2 class="row-container space-between">
<span>Menu Engineering Report</span>
<span class="spacer"></span>
<button type="button" mat-icon-button (click)="exportCsv()">
<mat-icon>save_alt</mat-icon>
</button>
<button type="button" mat-icon-button (click)="print()">
<mat-icon>print</mat-icon>
</button>
</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Start Date</mat-label>
<input
matInput
[matDatepicker]="startDate"
(focus)="startDate.open()"
[formField]="form.startDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
<mat-datepicker #startDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Finish Date</mat-label>
<input
matInput
[matDatepicker]="finishDate"
(focus)="finishDate.open()"
[formField]="form.finishDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<button type="button" mat-raised-button class="flex-auto basis-1-5" color="primary" (click)="show()">Show</button>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Filter</mat-label>
<input type="text" matInput [formField]="form.filter" autocomplete="off" />
<mat-hint
>n: Name, sc: Sale Category, mc: Menu Category, q:(=/&lt;=/&gt;=/&lt;/&gt;)Quantity,
s:(=/&lt;=/&gt;=/&lt;/&gt;)Sales</mat-hint
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Start Date</mat-label>
<input
matInput
[matDatepicker]="startDate"
(focus)="startDate.open()"
[formField]="form.startDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
<mat-datepicker #startDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Finish Date</mat-label>
<input
matInput
[matDatepicker]="finishDate"
(focus)="finishDate.open()"
[formField]="form.finishDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<button type="button" mat-raised-button class="flex-auto basis-1-5" color="primary" (click)="show()">Show</button>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Filter</mat-label>
<input type="text" matInput [formField]="form.filter" autocomplete="off" />
<mat-hint
>n: Name, sc: Sale Category, mc: Menu Category, q:(=/&lt;=/&gt;=/&lt;/&gt;)Quantity,
s:(=/&lt;=/&gt;=/&lt;/&gt;)Sales</mat-hint
>
</mat-form-field>
</div>
</form>
<mat-table #table [dataSource]="dataSource()" matSort>
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header>Name</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.name }}</mat-cell>
</ng-container>
<!-- Price Column -->
<ng-container matColumnDef="price">
<mat-header-cell *matHeaderCellDef mat-sort-header class="right">Price</mat-header-cell>
<mat-cell *matCellDef="let row" class="right"
>{{ row.average | number: '1.2-2' }} / {{ row.price | number: '1.2-2' }}</mat-cell
>
</mat-form-field>
</div>
</form>
<mat-table #table [dataSource]="dataSource()" matSort>
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header>Name</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.name }}</mat-cell>
</ng-container>
</ng-container>
<!-- Price Column -->
<ng-container matColumnDef="price">
<mat-header-cell *matHeaderCellDef mat-sort-header class="right">Price</mat-header-cell>
<mat-cell *matCellDef="let row" class="right"
>{{ row.average | number: '1.2-2' }} / {{ row.price | number: '1.2-2' }}</mat-cell
>
</ng-container>
<!-- Sale Category Column -->
<ng-container matColumnDef="saleCategory">
<mat-header-cell *matHeaderCellDef mat-sort-header>Sale Category</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.saleCategory }}</mat-cell>
</ng-container>
<!-- Sale Category Column -->
<ng-container matColumnDef="saleCategory">
<mat-header-cell *matHeaderCellDef mat-sort-header>Sale Category</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.saleCategory }}</mat-cell>
</ng-container>
<!-- Menu Category Column -->
<ng-container matColumnDef="menuCategory">
<mat-header-cell *matHeaderCellDef mat-sort-header>Menu Category</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.menuCategory }}</mat-cell>
</ng-container>
<!-- Menu Category Column -->
<ng-container matColumnDef="menuCategory">
<mat-header-cell *matHeaderCellDef mat-sort-header>Menu Category</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.menuCategory }}</mat-cell>
</ng-container>
<!-- Quantity Column -->
<ng-container matColumnDef="quantity">
<mat-header-cell *matHeaderCellDef mat-sort-header class="right">Quantity</mat-header-cell>
<mat-cell *matCellDef="let row" class="right"
>{{ row.quantity | number: '1.2-2' }} ({{ row.quantityPercent | percent: '1.2-2' }})</mat-cell
>
</ng-container>
<!-- Quantity Column -->
<ng-container matColumnDef="quantity">
<mat-header-cell *matHeaderCellDef mat-sort-header class="right">Quantity</mat-header-cell>
<mat-cell *matCellDef="let row" class="right"
>{{ row.quantity | number: '1.2-2' }} ({{ row.quantityPercent | percent: '1.2-2' }})</mat-cell
>
</ng-container>
<!-- Sales Column -->
<ng-container matColumnDef="sales">
<mat-header-cell *matHeaderCellDef mat-sort-header class="right">Sales</mat-header-cell>
<mat-cell *matCellDef="let row" class="right"
>{{ row.sales | number: '1.2-2' }} ({{ row.salesPercent | percent: '1.2-2' }})</mat-cell
>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-paginator
#paginator
[length]="dataSource().length"
[pageIndex]="0"
[pageSize]="500"
[pageSizeOptions]="[25, 50, 100, 250]"
>
</mat-paginator>
<!-- Sales Column -->
<ng-container matColumnDef="sales">
<mat-header-cell *matHeaderCellDef mat-sort-header class="right">Sales</mat-header-cell>
<mat-cell *matCellDef="let row" class="right"
>{{ row.sales | number: '1.2-2' }} ({{ row.salesPercent | percent: '1.2-2' }})</mat-cell
>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-paginator
#paginator
[length]="dataSource().length"
[pageIndex]="0"
[pageSize]="500"
[pageSizeOptions]="[25, 50, 100, 250]"
>
</mat-paginator>
}
@@ -14,6 +14,8 @@ import { Router } from '@angular/router';
import { equal, larger, largerEq, smaller, smallerEq } from 'mathjs';
import moment from 'moment';
import { ErrorStateComponent } from '../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../shared/skeleton-loader/skeleton-loader.component';
import { ToCsvService } from '../shared/to-csv.service';
import { MenuEngineeringReport } from './menu-engineering-report';
import { MenuEngineeringReportItem } from './menu-engineering-report-item';
@@ -41,6 +43,8 @@ export interface MenuEngineeringReportFormData {
MatTableModule,
PercentPipe,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class MenuEngineeringReportComponent {
@@ -1,65 +1,71 @@
<h2>Modifier Category</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Minimum</mat-label>
<input matInput type="number" [formField]="form.minimum" />
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Maximum</mat-label>
<input matInput type="number" [formField]="form.maximum" />
</mat-form-field>
</div>
<div class="row-container">
<mat-checkbox [formField]="form.isActive">Is Active?</mat-checkbox>
</div>
<mat-divider></mat-divider>
<mat-tree [dataSource]="dataSource" #tree [childrenAccessor]="childrenAccessor" class="example-tree">
<!-- This is the tree node template for leaf nodes -->
<mat-nested-tree-node *matTreeNodeDef="let node" class="mat-tree-node" [class.leaf-node]="!hasChild(0, node)">
<li class="mat-tree-node">
<!-- use a disabled button to provide padding for tree leaf -->
<!-- eslint-disable-next-line @angular-eslint/template/elements-content -->
<button type="button" mat-icon-button disabled></button>
<mat-checkbox
class="checklist-leaf-node"
[checked]="isProductSelected(node)"
(change)="toggleProductSelection(node)"
>{{ node.name }}</mat-checkbox
>
</li>
</mat-nested-tree-node>
<!-- This is the tree node template for expandable nodes -->
<mat-nested-tree-node *matTreeNodeDef="let node; when: hasChild">
<li>
<div class="mat-tree-node">
<button type="button" mat-icon-button matTreeNodeToggle [attr.aria-label]="'toggle ' + node.name">
<mat-icon class="mat-icon-rtl-mirror">
{{ tree.isExpanded(node) ? 'expand_more' : 'chevron_right' }}
</mat-icon>
</button>
@if (itemResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (itemResource.error()) {
<app-error-state (retryAction)="itemResource.reload()" />
} @else {
<h2>Modifier Category</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Minimum</mat-label>
<input matInput type="number" [formField]="form.minimum" />
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Maximum</mat-label>
<input matInput type="number" [formField]="form.maximum" />
</mat-form-field>
</div>
<div class="row-container">
<mat-checkbox [formField]="form.isActive">Is Active?</mat-checkbox>
</div>
<mat-divider></mat-divider>
<mat-tree [dataSource]="dataSource" #tree [childrenAccessor]="childrenAccessor" class="example-tree">
<!-- This is the tree node template for leaf nodes -->
<mat-nested-tree-node *matTreeNodeDef="let node" class="mat-tree-node" [class.leaf-node]="!hasChild(0, node)">
<li class="mat-tree-node">
<!-- use a disabled button to provide padding for tree leaf -->
<!-- eslint-disable-next-line @angular-eslint/template/elements-content -->
<button type="button" mat-icon-button disabled></button>
<mat-checkbox
[checked]="isMenuCategorySelected(node)"
[indeterminate]="isMenuCategoryPartiallySelected(node)"
(change)="toggleMenuCategorySelection(node)"
class="checklist-leaf-node"
[checked]="isProductSelected(node)"
(change)="toggleProductSelection(node)"
>{{ node.name }}</mat-checkbox
>
</div>
<ul [class.example-tree-invisible]="!tree.isExpanded(node)">
<ng-container matTreeNodeOutlet></ng-container>
</ul>
</li>
</mat-nested-tree-node>
</mat-tree>
</form>
</li>
</mat-nested-tree-node>
<!-- This is the tree node template for expandable nodes -->
<mat-nested-tree-node *matTreeNodeDef="let node; when: hasChild">
<li>
<div class="mat-tree-node">
<button type="button" mat-icon-button matTreeNodeToggle [attr.aria-label]="'toggle ' + node.name">
<mat-icon class="mat-icon-rtl-mirror">
{{ tree.isExpanded(node) ? 'expand_more' : 'chevron_right' }}
</mat-icon>
</button>
<mat-checkbox
[checked]="isMenuCategorySelected(node)"
[indeterminate]="isMenuCategoryPartiallySelected(node)"
(change)="toggleMenuCategorySelection(node)"
>{{ node.name }}</mat-checkbox
>
</div>
<ul [class.example-tree-invisible]="!tree.isExpanded(node)">
<ng-container matTreeNodeOutlet></ng-container>
</ul>
</li>
</mat-nested-tree-node>
</mat-tree>
</form>
<div class="row-container">
<button type="button" mat-raised-button color="primary" class="" (click)="save()">Save</button>
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
</div>
<div class="row-container">
<button type="button" mat-raised-button color="primary" class="" (click)="save()">Save</button>
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
</div>
}
@@ -13,6 +13,8 @@ import { Router } from '@angular/router';
import { ModifierCategory, MenuCategory, StockKeepingUnitLink } from '../../core/modifier-category';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { ModifierCategoryService } from '../modifier-category.service';
import { NodeItem } from '../node-item';
@@ -46,6 +48,8 @@ export interface ModifierCategoryDetailFormData {
MatInputModule,
MatTreeModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class ModifierCategoryDetailComponent {
@@ -1,63 +1,69 @@
<h2 class="row-container space-between">
<span>Modifier Categories</span>
<a mat-button [routerLink]="['/modifier-categories', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/modifier-categories', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
@if (listResource.isLoading()) {
<app-skeleton-loader type="table" [count]="5" />
} @else if (listResource.error()) {
<app-error-state (retryAction)="listResource.reload()" />
} @else {
<h2 class="row-container space-between">
<span>Modifier Categories</span>
<a mat-button [routerLink]="['/modifier-categories', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/modifier-categories', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
<!-- Minimum Column -->
<ng-container matColumnDef="minimum">
<mat-header-cell *matHeaderCellDef>Minimum</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.minimum }}</mat-cell>
</ng-container>
<!-- Minimum Column -->
<ng-container matColumnDef="minimum">
<mat-header-cell *matHeaderCellDef>Minimum</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.minimum }}</mat-cell>
</ng-container>
<!-- Maximum Column -->
<ng-container matColumnDef="maximum">
<mat-header-cell *matHeaderCellDef>Maximum</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.maximum }}</mat-cell>
</ng-container>
<!-- Maximum Column -->
<ng-container matColumnDef="maximum">
<mat-header-cell *matHeaderCellDef>Maximum</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.maximum }}</mat-cell>
</ng-container>
<!-- Is Active Column -->
<ng-container matColumnDef="isActive">
<mat-header-cell *matHeaderCellDef>Is Active</mat-header-cell>
<mat-cell *matCellDef="let row">
<mat-icon>
{{ row.isActive ? 'visibility' : 'visibility_off' }}
</mat-icon>
<b> {{ row.isActive ? 'Active' : 'Not Active' }}</b>
</mat-cell>
</ng-container>
<!-- Is Active Column -->
<ng-container matColumnDef="isActive">
<mat-header-cell *matHeaderCellDef>Is Active</mat-header-cell>
<mat-cell *matCellDef="let row">
<mat-icon>
{{ row.isActive ? 'visibility' : 'visibility_off' }}
</mat-icon>
<b> {{ row.isActive ? 'Active' : 'Not Active' }}</b>
</mat-cell>
</ng-container>
<!-- Products Column -->
<ng-container matColumnDef="products">
<mat-header-cell *matHeaderCellDef>Products</mat-header-cell>
<mat-cell *matCellDef="let row">
<ul>
@for (mc of row.menuCategories; track mc) {
<li>
{{ mc.name }}
@if (!mc.enabled) {
<ul>
@for (p of mc.skus; track p) {
<li>{{ p.name }}</li>
}
</ul>
}
</li>
}
</ul>
</mat-cell>
</ng-container>
<!-- Products Column -->
<ng-container matColumnDef="products">
<mat-header-cell *matHeaderCellDef>Products</mat-header-cell>
<mat-cell *matCellDef="let row">
<ul>
@for (mc of row.menuCategories; track mc) {
<li>
{{ mc.name }}
@if (!mc.enabled) {
<ul>
@for (p of mc.skus; track p) {
<li>{{ p.name }}</li>
}
</ul>
}
</li>
}
</ul>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
}
@@ -4,12 +4,14 @@ import { MatIconModule } from '@angular/material/icon';
import { MatTableModule } from '@angular/material/table';
import { RouterLink } from '@angular/router';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { ModifierCategoryService } from '../modifier-category.service';
@Component({
selector: 'app-modifier-category-list',
templateUrl: './modifier-category-list.component.html',
styleUrls: ['./modifier-category-list.component.css'],
imports: [MatButtonModule, MatIconModule, MatTableModule, RouterLink],
imports: [MatButtonModule, MatIconModule, MatTableModule, RouterLink, ErrorStateComponent, SkeletonLoaderComponent],
})
export class ModifierCategoryListComponent {
private modifierCategoryService = inject(ModifierCategoryService);
@@ -1,43 +1,49 @@
<h2>Modifier</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
</div>
<div class="row-container">
<mat-checkbox [formField]="form.showInBill">Show In Bill?</mat-checkbox>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Price</mat-label>
<input matInput type="number" [formField]="form.price" />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Category</mat-label>
<mat-select [formField]="form.modifierCategory">
@for (mc of modifierCategories(); track mc) {
<mat-option [value]="mc.id">
{{ mc.name }}
</mat-option>
@if (itemResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (itemResource.error()) {
<app-error-state (retryAction)="itemResource.reload()" />
} @else {
<h2>Modifier</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
</div>
<div class="row-container">
<mat-checkbox [formField]="form.showInBill">Show In Bill?</mat-checkbox>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Price</mat-label>
<input matInput type="number" [formField]="form.price" />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Category</mat-label>
<mat-select [formField]="form.modifierCategory">
@for (mc of modifierCategories(); track mc) {
<mat-option [value]="mc.id">
{{ mc.name }}
</mat-option>
}
</mat-select>
@for (error of form.modifierCategory().errors(); track error) {
<mat-error>{{ error.message }}</mat-error>
}
</mat-select>
@for (error of form.modifierCategory().errors(); track error) {
<mat-error>{{ error.message }}</mat-error>
}
</mat-form-field>
</div>
<div class="row-container">
<mat-checkbox [formField]="form.isActive">Is Active?</mat-checkbox>
</div>
</form>
</mat-form-field>
</div>
<div class="row-container">
<mat-checkbox [formField]="form.isActive">Is Active?</mat-checkbox>
</div>
</form>
<div class="row-container">
<button type="button" mat-raised-button color="primary" [disabled]="form().invalid()" (click)="save()">Save</button>
@if (!!item().id) {
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
}
</div>
<div class="row-container">
<button type="button" mat-raised-button color="primary" [disabled]="form().invalid()" (click)="save()">Save</button>
@if (!!item().id) {
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
}
</div>
}
@@ -14,6 +14,8 @@ import { Modifier } from '../../core/modifier';
import { ModifierCategory } from '../../core/modifier-category';
import { ModifierCategoryService } from '../../modifier-categories/modifier-category.service';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { ModifierService } from '../modifier.service';
export interface ModifierDetailFormData {
@@ -36,6 +38,8 @@ export interface ModifierDetailFormData {
MatOptionModule,
MatSelectModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class ModifierDetailComponent {
@@ -1,72 +1,78 @@
<h2 class="row-container space-between">
Modifiers
<a mat-button [routerLink]="['/modifiers', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Modifier Category</mat-label>
<mat-select [formField]="form.menuCategory">
<mat-option>-- All Categories --</mat-option>
@for (mc of modifierCategories(); track mc.id) {
<mat-option [value]="mc.id">
{{ mc.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
</form>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/modifiers', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
@if (listResource.isLoading()) {
<app-skeleton-loader type="table" [count]="5" />
} @else if (listResource.error()) {
<app-error-state (retryAction)="listResource.reload()" />
} @else {
<h2 class="row-container space-between">
Modifiers
<a mat-button [routerLink]="['/modifiers', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Modifier Category</mat-label>
<mat-select [formField]="form.menuCategory">
<mat-option [value]="null">-- All Categories --</mat-option>
@for (mc of modifierCategories(); track mc.id) {
<mat-option [value]="mc.id">
{{ mc.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
</form>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/modifiers', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
<!-- Show In Bill Column -->
<ng-container matColumnDef="showInBill">
<mat-header-cell *matHeaderCellDef>Show In Bill</mat-header-cell>
<mat-cell *matCellDef="let row">
<div layout="row">
<div>
<mat-icon>
{{ row.showInBill ? 'visibility' : 'visibility_off' }}
</mat-icon>
<b> {{ row.showInBill ? 'Show' : 'Hide' }}</b>
<!-- Show In Bill Column -->
<ng-container matColumnDef="showInBill">
<mat-header-cell *matHeaderCellDef>Show In Bill</mat-header-cell>
<mat-cell *matCellDef="let row">
<div layout="row">
<div>
<mat-icon>
{{ row.showInBill ? 'visibility' : 'visibility_off' }}
</mat-icon>
<b> {{ row.showInBill ? 'Show' : 'Hide' }}</b>
</div>
</div>
</div>
</mat-cell>
</ng-container>
</mat-cell>
</ng-container>
<!-- Price Column -->
<ng-container matColumnDef="price">
<mat-header-cell *matHeaderCellDef>Price</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.price | currency: 'INR' }}</mat-cell>
</ng-container>
<!-- Price Column -->
<ng-container matColumnDef="price">
<mat-header-cell *matHeaderCellDef>Price</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.price | currency: 'INR' }}</mat-cell>
</ng-container>
<!-- Modifier Category Column -->
<ng-container matColumnDef="modifierCategory">
<mat-header-cell *matHeaderCellDef>Category</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.modifierCategory.name }}</mat-cell>
</ng-container>
<!-- Modifier Category Column -->
<ng-container matColumnDef="modifierCategory">
<mat-header-cell *matHeaderCellDef>Category</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.modifierCategory.name }}</mat-cell>
</ng-container>
<!-- Is Active Column -->
<ng-container matColumnDef="isActive">
<mat-header-cell *matHeaderCellDef>Is Active</mat-header-cell>
<mat-cell *matCellDef="let row">
<mat-icon>
{{ row.isActive ? 'visibility' : 'visibility_off' }}
</mat-icon>
<b> {{ row.isActive ? 'Active' : 'Not Active' }}</b>
</mat-cell>
</ng-container>
<!-- Is Active Column -->
<ng-container matColumnDef="isActive">
<mat-header-cell *matHeaderCellDef>Is Active</mat-header-cell>
<mat-cell *matCellDef="let row">
<mat-icon>
{{ row.isActive ? 'visibility' : 'visibility_off' }}
</mat-icon>
<b> {{ row.isActive ? 'Active' : 'Not Active' }}</b>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
}
@@ -10,6 +10,8 @@ import { MatTableModule } from '@angular/material/table';
import { RouterLink } from '@angular/router';
import { ModifierCategoryService } from '../../modifier-categories/modifier-category.service';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { ModifierService } from '../modifier.service';
export interface ModifierListFormData {
@@ -30,6 +32,8 @@ export interface ModifierListFormData {
MatTableModule,
FormField,
RouterLink,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class ModifierListComponent {
@@ -1,26 +1,32 @@
<h2>Printer</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Address</mat-label>
<input matInput [formField]="form.address" />
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Cut Code</mat-label>
<input matInput [formField]="form.cutCode" />
</mat-form-field>
</div>
</form>
@if (itemResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (itemResource.error()) {
<app-error-state (retryAction)="itemResource.reload()" />
} @else {
<h2>Printer</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Address</mat-label>
<input matInput [formField]="form.address" />
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Cut Code</mat-label>
<input matInput [formField]="form.cutCode" />
</mat-form-field>
</div>
</form>
<div class="row-container">
<button type="button" mat-raised-button color="primary" class="" (click)="save()">Save</button>
@if (!!item().id) {
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
}
</div>
<div class="row-container">
<button type="button" mat-raised-button color="primary" class="" (click)="save()">Save</button>
@if (!!item().id) {
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
}
</div>
}
@@ -9,6 +9,8 @@ import { Router } from '@angular/router';
import { Printer } from '../../core/printer';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { PrinterService } from '../printer.service';
export interface PrinterDetailFormData {
@@ -21,7 +23,14 @@ export interface PrinterDetailFormData {
selector: 'app-printer-detail',
templateUrl: './printer-detail.component.html',
styleUrls: ['./printer-detail.component.css'],
imports: [MatButtonModule, MatFormFieldModule, MatInputModule, FormField],
imports: [
MatButtonModule,
MatFormFieldModule,
MatInputModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class PrinterDetailComponent {
private router = inject(Router);
@@ -1,31 +1,37 @@
<h2 class="row-container space-between">
<span>Printers</span>
<a mat-button [routerLink]="['/printers', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/printers', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
@if (listResource.isLoading()) {
<app-skeleton-loader type="table" [count]="5" />
} @else if (listResource.error()) {
<app-error-state (retryAction)="listResource.reload()" />
} @else {
<h2 class="row-container space-between">
<span>Printers</span>
<a mat-button [routerLink]="['/printers', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/printers', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
<!-- Address Column -->
<ng-container matColumnDef="address">
<mat-header-cell *matHeaderCellDef>Address</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.address }}</mat-cell>
</ng-container>
<!-- Address Column -->
<ng-container matColumnDef="address">
<mat-header-cell *matHeaderCellDef>Address</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.address }}</mat-cell>
</ng-container>
<!-- Cut Code Column -->
<ng-container matColumnDef="cutCode">
<mat-header-cell *matHeaderCellDef>Cut Code</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.cutCode }}</mat-cell>
</ng-container>
<!-- Cut Code Column -->
<ng-container matColumnDef="cutCode">
<mat-header-cell *matHeaderCellDef>Cut Code</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.cutCode }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
}
@@ -4,12 +4,14 @@ import { MatIconModule } from '@angular/material/icon';
import { MatTableModule } from '@angular/material/table';
import { RouterLink } from '@angular/router';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { PrinterService } from '../printer.service';
@Component({
selector: 'app-printer-list',
templateUrl: './printer-list.component.html',
styleUrls: ['./printer-list.component.css'],
imports: [MatButtonModule, MatIconModule, MatTableModule, RouterLink],
imports: [MatButtonModule, MatIconModule, MatTableModule, RouterLink, ErrorStateComponent, SkeletonLoaderComponent],
})
export class PrinterListComponent {
private printerService = inject(PrinterService);
@@ -1,91 +1,97 @@
<h2 class="row-container space-between">
<span>Product Sale Report</span>
<span class="spacer"></span>
<button type="button" mat-icon-button (click)="exportCsv()">
<mat-icon>save_alt</mat-icon>
</button>
<button type="button" mat-icon-button (click)="print()">
<mat-icon>print</mat-icon>
</button>
</h2>
@if (infoResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (infoResource.error()) {
<app-error-state (retryAction)="infoResource.reload()" />
} @else {
<h2 class="row-container space-between">
<span>Product Sale Report</span>
<span class="spacer"></span>
<button type="button" mat-icon-button (click)="exportCsv()">
<mat-icon>save_alt</mat-icon>
</button>
<button type="button" mat-icon-button (click)="print()">
<mat-icon>print</mat-icon>
</button>
</h2>
<form class="flex-col" [formRoot]="form">
<div class="row-container sm:max-lg:flex-col">
<mat-form-field class="flex-auto basis-1-3">
<mat-label>Start Date</mat-label>
<input
matInput
[matDatepicker]="startDate"
(focus)="startDate.open()"
[formField]="form.startDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
<mat-datepicker #startDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto basis-1-3">
<mat-label>Finish Date</mat-label>
<input
matInput
[matDatepicker]="finishDate"
(focus)="finishDate.open()"
[formField]="form.finishDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto basis-1-6">
<mat-label>Section</mat-label>
<mat-select [formField]="form.section">
<mat-option>-- All --</mat-option>
@for (p of sections(); track p.id) {
<mat-option [value]="p.id">
{{ p.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
<button type="button" mat-raised-button class="flex-auto basis-1-6" color="primary" (click)="show()">Show</button>
</div>
</form>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.name }}</mat-cell>
</ng-container>
<form class="flex-col" [formRoot]="form">
<div class="row-container sm:max-lg:flex-col">
<mat-form-field class="flex-auto basis-1-3">
<mat-label>Start Date</mat-label>
<input
matInput
[matDatepicker]="startDate"
(focus)="startDate.open()"
[formField]="form.startDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
<mat-datepicker #startDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto basis-1-3">
<mat-label>Finish Date</mat-label>
<input
matInput
[matDatepicker]="finishDate"
(focus)="finishDate.open()"
[formField]="form.finishDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto basis-1-6">
<mat-label>Section</mat-label>
<mat-select [formField]="form.section">
<mat-option [value]="null">-- All --</mat-option>
@for (p of sections(); track p.id) {
<mat-option [value]="p.id">
{{ p.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
<button type="button" mat-raised-button class="flex-auto basis-1-6" color="primary" (click)="show()">Show</button>
</div>
</form>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.name }}</mat-cell>
</ng-container>
<!-- Unbilled Column -->
<ng-container matColumnDef="unbilled">
<mat-header-cell *matHeaderCellDef class="right">Unbilled</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.kot | number: '1.2-2' }}</mat-cell>
</ng-container>
<!-- Unbilled Column -->
<ng-container matColumnDef="unbilled">
<mat-header-cell *matHeaderCellDef class="right">Unbilled</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.kot | number: '1.2-2' }}</mat-cell>
</ng-container>
<!-- Sale Column -->
<ng-container matColumnDef="sale">
<mat-header-cell *matHeaderCellDef class="right">Sale</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.regularBill | number: '1.2-2' }}</mat-cell>
</ng-container>
<!-- Sale Column -->
<ng-container matColumnDef="sale">
<mat-header-cell *matHeaderCellDef class="right">Sale</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.regularBill | number: '1.2-2' }}</mat-cell>
</ng-container>
<!-- No Charge Column -->
<ng-container matColumnDef="noCharge">
<mat-header-cell *matHeaderCellDef class="right">No Charge</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.noCharge | number: '1.2-2' }}</mat-cell>
</ng-container>
<!-- No Charge Column -->
<ng-container matColumnDef="noCharge">
<mat-header-cell *matHeaderCellDef class="right">No Charge</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.noCharge | number: '1.2-2' }}</mat-cell>
</ng-container>
<!-- Staff Column -->
<ng-container matColumnDef="staff">
<mat-header-cell *matHeaderCellDef class="right">Staff</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.staff | number: '1.2-2' }}</mat-cell>
</ng-container>
<!-- Staff Column -->
<ng-container matColumnDef="staff">
<mat-header-cell *matHeaderCellDef class="right">Staff</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.staff | number: '1.2-2' }}</mat-cell>
</ng-container>
<!-- Cancelled Column -->
<ng-container matColumnDef="cancel">
<mat-header-cell *matHeaderCellDef class="right">Cancelled</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.cancel | number: '1.2-2' }}</mat-cell>
</ng-container>
<!-- Cancelled Column -->
<ng-container matColumnDef="cancel">
<mat-header-cell *matHeaderCellDef class="right">Cancelled</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.cancel | number: '1.2-2' }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
}
@@ -13,6 +13,8 @@ import { Router } from '@angular/router';
import moment from 'moment';
import { SectionService } from '../sections/section.service';
import { ErrorStateComponent } from '../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../shared/skeleton-loader/skeleton-loader.component';
import { ToCsvService } from '../shared/to-csv.service';
import { ProductSaleReport } from './product-sale-report';
import { ProductSaleReportService } from './product-sale-report.service';
@@ -38,6 +40,8 @@ export interface ProductSaleReportFormData {
MatTableModule,
FormField,
FormRoot,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class ProductSaleReportComponent {
@@ -1,46 +1,52 @@
<h2 class="row-container space-between">
<span>Product Update Report</span>
<button type="button" mat-icon-button (click)="exportCsv()">
<mat-icon>save_alt</mat-icon>
</button>
</h2>
@if (infoResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (infoResource.error()) {
<app-error-state (retryAction)="infoResource.reload()" />
} @else {
<h2 class="row-container space-between">
<span>Product Update Report</span>
<button type="button" mat-icon-button (click)="exportCsv()">
<mat-icon>save_alt</mat-icon>
</button>
</h2>
<form class="flex-col">
<div class="row-container sm:max-lg:flex-col">
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Start Date</mat-label>
<input
matInput
[matDatepicker]="startDate"
(focus)="startDate.open()"
[formField]="form.startDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
<mat-datepicker #startDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Finish Date</mat-label>
<input
matInput
[matDatepicker]="finishDate"
(focus)="finishDate.open()"
[formField]="form.finishDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<button type="button" mat-raised-button class="flex-auto basis-1-5" color="primary" (click)="show()">Show</button>
</div>
</form>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Details Column -->
<ng-container matColumnDef="details">
<mat-header-cell *matHeaderCellDef>Details</mat-header-cell>
<mat-cell class="multi_lines_text" *matCellDef="let row">{{ row }}</mat-cell>
</ng-container>
<form class="flex-col">
<div class="row-container sm:max-lg:flex-col">
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Start Date</mat-label>
<input
matInput
[matDatepicker]="startDate"
(focus)="startDate.open()"
[formField]="form.startDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
<mat-datepicker #startDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Finish Date</mat-label>
<input
matInput
[matDatepicker]="finishDate"
(focus)="finishDate.open()"
[formField]="form.finishDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<button type="button" mat-raised-button class="flex-auto basis-1-5" color="primary" (click)="show()">Show</button>
</div>
</form>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Details Column -->
<ng-container matColumnDef="details">
<mat-header-cell *matHeaderCellDef>Details</mat-header-cell>
<mat-cell class="multi_lines_text" *matCellDef="let row">{{ row }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
}
@@ -9,6 +9,8 @@ import { MatTableModule } from '@angular/material/table';
import { Router } from '@angular/router';
import moment from 'moment';
import { ErrorStateComponent } from '../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../shared/skeleton-loader/skeleton-loader.component';
import { ToCsvService } from '../shared/to-csv.service';
import { ProductUpdatesReport } from './product-updates-report';
import { ProductUpdatesReportService } from './product-updates-report.service';
@@ -30,6 +32,8 @@ export interface ProductUpdatesReportFormData {
MatInputModule,
MatTableModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class ProductUpdatesReportComponent {
@@ -1,178 +1,184 @@
<h2>Product</h2>
<form>
<div class="row-container">
<mat-form-field class="basis-3-4">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
<mat-form-field class="basis-1-4">
<mat-label>Fraction Units</mat-label>
<input matInput [formField]="form.fractionUnits" />
</mat-form-field>
@if (itemResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (itemResource.error()) {
<app-error-state (retryAction)="itemResource.reload()" />
} @else {
<h2>Product</h2>
<form>
<div class="row-container">
<mat-form-field class="basis-3-4">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
<mat-form-field class="basis-1-4">
<mat-label>Fraction Units</mat-label>
<input matInput [formField]="form.fractionUnits" />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="basis-3-4">
<mat-label>Sale Category</mat-label>
<mat-select [formField]="form.saleCategory">
@for (sc of saleCategories(); track sc) {
<mat-option [value]="sc.id">
{{ sc.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
<mat-checkbox [formField]="form.enabled" class="basis-1-4">Enabled?</mat-checkbox>
</div>
<!-- SKU section -->
<h2>Stock Keeping Units</h2>
<div class="nutrition-grid">
<mat-form-field class="flex-auto">
<mat-label>Units</mat-label>
<input matInput [formField]="form.addRow.units" />
@for (error of form.addRow.units().errors(); track error) {
<mat-error>{{ error.message }}</mat-error>
}
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Fraction</mat-label>
<input matInput type="number" [formField]="form.addRow.fraction" />
@for (error of form.addRow.fraction().errors(); track error) {
<mat-error>{{ error.message }}</mat-error>
}
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Yield</mat-label>
<input matInput type="number" [formField]="form.addRow.productYield" />
@for (error of form.addRow.productYield().errors(); track error) {
<mat-error>{{ error.message }}</mat-error>
}
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Cost Price</mat-label>
<input matInput type="number" [formField]="form.addRow.costPrice" />
@for (error of form.addRow.costPrice().errors(); track error) {
<mat-error>{{ error.message }}</mat-error>
}
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Sale Price</mat-label>
<input matInput type="number" [formField]="form.addRow.salePrice" />
@for (error of form.addRow.salePrice().errors(); track error) {
<mat-error>{{ error.message }}</mat-error>
}
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Menu Category</mat-label>
<mat-select [formField]="form.addRow.menuCategory">
@for (mc of menuCategories(); track mc) {
<mat-option [value]="mc.id">
{{ mc.name }}
</mat-option>
}
</mat-select>
@for (error of form.addRow.menuCategory().errors(); track error) {
<mat-error>{{ error.message }}</mat-error>
}
</mat-form-field>
<mat-checkbox [formField]="form.addRow.hasHappyHour" class="flex-auto">Has Happy Hour?</mat-checkbox>
<mat-checkbox [formField]="form.addRow.isNotAvailable" class="flex-auto">Not Available?</mat-checkbox>
<button
type="button"
mat-raised-button
color="primary"
[disabled]="form.addRow().invalid()"
(click)="addRow()"
class="flex-auto"
>
Add
</button>
</div>
</form>
<!-- SKU table -->
<div class="row-container wrapped">
<mat-table [dataSource]="this.formModel().skus" aria-label="Stock Keeping Units" class="flex-auto">
<!-- Units Column -->
<ng-container matColumnDef="units">
<mat-header-cell *matHeaderCellDef>Units</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.units }}</mat-cell>
</ng-container>
<!-- Fraction Column -->
<ng-container matColumnDef="fraction">
<mat-header-cell *matHeaderCellDef>Fraction</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.fraction }}</mat-cell>
</ng-container>
<!-- Yield Column -->
<ng-container matColumnDef="productYield">
<mat-header-cell *matHeaderCellDef class="right">Yield</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.productYield }}</mat-cell>
</ng-container>
<!-- Cost Price Column -->
<ng-container matColumnDef="costPrice">
<mat-header-cell *matHeaderCellDef class="right">Cost Price</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.costPrice | currency: 'INR' }}</mat-cell>
</ng-container>
<!-- Sale Price Column -->
<ng-container matColumnDef="salePrice">
<mat-header-cell *matHeaderCellDef class="right">Sale Price</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.salePrice | currency: 'INR' }}</mat-cell>
</ng-container>
<!-- Menu Category Column -->
<ng-container matColumnDef="menuCategory">
<mat-header-cell *matHeaderCellDef>Menu Category</mat-header-cell>
<mat-cell *matCellDef="let row">
{{ row.menuCategory?.name ?? row.menuCategory?.id ?? '' }}
</mat-cell>
</ng-container>
<!-- Happy Hour Column -->
<ng-container matColumnDef="hasHappyHour">
<mat-header-cell *matHeaderCellDef class="center">Happy Hour</mat-header-cell>
<mat-cell *matCellDef="let row" class="center">
<mat-checkbox [checked]="row.hasHappyHour" disabled></mat-checkbox>
</mat-cell>
</ng-container>
<!-- Not Available Column -->
<ng-container matColumnDef="isNotAvailable">
<mat-header-cell *matHeaderCellDef class="center">Not Available</mat-header-cell>
<mat-cell *matCellDef="let row" class="center">
<mat-checkbox [checked]="row.isNotAvailable" disabled></mat-checkbox>
</mat-cell>
</ng-container>
<!-- Action Column -->
<ng-container matColumnDef="action">
<mat-header-cell *matHeaderCellDef class="center">Action</mat-header-cell>
<mat-cell *matCellDef="let row" class="center">
<button type="button" mat-icon-button tabindex="-1" (click)="editRow(row)">
<mat-icon>edit</mat-icon>
</button>
<button type="button" mat-icon-button tabindex="-1" color="warn" (click)="deleteRow(row)">
<mat-icon>delete</mat-icon>
</button>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
</div>
<div class="row-container">
<mat-form-field class="basis-3-4">
<mat-label>Sale Category</mat-label>
<mat-select [formField]="form.saleCategory">
@for (sc of saleCategories(); track sc) {
<mat-option [value]="sc.id">
{{ sc.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
<mat-checkbox [formField]="form.enabled" class="basis-1-4">Enabled?</mat-checkbox>
<button type="button" mat-raised-button color="primary" class="" (click)="save()">Save</button>
@if (!!item().id) {
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
}
</div>
<!-- SKU section -->
<h2>Stock Keeping Units</h2>
<div class="nutrition-grid">
<mat-form-field class="flex-auto">
<mat-label>Units</mat-label>
<input matInput [formField]="form.addRow.units" />
@for (error of form.addRow.units().errors(); track error) {
<mat-error>{{ error.message }}</mat-error>
}
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Fraction</mat-label>
<input matInput type="number" [formField]="form.addRow.fraction" />
@for (error of form.addRow.fraction().errors(); track error) {
<mat-error>{{ error.message }}</mat-error>
}
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Yield</mat-label>
<input matInput type="number" [formField]="form.addRow.productYield" />
@for (error of form.addRow.productYield().errors(); track error) {
<mat-error>{{ error.message }}</mat-error>
}
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Cost Price</mat-label>
<input matInput type="number" [formField]="form.addRow.costPrice" />
@for (error of form.addRow.costPrice().errors(); track error) {
<mat-error>{{ error.message }}</mat-error>
}
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Sale Price</mat-label>
<input matInput type="number" [formField]="form.addRow.salePrice" />
@for (error of form.addRow.salePrice().errors(); track error) {
<mat-error>{{ error.message }}</mat-error>
}
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Menu Category</mat-label>
<mat-select [formField]="form.addRow.menuCategory">
@for (mc of menuCategories(); track mc) {
<mat-option [value]="mc.id">
{{ mc.name }}
</mat-option>
}
</mat-select>
@for (error of form.addRow.menuCategory().errors(); track error) {
<mat-error>{{ error.message }}</mat-error>
}
</mat-form-field>
<mat-checkbox [formField]="form.addRow.hasHappyHour" class="flex-auto">Has Happy Hour?</mat-checkbox>
<mat-checkbox [formField]="form.addRow.isNotAvailable" class="flex-auto">Not Available?</mat-checkbox>
<button
type="button"
mat-raised-button
color="primary"
[disabled]="form.addRow().invalid()"
(click)="addRow()"
class="flex-auto"
>
Add
</button>
</div>
</form>
<!-- SKU table -->
<div class="row-container wrapped">
<mat-table [dataSource]="this.formModel().skus" aria-label="Stock Keeping Units" class="flex-auto">
<!-- Units Column -->
<ng-container matColumnDef="units">
<mat-header-cell *matHeaderCellDef>Units</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.units }}</mat-cell>
</ng-container>
<!-- Fraction Column -->
<ng-container matColumnDef="fraction">
<mat-header-cell *matHeaderCellDef>Fraction</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.fraction }}</mat-cell>
</ng-container>
<!-- Yield Column -->
<ng-container matColumnDef="productYield">
<mat-header-cell *matHeaderCellDef class="right">Yield</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.productYield }}</mat-cell>
</ng-container>
<!-- Cost Price Column -->
<ng-container matColumnDef="costPrice">
<mat-header-cell *matHeaderCellDef class="right">Cost Price</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.costPrice | currency: 'INR' }}</mat-cell>
</ng-container>
<!-- Sale Price Column -->
<ng-container matColumnDef="salePrice">
<mat-header-cell *matHeaderCellDef class="right">Sale Price</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.salePrice | currency: 'INR' }}</mat-cell>
</ng-container>
<!-- Menu Category Column -->
<ng-container matColumnDef="menuCategory">
<mat-header-cell *matHeaderCellDef>Menu Category</mat-header-cell>
<mat-cell *matCellDef="let row">
{{ row.menuCategory?.name ?? row.menuCategory?.id ?? '' }}
</mat-cell>
</ng-container>
<!-- Happy Hour Column -->
<ng-container matColumnDef="hasHappyHour">
<mat-header-cell *matHeaderCellDef class="center">Happy Hour</mat-header-cell>
<mat-cell *matCellDef="let row" class="center">
<mat-checkbox [checked]="row.hasHappyHour" disabled></mat-checkbox>
</mat-cell>
</ng-container>
<!-- Not Available Column -->
<ng-container matColumnDef="isNotAvailable">
<mat-header-cell *matHeaderCellDef class="center">Not Available</mat-header-cell>
<mat-cell *matCellDef="let row" class="center">
<mat-checkbox [checked]="row.isNotAvailable" disabled></mat-checkbox>
</mat-cell>
</ng-container>
<!-- Action Column -->
<ng-container matColumnDef="action">
<mat-header-cell *matHeaderCellDef class="center">Action</mat-header-cell>
<mat-cell *matCellDef="let row" class="center">
<button type="button" mat-icon-button tabindex="-1" (click)="editRow(row)">
<mat-icon>edit</mat-icon>
</button>
<button type="button" mat-icon-button tabindex="-1" color="warn" (click)="deleteRow(row)">
<mat-icon>delete</mat-icon>
</button>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
</div>
<div class="row-container">
<button type="button" mat-raised-button color="primary" class="" (click)="save()">Save</button>
@if (!!item().id) {
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
}
</div>
}
@@ -19,6 +19,8 @@ import { SaleCategory } from '../../core/sale-category';
import { MenuCategoryService } from '../../menu-category/menu-category.service';
import { SaleCategoryService } from '../../sale-category/sale-category.service';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { ProductService } from '../product.service';
import { ProductDetailDialogComponent } from './product-detail-dialog.component';
@@ -55,6 +57,8 @@ export interface ProductDetailFormData {
MatSelectModule,
MatTableModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class ProductDetailComponent {
@@ -1,134 +1,140 @@
<h2 class="row-container space-between">
<span>Products</span>
<button
type="button"
mat-button
(click)="updateSortOrder()"
[disabled]="menuCategoryFilter() === '' || formModel().filter !== ''"
@if (listResource.isLoading()) {
<app-skeleton-loader type="table" [count]="5" />
} @else if (listResource.error()) {
<app-error-state (retryAction)="listResource.reload()" />
} @else {
<h2 class="row-container space-between">
<span>Products</span>
<button
type="button"
mat-button
(click)="updateSortOrder()"
[disabled]="menuCategoryFilter() === '' || formModel().filter !== ''"
>
Update Order
</button>
<!-- This should check filtered data and not data-->
<button type="button" mat-icon-button (click)="exportCsv()" [disabled]="!dataSource().length">
<mat-icon>save_alt</mat-icon>
</button>
<a mat-button [routerLink]="['/products', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Filter</mat-label>
<input type="text" matInput [formField]="form.filter" autocomplete="off" />
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Menu Category</mat-label>
<mat-select [formField]="form.menuCategory">
<mat-option [value]="null">-- All Products --</mat-option>
@for (mc of menuCategoriesResource.value(); track mc) {
<mat-option [value]="mc.id">
{{ mc.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
</form>
<mat-table
#table
cdkDropList
[dataSource]="dataSource()"
[cdkDropListData]="dataSource()"
aria-label="Elements"
(cdkDropListDropped)="dropTable($event)"
>
Update Order
</button>
<!-- This should check filtered data and not data-->
<button type="button" mat-icon-button (click)="exportCsv()" [disabled]="!dataSource().length">
<mat-icon>save_alt</mat-icon>
</button>
<a mat-button [routerLink]="['/products', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Filter</mat-label>
<input type="text" matInput [formField]="form.filter" autocomplete="off" />
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Menu Category</mat-label>
<mat-select [formField]="form.menuCategory">
<mat-option>-- All Products --</mat-option>
@for (mc of menuCategoriesResource.value(); track mc) {
<mat-option [value]="mc.id">
{{ mc.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
</form>
<mat-table
#table
cdkDropList
[dataSource]="dataSource()"
[cdkDropListData]="dataSource()"
aria-label="Elements"
(cdkDropListDropped)="dropTable($event)"
>
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row">
<ul>
@for (sku of row.skus; track sku) {
<li>
<a [routerLink]="['/products', row.id]">{{ row.name }} ({{ sku.units }})</a>
</li>
}
</ul>
</mat-cell>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row">
<ul>
@for (sku of row.skus; track sku) {
<li>
<a [routerLink]="['/products', row.id]">{{ row.name }} ({{ sku.units }})</a>
</li>
}
</ul>
</mat-cell>
</ng-container>
<!-- Price Column -->
<ng-container matColumnDef="price">
<mat-header-cell *matHeaderCellDef class="right">Price</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">
<ul>
@for (sku of row.skus; track sku) {
<li>
{{ sku.salePrice | currency: 'INR' }}
</li>
}
</ul>
</mat-cell>
</ng-container>
<!-- Price Column -->
<ng-container matColumnDef="price">
<mat-header-cell *matHeaderCellDef class="right">Price</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">
<ul>
@for (sku of row.skus; track sku) {
<li>
{{ sku.salePrice | currency: 'INR' }}
</li>
}
</ul>
</mat-cell>
</ng-container>
<!-- Menu Category Column -->
<ng-container matColumnDef="menuCategory">
<mat-header-cell *matHeaderCellDef>Menu Category</mat-header-cell>
<mat-cell *matCellDef="let row">
<ul>
@for (sku of row.skus; track sku) {
<li>
{{ sku.menuCategory.name }}
</li>
}
</ul>
</mat-cell>
</ng-container>
<!-- Menu Category Column -->
<ng-container matColumnDef="menuCategory">
<mat-header-cell *matHeaderCellDef>Menu Category</mat-header-cell>
<mat-cell *matCellDef="let row">
<ul>
@for (sku of row.skus; track sku) {
<li>
{{ sku.menuCategory.name }}
</li>
}
</ul>
</mat-cell>
</ng-container>
<!-- Sale Category Column -->
<ng-container matColumnDef="saleCategory">
<mat-header-cell *matHeaderCellDef>Sale Category</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.saleCategory.name }}</mat-cell>
</ng-container>
<!-- Sale Category Column -->
<ng-container matColumnDef="saleCategory">
<mat-header-cell *matHeaderCellDef>Sale Category</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.saleCategory.name }}</mat-cell>
</ng-container>
<!-- Info Column -->
<ng-container matColumnDef="info">
<mat-header-cell *matHeaderCellDef>Details</mat-header-cell>
<mat-cell *matCellDef="let row">
<ul>
@for (sku of row.skus; track sku) {
<li layout="row">
<div>
<mat-icon>
{{ sku.hasHappyHour ? 'sentiment_satisfied_alt' : 'sentiment_dissatisfied' }}
</mat-icon>
<b> {{ sku.hasHappyHour ? 'Happy Hour' : 'Regular' }}</b>
</div>
<div>
<mat-icon>
{{ row.isNotAvailable ? 'pause' : 'play_arrow' }}
</mat-icon>
<b> {{ row.isNotAvailable ? 'Not Available' : 'Available' }}</b>
</div>
</li>
}
</ul>
</mat-cell>
</ng-container>
<!-- Info Column -->
<ng-container matColumnDef="info">
<mat-header-cell *matHeaderCellDef>Details</mat-header-cell>
<mat-cell *matCellDef="let row">
<ul>
@for (sku of row.skus; track sku) {
<li layout="row">
<div>
<mat-icon>
{{ sku.hasHappyHour ? 'sentiment_satisfied_alt' : 'sentiment_dissatisfied' }}
</mat-icon>
<b> {{ sku.hasHappyHour ? 'Happy Hour' : 'Regular' }}</b>
</div>
<div>
<mat-icon>
{{ row.isNotAvailable ? 'pause' : 'play_arrow' }}
</mat-icon>
<b> {{ row.isNotAvailable ? 'Not Available' : 'Available' }}</b>
</div>
</li>
}
</ul>
</mat-cell>
</ng-container>
<!-- Quantity Column -->
<ng-container matColumnDef="quantity">
<mat-header-cell *matHeaderCellDef class="right">Quantity</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">
<ul>
@for (sku of row.skus; track sku) {
<li>{{ sku.fraction | number: '1.2-2' }}{{ row.fractionUnits }}</li>
}
</ul>
</mat-cell>
</ng-container>
<!-- Quantity Column -->
<ng-container matColumnDef="quantity">
<mat-header-cell *matHeaderCellDef class="right">Quantity</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">
<ul>
@for (sku of row.skus; track sku) {
<li>{{ sku.fraction | number: '1.2-2' }}{{ row.fractionUnits }}</li>
}
</ul>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns" cdkDrag [cdkDragData]="row"></mat-row>
</mat-table>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns" cdkDrag [cdkDragData]="row"></mat-row>
</mat-table>
}
@@ -15,6 +15,8 @@ import { firstValueFrom } from 'rxjs';
import { Product } from '../../core/product';
import { MenuCategoryService } from '../../menu-category/menu-category.service';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { ToCsvService } from '../../shared/to-csv.service';
import { ProductService } from '../product.service';
@@ -40,6 +42,8 @@ export interface ProductListFormData {
MatTableModule,
FormField,
RouterModule,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class ProductListComponent {
@@ -59,7 +63,7 @@ export class ProductListComponent {
form = form(this.formModel);
menuCategoryFilter = computed(() => this.formModel().menuCategory ?? '');
menuCategoryFilter = computed(() => this.formModel().menuCategory ?? null);
filterSignal = computed(() => this.formModel().filter);
debouncedFilter = debounced(this.filterSignal, 150);
+1 -1
View File
@@ -63,7 +63,7 @@ export class ProductService {
.pipe(catchError(this.log.handleError(serviceName, 'update'))) as Observable<void>;
}
updateSortOrder(menuCategoryId: string, list: Product[]): Observable<Product[]> {
updateSortOrder(menuCategoryId: string | null, list: Product[]): Observable<Product[]> {
return this.http
.post<Product[]>(`${url}/list/${menuCategoryId}`, list, httpOptions)
.pipe(catchError(this.log.handleError(serviceName, 'updateSortOrder'))) as Observable<Product[]>;
@@ -1,32 +1,38 @@
<h2>Regime</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" (keyup.enter)="save()" />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Header</mat-label>
<textarea matInput [formField]="form.header"></textarea>
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Prefix</mat-label>
<input matInput [formField]="form.prefix" />
</mat-form-field>
</div>
</form>
@if (itemResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (itemResource.error()) {
<app-error-state (retryAction)="itemResource.reload()" />
} @else {
<h2>Regime</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" (keyup.enter)="save()" />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Header</mat-label>
<textarea matInput [formField]="form.header"></textarea>
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Prefix</mat-label>
<input matInput [formField]="form.prefix" />
</mat-form-field>
</div>
</form>
<div class="row-container">
<button type="button" mat-raised-button [disabled]="item().isFixture" color="primary" class="" (click)="save()">
Save
</button>
@if (!!item().id) {
<button type="button" mat-raised-button [disabled]="item().isFixture" color="warn" (click)="confirmDelete()">
Delete
<div class="row-container">
<button type="button" mat-raised-button [disabled]="item().isFixture" color="primary" class="" (click)="save()">
Save
</button>
}
</div>
@if (!!item().id) {
<button type="button" mat-raised-button [disabled]="item().isFixture" color="warn" (click)="confirmDelete()">
Delete
</button>
}
</div>
}
@@ -9,6 +9,8 @@ import { Router } from '@angular/router';
import { Regime } from '../../core/regime';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { RegimeService } from '../regime.service';
export interface RegimeDetailFormData {
@@ -21,7 +23,14 @@ export interface RegimeDetailFormData {
selector: 'app-regime-detail',
templateUrl: './regime-detail.component.html',
styleUrls: ['./regime-detail.component.css'],
imports: [MatButtonModule, MatFormFieldModule, MatInputModule, FormField],
imports: [
MatButtonModule,
MatFormFieldModule,
MatInputModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class RegimeDetailComponent {
private router = inject(Router);
@@ -1,37 +1,43 @@
<h2 class="row-container space-between">
<span>Regimes</span>
<a mat-button [routerLink]="['/regimes', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/regimes', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
@if (listResource.isLoading()) {
<app-skeleton-loader type="table" [count]="5" />
} @else if (listResource.error()) {
<app-error-state (retryAction)="listResource.reload()" />
} @else {
<h2 class="row-container space-between">
<span>Regimes</span>
<a mat-button [routerLink]="['/regimes', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/regimes', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
<!-- Header Column -->
<ng-container matColumnDef="header">
<mat-header-cell *matHeaderCellDef>Header</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.header }}</mat-cell>
</ng-container>
<!-- Header Column -->
<ng-container matColumnDef="header">
<mat-header-cell *matHeaderCellDef>Header</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.header }}</mat-cell>
</ng-container>
<!-- Prefix Column -->
<ng-container matColumnDef="prefix">
<mat-header-cell *matHeaderCellDef>Prefix</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.prefix }}</mat-cell>
</ng-container>
<!-- Prefix Column -->
<ng-container matColumnDef="prefix">
<mat-header-cell *matHeaderCellDef>Prefix</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.prefix }}</mat-cell>
</ng-container>
<!-- Is Fixture Column -->
<ng-container matColumnDef="isFixture">
<mat-header-cell *matHeaderCellDef>Is Fixture?</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.isFixture }}</mat-cell>
</ng-container>
<!-- Is Fixture Column -->
<ng-container matColumnDef="isFixture">
<mat-header-cell *matHeaderCellDef>Is Fixture?</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.isFixture }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
}
@@ -4,12 +4,14 @@ import { MatIconModule } from '@angular/material/icon';
import { MatTableModule } from '@angular/material/table';
import { RouterLink } from '@angular/router';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { RegimeService } from '../regime.service';
@Component({
selector: 'app-regime-list',
templateUrl: './regime-list.component.html',
styleUrls: ['./regime-list.component.css'],
imports: [MatButtonModule, MatIconModule, MatTableModule, RouterLink],
imports: [MatButtonModule, MatIconModule, MatTableModule, RouterLink, ErrorStateComponent, SkeletonLoaderComponent],
})
export class RegimeListComponent {
private regimeService = inject(RegimeService);
@@ -1,39 +1,45 @@
<h2>Role</h2>
<form class="flex-col">
@if (itemResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (itemResource.error()) {
<app-error-state (retryAction)="itemResource.reload()" />
} @else {
<h2>Role</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
</div>
<div class="two-col">
<div class="col">
<h3>Permissions</h3>
@for (p of form.permissions; track p; let i = $index) {
<div class="row-container">
<mat-checkbox
[formField]="p.enabled"
[disabled]="impliedPermissions().has(p.id().value())"
class="flex-auto"
>{{ p.name().value() }}</mat-checkbox
>
</div>
}
</div>
<div class="col">
<h3>Includes Roles</h3>
@for (r of form.includedRoles; track r; let i = $index) {
<div class="row-container">
<mat-checkbox [formField]="r.enabled" class="flex-auto">{{ r.name().value() }}</mat-checkbox>
</div>
}
</div>
</div>
</form>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
<button type="button" mat-raised-button color="primary" class="" (click)="save()">Save</button>
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
</div>
<div class="two-col">
<div class="col">
<h3>Permissions</h3>
@for (p of form.permissions; track p; let i = $index) {
<div class="row-container">
<mat-checkbox
[formField]="p.enabled"
[disabled]="impliedPermissions().has(p.id().value())"
class="flex-auto"
>{{ p.name().value() }}</mat-checkbox
>
</div>
}
</div>
<div class="col">
<h3>Includes Roles</h3>
@for (r of form.includedRoles; track r; let i = $index) {
<div class="row-container">
<mat-checkbox [formField]="r.enabled" class="flex-auto">{{ r.name().value() }}</mat-checkbox>
</div>
}
</div>
</div>
</form>
<div class="row-container">
<button type="button" mat-raised-button color="primary" class="" (click)="save()">Save</button>
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
</div>
}
@@ -9,6 +9,8 @@ import { MatSnackBar } from '@angular/material/snack-bar';
import { Router } from '@angular/router';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { Role } from '../role';
import { RoleService } from '../role.service';
@@ -22,7 +24,15 @@ export interface RoleDetailFormData {
selector: 'app-role-detail',
templateUrl: './role-detail.component.html',
styleUrls: ['./role-detail.component.css'],
imports: [MatButtonModule, MatCheckboxModule, MatFormFieldModule, MatInputModule, FormField],
imports: [
MatButtonModule,
MatCheckboxModule,
MatFormFieldModule,
MatInputModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class RoleDetailComponent {
private router = inject(Router);
@@ -1,47 +1,53 @@
<h2 class="row-container space-between">
<span>Roles</span>
<a mat-button [routerLink]="['/roles', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/roles', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
@if (listResource.isLoading()) {
<app-skeleton-loader type="table" [count]="5" />
} @else if (listResource.error()) {
<app-error-state (retryAction)="listResource.reload()" />
} @else {
<h2 class="row-container space-between">
<span>Roles</span>
<a mat-button [routerLink]="['/roles', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/roles', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
<!-- Included Roles Column (NEW) -->
<ng-container matColumnDef="includedRoles">
<mat-header-cell *matHeaderCellDef>Includes</mat-header-cell>
<mat-cell *matCellDef="let row">
@if (row.includedRoles?.length) {
<!-- Included Roles Column (NEW) -->
<ng-container matColumnDef="includedRoles">
<mat-header-cell *matHeaderCellDef>Includes</mat-header-cell>
<mat-cell *matCellDef="let row">
@if (row.includedRoles?.length) {
<ul>
@for (r of row.includedRoles; track r) {
<li>{{ r }}</li>
}
</ul>
} @else {
<span>-</span>
}
</mat-cell>
</ng-container>
<!-- Permissions Column -->
<ng-container matColumnDef="permissions">
<mat-header-cell *matHeaderCellDef>Permissions</mat-header-cell>
<mat-cell *matCellDef="let row">
<ul>
@for (r of row.includedRoles; track r) {
<li>{{ r }}</li>
@for (permission of row.permissions; track permission) {
<li>{{ permission }}</li>
}
</ul>
} @else {
<span>-</span>
}
</mat-cell>
</ng-container>
</mat-cell>
</ng-container>
<!-- Permissions Column -->
<ng-container matColumnDef="permissions">
<mat-header-cell *matHeaderCellDef>Permissions</mat-header-cell>
<mat-cell *matCellDef="let row">
<ul>
@for (permission of row.permissions; track permission) {
<li>{{ permission }}</li>
}
</ul>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
}
@@ -4,12 +4,14 @@ import { MatIconModule } from '@angular/material/icon';
import { MatTableModule } from '@angular/material/table';
import { RouterLink } from '@angular/router';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { RoleService } from '../role.service';
@Component({
selector: 'app-role-list',
templateUrl: './role-list.component.html',
styleUrls: ['./role-list.component.css'],
imports: [MatButtonModule, MatIconModule, MatTableModule, RouterLink],
imports: [MatButtonModule, MatIconModule, MatTableModule, RouterLink, ErrorStateComponent, SkeletonLoaderComponent],
})
export class RoleListComponent {
private roleService = inject(RoleService);
@@ -1,61 +1,67 @@
<h2>Sale Category</h2>
<form class="flex-col">
@if (itemResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (itemResource.error()) {
<app-error-state (retryAction)="itemResource.reload()" />
} @else {
<h2>Sale Category</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Discount Limit</mat-label>
<input matInput type="number" [formField]="form.discountLimit" class="right-align" />
<span matTextSuffix>%</span>
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Tax</mat-label>
<mat-select [formField]="form.tax">
@for (t of taxes(); track t) {
<mat-option [value]="t.id">
{{ t.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
</form>
<mat-divider></mat-divider>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
<button type="button" mat-raised-button color="primary" class="" (click)="save()">Save</button>
@if (!!item().id) {
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
}
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Discount Limit</mat-label>
<input matInput type="number" [formField]="form.discountLimit" class="right-align" />
<span matTextSuffix>%</span>
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Tax</mat-label>
<mat-select [formField]="form.tax">
@for (t of taxes(); track t) {
<mat-option [value]="t.id">
{{ t.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
</form>
<mat-divider></mat-divider>
<div class="row-container">
<button type="button" mat-raised-button color="primary" class="" (click)="save()">Save</button>
@if (!!item().id) {
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
}
</div>
<h2>Products</h2>
<mat-table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/products', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
<h2>Products</h2>
<mat-table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/products', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
<!-- Price Column -->
<ng-container matColumnDef="price">
<mat-header-cell *matHeaderCellDef class="right">Price</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.price | currency: 'INR' }}</mat-cell>
</ng-container>
<!-- Price Column -->
<ng-container matColumnDef="price">
<mat-header-cell *matHeaderCellDef class="right">Price</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.price | currency: 'INR' }}</mat-cell>
</ng-container>
<!-- Menu Category Column -->
<ng-container matColumnDef="menuCategory">
<mat-header-cell *matHeaderCellDef>Menu Category</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.menuCategory.name }}</mat-cell>
</ng-container>
<!-- Menu Category Column -->
<ng-container matColumnDef="menuCategory">
<mat-header-cell *matHeaderCellDef>Menu Category</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.menuCategory.name }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
}
@@ -17,6 +17,8 @@ import { SaleCategory } from '../../core/sale-category';
import { Tax } from '../../core/tax';
import { ProductService } from '../../product/product.service';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { TaxService } from '../../taxes/tax.service';
import { SaleCategoryService } from '../sale-category.service';
@@ -41,6 +43,8 @@ export interface SaleCategoryDetailFormData {
MatTableModule,
FormField,
RouterLink,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class SaleCategoryDetailComponent {
@@ -1,31 +1,37 @@
<h2 class="row-container space-between">
<span>Sale Categories</span>
<a mat-button [routerLink]="['/sale-categories', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/sale-categories', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
@if (listResource.isLoading()) {
<app-skeleton-loader type="table" [count]="5" />
} @else if (listResource.error()) {
<app-error-state (retryAction)="listResource.reload()" />
} @else {
<h2 class="row-container space-between">
<span>Sale Categories</span>
<a mat-button [routerLink]="['/sale-categories', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/sale-categories', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
<!-- Discount Limit Column -->
<ng-container matColumnDef="discountLimit">
<mat-header-cell *matHeaderCellDef>Discount Limit</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.discountLimit | percent: '1.2-2' }}</mat-cell>
</ng-container>
<!-- Discount Limit Column -->
<ng-container matColumnDef="discountLimit">
<mat-header-cell *matHeaderCellDef>Discount Limit</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.discountLimit | percent: '1.2-2' }}</mat-cell>
</ng-container>
<!-- Tax Column -->
<ng-container matColumnDef="tax">
<mat-header-cell *matHeaderCellDef>Tax</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.tax.rate | percent: '1.2-2' }} {{ row.tax.name }}</mat-cell>
</ng-container>
<!-- Tax Column -->
<ng-container matColumnDef="tax">
<mat-header-cell *matHeaderCellDef>Tax</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.tax.rate | percent: '1.2-2' }} {{ row.tax.name }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
}
@@ -5,12 +5,22 @@ import { MatIconModule } from '@angular/material/icon';
import { MatTableModule } from '@angular/material/table';
import { RouterLink } from '@angular/router';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { SaleCategoryService } from '../sale-category.service';
@Component({
selector: 'app-sale-category-list',
templateUrl: './sale-category-list.component.html',
styleUrls: ['./sale-category-list.component.css'],
imports: [MatButtonModule, MatIconModule, MatTableModule, PercentPipe, RouterLink],
imports: [
MatButtonModule,
MatIconModule,
MatTableModule,
PercentPipe,
RouterLink,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class SaleCategoryListComponent {
private ser = inject(SaleCategoryService);
@@ -1,66 +1,72 @@
<h2 class="row-container space-between">
<span>Sale Report</span>
<span class="spacer"></span>
<button type="button" mat-icon-button (click)="exportCsv()">
<mat-icon>save_alt</mat-icon>
</button>
<button type="button" mat-icon-button (click)="print()">
<mat-icon>print</mat-icon>
</button>
</h2>
@if (infoResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (infoResource.error()) {
<app-error-state (retryAction)="infoResource.reload()" />
} @else {
<h2 class="row-container space-between">
<span>Sale Report</span>
<span class="spacer"></span>
<button type="button" mat-icon-button (click)="exportCsv()">
<mat-icon>save_alt</mat-icon>
</button>
<button type="button" mat-icon-button (click)="print()">
<mat-icon>print</mat-icon>
</button>
</h2>
<form class="flex-col">
<div class="row-container sm:max-lg:flex-col">
<mat-form-field class="flex-auto basis-1-3">
<mat-label>Start Date</mat-label>
<input
matInput
[matDatepicker]="startDate"
(focus)="startDate.open()"
[formField]="form.startDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
<mat-datepicker #startDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto basis-1-3">
<mat-label>Finish Date</mat-label>
<input
matInput
[matDatepicker]="finishDate"
(focus)="finishDate.open()"
[formField]="form.finishDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto basis-1-6">
<mat-label>Section</mat-label>
<mat-select [formField]="form.section">
<mat-option>-- All --</mat-option>
@for (p of sections(); track p.id) {
<mat-option [value]="p.id">
{{ p.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
<button type="button" mat-raised-button class="flex-auto basis-1-6" color="primary" (click)="show()">Show</button>
</div>
</form>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.name }}</mat-cell>
</ng-container>
<form class="flex-col">
<div class="row-container sm:max-lg:flex-col">
<mat-form-field class="flex-auto basis-1-3">
<mat-label>Start Date</mat-label>
<input
matInput
[matDatepicker]="startDate"
(focus)="startDate.open()"
[formField]="form.startDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
<mat-datepicker #startDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto basis-1-3">
<mat-label>Finish Date</mat-label>
<input
matInput
[matDatepicker]="finishDate"
(focus)="finishDate.open()"
[formField]="form.finishDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto basis-1-6">
<mat-label>Section</mat-label>
<mat-select [formField]="form.section">
<mat-option [value]="null">-- All --</mat-option>
@for (p of sections(); track p.id) {
<mat-option [value]="p.id">
{{ p.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
<button type="button" mat-raised-button class="flex-auto basis-1-6" color="primary" (click)="show()">Show</button>
</div>
</form>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.name }}</mat-cell>
</ng-container>
<!-- Amount Column -->
<ng-container matColumnDef="amount">
<mat-header-cell *matHeaderCellDef class="right">Amount</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.amount | currency: 'INR' }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<!-- Amount Column -->
<ng-container matColumnDef="amount">
<mat-header-cell *matHeaderCellDef class="right">Amount</mat-header-cell>
<mat-cell *matCellDef="let row" class="right">{{ row.amount | currency: 'INR' }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
}
@@ -14,6 +14,8 @@ import { Router } from '@angular/router';
import moment from 'moment';
import { SectionService } from '../sections/section.service';
import { ErrorStateComponent } from '../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../shared/skeleton-loader/skeleton-loader.component';
import { ToCsvService } from '../shared/to-csv.service';
import { SaleReport } from './sale-report';
import { SaleReportService } from './sale-report.service';
@@ -39,6 +41,8 @@ export interface SaleReportFormData {
MatSelectModule,
MatTableModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class SaleReportComponent {
+221 -197
View File
@@ -1,207 +1,231 @@
<h2>Bill</h2>
<table mat-table #table [dataSource]="dataSource()" class="mat-elevation-z8" [trackBy]="trackByRow">
<ng-container matColumnDef="bill-no-title">
<mat-header-cell *matHeaderCellDef class="deep-purple-200 bold">Bill / KOT number</mat-header-cell>
</ng-container>
<ng-container matColumnDef="bill-no-details">
<mat-header-cell *matHeaderCellDef class="deep-purple-200 bold right-align"
>{{ bs.bill().billId }} / K-{{ bs.bill().kotId }}</mat-header-cell
>
</ng-container>
<ng-container matColumnDef="time-title">
<mat-header-cell *matHeaderCellDef class="deep-purple-100 bold"
>Time / Start Time / Last Edit Time
</mat-header-cell>
</ng-container>
<ng-container matColumnDef="time-details">
<mat-header-cell *matHeaderCellDef class="deep-purple-100 bold right-align"
><span [matTooltip]="bs.bill().dateTip">{{ bs.bill().date }}</span
>&nbsp;/&nbsp;<span [matTooltip]="bs.bill().creationDateTip">{{ bs.bill().creationDate }}</span
>&nbsp;/&nbsp;<span [matTooltip]="bs.bill().lastEditDateTip">{{ bs.bill().lastEditDate }}</span></mat-header-cell
>
</ng-container>
<ng-container matColumnDef="table-title">
<mat-header-cell *matHeaderCellDef class="deep-purple-50 bold">Table / Pax / Customer</mat-header-cell>
</ng-container>
<ng-container matColumnDef="table-details">
<mat-header-cell *matHeaderCellDef class="deep-purple-50 bold right-align"
><button>Table: {{ bs.bill().table.name }}</button> /
<button type="button" mat-button (click)="choosePax()">{{ bs.bill().pax }} Pax</button> /
<button type="button" mat-button (click)="chooseCustomer()">
{{ bs.bill().customer?.name ?? 'Customer' }}
</button></mat-header-cell
>
</ng-container>
@if (billResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (billResource.error()) {
<app-error-state (retryAction)="billResource.reload()" />
} @else {
<h2>Bill</h2>
<table mat-table #table [dataSource]="dataSource()" class="mat-elevation-z8" [trackBy]="trackByRow">
<ng-container matColumnDef="bill-no-title">
<mat-header-cell *matHeaderCellDef class="deep-purple-200 bold">Bill / KOT number</mat-header-cell>
</ng-container>
<ng-container matColumnDef="bill-no-details">
<mat-header-cell *matHeaderCellDef class="deep-purple-200 bold right-align"
>{{ bs.bill().billId }} / K-{{ bs.bill().kotId }}</mat-header-cell
>
</ng-container>
<ng-container matColumnDef="time-title">
<mat-header-cell *matHeaderCellDef class="deep-purple-100 bold"
>Time / Start Time / Last Edit Time
</mat-header-cell>
</ng-container>
<ng-container matColumnDef="time-details">
<mat-header-cell *matHeaderCellDef class="deep-purple-100 bold right-align"
><span [matTooltip]="bs.bill().dateTip">{{ bs.bill().date }}</span
>&nbsp;/&nbsp;<span [matTooltip]="bs.bill().creationDateTip">{{ bs.bill().creationDate }}</span
>&nbsp;/&nbsp;<span [matTooltip]="bs.bill().lastEditDateTip">{{
bs.bill().lastEditDate
}}</span></mat-header-cell
>
</ng-container>
<ng-container matColumnDef="table-title">
<mat-header-cell *matHeaderCellDef class="deep-purple-50 bold">Table / Pax / Customer</mat-header-cell>
</ng-container>
<ng-container matColumnDef="table-details">
<mat-header-cell *matHeaderCellDef class="deep-purple-50 bold right-align"
><button>Table: {{ bs.bill().table.name }}</button> /
<button type="button" mat-button (click)="choosePax()">{{ bs.bill().pax }} Pax</button> /
<button type="button" mat-button (click)="chooseCustomer()">
{{ bs.bill().customer?.name ?? 'Customer' }}
</button></mat-header-cell
>
</ng-container>
<!-- Checkbox Column -->
<ng-container matColumnDef="selectKot">
<mat-cell *matCellDef="let row">
@if (row.id) {
<!-- Checkbox Column -->
<ng-container matColumnDef="selectKot">
<mat-cell *matCellDef="let row">
@if (row.id) {
<mat-checkbox
(change)="$event ? masterToggle(row) : null"
[checked]="bs.selection.hasValue() && isAllSelected(row)"
[indeterminate]="isAnySelected(row)"
>
</mat-checkbox>
}
</mat-cell>
</ng-container>
<ng-container matColumnDef="selectInv">
<mat-cell *matCellDef="let row">
<mat-checkbox
(change)="$event ? masterToggle(row) : null"
[checked]="bs.selection.hasValue() && isAllSelected(row)"
[indeterminate]="isAnySelected(row)"
[disabled]="!row.id"
(click)="$event.stopPropagation()"
(change)="$event ? toggle(row) : null"
[checked]="isSelected(row)"
>
</mat-checkbox>
}
</mat-cell>
</ng-container>
<ng-container matColumnDef="selectInv">
<mat-cell *matCellDef="let row">
<mat-checkbox
[disabled]="!row.id"
(click)="$event.stopPropagation()"
(change)="$event ? toggle(row) : null"
[checked]="isSelected(row)"
>
</mat-checkbox>
</mat-cell>
</ng-container>
<ng-container matColumnDef="selectChild">
<mat-cell *matCellDef="let row"> </mat-cell>
</ng-container>
<!-- Info Column -->
<ng-container matColumnDef="infoKot">
<mat-cell *matCellDef="let row">
<span>{{ row.id ? `Kot: ${row.kot.code} / ${row.kot.date} (${row.kot.user.name})` : '== New Kot ==' }}</span>
</mat-cell>
</ng-container>
<ng-container matColumnDef="infoInv">
<mat-cell *matCellDef="let row">
<span>{{ `${row.inv.sku.name} @ ${row.inv.price} - ${discountPct(row.inv)}%` }}</span>
<ul>
@for (m of row.inv.modifiers; track m.id) {
<li>{{ m.name }}</li>
}
</ul>
</mat-cell>
</ng-container>
<ng-container matColumnDef="infoChild">
<mat-cell *matCellDef="let row" class="child-product">
<span>{{ `${row.inv.sku.name} @ ${row.inv.price} - ${discountPct(row.inv)}%` }}</span>
<ul>
@for (m of row.inv.modifiers; track m.id) {
<li>{{ m.name }}</li>
}
</ul>
</mat-cell>
</ng-container>
<!-- Quantity Column -->
<ng-container matColumnDef="kotActions">
<mat-header-cell *matHeaderCellDef>Quantity</mat-header-cell>
<mat-cell *matCellDef="let row" class="right-align">
<button type="button" mat-icon-button (click)="moveKot(row)" [disabled]="!row.kot.id">
<mat-icon class="del">open_in_new</mat-icon>
</button>
</mat-cell>
</ng-container>
<ng-container matColumnDef="quantity">
<mat-header-cell *matHeaderCellDef>Quantity</mat-header-cell>
<mat-cell *matCellDef="let row" class="right-align">
<button
type="button"
mat-icon-button
class="small-icon-button"
(click)="subtractOne(row)"
[disabled]="!!row.kot.id"
>
<mat-icon>indeterminate_check_box</mat-icon>
</button>
<button
type="button"
mat-icon-button
class="small-icon-button"
(click)="quantity(row)"
[disabled]="rowQuantityDisabled(row)"
>
{{ row.inv.quantity }}
</button>
<button type="button" mat-icon-button class="small-icon-button" (click)="addOne(row)" [disabled]="!!row.kot.id">
<mat-icon>control_point</mat-icon>
</button>
<button type="button" mat-icon-button class="small-icon-button" (click)="modifier(row)" [disabled]="!!row.kot.id">
<mat-icon>assignment</mat-icon>
</button>
</mat-cell>
</ng-container>
<ng-container matColumnDef="childQuantity">
<mat-header-cell *matHeaderCellDef>Quantity</mat-header-cell>
<mat-cell *matCellDef="let row" class="right-align">
<span mat-icon-button class="small-icon-button"> </span>
<button type="button" mat-icon-button class="small-icon-button" (click)="quantity(row)" [disabled]="true">
{{ row.inv.quantity }}
</button>
<span mat-icon-button class="small-icon-button"> </span>
<button type="button" mat-icon-button class="small-icon-button" (click)="modifier(row)" [disabled]="!!row.kot.id">
<mat-icon>assignment</mat-icon>
</button>
</mat-cell>
</ng-container>
</mat-cell>
</ng-container>
<ng-container matColumnDef="selectChild">
<mat-cell *matCellDef="let row"> </mat-cell>
</ng-container>
<!-- Info Column -->
<ng-container matColumnDef="infoKot">
<mat-cell *matCellDef="let row">
<span>{{ row.id ? `Kot: ${row.kot.code} / ${row.kot.date} (${row.kot.user.name})` : '== New Kot ==' }}</span>
</mat-cell>
</ng-container>
<ng-container matColumnDef="infoInv">
<mat-cell *matCellDef="let row">
<span>{{ `${row.inv.sku.name} @ ${row.inv.price} - ${discountPct(row.inv)}%` }}</span>
<ul>
@for (m of row.inv.modifiers; track m.id) {
<li>{{ m.name }}</li>
}
</ul>
</mat-cell>
</ng-container>
<ng-container matColumnDef="infoChild">
<mat-cell *matCellDef="let row" class="child-product">
<span>{{ `${row.inv.sku.name} @ ${row.inv.price} - ${discountPct(row.inv)}%` }}</span>
<ul>
@for (m of row.inv.modifiers; track m.id) {
<li>{{ m.name }}</li>
}
</ul>
</mat-cell>
</ng-container>
<!-- Quantity Column -->
<ng-container matColumnDef="kotActions">
<mat-header-cell *matHeaderCellDef>Quantity</mat-header-cell>
<mat-cell *matCellDef="let row" class="right-align">
<button type="button" mat-icon-button (click)="moveKot(row)" [disabled]="!row.kot.id">
<mat-icon class="del">open_in_new</mat-icon>
</button>
</mat-cell>
</ng-container>
<ng-container matColumnDef="quantity">
<mat-header-cell *matHeaderCellDef>Quantity</mat-header-cell>
<mat-cell *matCellDef="let row" class="right-align">
<button
type="button"
mat-icon-button
class="small-icon-button"
(click)="subtractOne(row)"
[disabled]="!!row.kot.id"
>
<mat-icon>indeterminate_check_box</mat-icon>
</button>
<button
type="button"
mat-icon-button
class="small-icon-button"
(click)="quantity(row)"
[disabled]="rowQuantityDisabled(row)"
>
{{ row.inv.quantity }}
</button>
<button type="button" mat-icon-button class="small-icon-button" (click)="addOne(row)" [disabled]="!!row.kot.id">
<mat-icon>control_point</mat-icon>
</button>
<button
type="button"
mat-icon-button
class="small-icon-button"
(click)="modifier(row)"
[disabled]="!!row.kot.id"
>
<mat-icon>assignment</mat-icon>
</button>
</mat-cell>
</ng-container>
<ng-container matColumnDef="childQuantity">
<mat-header-cell *matHeaderCellDef>Quantity</mat-header-cell>
<mat-cell *matCellDef="let row" class="right-align">
<span mat-icon-button class="small-icon-button"> </span>
<button type="button" mat-icon-button class="small-icon-button" (click)="quantity(row)" [disabled]="true">
{{ row.inv.quantity }}
</button>
<span mat-icon-button class="small-icon-button"> </span>
<button
type="button"
mat-icon-button
class="small-icon-button"
(click)="modifier(row)"
[disabled]="!!row.kot.id"
>
<mat-icon>assignment</mat-icon>
</button>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="['bill-no-title', 'bill-no-details']"></mat-header-row>
<mat-header-row *matHeaderRowDef="['time-title', 'time-details']"></mat-header-row>
<mat-header-row *matHeaderRowDef="['table-title', 'table-details']"></mat-header-row>
<mat-row
*matRowDef="let row; columns: kotColumns; when: isKot"
[class.old-kot]="!!row.id"
[class.new-kot]="!row.id"
></mat-row>
<mat-row
*matRowDef="let row; columns: displayedColumns; when: !isKot"
[class.is-printed]="!!row.kot.id && !row.inv.isHappyHour"
[class.hh-new]="!row.kot.id && row.inv.isHappyHour"
[class.hh-printed]="!!row.kot.id && row.inv.isHappyHour"
></mat-row>
<mat-row
*matRowDef="let row; columns: childColumns; when: isChild"
class="child-row"
[class.is-printed]="!!row.kot.id && !row.inv.isHappyHour"
[class.hh-new]="!row.kot.id && row.inv.isHappyHour"
[class.hh-printed]="!!row.kot.id && row.inv.isHappyHour"
></mat-row>
<mat-footer-row *matFooterRowDef="['gross-title', 'gross-amount']"></mat-footer-row>
<ng-container matColumnDef="gross-title">
<mat-footer-cell *matFooterCellDef class="bold">Gross</mat-footer-cell>
</ng-container>
<ng-container matColumnDef="gross-amount">
<mat-footer-cell *matFooterCellDef class="bold right-align">{{
bs.grossAmount() | currency: 'INR'
}}</mat-footer-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="['bill-no-title', 'bill-no-details']"></mat-header-row>
<mat-header-row *matHeaderRowDef="['time-title', 'time-details']"></mat-header-row>
<mat-header-row *matHeaderRowDef="['table-title', 'table-details']"></mat-header-row>
<mat-row
*matRowDef="let row; columns: kotColumns; when: isKot"
[class.old-kot]="!!row.id"
[class.new-kot]="!row.id"
></mat-row>
<mat-row
*matRowDef="let row; columns: displayedColumns; when: !isKot"
[class.is-printed]="!!row.kot.id && !row.inv.isHappyHour"
[class.hh-new]="!row.kot.id && row.inv.isHappyHour"
[class.hh-printed]="!!row.kot.id && row.inv.isHappyHour"
></mat-row>
<mat-row
*matRowDef="let row; columns: childColumns; when: isChild"
class="child-row"
[class.is-printed]="!!row.kot.id && !row.inv.isHappyHour"
[class.hh-new]="!row.kot.id && row.inv.isHappyHour"
[class.hh-printed]="!!row.kot.id && row.inv.isHappyHour"
></mat-row>
<mat-footer-row *matFooterRowDef="['gross-title', 'gross-amount']"></mat-footer-row>
<ng-container matColumnDef="gross-title">
<mat-footer-cell *matFooterCellDef class="bold">Gross</mat-footer-cell>
</ng-container>
<ng-container matColumnDef="gross-amount">
<mat-footer-cell *matFooterCellDef class="bold right-align">{{
bs.grossAmount() | currency: 'INR'
}}</mat-footer-cell>
</ng-container>
<mat-footer-row *matFooterRowDef="['hh-title', 'hh-amount']"></mat-footer-row>
<ng-container matColumnDef="hh-title">
<mat-footer-cell *matFooterCellDef class="bold">Happy Hour Discount</mat-footer-cell>
</ng-container>
<ng-container matColumnDef="hh-amount">
<mat-footer-cell *matFooterCellDef class="bold right-align">{{ bs.hhAmount() | currency: 'INR' }}</mat-footer-cell>
</ng-container>
<mat-footer-row *matFooterRowDef="['hh-title', 'hh-amount']"></mat-footer-row>
<ng-container matColumnDef="hh-title">
<mat-footer-cell *matFooterCellDef class="bold">Happy Hour Discount</mat-footer-cell>
</ng-container>
<ng-container matColumnDef="hh-amount">
<mat-footer-cell *matFooterCellDef class="bold right-align">{{
bs.hhAmount() | currency: 'INR'
}}</mat-footer-cell>
</ng-container>
<mat-footer-row *matFooterRowDef="['discount-title', 'discount-amount']"></mat-footer-row>
<ng-container matColumnDef="discount-title">
<mat-footer-cell *matFooterCellDef class="bold">Discount</mat-footer-cell>
</ng-container>
<ng-container matColumnDef="discount-amount">
<mat-footer-cell *matFooterCellDef class="bold right-align">{{
bs.discountAmount() | currency: 'INR'
}}</mat-footer-cell>
</ng-container>
<mat-footer-row *matFooterRowDef="['discount-title', 'discount-amount']"></mat-footer-row>
<ng-container matColumnDef="discount-title">
<mat-footer-cell *matFooterCellDef class="bold">Discount</mat-footer-cell>
</ng-container>
<ng-container matColumnDef="discount-amount">
<mat-footer-cell *matFooterCellDef class="bold right-align">{{
bs.discountAmount() | currency: 'INR'
}}</mat-footer-cell>
</ng-container>
<mat-footer-row *matFooterRowDef="['tax-title', 'tax-amount']"></mat-footer-row>
<ng-container matColumnDef="tax-title">
<mat-footer-cell *matFooterCellDef class="bold">Tax</mat-footer-cell>
</ng-container>
<ng-container matColumnDef="tax-amount">
<mat-footer-cell *matFooterCellDef class="bold right-align">{{ bs.taxAmount() | currency: 'INR' }}</mat-footer-cell>
</ng-container>
<mat-footer-row *matFooterRowDef="['tax-title', 'tax-amount']"></mat-footer-row>
<ng-container matColumnDef="tax-title">
<mat-footer-cell *matFooterCellDef class="bold">Tax</mat-footer-cell>
</ng-container>
<ng-container matColumnDef="tax-amount">
<mat-footer-cell *matFooterCellDef class="bold right-align">{{
bs.taxAmount() | currency: 'INR'
}}</mat-footer-cell>
</ng-container>
<mat-footer-row *matFooterRowDef="['amount-title', 'amount-amount']"></mat-footer-row>
<ng-container matColumnDef="amount-title">
<mat-footer-cell *matFooterCellDef>Amount</mat-footer-cell>
</ng-container>
<ng-container matColumnDef="amount-amount">
<mat-footer-cell *matFooterCellDef class="bold right-align">{{ bs.amount() | currency: 'INR' }}</mat-footer-cell>
</ng-container>
</table>
<mat-footer-row *matFooterRowDef="['amount-title', 'amount-amount']"></mat-footer-row>
<ng-container matColumnDef="amount-title">
<mat-footer-cell *matFooterCellDef>Amount</mat-footer-cell>
</ng-container>
<ng-container matColumnDef="amount-amount">
<mat-footer-cell *matFooterCellDef class="bold right-align">{{ bs.amount() | currency: 'INR' }}</mat-footer-cell>
</ng-container>
</table>
<router-outlet></router-outlet>
<router-outlet></router-outlet>
}
+14 -6
View File
@@ -1,5 +1,5 @@
import { CommonModule, CurrencyPipe } from '@angular/common';
import { Component, OnDestroy, OnInit, Signal, computed, effect, inject, input } from '@angular/core';
import { Component, OnDestroy, Signal, computed, effect, inject, input, untracked } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatDialog } from '@angular/material/dialog';
@@ -15,7 +15,9 @@ import { AuthService } from '../../auth/auth.service';
import { Customer } from '../../core/customer';
import { Table } from '../../core/table';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { MathService } from '../../shared/math.service';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { TableService } from '../../tables/table.service';
import { BillService } from '../bill.service';
import { ChooseCustomerComponent } from '../choose-customer/choose-customer.component';
@@ -42,9 +44,11 @@ import { VoucherService } from './voucher.service';
MatTableModule,
MatTooltipModule,
RouterOutlet,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class BillsComponent implements OnInit, OnDestroy {
export class BillsComponent implements OnDestroy {
private router = inject(Router);
private dialog = inject(MatDialog);
private snackBar = inject(MatSnackBar);
@@ -107,10 +111,6 @@ export class BillsComponent implements OnInit, OnDestroy {
displayedColumns: string[] = ['selectInv', 'infoInv', 'quantity'];
childColumns: string[] = ['selectChild', 'infoChild', 'childQuantity'];
ngOnInit() {
this.getPax();
}
ngOnDestroy() {
this.bs.reset();
}
@@ -122,6 +122,8 @@ export class BillsComponent implements OnInit, OnDestroy {
this.choosePax();
}
private paxChecked = false;
choosePax(): void {
const dialogRef = this.dialog.open(PaxComponent, {
// width: '750px',
@@ -320,6 +322,12 @@ export class BillsComponent implements OnInit, OnDestroy {
if (bill) {
this.bs.loadData(bill, this.updateTable());
}
const loading = this.billResource.isLoading() || this.tableResource.isLoading() || this.idResource.isLoading();
if (!loading && bill && !this.paxChecked) {
this.paxChecked = true;
untracked(() => this.getPax());
}
});
}
}
@@ -1,57 +1,63 @@
<h2 mat-dialog-title>Customer</h2>
<mat-dialog-content>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Phone</mat-label>
<input
matInput
type="text"
[formField]="form.phone"
[matAutocomplete]="auto"
autocomplete="off"
cdkFocusInitial
/>
</mat-form-field>
<mat-autocomplete
#auto="matAutocomplete"
autoActiveFirstOption
[displayWith]="displayFn"
(optionSelected)="selected($event)"
>
@for (customer of customers(); track customer) {
<mat-option [value]="customer">{{ customer.name }} - {{ customer.phone }}</mat-option>
}
</mat-autocomplete>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [value]="formModel().name" readonly />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Address</mat-label>
<textarea matInput [value]="formModel().address" readonly> </textarea>
</mat-form-field>
</div>
<div class="row-container">
<mat-checkbox [checked]="formModel().printInBill" [disabled]="true">Print in Bill?</mat-checkbox>
</div>
<p></p>
<div class="discounts">
<ul>
@for (r of formModel().discounts; track r.id) {
@if (r.discount > 0) {
<li>{{ r.name }} - {{ r.discount | percent: '1.2-2' }}</li>
@if (customersResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (customersResource.error()) {
<app-error-state (retryAction)="customersResource.reload()" />
} @else {
<h2 mat-dialog-title>Customer</h2>
<mat-dialog-content>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Phone</mat-label>
<input
matInput
type="text"
[formField]="form.phone"
[matAutocomplete]="auto"
autocomplete="off"
cdkFocusInitial
/>
</mat-form-field>
<mat-autocomplete
#auto="matAutocomplete"
autoActiveFirstOption
[displayWith]="displayFn"
(optionSelected)="selected($event)"
>
@for (customer of customers(); track customer) {
<mat-option [value]="customer">{{ customer.name }} - {{ customer.phone }}</mat-option>
}
}
</ul>
</div>
</form>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button [mat-dialog-close]="false">Cancel</button>
<button type="button" mat-raised-button color="primary" (click)="save()">Select</button>
</mat-dialog-actions>
</mat-autocomplete>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [value]="formModel().name" readonly />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Address</mat-label>
<textarea matInput [value]="formModel().address" readonly> </textarea>
</mat-form-field>
</div>
<div class="row-container">
<mat-checkbox [checked]="formModel().printInBill" [disabled]="true">Print in Bill?</mat-checkbox>
</div>
<p></p>
<div class="discounts">
<ul>
@for (r of formModel().discounts; track r.id) {
@if (r.discount > 0) {
<li>{{ r.name }} - {{ r.discount | percent: '1.2-2' }}</li>
}
}
</ul>
</div>
</form>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button [mat-dialog-close]="false">Cancel</button>
<button type="button" mat-raised-button color="primary" (click)="save()">Select</button>
</mat-dialog-actions>
}
@@ -13,6 +13,8 @@ import { MatInputModule } from '@angular/material/input';
import { Customer } from '../../core/customer';
import { CustomerDiscount } from '../../core/customer-discount';
import { CustomerService } from '../../customers/customer.service';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
export interface ChooseCustomerFormData {
id: string;
@@ -38,6 +40,8 @@ export interface ChooseCustomerFormData {
MatOptionModule,
PercentPipe,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class ChooseCustomerComponent {
@@ -1,76 +1,82 @@
<div class="tables-grid">
<mat-card
class="primary flex-col square-button"
matRipple
[routerLink]="['menu-categories']"
queryParamsHandling="preserve"
>
<h3>Add Product</h3>
</mat-card>
<mat-card
class="flex-col square-button"
matRipple
(click)="discount()"
[class.disabled]="!discountAllowed()"
[class.primary]="discountAllowed()"
>
<h3>Discount</h3>
</mat-card>
<mat-card
class="flex-col square-button"
matRipple
(click)="printKot()"
[class.disabled]="!printKotAllowed()"
[class.primary]="printKotAllowed()"
>
<h3>Print KOT</h3>
</mat-card>
<mat-card
class="flex-col square-button"
matRipple
(click)="printBill()"
[class.disabled]="!printBillAllowed()"
[class.primary]="printBillAllowed()"
>
<h3>Print Bill</h3>
</mat-card>
<mat-card class="flex-col square-button warn" matRipple [routerLink]="['/', 'sales', 'tables']">
<h3>Back to Tables</h3>
</mat-card>
<mat-card
class="flex-col square-button"
matRipple
(click)="receivePayment()"
[class.disabled]="!receivePaymentAllowed()"
[class.primary]="receivePaymentAllowed()"
>
<h3>Receive Payment</h3>
</mat-card>
<mat-card
class="flex-col square-button"
matRipple
(click)="moveTable()"
[class.disabled]="!moveTableAllowed()"
[class.primary]="moveTableAllowed()"
>
<h3>Move Table</h3>
</mat-card>
<mat-card
class="flex-col square-button"
matRipple
(click)="cancelBill()"
[class.disabled]="!cancelBillAllowed()"
[class.primary]="cancelBillAllowed()"
>
<h3>Cancel Bill</h3>
</mat-card>
<mat-card
class="flex-col square-button"
matRipple
(click)="splitBill()"
[class.disabled]="!splitBillAllowed()"
[class.primary]="splitBillAllowed()"
>
<h3>Split Bill</h3>
</mat-card>
</div>
@if (saleCategoriesResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (saleCategoriesResource.error()) {
<app-error-state (retryAction)="saleCategoriesResource.reload()" />
} @else {
<div class="tables-grid">
<mat-card
class="primary flex-col square-button"
matRipple
[routerLink]="['menu-categories']"
queryParamsHandling="preserve"
>
<h3>Add Product</h3>
</mat-card>
<mat-card
class="flex-col square-button"
matRipple
(click)="discount()"
[class.disabled]="!discountAllowed()"
[class.primary]="discountAllowed()"
>
<h3>Discount</h3>
</mat-card>
<mat-card
class="flex-col square-button"
matRipple
(click)="printKot()"
[class.disabled]="!printKotAllowed()"
[class.primary]="printKotAllowed()"
>
<h3>Print KOT</h3>
</mat-card>
<mat-card
class="flex-col square-button"
matRipple
(click)="printBill()"
[class.disabled]="!printBillAllowed()"
[class.primary]="printBillAllowed()"
>
<h3>Print Bill</h3>
</mat-card>
<mat-card class="flex-col square-button warn" matRipple [routerLink]="['/', 'sales', 'tables']">
<h3>Back to Tables</h3>
</mat-card>
<mat-card
class="flex-col square-button"
matRipple
(click)="receivePayment()"
[class.disabled]="!receivePaymentAllowed()"
[class.primary]="receivePaymentAllowed()"
>
<h3>Receive Payment</h3>
</mat-card>
<mat-card
class="flex-col square-button"
matRipple
(click)="moveTable()"
[class.disabled]="!moveTableAllowed()"
[class.primary]="moveTableAllowed()"
>
<h3>Move Table</h3>
</mat-card>
<mat-card
class="flex-col square-button"
matRipple
(click)="cancelBill()"
[class.disabled]="!cancelBillAllowed()"
[class.primary]="cancelBillAllowed()"
>
<h3>Cancel Bill</h3>
</mat-card>
<mat-card
class="flex-col square-button"
matRipple
(click)="splitBill()"
[class.disabled]="!splitBillAllowed()"
[class.primary]="splitBillAllowed()"
>
<h3>Split Bill</h3>
</mat-card>
</div>
}
@@ -13,6 +13,8 @@ import { SaleCategory } from '../../core/sale-category';
import { Table } from '../../core/table';
import { SaleCategoryService } from '../../sale-category/sale-category.service';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { TableService } from '../../tables/table.service';
import { BillTypeComponent } from '../bill-type/bill-type.component';
import { BillService } from '../bill.service';
@@ -28,7 +30,7 @@ import { TablesDialogComponent } from '../tables-dialog/tables-dialog.component'
selector: 'app-sales-home',
templateUrl: './sales-home.component.html',
styleUrls: ['./sales-home.component.sass'],
imports: [MatRippleModule, RouterLink, MatCardModule],
imports: [MatRippleModule, RouterLink, MatCardModule, ErrorStateComponent, SkeletonLoaderComponent],
})
export class SalesHomeComponent {
private router = inject(Router);
@@ -1,15 +1,21 @@
<div class="tables-grid">
<mat-card class="flex-col square-button warn" matRipple [routerLink]="['../']" queryParamsHandling="preserve">
<h3>Back</h3>
</mat-card>
@for (item of list(); track item) {
<mat-card
class="primary flex-col square-button"
matRipple
[routerLink]="['../products', item.id]"
queryParamsHandling="preserve"
>
<h3>{{ item.name }}</h3>
@if (listResource.isLoading()) {
<app-skeleton-loader type="table" [count]="5" />
} @else if (listResource.error()) {
<app-error-state (retryAction)="listResource.reload()" />
} @else {
<div class="tables-grid">
<mat-card class="flex-col square-button warn" matRipple [routerLink]="['../']" queryParamsHandling="preserve">
<h3>Back</h3>
</mat-card>
}
</div>
@for (item of list(); track item) {
<mat-card
class="primary flex-col square-button"
matRipple
[routerLink]="['../products', item.id]"
queryParamsHandling="preserve"
>
<h3>{{ item.name }}</h3>
</mat-card>
}
</div>
}
@@ -4,12 +4,14 @@ import { MatRippleModule } from '@angular/material/core';
import { RouterLink } from '@angular/router';
import { MenuCategoryService } from '../../menu-category/menu-category.service';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
@Component({
selector: 'app-menu-category',
templateUrl: './menu-categories.component.html',
styleUrls: ['./menu-categories.component.sass'],
imports: [MatRippleModule, RouterLink, MatCardModule],
imports: [MatRippleModule, RouterLink, MatCardModule, ErrorStateComponent, SkeletonLoaderComponent],
})
export class MenuCategoriesComponent {
private menuCategoryService = inject(MenuCategoryService);
@@ -1,23 +1,29 @@
<div class="tables-grid">
<mat-card
class="flex-col square-button warn"
matRipple
[routerLink]="['../../menu-categories']"
queryParamsHandling="preserve"
>
<h3>Back</h3>
</mat-card>
@for (item of list(); track item) {
@if (listResource.isLoading()) {
<app-skeleton-loader type="table" [count]="5" />
} @else if (listResource.error()) {
<app-error-state (retryAction)="listResource.reload()" />
} @else {
<div class="tables-grid">
<mat-card
class="flex-col square-button"
class="flex-col square-button warn"
matRipple
(click)="addSku(item)"
[class.accent]="item.hasHappyHour"
[class.disabled]="item.isNotAvailable"
[class.primary]="!item.hasHappyHour && !item.isNotAvailable"
[routerLink]="['../../menu-categories']"
queryParamsHandling="preserve"
>
<h3>{{ item.name }}</h3>
<span>{{ item.price | currency: 'INR' }}</span>
<h3>Back</h3>
</mat-card>
}
</div>
@for (item of list(); track item) {
<mat-card
class="flex-col square-button"
matRipple
(click)="addSku(item)"
[class.accent]="item.hasHappyHour"
[class.disabled]="item.isNotAvailable"
[class.primary]="!item.hasHappyHour && !item.isNotAvailable"
>
<h3>{{ item.name }}</h3>
<span>{{ item.price | currency: 'INR' }}</span>
</mat-card>
}
</div>
}
@@ -6,13 +6,15 @@ import { RouterLink } from '@angular/router';
import { ProductQuery } from '../../core/product-query';
import { ProductService } from '../../product/product.service';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { BillService } from '../bill.service';
@Component({
selector: 'app-products',
templateUrl: './products.component.html',
styleUrls: ['./products.component.sass'],
imports: [CurrencyPipe, MatRippleModule, RouterLink, MatCardModule],
imports: [CurrencyPipe, MatRippleModule, RouterLink, MatCardModule, ErrorStateComponent, SkeletonLoaderComponent],
})
export class ProductsComponent {
private productService = inject(ProductService);
@@ -1,44 +1,50 @@
<h2 mat-dialog-title>Receive Payment</h2>
<mat-dialog-content>
<form class="flex-col">
<mat-table #table [dataSource]="dataSource()" [style.visibility]="this.displayTable() ? 'visible' : 'hidden'">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef class="bold">Amount</mat-header-cell>
<mat-cell *matCellDef="let row; let i = index" (click)="maxAmount(row, i)">{{ row.name }}</mat-cell>
<mat-footer-cell *matFooterCellDef class="bold">Balance</mat-footer-cell>
</ng-container>
<!-- Amount Column -->
<ng-container matColumnDef="amount">
<mat-header-cell *matHeaderCellDef class="center bold" class="flex-auto">{{
amount | currency: 'INR'
}}</mat-header-cell>
<mat-cell *matCellDef="let row; let i = index" class="center flex-auto">
<mat-form-field>
<input matInput type="number" [formField]="form.amounts[i].amount" autocomplete="off" />
</mat-form-field>
</mat-cell>
<mat-footer-cell *matFooterCellDef class="bold">{{ balance() | currency: 'INR' }}</mat-footer-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
<mat-footer-row *matFooterRowDef="displayedColumns"></mat-footer-row>
</mat-table>
<mat-form-field class="flex-auto" [style.visibility]="this.displayReason() ? 'visible' : 'hidden'">
<mat-label>Reason</mat-label>
<input
type="text"
matInput
#son
[formField]="form.son"
autocomplete="off"
(focus)="select(son.value) && son.select()"
(input)="select(son.value)"
/>
</mat-form-field>
</form>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button [mat-dialog-close]>Cancel</button>
<button type="button" mat-button (click)="accept()" color="primary" [disabled]="!!balance()">Ok</button>
</mat-dialog-actions>
@if (settleOptionsResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (settleOptionsResource.error()) {
<app-error-state (retryAction)="settleOptionsResource.reload()" />
} @else {
<h2 mat-dialog-title>Receive Payment</h2>
<mat-dialog-content>
<form class="flex-col">
<mat-table #table [dataSource]="dataSource()" [style.visibility]="this.displayTable() ? 'visible' : 'hidden'">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef class="bold">Amount</mat-header-cell>
<mat-cell *matCellDef="let row; let i = index" (click)="maxAmount(row, i)">{{ row.name }}</mat-cell>
<mat-footer-cell *matFooterCellDef class="bold">Balance</mat-footer-cell>
</ng-container>
<!-- Amount Column -->
<ng-container matColumnDef="amount">
<mat-header-cell *matHeaderCellDef class="center bold" class="flex-auto">{{
amount | currency: 'INR'
}}</mat-header-cell>
<mat-cell *matCellDef="let row; let i = index" class="center flex-auto">
<mat-form-field>
<input matInput type="number" [formField]="form.amounts[i].amount" autocomplete="off" />
</mat-form-field>
</mat-cell>
<mat-footer-cell *matFooterCellDef class="bold">{{ balance() | currency: 'INR' }}</mat-footer-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
<mat-footer-row *matFooterRowDef="displayedColumns"></mat-footer-row>
</mat-table>
<mat-form-field class="flex-auto" [style.visibility]="this.displayReason() ? 'visible' : 'hidden'">
<mat-label>Reason</mat-label>
<input
type="text"
matInput
#son
[formField]="form.son"
autocomplete="off"
(focus)="select(son.value) && son.select()"
(input)="select(son.value)"
/>
</mat-form-field>
</form>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button [mat-dialog-close]>Cancel</button>
<button type="button" mat-button (click)="accept()" color="primary" [disabled]="!!balance()">Ok</button>
</mat-dialog-actions>
}
@@ -10,6 +10,8 @@ import { MatTableModule } from '@angular/material/table';
import { ReceivePaymentItem } from '../../core/receive-payment-item';
import { SettleOptionService } from '../../settle-option/settle-option.service';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { VoucherType } from '../bills/voucher-type';
export interface ReceivePaymentFormData {
@@ -33,6 +35,8 @@ export interface ReceivePaymentFormData {
MatInputModule,
MatTableModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class ReceivePaymentComponent {
@@ -1,27 +1,33 @@
<h2>Running Tables</h2>
@if (listResource.isLoading()) {
<app-skeleton-loader type="table" [count]="5" />
} @else if (listResource.error()) {
<app-error-state (retryAction)="listResource.reload()" />
} @else {
<h2>Running Tables</h2>
<div class="tables-grid">
@for (table of list(); track table) {
<mat-card
class="flex-col square-button"
matRipple
(click)="navigateToBill(table)"
[class.primary]="table.status !== 'running' && table.status !== 'printed'"
[class.accent]="table.status === 'running'"
[class.strong-accent]="table.status === 'printed'"
>
<h3>{{ table.name }}</h3>
<span>{{ table.guest }}</span>
<span>{{ table.pax ?? '-' }} / {{ table.seats }} / {{ table.section?.name }}</span>
@if (table.date) {
<span>{{ table.date }}</span>
}
@if (table.amount) {
<span>{{ table.amount | currency: 'INR' }}</span>
}
<div class="tables-grid">
@for (table of list(); track table) {
<mat-card
class="flex-col square-button"
matRipple
(click)="navigateToBill(table)"
[class.primary]="table.status !== 'running' && table.status !== 'printed'"
[class.accent]="table.status === 'running'"
[class.strong-accent]="table.status === 'printed'"
>
<h3>{{ table.name }}</h3>
<span>{{ table.guest }}</span>
<span>{{ table.pax ?? '-' }} / {{ table.seats }} / {{ table.section?.name }}</span>
@if (table.date) {
<span>{{ table.date }}</span>
}
@if (table.amount) {
<span>{{ table.amount | currency: 'INR' }}</span>
}
</mat-card>
}
<mat-card class="flex-col square-button strong-primary" matRipple (click)="openBill()">
<h3>Open Bill</h3>
</mat-card>
}
<mat-card class="flex-col square-button strong-primary" matRipple (click)="openBill()">
<h3>Open Bill</h3>
</mat-card>
</div>
</div>
}
@@ -9,6 +9,8 @@ import { map } from 'rxjs/operators';
import { Table } from '../../core/table';
import { RegimeService } from '../../regimes/regime.service';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { TableService } from '../../tables/table.service';
import { BillNumberComponent } from '../bill-number/bill-number.component';
@@ -16,7 +18,7 @@ import { BillNumberComponent } from '../bill-number/bill-number.component';
selector: 'app-running-tables',
templateUrl: './running-tables.component.html',
styleUrls: ['./running-tables.component.sass'],
imports: [CurrencyPipe, MatRippleModule, MatCardModule],
imports: [CurrencyPipe, MatRippleModule, MatCardModule, ErrorStateComponent, SkeletonLoaderComponent],
})
export class RunningTablesComponent {
private tableService = inject(TableService);
@@ -1,63 +1,69 @@
<h2>Section Printer</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Section</mat-label>
<mat-select [formField]="form.section" (selectionChange)="show($event)">
@for (s of sections(); track s) {
<mat-option [value]="s.id">
{{ s.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
<mat-divider></mat-divider>
<mat-table #table [dataSource]="formModel().saleCategories">
<!-- Sale Category Column -->
<ng-container matColumnDef="saleCategory">
<mat-header-cell *matHeaderCellDef>Sale Category</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.saleCategory?.name ?? 'Default' }}</mat-cell>
</ng-container>
@if (listResource.isLoading()) {
<app-skeleton-loader type="table" [count]="5" />
} @else if (listResource.error()) {
<app-error-state (retryAction)="listResource.reload()" />
} @else {
<h2>Section Printer</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Section</mat-label>
<mat-select [formField]="form.section" (selectionChange)="show($event)">
@for (s of sections(); track s) {
<mat-option [value]="s.id">
{{ s.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
<mat-divider></mat-divider>
<mat-table #table [dataSource]="formModel().saleCategories">
<!-- Sale Category Column -->
<ng-container matColumnDef="saleCategory">
<mat-header-cell *matHeaderCellDef>Sale Category</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.saleCategory?.name ?? 'Default' }}</mat-cell>
</ng-container>
<!-- Printer Column -->
<ng-container matColumnDef="printer">
<mat-header-cell *matHeaderCellDef>Printer</mat-header-cell>
<mat-cell *matCellDef="let row; let i = index">
<mat-form-field class="flex-auto">
<mat-label>Printer</mat-label>
<mat-select [formField]="form.saleCategories[i].printer">
<mat-option [value]="null">-- Default --</mat-option>
@for (p of printers(); track p) {
<mat-option [value]="p.id">
{{ p.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
</mat-cell>
</ng-container>
<!-- Copies Column -->
<ng-container matColumnDef="copies">
<mat-header-cell *matHeaderCellDef>Copies</mat-header-cell>
<mat-cell *matCellDef="let row; let i = index">
@if (form.saleCategories[i].printer().controlValue()) {
<!-- Printer Column -->
<ng-container matColumnDef="printer">
<mat-header-cell *matHeaderCellDef>Printer</mat-header-cell>
<mat-cell *matCellDef="let row; let i = index">
<mat-form-field class="flex-auto">
<mat-label>Copies</mat-label>
<input matInput type="number" [formField]="form.saleCategories[i].copies" />
<mat-label>Printer</mat-label>
<mat-select [formField]="form.saleCategories[i].printer">
<mat-option [value]="null">-- Default --</mat-option>
@for (p of printers(); track p) {
<mat-option [value]="p.id">
{{ p.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
}
</mat-cell>
</ng-container>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; let i = index; columns: displayedColumns"></mat-row>
</mat-table>
</form>
<div class="row-container">
<button type="button" mat-raised-button color="primary" class="" (click)="save()">Save</button>
@if (id()) {
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
}
</div>
<!-- Copies Column -->
<ng-container matColumnDef="copies">
<mat-header-cell *matHeaderCellDef>Copies</mat-header-cell>
<mat-cell *matCellDef="let row; let i = index">
@if (form.saleCategories[i].printer().controlValue()) {
<mat-form-field class="flex-auto">
<mat-label>Copies</mat-label>
<input matInput type="number" [formField]="form.saleCategories[i].copies" />
</mat-form-field>
}
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; let i = index; columns: displayedColumns"></mat-row>
</mat-table>
</form>
<div class="row-container">
<button type="button" mat-raised-button color="primary" class="" (click)="save()">Save</button>
@if (id()) {
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
}
</div>
}
@@ -16,6 +16,8 @@ import { SectionPrinter } from '../core/section-printer';
import { PrinterService } from '../printers/printer.service';
import { SectionService } from '../sections/section.service';
import { ConfirmDialogComponent } from '../shared/confirm-dialog/confirm-dialog.component';
import { ErrorStateComponent } from '../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../shared/skeleton-loader/skeleton-loader.component';
import { SectionPrinterService } from './section-printer.service';
export interface SectionPrinterFormData {
@@ -40,6 +42,8 @@ export interface SectionPrinterFormData {
MatSelectModule,
MatTableModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class SectionPrinterComponent {
@@ -1,16 +1,22 @@
<h2>Section</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" (keyup.enter)="save()" />
</mat-form-field>
</div>
</form>
@if (itemResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (itemResource.error()) {
<app-error-state (retryAction)="itemResource.reload()" />
} @else {
<h2>Section</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" (keyup.enter)="save()" />
</mat-form-field>
</div>
</form>
<div class="row-container">
<button type="button" mat-raised-button color="primary" class="" (click)="save()">Save</button>
@if (!!item().id) {
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
}
</div>
<div class="row-container">
<button type="button" mat-raised-button color="primary" class="" (click)="save()">Save</button>
@if (!!item().id) {
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
}
</div>
}
@@ -9,6 +9,8 @@ import { Router } from '@angular/router';
import { Section } from '../../core/section';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { SectionService } from '../section.service';
export interface SectionDetailFormData {
@@ -19,7 +21,14 @@ export interface SectionDetailFormData {
selector: 'app-section-detail',
templateUrl: './section-detail.component.html',
styleUrls: ['./section-detail.component.css'],
imports: [MatButtonModule, MatFormFieldModule, MatInputModule, FormField],
imports: [
MatButtonModule,
MatFormFieldModule,
MatInputModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class SectionDetailComponent {
private router = inject(Router);
@@ -1,19 +1,25 @@
<h2 class="row-container space-between">
<span>Sections</span>
<a mat-button [routerLink]="['/sections', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/sections', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
@if (listResource.isLoading()) {
<app-skeleton-loader type="table" [count]="5" />
} @else if (listResource.error()) {
<app-error-state (retryAction)="listResource.reload()" />
} @else {
<h2 class="row-container space-between">
<span>Sections</span>
<a mat-button [routerLink]="['/sections', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/sections', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
}
@@ -4,12 +4,14 @@ import { MatIconModule } from '@angular/material/icon';
import { MatTableModule } from '@angular/material/table';
import { RouterLink } from '@angular/router';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { SectionService } from '../section.service';
@Component({
selector: 'app-section-list',
templateUrl: './section-list.component.html',
styleUrls: ['./section-list.component.css'],
imports: [MatButtonModule, MatIconModule, MatTableModule, RouterLink],
imports: [MatButtonModule, MatIconModule, MatTableModule, RouterLink, ErrorStateComponent, SkeletonLoaderComponent],
})
export class SectionListComponent {
private sectionService = inject(SectionService);
+59 -53
View File
@@ -1,53 +1,59 @@
<mat-tab-group>
<mat-tab label="Prefill Customer Discount">
<mat-card>
<mat-card-content>
<mat-slide-toggle (click)="togglePrefill()" class="flex-auto" [checked]="prefillCustomerDiscount">
Prefill the customer discount
</mat-slide-toggle>
</mat-card-content>
</mat-card>
</mat-tab>
<mat-tab label="DB Maintenance">
<mat-card>
<mat-card-content>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Start Date</mat-label>
<input
matInput
[matDatepicker]="startDate"
(focus)="startDate.open()"
[formField]="maintenanceForm.startDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
<mat-datepicker #startDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Finish Date</mat-label>
<input
matInput
[matDatepicker]="finishDate"
(focus)="finishDate.open()"
[formField]="maintenanceForm.finishDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
</div>
<h1>Beer</h1>
<input mat-input class="flex-auto" type="file" (change)="detectBeer($event)" />
<h1>Sale</h1>
<input mat-input class="flex-auto" type="file" (change)="detectSale($event)" />
<button type="button" mat-raised-button color="primary" (click)="runMaintenance()">Upload</button>
</form>
</mat-card-content>
</mat-card>
</mat-tab>
</mat-tab-group>
<footer class="footer">
<p>Backend: v{{ auth.user()?.ver }} / Frontend: v{{ version }}</p>
</footer>
@if (prefillCustomerDiscountResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (prefillCustomerDiscountResource.error()) {
<app-error-state (retryAction)="prefillCustomerDiscountResource.reload()" />
} @else {
<mat-tab-group>
<mat-tab label="Prefill Customer Discount">
<mat-card>
<mat-card-content>
<mat-slide-toggle (click)="togglePrefill()" class="flex-auto" [checked]="prefillCustomerDiscount">
Prefill the customer discount
</mat-slide-toggle>
</mat-card-content>
</mat-card>
</mat-tab>
<mat-tab label="DB Maintenance">
<mat-card>
<mat-card-content>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Start Date</mat-label>
<input
matInput
[matDatepicker]="startDate"
(focus)="startDate.open()"
[formField]="maintenanceForm.startDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
<mat-datepicker #startDate></mat-datepicker>
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Finish Date</mat-label>
<input
matInput
[matDatepicker]="finishDate"
(focus)="finishDate.open()"
[formField]="maintenanceForm.finishDate"
autocomplete="off"
/>
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
</div>
<h1>Beer</h1>
<input mat-input class="flex-auto" type="file" (change)="detectBeer($event)" />
<h1>Sale</h1>
<input mat-input class="flex-auto" type="file" (change)="detectSale($event)" />
<button type="button" mat-raised-button color="primary" (click)="runMaintenance()">Upload</button>
</form>
</mat-card-content>
</mat-card>
</mat-tab>
</mat-tab-group>
<footer class="footer">
<p>Backend: v{{ auth.user()?.ver }} / Frontend: v{{ version }}</p>
</footer>
}
@@ -12,6 +12,8 @@ import moment from 'moment';
import { environment } from '../app.environment';
import { AuthService } from '../auth/auth.service';
import { ErrorStateComponent } from '../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../shared/skeleton-loader/skeleton-loader.component';
import { SettingsService } from './settings.service';
@Component({
@@ -28,6 +30,8 @@ import { SettingsService } from './settings.service';
MatTabsModule,
MatCardModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class SettingsComponent {
@@ -1,39 +1,45 @@
<h2>Settle Option</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Voucher Type</mat-label>
<mat-select [formField]="form.voucherType">
@for (vt of voucherTypes; track vt) {
<mat-option [value]="vt.id">
{{ vt.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Reporting Level</mat-label>
<mat-select [formField]="form.reportingLevel">
@for (rl of reportingLevel; track rl) {
<mat-option [value]="rl.id">
{{ rl.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
<mat-checkbox [formField]="form.hasReason">Has Reason?</mat-checkbox>
</div>
</form>
@if (itemResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (itemResource.error()) {
<app-error-state (retryAction)="itemResource.reload()" />
} @else {
<h2>Settle Option</h2>
<form class="flex-col">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Voucher Type</mat-label>
<mat-select [formField]="form.voucherType">
@for (vt of voucherTypes; track vt) {
<mat-option [value]="vt.id">
{{ vt.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Reporting Level</mat-label>
<mat-select [formField]="form.reportingLevel">
@for (rl of reportingLevel; track rl) {
<mat-option [value]="rl.id">
{{ rl.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
<mat-checkbox [formField]="form.hasReason">Has Reason?</mat-checkbox>
</div>
</form>
<div class="row-container">
<button type="button" mat-raised-button color="primary" class="" (click)="save()">Save</button>
@if (!!item().id) {
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
}
</div>
<div class="row-container">
<button type="button" mat-raised-button color="primary" class="" (click)="save()">Save</button>
@if (!!item().id) {
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
}
</div>
}
@@ -14,6 +14,8 @@ import { ReportingLevel } from '../../core/reporting-level';
import { SettleOption } from '../../core/settle-option';
import { VoucherType } from '../../sales/bills/voucher-type';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { SettleOptionService } from '../settle-option.service';
export interface SettleOptionDetailFormData {
@@ -35,6 +37,8 @@ export interface SettleOptionDetailFormData {
MatOptionModule,
MatSelectModule,
FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
],
})
export class SettleOptionDetailComponent {
@@ -1,43 +1,49 @@
<h2 class="row-container space-between">
<span>Settle Options</span>
<a mat-button [routerLink]="['/settle-options', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/settle-options', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
@if (listResource.isLoading()) {
<app-skeleton-loader type="table" [count]="5" />
} @else if (listResource.error()) {
<app-error-state (retryAction)="listResource.reload()" />
} @else {
<h2 class="row-container space-between">
<span>Settle Options</span>
<a mat-button [routerLink]="['/settle-options', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
<mat-table #table [dataSource]="dataSource()" aria-label="Elements">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/settle-options', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
<!-- Voucher Type Column -->
<ng-container matColumnDef="voucherType">
<mat-header-cell *matHeaderCellDef>Voucher Type</mat-header-cell>
<mat-cell *matCellDef="let row">{{ voucherType(row.voucherType) }}</mat-cell>
</ng-container>
<!-- Voucher Type Column -->
<ng-container matColumnDef="voucherType">
<mat-header-cell *matHeaderCellDef>Voucher Type</mat-header-cell>
<mat-cell *matCellDef="let row">{{ voucherType(row.voucherType) }}</mat-cell>
</ng-container>
<!-- Reporting Level Column -->
<ng-container matColumnDef="reportingLevel">
<mat-header-cell *matHeaderCellDef>Reporting Level</mat-header-cell>
<mat-cell *matCellDef="let row">{{ reportingLevel(row.reportingLevel) }}</mat-cell>
</ng-container>
<!-- Reporting Level Column -->
<ng-container matColumnDef="reportingLevel">
<mat-header-cell *matHeaderCellDef>Reporting Level</mat-header-cell>
<mat-cell *matCellDef="let row">{{ reportingLevel(row.reportingLevel) }}</mat-cell>
</ng-container>
<!-- Has Reason Column -->
<ng-container matColumnDef="hasReason">
<mat-header-cell *matHeaderCellDef>Has Reason?</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.hasReason }}</mat-cell>
</ng-container>
<!-- Has Reason Column -->
<ng-container matColumnDef="hasReason">
<mat-header-cell *matHeaderCellDef>Has Reason?</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.hasReason }}</mat-cell>
</ng-container>
<!-- Is Fixture Column -->
<ng-container matColumnDef="isFixture">
<mat-header-cell *matHeaderCellDef>Fixture?</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.isFixture }}</mat-cell>
</ng-container>
<!-- Is Fixture Column -->
<ng-container matColumnDef="isFixture">
<mat-header-cell *matHeaderCellDef>Fixture?</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.isFixture }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
}
@@ -6,12 +6,14 @@ import { RouterLink } from '@angular/router';
import { ReportingLevel } from '../../core/reporting-level';
import { VoucherType } from '../../sales/bills/voucher-type';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { SettleOptionService } from '../settle-option.service';
@Component({
selector: 'app-settle-option-list',
templateUrl: './settle-option-list.component.html',
styleUrls: ['./settle-option-list.component.css'],
imports: [MatButtonModule, MatIconModule, MatTableModule, RouterLink],
imports: [MatButtonModule, MatIconModule, MatTableModule, RouterLink, ErrorStateComponent, SkeletonLoaderComponent],
})
export class SettleOptionListComponent {
private ser = inject(SettleOptionService);
@@ -0,0 +1,10 @@
<div class="error-state-container">
<div class="error-state-icon">
<i class="material-icons">error_outline</i>
</div>
<h3 class="error-state-title">{{ title() }}</h3>
<p class="error-state-message">{{ message() }}</p>
<div class="error-state-actions">
<button mat-stroked-button color="warn" (click)="onRetry()">Try Again</button>
</div>
</div>
@@ -0,0 +1,33 @@
.error-state-container
display: flex
flex-direction: column
align-items: center
justify-content: center
padding: 48px 24px
text-align: center
background-color: #fef2f2
border-radius: 8px
border: 1px solid #f87171
.error-state-icon
font-size: 48px
color: #ef4444
margin-bottom: 16px
i
font-size: 48px
.error-state-title
font-size: 1.25rem
font-weight: 600
color: #991b1b
margin: 0 0 8px 0
.error-state-message
font-size: 0.875rem
color: #b91c1c
margin: 0 0 24px 0
max-width: 400px
.error-state-actions
display: flex
gap: 12px
@@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ErrorStateComponent } from './error-state.component';
describe('ErrorStateComponent', () => {
let component: ErrorStateComponent;
let fixture: ComponentFixture<ErrorStateComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ErrorStateComponent],
}).compileComponents();
fixture = TestBed.createComponent(ErrorStateComponent);
component = fixture.componentInstance;
await fixture.whenStable();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Loaded 100 of 132 files, more files were not shown because too many files have changed in this diff. Show more