Compare commits
7 commits
feature/em
...
trunk
Author | SHA1 | Date | |
---|---|---|---|
856d3e44b9 | |||
|
748df61dc6 | ||
c08df8c2d8 | |||
|
9d3be76744 | ||
c43d73aadb | |||
|
3bffc414ec | ||
3a528b0a01 |
8 changed files with 277 additions and 15 deletions
8
src/app/delete-model/DeleteModalData.d.ts
vendored
Normal file
8
src/app/delete-model/DeleteModalData.d.ts
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
interface DeleteModalData {
|
||||||
|
title: string,
|
||||||
|
description: string,
|
||||||
|
cancel: string,
|
||||||
|
ok: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DeleteModalData;
|
8
src/app/delete-model/delete-model.component.html
Normal file
8
src/app/delete-model/delete-model.component.html
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<h2 mat-dialog-title>{{ data.title}}</h2>
|
||||||
|
<mat-dialog-content>
|
||||||
|
<p>{{data.description}}</p>
|
||||||
|
</mat-dialog-content>
|
||||||
|
<mat-dialog-actions class="delete-modal">
|
||||||
|
<button mat-flat-button [mat-dialog-close]="false">{{data.cancel}}</button>
|
||||||
|
<button mat-flat-button [mat-dialog-close]="true" class="warn">{{data.ok}}</button>
|
||||||
|
</mat-dialog-actions>
|
4
src/app/delete-model/delete-model.component.scss
Normal file
4
src/app/delete-model/delete-model.component.scss
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
.delete-modal {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
32
src/app/delete-model/delete-model.component.ts
Normal file
32
src/app/delete-model/delete-model.component.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import {Component, Inject} from '@angular/core';
|
||||||
|
import {MatButton} from '@angular/material/button';
|
||||||
|
import {
|
||||||
|
MAT_DIALOG_DATA,
|
||||||
|
MatDialogActions, MatDialogClose,
|
||||||
|
MatDialogContent,
|
||||||
|
MatDialogTitle
|
||||||
|
} from '@angular/material/dialog';
|
||||||
|
import DeleteModalData from '@app/delete-model/DeleteModalData';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-delete-model',
|
||||||
|
imports: [
|
||||||
|
MatDialogContent,
|
||||||
|
MatDialogActions,
|
||||||
|
MatDialogTitle,
|
||||||
|
MatButton,
|
||||||
|
MatDialogClose
|
||||||
|
],
|
||||||
|
templateUrl: './delete-model.component.html',
|
||||||
|
styleUrl: './delete-model.component.scss'
|
||||||
|
})
|
||||||
|
export class DeleteModelComponent {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Inject(MAT_DIALOG_DATA) protected data: DeleteModalData,
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
8
src/app/views/dashboard/Filter.d.ts
vendored
Normal file
8
src/app/views/dashboard/Filter.d.ts
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import {Qualification} from '@core/ems';
|
||||||
|
|
||||||
|
interface Filter {
|
||||||
|
fuzzy: string,
|
||||||
|
qualification: Qualification|undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Filter;
|
|
@ -1,4 +1,63 @@
|
||||||
<a mat-flat-button routerLink="/employee/new">New Employee</a>
|
<div class="dashboard">
|
||||||
<a mat-flat-button routerLink="/employee/1">Edit Employee 3</a>
|
@if (auth.$user|async; as user) {
|
||||||
<button mat-flat-button (click)="testInfo()">Test Info</button>
|
<div class="dashboard__action-row">
|
||||||
<button mat-flat-button (click)="testError()">Test Error</button>
|
<mat-form-field>
|
||||||
|
<mat-label>Search</mat-label>
|
||||||
|
<input matInput (keyup)="onFuzzyFilter($event)">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-label>Qualification</mat-label>
|
||||||
|
<mat-select [(value)]="selectedQualificationFilter" (valueChange)="onFilterUpdate()">
|
||||||
|
<mat-option>None</mat-option>
|
||||||
|
@for (skill of ($qualifications|async); track skill) {
|
||||||
|
<mat-option [value]="skill">{{ skill.skill }}</mat-option>
|
||||||
|
}
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<button mat-fab class="shadowless" routerLink="employee/new">
|
||||||
|
<mat-icon>add</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<mat-table [dataSource]="employeeDataSource" class="dashboard__employees">
|
||||||
|
<ng-container matColumnDef="id">
|
||||||
|
<th mat-header-cell *matHeaderCellDef>Id</th>
|
||||||
|
<td mat-cell *matCellDef="let employee">{{ employee.id }}</td>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container matColumnDef="first-name">
|
||||||
|
<th mat-header-cell *matHeaderCellDef>First Name</th>
|
||||||
|
<td mat-cell *matCellDef="let employee">{{ employee.firstName }}</td>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container matColumnDef="last-name">
|
||||||
|
<th mat-header-cell *matHeaderCellDef>Last Name</th>
|
||||||
|
<td mat-cell *matCellDef="let employee">{{ employee.lastName }}</td>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container matColumnDef="skills">
|
||||||
|
<th mat-header-cell *matHeaderCellDef>Skills</th>
|
||||||
|
<td mat-cell *matCellDef="let employee">
|
||||||
|
<ul>
|
||||||
|
@for (skill of employee.skillSet; track skill) {
|
||||||
|
<li>{{ skill.skill }}</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container matColumnDef="actions">
|
||||||
|
<th mat-header-cell *matHeaderCellDef></th>
|
||||||
|
<td mat-cell *matCellDef="let employee">
|
||||||
|
<button mat-mini-fab class="shadowless" routerLink="employee/{{employee.id}}">
|
||||||
|
<mat-icon>edit</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-mini-fab class="shadowless warn" (click)="onDelete(employee)">
|
||||||
|
<mat-icon>delete</mat-icon>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
<tr mat-header-row *matHeaderRowDef="employeesDisplayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: employeesDisplayedColumns;"></tr>
|
||||||
|
</mat-table>
|
||||||
|
} @else {
|
||||||
|
<p>Log in to see more!</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
.dashboard {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
|
&__action-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
|
:first-child {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__employees {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
tr {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.mat-column-id{
|
||||||
|
width: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-column-first-name, .mat-column-last-name, .mat-column-skills {
|
||||||
|
width: 0;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul{
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
th.mat-column-actions{
|
||||||
|
width: calc(40px * 2 + 1rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
td.mat-column-actions{
|
||||||
|
gap: 1rem;
|
||||||
|
display: flex;
|
||||||
|
padding: 0;
|
||||||
|
padding-top: 0.25rem;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,20 +1,114 @@
|
||||||
|
import {AsyncPipe} from '@angular/common';
|
||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
|
import {ReactiveFormsModule} from '@angular/forms';
|
||||||
import {MatButtonModule} from '@angular/material/button';
|
import {MatButtonModule} from '@angular/material/button';
|
||||||
|
import {MatDialog} from '@angular/material/dialog';
|
||||||
|
import {MatFormFieldModule} from '@angular/material/form-field';
|
||||||
|
import {MatIcon} from '@angular/material/icon';
|
||||||
|
import {MatInputModule} from '@angular/material/input';
|
||||||
|
import {MatSelectModule} from '@angular/material/select';
|
||||||
|
import {MatTableDataSource, MatTableModule} from '@angular/material/table';
|
||||||
import {RouterLink} from '@angular/router';
|
import {RouterLink} from '@angular/router';
|
||||||
|
import {DeleteModelComponent} from '@app/delete-model/delete-model.component';
|
||||||
|
import Filter from '@app/views/dashboard/Filter';
|
||||||
|
import {AuthService} from '@core/auth/auth.service';
|
||||||
|
import {Employee, EmployeeService, Qualification, QualificationService} from '@core/ems';
|
||||||
import {NotificationService, NotificationType} from '@core/notification/notification.service';
|
import {NotificationService, NotificationType} from '@core/notification/notification.service';
|
||||||
|
import {Observable} from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-dashboard',
|
selector: 'app-dashboard',
|
||||||
imports: [MatButtonModule, RouterLink],
|
imports: [MatButtonModule, MatSelectModule, MatFormFieldModule, MatTableModule, ReactiveFormsModule, MatInputModule, MatIcon, RouterLink, AsyncPipe],
|
||||||
templateUrl: './dashboard.component.html',
|
templateUrl: './dashboard.component.html',
|
||||||
styleUrl: './dashboard.component.scss'
|
styleUrl: './dashboard.component.scss'
|
||||||
})
|
})
|
||||||
export class DashboardComponent {
|
export class DashboardComponent {
|
||||||
constructor(private notifications: NotificationService) { }
|
selectedQualificationFilter: Qualification | undefined;
|
||||||
testInfo() {
|
fuzzyFilter: string = '';
|
||||||
this.notifications.publish('Cake', NotificationType.Information);
|
|
||||||
|
employeeDataSource: MatTableDataSource<Employee> = new MatTableDataSource<Employee>([]);
|
||||||
|
employeesDisplayedColumns = ['id', 'first-name', 'last-name', 'skills', 'actions'];
|
||||||
|
$qualifications: Observable<Array<Qualification> | undefined>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected auth: AuthService,
|
||||||
|
private employeeService: EmployeeService,
|
||||||
|
private qualificationService: QualificationService,
|
||||||
|
private dialog: MatDialog,
|
||||||
|
private notifications: NotificationService
|
||||||
|
) {
|
||||||
|
this.$qualifications = this.qualificationService.getAllQualifications();
|
||||||
|
this.employeeService.getAllEmployees().subscribe((employees) => {
|
||||||
|
this.employeeDataSource = new MatTableDataSource(employees);
|
||||||
|
this.employeeDataSource.filterPredicate = (employee: Employee, rawFilter: string): boolean => {
|
||||||
|
const filter = JSON.parse(rawFilter) as Filter;
|
||||||
|
if (filter.fuzzy == '' && filter.qualification == undefined) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
testError() {
|
if (
|
||||||
this.notifications.publish('Cake', NotificationType.Error);
|
filter.qualification != undefined
|
||||||
}}
|
&& !employee.skillSet.map((skill) => skill.id).includes(filter.qualification.id)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
filter.fuzzy != ''
|
||||||
|
&& !employee.id.toString().includes(filter.fuzzy)
|
||||||
|
&& !employee.firstName.toLowerCase().includes(filter.fuzzy)
|
||||||
|
&& !employee.lastName.toLowerCase().includes(filter.fuzzy)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onDelete(employee: Employee) {
|
||||||
|
const dialogRef = this.dialog.open(DeleteModelComponent, {
|
||||||
|
data: {
|
||||||
|
title: `Delete ${employee.firstName} ${employee.lastName}`,
|
||||||
|
description: `Do you really want to delete ${employee.firstName} ${employee.lastName}?`,
|
||||||
|
cancel: 'No',
|
||||||
|
ok: 'Yes',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe((accepted: boolean) => {
|
||||||
|
if (!accepted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.employeeService.deleteEmployee({id: employee.id}).subscribe(() => {
|
||||||
|
const data = this.employeeDataSource.data;
|
||||||
|
const i = data.indexOf(employee);
|
||||||
|
if (i != -1) {
|
||||||
|
data.splice(i, 1);
|
||||||
|
this.employeeDataSource.data = data;
|
||||||
|
}
|
||||||
|
this.notifications.publish(`Deleted ${employee.firstName} ${employee.lastName}`, NotificationType.Information);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onFuzzyFilter(event: KeyboardEvent) {
|
||||||
|
this.fuzzyFilter = (event.target as HTMLInputElement).value;
|
||||||
|
this.onFilterUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
onFilterUpdate() {
|
||||||
|
const skill = this.selectedQualificationFilter;
|
||||||
|
const fuzzy = this.fuzzyFilter;
|
||||||
|
if (skill == undefined && fuzzy == '') {
|
||||||
|
this.employeeDataSource.filter = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.employeeDataSource.filter = JSON.stringify({
|
||||||
|
qualification: skill,
|
||||||
|
fuzzy: fuzzy.toLowerCase()
|
||||||
|
} as Filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue