Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
M
Meu-Template-Angular-CSR
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Trần Anh Phú
Meu-Template-Angular-CSR
Commits
5465e871
Commit
5465e871
authored
Dec 23, 2024
by
tinhbe
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update
parent
d3f8c729
Changes
33
Show whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
922 additions
and
420 deletions
+922
-420
JobDetail.component.html
.../Management/Job/Action/JobDetail/JobDetail.component.html
+57
-0
JobDetail.component.ts
...in/Management/Job/Action/JobDetail/JobDetail.component.ts
+41
-0
Modal.component.html
...admin/Management/Job/Action/ModalJob/Modal.component.html
+97
-0
Modal.component.ts
.../+admin/Management/Job/Action/ModalJob/Modal.component.ts
+150
-0
Job.component.html
src/app/+admin/Management/Job/Job.component.html
+34
-57
Job.component.scss
src/app/+admin/Management/Job/Job.component.scss
+0
-0
Job.component.ts
src/app/+admin/Management/Job/Job.component.ts
+109
-136
jobModel.model.ts
src/app/+admin/data-access/model/jobModel.model.ts
+22
-11
JobService.service.ts
src/app/+admin/data-access/services/JobService.service.ts
+11
-24
footer.component.html
...layout/feature/ui/Components/footer/footer.component.html
+8
-12
footer.component.ts
...n/layout/feature/ui/Components/footer/footer.component.ts
+7
-0
header.component.html
...layout/feature/ui/Components/header/header.component.html
+0
-4
header.component.ts
...n/layout/feature/ui/Components/header/header.component.ts
+0
-14
layout.component.html
src/app/+admin/layout/feature/ui/layout.component.html
+49
-20
layout.component.scss
src/app/+admin/layout/feature/ui/layout.component.scss
+3
-1
layout.component.ts
src/app/+admin/layout/feature/ui/layout.component.ts
+6
-4
JobCard.component.html
src/app/+home/component/JobCard/JobCard.component.html
+0
-33
JobCard.component.ts
src/app/+home/component/JobCard/JobCard.component.ts
+0
-29
JobDetail.component.html
src/app/+home/component/JobDetail/JobDetail.component.html
+39
-0
JobDetail.component.ts
src/app/+home/component/JobDetail/JobDetail.component.ts
+36
-0
JobList.component.html
src/app/+home/component/JobList/JobList.component.html
+59
-0
JobList.component.ts
src/app/+home/component/JobList/JobList.component.ts
+100
-0
JobListCard.component.html
...pp/+home/component/JobListCard/JobListCard.component.html
+0
-13
JobListCard.component.ts
src/app/+home/component/JobListCard/JobListCard.component.ts
+0
-40
Job.service.ts
src/app/+home/data-access/service/Job.service.ts
+5
-0
Auth.Service.ts
src/app/+login/data-access/Services/Auth.Service.ts
+0
-2
login.component.html
src/app/+login/feature/login.component.html
+6
-6
login.component.ts
src/app/+login/feature/login.component.ts
+2
-5
shell.routes.ts
src/app/+shell/feature/shell.routes.ts
+7
-1
header.component.html
...+shell/ui/components/header/feature/header.component.html
+7
-6
header.component.ts
...p/+shell/ui/components/header/feature/header.component.ts
+6
-0
layout.component.ts
src/app/+shell/ui/layout.component.ts
+4
-2
app.component.ts
src/app/app.component.ts
+57
-0
No files found.
src/app/+admin/Management/Job/Action/JobDetail/JobDetail.component.html
0 → 100644
View file @
5465e871
<nz-modal
[(
nzVisible
)]="
showViewModalComponent
"
nzTitle=
"Chi tiết công việc"
(
nzOnCancel
)="
handleCancel
()"
(
nzOnOk
)="
handleOk
()"
>
<ng-content
*
nzModalContent
>
<div
*
ngIf=
"jobData"
>
<div
class=
"tw-flex tw-flex-col tw-space-y-4"
>
<div
*
ngIf=
"jobData.company_logo"
>
<img
[
src
]="
jobData
.
company_logo
"
alt=
"{{ jobData.company }}"
class=
"tw-w-32 tw-h-32 tw-object-contain"
/>
</div>
<div><strong>
Loại công việc:
</strong>
{{ jobData.type || "N/A" }}
</div>
<div><strong>
Tiêu đề:
</strong>
{{ jobData.title || "N/A" }}
</div>
<div>
<strong>
Công ty:
</strong>
<a
*
ngIf=
"jobData.company_url"
[
href
]="
jobData
.
company_url
"
target=
"_blank"
rel=
"noopener noreferrer"
>
{{ jobData.company || "N/A" }}
</a>
<span
*
ngIf=
"!jobData.company_url"
>
{{ jobData.company || "N/A" }}
</span>
</div>
<div><strong>
Địa chỉ:
</strong>
{{ jobData.location || "N/A" }}
</div>
<div>
<strong>
Mô tả:
</strong>
<div
[
innerHTML
]="
getSanitizedDescription
(
jobData
.
description
||
'
N
/
A
')"
></div>
</div>
<div>
<strong>
Cách thức ứng tuyển:
</strong>
<div
[
innerHTML
]="
getSanitizedHowToApply
(
jobData
.
how_to_apply
||
'
N
/
A
')"
></div>
</div>
<div>
<strong>
Ngày tạo:
</strong>
{{ jobData.created_at | date : "short" }}
</div>
</div>
</div>
</ng-content>
</nz-modal>
src/app/+admin/Management/Job/Action/JobDetail/JobDetail.component.ts
0 → 100644
View file @
5465e871
import
{
Component
,
Input
,
Output
,
EventEmitter
}
from
'@angular/core'
;
import
{
DomSanitizer
,
SafeHtml
}
from
'@angular/platform-browser'
;
import
{
NzModalModule
}
from
'ng-zorro-antd/modal'
;
import
{
NzButtonModule
}
from
'ng-zorro-antd/button'
;
import
{
CommonModule
,
DatePipe
}
from
'@angular/common'
;
import
{
JobModel
}
from
'../../../../data-access/model/jobModel.model'
;
@
Component
({
selector
:
'app-view-job'
,
templateUrl
:
'./JobDetail.component.html'
,
standalone
:
true
,
imports
:
[
NzModalModule
,
NzButtonModule
,
DatePipe
,
CommonModule
]
})
export
class
ViewJobComponent
{
@
Input
()
showViewModalComponent
:
boolean
=
false
;
@
Output
()
close
=
new
EventEmitter
<
void
>
();
@
Input
()
jobData
:
JobModel
.
Job
|
null
=
null
;
constructor
(
private
sanitizer
:
DomSanitizer
)
{}
handleOk
():
void
{
this
.
close
.
emit
();
}
handleCancel
():
void
{
this
.
close
.
emit
();
}
getSanitizedDescription
(
description
:
string
|
null
|
undefined
):
SafeHtml
{
return
description
?
this
.
sanitizer
.
bypassSecurityTrustHtml
(
description
)
:
'N/A'
;
}
getSanitizedHowToApply
(
how_to_apply
:
string
|
null
|
undefined
):
SafeHtml
{
return
how_to_apply
?
this
.
sanitizer
.
bypassSecurityTrustHtml
(
how_to_apply
)
:
'N/A'
;
}
}
src/app/+admin/Management/Job/Action/ModalJob/Modal.component.html
0 → 100644
View file @
5465e871
<nz-modal
[(
nzVisible
)]="
showModal
"
[
nzTitle
]="(
isEdit
)?
'
Chi
ti
ế
t
c
ô
ng
vi
ệ
c
'
:
'
Th
ê
m
m
ớ
i
c
ô
ng
vi
ệ
c
'"
(
nzOnCancel
)="
onCancel
()"
(
nzOnOk
)="
onSubmit
()"
[
nzMaskClosable
]="
false
"
>
<ng-content
*
nzModalContent
>
<form
nz-form
[
formGroup
]="
JobForm
"
class=
"tw-p-6 tw-bg-white tw-rounded-lg tw-shadow-md tw-space-y-6"
>
<nz-form-item>
<nz-form-label
[
nzSpan
]="
7
"
>
Loại công việc
</nz-form-label>
<nz-form-control
[
nzSpan
]="
17
"
[
nzErrorTip
]="
getErrorTip
('
type
')"
>
<nz-select
formControlName=
"type"
placeholder=
"Loại công việc"
>
<nz-option
nzValue=
"Full Time"
nzLabel=
"Full Time"
></nz-option>
<nz-option
nzValue=
"Part Time"
nzLabel=
"Part Time"
></nz-option>
<nz-option
nzValue=
"Freelance"
nzLabel=
"Freelance"
></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label
[
nzSpan
]="
7
"
>
Tiêu đề
</nz-form-label>
<nz-form-control
[
nzSpan
]="
17
"
[
nzErrorTip
]="
getErrorTip
('
title
')"
>
<input
nz-input
formControlName=
"title"
placeholder=
"Tiêu đề"
class=
"tw-w-full tw-p-2 tw-bg-white tw-border tw-rounded-md focus:tw-outline-none focus:tw-ring-1 focus:tw-ring-blue-500 focus:tw-border-blue-500"
/>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label
[
nzSpan
]="
7
"
>
Công ty
</nz-form-label>
<nz-form-control
[
nzSpan
]="
17
"
[
nzErrorTip
]="
getErrorTip
('
company
')"
>
<input
nz-input
formControlName=
"company"
placeholder=
"Công ty"
class=
"tw-w-full tw-p-2 tw-bg-white tw-border tw-rounded-md focus:tw-outline-none focus:tw-ring-1 focus:tw-ring-blue-500 focus:tw-border-blue-500"
/>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label
[
nzSpan
]="
7
"
>
Địa chỉ
</nz-form-label>
<nz-form-control
[
nzSpan
]="
17
"
[
nzErrorTip
]="
getErrorTip
('
location
')"
>
<input
nz-input
formControlName=
"location"
placeholder=
"Địa chỉ"
class=
"tw-w-full tw-p-2 tw-bg-white tw-border tw-rounded-md focus:tw-outline-none focus:tw-ring-1 focus:tw-ring-blue-500 focus:tw-border-blue-500"
/>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label
[
nzSpan
]="
7
"
>
Mô tả
</nz-form-label>
<nz-form-control
[
nzSpan
]="
17
"
[
nzErrorTip
]="
getErrorTip
('
description
')"
>
<textarea
nz-input
formControlName=
"description"
placeholder=
"Mô tả công việc"
class=
"tw-w-full tw-h-40 tw-p-2 tw-bg-white tw-border tw-rounded-md focus:tw-outline-none focus:tw-ring-1 focus:tw-ring-blue-500 focus:tw-border-blue-500"
></textarea>
</nz-form-control>
</nz-form-item>
</form>
</ng-content>
</nz-modal>
src/app/+admin/Management/Job/Action/ModalJob/Modal.component.ts
0 → 100644
View file @
5465e871
import
{
ChangeDetectionStrategy
,
Component
,
EventEmitter
,
Input
,
OnChanges
,
Output
,
SimpleChanges
}
from
'@angular/core'
;
import
{
FormBuilder
,
FormGroup
,
Validators
}
from
'@angular/forms'
;
import
{
NzModalModule
}
from
'ng-zorro-antd/modal'
;
import
{
NzFormModule
}
from
'ng-zorro-antd/form'
;
import
{
NzInputModule
}
from
'ng-zorro-antd/input'
;
import
{
NzSelectModule
}
from
'ng-zorro-antd/select'
;
import
{
NzButtonModule
}
from
'ng-zorro-antd/button'
;
import
{
ReactiveFormsModule
}
from
'@angular/forms'
;
import
{
NzMessageService
}
from
'ng-zorro-antd/message'
;
import
{
CommonModule
}
from
'@angular/common'
;
import
{
JobModel
}
from
'../../../../data-access/model/jobModel.model'
;
import
{
JobService
}
from
'../../../../data-access/services/JobService.service'
;
import
{
catchError
,
of
,
tap
}
from
'rxjs'
;
@
Component
({
selector
:
'app-modal-job'
,
templateUrl
:
`Modal.component.html`
,
standalone
:
true
,
imports
:
[
NzModalModule
,
NzFormModule
,
NzInputModule
,
NzSelectModule
,
NzButtonModule
,
ReactiveFormsModule
,
CommonModule
],
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
})
export
class
ModalJobComponent
implements
OnChanges
{
@
Input
()
isEdit
:
boolean
=
false
;
@
Input
()
showModal
:
boolean
=
false
;
@
Input
()
jobData
:
JobModel
.
Job
|
null
=
null
;
@
Output
()
submit
=
new
EventEmitter
<
void
>
();
@
Output
()
close
=
new
EventEmitter
<
void
>
();
JobForm
:
FormGroup
;
isSubmitting
:
boolean
=
false
;
constructor
(
private
fb
:
FormBuilder
,
private
jobService
:
JobService
,
private
message
:
NzMessageService
)
{
this
.
JobForm
=
this
.
fb
.
group
({
type
:
[
null
,
[
Validators
.
required
]],
title
:
[
null
,
[
Validators
.
required
]],
company
:
[
null
,
[
Validators
.
required
]],
location
:
[
null
],
description
:
[
null
,
[
Validators
.
required
]],
how_to_apply
:
[
null
],
company_logo
:
[
null
],
});
}
ngOnChanges
(
changes
:
SimpleChanges
):
void
{
if
(
changes
[
'jobData'
]
&&
this
.
isEdit
&&
this
.
jobData
)
{
this
.
JobForm
.
patchValue
({
type
:
this
.
jobData
.
type
,
title
:
this
.
jobData
.
title
,
company
:
this
.
jobData
.
company
,
location
:
this
.
jobData
.
location
,
description
:
this
.
jobData
.
description
,
how_to_apply
:
this
.
jobData
.
how_to_apply
,
company_logo
:
this
.
jobData
.
company_logo
,
});
}
if
(
changes
[
'showModal'
]
&&
!
this
.
showModal
)
{
this
.
JobForm
.
reset
();
}
}
getErrorTip
(
controlName
:
string
):
string
{
const
control
=
this
.
JobForm
.
get
(
controlName
);
return
control
?.
errors
?
'vui lòng nhập trường '
+
controlName
:
''
;
}
onSubmit
():
void
{
this
.
isEdit
?
this
.
onSubmitEditJob
()
:
this
.
onSubmitAddJob
();
}
onSubmitEditJob
():
void
{
if
(
this
.
JobForm
.
valid
&&
this
.
jobData
)
{
this
.
isSubmitting
=
true
;
const
jobToUpdate
:
JobModel
.
Job
=
{
...
this
.
jobData
,
...
this
.
JobForm
.
value
,
};
this
.
jobService
.
editJob
(
jobToUpdate
).
pipe
(
tap
((
res
)
=>
{
this
.
isSubmitting
=
false
;
this
.
message
.
success
(
res
.
message
||
'Cập nhật công việc thành công!'
,
{
nzDuration
:
2500
,
});
this
.
submit
.
emit
();
this
.
onCancel
();
}),
catchError
((
err
)
=>
{
this
.
isSubmitting
=
false
;
this
.
message
.
error
(
err
.
message
||
'Đã xảy ra lỗi khi cập nhật công việc.'
,
{
nzDuration
:
2500
}
);
return
of
(
null
);
})
)
.
subscribe
();
}
}
onSubmitAddJob
():
void
{
if
(
this
.
JobForm
.
invalid
)
{
Object
.
values
(
this
.
JobForm
.
controls
).
forEach
(
control
=>
{
if
(
control
.
invalid
)
{
control
.
markAsDirty
();
control
.
updateValueAndValidity
();
}
});
return
;
}
const
newJob
:
JobModel
.
JobRequest
=
this
.
JobForm
.
value
;
console
.
log
(
newJob
);
this
.
jobService
.
addingNewJob
(
newJob
)
.
pipe
(
tap
((
res
)
=>
{
this
.
message
.
success
(
res
.
message
,
{
nzDuration
:
2500
});
this
.
submit
.
emit
();
this
.
JobForm
.
reset
();
this
.
showModal
=
false
;
}),
catchError
((
err
)
=>
{
this
.
message
.
error
(
err
.
message
,
{
nzDuration
:
2500
});
return
of
(
null
);
})
)
.
subscribe
();
}
onCancel
():
void
{
this
.
close
.
emit
();
this
.
JobForm
.
reset
();
}
}
src/app/+admin/Management/Job/Job.component.html
View file @
5465e871
<div
className=
"tw-container tw-content-center"
>
<div
class=
"tw-flex tw-justify-end tw-pb-5"
>
<button
nz-button
nzType=
"primary"
(
click
)="
addJob
()"
>
+ Thêm công việc mới
</button>
<div
class=
"tw-container tw-content-center"
>
<div
class=
"tw-flex tw-justify-end tw-pb-5 tw-pt-5"
>
<button
nz-button
nzType=
"primary"
(
click
)="
addJob
()"
>
+ Thêm công việc mới
</button>
</div>
<nz-table
#
JobTable
[
nzData
]="
listOfJob
"
[
nzLoading
]="
loading
"
[
nzFrontPagination
]="
true
"
nzShowSizeChanger
[
nzPageSize
]="
5
"
[
nzScroll
]="{
x:
'
300px
'
}"
>
<thead>
<tr>
...
...
@@ -21,16 +23,21 @@
</tr>
</thead>
<tbody>
@for (data of JobTable.data; track data) {
<tr>
<td>
{{ listOfJob.indexOf(data) + 1 }}
</td>
<tr
*
ngFor=
"let data of JobTable.data; let i = index"
>
<td>
{{ i + 1 }}
</td>
<td>
{{ data.type }}
</td>
<td>
{{ data.title }}
</td>
<td>
{{ data.company }}
</td>
<td>
{{ data.location }}
</td>
<td>
<nz-space>
<button
class=
"tw-mr-2"
nz-button
nzType=
"primary"
nzSize=
"small"
(
click
)="
JobDetail
(
data
.
id
)"
>
<button
class=
"tw-mr-2"
nz-button
nzType=
"primary"
nzSize=
"small"
(
click
)="
JobDetail
(
data
.
id
)"
>
Xem chi tiết
</button>
<button
...
...
@@ -42,61 +49,31 @@
>
Sửa
</button>
<button
nz-button
nzType=
"dashed"
nzSize=
"small"
nzDanger
(
click
)="
showDeleteConfirm
(
data
.
id
)"
>
<button
nz-button
nzType=
"dashed"
nzSize=
"small"
nzDanger
(
click
)="
showDeleteConfirm
(
data
.
id
)"
>
Xóa
</button>
</nz-space>
</td>
</tr>
}
</tbody>
</nz-table>
<app-modal-job
[
showModal
]="
showModal
"
[
jobData
]="
currentEditJob
"
[
isEdit
]="
isEdit
"
(
close
)="
onCloseModal
()"
(
submit
)="
onSubmit
()"
></app-modal-job>
<nz-modal
[(
nzVisible
)]="
isOpenModal
"
[
nzTitle
]="
isOnEdit
?
'
S
ử
a
c
ô
ng
vi
ệ
c
'
:
'
Chi
ti
ế
t
c
ô
ng
vi
ệ
c
'"
(
nzOnOk
)="
onOk
()"
(
nzOnCancel
)="
onCancel
()"
>
<ng-container
*
nzModalContent
>
<div
*
ngIf=
"selectedJob"
>
<form
nz-form
[
formGroup
]="
validateJobForm
"
>
<nz-form-item>
<nz-form-label
[
nzSpan
]="
7
"
>
Loại công việc
</nz-form-label>
<nz-form-control
[
nzSpan
]="
17
"
>
<nz-select
formControlName=
"type"
placeholder=
"Loại công việc"
ngModel=
{{selectedJob.type}}
>
<nz-option
nzValue=
"Full Time"
nzLabel=
"Full Time"
></nz-option>
<nz-option
nzValue=
"Part Time"
nzLabel=
"Part Time"
></nz-option>
<nz-option
nzValue=
"Freelance"
nzLabel=
"Freelance"
></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label
[
nzSpan
]="
7
"
>
Tên công việc
</nz-form-label>
<nz-form-control
[
nzSpan
]="
17
"
>
<input
class=
"tw-w-full tw-p-2 tw-bg-white tw-border tw-rounded-md focus:tw-outline-none focus:tw-ring-1 focus:tw-ring-blue-500 focus:tw-border-blue-500"
nz-input
formControlName=
"location"
nz-input
formControlName=
"title"
placeholder=
"Tên công việc"
[
ngModel
]="
selectedJob
.
title
"
/>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label
[
nzSpan
]="
7
"
>
Công ty
</nz-form-label>
<nz-form-control
[
nzSpan
]="
17
"
>
<input
class=
"tw-w-full tw-p-2 tw-bg-white tw-border tw-rounded-md focus:tw-outline-none focus:tw-ring-1 focus:tw-ring-blue-500 focus:tw-border-blue-500"
nz-input
formControlName=
"location"
nz-input
formControlName=
"company"
placeholder=
"Công ty"
[
ngModel
]="
selectedJob
.
company
"
/>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label
[
nzSpan
]="
7
"
>
Địa chỉ
</nz-form-label>
<nz-form-control
[
nzSpan
]="
17
"
>
<input
class=
"tw-w-full tw-p-2 tw-bg-white tw-border tw-rounded-md focus:tw-outline-none focus:tw-ring-1 focus:tw-ring-blue-500 focus:tw-border-blue-500"
nz-input
formControlName=
"location"
placeholder=
"Địa chỉ"
[
ngModel
]="
selectedJob
.
location
"
/>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label
[
nzSpan
]="
7
"
>
Mô tả
</nz-form-label>
<nz-form-control
[
nzSpan
]="
17
"
>
<textarea
class=
"tw-w-full tw-h-40 tw-p-2 tw-bg-white tw-border tw-rounded-md focus:tw-outline-none focus:tw-ring-1 focus:tw-ring-blue-500 focus:tw-border-blue-500"
nz-input
formControlName=
"description"
placeholder=
"Mô tả công việc"
[
ngModel
]="
selectedJob
.
description
"
></textarea>
</nz-form-control>
</nz-form-item>
</form>
</div>
</ng-container>
</nz-modal>
<app-view-job
[
showViewModalComponent
]="
showViewModalComponent
"
[
jobData
]="
currentViewJob
"
(
close
)="
onCloseViewModal
()"
></app-view-job>
</div>
src/app/+admin/Management/Job/Job.component.scss
deleted
100644 → 0
View file @
d3f8c729
src/app/+admin/Management/Job/Job.component.ts
View file @
5465e871
//#region imports
import
{
CommonModule
}
from
"@angular/common"
;
import
{
C
omponent
,
OnInit
}
from
"@angular/core"
;
import
{
C
hangeDetectionStrategy
,
ChangeDetectorRef
,
Component
,
HostListener
,
OnInit
}
from
"@angular/core"
;
import
{
JobService
}
from
"../../data-access/services/JobService.service"
;
import
{
NzTableModule
,
NzTableQueryParams
}
from
'ng-zorro-antd/table'
;
import
{
NzTableModule
}
from
'ng-zorro-antd/table'
;
import
{
catchError
,
finalize
,
of
,
tap
}
from
"rxjs"
;
import
{
JobModel
}
from
"../../data-access/model/jobModel.model"
;
import
{
NzDividerModule
}
from
'ng-zorro-antd/divider'
;
import
{
NzButtonModule
}
from
"ng-zorro-antd/button"
;
import
{
NzSpaceModule
}
from
'ng-zorro-antd/space'
;
import
{
NzModalModule
,
NzModalService
}
from
'ng-zorro-antd/modal'
;
import
{
FormBuilder
,
ReactiveFormsModule
,
Validators
}
from
"@angular/forms"
;
import
{
FormsModule
,
ReactiveFormsModule
}
from
"@angular/forms"
;
import
{
NzFormModule
}
from
"ng-zorro-antd/form"
;
import
{
NzSelectModule
}
from
'ng-zorro-antd/select'
;
import
{
NzMessageService
}
from
'ng-zorro-antd/message'
;
import
{
NzAlertModule
}
from
"ng-zorro-antd/alert"
;
import
{
NzNotificationService
}
from
'ng-zorro-antd/notification'
;
import
{
ViewJobComponent
}
from
"./Action/JobDetail/JobDetail.component"
;
import
{
ModalJobComponent
}
from
"./Action/ModalJob/Modal.component"
;
//#endregion
//#region Component
@
Component
({
selector
:
"meu-admin-job"
,
templateUrl
:
"./Job.component.html"
,
standalone
:
true
,
imports
:
[
CommonModule
,
imports
:
[
CommonModule
,
NzTableModule
,
NzDividerModule
,
NzButtonModule
,
NzSpaceModule
,
NzModalModule
,
NzModalModule
,
NzFormModule
,
ReactiveFormsModule
,
NzSelectModule
NzSelectModule
,
FormsModule
,
NzAlertModule
,
ViewJobComponent
,
ModalJobComponent
],
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
})
//#endregion
export
class
JobComponent
implements
OnInit
{
isMobileView
:
boolean
=
false
;
searchTerm
:
string
=
''
;
//#region Variable
selectedJob
?:
JobModel
;
listOfJob
:
JobModel
[]
=
[];
loading
=
true
;
message
=
""
;
//modal
isOpenModal
=
false
;
isOnEdit
=
false
;
isOnAdd
=
false
;
validateJobForm
=
this
.
fb
.
group
({
type
:
this
.
fb
.
control
(
''
,
[
Validators
.
required
]),
create_at
:
this
.
fb
.
control
(
''
,
[
Validators
.
required
]),
company_url
:
this
.
fb
.
control
(
''
,
[
Validators
.
required
]),
company
:
this
.
fb
.
control
(
''
,
[
Validators
.
required
]),
location
:
this
.
fb
.
control
(
''
,
[
Validators
.
required
]),
title
:
this
.
fb
.
control
(
''
,
[
Validators
.
required
]),
description
:
this
.
fb
.
control
(
''
,
[
Validators
.
required
]),
});
selectedJob
?:
JobModel
.
Job
;
listOfJob
:
JobModel
.
Job
[]
=
[];
showModal
:
boolean
=
false
;
isEdit
:
boolean
=
false
;
showViewModalComponent
:
boolean
=
false
;
// Công việc hiện tại để chỉnh sửa hoặc xem chi tiết
currentEditJob
:
JobModel
.
Job
|
null
=
null
;
currentViewJob
:
JobModel
.
Job
|
null
=
null
;
//#endregion
//#region LoadData
constructor
(
private
fb
:
FormBuilder
,
private
jobService
:
JobService
,
private
modal
:
NzModalService
)
{
}
constructor
(
private
_cdr
:
ChangeDetectorRef
,
private
jobService
:
JobService
,
private
modal
:
NzModalService
,
private
message
:
NzMessageService
,
private
notification
:
NzNotificationService
)
{
}
loadDataFromServer
():
void
{
console
.
log
(
"hello"
);
this
.
loading
=
true
;
this
.
jobService
.
jobsGet
().
pipe
(
tap
((
res
)
=>
{
if
(
res
.
responseData
)
if
(
res
.
responseData
)
{
this
.
listOfJob
=
res
.
responseData
.
rows
;
}
this
.
_cdr
.
detectChanges
();
}),
catchError
((
err
)
=>
{
this
.
listOfJob
=
[];
this
.
notification
.
error
(
'Lỗi'
,
'Không tải được dữ liệu công việc.'
);
return
of
(
null
);
}),
finalize
(()
=>
(
this
.
loading
=
false
))
})
).
subscribe
();
}
ngOnInit
():
void
{
this
.
loadDataFromServer
();
this
.
checkScreenSize
();
// Kiểm tra kích thước màn hình ban đầu
}
//#endregion
//#region Handler
resetForm
()
{
this
.
validateJobForm
.
reset
();
this
.
selectedJob
=
{}
as
JobModel
;
onCloseViewModal
():
void
{
this
.
showViewModalComponent
=
false
;
}
EnableForm
()
{
this
.
validateJobForm
.
enable
();
onSubmit
():
void
{
this
.
isEdit
=
false
;
this
.
showModal
=
false
;
this
.
_cdr
.
detectChanges
();
this
.
loadDataFromServer
();
}
DisableForm
()
{
this
.
validateJobForm
.
disable
()
;
onCloseModal
():
void
{
this
.
showModal
=
false
;
}
onOk
():
void
{
console
.
log
(
this
.
onEdit
,
this
.
selectedJob
);
if
(
this
.
isOnEdit
&&
this
.
selectedJob
)
{
const
updatedJob
:
JobModel
=
{
id
:
this
.
selectedJob
.
id
,
type
:
this
.
validateJobForm
.
value
.
type
??
undefined
,
created_at
:
this
.
selectedJob
.
created_at
,
company
:
this
.
validateJobForm
.
value
.
company
??
undefined
,
company_url
:
this
.
validateJobForm
.
value
.
company_url
??
undefined
,
location
:
this
.
validateJobForm
.
value
.
location
??
undefined
,
title
:
this
.
validateJobForm
.
value
.
title
??
undefined
,
description
:
this
.
validateJobForm
.
value
.
description
??
undefined
,
};
this
.
loading
=
true
;
this
.
jobService
.
editJob
(
updatedJob
).
pipe
(
//#endregion
//#region Handlers
// Handler xem chi tiết công việc
handleViewJob
(
id
:
string
):
void
{
this
.
jobService
.
getJobById
(
id
)
.
pipe
(
tap
((
res
)
=>
{
this
.
message
=
res
.
message
;
this
.
loadDataFromServer
();
this
.
showViewModalComponent
=
true
;
this
.
currentViewJob
=
res
.
responseData
as
JobModel
.
Job
;
this
.
_cdr
.
detectChanges
();
}),
catchError
((
err
)
=>
{
console
.
error
(
err
);
this
.
message
.
error
(
err
.
message
||
'An error occurred while fetching job data.'
,
{
nzDuration
:
2500
}
);
return
of
(
null
);
})
).
subscribe
();
}
else
if
(
this
.
isOnAdd
&&
this
.
selectedJob
)
{
const
newJob
:
JobModel
=
{
id
:
this
.
selectedJob
.
id
,
type
:
this
.
validateJobForm
.
value
.
type
??
undefined
,
created_at
:
this
.
selectedJob
.
created_at
,
company
:
this
.
validateJobForm
.
value
.
company
??
undefined
,
company_url
:
this
.
validateJobForm
.
value
.
company_url
??
undefined
,
location
:
this
.
validateJobForm
.
value
.
location
??
undefined
,
title
:
this
.
validateJobForm
.
value
.
title
??
undefined
,
description
:
this
.
validateJobForm
.
value
.
description
??
undefined
,
};
this
.
loading
=
true
;
this
.
jobService
.
addingNewJob
(
newJob
).
pipe
(
)
.
subscribe
();
}
// Handler xóa công việc
onDelete
(
id
:
string
):
void
{
this
.
jobService
.
deleteJob
(
id
)
.
pipe
(
tap
((
res
)
=>
{
this
.
message
=
res
.
message
;
this
.
message
.
success
(
res
.
message
,
{
nzDuration
:
2500
});
this
.
_cdr
.
markForCheck
();
this
.
loadDataFromServer
();
}),
catchError
((
err
)
=>
{
console
.
error
(
err
);
this
.
message
.
error
(
err
.
message
,
{
nzDuration
:
2500
}
);
return
of
(
null
);
})
).
subscribe
();
}
this
.
isOpenModal
=
false
;
this
.
isOnEdit
=
false
;
this
.
isOnAdd
=
false
;
)
.
subscribe
();
}
onCancel
():
void
{
this
.
isOpenModal
=
false
;
this
.
isOnEdit
=
fals
e
;
// Xử lý khi nhấn nút "Thêm công việc"
addJob
():
void
{
this
.
showModal
=
tru
e
;
}
//#endregion
//#region Action
JobDetail
(
id
:
string
)
{
this
.
DisableForm
();
this
.
isOnEdit
=
false
;
this
.
isOpenModal
=
true
;
this
.
isOnAdd
=
false
;
this
.
jobService
.
getJob
(
id
).
pipe
(
tap
((
res
)
=>
{
console
.
log
(
res
);
this
.
selectedJob
=
res
.
responseData
as
JobModel
;
}),
catchError
((
err
)
=>
{
console
.
log
(
err
);
return
of
(
null
);
}),
finalize
(()
=>
(
this
.
loadDataFromServer
(),
this
.
loading
=
false
))
).
subscribe
();
}
onDelete
(
id
:
string
)
{
this
.
jobService
.
deleteJob
(
id
).
pipe
(
tap
((
res
)
=>
{
this
.
loading
=
true
;
this
.
message
=
res
.
message
;
}),
catchError
((
err
)
=>
{
console
.
log
(
err
);
return
of
(
null
);
}),
finalize
(()
=>
(
this
.
loadDataFromServer
(),
this
.
loading
=
false
))
).
subscribe
();
}
onEdit
(
data
:
JobModel
)
{
this
.
EnableForm
();
this
.
isOpenModal
=
true
;
this
.
isOnEdit
=
true
;
this
.
isOnAdd
=
false
;
this
.
selectedJob
=
data
;
// Xử lý khi nhấn nút "Sửa"
onEdit
(
data
:
JobModel
.
Job
):
void
{
this
.
isEdit
=
true
;
this
.
currentEditJob
=
data
;
this
.
showModal
=
true
;
}
addJob
()
{
this
.
EnableForm
();
this
.
resetForm
();
this
.
isOpenModal
=
true
;
this
.
isOnEdit
=
false
;
this
.
isOnAdd
=
true
;
// Xử lý khi nhấn nút "Xem chi tiết"
JobDetail
(
id
:
string
):
void
{
this
.
handleViewJob
(
id
);
}
// Hiển thị hộp thoại xác nhận xóa
showDeleteConfirm
(
id
:
string
):
void
{
this
.
modal
.
confirm
({
nzTitle
:
'Bạn có chắc rằng xóa công việc này không?'
,
...
...
@@ -204,8 +160,25 @@ export class JobComponent implements OnInit {
nzOkType
:
'primary'
,
nzOkDanger
:
true
,
nzOnOk
:
()
=>
this
.
onDelete
(
id
),
nzCancelText
:
'
t
rở về'
,
nzCancelText
:
'
T
rở về'
,
});
}
//#endregion
//#region HostListener
@
HostListener
(
'window:resize'
,
[
'$event'
])
onResize
(
event
:
any
)
{
this
.
checkScreenSize
();
}
checkScreenSize
()
{
this
.
isMobileView
=
window
.
innerWidth
<
768
;
this
.
_cdr
.
detectChanges
();
}
isMobile
():
boolean
{
return
this
.
isMobileView
;
}
//#endregion
}
src/app/+admin/data-access/model/jobModel.model.ts
View file @
5465e871
export
interface
JobModel
{
export
namespace
JobModel
{
export
interface
Job
{
id
:
string
;
type
?:
string
;
created_at
:
string
;
...
...
@@ -9,4 +10,14 @@ export interface JobModel {
description
?:
string
;
how_to_apply
?:
string
;
company_logo
?:
string
;
}
export
interface
JobRequest
{
type
:
string
;
created_at
:
string
;
company
:
string
;
company_url
:
string
;
location
:
string
;
title
:
string
;
description
:
string
;
}
}
src/app/+admin/data-access/services/JobService.service.ts
View file @
5465e871
...
...
@@ -14,37 +14,24 @@ export class JobService {
apiUrlById
=
environment
.
API_DOMAIN
+
'/jobById'
;
constructor
(
private
http
:
HttpClient
)
{}
jobsGet
():
Observable
<
ResponseResult
<
Rows
<
JobModel
>>>
{
return
this
.
http
.
get
<
ResponseResult
<
Rows
<
JobModel
>>>
(
this
.
apiUrl
);
jobsGet
():
Observable
<
ResponseResult
<
Rows
<
JobModel
.
Job
>>>
{
return
this
.
http
.
get
<
ResponseResult
<
Rows
<
JobModel
.
Job
>>>
(
this
.
apiUrl
);
}
addingNewJob
(
data
:
JobModel
):
Observable
<
ResponseResult
<
JobModel
>>
{
const
headers
=
new
HttpHeaders
()
.
set
(
'Content-Type'
,
'application/json'
)
.
set
(
'Authorization'
,
`Bearer
${
localStorage
.
getItem
(
'token'
)}
`
);
return
this
.
http
.
post
<
ResponseResult
<
JobModel
>>
(
this
.
apiUrl
,
data
,
{
headers
});
addingNewJob
(
data
:
JobModel
.
JobRequest
):
Observable
<
ResponseResult
<
JobModel
.
Job
>>
{
return
this
.
http
.
post
<
ResponseResult
<
JobModel
.
Job
>>
(
this
.
apiUrl
,
data
);
}
deleteJob
(
id
:
string
):
Observable
<
ResponseResult
<
JobModel
>>
{
const
headers
=
new
HttpHeaders
()
.
set
(
'Content-Type'
,
'application/json'
)
.
set
(
'Authorization'
,
`Bearer
${
localStorage
.
getItem
(
'token'
)}
`
);
deleteJob
(
id
:
string
):
Observable
<
ResponseResult
<
JobModel
.
Job
>>
{
const
url
=
`
${
this
.
apiUrl
}
/
${
id
}
`
;
return
this
.
http
.
delete
<
ResponseResult
<
JobModel
>>
(
url
,
{
headers
}
);
return
this
.
http
.
delete
<
ResponseResult
<
JobModel
.
Job
>>
(
url
);
}
editJob
(
data
:
JobModel
):
Observable
<
ResponseResult
<
JobModel
>>
{
const
headers
=
new
HttpHeaders
()
.
set
(
'Content-Type'
,
'application/json'
)
.
set
(
'Authorization'
,
`Bearer
${
localStorage
.
getItem
(
'token'
)}
`
);
editJob
(
data
:
JobModel
.
Job
):
Observable
<
ResponseResult
<
JobModel
.
Job
>>
{
const
url
=
`
${
this
.
apiUrl
}
/
${
data
.
id
}
`
;
return
this
.
http
.
put
<
ResponseResult
<
JobModel
>>
(
url
,
data
,
{
headers
}
);
return
this
.
http
.
put
<
ResponseResult
<
JobModel
.
Job
>>
(
url
,
data
);
}
getJob
(
id
:
string
):
Observable
<
ResponseResult
<
JobModel
>>
{
const
headers
=
new
HttpHeaders
()
.
set
(
'Content-Type'
,
'application/json'
)
.
set
(
'Authorization'
,
`Bearer
${
localStorage
.
getItem
(
'token'
)}
`
);
getJobById
(
id
:
string
):
Observable
<
ResponseResult
<
JobModel
.
Job
>>
{
const
url
=
`
${
this
.
apiUrlById
}
/
${
id
}
`
;
console
.
log
(
id
,
url
);
return
this
.
http
.
get
<
ResponseResult
<
JobModel
>>
(
url
,
{
headers
});
return
this
.
http
.
get
<
ResponseResult
<
JobModel
.
Job
>>
(
url
);
}
}
src/app/+admin/layout/feature/ui/Components/footer/footer.component.html
View file @
5465e871
...
...
@@ -5,23 +5,19 @@
<p>
Designed by Meu Solution
</p>
<div
class=
"tw-flex tw-justify-center tw-space-x-4 tw-mt-4"
>
<
a
href=
"#about"
class=
" hover:tw-text-blue-500"
>
About Us
</a
>
<a
href=
"#contact"
class=
" hover:tw-text-blue-500"
>
Contact
</a>
<
a
href=
"#privacy"
class=
" hover:tw-text-blue-500"
>
Privacy Policy
</a
>
<
div
*
ngFor=
"let item of list"
>
<a
href=
"#{{item.href}}"
class=
" hover:tw-text-blue-500"
>
{{item.title}}
</a>
<
/div
>
</div>
<div
class=
"tw-flex tw-justify-center tw-space-x-4 tw-mt-4"
>
<div
*
ngFor=
"let item of listIcon"
>
<a
href=
"#"
target=
"_blank"
class=
" hover:tw-text-blue-500"
>
<i
nz-icon
nzType=
"facebook"
class=
"tw-text-2xl"
></i>
</a>
<a
href=
"#"
target=
"_blank"
class=
" hover:tw-text-blue-500"
>
<i
nz-icon
nzType=
"twitter"
class=
"tw-text-2xl"
></i>
</a>
<a
href=
"#"
target=
"_blank"
class=
" hover:tw-text-blue-500"
>
<i
nz-icon
nzType=
"instagram"
class=
"tw-text-2xl"
></i>
<i
nz-icon
nzType=
"{{item}}"
class=
"tw-text-2xl"
></i>
</a>
</div>
</div>
</div>
</footer>
...
...
src/app/+admin/layout/feature/ui/Components/footer/footer.component.ts
View file @
5465e871
...
...
@@ -13,5 +13,12 @@ import { NzLayoutModule } from 'ng-zorro-antd/layout';
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
})
export
class
FooterComponent
implements
OnInit
{
list
:
{
href
:
string
,
title
:
string
}[]
=
[
{
href
:
'about'
,
title
:
'về chúng tôi'
},
{
href
:
'contact'
,
title
:
'liên hệ'
},
{
href
:
'privacy'
,
title
:
'chính sách bảo mật'
}
];
listIcon
:
string
[]
=
[
'facebook'
,
'instagram'
,
'twitter'
];
ngOnInit
():
void
{}
}
src/app/+admin/layout/feature/ui/Components/header/header.component.html
deleted
100644 → 0
View file @
d3f8c729
<header
class=
"tw-flex tw-justify-between tw-items-center tw-p-4 tw-bg-gray-900"
>
<h3
class=
"tw-text-2xl"
>
Role: {{role}}
</h3>
</header>
src/app/+admin/layout/feature/ui/Components/header/header.component.ts
deleted
100644 → 0
View file @
d3f8c729
import
{
CommonModule
}
from
'@angular/common'
;
import
{
ChangeDetectionStrategy
,
Component
,
Input
,
OnInit
}
from
'@angular/core'
;
import
{
NzLayoutModule
}
from
'ng-zorro-antd/layout'
;
@
Component
({
selector
:
'meu-admin-header'
,
standalone
:
true
,
imports
:
[
CommonModule
,
NzLayoutModule
],
templateUrl
:
'./header.component.html'
,
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
})
export
class
HeaderComponent
implements
OnInit
{
@
Input
()
role
=
''
;
ngOnInit
():
void
{}
}
src/app/+admin/layout/feature/ui/layout.component.html
View file @
5465e871
<nz-layout>
<nz-sider
nzCollapsible
[
nzTrigger
]="
null
"
>
<div
class=
"logo"
></div>
<nz-layout
class=
"tw-h-screen tw-flex tw-flex-col"
>
<nz-header
class=
"tw-flex tw-justify-between tw-items-center tw-px-4 tw-bg-[#1f487725] tw-shadow-md"
>
<div
class=
"tw-flex tw-items-center"
>
<button
nz-button
nzType=
"text"
class=
"tw-block md:tw-hidden"
(
click
)="
toggleSider
()"
>
<span
nz-icon
[
nzType
]="
isCollapsed
?
'
menu-unfold
'
:
'
menu-fold
'"
nzTheme=
"outline"
></span>
</button>
<div
class=
"tw-ml-2 tw-text-xl tw-font-bold"
>
MeU Solution
</div>
</div>
<div
class=
"tw-hidden md:tw-flex tw-items-center"
>
<button
nz-button
nzType=
"default"
(
click
)="
logout
()"
>
<span
nz-icon
nzType=
"logout"
nzTheme=
"outline"
></span>
<span
class=
"tw-ml-2"
>
Đăng xuất
</span>
</button>
</div>
</nz-header>
<nz-layout
class=
"tw-flex-1"
>
<nz-sider
nzCollapsible
[(
nzCollapsed
)]="
isCollapsed
"
[
nzBreakpoint
]="'
lg
'"
[
nzWidth
]="
200
"
[
nzCollapsedWidth
]="
80
"
class=
"tw-bg-gray-800"
>
<ul
nz-menu
nzTheme=
"dark"
nzMode=
"inline"
>
<li
nz-menu-item
routerLink=
"/home"
>
Trang chủ
</li>
<li
nz-menu-item
routerLink=
"/admin/job-management/Job"
>
Danh sách công việc
<li
nz-menu-item
routerLink=
"/home"
routerLinkActive=
"tw-bg-gray-700"
>
<span
nz-icon
nzType=
"home"
nzTheme=
"outline"
></span>
<span
class=
"tw-ml-2"
>
Trang chủ
</span>
</li>
<li
nz-menu-item
(
click
)="
logout
()
"
>
<span
nz-icon
nzType=
"logou
t"
nzTheme=
"outline"
></span>
Đăng xuất
<li
nz-menu-item
routerLink=
"/admin/job-management/Job"
routerLinkActive=
"tw-bg-gray-700
"
>
<span
nz-icon
nzType=
"unordered-lis
t"
nzTheme=
"outline"
></span>
<span
class=
"tw-ml-2"
>
Danh sách công việc
</span>
</li>
</ul>
</nz-sider>
<nz-layout>
<nz-content>
<nz-layout
class=
"tw-flex-1 tw-bg-gray-100"
>
<nz-content
>
<router-outlet></router-outlet>
</nz-content>
<meu-footer></meu-footer>
<meu-footer
>
©
2024 Công ty của bạn. Bảo lưu mọi quyền.
</meu-footer>
</nz-layout>
</nz-layout>
</nz-layout>
src/app/+admin/layout/feature/ui/layout.component.scss
View file @
5465e871
...
...
@@ -15,7 +15,9 @@
background
:
rgba
(
255
,
255
,
255
,
0
.2
);
margin
:
16px
;
}
::ng-deep
.ant-drawer-body
{
padding
:
0
;
}
nz-header
{
background
:
#fff
;
padding
:
0
;
...
...
src/app/+admin/layout/feature/ui/layout.component.ts
View file @
5465e871
...
...
@@ -3,7 +3,6 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import
{
NzLayoutModule
}
from
'ng-zorro-antd/layout'
;
import
{
CommonModule
,
DatePipe
}
from
'@angular/common'
;
import
{
HeaderComponent
}
from
'./Components/header/header.component'
;
import
{
FooterComponent
}
from
'./Components/footer/footer.component'
;
import
{
NzButtonModule
}
from
'ng-zorro-antd/button'
;
import
{
NzBreadCrumbModule
}
from
'ng-zorro-antd/breadcrumb'
;
...
...
@@ -20,20 +19,23 @@ import { AuthService } from '../../../../+login/data-access/Services/Auth.Servic
RouterLink
,
CommonModule
,
RouterModule
,
HeaderComponent
,
FooterComponent
,
NzButtonModule
,
NzBreadCrumbModule
,
NzIconModule
,
NzLayoutModule
,
NzMenuModule
,
NzToolTipModule
,
NzIconModule
,
FooterComponent
],
styleUrls
:
[
'./layout.component.scss'
],
templateUrl
:
'./layout.component.html'
,
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
})
export
class
AdminLayoutComponent
implements
OnInit
{
isCollapsed
=
false
;
toggleSider
():
void
{
this
.
isCollapsed
=
!
this
.
isCollapsed
;
}
constructor
(
private
authentication
:
AuthService
)
{}
ngOnInit
():
void
{
}
...
...
src/app/+home/component/JobCard/JobCard.component.html
deleted
100644 → 0
View file @
d3f8c729
<nz-card
*
ngIf=
"job"
[
nzTitle
]="
job
.
title
"
[
nzExtra
]="
extraTemplate
"
[
nzBodyStyle
]="{'
padding
'
:
'
8px
'}"
>
<p>
loại công việc: {{job.type}}
</p>
<p>
Công ty: {{job.company}}
</p>
<p>
Địa chỉ làm việc: {{job.location}}
</p>
</nz-card>
<ng-template
#
extraTemplate
>
<a
(
click
)="
onShowDetail
()"
>
Chi tiết
</a>
</ng-template>
<nz-modal
[(
nzVisible
)]="
isModalVisible
"
nzTitle=
{{job?.title}}
nzOkText=
"Ứng tuyển"
nzCancelText=
"Trở về"
(
nzOnOk
)="
onOk
()"
(
nzOnCancel
)="
onCancel
()"
>
<ng-container
*
nzModalContent
>
<p>
<strong>
Chi tiết công việc
</strong>
</p>
<p>
<label>
Loại công việc
</label>
{{ job?.type }}
</p>
<p>
<label>
Ngày tạo
</label>
{{ job?.created_at| date: 'dd/MM/yyyy' }}
</p>
<p>
<label>
Link công ty
</label>
{{ job?.company_url }}
</p>
<div>
<strong>
Mô tả:
</strong>
<div
[
innerHTML
]="
job
?.
description
"
></div>
</div>
</ng-container>
</nz-modal>
src/app/+home/component/JobCard/JobCard.component.ts
deleted
100644 → 0
View file @
d3f8c729
import
{
ChangeDetectionStrategy
,
Component
,
Input
}
from
"@angular/core"
;
import
{
NzCardModule
}
from
"ng-zorro-antd/card"
;
import
{
Job
}
from
"../../data-access/model/Job.model"
;
import
{
CommonModule
}
from
"@angular/common"
;
import
{
NzModalModule
}
from
"ng-zorro-antd/modal"
;
@
Component
({
selector
:
'job-card'
,
templateUrl
:
'./JobCard.component.html'
,
imports
:
[
NzCardModule
,
CommonModule
,
NzModalModule
],
standalone
:
true
,
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
})
export
class
JobCardComponent
{
@
Input
()
job
?:
Job
;
isModalVisible
=
false
;
onShowDetail
()
{
this
.
isModalVisible
=
true
;
}
onOk
()
{
this
.
isModalVisible
=
false
}
onCancel
(){
this
.
isModalVisible
=
false
}
}
src/app/+home/component/JobDetail/JobDetail.component.html
0 → 100644
View file @
5465e871
<div
*
ngIf=
"Job; else loadingOrError"
>
<div
class=
"header flex items-center space-x-4"
>
<img
*
ngIf=
"Job.company_logo"
[
src
]="
Job
.
company_logo
"
alt=
"{{ Job.company }} Logo"
class=
"company-logo w-16 h-16 object-contain"
/>
<h2
class=
"tw-text-2xl tw-font-bold"
>
{{ Job.title }}
</h2>
</div>
<div
class=
"details mt-4"
>
<p
*
ngIf=
"Job.type"
><strong>
Loại công việc:
</strong>
{{ Job.type }}
</p>
<p
*
ngIf=
"Job.company"
>
<strong>
Công ty:
</strong>
<a>
{{ Job.company }}
</a
>
<span
*
ngIf=
"!Job.company_url"
>
{{ Job.company }}
</span>
</p>
<p
*
ngIf=
"Job.location"
><strong>
Vị trí:
</strong>
{{ Job.location }}
</p>
<p
class=
"tw-text-sm tw-text-gray-500"
>
<strong>
Ngày đăng:
</strong>
{{ Job.created_at | date : "medium" }}
</p>
</div>
<hr
class=
"my-4"
/>
<div
class=
"description mt-6"
>
<p
[
innerHTML
]="
Job
.
description
"
></p>
</div>
</div>
<ng-template
#
loadingOrError
>
<div
class=
"status-message"
>
<p
*
ngIf=
"Job === null"
class=
"error text-red-500"
>
Có lỗi khi tải thông tin công việc.
</p>
<p
*
ngIf=
"Job === undefined"
class=
"loading"
>
Đang tải...
</p>
</div>
</ng-template>
src/app/+home/component/JobDetail/JobDetail.component.ts
0 → 100644
View file @
5465e871
import
{
ChangeDetectionStrategy
,
ChangeDetectorRef
,
Component
,
Input
,
OnInit
}
from
"@angular/core"
;
import
{
Job
}
from
"../../data-access/model/Job.model"
;
import
{
JobService
}
from
"../../data-access/service/Job.service"
;
import
{
catchError
,
of
,
tap
}
from
"rxjs"
;
import
{
CommonModule
}
from
"@angular/common"
;
import
{
FormsModule
}
from
"@angular/forms"
;
@
Component
(
{
selector
:
'app-home-job-detail'
,
templateUrl
:
'./JobDetail.component.html'
,
standalone
:
true
,
imports
:
[
CommonModule
,
FormsModule
],
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
}
)
export
class
JobDetailComponent
implements
OnInit
{
@
Input
()
id
:
string
=
""
;
Job
?:
Job
;
constructor
(
private
JobService
:
JobService
,
private
_cdr
:
ChangeDetectorRef
)
{
}
ngOnInit
():
void
{
this
.
JobService
.
jobGetById
(
this
.
id
).
pipe
(
tap
((
data
)
=>
{
this
.
Job
=
data
.
responseData
as
Job
;
this
.
_cdr
.
markForCheck
();
}),
catchError
((
error
)
=>
{
return
of
(
null
);
})
).
subscribe
();
}
}
src/app/+home/component/JobList/JobList.component.html
0 → 100644
View file @
5465e871
<div
class=
"tw-flex tw-justify-center tw-py-8"
>
<h1
class=
"tw-text-2xl tw-font-bold"
>
Danh sách công việc
</h1>
</div>
<div
class=
"tw-flex tw-justify-center tw-space-x-4 tw-mb-4"
>
<input
nz-input
placeholder=
"Tìm kiếm"
class=
"tw-w-full tw-max-w-md"
[(
ngModel
)]="
searchTerm
"
(
ngModelChange
)="
search
()"
/>
</div>
<div
class=
"tw-flex tw-justify-center"
>
<nz-list
nzItemLayout=
"vertical"
[
nzDataSource
]="
displayedJobs
"
class=
"tw-w-full tw-max-w-4xl"
nzBordered
>
<nz-list-item
*
ngFor=
"let item of displayedJobs"
class=
"tw-bg-[#3174c025] tw-shadow tw-rounded tw-p-4"
>
<nz-list-item-meta>
<nz-list-item-meta-title>
<a
href=
"/DetailJob/{{ item?.id }}"
class=
"tw-text-base tw-font-bold"
>
{{ item?.title }}
</a>
</nz-list-item-meta-title>
</nz-list-item-meta>
<ul
nz-list-item-actions
class=
"tw-flex tw-flex-wrap tw-gap-4 tw-mt-2"
>
<nz-list-item-action
*
ngIf=
"item?.type"
>
<i
nz-icon
nzType=
"star-o"
class=
"tw-mr-1"
></i>
{{ item?.type }}
</nz-list-item-action>
<nz-list-item-action
*
ngIf=
"item?.location"
>
<i
nz-icon
nzType=
"environment-o"
class=
"tw-mr-1"
></i>
{{ item?.location }}
</nz-list-item-action>
<nz-list-item-action
*
ngIf=
"item?.created_at"
>
<i
nz-icon
nzType=
"calendar-o"
class=
"tw-mr-1"
></i>
{{ item?.created_at | date:'medium' }}
</nz-list-item-action>
</ul>
</nz-list-item>
</nz-list>
</div>
<div
class=
"tw-flex tw-justify-center tw-my-8"
>
<nz-pagination
[
nzPageIndex
]="
currentPage
"
[
nzPageSize
]="
pageSize
"
[
nzTotal
]="
filteredJobs
.
length
"
(
nzPageIndexChange
)="
onPageChange
($
event
)"
[
nzShowSizeChanger
]="
false
"
>
</nz-pagination>
</div>
src/app/+home/component/JobList/JobList.component.ts
0 → 100644
View file @
5465e871
// JobListCard.component.ts
import
{
ChangeDetectionStrategy
,
ChangeDetectorRef
,
Component
,
OnInit
,
}
from
"@angular/core"
;
import
{
NzDividerModule
}
from
"ng-zorro-antd/divider"
;
import
{
NzGridModule
}
from
"ng-zorro-antd/grid"
;
import
{
JobModel
}
from
"../../../+admin/data-access/model/jobModel.model"
;
import
{
JobService
}
from
"../../data-access/service/Job.service"
;
import
{
tap
}
from
"rxjs/operators"
;
import
{
CommonModule
}
from
"@angular/common"
;
import
{
NzListModule
}
from
"ng-zorro-antd/list"
;
import
{
NzCardModule
}
from
"ng-zorro-antd/card"
;
import
{
NzTableModule
}
from
"ng-zorro-antd/table"
;
import
{
NzPaginationModule
}
from
"ng-zorro-antd/pagination"
;
import
{
FormsModule
}
from
"@angular/forms"
;
import
{
NzInputModule
}
from
"ng-zorro-antd/input"
;
import
{
NzButtonModule
}
from
"ng-zorro-antd/button"
;
import
{
NzIconModule
}
from
"ng-zorro-antd/icon"
;
import
{
RouterLink
}
from
"@angular/router"
;
@
Component
({
selector
:
"app-home-list-job"
,
templateUrl
:
"./JobList.component.html"
,
imports
:
[
CommonModule
,
FormsModule
,
NzDividerModule
,
NzGridModule
,
NzListModule
,
NzCardModule
,
NzTableModule
,
NzPaginationModule
,
NzInputModule
,
NzButtonModule
,
NzIconModule
,
],
standalone
:
true
,
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
})
export
class
JobListCardComponent
implements
OnInit
{
listOfJob
:
JobModel
.
Job
[]
=
[];
filteredJobs
:
JobModel
.
Job
[]
=
[];
displayedJobs
:
JobModel
.
Job
[]
=
[];
searchTerm
:
string
=
""
;
currentPage
:
number
=
1
;
pageSize
:
number
=
10
;
constructor
(
private
jobService
:
JobService
,
private
_changeDetectorRef
:
ChangeDetectorRef
)
{}
ngOnInit
()
{
this
.
fetchJobs
();
}
fetchJobs
():
void
{
this
.
jobService
.
jobsGet
().
pipe
(
tap
((
res
)
=>
{
this
.
listOfJob
=
res
.
responseData
?.
rows
as
JobModel
.
Job
[];
this
.
filteredJobs
=
[...
this
.
listOfJob
];
this
.
updateDisplayedJobs
();
this
.
_changeDetectorRef
.
markForCheck
();
})
).
subscribe
();
}
search
():
void
{
if
(
this
.
searchTerm
.
trim
())
{
const
term
=
this
.
searchTerm
.
trim
().
toLowerCase
();
this
.
filteredJobs
=
this
.
listOfJob
.
filter
((
job
)
=>
(
job
.
title
&&
job
.
title
.
toLowerCase
().
includes
(
term
))
||
(
job
.
type
&&
job
.
type
.
toLowerCase
().
includes
(
term
))
||
(
job
.
location
&&
job
.
location
.
toLowerCase
().
includes
(
term
))
);
}
else
{
this
.
filteredJobs
=
[...
this
.
listOfJob
];
}
this
.
currentPage
=
1
;
this
.
updateDisplayedJobs
();
this
.
_changeDetectorRef
.
markForCheck
();
}
onPageChange
(
page
:
number
):
void
{
this
.
currentPage
=
page
;
this
.
updateDisplayedJobs
();
this
.
_changeDetectorRef
.
markForCheck
();
}
updateDisplayedJobs
():
void
{
const
startIndex
=
(
this
.
currentPage
-
1
)
*
this
.
pageSize
;
const
endIndex
=
startIndex
+
this
.
pageSize
;
this
.
displayedJobs
=
this
.
filteredJobs
.
slice
(
startIndex
,
endIndex
);
}
}
src/app/+home/component/JobListCard/JobListCard.component.html
deleted
100644 → 0
View file @
d3f8c729
<nz-list
nzGrid
>
<div
nz-row
[
nzGutter
]="
16
"
>
@for (item of listOfJob; track item) {
<div
nz-col
[
nzSpan
]="
6
"
>
<nz-list-item>
<button
nz-button
class=
"tw-w-full"
>
<job-card
[
job
]="
item
"
></job-card>
</button>
</nz-list-item>
</div>
}
</div>
</nz-list>
src/app/+home/component/JobListCard/JobListCard.component.ts
deleted
100644 → 0
View file @
d3f8c729
import
{
ChangeDetectionStrategy
,
ChangeDetectorRef
,
Component
,
OnInit
}
from
"@angular/core"
;
import
{
JobCardComponent
}
from
"../JobCard/JobCard.component"
;
import
{
NzDividerModule
}
from
"ng-zorro-antd/divider"
;
import
{
NzGridModule
}
from
"ng-zorro-antd/grid"
;
import
{
JobModel
}
from
"../../../+admin/data-access/model/jobModel.model"
;
import
{
JobService
}
from
"../../data-access/service/Job.service"
;
import
{
tap
}
from
"rxjs"
;
import
{
CommonModule
}
from
"@angular/common"
;
import
{
NzListModule
}
from
'ng-zorro-antd/list'
;
import
{
NzCardModule
}
from
"ng-zorro-antd/card"
;
import
{
RouterLink
}
from
"@angular/router"
;
@
Component
({
selector
:
'app-home-list-job'
,
templateUrl
:
'./JobListCard.component.html'
,
imports
:
[
CommonModule
,
NzDividerModule
,
NzGridModule
,
JobCardComponent
,
NzGridModule
,
NzListModule
,
NzCardModule
,
RouterLink
],
standalone
:
true
,
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
})
export
class
JobListCardComponent
implements
OnInit
{
listOfJob
?:
JobModel
[]
;
constructor
(
private
jobService
:
JobService
,
private
_changeDetectorRef
:
ChangeDetectorRef
,)
{}
ngOnInit
()
{
this
.
jobService
.
jobsGet
().
pipe
(
tap
((
res
)
=>
{
this
.
listOfJob
=
res
.
responseData
?.
rows
as
JobModel
[];
this
.
_changeDetectorRef
.
markForCheck
();
console
.
log
(
this
.
listOfJob
);
}),
).
subscribe
();
}
}
src/app/+home/data-access/service/Job.service.ts
View file @
5465e871
...
...
@@ -10,8 +10,13 @@ import { HttpClient } from "@angular/common/http";
})
export
class
JobService
{
apiUrl
=
environment
.
API_DOMAIN
+
'/jobs'
;
apiUrlById
=
environment
.
API_DOMAIN
+
'/jobById'
;
constructor
(
private
http
:
HttpClient
)
{}
jobsGet
():
Observable
<
ResponseResult
<
Rows
<
Job
>>>
{
return
this
.
http
.
get
<
ResponseResult
<
Rows
<
Job
>>>
(
this
.
apiUrl
);
}
jobGetById
(
id
:
string
):
Observable
<
ResponseResult
<
Job
>>
{
return
this
.
http
.
get
<
ResponseResult
<
Job
>>
(
`
${
this
.
apiUrlById
}
/
${
id
}
`
);
}
}
src/app/+login/data-access/Services/Auth.Service.ts
View file @
5465e871
...
...
@@ -18,7 +18,6 @@ export class AuthService {
return
this
.
http
.
post
<
any
>
(
this
.
apiUrl
,
body
,
{
headers
}).
pipe
(
tap
((
response
)
=>
{
localStorage
.
setItem
(
'token'
,
response
.
responseData
.
token
);
localStorage
.
setItem
(
'expirationTime'
,
response
.
responseData
.
expirationTime
);
localStorage
.
setItem
(
'role'
,
response
.
responseData
.
role
);
})
);
...
...
@@ -26,7 +25,6 @@ export class AuthService {
logout
():
void
{
localStorage
.
removeItem
(
'token'
);
localStorage
.
removeItem
(
'expirationTime'
);
localStorage
.
removeItem
(
'role'
);
this
.
router
.
navigate
([
'/login'
]);
}
...
...
src/app/+login/feature/login.component.html
View file @
5465e871
<div
class=
"tw-flex tw-items-center tw-justify-center tw-min-h-screen tw-bg-gray-100"
>
<form
nz-form
[
formGroup
]="
loginForm
"
class=
"tw-login-form tw-bg-white tw-p-8 tw-shadow-lg tw-rounded-lg tw-w-full tw-max-w-md"
(
ngSubmit
)="
onSubmit
()"
>
<nz-form-text
class=
"tw-text-4xl tw-font-bold tw-text-center tw-mb-6"
>
LOGIN
</nz-form-text>
<nz-form-text
class=
"tw-text-4xl tw-font-bold tw-text-center tw-mb-6"
>
Đăng nhập
</nz-form-text>
<nz-form-item>
<nz-form-control
nzErrorTip=
"
Please input your username
!"
>
<nz-form-control
nzErrorTip=
"
Nhập tên tài khoản
!"
>
<nz-input-group
nzPrefixIcon=
"user"
>
<input
type=
"text"
nz-input
formControlName=
"userName"
placeholder=
"
Username
"
/>
<input
type=
"text"
nz-input
formControlName=
"userName"
placeholder=
"
tên tài khoản
"
/>
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control
nzErrorTip=
"
Please input your Password
!"
>
<nz-form-control
nzErrorTip=
"
Tối thiểu 6 ký tự
!"
>
<nz-input-group
nzPrefixIcon=
"lock"
>
<input
type=
"password"
nz-input
formControlName=
"password"
placeholder=
"
Password
"
minlength=
"6"
/>
<input
type=
"password"
nz-input
formControlName=
"password"
placeholder=
"
Mật khẩu
"
minlength=
"6"
/>
</nz-input-group>
</nz-form-control>
</nz-form-item>
<p
*
ngIf=
"MgsError"
class=
"error-message tw-text-center"
>
{{MgsError}}
</p>
<button
nz-button
class=
"login-form-button login-form-margin"
[
nzType
]="'
primary
'"
>
Log in
</button>
<button
nz-button
class=
"login-form-button login-form-margin"
[
nzType
]="'
primary
'"
>
Đăng nhập
</button>
</form>
</div>
src/app/+login/feature/login.component.ts
View file @
5465e871
...
...
@@ -62,14 +62,11 @@ export class LoginComponent implements OnInit {
this
.
authService
.
login
(
this
.
loginForm
.
value
.
userName
,
this
.
loginForm
.
value
.
password
).
pipe
(
catchError
((
err
)
=>
{
this
.
MgsError
=
err
.
message
;
console
.
log
(
this
.
MgsError
);
console
.
log
(
err
);
return
of
(
null
);
}),
finalize
(()
=>
{
if
(
this
.
authService
.
isLoggedIn
())
this
.
authService
.
loginSussces
();
console
.
log
(
'Login request completed'
);
if
(
this
.
authService
.
isLoggedIn
()){
this
.
authService
.
loginSussces
();}
})
).
subscribe
();
}
...
...
src/app/+shell/feature/shell.routes.ts
View file @
5465e871
...
...
@@ -24,7 +24,13 @@ export const shellRoutes: Routes = [
path
:
'ListJob'
,
canActivate
:
[],
loadComponent
:
()
=>
import
(
'../../+home/component/JobListCard/JobListCard.component'
).
then
((
m
)
=>
m
.
JobListCardComponent
),
import
(
'../../+home/component/JobList/JobList.component'
).
then
((
m
)
=>
m
.
JobListCardComponent
),
},
{
path
:
'DetailJob/:id'
,
canActivate
:
[],
loadComponent
:
()
=>
import
(
'../../+home/component/JobDetail/JobDetail.component'
).
then
((
m
)
=>
m
.
JobDetailComponent
),
},
],
...
...
src/app/+shell/ui/components/header/feature/header.component.html
View file @
5465e871
<header
class=
"tw-bg-gray-900 tw-py-4"
>
<div
class=
"tw-container tw-mx-auto tw-flex tw-justify-between tw-items-center tw-px-4"
>
<header
class=
"tw-bg-gray-900 tw-py-4
md:tw-px-4
"
>
<div
class=
"tw-container tw-mx-auto tw-flex tw-justify-between tw-items-center tw-px-4
md:tw-px-0
"
>
<div
class=
"tw-text-3xl tw-font-bold"
>
<a
href=
"/home"
class=
"hover:tw-text-gray-400"
>
MeU Solution
</a>
</div>
...
...
@@ -7,12 +7,13 @@
<nav
class=
"tw-bg-gray-900 tw-py-2"
>
<div
class=
"tw-container tw-mx-auto"
>
<ul
class=
"tw-flex tw-space-x-8 tw-justify-center"
>
<
li><a
href=
"/home"
class=
"tw-text-gray-300 hover:tw-text-white"
>
Trang chủ
</a></li
>
<li><a
href=
"/ListJob"
class=
"tw-text-gray-300 hover:tw-text-white"
>
Danh sách công việc
</a></li>
<
li><a
href=
"/admin"
class=
"tw-text-gray-300 hover:tw-text-white"
>
Admin
</a></li
>
<ul
class=
"tw-flex tw-space-x-8 tw-justify-center
md:tw-justify-end
"
>
<
div
*
ngFor=
"let item of list"
>
<li><a
href=
"/{{item.href}}"
class=
"tw-text-gray-300 hover:tw-text-white"
>
{{item.title}}
</a></li>
<
/div
>
<li><a
(
click
)="
logout
()"
class=
"tw-text-gray-300 hover:tw-text-white"
>
Đăng xuất
</a></li>
</ul>
</div>
</nav>
</header>
src/app/+shell/ui/components/header/feature/header.component.ts
View file @
5465e871
...
...
@@ -10,6 +10,12 @@ import { AuthService } from '../../../../../+login/data-access/Services/Auth.Ser
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
})
export
class
HeaderComponent
implements
OnInit
{
list
:
{
href
:
string
,
title
:
string
}[]
=
[
{
href
:
'home'
,
title
:
'Trang chủ'
},
{
href
:
'ListJob'
,
title
:
'Danh sách công việc'
},
{
href
:
'admin'
,
title
:
'Trang Admin'
}
];
ngOnInit
():
void
{}
constructor
(
private
authentication
:
AuthService
)
{}
logout
()
{
...
...
src/app/+shell/ui/layout.component.ts
View file @
5465e871
...
...
@@ -33,8 +33,10 @@ import { NzLayoutModule } from 'ng-zorro-antd/layout';
<nz-layout>
<meu-header></meu-header>
<div class="tw-relative tw-min-h-[92dvh]">
<div class="tw-max-w-5xl tw-mx-auto tw-py-10 tw-px-3 tw-bg-white">
<router-outlet></router-outlet>
</div>
</div>
<meu-footer></meu-footer>
</nz-layout>
</div>
...
...
@@ -45,7 +47,7 @@ import { NzLayoutModule } from 'ng-zorro-antd/layout';
export
class
LayoutComponent
implements
OnInit
{
isSmallScreen
=
signal
(
false
);
constructor
(
private
breakpointObserver
:
BreakpointObserver
)
{}
constructor
(
private
breakpointObserver
:
BreakpointObserver
)
{
}
ngOnInit
()
{
this
.
breakpointObserver
.
observe
([
Breakpoints
.
Handset
]).
subscribe
((
res
)
=>
{
this
.
isSmallScreen
.
set
(
res
.
matches
);
...
...
src/app/app.component.ts
View file @
5465e871
...
...
@@ -12,3 +12,60 @@ import { RouterOutlet } from '@angular/router';
export
class
AppComponent
{
title
=
'Meu-template-CSR'
;
}
// onOk(): void {
// if (this.isOnEdit && this.selectedJob) {
// if(!this.validateJobForm.valid){
// this.createNotification();
// return;}
// const updatedJob: JobModel = {
// id: this.selectedJob.id,
// type: this.validateJobForm.value.type ?? undefined,
// created_at: this.selectedJob.created_at,
// company: this.validateJobForm.value.company ?? undefined,
// location: this.validateJobForm.value.location ?? undefined,
// title: this.validateJobForm.value.title ?? undefined,
// description: this.validateJobForm.value.description ?? undefined,
// };
// this.jobService.editJob(updatedJob).pipe(
// tap((res) => {
// this.message.success(res.message, { nzDuration: 2500 });
// this._cdr.markForCheck();
// this.loadDataFromServer();
// }),
// catchError((err) => {
// this.message.error(err.message, { nzDuration: 2500 });
// return of(null);
// })
// ).subscribe();
// } else if (this.isOnAdd && this.selectedJob) {
// if(!this.validateJobForm.valid){
// this.createNotification();
// return;}
// const newJob: JobModel = {
// id: this.selectedJob.id,
// type: this.validateJobForm.value.type ?? undefined,
// created_at: this.selectedJob.created_at,
// company: this.validateJobForm.value.company ?? undefined,
// location: this.validateJobForm.value.location ?? undefined,
// title: this.validateJobForm.value.title ?? undefined,
// description: this.validateJobForm.value.description ?? undefined,
// };
// this.loading = true;
// this.jobService.addingNewJob(newJob).pipe(
// tap((res) => {
// this.message.success(res.message, { nzDuration: 2500 });
// this.loadDataFromServer();
// }),
// catchError((err) => {
// this.message.error(err.message, { nzDuration: 2500 });
// return of(null);
// })
// ).subscribe();
// }
// this.isOpenModal = false;
// this.isOnEdit = false;
// this.isOnAdd = false;
// }
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment