fdsa
This commit is contained in:
1 parent
10448e8b12
commit
85a063c1a7
132 files changed
+4377
-3348
No files matched your search
@@ -0,0 +1,61 @@
|
||||
# Version control & IDEs
|
||||
.git
|
||||
.gitignore
|
||||
.vscode
|
||||
.idea
|
||||
.agents
|
||||
.gemini
|
||||
|
||||
# Build artifacts & compiled outputs
|
||||
frontend
|
||||
dist
|
||||
**/dist
|
||||
out-tsc
|
||||
**/out-tsc
|
||||
bazel-out
|
||||
|
||||
# Dependencies & framework caches
|
||||
node_modules
|
||||
**/node_modules
|
||||
.angular
|
||||
**/.angular
|
||||
.nx
|
||||
**/.nx
|
||||
.sass-cache
|
||||
**/.sass-cache
|
||||
|
||||
# Python virtual environments & caches
|
||||
.venv
|
||||
**/__pycache__
|
||||
**/.mypy_cache
|
||||
**/.ruff_cache
|
||||
**/.pytest_cache
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.egg-info
|
||||
|
||||
# Testing & coverage
|
||||
coverage
|
||||
**/coverage
|
||||
.coverage
|
||||
htmlcov
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Environment & local deployment/dev files
|
||||
.env*
|
||||
!.env.example
|
||||
ansible
|
||||
deploy.sh
|
||||
lint.sh
|
||||
version_bump.sh
|
||||
Makefile
|
||||
README.md
|
||||
CHANGES.md
|
||||
typings
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
+50
-10
@@ -1,12 +1,52 @@
|
||||
*.pyc
|
||||
venv
|
||||
.project
|
||||
.pydevproject
|
||||
*/__pycache__/
|
||||
# IDEs & System Files
|
||||
.idea/
|
||||
*.egg-info/
|
||||
DB/Data/*.sql
|
||||
barker/static/
|
||||
build/
|
||||
dist/
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Build outputs
|
||||
frontend/
|
||||
dist/
|
||||
**/dist/
|
||||
out-tsc/
|
||||
**/out-tsc/
|
||||
bazel-out/
|
||||
|
||||
# Angular & Nx caches
|
||||
.angular/
|
||||
**/.angular/
|
||||
.nx/
|
||||
**/.nx/
|
||||
.sass-cache/
|
||||
|
||||
# Dependencies
|
||||
node_modules/
|
||||
**/node_modules/
|
||||
|
||||
# Python & Virtual Environments
|
||||
.venv/
|
||||
**/__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.egg-info/
|
||||
.mypy_cache/
|
||||
**/.mypy_cache/
|
||||
.ruff_cache/
|
||||
**/.ruff_cache/
|
||||
.pytest_cache/
|
||||
**/.pytest_cache/
|
||||
|
||||
# Testing & Coverage
|
||||
coverage/
|
||||
**/coverage/
|
||||
.coverage
|
||||
htmlcov/
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Ignore Pyright-generated stubs
|
||||
*.pyi
|
||||
typings/
|
||||
Vendored
+26
-7
@@ -26,6 +26,7 @@
|
||||
"[python]": {
|
||||
"editor.defaultFormatter": "charliermarsh.ruff"
|
||||
},
|
||||
"ruff.enable": true,
|
||||
"files.eol": "\n",
|
||||
"eslint.workingDirectories": [
|
||||
{
|
||||
@@ -37,24 +38,42 @@
|
||||
"files.exclude": {
|
||||
"**/__pycache__": true,
|
||||
"**/.mypy_cache": true,
|
||||
"**/.ruff_cache": true,
|
||||
"**/.pytest_cache": true,
|
||||
".idea": true,
|
||||
"**/node_modules": true,
|
||||
"**/.venv": true,
|
||||
"typings": true
|
||||
"typings": true,
|
||||
"frontend": true,
|
||||
"**/.angular": true,
|
||||
"**/.nx": true,
|
||||
"**/out-tsc": true,
|
||||
"**/dist": true,
|
||||
"**/.sass-cache": true,
|
||||
"**/coverage": true
|
||||
},
|
||||
"search.exclude": {
|
||||
"**/__pycache__": true,
|
||||
"**/.mypy_cache": true,
|
||||
"**/.ruff_cache": true,
|
||||
"**/.pytest_cache": true,
|
||||
".idea": true,
|
||||
"**/node_modules": true,
|
||||
"**/uv.lock": true,
|
||||
"**/poetry.lock": true,
|
||||
"**/package-lock.json": true,
|
||||
"/bookie/.angular/**": true,
|
||||
"**/.venv": true,
|
||||
"typings": true
|
||||
"typings": true,
|
||||
"frontend/**": true,
|
||||
"**/.angular/**": true,
|
||||
"**/.nx/**": true,
|
||||
"**/out-tsc/**": true,
|
||||
"**/dist/**": true,
|
||||
"**/.sass-cache/**": true,
|
||||
"**/coverage/**": true
|
||||
},
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.ruff": "always",
|
||||
"source.fixAll.eslint": "always"
|
||||
}
|
||||
},
|
||||
"python-envs.defaultEnvManager": "ms-python.python:venv",
|
||||
"python-envs.defaultPackageManager": "ms-python.python:pip",
|
||||
"python-envs.pythonProjects": []
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 }} @ {{ 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 }} @ {{ 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 {
|
||||
|
||||
+27
-21
@@ -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>
|
||||
}
|
||||
+11
-1
@@ -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:(=/<=/>=/</>)Quantity,
|
||||
s:(=/<=/>=/</>)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:(=/<=/>=/</>)Quantity,
|
||||
s:(=/<=/>=/</>)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 {
|
||||
|
||||
+67
-61
@@ -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>
|
||||
}
|
||||
+4
@@ -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 {
|
||||
|
||||
+64
-58
@@ -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>
|
||||
}
|
||||
+3
-1
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
+61
-55
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
> / <span [matTooltip]="bs.bill().creationDateTip">{{ bs.bill().creationDate }}</span
|
||||
> / <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
|
||||
> / <span [matTooltip]="bs.bill().creationDateTip">{{ bs.bill().creationDate }}</span
|
||||
> / <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>
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+44
-38
@@ -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);
|
||||
|
||||
Loaded 100 of 132 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user