Commit 41d4ff00 authored by vtduong0912's avatar vtduong0912

form

parent 8b23d2da
...@@ -18,15 +18,19 @@ export class JobManagerService { ...@@ -18,15 +18,19 @@ export class JobManagerService {
}); });
} }
jobsGetOne(id: string) {
return this._http.get<ResponseResult<JobApi.Response>>('jobs/' + id);
}
jobsPost(request: JobApi.Request) { jobsPost(request: JobApi.Request) {
return this._http.post<ResponseResult<JobApi.Request>>('jobs', request); return this._http.post<ResponseResult<JobApi.Request>>('jobs', request);
} }
jobsPut(request: JobApi.Request) { jobsPut(id: string, request: JobApi.Request) {
return this._http.put<ResponseResult<JobApi.Request>>('jobs', request); return this._http.put<ResponseResult<JobApi.Request>>('jobs/' + id, request);
} }
jobsDelete(id: number) { jobsDelete(id: string) {
return this._http.delete<ResponseResult<JobApi.Request>>('jobs'); return this._http.delete<ResponseResult<JobApi.Request>>('jobs/' + id);
} }
} }
\ No newline at end of file
import { Component, OnInit } from '@angular/core'; import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
import { NzButtonModule } from 'ng-zorro-antd/button';
import { NzModalModule } from 'ng-zorro-antd/modal';
import { JobManagerService } from '../data-access/service/job-manager.service';
import { ResponseResult } from '../../../../shared/data-access/interface/response.type';
import { JobApi } from '../data-access/model/job-manager.model';
import { catchError, of, tap } from 'rxjs';
@Component({ @Component({
selector: 'job-form', selector: 'job-form',
standalone: true, standalone: true,
imports: [
NzButtonModule,
NzModalModule,
ReactiveFormsModule
],
template: ` template: `
<div [class]="{'tw-hidden': isHidden}"> <div class="tw-w-full tw-grid tw-justify-items-end">
<button nz-button nzType="primary" (click)="isCreate = true">Create new job</button>
</div>
<nz-modal [(nzVisible)]="isCreate" nzTitle="Create new job" nzCancelText="Cancel" nzOkText="Create" (nzOnCancel)="isCreate = false" (nzOnOk)="isCreate = false; onCreateSubmit()">
<ng-container *nzModalContent>
<form [formGroup]="jobCreatingFormGroup">
<div class="tw-flex tw-flex-col tw-flex-wrap tw-gap-y-1">
<label>Type</label>
<select class="tw-border tw-rounded-lg tw-h-8" formControlName="type">
<option value="Full Time">Full Time</option>
<option value="Part Time">Part Time</option>
</select>
<label>Company</label>
<input class="tw-border tw-rounded-lg tw-h-8" type="text" formControlName="company">
<label>Company Url</label>
<input class="tw-border tw-rounded-lg tw-h-8" type="text" formControlName="company_url">
<label>Location</label>
<input class="tw-border tw-rounded-lg tw-h-8" type="text" formControlName="location">
<label>Tilte</label>
<input class="tw-border tw-rounded-lg tw-h-8" type="text" formControlName="title">
<label>Description</label>
<textarea class="tw-border tw-rounded-lg tw-h-20" type="text" formControlName="description"></textarea>
<label>How to Apply</label>
<input class="tw-border tw-rounded-lg tw-h-8" type="text" formControlName="how_to_apply">
<label>Company Logo</label>
<input class="tw-border tw-rounded-lg tw-h-8" type="text" formControlName="company_logo">
<label>Url</label>
<input class="tw-border tw-rounded-lg tw-h-8" type="text" formControlName="url">
</div> </div>
</form>
</ng-container>
</nz-modal>
` `
}) })
export class JobFormComponent implements OnInit { export class JobFormComponent implements OnInit, OnDestroy {
isHidden: boolean = true;
constructor() { } isCreate: boolean = false;
jobCreatingFormGroup: FormGroup;
constructor(private _fb: FormBuilder, private _service: JobManagerService) {
this.jobCreatingFormGroup = this._fb.group({
type: ['Full Time', Validators.required],
company: ['', Validators.required],
company_url: ['', Validators.required],
location: ['', Validators.required],
title: ['', Validators.required],
description: ['', Validators.required],
how_to_apply: ['', Validators.required],
company_logo: ['', Validators.required],
url: ['', Validators.required],
});
}
ngOnInit() {
}
ngOnDestroy() {
}
onCreateSubmit() {
const data = this.jobCreatingFormGroup.value;
if (!this.jobCreatingFormGroup.valid) {
Object.values(this.jobCreatingFormGroup.controls).forEach(control => {
if (control.invalid) {
control.markAsDirty();
control.updateValueAndValidity({ onlySelf: true });
}
});
return;
}
this.jobCreatingFormGroup.markAllAsTouched();
this._service.jobsPost(data)
.pipe(
tap((response: ResponseResult<JobApi.Request>) => {
console.log(response);
}),
catchError((err) => {
return of(null);
})
)
.subscribe();
}
onEditSubmit() {
}
ngOnInit() { }
} }
\ No newline at end of file
...@@ -7,6 +7,11 @@ import { catchError, of, tap } from 'rxjs'; ...@@ -7,6 +7,11 @@ import { catchError, of, tap } from 'rxjs';
import { ResponseResult, Rows } from '../../../../shared/data-access/interface/response.type'; import { ResponseResult, Rows } from '../../../../shared/data-access/interface/response.type';
import { JobApi } from '../data-access/model/job-manager.model'; import { JobApi } from '../data-access/model/job-manager.model';
import { NzButtonModule } from 'ng-zorro-antd/button'; import { NzButtonModule } from 'ng-zorro-antd/button';
import { NzModalModule } from 'ng-zorro-antd/modal';
import { NzPaginationModule } from 'ng-zorro-antd/pagination';
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
import { response } from 'express';
import { NzFormModule } from 'ng-zorro-antd/form';
@Component({ @Component({
selector: 'job-list', selector: 'job-list',
...@@ -16,6 +21,10 @@ import { NzButtonModule } from 'ng-zorro-antd/button'; ...@@ -16,6 +21,10 @@ import { NzButtonModule } from 'ng-zorro-antd/button';
NzLayoutModule, NzLayoutModule,
NzTableModule, NzTableModule,
NzButtonModule, NzButtonModule,
NzModalModule,
NzPaginationModule,
ReactiveFormsModule,
NzFormModule
], ],
styles: ` styles: `
nz-table[_ngcontent-jjj-c198] nz-pagination[_ngcontent-jjj-c198] { nz-table[_ngcontent-jjj-c198] nz-pagination[_ngcontent-jjj-c198] {
...@@ -23,40 +32,79 @@ import { NzButtonModule } from 'ng-zorro-antd/button'; ...@@ -23,40 +32,79 @@ import { NzButtonModule } from 'ng-zorro-antd/button';
} }
`, `,
template: ` template: `
<nz-modal [(nzVisible)]="isDeleting" nzTitle="Warning" nzCancelText="No" nzOkText="Yes" (nzOnCancel)="isDeleting = false" (nzOnOk)="onDelete()">
<ng-container *nzModalContent>
<p>Are you sure you want to delete this job?</p>
</ng-container>
</nz-modal>
<nz-modal [(nzVisible)]="isEdit" nzTitle="Create new job" nzCancelText="Cancel" nzOkText="Confirm" (nzOnCancel)="isEdit = false" (nzOnOk)="onEditSubmit()">
<ng-container *nzModalContent>
<form nz-form [formGroup]="jobEdittingFormGroup">
<div class="tw-flex tw-flex-col tw-flex-wrap tw-gap-y-1">
<label>Type</label>
<select class="tw-border tw-rounded-lg tw-h-8" formControlName="type">
<option value="Full Time">Full Time</option>
<option value="Part Time">Part Time</option>
</select>
<nz-form-item>
<label>Company</label>
<nz-form-control nzErrorTip="Please input your username!">
<nz-input-group class="tw-h-12">
<input class="tw-border tw-rounded-lg tw-h-8" type="text" formControlName="company">
</nz-input-group>
</nz-form-control>
</nz-form-item>
<label>Company Url</label>
<input class="tw-border tw-rounded-lg tw-h-8" type="text" formControlName="company_url">
<label>Location</label>
<input class="tw-border tw-rounded-lg tw-h-8" type="text" formControlName="location">
<label>Tilte</label>
<input class="tw-border tw-rounded-lg tw-h-8" type="text" formControlName="title">
<label>Description</label>
<textarea class="tw-border tw-rounded-lg tw-h-20" type="text" formControlName="description"></textarea>
<label>How to Apply</label>
<input class="tw-border tw-rounded-lg tw-h-8" type="text" formControlName="how_to_apply">
<label>Company Logo</label>
<input class="tw-border tw-rounded-lg tw-h-8" type="text" formControlName="company_logo">
<label>Url</label>
<input class="tw-border tw-rounded-lg tw-h-8" type="text" formControlName="url">
</div>
</form>
</ng-container>
</nz-modal>
<nz-content class="tw-my-3"> <nz-content class="tw-my-3">
<nz-table <nz-table
#rowTable #rowTable
[nzData]="jobsList" [nzData]="['']"
[nzPageSize]="5" [nzPageSize]="5"
nzShowPagination [nzFrontPagination]="false"
nzShowSizeChanger
[nzPageSizeOptions]="[5, 10, 25, 50, 100]"
class="tw-my-3" class="tw-my-3"
> >
<thead> <thead>
<tr> <tr>
<th> <th nzWidth="100px">
Ord. Ord.
</th> </th>
<th> <th nzWidth="100px">
Title Title
</th> </th>
<th> <th nzWidth="100px">
Company Company
</th> </th>
<th> <th nzWidth="100px">
Created at Created at
</th> </th>
<th> <th nzWidth="100px">
Actions Actions
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr *ngFor="let job of rowTable.data; let idx = index" class="tw-border-b"> <tr *ngFor="let job of jobsList?.rows; let idx = index" class="tw-border-b">
<td> <td>
<p> {{ rowTable.nzPageSize * (rowTable.nzPageIndex - 1) + idx }}</p> <p>{{ idx + ((pageIndex - 1) * pageSize) + 1}}</p>
</td> </td>
<td> <td>
<p>{{ job.title }}</p> <p>{{ job.title }}</p>
...@@ -68,24 +116,56 @@ import { NzButtonModule } from 'ng-zorro-antd/button'; ...@@ -68,24 +116,56 @@ import { NzButtonModule } from 'ng-zorro-antd/button';
<p>{{ job.created_at | date: 'dd/MM/yyyy' }}</p> <p>{{ job.created_at | date: 'dd/MM/yyyy' }}</p>
</td> </td>
<td> <td>
<button nz-button nzType="primary" class="tw-mx-0.5">Edit</button> <button nz-button nzType="primary" class="tw-mx-0.5" (click)="onEditOpen(job.id)">Edit</button>
<button nz-button nzType="primary" nzDanger class="tw-mx-0.5">Delete</button> <button nz-button nzType="primary" nzDanger class="tw-mx-0.5" (click)="showConfirmModal(job.id)">Delete</button>
</td> </td>
</tr> </tr>
</tbody> </tbody>
</nz-table> </nz-table>
</nz-content> </nz-content>
<div class="tw-w-full tw-grid tw-justify-items-center tw-my-3">
<nz-pagination
(nzPageIndexChange)="onPageIndexChange($event)"
[nzPageIndex]="pageIndex"
[nzPageSize]="pageSize"
[nzTotal]="jobsList?.itemCount || 0 * 10"
>
</nz-pagination>
</div>
`, `,
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class JobListComponent implements OnInit { export class JobListComponent implements OnInit {
pageIndex: number = 1; pageIndex: number = 1;
pageSize: number = 999; pageSize: number = 5;
jobsList: JobApi.Response[] = []; jobsList: Rows<JobApi.Response> | null = null;
isDeleting: boolean = false;
deletetingId: string = "";
isEdit: boolean = false;
edittingId: string = "";
jobEdittingFormGroup: FormGroup;
@Output() pageIndexChange: EventEmitter<number> = new EventEmitter<number>; @Output() pageIndexChange: EventEmitter<number> = new EventEmitter<number>;
constructor(private _service: JobManagerService, private _cdr: ChangeDetectorRef) { } constructor(
private _service: JobManagerService,
private _cdr: ChangeDetectorRef,
private _fb: FormBuilder) {
this.jobEdittingFormGroup = this._fb.group({
type: ['Full Time', Validators.required],
company: ['', Validators.required],
company_url: ['', Validators.required],
location: ['', Validators.required],
title: ['', Validators.required],
description: ['', Validators.required],
how_to_apply: ['', Validators.required],
company_logo: ['', Validators.required],
url: ['', Validators.required],
});
}
ngOnInit(): void { ngOnInit(): void {
this.getAllJobs(this.pageIndex, this.pageSize); this.getAllJobs(this.pageIndex, this.pageSize);
} }
...@@ -94,7 +174,7 @@ export class JobListComponent implements OnInit { ...@@ -94,7 +174,7 @@ export class JobListComponent implements OnInit {
this._service.jobsGet(pageIndex, pageSize) this._service.jobsGet(pageIndex, pageSize)
.pipe( .pipe(
tap((response: ResponseResult<Rows<JobApi.Response>>) => { tap((response: ResponseResult<Rows<JobApi.Response>>) => {
this.jobsList = response.responseData?.rows || []; this.jobsList = response.responseData;
console.log(this.jobsList); console.log(this.jobsList);
this._cdr.markForCheck(); this._cdr.markForCheck();
}), }),
...@@ -106,6 +186,80 @@ export class JobListComponent implements OnInit { ...@@ -106,6 +186,80 @@ export class JobListComponent implements OnInit {
} }
onPageIndexChange(index: number) { onPageIndexChange(index: number) {
this.getAllJobs(index, this.pageSize); this.pageIndex = index;
this.getAllJobs(index, 5);
}
showConfirmModal(id: string) {
this.isDeleting = true;
this.deletetingId = id;
}
onDelete() {
this._service.jobsDelete(this.deletetingId).
pipe(
tap((response: ResponseResult<JobApi.Request>) => {
this.getAllJobs();
}),
catchError((err) => {
console.log(err);
return of(null);
})
)
.subscribe();
this.isDeleting = false;
this.deletetingId = "";
}
onEditSubmit() {
const data = this.jobEdittingFormGroup.value;
if (!this.jobEdittingFormGroup.valid) {
Object.values(this.jobEdittingFormGroup.controls).forEach(control => {
if (control.invalid) {
control.markAsDirty();
control.updateValueAndValidity({ onlySelf: true });
}
});
return;
}
this.jobEdittingFormGroup.markAllAsTouched();
this._service.jobsPut(this.edittingId, data)
.pipe(
tap((response: ResponseResult<JobApi.Request>) => {
this.getAllJobs();
this.isEdit = false;
console.log(response);
}),
catchError((err) => {
console.log(err);
return of(null);
})
)
.subscribe();
}
onEditOpen(id: string) {
this.isEdit = true;
this.edittingId = id;
this._service.jobsGetOne(id)
.pipe(
tap((response: ResponseResult<JobApi.Response>) => {
this.jobEdittingFormGroup = this._fb.group({
type: [response.responseData?.type, Validators.required],
company: [response.responseData?.company, Validators.required],
company_url: [response.responseData?.company_url, Validators.required],
location: [response.responseData?.location, Validators.required],
title: [response.responseData?.title, Validators.required],
description: [response.responseData?.description, Validators.required],
how_to_apply: [response.responseData?.how_to_apply, Validators.required],
company_logo: [response.responseData?.company_logo, Validators.required],
url: [response.responseData?.url],
});
}),
catchError((err) => {
return of(null);
})
)
.subscribe();
} }
} }
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { JobListComponent } from './job-list.component'; import { JobListComponent } from './job-list.component';
import { NzButtonModule } from 'ng-zorro-antd/button';
import { JobFormComponent } from './job-form.component'; import { JobFormComponent } from './job-form.component';
@Component({ @Component({
...@@ -9,13 +8,9 @@ import { JobFormComponent } from './job-form.component'; ...@@ -9,13 +8,9 @@ import { JobFormComponent } from './job-form.component';
imports: [ imports: [
JobListComponent, JobListComponent,
JobFormComponent, JobFormComponent,
NzButtonModule
], ],
template: ` template: `
<h1 class="tw-text-center tw-text-3xl tw-font-semibold tw-my-3">Jobs</h1> <h1 class="tw-text-center tw-text-3xl tw-font-semibold tw-my-3">Jobs</h1>
<div class="tw-w-full tw-grid tw-justify-items-end">
<button nz-button nzType="primary">Create new job</button>
</div>
<job-form></job-form> <job-form></job-form>
<job-list></job-list> <job-list></job-list>
` `
......
...@@ -4,7 +4,7 @@ import { CommonModule, DatePipe, JsonPipe, NgFor } from '@angular/common'; ...@@ -4,7 +4,7 @@ import { CommonModule, DatePipe, JsonPipe, NgFor } from '@angular/common';
import { JobService } from '../data-access/service/job.service' import { JobService } from '../data-access/service/job.service'
import { ResponseResult, Rows } from '../../shared/data-access/interface/response.type'; import { ResponseResult, Rows } from '../../shared/data-access/interface/response.type';
import { Jobs } from '../data-access/model/job.model'; import { Jobs } from '../data-access/model/job.model';
import { catchError, map, of, tap } from 'rxjs'; import { catchError, of, tap } from 'rxjs';
import { NzCardModule } from 'ng-zorro-antd/card'; import { NzCardModule } from 'ng-zorro-antd/card';
import { NzAvatarModule } from 'ng-zorro-antd/avatar'; import { NzAvatarModule } from 'ng-zorro-antd/avatar';
import { NzPaginationModule } from 'ng-zorro-antd/pagination'; import { NzPaginationModule } from 'ng-zorro-antd/pagination';
...@@ -17,7 +17,6 @@ import { NzPaginationModule } from 'ng-zorro-antd/pagination'; ...@@ -17,7 +17,6 @@ import { NzPaginationModule } from 'ng-zorro-antd/pagination';
imports: [ imports: [
CommonModule, CommonModule,
NgFor, NgFor,
JsonPipe,
NzCardModule, NzCardModule,
NzAvatarModule, NzAvatarModule,
NzPaginationModule, NzPaginationModule,
......
...@@ -11,7 +11,7 @@ import { NzAlertModule } from 'ng-zorro-antd/alert'; ...@@ -11,7 +11,7 @@ import { NzAlertModule } from 'ng-zorro-antd/alert';
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
import { AuthService } from '../data-access/service/auth.service'; import { AuthService } from '../data-access/service/auth.service';
import { validateUsername } from '../../shared/utils/form-validator/username.validator'; import { validateUsername } from '../../shared/utils/form-validator/username.validator';
import { catchError, map, of, tap } from 'rxjs'; import { catchError, of, tap } from 'rxjs';
import { ResponseResult } from '../../shared/data-access/interface/response.type'; import { ResponseResult } from '../../shared/data-access/interface/response.type';
import { Login } from '../data-access/model/login.model'; import { Login } from '../data-access/model/login.model';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
...@@ -31,7 +31,6 @@ import { Router } from '@angular/router'; ...@@ -31,7 +31,6 @@ import { Router } from '@angular/router';
NzAlertModule, NzAlertModule,
NzFormModule, NzFormModule,
ReactiveFormsModule, ReactiveFormsModule,
JsonPipe
], ],
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
...@@ -43,7 +42,6 @@ export class LoginComponent implements OnInit { ...@@ -43,7 +42,6 @@ export class LoginComponent implements OnInit {
constructor( constructor(
private _fb: FormBuilder, private _fb: FormBuilder,
private _authService: AuthService, private _authService: AuthService,
private _changeDetectorRef: ChangeDetectorRef,
private _router: Router private _router: Router
) { ) {
this.signInFormGroup = this._fb.group({ this.signInFormGroup = this._fb.group({
...@@ -82,6 +80,7 @@ export class LoginComponent implements OnInit { ...@@ -82,6 +80,7 @@ export class LoginComponent implements OnInit {
} }
onSuccess(response: ResponseResult<Login.Response>) { onSuccess(response: ResponseResult<Login.Response>) {
console.log(response.responseData?.token);
localStorage.setItem("token", response.responseData?.token ?? ""); localStorage.setItem("token", response.responseData?.token ?? "");
localStorage.setItem("role", response.responseData?.role ?? ""); localStorage.setItem("role", response.responseData?.role ?? "");
this._router.navigate(['/home']); this._router.navigate(['/home']);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment