change over primeng v22

This commit is contained in:
Kham
2026-09-18 15:19:16 +10:00
parent f74125a92c
commit 3807524412
108 changed files with 17705 additions and 84 deletions
@@ -0,0 +1,12 @@
table {
width: 100%;
}
.mat-form-field {
font-size: 14px;
width: 100%;
}
td.mat-column-edit, .mat-column-delete {
width: 35px;
padding-right: 2px;
}
@@ -0,0 +1,56 @@
<div class="edit-content ml-6">
<h3>Application Administrators</h3>
<a class="p-ripple p-button p-component flex justify-self-end mb-2" [routerLink]='["/adminuser", -1]' [queryParams]="{returnUrl:'/home/adminuser'}">
Add User
</a>
<div class="mb-3 flex justify-end">
<p-iconfield iconPosition="left">
<p-inputicon>
<svg data-p-icon="search" ></svg>
</p-inputicon>
<input pInputText pSize="small" type="text" (input)="dt.filterGlobal($event.target.value, 'contains')" placeholder="Keyword Search" />
</p-iconfield>
</div>
<p-table #dt [value]="dataSource()" rowHover="true" dataKey="id"
[rows]="25" [rowsPerPageOptions]="[ 25, 50,100]" [paginator]="true"
[globalFilterFields]="['stafflinkNo', 'name', 'roleType', 'validationPoint']" >
<ng-template #header>
<tr>
<th>Stafflink Id</th>
<th>Name</th>
<th>Role</th>
<th>Validation Point</th>
<th>Active</th>
<th>Edit</th>
</tr>
</ng-template>
<ng-template #body let-item>
<tr>
<td>{{ item.stafflinkNo }}</td>
<td>{{ item.name }}</td>
<td>{{ item.roleType }}</td>
<td>{{ item.validationPoint }}</td>
<td>
@if(item.active == true) {
<svg data-p-icon="check" color="green"></svg>
}
@else {
<svg data-p-icon="times" color="red"></svg>
}
</td>
<td>
<button pButton (click)="showEdit(item)">
<svg data-p-icon="pencil"></svg>
</button>
</td>
</tr>
</ng-template>
</p-table>
</div>
@@ -0,0 +1,96 @@
import { Component, OnInit, signal, OnDestroy } from '@angular/core';
import { AdminUserView } from '../models';
import { take } from 'rxjs/operators';
import { Subscription } from 'rxjs';
import { Router, RouterModule } from '@angular/router';
import { AdminUserService } from './adminuser.service';
import { MessageService } from 'primeng/api';
import { TableModule } from 'primeng/table';
import { Check } from '@primeicons/angular/check';
import { Times } from '@primeicons/angular/times';
import { Pencil } from '@primeicons/angular/pencil';
import { Search } from '@primeicons/angular/search';
import { IconFieldModule } from 'primeng/iconfield';
import { InputIconModule } from 'primeng/inputicon';
import { InputTextModule } from 'primeng/inputtext';
@Component({
selector: 'adminuser-list',
templateUrl: './adminuser.component.html',
imports: [TableModule, RouterModule, Times, Check, Pencil, InputIconModule, IconFieldModule, Search, InputTextModule],
styleUrls: ['./adminuser.component.css']
})
export class AdminUserComponent implements OnInit, OnDestroy {
dataSource = signal<AdminUserView[]>([]);
private subscription: Subscription = new Subscription();
displayedColumns: string[] = ['stafflinkNo', 'name', 'roleType', 'validationPoint', 'active', 'edit'];
msg = "[AdminUser component]";
/*
private store: Store<appValidationState>
*/
constructor(
private adminUserService: AdminUserService,
private router: Router,
private messageService: MessageService,
) {
}
//KeyboardEvent
applyFilter(event: Event) {
const filterValue = (event.target as HTMLInputElement).value;
//this.dataSource.filter = filterValue.trim().toLowerCase();
}
ngOnInit(): void {
this.subscription.add(
this.adminUserService.loadAdminusers().subscribe(result => {
// console.log(this.msg + "onInit load Data", result);
this.dataSource.set(result.data);
}, error => {
console.log("error ", error);
})
);
/*
this.store.dispatch(validationActions.LoadValidationpoints());
this.store.pipe(select(validationSelector.getAllValidations)).subscribe(result => this.dataSource.data = result);
*/
}
showEdit(item: AdminUserView) {
console.log(this.msg + "on row click", item);
this.router.navigate(['/adminuser/' + item.id], { queryParams: { returnUrl: '/adminuser' } });
}
deleteItem(id: number): void {
this.adminUserService.deleteAdminuser(id)
.pipe(take(1))
.subscribe({
next: result => {
console.log(this.msg + " deleteItem success", result);
let data = this.dataSource();
let index: number = data.findIndex(d => d.id === id);
console.log(this.msg + "delete from datasource");
data.splice(index, 1)
this.dataSource.set(data);
},
error: e => console.error('error loading', e)
});
console.log(this.msg + "click button to delete");
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
@@ -0,0 +1,12 @@
table {
width: 100%;
}
.mat-form-field {
font-size: 14px;
width: 100%;
}
td.mat-column-edit, .mat-column-delete {
width: 35px;
padding-right: 2px;
}
@@ -0,0 +1,48 @@
<div class="edit-content">
<div class="title">
{{getEditText()}}
</div>
<form [formGroup]="adminuserForm" (ngSubmit)="onSubmit()" class="ml-10 flex flex-col gap-2">
<div class="flex flex-col">
<div>
<label class="flex w-full">Stafflink Number<strong class="app-require">*</strong></label>
<input pInputText formControlName="stafflinkNo" (blur)="searchUser()" maxlength="10" name="stafflinkno"
placeholder="Stafflink Number" #mystaffid>
</div>
<div>
<label class="flex w-full">Name</label>
<input pInputText formControlName="name" maxlength="100" name="name" placeholder="Name">
</div>
<div>
<label class="flex w-full">Role<strong class="app-require">*</strong></label>
<p-select formControlName="roleType" [options]="Roles()"
optionLabel="description" optionValue="categoryId"
>
</p-select>
</div>
<div>
<label class="flex w-full">Validation Point<strong class="app-require">*</strong></label>
<p-select formControlName="validationPointId" [options]="validationPoints()"
optionLabel="description" optionValue="id"
>
</p-select>
</div>
<div>
<label for="acheckbox" class="mr-2 text-sm">Active</label>
<p-checkbox formControlName="active" [binary]="true" inputId="acheckbox" size="small" />
</div>
</div>
<div class="flex justify-content-end mt-2">
<button type="submit" pButton class="mr-2" [disabled]="isFieldsChange">Submit</button>
<button type="button" pButton="" (click)="goBack()">Cancel</button>
</div>
</form>
<!--pre>{{ adminuserForm.value|json}}</pre-->
</div>
@@ -0,0 +1,203 @@
import { Component, inject, OnDestroy, OnInit, signal, ViewChild } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { FormGroup, Validators, ReactiveFormsModule, FormBuilder, FormControl } from '@angular/forms';
import { Subject, pipe, Subscription, single } from 'rxjs';
import { AdminUser, Lookup, userRole } from '../models';
import { LookupService, Utils } from '../shares';
import { AdminUserService } from './adminuser.service';
import { MessageService } from 'primeng/api';
import { InputTextModule } from 'primeng/inputtext';
import { SelectModule } from 'primeng/select';
import { ButtonModule } from 'primeng/button';
import { CheckboxModule } from 'primeng/checkbox';
@Component({
templateUrl: 'adminuser.edit.component.html',
imports: [InputTextModule, ButtonModule, ReactiveFormsModule, SelectModule, CheckboxModule],
selector: 'adminuser-edit',
styleUrls: ['adminuser.edit.component.css']
})
export class AdminUserEditComponent implements OnInit, OnDestroy {
returnUrl = '';
loginUser = '';
_id = -1;
Roles = signal<Lookup[]>([]);
validationPoints = signal<Lookup[]>([]);
msg = "[adminUser Component] ";
//for focus input
// @ViewChild('mystaffid') mystaffNo!: MatInput;
isChange = true; // disable use false//true for not disable. make sure it true is disable button.
private subscription: Subscription = new Subscription();
subChanged$ = new Subject<boolean>();
private formBuilder = inject(FormBuilder);
private adminUserService = inject(AdminUserService);
private messageService = inject(MessageService);
private lookupService = inject(LookupService);
adminuserForm = this.formBuilder.group({
id: [0], //Validators.required
stafflinkNo: [''], //Validators.required
name: [''], //Validators.required
addedBy: [''], //Validators.required
addedOn: new FormControl<Date | null>(null), //Validators.required
active: [false], //Validators.required
roleType: [0, Validators.required],
validationPointId: [0, Validators.required]
});
constructor(
private router: Router, private route: ActivatedRoute,
) {
const roles = [];
let item: Lookup = { id: userRole.Admin, categoryId: userRole.Admin, description: 'Admin' };
roles.push(item);
item = { id: userRole.Normal, categoryId: userRole.Normal, description: 'Normal' };
roles.push(item);
this.Roles.set(roles);
}
loadData(id: number): void {
this.subscription.add(
this.lookupService.loadValidationPoint()
.subscribe({
next: x => {
this.validationPoints.set(x.data);
if (id > 0) {
this.subscription.add(
this.adminUserService.loadAdminuserById(id)
.subscribe({
next: x => this.assignValue(x.data),
error: e => console.error("error ", e.message)
}));
}
},
error: e => console.error("error ", e)
}
));
}
ngOnInit(): void {
this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/adminuser';
const id = Number(this.route.snapshot.paramMap.get('id'));
// now load thing up
const user = Utils.getCurrentUser();
// console.log(this.msg + "current login user ", user);
if (user.username === '')
alert("you are not login.");
else
this.loginUser = user.firstName;
this._id = id;
//console.log(this.msg + " " + id );
this.subscription.add(this.adminuserForm.valueChanges.subscribe(x => this.isChange = false));
this.subscription.add(this.subChanged$.subscribe(x => this.isChange = x));
this.loadData(id);
}
getEditText(): string {
if (this._id > 0)
return "Edit Admin User";
else
return "New Admin User";
}
// this for disable submit button
get isFieldsChange() {
const chan = this.isChange || !this.adminuserForm.valid; // this disable so need true valid = true not
//console.log(this.msg + 'is fields change', chan);
return chan;
}
searchUser(): void {
const staffid = this.adminuserForm.controls["stafflinkNo"].value ?? '';
// console.log(this.msg + " the staffid is ", staffid);
if (staffid != '') {
//this.form.controls['your form control name'].value
this.adminUserService.getStaffLinkId(staffid).subscribe(
{
next: x => {
//console.log(this.msg + " this is stafflink no ", x);
// now get current user.
if (x.data) {
//this.error = true;
const fname = x.data.firstName + " " + x.data.lastName;
this.adminuserForm.patchValue({ name: fname, addedBy: this.loginUser });
}
else {
this.messageService.add({ severity: 'error', summary: 'Error', detail: "can not find stafflinkNo:" + staffid });
// this.adminuserForm.patchValue({name:x.data.firstName + " " + x.data.lastName
}
},
error: e => {
console.log("error ", e);
}
});
}
else {
this.messageService.add({ severity: 'error', summary: 'Error', detail: "please enter staff link no" });
}
}
assignValue(adminuser: AdminUser): void {
this.adminuserForm.patchValue({
id: adminuser.id,
stafflinkNo: adminuser.stafflinkNo,
name: adminuser.name,
addedBy: adminuser.addedBy,
addedOn: adminuser.addedOn,
active: adminuser.active,
roleType: adminuser.roleType,
validationPointId: adminuser.validationPointId
});
// disable use false//true for not disable.
this.subChanged$.next(true);
}
// convenience getter for easy access in form fields
get f() { return this.adminuserForm.controls; }
onSubmit(): void {
// if form valid then go save
//make sure
const okToSave = this.adminuserForm.valid;
if (okToSave) {
let adminuserValue = this.adminuserForm.value;
let adminuser: AdminUser = {
id: adminuserValue.id ?? -1,
stafflinkNo: adminuserValue.stafflinkNo ?? '',
name: adminuserValue.name ?? '',
addedBy: adminuserValue.addedBy ?? '',
addedOn: new Date(),
active: adminuserValue.active ?? false,
roleType: adminuserValue.roleType ?? 0,
validationPointId: adminuserValue.validationPointId ?? 0,
};
this.subscription.add(
this.adminUserService.saveAdminuser(adminuser).subscribe(x => {
if (x.statusCode >= 1) {
this.messageService.add({ severity: 'success', summary: 'Success', detail: "Save is OK" });
this.router.navigate([this.returnUrl]);
}
else {
this.messageService.add({ severity: 'error', summary: 'Error', detail: "Fail to save" });
}
},
error => {
console.log("error ", error);
}
)
);
}
}
goBack(): void {
console.log("the return url", this.returnUrl);
this.router.navigate([this.returnUrl]);
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
@@ -0,0 +1,51 @@
import { Injectable, Inject } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { AdminUser, AdminUserView, ResultModel,ConfigureUrl,User } from '../models';
import { AppSettingService } from '../shares';
@Injectable({ providedIn: 'root' })
export class AdminUserService {
constructor(private http: HttpClient,
private appSetting :AppSettingService
) {}
loadAdminusers(): Observable<ResultModel<AdminUserView[]>> {
let config = { headers : { 'Content-Type': 'application/json' } };
//const baseUrl = ConfigureUrl.baseUrl + "/"+ ConfigureUrl.adminUserUrl;
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.adminUserUrl;
return this.http.get<ResultModel<AdminUserView[]>>(baseUrl);
}
getStaffLinkId(staffid:string) :Observable<ResultModel<User>>{
const userUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.userByStaffIdUrl;
let params = new HttpParams().set("stafflinkNo", ""+staffid);
let headers = new HttpHeaders().set('Content-Type', 'application/json');
let options = {
headers: headers,
params: params
};
return this.http.get<ResultModel<User>>(userUrl, options);
}
loadAdminuserById(id:number): Observable<ResultModel<AdminUser>> {
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.adminUserUrl;
let params = new HttpParams().set("id", ""+id);
let headers = new HttpHeaders().set('Content-Type', 'application/json');
let options = {
headers: headers,
params: params
};
//return this.http.get<AdminUser>(this.baseUrl + 'api/Adminuser/LoadAdminuserById',options);
return this.http.get<ResultModel<AdminUser>>(baseUrl + "/" + id);
}
saveAdminuser(jsData:AdminUser): Observable<ResultModel<number>> { //insert Adminuser
let config = { headers : { 'Content-Type': 'application/json' } };
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.adminUserUrl;
return this.http.post<ResultModel<number>>(baseUrl, jsData, config);
}
deleteAdminuser(id:number): Observable<ResultModel<number>>{
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.adminUserUrl;
let config = { headers : { 'Content-Type': 'application/json' } };
return this.http.delete<ResultModel<number>>(baseUrl + "/" + id);
}
}
+4
View File
@@ -0,0 +1,4 @@
export * from './adminuser.component';
export * from './adminuser.edit.component';
export * from './adminuser.service';
+48
View File
@@ -0,0 +1,48 @@
import { ApplicationConfig, inject, provideAppInitializer, provideBrowserGlobalErrorListeners } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import { PrimeNG, providePrimeNG } from 'primeng/config';
import { ConfirmationService, MessageService } from 'primeng/api';
import { provideHttpClient, withInterceptors, withXhr } from '@angular/common/http';
import { AppSettingService, ErrorInterceptor, initializeApp, JwtInterceptor } from './shares';
import MyPreset from './mytheme_aura';
export const appConfig: ApplicationConfig = {
providers: [
MessageService,
ConfirmationService,
provideAppInitializer(() => {
const primeNG = inject(PrimeNG);
const appSettingService = inject(AppSettingService);
const loadAppSetting = initializeApp();
// Return the promise chain so Angular blocks app loading until the request completes
return loadAppSetting().then((result) => {
// Read the setting directly from the populated service instance
const settings = appSettingService.appSetting;
console.log('Loaded app settings:', settings, result);
const licenseKey = settings?.primeNGLicense || '';
console.log("primeng license", licenseKey);
// Apply configuration to PrimeNG
primeNG.setConfig({
license: licenseKey,
theme: {
preset: MyPreset,
options: {
cssLayer: {
name: 'primeng',
order: 'theme, base, primeng'
}
}
}
});
});
}),
provideHttpClient(withXhr(), withInterceptors([JwtInterceptor, ErrorInterceptor])),
provideBrowserGlobalErrorListeners(),
provideRouter(routes)
]
};
View File
+6
View File
@@ -0,0 +1,6 @@
@if (isAuth() == true) {
<app-nav-toolbar ></app-nav-toolbar>
}
<router-outlet />
<p-confirmdialog></p-confirmdialog>
<p-toast></p-toast>
+28
View File
@@ -0,0 +1,28 @@
import { Routes } from '@angular/router';
import { AuthGuard } from './route-guard';
import { AdminUserComponent, AdminUserEditComponent } from './adminuser';
import { LoginComponent } from './login';
import { ConcessionTypeComponent, ConcessiontypeEditComponent } from './concessiontype';
import { ValidationPointComponent, ValidationpointEditComponent } from './validationPoint';
import { ConcessionValidationComponent, ConcessionValidationEditComponent } from './concessionValidation';
import { ConcessionvalidationReportComponent } from './concessionvalidationreport';
export const routes: Routes = [
{ path: 'login', component: LoginComponent },
{ path: 'adminuser', component: AdminUserComponent, canActivate: [AuthGuard], data: { roleAllowed: 'Admin' } },
{ path: 'adminuser/:id', component: AdminUserEditComponent, canActivate: [AuthGuard], data: { roleAllowed: 'Admin' } },
{ path: 'concessiontype', component: ConcessionTypeComponent, canActivate: [AuthGuard], data: { roleAllowed: 'Admin' } },
{ path: 'concessiontype/:id', component: ConcessiontypeEditComponent, canActivate: [AuthGuard], data: { roleAllowed: 'Admin' } },
{ path: 'validationpoint', component: ValidationPointComponent, canActivate: [AuthGuard], data: { roleAllowed: 'Admin' } },
{ path: 'validationpoint/:id', component: ValidationpointEditComponent, canActivate: [AuthGuard], data: { roleAllowed: 'Admin' } },
{ path: 'concessionvalidation', component: ConcessionValidationComponent, canActivate: [AuthGuard] },
{ path: 'concessionvalidation/:id', component: ConcessionValidationEditComponent, canActivate: [AuthGuard] },
{ path: 'app-concessionvalidation-report', component: ConcessionvalidationReportComponent, canActivate: [AuthGuard], data: { roleAllowed: 'Admin' } },
{ path: '', redirectTo: 'login', pathMatch: 'full' },
{ path: '**', redirectTo: 'login' },
];
+19
View File
@@ -0,0 +1,19 @@
import { Component, computed, inject, signal, viewChild } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { ConfirmDialogModule } from 'primeng/confirmdialog';
import { ToastModule } from 'primeng/toast';
import { NavToolarComponent } from './nav-toolbar/nav-toolbar.component';
import { AuthenticationService } from './user-services';
@Component({
imports: [RouterOutlet, ConfirmDialogModule, ToastModule, NavToolarComponent],
selector: 'app-root',
styleUrl: './app.css',
templateUrl: './app.html',
})
export class App {
authService = inject(AuthenticationService);
protected readonly title = signal('carparkvalidation');
isAuth = computed(() => this.authService.authChange().firstName != '');
}
@@ -0,0 +1,12 @@
table {
width: 100%;
}
.mat-form-field {
font-size: 14px;
width: 100%;
}
td.mat-column-edit, .mat-column-delete {
width: 35px;
padding-right: 2px;
}
@@ -0,0 +1,99 @@
<div class="edit-content">
<h3>Concession Validation</h3>
@if (isAdmin) {
<div >
<div class="flex flex-row gap-2 w-full">
<label>Choose a from date</label>
<p-datepicker [(ngModel)]="fromDate" dateFormat="dd/mm/yy" />
<label>Choose a to date</label>
<p-datepicker [(ngModel)]="toDate" dateFormat="dd/mm/yy" />
<button pButton (click)="onLoad()" >
Load
</button>
</div>
</div>
}
<div class="addlink">
<a class="p-ripple p-button p-component flex justify-self-end mb-2" [routerLink]='["/concessionvalidation", 0]'
[queryParams]="{returnUrl:'/concessionvalidation'}"
(click)="setDate()">
Add Concession Validation
</a>
</div>
<p-table [value]="dataSource()" rowHover="true" dataKey="id"
[rows]="25" [rowsPerPageOptions]="[ 25, 50,100]" [paginator]="true">
<ng-template #header>
<tr>
<th >Date </th>
<th >Concession Type </th>
<th >Concession Card Number</th>
<th >Concession Holder Name</th>
<th >Validation Point </th>
<th>Expiry date checked</th>
@if(isAdmin) {
<th >Staff Name</th>
<th>Delete</th>
}
<th >Edit</th>
<!-- validateDate Column -->
</ng-template>
<ng-template #body let-element>
<tr>
<td > {{element.validateDate | date: 'dd/MM/yyyy HH:mm'}} </td>
<td > {{element.concessionType}} </td>
<td > {{element.concessionCard}} </td>
<td > {{element.concessionHolder}} </td>
<td > {{element.validationPoint}} </td>
<td >
@if (element.concessionExpiry == true)
{
<svg data-p-icon="check" color="green"></svg>
}
@else {
<svg data-p-icon="times" color="red"></svg>
}
</td>
<!-- staffFirstName Column -->
@if(isAdmin) {
<td >{{element.staffFirstName}} {{element.staffLastName}} </td>
<td >
<button pButton (click)='deleteItem(element.id)'>
<svg data-p-icon="times"></svg>
</button>
</td>
}
<td>
<button pButton (click)="showEdit(element)" >
<svg data-p-icon="pencil"></svg>
</button>
</td>
</ng-template>
</p-table>
@@ -0,0 +1,149 @@
import { Component, OnInit, OnDestroy, signal, inject } from '@angular/core';
import { ConcessionValidation } from '../models';
import { Utils } from '../shares';
import { Router, RouterModule } from '@angular/router';
import { Subscription } from 'rxjs';
import { ConcessionValidationService } from './concessionvalidation.service';
import { DatePickerModule } from 'primeng/datepicker';
import { ConfirmationService, MessageService } from 'primeng/api';
import { TableModule } from 'primeng/table';
import { ButtonModule } from 'primeng/button';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { Pencil } from '@primeicons/angular/pencil';
import { Times } from '@primeicons/angular/times';
import { Check } from '@primeicons/angular/check';
@Component({
selector: 'concessionvalidation-list',
templateUrl: './concessionvalidation.component.html',
imports: [TableModule, ButtonModule, CommonModule, FormsModule, Check, Times, Pencil, DatePickerModule, RouterModule],
styleUrls: ['./concessionvalidation.component.css']
})
export class ConcessionValidationComponent implements OnInit, OnDestroy {
private concessionValidationService = inject(ConcessionValidationService);
private router = inject(Router);
private messageService = inject(MessageService);
private confirmationService = inject(ConfirmationService);
dataSource = signal<ConcessionValidation[]>([]);
isAdmin = false;
isAllowFilter = true;
fromDate = new Date();
toDate = new Date();
username = '';
private subscription: Subscription = new Subscription();
msg = "[ConcessionValidation component]";
/*
private store: Store<appValidationState>
*/
constructor(
) {
this.isAdmin = Utils.getIsAdmin();
}
//KeyboardEvent
applyFilter(event: Event) {
const filterValue = (event.target as HTMLInputElement).value;
// this.dataSource.filter = filterValue.trim().toLowerCase();
}
ngOnInit(): void {
const user = Utils.getCurrentUser();
// console.log(this.msg + "current login user ", user);
if (user.username === "") {
user.username = "60249360";
this.messageService.add({ severity: 'error', summary: 'Error', detail: "you are not login! using my number " + user.username });
}
this.username = user.username;
if (this.isAdmin)
this.username = '';
const dateRange = this.concessionValidationService.getDate();
// console.log("the date range for now ", dateRange);
if (dateRange.fromDate != '')
this.fromDate = dateRange.fromDate;
if (dateRange.toDate != '')
this.toDate = dateRange.toDate;
this.onLoad();
/*
this.store.dispatch(validationActions.LoadValidationpoints());
this.store.pipe(select(validationSelector.getAllValidations)).subscribe(result => this.dataSource.data = result);
*/
}
onLoad(): void {
const cDate = this.fromDate;
const tDate = this.toDate;
this.subscription.add(
this.concessionValidationService.loadConcessionvalidationByStaffId(this.username, cDate, tDate)
.subscribe({
next: result => {
//console.log(this.msg + "onInit load Data by staffId "+ this.username, result);
this.dataSource.set(result.data);
}, error: e => console.error("error in loading concession validation", e)
})
);
//this.dataList$ = this.concessionValidationService.loadConcessionvalidationByStaffId(this.username, cDate, tDate)
// .pipe(catchError(err => {this.toastr.error(err.message); return EMPTY}));
}
setDate(): void {
this.concessionValidationService.setDateRange(this.fromDate, this.toDate);
}
showEdit(item: ConcessionValidation) {
// console.log(this.msg + "on row click", item);
this.setDate();
this.router.navigate(['/concessionvalidation/' + item.id], { queryParams: { returnUrl: '/concessionvalidation' } });
}
deleteItem(id: number): void {
const message = "Are you sure you want to delete this?";
const title = " Confirmation";
this.confirmationService.confirm({
message: message,
header: title,
icon: 'pi pi-exclamation-triangle',
accept: () => {
this.concessionValidationService.deleteConcessionvalidation(id)
.subscribe(result => {
console.log(this.msg + " deleteItem success", result);
let data = this.dataSource();
let index: number = data.findIndex(d => d.id === id);
console.log(this.msg + "delete from datasource");
data.splice(index, 1)
this.dataSource.set(data);
},
error => {
console.log("error ", error);
}
);
},
reject: () => {
console.log(this.msg + "click on No to delete");
}
});
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
@@ -0,0 +1,12 @@
table {
width: 100%;
}
.mat-form-field {
font-size: 14px;
width: 100%;
}
td.mat-column-edit, .mat-column-delete {
width: 35px;
padding-right: 2px;
}
@@ -0,0 +1,68 @@
<div class="p-10">
<div class="title">
{{getEditText()}}
</div>
<form [formGroup]="concessionvalidationForm" (ngSubmit)="onSubmit()">
<div class="flex flex-col">
<div class="m-2">
<label class="flex w-full">Concession Card Number<strong class="app-require">*</strong></label>
<input pInputText formControlName="concessionCard" maxlength="60" name="concessionCard" (blur)="searchCard()"
placeholder="Concession Card Number" required>
</div>
@if(isAdmin) {
<div class="m-2">
<label for="time" class="flex w-full">Current Date</label>
<p-datepicker formControlName="validateDate" [showTime]="true" inputId="time"
dateFormat="dd/mm/yy"></p-datepicker>
</div>
}
<!--end-->
<div class="m-2">
<label class="flex w-full">Concession Type<strong class="app-require">*</strong></label>
<p-select formControlName="concessionTypeId"
[options]="concessionTypes()"
optionLabel="description" optionValue="id">
</p-select>
</div>
<div class="m-2">
<label class="flex w-full">Concession Holder Name<strong class="app-require">*</strong></label>
<input pInputText formControlName="concessionHolder" maxlength="100" name=""
placeholder="Concession Holder Name" >
</div>
<div class="m-2">
<label class="flex w-full"> Expiry date checked <strong
class="app-require">*</strong> </label>
<p-checkbox formControlName="concessionExpiry" [binary]="true"></p-checkbox>
@if(isAdmin) {
<div >
<label class="flex w-full">Validation Point<strong class="app-require">*</strong></label>
<p-select formControlName="validationPointId" [options]="validationPoints()" optionLabel="description" optionValue="id">
</p-select>
</div>
}
</div>
</div>
<div class="flex justify-content-end mt-2">
<button class="mr-2" type="submit" pButton [disabled]="isFieldsChange">Submit</button>
<button type="button" pButton (click)="goBack()">Cancel</button>
</div>
</form>
<!--pre>{{ concessionvalidationForm.value|json}}</pre-->
</div>
@@ -0,0 +1,296 @@
import { Component, inject, OnDestroy, OnInit, signal, ViewChild } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { FormGroup, Validators, ReactiveFormsModule, FormBuilder, FormControl } from '@angular/forms';
import { ConcessionValidation, Lookup, ResultModel } from '../models';
import { Subject, Subscription } from 'rxjs';
import { LookupService } from '../shares';
import { ConcessionValidationService } from './concessionvalidation.service';
import { Utils } from '../shares';
import moment from 'moment';
import { ConfirmationService, MessageService } from 'primeng/api';
import { ButtonModule } from 'primeng/button';
import { InputTextModule } from 'primeng/inputtext';
import { CheckboxModule } from 'primeng/checkbox';
import { DatePickerModule } from 'primeng/datepicker';
import { SelectModule } from 'primeng/select';
@Component({
templateUrl: 'concessionvalidation.edit.component.html',
selector: 'concessionvalidation-edit',
imports: [ButtonModule, InputTextModule, CheckboxModule, DatePickerModule,
SelectModule, ReactiveFormsModule],
styleUrls: ['concessionvalidation.edit.component.css']
})
export class ConcessionValidationEditComponent implements OnInit, OnDestroy {
returnUrl = "";
private formBuilder = inject(FormBuilder);
private lookupService = inject(LookupService);
private concessionValidationService = inject(ConcessionValidationService);
private router = inject(Router);
private confirmationService = inject(ConfirmationService);
private messageService = inject(MessageService);
private route = inject(ActivatedRoute);
msg = "[concessionvalidation edit Component] "
isChange = true; // disable use false//true for not disable. make sure it true is disable button.
subChanged$ = new Subject<boolean>();
_id = -1;
isAdmin = false;
concessionTypes = signal<Lookup[]>([]);
validationPoints = signal<Lookup[]>([]);
private subscription: Subscription = new Subscription();
concessionvalidationForm = this.formBuilder.group({
id: [0], //Validators.required
validateDate: new FormControl<Date | null>(null), //Validators.required
concessionCard: ['', Validators.required],
concessionHolder: ['', Validators.required],
concessionExpiry: [false, Validators.required], //Validators.required
concessionTypeId: [-1, Validators.min(1)],
stafflinkNo: [''], //Validators.required
validationPointId: [-1, Validators.min(1)],
validationPoint: [''], //Validators.required
staffFirstName: [''], //Validators.required
staffLastName: [''], //Validators.required
staffEmail: [''], //Validators.required
active: [false], //Validators.required
});
constructor() {
/*
this.concessionTypes = [];
let item:Lookup = {id:1,categoryId:0, description:'Health Care Card'};
this.concessionTypes.push(item);
item = {id:3,categoryId:1, description:'Gold Veterans Affairs Card'};
this.concessionTypes.push(item);
item = {id:3,categoryId:1, description:'Pensioner Concession Card'};
this.concessionTypes.push(item);
*/
}
searchCard(): void {
const cardNo = this.concessionvalidationForm.controls["concessionCard"].value ?? '';
if (cardNo != "") {
const card$ = this.concessionValidationService.loadConcessionvalidationByCard(cardNo);
this.subscription.add(card$.subscribe({
next: x => {
if (x.statusCode == 1) {
const data = x.data;
this.concessionvalidationForm.patchValue({
concessionHolder: data.concessionHolder,
concessionTypeId: data.concessionTypeId,
});
}
}
})
);
}
}
ngOnInit(): void {
this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/';
const id = Number(this.route.snapshot.paramMap.get('id'));
// now load thing up
this._id = id;
this.isAdmin = Utils.getIsAdmin();
this.subscription.add(this.lookupService.loadConcessionType().subscribe({
next: x => this.concessionTypes.set(x.data),
error: e => console.error("error loading concession type", e)
}
));
this.subscription.add(
this.lookupService.loadValidationPoint().subscribe({
next: x => this.validationPoints.set(x.data),
error: e => console.error("error validation Point", e)
})
);
this.subscription.add(this.concessionvalidationForm.valueChanges.subscribe(x => this.isChange = false));
this.subscription.add(this.subChanged$.subscribe(x => this.isChange = x));
const user = Utils.getCurrentUser();
console.log(this.msg + "current login user ", user);
if (user.username === "") {
user.username = "60249360";
this.messageService.add({ severity: 'error', summary: 'Error', detail: "you are not login! using my number " + user.username });
}
if (this._id < 1) {
this.concessionvalidationForm.patchValue({
validateDate: new Date(),
stafflinkNo: user.username,
staffFirstName: user.firstName,
staffLastName: user.lastName,
staffEmail: user.email,
validationPointId: user.validationPointId,
active: true
});
}
else {
this.subscription.add(
this.concessionValidationService.loadConcessionvalidationById(id)
.subscribe({
next: x => this.assignValue(x.data),
error: e => console.log(e.message)
}));
// console.log(this.msg + " load from db"+id);
}
}
get isFieldsChange() {
const chan = this.isChange || !this.concessionvalidationForm.valid; // this disable so need true valid = true not
const fvalid = this.concessionvalidationForm.valid;
// console.log(this.msg + "is fields change is valid: " + fvalid , chan,);
return chan;
}
getEditText(): string {
if (this._id > 0)
return "Edit Concession Validation";
else
return "New Concession Validation";
}
onChangeValidation($event: Event) {
//$event.target.value
//this.selectedCar = (event.target as HTMLSelectElement).value;
var val = ($event.target as HTMLSelectElement).value;
// console.log("the log for val " , val);
}
assignValue(concessionvalidation: ConcessionValidation): void {
this.concessionvalidationForm.patchValue({
id: concessionvalidation.id,
validateDate: moment(concessionvalidation.validateDate).toDate(),
concessionCard: concessionvalidation.concessionCard,
concessionHolder: concessionvalidation.concessionHolder,
concessionExpiry: concessionvalidation.concessionExpiry,
concessionTypeId: concessionvalidation.concessionTypeId,
stafflinkNo: concessionvalidation.stafflinkNo,
staffFirstName: concessionvalidation.staffFirstName,
staffLastName: concessionvalidation.staffLastName,
staffEmail: concessionvalidation.staffEmail,
validationPointId: concessionvalidation.validationPointId,
active: concessionvalidation.active,
});
// disable use false//true for not disable.
this.subChanged$.next(true);
}
// convenience getter for easy access in form fields
get f() { return this.concessionvalidationForm.controls; }
onSubmit(): void {
const OkToSave = this.concessionvalidationForm.valid;
const checkActive = this.concessionvalidationForm.value.concessionExpiry ?? false;
console.log("onsubmit value", checkActive, this.concessionvalidationForm.value);
if (checkActive == false) {
this.messageService.add({ severity: 'error', summary: 'Check Concession Expiry', detail: 'Not Check Concession Expiry' });
return;
}
if (OkToSave) {
const concessionvalidationValue = this.concessionvalidationForm.value;
const concessionvalidation: ConcessionValidation = {
id: concessionvalidationValue.id ?? 0,
validateDate: moment(concessionvalidationValue.validateDate).toDate(),
concessionCard: concessionvalidationValue.concessionCard ?? '',
concessionHolder: concessionvalidationValue.concessionHolder ?? '',
concessionExpiry: concessionvalidationValue.concessionExpiry ?? false,
concessionTypeId: concessionvalidationValue.concessionTypeId ?? 0,
stafflinkNo: concessionvalidationValue.stafflinkNo ?? '',
staffFirstName: concessionvalidationValue.staffFirstName ?? '',
staffLastName: concessionvalidationValue.staffLastName ?? '',
staffEmail: concessionvalidationValue.staffEmail ?? '',
validationPointId: concessionvalidationValue.validationPointId ?? 0,
active: concessionvalidationValue.active ?? false,
};
// console.log(this.msg + "this is OKTOsave", concessionvalidation);
//if edit mode just save it don't check
if (concessionvalidation.id > 0) {
this.saveConcession(concessionvalidation);
}
else {
//check first only if new
this.checkAndSave(concessionvalidation);
}
}
else {
// console.log(this.msg + "this is NOT OKTOsave");
this.messageService.add({ severity: 'error', summary: 'Error', detail: "please fill in the required fields" });
}
}
checkAndSave(concessionvalidation: ConcessionValidation): void {
const currentDate = moment(concessionvalidation.validateDate).format("YYYY-MM-DD");
const id = concessionvalidation.id;
this.subscription.add(
this.concessionValidationService.checkConcessionValidationByStaff(concessionvalidation.stafflinkNo,
concessionvalidation.concessionCard, currentDate, id)
.subscribe(x => {
let okTo = true;
if (x.data < 0) {
const message = "This card was used earlier today. Is it Ok to continue?";
const title = "Alert";
this.confirmationService.confirm({
message: message,
header: 'Confirmation',
icon: 'pi pi-exclamation-triangle',
accept: () => {
this.saveConcession(concessionvalidation);
},
reject: () => {
this.router.navigate([this.returnUrl]);
}
});
}
else {
this.saveConcession(concessionvalidation);
}
})
);
}
saveConcession(concessionvalidation: ConcessionValidation): void {
//console.log(this.msg + " Save Concession validation to server");
this.subscription.add(
this.concessionValidationService.saveConcessionvalidation(concessionvalidation)
.subscribe({
next: x => {
if (x.statusCode >= 1) {
this.messageService.add({ severity: 'success', summary: 'Success', detail: "Save is OK" });
this.router.navigate([this.returnUrl]);
}
else
this.messageService.add({ severity: 'error', summary: 'Fail to Save', detail: x.message });
}, error: e => {
const message = e || e.message;
this.messageService.add({ severity: 'error', summary: 'Fail to Save', detail: message });
console.log("error ", e);
}
}
));
}
goBack(): void {
this.router.navigate([this.returnUrl]);
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
@@ -0,0 +1,102 @@
import { Injectable, Inject } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { ConcessionValidation, ResultModel, ConfigureUrl } from '../models';
import moment from 'moment';
import { AppSettingService } from '../shares';
@Injectable({ providedIn: 'root' })
export class ConcessionValidationService {
private dateRange: any;
constructor(private http: HttpClient,
private appSetting: AppSettingService
) {
this.dateRange = {};
this.dateRange.fromDate = '';
this.dateRange.toDate = '';
console.log("constructor concessionValidationService daterange", this.dateRange);
}
public setDateRange(fromDate: any, toDate: any) {
this.dateRange.fromDate = moment(fromDate).toDate();
this.dateRange.toDate = moment(toDate).toDate();
// console.log("concessionValidationService setdaterange", this.dateRange);
}
public getDate(): any {
// console.log("concessionValidationService getdaterange", this.dateRange);
return this.dateRange;
}
loadConcessionvalidations(): Observable<ResultModel<ConcessionValidation[]>> {
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.concessionValidationUrl;
let config = { headers: { 'Content-Type': 'application/json' } };
// console.log("the concession", baseUrl);
return this.http.get<ResultModel<ConcessionValidation[]>>(baseUrl);
}
loadConcessionvalidationByStaffId(staffLinkId: string, fromDate: Date, toDate: Date): Observable<ResultModel<ConcessionValidation[]>> {
this.setDateRange(fromDate, toDate);
const strDate = moment(fromDate).format("YYYY-MM-DD");
const strtoDate = moment(toDate).format("YYYY-MM-DD");
const url = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.concessionValidationByIdUrl;
const params = new HttpParams().set("staffLinkNo", staffLinkId)
.set("fromDate", strDate)
.set("toDate", strtoDate);
const headers = new HttpHeaders().set('Content-Type', 'application/json');
const options = {
headers: headers,
params: params
};
//console.log("loadConcessionvalidationByStaffId url", url);
return this.http.get<ResultModel<ConcessionValidation[]>>(url, options);
}
loadConcessionvalidationById(id: number): Observable<ResultModel<ConcessionValidation>> {
let params = new HttpParams().set("id", "" + id);
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.concessionValidationUrl;
let headers = new HttpHeaders().set('Content-Type', 'application/json');
let options = {
headers: headers,
params: params
};
//return this.http.get<Concessionvalidation>(this.baseUrl + 'api/Concessionvalidation/LoadConcessionvalidationById',options);
return this.http.get<ResultModel<ConcessionValidation>>(baseUrl + "/" + id);
}
loadConcessionvalidationByCard(cardNo: string): Observable<ResultModel<ConcessionValidation>> {
const data = { cardNo };
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.concessionValidationUrl + "/GetConcessionCard";
/*
let params = new HttpParams().set("id", "" + id);
let headers = new HttpHeaders().set('Content-Type', 'application/json');
let options = {
headers: headers,
params: params
};
*/
//return this.http.get<Concessionvalidation>(this.baseUrl + 'api/Concessionvalidation/LoadConcessionvalidationById',options);
return this.http.post<ResultModel<ConcessionValidation>>(baseUrl, data);
}
checkConcessionValidationByStaff(staffLinkNo: string, concessionCard: string, currentDate: string, id: number): Observable<ResultModel<number>> {
let params = new HttpParams().set("staffLinkNo", staffLinkNo)
.set("concessionCard", concessionCard)
.set("currentDate", currentDate)
.set("id", "" + id);
let headers = new HttpHeaders().set('Content-Type', 'application/json');
let options = {
headers: headers,
params: params
};
const baseUrl = this.appSetting.appSetting.baseUrl;
const url = baseUrl + "/" + ConfigureUrl.CheckConcessionValidationByStaffUrl;
//return this.http.get<Concessionvalidation>(this.baseUrl + 'api/Concessionvalidation/LoadConcessionvalidationById',options);
return this.http.get<ResultModel<number>>(url, options);
}
saveConcessionvalidation(item: ConcessionValidation): Observable<ResultModel<number>> { //insert Concessionvalidation
let config = { headers: { 'Content-Type': 'application/json' } };
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.concessionValidationUrl;
return this.http.post<ResultModel<number>>(baseUrl, item, config);
}
deleteConcessionvalidation(Id: number): Observable<ResultModel<number>> {
let config = { headers: { 'Content-Type': 'application/json' } };
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.concessionValidationUrl;
return this.http.delete<ResultModel<number>>(baseUrl + "/" + Id);
}
}
@@ -0,0 +1,4 @@
export * from './concessionvalidation.component';
export * from './concessionvalidation.edit.component';
export * from './concessionvalidation.service';
@@ -0,0 +1,12 @@
table {
width: 100%;
}
.mat-form-field {
font-size: 14px;
width: 100%;
}
td.mat-column-edit, .mat-column-delete {
width: 35px;
padding-right: 2px;
}
@@ -0,0 +1,45 @@
<div class="edit-content">
<h3>Concession Type</h3>
<div class="addlink">
<a class="p-ripple p-button p-component flex justify-self-end mb-2" [routerLink]='["/concessiontype", -1]' [queryParams]="{returnUrl:'/concessiontype'}">
Add Concession Type
</a>
</div>
<p-table [value]="dataSource()" rowHover="true" dataKey="id"
[rows]="25" [rowsPerPageOptions]="[ 25, 50,100]" [paginator]="true">
<ng-template #header>
<tr>
<th>Description</th>
<th>Display</th>
<th>Active</th>
<th>Edit</th>
</tr>
</ng-template>
<ng-template #body let-item>
<tr>
<td>{{ item.description }}</td>
<td> {{item.display}}</td>
<td>
@if(item.active == true) {
<svg data-p-icon="check" color="green"></svg>
}
@else {
<svg data-p-icon="times" color="red"></svg>
}
</td>
<td>
<button pButton (click)="showEdit(item)">
<svg data-p-icon="pencil"></svg>
</button>
</td>
</tr>
</ng-template>
</p-table>
</div>
@@ -0,0 +1,99 @@
import { Component, OnInit, OnDestroy, signal, inject } from '@angular/core';
import { ConcessionTypeService } from './concessiontype.service';
import { ConcessionType } from '../models';
import { take } from 'rxjs/operators';
import { Router, RouterModule } from '@angular/router';
import { Subscription } from 'rxjs';
import { MessageService } from 'primeng/api';
import { ButtonModule } from 'primeng/button';
import { Pencil } from '@primeicons/angular/pencil';
import { TableModule } from 'primeng/table';
import { Check } from '@primeicons/angular/check';
import { Times } from '@primeicons/angular/times';
@Component({
selector: 'concessiontype-list',
templateUrl: './concessiontype.component.html',
imports: [ButtonModule, TableModule, RouterModule, Pencil, Check, Times],
styleUrls: ['./concessiontype.component.css']
})
export class ConcessionTypeComponent implements OnInit, OnDestroy {
private concessionTypeService = inject(ConcessionTypeService);
private messageService = inject(MessageService);
private router = inject(Router);
dataSource = signal<ConcessionType[]>([]);
private subscription: Subscription = new Subscription();
msg = "[concessionType.com]";
/*
private store: Store<appValidationState>
*/
constructor(
) {
}
/*
applyFilter($event:any) {
const filterValue = $event.target.value;
this.dataSource.filter = filterValue.trim().toLowerCase();
}
*/
ngOnInit(): void {
this.subscription.add(
this.concessionTypeService.loadConcessiontypes().subscribe(
{
next: result => {
// console.log(this.msg + "onInit", result);
this.dataSource.set(result.data);
}, error: e => {
console.log("error ", e);
}
}
)
);
/*
this.store.dispatch(validationActions.LoadValidationpoints());
this.store.pipe(select(validationSelector.getAllValidations)).subscribe(result => this.dataSource.data = result);
*/
}
showEdit(item: ConcessionType) {
console.log(this.msg + "on row click", item);
this.router.navigate(['/concessiontype/' + item.id], { queryParams: { returnUrl: '/concessiontype' } });
}
deleteItem(id: number): void {
this.concessionTypeService.deleteConcessiontype(id)
.pipe(take(1))
.subscribe(result => {
// console.log(this.msg + " deleteItem success", result);
let data = this.dataSource();
let index: number = data.findIndex(d => d.id === id);
// console.log(this.msg + "delete from datasource");
data.splice(index, 1)
this.dataSource.set(data);
},
error => {
console.log("error ", error);
}
);
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
@@ -0,0 +1,12 @@
table {
width: 100%;
}
.mat-form-field {
font-size: 14px;
width: 100%;
}
td.mat-column-edit, .mat-column-delete {
width: 35px;
padding-right: 2px;
}
@@ -0,0 +1,34 @@
<div class="edit-content">
<div class="title"> {{getEditText()}} </div>
<form [formGroup]="concessiontypeForm" (ngSubmit)="onSubmit()">
<div class="flex flex-col">
<div>
<label class="flex w-full">Concession Type<strong class="app-require">*</strong></label>
<input pInputText formControlName="description" maxlength="80"
placeholder="description" >
</div>
<div>
<label class="flex w-full">Display</label>
<input pInputText formControlName="display" maxlength="80"
placeholder="display" >
</div>
<div>
<label for="acheckbox" class="mr-2">Active</label>
<p-checkbox formControlName="active" [binary]="true" inputId="acheckbox" size="small" ></p-checkbox>
</div>
</div>
<div class="flex justify-content-end mt-2">
<button class="mr-2" type="submit" pButton
[disabled]="isFieldsChange">Submit</button>
<button type="button" pButton (click)="goBack()">Cancel</button>
</div>
</form>
<!--pre>{{ concessiontypeForm.value|json}}</pre-->
</div>
@@ -0,0 +1,122 @@
import { Component, inject, OnInit, ViewChild } from '@angular/core';
import { UntypedFormBuilder, FormGroup, Validators, ReactiveFormsModule, FormBuilder } from '@angular/forms';
import { Router, ActivatedRoute } from '@angular/router';
import { ConcessionType } from '../models';
import { Subject, pipe, Subscription } from 'rxjs';
import { ConcessionTypeService } from './concessiontype.service';
import { MessageService } from 'primeng/api';
import { ButtonModule } from 'primeng/button';
import { CheckboxModule } from 'primeng/checkbox';
import { InputTextModule } from 'primeng/inputtext';
@Component({
templateUrl: 'concessiontype.edit.component.html',
selector: 'concessiontype-edit',
imports: [ButtonModule, CheckboxModule, ReactiveFormsModule, InputTextModule],
styleUrls: ['concessiontype.edit.component.css']
})
export class ConcessiontypeEditComponent implements OnInit {
private formBuilder = inject(FormBuilder);
private messageService = inject(MessageService);
private concessionTypeService = inject(ConcessionTypeService);
private route = inject(ActivatedRoute);
private router = inject(Router);
returnUrl = '';
_id = -1;
msg = "[Concession type edit Component] ";
isChange = true; // disable use false//true for not disable. make sure it true is disable button.
private subscription: Subscription = new Subscription();
subChanged$ = new Subject<boolean>();
concessiontypeForm = this.formBuilder.group({
id: [0], //Validators.required
description: [''], //Validators.required
display: [''], //Validators.required
active: [false], //Validators.required
});
constructor() { }
ngOnInit(): void {
this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/';
const id = Number(this.route.snapshot.paramMap.get('id'));
// now load thing up
this.subscription.add(this.concessiontypeForm.valueChanges.subscribe(x => this.isChange = false));
this.subscription.add(this.subChanged$.subscribe(x => this.isChange = x));
if (id > 0) {
this.subscription.add(
this.concessionTypeService.loadConcessiontypeById(id).subscribe({
next: x => {
this.assignValue(x.data)
}, error: e => {
console.log("error ", e);
}
}
)
);
}
}
getEditText(): string {
if (this._id > 0)
return "Edit Concession Type";
else
return "New Concession Type";
}
// this for disable submit button
get isFieldsChange() {
const chan = this.isChange || !this.concessiontypeForm.valid; // this disable so need true valid = true not
//console.log(this.msg + 'is fields change', chan);
return chan;
}
assignValue(concessiontype: ConcessionType): void {
this.concessiontypeForm.patchValue({
id: concessiontype.id,
description: concessiontype.description,
display: concessiontype.display,
active: concessiontype.active,
});
// disable use false//true for not disable.
this.subChanged$.next(true);
}
// convenience getter for easy access in form fields
get f() { return this.concessiontypeForm.controls; }
onSubmit(): void {
// if form valid then go save
//make sure
const okToSave = this.concessiontypeForm.valid;
if (okToSave) {
let concessiontypeValue = this.concessiontypeForm.value;
let concessiontype: ConcessionType = {
id: concessiontypeValue.id ?? 0,
description: concessiontypeValue.description ?? '',
display: concessiontypeValue.display ?? '',
active: concessiontypeValue.active ?? false,
};
this.subscription.add(this.concessionTypeService.saveConcessiontype(concessiontype).subscribe(x => {
//console.log("after save return is", x);
if (x.statusCode > 0) {
//alert("save ok");
this.messageService.add({ severity: 'success', summary: 'Success', detail: "Save is OK" });
this.router.navigate([this.returnUrl]);
//this.router.navigate(['/home/concessiontype'])
}
},
error => {
console.log("error ", error);
}
));
}
}
goBack(): void {
this.router.navigate([this.returnUrl]);
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
@@ -0,0 +1,40 @@
import { Injectable, Inject } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { ConcessionType, ResultModel, ConfigureUrl } from '../models';
import { AppSettingService } from '../shares';
@Injectable({ providedIn: 'root' })
export class ConcessionTypeService {
constructor(private http: HttpClient,
private appSetting :AppSettingService
) {}
loadConcessiontypes(): Observable<ResultModel<ConcessionType[]> > {
const baseUrl = this.appSetting.appSetting.baseUrl + "/" +ConfigureUrl.concessionTypeUrl;
let config = { headers : { 'Content-Type': 'application/json' } };
return this.http.get<ResultModel<ConcessionType[]>>(baseUrl);
}
loadConcessiontypeById(id:number): Observable<ResultModel<ConcessionType>> {
const baseUrl = this.appSetting.appSetting.baseUrl + "/" +ConfigureUrl.concessionTypeUrl;
let params = new HttpParams().set("id", ""+id);
let headers = new HttpHeaders().set('Content-Type', 'application/json');
let options = {
headers: headers,
params: params
};
return this.http.get<ResultModel<ConcessionType>>(baseUrl +"/"+id);
}
saveConcessiontype(concessType:ConcessionType): Observable<ResultModel<number>> { //insert Concessiontype
const baseUrl = this.appSetting.appSetting.baseUrl + "/" +ConfigureUrl.concessionTypeUrl;
let config = { headers : { 'Content-Type': 'application/json' } };
return this.http.post<ResultModel<number>>(baseUrl , concessType, config);
}
deleteConcessiontype(id:number): Observable<ResultModel<number>>{
const baseUrl = this.appSetting.appSetting.baseUrl + "/" +ConfigureUrl.concessionTypeUrl;
let config = { headers : { 'Content-Type': 'application/json' } };
return this.http.delete<ResultModel<number>>(baseUrl +"/" + id);
}
}
+4
View File
@@ -0,0 +1,4 @@
export * from './concessiontype.component';
export * from './concessiontype.edit.component';
export * from './concessiontype.service';
@@ -0,0 +1,24 @@
<div class="edit-content">
<h3>Concession Validation Report</h3>
<form [formGroup]="concessionvalidationreportForm">
<div class="flex flex-row gap-2">
<label>Choose a from date</label>
<p-datepicker formControlName="fromDate" ></p-datepicker>
</div>
<div>
<label>Choose a to date</label>
<p-datepicker formControlName="toDate" ></p-datepicker>
</div>
<div>
<button type="button" pButton (click)="onDownload()">Download</button>
</div>
<br />
<br />
<h3>User Report</h3>
<div>
<button type="button" pButton (click)="onDownloadUser()">Download Users</button>
</div>
</form>
</div>
@@ -0,0 +1,96 @@
import { Component, inject, OnInit } from '@angular/core';
import { ReactiveFormsModule, UntypedFormBuilder, Validators } from '@angular/forms';
import moment from 'moment';
import { HttpUtility, CommonUtilities } from '../shares';
import { catchError, finalize } from 'rxjs/operators';
import { EMPTY } from 'rxjs';
import { HttpResponse } from '@angular/common/http';
import { ActivatedRoute, Router } from '@angular/router';
import { MessageService } from 'primeng/api';
import { ButtonModule } from 'primeng/button';
import { DatePickerModule } from 'primeng/datepicker';
@Component({
selector: 'app-concessionvalidation-report',
templateUrl: './concessionvalidationreport.component.html',
imports: [ReactiveFormsModule, ButtonModule, DatePickerModule],
styleUrls: ['./concessionvalidationreport.component.css']
})
export class ConcessionvalidationReportComponent implements OnInit {
private formBuilder = inject(UntypedFormBuilder);
private http = inject(HttpUtility);
private route = inject(ActivatedRoute);
private messageService = inject(MessageService);
msg = "[concessionvalidation] ";
returnUrl = "";
concessionvalidationreportForm = this.formBuilder.group({
fromDate: [new Date()], //Validators.required
toDate: [new Date(), Validators.required],
});
constructor(
) {
}
onDownload(): void {
const constDate = this.concessionvalidationreportForm.value;
const fromDate = moment(constDate.fromDate).format("YYYY-MM-DD");
const toDate = moment(constDate.toDate).format("YYYY-MM-DD");
console.log(this.msg + "click on download", fromDate);
//GetReportFile
this.http.getFileResponse(`api/v1/ConcessionValidation/GetReportFile?fromDate=${fromDate}&toDate=${toDate}`).pipe(
catchError(err => {
return EMPTY;
}),
finalize(() => {
this.messageService.add({ severity: 'success', summary: 'Success', detail: "download completed ok to view now" });
})).subscribe((response: HttpResponse<Blob>) => {
if (response) {
console.log("the download report response", response);
CommonUtilities.downloadFile(response, 'report.xlsx');
}
});
}
onDownloadUser(): void {
//GetReportFile
this.http.getFileResponse(`api/v1/Users/GetReportFile`).pipe(
catchError(err => {
return EMPTY;
}),
finalize(() => {
this.messageService.add({ severity: 'success', summary: 'Success', detail: "download completed ok to view now" });
})).subscribe((response: HttpResponse<Blob>) => {
if (response) {
console.log("the download user report response", response);
CommonUtilities.downloadFile(response, 'UserReport.xlsx');
}
});
}
ngOnInit(): void {
this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/';
this.assignValue();
}
assignValue(): void {
this.concessionvalidationreportForm.patchValue({
fromDate: new Date(),
toDate: moment(new Date()).add(30, 'd')
});
}
}
@@ -0,0 +1 @@
export * from './concessionvalidationreport.component';
+2
View File
@@ -0,0 +1,2 @@
export * from './login.component';
+5
View File
@@ -0,0 +1,5 @@
.btnloginRigh {
display: flex;
flex-direction:reverse;
justify-content:flex-end;
}
+47
View File
@@ -0,0 +1,47 @@
<div style="position:absolute;top:50%;left:50%;transform: translate(-50%, -50%);">
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()">
<p-card style="max-width:600px">
<img mat-card-image src="images/application_image.png" alt="Nepean Car Park Validation">
<div>
<p class="mb-2">Please Login to Continue</p>
<div class="flex flex-col gap-2">
<input type="text" formControlName="username" pInputText placeholder="StaffLinkNo/Employee no"
[ngClass]="{ 'is-invalid': f.username.errors }" />
<input type="password" formControlName="password" pInputText placeholder="password"
[ngClass]="{ 'is-invalid': f.password.errors }" />
</div>
</div>
<ng-template #footer>
<div class="flex justify-end mb-2">
<button pButton type="submit" class="p-button-sm">
@if (loading() == true) {
Please Wait...
}
@else {
Login
}
</button>
</div>
<div class="border-2 border-gray-300 rounded-xl p-2">
<p class="font-medium">
Please NOTE access to this database is restricted to approved employees for parking validations only.
If you require access to this database or further information, please email
</p>
<a class="text-blue-500" href="mailto:{{adminEmail}}"> {{adminEmail}}
</a>
</div>
</ng-template>
@if(error) {
<div class="alert alert-danger">{{error}}</div>
}
</p-card>
</form>
</div>
+82
View File
@@ -0,0 +1,82 @@
import { Component, inject, OnInit, signal } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { Validators, FormBuilder, ReactiveFormsModule } from '@angular/forms';
import { first } from 'rxjs/operators';
import { AuthenticationService } from '../user-services';
import { AppSettingService } from '../shares';
import { CardModule } from 'primeng/card';
import { InputTextModule } from 'primeng/inputtext';
import { CommonModule } from '@angular/common';
import { ButtonModule } from 'primeng/button';
@Component({
templateUrl: './login.component.html',
styleUrls: ['./login.component.css'],
imports: [CardModule, ButtonModule, InputTextModule, ReactiveFormsModule, CommonModule],
selector: 'login'
})
export class LoginComponent implements OnInit {
private formBuilder = inject(FormBuilder);
private route = inject(ActivatedRoute);
private router = inject(Router);
private appSetting = inject(AppSettingService);
private authenticationService = inject(AuthenticationService);
loginForm = this.formBuilder.group({
username: ['', Validators.required],
password: ['', Validators.required]
});
loading = signal(false);
adminEmail = "";
// get return url from route parameters or default to '/'
returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/concessionvalidation';
error = '';
constructor(
) {
this.adminEmail = this.appSetting.appSetting.adminEmail;
}
ngOnInit() {
// reset login status
this.authenticationService.logout();
}
// convenience getter for easy access to form fields
get f() { return this.loginForm.controls; }
onSubmit() {
// stop here if form is invalid
if (this.loginForm.invalid) {
return;
}
this.loading.set(true);
this.authenticationService.login(this.f.username.value ?? '', this.f.password.value ?? '')
.pipe(first())
.subscribe({
next: data => {
this.loading.set(false);
console.log("login result ", data);
if (data == 1)
this.router.navigate([this.returnUrl]);
else {
this.loginForm.patchValue({ password: '' });
alert("Invalid Username or Password. Please try again.");
}
},
error: er => {
console.log("error in login", er);
this.error = er.message;
this.loading.set(false);
}
});
}
}
+21
View File
@@ -0,0 +1,21 @@
export interface AdminUser {
id: number,
stafflinkNo: string,
name: string,
addedBy: string,
addedOn: Date,
active: boolean,
roleType: number,
validationPointId: number,
}
export interface AdminUserView {
id: number,
stafflinkNo: string,
name: string,
addedBy: string,
addedOn: Date,
active: boolean,
roleType: string,
validationPoint: string,
}
+6
View File
@@ -0,0 +1,6 @@
export interface ConcessionType {
id: number,
description: string,
display: string,
active: boolean,
}
@@ -0,0 +1,14 @@
export interface ConcessionValidation {
id: number,
validateDate: Date,
concessionCard: string,
concessionHolder: string,
concessionExpiry: boolean,
concessionTypeId: number,
stafflinkNo: string,
staffFirstName:string,
staffLastName:string,
staffEmail:string,
validationPointId: number,
active: boolean,
}
+17
View File
@@ -0,0 +1,17 @@
export enum ConfigureUrl
{
//baseUrl = "http://localhost:61744",
authenticateUrl = "api/v1/Users/Authenticate", //no use anymore
loginADUrl = "api/v1/Users/LoginAD",
loginApiUrl = "api/v1/Users/LoginApiAD",
validationPoint = "api/v1/ValidationPoint", //no "/" at the front
adminUserUrl = "api/v1/AdminUser",
concessionValidationUrl = "api/v1/ConcessionValidation",
concessionValidationByIdUrl = "api/v1/ConcessionValidation/ConcessionValidationByStaff",
CheckConcessionValidationByStaffUrl = "api/v1/ConcessionValidation/CheckConcessionValidationByStaff",
concessionTypeUrl = "api/v1/ConcessionType",
userByStaffIdUrl = "api/v1/Users/SearchApiStaff",
luConcessionTypeUrl = "api/v1/LookupCode/ConcessionTypes",
luValidationPointUrl = "api/v1/LookupCode/ValidationPoints",
}
+44
View File
@@ -0,0 +1,44 @@
export const MIMEType = {
png: 'image/png',
jpg: 'image/jpg',
jpeg: 'image/jpeg',
gif: 'image/gif',
txt: 'text/plain',
pdf: 'application/pdf'
};
//for status of object 0 no change, 1 changed , -1 is deleted.
export enum mState {
Delete = -1,
NoChange = 0,
Modified = 1,
New =2,
};
export enum PickListType {
Ok =0,
BodyPart = 16, // Body Part
Location = 17,
Equipment = 18,
LocationType = 19,
CheckList = 20,
Company = 21,
NonConformance = 22,
Occupation = 23,
IncidentType = 24,
InvestigationAgency = 25,
OutCome = 26,
Visibility = 27,
Surface = 28,
Lighting = 29,
Weather = 30,
CauseOfPrimaryInjury = 31,
ContributingFactor = 32,
HazardControlType = 33,
}
export enum userRole {
Normal = 1,
Admin = 2,
};
+9
View File
@@ -0,0 +1,9 @@
export * from './user';
export * from './validationpoint';
export * from './enum';
export * from './resultmodel';
export * from './adminuser';
export * from './configureUrl';
export * from './concessionvalidation';
export * from './lookup';
export * from './concessiontype';
+7
View File
@@ -0,0 +1,7 @@
export interface Lookup {
id: number;
categoryId: number;
description: string;
};
+44
View File
@@ -0,0 +1,44 @@
export interface treeLookupCode {
id: number;
code: string;
description: string;
canCheck: number; // 0 no 1 is yes
hasChild: number; // 0 no 1 is yes
}
export interface LookupCode {
id: number;
code: string;
description: string;
}
export interface LookupEnumContainer {
enumId: number;
list: LookupCode[];
}
export interface BusinessUnitLookup {
id: number;
abbreviation: string;
levelID: number;
name: string;
parentID: number;
}
export interface LookupBUData {
allowMultiSelect: boolean;
pickListTitle: string;
lookupList: BusinessUnitLookup[];
}
export interface LookupData {
allowMultiSelect:boolean;
pickListTitle: string;
lookupList: LookupCode[];
};
export interface LookupCodeContainer {
list: LookupCode[];
totalPages: number;
}
+7
View File
@@ -0,0 +1,7 @@
export interface PageQuery {
pageIndex: number;
pageSize: number;
search: string;
};
+80
View File
@@ -0,0 +1,80 @@
import { Lookup } from './lookup';
export interface SharePersonContainer {
list: PersonLite[];
totalPages: number;
}
export interface PersonLite {
id: number;
firstName: string;
surname: string;
referenceNo: string;
payrollNo: number;
email: string;
phoneNo: string;
}
export interface PersonLookup {
categorys: Lookup[];
title: Lookup[]; ///for source
positions: Lookup[]; ///for source
companys: Lookup[];
personStatus: Lookup[];
englishLevel: Lookup[];
yesNoPickList: Lookup[];
language: Lookup[];
residence: Lookup[];
nationality: Lookup[];
gender: Lookup[];
}
export interface PersonContainer {
person: Person;
}
export class Person {
id: number =0;
titleId: number =0;
firstName: string = '';
surname: string = '';
referenceNo: string = '';
workNo: string = '';
email: string = '';
categoryId: number = 0;
statusId: number = 0;
statusDate: string = '';
businessUnitId: number = 0;
businessUnitDesc: string = '';
}
export interface PersonDetail {
street: string;
postCode: string;
suburb: string;
state: string;
country: string;
home: string;
fax: string;
mobile: string;
work: string;
email: string;
mailStreetPostCode: string;
mailPostCode: string;
mailSuburb: string;
mailState: string;
mailCountry: string;
dateOfBirth: string;
genderId: number;
nationalityId: number;
residenceId: number;
englishLevelId: number;
interpretRequired: number;
languageSpokenId: string;
driverLicenceNo: string;
expiryDate: string;
}
+45
View File
@@ -0,0 +1,45 @@
import { BehaviorSubject } from 'rxjs';
import { treeLookupCode } from './lookupcode';
enum EnumLookup {
BodyPart = 16,
Location = 17,
Equipment = 18,
LocationType = 19,
CheckList = 20
}
export class DataNode {
loaded: boolean = false;
name: string ='';
id: number = 0;
children: DataNode[] =[];
}
export class UIDataNode {
allowMultiSelect: boolean = false;
pickListTitle: string = '';
enumPickType: number = 0;
children: treeLookupCode[] = [];
}
/** Nested node */
export class DataNode$ {
childrenChange = new BehaviorSubject<DataNode$[]>([]);
expanable = new BehaviorSubject<boolean>(true);
get children(): DataNode$[] {
return this.childrenChange.value;
}
get isExpanable(): boolean {
return this.expanable.value;
}
constructor(public id: number,
public name: string,
public canCheck: boolean,
public hasChildren: boolean,
public parentId: number,
public loadMoreParentItem: number | null = null) { }
}
+5
View File
@@ -0,0 +1,5 @@
export interface ResultModel<T> {
data: T;
message: string;
statusCode:number;
}
+10
View File
@@ -0,0 +1,10 @@
export class User {
id: number = 0;
username: string = '';
role: number = -1;
firstName: string = '';
lastName: string = '';
email:string = '';
token:string ='';
validationPointId:number = 0;
}
+6
View File
@@ -0,0 +1,6 @@
export interface ValidationPoint {
id: number,
description: string,
display: string,
active: boolean,
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,38 @@
a {
text-decoration: none;
color: white;
}
a:hover,
a:active {
color: lightgray;
}
/* may be is not use anymore */
li .glyphicon {
margin-right: 10px;
}
.navigation-items {
list-style: none;
padding: 0;
margin: 0;
}
/* Highlighting rules for nav menu items */
li.link-active a,
li.link-active a:hover,
li.link-active a:focus {
background-color: #4189C7;
color: white;
}
/* Keep the nav menu independent of scrolling and on top of other items */
.main-nav {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1;
}
@@ -0,0 +1,24 @@
<div class="flex justify-between" style="background-color: #e12a40;">
<div style="margin-top: 5px;padding-right: 35px; cursor: pointer;height:70px;">
<img (click)="onHome()" src="images/application_image.png" alt="Parking Concession Validation Register"
style="height:70px;width:320px" />
</div>
<div class="flex justify-content-end">
<ul class="navigation-items">
@if( !isAuth()) {
<li >
<a [routerLink]='["/login"]'>
Login
</a>
</li>
}
</ul>
<div class="font-bold text-white">
{{currentUserName}}
</div>
<button (click)="onToggle()" type="button">
<svg data-p-icon="angle-down" [size]="20"></svg>
</button>
</div>
</div>
@@ -0,0 +1,59 @@
import { AuthenticationService } from '../user-services';
import { Subscription } from 'rxjs'
import { Component, EventEmitter, Output, OnInit, OnDestroy, inject, signal } from '@angular/core';
import { Router, RouterModule } from '@angular/router';
import { Utils } from '../shares';
import { AngleDown } from '@primeicons/angular/angle-down';
import { SidebarModule } from 'primeng/sidebar';
@Component({
selector: 'app-nav-toolbar',
imports: [RouterModule, AngleDown, SidebarModule],
templateUrl: './nav-toolbar.component.html',
styleUrls: ['./nav-toolbar.component.css']
})
export class NavToolarComponent implements OnInit, OnDestroy {
isExpanded = false;
isAuth = signal(false);
isAdmin = signal(false);
currentUserName = "";
authSubscription: Subscription = new Subscription;
@Output() toggleEvent: EventEmitter<boolean> = new EventEmitter();
private authService = inject(AuthenticationService);
constructor(
private router: Router) { }
ngOnInit() {
const currentUser = this.authService.authChange();
this.isAuth.set(false);
this.isAdmin.set(false);
if (currentUser.firstName != '') {
this.isAuth.set(Utils.getIsAuth());
this.isAdmin.set(Utils.getIsAdmin());
this.currentUserName = currentUser.firstName + ' ' + currentUser.lastName;
}
}
ngOnDestroy() {
if (this.authSubscription) {
this.authSubscription.unsubscribe();
}
}
onHome() {
this.router.navigate(['/concessionvalidation']);
}
onToggle() {
this.isExpanded = !this.isExpanded;
this.toggleEvent.emit(this.isExpanded);
}
onLogout() {
this.authService.logout();
this.router.navigate(['/login']);
}
}
+42
View File
@@ -0,0 +1,42 @@
import { Injectable } from '@angular/core';
import { Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Utils } from '../shares';
@Injectable({ providedIn: 'root' })
export class AuthGuard {
msg = "[AuthGuard] ";
constructor(private router: Router) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const roleAllowed = route.data['roleAllowed'];
const user = Utils.getCurrentUser();
const userRole = Utils.getUserRole(user);
let hasLoggedIn = Utils.getIsAuth();
console.log(this.msg + " the userlogin ", user);
if (hasLoggedIn) {
if (roleAllowed != undefined) {
console.log("[auth-guard] ther roleAllow ", roleAllowed);
if (roleAllowed.indexOf(userRole) != -1) {
return true;
}
else {
this.router.navigate(['/login']);
return false;
}
}
else //if no role define just return hasLoggedIn
{
return hasLoggedIn;
}
}
else {
this.router.navigate(['/login']);
return false;
}
// not logged in so redirect to login page with the return url
this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } });
return false;
}
}
+7
View File
@@ -0,0 +1,7 @@
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(require("./auth.guard"));
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
export * from './auth.guard';
+60
View File
@@ -0,0 +1,60 @@
import { FormControl, FormGroup } from '@angular/forms';
declare global {
interface Navigator {
msSaveBlob?: (blob: any, defaultName?: string) => boolean
msSaveOrOpenBlob?: (blob: any, defaultName?: string) => boolean
}
}
export class CommonUtilities {
/** Display the blob */
static displayFileInNewTab(response: any, defaultFileName: string) {
const contentType = response.headers.get('content-type');
const blob = new Blob([response.body], { type: contentType });
const fileName = this.getFileName(response, defaultFileName);
if (window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(blob, fileName);
} else {
const data = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = data;
link.target = '_blank';
link.click();
}
}
/*** Download the blob ***/
static downloadFile(response: any, defaultFileName: string) {
const contentType = response.headers.get('content-type');
const blob = new Blob([response.body], { type: contentType });
const fileName = this.getFileName(response, defaultFileName);
if (typeof window.navigator.msSaveBlob === 'function') {
console.log("download the report saveblob");
window.navigator.msSaveBlob(blob, fileName);
console.log("download the report saveblob done");
}
else {
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
console.log("no msSaveBlob download the report saveblob done");
//link.download? = fileName;
link.download = fileName;
link.click();
}
}
/** Get the attachment file name */
static getFileName(response: any, defaultFileName: string) {
const contentDis = response.headers.get('content-disposition');
let fileName = defaultFileName;
if (contentDis && contentDis.indexOf('attachment') !== -1) {
const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
const matches = filenameRegex.exec(contentDis);
if (matches != null && matches[1]) {
fileName = matches[1].replace(/['"]/g, '');
}
}
return fileName;
}
}
+65
View File
@@ -0,0 +1,65 @@
import { inject, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { firstValueFrom } from 'rxjs';
export function initializeApp() {
return (): Promise<any> => {
return inject(AppSettingService).loadAppSetting();
}
// return () => inject(AppSettingService).loadAppSetting();
};
@Injectable({ providedIn: 'root' })
export class AppSettingService {
private _appsetting: any;
constructor(private http: HttpClient
) { }
public loadAppSetting(): Promise<any> {
const source$ = this.http.get("config/appsetting.json")
const rs$ = firstValueFrom(source$)
.then(x => {
this._appsetting = x;
console.log("[AppSettingService] assign", x);
return x;
});
return rs$;
}
set appSeting(value: any) {
this._appsetting = value;
}
get appSetting(): any {
return this._appsetting;
}
}
/* module put this
to use it
in app.module.ts
add
1)
providers: [
{ provide : APP_INITIALIZER, multi : true, deps : [AppSettingService],
useFactory: initializeApp
},
]
2)
other this one work too.
providers: [
{
provide : APP_INITIALIZER,
multi : true,
deps : [AppSettingService],
useFactory : (appConfigService : AppSettingService) => () => appConfigService.loadAppSetting()
}
]
to use it calling something like this
export class TestComponent {
public test1ServiceUrl: string;
constructor(public configService: AppConfigService) {
this.test1ServiceUrl = this.configService.appSetting.test1ServiceUrl;
}
}
*/
+97
View File
@@ -0,0 +1,97 @@
import { Injectable, inject } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpInterceptorFn, HttpHandlerFn } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { AuthenticationService } from '../user-services';
//import { ToastrService } from 'ngx-toastr';
import { NavigationExtras, Router } from '@angular/router';
/*
@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
//private authenticationService: AuthenticationService;
constructor(
private router: Router,
// private toastr: ToastrService,
) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// console.log("I am intercept to catch error status = 401...", request);
return next.handle(request).pipe(catchError(err => {
/* no use yet
if (err) {
switch(err.status) {
case 400:
if (err.error.errors) {
const modalStateErrors = [];
for (const key in err.error.errors) {
if (err.error.errors[key]) {
modalStateErrors.push(err.error.errors[key]);
}
}
throw modalStateErrors;
} else {
this.toastr.error(err.statusText, err.status);
}
break;
case 401:
this.toastr.error(err.statusText, err.status);
break;
case 404:
this.router.navigateByUrl('/not-found');
break;
case 500:
const navigationExtras: NavigationExtras = {state:{error:err.error}};
this.router.navigateByUrl('/server-error', navigationExtras);
break;
default:
this.toastr.error('Something unexpected went wrong');
console.log("this error interceptor",err);
break;
}
}
*/
/*
if (err.status === 401) {
// auto logout if 401 response returned from api Unauthorized
// this.authenticationService.logout();
//location.reload();
const error = err.error.message || err.statusText;
console.log("After I Get Error status = 401...", error, err);
return throwError(error);
}
else {
console.log("I Get Error .", err);
return throwError(err);
}
}))
}
}
*/
//new one
//https://blog.ninja-squad.com/2022/11/09/angular-http-in-standalone-applications/
////////////////
export const ErrorInterceptor: HttpInterceptorFn = (req: HttpRequest<unknown>, next: HttpHandlerFn): Observable<HttpEvent<unknown>> => {
const authenticationService = inject(AuthenticationService);
// logger.log(`Request is on its way to ${req.url}`);
return next(req).pipe(catchError(err => {
if (err.status === 401) {
// auto logout if 401 response returned from api Unauthorized
// this.authenticationService.logout();
//location.reload();
const error = err.error.message || err.statusText;
// console.log("After I Get Error status = 401...", error, err);
return throwError(() => error);
}
else {
console.log("I Get Error .", err);
return throwError(() => err);
}
}));
}
////////////////
+115
View File
@@ -0,0 +1,115 @@
import { HttpClient, HttpErrorResponse, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { ConfigureUrl } from '../models';
import { AppSettingService } from './appsetting';
@Injectable({
providedIn: 'root'
})
export class HttpUtility {
private baseApiUrl: string = "";
constructor(private http: HttpClient,
private appSetting :AppSettingService,
private router: Router) {
}
/**
* getFile
* @param url
*/
public getFileAsText(url: string): Observable<any> {
return this.http
.get(this.getApiUrl(url), { responseType: 'blob' as 'text' })
.pipe(catchError(e => this.handleError(e)));
}
/**
* getFile
* @param url
*/
public getFile(url: string): Observable<any> {
return this.http
.get(this.getApiUrl(url), { responseType: 'blob' as 'json' })
.pipe(catchError(e => this.handleError(e)));
}
/**
* handleError
* @param response
*/
private handleError(errorResponse: HttpErrorResponse) {
// in a real world app, we may send the server to some remote logging infrastructure
// instead of just logging it to the console
return throwError(errorResponse);
}
//get excel file zip file etc ..
/*
allowedToDisplay = [
this.mimeConstant.png,
this.mimeConstant.jpeg,
this.mimeConstant.jpg,
this.mimeConstant.gif,
this.mimeConstant.txt,
this.mimeConstant.pdf
];
*/
/* how to use it
this.http.getFileResponse(`Person/GetPhoto?recordId=${personId}`).pipe(
catchError(err => {
this.snackBar.error(err || this.constants.error_Getting_photo);
return EMPTY;
}),
finalize(() => {
this.spinner.hide();
})).subscribe(response => {
if (response) {
if (isDownload) {
CommonUtilities.downloadFile(response);
} else {
if (response.body && response.body.type) {
if (this.allowedToDisplay.includes(response.body.type)) {
CommonUtilities.displayFileInNewTab(response);
} else {
this.temporaryFile = response;
this.downloadWarning = true;
}
}
}
}
});
*/
public getFileResponse(url: string, data?: any): Observable<any> {
if (data) {
return this.http.post(this.getApiUrl(url),
data,
{ responseType: 'blob', observe: 'response' })
.pipe(catchError(e => this.handleError(e)));
}
return this.http
.get(this.getApiUrl(url), { responseType: 'blob', observe: 'response' })
.pipe(catchError(e => this.handleError(e)));
}
public getFileAsPDF(url: string, data: any): Observable<any> {
let updateURL;
if (data) {
updateURL = url + data;
} else {
updateURL = url;
}
return this.http
.get(this.getApiUrl(updateURL), { responseType: 'blob' as 'text', observe: 'response' })
.pipe(catchError(e => this.handleError(e)));
}
/**
* getApiUrl
* @param url
*/
private getApiUrl(url:string) {
const baseUrl = this.appSetting.appSetting.baseUrl;
return baseUrl + "/"+ url;
}
}
+8
View File
@@ -0,0 +1,8 @@
export * from './lookup.service';
export * from './utils';
export * from './httpfile.service';
export * from './CommonUtilities';
export * from './error.interceptor';
export * from './jwt.interceptor';
export { initializeApp, AppSettingService } from './appsetting';
+50
View File
@@ -0,0 +1,50 @@
import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpInterceptorFn, HttpHandlerFn } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Utils } from './utils';
/*
@Injectable()
export class JwtInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// add authorization header with jwt token if available
const currentUser = Utils.getCurrentUser();//localStorage.getItem('currentUser')!;
console.log('I am interceptor debug for currentUser obj', currentUser);
if (currentUser && currentUser.token) {
//console.log('I am interceptor add authorization header with jwt token');
request = request.clone({
setHeaders: {
Authorization: `Bearer ${currentUser.token}`
}
});
}
return next.handle(request);
}
}
/*
new one
////////////////
*/
export const JwtInterceptor: HttpInterceptorFn = (request: HttpRequest<unknown>, next: HttpHandlerFn): Observable<HttpEvent<unknown>> => {
//const logger = inject(Logger);
//logger.log(`Request is on its way to ${req.url}`);
let data: any = {
withCredentials: true
}
const currentUser = Utils.getCurrentUser();//localStorage.getItem('currentUser')!;
// console.log('I am interceptor debug for currentUser obj', currentUser);
if (currentUser && currentUser.token && currentUser.token != "") {
// console.log('I am interceptor add authorization header with jwt token');
data.setHeaders = {
Authorization: `Bearer ${currentUser.token}`
};
}
request = request.clone(data);
return next(request);
}
////////////////
/*
providers: [provideHttpClient(withInterceptors([loggerInterceptor]))]
*/
+25
View File
@@ -0,0 +1,25 @@
import { Injectable, Inject } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { ConfigureUrl,Lookup,ResultModel } from '../models';
import { AppSettingService } from '../shares';
@Injectable({ providedIn: 'root' })
export class LookupService {
constructor(private http: HttpClient,
private appSetting :AppSettingService
) {}
loadConcessionType(): Observable<ResultModel<Lookup[]>> {
const url = this.appSetting.appSetting.baseUrl +"/"+ConfigureUrl.luConcessionTypeUrl;
return this.http.get<ResultModel<Lookup[]>>(url);
}
loadValidationPoint(): Observable<ResultModel<Lookup[]>> {
const url = this.appSetting.appSetting.baseUrl +"/"+ConfigureUrl.luValidationPointUrl;
return this.http.get<ResultModel<Lookup[]>>(url);
}
}
+66
View File
@@ -0,0 +1,66 @@
import { User, userRole } from "../models"
export class Utils {
static getCurrentUser(): User {
let myUser = new User();
myUser.username = "";
const obj = sessionStorage.getItem('currentUser');
//const obj = localStorage.getItem('currentUser');
if (obj != undefined) {
let user = JSON.parse(obj);
myUser.firstName = user.firstName;
myUser.lastName = user.lastName;
myUser.role = user.role;
myUser.username = user.username;
myUser.email = user.email;
myUser.token = user.token;
myUser.validationPointId = user.validationPointId;
}
// console.log("[util] getcurrentUser",myUser);
return myUser;
}
static setLocalStore(user: User): void {
if (user && user.token) {
// store user details and jwt token in local storage to keep user logged in between page refreshes
// localStorage.setItem('currentUser', JSON.stringify(user));
sessionStorage.setItem('currentUser', JSON.stringify(user));
}
}
static getUserRole(user: User): string {
let ret: string;
if (user.role == userRole.Normal)
ret = "Normal";
else (user.role == userRole.Admin)
ret = "Admin";
return ret;
}
static getIsAuth(): boolean {
const user = this.getCurrentUser();
if (user.username != "") {
return true;
}
else
return false;
}
static getIsAdmin(): boolean {
const user = this.getCurrentUser();
let result = false;
// console.log("[util] get isAdmin", user);
if (user.username != "") {
// console.log("[util] get isAdmin username is not null", user);
if (user.role == userRole.Admin)
// console.log("[util] this user is admin", user);
result = user.role == userRole.Admin;
}
else
result = false;
return result;
}
static clearCurrentUser(): void {
sessionStorage.clear();
//localStorage.clear();
}
}
@@ -0,0 +1,72 @@
import { Injectable, Inject, Output, signal } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators';
import { BehaviorSubject, Observable } from 'rxjs';
import { ConfigureUrl, User } from '../models';
import { Utils, AppSettingService } from '../shares';
@Injectable({ providedIn: 'root' })
export class AuthenticationService {
currentUser: string = '';
public authChange = signal(new User());
baseUrl = ''; // this.appSettingService.appSetting.baseUrl + "/"+ ConfigureUrl.loginApiUrl;
constructor(private http: HttpClient,
private appSetting: AppSettingService
) {
// this default when load look for previous login information
// if no need then comment out downthere
const fname = this.getCurrentUser();
if (fname) {
this.authChange.set(fname);
}
}
login(username: string, password: string): Observable<number> {
const url = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.loginApiUrl;
return this.http.post<any>(url, { username, password })
.pipe(map(resultModel => {
// login successful if there's a jwt token in the response
if (resultModel.statusCode == 1) {
const user = resultModel.data;
console.log("login result ", user);
Utils.setLocalStore(user);
this.currentUser = user.firstName + " " + user.lastName;
this.authChange.set(user);
}
return resultModel.statusCode;
}));
}
getCurrentUser(): User {
let userObj = new User();
let user = sessionStorage.getItem('currentUser');
if (user) {
userObj = JSON.parse(user);
// logged in so return true
}
return userObj;
}
isAuth(): boolean {
let val: boolean;
val = false;
if (sessionStorage.getItem('currentUser')) {
// logged in so return true
val = true;
}
return val;
}
logout() {
// remove user from local storage to log user out
sessionStorage.removeItem('currentUser');
this.authChange.set(new User());
}
}
+8
View File
@@ -0,0 +1,8 @@
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(require("./authentication.service"));
__export(require("./user.service"));
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;;;AAAA,8CAAyC;AACzC,oCAA+B"}
+2
View File
@@ -0,0 +1,2 @@
export * from './authentication.service';
export * from './user.service';
+19
View File
@@ -0,0 +1,19 @@
import { Injectable, Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { User,ConfigureUrl } from '../models';
@Injectable({ providedIn: 'root' })
export class UserService {
constructor(private http: HttpClient,
) {
}
// getAll() {
// return this.http.get<User[]>(`${config.apiUrl}/users`);
// return this.http.get<User[]>(`${ConfigureUrl.baseUrl}/${ConfigureUrl.getAllUrl}`);
// }
}
+4
View File
@@ -0,0 +1,4 @@
export * from './validationpoint.component';
export * from './validationpoint.edit.component';
export * from './validationpoint.service';
@@ -0,0 +1,12 @@
table {
width: 100%;
}
.mat-form-field {
font-size: 14px;
width: 100%;
}
td.mat-column-edit, .mat-column-delete {
width: 35px;
padding-right: 2px;
}
@@ -0,0 +1,46 @@
<div class="edit-content">
<h3>Validation Point</h3>
<div class="addlink">
<a class="p-ripple p-button p-component flex justify-self-end mb-2" [routerLink]='["/validationpoint", 0]'
[queryParams]="{returnUrl:'/validationpoint'}">
<i class="material-icons">playlist_add</i>
Add Validation Point
</a>
</div>
<label>Filter</label>
<input matInput (keyup)="applyFilter($event)" placeholder="Ex. ium" #input>
<p-table [value]="dataSource()" rowHover="true" dataKey="id"
[rows]="25" [rowsPerPageOptions]="[ 25, 50,100]" [paginator]="true">
<ng-template #header>
<tr>
<th>Description</th>
<th>Display</th>
<th>Active</th>
<th>Edit</th>
</tr>
</ng-template>
<ng-template #body let-item>
<tr>
<td>{{ item.description }}</td>
<td> {{item.display}}</td>
<td>
@if(item.active == true) {
<svg data-p-icon="check" color="green"></svg>
}
@else {
<svg data-p-icon="times" color="red"></svg>
}
</td>
<td>
<button pButton (click)="showEdit(item)">
<svg data-p-icon="pencil"></svg>
</button>
</td>
</tr>
</ng-template>
</p-table>
</div>
@@ -0,0 +1,95 @@
import { Component, Inject, OnInit, ViewChild, AfterViewInit, OnDestroy, signal } from '@angular/core';
import { ValidationPointService } from './validationpoint.service';
import { ValidationPoint } from '../models';
import { MessageService } from 'primeng/api';
import { ButtonModule } from 'primeng/button';
import { Pencil } from '@primeicons/angular/pencil';
import { TableModule } from 'primeng/table';
import { Check } from '@primeicons/angular/check';
import { Times } from '@primeicons/angular/times';
import { take } from 'rxjs/operators';
import { Router, RouterModule } from '@angular/router';
import { Subscription } from 'rxjs';
@Component({
selector: 'validationpoint-list',
templateUrl: './validationpoint.component.html',
imports: [ButtonModule, TableModule, Times, Check, Pencil, RouterModule],
styleUrls: ['./validationpoint.component.css']
})
export class ValidationPointComponent implements OnInit, OnDestroy {
dataSource = signal<ValidationPoint[]>([]);
private subscription: Subscription = new Subscription();
displayedColumns: string[] = ['description', 'active', 'edit'];
msg = "[validationpoint.com]";
/*
private store: Store<appValidationState>
*/
constructor(
private validationPointService: ValidationPointService,
private messageService: MessageService,
private router: Router
) {
}
//KeyboardEvent
applyFilter(event: Event) {
const filterValue = (event.target as HTMLInputElement).value;
// this.dataSource.filter = filterValue.trim().toLowerCase();
}
ngOnInit(): void {
this.subscription.add(
this.validationPointService.loadValidationpoints().subscribe(
{
next: result => {
// console.log(this.msg + "onInit", result);
this.dataSource.set(result.data);
}, error: e => {
console.log("error ", e);
}
}
)
);
/*
this.store.dispatch(validationActions.LoadValidationpoints());
this.store.pipe(select(validationSelector.getAllValidations)).subscribe(result => this.dataSource.data = result);
*/
}
showEdit(item: ValidationPoint) {
// console.log(this.msg + "on row click", item);
this.router.navigate(['/validationpoint/' + item.id], { queryParams: { returnUrl: '/validationpoint' } });
}
deleteItem(id: number): void {
this.validationPointService.deleteValidationpoint(id)
.pipe(take(1))
.subscribe(result => {
console.log(this.msg + " deleteItem success", result);
let data = this.dataSource();
let index: number = data.findIndex(d => d.id === id);
// console.log(this.msg + "delete from datasource");
data.splice(index, 1)
this.dataSource.set(data);
},
error => {
const message = error || error.message;
}
);
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
@@ -0,0 +1,12 @@
table {
width: 100%;
}
.mat-form-field {
font-size: 14px;
width: 100%;
}
td.mat-column-edit, .mat-column-delete {
width: 35px;
padding-right: 2px;
}
@@ -0,0 +1,36 @@
<div class="edit-content">
<div class="title">
{{getEditText()}}
</div>
<form [formGroup]="validationpointForm" (ngSubmit)="onSubmit()" class="ml-10">
<div class="flex flex-col">
<div>
<label class="flex w-full">Validation Point<strong class="app-require">*</strong></label>
<input pInputText formControlName="description" maxlength="100"
placeholder="Validatio Point" required>
</div>
<div>
<label class="flex w-full">Display<strong class="app-require">*</strong></label>
<input pInputText formControlName="display" maxlength="10"
placeholder="Validatio Point" required>
</div>
<div>
<label for="acheckbox" class="mr-2">Active</label>
<p-checkbox formControlName="active" [binary]="true" inputId="acheckbox" size="small"></p-checkbox>
</div>
</div>
<div class="mt-2 flex justify-content-end">
<button class="mr-2" type="submit" pButton
[disabled]="isFieldsChange">Submit</button>
<button type="button" pButton (click)="goBack()">Cancel</button>
</div>
</form>
<!--pre>{{ validationpointForm.value|json}}</pre-->
</div>
@@ -0,0 +1,125 @@
import { Component, inject, OnDestroy, OnInit } from '@angular/core';
import { Router, ActivatedRoute, Route } from '@angular/router';
import { UntypedFormBuilder, FormGroup, Validators, ReactiveFormsModule, FormBuilder } from '@angular/forms';
import { Subject, pipe, Subscription } from 'rxjs';
import { ValidationPoint } from '../models';
import { ValidationPointService } from '.';
import { MessageService } from 'primeng/api';
import { ButtonModule } from 'primeng/button';
import { CheckboxModule } from 'primeng/checkbox';
import { InputTextModule } from 'primeng/inputtext';
@Component({
templateUrl: 'validationpoint.edit.component.html',
selector: 'validationpoint-edit',
styleUrls: ['validationpoint.edit.component.css'],
imports: [ButtonModule, ReactiveFormsModule, CheckboxModule, InputTextModule]
})
export class ValidationpointEditComponent implements OnInit, OnDestroy {
returnUrl = '';
msg = "[ValidationPoint Edit]";
_id: number = -1;
private subscription: Subscription = new Subscription();
isChange = true; // disable use false//true for not disable. make sure it true is disable button.
subChanged$ = new Subject<boolean>();
private formBuilder = inject(FormBuilder);
private validationPointService = inject(ValidationPointService);
private messageService = inject(MessageService);
private route = inject(ActivatedRoute);
private router = inject(Router);
validationpointForm = this.formBuilder.group({
id: [0], //Validators.required
description: ['', Validators.required],
display: [''], //Validators.required
active: [false], //Validators.required
});
constructor() { }
ngOnInit(): void {
this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/';
const id = Number(this.route.snapshot.paramMap.get('id'));
// now load thing up
this._id = id;
//console.log(this.msg + " " + id );
this.subscription.add(this.validationpointForm.valueChanges.subscribe(x => this.isChange = false));
this.subscription.add(this.subChanged$.subscribe(x => this.isChange = x));
// console.log(this.msg + "ngOnInit load data id " + id );
if (id > 0) {
this.subscription.add(
this.validationPointService.loadValidationpointById(id).subscribe(x => {
this.assignValue(x.data)
},
error => {
console.log("error ", error);
}
));
}
}
getEditText(): string {
if (this._id > 0)
return "Edit Validation Point";
else
return "New Validation Point";
}
// this for disable submit button
get isFieldsChange() {
const chan = this.isChange || !this.validationpointForm.valid; // this disable so need true valid = true not
//console.log(this.msg + 'is fields change', chan);
return chan;
}
assignValue(validationpoint: ValidationPoint): void {
this.validationpointForm.patchValue({
id: validationpoint.id,
description: validationpoint.description,
display: validationpoint.display,
active: validationpoint.active,
});
// disable use false//true for not disable.
this.subChanged$.next(true);
}
// convenience getter for easy access in form fields
get f() { return this.validationpointForm.controls; }
onSubmit(): void {
// if form valid then go save
//make sure
const okToSave = this.validationpointForm.valid;
if (okToSave) {
let validationpointValue = this.validationpointForm.value;
let validationpoint: ValidationPoint = {
id: validationpointValue.id ?? 0,
description: validationpointValue.description ?? '',
display: validationpointValue.display ?? '',
active: validationpointValue.active ?? false,
};
this.validationPointService.saveValidationpoint(validationpoint).subscribe(
{
next: x => {
if (x.statusCode >= 1) {
this.messageService.add({ severity: 'success', summary: 'Success', detail: "Save is OK" });
this.router.navigate(['/home/validationpoint']);
}
},
error: e => {
console.log("error ", e);
}
}
);
}
}
goBack(): void {
this.router.navigate([this.returnUrl]);
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
@@ -0,0 +1,44 @@
import { Injectable, Inject } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { ValidationPoint,ResultModel ,ConfigureUrl} from '../models';
import { AppSettingService } from '../shares';
@Injectable({ providedIn: 'root' })
export class ValidationPointService {
constructor(
private http: HttpClient,
private appSetting :AppSettingService
) { }
loadValidationpoints(): Observable<ResultModel<ValidationPoint[]>> {
let config = { headers : { 'Content-Type': 'application/json' } };
//const url = this.appUrl.baseUrl + "/" + this.appUrl.validationPoint;
const baseUrl = this.appSetting.appSetting.baseUrl+ "/"+ ConfigureUrl.validationPoint;
console.log("[validation service] loadValidtionpoints url is: " + baseUrl );
return this.http.get<ResultModel<ValidationPoint[]>>(baseUrl);
}
loadValidationpointById(id:number): Observable<ResultModel<ValidationPoint>> {
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.validationPoint;
let params = new HttpParams().set("id", ""+id);
let headers = new HttpHeaders().set('Content-Type', 'application/json');
let options = {
headers: headers,
params: params
};
//const url = this.appUrl.baseUrl + "/" + this.appUrl.validationPoint;
return this.http.get<ResultModel<ValidationPoint>>(baseUrl + "/"+ id);
}
saveValidationpoint(jsData:ValidationPoint): Observable<ResultModel<number>> { //insert Validationpoint
let config = { headers : { 'Content-Type': 'application/json' } };
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.validationPoint;
return this.http.post<ResultModel<number>>(baseUrl, jsData, config);
}
deleteValidationpoint(Id:number): Observable<ResultModel<number>>{
let config = { headers : { 'Content-Type': 'application/json' } };
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.validationPoint;
//const url = this.appUrl.baseUrl + "/" + this.appUrl.validationPoint;
return this.http.delete<ResultModel<number>> (baseUrl + "/" + Id);
}
}