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:
1 parent
fe5e4a2308
commit
e3719faddd
79 files changed
+737
-990
No files matched your search
@@ -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)">
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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')) {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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')) {
|
||||
|
||||
Whitespace-only changes.
-35
@@ -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>
|
||||
}
|
||||
-22
@@ -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();
|
||||
});
|
||||
});
|
||||
-119
@@ -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;
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
-47
@@ -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>
|
||||
}
|
||||
-22
@@ -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();
|
||||
});
|
||||
});
|
||||
-81
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
+4
-4
@@ -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 -->
|
||||
|
||||
+65
-28
@@ -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();
|
||||
|
||||
Reference in new issue
Block a user