Chore: Eslint v9
Chore: Angular Zoneless Chore: Removed Angular-Hotkeys dependency Fix: Localization works properly now Chore: Using Material 3 theme now Chore: Removed toaster service to use snackbar directly Fix: F2 Date working on all components now
This commit is contained in:
1 parent
c07c79ffda
commit
336a8f59c5
94 files changed
+846
-1030
No files matched your search
@@ -22,7 +22,7 @@ import { Account } from '../../core/account';
|
||||
import { AccountType } from '../../core/account-type';
|
||||
import { AccountService } from '../../core/account.service';
|
||||
import { CostCentre } from '../../core/cost-centre';
|
||||
import { ToasterService } from '../../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||
|
||||
@Component({
|
||||
@@ -50,7 +50,7 @@ import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dial
|
||||
],
|
||||
})
|
||||
export class AccountDetailComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
@ViewChild('nameElement', { static: true }) nameElement!: ElementRef<HTMLInputElement>;
|
||||
form: FormGroup<{
|
||||
code: FormControl<number | string>;
|
||||
name: FormControl<string | null>;
|
||||
@@ -68,7 +68,7 @@ export class AccountDetailComponent implements OnInit, AfterViewInit {
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
private ser: AccountService,
|
||||
) {
|
||||
this.form = new FormGroup({
|
||||
@@ -109,20 +109,18 @@ export class AccountDetailComponent implements OnInit, AfterViewInit {
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
this.nameElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
save() {
|
||||
this.ser.saveOrUpdate(this.getItem()).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/accounts');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -130,11 +128,11 @@ export class AccountDetailComponent implements OnInit, AfterViewInit {
|
||||
delete() {
|
||||
this.ser.delete(this.item.id as string).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/accounts');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -63,9 +63,9 @@ import { AccountListDataSource } from './account-list-datasource';
|
||||
],
|
||||
})
|
||||
export class AccountListComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('filterElement', { static: true }) filterElement?: ElementRef;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild('filterElement', { static: true }) filterElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
dataSource: AccountListDataSource;
|
||||
filter: Observable<string>;
|
||||
form: FormGroup<{
|
||||
@@ -85,7 +85,7 @@ export class AccountListComponent implements OnInit, AfterViewInit {
|
||||
// Listen to Filter Change
|
||||
this.filter = this.form.controls.filter.valueChanges.pipe(debounceTime(150), distinctUntilChanged());
|
||||
|
||||
this.dataSource = new AccountListDataSource(this.list, this.filter);
|
||||
this.dataSource = new AccountListDataSource(this.list, this.filter, this.paginator, this.sort);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -100,9 +100,7 @@ export class AccountListComponent implements OnInit, AfterViewInit {
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.filterElement) {
|
||||
this.filterElement.nativeElement.focus();
|
||||
}
|
||||
this.filterElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,11 @@
|
||||
import { LayoutModule } from '@angular/cdk/layout';
|
||||
import { provideHttpClient, withInterceptors } from '@angular/common/http';
|
||||
import { LOCALE_ID, importProvidersFrom, ApplicationConfig } from '@angular/core';
|
||||
import {
|
||||
LOCALE_ID,
|
||||
importProvidersFrom,
|
||||
ApplicationConfig,
|
||||
provideExperimentalZonelessChangeDetection,
|
||||
} from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
@@ -13,7 +18,7 @@ import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSidenavModule } from '@angular/material/sidenav';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { MAT_SNACK_BAR_DEFAULT_OPTIONS, MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { MatSortModule } from '@angular/material/sort';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
@@ -21,7 +26,6 @@ import { MomentDateAdapter } from '@angular/material-moment-adapter';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { provideAnimations } from '@angular/platform-browser/animations';
|
||||
import { provideRouter, withRouterConfig } from '@angular/router';
|
||||
import { HotkeyModule } from 'angular2-hotkeys';
|
||||
|
||||
import { dateFormat } from './app.environment';
|
||||
import { routes } from './app.routes';
|
||||
@@ -34,7 +38,6 @@ export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
importProvidersFrom(
|
||||
BrowserModule,
|
||||
HotkeyModule.forRoot(),
|
||||
LayoutModule,
|
||||
MatButtonModule,
|
||||
MatCardModule,
|
||||
@@ -64,5 +67,7 @@ export const appConfig: ApplicationConfig = {
|
||||
),
|
||||
{ provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE] },
|
||||
{ provide: MAT_DATE_FORMATS, useValue: dateFormat },
|
||||
{ provide: MAT_SNACK_BAR_DEFAULT_OPTIONS, useValue: { duration: 3000 } },
|
||||
provideExperimentalZonelessChangeDetection(),
|
||||
],
|
||||
};
|
||||
@@ -1,5 +1,4 @@
|
||||
export const environment = {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
ACCESS_TOKEN_REFRESH_MINUTES: 10, // refresh token 10 minutes before expiry
|
||||
version: '13.0.0',
|
||||
title: 'HnG / TGB',
|
||||
|
||||
@@ -7,7 +7,14 @@
|
||||
<div class="flex flex-row justify-around content-start items-start sm:max-lg:flex-col">
|
||||
<mat-form-field class="flex-auto basis-4/5 mr-5">
|
||||
<mat-label>Date</mat-label>
|
||||
<input matInput [matDatepicker]="date" (focus)="date.open()" formControlName="date" autocomplete="off" />
|
||||
<input
|
||||
matInput
|
||||
#dateElement
|
||||
[matDatepicker]="date"
|
||||
(focus)="dateElement.select()"
|
||||
formControlName="date"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
|
||||
<mat-datepicker #date></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -27,13 +27,16 @@ import moment from 'moment';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
import { AuthService } from '../auth/auth.service';
|
||||
import { ToasterService } from '../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
import { Attendance } from './attendance';
|
||||
import { AttendanceDataSource } from './attendance-datasource';
|
||||
import { AttendanceItem } from './attendance-item';
|
||||
import { AttendanceType } from './attendance-type';
|
||||
import { AttendanceService } from './attendance.service';
|
||||
import { ViewChild } from '@angular/core';
|
||||
import { ElementRef } from '@angular/core';
|
||||
import { HostListener } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-attendance',
|
||||
@@ -73,6 +76,7 @@ import { AttendanceService } from './attendance.service';
|
||||
],
|
||||
})
|
||||
export class AttendanceComponent implements OnInit {
|
||||
@ViewChild('dateElement', { static: false }) dateElement!: ElementRef<HTMLInputElement>;
|
||||
public attendanceObservable = new BehaviorSubject<AttendanceItem[]>([]);
|
||||
dataSource: AttendanceDataSource = new AttendanceDataSource(this.attendanceObservable);
|
||||
form: FormGroup<{
|
||||
@@ -89,11 +93,18 @@ export class AttendanceComponent implements OnInit {
|
||||
|
||||
displayedColumns = ['code', 'name', 'designation', 'department', 'status', 'prints'];
|
||||
|
||||
@HostListener('window:keydown.f2', ['$event'])
|
||||
focusDate(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.dateElement.nativeElement.focus();
|
||||
this.dateElement.nativeElement.select();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
private auth: AuthService,
|
||||
private ser: AttendanceService,
|
||||
) {
|
||||
@@ -138,10 +149,10 @@ export class AttendanceComponent implements OnInit {
|
||||
save() {
|
||||
this.ser.save(this.getAttendance()).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { inject } from '@angular/core';
|
||||
import { CanActivateFn } from '@angular/router';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { ToasterService } from '../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
@@ -18,7 +18,7 @@ export const authGuard: CanActivateFn = (route, state) => {
|
||||
return false;
|
||||
}
|
||||
if (permission !== undefined && user.perms.indexOf(permission) === -1) {
|
||||
inject(ToasterService).show('Danger', 'You do not have the permission to access this area.');
|
||||
inject(MatSnackBar).open('You do not have the permission to access this area.', 'Danger');
|
||||
return false;
|
||||
}
|
||||
// logged in so return true
|
||||
|
||||
@@ -8,7 +8,7 @@ import { MatIcon } from '@angular/material/icon';
|
||||
import { MatInput } from '@angular/material/input';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
import { ToasterService } from '../../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { CookieService } from '../../shared/cookie.service';
|
||||
import { AuthService } from '../auth.service';
|
||||
|
||||
@@ -34,7 +34,7 @@ import { AuthService } from '../auth.service';
|
||||
],
|
||||
})
|
||||
export class LoginComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
@ViewChild('nameElement', { static: true }) nameElement!: ElementRef<HTMLInputElement>;
|
||||
form: FormGroup<{
|
||||
username: FormControl<string>;
|
||||
password: FormControl<string>;
|
||||
@@ -50,7 +50,7 @@ export class LoginComponent implements OnInit, AfterViewInit {
|
||||
private route: ActivatedRoute,
|
||||
private auth: AuthService,
|
||||
private router: Router,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
private cs: CookieService,
|
||||
) {
|
||||
this.hide = true;
|
||||
@@ -68,9 +68,7 @@ export class LoginComponent implements OnInit, AfterViewInit {
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
this.nameElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -91,7 +89,7 @@ export class LoginComponent implements OnInit, AfterViewInit {
|
||||
this.showOtp = true;
|
||||
this.clientId = this.cs.getCookie('client_id');
|
||||
}
|
||||
this.toaster.show('Danger', error.error.details);
|
||||
this.snackBar.open(error.error.details, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { ToasterService } from '../../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { AuthService } from '../auth.service';
|
||||
|
||||
@Component({
|
||||
@@ -13,7 +13,7 @@ export class LogoutComponent implements OnInit {
|
||||
constructor(
|
||||
private auth: AuthService,
|
||||
private router: Router,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
@@ -7,13 +7,7 @@
|
||||
<div class="flex flex-row justify-around content-start items-start sm:max-lg:flex-col">
|
||||
<mat-form-field class="flex-auto mr-5">
|
||||
<mat-label>Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="dateInput"
|
||||
(focus)="dateInput.open()"
|
||||
formControlName="date"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<input matInput #dateElement [matDatepicker]="dateInput" formControlName="date" autocomplete="off" />
|
||||
<mat-datepicker-toggle matSuffix [for]="dateInput"></mat-datepicker-toggle>
|
||||
<mat-datepicker #dateInput></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CurrencyPipe } from '@angular/common';
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButton } from '@angular/material/button';
|
||||
import { MatCard, MatCardHeader, MatCardTitle, MatCardContent } from '@angular/material/card';
|
||||
@@ -73,10 +73,11 @@ import { BalanceSheetDataSource } from './balance-sheet-datasource';
|
||||
],
|
||||
})
|
||||
export class BalanceSheetComponent implements OnInit {
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
@ViewChild('dateElement', { static: true }) dateElement!: ElementRef<HTMLInputElement>;
|
||||
info: BalanceSheet = new BalanceSheet();
|
||||
dataSource: BalanceSheetDataSource = new BalanceSheetDataSource(this.info.body);
|
||||
dataSource: BalanceSheetDataSource = new BalanceSheetDataSource(this.info.body, this.paginator, this.sort);
|
||||
form: FormGroup<{
|
||||
date: FormControl<Date>;
|
||||
}>;
|
||||
@@ -84,6 +85,13 @@ export class BalanceSheetComponent implements OnInit {
|
||||
/** 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: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.dateElement.nativeElement.focus();
|
||||
this.dateElement.nativeElement.select();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
<mat-label>Start Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
#startDateElement
|
||||
[matDatepicker]="startDate"
|
||||
(focus)="startDate.open()"
|
||||
formControlName="startDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
@@ -19,13 +19,7 @@
|
||||
</mat-form-field>
|
||||
<mat-form-field class="flex-auto basis-2/5 mr-5">
|
||||
<mat-label>Finish Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="finishDate"
|
||||
(focus)="finishDate.open()"
|
||||
formControlName="finishDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<input matInput [matDatepicker]="finishDate" formControlName="finishDate" autocomplete="off" />
|
||||
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
|
||||
<mat-datepicker #finishDate></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CurrencyPipe } from '@angular/common';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButton } from '@angular/material/button';
|
||||
import { MatCard, MatCardHeader, MatCardTitle, MatCardContent } from '@angular/material/card';
|
||||
@@ -64,6 +64,7 @@ import { CashFlowDataSource } from './cash-flow-datasource';
|
||||
],
|
||||
})
|
||||
export class CashFlowComponent implements OnInit {
|
||||
@ViewChild('startDateElement', { static: true }) startDate!: ElementRef<HTMLInputElement>;
|
||||
info: CashFlow = new CashFlow();
|
||||
dataSource: CashFlowDataSource = new CashFlowDataSource(CashFlow.Data(this.info));
|
||||
form: FormGroup<{
|
||||
@@ -74,6 +75,13 @@ export class CashFlowComponent implements OnInit {
|
||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||
displayedColumns = ['name', 'amount'];
|
||||
|
||||
@HostListener('window:keydown.f2', ['$event'])
|
||||
focusDate(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.startDate.nativeElement.focus();
|
||||
this.startDate.nativeElement.select();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
|
||||
@@ -8,7 +8,7 @@ import { MatFormField, MatLabel } from '@angular/material/form-field';
|
||||
import { MatInput } from '@angular/material/input';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
import { ToasterService } from '../../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||
import { Client } from '../client';
|
||||
import { ClientService } from '../client.service';
|
||||
@@ -33,7 +33,7 @@ import { ClientService } from '../client.service';
|
||||
],
|
||||
})
|
||||
export class ClientDetailComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
@ViewChild('nameElement', { static: true }) nameElement!: ElementRef<HTMLInputElement>;
|
||||
form: FormGroup<{
|
||||
code: FormControl<number | string>;
|
||||
name: FormControl<string | null>;
|
||||
@@ -47,7 +47,7 @@ export class ClientDetailComponent implements OnInit, AfterViewInit {
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
private ser: ClientService,
|
||||
) {
|
||||
this.form = new FormGroup({
|
||||
@@ -78,20 +78,18 @@ export class ClientDetailComponent implements OnInit, AfterViewInit {
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
this.nameElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
save() {
|
||||
this.ser.update(this.getItem()).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/clients');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -99,11 +97,11 @@ export class ClientDetailComponent implements OnInit, AfterViewInit {
|
||||
delete() {
|
||||
this.ser.delete(this.item.id).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/clients');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -49,10 +49,10 @@ import { ClientListDataSource } from './client-list-datasource';
|
||||
],
|
||||
})
|
||||
export class ClientListComponent implements OnInit {
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
list: Client[] = [];
|
||||
dataSource: ClientListDataSource = new ClientListDataSource(this.list);
|
||||
dataSource: ClientListDataSource = new ClientListDataSource(this.list, this.paginator, this.sort);
|
||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||
displayedColumns = ['code', 'name', 'enabled', 'otp', 'created', 'last'];
|
||||
|
||||
|
||||
@@ -24,13 +24,7 @@
|
||||
</mat-form-field>
|
||||
<mat-form-field class="flex-auto basis-2/5 mr-5">
|
||||
<mat-label>Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="dateInput"
|
||||
(focus)="dateInput.open()"
|
||||
formControlName="date"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<input matInput #dateElement [matDatepicker]="dateInput" formControlName="date" autocomplete="off" />
|
||||
<mat-datepicker-toggle matSuffix [for]="dateInput"></mat-datepicker-toggle>
|
||||
<mat-datepicker #dateInput></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { DecimalPipe, CurrencyPipe } from '@angular/common';
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
|
||||
import { FormGroup, FormArray, FormControl, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatIconButton, MatButton } from '@angular/material/button';
|
||||
import {
|
||||
@@ -36,7 +36,7 @@ import moment from 'moment';
|
||||
|
||||
import { AuthService } from '../auth/auth.service';
|
||||
import { CostCentre } from '../core/cost-centre';
|
||||
import { ToasterService } from '../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { User } from '../core/user';
|
||||
import { ConfirmDialogComponent } from '../shared/confirm-dialog/confirm-dialog.component';
|
||||
import { ToCsvService } from '../shared/to-csv.service';
|
||||
@@ -89,10 +89,11 @@ import { ClosingStockService } from './closing-stock.service';
|
||||
],
|
||||
})
|
||||
export class ClosingStockComponent implements OnInit {
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
@ViewChild('dateElement', { static: true }) dateElement!: ElementRef<HTMLInputElement>;
|
||||
info: ClosingStock = new ClosingStock();
|
||||
dataSource: ClosingStockDataSource = new ClosingStockDataSource(this.info.items);
|
||||
dataSource: ClosingStockDataSource = new ClosingStockDataSource(this.info.items, this.paginator, this.sort);
|
||||
form: FormGroup<{
|
||||
date: FormControl<Date>;
|
||||
costCentre: FormControl<string | null>;
|
||||
@@ -109,12 +110,19 @@ export class ClosingStockComponent implements OnInit {
|
||||
|
||||
costCentres: CostCentre[];
|
||||
|
||||
@HostListener('window:keydown.f2', ['$event'])
|
||||
focusDate(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.dateElement.nativeElement.focus();
|
||||
this.dateElement.nativeElement.select();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private toCsv: ToCsvService,
|
||||
private dialog: MatDialog,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
public auth: AuthService,
|
||||
private ser: ClosingStockService,
|
||||
) {
|
||||
@@ -162,10 +170,10 @@ export class ClosingStockComponent implements OnInit {
|
||||
save() {
|
||||
this.ser.save(this.getClosingStock()).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -243,10 +251,10 @@ export class ClosingStockComponent implements OnInit {
|
||||
post() {
|
||||
this.ser.post(this.info.date, this.info.costCentre.id as string).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', 'Voucher Posted');
|
||||
this.snackBar.open('Voucher Posted', 'Success');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -254,11 +262,11 @@ export class ClosingStockComponent implements OnInit {
|
||||
delete() {
|
||||
this.ser.delete(this.info.date, this.info.costCentre.id as string).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigate(['/closing-stock'], { replaceUrl: true });
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import { catchError } from 'rxjs/operators';
|
||||
import { AuthService } from '../auth/auth.service';
|
||||
import { ConfirmDialogComponent } from '../shared/confirm-dialog/confirm-dialog.component';
|
||||
|
||||
import { ToasterService } from './toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
export const authInterceptor: HttpInterceptorFn = (req, next) => {
|
||||
return next(req).pipe(
|
||||
@@ -31,7 +31,7 @@ export const authInterceptor: HttpInterceptorFn = (req, next) => {
|
||||
}
|
||||
// auto logout if 401 response returned from api
|
||||
inject(AuthService).logout();
|
||||
inject(ToasterService).show('Danger', 'User has been logged out');
|
||||
inject(MatSnackBar).open('User has been logged out', 'Danger');
|
||||
const dialogRef = inject(MatDialog).open(ConfirmDialogComponent, {
|
||||
width: '250px',
|
||||
data: {
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import { inject, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ToasterService } from './toaster.service';
|
||||
|
||||
describe('ToasterService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [ToasterService],
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject([ToasterService], (service: ToasterService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
||||
@@ -1,15 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ToasterService {
|
||||
constructor(private snackBar: MatSnackBar) {}
|
||||
|
||||
show(type: string, msg: string) {
|
||||
this.snackBar.open(msg, type, {
|
||||
duration: 3000,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import { MatInput } from '@angular/material/input';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
import { CostCentre } from '../../core/cost-centre';
|
||||
import { ToasterService } from '../../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { CostCentreService } from '../cost-centre.service';
|
||||
|
||||
@Component({
|
||||
@@ -29,7 +29,7 @@ import { CostCentreService } from '../cost-centre.service';
|
||||
],
|
||||
})
|
||||
export class CostCentreDetailComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
@ViewChild('nameElement', { static: true }) nameElement!: ElementRef<HTMLInputElement>;
|
||||
form: FormGroup<{
|
||||
name: FormControl<string | null>;
|
||||
}>;
|
||||
@@ -39,7 +39,7 @@ export class CostCentreDetailComponent implements OnInit, AfterViewInit {
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
private ser: CostCentreService,
|
||||
) {
|
||||
this.form = new FormGroup({
|
||||
@@ -64,20 +64,18 @@ export class CostCentreDetailComponent implements OnInit, AfterViewInit {
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
this.nameElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
save() {
|
||||
this.ser.saveOrUpdate(this.getItem()).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/cost-centres');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -52,10 +52,10 @@ import { CostCentreListDataSource } from './cost-centre-list-datasource';
|
||||
],
|
||||
})
|
||||
export class CostCentreListComponent implements OnInit {
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
list: CostCentre[] = [];
|
||||
dataSource: CostCentreListDataSource = new CostCentreListDataSource(this.list);
|
||||
dataSource: CostCentreListDataSource = new CostCentreListDataSource(this.list, this.paginator, this.sort);
|
||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||
displayedColumns = ['name', 'isFixture'];
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
<mat-label>Start Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
#startDateElement
|
||||
[matDatepicker]="startDate"
|
||||
(focus)="startDate.open()"
|
||||
formControlName="startDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
@@ -19,13 +19,7 @@
|
||||
</mat-form-field>
|
||||
<mat-form-field class="flex-auto basis-2/5 mr-5">
|
||||
<mat-label>Finish Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="finishDate"
|
||||
(focus)="finishDate.open()"
|
||||
formControlName="finishDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<input matInput [matDatepicker]="finishDate" formControlName="finishDate" autocomplete="off" />
|
||||
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
|
||||
<mat-datepicker #finishDate></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CurrencyPipe } from '@angular/common';
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButton } from '@angular/material/button';
|
||||
import { MatCard, MatCardHeader, MatCardTitle, MatCardContent } from '@angular/material/card';
|
||||
@@ -63,10 +63,11 @@ import { DaybookDataSource } from './daybook-datasource';
|
||||
],
|
||||
})
|
||||
export class DaybookComponent implements OnInit {
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
@ViewChild('startDateElement', { static: true }) startDate!: ElementRef<HTMLInputElement>;
|
||||
info: Daybook = new Daybook();
|
||||
dataSource: DaybookDataSource = new DaybookDataSource(this.info.body);
|
||||
dataSource: DaybookDataSource = new DaybookDataSource(this.info.body, this.paginator, this.sort);
|
||||
form: FormGroup<{
|
||||
startDate: FormControl<Date>;
|
||||
finishDate: FormControl<Date>;
|
||||
@@ -76,6 +77,13 @@ export class DaybookComponent implements OnInit {
|
||||
/** 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: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.startDate.nativeElement.focus();
|
||||
this.startDate.nativeElement.select();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
<mat-label>Start Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
#startDateElement
|
||||
[matDatepicker]="startDate"
|
||||
(focus)="startDate.open()"
|
||||
formControlName="startDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
@@ -19,13 +19,7 @@
|
||||
</mat-form-field>
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Finish Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="finishDate"
|
||||
(focus)="finishDate.open()"
|
||||
formControlName="finishDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<input matInput [matDatepicker]="finishDate" formControlName="finishDate" autocomplete="off" />
|
||||
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
|
||||
<mat-datepicker #finishDate></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AsyncPipe } from '@angular/common';
|
||||
import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
||||
import { AfterViewInit, Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
|
||||
import { FormArray, FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatAutocompleteSelectedEvent, MatAutocompleteTrigger, MatAutocomplete } from '@angular/material/autocomplete';
|
||||
import { MatButton } from '@angular/material/button';
|
||||
@@ -31,7 +31,7 @@ import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators';
|
||||
|
||||
import { AttendanceType } from '../attendance/attendance-type';
|
||||
import { AuthService } from '../auth/auth.service';
|
||||
import { ToasterService } from '../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { Employee } from '../employee/employee';
|
||||
import { EmployeeService } from '../employee/employee.service';
|
||||
|
||||
@@ -81,7 +81,8 @@ import { EmployeeAttendanceService } from './employee-attendance.service';
|
||||
],
|
||||
})
|
||||
export class EmployeeAttendanceComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('employeeElement', { static: true }) employeeElement?: ElementRef;
|
||||
@ViewChild('employeeElement', { static: true }) employeeElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('startDateElement', { static: true }) startDate!: ElementRef<HTMLInputElement>;
|
||||
public employeeAttendanceObservable = new BehaviorSubject<EmployeeAttendanceItem[]>([]);
|
||||
dataSource: EmployeeAttendanceDataSource = new EmployeeAttendanceDataSource(this.employeeAttendanceObservable);
|
||||
|
||||
@@ -103,11 +104,18 @@ export class EmployeeAttendanceComponent implements OnInit, AfterViewInit {
|
||||
|
||||
employees: Observable<Employee[]>;
|
||||
|
||||
@HostListener('window:keydown.f2', ['$event'])
|
||||
focusDate(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.startDate.nativeElement.focus();
|
||||
this.startDate.nativeElement.select();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
private auth: AuthService,
|
||||
private ser: EmployeeAttendanceService,
|
||||
private employeeSer: EmployeeService,
|
||||
@@ -150,9 +158,7 @@ export class EmployeeAttendanceComponent implements OnInit, AfterViewInit {
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.employeeElement) {
|
||||
this.employeeElement.nativeElement.focus();
|
||||
}
|
||||
this.employeeElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -188,10 +194,10 @@ export class EmployeeAttendanceComponent implements OnInit, AfterViewInit {
|
||||
save() {
|
||||
this.ser.save(this.getEmployeeAttendance()).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,7 +7,14 @@
|
||||
<div class="flex flex-row justify-around content-start items-start">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Date</mat-label>
|
||||
<input matInput [matDatepicker]="date" (focus)="date.open()" formControlName="date" autocomplete="off" />
|
||||
<input
|
||||
matInput
|
||||
#dateElement
|
||||
[matDatepicker]="date"
|
||||
(focus)="dateElement.select()"
|
||||
formControlName="date"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
|
||||
<mat-datepicker #date></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -37,7 +37,7 @@ import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators';
|
||||
import { AuthService } from '../auth/auth.service';
|
||||
import { AccountBalance } from '../core/account-balance';
|
||||
import { EmployeeBenefit } from '../core/employee-benefit';
|
||||
import { ToasterService } from '../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { User } from '../core/user';
|
||||
import { Voucher } from '../core/voucher';
|
||||
import { VoucherService } from '../core/voucher.service';
|
||||
@@ -47,6 +47,7 @@ import { ConfirmDialogComponent } from '../shared/confirm-dialog/confirm-dialog.
|
||||
import { LocalTimePipe } from '../shared/local-time.pipe';
|
||||
|
||||
import { EmployeeBenefitsDataSource } from './employee-benefits-datasource';
|
||||
import { HostListener } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-employee-benefits',
|
||||
@@ -91,7 +92,8 @@ import { EmployeeBenefitsDataSource } from './employee-benefits-datasource';
|
||||
],
|
||||
})
|
||||
export class EmployeeBenefitsComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('employeeElement', { static: true }) employeeElement?: ElementRef;
|
||||
@ViewChild('employeeElement', { static: true }) employeeElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('dateElement', { static: true }) dateElement!: ElementRef<HTMLInputElement>;
|
||||
public benefitsObservable = new BehaviorSubject<EmployeeBenefit[]>([]);
|
||||
dataSource: EmployeeBenefitsDataSource = new EmployeeBenefitsDataSource(this.benefitsObservable);
|
||||
form: FormGroup<{
|
||||
@@ -121,11 +123,18 @@ export class EmployeeBenefitsComponent implements OnInit, AfterViewInit {
|
||||
|
||||
employees: Observable<Employee[]>;
|
||||
|
||||
@HostListener('window:keydown.f2', ['$event'])
|
||||
focusDate(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.dateElement.nativeElement.focus();
|
||||
this.dateElement.nativeElement.select();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
public auth: AuthService,
|
||||
private ser: VoucherService,
|
||||
private employeeSer: EmployeeService,
|
||||
@@ -174,9 +183,7 @@ export class EmployeeBenefitsComponent implements OnInit, AfterViewInit {
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.employeeElement) {
|
||||
this.employeeElement.nativeElement.focus();
|
||||
}
|
||||
this.employeeElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -205,7 +212,7 @@ export class EmployeeBenefitsComponent implements OnInit, AfterViewInit {
|
||||
addRow() {
|
||||
const oldFiltered = this.voucher.employeeBenefits.filter((x) => x.employee.id === (this.employee as Employee).id);
|
||||
if (oldFiltered.length) {
|
||||
this.toaster.show('Danger', 'Employee has already been added');
|
||||
this.snackBar.open('Employee has already been added', 'Danger');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -239,9 +246,7 @@ export class EmployeeBenefitsComponent implements OnInit, AfterViewInit {
|
||||
this.form.controls.addRow.reset();
|
||||
this.employee = null;
|
||||
setTimeout(() => {
|
||||
if (this.employeeElement) {
|
||||
this.employeeElement.nativeElement.focus();
|
||||
}
|
||||
this.employeeElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -264,10 +269,10 @@ export class EmployeeBenefitsComponent implements OnInit, AfterViewInit {
|
||||
this.ser.post(this.voucher.id as string).subscribe({
|
||||
next: (result) => {
|
||||
this.loadVoucher(result);
|
||||
this.toaster.show('Success', 'Voucher Posted');
|
||||
this.snackBar.open('Voucher Posted', 'Success');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -276,7 +281,7 @@ export class EmployeeBenefitsComponent implements OnInit, AfterViewInit {
|
||||
const voucher: Voucher = this.getVoucher();
|
||||
this.ser.saveOrUpdate(voucher).subscribe({
|
||||
next: (result) => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
if (voucher.id === result.id) {
|
||||
this.loadVoucher(result);
|
||||
} else {
|
||||
@@ -284,7 +289,7 @@ export class EmployeeBenefitsComponent implements OnInit, AfterViewInit {
|
||||
}
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -298,11 +303,11 @@ export class EmployeeBenefitsComponent implements OnInit, AfterViewInit {
|
||||
delete() {
|
||||
this.ser.delete(this.voucher.id as string).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigate(['/employee-benefits'], { replaceUrl: true });
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,13 +6,7 @@
|
||||
<div class="flex flex-row justify-around content-start items-start sm:max-lg:flex-col">
|
||||
<mat-form-field class="flex-auto basis-4/5 mr-5">
|
||||
<mat-label>Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="creditSalaryMonth"
|
||||
(focus)="creditSalaryMonth.open()"
|
||||
formControlName="date"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<input matInput [matDatepicker]="creditSalaryMonth" formControlName="date" autocomplete="off" />
|
||||
<mat-datepicker-toggle matSuffix [for]="creditSalaryMonth"></mat-datepicker-toggle>
|
||||
<mat-datepicker
|
||||
#creditSalaryMonth
|
||||
@@ -39,25 +33,13 @@
|
||||
>
|
||||
<mat-form-field class="flex-auto basis-[35%] mr-5">
|
||||
<mat-label>Start Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="attendanceStartDate"
|
||||
(focus)="attendanceStartDate.open()"
|
||||
formControlName="startDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<input matInput [matDatepicker]="attendanceStartDate" formControlName="startDate" autocomplete="off" />
|
||||
<mat-datepicker-toggle matSuffix [for]="attendanceStartDate"></mat-datepicker-toggle>
|
||||
<mat-datepicker #attendanceStartDate></mat-datepicker>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="flex-auto basis-[35%] mr-5">
|
||||
<mat-label>Finish Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="attendanceFinishDate"
|
||||
(focus)="attendanceFinishDate.open()"
|
||||
formControlName="finishDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<input matInput [matDatepicker]="attendanceFinishDate" formControlName="finishDate" autocomplete="off" />
|
||||
<mat-datepicker-toggle matSuffix [for]="attendanceFinishDate"></mat-datepicker-toggle>
|
||||
<mat-datepicker #attendanceFinishDate></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -9,7 +9,7 @@ import { MatTabGroup, MatTab } from '@angular/material/tabs';
|
||||
import moment from 'moment';
|
||||
import { Moment } from 'moment';
|
||||
|
||||
import { ToasterService } from '../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
import { EmployeeFunctionsService } from './employee-functions.service';
|
||||
|
||||
@@ -48,7 +48,7 @@ export class EmployeeFunctionsComponent {
|
||||
fingerprintFile: File | null = null;
|
||||
|
||||
constructor(
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
private ser: EmployeeFunctionsService,
|
||||
) {
|
||||
const startDate = moment().date(1);
|
||||
@@ -80,15 +80,15 @@ export class EmployeeFunctionsComponent {
|
||||
creditSalary() {
|
||||
const date = (this.creditSalaryForm.value.date ?? moment()).format('DD-MMM-YYYY');
|
||||
if (!date) {
|
||||
this.toaster.show('Danger', 'Please choose a valid date.');
|
||||
this.snackBar.open('Please choose a valid date.', 'Danger');
|
||||
return;
|
||||
}
|
||||
this.ser.creditSalary(date).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', 'Salaries Credited');
|
||||
this.snackBar.open('Salaries Credited', 'Success');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -97,7 +97,7 @@ export class EmployeeFunctionsComponent {
|
||||
const startDate = (this.attendanceRecordForm.value.startDate ?? moment()).format('DD-MMM-YYYY');
|
||||
const finishDate = (this.attendanceRecordForm.value.finishDate ?? moment()).format('DD-MMM-YYYY');
|
||||
if (!startDate || !finishDate) {
|
||||
// this.toaster.show('Danger', 'Please choose a start and finish date.');
|
||||
// this.snackBar.open('Please choose a start and finish date.', 'Danger');
|
||||
return '';
|
||||
}
|
||||
return `/attendance-report?s=${startDate}&f=${finishDate}`;
|
||||
@@ -107,7 +107,7 @@ export class EmployeeFunctionsComponent {
|
||||
const startDate = (this.attendanceRecordForm.value.startDate ?? moment()).format('DD-MMM-YYYY');
|
||||
const finishDate = (this.attendanceRecordForm.value.finishDate ?? moment()).format('DD-MMM-YYYY');
|
||||
if (!startDate || !finishDate) {
|
||||
// this.toaster.show('Danger', 'Please choose a start and finish date.');
|
||||
// this.snackBar.open('Please choose a start and finish date.', 'Danger');
|
||||
return '';
|
||||
}
|
||||
return `/fingerprint-report?s=${startDate}&f=${finishDate}`;
|
||||
@@ -119,15 +119,15 @@ export class EmployeeFunctionsComponent {
|
||||
|
||||
uploadFingerprints() {
|
||||
if (!this.fingerprintFile) {
|
||||
this.toaster.show('Danger', 'Please choose a file first!');
|
||||
this.snackBar.open('Please choose a file first!', 'Danger');
|
||||
return;
|
||||
}
|
||||
this.ser.uploadFingerprints(this.fingerprintFile).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', 'Fingerprints uploaded');
|
||||
this.snackBar.open('Fingerprints uploaded', 'Success');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -56,26 +56,14 @@
|
||||
</div>
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Joining Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="joiningDate"
|
||||
(focus)="joiningDate.open()"
|
||||
formControlName="joiningDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<input matInput [matDatepicker]="joiningDate" formControlName="joiningDate" autocomplete="off" />
|
||||
<mat-datepicker-toggle matSuffix [for]="joiningDate"></mat-datepicker-toggle>
|
||||
<mat-datepicker #joiningDate></mat-datepicker>
|
||||
</mat-form-field>
|
||||
@if (!item.isActive) {
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Leaving Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="leavingDate"
|
||||
(focus)="leavingDate.open()"
|
||||
formControlName="leavingDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<input matInput [matDatepicker]="leavingDate" formControlName="leavingDate" autocomplete="off" />
|
||||
<mat-datepicker-toggle matSuffix [for]="leavingDate"></mat-datepicker-toggle>
|
||||
<mat-datepicker #leavingDate></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -21,7 +21,7 @@ import { ActivatedRoute, Router } from '@angular/router';
|
||||
import moment from 'moment';
|
||||
|
||||
import { CostCentre } from '../../core/cost-centre';
|
||||
import { ToasterService } from '../../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||
import { Employee } from '../employee';
|
||||
import { EmployeeService } from '../employee.service';
|
||||
@@ -54,7 +54,7 @@ import { EmployeeService } from '../employee.service';
|
||||
],
|
||||
})
|
||||
export class EmployeeDetailComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
@ViewChild('nameElement', { static: true }) nameElement!: ElementRef<HTMLInputElement>;
|
||||
form: FormGroup<{
|
||||
code: FormControl<string | number>;
|
||||
name: FormControl<string | null>;
|
||||
@@ -74,7 +74,7 @@ export class EmployeeDetailComponent implements OnInit, AfterViewInit {
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
private ser: EmployeeService,
|
||||
) {
|
||||
this.form = new FormGroup({
|
||||
@@ -120,20 +120,18 @@ export class EmployeeDetailComponent implements OnInit, AfterViewInit {
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
this.nameElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
save() {
|
||||
this.ser.saveOrUpdate(this.getItem()).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/employees');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -141,11 +139,11 @@ export class EmployeeDetailComponent implements OnInit, AfterViewInit {
|
||||
delete() {
|
||||
this.ser.delete(this.item.id as string).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/employees');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -67,9 +67,9 @@ import { EmployeeListDataSource } from './employee-list-datasource';
|
||||
],
|
||||
})
|
||||
export class EmployeeListComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('filterElement', { static: true }) filterElement?: ElementRef;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild('filterElement', { static: true }) filterElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
dataSource: EmployeeListDataSource;
|
||||
filter: Observable<string>;
|
||||
form: FormGroup<{
|
||||
@@ -89,7 +89,7 @@ export class EmployeeListComponent implements OnInit, AfterViewInit {
|
||||
filter: new FormControl<string>('', { nonNullable: true }),
|
||||
});
|
||||
this.filter = this.form.controls.filter.valueChanges.pipe(debounceTime(150), distinctUntilChanged());
|
||||
this.dataSource = new EmployeeListDataSource(this.list, this.filter);
|
||||
this.dataSource = new EmployeeListDataSource(this.list, this.filter, this.paginator, this.sort);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -103,9 +103,7 @@ export class EmployeeListComponent implements OnInit, AfterViewInit {
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.filterElement) {
|
||||
this.filterElement.nativeElement.focus();
|
||||
}
|
||||
this.filterElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,13 @@
|
||||
<div class="flex flex-row justify-around content-start items-start sm:max-lg:flex-col">
|
||||
<mat-form-field class="flex-auto basis-2/5 mr-5">
|
||||
<mat-label>Create / Last Edit Date From</mat-label>
|
||||
<input matInput [matDatepicker]="startDate" formControlName="startDate" autocomplete="off" />
|
||||
<input
|
||||
matInput
|
||||
#startDateElement
|
||||
[matDatepicker]="startDate"
|
||||
formControlName="startDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
|
||||
<mat-datepicker #startDate></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CurrencyPipe } from '@angular/common';
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButton } from '@angular/material/button';
|
||||
import { MatCard, MatCardHeader, MatCardTitle, MatCardContent } from '@angular/material/card';
|
||||
@@ -73,10 +73,11 @@ import { Report } from './report';
|
||||
],
|
||||
})
|
||||
export class EntriesComponent implements OnInit {
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
@ViewChild('startDateElement', { static: true }) startDate!: ElementRef<HTMLInputElement>;
|
||||
info: Report = new Report();
|
||||
dataSource: EntriesDatasource = new EntriesDatasource(this.info.report, 0);
|
||||
dataSource: EntriesDatasource;
|
||||
form: FormGroup<{
|
||||
startDate: FormControl<Date>;
|
||||
finishDate: FormControl<Date>;
|
||||
@@ -88,6 +89,14 @@ export class EntriesComponent implements OnInit {
|
||||
|
||||
posted: boolean | null = null;
|
||||
issue = false;
|
||||
|
||||
@HostListener('window:keydown.f2', ['$event'])
|
||||
focusDate(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.startDate.nativeElement.focus();
|
||||
this.startDate.nativeElement.select();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
@@ -98,6 +107,7 @@ export class EntriesComponent implements OnInit {
|
||||
posted: new FormControl<boolean | null>(null),
|
||||
issue: new FormControl<boolean>(false, { nonNullable: true }),
|
||||
});
|
||||
this.dataSource = new EntriesDatasource(this.info.report, 0, this.paginator, this.sort);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -141,7 +151,7 @@ export class EntriesComponent implements OnInit {
|
||||
sortDirection,
|
||||
);
|
||||
});
|
||||
this.sort?.sortChange.subscribe({
|
||||
this.sort.sortChange.subscribe({
|
||||
next: () =>
|
||||
this.router.navigate([], {
|
||||
relativeTo: this.route,
|
||||
@@ -149,11 +159,11 @@ export class EntriesComponent implements OnInit {
|
||||
queryParamsHandling: 'merge',
|
||||
}),
|
||||
});
|
||||
this.paginator?.page.subscribe({
|
||||
this.paginator.page.subscribe({
|
||||
next: () =>
|
||||
this.router.navigate([], {
|
||||
relativeTo: this.route,
|
||||
queryParams: { ps: this.paginator?.pageSize, pi: this.paginator?.pageIndex },
|
||||
queryParams: { ps: this.paginator.pageSize, pi: this.paginator.pageIndex },
|
||||
queryParamsHandling: 'merge',
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -7,7 +7,14 @@
|
||||
<div class="flex flex-row justify-around content-start items-start">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Date</mat-label>
|
||||
<input matInput [matDatepicker]="date" (focus)="date.open()" formControlName="date" autocomplete="off" />
|
||||
<input
|
||||
matInput
|
||||
#dateElement
|
||||
[matDatepicker]="date"
|
||||
(focus)="dateElement.select()"
|
||||
formControlName="date"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
|
||||
<mat-datepicker #date></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -36,7 +36,7 @@ import { AuthService } from '../auth/auth.service';
|
||||
import { Account } from '../core/account';
|
||||
import { AccountBalance } from '../core/account-balance';
|
||||
import { Incentive } from '../core/incentive';
|
||||
import { ToasterService } from '../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { User } from '../core/user';
|
||||
import { Voucher } from '../core/voucher';
|
||||
import { VoucherService } from '../core/voucher.service';
|
||||
@@ -44,6 +44,9 @@ import { ConfirmDialogComponent } from '../shared/confirm-dialog/confirm-dialog.
|
||||
import { LocalTimePipe } from '../shared/local-time.pipe';
|
||||
|
||||
import { IncentiveDataSource } from './incentive-datasource';
|
||||
import { ViewChild } from '@angular/core';
|
||||
import { ElementRef } from '@angular/core';
|
||||
import { HostListener } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-incentive',
|
||||
@@ -85,6 +88,7 @@ import { IncentiveDataSource } from './incentive-datasource';
|
||||
],
|
||||
})
|
||||
export class IncentiveComponent implements OnInit {
|
||||
@ViewChild('dateElement', { static: true }) dateElement!: ElementRef<HTMLInputElement>;
|
||||
public incentiveObservable = new BehaviorSubject<Incentive[]>([]);
|
||||
dataSource: IncentiveDataSource = new IncentiveDataSource(this.incentiveObservable);
|
||||
form: FormGroup<{
|
||||
@@ -102,11 +106,18 @@ export class IncentiveComponent implements OnInit {
|
||||
|
||||
displayedColumns = ['name', 'designation', 'department', 'daysWorked', 'points', 'amount'];
|
||||
|
||||
@HostListener('window:keydown.f2', ['$event'])
|
||||
focusDate(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.dateElement.nativeElement.focus();
|
||||
this.dateElement.nativeElement.select();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
public auth: AuthService,
|
||||
private ser: VoucherService,
|
||||
) {
|
||||
@@ -193,10 +204,10 @@ export class IncentiveComponent implements OnInit {
|
||||
this.ser.post(this.voucher.id as string).subscribe({
|
||||
next: (result) => {
|
||||
this.loadVoucher(result);
|
||||
this.toaster.show('Success', 'Voucher Posted');
|
||||
this.snackBar.open('Voucher Posted', 'Success');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -212,7 +223,7 @@ export class IncentiveComponent implements OnInit {
|
||||
}
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -231,11 +242,11 @@ export class IncentiveComponent implements OnInit {
|
||||
delete() {
|
||||
this.ser.delete(this.voucher.id as string).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigate(['/incentive'], { replaceUrl: true });
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,14 +7,7 @@
|
||||
<div class="flex flex-row justify-around content-start items-start sm:max-lg:flex-col">
|
||||
<mat-form-field class="flex-auto basis-[28%] mr-5">
|
||||
<mat-label>Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="date"
|
||||
formControlName="date"
|
||||
autocomplete="off"
|
||||
#dateElement
|
||||
(focus)="dateElement.select()"
|
||||
/>
|
||||
<input matInput [matDatepicker]="date" formControlName="date" autocomplete="off" #dateElement />
|
||||
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
|
||||
<mat-datepicker #date></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AsyncPipe, DecimalPipe, CurrencyPipe } from '@angular/common';
|
||||
import { AfterViewInit, Component, ElementRef, OnInit, OnDestroy, ViewChild } from '@angular/core';
|
||||
import { AfterViewInit, Component, ElementRef, OnInit, ViewChild, HostListener } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatAutocompleteSelectedEvent, MatAutocompleteTrigger, MatAutocomplete } from '@angular/material/autocomplete';
|
||||
import { MatButton, MatIconButton } from '@angular/material/button';
|
||||
@@ -32,7 +32,6 @@ import {
|
||||
MatRow,
|
||||
} from '@angular/material/table';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Hotkey, HotkeysService } from 'angular2-hotkeys';
|
||||
import { round } from 'mathjs';
|
||||
import moment from 'moment';
|
||||
import { BehaviorSubject, Observable, of as observableOf } from 'rxjs';
|
||||
@@ -44,7 +43,7 @@ import { BatchService } from '../core/batch.service';
|
||||
import { CostCentre } from '../core/cost-centre';
|
||||
import { Inventory } from '../core/inventory';
|
||||
import { IssueGridItem } from '../core/issue-grid-item';
|
||||
import { ToasterService } from '../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { User } from '../core/user';
|
||||
import { Voucher } from '../core/voucher';
|
||||
import { VoucherService } from '../core/voucher.service';
|
||||
@@ -102,9 +101,25 @@ import { IssueGridService } from './issue-grid.service';
|
||||
LocalTimePipe,
|
||||
],
|
||||
})
|
||||
export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
@ViewChild('batchElement', { static: true }) batchElement?: ElementRef;
|
||||
@ViewChild('dateElement', { static: true }) dateElement?: ElementRef;
|
||||
export class IssueComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('batchElement', { static: true }) batchElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('dateElement', { static: true }) dateElement!: ElementRef<HTMLInputElement>;
|
||||
|
||||
@HostListener('window:keydown.f2', ['$event'])
|
||||
focusDate(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.dateElement.nativeElement.focus();
|
||||
this.dateElement.nativeElement.select();
|
||||
}
|
||||
|
||||
@HostListener('window:keydown.control.s', ['$event'])
|
||||
saveListner(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
if (this.canSave()) {
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
|
||||
public inventoryObservable = new BehaviorSubject<Inventory[]>([]);
|
||||
public gridObservable = new BehaviorSubject<IssueGridItem[]>([]);
|
||||
dataSource: IssueDataSource = new IssueDataSource(this.inventoryObservable);
|
||||
@@ -134,8 +149,7 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
private hotkeys: HotkeysService,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
private auth: AuthService,
|
||||
private math: MathService,
|
||||
private ser: VoucherService,
|
||||
@@ -177,42 +191,12 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.costCentres = data.costCentres;
|
||||
this.loadVoucher(data.voucher);
|
||||
});
|
||||
this.hotkeys.add(
|
||||
new Hotkey(
|
||||
'f2',
|
||||
(): boolean => {
|
||||
setTimeout(() => {
|
||||
if (this.dateElement) {
|
||||
this.dateElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
return false; // Prevent bubbling
|
||||
},
|
||||
['INPUT', 'SELECT', 'TEXTAREA'],
|
||||
),
|
||||
);
|
||||
this.hotkeys.add(
|
||||
new Hotkey(
|
||||
'ctrl+s',
|
||||
(): boolean => {
|
||||
if (this.canSave()) {
|
||||
this.save();
|
||||
}
|
||||
return false; // Prevent bubbling
|
||||
},
|
||||
['INPUT', 'SELECT', 'TEXTAREA'],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.focusBatch();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.hotkeys.reset();
|
||||
}
|
||||
|
||||
loadVoucher(voucher: Voucher) {
|
||||
this.voucher = voucher;
|
||||
this.form.setValue({
|
||||
@@ -232,9 +216,7 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
focusBatch() {
|
||||
setTimeout(() => {
|
||||
if (this.batchElement) {
|
||||
this.batchElement.nativeElement.focus();
|
||||
}
|
||||
this.batchElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -251,13 +233,13 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
const old = this.voucher.inventories.find((x) => x.batch.id === (this.batch as Batch).id);
|
||||
if (old !== undefined) {
|
||||
if (isConsumption && old.quantity + quantity > this.batch.quantityRemaining) {
|
||||
this.toaster.show('Danger', 'Quantity issued cannot be more than quantity available');
|
||||
this.snackBar.open('Quantity issued cannot be more than quantity available', 'Danger');
|
||||
return;
|
||||
}
|
||||
old.quantity += quantity;
|
||||
} else {
|
||||
if (isConsumption && quantity > this.batch.quantityRemaining) {
|
||||
this.toaster.show('Danger', 'Quantity issued cannot be more than quantity available');
|
||||
this.snackBar.open('Quantity issued cannot be more than quantity available', 'Danger');
|
||||
return;
|
||||
}
|
||||
this.voucher.inventories.push(
|
||||
@@ -279,9 +261,7 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.form.controls.addRow.reset();
|
||||
this.batch = null;
|
||||
setTimeout(() => {
|
||||
if (this.batchElement) {
|
||||
this.batchElement.nativeElement.focus();
|
||||
}
|
||||
this.batchElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -335,7 +315,7 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
const voucher: Voucher = this.getVoucher();
|
||||
this.ser.saveOrUpdate(voucher).subscribe({
|
||||
next: (result) => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
if (voucher.id === result.id) {
|
||||
this.loadVoucher(result);
|
||||
} else {
|
||||
@@ -343,7 +323,7 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -364,11 +344,11 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
delete() {
|
||||
this.ser.delete(this.voucher.id as string).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigate(['/issue'], { replaceUrl: true });
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -17,14 +17,7 @@
|
||||
<div class="flex flex-row justify-around content-start items-start">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="date"
|
||||
formControlName="date"
|
||||
autocomplete="off"
|
||||
#dateElement
|
||||
(focus)="dateElement.select()"
|
||||
/>
|
||||
<input matInput [matDatepicker]="date" formControlName="date" autocomplete="off" #dateElement />
|
||||
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
|
||||
<mat-datepicker #date></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { COMMA, ENTER } from '@angular/cdk/keycodes';
|
||||
import { AsyncPipe, CurrencyPipe } from '@angular/common';
|
||||
import { AfterViewInit, Component, ElementRef, OnInit, OnDestroy, ViewChild } from '@angular/core';
|
||||
import { AfterViewInit, Component, ElementRef, OnInit, ViewChild, HostListener } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatAutocompleteSelectedEvent, MatAutocompleteTrigger, MatAutocomplete } from '@angular/material/autocomplete';
|
||||
import { MatButton, MatIconButton } from '@angular/material/button';
|
||||
@@ -34,7 +34,6 @@ import {
|
||||
MatRow,
|
||||
} from '@angular/material/table';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Hotkey, HotkeysService } from 'angular2-hotkeys';
|
||||
import { round } from 'mathjs';
|
||||
import moment from 'moment';
|
||||
import { BehaviorSubject, Observable, of as observableOf } from 'rxjs';
|
||||
@@ -48,7 +47,7 @@ import { DbFile } from '../core/db-file';
|
||||
import { Journal } from '../core/journal';
|
||||
import { Tag } from '../core/tag';
|
||||
import { TagService } from '../core/tag.service';
|
||||
import { ToasterService } from '../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { User } from '../core/user';
|
||||
import { Voucher } from '../core/voucher';
|
||||
import { VoucherService } from '../core/voucher.service';
|
||||
@@ -112,10 +111,34 @@ import { JournalDialogComponent } from './journal-dialog.component';
|
||||
LocalTimePipe,
|
||||
],
|
||||
})
|
||||
export class JournalComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
@ViewChild('accountElement', { static: true }) accountElement?: ElementRef;
|
||||
@ViewChild('dateElement', { static: true }) dateElement?: ElementRef;
|
||||
export class JournalComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('accountElement', { static: true }) accountElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('dateElement', { static: false }) dateElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('tagInput') tagInput?: ElementRef<HTMLInputElement>;
|
||||
|
||||
@HostListener('window:keydown.f2', ['$event'])
|
||||
focusDate(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.dateElement.nativeElement.focus();
|
||||
this.dateElement.nativeElement.select();
|
||||
}
|
||||
|
||||
@HostListener('window:keydown.control.s', ['$event'])
|
||||
saveListner(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
if (this.canSave()) {
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('window:keydown.control.p', ['$event'])
|
||||
postListner(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
if (this.voucher.id && !this.voucher.posted && this.auth.allowed('post-vouchers')) {
|
||||
this.post();
|
||||
}
|
||||
}
|
||||
|
||||
separatorKeysCodes: number[] = [ENTER, COMMA];
|
||||
public journalObservable = new BehaviorSubject<Journal[]>([]);
|
||||
dataSource: JournalDataSource = new JournalDataSource(this.journalObservable);
|
||||
@@ -143,8 +166,7 @@ export class JournalComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
private hotkeys: HotkeysService,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
public auth: AuthService,
|
||||
private math: MathService,
|
||||
public image: ImageService,
|
||||
@@ -184,54 +206,12 @@ export class JournalComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
this.loadVoucher(data.voucher);
|
||||
});
|
||||
this.hotkeys.add(
|
||||
new Hotkey(
|
||||
'f2',
|
||||
(): boolean => {
|
||||
setTimeout(() => {
|
||||
if (this.dateElement) {
|
||||
this.dateElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
return false; // Prevent bubbling
|
||||
},
|
||||
['INPUT', 'SELECT', 'TEXTAREA'],
|
||||
),
|
||||
);
|
||||
this.hotkeys.add(
|
||||
new Hotkey(
|
||||
'ctrl+s',
|
||||
(): boolean => {
|
||||
if (this.canSave()) {
|
||||
this.save();
|
||||
}
|
||||
return false; // Prevent bubbling
|
||||
},
|
||||
['INPUT', 'SELECT', 'TEXTAREA'],
|
||||
),
|
||||
);
|
||||
this.hotkeys.add(
|
||||
new Hotkey(
|
||||
'ctrl+p',
|
||||
(): boolean => {
|
||||
if (this.voucher.id && !this.voucher.posted && this.auth.allowed('post-vouchers')) {
|
||||
this.post();
|
||||
}
|
||||
return false; // Prevent bubbling
|
||||
},
|
||||
['INPUT', 'SELECT', 'TEXTAREA'],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.focusAccount();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.hotkeys.reset();
|
||||
}
|
||||
|
||||
loadVoucher(voucher: Voucher) {
|
||||
this.voucher = voucher;
|
||||
this.form.setValue({
|
||||
@@ -250,9 +230,7 @@ export class JournalComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
focusAccount() {
|
||||
setTimeout(() => {
|
||||
if (this.accountElement) {
|
||||
this.accountElement.nativeElement.focus();
|
||||
}
|
||||
this.accountElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -295,9 +273,7 @@ export class JournalComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.account = null;
|
||||
this.accBal = null;
|
||||
setTimeout(() => {
|
||||
if (this.accountElement) {
|
||||
this.accountElement.nativeElement.focus();
|
||||
}
|
||||
this.accountElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -350,10 +326,10 @@ export class JournalComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.ser.post(this.voucher.id as string).subscribe({
|
||||
next: (result) => {
|
||||
this.loadVoucher(result);
|
||||
this.toaster.show('Success', 'Voucher Posted');
|
||||
this.snackBar.open('Voucher Posted', 'Success');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -362,7 +338,7 @@ export class JournalComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
const voucher: Voucher = this.getVoucher();
|
||||
this.ser.saveOrUpdate(voucher).subscribe({
|
||||
next: (result) => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
if (voucher.id === result.id) {
|
||||
this.loadVoucher(result);
|
||||
} else {
|
||||
@@ -370,7 +346,7 @@ export class JournalComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -385,11 +361,11 @@ export class JournalComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
delete() {
|
||||
this.ser.delete(this.voucher.id as string).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigate(['/journal'], { replaceUrl: true });
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
<mat-label>Start Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
#startDateElement
|
||||
[matDatepicker]="startDate"
|
||||
(focus)="startDate.open()"
|
||||
formControlName="startDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
@@ -26,13 +26,7 @@
|
||||
</mat-form-field>
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Finish Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="finishDate"
|
||||
(focus)="finishDate.open()"
|
||||
formControlName="finishDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<input matInput [matDatepicker]="finishDate" formControlName="finishDate" autocomplete="off" />
|
||||
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
|
||||
<mat-datepicker #finishDate></mat-datepicker>
|
||||
</mat-form-field>
|
||||
@@ -109,7 +103,7 @@
|
||||
|
||||
<!-- Running Column -->
|
||||
<ng-container matColumnDef="running">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header class="right">Running</mat-header-cell>
|
||||
<mat-header-cell *matHeaderCellDef class="right">Running</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" class="right">{{ row.running | currency: 'INR' | accounting }}</mat-cell>
|
||||
<mat-footer-cell *matFooterCellDef class="right">{{ running | currency: 'INR' | accounting }}</mat-footer-cell>
|
||||
</ng-container>
|
||||
|
||||
@@ -92,9 +92,10 @@ import { LedgerService } from './ledger.service';
|
||||
],
|
||||
})
|
||||
export class LedgerComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('accountElement', { static: true }) accountElement?: ElementRef;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild('accountElement', { static: true }) accountElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('startDateElement', { static: true }) startDate!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
info: Ledger = new Ledger();
|
||||
dataSource: LedgerDataSource = new LedgerDataSource(this.info.body);
|
||||
form: FormGroup<{
|
||||
@@ -112,6 +113,13 @@ export class LedgerComponent implements OnInit, AfterViewInit {
|
||||
|
||||
accounts: Observable<Account[]>;
|
||||
|
||||
@HostListener('window:keydown.f2', ['$event'])
|
||||
focusDate(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.startDate.nativeElement.focus();
|
||||
this.startDate.nativeElement.select();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
<mat-label>Start Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
#startDateElement
|
||||
[matDatepicker]="startDate"
|
||||
(focus)="startDate.open()"
|
||||
formControlName="startDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
@@ -19,13 +19,7 @@
|
||||
</mat-form-field>
|
||||
<mat-form-field class="flex-auto basis-2/5 mr-5">
|
||||
<mat-label>Finish Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="finishDate"
|
||||
(focus)="finishDate.open()"
|
||||
formControlName="finishDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<input matInput [matDatepicker]="finishDate" formControlName="finishDate" autocomplete="off" />
|
||||
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
|
||||
<mat-datepicker #finishDate></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CurrencyPipe } from '@angular/common';
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButton } from '@angular/material/button';
|
||||
import { MatCard, MatCardHeader, MatCardTitle, MatCardContent } from '@angular/material/card';
|
||||
@@ -65,10 +65,11 @@ import { NetTransactionsDataSource } from './net-transactions-datasource';
|
||||
],
|
||||
})
|
||||
export class NetTransactionsComponent implements OnInit {
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
@ViewChild('startDateElement', { static: true }) startDate!: ElementRef<HTMLInputElement>;
|
||||
info: NetTransactions = new NetTransactions();
|
||||
dataSource: NetTransactionsDataSource = new NetTransactionsDataSource(this.info.body);
|
||||
dataSource: NetTransactionsDataSource = new NetTransactionsDataSource(this.info.body, this.paginator, this.sort);
|
||||
form: FormGroup<{
|
||||
startDate: FormControl<Date>;
|
||||
finishDate: FormControl<Date>;
|
||||
@@ -78,6 +79,13 @@ export class NetTransactionsComponent implements OnInit {
|
||||
/** 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: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.startDate.nativeElement.focus();
|
||||
this.startDate.nativeElement.select();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
|
||||
@@ -17,14 +17,7 @@
|
||||
<div class="flex flex-row justify-around content-start items-start sm:max-lg:flex-col">
|
||||
<mat-form-field class="flex-auto basis-2/5 mr-5">
|
||||
<mat-label>Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="date"
|
||||
formControlName="date"
|
||||
autocomplete="off"
|
||||
#dateElement
|
||||
(focus)="dateElement.select()"
|
||||
/>
|
||||
<input matInput [matDatepicker]="date" formControlName="date" autocomplete="off" #dateElement />
|
||||
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
|
||||
<mat-datepicker #date></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { COMMA, ENTER } from '@angular/cdk/keycodes';
|
||||
import { AsyncPipe, CurrencyPipe } from '@angular/common';
|
||||
import { AfterViewInit, Component, ElementRef, OnInit, OnDestroy, ViewChild } from '@angular/core';
|
||||
import { AfterViewInit, Component, ElementRef, OnInit, ViewChild, HostListener } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatAutocompleteSelectedEvent, MatAutocompleteTrigger, MatAutocomplete } from '@angular/material/autocomplete';
|
||||
import { MatButton, MatIconButton } from '@angular/material/button';
|
||||
@@ -34,7 +34,6 @@ import {
|
||||
MatRow,
|
||||
} from '@angular/material/table';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Hotkey, HotkeysService } from 'angular2-hotkeys';
|
||||
import { round } from 'mathjs';
|
||||
import moment from 'moment';
|
||||
import { BehaviorSubject, Observable, of as observableOf } from 'rxjs';
|
||||
@@ -48,7 +47,7 @@ import { DbFile } from '../core/db-file';
|
||||
import { Journal } from '../core/journal';
|
||||
import { Tag } from '../core/tag';
|
||||
import { TagService } from '../core/tag.service';
|
||||
import { ToasterService } from '../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { User } from '../core/user';
|
||||
import { Voucher } from '../core/voucher';
|
||||
import { VoucherService } from '../core/voucher.service';
|
||||
@@ -112,10 +111,34 @@ import { PaymentDialogComponent } from './payment-dialog.component';
|
||||
LocalTimePipe,
|
||||
],
|
||||
})
|
||||
export class PaymentComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
@ViewChild('accountElement', { static: true }) accountElement?: ElementRef;
|
||||
@ViewChild('dateElement', { static: true }) dateElement?: ElementRef;
|
||||
export class PaymentComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('accountElement', { static: true }) accountElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('dateElement', { static: true }) dateElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('tagInput') tagInput?: ElementRef<HTMLInputElement>;
|
||||
|
||||
@HostListener('window:keydown.f2', ['$event'])
|
||||
focusDate(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.dateElement.nativeElement.focus();
|
||||
this.dateElement.nativeElement.select();
|
||||
}
|
||||
|
||||
@HostListener('window:keydown.control.s', ['$event'])
|
||||
saveListner(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
if (this.canSave()) {
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('window:keydown.control.p', ['$event'])
|
||||
postListner(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
if (this.voucher.id && !this.voucher.posted && this.auth.allowed('post-vouchers')) {
|
||||
this.post();
|
||||
}
|
||||
}
|
||||
|
||||
separatorKeysCodes: number[] = [ENTER, COMMA];
|
||||
public journalObservable = new BehaviorSubject<Journal[]>([]);
|
||||
dataSource: PaymentDataSource = new PaymentDataSource(this.journalObservable);
|
||||
@@ -146,8 +169,7 @@ export class PaymentComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
private hotkeys: HotkeysService,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
public auth: AuthService,
|
||||
private math: MathService,
|
||||
public image: ImageService,
|
||||
@@ -197,54 +219,12 @@ export class PaymentComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.paymentAccounts = data.paymentAccounts;
|
||||
this.loadVoucher(data.voucher);
|
||||
});
|
||||
this.hotkeys.add(
|
||||
new Hotkey(
|
||||
'f2',
|
||||
(): boolean => {
|
||||
setTimeout(() => {
|
||||
if (this.dateElement) {
|
||||
this.dateElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
return false; // Prevent bubbling
|
||||
},
|
||||
['INPUT', 'SELECT', 'TEXTAREA'],
|
||||
),
|
||||
);
|
||||
this.hotkeys.add(
|
||||
new Hotkey(
|
||||
'ctrl+s',
|
||||
(): boolean => {
|
||||
if (this.canSave()) {
|
||||
this.save();
|
||||
}
|
||||
return false; // Prevent bubbling
|
||||
},
|
||||
['INPUT', 'SELECT', 'TEXTAREA'],
|
||||
),
|
||||
);
|
||||
this.hotkeys.add(
|
||||
new Hotkey(
|
||||
'ctrl+p',
|
||||
(): boolean => {
|
||||
if (this.voucher.id && !this.voucher.posted && this.auth.allowed('post-vouchers')) {
|
||||
this.post();
|
||||
}
|
||||
return false; // Prevent bubbling
|
||||
},
|
||||
['INPUT', 'SELECT', 'TEXTAREA'],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.focusAccount();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.hotkeys.reset();
|
||||
}
|
||||
|
||||
loadVoucher(voucher: Voucher) {
|
||||
this.voucher = voucher;
|
||||
[this.paymentJournal] = this.voucher.journals.filter((x) => x.debit === -1);
|
||||
@@ -265,9 +245,7 @@ export class PaymentComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
focusAccount() {
|
||||
setTimeout(() => {
|
||||
if (this.accountElement) {
|
||||
this.accountElement.nativeElement.focus();
|
||||
}
|
||||
this.accountElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -303,9 +281,7 @@ export class PaymentComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.account = null;
|
||||
this.accBal = null;
|
||||
setTimeout(() => {
|
||||
if (this.accountElement) {
|
||||
this.accountElement.nativeElement.focus();
|
||||
}
|
||||
this.accountElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -360,10 +336,10 @@ export class PaymentComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.ser.post(this.voucher.id as string).subscribe({
|
||||
next: (result) => {
|
||||
this.loadVoucher(result);
|
||||
this.toaster.show('Success', 'Voucher Posted');
|
||||
this.snackBar.open('Voucher Posted', 'Success');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -372,7 +348,7 @@ export class PaymentComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
const voucher: Voucher = this.getVoucher();
|
||||
this.ser.saveOrUpdate(voucher).subscribe({
|
||||
next: (result) => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
if (voucher.id === result.id) {
|
||||
this.loadVoucher(result);
|
||||
} else {
|
||||
@@ -380,7 +356,7 @@ export class PaymentComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -396,11 +372,11 @@ export class PaymentComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
delete() {
|
||||
this.ser.delete(this.voucher.id as string).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigate(['/payment'], { replaceUrl: true });
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,7 +7,13 @@
|
||||
<div class="flex flex-row justify-around content-start items-start">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Valid From</mat-label>
|
||||
<input matInput [matDatepicker]="validFrom" formControlName="validFrom" autocomplete="off" />
|
||||
<input
|
||||
matInput
|
||||
#validFromElement
|
||||
[matDatepicker]="validFrom"
|
||||
formControlName="validFrom"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<mat-datepicker-toggle matSuffix [for]="validFrom"></mat-datepicker-toggle>
|
||||
<mat-datepicker #validFrom></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButton } from '@angular/material/button';
|
||||
import { MatCard, MatCardHeader, MatCardTitle, MatCardContent, MatCardActions } from '@angular/material/card';
|
||||
@@ -9,7 +9,7 @@ import { MatInput } from '@angular/material/input';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import moment from 'moment';
|
||||
|
||||
import { ToasterService } from '../../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||
import { Period } from '../period';
|
||||
import { PeriodService } from '../period.service';
|
||||
@@ -37,6 +37,7 @@ import { PeriodService } from '../period.service';
|
||||
],
|
||||
})
|
||||
export class PeriodDetailComponent implements OnInit {
|
||||
@ViewChild('startDateElement', { static: true }) startDate!: ElementRef<HTMLInputElement>;
|
||||
form: FormGroup<{
|
||||
validFrom: FormControl<Date>;
|
||||
validTill: FormControl<Date>;
|
||||
@@ -44,11 +45,18 @@ export class PeriodDetailComponent implements OnInit {
|
||||
|
||||
item: Period = new Period();
|
||||
|
||||
@HostListener('window:keydown.f2', ['$event'])
|
||||
focusDate(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.startDate.nativeElement.focus();
|
||||
this.startDate.nativeElement.select();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
private ser: PeriodService,
|
||||
) {
|
||||
this.form = new FormGroup({
|
||||
@@ -76,11 +84,11 @@ export class PeriodDetailComponent implements OnInit {
|
||||
save() {
|
||||
this.ser.saveOrUpdate(this.getItem()).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/periods');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -88,11 +96,11 @@ export class PeriodDetailComponent implements OnInit {
|
||||
delete() {
|
||||
this.ser.delete(this.item.id as string).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/periods');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
+6
-8
@@ -8,7 +8,7 @@ import { MatInput } from '@angular/material/input';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
import { ProductGroup } from '../../core/product-group';
|
||||
import { ToasterService } from '../../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { ProductGroupService } from '../product-group.service';
|
||||
|
||||
@Component({
|
||||
@@ -31,7 +31,7 @@ import { ProductGroupService } from '../product-group.service';
|
||||
],
|
||||
})
|
||||
export class ProductGroupDetailComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
@ViewChild('nameElement', { static: true }) nameElement!: ElementRef<HTMLInputElement>;
|
||||
form: FormGroup<{
|
||||
name: FormControl<string | null>;
|
||||
nutritional: FormControl<boolean>;
|
||||
@@ -43,7 +43,7 @@ export class ProductGroupDetailComponent implements OnInit, AfterViewInit {
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
private ser: ProductGroupService,
|
||||
) {
|
||||
this.form = new FormGroup({
|
||||
@@ -72,20 +72,18 @@ export class ProductGroupDetailComponent implements OnInit, AfterViewInit {
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
this.nameElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
save() {
|
||||
this.ser.saveOrUpdate(this.getItem()).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/product-groups');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -52,10 +52,10 @@ import { ProductGroupListDataSource } from './product-group-list-datasource';
|
||||
],
|
||||
})
|
||||
export class ProductGroupListComponent implements OnInit {
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
list: ProductGroup[] = [];
|
||||
dataSource: ProductGroupListDataSource = new ProductGroupListDataSource(this.list);
|
||||
dataSource: ProductGroupListDataSource = new ProductGroupListDataSource(this.list, this.paginator, this.sort);
|
||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||
displayedColumns = ['name', 'isFixture'];
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
<mat-label>Start Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
#startDateElement
|
||||
[matDatepicker]="startDate"
|
||||
(focus)="startDate.open()"
|
||||
formControlName="startDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
@@ -26,13 +26,7 @@
|
||||
</mat-form-field>
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Finish Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="finishDate"
|
||||
(focus)="finishDate.open()"
|
||||
formControlName="finishDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<input matInput [matDatepicker]="finishDate" formControlName="finishDate" autocomplete="off" />
|
||||
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
|
||||
<mat-datepicker #finishDate></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AsyncPipe, DecimalPipe, CurrencyPipe } from '@angular/common';
|
||||
import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
||||
import { AfterViewInit, Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatAutocompleteSelectedEvent, MatAutocompleteTrigger, MatAutocomplete } from '@angular/material/autocomplete';
|
||||
import { MatIconButton, MatButton } from '@angular/material/button';
|
||||
@@ -90,11 +90,12 @@ import { ProductLedgerService } from './product-ledger.service';
|
||||
],
|
||||
})
|
||||
export class ProductLedgerComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('productElement', { static: true }) productElement?: ElementRef;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild('productElement', { static: true }) productElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
@ViewChild('startDateElement', { static: true }) startDate!: ElementRef<HTMLInputElement>;
|
||||
info: ProductLedger = new ProductLedger();
|
||||
dataSource: ProductLedgerDataSource = new ProductLedgerDataSource(this.info.body);
|
||||
dataSource: ProductLedgerDataSource = new ProductLedgerDataSource(this.info.body, this.paginator, this.sort);
|
||||
form: FormGroup<{
|
||||
startDate: FormControl<Date>;
|
||||
finishDate: FormControl<Date>;
|
||||
@@ -124,6 +125,13 @@ export class ProductLedgerComponent implements OnInit, AfterViewInit {
|
||||
|
||||
products: Observable<ProductSku[]>;
|
||||
|
||||
@HostListener('window:keydown.f2', ['$event'])
|
||||
focusDate(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.startDate.nativeElement.focus();
|
||||
this.startDate.nativeElement.select();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
@@ -161,9 +169,7 @@ export class ProductLedgerComponent implements OnInit, AfterViewInit {
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.productElement) {
|
||||
this.productElement.nativeElement.focus();
|
||||
}
|
||||
this.productElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
import { Product, StockKeepingUnit } from '../../core/product';
|
||||
import { ProductGroup } from '../../core/product-group';
|
||||
import { ToasterService } from '../../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||
import { ProductService } from '../product.service';
|
||||
|
||||
@@ -69,7 +69,7 @@ import { ProductDetailDialogComponent } from './product-detail-dialog.component'
|
||||
],
|
||||
})
|
||||
export class ProductDetailComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
@ViewChild('nameElement', { static: true }) nameElement!: ElementRef<HTMLInputElement>;
|
||||
form: FormGroup<{
|
||||
code: FormControl<string | number>;
|
||||
name: FormControl<string | null>;
|
||||
@@ -115,7 +115,7 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
private ser: ProductService,
|
||||
) {
|
||||
this.form = new FormGroup({
|
||||
@@ -182,7 +182,7 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
||||
isPurchased: this.item.isPurchased,
|
||||
isSold: this.item.isSold,
|
||||
isActive: this.item.isActive,
|
||||
productGroup: this.item.productGroup ? this.item.productGroup.id ?? '' : '',
|
||||
productGroup: this.item.productGroup ? (this.item.productGroup.id ?? '') : '',
|
||||
|
||||
allergen: this.item.allergen ?? '',
|
||||
protein: this.item.protein,
|
||||
@@ -204,9 +204,7 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
this.nameElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -221,22 +219,22 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
||||
}
|
||||
const fraction = Number(formValue.fraction);
|
||||
if (fraction < 1) {
|
||||
this.toaster.show('Danger', 'Fraction has to be >= 1');
|
||||
this.snackBar.open('Fraction has to be >= 1', 'Danger');
|
||||
return;
|
||||
}
|
||||
const productYield = Number(formValue.productYield);
|
||||
if (productYield < 0 || productYield > 1) {
|
||||
this.toaster.show('Danger', 'Product Yield has to be > 0 and <= 1');
|
||||
this.snackBar.open('Product Yield has to be > 0 and <= 1', 'Danger');
|
||||
return;
|
||||
}
|
||||
const costPrice = Number(formValue.costPrice);
|
||||
if (costPrice < 0) {
|
||||
this.toaster.show('Danger', 'Price has to be >= 0');
|
||||
this.snackBar.open('Price has to be >= 0', 'Danger');
|
||||
return;
|
||||
}
|
||||
const salePrice = Number(formValue.salePrice);
|
||||
if (salePrice < 0) {
|
||||
this.toaster.show('Danger', 'Sale Price has to be >= 0');
|
||||
this.snackBar.open('Sale Price has to be >= 0', 'Danger');
|
||||
return;
|
||||
}
|
||||
this.item.skus.push(
|
||||
@@ -285,11 +283,11 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
||||
save() {
|
||||
this.ser.saveOrUpdate(this.getItem()).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/products');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -297,11 +295,11 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
||||
delete() {
|
||||
this.ser.delete(this.item.id as string).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/products');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -66,9 +66,9 @@ import { ProductListDataSource } from './product-list-datasource';
|
||||
],
|
||||
})
|
||||
export class ProductListComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('filterElement', { static: true }) filterElement?: ElementRef;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild('filterElement', { static: true }) filterElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
list: Product[] = [];
|
||||
filter: Observable<string>;
|
||||
dataSource: ProductListDataSource;
|
||||
@@ -90,7 +90,7 @@ export class ProductListComponent implements OnInit, AfterViewInit {
|
||||
filter: new FormControl<string>('', { nonNullable: true }),
|
||||
});
|
||||
this.filter = this.form.controls.filter.valueChanges.pipe(debounceTime(150), distinctUntilChanged());
|
||||
this.dataSource = new ProductListDataSource(this.list, this.filter);
|
||||
this.dataSource = new ProductListDataSource(this.list, this.filter, this.paginator, this.sort);
|
||||
}
|
||||
|
||||
get showExtended(): boolean {
|
||||
@@ -117,9 +117,7 @@ export class ProductListComponent implements OnInit, AfterViewInit {
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.filterElement) {
|
||||
this.filterElement.nativeElement.focus();
|
||||
}
|
||||
this.filterElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
<mat-label>Start Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
#startDateElement
|
||||
[matDatepicker]="startDate"
|
||||
(focus)="startDate.open()"
|
||||
formControlName="startDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
@@ -19,13 +19,7 @@
|
||||
</mat-form-field>
|
||||
<mat-form-field class="flex-auto basis-2/5 mr-5">
|
||||
<mat-label>Finish Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="finishDate"
|
||||
(focus)="finishDate.open()"
|
||||
formControlName="finishDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<input matInput [matDatepicker]="finishDate" formControlName="finishDate" autocomplete="off" />
|
||||
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
|
||||
<mat-datepicker #finishDate></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CurrencyPipe } from '@angular/common';
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButton } from '@angular/material/button';
|
||||
import { MatCard, MatCardHeader, MatCardTitle, MatCardContent } from '@angular/material/card';
|
||||
@@ -70,10 +70,11 @@ import { ProfitLossDataSource } from './profit-loss-datasource';
|
||||
],
|
||||
})
|
||||
export class ProfitLossComponent implements OnInit {
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
@ViewChild('startDateElement', { static: true }) startDate!: ElementRef<HTMLInputElement>;
|
||||
info: ProfitLoss = new ProfitLoss();
|
||||
dataSource: ProfitLossDataSource = new ProfitLossDataSource(this.info.body);
|
||||
dataSource: ProfitLossDataSource = new ProfitLossDataSource(this.info.body, this.paginator, this.sort);
|
||||
form: FormGroup<{
|
||||
startDate: FormControl<Date>;
|
||||
finishDate: FormControl<Date>;
|
||||
@@ -83,6 +84,13 @@ export class ProfitLossComponent implements OnInit {
|
||||
/** 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: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.startDate.nativeElement.focus();
|
||||
this.startDate.nativeElement.select();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
<mat-label>Start Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
#startDateElement
|
||||
[matDatepicker]="startDate"
|
||||
(focus)="startDate.open()"
|
||||
formControlName="startDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
@@ -19,13 +19,7 @@
|
||||
</mat-form-field>
|
||||
<mat-form-field class="flex-auto basis-2/5 mr-5">
|
||||
<mat-label>Finish Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="finishDate"
|
||||
(focus)="finishDate.open()"
|
||||
formControlName="finishDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<input matInput [matDatepicker]="finishDate" formControlName="finishDate" autocomplete="off" />
|
||||
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
|
||||
<mat-datepicker #finishDate></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { DecimalPipe, PercentPipe, CurrencyPipe } from '@angular/common';
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButton } from '@angular/material/button';
|
||||
import { MatCard, MatCardHeader, MatCardTitle, MatCardContent } from '@angular/material/card';
|
||||
@@ -65,10 +65,11 @@ import { PurchaseEntriesDataSource } from './purchase-entries-datasource';
|
||||
],
|
||||
})
|
||||
export class PurchaseEntriesComponent implements OnInit {
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
@ViewChild('startDateElement', { static: true }) startDate!: ElementRef<HTMLInputElement>;
|
||||
info: PurchaseEntries = new PurchaseEntries();
|
||||
dataSource: PurchaseEntriesDataSource = new PurchaseEntriesDataSource(this.info.body);
|
||||
dataSource: PurchaseEntriesDataSource = new PurchaseEntriesDataSource(this.info.body, this.paginator, this.sort);
|
||||
form: FormGroup<{
|
||||
startDate: FormControl<Date>;
|
||||
finishDate: FormControl<Date>;
|
||||
@@ -78,6 +79,13 @@ export class PurchaseEntriesComponent implements OnInit {
|
||||
/** 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: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.startDate.nativeElement.focus();
|
||||
this.startDate.nativeElement.select();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
|
||||
@@ -17,14 +17,7 @@
|
||||
<div class="flex flex-row justify-around content-start items-start sm:max-lg:flex-col">
|
||||
<mat-form-field class="flex-auto basis-2/5 mr-5">
|
||||
<mat-label>Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="date"
|
||||
formControlName="date"
|
||||
autocomplete="off"
|
||||
#dateElement
|
||||
(focus)="dateElement.select()"
|
||||
/>
|
||||
<input matInput [matDatepicker]="date" formControlName="date" autocomplete="off" #dateElement />
|
||||
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
|
||||
<mat-datepicker #date></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { COMMA, ENTER } from '@angular/cdk/keycodes';
|
||||
import { AsyncPipe, DecimalPipe, PercentPipe, CurrencyPipe } from '@angular/common';
|
||||
import { AfterViewInit, Component, ElementRef, OnInit, OnDestroy, ViewChild } from '@angular/core';
|
||||
import { AfterViewInit, Component, ElementRef, OnInit, ViewChild, HostListener } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatAutocompleteSelectedEvent, MatAutocompleteTrigger, MatAutocomplete } from '@angular/material/autocomplete';
|
||||
import { MatButton, MatIconButton } from '@angular/material/button';
|
||||
@@ -33,7 +33,6 @@ import {
|
||||
MatRow,
|
||||
} from '@angular/material/table';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Hotkey, HotkeysService } from 'angular2-hotkeys';
|
||||
import { round } from 'mathjs';
|
||||
import moment from 'moment';
|
||||
import { BehaviorSubject, Observable, of as observableOf } from 'rxjs';
|
||||
@@ -49,7 +48,7 @@ import { DbFile } from '../core/db-file';
|
||||
import { Inventory } from '../core/inventory';
|
||||
import { Tag } from '../core/tag';
|
||||
import { TagService } from '../core/tag.service';
|
||||
import { ToasterService } from '../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { User } from '../core/user';
|
||||
import { Voucher } from '../core/voucher';
|
||||
import { VoucherService } from '../core/voucher.service';
|
||||
@@ -114,11 +113,35 @@ import { PurchaseReturnDialogComponent } from './purchase-return-dialog.componen
|
||||
LocalTimePipe,
|
||||
],
|
||||
})
|
||||
export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
@ViewChild('accountElement', { static: true }) accountElement?: ElementRef;
|
||||
@ViewChild('batchElement', { static: true }) batchElement?: ElementRef;
|
||||
@ViewChild('dateElement', { static: true }) dateElement?: ElementRef;
|
||||
export class PurchaseReturnComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('accountElement', { static: true }) accountElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('batchElement', { static: true }) batchElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('dateElement', { static: true }) dateElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('tagInput') tagInput?: ElementRef<HTMLInputElement>;
|
||||
|
||||
@HostListener('window:keydown.f2', ['$event'])
|
||||
focusDate(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.dateElement.nativeElement.focus();
|
||||
this.dateElement.nativeElement.select();
|
||||
}
|
||||
|
||||
@HostListener('window:keydown.control.s', ['$event'])
|
||||
saveListner(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
if (this.canSave()) {
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('window:keydown.control.p', ['$event'])
|
||||
postListner(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
if (this.voucher.id && !this.voucher.posted && this.auth.allowed('post-vouchers')) {
|
||||
this.post();
|
||||
}
|
||||
}
|
||||
|
||||
separatorKeysCodes: number[] = [ENTER, COMMA];
|
||||
public inventoryObservable = new BehaviorSubject<Inventory[]>([]);
|
||||
dataSource: PurchaseReturnDataSource = new PurchaseReturnDataSource(this.inventoryObservable);
|
||||
@@ -148,8 +171,7 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
private hotkeys: HotkeysService,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
public auth: AuthService,
|
||||
private math: MathService,
|
||||
public image: ImageService,
|
||||
@@ -199,54 +221,12 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
|
||||
this.loadVoucher(data.voucher);
|
||||
});
|
||||
this.hotkeys.add(
|
||||
new Hotkey(
|
||||
'f2',
|
||||
(): boolean => {
|
||||
setTimeout(() => {
|
||||
if (this.dateElement) {
|
||||
this.dateElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
return false; // Prevent bubbling
|
||||
},
|
||||
['INPUT', 'SELECT', 'TEXTAREA'],
|
||||
),
|
||||
);
|
||||
this.hotkeys.add(
|
||||
new Hotkey(
|
||||
'ctrl+s',
|
||||
(): boolean => {
|
||||
if (this.canSave()) {
|
||||
this.save();
|
||||
}
|
||||
return false; // Prevent bubbling
|
||||
},
|
||||
['INPUT', 'SELECT', 'TEXTAREA'],
|
||||
),
|
||||
);
|
||||
this.hotkeys.add(
|
||||
new Hotkey(
|
||||
'ctrl+p',
|
||||
(): boolean => {
|
||||
if (this.voucher.id && !this.voucher.posted && this.auth.allowed('post-vouchers')) {
|
||||
this.post();
|
||||
}
|
||||
return false; // Prevent bubbling
|
||||
},
|
||||
['INPUT', 'SELECT', 'TEXTAREA'],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.focusAccount();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.hotkeys.reset();
|
||||
}
|
||||
|
||||
loadVoucher(voucher: Voucher) {
|
||||
this.voucher = voucher;
|
||||
this.form.setValue({
|
||||
@@ -266,9 +246,7 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
|
||||
focusAccount() {
|
||||
setTimeout(() => {
|
||||
if (this.accountElement) {
|
||||
this.accountElement.nativeElement.focus();
|
||||
}
|
||||
this.accountElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -283,7 +261,7 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
}
|
||||
const old = this.voucher.inventories.find((x) => x.batch.id === (this.batch as Batch).id);
|
||||
if (old !== undefined) {
|
||||
this.toaster.show('Danger', 'Product already added');
|
||||
this.snackBar.open('Product already added', 'Danger');
|
||||
return;
|
||||
}
|
||||
this.voucher.inventories.push(
|
||||
@@ -304,9 +282,7 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
this.form.controls.addRow.reset();
|
||||
this.batch = null;
|
||||
setTimeout(() => {
|
||||
if (this.batchElement) {
|
||||
this.batchElement.nativeElement.focus();
|
||||
}
|
||||
this.batchElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -361,10 +337,10 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
this.ser.post(this.voucher.id as string).subscribe({
|
||||
next: (result) => {
|
||||
this.loadVoucher(result);
|
||||
this.toaster.show('Success', 'Voucher Posted');
|
||||
this.snackBar.open('Voucher Posted', 'Success');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -373,7 +349,7 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
const voucher: Voucher = this.getVoucher();
|
||||
this.ser.saveOrUpdate(voucher).subscribe({
|
||||
next: (result) => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
if (voucher.id === result.id) {
|
||||
this.loadVoucher(result);
|
||||
} else {
|
||||
@@ -381,7 +357,7 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
}
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -399,11 +375,11 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
delete() {
|
||||
this.ser.delete(this.voucher.id as string).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigate(['/purchase-return'], { replaceUrl: true });
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -17,14 +17,7 @@
|
||||
<div class="flex flex-row justify-around content-start items-start sm:max-lg:flex-col">
|
||||
<mat-form-field class="flex-auto basis-2/5 mr-5">
|
||||
<mat-label>Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="date"
|
||||
formControlName="date"
|
||||
autocomplete="off"
|
||||
#dateElement
|
||||
(focus)="dateElement.select()"
|
||||
/>
|
||||
<input matInput [matDatepicker]="date" formControlName="date" autocomplete="off" #dateElement />
|
||||
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
|
||||
<mat-datepicker #date></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { COMMA, ENTER } from '@angular/cdk/keycodes';
|
||||
import { AsyncPipe, DecimalPipe, PercentPipe, CurrencyPipe } from '@angular/common';
|
||||
import { AfterViewInit, Component, ElementRef, OnInit, OnDestroy, ViewChild } from '@angular/core';
|
||||
import { AfterViewInit, Component, ElementRef, OnInit, ViewChild, HostListener } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatAutocompleteSelectedEvent, MatAutocompleteTrigger, MatAutocomplete } from '@angular/material/autocomplete';
|
||||
import { MatButton, MatIconButton } from '@angular/material/button';
|
||||
@@ -33,7 +33,6 @@ import {
|
||||
MatRow,
|
||||
} from '@angular/material/table';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Hotkey, HotkeysService } from 'angular2-hotkeys';
|
||||
import { round } from 'mathjs';
|
||||
import moment from 'moment';
|
||||
import { BehaviorSubject, Observable, of as observableOf } from 'rxjs';
|
||||
@@ -50,7 +49,7 @@ import { Product } from '../core/product';
|
||||
import { ProductSku } from '../core/product-sku';
|
||||
import { Tag } from '../core/tag';
|
||||
import { TagService } from '../core/tag.service';
|
||||
import { ToasterService } from '../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { User } from '../core/user';
|
||||
import { Voucher } from '../core/voucher';
|
||||
import { VoucherService } from '../core/voucher.service';
|
||||
@@ -116,11 +115,35 @@ import { PurchaseDialogComponent } from './purchase-dialog.component';
|
||||
LocalTimePipe,
|
||||
],
|
||||
})
|
||||
export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
@ViewChild('accountElement', { static: true }) accountElement?: ElementRef;
|
||||
@ViewChild('productElement', { static: true }) productElement?: ElementRef;
|
||||
@ViewChild('dateElement', { static: true }) dateElement?: ElementRef;
|
||||
export class PurchaseComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('accountElement', { static: true }) accountElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('productElement', { static: true }) productElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('dateElement', { static: true }) dateElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('tagInput') tagInput?: ElementRef<HTMLInputElement>;
|
||||
|
||||
@HostListener('window:keydown.f2', ['$event'])
|
||||
focusDate(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.dateElement.nativeElement.focus();
|
||||
this.dateElement.nativeElement.select();
|
||||
}
|
||||
|
||||
@HostListener('window:keydown.control.s', ['$event'])
|
||||
saveListner(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
if (this.canSave()) {
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('window:keydown.control.p', ['$event'])
|
||||
postListner(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
if (this.voucher.id && !this.voucher.posted && this.auth.allowed('post-vouchers')) {
|
||||
this.post();
|
||||
}
|
||||
}
|
||||
|
||||
separatorKeysCodes: number[] = [ENTER, COMMA];
|
||||
public inventoryObservable = new BehaviorSubject<Inventory[]>([]);
|
||||
dataSource: PurchaseDataSource = new PurchaseDataSource(this.inventoryObservable);
|
||||
@@ -153,8 +176,7 @@ export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
private hotkeys: HotkeysService,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
public auth: AuthService,
|
||||
private math: MathService,
|
||||
public image: ImageService,
|
||||
@@ -214,54 +236,12 @@ export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
this.loadVoucher(data.voucher);
|
||||
});
|
||||
this.hotkeys.add(
|
||||
new Hotkey(
|
||||
'f2',
|
||||
(): boolean => {
|
||||
setTimeout(() => {
|
||||
if (this.dateElement) {
|
||||
this.dateElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
return false; // Prevent bubbling
|
||||
},
|
||||
['INPUT', 'SELECT', 'TEXTAREA'],
|
||||
),
|
||||
);
|
||||
this.hotkeys.add(
|
||||
new Hotkey(
|
||||
'ctrl+s',
|
||||
(): boolean => {
|
||||
if (this.canSave()) {
|
||||
this.save();
|
||||
}
|
||||
return false; // Prevent bubbling
|
||||
},
|
||||
['INPUT', 'SELECT', 'TEXTAREA'],
|
||||
),
|
||||
);
|
||||
this.hotkeys.add(
|
||||
new Hotkey(
|
||||
'ctrl+p',
|
||||
(): boolean => {
|
||||
if (this.voucher.id && !this.voucher.posted && this.auth.allowed('post-vouchers')) {
|
||||
this.post();
|
||||
}
|
||||
return false; // Prevent bubbling
|
||||
},
|
||||
['INPUT', 'SELECT', 'TEXTAREA'],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.focusAccount();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.hotkeys.reset();
|
||||
}
|
||||
|
||||
loadVoucher(voucher: Voucher) {
|
||||
this.voucher = voucher;
|
||||
this.form.setValue({
|
||||
@@ -284,9 +264,7 @@ export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
focusAccount() {
|
||||
setTimeout(() => {
|
||||
if (this.accountElement) {
|
||||
this.accountElement.nativeElement.focus();
|
||||
}
|
||||
this.accountElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -309,7 +287,7 @@ export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
const oldFiltered = this.voucher.inventories.filter((x) => x.batch?.sku.id === (this.product as ProductSku).id);
|
||||
if (oldFiltered.length) {
|
||||
this.toaster.show('Danger', 'Product already added');
|
||||
this.snackBar.open('Product already added', 'Danger');
|
||||
return;
|
||||
}
|
||||
this.voucher.inventories.push(
|
||||
@@ -333,9 +311,7 @@ export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.form.controls.addRow.controls.tax.enable();
|
||||
this.form.controls.addRow.controls.discount.enable();
|
||||
setTimeout(() => {
|
||||
if (this.productElement) {
|
||||
this.productElement.nativeElement.focus();
|
||||
}
|
||||
this.productElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -387,10 +363,10 @@ export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.ser.post(this.voucher.id as string).subscribe({
|
||||
next: (result) => {
|
||||
this.loadVoucher(result);
|
||||
this.toaster.show('Success', 'Voucher Posted');
|
||||
this.snackBar.open('Voucher Posted', 'Success');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -399,7 +375,7 @@ export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
const voucher: Voucher = this.getVoucher();
|
||||
this.ser.saveOrUpdate(voucher).subscribe({
|
||||
next: (result) => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
if (voucher.id === result.id) {
|
||||
this.loadVoucher(result);
|
||||
} else {
|
||||
@@ -407,7 +383,7 @@ export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -425,11 +401,11 @@ export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
delete() {
|
||||
this.ser.delete(this.voucher.id as string).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigate(['/purchase'], { replaceUrl: true });
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
<mat-label>Start Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
#startDateElement
|
||||
[matDatepicker]="startDate"
|
||||
(focus)="startDate.open()"
|
||||
formControlName="startDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
@@ -19,13 +19,7 @@
|
||||
</mat-form-field>
|
||||
<mat-form-field class="flex-auto basis-2/5 mr-5">
|
||||
<mat-label>Finish Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="finishDate"
|
||||
(focus)="finishDate.open()"
|
||||
formControlName="finishDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<input matInput [matDatepicker]="finishDate" formControlName="finishDate" autocomplete="off" />
|
||||
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
|
||||
<mat-datepicker #finishDate></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { DecimalPipe, CurrencyPipe } from '@angular/common';
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButton } from '@angular/material/button';
|
||||
import { MatCard, MatCardHeader, MatCardTitle, MatCardContent } from '@angular/material/card';
|
||||
@@ -73,10 +73,11 @@ import { PurchasesItem } from './purchases-item';
|
||||
],
|
||||
})
|
||||
export class PurchasesComponent implements OnInit {
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
@ViewChild('startDateElement', { static: true }) startDate!: ElementRef<HTMLInputElement>;
|
||||
info: Purchases = new Purchases();
|
||||
dataSource: PurchasesDataSource = new PurchasesDataSource(this.info.body);
|
||||
dataSource: PurchasesDataSource = new PurchasesDataSource(this.info.body, this.paginator, this.sort);
|
||||
form: FormGroup<{
|
||||
startDate: FormControl<Date>;
|
||||
finishDate: FormControl<Date>;
|
||||
@@ -86,6 +87,13 @@ export class PurchasesComponent implements OnInit {
|
||||
/** 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: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.startDate.nativeElement.focus();
|
||||
this.startDate.nativeElement.select();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
|
||||
+20
-15
@@ -32,7 +32,7 @@ import { Account } from '../../core/account';
|
||||
import { AccountService } from '../../core/account.service';
|
||||
import { Product } from '../../core/product';
|
||||
import { ProductSku } from '../../core/product-sku';
|
||||
import { ToasterService } from '../../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { ProductService } from '../../product/product.service';
|
||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||
import { MathService } from '../../shared/math.service';
|
||||
@@ -41,6 +41,7 @@ import { RateContractItem } from '../rate-contract-item';
|
||||
import { RateContractService } from '../rate-contract.service';
|
||||
|
||||
import { RateContractDetailDatasource } from './rate-contract-detail-datasource';
|
||||
import { HostListener } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-rate-contract-detail',
|
||||
@@ -83,8 +84,9 @@ import { RateContractDetailDatasource } from './rate-contract-detail-datasource'
|
||||
],
|
||||
})
|
||||
export class RateContractDetailComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('accountElement', { static: true }) accountElement?: ElementRef;
|
||||
@ViewChild('productElement', { static: true }) productElement?: ElementRef;
|
||||
@ViewChild('accountElement', { static: true }) accountElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('productElement', { static: true }) productElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('dateElement', { static: true }) dateElement!: ElementRef<HTMLInputElement>;
|
||||
public itemsObservable = new BehaviorSubject<RateContractItem[]>([]);
|
||||
dataSource: RateContractDetailDatasource = new RateContractDetailDatasource(this.itemsObservable);
|
||||
form: FormGroup<{
|
||||
@@ -109,10 +111,17 @@ export class RateContractDetailComponent implements OnInit, AfterViewInit {
|
||||
accounts: Observable<Account[]>;
|
||||
products: Observable<ProductSku[]>;
|
||||
|
||||
@HostListener('window:keydown.f2', ['$event'])
|
||||
focusDate(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.dateElement.nativeElement.focus();
|
||||
this.dateElement.nativeElement.select();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
private dialog: MatDialog,
|
||||
private math: MathService,
|
||||
private ser: RateContractService,
|
||||
@@ -169,9 +178,7 @@ export class RateContractDetailComponent implements OnInit, AfterViewInit {
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.accountElement) {
|
||||
this.accountElement.nativeElement.focus();
|
||||
}
|
||||
this.accountElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -186,7 +193,7 @@ export class RateContractDetailComponent implements OnInit, AfterViewInit {
|
||||
}
|
||||
const oldFiltered = this.item.items.filter((x) => x.sku.id === (this.product as Product).id);
|
||||
if (oldFiltered.length) {
|
||||
this.toaster.show('Danger', 'Product already added');
|
||||
this.snackBar.open('Product already added', 'Danger');
|
||||
return;
|
||||
}
|
||||
this.item.items.push(
|
||||
@@ -203,9 +210,7 @@ export class RateContractDetailComponent implements OnInit, AfterViewInit {
|
||||
this.form.controls.addRow.reset();
|
||||
this.product = null;
|
||||
setTimeout(() => {
|
||||
if (this.productElement) {
|
||||
this.productElement.nativeElement.focus();
|
||||
}
|
||||
this.productElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -233,11 +238,11 @@ export class RateContractDetailComponent implements OnInit, AfterViewInit {
|
||||
save() {
|
||||
this.ser.saveOrUpdate(this.getItem()).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/rate-contracts');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -245,11 +250,11 @@ export class RateContractDetailComponent implements OnInit, AfterViewInit {
|
||||
delete() {
|
||||
this.ser.delete(this.item.id as string).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/rate-contracts');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -54,10 +54,10 @@ import { RateContractListDatasource } from './rate-contract-list-datasource';
|
||||
],
|
||||
})
|
||||
export class RateContractListComponent implements OnInit {
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
list: RateContract[] = [];
|
||||
dataSource: RateContractListDatasource = new RateContractListDatasource(this.list);
|
||||
dataSource: RateContractListDatasource = new RateContractListDatasource(this.list, this.paginator, this.sort);
|
||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||
displayedColumns = ['vendor', 'validity', 'products'];
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
<mat-label>Start Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
#startDateElement
|
||||
[matDatepicker]="startDate"
|
||||
(focus)="startDate.open()"
|
||||
formControlName="startDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
@@ -26,13 +26,7 @@
|
||||
</mat-form-field>
|
||||
<mat-form-field class="flex-auto basis-2/5 mr-5">
|
||||
<mat-label>Finish Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="finishDate"
|
||||
(focus)="finishDate.open()"
|
||||
formControlName="finishDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<input matInput [matDatepicker]="finishDate" formControlName="finishDate" autocomplete="off" />
|
||||
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
|
||||
<mat-datepicker #finishDate></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { DecimalPipe, PercentPipe, CurrencyPipe } from '@angular/common';
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatIconButton, MatButton } from '@angular/material/button';
|
||||
import { MatCard, MatCardHeader, MatCardTitleGroup, MatCardTitle, MatCardContent } from '@angular/material/card';
|
||||
@@ -79,10 +79,11 @@ import { RawMaterialCostDataSource } from './raw-material-cost-datasource';
|
||||
],
|
||||
})
|
||||
export class RawMaterialCostComponent implements OnInit {
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
@ViewChild('startDateElement', { static: true }) startDate!: ElementRef<HTMLInputElement>;
|
||||
info: RawMaterialCost = new RawMaterialCost();
|
||||
dataSource: RawMaterialCostDataSource = new RawMaterialCostDataSource(this.info.body);
|
||||
dataSource: RawMaterialCostDataSource = new RawMaterialCostDataSource(this.info.body, this.paginator, this.sort);
|
||||
form: FormGroup<{
|
||||
startDate: FormControl<Date>;
|
||||
finishDate: FormControl<Date>;
|
||||
@@ -99,6 +100,13 @@ export class RawMaterialCostComponent implements OnInit {
|
||||
columnsNoId = ['name', 'issue', 'sale', 'rmc'];
|
||||
columnsId = ['name', 'group', 'quantity', 'net', 'gross'];
|
||||
|
||||
@HostListener('window:keydown.f2', ['$event'])
|
||||
focusDate(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.startDate.nativeElement.focus();
|
||||
this.startDate.nativeElement.select();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
@@ -144,7 +152,7 @@ export class RawMaterialCostComponent implements OnInit {
|
||||
}
|
||||
|
||||
exportCsv() {
|
||||
let headers: { [display: string]: string };
|
||||
let headers: Record<string, string>;
|
||||
if (this.info.id) {
|
||||
headers = { Name: 'name', Group: 'group', Quantity: 'quantity', Net: 'net', Gross: 'gross' };
|
||||
} else {
|
||||
|
||||
@@ -17,14 +17,7 @@
|
||||
<div class="flex flex-row justify-around content-start items-start sm:max-lg:flex-col">
|
||||
<mat-form-field class="flex-auto basis-2/5 mr-5">
|
||||
<mat-label>Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="date"
|
||||
formControlName="date"
|
||||
autocomplete="off"
|
||||
#dateElement
|
||||
(focus)="dateElement.select()"
|
||||
/>
|
||||
<input matInput [matDatepicker]="date" formControlName="date" autocomplete="off" #dateElement />
|
||||
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
|
||||
<mat-datepicker #date></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { COMMA, ENTER } from '@angular/cdk/keycodes';
|
||||
import { AsyncPipe, CurrencyPipe } from '@angular/common';
|
||||
import { AfterViewInit, Component, ElementRef, OnInit, OnDestroy, ViewChild } from '@angular/core';
|
||||
import { AfterViewInit, Component, ElementRef, OnInit, ViewChild, HostListener } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatAutocompleteSelectedEvent, MatAutocompleteTrigger, MatAutocomplete } from '@angular/material/autocomplete';
|
||||
import { MatButton, MatIconButton } from '@angular/material/button';
|
||||
@@ -34,7 +34,6 @@ import {
|
||||
MatRow,
|
||||
} from '@angular/material/table';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Hotkey, HotkeysService } from 'angular2-hotkeys';
|
||||
import { round } from 'mathjs';
|
||||
import moment from 'moment';
|
||||
import { BehaviorSubject, Observable, of as observableOf } from 'rxjs';
|
||||
@@ -48,7 +47,7 @@ import { DbFile } from '../core/db-file';
|
||||
import { Journal } from '../core/journal';
|
||||
import { Tag } from '../core/tag';
|
||||
import { TagService } from '../core/tag.service';
|
||||
import { ToasterService } from '../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { User } from '../core/user';
|
||||
import { Voucher } from '../core/voucher';
|
||||
import { VoucherService } from '../core/voucher.service';
|
||||
@@ -112,10 +111,34 @@ import { ReceiptDialogComponent } from './receipt-dialog.component';
|
||||
LocalTimePipe,
|
||||
],
|
||||
})
|
||||
export class ReceiptComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
@ViewChild('accountElement', { static: true }) accountElement?: ElementRef;
|
||||
@ViewChild('dateElement', { static: true }) dateElement?: ElementRef;
|
||||
export class ReceiptComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('accountElement', { static: true }) accountElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('dateElement', { static: true }) dateElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('tagInput') tagInput?: ElementRef<HTMLInputElement>;
|
||||
|
||||
@HostListener('window:keydown.f2', ['$event'])
|
||||
focusDate(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.dateElement.nativeElement.focus();
|
||||
this.dateElement.nativeElement.select();
|
||||
}
|
||||
|
||||
@HostListener('window:keydown.control.s', ['$event'])
|
||||
saveListner(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
if (this.canSave()) {
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('window:keydown.control.p', ['$event'])
|
||||
postListner(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
if (this.voucher.id && !this.voucher.posted && this.auth.allowed('post-vouchers')) {
|
||||
this.post();
|
||||
}
|
||||
}
|
||||
|
||||
separatorKeysCodes: number[] = [ENTER, COMMA];
|
||||
public journalObservable = new BehaviorSubject<Journal[]>([]);
|
||||
dataSource: ReceiptDataSource = new ReceiptDataSource(this.journalObservable);
|
||||
@@ -146,8 +169,7 @@ export class ReceiptComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
private hotkeys: HotkeysService,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
public auth: AuthService,
|
||||
private math: MathService,
|
||||
public image: ImageService,
|
||||
@@ -196,54 +218,12 @@ export class ReceiptComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.receiptAccounts = data.receiptAccounts;
|
||||
this.loadVoucher(data.voucher);
|
||||
});
|
||||
this.hotkeys.add(
|
||||
new Hotkey(
|
||||
'f2',
|
||||
(): boolean => {
|
||||
setTimeout(() => {
|
||||
if (this.dateElement) {
|
||||
this.dateElement.nativeElement.focus();
|
||||
}
|
||||
}, 0);
|
||||
return false; // Prevent bubbling
|
||||
},
|
||||
['INPUT', 'SELECT', 'TEXTAREA'],
|
||||
),
|
||||
);
|
||||
this.hotkeys.add(
|
||||
new Hotkey(
|
||||
'ctrl+s',
|
||||
(): boolean => {
|
||||
if (this.canSave()) {
|
||||
this.save();
|
||||
}
|
||||
return false; // Prevent bubbling
|
||||
},
|
||||
['INPUT', 'SELECT', 'TEXTAREA'],
|
||||
),
|
||||
);
|
||||
this.hotkeys.add(
|
||||
new Hotkey(
|
||||
'ctrl+p',
|
||||
(): boolean => {
|
||||
if (this.voucher.id && !this.voucher.posted && this.auth.allowed('post-vouchers')) {
|
||||
this.post();
|
||||
}
|
||||
return false; // Prevent bubbling
|
||||
},
|
||||
['INPUT', 'SELECT', 'TEXTAREA'],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.focusAccount();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.hotkeys.reset();
|
||||
}
|
||||
|
||||
loadVoucher(voucher: Voucher) {
|
||||
this.voucher = voucher;
|
||||
[this.receiptJournal] = this.voucher.journals.filter((x) => x.debit === 1);
|
||||
@@ -264,9 +244,7 @@ export class ReceiptComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
focusAccount() {
|
||||
setTimeout(() => {
|
||||
if (this.accountElement) {
|
||||
this.accountElement.nativeElement.focus();
|
||||
}
|
||||
this.accountElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -302,9 +280,7 @@ export class ReceiptComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.account = null;
|
||||
this.accBal = null;
|
||||
setTimeout(() => {
|
||||
if (this.accountElement) {
|
||||
this.accountElement.nativeElement.focus();
|
||||
}
|
||||
this.accountElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -359,10 +335,10 @@ export class ReceiptComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.ser.post(this.voucher.id as string).subscribe({
|
||||
next: (result) => {
|
||||
this.loadVoucher(result);
|
||||
this.toaster.show('Success', 'Voucher Posted');
|
||||
this.snackBar.open('Voucher Posted', 'Success');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -371,7 +347,7 @@ export class ReceiptComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
const voucher: Voucher = this.getVoucher();
|
||||
this.ser.saveOrUpdate(voucher).subscribe({
|
||||
next: (result) => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
if (voucher.id === result.id) {
|
||||
this.loadVoucher(result);
|
||||
} else {
|
||||
@@ -379,7 +355,7 @@ export class ReceiptComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -395,11 +371,11 @@ export class ReceiptComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
delete() {
|
||||
this.ser.delete(this.voucher.id as string).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigate(['/receipt'], { replaceUrl: true });
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
+1
-8
@@ -12,14 +12,7 @@
|
||||
</mat-form-field>
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="date"
|
||||
formControlName="date"
|
||||
autocomplete="off"
|
||||
#dateElement
|
||||
(focus)="dateElement.select()"
|
||||
/>
|
||||
<input matInput [matDatepicker]="date" formControlName="date" autocomplete="off" #dateElement />
|
||||
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
|
||||
<mat-datepicker #date></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
+8
-10
@@ -10,7 +10,7 @@ import { MatInput } from '@angular/material/input';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import moment from 'moment';
|
||||
|
||||
import { ToasterService } from '../../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||
import { RecipeTemplate } from '../recipe-template';
|
||||
import { RecipeTemplateService } from '../recipe-template.service';
|
||||
@@ -39,7 +39,7 @@ import { RecipeTemplateService } from '../recipe-template.service';
|
||||
],
|
||||
})
|
||||
export class RecipeTemplateDetailComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
@ViewChild('nameElement', { static: true }) nameElement!: ElementRef<HTMLInputElement>;
|
||||
form: FormGroup<{
|
||||
name: FormControl<string>;
|
||||
date: FormControl<Date>;
|
||||
@@ -53,7 +53,7 @@ export class RecipeTemplateDetailComponent implements OnInit, AfterViewInit {
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
private ser: RecipeTemplateService,
|
||||
) {
|
||||
this.form = new FormGroup({
|
||||
@@ -84,20 +84,18 @@ export class RecipeTemplateDetailComponent implements OnInit, AfterViewInit {
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
this.nameElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
save() {
|
||||
this.ser.saveOrUpdate(this.getItem()).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/recipe-templates');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -105,11 +103,11 @@ export class RecipeTemplateDetailComponent implements OnInit, AfterViewInit {
|
||||
delete() {
|
||||
this.ser.delete(this.item.id).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/recipe-templates');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
+3
-3
@@ -52,10 +52,10 @@ import { RecipeTemplateListDataSource } from './recipe-template-list-datasource'
|
||||
],
|
||||
})
|
||||
export class RecipeTemplateListComponent implements OnInit {
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
list: RecipeTemplate[] = [];
|
||||
dataSource: RecipeTemplateListDataSource = new RecipeTemplateListDataSource(this.list);
|
||||
dataSource: RecipeTemplateListDataSource = new RecipeTemplateListDataSource(this.list, this.paginator, this.sort);
|
||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||
displayedColumns = ['name', 'selected', 'date'];
|
||||
|
||||
|
||||
@@ -7,14 +7,7 @@
|
||||
<div class="flex flex-row justify-around content-start items-start">
|
||||
<mat-form-field class="flex-auto mr-5">
|
||||
<mat-label>Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="date"
|
||||
formControlName="date"
|
||||
autocomplete="off"
|
||||
#dateElement
|
||||
(focus)="dateElement.select()"
|
||||
/>
|
||||
<input matInput [matDatepicker]="date" formControlName="date" autocomplete="off" #dateElement />
|
||||
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
|
||||
<mat-datepicker #date></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -31,7 +31,7 @@ import { Period } from 'src/app/period/period';
|
||||
|
||||
import { Product } from '../../core/product';
|
||||
import { ProductSku } from '../../core/product-sku';
|
||||
import { ToasterService } from '../../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { ProductService } from '../../product/product.service';
|
||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||
import { MathService } from '../../shared/math.service';
|
||||
@@ -82,8 +82,8 @@ import { RecipeDetailDatasource } from './recipe-detail-datasource';
|
||||
],
|
||||
})
|
||||
export class RecipeDetailComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('productElement', { static: true }) productElement?: ElementRef;
|
||||
@ViewChild('ingredientElement', { static: true }) ingredientElement?: ElementRef;
|
||||
@ViewChild('productElement', { static: true }) productElement!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('ingredientElement', { static: true }) ingredientElement!: ElementRef<HTMLInputElement>;
|
||||
public itemsObservable = new BehaviorSubject<RecipeItem[]>([]);
|
||||
dataSource: RecipeDetailDatasource = new RecipeDetailDatasource(this.itemsObservable);
|
||||
form: FormGroup<{
|
||||
@@ -114,7 +114,7 @@ export class RecipeDetailComponent implements OnInit, AfterViewInit {
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
private math: MathService,
|
||||
private ser: RecipeService,
|
||||
private productSer: ProductService,
|
||||
@@ -182,9 +182,7 @@ export class RecipeDetailComponent implements OnInit, AfterViewInit {
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.productElement) {
|
||||
this.productElement.nativeElement.focus();
|
||||
}
|
||||
this.productElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -218,7 +216,7 @@ export class RecipeDetailComponent implements OnInit, AfterViewInit {
|
||||
}
|
||||
const oldFiltered = this.item.items.filter((x) => x.product.id === (this.ingredient as ProductSku).id);
|
||||
if (oldFiltered.length) {
|
||||
this.toaster.show('Danger', 'Product already added');
|
||||
this.snackBar.open('Product already added', 'Danger');
|
||||
return;
|
||||
}
|
||||
this.item.items.push(
|
||||
@@ -236,9 +234,7 @@ export class RecipeDetailComponent implements OnInit, AfterViewInit {
|
||||
this.form.controls.addRow.reset();
|
||||
this.ingredient = null;
|
||||
setTimeout(() => {
|
||||
if (this.ingredientElement) {
|
||||
this.ingredientElement.nativeElement.focus();
|
||||
}
|
||||
this.ingredientElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -254,11 +250,11 @@ export class RecipeDetailComponent implements OnInit, AfterViewInit {
|
||||
save() {
|
||||
this.ser.saveOrUpdate(this.getItem()).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/recipes');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -266,11 +262,11 @@ export class RecipeDetailComponent implements OnInit, AfterViewInit {
|
||||
delete() {
|
||||
this.ser.delete(this.item.id as string).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigate(['/recipes']);
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -65,8 +65,8 @@ import { RecipeListDatasource } from './recipe-list-datasource';
|
||||
],
|
||||
})
|
||||
export class RecipeListComponent implements OnInit {
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
form: FormGroup<{
|
||||
period: FormControl<Period>;
|
||||
productGroup: FormControl<ProductGroup | string | null>;
|
||||
@@ -75,10 +75,16 @@ export class RecipeListComponent implements OnInit {
|
||||
productGroups: ProductGroup[] = [];
|
||||
periods: Period[] = [];
|
||||
periodFilter: BehaviorSubject<Period> = new BehaviorSubject<Period>(new Period());
|
||||
productGroupFilter: BehaviorSubject<string> = new BehaviorSubject('');
|
||||
productGroupFilter = new BehaviorSubject<string>('');
|
||||
list: Recipe[] = [];
|
||||
data: BehaviorSubject<Recipe[]> = new BehaviorSubject<Recipe[]>([]);
|
||||
dataSource: RecipeListDatasource = new RecipeListDatasource(this.productGroupFilter, this.data);
|
||||
dataSource: RecipeListDatasource = new RecipeListDatasource(
|
||||
this.productGroupFilter,
|
||||
this.data,
|
||||
this.paginator,
|
||||
this.sort,
|
||||
);
|
||||
|
||||
period: Period = new Period();
|
||||
|
||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||
|
||||
@@ -9,7 +9,7 @@ import { MatFormField, MatLabel } from '@angular/material/form-field';
|
||||
import { MatInput } from '@angular/material/input';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
import { ToasterService } from '../../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||
import { Role } from '../role';
|
||||
import { RoleService } from '../role.service';
|
||||
@@ -35,7 +35,7 @@ import { RoleService } from '../role.service';
|
||||
],
|
||||
})
|
||||
export class RoleDetailComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
@ViewChild('nameElement', { static: true }) nameElement!: ElementRef<HTMLInputElement>;
|
||||
form: FormGroup<{
|
||||
name: FormControl<string | null>;
|
||||
permissions: FormArray<
|
||||
@@ -50,7 +50,7 @@ export class RoleDetailComponent implements OnInit, AfterViewInit {
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
private dialog: MatDialog,
|
||||
private ser: RoleService,
|
||||
) {
|
||||
@@ -79,20 +79,18 @@ export class RoleDetailComponent implements OnInit, AfterViewInit {
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
this.nameElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
save() {
|
||||
this.ser.saveOrUpdate(this.getItem()).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/roles');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -100,11 +98,11 @@ export class RoleDetailComponent implements OnInit, AfterViewInit {
|
||||
delete() {
|
||||
this.ser.delete(this.item.id as string).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/roles');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -52,10 +52,10 @@ import { RoleListDatasource } from './role-list-datasource';
|
||||
],
|
||||
})
|
||||
export class RoleListComponent implements OnInit {
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
list: Role[] = [];
|
||||
dataSource: RoleListDatasource = new RoleListDatasource(this.list);
|
||||
dataSource: RoleListDatasource = new RoleListDatasource(this.list, this.paginator, this.sort);
|
||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||
displayedColumns = ['name', 'permissions'];
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ import { BehaviorSubject } from 'rxjs';
|
||||
import { environment } from '../app.environment';
|
||||
import { AuthService } from '../auth/auth.service';
|
||||
import { AccountType } from '../core/account-type';
|
||||
import { ToasterService } from '../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { ConfirmDialogComponent } from '../shared/confirm-dialog/confirm-dialog.component';
|
||||
|
||||
import { LockDataSource } from './lock-datasource';
|
||||
@@ -115,7 +115,7 @@ export class SettingsComponent implements OnInit {
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
public auth: AuthService,
|
||||
private ser: SettingsService,
|
||||
) {
|
||||
@@ -243,10 +243,10 @@ export class SettingsComponent implements OnInit {
|
||||
this.ser.setLockInformation(item).subscribe({
|
||||
next: (result) => {
|
||||
this.showLockInformation(result);
|
||||
this.toaster.show('Success', 'Lock information Updated');
|
||||
this.snackBar.open('Lock information Updated', 'Success');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -277,10 +277,10 @@ export class SettingsComponent implements OnInit {
|
||||
rebaseData(rebaseDate: string) {
|
||||
this.ser.rebaseDatabase(rebaseDate).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', 'Data has been rebased!');
|
||||
this.snackBar.open('Data has been rebased!', 'Success');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Injectable } from '@angular/core';
|
||||
})
|
||||
export class CookieService {
|
||||
public getCookie(name: string) {
|
||||
const ca: Array<string> = document.cookie.split(';');
|
||||
const ca: string[] = document.cookie.split(';');
|
||||
const caLen: number = ca.length;
|
||||
const cookieName = `${name}=`;
|
||||
let c: string;
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
export interface ToCsvType {
|
||||
[column: string]: string | number | boolean | null;
|
||||
}
|
||||
export type ToCsvType = Record<string, string | number | boolean | null>;
|
||||
@@ -6,7 +6,7 @@ import { ToCsvType } from './to-csv-type';
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ToCsvService {
|
||||
toCsv(headers: { [display: string]: string }, data: unknown[]): string {
|
||||
toCsv(headers: Record<string, string>, data: unknown[]): string {
|
||||
const header = Object.keys(headers);
|
||||
const replacer = (key: string, value: string | number | null) => (value === null ? '' : value);
|
||||
const csv = data.map((row) =>
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
<mat-label>Start Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
#startDateElement
|
||||
[matDatepicker]="startDate"
|
||||
(focus)="startDate.open()"
|
||||
formControlName="startDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
@@ -19,13 +19,7 @@
|
||||
</mat-form-field>
|
||||
<mat-form-field class="flex-auto basis-2/5 mr-5">
|
||||
<mat-label>Finish Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="finishDate"
|
||||
(focus)="finishDate.open()"
|
||||
formControlName="finishDate"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<input matInput [matDatepicker]="finishDate" formControlName="finishDate" autocomplete="off" />
|
||||
<mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
|
||||
<mat-datepicker #finishDate></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { DecimalPipe } from '@angular/common';
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButton } from '@angular/material/button';
|
||||
import { MatCard, MatCardHeader, MatCardTitle, MatCardContent } from '@angular/material/card';
|
||||
@@ -63,10 +63,11 @@ import { StockMovementDataSource } from './stock-movement-datasource';
|
||||
],
|
||||
})
|
||||
export class StockMovementComponent implements OnInit {
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
@ViewChild('startDateElement', { static: true }) startDate!: ElementRef<HTMLInputElement>;
|
||||
info: StockMovement = new StockMovement();
|
||||
dataSource: StockMovementDataSource = new StockMovementDataSource(this.info.body);
|
||||
dataSource: StockMovementDataSource = new StockMovementDataSource(this.info.body, this.paginator, this.sort);
|
||||
form: FormGroup<{
|
||||
startDate: FormControl<Date>;
|
||||
finishDate: FormControl<Date>;
|
||||
@@ -76,6 +77,13 @@ export class StockMovementComponent implements OnInit {
|
||||
/** 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: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.startDate.nativeElement.focus();
|
||||
this.startDate.nativeElement.select();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
|
||||
@@ -7,13 +7,7 @@
|
||||
<div class="flex flex-row justify-around content-start items-start sm:max-lg:flex-col">
|
||||
<mat-form-field class="flex-auto basis-4/5 mr-5">
|
||||
<mat-label>Date</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="dateInput"
|
||||
(focus)="dateInput.open()"
|
||||
formControlName="date"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<input matInput #dateElement [matDatepicker]="dateInput" formControlName="date" autocomplete="off" />
|
||||
<mat-datepicker-toggle matSuffix [for]="dateInput"></mat-datepicker-toggle>
|
||||
<mat-datepicker #dateInput></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CurrencyPipe } from '@angular/common';
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButton } from '@angular/material/button';
|
||||
import { MatCard, MatCardHeader, MatCardTitle, MatCardContent } from '@angular/material/card';
|
||||
@@ -65,10 +65,11 @@ import { TrialBalanceDataSource } from './trial-balance-datasource';
|
||||
],
|
||||
})
|
||||
export class TrialBalanceComponent implements OnInit {
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
@ViewChild('dateElement', { static: true }) dateElement!: ElementRef<HTMLInputElement>;
|
||||
info: TrialBalance = new TrialBalance();
|
||||
dataSource: TrialBalanceDataSource = new TrialBalanceDataSource(this.info.body);
|
||||
dataSource: TrialBalanceDataSource = new TrialBalanceDataSource(this.info.body, this.paginator, this.sort);
|
||||
form: FormGroup<{
|
||||
date: FormControl<Date>;
|
||||
}>;
|
||||
@@ -76,6 +77,13 @@ export class TrialBalanceComponent implements OnInit {
|
||||
/** 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: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
this.dateElement.nativeElement.focus();
|
||||
this.dateElement.nativeElement.select();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
|
||||
@@ -10,7 +10,7 @@ import { MatIcon } from '@angular/material/icon';
|
||||
import { MatInput } from '@angular/material/input';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
import { ToasterService } from '../../core/toaster.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { User } from '../../core/user';
|
||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||
import { UserService } from '../user.service';
|
||||
@@ -38,7 +38,7 @@ import { UserService } from '../user.service';
|
||||
],
|
||||
})
|
||||
export class UserDetailComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
@ViewChild('nameElement', { static: true }) nameElement!: ElementRef<HTMLInputElement>;
|
||||
form: FormGroup<{
|
||||
name: FormControl<string | null>;
|
||||
password: FormControl<string | null>;
|
||||
@@ -56,7 +56,7 @@ export class UserDetailComponent implements OnInit, AfterViewInit {
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private toaster: ToasterService,
|
||||
private snackBar: MatSnackBar,
|
||||
private dialog: MatDialog,
|
||||
private ser: UserService,
|
||||
) {
|
||||
@@ -94,9 +94,7 @@ export class UserDetailComponent implements OnInit, AfterViewInit {
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
if (this.nameElement) {
|
||||
this.nameElement.nativeElement.focus();
|
||||
}
|
||||
this.nameElement.nativeElement.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -104,21 +102,21 @@ export class UserDetailComponent implements OnInit, AfterViewInit {
|
||||
if (this.route.snapshot.paramMap.get('id') === 'me') {
|
||||
this.ser.updateMe(this.getItem()).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this.ser.saveOrUpdate(this.getItem()).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/users');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -127,11 +125,11 @@ export class UserDetailComponent implements OnInit, AfterViewInit {
|
||||
delete() {
|
||||
this.ser.delete(this.item.id as string).subscribe({
|
||||
next: () => {
|
||||
this.toaster.show('Success', '');
|
||||
this.snackBar.open('', 'Success');
|
||||
this.router.navigateByUrl('/users');
|
||||
},
|
||||
error: (error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
this.snackBar.open(error, 'Danger');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -54,8 +54,8 @@ import { UserListDataSource } from './user-list-datasource';
|
||||
],
|
||||
})
|
||||
export class UserListComponent implements OnInit {
|
||||
@ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator = undefined;
|
||||
@ViewChild(MatSort, { static: true }) sort?: MatSort = undefined;
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort!: MatSort;
|
||||
list: User[] = [];
|
||||
dataSource: UserListDataSource = new UserListDataSource(this.list);
|
||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||
|
||||
@@ -3,6 +3,11 @@ import { bootstrapApplication } from '@angular/platform-browser';
|
||||
import { AppComponent } from './app/app.component';
|
||||
import { appConfig } from './app/app.config';
|
||||
|
||||
import enIn from '@angular/common/locales/en-IN';
|
||||
import {registerLocaleData} from '@angular/common'; //function to register it.
|
||||
|
||||
registerLocaleData(enIn);
|
||||
|
||||
bootstrapApplication(AppComponent, appConfig)
|
||||
.catch((err) => console.error(err));
|
||||
|
||||
|
||||
Reference in new issue
Block a user