fad
This commit is contained in:
1 parent
2a29dc9195
commit
43204e8441
78 files changed
+904
-1235
No files matched your search
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bookie",
|
||||
"version": "14.5.0",
|
||||
"version": "14.5.1",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export const environment = {
|
||||
production: true,
|
||||
ACCESS_TOKEN_REFRESH_MINUTES: 10, // refresh token 10 minutes before expiry
|
||||
version: '14.5.0',
|
||||
version: '14.5.1',
|
||||
};
|
||||
|
||||
export const dateFormat = {
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Username</mat-label>
|
||||
<input matInput #nameElement [formField]="form.username" />
|
||||
<input matInput [formField]="form.username" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Password</mat-label>
|
||||
<input matInput [formField]="form.password" [type]="hide ? 'password' : 'text'" (keyup.enter)="login()" />
|
||||
<mat-icon matSuffix (click)="hide = !hide">{{ hide ? 'visibility' : 'visibility_off' }}</mat-icon>
|
||||
<input matInput [formField]="form.password" [type]="hide() ? 'password' : 'text'" (keyup.enter)="login()" />
|
||||
<mat-icon matSuffix (click)="hide.set(!hide())">{{ hide() ? 'visibility' : 'visibility_off' }}</mat-icon>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
@if (unregisteredDevice()) {
|
||||
|
||||
@@ -1,13 +1,4 @@
|
||||
import {
|
||||
AfterViewInit,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
ElementRef,
|
||||
OnInit,
|
||||
ViewChild,
|
||||
inject,
|
||||
signal,
|
||||
} from '@angular/core';
|
||||
import { Component, afterNextRender, inject, input, signal } from '@angular/core';
|
||||
import { form, FormField, required } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
@@ -15,7 +6,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { CookieService } from '../../shared/cookie.service';
|
||||
import { AuthService } from '../auth.service';
|
||||
@@ -31,14 +22,15 @@ export interface LoginFormData {
|
||||
styleUrls: ['./login.component.css'],
|
||||
imports: [MatButtonModule, MatDividerModule, MatFormFieldModule, MatIconModule, MatInputModule, FormField],
|
||||
})
|
||||
export class LoginComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
private route = inject(ActivatedRoute);
|
||||
export class LoginComponent {
|
||||
private auth = inject(AuthService);
|
||||
private router = inject(Router);
|
||||
private snackBar = inject(MatSnackBar);
|
||||
private cs = inject(CookieService);
|
||||
private cd = inject(ChangeDetectorRef);
|
||||
|
||||
returnUrl = input<string | null | undefined, string>('/', {
|
||||
transform: (v: string | null | undefined): string => v ?? '/',
|
||||
});
|
||||
|
||||
formModel = signal<LoginFormData>({
|
||||
username: '',
|
||||
@@ -50,28 +42,14 @@ export class LoginComponent implements OnInit, AfterViewInit {
|
||||
required(schemaPath.password);
|
||||
});
|
||||
|
||||
hide: boolean;
|
||||
unregisteredDevice = signal<boolean | undefined>(undefined);
|
||||
deviceName = signal<string | undefined>(undefined);
|
||||
private returnUrl: string;
|
||||
hide = signal<boolean>(true);
|
||||
unregisteredDevice = signal<boolean>(false);
|
||||
deviceName = signal<string>('');
|
||||
|
||||
constructor() {
|
||||
this.hide = true;
|
||||
this.unregisteredDevice.set(false);
|
||||
this.deviceName.set('');
|
||||
this.returnUrl = '';
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.returnUrl = this.route.snapshot.queryParams['returnUrl'] ?? '/';
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement !== undefined) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
afterNextRender(() => {
|
||||
this.form().focusBoundControl();
|
||||
});
|
||||
}
|
||||
|
||||
login(): void {
|
||||
@@ -80,13 +58,12 @@ export class LoginComponent implements OnInit, AfterViewInit {
|
||||
const password = formModel.password ?? '';
|
||||
this.auth.login(username.trim(), password.trim()).subscribe({
|
||||
next: () => {
|
||||
this.router.navigateByUrl(this.returnUrl);
|
||||
this.router.navigateByUrl(this.returnUrl() ?? '/');
|
||||
},
|
||||
error: (error) => {
|
||||
if (error.status === 401 && error.error.detail === 'Device is not registered') {
|
||||
this.unregisteredDevice.set(true);
|
||||
this.deviceName.set(this.cs.getCookie('device'));
|
||||
this.cd.detectChanges();
|
||||
}
|
||||
this.snackBar.open(error.error.detail, 'Error');
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, OnInit, inject } from '@angular/core';
|
||||
import { Component, inject } from '@angular/core';
|
||||
|
||||
import { AuthService } from '../auth.service';
|
||||
|
||||
@@ -7,10 +7,10 @@ import { AuthService } from '../auth.service';
|
||||
template: '',
|
||||
standalone: true,
|
||||
})
|
||||
export class LogoutComponent implements OnInit {
|
||||
export class LogoutComponent {
|
||||
private auth = inject(AuthService);
|
||||
|
||||
ngOnInit() {
|
||||
constructor() {
|
||||
this.auth.logout();
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<mat-form-field class="w-full">
|
||||
<mat-label>Item</mat-label>
|
||||
<input matInput type="text" [formField]="form.product" [matAutocomplete]="autoP" />
|
||||
<mat-autocomplete #autoP="matAutocomplete" [displayWith]="displayFn" (optionSelected)="productSelected($event)">
|
||||
<mat-autocomplete #autoP="matAutocomplete" [displayWith]="displayFn">
|
||||
@for (p of products(); track p) {
|
||||
<mat-option [value]="p">{{ p.name }}</mat-option>
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, OnInit, inject, signal, computed, effect, debounced } from '@angular/core';
|
||||
import { Component, inject, computed, debounced, linkedSignal } from '@angular/core';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { MatAutocompleteModule, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
|
||||
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
||||
@@ -13,7 +13,7 @@ import { ProductService } from '../../product/product.service';
|
||||
import { BundleItem } from '../bundle';
|
||||
|
||||
export interface BundleDetailDialogFormData {
|
||||
product: ProductQuery | string;
|
||||
product: BundleItem | ProductQuery | string;
|
||||
quantity: number;
|
||||
salePrice: number;
|
||||
printInBill: boolean;
|
||||
@@ -35,19 +35,20 @@ export interface BundleDetailDialogFormData {
|
||||
FormField,
|
||||
],
|
||||
})
|
||||
export class BundleDetailDialogComponent implements OnInit {
|
||||
export class BundleDetailDialogComponent {
|
||||
private readonly dialogRef = inject<MatDialogRef<BundleDetailDialogComponent>>(MatDialogRef);
|
||||
private readonly productSer = inject(ProductService);
|
||||
|
||||
data = inject<{ item: BundleItem }>(MAT_DIALOG_DATA);
|
||||
|
||||
selectedProduct = signal<ProductQuery | null>(null);
|
||||
|
||||
formModel = signal<BundleDetailDialogFormData>({
|
||||
product: '',
|
||||
quantity: 1,
|
||||
salePrice: 0,
|
||||
printInBill: true,
|
||||
formModel = linkedSignal<BundleItem, BundleDetailDialogFormData>({
|
||||
source: () => this.data.item,
|
||||
computation: (item) => ({
|
||||
product: item,
|
||||
quantity: Number(item.quantity ?? 1),
|
||||
salePrice: Number(item.salePrice ?? 0),
|
||||
printInBill: item.printInBill ?? false,
|
||||
}),
|
||||
});
|
||||
|
||||
form = form(this.formModel);
|
||||
@@ -59,62 +60,35 @@ export class BundleDetailDialogComponent implements OnInit {
|
||||
|
||||
debouncedProduct = debounced(this.productSignal, 150);
|
||||
|
||||
productsResource = this.productSer.query(computed(() => this.debouncedProduct.value()));
|
||||
productsResource = this.productSer.query(this.debouncedProduct.value);
|
||||
products = computed(() => {
|
||||
if (!this.debouncedProduct.value()) return [];
|
||||
return this.productsResource.value() ?? [];
|
||||
});
|
||||
|
||||
constructor() {
|
||||
// typing after selecting invalidates prior selection
|
||||
effect(() => {
|
||||
const x = this.formModel().product;
|
||||
if (typeof x === 'string') this.selectedProduct.set(null);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
// preload display text using existing name
|
||||
this.formModel.set({
|
||||
product: this.data.item.name ?? '',
|
||||
quantity: Number(this.data.item.quantity ?? 1),
|
||||
salePrice: Number(this.data.item.salePrice ?? 0),
|
||||
printInBill: this.data.item.printInBill,
|
||||
});
|
||||
|
||||
this.selectedProduct.set(null);
|
||||
}
|
||||
|
||||
displayFn(product?: ProductQuery | string): string {
|
||||
return !product ? '' : typeof product === 'string' ? product : product.name;
|
||||
}
|
||||
|
||||
productSelected(event: MatAutocompleteSelectedEvent): void {
|
||||
const p = event.option.value as ProductQuery;
|
||||
this.selectedProduct.set(p);
|
||||
}
|
||||
|
||||
accept(): void {
|
||||
const v = this.formModel();
|
||||
const formValue = this.form().value();
|
||||
|
||||
const quantity = Number(v.quantity ?? 0);
|
||||
const quantity = Number(formValue.quantity ?? 0);
|
||||
if (Number.isNaN(quantity) || quantity <= 0) return;
|
||||
|
||||
const salePrice = Number(v.salePrice ?? 0);
|
||||
const salePrice = Number(formValue.salePrice ?? 0);
|
||||
if (Number.isNaN(salePrice) || salePrice < 0) return;
|
||||
|
||||
// If a new product was selected, update itemId + name
|
||||
if (this.selectedProduct()?.id) {
|
||||
this.data.item.itemId = this.selectedProduct()?.id ?? '';
|
||||
this.data.item.name = this.selectedProduct()?.name ?? '';
|
||||
} else {
|
||||
// If no selection, don't allow changing SKU silently
|
||||
// but still allow quantity/price edit
|
||||
const product = typeof formValue.product === 'string' ? null : formValue.product;
|
||||
if (!product || !product.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.data.item.itemId = product.id ?? '';
|
||||
this.data.item.name = product.name ?? '';
|
||||
this.data.item.quantity = quantity;
|
||||
this.data.item.salePrice = salePrice;
|
||||
this.data.item.printInBill = v.printInBill || false;
|
||||
this.data.item.printInBill = formValue.printInBill ?? false;
|
||||
|
||||
this.dialogRef.close(this.data.item);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="row-container">
|
||||
<mat-form-field class="basis-3-4">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput #name [formField]="form.name" />
|
||||
<input matInput [formField]="form.name" />
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="basis-1-4">
|
||||
@@ -65,7 +65,7 @@
|
||||
[matAutocomplete]="autoItem"
|
||||
[value]="displayFn(formModel().addRow.itemId)"
|
||||
/>
|
||||
<mat-autocomplete #autoItem="matAutocomplete" [displayWith]="displayFn" (optionSelected)="bundleSelected($event)">
|
||||
<mat-autocomplete #autoItem="matAutocomplete" [displayWith]="displayFn">
|
||||
@for (p of itemProducts(); track p) {
|
||||
<mat-option [value]="p">{{ p.name }}</mat-option>
|
||||
}
|
||||
@@ -88,7 +88,7 @@
|
||||
</form>
|
||||
|
||||
<div class="row-container wrapped">
|
||||
<mat-table [dataSource]="dataSource()" aria-label="Bundle Items" class="flex-auto">
|
||||
<mat-table [dataSource]="formModel().items" aria-label="Bundle Items" class="flex-auto">
|
||||
<!-- Name Column (name is "name (units)") -->
|
||||
<ng-container matColumnDef="name">
|
||||
<mat-header-cell *matHeaderCellDef>Item</mat-header-cell>
|
||||
@@ -143,7 +143,7 @@
|
||||
|
||||
<div class="row-container">
|
||||
<button type="button" mat-raised-button color="primary" (click)="save()">Save</button>
|
||||
@if (!!item.id) {
|
||||
@if (!!item().id) {
|
||||
<button type="button" mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
|
||||
}
|
||||
</div>
|
||||
@@ -1,19 +1,7 @@
|
||||
import { CurrencyPipe } from '@angular/common';
|
||||
import {
|
||||
AfterViewInit,
|
||||
Component,
|
||||
ElementRef,
|
||||
ViewChild,
|
||||
inject,
|
||||
computed,
|
||||
signal,
|
||||
effect,
|
||||
debounced,
|
||||
linkedSignal,
|
||||
input,
|
||||
} from '@angular/core';
|
||||
import { Component, inject, computed, effect, debounced, linkedSignal, input, afterNextRender } from '@angular/core';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { MatAutocompleteModule, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
|
||||
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatOptionModule } from '@angular/material/core';
|
||||
@@ -24,7 +12,7 @@ import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { MenuCategory } from '../../core/menu-category';
|
||||
import { ProductQuery } from '../../core/product-query';
|
||||
@@ -41,8 +29,8 @@ export interface BundleDetailFormData {
|
||||
name: string;
|
||||
units: string;
|
||||
salePrice: number;
|
||||
menuCategory: string;
|
||||
saleCategory: string;
|
||||
menuCategory: MenuCategory | null;
|
||||
saleCategory: SaleCategory | null;
|
||||
hasHappyHour: boolean;
|
||||
isNotAvailable: boolean;
|
||||
addRow: {
|
||||
@@ -51,6 +39,7 @@ export interface BundleDetailFormData {
|
||||
salePrice: number;
|
||||
printInBill: boolean;
|
||||
};
|
||||
items: BundleItem[];
|
||||
}
|
||||
|
||||
@Component({
|
||||
@@ -71,53 +60,34 @@ export interface BundleDetailFormData {
|
||||
FormField,
|
||||
],
|
||||
})
|
||||
export class BundleDetailComponent implements AfterViewInit {
|
||||
@ViewChild('name', { static: true }) nameElement?: ElementRef;
|
||||
export class BundleDetailComponent {
|
||||
private menuCategoryService = inject(MenuCategoryService);
|
||||
private saleCategoryService = inject(SaleCategoryService);
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
private dialog = inject(MatDialog);
|
||||
private snackBar = inject(MatSnackBar);
|
||||
private ser = inject(BundleService);
|
||||
private productSer = inject(ProductService);
|
||||
id = input(null, { transform: (v: string | null | undefined) => v ?? null });
|
||||
|
||||
saleCategoriesResource = this.saleCategoryService.list();
|
||||
|
||||
menuCategoriesResource = this.menuCategoryService.list(undefined);
|
||||
|
||||
menuCategories = computed(() => this.menuCategoriesResource.value() ?? []);
|
||||
saleCategoriesResource = this.saleCategoryService.list();
|
||||
saleCategories = computed(() => this.saleCategoriesResource.value() ?? []);
|
||||
id = input(null, { transform: (v: string | null | undefined) => v ?? null });
|
||||
itemResource = this.ser.get(this.id);
|
||||
|
||||
item = computed(() => this.itemResource.value() ?? new Bundle());
|
||||
formModel = linkedSignal({
|
||||
source: () => this.menuCategoriesResource.value(),
|
||||
computation: (menuCategoriesVal): BundleDetailFormData => {
|
||||
if (menuCategoriesVal) {
|
||||
return {
|
||||
name: this.item.name ?? '',
|
||||
units: this.item.units ?? '',
|
||||
salePrice: Number(this.item.salePrice ?? 0),
|
||||
menuCategory: this.item.menuCategory?.id ?? '',
|
||||
saleCategory: this.item.saleCategory?.id ?? '',
|
||||
hasHappyHour: this.item.hasHappyHour ?? false,
|
||||
isNotAvailable: this.item.isNotAvailable ?? false,
|
||||
|
||||
addRow: {
|
||||
itemId: '',
|
||||
quantity: 1,
|
||||
salePrice: 0,
|
||||
printInBill: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
source: this.item,
|
||||
computation: (itemVal): BundleDetailFormData => {
|
||||
const items = [...(itemVal.items ?? [])];
|
||||
return {
|
||||
name: '',
|
||||
units: '',
|
||||
salePrice: 0,
|
||||
menuCategory: '',
|
||||
saleCategory: '',
|
||||
hasHappyHour: false,
|
||||
isNotAvailable: false,
|
||||
name: itemVal.name ?? '',
|
||||
units: itemVal.units ?? '',
|
||||
salePrice: Number(itemVal.salePrice ?? 0),
|
||||
menuCategory: itemVal.menuCategory ?? null,
|
||||
saleCategory: itemVal.saleCategory ?? null,
|
||||
hasHappyHour: itemVal.hasHappyHour ?? false,
|
||||
isNotAvailable: itemVal.isNotAvailable ?? false,
|
||||
items,
|
||||
addRow: {
|
||||
itemId: '',
|
||||
quantity: 1,
|
||||
@@ -130,25 +100,15 @@ export class BundleDetailComponent implements AfterViewInit {
|
||||
|
||||
form = form(this.formModel);
|
||||
|
||||
menuCategories = signal<MenuCategory[]>([]);
|
||||
saleCategories = signal<SaleCategory[]>([]);
|
||||
items = signal<BundleItem[]>([]);
|
||||
dataSource = computed(() => this.items());
|
||||
|
||||
item: Bundle = new Bundle();
|
||||
|
||||
itemProduct = signal<ProductQuery | null>(null);
|
||||
|
||||
itemIdSignal = computed(() => {
|
||||
const x = this.formModel().addRow?.itemId;
|
||||
return typeof x === 'string' ? x.trim() : '';
|
||||
private itemProductSearch = computed(() => {
|
||||
const v = this.form.addRow.itemId().value();
|
||||
return typeof v === 'string' ? v : null;
|
||||
});
|
||||
|
||||
debouncedItemId = debounced(this.itemIdSignal, 150);
|
||||
debouncedItemProduct = debounced(this.itemProductSearch, 150);
|
||||
|
||||
itemProductsResource = this.productSer.query(computed(() => this.debouncedItemId.value()));
|
||||
itemProductsResource = this.productSer.query(this.debouncedItemProduct.value);
|
||||
itemProducts = computed(() => {
|
||||
if (!this.debouncedItemId.value()) return [];
|
||||
return this.itemProductsResource.value() ?? [];
|
||||
});
|
||||
|
||||
@@ -156,25 +116,26 @@ export class BundleDetailComponent implements AfterViewInit {
|
||||
|
||||
constructor() {
|
||||
effect(() => {
|
||||
const x = this.formModel().addRow?.itemId;
|
||||
if (typeof x === 'string') {
|
||||
this.itemProduct.set(null);
|
||||
const v = this.form.addRow.itemId().value();
|
||||
if (typeof v === 'object' && v !== null) {
|
||||
this.formModel.update((f) => ({
|
||||
...f,
|
||||
addRow: {
|
||||
...f.addRow,
|
||||
salePrice: v.price ?? 0,
|
||||
},
|
||||
}));
|
||||
}
|
||||
});
|
||||
effect(() => {
|
||||
const menuCategoriesVal = this.menuCategoriesResource.value();
|
||||
if (menuCategoriesVal) this.menuCategories.set(menuCategoriesVal);
|
||||
const saleCategoriesVal = this.saleCategoriesResource.value();
|
||||
if (saleCategoriesVal) this.saleCategories.set(saleCategoriesVal);
|
||||
const itemVal = this.itemResource.value();
|
||||
if (itemVal) {
|
||||
this.item = itemVal;
|
||||
|
||||
this.itemProduct.set(null);
|
||||
|
||||
this.items.set(this.item.items ?? []);
|
||||
this.recalcBundleSalePrice();
|
||||
}
|
||||
const items = this.form.items().value();
|
||||
this.formModel.update((f) => ({
|
||||
...f,
|
||||
salePrice: Number(items.reduce((sum, x) => sum + x.quantity * x.salePrice, 0).toFixed(2)),
|
||||
}));
|
||||
});
|
||||
afterNextRender(() => {
|
||||
this.form().focusBoundControl();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -182,40 +143,6 @@ export class BundleDetailComponent implements AfterViewInit {
|
||||
return !product ? '' : typeof product === 'string' ? product : product.name;
|
||||
}
|
||||
|
||||
bundleSelected(event: MatAutocompleteSelectedEvent): void {
|
||||
const product = event.option.value as ProductQuery;
|
||||
this.itemProduct.set(product);
|
||||
this.formModel.update((f) => ({
|
||||
...f,
|
||||
addRow: {
|
||||
...f.addRow,
|
||||
salePrice: product.price ?? 0,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
private recalcBundleSalePrice(): void {
|
||||
const total = (this.item.items ?? []).reduce((sum, x) => {
|
||||
const qty = Number(x.quantity ?? 0);
|
||||
const price = Number(x.salePrice ?? 0);
|
||||
if (Number.isNaN(qty) || Number.isNaN(price)) return sum;
|
||||
return sum + qty * price;
|
||||
}, 0);
|
||||
|
||||
// keep model + form in sync
|
||||
this.item.salePrice = Number(total.toFixed(2));
|
||||
|
||||
this.formModel.update((f) => ({ ...f, salePrice: this.item.salePrice }));
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement !== undefined) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
|
||||
resetAddRow() {
|
||||
this.formModel.update((f) => ({
|
||||
...f,
|
||||
@@ -226,47 +153,43 @@ export class BundleDetailComponent implements AfterViewInit {
|
||||
printInBill: true,
|
||||
},
|
||||
}));
|
||||
this.itemProduct.set(null);
|
||||
}
|
||||
|
||||
addRow() {
|
||||
const v = this.formModel().addRow;
|
||||
if (!v) {
|
||||
return;
|
||||
}
|
||||
const formValue = this.form().value().addRow;
|
||||
if (!formValue) return;
|
||||
const itemProduct = formValue.itemId as ProductQuery;
|
||||
|
||||
if (!this.itemProduct()?.id) {
|
||||
if (!itemProduct || typeof itemProduct === 'string') {
|
||||
this.snackBar.open('Please select a product', 'Error');
|
||||
return;
|
||||
}
|
||||
|
||||
const quantity = Number(v.quantity ?? 0);
|
||||
const quantity = Number(formValue.quantity ?? 0);
|
||||
if (Number.isNaN(quantity) || quantity <= 0) {
|
||||
this.snackBar.open('Quantity has to be > 0', 'Error');
|
||||
return;
|
||||
}
|
||||
|
||||
const salePrice = Number(v.salePrice ?? 0);
|
||||
const salePrice = Number(formValue.salePrice ?? 0);
|
||||
if (Number.isNaN(salePrice) || salePrice < 0) {
|
||||
this.snackBar.open('Sale Price has to be >= 0', 'Error');
|
||||
return;
|
||||
}
|
||||
|
||||
// name is expected from backend as "name (units)" on GET;
|
||||
// for new rows we keep it blank (or you can set placeholder)
|
||||
const bi = new BundleItem({
|
||||
itemId: this.itemProduct()?.id,
|
||||
name: this.itemProduct()?.name ?? '',
|
||||
itemId: itemProduct.id,
|
||||
name: itemProduct.name ?? '',
|
||||
quantity,
|
||||
salePrice,
|
||||
printInBill: v.printInBill || false,
|
||||
printInBill: formValue.printInBill || false,
|
||||
});
|
||||
|
||||
this.item.items.push(bi);
|
||||
this.items.set(this.item.items);
|
||||
this.formModel.update((m) => ({
|
||||
...m,
|
||||
items: [...m.items, bi],
|
||||
}));
|
||||
this.resetAddRow();
|
||||
|
||||
this.recalcBundleSalePrice();
|
||||
}
|
||||
|
||||
editRow(row: BundleItem) {
|
||||
@@ -281,25 +204,28 @@ export class BundleDetailComponent implements AfterViewInit {
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
Object.assign(row, result as BundleItem);
|
||||
this.items.set(this.item.items);
|
||||
const updated = result as BundleItem;
|
||||
this.formModel.update((m) => ({
|
||||
...m,
|
||||
items: m.items.map((item) => (item === row ? Object.assign(new BundleItem(item), updated) : item)),
|
||||
}));
|
||||
this.resetAddRow();
|
||||
this.recalcBundleSalePrice();
|
||||
});
|
||||
}
|
||||
|
||||
deleteRow(row: BundleItem) {
|
||||
this.item.items.splice(this.item.items.indexOf(row), 1);
|
||||
this.items.set(this.item.items);
|
||||
this.recalcBundleSalePrice();
|
||||
this.formModel.update((m) => ({
|
||||
...m,
|
||||
items: m.items.filter((item) => item !== row),
|
||||
}));
|
||||
}
|
||||
|
||||
save() {
|
||||
if (!this.item.items || this.item.items.length === 0) {
|
||||
this.snackBar.open('Bundle must contain at least one item', 'Error');
|
||||
const item = this.getItem();
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
this.ser.saveOrUpdate(this.getItem()).subscribe({
|
||||
this.ser.saveOrUpdate(item).subscribe({
|
||||
next: () => {
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/bundles');
|
||||
@@ -311,7 +237,7 @@ export class BundleDetailComponent implements AfterViewInit {
|
||||
}
|
||||
|
||||
delete() {
|
||||
this.ser.delete(this.item.id as string).subscribe({
|
||||
this.ser.delete(this.item().id as string).subscribe({
|
||||
next: () => {
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/bundles');
|
||||
@@ -335,47 +261,33 @@ export class BundleDetailComponent implements AfterViewInit {
|
||||
});
|
||||
}
|
||||
|
||||
getItem(): Bundle {
|
||||
getItem(): Bundle | null {
|
||||
const v = this.formModel();
|
||||
|
||||
this.item.name = v.name ?? '';
|
||||
this.item.units = v.units ?? '';
|
||||
this.item.salePrice = Number(v.salePrice ?? 0);
|
||||
this.item.hasHappyHour = v.hasHappyHour ?? false;
|
||||
this.item.isNotAvailable = v.isNotAvailable ?? false;
|
||||
this.item.sortOrder = this.item.sortOrder ?? 0;
|
||||
|
||||
// menu category
|
||||
const menuCategoryId = v.menuCategory ?? '';
|
||||
if (!menuCategoryId) {
|
||||
// keep it as-is; backend will 422 anyway, but we can show UI error too
|
||||
if (!v.menuCategory) {
|
||||
this.snackBar.open('Menu Category is required', 'Error');
|
||||
return this.item;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.item.menuCategory === null || this.item.menuCategory === undefined) {
|
||||
this.item.menuCategory = new MenuCategory();
|
||||
}
|
||||
this.item.menuCategory.id = menuCategoryId;
|
||||
|
||||
// sale category
|
||||
const saleCategoryId = v.saleCategory ?? '';
|
||||
if (!saleCategoryId) {
|
||||
// keep it as-is; backend will 422 anyway, but we can show UI error too
|
||||
if (!v.saleCategory) {
|
||||
this.snackBar.open('Menu Category is required', 'Error');
|
||||
return this.item;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.item.saleCategory === null || this.item.saleCategory === undefined) {
|
||||
this.item.saleCategory = new SaleCategory();
|
||||
if (!v.items.length) {
|
||||
this.snackBar.open('Bundle must contain at least one item', 'Error');
|
||||
return null;
|
||||
}
|
||||
this.item.saleCategory.id = saleCategoryId;
|
||||
|
||||
// ensure items array exists
|
||||
if (!this.item.items) {
|
||||
this.item.items = [];
|
||||
}
|
||||
|
||||
return this.item;
|
||||
return new Bundle({
|
||||
...this.item(),
|
||||
name: v.name ?? '',
|
||||
units: v.units ?? '',
|
||||
salePrice: Number(v.salePrice ?? 0),
|
||||
hasHappyHour: v.hasHappyHour ?? false,
|
||||
isNotAvailable: v.isNotAvailable ?? false,
|
||||
sortOrder: this.item().sortOrder ?? 0,
|
||||
menuCategory: v.menuCategory,
|
||||
saleCategory: v.saleCategory,
|
||||
items: v.items ?? [],
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput #nameElement [formField]="form.name" />
|
||||
<input matInput [formField]="form.name" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { PercentPipe } from '@angular/common';
|
||||
import { AfterViewInit, Component, ElementRef, ViewChild, computed, inject, linkedSignal, input } from '@angular/core';
|
||||
import { Component, computed, inject, linkedSignal, input, afterNextRender } from '@angular/core';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
@@ -39,8 +39,7 @@ export interface CustomerDetailFormData {
|
||||
FormField,
|
||||
],
|
||||
})
|
||||
export class CustomerDetailComponent implements AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
export class CustomerDetailComponent {
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
private snackBar = inject(MatSnackBar);
|
||||
@@ -68,12 +67,10 @@ export class CustomerDetailComponent implements AfterViewInit {
|
||||
|
||||
hide = true;
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement !== undefined) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
constructor() {
|
||||
afterNextRender(() => {
|
||||
this.form().focusBoundControl();
|
||||
});
|
||||
}
|
||||
|
||||
save() {
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Filter</mat-label>
|
||||
<input type="text" matInput #filterElement [formField]="form.filter" autocomplete="off" />
|
||||
<input type="text" matInput [formField]="form.filter" autocomplete="off" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</form>
|
||||
<mat-table #table [dataSource]="dataSource().items" matSort aria-label="Elements">
|
||||
<mat-table #table [dataSource]="dataSource().items" matSort (matSortChange)="sortData($event)" aria-label="Elements">
|
||||
<!-- Name Column -->
|
||||
<ng-container matColumnDef="name">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Name</mat-header-cell>
|
||||
|
||||
@@ -1,21 +1,12 @@
|
||||
/* eslint-disable @angular-eslint/no-input-rename */
|
||||
import { PercentPipe } from '@angular/common';
|
||||
import {
|
||||
AfterViewInit,
|
||||
Component,
|
||||
ElementRef,
|
||||
ViewChild,
|
||||
inject,
|
||||
signal,
|
||||
effect,
|
||||
computed,
|
||||
debounced,
|
||||
} from '@angular/core';
|
||||
import { Component, inject, signal, effect, computed, debounced, afterNextRender, input } from '@angular/core';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatSort, MatSortModule } from '@angular/material/sort';
|
||||
import { MatPaginatorModule, PageEvent } from '@angular/material/paginator';
|
||||
import { MatSortModule, Sort } from '@angular/material/sort';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
||||
|
||||
@@ -42,13 +33,23 @@ export interface CustomerListFormData {
|
||||
FormField,
|
||||
],
|
||||
})
|
||||
export class CustomerListComponent implements AfterViewInit {
|
||||
@ViewChild('filterElement', { static: true }) filterElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
export class CustomerListComponent {
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
private customerService = inject(CustomerService);
|
||||
q = input('', { transform: (v: string | null | undefined) => v ?? '' });
|
||||
pageSize = input(50, {
|
||||
transform: (v: string | number | null | undefined): number => (v ? Number(v) : 50),
|
||||
alias: 's',
|
||||
});
|
||||
|
||||
pageIndex = input(0, {
|
||||
transform: (v: string | number | null | undefined): number => (v ? Number(v) : 0),
|
||||
alias: 'i',
|
||||
});
|
||||
|
||||
sortInput = input<string>('name', { alias: 'f' });
|
||||
direction = input<string>('asc', { alias: 'd' });
|
||||
|
||||
formModel = signal<CustomerListFormData>({
|
||||
filter: this.route.snapshot.queryParamMap.get('q') ?? '',
|
||||
@@ -56,23 +57,10 @@ export class CustomerListComponent implements AfterViewInit {
|
||||
|
||||
form = form(this.formModel);
|
||||
|
||||
filterSignal = computed(() => this.formModel().filter);
|
||||
filterSignal = computed(() => this.formModel().filter ?? null);
|
||||
debouncedFilter = debounced(this.filterSignal, 150);
|
||||
|
||||
pageIndex = signal(+(this.route.snapshot.queryParamMap.get('p') ?? '0'));
|
||||
pageSize = signal(+(this.route.snapshot.queryParamMap.get('s') ?? '50'));
|
||||
sortField = signal(this.route.snapshot.queryParamMap.get('f') ?? 'name');
|
||||
sortDirection = signal(this.route.snapshot.queryParamMap.get('d') ?? 'asc');
|
||||
|
||||
queryParams = computed(() => ({
|
||||
q: this.debouncedFilter.value() ?? '',
|
||||
p: this.pageIndex(),
|
||||
s: this.pageSize(),
|
||||
f: this.sortField(),
|
||||
d: this.sortDirection(),
|
||||
}));
|
||||
|
||||
listResource = this.customerService.query(this.queryParams);
|
||||
listResource = this.customerService.query(this.q, this.pageIndex, this.pageSize, this.sortInput, this.direction);
|
||||
|
||||
dataSource = computed(() => {
|
||||
const data = this.listResource.value();
|
||||
@@ -84,32 +72,37 @@ export class CustomerListComponent implements AfterViewInit {
|
||||
displayedColumns = ['name', 'phone', 'address', 'printInBill', 'discounts'];
|
||||
|
||||
constructor() {
|
||||
// Sync query string whenever params change
|
||||
effect(() => {
|
||||
const p = this.queryParams();
|
||||
const q = this.debouncedFilter.value();
|
||||
this.router.navigate([], {
|
||||
relativeTo: this.route,
|
||||
queryParams: { q: p.q, p: p.p, s: p.s, f: p.f, d: p.d },
|
||||
queryParams: { q: q },
|
||||
queryParamsHandling: 'merge',
|
||||
replaceUrl: true,
|
||||
});
|
||||
});
|
||||
afterNextRender(() => {
|
||||
this.form().focusBoundControl();
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.sort.sortChange.subscribe(() => {
|
||||
this.sortField.set(this.sort.active);
|
||||
this.sortDirection.set(this.sort.direction);
|
||||
this.pageIndex.set(0);
|
||||
});
|
||||
handlePageEvent(e: PageEvent) {
|
||||
if (e.pageSize !== this.pageSize() || e.pageIndex !== this.pageIndex()) {
|
||||
this.router.navigate([], {
|
||||
relativeTo: this.route,
|
||||
queryParams: { s: e.pageSize, p: e.pageIndex },
|
||||
queryParamsHandling: 'merge',
|
||||
replaceUrl: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.paginator.page.subscribe(() => {
|
||||
this.pageSize.set(this.paginator.pageSize);
|
||||
this.pageIndex.set(this.paginator.pageIndex);
|
||||
sortData(sort: Sort) {
|
||||
this.router.navigate([], {
|
||||
relativeTo: this.route,
|
||||
queryParams: { f: sort.active || null, d: sort.direction || null },
|
||||
queryParamsHandling: 'merge',
|
||||
replaceUrl: true,
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
this.filterElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
@@ -41,18 +41,21 @@ export class CustomerService {
|
||||
}
|
||||
|
||||
query(
|
||||
params: Signal<{ q: string; p: number; s: number; f: string; d: string }>,
|
||||
q: Signal<string>,
|
||||
p: Signal<number>,
|
||||
s: Signal<number>,
|
||||
f: Signal<string>,
|
||||
d: Signal<string>,
|
||||
): HttpResourceRef<PagedResult<Customer> | undefined> {
|
||||
return httpResource<PagedResult<Customer>>(() => {
|
||||
const p = params();
|
||||
return {
|
||||
url: `${url}/list`,
|
||||
params: {
|
||||
...(p.q ? { q: p.q } : {}),
|
||||
p: p.p,
|
||||
s: p.s,
|
||||
f: p.f,
|
||||
d: p.d,
|
||||
q: q(),
|
||||
p: p(),
|
||||
s: s(),
|
||||
f: f(),
|
||||
d: d(),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput #nameElement [formField]="form.name" (keyup.enter)="save()" />
|
||||
<input matInput [formField]="form.name" (keyup.enter)="save()" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AfterViewInit, Component, ElementRef, ViewChild, computed, inject, linkedSignal, input } from '@angular/core';
|
||||
import { Component, computed, inject, linkedSignal, input, afterNextRender } from '@angular/core';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
@@ -38,8 +38,7 @@ export interface DeviceDetailFormData {
|
||||
FormField,
|
||||
],
|
||||
})
|
||||
export class DeviceDetailComponent implements AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
export class DeviceDetailComponent {
|
||||
private sectionService = inject(SectionService);
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
@@ -68,12 +67,10 @@ export class DeviceDetailComponent implements AfterViewInit {
|
||||
|
||||
sections = computed(() => this.sectionsResource.value() ?? []);
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement !== undefined) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
constructor() {
|
||||
afterNextRender(() => {
|
||||
this.form().focusBoundControl();
|
||||
});
|
||||
}
|
||||
|
||||
save() {
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput #name [formField]="form.name" />
|
||||
<input matInput [formField]="form.name" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Phone</mat-label>
|
||||
<input matInput #phone type="text" [formField]="form.phone" [matAutocomplete]="auto" autocomplete="off" />
|
||||
<input matInput type="text" [formField]="form.phone" [matAutocomplete]="auto" autocomplete="off" />
|
||||
</mat-form-field>
|
||||
<mat-autocomplete
|
||||
#auto="matAutocomplete"
|
||||
|
||||
@@ -1,14 +1,4 @@
|
||||
import {
|
||||
AfterViewInit,
|
||||
Component,
|
||||
ElementRef,
|
||||
ViewChild,
|
||||
computed,
|
||||
inject,
|
||||
debounced,
|
||||
linkedSignal,
|
||||
input,
|
||||
} from '@angular/core';
|
||||
import { Component, computed, inject, debounced, linkedSignal, input, afterNextRender } from '@angular/core';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { MatAutocompleteSelectedEvent, MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
@@ -53,8 +43,7 @@ export interface GuestBookDetailFormData {
|
||||
FormField,
|
||||
],
|
||||
})
|
||||
export class GuestBookDetailComponent implements AfterViewInit {
|
||||
@ViewChild('phone', { static: true }) phoneElement?: ElementRef;
|
||||
export class GuestBookDetailComponent {
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
private dialog = inject(MatDialog);
|
||||
@@ -111,12 +100,10 @@ export class GuestBookDetailComponent implements AfterViewInit {
|
||||
return this.customersResource.value() ?? [];
|
||||
});
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.phoneElement !== undefined) {
|
||||
this.phoneElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
constructor() {
|
||||
afterNextRender(() => {
|
||||
this.form().focusBoundControl();
|
||||
});
|
||||
}
|
||||
|
||||
save() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, ElementRef, ViewChild, computed, inject, linkedSignal, input } from '@angular/core';
|
||||
import { Component, computed, inject, linkedSignal, input } from '@angular/core';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatOptionModule } from '@angular/material/core';
|
||||
@@ -33,7 +33,6 @@ export interface HeaderFooterFormData {
|
||||
],
|
||||
})
|
||||
export class HeaderFooterComponent {
|
||||
@ViewChild('section', { static: true }) sectionElement?: ElementRef;
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
private snackBar = inject(MatSnackBar);
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput #nameElement [formField]="form.name" />
|
||||
<input matInput [formField]="form.name" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AfterViewInit, Component, ElementRef, ViewChild, computed, inject, linkedSignal, input } from '@angular/core';
|
||||
import { Component, computed, inject, linkedSignal, input, afterNextRender } from '@angular/core';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
@@ -23,8 +23,7 @@ export interface MenuCategoryDetailFormData {
|
||||
styleUrls: ['./menu-category-detail.component.css'],
|
||||
imports: [MatButtonModule, MatCheckboxModule, MatFormFieldModule, MatInputModule, FormField],
|
||||
})
|
||||
export class MenuCategoryDetailComponent implements AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
export class MenuCategoryDetailComponent {
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
private dialog = inject(MatDialog);
|
||||
@@ -47,12 +46,10 @@ export class MenuCategoryDetailComponent implements AfterViewInit {
|
||||
|
||||
form = form(this.formModel);
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement !== undefined) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
constructor() {
|
||||
afterNextRender(() => {
|
||||
this.form().focusBoundControl();
|
||||
});
|
||||
}
|
||||
|
||||
save() {
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Filter</mat-label>
|
||||
<input type="text" matInput #filterElement [formField]="form.filter" autocomplete="off" />
|
||||
<input type="text" matInput [formField]="form.filter" autocomplete="off" />
|
||||
<mat-hint
|
||||
>n: Name, sc: Sale Category, mc: Menu Category, q:(=/<=/>=/</>)Quantity,
|
||||
s:(=/<=/>=/</>)Sales</mat-hint
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { DecimalPipe, PercentPipe } from '@angular/common';
|
||||
import { Component, ViewChild, ElementRef, inject, computed, linkedSignal, input } from '@angular/core';
|
||||
import { Component, inject, computed, linkedSignal, input, afterNextRender } from '@angular/core';
|
||||
import { toObservable } from '@angular/core/rxjs-interop';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
@@ -7,9 +7,9 @@ import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { MatSort, MatSortModule } from '@angular/material/sort';
|
||||
import { MatSortModule } from '@angular/material/sort';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import moment from 'moment';
|
||||
@@ -45,9 +45,6 @@ export interface MenuEngineeringReportFormData {
|
||||
],
|
||||
})
|
||||
export class MenuEngineeringReportComponent {
|
||||
@ViewChild('filterElement', { static: true }) filterElement?: ElementRef;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
private toCsv = inject(ToCsvService);
|
||||
@@ -89,6 +86,9 @@ export class MenuEngineeringReportComponent {
|
||||
// Listen to Filter Change
|
||||
const filterSignal = computed(() => this.formModel().filter);
|
||||
this.filter = toObservable(filterSignal).pipe(debounceTime(150), distinctUntilChanged());
|
||||
afterNextRender(() => {
|
||||
this.form().focusBoundControl();
|
||||
});
|
||||
}
|
||||
|
||||
show() {
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput #nameElement [formField]="form.name" />
|
||||
<input matInput [formField]="form.name" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
|
||||
+5
-11
@@ -1,4 +1,4 @@
|
||||
import { AfterViewInit, Component, ElementRef, ViewChild, effect, inject, input, signal } from '@angular/core';
|
||||
import { Component, effect, inject, input, signal, afterNextRender } from '@angular/core';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
@@ -48,8 +48,7 @@ export interface ModifierCategoryDetailFormData {
|
||||
FormField,
|
||||
],
|
||||
})
|
||||
export class ModifierCategoryDetailComponent implements AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
export class ModifierCategoryDetailComponent {
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
private snackBar = inject(MatSnackBar);
|
||||
@@ -108,14 +107,9 @@ export class ModifierCategoryDetailComponent implements AfterViewInit {
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement !== undefined) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
afterNextRender(() => {
|
||||
this.form().focusBoundControl();
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput #name [formField]="form.name" />
|
||||
<input matInput [formField]="form.name" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AfterViewInit, Component, ElementRef, ViewChild, computed, inject, linkedSignal, input } from '@angular/core';
|
||||
import { Component, computed, inject, linkedSignal, input, afterNextRender } from '@angular/core';
|
||||
import { form, FormField, required } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
@@ -38,8 +38,7 @@ export interface ModifierDetailFormData {
|
||||
FormField,
|
||||
],
|
||||
})
|
||||
export class ModifierDetailComponent implements AfterViewInit {
|
||||
@ViewChild('name', { static: true }) nameElement?: ElementRef;
|
||||
export class ModifierDetailComponent {
|
||||
private modifierCategoryService = inject(ModifierCategoryService);
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
@@ -71,12 +70,10 @@ export class ModifierDetailComponent implements AfterViewInit {
|
||||
required(schema.modifierCategory, { message: 'Modifier Category is required' });
|
||||
});
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement !== undefined) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
constructor() {
|
||||
afterNextRender(() => {
|
||||
this.form().focusBoundControl();
|
||||
});
|
||||
}
|
||||
|
||||
save() {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput #nameElement [formField]="form.name" />
|
||||
<input matInput [formField]="form.name" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AfterViewInit, Component, ElementRef, ViewChild, computed, inject, linkedSignal, input } from '@angular/core';
|
||||
import { Component, computed, inject, linkedSignal, input, afterNextRender } from '@angular/core';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
@@ -23,8 +23,7 @@ export interface PrinterDetailFormData {
|
||||
styleUrls: ['./printer-detail.component.css'],
|
||||
imports: [MatButtonModule, MatFormFieldModule, MatInputModule, FormField],
|
||||
})
|
||||
export class PrinterDetailComponent implements AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
export class PrinterDetailComponent {
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
private dialog = inject(MatDialog);
|
||||
@@ -48,12 +47,10 @@ export class PrinterDetailComponent implements AfterViewInit {
|
||||
|
||||
form = form(this.formModel);
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement !== undefined) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
constructor() {
|
||||
afterNextRender(() => {
|
||||
this.form().focusBoundControl();
|
||||
});
|
||||
}
|
||||
|
||||
save() {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
</button>
|
||||
</h2>
|
||||
|
||||
<form class="flex-col">
|
||||
<form class="flex-col" [formRoot]="form">
|
||||
<div class="row-container sm:max-lg:flex-col">
|
||||
<mat-form-field class="flex-auto basis-1-3">
|
||||
<mat-label>Start Date</mat-label>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { DecimalPipe } from '@angular/common';
|
||||
import { Component, inject, computed, linkedSignal, input } from '@angular/core';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { form, FormField, FormRoot } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
@@ -37,6 +37,7 @@ export interface ProductSaleReportFormData {
|
||||
MatSelectModule,
|
||||
MatTableModule,
|
||||
FormField,
|
||||
FormRoot,
|
||||
],
|
||||
})
|
||||
export class ProductSaleReportComponent {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="row-container">
|
||||
<mat-form-field class="basis-3-4">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput #name [formField]="form.name" />
|
||||
<input matInput [formField]="form.name" />
|
||||
</mat-form-field>
|
||||
<mat-form-field class="basis-1-4">
|
||||
<mat-label>Fraction Units</mat-label>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CurrencyPipe } from '@angular/common';
|
||||
import { AfterViewInit, Component, ElementRef, ViewChild, inject, computed, linkedSignal, input } from '@angular/core';
|
||||
import { Component, inject, computed, linkedSignal, input, afterNextRender } from '@angular/core';
|
||||
import { form, FormField, required, min, max } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
@@ -57,8 +57,7 @@ export interface ProductDetailFormData {
|
||||
FormField,
|
||||
],
|
||||
})
|
||||
export class ProductDetailComponent implements AfterViewInit {
|
||||
@ViewChild('name', { static: true }) nameElement?: ElementRef;
|
||||
export class ProductDetailComponent {
|
||||
private menuCategoryService = inject(MenuCategoryService);
|
||||
private saleCategoryService = inject(SaleCategoryService);
|
||||
private route = inject(ActivatedRoute);
|
||||
@@ -123,12 +122,10 @@ export class ProductDetailComponent implements AfterViewInit {
|
||||
'action',
|
||||
];
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement !== undefined) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
constructor() {
|
||||
afterNextRender(() => {
|
||||
this.form().focusBoundControl();
|
||||
});
|
||||
}
|
||||
|
||||
addRow() {
|
||||
|
||||
@@ -44,9 +44,9 @@ export class ProductService {
|
||||
});
|
||||
}
|
||||
|
||||
query(query: Signal<string | null> | string | null): HttpResourceRef<ProductQuery[] | undefined> {
|
||||
query(query: Signal<string | null>): HttpResourceRef<ProductQuery[] | undefined> {
|
||||
return httpResource<ProductQuery[]>(() => {
|
||||
const qVal = typeof query === 'function' ? query() : query;
|
||||
const qVal = query();
|
||||
return `${url}/query?q=${qVal ?? ''}`;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput #nameElement [formField]="form.name" (keyup.enter)="save()" />
|
||||
<input matInput [formField]="form.name" (keyup.enter)="save()" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AfterViewInit, Component, ElementRef, ViewChild, computed, inject, linkedSignal, input } from '@angular/core';
|
||||
import { Component, computed, inject, linkedSignal, input, afterNextRender } from '@angular/core';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
@@ -23,8 +23,7 @@ export interface RegimeDetailFormData {
|
||||
styleUrls: ['./regime-detail.component.css'],
|
||||
imports: [MatButtonModule, MatFormFieldModule, MatInputModule, FormField],
|
||||
})
|
||||
export class RegimeDetailComponent implements AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
export class RegimeDetailComponent {
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
private dialog = inject(MatDialog);
|
||||
@@ -48,12 +47,10 @@ export class RegimeDetailComponent implements AfterViewInit {
|
||||
|
||||
form = form(this.formModel);
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement !== undefined) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
constructor() {
|
||||
afterNextRender(() => {
|
||||
this.form().focusBoundControl();
|
||||
});
|
||||
}
|
||||
|
||||
save() {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput #nameElement [formField]="form.name" />
|
||||
<input matInput [formField]="form.name" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AfterViewInit, Component, ElementRef, ViewChild, computed, inject, linkedSignal, input } from '@angular/core';
|
||||
import { Component, computed, inject, linkedSignal, input, afterNextRender } from '@angular/core';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
@@ -24,8 +24,7 @@ export interface RoleDetailFormData {
|
||||
styleUrls: ['./role-detail.component.css'],
|
||||
imports: [MatButtonModule, MatCheckboxModule, MatFormFieldModule, MatInputModule, FormField],
|
||||
})
|
||||
export class RoleDetailComponent implements AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
export class RoleDetailComponent {
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
private snackBar = inject(MatSnackBar);
|
||||
@@ -60,12 +59,10 @@ export class RoleDetailComponent implements AfterViewInit {
|
||||
return implied;
|
||||
});
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement !== undefined) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
constructor() {
|
||||
afterNextRender(() => {
|
||||
this.form().focusBoundControl();
|
||||
});
|
||||
}
|
||||
|
||||
save() {
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput #nameElement [formField]="form.name" />
|
||||
<input matInput [formField]="form.name" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CurrencyPipe } from '@angular/common';
|
||||
import { AfterViewInit, Component, ElementRef, ViewChild, inject, computed, linkedSignal, input } from '@angular/core';
|
||||
import { Component, inject, computed, linkedSignal, input, afterNextRender } from '@angular/core';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatOptionModule } from '@angular/material/core';
|
||||
@@ -43,8 +43,7 @@ export interface SaleCategoryDetailFormData {
|
||||
RouterLink,
|
||||
],
|
||||
})
|
||||
export class SaleCategoryDetailComponent implements AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
export class SaleCategoryDetailComponent {
|
||||
private taxService = inject(TaxService);
|
||||
private productService = inject(ProductService);
|
||||
private route = inject(ActivatedRoute);
|
||||
@@ -80,12 +79,10 @@ export class SaleCategoryDetailComponent implements AfterViewInit {
|
||||
dataSource = computed(() => this.products());
|
||||
displayedColumns = ['name', 'price', 'menuCategory'];
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement !== undefined) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
constructor() {
|
||||
afterNextRender(() => {
|
||||
this.form().focusBoundControl();
|
||||
});
|
||||
}
|
||||
|
||||
save() {
|
||||
|
||||
@@ -20,7 +20,6 @@ export class SaleCategoryListComponent {
|
||||
private ser = inject(SaleCategoryService);
|
||||
listResource = this.ser.list();
|
||||
|
||||
// @ViewChild('table', { static: true }) table?: MatTable<SaleCategory>;
|
||||
dataSource = computed(() => this.listResource.value() ?? []);
|
||||
|
||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CdkScrollableModule } from '@angular/cdk/scrolling';
|
||||
import { Component, ElementRef, ViewChild, 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 { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule } from '@angular/material/dialog';
|
||||
@@ -26,7 +26,6 @@ export interface ReasonFormData {
|
||||
],
|
||||
})
|
||||
export class ReasonComponent {
|
||||
@ViewChild('son', { static: true }) son?: ElementRef;
|
||||
dialogRef = inject<MatDialogRef<ReasonComponent>>(MatDialogRef);
|
||||
private data = inject<{
|
||||
title: string;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { CdkScrollableModule } from '@angular/cdk/scrolling';
|
||||
import { CurrencyPipe } from '@angular/common';
|
||||
import { Component, ElementRef, ViewChild, inject, signal, computed } from '@angular/core';
|
||||
import { Component, inject, signal, computed } from '@angular/core';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule } from '@angular/material/dialog';
|
||||
@@ -38,7 +38,6 @@ export interface ReceivePaymentFormData {
|
||||
],
|
||||
})
|
||||
export class ReceivePaymentComponent {
|
||||
@ViewChild('son', { static: true }) son?: ElementRef;
|
||||
private ser = inject(SettleOptionService);
|
||||
dialogRef = inject<MatDialogRef<ReceivePaymentComponent>>(MatDialogRef);
|
||||
data = inject<{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, ElementRef, ViewChild, computed, inject, linkedSignal, input } from '@angular/core';
|
||||
import { Component, computed, inject, linkedSignal, input } from '@angular/core';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatOptionModule } from '@angular/material/core';
|
||||
@@ -43,7 +43,6 @@ export interface SectionPrinterFormData {
|
||||
],
|
||||
})
|
||||
export class SectionPrinterComponent {
|
||||
@ViewChild('section', { static: true }) sectionElement?: ElementRef;
|
||||
private printerService = inject(PrinterService);
|
||||
private sectionService = inject(SectionService);
|
||||
private route = inject(ActivatedRoute);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput #nameElement [formField]="form.name" (keyup.enter)="save()" />
|
||||
<input matInput [formField]="form.name" (keyup.enter)="save()" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AfterViewInit, Component, ElementRef, ViewChild, computed, inject, linkedSignal, input } from '@angular/core';
|
||||
import { Component, computed, inject, linkedSignal, input, afterNextRender } from '@angular/core';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
@@ -21,8 +21,7 @@ export interface SectionDetailFormData {
|
||||
styleUrls: ['./section-detail.component.css'],
|
||||
imports: [MatButtonModule, MatFormFieldModule, MatInputModule, FormField],
|
||||
})
|
||||
export class SectionDetailComponent implements AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
export class SectionDetailComponent {
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
private dialog = inject(MatDialog);
|
||||
@@ -44,12 +43,10 @@ export class SectionDetailComponent implements AfterViewInit {
|
||||
|
||||
form = form(this.formModel);
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement !== undefined) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
constructor() {
|
||||
afterNextRender(() => {
|
||||
this.form().focusBoundControl();
|
||||
});
|
||||
}
|
||||
|
||||
save() {
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput #nameElement [formField]="form.name" />
|
||||
<input matInput [formField]="form.name" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
|
||||
+5
-11
@@ -1,4 +1,4 @@
|
||||
import { AfterViewInit, Component, ElementRef, ViewChild, computed, inject, linkedSignal, input } from '@angular/core';
|
||||
import { Component, computed, inject, linkedSignal, input, afterNextRender } from '@angular/core';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
@@ -37,8 +37,7 @@ export interface SettleOptionDetailFormData {
|
||||
FormField,
|
||||
],
|
||||
})
|
||||
export class SettleOptionDetailComponent implements AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
export class SettleOptionDetailComponent {
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
private dialog = inject(MatDialog);
|
||||
@@ -73,14 +72,9 @@ export class SettleOptionDetailComponent implements AfterViewInit {
|
||||
this.reportingLevel = Object.keys(ReportingLevel)
|
||||
.filter((e) => !isNaN(+e))
|
||||
.map((o) => ({ id: +o, name: ReportingLevel[+o] as string }));
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement !== undefined) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
afterNextRender(() => {
|
||||
this.form().focusBoundControl();
|
||||
});
|
||||
}
|
||||
|
||||
save() {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput #nameElement [formField]="form.name" (keyup.enter)="save()" />
|
||||
<input matInput [formField]="form.name" (keyup.enter)="save()" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AfterViewInit, Component, ElementRef, ViewChild, computed, inject, linkedSignal, input } from '@angular/core';
|
||||
import { Component, computed, inject, linkedSignal, input, afterNextRender } from '@angular/core';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
@@ -37,8 +37,7 @@ export interface TableDetailFormData {
|
||||
FormField,
|
||||
],
|
||||
})
|
||||
export class TableDetailComponent implements AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
export class TableDetailComponent {
|
||||
private sectionService = inject(SectionService);
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
@@ -68,12 +67,10 @@ export class TableDetailComponent implements AfterViewInit {
|
||||
|
||||
sections = computed(() => this.sectionsResource.value() ?? []);
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement !== undefined) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
constructor() {
|
||||
afterNextRender(() => {
|
||||
this.form().focusBoundControl();
|
||||
});
|
||||
}
|
||||
|
||||
save() {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput #nameElement [formField]="form.name" (keyup.enter)="save()" />
|
||||
<input matInput [formField]="form.name" (keyup.enter)="save()" />
|
||||
<mat-hint> Format for GST: ST GST @ x% (1/2) ; CGST @ x% (1/2) </mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AfterViewInit, Component, ElementRef, ViewChild, computed, inject, linkedSignal, input } from '@angular/core';
|
||||
import { Component, computed, inject, linkedSignal, input, afterNextRender } from '@angular/core';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatOptionModule } from '@angular/material/core';
|
||||
@@ -28,8 +28,7 @@ export interface TaxDetailFormData {
|
||||
styleUrls: ['./tax-detail.component.css'],
|
||||
imports: [MatButtonModule, MatFormFieldModule, MatInputModule, MatOptionModule, MatSelectModule, FormField],
|
||||
})
|
||||
export class TaxDetailComponent implements AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
export class TaxDetailComponent {
|
||||
private regimeService = inject(RegimeService);
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
@@ -58,12 +57,10 @@ export class TaxDetailComponent implements AfterViewInit {
|
||||
|
||||
regimes = computed(() => this.regimesResource.value() ?? []);
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement !== undefined) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
constructor() {
|
||||
afterNextRender(() => {
|
||||
this.form().focusBoundControl();
|
||||
});
|
||||
}
|
||||
|
||||
save() {
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto basis-3-4">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput #name [formField]="productForm.name" />
|
||||
<input matInput [formField]="productForm.name" />
|
||||
</mat-form-field>
|
||||
<mat-form-field class="flex-auto basis-1-4">
|
||||
<mat-label>Fraction Units</mat-label>
|
||||
|
||||
+7
-20
@@ -1,14 +1,4 @@
|
||||
import {
|
||||
AfterViewInit,
|
||||
Component,
|
||||
ElementRef,
|
||||
ViewChild,
|
||||
computed,
|
||||
inject,
|
||||
signal,
|
||||
linkedSignal,
|
||||
input,
|
||||
} from '@angular/core';
|
||||
import { Component, computed, inject, signal, linkedSignal, input, afterNextRender } from '@angular/core';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
@@ -74,8 +64,7 @@ export interface TemporalSkuFormData {
|
||||
FormField,
|
||||
],
|
||||
})
|
||||
export class TemporalProductDetailComponent implements AfterViewInit {
|
||||
@ViewChild('name', { static: true }) nameElement?: ElementRef;
|
||||
export class TemporalProductDetailComponent {
|
||||
private menuCategoryService = inject(MenuCategoryService);
|
||||
private saleCategoryService = inject(SaleCategoryService);
|
||||
private route = inject(ActivatedRoute);
|
||||
@@ -175,12 +164,10 @@ export class TemporalProductDetailComponent implements AfterViewInit {
|
||||
//
|
||||
// // }
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement !== undefined) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
constructor() {
|
||||
afterNextRender(() => {
|
||||
this.productForm().focusBoundControl();
|
||||
});
|
||||
}
|
||||
|
||||
editProduct(p: Product) {
|
||||
@@ -188,7 +175,7 @@ export class TemporalProductDetailComponent implements AfterViewInit {
|
||||
|
||||
console.log(p);
|
||||
|
||||
setTimeout(() => this.nameElement?.nativeElement?.focus?.(), 0);
|
||||
this.productForm().focusBoundControl();
|
||||
}
|
||||
|
||||
updateProduct() {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput #nameElement [formField]="form.name" />
|
||||
<input matInput [formField]="form.name" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AfterViewInit, Component, ElementRef, ViewChild, computed, inject, linkedSignal, input } from '@angular/core';
|
||||
import { Component, computed, inject, linkedSignal, input, afterNextRender } from '@angular/core';
|
||||
import { form, FormField } from '@angular/forms/signals';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
@@ -35,8 +35,7 @@ export interface UserDetailFormData {
|
||||
FormField,
|
||||
],
|
||||
})
|
||||
export class UserDetailComponent implements AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
export class UserDetailComponent {
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
private snackBar = inject(MatSnackBar);
|
||||
@@ -64,15 +63,10 @@ export class UserDetailComponent implements AfterViewInit {
|
||||
hide = true;
|
||||
|
||||
constructor() {
|
||||
this.hide = true;
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement !== undefined) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
afterNextRender(() => {
|
||||
this.form().focusBoundControl();
|
||||
// this.formModel().root.focus("name");
|
||||
});
|
||||
}
|
||||
|
||||
save() {
|
||||
|
||||
+438
-451
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user