Removed Recipe Template as it was not needed.

Moved host listeners to the component declaration.
Form submit on Return fixed.
This commit is contained in:
tanshu committed 2026-08-26 06:00:13 +00:00
1 parent fe5e4a2308
commit e3719faddd
79 files changed
+737 -990

No files matched your search

-4
View File
@@ -65,10 +65,6 @@ export const routes: Routes = [
path: 'recipes',
loadChildren: () => import('./recipe/recipe.routes').then((mod) => mod.routes),
},
{
path: 'recipe-templates',
loadChildren: () => import('./recipe-template/recipe-template.routes').then((mod) => mod.routes),
},
{
path: 'roles',
loadChildren: () => import('./role/role.routes').then((mod) => mod.routes),
@@ -1,6 +1,6 @@
<h2>Attendance</h2>
<form class="flex-col" [formRoot]="form">
<form class="flex-col" [formRoot]="form" (submit)="$event.preventDefault(); show()">
<div class="row-container">
<mat-form-field class="flex-auto basis-4-5">
<mat-label>Date</mat-label>
@@ -15,7 +15,7 @@
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
<mat-datepicker #date></mat-datepicker>
</mat-form-field>
<button mat-raised-button color="primary" (click)="show()" class="flex-auto basis-1-5">Show</button>
<button mat-raised-button type="submit" color="primary" class="flex-auto basis-1-5">Show</button>
</div>
@if (infoResource.isLoading()) {
<app-skeleton-loader type="table" [count]="1" />
@@ -1,4 +1,4 @@
import { Component, HostListener, inject, input, computed, linkedSignal, afterNextRender } from '@angular/core';
import { Component, inject, input, computed, linkedSignal, afterNextRender } from '@angular/core';
import { form as createForm, FormField, FormRoot } from '@angular/forms/signals';
import { MatButtonModule } from '@angular/material/button';
import { MatChipsModule } from '@angular/material/chips';
@@ -22,7 +22,7 @@ import { AttendanceTypeService } from './attendance-type.service';
import { AttendanceService } from './attendance.service';
export interface AttendanceFormData {
date: moment.Moment;
date: Date;
attendances: { attendanceType: number | null }[];
}
@@ -30,6 +30,9 @@ export interface AttendanceFormData {
selector: 'app-attendance',
templateUrl: './attendance.component.html',
styleUrls: ['./attendance.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
},
imports: [
FormField,
FormRoot,
@@ -64,7 +67,7 @@ export class AttendanceComponent {
model = linkedSignal({
source: this.info,
computation: (infoVal): AttendanceFormData => ({
date: moment(infoVal.date),
date: moment(infoVal.date, 'DD-MMM-YYYY').toDate(),
attendances: infoVal.body.map((x) => ({
attendanceType: x.attendanceType.id,
})),
@@ -75,7 +78,6 @@ export class AttendanceComponent {
displayedColumns = ['code', 'name', 'designation', 'department', 'status', 'prints'];
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
this.form().focusBoundControl();
@@ -1,6 +1,6 @@
<h2>Balance Sheet</h2>
<form class="flex-col" [formRoot]="form">
<form class="flex-col" [formRoot]="form" (submit)="$event.preventDefault(); show()">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Date</mat-label>
@@ -8,7 +8,7 @@
<mat-datepicker-toggle matSuffix [for]="dateInput"></mat-datepicker-toggle>
<mat-datepicker #dateInput></mat-datepicker>
</mat-form-field>
<button mat-raised-button color="primary" (click)="show()">Show</button>
<button mat-raised-button type="submit" color="primary">Show</button>
</div>
</form>
@if (infoResource.isLoading()) {
@@ -1,8 +1,8 @@
import { CurrencyPipe } from '@angular/common';
import { Component, HostListener, inject, input, computed, linkedSignal, signal, afterNextRender } from '@angular/core';
import { Component, inject, input, computed, linkedSignal, signal, afterNextRender } from '@angular/core';
import { form as createForm, FormField, FormRoot } from '@angular/forms/signals';
export interface BalanceSheetFormData {
date: moment.Moment;
date: Date;
}
import { MatButtonModule } from '@angular/material/button';
import { MatDatepickerModule } from '@angular/material/datepicker';
@@ -24,6 +24,9 @@ import { BalanceSheetService } from './balance-sheet.service';
selector: 'app-balance-sheet',
templateUrl: './balance-sheet.component.html',
styleUrls: ['./balance-sheet.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
},
imports: [
FormField,
FormRoot,
@@ -56,7 +59,7 @@ export class BalanceSheetComponent {
formModel = linkedSignal<import('./balance-sheet').BalanceSheet, BalanceSheetFormData>({
source: this.info,
computation: (info: BalanceSheet): BalanceSheetFormData => ({
date: info.date ? moment(info.date, 'DD-MMM-YYYY') : moment(new Date()),
date: info.date ? moment(info.date, 'DD-MMM-YYYY').toDate() : new Date(),
}),
});
@@ -103,7 +106,6 @@ export class BalanceSheetComponent {
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns = ['group', 'name', 'subAmount', 'total'];
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
this.form().focusBoundControl();
@@ -1,6 +1,6 @@
<h2>Cash Flow</h2>
<form class="flex-col" [formRoot]="form">
<form class="flex-col" [formRoot]="form" (submit)="$event.preventDefault(); show()">
<div class="row-container">
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Start Date</mat-label>
@@ -14,7 +14,7 @@
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<button mat-raised-button color="primary" (click)="show()" class="flex-auto basis-1-5">Show</button>
<button mat-raised-button type="submit" color="primary" class="flex-auto basis-1-5">Show</button>
</div>
</form>
@if (infoResource.isLoading()) {
@@ -1,9 +1,9 @@
import { CurrencyPipe } from '@angular/common';
import { Component, HostListener, inject, input, computed, linkedSignal, afterNextRender, signal } from '@angular/core';
import { Component, inject, input, computed, linkedSignal, afterNextRender, signal } from '@angular/core';
import { form as createForm, FormField, FormRoot } from '@angular/forms/signals';
export interface CashFlowFormData {
startDate: moment.Moment;
finishDate: moment.Moment;
startDate: Date;
finishDate: Date;
}
import { MatButtonModule } from '@angular/material/button';
import { MatDatepickerModule } from '@angular/material/datepicker';
@@ -24,6 +24,9 @@ import { CashFlowService } from './cash-flow.service';
selector: 'app-cash-flow',
templateUrl: './cash-flow.component.html',
styleUrls: ['./cash-flow.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
},
imports: [
FormField,
FormRoot,
@@ -78,8 +81,8 @@ export class CashFlowComponent {
model = linkedSignal({
source: this.info,
computation: (info: CashFlow): CashFlowFormData => ({
startDate: info.startDate ? moment(info.startDate, 'DD-MMM-YYYY') : moment(new Date()),
finishDate: info.finishDate ? moment(info.finishDate, 'DD-MMM-YYYY') : moment(new Date()),
startDate: info.startDate ? moment(info.startDate, 'DD-MMM-YYYY').toDate() : new Date(),
finishDate: info.finishDate ? moment(info.finishDate, 'DD-MMM-YYYY').toDate() : new Date(),
}),
});
@@ -88,7 +91,6 @@ export class CashFlowComponent {
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns = ['name', 'amount'];
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
// TODO: also select the contents
@@ -7,7 +7,7 @@
}
</h2>
<form class="flex-col" [formRoot]="form">
<form class="flex-col" [formRoot]="form" (submit)="$event.preventDefault(); show()">
<div class="row-container">
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Department</mat-label>
@@ -25,7 +25,7 @@
<mat-datepicker-toggle matSuffix [for]="dateInput"></mat-datepicker-toggle>
<mat-datepicker #dateInput></mat-datepicker>
</mat-form-field>
<button mat-raised-button color="primary" (click)="show()" class="flex-auto basis-1-5">Show</button>
<button mat-raised-button type="submit" color="primary" class="flex-auto basis-1-5">Show</button>
</div>
@if (infoResource.isLoading()) {
<app-skeleton-loader type="table" [count]="1" />
@@ -1,5 +1,5 @@
import { CurrencyPipe, DecimalPipe } from '@angular/common';
import { Component, HostListener, inject, computed, input, linkedSignal, signal, afterNextRender } from '@angular/core';
import { Component, inject, computed, input, linkedSignal, signal, afterNextRender } from '@angular/core';
import { form as createForm, FormField, FormRoot } from '@angular/forms/signals';
import { MatButtonModule } from '@angular/material/button';
import { MatOptionModule } from '@angular/material/core';
@@ -29,7 +29,7 @@ import { ClosingStockItem } from './closing-stock-item';
import { ClosingStockService } from './closing-stock.service';
export interface ClosingStockFormData {
date: moment.Moment;
date: Date;
costCentre: CostCentre | null;
stocks: { physical: number; costCentre: string | undefined }[];
}
@@ -38,6 +38,9 @@ export interface ClosingStockFormData {
selector: 'app-closing-stock',
templateUrl: './closing-stock.component.html',
styleUrls: ['./closing-stock.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
},
imports: [
MatIconModule,
FormField,
@@ -83,7 +86,7 @@ export class ClosingStockComponent {
model = linkedSignal({
source: computed(() => ({ info: this.info(), costCentres: this.costCentres() })),
computation: ({ info, costCentres }): ClosingStockFormData => ({
date: moment(info.date, 'DD-MMM-YYYY'),
date: moment(info.date, 'DD-MMM-YYYY').toDate(),
costCentre: costCentres.find((c) => c.id === info.costCentre?.id) || null,
stocks: info.items.map((x) => ({
physical: x.physical,
@@ -130,7 +133,6 @@ export class ClosingStockComponent {
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns = ['product', 'group', 'quantity', 'physical', 'variance', 'department', 'amount'];
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
this.form().focusBoundControl();
@@ -165,7 +167,7 @@ export class ClosingStockComponent {
getClosingStock(): ClosingStock {
const formModel = this.model();
const currentInfo = this.info();
currentInfo.date = formModel.date.format('DD-MMM-YYYY');
currentInfo.date = moment(formModel.date).format('DD-MMM-YYYY');
const array = formModel.stocks;
currentInfo.items.forEach((item, index) => {
item.physical = array[index].physical ?? 0;
@@ -178,7 +180,7 @@ export class ClosingStockComponent {
const formModel = this.model();
return new ClosingStock({
date: formModel.date.format('DD-MMM-YYYY'),
date: moment(formModel.date).format('DD-MMM-YYYY'),
costCentre: new CostCentre({ id: formModel.costCentre?.id ?? '' }),
});
}
@@ -58,7 +58,6 @@
<a mat-menu-item routerLink="/products">Products</a>
<a mat-menu-item routerLink="/product-groups">Product Groups</a>
<a mat-menu-item routerLink="/recipes">Recipes</a>
<a mat-menu-item routerLink="/recipe-templates">Recipe Templates</a>
<a mat-menu-item routerLink="/periods">Periods</a>
<a mat-menu-item routerLink="/tags">Tags</a>
</mat-menu>
@@ -1,6 +1,6 @@
<h2>Daybook</h2>
<form class="flex-col" [formRoot]="form">
<form class="flex-col" [formRoot]="form" (submit)="$event.preventDefault(); show()">
<div class="row-container">
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Start Date</mat-label>
@@ -14,7 +14,7 @@
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<button mat-raised-button class="flex-auto basis-1-5" color="primary" (click)="show()">Show</button>
<button mat-raised-button type="submit" class="flex-auto basis-1-5" color="primary">Show</button>
</div>
</form>
@if (infoResource.isLoading()) {
@@ -1,5 +1,5 @@
import { CurrencyPipe } from '@angular/common';
import { Component, HostListener, inject, linkedSignal, input, computed, afterNextRender, signal } from '@angular/core';
import { Component, inject, linkedSignal, input, computed, afterNextRender, signal } from '@angular/core';
import { form as createForm, FormField, FormRoot } from '@angular/forms/signals';
export interface DaybookFormData {
startDate: Date;
@@ -24,6 +24,9 @@ import { DaybookService } from './daybook.service';
selector: 'app-daybook',
templateUrl: './daybook.component.html',
styleUrls: ['./daybook.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
},
imports: [
FormField,
FormRoot,
@@ -107,7 +110,6 @@ export class DaybookComponent {
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns = ['date', 'type', 'narration', 'debitText', 'debitAmount', 'creditText', 'creditAmount'];
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
// TODO: Also select the text
@@ -1,6 +1,6 @@
<h2>Employee Attendance</h2>
<form class="flex-col" [formRoot]="form">
<form class="flex-col" [formRoot]="form" (submit)="$event.preventDefault(); show()">
<div class="row-container">
<mat-form-field class="flex-auto basis-1-4">
<mat-label>Start Date</mat-label>
@@ -48,7 +48,7 @@
</mat-autocomplete>
</mat-form-field>
<button mat-raised-button color="primary" (click)="show()" class="flex-auto basis-1-5">Show</button>
<button mat-raised-button type="submit" color="primary" class="flex-auto basis-1-5">Show</button>
</div>
@if (infoResource.isLoading()) {
<app-skeleton-loader type="table" [count]="1" />
@@ -1,13 +1,4 @@
import {
computed,
Component,
HostListener,
inject,
debounced,
input,
linkedSignal,
afterNextRender,
} from '@angular/core';
import { computed, Component, inject, debounced, input, linkedSignal, afterNextRender } from '@angular/core';
import { form as createForm, FormField, FormRoot } from '@angular/forms/signals';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
@@ -42,6 +33,9 @@ export interface EmployeeAttendanceFormData {
selector: 'app-employee-attendance',
templateUrl: './employee-attendance.component.html',
styleUrls: ['./employee-attendance.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
},
imports: [
FormField,
FormRoot,
@@ -101,7 +95,6 @@ export class EmployeeAttendanceComponent {
employeesResource = this.employeeSer.autocomplete(computed(() => this.debouncedEmployeeSearch.value() ?? ''));
employees = computed(() => this.employeesResource.value() ?? []);
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
this.form().focusBoundControl();
@@ -1,5 +1,5 @@
import { CurrencyPipe, DecimalPipe } from '@angular/common';
import { afterNextRender, Component, computed, HostListener, inject, input, linkedSignal, signal } from '@angular/core';
import { afterNextRender, Component, computed, inject, input, linkedSignal, signal } from '@angular/core';
import { form, FormField, FormRoot } from '@angular/forms/signals';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
@@ -48,6 +48,9 @@ export interface EmployeeBenefitsFormData {
selector: 'app-employee-benefits',
templateUrl: './employee-benefits.component.html',
styleUrls: ['./employee-benefits.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
},
imports: [
FormField,
FormRoot,
@@ -122,7 +125,6 @@ export class EmployeeBenefitsComponent {
employeesResource = this.employeeSer.autocomplete(computed(() => this.employeesSearch() ?? ''));
employees = computed(() => this.employeesResource.value() ?? []);
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
this.form.date().focusBoundControl();
@@ -1,6 +1,6 @@
<h2>Entries</h2>
<form class="flex-col" [formRoot]="form">
<form class="flex-col" [formRoot]="form" (submit)="$event.preventDefault(); refresh()">
<div class="row-container">
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Create / Last Edit Date From</mat-label>
@@ -20,9 +20,7 @@
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<button mat-raised-button (click)="refresh()" class="flex-auto basis-1-5">
<mat-icon>refresh</mat-icon>Refresh
</button>
<button mat-raised-button type="submit" class="flex-auto basis-1-5"><mat-icon>refresh</mat-icon>Refresh</button>
</div>
<div class="row-container">
<mat-radio-group class="flex-auto basis-2-5" [formField]="form.posted" (change)="togglePosted($event)">
+4 -11
View File
@@ -1,15 +1,6 @@
/* eslint-disable @angular-eslint/no-input-rename */
import { CurrencyPipe } from '@angular/common';
import {
Component,
HostListener,
inject,
input,
computed,
booleanAttribute,
afterNextRender,
linkedSignal,
} from '@angular/core';
import { Component, inject, input, computed, booleanAttribute, afterNextRender, linkedSignal } from '@angular/core';
export interface EntriesFormData {
startDate: Date;
finishDate: Date;
@@ -40,6 +31,9 @@ import { Report } from './report';
selector: 'app-entries',
templateUrl: './entries.component.html',
styleUrls: ['./entries.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
},
imports: [
FormField,
FormRoot,
@@ -120,7 +114,6 @@ export class EntriesComponent {
displayedColumns = ['date', 'voucherType', 'narration', 'debitNames', 'creditNames', 'amount', 'user'];
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
this.form().focusBoundControl();
@@ -1,5 +1,5 @@
import { CurrencyPipe, DecimalPipe } from '@angular/common';
import { signal, Component, HostListener, inject, input, computed, linkedSignal } from '@angular/core';
import { signal, Component, inject, input, computed, linkedSignal } from '@angular/core';
import { form as createForm, FormField, FormRoot } from '@angular/forms/signals';
import { MatButtonModule } from '@angular/material/button';
import { MatDatepickerModule } from '@angular/material/datepicker';
@@ -23,7 +23,7 @@ import { ConfirmDialogComponent } from '../shared/confirm-dialog/confirm-dialog.
import { LocalTimePipe } from '../shared/local-time.pipe';
export interface IncentiveFormData {
date: moment.Moment;
date: Date;
incentives: { points: number }[];
}
@@ -31,6 +31,9 @@ export interface IncentiveFormData {
selector: 'app-incentive',
templateUrl: './incentive.component.html',
styleUrls: ['./incentive.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
},
imports: [
FormField,
FormRoot,
@@ -61,7 +64,7 @@ export class IncentiveComponent {
model = linkedSignal({
source: this.voucher,
computation: (v): IncentiveFormData => ({
date: moment(v.date, 'DD-MMM-YYYY'),
date: moment(v.date, 'DD-MMM-YYYY').toDate(),
incentives: v.incentives.map((x) => ({ points: x.points })),
}),
});
@@ -75,7 +78,6 @@ export class IncentiveComponent {
displayedColumns = ['name', 'designation', 'department', 'daysWorked', 'points', 'amount'];
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
this.form().focusBoundControl();
@@ -159,7 +161,7 @@ export class IncentiveComponent {
getVoucher(): Voucher {
const formModel = this.model();
const v = this.voucher();
v.date = formModel.date.format('DD-MMM-YYYY');
v.date = moment(formModel.date).format('DD-MMM-YYYY');
const array = formModel.incentives;
v.incentives.forEach((item: Incentive, index: number) => {
+7 -15
View File
@@ -1,15 +1,5 @@
import { CurrencyPipe, DecimalPipe } from '@angular/common';
import {
afterNextRender,
Component,
computed,
effect,
HostListener,
inject,
input,
linkedSignal,
signal,
} from '@angular/core';
import { afterNextRender, Component, computed, effect, inject, input, linkedSignal, signal } from '@angular/core';
import { form, FormField, FormRoot } from '@angular/forms/signals';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
@@ -76,6 +66,12 @@ export interface IssueFormModel {
selector: 'app-issue',
templateUrl: './issue.component.html',
styleUrls: ['./issue.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
'(window:keydown.f3)': 'focusBatchHost($event)',
'(window:keydown.control.s)': 'saveListner($event)',
'(window:keydown.control.p)': 'postListner($event)',
},
imports: [
FormField,
FormRoot,
@@ -174,19 +170,16 @@ export class IssueComponent {
issueGridResource = this.issueGridSer.issueGrid(this.balanceDate);
gridData = computed(() => this.issueGridResource.value() ?? []);
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
this.form().focusBoundControl();
}
@HostListener('window:keydown.f3', ['$event'])
focusBatchHost(event: Event) {
event.preventDefault();
this.form.addRow.batch().focusBoundControl();
}
@HostListener('window:keydown.control.s', ['$event'])
saveListner(event: Event) {
event.preventDefault();
if (this.canSave()) {
@@ -194,7 +187,6 @@ export class IssueComponent {
}
}
@HostListener('window:keydown.control.p', ['$event'])
postListner(event: Event) {
event.preventDefault();
if (this.id() && !this.form.posted().controlValue() && this.auth.allowed('post-vouchers')) {
+12 -10
View File
@@ -1,6 +1,6 @@
import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { CurrencyPipe } from '@angular/common';
import { Component, HostListener, inject, input, computed, signal, linkedSignal, afterNextRender } from '@angular/core';
import { Component, inject, input, computed, signal, linkedSignal, afterNextRender } from '@angular/core';
import { FormField, FormRoot, form } from '@angular/forms/signals';
import { MatAutocompleteModule, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
@@ -72,6 +72,15 @@ export interface JournalFormModel {
selector: 'app-journal',
templateUrl: './journal.component.html',
styleUrls: ['./journal.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
'(window:keydown.f3)': 'focusAccountHost($event)',
'(window:keydown.f5)': 'redirectToPayment($event)',
'(window:keydown.f6)': 'redirectToReciept($event)',
'(window:keydown.f7)': 'redirectToJournal($event)',
'(window:keydown.control.s)': 'saveListner($event)',
'(window:keydown.control.p)': 'postListner($event)',
},
imports: [
MatIconModule,
MatFormFieldModule,
@@ -112,19 +121,16 @@ export class JournalComponent {
itemResource = this.ser.getVoucher(this.id, this.type, signal(null), this.d);
item = linkedSignal(() => this.itemResource.value() ?? new Voucher());
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
this.form().focusBoundControl();
}
@HostListener('window:keydown.f3', ['$event'])
focusAccountHost(event: Event) {
event.preventDefault();
this.form.addRow.account().focusBoundControl();
}
@HostListener('window:keydown.f5', ['$event'])
redirectToPayment(event: Event) {
event.preventDefault();
this.router.navigate(['payment'], {
@@ -135,7 +141,6 @@ export class JournalComponent {
});
}
@HostListener('window:keydown.f6', ['$event'])
redirectToReciept(event: Event) {
event.preventDefault();
this.router.navigate(['receipt'], {
@@ -146,12 +151,10 @@ export class JournalComponent {
});
}
@HostListener('window:keydown.f7', ['$event'])
redirectToJournal(event: Event) {
event.preventDefault();
}
@HostListener('window:keydown.control.s', ['$event'])
saveListner(event: Event) {
event.preventDefault();
if (this.canSave()) {
@@ -159,7 +162,6 @@ export class JournalComponent {
}
}
@HostListener('window:keydown.control.p', ['$event'])
postListner(event: Event) {
event.preventDefault();
if (this.id() && !this.form.posted() && this.auth.allowed('post-vouchers')) {
@@ -233,9 +235,9 @@ export class JournalComponent {
});
}
dateChanged(newDate: moment.Moment) {
dateChanged(newDate: Date) {
this.router.navigate([], {
queryParams: { d: newDate.format('DD-MMM-YYYY') },
queryParams: { d: moment(newDate).format('DD-MMM-YYYY') },
replaceUrl: true,
queryParamsHandling: 'merge',
});
@@ -7,7 +7,7 @@
}
</h2>
<form class="flex-col" [formRoot]="form">
<form class="flex-col" [formRoot]="form" (submit)="$event.preventDefault(); show()">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Start Date</mat-label>
@@ -33,18 +33,13 @@
[formField]="form.account"
autocomplete="off"
/>
<mat-autocomplete
#auto="matAutocomplete"
autoActiveFirstOption
[displayWith]="displayFn"
(optionSelected)="selected($event)"
>
<mat-autocomplete #auto="matAutocomplete" autoActiveFirstOption [displayWith]="displayFn">
@for (account of accounts(); track account) {
<mat-option [value]="account">{{ account.name }}</mat-option>
}
</mat-autocomplete>
</mat-form-field>
<button mat-raised-button type="button" class="flex-auto basis-1-5" color="primary" (click)="show()">Show</button>
<button mat-raised-button type="submit" class="flex-auto basis-1-5" color="primary">Show</button>
</div>
<div class="row-container">
<mat-form-field class="flex-auto basis-4-5">
@@ -55,7 +50,7 @@
}
</mat-select>
</mat-form-field>
<button mat-raised-button tabindex="-1" extended class="flex-auto basis-1-5" (click)="labels()">
<button mat-raised-button tabindex="-1" type="button" extended class="flex-auto basis-1-5" (click)="labels()">
<mat-icon>label</mat-icon>
Manage Labels
</button>
+14 -14
View File
@@ -1,8 +1,8 @@
import { SelectionModel } from '@angular/cdk/collections';
import { CurrencyPipe } from '@angular/common';
import { Component, inject, input, linkedSignal, computed, signal, afterNextRender, HostListener } from '@angular/core';
import { Component, inject, input, linkedSignal, computed, signal, afterNextRender } from '@angular/core';
import { form as createForm, FormField, FormRoot } 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 { MatChipsModule } from '@angular/material/chips';
@@ -27,8 +27,8 @@ import { ToCsvService } from '../shared/to-csv.service';
import { TagDialogComponent } from '../tag-dialog/tag-dialog.component';
import { TagService } from '../tag/tag.service';
export interface LedgerFormData {
startDate: moment.Moment;
finishDate: moment.Moment;
startDate: Date;
finishDate: Date;
account: string | Account | null;
tags: string[];
}
@@ -42,6 +42,9 @@ import { LedgerService } from './ledger.service';
selector: 'app-ledger',
templateUrl: './ledger.component.html',
styleUrls: ['./ledger.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
},
imports: [
MatCheckboxModule,
MatChipsModule,
@@ -144,9 +147,9 @@ export class LedgerComponent {
model = linkedSignal<import('./ledger').Ledger, LedgerFormData>({
source: this.info,
computation: (info: Ledger): LedgerFormData => ({
startDate: info.startDate ? moment(info.startDate, 'DD-MMM-YYYY') : moment(new Date()),
finishDate: info.finishDate ? moment(info.finishDate, 'DD-MMM-YYYY') : moment(new Date()),
account: info.account?.name ?? '',
startDate: info.startDate ? moment(info.startDate, 'DD-MMM-YYYY').toDate() : new Date(),
finishDate: info.finishDate ? moment(info.finishDate, 'DD-MMM-YYYY').toDate() : new Date(),
account: info.account ?? null,
tags: this.tags(),
}),
});
@@ -165,7 +168,6 @@ export class LedgerComponent {
private accountsResource = this.accountSer.autocomplete(this.accountSearch);
accounts = computed(() => this.accountsResource.value() ?? []);
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
this.form().focusBoundControl();
@@ -177,14 +179,10 @@ export class LedgerComponent {
});
}
displayFn(account?: Account | string): string {
displayFn(account: Account | string | null): string {
return !account ? '' : typeof account === 'string' ? account : account.name;
}
selected(event: MatAutocompleteSelectedEvent): void {
this.info().account = event.option.value as Account;
}
selectRow(id: string): void {
this.selectedRowId = id;
}
@@ -247,9 +245,11 @@ export class LedgerComponent {
getInfo(): Ledger {
const formModel = this.model();
const accVal = formModel.account;
const account = accVal && typeof accVal !== 'string' ? accVal : undefined;
return new Ledger({
account: this.info().account,
account,
startDate: moment(formModel.startDate).format('DD-MMM-YYYY'),
finishDate: moment(formModel.finishDate).format('DD-MMM-YYYY'),
});
@@ -7,7 +7,7 @@
}
</h2>
<form class="flex-col" [formRoot]="form">
<form class="flex-col" [formRoot]="form" (submit)="$event.preventDefault(); show()">
<div class="row-container">
<mat-form-field class="flex-auto basis-4-5">
<mat-label>Date</mat-label>
@@ -22,7 +22,7 @@
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
<mat-datepicker #date></mat-datepicker>
</mat-form-field>
<button mat-raised-button class="flex-auto basis-1-5" color="primary" (click)="show()">Show</button>
<button mat-raised-button type="submit" class="flex-auto basis-1-5" color="primary">Show</button>
</div>
@if (infoResource.isLoading()) {
<app-skeleton-loader type="table" [count]="1" />
@@ -25,7 +25,7 @@ import { MozimoDailyRegisterItem } from './mozimo-daily-register-item';
import { MozimoDailyRegisterService } from './mozimo-daily-register.service';
export interface MozimoDailyRegisterFormData {
date: moment.Moment;
date: Date;
items: {
received: number;
sale: number;
@@ -79,7 +79,7 @@ export class MozimoDailyRegisterComponent {
model = linkedSignal({
source: this.info,
computation: (v): MozimoDailyRegisterFormData => ({
date: moment(v.date, 'DD-MMM-YYYY'),
date: moment(v.date, 'DD-MMM-YYYY').toDate(),
items: v.body.map((x) => ({
received: x.received,
sale: x.sale,
@@ -129,7 +129,7 @@ export class MozimoDailyRegisterComponent {
getMozimoDailyRegister(): MozimoDailyRegister {
const formModel = this.model();
const info = this.info();
info.date = formModel.date.format('DD-MMM-YYYY');
info.date = moment(formModel.date).format('DD-MMM-YYYY');
const array = formModel.items;
if (array) {
@@ -7,7 +7,7 @@
}
</h2>
<form class="flex-col" [formRoot]="form">
<form class="flex-col" [formRoot]="form" (submit)="$event.preventDefault(); show()">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Start Date</mat-label>
@@ -44,7 +44,7 @@
}
</mat-autocomplete>
</mat-form-field>
<button mat-raised-button class="flex-auto basis-1-5" color="primary" (click)="show()">Show</button>
<button mat-raised-button type="submit" class="flex-auto basis-1-5" color="primary">Show</button>
</div>
@if (infoResource.isLoading()) {
<app-skeleton-loader type="table" [count]="1" />
@@ -27,8 +27,8 @@ import { MozimoProductRegisterItem } from './mozimo-product-register-item';
import { MozimoProductRegisterService } from './mozimo-product-register.service';
export interface MozimoProductRegisterFormData {
startDate: moment.Moment;
finishDate: moment.Moment;
startDate: Date;
finishDate: Date;
product: Product | string | null;
items: {
received: number;
@@ -84,11 +84,11 @@ export class MozimoProductRegisterComponent {
model = linkedSignal({
source: this.info,
computation: (v): MozimoProductRegisterFormData => ({
startDate: moment(v.startDate, 'DD-MMM-YYYY'),
finishDate: moment(v.finishDate, 'DD-MMM-YYYY'),
product: v.product ?? '',
items: v.body.map((x) => ({
computation: (info): MozimoProductRegisterFormData => ({
startDate: info.startDate ? moment(info.startDate, 'DD-MMM-YYYY').toDate() : new Date(),
finishDate: info.finishDate ? moment(info.finishDate, 'DD-MMM-YYYY').toDate() : new Date(),
product: info.product ?? '',
items: info.body.map((x) => ({
received: x.received,
sale: x.sale,
nc: x.nc,
@@ -160,8 +160,8 @@ export class MozimoProductRegisterComponent {
getMozimoProductRegister(): MozimoProductRegister {
const formModel = this.model();
const info = this.info();
info.startDate = formModel.startDate.format('DD-MMM-YYYY');
info.finishDate = formModel.finishDate.format('DD-MMM-YYYY');
info.startDate = moment(formModel.startDate).format('DD-MMM-YYYY');
info.finishDate = moment(formModel.finishDate).format('DD-MMM-YYYY');
const array = formModel.items;
if (array) {
@@ -183,8 +183,8 @@ export class MozimoProductRegisterComponent {
return new MozimoProductRegister({
product: formModel.product as Product,
startDate: formModel.startDate.format('DD-MMM-YYYY'),
finishDate: formModel.finishDate.format('DD-MMM-YYYY'),
startDate: moment(formModel.startDate).format('DD-MMM-YYYY'),
finishDate: moment(formModel.finishDate).format('DD-MMM-YYYY'),
});
}
@@ -1,6 +1,6 @@
<h2>Net Transactions</h2>
<form class="flex-col" [formRoot]="form">
<form class="flex-col" [formRoot]="form" (submit)="$event.preventDefault(); show()">
<div class="row-container">
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Start Date</mat-label>
@@ -14,7 +14,7 @@
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<button mat-raised-button class="flex-auto basis-1-5" color="primary" (click)="show()">Show</button>
<button mat-raised-button type="submit" class="flex-auto basis-1-5" color="primary">Show</button>
</div>
</form>
@if (infoResource.isLoading()) {
@@ -1,5 +1,5 @@
import { CurrencyPipe } from '@angular/common';
import { Component, HostListener, inject, input, linkedSignal, computed, afterNextRender, signal } from '@angular/core';
import { Component, inject, input, linkedSignal, computed, afterNextRender, signal } from '@angular/core';
export interface NetTransactionsFormData {
startDate: Date;
finishDate: Date;
@@ -25,6 +25,9 @@ import { NetTransactionsService } from './net-transactions.service';
selector: 'app-net-transactions',
templateUrl: './net-transactions.component.html',
styleUrls: ['./net-transactions.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
},
imports: [
FormField,
FormRoot,
@@ -103,7 +106,6 @@ export class NetTransactionsComponent {
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns = ['type', 'name', 'debit', 'credit'];
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
// TODO: Also select the text
+9 -17
View File
@@ -1,16 +1,6 @@
import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { CurrencyPipe } from '@angular/common';
import {
Component,
HostListener,
inject,
computed,
effect,
signal,
input,
linkedSignal,
afterNextRender,
} from '@angular/core';
import { Component, inject, computed, effect, signal, input, linkedSignal, afterNextRender } from '@angular/core';
import { form, FormField, FormRoot } from '@angular/forms/signals';
import { MatAutocompleteModule, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
@@ -83,6 +73,14 @@ export interface PaymentFormModel {
selector: 'app-payment',
templateUrl: './payment.component.html',
styleUrls: ['./payment.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
'(window:keydown.f5)': 'redirectToPayment($event)',
'(window:keydown.f6)': 'redirectToReciept($event)',
'(window:keydown.f7)': 'redirectToJournal($event)',
'(window:keydown.control.s)': 'saveListner($event)',
'(window:keydown.control.p)': 'postListner($event)',
},
imports: [
FormField,
FormRoot,
@@ -199,18 +197,15 @@ export class PaymentComponent {
paymentAccountsResource = this.accountSer.paymentAutocomplete(signal(''));
paymentAccounts = computed(() => this.paymentAccountsResource.value() ?? []);
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
this.form().focusBoundControl();
}
@HostListener('window:keydown.f5', ['$event'])
redirectToPayment(event: Event) {
event.preventDefault();
}
@HostListener('window:keydown.f6', ['$event'])
redirectToReciept(event: Event) {
event.preventDefault();
this.router.navigate(['receipt'], {
@@ -222,7 +217,6 @@ export class PaymentComponent {
});
}
@HostListener('window:keydown.f7', ['$event'])
redirectToJournal(event: Event) {
event.preventDefault();
this.router.navigate(['journal'], {
@@ -233,7 +227,6 @@ export class PaymentComponent {
});
}
@HostListener('window:keydown.control.s', ['$event'])
saveListner(event: Event) {
event.preventDefault();
if (this.canSave()) {
@@ -241,7 +234,6 @@ export class PaymentComponent {
}
}
@HostListener('window:keydown.control.p', ['$event'])
postListner(event: Event) {
event.preventDefault();
if (this.id() && !this.form.posted().controlValue() && this.auth.allowed('post-vouchers')) {
@@ -1,7 +1,7 @@
import { Component, HostListener, inject, linkedSignal, input, computed } from '@angular/core';
import { Component, inject, linkedSignal, input, computed } from '@angular/core';
export interface PeriodFormData {
validFrom: moment.Moment;
validTill: moment.Moment;
validFrom: Date;
validTill: Date;
}
import { form as createForm, FormField, FormRoot } from '@angular/forms/signals';
import { MatButtonModule } from '@angular/material/button';
@@ -23,6 +23,9 @@ import { PeriodService } from '../period.service';
selector: 'app-period-detail',
templateUrl: './period-detail.component.html',
styleUrls: ['./period-detail.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
},
imports: [
FormField,
FormRoot,
@@ -49,14 +52,13 @@ export class PeriodDetailComponent {
model = linkedSignal({
source: this.item,
computation: (item): PeriodFormData => ({
validFrom: item.validFrom ? moment(item.validFrom, 'DD-MMM-YYYY') : moment(new Date()),
validTill: item.validTill ? moment(item.validTill, 'DD-MMM-YYYY') : moment(new Date()),
validFrom: item.validFrom ? moment(item.validFrom, 'DD-MMM-YYYY').toDate() : new Date(),
validTill: item.validTill ? moment(item.validTill, 'DD-MMM-YYYY').toDate() : new Date(),
}),
});
form = createForm(this.model);
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
this.form().focusBoundControl();
@@ -7,7 +7,7 @@
}
</h2>
<form class="flex-col" [formRoot]="form">
<form class="flex-col" [formRoot]="form" (submit)="$event.preventDefault(); show()">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Start Date</mat-label>
@@ -44,7 +44,7 @@
}
</mat-autocomplete>
</mat-form-field>
<button mat-raised-button class="flex-auto basis-1-5" color="primary" (click)="show()">Show</button>
<button mat-raised-button type="submit" class="flex-auto basis-1-5" color="primary">Show</button>
</div>
</form>
@if (infoResource.isLoading()) {
@@ -1,16 +1,5 @@
import { CurrencyPipe, DecimalPipe } from '@angular/common';
import {
Component,
HostListener,
inject,
computed,
signal,
linkedSignal,
ResourceRef,
Signal,
input,
afterNextRender,
} from '@angular/core';
import { Component, inject, computed, signal, linkedSignal, input, afterNextRender } from '@angular/core';
import { form as createForm, FormField, FormRoot } from '@angular/forms/signals';
import { MatAutocompleteModule, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
@@ -30,9 +19,9 @@ import { ProductSku } from '../core/product-sku';
import { ProductService } from '../product/product.service';
import { ToCsvService } from '../shared/to-csv.service';
export interface ProductLedgerFormData {
startDate: moment.Moment;
finishDate: moment.Moment;
product: string;
startDate: Date;
finishDate: Date;
product: Product | string | null;
}
import { ErrorStateComponent } from '../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../shared/skeleton-loader/skeleton-loader.component';
@@ -43,6 +32,9 @@ import { ProductLedgerService } from './product-ledger.service';
selector: 'app-product-ledger',
templateUrl: './product-ledger.component.html',
styleUrls: ['./product-ledger.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
},
imports: [
MatIconModule,
@@ -60,7 +52,6 @@ import { ProductLedgerService } from './product-ledger.service';
MatPaginatorModule,
DecimalPipe,
CurrencyPipe,
SkeletonLoaderComponent,
ErrorStateComponent,
],
@@ -161,9 +152,9 @@ export class ProductLedgerComponent {
model = linkedSignal({
source: this.info,
computation: (info: ProductLedger): ProductLedgerFormData => ({
startDate: info.startDate ? moment(info.startDate, 'DD-MMM-YYYY') : moment(new Date()),
finishDate: info.finishDate ? moment(info.finishDate, 'DD-MMM-YYYY') : moment(new Date()),
product: info.product?.name ?? '',
startDate: info.startDate ? moment(info.startDate, 'DD-MMM-YYYY').toDate() : new Date(),
finishDate: info.finishDate ? moment(info.finishDate, 'DD-MMM-YYYY').toDate() : new Date(),
product: info.product ?? null,
}),
});
@@ -185,11 +176,14 @@ export class ProductLedgerComponent {
'runningAmount',
];
productSearch!: Signal<string | null>;
productsResource!: ResourceRef<ProductSku[] | undefined>;
products!: Signal<ProductSku[]>;
productSearch = computed(() => {
const v = this.model().product;
return typeof v === 'string' ? v : null;
});
productsResource = this.productSer.autocompleteProduct(this.productSearch, signal(null));
products = computed(() => this.productsResource.value() ?? []);
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
this.form().focusBoundControl();
@@ -199,21 +193,15 @@ export class ProductLedgerComponent {
afterNextRender(() => {
this.form().focusBoundControl();
});
this.productSearch = computed(() => {
const v = this.model().product;
return typeof v === 'string' ? v : null;
});
this.productsResource = this.productSer.autocompleteProduct(this.productSearch, signal(null));
this.products = computed(() => this.productsResource.value() ?? []);
}
displayFn(product?: Product | string): string {
displayFn(product?: Product | ProductSku | string | null): string {
return !product ? '' : typeof product === 'string' ? product : product.name;
}
selected(event: MatAutocompleteSelectedEvent): void {
const p = event.option.value;
this.model.update((m) => ({ ...m, product: p.name }));
this.model.update((m) => ({ ...m, product: p }));
}
selectRow(id: string): void {
@@ -234,9 +222,10 @@ export class ProductLedgerComponent {
getInfo(): ProductLedger {
const formModel = this.model();
const prodVal = formModel.product;
const product = prodVal && typeof prodVal !== 'string' ? prodVal : undefined;
return new ProductLedger({
product: this.info().product,
product,
startDate: moment(formModel.startDate).format('DD-MMM-YYYY'),
finishDate: moment(formModel.finishDate).format('DD-MMM-YYYY'),
});
@@ -1,6 +1,6 @@
<h2>Profit & Loss</h2>
<form class="flex-col" [formRoot]="form">
<form class="flex-col" [formRoot]="form" (submit)="$event.preventDefault(); show()">
<div class="row-container">
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Start Date</mat-label>
@@ -14,7 +14,7 @@
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<button mat-raised-button class="flex-auto basis-1-5" color="primary" (click)="show()">Show</button>
<button mat-raised-button type="submit" class="flex-auto basis-1-5" color="primary">Show</button>
</div>
</form>
@if (infoResource.isLoading()) {
@@ -1,5 +1,5 @@
import { CurrencyPipe } from '@angular/common';
import { Component, HostListener, inject, linkedSignal, computed, signal, input, afterNextRender } from '@angular/core';
import { Component, inject, linkedSignal, computed, signal, input, afterNextRender } from '@angular/core';
import { form, FormField, FormRoot } from '@angular/forms/signals';
import { MatButtonModule } from '@angular/material/button';
import { MatDatepickerModule } from '@angular/material/datepicker';
@@ -17,14 +17,17 @@ import { ProfitLoss } from './profit-loss';
import { ProfitLossService } from './profit-loss.service';
export interface ProfitLossFormData {
startDate: moment.Moment;
finishDate: moment.Moment;
startDate: Date;
finishDate: Date;
}
@Component({
selector: 'app-profit-loss',
templateUrl: './profit-loss.component.html',
styleUrls: ['./profit-loss.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
},
imports: [
FormField,
@@ -57,8 +60,8 @@ export class ProfitLossComponent {
formModel = linkedSignal({
source: this.info,
computation: (info: ProfitLoss): ProfitLossFormData => ({
startDate: info.startDate ? moment(info.startDate, 'DD-MMM-YYYY') : moment(new Date()),
finishDate: info.finishDate ? moment(info.finishDate, 'DD-MMM-YYYY') : moment(new Date()),
startDate: info.startDate ? moment(info.startDate, 'DD-MMM-YYYY').toDate() : new Date(),
finishDate: info.finishDate ? moment(info.finishDate, 'DD-MMM-YYYY').toDate() : new Date(),
}),
});
@@ -103,7 +106,6 @@ export class ProfitLossComponent {
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns = ['group', 'name', 'amount', 'total'];
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
this.form().focusBoundControl();
@@ -1,6 +1,6 @@
<h2>Purchase Entries</h2>
<form class="flex-col" [formRoot]="form">
<form class="flex-col" [formRoot]="form" (submit)="$event.preventDefault(); show()">
<div class="row-container">
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Start Date</mat-label>
@@ -14,7 +14,7 @@
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<button mat-raised-button class="flex-auto basis-1-5" color="primary" (click)="show()">Show</button>
<button mat-raised-button type="submit" class="flex-auto basis-1-5" color="primary">Show</button>
</div>
</form>
@if (resource.isLoading()) {
@@ -1,5 +1,5 @@
import { CurrencyPipe, DecimalPipe, PercentPipe } from '@angular/common';
import { Component, HostListener, inject, linkedSignal, computed, signal, input } from '@angular/core';
import { Component, inject, linkedSignal, computed, signal, input } from '@angular/core';
import { form, FormField, FormRoot } from '@angular/forms/signals';
import { MatButtonModule } from '@angular/material/button';
import { MatDatepickerModule } from '@angular/material/datepicker';
@@ -17,14 +17,17 @@ import { PurchaseEntries } from './purchase-entries';
import { PurchaseEntriesService } from './purchase-entries.service';
export interface PurchaseEntriesFormData {
startDate: moment.Moment | null | string;
finishDate: moment.Moment | null | string;
startDate: Date;
finishDate: Date;
}
@Component({
selector: 'app-purchase-entries',
templateUrl: './purchase-entries.component.html',
styleUrls: ['./purchase-entries.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
},
imports: [
FormField,
@@ -101,10 +104,10 @@ export class PurchaseEntriesComponent {
});
formModel = linkedSignal({
source: () => null,
computation: (): PurchaseEntriesFormData => ({
startDate: moment(new Date()),
finishDate: moment(new Date()),
source: () => this.info(),
computation: (info: PurchaseEntries): PurchaseEntriesFormData => ({
startDate: info.startDate ? moment(info.startDate, 'DD-MMM-YYYY').toDate() : new Date(),
finishDate: info.finishDate ? moment(info.finishDate, 'DD-MMM-YYYY').toDate() : new Date(),
}),
});
@@ -114,7 +117,6 @@ export class PurchaseEntriesComponent {
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns = ['date', 'supplier', 'product', 'quantity', 'rate', 'tax', 'discount', 'amount'];
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
this.form().focusBoundControl();
@@ -1,16 +1,6 @@
import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { CurrencyPipe, DecimalPipe, PercentPipe } from '@angular/common';
import {
afterNextRender,
Component,
computed,
effect,
HostListener,
inject,
input,
linkedSignal,
signal,
} from '@angular/core';
import { afterNextRender, Component, computed, effect, inject, input, linkedSignal, signal } from '@angular/core';
import { form, FormField, FormRoot } from '@angular/forms/signals';
import { MatAutocompleteModule, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
@@ -86,6 +76,13 @@ export interface PurchaseReturnFormModel {
selector: 'app-purchase-return',
templateUrl: './purchase-return.component.html',
styleUrls: ['./purchase-return.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
'(window:keydown.f3)': 'focusAccountHost($event)',
'(window:keydown.f4)': 'focusBatchHost($event)',
'(window:keydown.control.s)': 'saveListner($event)',
'(window:keydown.control.p)': 'postListner($event)',
},
imports: [
FormField,
FormRoot,
@@ -208,25 +205,21 @@ export class PurchaseReturnComponent {
batchesResource = this.batchSer.autocomplete(this.balanceDate, this.batchSearch);
batches = computed(() => this.batchesResource.value() ?? []);
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
this.form().focusBoundControl();
}
@HostListener('window:keydown.f3', ['$event'])
focusAccountHost(event: Event) {
event.preventDefault();
this.form.account().focusBoundControl();
}
@HostListener('window:keydown.f4', ['$event'])
focusBatchHost(event: Event) {
event.preventDefault();
this.form.addRow.batch().focusBoundControl();
}
@HostListener('window:keydown.control.s', ['$event'])
saveListner(event: Event) {
event.preventDefault();
if (this.canSave()) {
@@ -234,7 +227,6 @@ export class PurchaseReturnComponent {
}
}
@HostListener('window:keydown.control.p', ['$event'])
postListner(event: Event) {
event.preventDefault();
if (this.id() && !this.form.posted().controlValue() && this.auth.allowed('post-vouchers')) {
@@ -1,16 +1,6 @@
import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { CurrencyPipe, DecimalPipe, PercentPipe } from '@angular/common';
import {
afterNextRender,
Component,
computed,
effect,
HostListener,
inject,
input,
linkedSignal,
signal,
} from '@angular/core';
import { afterNextRender, Component, computed, effect, inject, input, linkedSignal, signal } from '@angular/core';
import { form, FormField, FormRoot } from '@angular/forms/signals';
import { MatAutocompleteModule, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
@@ -91,6 +81,13 @@ export interface PurchaseFormModel {
selector: 'app-purchase',
templateUrl: './purchase.component.html',
styleUrls: ['./purchase.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
'(window:keydown.f3)': 'focusAccountHost($event)',
'(window:keydown.f4)': 'focusProductHost($event)',
'(window:keydown.control.s)': 'saveListner($event)',
'(window:keydown.control.p)': 'postListner($event)',
},
imports: [
FormField,
FormRoot,
@@ -222,25 +219,21 @@ export class PurchaseComponent {
products = computed(() => this.productsResource.value() ?? []);
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
this.form().focusBoundControl();
}
@HostListener('window:keydown.f3', ['$event'])
focusAccountHost(event: Event) {
event.preventDefault();
this.form.account().focusBoundControl();
}
@HostListener('window:keydown.f4', ['$event'])
focusProductHost(event: Event) {
event.preventDefault();
this.form.addRow.product().focusBoundControl();
}
@HostListener('window:keydown.control.s', ['$event'])
saveListner(event: Event) {
event.preventDefault();
if (this.canSave()) {
@@ -248,7 +241,6 @@ export class PurchaseComponent {
}
}
@HostListener('window:keydown.control.p', ['$event'])
postListner(event: Event) {
event.preventDefault();
if (this.id() && !this.form.posted().controlValue() && this.auth.allowed('post-vouchers')) {
@@ -1,6 +1,6 @@
<h2>Purchases</h2>
<form class="flex-col" [formRoot]="form">
<form class="flex-col" [formRoot]="form" (submit)="$event.preventDefault(); show()">
<div class="row-container">
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Start Date</mat-label>
@@ -14,7 +14,7 @@
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<button mat-raised-button class="flex-auto basis-1-5" color="primary" (click)="show()">Show</button>
<button mat-raised-button type="submit" class="flex-auto basis-1-5" color="primary">Show</button>
</div>
</form>
@if (resource.isLoading()) {
@@ -1,5 +1,5 @@
import { CurrencyPipe, DecimalPipe } from '@angular/common';
import { Component, HostListener, inject, linkedSignal, computed, signal, input } from '@angular/core';
import { Component, inject, linkedSignal, computed, signal, input } from '@angular/core';
import { form, FormField, FormRoot } from '@angular/forms/signals';
import { MatButtonModule } from '@angular/material/button';
import { MatDatepickerModule } from '@angular/material/datepicker';
@@ -18,14 +18,17 @@ import { PurchasesItem } from './purchases-item';
import { PurchasesService } from './purchases.service';
export interface PurchasesFormData {
startDate: moment.Moment | null | string;
finishDate: moment.Moment | null | string;
startDate: Date;
finishDate: Date;
}
@Component({
selector: 'app-purchases',
templateUrl: './purchases.component.html',
styleUrls: ['./purchases.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
},
imports: [
FormField,
@@ -93,10 +96,10 @@ export class PurchasesComponent {
});
formModel = linkedSignal({
source: () => null,
computation: (): PurchasesFormData => ({
startDate: moment(new Date()),
finishDate: moment(new Date()),
source: () => this.info(),
computation: (info: Purchases): PurchasesFormData => ({
startDate: info.startDate ? moment(info.startDate, 'DD-MMM-YYYY').toDate() : new Date(),
finishDate: info.finishDate ? moment(info.finishDate, 'DD-MMM-YYYY').toDate() : new Date(),
}),
});
@@ -106,7 +109,6 @@ export class PurchasesComponent {
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns = ['product', 'quantity', 'rate', 'amount'];
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
this.form().focusBoundControl();
@@ -7,7 +7,7 @@
}
</h2>
<form class="flex-col" [formRoot]="form">
<form class="flex-col" [formRoot]="form" (submit)="$event.preventDefault(); show()">
<div class="row-container">
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Start Date</mat-label>
@@ -21,7 +21,7 @@
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<button mat-raised-button class="flex-auto basis-1-5" color="primary" (click)="show()">Show</button>
<button mat-raised-button type="submit" class="flex-auto basis-1-5" color="primary">Show</button>
</div>
</form>
@if (infoResource.isLoading()) {
@@ -1,5 +1,5 @@
import { CurrencyPipe, DecimalPipe, PercentPipe } from '@angular/common';
import { Component, HostListener, inject, linkedSignal, computed, signal, input } from '@angular/core';
import { Component, inject, linkedSignal, computed, signal, input } from '@angular/core';
import { form, FormField, FormRoot } from '@angular/forms/signals';
import { MatButtonModule } from '@angular/material/button';
import { MatDatepickerModule } from '@angular/material/datepicker';
@@ -19,14 +19,17 @@ import { RawMaterialCost } from './raw-material-cost';
import { RawMaterialCostService } from './raw-material-cost.service';
export interface RawMaterialCostFormData {
startDate: Date | null;
finishDate: Date | null;
startDate: Date;
finishDate: Date;
}
@Component({
selector: 'app-raw-material-cost',
templateUrl: './raw-material-cost.component.html',
styleUrls: ['./raw-material-cost.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
},
imports: [
MatIconModule,
@@ -104,10 +107,10 @@ export class RawMaterialCostComponent {
displayedColumns = computed(() => (this.info().id ? this.columnsId : this.columnsNoId));
formModel = linkedSignal({
source: () => null,
computation: (): RawMaterialCostFormData => ({
startDate: new Date(),
finishDate: new Date(),
source: () => this.info(),
computation: (info): RawMaterialCostFormData => ({
startDate: info.startDate ? moment(info.startDate, 'DD-MMM-YYYY').toDate() : new Date(),
finishDate: info.finishDate ? moment(info.finishDate, 'DD-MMM-YYYY').toDate() : new Date(),
}),
});
@@ -122,7 +125,6 @@ export class RawMaterialCostComponent {
columnsNoId = ['name', 'issue', 'sale', 'rmc'];
columnsId = ['name', 'group', 'quantity', 'net', 'gross'];
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
this.form().focusBoundControl();
+10 -18
View File
@@ -1,16 +1,6 @@
import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { CurrencyPipe } from '@angular/common';
import {
afterNextRender,
Component,
computed,
effect,
HostListener,
inject,
input,
linkedSignal,
signal,
} from '@angular/core';
import { afterNextRender, Component, computed, effect, inject, input, linkedSignal, signal } from '@angular/core';
import { form, FormField, FormRoot } from '@angular/forms/signals';
import { MatAutocompleteModule, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
@@ -83,6 +73,15 @@ export interface ReceiptFormModel {
selector: 'app-receipt',
templateUrl: './receipt.component.html',
styleUrls: ['./receipt.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
'(window:keydown.f3)': 'focusAccountHost($event)',
'(window:keydown.f5)': 'redirectToPayment($event)',
'(window:keydown.f6)': 'redirectToReciept($event)',
'(window:keydown.f7)': 'redirectToJournal($event)',
'(window:keydown.control.s)': 'saveListner($event)',
'(window:keydown.control.p)': 'postListner($event)',
},
imports: [
FormField,
FormRoot,
@@ -199,19 +198,16 @@ export class ReceiptComponent {
receiptAccountsResource = this.accountSer.receiptAutocomplete(signal(''));
receiptAccounts = computed(() => this.receiptAccountsResource.value() ?? []);
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
this.form().focusBoundControl();
}
@HostListener('window:keydown.f3', ['$event'])
focusAccountHost(event: Event) {
event.preventDefault();
this.form.addRow.account().focusBoundControl();
}
@HostListener('window:keydown.f5', ['$event'])
redirectToPayment(event: Event) {
event.preventDefault();
this.router.navigate(['payment'], {
@@ -223,12 +219,10 @@ export class ReceiptComponent {
});
}
@HostListener('window:keydown.f6', ['$event'])
redirectToReciept(event: Event) {
event.preventDefault();
}
@HostListener('window:keydown.f7', ['$event'])
redirectToJournal(event: Event) {
event.preventDefault();
this.router.navigate(['journal'], {
@@ -239,7 +233,6 @@ export class ReceiptComponent {
});
}
@HostListener('window:keydown.control.s', ['$event'])
saveListner(event: Event) {
event.preventDefault();
if (this.canSave()) {
@@ -247,7 +240,6 @@ export class ReceiptComponent {
}
}
@HostListener('window:keydown.control.p', ['$event'])
postListner(event: Event) {
event.preventDefault();
if (this.id() && !this.form.posted().controlValue() && this.auth.allowed('post-vouchers')) {
@@ -1,35 +0,0 @@
<h2>RecipeTemplate</h2>
@if (itemResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
<app-skeleton-loader type="line" [count]="10" />
} @else if (itemResource.error()) {
<app-error-state [message]="'Failed to load data.'" (retryAction)="itemResource.reload()" />
} @else {
<form class="flex flex-col wrapped" [formRoot]="form">
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Name</mat-label>
<input matInput [formField]="form.name" />
</mat-form-field>
<mat-form-field class="flex-auto">
<mat-label>Date</mat-label>
<input matInput [matDatepicker]="date" [formField]="form.date" autocomplete="off" #dateElement />
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
<mat-datepicker #date></mat-datepicker>
</mat-form-field>
<mat-checkbox [formField]="form.selected" class="flex-auto">Is Selected?</mat-checkbox>
</div>
<div class="row-container">
<mat-form-field class="flex-auto">
<mat-label>Text</mat-label>
<textarea matInput matAutosizeMinRows="20" [formField]="form.text"></textarea>
</mat-form-field>
</div>
</form>
<div class="row-container">
<button mat-raised-button color="primary" (click)="save()">Save</button>
<button mat-raised-button color="warn" (click)="confirmDelete()">Delete</button>
</div>
}
@@ -1,22 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RecipeTemplateDetailComponent } from './recipe-template-detail.component';
describe('RecipeTemplateDetailComponent', () => {
let component: RecipeTemplateDetailComponent;
let fixture: ComponentFixture<RecipeTemplateDetailComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [RecipeTemplateDetailComponent],
}).compileComponents();
fixture = TestBed.createComponent(RecipeTemplateDetailComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -1,119 +0,0 @@
import { Component, inject, afterNextRender, linkedSignal, input, computed } from '@angular/core';
import { FormField, FormRoot, form as createForm } from '@angular/forms/signals';
import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatDialog } from '@angular/material/dialog';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Router } from '@angular/router';
import moment from 'moment';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { RecipeTemplate } from '../recipe-template';
import { RecipeTemplateService } from '../recipe-template.service';
export interface RecipeTemplateDetailFormData {
name: string;
date: moment.Moment | null | string;
text: string;
selected: boolean;
}
@Component({
selector: 'app-recipe-template-detail',
templateUrl: './recipe-template-detail.component.html',
styleUrls: ['./recipe-template-detail.component.css'],
imports: [
FormField,
FormRoot,
MatFormFieldModule,
MatInputModule,
MatDatepickerModule,
MatCheckboxModule,
MatButtonModule,
SkeletonLoaderComponent,
ErrorStateComponent,
],
})
export class RecipeTemplateDetailComponent {
id = input(null, { transform: (v: string | null | undefined) => v ?? null });
private router = inject(Router);
private dialog = inject(MatDialog);
private snackBar = inject(MatSnackBar);
private ser = inject(RecipeTemplateService);
itemResource = this.ser.get(this.id);
item = computed(() => this.itemResource.value() ?? new RecipeTemplate());
formModel = linkedSignal({
source: this.item,
computation: (itemVal): RecipeTemplateDetailFormData => ({
name: itemVal.name || '',
date: itemVal.date ? moment(itemVal.date, 'DD-MMM-YYYY') : moment(new Date()),
text: itemVal.text || '',
selected: itemVal.selected || false,
}),
});
form = createForm(this.formModel, () => {});
constructor() {
afterNextRender(() => {
this.form().focusBoundControl();
});
}
save() {
this.ser.saveOrUpdate(this.getItem()).subscribe({
next: () => {
this.snackBar.open('', 'Success');
this.router.navigateByUrl('/recipe-templates');
},
error: (error) => {
this.snackBar.open(error as string, 'Danger');
},
});
}
delete() {
this.ser.delete(this.item().id).subscribe({
next: () => {
this.snackBar.open('', 'Success');
this.router.navigateByUrl('/recipe-templates');
},
error: (error) => {
this.snackBar.open(error as string, 'Danger');
},
});
}
confirmDelete(): void {
const dialogRef = this.dialog.open(ConfirmDialogComponent, {
width: '250px',
data: { title: 'Delete Recipe Template?', content: 'Are you sure? This cannot be undone.' },
});
dialogRef.afterClosed().subscribe((result: boolean) => {
if (result) {
this.delete();
}
});
}
getItem(): RecipeTemplate {
const formModel = this.formModel();
const item = this.item();
item.name = formModel.name ?? '';
item.date = moment(formModel.date).format('DD-MMM-YYYY');
item.text = formModel.text ?? '';
item.selected = formModel.selected ?? false;
return item;
}
}
@@ -1,47 +0,0 @@
<h2 class="row-container space-between">
<span>Recipe Templates</span>
<a mat-button [routerLink]="['/recipe-templates', 'new']">
<mat-icon>add_box</mat-icon>
Add
</a>
</h2>
@if (listResource.isLoading()) {
<app-skeleton-loader type="table" [count]="1" />
} @else if (listResource.error()) {
<app-error-state [message]="'Failed to load list.'" (retryAction)="listResource.reload()" />
} @else {
<mat-table #table [dataSource]="dataSource()" matSort (matSortChange)="sortData($event)">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header>Name</mat-header-cell>
<mat-cell *matCellDef="let row"
><a [routerLink]="['/recipe-templates', row.id]">{{ row.name }}</a></mat-cell
>
</ng-container>
<!-- Selected Column -->
<ng-container matColumnDef="selected">
<mat-header-cell *matHeaderCellDef mat-sort-header>Is Selected?</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.selected }}</mat-cell>
</ng-container>
<!-- Date Column -->
<ng-container matColumnDef="date">
<mat-header-cell *matHeaderCellDef mat-sort-header>Date</mat-header-cell>
<mat-cell *matCellDef="let row">{{ row.date }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-paginator
(page)="handlePageEvent($event)"
[length]="list().length"
[pageIndex]="pageIndex()"
[pageSize]="pageSize()"
[pageSizeOptions]="[25, 50, 100, 250]"
>
</mat-paginator>
}
@@ -1,22 +0,0 @@
import { ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing';
import { RecipeTemplateListComponent } from './recipe-template-list.component';
describe('RecipeTemplateListComponent', () => {
let component: RecipeTemplateListComponent;
let fixture: ComponentFixture<RecipeTemplateListComponent>;
beforeEach(fakeAsync(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule, RecipeTemplateListComponent],
}).compileComponents();
fixture = TestBed.createComponent(RecipeTemplateListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should compile', () => {
expect(component).toBeTruthy();
});
});
@@ -1,81 +0,0 @@
import { Component, computed, inject, signal } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatPaginatorModule, PageEvent } from '@angular/material/paginator';
import { MatSortModule, Sort } from '@angular/material/sort';
import { MatTableModule } from '@angular/material/table';
import { RouterModule } from '@angular/router';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { RecipeTemplateService } from '../recipe-template.service';
@Component({
selector: 'app-recipe-template-list',
templateUrl: './recipe-template-list.component.html',
styleUrls: ['./recipe-template-list.component.css'],
imports: [
RouterModule,
MatIconModule,
MatTableModule,
MatSortModule,
MatPaginatorModule,
MatButtonModule,
SkeletonLoaderComponent,
ErrorStateComponent,
],
})
export class RecipeTemplateListComponent {
private ser = inject(RecipeTemplateService);
pageSize = signal(50);
pageIndex = signal(0);
sortActive = signal('');
sortDirection = signal('');
listResource = this.ser.list();
list = computed(() => this.listResource.value() ?? []);
sortedList = computed(() => {
const data = this.list();
const active = this.sortActive();
const direction = this.sortDirection();
if (!active || direction === '') {
return data;
}
return [...data].sort((a, b) => {
const isAsc = direction === 'asc';
switch (active) {
case 'name':
return compare(a.name, b.name, isAsc);
case 'selected':
return compare(a.selected, b.selected, isAsc);
case 'date':
return compare(a.date, b.date, isAsc);
default:
return 0;
}
});
});
dataSource = computed(() => {
const data = this.sortedList();
const pageIndex = this.pageIndex();
const pageSize = this.pageSize();
return data.slice(pageIndex * pageSize, (pageIndex + 1) * pageSize);
});
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns = ['name', 'selected', 'date'];
handlePageEvent(e: PageEvent) {
this.pageSize.set(e.pageSize);
this.pageIndex.set(e.pageIndex);
}
sortData(sort: Sort) {
this.sortActive.set(sort.active);
this.sortDirection.set(sort.direction);
}
}
const compare = (a: string | number | boolean, b: string | number | boolean, isAsc: boolean) =>
(a < b ? -1 : 1) * (isAsc ? 1 : -1);
@@ -1,32 +0,0 @@
import { Routes } from '@angular/router';
import { authGuard } from '../auth/auth-guard.service';
import { RecipeTemplateDetailComponent } from './recipe-template-detail/recipe-template-detail.component';
import { RecipeTemplateListComponent } from './recipe-template-list/recipe-template-list.component';
export const routes: Routes = [
{
path: '',
component: RecipeTemplateListComponent,
canActivate: [authGuard],
data: {
permission: 'Recipes',
},
},
{
path: 'new',
component: RecipeTemplateDetailComponent,
canActivate: [authGuard],
data: {
permission: 'Recipes',
},
},
{
path: ':id',
component: RecipeTemplateDetailComponent,
canActivate: [authGuard],
data: {
permission: 'Recipes',
},
},
];
@@ -1,17 +0,0 @@
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
import { inject, TestBed } from '@angular/core/testing';
import { RecipeTemplateService } from './recipe-template.service';
describe('RecipeTemplateService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [],
providers: [RecipeTemplateService, provideHttpClient(withInterceptorsFromDi())],
});
});
it('should be created', inject([RecipeTemplateService], (service: RecipeTemplateService) => {
expect(service).toBeTruthy();
}));
});
@@ -1,52 +0,0 @@
import { HttpClient, httpResource } from '@angular/common/http';
import { inject, Injectable, Signal } from '@angular/core';
import { Observable } from 'rxjs/internal/Observable';
import { catchError } from 'rxjs/operators';
import { ErrorLoggerService } from '../core/error-logger.service';
import { RecipeTemplate } from './recipe-template';
const url = '/api/recipe-templates';
@Injectable({
providedIn: 'root',
})
export class RecipeTemplateService {
private http = inject(HttpClient);
private log = inject(ErrorLoggerService);
get(id: Signal<string | null>) {
return httpResource<RecipeTemplate>(() => {
const getUrl: string = id() === null ? `${url}` : `${url}/${id()}`;
return getUrl;
});
}
list() {
return httpResource<RecipeTemplate[]>(() => `${url}/list`);
}
save(recipeTemplate: RecipeTemplate): Observable<RecipeTemplate> {
return this.http
.post<RecipeTemplate>(`${url}`, recipeTemplate)
.pipe(catchError(this.log.handleError('RecipeTemplateService', 'save'))) as Observable<RecipeTemplate>;
}
update(recipeTemplate: RecipeTemplate): Observable<RecipeTemplate> {
return this.http
.put<RecipeTemplate>(`${url}/${recipeTemplate.id}`, recipeTemplate)
.pipe(catchError(this.log.handleError('RecipeTemplateService', 'update'))) as Observable<RecipeTemplate>;
}
saveOrUpdate(recipeTemplate: RecipeTemplate): Observable<RecipeTemplate> {
if (!recipeTemplate.id) {
return this.save(recipeTemplate);
}
return this.update(recipeTemplate);
}
delete(id: string): Observable<RecipeTemplate> {
return this.http
.delete<RecipeTemplate>(`${url}/${id}`)
.pipe(catchError(this.log.handleError('RecipeTemplateService', 'delete'))) as Observable<RecipeTemplate>;
}
}
@@ -1,16 +0,0 @@
export class RecipeTemplate {
id: string;
name: string;
date: string;
text: string;
selected: boolean;
public constructor(init?: Partial<RecipeTemplate>) {
this.id = '';
this.name = '';
this.date = '';
this.text = '';
this.selected = false;
Object.assign(this, init);
}
}
@@ -312,7 +312,7 @@
<div class="recipe-print__header">
<h1 class="recipe-print__title">{{ dishName }}</h1>
<div class="recipe-print__meta">
<span><strong>Date:</strong> {{ formModel().basics.date.format('DD-MMM-YYYY') }}</span>
<span><strong>Date:</strong> {{ formModel().basics.date }}</span>
<span><strong>Source:</strong> {{ formModel().basics.source }}</span>
<span>
<strong>Yield:</strong>
@@ -63,7 +63,7 @@ export interface IngredientFormData {
export interface RecipeDetailFormData {
basics: {
date: moment.Moment;
date: string;
source: string;
recipeYield: string;
product: ProductSku | string | null;
@@ -136,7 +136,7 @@ export class RecipeDetailComponent {
source: this.item,
computation: (itemVal): RecipeDetailFormData => ({
basics: {
date: itemVal.date ? moment(itemVal.date) : moment(new Date()),
date: itemVal.date,
source: itemVal.source ?? '',
recipeYield: `${itemVal.recipeYield ?? ''}`,
product: itemVal.sku ?? null,
+10 -10
View File
@@ -24,16 +24,16 @@ import { SettingsService } from './settings.service';
import { VoucherTypeService } from './voucher-type.service';
export interface LockInfoFormData {
validFrom: moment.Moment | null;
validTill: moment.Moment | null;
validFrom: Date | null;
validTill: Date | null;
index: number;
lockOlder: boolean;
olderRolling: boolean;
olderDate: moment.Moment;
olderDate: Date;
olderDays: number;
lockNewer: boolean;
newerRolling: boolean;
newerDate: moment.Moment;
newerDate: Date;
newerDays: number;
accountTypes: { accountType: boolean }[];
voucherTypes: { voucherType: boolean }[];
@@ -82,16 +82,16 @@ export class SettingsComponent {
lockInfoModel = linkedSignal({
source: this.lockInfoSource,
computation: (s): LockInfoFormData => ({
validFrom: null as moment.Moment | null,
validTill: null as moment.Moment | null,
validFrom: null as Date | null,
validTill: null as Date | null,
index: 0,
lockOlder: false,
olderRolling: false,
olderDate: moment().date(moment().date(1).daysInMonth()),
olderDate: moment().date(moment().date(1).daysInMonth()).toDate(),
olderDays: 0,
lockNewer: false,
newerRolling: false,
newerDate: moment().date(moment().date(1).daysInMonth()),
newerDate: moment().date(moment().date(1).daysInMonth()).toDate(),
newerDays: 0,
accountTypes: s.accTypes.map(() => ({ accountType: false })),
voucherTypes: s.vchTypes.map(() => ({ voucherType: false })),
@@ -133,13 +133,13 @@ export class SettingsComponent {
if (this.lockOlder() && this.olderRolling()) {
item.start.days = model.olderDays ?? 0;
} else if (this.lockOlder() && !this.olderRolling()) {
item.start.date = (model.olderDate ?? moment()).format('DD-MMM-YYYY');
item.start.date = moment(model.olderDate ?? new Date()).format('DD-MMM-YYYY');
}
if (this.lockNewer() && this.newerRolling()) {
item.finish.days = model.newerDays ?? 0;
}
if (this.lockNewer() && !this.newerRolling()) {
item.finish.date = (model.newerDate ?? moment()).format('DD-MMM-YYYY');
item.finish.date = moment(model.newerDate ?? new Date()).format('DD-MMM-YYYY');
}
this.accountTypes().forEach((at: AccountType, index: number) => {
@@ -1,6 +1,6 @@
<h2>Stock Movement</h2>
<form class="flex-col" [formRoot]="form">
<form class="flex-col" [formRoot]="form" (submit)="$event.preventDefault(); show()">
<div class="row-container">
<mat-form-field class="flex-auto basis-2-5">
<mat-label>Start Date</mat-label>
@@ -14,7 +14,7 @@
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
<mat-datepicker #finishDate></mat-datepicker>
</mat-form-field>
<button mat-raised-button class="flex-auto basis-1-5" color="primary" (click)="show()">Show</button>
<button mat-raised-button type="submit" class="flex-auto basis-1-5" color="primary">Show</button>
</div>
</form>
@if (resource.isLoading()) {
@@ -1,5 +1,5 @@
import { DecimalPipe } from '@angular/common';
import { Component, HostListener, inject, computed, linkedSignal, signal, input } from '@angular/core';
import { Component, inject, computed, linkedSignal, signal, input } from '@angular/core';
import { form, FormField, FormRoot } from '@angular/forms/signals';
import { MatButtonModule } from '@angular/material/button';
import { MatDatepickerModule } from '@angular/material/datepicker';
@@ -25,6 +25,9 @@ export interface StockMovementFormData {
selector: 'app-stock-movement',
templateUrl: './stock-movement.component.html',
styleUrls: ['./stock-movement.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
},
imports: [
FormField,
@@ -104,7 +107,6 @@ export class StockMovementComponent {
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns = ['group', 'name', 'opening', 'purchase', 'issue', 'closing'];
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
this.form().focusBoundControl();
@@ -7,7 +7,7 @@
</mat-form-field>
<mat-form-field class="flex-auto basis-30">
<mat-label>Product Group</mat-label>
<mat-select [formField]="form.productGroup" (selectionChange)="filterOn($event.value)">
<mat-select [formField]="form.productGroup">
<mat-option>-- All Products --</mat-option>
@for (pg of productGroups(); track pg) {
<mat-option [value]="pg.id">
@@ -18,10 +18,10 @@
</mat-form-field>
</div>
</form>
@if (resource.isLoading()) {
@if (listResource.isLoading()) {
<app-skeleton-loader type="table" [count]="1" />
} @else if (resource.error()) {
<app-error-state [message]="'Failed to load data.'" (retryAction)="resource.reload()" />
} @else if (listResource.error()) {
<app-error-state [message]="'Failed to load data.'" (retryAction)="listResource.reload()" />
} @else {
<mat-table [dataSource]="dataSource()">
<!-- Name Column -->
@@ -1,5 +1,5 @@
import { CommonModule } from '@angular/common';
import { Component, inject, computed, linkedSignal } from '@angular/core';
import { Component, inject, computed, linkedSignal, input, debounced, effect } from '@angular/core';
import { FormField, FormRoot, form as createForm } from '@angular/forms/signals';
import { MatOptionModule } from '@angular/material/core';
import { MatFormFieldModule } from '@angular/material/form-field';
@@ -7,12 +7,13 @@ import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select';
import { MatTableModule } from '@angular/material/table';
import { RouterLink } from '@angular/router';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { Product, StockKeepingUnit } from '../../core/product';
import { ProductGroupService } from '../../product-group/product-group.service';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
import { TemporalProduct } from '../temporal-product';
import { TemporalProductService } from '../temporal-product.service';
export interface TemporalProductListFormData {
@@ -42,48 +43,84 @@ export interface TemporalProductListFormData {
],
})
export class TemporalProductListComponent {
private router = inject(Router);
private route = inject(ActivatedRoute);
private ser = inject(TemporalProductService);
private productGroupSer = inject(ProductGroupService);
q = input('', { transform: (v: string | null | undefined) => v ?? '' });
g = input('', { transform: (v: string | null | undefined) => v ?? '' });
productGroupsResource = this.productGroupSer.list();
productGroups = computed(() => this.productGroupsResource.value() ?? []);
listResource = this.ser.list();
list = computed(() => this.listResource.value() ?? []);
formModel = linkedSignal({
source: () => null,
computation: (): TemporalProductListFormData => ({
filter: '',
productGroup: '',
source: () => ({ q: this.q(), g: this.g() }),
computation: (v: { q: string; g: string }): TemporalProductListFormData => ({
filter: v.q,
productGroup: v.g,
}),
});
form = createForm(this.formModel);
filterSignal = computed(() => this.formModel().filter);
debouncedFilter = debounced(this.filterSignal, 150);
filteredList = computed(() => {
const data = this.list();
const search = this.debouncedFilter.value() ?? '';
const productGroup = this.formModel().productGroup;
const groupId =
typeof productGroup === 'string'
? productGroup
: productGroup && 'id' in productGroup
? (productGroup.id ?? '')
: '';
productGroupsResource = this.productGroupSer.list();
productGroups = computed(() => this.productGroupsResource.value() ?? []);
const tokens = search.trim().toLowerCase().split(/\s+/).filter(Boolean);
resource = this.ser.list();
return data.filter((tp: TemporalProduct) => {
const products = tp.products ?? [];
const skus = tp.skus ?? [];
dataSource = computed(() => {
let data = this.resource.value() ?? [];
const filterValue = (this.formModel().filter ?? '').trim().toLowerCase();
const groupValue = this.formModel().productGroup;
const matchesSearch =
tokens.length === 0 ||
tokens.every(
(token) =>
products.some((p) => {
const hay = `${p.name ?? ''} ${p.fractionUnits ?? ''} ${p.productGroup?.name ?? ''}`.toLowerCase();
return hay.includes(token);
}) ||
skus.some((k) => {
const hay = `${k.units ?? ''}`.toLowerCase();
return hay.includes(token);
}),
);
if (filterValue || groupValue) {
data = data.filter((d) => {
let match = true;
if (filterValue) {
match = match && d.products[0].name.toLowerCase().includes(filterValue);
}
if (groupValue) {
match = match && d.products[0].productGroup?.id === groupValue;
}
return match;
});
}
return data;
const matchesProductGroup = !groupId || products.some((k) => (k.productGroup?.id ?? '') === groupId);
return matchesSearch && matchesProductGroup;
});
});
dataSource = computed(() => this.filteredList());
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns: string[] = ['product', 'sku', 'info'];
filterOn(val: string) {
this.formModel.update((m) => ({ ...m, productGroup: val }));
constructor() {
effect(() => {
const q = this.debouncedFilter.value() ?? '';
const g = this.formModel().productGroup;
this.router.navigate([], {
relativeTo: this.route,
queryParams: {
q: q || null,
g: g || null,
},
queryParamsHandling: 'merge',
replaceUrl: true,
});
});
}
}
@@ -1,6 +1,6 @@
<h2>Trial Balance</h2>
<form class="flex-col" [formRoot]="form">
<form class="flex-col" [formRoot]="form" (submit)="$event.preventDefault(); show()">
<div class="row-container">
<mat-form-field class="flex-auto basis-4-5">
<mat-label>Date</mat-label>
@@ -8,7 +8,7 @@
<mat-datepicker-toggle matSuffix [for]="dateInput"></mat-datepicker-toggle>
<mat-datepicker #dateInput></mat-datepicker>
</mat-form-field>
<button mat-raised-button color="primary" (click)="show()" class="flex-auto">Show</button>
<button mat-raised-button type="submit" color="primary" class="flex-auto">Show</button>
</div>
</form>
@if (resource.isLoading()) {
@@ -1,5 +1,5 @@
import { CurrencyPipe } from '@angular/common';
import { Component, HostListener, inject, computed, linkedSignal, signal, input } from '@angular/core';
import { Component, inject, computed, linkedSignal, signal, input } from '@angular/core';
import { FormField, FormRoot, form as createForm } from '@angular/forms/signals';
import { MatButtonModule } from '@angular/material/button';
import { MatDatepickerModule } from '@angular/material/datepicker';
@@ -25,6 +25,9 @@ export interface TrialBalanceFormData {
selector: 'app-trial-balance',
templateUrl: './trial-balance.component.html',
styleUrls: ['./trial-balance.component.css'],
host: {
'(window:keydown.f2)': 'focusDate($event)',
},
imports: [
FormField,
@@ -100,7 +103,6 @@ export class TrialBalanceComponent {
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns = ['type', 'name', 'debit', 'credit'];
@HostListener('window:keydown.f2', ['$event'])
focusDate(event: Event) {
event.preventDefault();
this.form().focusBoundControl();