change over primeng v22
This commit is contained in:
@@ -0,0 +1,17 @@
|
|||||||
|
# Editor configuration, see https://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.ts]
|
||||||
|
quote_type = single
|
||||||
|
ij_typescript_use_double_quotes = false
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
max_line_length = off
|
||||||
|
trim_trailing_whitespace = false
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
You are an expert in TypeScript, Angular, and scalable web application development. You write functional, maintainable, performant, and accessible code following Angular and TypeScript best practices.
|
||||||
|
|
||||||
|
## TypeScript Best Practices
|
||||||
|
|
||||||
|
- Use strict type checking
|
||||||
|
- Prefer type inference when the type is obvious
|
||||||
|
- Avoid the `any` type; use `unknown` when type is uncertain
|
||||||
|
|
||||||
|
## Angular Best Practices
|
||||||
|
|
||||||
|
- Always use standalone components over NgModules
|
||||||
|
- Must NOT set `standalone: true` inside Angular decorators. It's the default in Angular v20+.
|
||||||
|
- Do NOT set `changeDetection: ChangeDetectionStrategy.OnPush` explicitly. `OnPush` is the default in Angular v22+.
|
||||||
|
- Use signals for state management
|
||||||
|
- Implement lazy loading for feature routes
|
||||||
|
- Do NOT use the `@HostBinding` and `@HostListener` decorators. Put host bindings inside the `host` object of the `@Component` or `@Directive` decorator instead
|
||||||
|
- Use `NgOptimizedImage` for all static images.
|
||||||
|
- `NgOptimizedImage` does not work for inline base64 images.
|
||||||
|
|
||||||
|
## Accessibility Requirements
|
||||||
|
|
||||||
|
- It MUST pass all AXE checks.
|
||||||
|
- It MUST follow all WCAG AA minimums, including focus management, color contrast, and ARIA attributes.
|
||||||
|
|
||||||
|
### Components
|
||||||
|
|
||||||
|
- Keep components small and focused on a single responsibility
|
||||||
|
- Use `input()` and `output()` functions instead of decorators
|
||||||
|
- Use `model()` for two-way bound properties with `[(prop)]` syntax instead of pairing `input()` with `output()`
|
||||||
|
- Use `computed()` for derived state
|
||||||
|
- Use `linkedSignal()` for state derived from multiple reactive sources that must stay synchronized
|
||||||
|
- Prefer inline templates for small components
|
||||||
|
- Prefer Signal Forms (`@angular/forms/signals`) for new forms. They are stable in Angular v22+ and provide signal-based state, type-safe field access, and schema-based validation
|
||||||
|
- When not using Signal Forms, prefer Reactive forms instead of Template-driven ones
|
||||||
|
- Do NOT use `ngClass`, use `class` bindings instead
|
||||||
|
- Do NOT use `ngStyle`, use `style` bindings instead
|
||||||
|
- When using external templates/styles, use paths relative to the component TS file.
|
||||||
|
|
||||||
|
## State Management
|
||||||
|
|
||||||
|
- Use signals for local component state
|
||||||
|
- Use `computed()` for derived state
|
||||||
|
- Keep state transformations pure and predictable
|
||||||
|
- Do NOT use `mutate` on signals, use `update` or `set` instead
|
||||||
|
|
||||||
|
## Templates
|
||||||
|
|
||||||
|
- Keep templates simple and avoid complex logic
|
||||||
|
- Use native control flow (`@if`, `@for`, `@switch`) instead of `*ngIf`, `*ngFor`, `*ngSwitch`
|
||||||
|
- Use the async pipe to handle observables
|
||||||
|
- Do not assume globals like (`new Date()`) are available.
|
||||||
|
|
||||||
|
## Services
|
||||||
|
|
||||||
|
- Design services around a single responsibility
|
||||||
|
- Use the `providedIn: 'root'` option for singleton services
|
||||||
|
- Prefer the `@Service` decorator over `@Injectable({providedIn: 'root'})` for new singleton services (Angular v22+)
|
||||||
|
- Use the `inject()` function instead of constructor injection
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"angular-cli": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": ["-y", "@angular/cli", "mcp"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ui": {
|
||||||
|
"showLineNumbers": false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
|
||||||
|
|
||||||
|
# Compiled output
|
||||||
|
/dist
|
||||||
|
/tmp
|
||||||
|
/out-tsc
|
||||||
|
/bazel-out
|
||||||
|
|
||||||
|
# Node
|
||||||
|
/node_modules
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
.idea/
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# Visual Studio Code
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
!.vscode/mcp.json
|
||||||
|
.history/*
|
||||||
|
|
||||||
|
# Miscellaneous
|
||||||
|
/.angular/cache
|
||||||
|
.sass-cache/
|
||||||
|
/connect.lock
|
||||||
|
/coverage
|
||||||
|
/libpeerconnection.log
|
||||||
|
testem.log
|
||||||
|
/typings
|
||||||
|
__screenshots__/
|
||||||
|
|
||||||
|
# System files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"plugins": {
|
||||||
|
"@tailwindcss/postcss": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"printWidth": 100,
|
||||||
|
"singleQuote": true,
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": "*.html",
|
||||||
|
"options": {
|
||||||
|
"parser": "angular"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
|
||||||
|
"recommendations": ["angular.ng-template"]
|
||||||
|
}
|
||||||
Vendored
+20
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "ng serve",
|
||||||
|
"type": "chrome",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "npm: start",
|
||||||
|
"url": "http://localhost:4200/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ng test",
|
||||||
|
"type": "chrome",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "npm: test",
|
||||||
|
"url": "http://localhost:9876/debug.html"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Vendored
+42
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"type": "npm",
|
||||||
|
"script": "start",
|
||||||
|
"isBackground": true,
|
||||||
|
"problemMatcher": {
|
||||||
|
"owner": "typescript",
|
||||||
|
"pattern": "$tsc",
|
||||||
|
"background": {
|
||||||
|
"activeOnStart": true,
|
||||||
|
"beginsPattern": {
|
||||||
|
"regexp": "Changes detected"
|
||||||
|
},
|
||||||
|
"endsPattern": {
|
||||||
|
"regexp": "bundle generation (complete|failed)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "npm",
|
||||||
|
"script": "test",
|
||||||
|
"isBackground": true,
|
||||||
|
"problemMatcher": {
|
||||||
|
"owner": "typescript",
|
||||||
|
"pattern": "$tsc",
|
||||||
|
"background": {
|
||||||
|
"activeOnStart": true,
|
||||||
|
"beginsPattern": {
|
||||||
|
"regexp": "Changes detected"
|
||||||
|
},
|
||||||
|
"endsPattern": {
|
||||||
|
"regexp": "bundle generation (complete|failed)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
# Carparkvalidation
|
||||||
|
|
||||||
|
https://www.youtube.com/watch?v=KpNzBU4fNdU
|
||||||
|
|
||||||
|
# install AI google
|
||||||
|
npm install -g @google/gemini-cli
|
||||||
|
|
||||||
|
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 22.1.6.
|
||||||
|
|
||||||
|
## Development server
|
||||||
|
|
||||||
|
To start a local development server, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ng serve
|
||||||
|
```
|
||||||
|
|
||||||
|
Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files.
|
||||||
|
|
||||||
|
## Code scaffolding
|
||||||
|
|
||||||
|
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ng generate component component-name
|
||||||
|
```
|
||||||
|
|
||||||
|
For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ng generate --help
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
To build the project run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ng build
|
||||||
|
```
|
||||||
|
|
||||||
|
This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed.
|
||||||
|
|
||||||
|
## Running unit tests
|
||||||
|
|
||||||
|
To execute unit tests with the [Vitest](https://vitest.dev/) test runner, use the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ng test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running end-to-end tests
|
||||||
|
|
||||||
|
For end-to-end (e2e) testing, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ng e2e
|
||||||
|
```
|
||||||
|
|
||||||
|
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
|
||||||
|
|
||||||
|
## Additional Resources
|
||||||
|
|
||||||
|
For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
{
|
||||||
|
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||||
|
"version": 1,
|
||||||
|
"cli": {
|
||||||
|
"packageManager": "npm"
|
||||||
|
},
|
||||||
|
"newProjectRoot": "projects",
|
||||||
|
"projects": {
|
||||||
|
"carparkvalidation": {
|
||||||
|
"projectType": "application",
|
||||||
|
"schematics": {},
|
||||||
|
"root": "",
|
||||||
|
"sourceRoot": "src",
|
||||||
|
"prefix": "app",
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular/build:application",
|
||||||
|
"options": {
|
||||||
|
"browser": "src/main.ts",
|
||||||
|
"tsConfig": "tsconfig.app.json",
|
||||||
|
"assets": [
|
||||||
|
{
|
||||||
|
"glob": "**/*",
|
||||||
|
"input": "public"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"src/styles.css"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"budgets": [
|
||||||
|
{
|
||||||
|
"type": "initial",
|
||||||
|
"maximumWarning": "500kB",
|
||||||
|
"maximumError": "1MB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "anyComponentStyle",
|
||||||
|
"maximumWarning": "4kB",
|
||||||
|
"maximumError": "8kB"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputHashing": "all"
|
||||||
|
},
|
||||||
|
"development": {
|
||||||
|
"optimization": false,
|
||||||
|
"extractLicenses": false,
|
||||||
|
"sourceMap": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultConfiguration": "production"
|
||||||
|
},
|
||||||
|
"serve": {
|
||||||
|
"builder": "@angular/build:dev-server",
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"buildTarget": "carparkvalidation:build:production"
|
||||||
|
},
|
||||||
|
"development": {
|
||||||
|
"buildTarget": "carparkvalidation:build:development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultConfiguration": "development"
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular/build:unit-test"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+8582
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"name": "carparkvalidation",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"ng": "ng",
|
||||||
|
"start": "ng serve",
|
||||||
|
"build": "ng build",
|
||||||
|
"watch": "ng build --watch --configuration development",
|
||||||
|
"test": "ng test"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"packageManager": "npm@11.12.1",
|
||||||
|
"dependencies": {
|
||||||
|
"@angular/common": "^22.1.0",
|
||||||
|
"@angular/compiler": "^22.1.0",
|
||||||
|
"@angular/core": "^22.1.0",
|
||||||
|
"@angular/forms": "^22.1.0",
|
||||||
|
"@angular/platform-browser": "^22.1.0",
|
||||||
|
"@angular/router": "^22.1.0",
|
||||||
|
"@google/generative-ai": "^0.24.1",
|
||||||
|
"@primeicons/angular": "^8.0.1",
|
||||||
|
"@primeuix/themes": "^3.0.1",
|
||||||
|
"moment": "^2.31.0",
|
||||||
|
"primeng": "^22.1.1",
|
||||||
|
"rxjs": "~7.8.0",
|
||||||
|
"tslib": "^2.3.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@angular/build": "^22.1.6",
|
||||||
|
"@angular/cli": "^22.1.6",
|
||||||
|
"@angular/compiler-cli": "^22.1.0",
|
||||||
|
"@tailwindcss/postcss": "^4.1.12",
|
||||||
|
"jsdom": "^28.0.0",
|
||||||
|
"postcss": "^8.5.3",
|
||||||
|
"prettier": "^3.8.1",
|
||||||
|
"tailwindcss": "^4.1.12",
|
||||||
|
"typescript": "~6.0.2",
|
||||||
|
"vitest": "^4.0.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"baseUrl4": "http://localhost:5100",
|
||||||
|
"baseUrl": "http://nephmdb-sql007/CarParkValidationAPI",
|
||||||
|
"loginUrl": "api/login",
|
||||||
|
"updatePersonUrl": "api/updatePerson",
|
||||||
|
"getAllUrl": "api/v1/Users/GetAllUsers",
|
||||||
|
"authenticateUrl": "api/v1/Users/Authenticate",
|
||||||
|
"validationPoint": "api/v1/ValidationPoint",
|
||||||
|
"adminEmail": "NBMLHD-parking@health.nsw.gov.au"
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 74 KiB |
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export * from './adminuser.component';
|
||||||
|
export * from './adminuser.edit.component';
|
||||||
|
export * from './adminuser.service';
|
||||||
|
|
||||||
@@ -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)
|
||||||
|
]
|
||||||
|
};
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
@if (isAuth() == true) {
|
||||||
|
<app-nav-toolbar ></app-nav-toolbar>
|
||||||
|
}
|
||||||
|
<router-outlet />
|
||||||
|
<p-confirmdialog></p-confirmdialog>
|
||||||
|
<p-toast></p-toast>
|
||||||
@@ -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' },
|
||||||
|
];
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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';
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './login.component';
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
.btnloginRigh {
|
||||||
|
display: flex;
|
||||||
|
flex-direction:reverse;
|
||||||
|
justify-content:flex-end;
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
}
|
||||||
@@ -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",
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
};
|
||||||
@@ -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';
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
export interface Lookup {
|
||||||
|
id: number;
|
||||||
|
categoryId: number;
|
||||||
|
description: string;
|
||||||
|
};
|
||||||
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
export interface PageQuery {
|
||||||
|
pageIndex: number;
|
||||||
|
pageSize: number;
|
||||||
|
search: string;
|
||||||
|
};
|
||||||
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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) { }
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export interface ResultModel<T> {
|
||||||
|
data: T;
|
||||||
|
message: string;
|
||||||
|
statusCode:number;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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']);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './auth.guard';
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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';
|
||||||
|
|
||||||
@@ -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]))]
|
||||||
|
*/
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;;;AAAA,8CAAyC;AACzC,oCAA+B"}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './authentication.service';
|
||||||
|
export * from './user.service';
|
||||||
@@ -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}`);
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Carparkvalidation</title>
|
||||||
|
<base href="/">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<app-root></app-root>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { bootstrapApplication } from '@angular/platform-browser';
|
||||||
|
import { appConfig } from './app/app.config';
|
||||||
|
import { App } from './app/app';
|
||||||
|
|
||||||
|
bootstrapApplication(App, appConfig)
|
||||||
|
.catch((err) => console.error(err));
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user