This commit is contained in:
tanshu committed 2026-08-28 15:44:19 +00:00
1 parent af07bb5043
commit 103983846d
76 files changed
+415 -473

No files matched your search

+1
View File
@@ -1,5 +1,6 @@
{ {
"python.defaultInterpreterPath": "/home/tanshu/programming/barker/barker/.venv/bin/python", "python.defaultInterpreterPath": "/home/tanshu/programming/barker/barker/.venv/bin/python",
"python.terminal.useEnvFile": true,
"python.interpreterPath": "/home/tanshu/programming/barker/barker/.venv/bin/python", "python.interpreterPath": "/home/tanshu/programming/barker/barker/.venv/bin/python",
"python.venvFolders": [ "python.venvFolders": [
"barker/.venv", "barker/.venv",
+2 -2
View File
@@ -6,8 +6,8 @@ SQLALCHEMY_DATABASE_URI=postgresql+psycopg://postgres:123456@postgres:5432/petty
MODULE_NAME=barker.main MODULE_NAME=barker.main
PROJECT_NAME=barker PROJECT_NAME=barker
MAX_WORKERS=4 MAX_WORKERS=4
REDIS_HOST=valkey NATS_HOST=nats
REDIS_PORT=6379 NATS_PORT=4222
SECRET_KEY={{ secret_key }} SECRET_KEY={{ secret_key }}
MIDDLEWARE_SECRET_KEY={{ middleware_key }} MIDDLEWARE_SECRET_KEY={{ middleware_key }}
ALGORITHM=HS256 ALGORITHM=HS256
+2 -2
View File
@@ -1,3 +1,3 @@
REDIS_HOST=localhost NATS_HOST=localhost
REDIS_PORT=6379 NATS_PORT=4222
QUEUE_NAME={{ queue_name }} QUEUE_NAME={{ queue_name }}
+40 -12
View File
@@ -1,11 +1,33 @@
import asyncio import asyncio
from nats.js.api import StreamConfig
from taskiq import BrokerMessage
from taskiq_nats import PullBasedJetStreamBroker from taskiq_nats import PullBasedJetStreamBroker
from .config import settings from .config import settings
broker = PullBasedJetStreamBroker(settings.NATS_URL) class RoutedJetStreamBroker(PullBasedJetStreamBroker):
async def kick(self, message: BrokerMessage) -> None:
subject = message.labels.get("queue", self.subject)
await self.js.publish(
subject,
payload=message.message,
headers=message.labels,
)
broker = RoutedJetStreamBroker(
settings.NATS_URL,
subject="barker.print.>",
stream_name="barker_print_stream",
stream_config=StreamConfig(
name="barker_print_stream",
subjects=["barker.print.>"],
),
)
main_loop: asyncio.AbstractEventLoop | None = None
@broker.task(task_name="sent_to_printer") @broker.task(task_name="sent_to_printer")
@@ -14,15 +36,21 @@ async def sent_to_printer(data: str, address: str, cut_code: str) -> None:
def enqueue_print_job_sync(printer_name: str, data: str, address: str, cut_code: str) -> None: def enqueue_print_job_sync(printer_name: str, data: str, address: str, cut_code: str) -> None:
async def _enqueue() -> None: coro = sent_to_printer.kicker().with_labels(queue=f"barker.print.{printer_name}").kiq(data, address, cut_code)
await broker.startup()
try:
await (
sent_to_printer.kicker().with_labels(queue=f"barker.print.{printer_name}").kiq(data, address, cut_code)
)
finally:
await broker.shutdown()
loop = asyncio.new_event_loop() if main_loop is not None and main_loop.is_running():
loop.run_until_complete(_enqueue()) asyncio.run_coroutine_threadsafe(coro, main_loop)
loop.close() else:
async def _enqueue() -> None:
await broker.startup()
try:
await coro
finally:
await broker.shutdown()
loop = asyncio.new_event_loop()
try:
loop.run_until_complete(_enqueue())
finally:
loop.close()
+17 -2
View File
@@ -1,5 +1,9 @@
import asyncio
import logging import logging
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
import uvicorn import uvicorn
from fastapi import FastAPI, Request from fastapi import FastAPI, Request
@@ -7,6 +11,7 @@ from fastapi.responses import JSONResponse
from sqlalchemy.exc import IntegrityError, SQLAlchemyError from sqlalchemy.exc import IntegrityError, SQLAlchemyError
from starlette.middleware.sessions import SessionMiddleware from starlette.middleware.sessions import SessionMiddleware
from .core import taskiq
from .core.config import settings from .core.config import settings
from .db.base import reg # noqa: F401 from .db.base import reg # noqa: F401
from .db.friendly_db_error import constraint_to_friendly from .db.friendly_db_error import constraint_to_friendly
@@ -60,8 +65,18 @@ from .routers.voucher import (
) )
@asynccontextmanager
async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
taskiq.main_loop = asyncio.get_running_loop()
await taskiq.broker.startup()
try:
yield
finally:
await taskiq.broker.shutdown()
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
app = FastAPI() app = FastAPI(lifespan=lifespan)
@app.exception_handler(SQLAlchemyError) @app.exception_handler(SQLAlchemyError)
@@ -151,4 +166,4 @@ app.frontend("/", directory="frontend", check_dir="auto")
def init() -> None: def init() -> None:
uvicorn.run(app, host=settings.HOST, port=settings.PORT) uvicorn.run(app, host=settings.HOST, port=9995)
+1 -1
View File
@@ -5,7 +5,7 @@ import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from './auth.service'; import { AuthService } from './auth.service';
export const authGuard: CanActivateFn = (route, state) => { export const authGuard: CanActivateFn = (route, state) => {
const user = inject(AuthService).user; const user = inject(AuthService).user();
const permission = const permission =
route.data['permission'] === undefined route.data['permission'] === undefined
? route.data['permission'] ? route.data['permission']
+73 -47
View File
@@ -1,6 +1,5 @@
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Injectable, inject } from '@angular/core'; import { Injectable, computed, inject, signal } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { environment } from '../app.environment'; import { environment } from '../app.environment';
@@ -18,14 +17,22 @@ export class AuthService {
private http = inject(HttpClient); private http = inject(HttpClient);
private cs = inject(CookieService); private cs = inject(CookieService);
public currentUser: Observable<User | null>; private _user = signal<User | null>(this.readStorage());
public user = this._user.asReadonly();
public isLoggedIn = computed(() => this.user() !== null);
private _needsRefreshing = signal<boolean>(false);
public needsRefreshing = this._needsRefreshing.asReadonly();
public device: Device; public device: Device;
private currentUserSubject: BehaviorSubject<User | null> = new BehaviorSubject<User | null>(null); public isRefreshing = signal<boolean>(false);
public isRefreshing = false; private expirationTimer: ReturnType<typeof setTimeout> | null = null;
private refreshTimer: ReturnType<typeof setTimeout> | null = null;
constructor() { constructor() {
this.checkStorage(); const user = this._user();
this.currentUser = this.currentUserSubject.asObservable(); this.scheduleExpiryTimer(user);
this.scheduleRefreshTimer(user);
const deviceId = this.cs.getCookie('device_id'); const deviceId = this.cs.getCookie('device_id');
const device = this.cs.getCookie('device'); const device = this.cs.getCookie('device');
const section = this.cs.getCookie('section'); const section = this.cs.getCookie('section');
@@ -58,38 +65,71 @@ export class AuthService {
}); });
} }
checkStorage(): User | null { private readStorage(): User | null {
const storageToken = localStorage.getItem(JWT_USER); const storageToken = localStorage.getItem(JWT_USER);
let existingToken: User | null = null; if (!storageToken) {
if (storageToken !== null) { return null;
existingToken = JSON.parse(storageToken);
} }
if (existingToken === null || Date.now() > existingToken.exp * 1000) { try {
const token: User = JSON.parse(storageToken);
if (!token || Date.now() > token.exp * 1000) {
localStorage.removeItem(JWT_USER);
return null;
}
return token;
} catch {
localStorage.removeItem(JWT_USER); localStorage.removeItem(JWT_USER);
this.currentUserSubject.next(null);
return null; return null;
} }
this.currentUserSubject.next(existingToken);
return existingToken;
} }
public get user(): User | null { private scheduleExpiryTimer(user: User | null): void {
let val = this.currentUserSubject.value; if (this.expirationTimer) {
if (val == null) { clearTimeout(this.expirationTimer);
return val; this.expirationTimer = null;
} }
let expired = Date.now() > val.exp * 1000; if (!user || !user.exp) {
if (expired) { return;
val = this.checkStorage();
} }
if (val == null) { const expiresInMs = user.exp * 1000 - Date.now();
return new User(); if (expiresInMs <= 0) {
}
expired = Date.now() > val.exp * 1000;
if (expired) {
this.logout(); this.logout();
return;
} }
return this.currentUserSubject.value; this.expirationTimer = setTimeout(() => {
this.logout();
}, expiresInMs);
}
private scheduleRefreshTimer(user: User | null): void {
if (this.refreshTimer) {
clearTimeout(this.refreshTimer);
this.refreshTimer = null;
}
if (!user || !user.exp) {
this._needsRefreshing.set(false);
return;
}
const refreshInMs = (user.exp - environment.ACCESS_TOKEN_REFRESH_MINUTES * 60) * 1000 - Date.now();
if (refreshInMs <= 0) {
this._needsRefreshing.set(true);
return;
}
this._needsRefreshing.set(false);
this.refreshTimer = setTimeout(() => {
this._needsRefreshing.set(true);
}, refreshInMs);
}
private saveUser(user: User | null): void {
if (user) {
localStorage.setItem(JWT_USER, JSON.stringify(user));
} else {
localStorage.removeItem(JWT_USER);
}
this._user.set(user);
this.scheduleExpiryTimer(user);
this.scheduleRefreshTimer(user);
} }
login(username: string, password: string) { login(username: string, password: string) {
@@ -103,26 +143,14 @@ export class AuthService {
.pipe(map((u) => AuthService.parseJwt(u))) .pipe(map((u) => AuthService.parseJwt(u)))
.pipe( .pipe(
map((user) => { map((user) => {
// store user details and jwt token in local storage to keep user logged in between page refreshes this.saveUser(user);
localStorage.setItem(JWT_USER, JSON.stringify(user));
this.currentUserSubject.next(user);
return user; return user;
}), }),
); );
} }
needsRefreshing(): boolean { logout(): void {
const { user } = this; this.saveUser(null);
if (user === null) {
return true;
}
return Date.now() > (user.exp - environment.ACCESS_TOKEN_REFRESH_MINUTES * 60) * 1000;
}
logout() {
// remove user from local storage to log user out
localStorage.removeItem(JWT_USER);
this.currentUserSubject.next(null);
} }
refreshToken() { refreshToken() {
@@ -132,16 +160,14 @@ export class AuthService {
.pipe(map((u) => AuthService.parseJwt(u))) .pipe(map((u) => AuthService.parseJwt(u)))
.pipe( .pipe(
map((user) => { map((user) => {
// store user details and jwt token in local storage to keep user logged in between page refreshes this.saveUser(user);
localStorage.setItem(JWT_USER, JSON.stringify(user));
this.currentUserSubject.next(user);
return user; return user;
}), }),
); );
} }
allowed(permission: string): boolean { allowed(permission: string): boolean {
const { user } = this; const user = this.user();
if (user == null || user.perms.indexOf(permission) === -1) { if (user == null || user.perms.indexOf(permission) === -1) {
return false; return false;
} }
@@ -36,7 +36,7 @@
</mat-form-field> </mat-form-field>
<mat-form-field class="flex-auto"> <mat-form-field class="flex-auto">
<mat-label>Sale Category</mat-label> <mat-label>Sale Category</mat-label>
<mat-select [formField]="form.saleCategory" (selectionChange)="filterOn($event.value)"> <mat-select [formField]="form.saleCategory">
@for (sc of saleCategories(); track sc) { @for (sc of saleCategories(); track sc) {
<mat-option [value]="sc.id"> <mat-option [value]="sc.id">
{{ sc.name }} {{ sc.name }}
@@ -9,10 +9,9 @@ import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import moment from 'moment'; import moment from 'moment';
import { SaleCategory } from '../core/sale-category';
import { SaleCategoryService } from '../sale-category/sale-category.service'; import { SaleCategoryService } from '../sale-category/sale-category.service';
import { ToCsvService } from '../shared/to-csv.service'; import { ToCsvService } from '../shared/to-csv.service';
import { BeerSaleExportHeaderInterface } from './beer-sale-export-header-interface'; import { BeerSaleExportHeaderInterface } from './beer-sale-export-header-interface';
@@ -48,7 +47,6 @@ export interface BeerSaleReportFormData {
}) })
export class BeerSaleReportComponent { export class BeerSaleReportComponent {
private router = inject(Router); private router = inject(Router);
private route = inject(ActivatedRoute);
private toCsv = inject(ToCsvService); private toCsv = inject(ToCsvService);
private ser = inject(BeerSaleReportService); private ser = inject(BeerSaleReportService);
private saleCategoryService = inject(SaleCategoryService); private saleCategoryService = inject(SaleCategoryService);
@@ -125,22 +123,13 @@ export class BeerSaleReportComponent {
}); });
} }
filterOn(id: string) {
const sc = this.saleCategories().find((x: SaleCategory) => x.id === id);
const currentInfo = this.info();
if (currentInfo) {
currentInfo.saleCategory = sc ? sc : new SaleCategory({ id });
}
}
getInfo(): BeerSaleReport { getInfo(): BeerSaleReport {
const formModel = this.formModel(); const formModel = this.formModel();
const currentInfo = this.info();
return new BeerSaleReport({ return new BeerSaleReport({
startDate: moment(formModel.startDate).format('DD-MMM-YYYY'), startDate: moment(formModel.startDate).format('DD-MMM-YYYY'),
finishDate: moment(formModel.finishDate).format('DD-MMM-YYYY'), finishDate: moment(formModel.finishDate).format('DD-MMM-YYYY'),
saleCategory: currentInfo?.saleCategory, saleCategory: this.saleCategories().find((sc) => sc.id === formModel.saleCategory),
regular: formModel.regular, regular: formModel.regular,
happy: formModel.happy, happy: formModel.happy,
staff: formModel.staff, staff: formModel.staff,
@@ -7,7 +7,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import moment from 'moment'; import moment from 'moment';
import { LocalTimePipe } from '../shared/local-time.pipe'; import { LocalTimePipe } from '../shared/local-time.pipe';
@@ -38,7 +38,6 @@ export interface BillSettlementReportFormData {
}) })
export class BillSettlementReportComponent { export class BillSettlementReportComponent {
private billSettlementReportService = inject(BillSettlementReportService); private billSettlementReportService = inject(BillSettlementReportService);
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private toCsv = inject(ToCsvService); private toCsv = inject(ToCsvService);
startDate = input(null, { transform: (v: string | null | undefined) => v ?? null }); startDate = input(null, { transform: (v: string | null | undefined) => v ?? null });
@@ -18,7 +18,7 @@
<mat-form-field class="flex-auto"> <mat-form-field class="flex-auto">
<mat-label>Menu Category</mat-label> <mat-label>Menu Category</mat-label>
<mat-select [formField]="form.menuCategory" (selectionChange)="filterOn($event.value)"> <mat-select [formField]="form.menuCategory">
<mat-option>-- All Bundles --</mat-option> <mat-option>-- All Bundles --</mat-option>
@for (mc of menuCategoriesResource.value(); track mc) { @for (mc of menuCategoriesResource.value(); track mc) {
<mat-option [value]="mc.id"> <mat-option [value]="mc.id">
@@ -45,7 +45,7 @@ export class BundleListComponent {
menuCategoriesResource = this.menuCategoryService.list(); menuCategoriesResource = this.menuCategoryService.list();
listResource = this.bundleService.list(); listResource = this.bundleService.list();
menuCategoryFilter = signal<string>(''); menuCategoryFilter = computed(() => this.formModel().menuCategory);
formModel = signal<BundleListFormData>({ formModel = signal<BundleListFormData>({
menuCategory: '', menuCategory: '',
@@ -69,10 +69,6 @@ export class BundleListComponent {
displayedColumns: string[] = ['name', 'price', 'menuCategory', 'saleCategory', 'info', 'items']; displayedColumns: string[] = ['name', 'price', 'menuCategory', 'saleCategory', 'info', 'items'];
filterOn(val: string) {
this.menuCategoryFilter.set(val);
}
exportCsv() { exportCsv() {
const headers = { const headers = {
Name: 'name', Name: 'name',
@@ -10,7 +10,7 @@ import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import moment from 'moment'; import moment from 'moment';
import { User } from '../core/user'; import { User } from '../core/user';
@@ -42,7 +42,6 @@ export interface CashierReportFormData {
], ],
}) })
export class CashierReportComponent { export class CashierReportComponent {
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private toCsv = inject(ToCsvService); private toCsv = inject(ToCsvService);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
+1 -1
View File
@@ -5,7 +5,7 @@ import { AuthService } from '../auth/auth.service';
export const jwtInterceptor: HttpInterceptorFn = (req, next) => { export const jwtInterceptor: HttpInterceptorFn = (req, next) => {
// add authorization header with jwt token if available // add authorization header with jwt token if available
const currentUser = inject(AuthService).user; const currentUser = inject(AuthService).user();
if (currentUser?.access_token) { if (currentUser?.access_token) {
req = req.clone({ req = req.clone({
setHeaders: { setHeaders: {
+3 -3
View File
@@ -5,11 +5,11 @@ import { AuthService } from '../auth/auth.service';
export const refreshInterceptor: HttpInterceptorFn = (req, next) => { export const refreshInterceptor: HttpInterceptorFn = (req, next) => {
const authService = inject(AuthService); const authService = inject(AuthService);
if (!authService.isRefreshing && authService.user && authService.needsRefreshing()) { if (!authService.isRefreshing() && authService.user() && authService.needsRefreshing()) {
authService.isRefreshing = true; authService.isRefreshing.set(true);
authService.refreshToken().subscribe({ authService.refreshToken().subscribe({
next: () => { next: () => {
authService.isRefreshing = false; authService.isRefreshing.set(false);
}, },
}); });
} }
@@ -8,7 +8,7 @@ import { MatDividerModule } from '@angular/material/divider';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import { round } from 'mathjs'; import { round } from 'mathjs';
import { Customer } from '../../core/customer'; import { Customer } from '../../core/customer';
@@ -40,7 +40,6 @@ export interface CustomerDetailFormData {
], ],
}) })
export class CustomerDetailComponent { export class CustomerDetailComponent {
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
private dialog = inject(MatDialog); private dialog = inject(MatDialog);
@@ -65,8 +64,6 @@ export class CustomerDetailComponent {
form = form(this.formModel); form = form(this.formModel);
hide = true;
constructor() { constructor() {
afterNextRender(() => { afterNextRender(() => {
this.form().focusBoundControl(); this.form().focusBoundControl();
@@ -8,7 +8,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import { Device } from '../../core/device'; import { Device } from '../../core/device';
import { Section } from '../../core/section'; import { Section } from '../../core/section';
@@ -40,7 +40,6 @@ export interface DeviceDetailFormData {
}) })
export class DeviceDetailComponent { export class DeviceDetailComponent {
private sectionService = inject(SectionService); private sectionService = inject(SectionService);
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private dialog = inject(MatDialog); private dialog = inject(MatDialog);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
@@ -2,7 +2,7 @@ import { Component, inject, computed } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { LocalTimePipe } from '../../shared/local-time.pipe'; import { LocalTimePipe } from '../../shared/local-time.pipe';
import { DeviceService } from '../device.service'; import { DeviceService } from '../device.service';
@@ -14,7 +14,6 @@ import { DeviceService } from '../device.service';
}) })
export class DeviceListComponent { export class DeviceListComponent {
private deviceService = inject(DeviceService); private deviceService = inject(DeviceService);
private route = inject(ActivatedRoute);
listResource = this.deviceService.list(); listResource = this.deviceService.list();
dataSource = computed(() => this.listResource.value() ?? []); dataSource = computed(() => this.listResource.value() ?? []);
@@ -8,7 +8,7 @@ import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import moment from 'moment'; import moment from 'moment';
import { ToCsvService } from '../shared/to-csv.service'; import { ToCsvService } from '../shared/to-csv.service';
@@ -36,7 +36,6 @@ export interface DiscountReportFormData {
], ],
}) })
export class DiscountReportComponent { export class DiscountReportComponent {
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private toCsv = inject(ToCsvService); private toCsv = inject(ToCsvService);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
@@ -9,7 +9,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTimepickerModule } from '@angular/material/timepicker'; import { MatTimepickerModule } from '@angular/material/timepicker';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import moment from 'moment'; import moment from 'moment';
import { Customer } from '../../core/customer'; import { Customer } from '../../core/customer';
@@ -44,7 +44,6 @@ export interface GuestBookDetailFormData {
], ],
}) })
export class GuestBookDetailComponent { export class GuestBookDetailComponent {
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private dialog = inject(MatDialog); private dialog = inject(MatDialog);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
@@ -5,7 +5,6 @@ import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, Router, RouterLink } from '@angular/router'; import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import moment from 'moment'; import moment from 'moment';
@@ -37,7 +36,6 @@ export interface GuestBookListFormData {
export class GuestBookListComponent { export class GuestBookListComponent {
private route = inject(ActivatedRoute); private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private snackBar = inject(MatSnackBar);
private ser = inject(GuestBookService); private ser = inject(GuestBookService);
date = input(new Date(), { date = input(new Date(), {
@@ -2,13 +2,12 @@ import { Component, computed, inject, linkedSignal, input } from '@angular/core'
import { form, FormField } from '@angular/forms/signals'; import { form, FormField } from '@angular/forms/signals';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatOptionModule } from '@angular/material/core'; import { MatOptionModule } from '@angular/material/core';
import { MatDialog } from '@angular/material/dialog';
import { MatDividerModule } from '@angular/material/divider'; import { MatDividerModule } from '@angular/material/divider';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatSelectChange, MatSelectModule } from '@angular/material/select'; import { MatSelectChange, MatSelectModule } from '@angular/material/select';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import { HeaderFooter } from './header-footer'; import { HeaderFooter } from './header-footer';
import { HeaderFooterService } from './header-footer.service'; import { HeaderFooterService } from './header-footer.service';
@@ -33,10 +32,8 @@ export interface HeaderFooterFormData {
], ],
}) })
export class HeaderFooterComponent { export class HeaderFooterComponent {
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
private dialog = inject(MatDialog);
private ser = inject(HeaderFooterService); private ser = inject(HeaderFooterService);
id = input(null, { transform: (v: string | null | undefined) => v ?? null }); id = input(null, { transform: (v: string | null | undefined) => v ?? null });
listResource = this.ser.list(); listResource = this.ser.list();
+1 -1
View File
@@ -198,7 +198,7 @@
</div> </div>
<footer class="footer"> <footer class="footer">
<p> <p>
Backend: v{{ auth.user?.ver }} / Frontend: v{{ version }} on {{ auth.device.name }} &#64; Backend: v{{ auth.user()?.ver }} / Frontend: v{{ version }} on {{ auth.device.name }} &#64;
{{ auth.device.section.name }} {{ auth.device.section.name }}
</p> </p>
</footer> </footer>
@@ -6,7 +6,7 @@ import { MatDialog } from '@angular/material/dialog';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import { MenuCategory } from '../../core/menu-category'; import { MenuCategory } from '../../core/menu-category';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component'; import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
@@ -24,7 +24,6 @@ export interface MenuCategoryDetailFormData {
imports: [MatButtonModule, MatCheckboxModule, MatFormFieldModule, MatInputModule, FormField], imports: [MatButtonModule, MatCheckboxModule, MatFormFieldModule, MatInputModule, FormField],
}) })
export class MenuCategoryDetailComponent { export class MenuCategoryDetailComponent {
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private dialog = inject(MatDialog); private dialog = inject(MatDialog);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
@@ -4,7 +4,7 @@ import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, Router, RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { firstValueFrom } from 'rxjs'; import { firstValueFrom } from 'rxjs';
import { MenuCategory } from '../../core/menu-category'; import { MenuCategory } from '../../core/menu-category';
@@ -16,8 +16,6 @@ import { MenuCategoryService } from '../menu-category.service';
imports: [DragDropModule, MatButtonModule, MatIconModule, MatTableModule, RouterLink], imports: [DragDropModule, MatButtonModule, MatIconModule, MatTableModule, RouterLink],
}) })
export class MenuCategoryListComponent { export class MenuCategoryListComponent {
private route = inject(ActivatedRoute);
private router = inject(Router);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
private ser = inject(MenuCategoryService); private ser = inject(MenuCategoryService);
listResource = this.ser.list(undefined); listResource = this.ser.list(undefined);
@@ -9,7 +9,7 @@ import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTreeModule, MatTreeNestedDataSource } from '@angular/material/tree'; import { MatTreeModule, MatTreeNestedDataSource } from '@angular/material/tree';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import { ModifierCategory, MenuCategory, StockKeepingUnitLink } from '../../core/modifier-category'; import { ModifierCategory, MenuCategory, StockKeepingUnitLink } from '../../core/modifier-category';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component'; import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
@@ -49,7 +49,6 @@ export interface ModifierCategoryDetailFormData {
], ],
}) })
export class ModifierCategoryDetailComponent { export class ModifierCategoryDetailComponent {
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
private dialog = inject(MatDialog); private dialog = inject(MatDialog);
@@ -112,11 +111,6 @@ export class ModifierCategoryDetailComponent {
}); });
} }
// eslint-disable-next-line @typescript-eslint/no-unused-vars
isExpanded(mc: MenuCategory) {
return true;
}
save() { save() {
this.ser.saveOrUpdate(this.getItem()).subscribe({ this.ser.saveOrUpdate(this.getItem()).subscribe({
next: () => { next: () => {
@@ -2,7 +2,7 @@ import { Component, inject, computed } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { ModifierCategoryService } from '../modifier-category.service'; import { ModifierCategoryService } from '../modifier-category.service';
@Component({ @Component({
@@ -13,7 +13,6 @@ import { ModifierCategoryService } from '../modifier-category.service';
}) })
export class ModifierCategoryListComponent { export class ModifierCategoryListComponent {
private modifierCategoryService = inject(ModifierCategoryService); private modifierCategoryService = inject(ModifierCategoryService);
private route = inject(ActivatedRoute);
listResource = this.modifierCategoryService.list(); listResource = this.modifierCategoryService.list();
dataSource = computed(() => this.listResource.value() ?? []); dataSource = computed(() => this.listResource.value() ?? []);
@@ -8,7 +8,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import { Modifier } from '../../core/modifier'; import { Modifier } from '../../core/modifier';
import { ModifierCategory } from '../../core/modifier-category'; import { ModifierCategory } from '../../core/modifier-category';
@@ -40,7 +40,6 @@ export interface ModifierDetailFormData {
}) })
export class ModifierDetailComponent { export class ModifierDetailComponent {
private modifierCategoryService = inject(ModifierCategoryService); private modifierCategoryService = inject(ModifierCategoryService);
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private dialog = inject(MatDialog); private dialog = inject(MatDialog);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
@@ -9,7 +9,7 @@
<div class="row-container"> <div class="row-container">
<mat-form-field class="flex-auto"> <mat-form-field class="flex-auto">
<mat-label>Modifier Category</mat-label> <mat-label>Modifier Category</mat-label>
<mat-select (selectionChange)="filterOn($event)"> <mat-select [formField]="form.menuCategory">
<mat-option>-- All Categories --</mat-option> <mat-option>-- All Categories --</mat-option>
@for (mc of modifierCategories(); track mc.id) { @for (mc of modifierCategories(); track mc.id) {
<mat-option [value]="mc.id"> <mat-option [value]="mc.id">
@@ -1,16 +1,21 @@
import { CurrencyPipe } from '@angular/common'; import { CurrencyPipe } from '@angular/common';
import { Component, inject, computed, signal } from '@angular/core'; import { Component, inject, computed, signal } from '@angular/core';
import { form, FormField } from '@angular/forms/signals';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatOptionModule } from '@angular/material/core'; import { MatOptionModule } from '@angular/material/core';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatSelectChange, MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { ModifierCategoryService } from '../../modifier-categories/modifier-category.service'; import { ModifierCategoryService } from '../../modifier-categories/modifier-category.service';
import { ModifierService } from '../modifier.service'; import { ModifierService } from '../modifier.service';
export interface ModifierListFormData {
menuCategory: string | null;
}
@Component({ @Component({
selector: 'app-modifier-list', selector: 'app-modifier-list',
templateUrl: './modifier-list.component.html', templateUrl: './modifier-list.component.html',
@@ -23,6 +28,7 @@ import { ModifierService } from '../modifier.service';
MatOptionModule, MatOptionModule,
MatSelectModule, MatSelectModule,
MatTableModule, MatTableModule,
FormField,
RouterLink, RouterLink,
], ],
}) })
@@ -34,11 +40,18 @@ export class ModifierListComponent {
listResource = this.modifierService.list(); listResource = this.modifierService.list();
modifierCategories = computed(() => this.modifierCategoriesResource.value() ?? []); modifierCategories = computed(() => this.modifierCategoriesResource.value() ?? []);
filter = signal<string>('');
formModel = signal<ModifierListFormData>({
menuCategory: '',
});
form = form(this.formModel);
menuCategoryFilter = computed(() => this.formModel().menuCategory);
dataSource = computed(() => { dataSource = computed(() => {
const items = this.listResource.value() ?? []; const items = this.listResource.value() ?? [];
const cat = this.filter(); const cat = this.menuCategoryFilter();
if (cat) { if (cat) {
return items.filter((x) => x.modifierCategory?.id === cat); return items.filter((x) => x.modifierCategory?.id === cat);
} }
@@ -47,8 +60,4 @@ export class ModifierListComponent {
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */ /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns: string[] = ['name', 'showInBill', 'price', 'isActive', 'modifierCategory']; displayedColumns: string[] = ['name', 'showInBill', 'price', 'isActive', 'modifierCategory'];
filterOn(val: MatSelectChange): void {
this.filter.set(val.value);
}
} }
@@ -16,13 +16,13 @@
</a> </a>
} }
<span class="spacer"></span> <span class="spacer"></span>
@if ((auth.currentUser | async) === null) { @if (auth.user() === null) {
<button mat-button [routerLink]="['/', 'login']"> <button mat-button [routerLink]="['/', 'login']">
<mat-icon>account_box</mat-icon> <mat-icon>account_box</mat-icon>
Login Login
</button> </button>
} }
@if ((auth.currentUser | async)?.name; as name) { @if (auth.user()?.name; as name) {
<button mat-button [routerLink]="['/', 'logout']"> <button mat-button [routerLink]="['/', 'logout']">
<mat-icon>account_box</mat-icon> <mat-icon>account_box</mat-icon>
Logout {{ name }} Logout {{ name }}
+1 -2
View File
@@ -1,4 +1,3 @@
import { AsyncPipe } from '@angular/common';
import { Component, inject } from '@angular/core'; import { Component, inject } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
@@ -11,7 +10,7 @@ import { AuthService } from '../auth/auth.service';
selector: 'app-nav-bar', selector: 'app-nav-bar',
templateUrl: './nav-bar.component.html', templateUrl: './nav-bar.component.html',
styleUrls: ['./nav-bar.component.css'], styleUrls: ['./nav-bar.component.css'],
imports: [AsyncPipe, MatButtonModule, MatButtonModule, MatIconModule, MatToolbarModule, RouterLink], imports: [MatButtonModule, MatIconModule, MatToolbarModule, RouterLink],
}) })
export class NavBarComponent { export class NavBarComponent {
private router = inject(Router); private router = inject(Router);
@@ -5,7 +5,7 @@ import { MatDialog } from '@angular/material/dialog';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import { Printer } from '../../core/printer'; import { Printer } from '../../core/printer';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component'; import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
@@ -24,7 +24,6 @@ export interface PrinterDetailFormData {
imports: [MatButtonModule, MatFormFieldModule, MatInputModule, FormField], imports: [MatButtonModule, MatFormFieldModule, MatInputModule, FormField],
}) })
export class PrinterDetailComponent { export class PrinterDetailComponent {
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private dialog = inject(MatDialog); private dialog = inject(MatDialog);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
@@ -2,7 +2,7 @@ import { Component, inject, computed } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { PrinterService } from '../printer.service'; import { PrinterService } from '../printer.service';
@Component({ @Component({
@@ -13,7 +13,6 @@ import { PrinterService } from '../printer.service';
}) })
export class PrinterListComponent { export class PrinterListComponent {
private printerService = inject(PrinterService); private printerService = inject(PrinterService);
private route = inject(ActivatedRoute);
listResource = this.printerService.list(); listResource = this.printerService.list();
dataSource = computed(() => this.listResource.value() ?? []); dataSource = computed(() => this.listResource.value() ?? []);
@@ -9,7 +9,7 @@ import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import moment from 'moment'; import moment from 'moment';
import { SectionService } from '../sections/section.service'; import { SectionService } from '../sections/section.service';
@@ -42,7 +42,6 @@ export interface ProductSaleReportFormData {
}) })
export class ProductSaleReportComponent { export class ProductSaleReportComponent {
private sectionService = inject(SectionService); private sectionService = inject(SectionService);
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private toCsv = inject(ToCsvService); private toCsv = inject(ToCsvService);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
@@ -6,7 +6,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import moment from 'moment'; import moment from 'moment';
import { ToCsvService } from '../shared/to-csv.service'; import { ToCsvService } from '../shared/to-csv.service';
@@ -34,7 +34,6 @@ export interface ProductUpdatesReportFormData {
}) })
export class ProductUpdatesReportComponent { export class ProductUpdatesReportComponent {
private productUpdatesReportService = inject(ProductUpdatesReportService); private productUpdatesReportService = inject(ProductUpdatesReportService);
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private toCsv = inject(ToCsvService); private toCsv = inject(ToCsvService);
startDate = input(null, { transform: (v: string | null | undefined) => v ?? null }); startDate = input(null, { transform: (v: string | null | undefined) => v ?? null });
@@ -11,7 +11,7 @@ import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import { MenuCategory } from '../../core/menu-category'; import { MenuCategory } from '../../core/menu-category';
import { Product, StockKeepingUnit } from '../../core/product'; import { Product, StockKeepingUnit } from '../../core/product';
@@ -60,7 +60,6 @@ export interface ProductDetailFormData {
export class ProductDetailComponent { export class ProductDetailComponent {
private menuCategoryService = inject(MenuCategoryService); private menuCategoryService = inject(MenuCategoryService);
private saleCategoryService = inject(SaleCategoryService); private saleCategoryService = inject(SaleCategoryService);
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private dialog = inject(MatDialog); private dialog = inject(MatDialog);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
@@ -258,13 +257,3 @@ export class ProductDetailComponent {
}); });
} }
} }
// if (this.item().menuCategory === null || this.item().menuCategory === undefined) {
// this.item().menuCategory = new MenuCategory();
// }
// this.item().menuCategory.id = formModel.menuCategory;
// this.item().price = formModel.price ?? 0;
// this.item().hasHappyHour = formModel.hasHappyHour ?? false;
// this.item().isNotAvailable = formModel.isNotAvailable ?? false;
// this.item().quantity = formModel.quantity ?? 0;
@@ -25,7 +25,7 @@
</mat-form-field> </mat-form-field>
<mat-form-field class="flex-auto"> <mat-form-field class="flex-auto">
<mat-label>Menu Category</mat-label> <mat-label>Menu Category</mat-label>
<mat-select [formField]="form.menuCategory" (selectionChange)="filterOn($event.value)"> <mat-select [formField]="form.menuCategory">
<mat-option>-- All Products --</mat-option> <mat-option>-- All Products --</mat-option>
@for (mc of menuCategoriesResource.value(); track mc) { @for (mc of menuCategoriesResource.value(); track mc) {
<mat-option [value]="mc.id"> <mat-option [value]="mc.id">
@@ -52,8 +52,6 @@ export class ProductListComponent {
listResource = this.ser.list(); listResource = this.ser.list();
menuCategoryFilter = signal<string>('');
formModel = signal<ProductListFormData>({ formModel = signal<ProductListFormData>({
menuCategory: '', menuCategory: '',
filter: '', filter: '',
@@ -61,6 +59,8 @@ export class ProductListComponent {
form = form(this.formModel); form = form(this.formModel);
menuCategoryFilter = computed(() => this.formModel().menuCategory ?? '');
filterSignal = computed(() => this.formModel().filter); filterSignal = computed(() => this.formModel().filter);
debouncedFilter = debounced(this.filterSignal, 150); debouncedFilter = debounced(this.filterSignal, 150);
@@ -81,10 +81,6 @@ export class ProductListComponent {
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */ /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns: string[] = ['name', 'price', 'menuCategory', 'saleCategory', 'info', 'quantity']; displayedColumns: string[] = ['name', 'price', 'menuCategory', 'saleCategory', 'info', 'quantity'];
filterOn(val: string): void {
this.menuCategoryFilter.set(val);
}
async updateSortOrder() { async updateSortOrder() {
try { try {
await firstValueFrom(this.ser.updateSortOrder(this.menuCategoryFilter(), this.dataSource())); await firstValueFrom(this.ser.updateSortOrder(this.menuCategoryFilter(), this.dataSource()));
@@ -5,7 +5,7 @@ import { MatDialog } from '@angular/material/dialog';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import { Regime } from '../../core/regime'; import { Regime } from '../../core/regime';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component'; import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
@@ -24,7 +24,6 @@ export interface RegimeDetailFormData {
imports: [MatButtonModule, MatFormFieldModule, MatInputModule, FormField], imports: [MatButtonModule, MatFormFieldModule, MatInputModule, FormField],
}) })
export class RegimeDetailComponent { export class RegimeDetailComponent {
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private dialog = inject(MatDialog); private dialog = inject(MatDialog);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
@@ -2,7 +2,7 @@ import { Component, inject, computed } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { RegimeService } from '../regime.service'; import { RegimeService } from '../regime.service';
@Component({ @Component({
@@ -13,7 +13,6 @@ import { RegimeService } from '../regime.service';
}) })
export class RegimeListComponent { export class RegimeListComponent {
private regimeService = inject(RegimeService); private regimeService = inject(RegimeService);
private route = inject(ActivatedRoute);
listResource = this.regimeService.list(); listResource = this.regimeService.list();
dataSource = computed(() => this.listResource.value() ?? []); dataSource = computed(() => this.listResource.value() ?? []);
@@ -6,7 +6,7 @@ import { MatDialog } from '@angular/material/dialog';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component'; import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
import { Role } from '../role'; import { Role } from '../role';
@@ -25,7 +25,6 @@ export interface RoleDetailFormData {
imports: [MatButtonModule, MatCheckboxModule, MatFormFieldModule, MatInputModule, FormField], imports: [MatButtonModule, MatCheckboxModule, MatFormFieldModule, MatInputModule, FormField],
}) })
export class RoleDetailComponent { export class RoleDetailComponent {
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
private dialog = inject(MatDialog); private dialog = inject(MatDialog);
@@ -2,7 +2,7 @@ import { Component, inject, computed } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { RoleService } from '../role.service'; import { RoleService } from '../role.service';
@Component({ @Component({
@@ -13,7 +13,6 @@ import { RoleService } from '../role.service';
}) })
export class RoleListComponent { export class RoleListComponent {
private roleService = inject(RoleService); private roleService = inject(RoleService);
private route = inject(ActivatedRoute);
listResource = this.roleService.list(); listResource = this.roleService.list();
dataSource = computed(() => this.listResource.value() ?? []); dataSource = computed(() => this.listResource.value() ?? []);
@@ -10,7 +10,7 @@ import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, Router, RouterLink } from '@angular/router'; import { Router, RouterLink } from '@angular/router';
import { round } from 'mathjs'; import { round } from 'mathjs';
import { SaleCategory } from '../../core/sale-category'; import { SaleCategory } from '../../core/sale-category';
@@ -46,7 +46,6 @@ export interface SaleCategoryDetailFormData {
export class SaleCategoryDetailComponent { export class SaleCategoryDetailComponent {
private taxService = inject(TaxService); private taxService = inject(TaxService);
private productService = inject(ProductService); private productService = inject(ProductService);
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private dialog = inject(MatDialog); private dialog = inject(MatDialog);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
@@ -2,9 +2,8 @@ import { PercentPipe } from '@angular/common';
import { Component, inject, computed } from '@angular/core'; import { Component, inject, computed } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, Router, RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { SaleCategoryService } from '../sale-category.service'; import { SaleCategoryService } from '../sale-category.service';
@Component({ @Component({
@@ -14,9 +13,6 @@ import { SaleCategoryService } from '../sale-category.service';
imports: [MatButtonModule, MatIconModule, MatTableModule, PercentPipe, RouterLink], imports: [MatButtonModule, MatIconModule, MatTableModule, PercentPipe, RouterLink],
}) })
export class SaleCategoryListComponent { export class SaleCategoryListComponent {
private route = inject(ActivatedRoute);
private router = inject(Router);
private snackBar = inject(MatSnackBar);
private ser = inject(SaleCategoryService); private ser = inject(SaleCategoryService);
listResource = this.ser.list(); listResource = this.ser.list();
@@ -10,7 +10,7 @@ import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import moment from 'moment'; import moment from 'moment';
import { SectionService } from '../sections/section.service'; import { SectionService } from '../sections/section.service';
@@ -43,7 +43,6 @@ export interface SaleReportFormData {
}) })
export class SaleReportComponent { export class SaleReportComponent {
private sectionService = inject(SectionService); private sectionService = inject(SectionService);
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private toCsv = inject(ToCsvService); private toCsv = inject(ToCsvService);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
@@ -1,5 +1,5 @@
import { ScrollingModule } from '@angular/cdk/scrolling'; import { ScrollingModule } from '@angular/cdk/scrolling';
import { Component, OnInit, inject, signal } from '@angular/core'; import { Component, inject, signal } from '@angular/core';
import { form, FormField } from '@angular/forms/signals'; import { form, FormField } from '@angular/forms/signals';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatOptionModule } from '@angular/material/core'; import { MatOptionModule } from '@angular/material/core';
@@ -30,39 +30,23 @@ export interface BillNumberFormData {
ScrollingModule, ScrollingModule,
], ],
}) })
export class BillNumberComponent implements OnInit { export class BillNumberComponent {
data = inject(MAT_DIALOG_DATA); regimes = inject<Regime[]>(MAT_DIALOG_DATA) ?? [];
dialogRef = inject<MatDialogRef<BillNumberComponent>>(MatDialogRef); private dialogRef = inject<MatDialogRef<BillNumberComponent>>(MatDialogRef);
formModel = signal<BillNumberFormData>({ formModel = signal<BillNumberFormData>({
regime: null, regime: null,
billNumber: null, billNumber: 0,
}); });
form = form(this.formModel); form = form(this.formModel);
regimes: Regime[] = [];
constructor() {
const data = this.data;
this.regimes = data;
// Create form
}
ngOnInit() {
this.formModel.set({
regime: null,
billNumber: 0,
});
}
accept(): void { accept(): void {
const formValue = this.formModel(); const { regime, billNumber } = this.formModel();
const billNumber = formValue.billNumber ?? 0; if (!regime) {
const regime = formValue.regime ?? null;
if (regime == null) {
this.dialogRef.close(undefined); this.dialogRef.close(undefined);
return;
} }
this.dialogRef.close(`${regime?.prefix}-${billNumber}`); this.dialogRef.close(`${regime.prefix}-${billNumber ?? 0}`);
} }
} }
+106 -95
View File
@@ -1,10 +1,9 @@
import { SelectionModel } from '@angular/cdk/collections'; import { SelectionModel } from '@angular/cdk/collections';
import { Injectable, Injector, computed, inject, signal } from '@angular/core'; import { Injectable, Injector, computed, effect, inject, signal } from '@angular/core';
import { toObservable } from '@angular/core/rxjs-interop';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { Observable, throwError } from 'rxjs'; import { Observable, throwError } from 'rxjs';
import { filter, take, tap } from 'rxjs/operators'; import { tap } from 'rxjs/operators';
import { ModifierCategory } from '../core/modifier-category'; import { ModifierCategory } from '../core/modifier-category';
import { ProductQuery } from '../core/product-query'; import { ProductQuery } from '../core/product-query';
@@ -32,8 +31,8 @@ export class BillService {
private modifierCategoryService = inject(ModifierCategoryService); private modifierCategoryService = inject(ModifierCategoryService);
private injector = inject(Injector); private injector = inject(Injector);
public data = signal<Kot[]>([]); public bill = signal<Bill>(new Bill());
public bill: Bill = new Bill(); public data = computed(() => this.bill().kots);
private originalBill: Bill = new Bill(); private originalBill: Bill = new Bill();
public grossAmount = computed(() => public grossAmount = computed(() =>
@@ -75,32 +74,29 @@ export class BillService {
public amount = computed(() => this.grossAmount() - this.discountAmount() + this.taxAmount()); public amount = computed(() => this.grossAmount() - this.discountAmount() + this.taxAmount());
public selection = new SelectionModel<string>(true, []); public selection = new SelectionModel<string>(true, []);
private updateTable: boolean; private updateTable = signal<boolean>(true);
private allowDeactivate: boolean; private allowDeactivate = signal<boolean>(false);
// To disable Deactivate Guard on navigation after printing bill or kot. // To disable Deactivate Guard on navigation after printing bill or kot.
constructor() {
this.updateTable = true;
this.allowDeactivate = false;
}
displayBill(): void {
this.allowDeactivate = false;
this.data.set([...this.bill.kots]);
}
loadData(bill: Bill, updateTable: boolean): void { loadData(bill: Bill, updateTable: boolean): void {
this.updateTable = updateTable; this.updateTable.set(updateTable);
bill.kots.push(new Kot()); bill.kots.push(new Kot());
this.bill = bill; this.originalBill = JSON.parse(JSON.stringify(bill));
this.originalBill = JSON.parse(JSON.stringify(this.bill));
this.selection.clear(); this.selection.clear();
this.displayBill(); this.bill.set(bill);
this.allowDeactivate.set(false);
}
reset(): void {
this.bill.set(new Bill());
this.originalBill = new Bill();
this.selection.clear();
this.allowDeactivate.set(false);
} }
minimum(skuId: string, happyHour: boolean): number { minimum(skuId: string, happyHour: boolean): number {
return this.bill.kots.reduce( return this.bill().kots.reduce(
(t, k) => (t, k) =>
k.inventories k.inventories
.filter((i) => i.sku.id === skuId && i.isHappyHour === happyHour) .filter((i) => i.sku.id === skuId && i.isHappyHour === happyHour)
@@ -112,7 +108,7 @@ export class BillService {
addOneSku(sku: ProductQuery): void { addOneSku(sku: ProductQuery): void {
const quantity = 1; const quantity = 1;
const discount = 0; const discount = 0;
const newKot = this.bill.kots.find((k) => k.id === undefined) as Kot; const newKot = this.bill().kots.find((k) => k.id === undefined) as Kot;
const old = newKot.inventories.find( const old = newKot.inventories.find(
(x) => (x) =>
x.sku.id === sku.id && x.isHappyHour === sku.hasHappyHour && x.type === (sku.isBundle ? 'bundle' : 'regular'), x.sku.id === sku.id && x.isHappyHour === sku.hasHappyHour && x.type === (sku.isBundle ? 'bundle' : 'regular'),
@@ -155,18 +151,21 @@ export class BillService {
} }
newKot.inventories.push(item); newKot.inventories.push(item);
const modRes = this.modifierCategoryService.listForSku(signal(sku.id as string)); const modRes = this.modifierCategoryService.listForSku(signal(sku.id as string));
toObservable(modRes.value, { injector: this.injector }) const effectRef = effect(
.pipe( () => {
filter((result): result is ModifierCategory[] => !!result), const result = modRes.value();
take(1), if (result) {
) if (result.reduce((a: number, c: ModifierCategory) => a + c.minimum, 0)) {
.subscribe((result) => { this.showModifier(item);
if (result.reduce((a: number, c: ModifierCategory) => a + c.minimum, 0)) { }
this.showModifier(item); effectRef.destroy();
} }
}); },
{ injector: this.injector },
);
} }
this.displayBill(); this.allowDeactivate.set(false);
this.bill.update((b) => new Bill({ ...b, kots: [...b.kots] }));
} }
showModifier(item: Inventory): void { showModifier(item: Inventory): void {
@@ -188,7 +187,8 @@ export class BillService {
if (result !== undefined) { if (result !== undefined) {
item.modifiers = result; item.modifiers = result;
} }
this.displayBill(); this.allowDeactivate.set(false);
this.bill.update((b) => new Bill({ ...b, kots: [...b.kots] }));
}); });
} }
@@ -200,7 +200,8 @@ export class BillService {
child.quantity += old.sku.bundleItems.find((bi) => bi.id === child.sku.id)?.quantity || 0; child.quantity += old.sku.bundleItems.find((bi) => bi.id === child.sku.id)?.quantity || 0;
}); });
} }
this.displayBill(); this.allowDeactivate.set(false);
this.bill.update((b) => new Bill({ ...b, kots: [...b.kots] }));
} }
quantity(item: BillRow, quantity: number): void { quantity(item: BillRow, quantity: number): void {
@@ -211,7 +212,8 @@ export class BillService {
child.quantity = (old.sku.bundleItems.find((bi) => bi.id === child.sku.id)?.quantity || 0) * quantity; child.quantity = (old.sku.bundleItems.find((bi) => bi.id === child.sku.id)?.quantity || 0) * quantity;
}); });
} }
this.displayBill(); this.allowDeactivate.set(false);
this.bill.update((b) => new Bill({ ...b, kots: [...b.kots] }));
} }
subtractOne(item: BillRow, canEdit: boolean): void { subtractOne(item: BillRow, canEdit: boolean): void {
@@ -230,14 +232,16 @@ export class BillService {
} else if (old.quantity === 0) { } else if (old.quantity === 0) {
newKot.inventories.splice(newKot.inventories.indexOf(old), 1); newKot.inventories.splice(newKot.inventories.indexOf(old), 1);
} }
this.displayBill(); this.allowDeactivate.set(false);
this.bill.update((b) => new Bill({ ...b, kots: [...b.kots] }));
} }
removeItem(item: BillRow): void { removeItem(item: BillRow): void {
const newKot = item.kot as Kot; const newKot = item.kot as Kot;
const old = item.inv as Inventory; const old = item.inv as Inventory;
newKot.inventories.splice(newKot.inventories.indexOf(old), 1); newKot.inventories.splice(newKot.inventories.indexOf(old), 1);
this.displayBill(); this.allowDeactivate.set(false);
this.bill.update((b) => new Bill({ ...b, kots: [...b.kots] }));
} }
modifier(item: BillRow): void { modifier(item: BillRow): void {
@@ -246,7 +250,7 @@ export class BillService {
} }
discount(discounts: { id: string; name: string; discount: number }[]): void { discount(discounts: { id: string; name: string; discount: number }[]): void {
for (const kot of this.bill.kots) { for (const kot of this.bill().kots) {
const noDiscount = kot.inventories.filter((x) => x.isHappyHour).map((x) => x.sku.id as string); const noDiscount = kot.inventories.filter((x) => x.isHappyHour).map((x) => x.sku.id as string);
for (const inventory of kot.inventories) { for (const inventory of kot.inventories) {
if (noDiscount.indexOf(inventory.sku.id as string) !== -1) { if (noDiscount.indexOf(inventory.sku.id as string) !== -1) {
@@ -259,7 +263,8 @@ export class BillService {
} }
} }
} }
this.displayBill(); this.allowDeactivate.set(false);
this.bill.update((b) => new Bill({ ...b, kots: [...b.kots] }));
} }
isBillDiffent(bill: Bill, guestBookId: string | null): boolean { isBillDiffent(bill: Bill, guestBookId: string | null): boolean {
@@ -282,7 +287,7 @@ export class BillService {
} }
printKot(guestBookId: string | null): Observable<boolean> { printKot(guestBookId: string | null): Observable<boolean> {
const item = JSON.parse(JSON.stringify(this.bill)); const item = JSON.parse(JSON.stringify(this.bill()));
if (!this.isBillDiffent(item, guestBookId)) { if (!this.isBillDiffent(item, guestBookId)) {
return throwError(() => Error('Cannot print a blank KOT\nPlease add some products!')); return throwError(() => Error('Cannot print a blank KOT\nPlease add some products!'));
} }
@@ -290,12 +295,12 @@ export class BillService {
return throwError(() => Error('Happy hour products are not balanced.')); return throwError(() => Error('Happy hour products are not balanced.'));
} }
return this.ser return this.ser
.saveOrUpdate(item, VoucherType.Kot, guestBookId, this.updateTable) .saveOrUpdate(item, VoucherType.Kot, guestBookId, this.updateTable())
.pipe(tap(() => (this.allowDeactivate = true))); .pipe(tap(() => this.allowDeactivate.set(true)));
} }
printBill(guestBookId: string | null, voucherType: VoucherType): Observable<boolean> { printBill(guestBookId: string | null, voucherType: VoucherType): Observable<boolean> {
const item = JSON.parse(JSON.stringify(this.bill)); const item = JSON.parse(JSON.stringify(this.bill()));
const skus = item.kots.reduce((p: number, k: Kot) => p + k.inventories.filter((i) => i.quantity !== 0).length, 0); const skus = item.kots.reduce((p: number, k: Kot) => p + k.inventories.filter((i) => i.quantity !== 0).length, 0);
if (skus === 0) { if (skus === 0) {
return throwError(() => Error('Cannot print a blank Bill\nPlease add some products!')); return throwError(() => Error('Cannot print a blank Bill\nPlease add some products!'));
@@ -304,41 +309,41 @@ export class BillService {
return throwError(() => Error('Happy hour products are not balanced.')); return throwError(() => Error('Happy hour products are not balanced.'));
} }
return this.ser return this.ser
.saveOrUpdate(item, voucherType, guestBookId, this.updateTable) .saveOrUpdate(item, voucherType, guestBookId, this.updateTable())
.pipe(tap(() => (this.allowDeactivate = true))); .pipe(tap(() => this.allowDeactivate.set(true)));
} }
receivePayment(value: { choices: ReceivePaymentItem[]; reason: string }): Observable<boolean> { receivePayment(value: { choices: ReceivePaymentItem[]; reason: string }): Observable<boolean> {
return this.ser.receivePayment(this.bill.id as string, value.choices, value.reason, this.updateTable); return this.ser.receivePayment(this.bill().id as string, value.choices, value.reason, this.updateTable());
} }
moveTable(table: Table): Observable<boolean> { moveTable(table: Table): Observable<boolean> {
return this.ser.moveTable(this.bill.id as string, table); return this.ser.moveTable(this.bill().id as string, table);
} }
mergeTable(table: Table): Observable<boolean> { mergeTable(table: Table): Observable<boolean> {
return this.ser.mergeTable(this.bill.id as string, table); return this.ser.mergeTable(this.bill().id as string, table);
} }
moveKot(kotId: string, table: Table): Observable<boolean> { moveKot(kotId: string, table: Table): Observable<boolean> {
return this.ser.moveKotToNewTable(this.bill.id as string, kotId, table); return this.ser.moveKotToNewTable(this.bill().id as string, kotId, table);
} }
mergeKot(kotId: string, table: Table): Observable<boolean> { mergeKot(kotId: string, table: Table): Observable<boolean> {
return this.ser.mergeKotWithOldBill(this.bill.id as string, kotId, table); return this.ser.mergeKotWithOldBill(this.bill().id as string, kotId, table);
} }
cancelBill(reason: string): Observable<boolean> { cancelBill(reason: string): Observable<boolean> {
return this.ser.cancelBill(this.bill.id as string, reason, this.updateTable); return this.ser.cancelBill(this.bill().id as string, reason, this.updateTable());
} }
splitBill(inventories: string[], table: Table): Observable<boolean> { splitBill(inventories: string[], table: Table): Observable<boolean> {
return this.ser.splitBill(this.bill.id as string, inventories, table, this.updateTable); return this.ser.splitBill(this.bill().id as string, inventories, table, this.updateTable());
} }
public getInventories(saleCategories: string[]): { move: string[]; keep: string[] } { public getInventories(saleCategories: string[]): { move: string[]; keep: string[] } {
const data: { move: string[]; keep: string[] } = { move: [], keep: [] }; const data: { move: string[]; keep: string[] } = { move: [], keep: [] };
for (const kot of this.bill.kots) { for (const kot of this.bill().kots) {
for (const inv of kot.inventories) { for (const inv of kot.inventories) {
if (saleCategories.indexOf(inv.sku.saleCategory?.id as string) === -1) { if (saleCategories.indexOf(inv.sku.saleCategory?.id as string) === -1) {
data.keep.push(inv.id as string); data.keep.push(inv.id as string);
@@ -350,57 +355,63 @@ export class BillService {
return data; return data;
} }
private happyHourItemsBalanced(): boolean { private happyHourItemsBalanced = computed<boolean>(() => {
return this.bill.kots.every((kot) => { return this.bill().kots.every((kot) => {
const happyHourItems = kot.inventories const happyHourQtyMap = new Map<string, number>();
.filter((x) => x.isHappyHour) const regularQtyMap = new Map<string, number>();
.map((x) => ({ id: x.sku.id as string, quantity: x.quantity }))
.sort((a, b) => (a.id < b.id ? -1 : 1));
const happyHourIds = happyHourItems.map((x) => x.id);
const rest = kot.inventories
.filter((x) => !x.isHappyHour && happyHourIds.indexOf(x.sku.id as string) !== -1)
.map((x) => ({ id: x.sku.id as string, quantity: x.quantity }))
.sort((a, b) => (a.id < b.id ? -1 : 1));
if (happyHourIds.length === 0) {
return true;
}
return (
happyHourItems.length === rest.length &&
happyHourItems.every((v, i) => v.id === rest[i].id && v.quantity === rest[i].quantity)
);
});
}
private regularItemsMoreThanHappyHour(): boolean { for (const item of kot.inventories) {
const id = item.sku.id as string;
if (item.isHappyHour) {
happyHourQtyMap.set(id, (happyHourQtyMap.get(id) ?? 0) + item.quantity);
} else {
regularQtyMap.set(id, (regularQtyMap.get(id) ?? 0) + item.quantity);
}
}
for (const [id, hhQty] of happyHourQtyMap.entries()) {
if (regularQtyMap.get(id) !== hhQty) {
return false;
}
}
return true;
});
});
private regularItemsMoreThanHappyHour = computed<boolean>(() => {
// This is for the whole bill. eg. Kot 1 => Reg 2 + HH 2; Kot 2 => Reg 4; Kot 3 => Reg - 4 // This is for the whole bill. eg. Kot 1 => Reg 2 + HH 2; Kot 2 => Reg 4; Kot 3 => Reg - 4
// This is pass okay in happy hours items balanced, but overall this is wrong. Hence this check // This is pass okay in happy hours items balanced, but overall this is wrong. Hence this check
const inventories = this.bill.kots const happyHourQtyMap = new Map<string, number>();
.flatMap((kot) => kot.inventories) const regularQtyMap = new Map<string, number>();
.reduce((acc: { id: string; quantity: number; isHappyHour: boolean }[], curr) => {
const existing = acc.find((x) => x.id === curr.sku.id && x.isHappyHour === curr.isHappyHour); for (const kot of this.bill().kots) {
if (existing) { for (const item of kot.inventories) {
existing.quantity += curr.quantity; const id = item.sku.id as string;
if (item.isHappyHour) {
happyHourQtyMap.set(id, (happyHourQtyMap.get(id) ?? 0) + item.quantity);
} else { } else {
acc.push({ id: curr.sku.id as string, quantity: curr.quantity, isHappyHour: curr.isHappyHour }); regularQtyMap.set(id, (regularQtyMap.get(id) ?? 0) + item.quantity);
} }
return acc; }
}, []) }
.sort((a, b) => (a.id < b.id ? -1 : 1));
const happyHourItems = inventories.filter((x) => x.isHappyHour); for (const [id, hhQty] of happyHourQtyMap.entries()) {
const happyHourIds = happyHourItems.map((x) => x.id); const regQty = regularQtyMap.get(id) ?? 0;
const rest = inventories.filter((x) => !x.isHappyHour && happyHourIds.indexOf(x.id as string) !== -1); if (regQty < hhQty) {
return ( return false;
happyHourItems.length === rest.length && }
happyHourItems.every((hh, index) => hh.id === rest[index].id && hh.quantity <= rest[index].quantity) }
);
} return true;
});
public canDeactivate(): boolean { public canDeactivate(): boolean {
if (this.allowDeactivate) { if (this.allowDeactivate()) {
return true; return true;
} }
const newKot = this.bill.kots.find((k) => k.id === undefined) as Kot; const newKot = this.bill().kots.find((k) => k.id === undefined) as Kot;
return newKot.inventories.length === 0; return newKot.inventories.length === 0;
} }
} }
@@ -5,7 +5,7 @@
</ng-container> </ng-container>
<ng-container matColumnDef="bill-no-details"> <ng-container matColumnDef="bill-no-details">
<mat-header-cell *matHeaderCellDef class="deep-purple-200 bold right-align" <mat-header-cell *matHeaderCellDef class="deep-purple-200 bold right-align"
>{{ bs.bill.billId }} / K-{{ bs.bill.kotId }}</mat-header-cell >{{ bs.bill().billId }} / K-{{ bs.bill().kotId }}</mat-header-cell
> >
</ng-container> </ng-container>
<ng-container matColumnDef="time-title"> <ng-container matColumnDef="time-title">
@@ -15,9 +15,9 @@
</ng-container> </ng-container>
<ng-container matColumnDef="time-details"> <ng-container matColumnDef="time-details">
<mat-header-cell *matHeaderCellDef class="deep-purple-100 bold right-align" <mat-header-cell *matHeaderCellDef class="deep-purple-100 bold right-align"
><span [matTooltip]="bs.bill.dateTip">{{ bs.bill.date }}</span ><span [matTooltip]="bs.bill().dateTip">{{ bs.bill().date }}</span
>&nbsp;/&nbsp;<span [matTooltip]="bs.bill.creationDateTip">{{ bs.bill.creationDate }}</span >&nbsp;/&nbsp;<span [matTooltip]="bs.bill().creationDateTip">{{ bs.bill().creationDate }}</span
>&nbsp;/&nbsp;<span [matTooltip]="bs.bill.lastEditDateTip">{{ bs.bill.lastEditDate }}</span></mat-header-cell >&nbsp;/&nbsp;<span [matTooltip]="bs.bill().lastEditDateTip">{{ bs.bill().lastEditDate }}</span></mat-header-cell
> >
</ng-container> </ng-container>
<ng-container matColumnDef="table-title"> <ng-container matColumnDef="table-title">
@@ -25,10 +25,10 @@
</ng-container> </ng-container>
<ng-container matColumnDef="table-details"> <ng-container matColumnDef="table-details">
<mat-header-cell *matHeaderCellDef class="deep-purple-50 bold right-align" <mat-header-cell *matHeaderCellDef class="deep-purple-50 bold right-align"
><button>Table: {{ bs.bill.table.name }}</button> / ><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)="choosePax()">{{ bs.bill().pax }} Pax</button> /
<button type="button" mat-button (click)="chooseCustomer()"> <button type="button" mat-button (click)="chooseCustomer()">
{{ bs.bill.customer?.name ?? 'Customer' }} {{ bs.bill().customer?.name ?? 'Customer' }}
</button></mat-header-cell </button></mat-header-cell
> >
</ng-container> </ng-container>
+18 -15
View File
@@ -1,5 +1,5 @@
import { CommonModule, CurrencyPipe } from '@angular/common'; import { CommonModule, CurrencyPipe } from '@angular/common';
import { Component, OnInit, inject, computed, effect, input } from '@angular/core'; import { Component, OnDestroy, OnInit, Signal, computed, effect, inject, input } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
@@ -7,7 +7,7 @@ import { MatIconModule } from '@angular/material/icon';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { MatTooltipModule } from '@angular/material/tooltip'; import { MatTooltipModule } from '@angular/material/tooltip';
import { ActivatedRoute, Router, RouterOutlet } from '@angular/router'; import { Router, RouterOutlet } from '@angular/router';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { map, switchMap } from 'rxjs/operators'; import { map, switchMap } from 'rxjs/operators';
@@ -44,8 +44,7 @@ import { VoucherService } from './voucher.service';
RouterOutlet, RouterOutlet,
], ],
}) })
export class BillsComponent implements OnInit { export class BillsComponent implements OnInit, OnDestroy {
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private dialog = inject(MatDialog); private dialog = inject(MatDialog);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
@@ -112,8 +111,12 @@ export class BillsComponent implements OnInit {
this.getPax(); this.getPax();
} }
ngOnDestroy() {
this.bs.reset();
}
getPax(): void { getPax(): void {
if (this.bs.bill.id || this.bs.bill.customer) { if (this.bs.bill().id || this.bs.bill().customer) {
return; return;
} }
this.choosePax(); this.choosePax();
@@ -122,14 +125,14 @@ export class BillsComponent implements OnInit {
choosePax(): void { choosePax(): void {
const dialogRef = this.dialog.open(PaxComponent, { const dialogRef = this.dialog.open(PaxComponent, {
// width: '750px', // width: '750px',
data: this.bs.bill.pax, data: this.bs.bill().pax,
}); });
dialogRef.afterClosed().subscribe((result: boolean | number) => { dialogRef.afterClosed().subscribe((result: boolean | number) => {
if (!result) { if (!result) {
return; return;
} }
this.bs.bill.pax = result as number; this.bs.bill.update((b) => new Bill({ ...b, pax: result as number }));
}); });
} }
@@ -137,14 +140,14 @@ export class BillsComponent implements OnInit {
const dialogRef = this.dialog.open(ChooseCustomerComponent, { const dialogRef = this.dialog.open(ChooseCustomerComponent, {
maxWidth: '100%', maxWidth: '100%',
width: '50%', width: '50%',
data: this.bs.bill.customer, data: this.bs.bill().customer,
}); });
dialogRef.afterClosed().subscribe((result: boolean | Customer) => { dialogRef.afterClosed().subscribe((result: boolean | Customer) => {
if (!result) { if (!result) {
this.bs.bill.customer = null; this.bs.bill.update((b) => new Bill({ ...b, customer: null }));
} else { } else {
this.bs.bill.customer = result as Customer; this.bs.bill.update((b) => new Bill({ ...b, customer: result as Customer }));
} }
}); });
} }
@@ -248,7 +251,7 @@ export class BillsComponent implements OnInit {
); );
} }
chooseTable(allowMerge: boolean): Observable<Table> { chooseTable(allowMerge: Signal<boolean>): Observable<Table> {
return this.dialog return this.dialog
.open(TablesDialogComponent, { .open(TablesDialogComponent, {
// width: '750px', // width: '750px',
@@ -269,15 +272,15 @@ export class BillsComponent implements OnInit {
} }
moveKot(kot: BillRow): void { moveKot(kot: BillRow): void {
const canMergeTables = this.auth.allowed('merge-tables'); const canMergeTables = computed(() => this.auth.allowed('merge-tables'));
this.chooseTable(canMergeTables) this.chooseTable(canMergeTables)
.pipe( .pipe(
switchMap((table: Table) => this.confirmMoveKotDialog(table)), switchMap((table: Table) => this.confirmMoveKotDialog(table)),
switchMap((table: Table) => { switchMap((table: Table) => {
if (this.bs.bill.kots.length === 1 && table.status) { if (this.bs.bill().kots.length === 1 && table.status) {
return this.bs.mergeTable(table); return this.bs.mergeTable(table);
} }
if (this.bs.bill.kots.length === 1 && !table.status) { if (this.bs.bill().kots.length === 1 && !table.status) {
return this.bs.moveTable(table); return this.bs.moveTable(table);
} }
if (table.status) { if (table.status) {
@@ -302,7 +305,7 @@ export class BillsComponent implements OnInit {
if (!isPrinted) { if (!isPrinted) {
return false; return false;
} }
if (this.bs.bill.voucherType === VoucherType.Void) { if (this.bs.bill().voucherType === VoucherType.Void) {
return true; return true;
} }
if (!this.auth.allowed('edit-printed-product')) { if (!this.auth.allowed('edit-printed-product')) {
@@ -1,4 +1,4 @@
import { Component, inject, computed, signal, input } from '@angular/core'; import { Component, Signal, computed, inject, input, signal } from '@angular/core';
import { MatCardModule } from '@angular/material/card'; import { MatCardModule } from '@angular/material/card';
import { MatRippleModule } from '@angular/material/core'; import { MatRippleModule } from '@angular/material/core';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
@@ -47,18 +47,18 @@ export class SalesHomeComponent {
return (x || []).map((y: SaleCategory) => ({ id: y.id, name: y.name, selected: false })); return (x || []).map((y: SaleCategory) => ({ id: y.id, name: y.name, selected: false }));
}); });
printKotAllowed(): boolean { printKotAllowed = computed<boolean>(() => {
if (!this.auth.allowed('print-kot')) { if (!this.auth.allowed('print-kot')) {
return false; return false;
} }
if (!this.bs.bill.id) { if (!this.bs.bill().id) {
return true; return true;
} }
if (this.bs.bill.voucherType !== VoucherType.Kot) { if (this.bs.bill().voucherType !== VoucherType.Kot) {
return false; return false;
} }
return true; return true;
} });
printKot() { printKot() {
if (!this.printKotAllowed()) { if (!this.printKotAllowed()) {
@@ -75,15 +75,15 @@ export class SalesHomeComponent {
}); });
} }
discountAllowed(): boolean { discountAllowed = computed<boolean>(() => {
return this.auth.allowed('discount'); return this.auth.allowed('discount');
} });
showDiscount(): Observable<boolean | { id: string; name: string; discount: number }[]> { showDiscount(): Observable<boolean | { id: string; name: string; discount: number }[]> {
if (this.discountAllowed()) { if (this.discountAllowed()) {
const dialogRef = this.dialog.open(DiscountComponent, { const dialogRef = this.dialog.open(DiscountComponent, {
// width: '750px', // width: '750px',
data: this.customerDiscountsService.list(signal(this.bs.bill.customer?.id)), data: this.customerDiscountsService.list(signal(this.bs.bill().customer?.id)),
}); });
return dialogRef.afterClosed(); return dialogRef.afterClosed();
} }
@@ -99,8 +99,8 @@ export class SalesHomeComponent {
} }
billTypeDialog() { billTypeDialog() {
if (this.bs.bill.voucherType !== VoucherType.Kot) { if (this.bs.bill().voucherType !== VoucherType.Kot) {
return observableOf(this.bs.bill.voucherType); return observableOf(this.bs.bill().voucherType);
} }
return this.dialog.open(BillTypeComponent).afterClosed(); return this.dialog.open(BillTypeComponent).afterClosed();
} }
@@ -125,21 +125,21 @@ export class SalesHomeComponent {
.pipe(map((x: boolean) => (x ? reason : x))); .pipe(map((x: boolean) => (x ? reason : x)));
} }
printBillAllowed(): boolean { printBillAllowed = computed<boolean>(() => {
if (!this.auth.allowed('print-bill')) { if (!this.auth.allowed('print-bill')) {
return false; return false;
} }
if (!this.bs.bill.id) { if (!this.bs.bill().id) {
return true; return true;
} }
if (this.bs.bill.voucherType !== VoucherType.Kot && !this.auth.allowed('edit-printed-bill')) { if (this.bs.bill().voucherType !== VoucherType.Kot && !this.auth.allowed('edit-printed-bill')) {
return false; return false;
} }
if (this.bs.bill.voucherType === VoucherType.Void) { if (this.bs.bill().voucherType === VoucherType.Void) {
return false; return false;
} }
return true; return true;
} });
printBill() { printBill() {
if (!this.printBillAllowed()) { if (!this.printBillAllowed()) {
@@ -174,28 +174,28 @@ export class SalesHomeComponent {
}); });
} }
receivePaymentAllowed(): boolean { receivePaymentAllowed = computed<boolean>(() => {
if (!this.auth.allowed('settle-bill')) { if (!this.auth.allowed('settle-bill')) {
return false; return false;
} }
if (!this.bs.bill.id) { if (!this.bs.bill().id) {
return false; return false;
} }
if (this.bs.bill.voucherType === VoucherType.Kot) { if (this.bs.bill().voucherType === VoucherType.Kot) {
return false; return false;
} }
if (this.bs.bill.voucherType === VoucherType.Void) { if (this.bs.bill().voucherType === VoucherType.Void) {
return false; return false;
} }
return true; return true;
} });
receivePayment() { receivePayment() {
if (!this.receivePaymentAllowed()) { if (!this.receivePaymentAllowed()) {
return; return;
} }
const amount = this.bs.amount(); const amount = this.bs.amount();
const type = this.bs.bill.voucherType; const type = this.bs.bill().voucherType;
this.dialog this.dialog
.open(ReceivePaymentComponent, { .open(ReceivePaymentComponent, {
data: { data: {
@@ -223,21 +223,21 @@ export class SalesHomeComponent {
}); });
} }
moveTableAllowed(): boolean { moveTableAllowed = computed<boolean>(() => {
if (!this.auth.allowed('move-table') && !this.auth.allowed('merge-tables')) { if (!this.auth.allowed('move-table') && !this.auth.allowed('merge-tables')) {
return false; return false;
} }
if (!this.bs.bill.id) { if (!this.bs.bill().id) {
return false; return false;
} }
return true; return true;
} });
moveTable() { moveTable() {
if (!this.moveTableAllowed()) { if (!this.moveTableAllowed()) {
return; return;
} }
const canMergeTables = this.auth.allowed('merge-tables'); const canMergeTables = computed(() => this.auth.allowed('merge-tables'));
this.showChooseTableDialog(canMergeTables) this.showChooseTableDialog(canMergeTables)
.pipe( .pipe(
tap((x) => { tap((x) => {
@@ -266,15 +266,15 @@ export class SalesHomeComponent {
}); });
} }
cancelBillAllowed(): boolean { cancelBillAllowed = computed<boolean>(() => {
if (!this.auth.allowed('void-bill')) { if (!this.auth.allowed('void-bill')) {
return false; return false;
} }
if (!this.bs.bill.id) { if (!this.bs.bill().id) {
return false; return false;
} }
return true; return true;
} });
cancelBill() { cancelBill() {
if (!this.cancelBillAllowed()) { if (!this.cancelBillAllowed()) {
@@ -322,15 +322,15 @@ export class SalesHomeComponent {
}); });
} }
splitBillAllowed(): boolean { splitBillAllowed = computed<boolean>(() => {
if (!this.auth.allowed('split-bill')) { if (!this.auth.allowed('split-bill')) {
return false; return false;
} }
if (!this.bs.bill.id) { if (!this.bs.bill().id) {
return false; return false;
} }
return true; return true;
} });
showBillSplitChoices(): Observable<{ id: string; name: string; selected: boolean }[] | undefined | false> { showBillSplitChoices(): Observable<{ id: string; name: string; selected: boolean }[] | undefined | false> {
return this.dialog return this.dialog
@@ -340,7 +340,7 @@ export class SalesHomeComponent {
.afterClosed(); .afterClosed();
} }
showChooseTableDialog(canChooseRunning: boolean): Observable<Table | undefined | null> { showChooseTableDialog(canChooseRunning: Signal<boolean>): Observable<Table | undefined | null> {
return this.dialog return this.dialog
.open(TablesDialogComponent, { .open(TablesDialogComponent, {
data: { data: {
@@ -360,7 +360,7 @@ export class SalesHomeComponent {
obs obs
.pipe( .pipe(
tap((x) => (inventories = x)), tap((x) => (inventories = x)),
switchMap(() => this.showChooseTableDialog(false)), switchMap(() => this.showChooseTableDialog(signal(false))),
tap((x) => { tap((x) => {
if (!x) { if (!x) {
throw new Error('Please choose a table'); throw new Error('Please choose a table');
+2 -2
View File
@@ -1,6 +1,6 @@
<h2 mat-dialog-title>Pax</h2> <h2 mat-dialog-title>Pax</h2>
<mat-dialog-content> <mat-dialog-content>
<form> <form (submit)="$event.preventDefault(); accept()">
<div class="row-container"> <div class="row-container">
<mat-form-field class="flex-auto"> <mat-form-field class="flex-auto">
<mat-label>Pax</mat-label> <mat-label>Pax</mat-label>
@@ -18,6 +18,6 @@
</form> </form>
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions> <mat-dialog-actions>
<button mat-button [mat-dialog-close]="false">Cancel</button> <button type="button" mat-button [mat-dialog-close]="false">Cancel</button>
<button type="button" mat-button (click)="accept()" color="primary">Ok</button> <button type="button" mat-button (click)="accept()" color="primary">Ok</button>
</mat-dialog-actions> </mat-dialog-actions>
+7 -17
View File
@@ -1,5 +1,5 @@
import { CdkScrollableModule } from '@angular/cdk/scrolling'; import { CdkScrollableModule } from '@angular/cdk/scrolling';
import { Component, OnInit, inject, signal } from '@angular/core'; import { Component, inject, signal } from '@angular/core';
import { form, FormField } from '@angular/forms/signals'; import { form, FormField } from '@angular/forms/signals';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule } from '@angular/material/dialog';
@@ -16,27 +16,17 @@ export interface PaxFormData {
styleUrls: ['./pax.component.css'], styleUrls: ['./pax.component.css'],
imports: [CdkScrollableModule, MatButtonModule, MatDialogModule, MatFormFieldModule, MatInputModule, FormField], imports: [CdkScrollableModule, MatButtonModule, MatDialogModule, MatFormFieldModule, MatInputModule, FormField],
}) })
export class PaxComponent implements OnInit { export class PaxComponent {
data = inject(MAT_DIALOG_DATA); private data = inject<number | null>(MAT_DIALOG_DATA, { optional: true });
dialogRef = inject<MatDialogRef<PaxComponent>>(MatDialogRef); private dialogRef = inject<MatDialogRef<PaxComponent>>(MatDialogRef);
formModel = signal<PaxFormData>({ formModel = signal<PaxFormData>({
pax: null, pax: this.data ?? 0,
}); });
form = form(this.formModel); form = form(this.formModel);
constructor() {
// Create form
}
ngOnInit() {
this.formModel.set({
pax: this.data,
});
}
accept(): void { accept(): void {
const pax = this.formModel().pax ?? 0; this.dialogRef.close(this.formModel().pax ?? 0);
this.dialogRef.close(pax);
} }
} }
@@ -1,5 +1,5 @@
import { CdkScrollableModule } from '@angular/cdk/scrolling'; import { CdkScrollableModule } from '@angular/cdk/scrolling';
import { Component, OnInit, inject, signal } from '@angular/core'; import { Component, inject, signal } from '@angular/core';
import { form, FormField } from '@angular/forms/signals'; import { form, FormField } from '@angular/forms/signals';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule } from '@angular/material/dialog';
@@ -18,26 +18,17 @@ export interface QuantityFormData {
styleUrls: ['./quantity.component.css'], styleUrls: ['./quantity.component.css'],
imports: [CdkScrollableModule, MatButtonModule, MatDialogModule, MatFormFieldModule, MatInputModule, FormField], imports: [CdkScrollableModule, MatButtonModule, MatDialogModule, MatFormFieldModule, MatInputModule, FormField],
}) })
export class QuantityComponent implements OnInit { export class QuantityComponent {
data = inject(MAT_DIALOG_DATA); private data = inject<unknown>(MAT_DIALOG_DATA, { optional: true });
private math = inject(MathService); private math = inject(MathService);
dialogRef = inject<MatDialogRef<QuantityComponent>>(MatDialogRef); private dialogRef = inject<MatDialogRef<QuantityComponent>>(MatDialogRef);
formModel = signal<QuantityFormData>({ formModel = signal<QuantityFormData>({
quantity: '', quantity: `${this.data ?? ''}`,
}); });
form = form(this.formModel); form = form(this.formModel);
constructor() {
// Create form
}
ngOnInit() {
this.formModel.set({
quantity: `${this.data}`,
});
}
accept(): void { accept(): void {
const quantity = this.math.parseAmount(this.formModel().quantity ?? ''); const quantity = this.math.parseAmount(this.formModel().quantity ?? '');
this.dialogRef.close(quantity); this.dialogRef.close(quantity);
@@ -26,32 +26,25 @@ export interface ReasonFormData {
], ],
}) })
export class ReasonComponent { export class ReasonComponent {
dialogRef = inject<MatDialogRef<ReasonComponent>>(MatDialogRef); private dialogRef = inject<MatDialogRef<ReasonComponent>>(MatDialogRef);
private data = inject<{ private data = inject<{
title: string; title: string;
reasons: string[]; reasons: string[];
}>(MAT_DIALOG_DATA); }>(MAT_DIALOG_DATA);
title = this.data.title;
reasons = this.data.reasons ?? [];
dataSource = computed(() => this.reasons);
displayedColumns = ['reason'];
selected = '';
formModel = signal<ReasonFormData>({ formModel = signal<ReasonFormData>({
son: '', son: '',
}); });
form = form(this.formModel); form = form(this.formModel);
dataSource = computed(() => this.reasons); select(reason: string): boolean {
title: string;
selected = '';
reasons: string[];
displayedColumns = ['reason'];
constructor() {
const data = this.data;
this.reasons = data.reasons ?? [];
this.title = data.title;
}
select(reason: string) {
this.selected = reason.trim(); this.selected = reason.trim();
return true; return true;
} }
@@ -4,7 +4,7 @@ import { MatCardModule } from '@angular/material/card';
import { MatRippleModule } from '@angular/material/core'; import { MatRippleModule } from '@angular/material/core';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, NavigationExtras, Router } from '@angular/router'; import { NavigationExtras, Router } from '@angular/router';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { Table } from '../../core/table'; import { Table } from '../../core/table';
@@ -23,7 +23,6 @@ export class RunningTablesComponent {
private regimeService = inject(RegimeService); private regimeService = inject(RegimeService);
private dialog = inject(MatDialog); private dialog = inject(MatDialog);
private router = inject(Router); private router = inject(Router);
private route = inject(ActivatedRoute);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
regimesResource = this.regimeService.list(); regimesResource = this.regimeService.list();
@@ -9,7 +9,7 @@ import { MatInputModule } from '@angular/material/input';
import { MatSelectChange, MatSelectModule } from '@angular/material/select'; import { MatSelectChange, MatSelectModule } from '@angular/material/select';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import { Printer } from '../core/printer'; import { Printer } from '../core/printer';
import { SectionPrinter } from '../core/section-printer'; import { SectionPrinter } from '../core/section-printer';
@@ -45,7 +45,6 @@ export interface SectionPrinterFormData {
export class SectionPrinterComponent { export class SectionPrinterComponent {
private printerService = inject(PrinterService); private printerService = inject(PrinterService);
private sectionService = inject(SectionService); private sectionService = inject(SectionService);
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
private dialog = inject(MatDialog); private dialog = inject(MatDialog);
@@ -5,7 +5,7 @@ import { MatDialog } from '@angular/material/dialog';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import { Section } from '../../core/section'; import { Section } from '../../core/section';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component'; import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
@@ -22,7 +22,6 @@ export interface SectionDetailFormData {
imports: [MatButtonModule, MatFormFieldModule, MatInputModule, FormField], imports: [MatButtonModule, MatFormFieldModule, MatInputModule, FormField],
}) })
export class SectionDetailComponent { export class SectionDetailComponent {
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private dialog = inject(MatDialog); private dialog = inject(MatDialog);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
@@ -2,7 +2,7 @@ import { Component, inject, computed } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { SectionService } from '../section.service'; import { SectionService } from '../section.service';
@Component({ @Component({
@@ -13,7 +13,6 @@ import { SectionService } from '../section.service';
}) })
export class SectionListComponent { export class SectionListComponent {
private sectionService = inject(SectionService); private sectionService = inject(SectionService);
private route = inject(ActivatedRoute);
listResource = this.sectionService.list(); listResource = this.sectionService.list();
dataSource = computed(() => this.listResource.value() ?? []); dataSource = computed(() => this.listResource.value() ?? []);
@@ -49,5 +49,5 @@
</mat-tab> </mat-tab>
</mat-tab-group> </mat-tab-group>
<footer class="footer"> <footer class="footer">
<p>Backend: v{{ auth.user?.ver }} / Frontend: v{{ version }}</p> <p>Backend: v{{ auth.user()?.ver }} / Frontend: v{{ version }}</p>
</footer> </footer>
@@ -3,13 +3,11 @@ import { form, FormField } from '@angular/forms/signals';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card'; import { MatCardModule } from '@angular/material/card';
import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatDialog } from '@angular/material/dialog';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatSlideToggleModule } from '@angular/material/slide-toggle'; import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTabsModule } from '@angular/material/tabs'; import { MatTabsModule } from '@angular/material/tabs';
import { ActivatedRoute, Router } from '@angular/router';
import moment from 'moment'; import moment from 'moment';
import { environment } from '../app.environment'; import { environment } from '../app.environment';
@@ -33,9 +31,6 @@ import { SettingsService } from './settings.service';
], ],
}) })
export class SettingsComponent { export class SettingsComponent {
private route = inject(ActivatedRoute);
private router = inject(Router);
private dialog = inject(MatDialog);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
auth = inject(AuthService); auth = inject(AuthService);
private ser = inject(SettingsService); private ser = inject(SettingsService);
@@ -8,7 +8,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import { ReportingLevel } from '../../core/reporting-level'; import { ReportingLevel } from '../../core/reporting-level';
import { SettleOption } from '../../core/settle-option'; import { SettleOption } from '../../core/settle-option';
@@ -38,7 +38,6 @@ export interface SettleOptionDetailFormData {
], ],
}) })
export class SettleOptionDetailComponent { export class SettleOptionDetailComponent {
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private dialog = inject(MatDialog); private dialog = inject(MatDialog);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
@@ -1,9 +1,8 @@
import { Component, inject, computed } from '@angular/core'; import { Component, inject, computed } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, Router, RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { ReportingLevel } from '../../core/reporting-level'; import { ReportingLevel } from '../../core/reporting-level';
import { VoucherType } from '../../sales/bills/voucher-type'; import { VoucherType } from '../../sales/bills/voucher-type';
@@ -15,9 +14,6 @@ import { SettleOptionService } from '../settle-option.service';
imports: [MatButtonModule, MatIconModule, MatTableModule, RouterLink], imports: [MatButtonModule, MatIconModule, MatTableModule, RouterLink],
}) })
export class SettleOptionListComponent { export class SettleOptionListComponent {
private route = inject(ActivatedRoute);
private router = inject(Router);
private snackBar = inject(MatSnackBar);
private ser = inject(SettleOptionService); private ser = inject(SettleOptionService);
listResource = this.ser.list(); listResource = this.ser.list();
@@ -8,7 +8,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import { Section } from '../../core/section'; import { Section } from '../../core/section';
import { Table } from '../../core/table'; import { Table } from '../../core/table';
@@ -39,7 +39,6 @@ export interface TableDetailFormData {
}) })
export class TableDetailComponent { export class TableDetailComponent {
private sectionService = inject(SectionService); private sectionService = inject(SectionService);
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private dialog = inject(MatDialog); private dialog = inject(MatDialog);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
@@ -5,7 +5,7 @@ import { MatIconModule } from '@angular/material/icon';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { MatToolbarModule } from '@angular/material/toolbar'; import { MatToolbarModule } from '@angular/material/toolbar';
import { ActivatedRoute, Router, RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { firstValueFrom } from 'rxjs'; import { firstValueFrom } from 'rxjs';
import { Table } from '../../core/table'; import { Table } from '../../core/table';
@@ -17,8 +17,6 @@ import { TableService } from '../table.service';
imports: [DragDropModule, MatButtonModule, MatIconModule, MatTableModule, RouterLink, MatToolbarModule], imports: [DragDropModule, MatButtonModule, MatIconModule, MatTableModule, RouterLink, MatToolbarModule],
}) })
export class TableListComponent { export class TableListComponent {
private route = inject(ActivatedRoute);
private router = inject(Router);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
private ser = inject(TableService); private ser = inject(TableService);
listResource = this.ser.list(); listResource = this.ser.list();
@@ -7,7 +7,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import moment from 'moment'; import moment from 'moment';
import { ToCsvService } from '../shared/to-csv.service'; import { ToCsvService } from '../shared/to-csv.service';
@@ -37,7 +37,6 @@ export interface TaxReportFormData {
}) })
export class TaxReportComponent { export class TaxReportComponent {
private taxReportService = inject(TaxReportService); private taxReportService = inject(TaxReportService);
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private toCsv = inject(ToCsvService); private toCsv = inject(ToCsvService);
startDate = input(null, { transform: (v: string | null | undefined) => v ?? null }); startDate = input(null, { transform: (v: string | null | undefined) => v ?? null });
@@ -7,7 +7,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import { round } from 'mathjs'; import { round } from 'mathjs';
import { Regime } from '../../core/regime'; import { Regime } from '../../core/regime';
@@ -30,7 +30,6 @@ export interface TaxDetailFormData {
}) })
export class TaxDetailComponent { export class TaxDetailComponent {
private regimeService = inject(RegimeService); private regimeService = inject(RegimeService);
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private dialog = inject(MatDialog); private dialog = inject(MatDialog);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
@@ -3,7 +3,7 @@ import { Component, inject, computed } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { TaxService } from '../tax.service'; import { TaxService } from '../tax.service';
@Component({ @Component({
@@ -14,7 +14,6 @@ import { TaxService } from '../tax.service';
}) })
export class TaxListComponent { export class TaxListComponent {
private taxService = inject(TaxService); private taxService = inject(TaxService);
private route = inject(ActivatedRoute);
listResource = this.taxService.list(); listResource = this.taxService.list();
dataSource = computed(() => this.listResource.value() ?? []); dataSource = computed(() => this.listResource.value() ?? []);
@@ -13,7 +13,7 @@ import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import moment from 'moment'; import moment from 'moment';
import { MenuCategory } from '../../core/menu-category'; import { MenuCategory } from '../../core/menu-category';
@@ -67,7 +67,6 @@ export interface TemporalSkuFormData {
export class TemporalProductDetailComponent { export class TemporalProductDetailComponent {
private menuCategoryService = inject(MenuCategoryService); private menuCategoryService = inject(MenuCategoryService);
private saleCategoryService = inject(SaleCategoryService); private saleCategoryService = inject(SaleCategoryService);
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private dialog = inject(MatDialog); private dialog = inject(MatDialog);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
@@ -156,14 +155,6 @@ export class TemporalProductDetailComponent {
return !d ? null : moment(d).format('DD-MMM-YYYY'); return !d ? null : moment(d).format('DD-MMM-YYYY');
} }
// showItem(item: TemporalProduct) {
// this.item = item;
// this.selectedProduct = this.item.products[0];
// this.selectedSku = this.item.skus[0];
//
// // }
constructor() { constructor() {
afterNextRender(() => { afterNextRender(() => {
this.productForm().focusBoundControl(); this.productForm().focusBoundControl();
@@ -7,7 +7,7 @@
</mat-form-field> </mat-form-field>
<mat-form-field class="flex-auto basis-30"> <mat-form-field class="flex-auto basis-30">
<mat-label>Menu Category</mat-label> <mat-label>Menu Category</mat-label>
<mat-select [formField]="form.menuCategory" (selectionChange)="filterMcOn($event.value)"> <mat-select [formField]="form.menuCategory">
<mat-option>-- All Products --</mat-option> <mat-option>-- All Products --</mat-option>
@for (mc of menuCategoriesResource.value(); track mc) { @for (mc of menuCategoriesResource.value(); track mc) {
<mat-option [value]="mc.id"> <mat-option [value]="mc.id">
@@ -18,7 +18,7 @@
</mat-form-field> </mat-form-field>
<mat-form-field class="flex-auto basis-30"> <mat-form-field class="flex-auto basis-30">
<mat-label>Sale Category</mat-label> <mat-label>Sale Category</mat-label>
<mat-select [formField]="form.saleCategory" (selectionChange)="filterScOn($event.value)"> <mat-select [formField]="form.saleCategory">
<mat-option>-- All Products --</mat-option> <mat-option>-- All Products --</mat-option>
@for (mc of saleCategoriesResource.value(); track mc) { @for (mc of saleCategoriesResource.value(); track mc) {
<mat-option [value]="mc.id"> <mat-option [value]="mc.id">
@@ -25,7 +25,6 @@ export interface TemporalProductListFormData {
styleUrls: ['./temporal-product-list.component.css'], styleUrls: ['./temporal-product-list.component.css'],
imports: [ imports: [
CurrencyPipe, CurrencyPipe,
// DecimalPipe,
MatFormFieldModule, MatFormFieldModule,
MatIconModule, MatIconModule,
MatInputModule, MatInputModule,
@@ -45,9 +44,6 @@ export class TemporalProductListComponent {
menuCategoriesResource = this.menuCategoryService.list(); menuCategoriesResource = this.menuCategoryService.list();
listResource = this.temporalProductService.list(); listResource = this.temporalProductService.list();
menuCategoryFilter = signal<string>('');
saleCategoryFilter = signal<string>('');
formModel = signal<TemporalProductListFormData>({ formModel = signal<TemporalProductListFormData>({
filter: '', filter: '',
menuCategory: '', menuCategory: '',
@@ -56,6 +52,9 @@ export class TemporalProductListComponent {
form = form(this.formModel); form = form(this.formModel);
menuCategoryFilter = computed(() => this.formModel().menuCategory ?? '');
saleCategoryFilter = computed(() => this.formModel().saleCategory ?? '');
filterSignal = computed(() => this.formModel().filter); filterSignal = computed(() => this.formModel().filter);
debouncedFilter = debounced(this.filterSignal, 150); debouncedFilter = debounced(this.filterSignal, 150);
@@ -79,12 +78,4 @@ export class TemporalProductListComponent {
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */ /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns: string[] = ['product', 'sku', 'price', 'menuCategory', 'saleCategory', 'info']; displayedColumns: string[] = ['product', 'sku', 'price', 'menuCategory', 'saleCategory', 'info'];
filterMcOn(val: string) {
this.menuCategoryFilter.set(val);
}
filterScOn(val: string) {
this.saleCategoryFilter.set(val);
}
} }
@@ -10,7 +10,7 @@ import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import moment from 'moment'; import moment from 'moment';
import { MenuCategoryService } from '../menu-category/menu-category.service'; import { MenuCategoryService } from '../menu-category/menu-category.service';
@@ -43,7 +43,6 @@ export interface UpdateProductPricesFormData {
}) })
export class UpdateProductPricesComponent { export class UpdateProductPricesComponent {
private menuCategoryService = inject(MenuCategoryService); private menuCategoryService = inject(MenuCategoryService);
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private toCsv = inject(ToCsvService); private toCsv = inject(ToCsvService);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
@@ -8,7 +8,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, Router } from '@angular/router'; import { Router } from '@angular/router';
import { User } from '../../core/user'; import { User } from '../../core/user';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component'; import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
@@ -36,7 +36,6 @@ export interface UserDetailFormData {
], ],
}) })
export class UserDetailComponent { export class UserDetailComponent {
private route = inject(ActivatedRoute);
private router = inject(Router); private router = inject(Router);
private snackBar = inject(MatSnackBar); private snackBar = inject(MatSnackBar);
private dialog = inject(MatDialog); private dialog = inject(MatDialog);
@@ -2,7 +2,7 @@ import { Component, computed, inject } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { LocalTimePipe } from '../../shared/local-time.pipe'; import { LocalTimePipe } from '../../shared/local-time.pipe';
import { UserService } from '../user.service'; import { UserService } from '../user.service';
@@ -14,7 +14,6 @@ import { UserService } from '../user.service';
}) })
export class UserListComponent { export class UserListComponent {
private userService = inject(UserService); private userService = inject(UserService);
private route = inject(ActivatedRoute);
listResource = this.userService.list(); listResource = this.userService.list();
dataSource = computed(() => this.listResource.value() ?? []); dataSource = computed(() => this.listResource.value() ?? []);
+1 -1
View File
@@ -10,7 +10,7 @@ npx ng lint --fix
cd "$parent_path/barker" || exit cd "$parent_path/barker" || exit
uv run ruff format . uv run ruff format .
uv run ruff check . uv run ruff check . --fix
uv run bandit --recursive barker uv run bandit --recursive barker
uv run bandit --recursive . uv run bandit --recursive .
uv run safety check uv run safety check
+2
View File
@@ -31,6 +31,7 @@ then
sed --in-place --regexp-extended 's/"([0-9]{1,2}.[0-9]+.[0-9]+)"/"'"$new_version"'"/g' barker/barker/__version__.py sed --in-place --regexp-extended 's/"([0-9]{1,2}.[0-9]+.[0-9]+)"/"'"$new_version"'"/g' barker/barker/__version__.py
git add barker/barker/__version__.py git add barker/barker/__version__.py
sed --in-place --regexp-extended 's/version = "([0-9]{1,2}.[0-9]+.[0-9]+)"/version = "'"$new_version"'"/g' barker/pyproject.toml sed --in-place --regexp-extended 's/version = "([0-9]{1,2}.[0-9]+.[0-9]+)"/version = "'"$new_version"'"/g' barker/pyproject.toml
(cd barker && uv lock)
git add barker/pyproject.toml git add barker/pyproject.toml
sed --in-place --regexp-extended 's/version = "([0-9]{1,2}.[0-9]+.[0-9]+)"/version = "'"$new_version"'"/g' frank/pyproject.toml sed --in-place --regexp-extended 's/version = "([0-9]{1,2}.[0-9]+.[0-9]+)"/version = "'"$new_version"'"/g' frank/pyproject.toml
git add frank/pyproject.toml git add frank/pyproject.toml
@@ -45,4 +46,5 @@ else
echo "Usage: $0 <major|minor|patch|version_string>" echo "Usage: $0 <major|minor|patch|version_string>"
exit 1 exit 1
fi fi
git push
git push --tags git push --tags