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
2 months ago
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>
This diff is collapsed.
Click to expand it.
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'
;
}
}
This diff is collapsed.
Click to expand it.
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>
This diff is collapsed.
Click to expand it.
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
();
}
}
This diff is collapsed.
Click to expand it.
src/app/+admin/Management/Job/Job.component.html
View file @
5465e871
<div
className=
"tw-container tw-content-center"
>
<div
class=
"tw-container tw-content-center"
>
<div
class=
"tw-flex tw-justify-end tw-pb-5"
>
<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>
<button
nz-button
nzType=
"primary"
(
click
)="
addJob
()"
>
+ Thêm công việc mới
</button>
</div>
</div>
<nz-table
<nz-table
#
JobTable
#
JobTable
[
nzData
]="
listOfJob
"
[
nzData
]="
listOfJob
"
[
nzLoading
]="
loading
"
[
nzFrontPagination
]="
true
"
[
nzFrontPagination
]="
true
"
nzShowSizeChanger
nzShowSizeChanger
[
nzPageSize
]="
5
"
[
nzPageSize
]="
5
"
[
nzScroll
]="{
x:
'
300px
'
}"
>
>
<thead>
<thead>
<tr>
<tr>
...
@@ -21,16 +23,21 @@
...
@@ -21,16 +23,21 @@
</tr>
</tr>
</thead>
</thead>
<tbody>
<tbody>
@for (data of JobTable.data; track data) {
<tr
*
ngFor=
"let data of JobTable.data; let i = index"
>
<tr>
<td>
{{ i + 1 }}
</td>
<td>
{{ listOfJob.indexOf(data) + 1 }}
</td>
<td>
{{ data.type }}
</td>
<td>
{{ data.type }}
</td>
<td>
{{ data.title }}
</td>
<td>
{{ data.title }}
</td>
<td>
{{ data.company }}
</td>
<td>
{{ data.company }}
</td>
<td>
{{ data.location }}
</td>
<td>
{{ data.location }}
</td>
<td>
<td>
<nz-space>
<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
Xem chi tiết
</button>
</button>
<button
<button
...
@@ -42,61 +49,31 @@
...
@@ -42,61 +49,31 @@
>
>
Sửa
Sửa
</button>
</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
Xóa
</button>
</button>
</nz-space>
</nz-space>
</td>
</td>
</tr>
</tr>
}
</tbody>
</tbody>
</nz-table>
</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
()"
>
<app-view-job
<ng-container
*
nzModalContent
>
[
showViewModalComponent
]="
showViewModalComponent
"
<div
*
ngIf=
"selectedJob"
>
[
jobData
]="
currentViewJob
"
<form
nz-form
[
formGroup
]="
validateJobForm
"
>
(
close
)="
onCloseViewModal
()"
<nz-form-item>
></app-view-job>
<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>
</div>
</div>
This diff is collapsed.
Click to expand it.
src/app/+admin/Management/Job/Job.component.scss
deleted
100644 → 0
View file @
d3f8c729
This diff is collapsed.
Click to expand it.
src/app/+admin/Management/Job/Job.component.ts
View file @
5465e871
//#region imports
import
{
CommonModule
}
from
"@angular/common"
;
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
{
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
{
catchError
,
finalize
,
of
,
tap
}
from
"rxjs"
;
import
{
JobModel
}
from
"../../data-access/model/jobModel.model"
;
import
{
JobModel
}
from
"../../data-access/model/jobModel.model"
;
import
{
NzDividerModule
}
from
'ng-zorro-antd/divider'
;
import
{
NzDividerModule
}
from
'ng-zorro-antd/divider'
;
import
{
NzButtonModule
}
from
"ng-zorro-antd/button"
;
import
{
NzButtonModule
}
from
"ng-zorro-antd/button"
;
import
{
NzSpaceModule
}
from
'ng-zorro-antd/space'
;
import
{
NzSpaceModule
}
from
'ng-zorro-antd/space'
;
import
{
NzModalModule
,
NzModalService
}
from
'ng-zorro-antd/modal'
;
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
{
NzFormModule
}
from
"ng-zorro-antd/form"
;
import
{
NzSelectModule
}
from
'ng-zorro-antd/select'
;
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
({
@
Component
({
selector
:
"meu-admin-job"
,
selector
:
"meu-admin-job"
,
templateUrl
:
"./Job.component.html"
,
templateUrl
:
"./Job.component.html"
,
standalone
:
true
,
standalone
:
true
,
imports
:
[
CommonModule
,
imports
:
[
CommonModule
,
NzTableModule
,
NzTableModule
,
NzDividerModule
,
NzDividerModule
,
NzButtonModule
,
NzButtonModule
,
NzSpaceModule
,
NzSpaceModule
,
NzModalModule
,
NzModalModule
,
NzModalModule
,
NzFormModule
,
NzFormModule
,
ReactiveFormsModule
,
ReactiveFormsModule
,
NzSelectModule
NzSelectModule
,
FormsModule
,
NzAlertModule
,
ViewJobComponent
,
ModalJobComponent
],
],
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
})
})
//#endregion
export
class
JobComponent
implements
OnInit
{
export
class
JobComponent
implements
OnInit
{
isMobileView
:
boolean
=
false
;
searchTerm
:
string
=
''
;
//#region Variable
//#region Variable
selectedJob
?:
JobModel
;
selectedJob
?:
JobModel
.
Job
;
listOfJob
:
JobModel
[]
=
[];
listOfJob
:
JobModel
.
Job
[]
=
[];
loading
=
true
;
message
=
""
;
showModal
:
boolean
=
false
;
//modal
isEdit
:
boolean
=
false
;
isOpenModal
=
false
;
showViewModalComponent
:
boolean
=
false
;
isOnEdit
=
false
;
isOnAdd
=
false
;
// Công việc hiện tại để chỉnh sửa hoặc xem chi tiết
validateJobForm
=
this
.
fb
.
group
({
currentEditJob
:
JobModel
.
Job
|
null
=
null
;
type
:
this
.
fb
.
control
(
''
,
[
Validators
.
required
]),
currentViewJob
:
JobModel
.
Job
|
null
=
null
;
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
]),
});
//#endregion
//#endregion
//#region LoadData
//#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
{
loadDataFromServer
():
void
{
console
.
log
(
"hello"
);
this
.
loading
=
true
;
this
.
jobService
.
jobsGet
().
pipe
(
this
.
jobService
.
jobsGet
().
pipe
(
tap
((
res
)
=>
{
tap
((
res
)
=>
{
if
(
res
.
responseData
)
if
(
res
.
responseData
)
{
this
.
listOfJob
=
res
.
responseData
.
rows
;
this
.
listOfJob
=
res
.
responseData
.
rows
;
}
this
.
_cdr
.
detectChanges
();
}),
}),
catchError
((
err
)
=>
{
catchError
((
err
)
=>
{
this
.
listOfJob
=
[];
this
.
listOfJob
=
[];
this
.
notification
.
error
(
'Lỗi'
,
'Không tải được dữ liệu công việc.'
);
return
of
(
null
);
return
of
(
null
);
}),
})
finalize
(()
=>
(
this
.
loading
=
false
))
).
subscribe
();
).
subscribe
();
}
}
ngOnInit
():
void
{
ngOnInit
():
void
{
this
.
loadDataFromServer
();
this
.
loadDataFromServer
();
this
.
checkScreenSize
();
// Kiểm tra kích thước màn hình ban đầu
}
}
//#endregion
//#region Handler
onCloseViewModal
():
void
{
resetForm
()
{
this
.
showViewModalComponent
=
false
;
this
.
validateJobForm
.
reset
();
this
.
selectedJob
=
{}
as
JobModel
;
}
}
EnableForm
()
{
onSubmit
():
void
{
this
.
validateJobForm
.
enable
();
this
.
isEdit
=
false
;
this
.
showModal
=
false
;
this
.
_cdr
.
detectChanges
();
this
.
loadDataFromServer
();
}
}
DisableForm
()
{
onCloseModal
():
void
{
this
.
validateJobForm
.
disable
()
;
this
.
showModal
=
false
;
}
}
onOk
():
void
{
//#endregion
console
.
log
(
this
.
onEdit
,
this
.
selectedJob
);
if
(
this
.
isOnEdit
&&
this
.
selectedJob
)
{
//#region Handlers
const
updatedJob
:
JobModel
=
{
id
:
this
.
selectedJob
.
id
,
// Handler xem chi tiết công việc
type
:
this
.
validateJobForm
.
value
.
type
??
undefined
,
handleViewJob
(
id
:
string
):
void
{
created_at
:
this
.
selectedJob
.
created_at
,
this
.
jobService
.
getJobById
(
id
)
company
:
this
.
validateJobForm
.
value
.
company
??
undefined
,
.
pipe
(
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
(
tap
((
res
)
=>
{
tap
((
res
)
=>
{
this
.
message
=
res
.
message
;
this
.
showViewModalComponent
=
true
;
this
.
loadDataFromServer
();
this
.
currentViewJob
=
res
.
responseData
as
JobModel
.
Job
;
this
.
_cdr
.
detectChanges
();
}),
}),
catchError
((
err
)
=>
{
catchError
((
err
)
=>
{
console
.
error
(
err
);
this
.
message
.
error
(
err
.
message
||
'An error occurred while fetching job data.'
,
{
nzDuration
:
2500
}
);
return
of
(
null
);
return
of
(
null
);
})
})
).
subscribe
();
)
}
else
if
(
this
.
isOnAdd
&&
this
.
selectedJob
)
{
.
subscribe
();
const
newJob
:
JobModel
=
{
}
id
:
this
.
selectedJob
.
id
,
type
:
this
.
validateJobForm
.
value
.
type
??
undefined
,
// Handler xóa công việc
created_at
:
this
.
selectedJob
.
created_at
,
onDelete
(
id
:
string
):
void
{
company
:
this
.
validateJobForm
.
value
.
company
??
undefined
,
this
.
jobService
.
deleteJob
(
id
)
company_url
:
this
.
validateJobForm
.
value
.
company_url
??
undefined
,
.
pipe
(
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
)
=>
{
tap
((
res
)
=>
{
this
.
message
=
res
.
message
;
this
.
message
.
success
(
res
.
message
,
{
nzDuration
:
2500
});
this
.
_cdr
.
markForCheck
();
this
.
loadDataFromServer
();
this
.
loadDataFromServer
();
}),
}),
catchError
((
err
)
=>
{
catchError
((
err
)
=>
{
console
.
error
(
err
);
this
.
message
.
error
(
err
.
message
,
{
nzDuration
:
2500
}
);
return
of
(
null
);
return
of
(
null
);
})
})
).
subscribe
();
)
}
.
subscribe
();
this
.
isOpenModal
=
false
;
this
.
isOnEdit
=
false
;
this
.
isOnAdd
=
false
;
}
}
onCancel
():
void
{
// Xử lý khi nhấn nút "Thêm công việc"
this
.
isOpenModal
=
false
;
addJob
():
void
{
this
.
isOnEdit
=
fals
e
;
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
(()
=>
(
// Xử lý khi nhấn nút "Sửa"
this
.
loadDataFromServer
(),
this
.
loading
=
false
))
onEdit
(
data
:
JobModel
.
Job
):
void
{
).
subscribe
();
this
.
isEdit
=
true
;
}
this
.
currentEditJob
=
data
;
onDelete
(
id
:
string
)
{
this
.
showModal
=
true
;
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
;
}
}
addJob
()
{
this
.
EnableForm
();
// Xử lý khi nhấn nút "Xem chi tiết"
this
.
resetForm
();
JobDetail
(
id
:
string
):
void
{
this
.
isOpenModal
=
true
;
this
.
handleViewJob
(
id
);
this
.
isOnEdit
=
false
;
this
.
isOnAdd
=
true
;
}
}
// Hiển thị hộp thoại xác nhận xóa
showDeleteConfirm
(
id
:
string
):
void
{
showDeleteConfirm
(
id
:
string
):
void
{
this
.
modal
.
confirm
({
this
.
modal
.
confirm
({
nzTitle
:
'Bạn có chắc rằng xóa công việc này không?'
,
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 {
...
@@ -204,8 +160,25 @@ export class JobComponent implements OnInit {
nzOkType
:
'primary'
,
nzOkType
:
'primary'
,
nzOkDanger
:
true
,
nzOkDanger
:
true
,
nzOnOk
:
()
=>
this
.
onDelete
(
id
),
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
//#endregion
}
}
This diff is collapsed.
Click to expand it.
src/app/+admin/data-access/model/jobModel.model.ts
View file @
5465e871
export
interface
JobModel
{
export
namespace
JobModel
{
export
interface
Job
{
id
:
string
;
id
:
string
;
type
?:
string
;
type
?:
string
;
created_at
:
string
;
created_at
:
string
;
...
@@ -9,4 +10,14 @@ export interface JobModel {
...
@@ -9,4 +10,14 @@ export interface JobModel {
description
?:
string
;
description
?:
string
;
how_to_apply
?:
string
;
how_to_apply
?:
string
;
company_logo
?:
string
;
company_logo
?:
string
;
}
export
interface
JobRequest
{
type
:
string
;
created_at
:
string
;
company
:
string
;
company_url
:
string
;
location
:
string
;
title
:
string
;
description
:
string
;
}
}
}
This diff is collapsed.
Click to expand it.
src/app/+admin/data-access/services/JobService.service.ts
View file @
5465e871
...
@@ -14,37 +14,24 @@ export class JobService {
...
@@ -14,37 +14,24 @@ export class JobService {
apiUrlById
=
environment
.
API_DOMAIN
+
'/jobById'
;
apiUrlById
=
environment
.
API_DOMAIN
+
'/jobById'
;
constructor
(
private
http
:
HttpClient
)
{}
constructor
(
private
http
:
HttpClient
)
{}
jobsGet
():
Observable
<
ResponseResult
<
Rows
<
JobModel
>>>
{
jobsGet
():
Observable
<
ResponseResult
<
Rows
<
JobModel
.
Job
>>>
{
return
this
.
http
.
get
<
ResponseResult
<
Rows
<
JobModel
>>>
(
this
.
apiUrl
);
return
this
.
http
.
get
<
ResponseResult
<
Rows
<
JobModel
.
Job
>>>
(
this
.
apiUrl
);
}
}
addingNewJob
(
data
:
JobModel
):
Observable
<
ResponseResult
<
JobModel
>>
{
addingNewJob
(
data
:
JobModel
.
JobRequest
):
Observable
<
ResponseResult
<
JobModel
.
Job
>>
{
const
headers
=
new
HttpHeaders
()
return
this
.
http
.
post
<
ResponseResult
<
JobModel
.
Job
>>
(
this
.
apiUrl
,
data
);
.
set
(
'Content-Type'
,
'application/json'
)
.
set
(
'Authorization'
,
`Bearer
${
localStorage
.
getItem
(
'token'
)}
`
);
return
this
.
http
.
post
<
ResponseResult
<
JobModel
>>
(
this
.
apiUrl
,
data
,
{
headers
});
}
}
deleteJob
(
id
:
string
):
Observable
<
ResponseResult
<
JobModel
>>
{
deleteJob
(
id
:
string
):
Observable
<
ResponseResult
<
JobModel
.
Job
>>
{
const
headers
=
new
HttpHeaders
()
.
set
(
'Content-Type'
,
'application/json'
)
.
set
(
'Authorization'
,
`Bearer
${
localStorage
.
getItem
(
'token'
)}
`
);
const
url
=
`
${
this
.
apiUrl
}
/
${
id
}
`
;
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
>>
{
editJob
(
data
:
JobModel
.
Job
):
Observable
<
ResponseResult
<
JobModel
.
Job
>>
{
const
headers
=
new
HttpHeaders
()
.
set
(
'Content-Type'
,
'application/json'
)
.
set
(
'Authorization'
,
`Bearer
${
localStorage
.
getItem
(
'token'
)}
`
);
const
url
=
`
${
this
.
apiUrl
}
/
${
data
.
id
}
`
;
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
>>
{
getJobById
(
id
:
string
):
Observable
<
ResponseResult
<
JobModel
.
Job
>>
{
const
headers
=
new
HttpHeaders
()
.
set
(
'Content-Type'
,
'application/json'
)
.
set
(
'Authorization'
,
`Bearer
${
localStorage
.
getItem
(
'token'
)}
`
);
const
url
=
`
${
this
.
apiUrlById
}
/
${
id
}
`
;
const
url
=
`
${
this
.
apiUrlById
}
/
${
id
}
`
;
console
.
log
(
id
,
url
);
return
this
.
http
.
get
<
ResponseResult
<
JobModel
.
Job
>>
(
url
);
return
this
.
http
.
get
<
ResponseResult
<
JobModel
>>
(
url
,
{
headers
});
}
}
}
}
This diff is collapsed.
Click to expand it.
src/app/+admin/layout/feature/ui/Components/footer/footer.component.html
View file @
5465e871
...
@@ -5,23 +5,19 @@
...
@@ -5,23 +5,19 @@
<p>
Designed by Meu Solution
</p>
<p>
Designed by Meu Solution
</p>
<div
class=
"tw-flex tw-justify-center tw-space-x-4 tw-mt-4"
>
<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
>
<
div
*
ngFor=
"let item of list"
>
<a
href=
"#contact"
class=
" hover:tw-text-blue-500"
>
Contact
</a>
<a
href=
"#{{item.href}}"
class=
" hover:tw-text-blue-500"
>
{{item.title}}
</a>
<
a
href=
"#privacy"
class=
" hover:tw-text-blue-500"
>
Privacy Policy
</a
>
<
/div
>
</div>
</div>
<div
class=
"tw-flex tw-justify-center tw-space-x-4 tw-mt-4"
>
<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"
>
<a
href=
"#"
target=
"_blank"
class=
" hover:tw-text-blue-500"
>
<i
nz-icon
nzType=
"facebook"
class=
"tw-text-2xl"
></i>
<i
nz-icon
nzType=
"{{item}}"
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>
</a>
</a>
</div>
</div>
</div>
</div>
</div>
</footer>
</footer>
...
...
This diff is collapsed.
Click to expand it.
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';
...
@@ -13,5 +13,12 @@ import { NzLayoutModule } from 'ng-zorro-antd/layout';
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
})
})
export
class
FooterComponent
implements
OnInit
{
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
{}
ngOnInit
():
void
{}
}
}
This diff is collapsed.
Click to expand it.
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>
This diff is collapsed.
Click to expand it.
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
{}
}
This diff is collapsed.
Click to expand it.
src/app/+admin/layout/feature/ui/layout.component.html
View file @
5465e871
<nz-layout>
<nz-layout
class=
"tw-h-screen tw-flex tw-flex-col"
>
<nz-sider
nzCollapsible
[
nzTrigger
]="
null
"
>
<nz-header
class=
"tw-flex tw-justify-between tw-items-center tw-px-4 tw-bg-[#1f487725] tw-shadow-md"
>
<div
class=
"logo"
></div>
<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"
>
<ul
nz-menu
nzTheme=
"dark"
nzMode=
"inline"
>
<li
nz-menu-item
routerLink=
"/home"
>
<li
nz-menu-item
routerLink=
"/home"
routerLinkActive=
"tw-bg-gray-700"
>
Trang chủ
<span
nz-icon
nzType=
"home"
nzTheme=
"outline"
></span>
</li>
<span
class=
"tw-ml-2"
>
Trang chủ
</span>
<li
nz-menu-item
routerLink=
"/admin/job-management/Job"
>
Danh sách công việc
</li>
</li>
<li
nz-menu-item
(
click
)="
logout
()
"
>
<li
nz-menu-item
routerLink=
"/admin/job-management/Job"
routerLinkActive=
"tw-bg-gray-700
"
>
<span
nz-icon
nzType=
"logou
t"
nzTheme=
"outline"
></span>
<span
nz-icon
nzType=
"unordered-lis
t"
nzTheme=
"outline"
></span>
Đăng xuất
<span
class=
"tw-ml-2"
>
Danh sách công việc
</span>
</li>
</li>
</ul>
</ul>
</nz-sider>
</nz-sider>
<nz-layout>
<nz-content>
<nz-layout
class=
"tw-flex-1 tw-bg-gray-100"
>
<nz-content
>
<router-outlet></router-outlet>
<router-outlet></router-outlet>
</nz-content>
</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>
</nz-layout>
</nz-layout>
This diff is collapsed.
Click to expand it.
src/app/+admin/layout/feature/ui/layout.component.scss
View file @
5465e871
...
@@ -15,7 +15,9 @@
...
@@ -15,7 +15,9 @@
background
:
rgba
(
255
,
255
,
255
,
0
.2
);
background
:
rgba
(
255
,
255
,
255
,
0
.2
);
margin
:
16px
;
margin
:
16px
;
}
}
::ng-deep
.ant-drawer-body
{
padding
:
0
;
}
nz-header
{
nz-header
{
background
:
#fff
;
background
:
#fff
;
padding
:
0
;
padding
:
0
;
...
...
This diff is collapsed.
Click to expand it.
src/app/+admin/layout/feature/ui/layout.component.ts
View file @
5465e871
...
@@ -3,7 +3,6 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
...
@@ -3,7 +3,6 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import
{
NzLayoutModule
}
from
'ng-zorro-antd/layout'
;
import
{
NzLayoutModule
}
from
'ng-zorro-antd/layout'
;
import
{
CommonModule
,
DatePipe
}
from
'@angular/common'
;
import
{
CommonModule
,
DatePipe
}
from
'@angular/common'
;
import
{
HeaderComponent
}
from
'./Components/header/header.component'
;
import
{
FooterComponent
}
from
'./Components/footer/footer.component'
;
import
{
FooterComponent
}
from
'./Components/footer/footer.component'
;
import
{
NzButtonModule
}
from
'ng-zorro-antd/button'
;
import
{
NzButtonModule
}
from
'ng-zorro-antd/button'
;
import
{
NzBreadCrumbModule
}
from
'ng-zorro-antd/breadcrumb'
;
import
{
NzBreadCrumbModule
}
from
'ng-zorro-antd/breadcrumb'
;
...
@@ -20,20 +19,23 @@ import { AuthService } from '../../../../+login/data-access/Services/Auth.Servic
...
@@ -20,20 +19,23 @@ import { AuthService } from '../../../../+login/data-access/Services/Auth.Servic
RouterLink
,
RouterLink
,
CommonModule
,
CommonModule
,
RouterModule
,
RouterModule
,
HeaderComponent
,
FooterComponent
,
NzButtonModule
,
NzButtonModule
,
NzBreadCrumbModule
,
NzBreadCrumbModule
,
NzIconModule
,
NzLayoutModule
,
NzLayoutModule
,
NzMenuModule
,
NzMenuModule
,
NzToolTipModule
,
NzToolTipModule
,
NzIconModule
,
FooterComponent
],
],
styleUrls
:
[
'./layout.component.scss'
],
styleUrls
:
[
'./layout.component.scss'
],
templateUrl
:
'./layout.component.html'
,
templateUrl
:
'./layout.component.html'
,
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
})
})
export
class
AdminLayoutComponent
implements
OnInit
{
export
class
AdminLayoutComponent
implements
OnInit
{
isCollapsed
=
false
;
toggleSider
():
void
{
this
.
isCollapsed
=
!
this
.
isCollapsed
;
}
constructor
(
private
authentication
:
AuthService
)
{}
constructor
(
private
authentication
:
AuthService
)
{}
ngOnInit
():
void
{
ngOnInit
():
void
{
}
}
...
...
This diff is collapsed.
Click to expand it.
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>
This diff is collapsed.
Click to expand it.
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
}
}
This diff is collapsed.
Click to expand it.
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>
This diff is collapsed.
Click to expand it.
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
();
}
}
This diff is collapsed.
Click to expand it.
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>
This diff is collapsed.
Click to expand it.
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
);
}
}
This diff is collapsed.
Click to expand it.
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>
This diff is collapsed.
Click to expand it.
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
();
}
}
This diff is collapsed.
Click to expand it.
src/app/+home/data-access/service/Job.service.ts
View file @
5465e871
...
@@ -10,8 +10,13 @@ import { HttpClient } from "@angular/common/http";
...
@@ -10,8 +10,13 @@ import { HttpClient } from "@angular/common/http";
})
})
export
class
JobService
{
export
class
JobService
{
apiUrl
=
environment
.
API_DOMAIN
+
'/jobs'
;
apiUrl
=
environment
.
API_DOMAIN
+
'/jobs'
;
apiUrlById
=
environment
.
API_DOMAIN
+
'/jobById'
;
constructor
(
private
http
:
HttpClient
)
{}
constructor
(
private
http
:
HttpClient
)
{}
jobsGet
():
Observable
<
ResponseResult
<
Rows
<
Job
>>>
{
jobsGet
():
Observable
<
ResponseResult
<
Rows
<
Job
>>>
{
return
this
.
http
.
get
<
ResponseResult
<
Rows
<
Job
>>>
(
this
.
apiUrl
);
return
this
.
http
.
get
<
ResponseResult
<
Rows
<
Job
>>>
(
this
.
apiUrl
);
}
}
jobGetById
(
id
:
string
):
Observable
<
ResponseResult
<
Job
>>
{
return
this
.
http
.
get
<
ResponseResult
<
Job
>>
(
`
${
this
.
apiUrlById
}
/
${
id
}
`
);
}
}
}
This diff is collapsed.
Click to expand it.
src/app/+login/data-access/Services/Auth.Service.ts
View file @
5465e871
...
@@ -18,7 +18,6 @@ export class AuthService {
...
@@ -18,7 +18,6 @@ export class AuthService {
return
this
.
http
.
post
<
any
>
(
this
.
apiUrl
,
body
,
{
headers
}).
pipe
(
return
this
.
http
.
post
<
any
>
(
this
.
apiUrl
,
body
,
{
headers
}).
pipe
(
tap
((
response
)
=>
{
tap
((
response
)
=>
{
localStorage
.
setItem
(
'token'
,
response
.
responseData
.
token
);
localStorage
.
setItem
(
'token'
,
response
.
responseData
.
token
);
localStorage
.
setItem
(
'expirationTime'
,
response
.
responseData
.
expirationTime
);
localStorage
.
setItem
(
'role'
,
response
.
responseData
.
role
);
localStorage
.
setItem
(
'role'
,
response
.
responseData
.
role
);
})
})
);
);
...
@@ -26,7 +25,6 @@ export class AuthService {
...
@@ -26,7 +25,6 @@ export class AuthService {
logout
():
void
{
logout
():
void
{
localStorage
.
removeItem
(
'token'
);
localStorage
.
removeItem
(
'token'
);
localStorage
.
removeItem
(
'expirationTime'
);
localStorage
.
removeItem
(
'role'
);
localStorage
.
removeItem
(
'role'
);
this
.
router
.
navigate
([
'/login'
]);
this
.
router
.
navigate
([
'/login'
]);
}
}
...
...
This diff is collapsed.
Click to expand it.
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"
>
<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
()"
>
<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-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"
>
<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-input-group>
</nz-form-control>
</nz-form-control>
</nz-form-item>
</nz-form-item>
<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"
>
<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-input-group>
</nz-form-control>
</nz-form-control>
</nz-form-item>
</nz-form-item>
<p
*
ngIf=
"MgsError"
class=
"error-message tw-text-center"
>
{{MgsError}}
</p>
<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>
</form>
</div>
</div>
This diff is collapsed.
Click to expand it.
src/app/+login/feature/login.component.ts
View file @
5465e871
...
@@ -62,14 +62,11 @@ export class LoginComponent implements OnInit {
...
@@ -62,14 +62,11 @@ export class LoginComponent implements OnInit {
this
.
authService
.
login
(
this
.
loginForm
.
value
.
userName
,
this
.
loginForm
.
value
.
password
).
pipe
(
this
.
authService
.
login
(
this
.
loginForm
.
value
.
userName
,
this
.
loginForm
.
value
.
password
).
pipe
(
catchError
((
err
)
=>
{
catchError
((
err
)
=>
{
this
.
MgsError
=
err
.
message
;
this
.
MgsError
=
err
.
message
;
console
.
log
(
this
.
MgsError
);
console
.
log
(
err
);
return
of
(
null
);
return
of
(
null
);
}),
}),
finalize
(()
=>
{
finalize
(()
=>
{
if
(
this
.
authService
.
isLoggedIn
())
if
(
this
.
authService
.
isLoggedIn
()){
this
.
authService
.
loginSussces
();
this
.
authService
.
loginSussces
();}
console
.
log
(
'Login request completed'
);
})
})
).
subscribe
();
).
subscribe
();
}
}
...
...
This diff is collapsed.
Click to expand it.
src/app/+shell/feature/shell.routes.ts
View file @
5465e871
...
@@ -24,7 +24,13 @@ export const shellRoutes: Routes = [
...
@@ -24,7 +24,13 @@ export const shellRoutes: Routes = [
path
:
'ListJob'
,
path
:
'ListJob'
,
canActivate
:
[],
canActivate
:
[],
loadComponent
:
()
=>
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
),
},
},
],
],
...
...
This diff is collapsed.
Click to expand it.
src/app/+shell/ui/components/header/feature/header.component.html
View file @
5465e871
<header
class=
"tw-bg-gray-900 tw-py-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"
>
<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"
>
<div
class=
"tw-text-3xl tw-font-bold"
>
<a
href=
"/home"
class=
"hover:tw-text-gray-400"
>
MeU Solution
</a>
<a
href=
"/home"
class=
"hover:tw-text-gray-400"
>
MeU Solution
</a>
</div>
</div>
...
@@ -7,12 +7,13 @@
...
@@ -7,12 +7,13 @@
<nav
class=
"tw-bg-gray-900 tw-py-2"
>
<nav
class=
"tw-bg-gray-900 tw-py-2"
>
<div
class=
"tw-container tw-mx-auto"
>
<div
class=
"tw-container tw-mx-auto"
>
<ul
class=
"tw-flex tw-space-x-8 tw-justify-center"
>
<ul
class=
"tw-flex tw-space-x-8 tw-justify-center
md:tw-justify-end
"
>
<
li><a
href=
"/home"
class=
"tw-text-gray-300 hover:tw-text-white"
>
Trang chủ
</a></li
>
<
div
*
ngFor=
"let item of list"
>
<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=
"/{{item.href}}"
class=
"tw-text-gray-300 hover:tw-text-white"
>
{{item.title}}
</a></li>
<
li><a
href=
"/admin"
class=
"tw-text-gray-300 hover:tw-text-white"
>
Admin
</a></li
>
<
/div
>
<li><a
(
click
)="
logout
()"
class=
"tw-text-gray-300 hover:tw-text-white"
>
Đăng xuất
</a></li>
<li><a
(
click
)="
logout
()"
class=
"tw-text-gray-300 hover:tw-text-white"
>
Đăng xuất
</a></li>
</ul>
</ul>
</div>
</div>
</nav>
</nav>
</header>
</header>
This diff is collapsed.
Click to expand it.
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
...
@@ -10,6 +10,12 @@ import { AuthService } from '../../../../../+login/data-access/Services/Auth.Ser
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
})
})
export
class
HeaderComponent
implements
OnInit
{
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
{}
ngOnInit
():
void
{}
constructor
(
private
authentication
:
AuthService
)
{}
constructor
(
private
authentication
:
AuthService
)
{}
logout
()
{
logout
()
{
...
...
This diff is collapsed.
Click to expand it.
src/app/+shell/ui/layout.component.ts
View file @
5465e871
...
@@ -33,8 +33,10 @@ import { NzLayoutModule } from 'ng-zorro-antd/layout';
...
@@ -33,8 +33,10 @@ import { NzLayoutModule } from 'ng-zorro-antd/layout';
<nz-layout>
<nz-layout>
<meu-header></meu-header>
<meu-header></meu-header>
<div class="tw-relative tw-min-h-[92dvh]">
<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>
<router-outlet></router-outlet>
</div>
</div>
</div>
<meu-footer></meu-footer>
<meu-footer></meu-footer>
</nz-layout>
</nz-layout>
</div>
</div>
...
@@ -45,7 +47,7 @@ import { NzLayoutModule } from 'ng-zorro-antd/layout';
...
@@ -45,7 +47,7 @@ import { NzLayoutModule } from 'ng-zorro-antd/layout';
export
class
LayoutComponent
implements
OnInit
{
export
class
LayoutComponent
implements
OnInit
{
isSmallScreen
=
signal
(
false
);
isSmallScreen
=
signal
(
false
);
constructor
(
private
breakpointObserver
:
BreakpointObserver
)
{}
constructor
(
private
breakpointObserver
:
BreakpointObserver
)
{
}
ngOnInit
()
{
ngOnInit
()
{
this
.
breakpointObserver
.
observe
([
Breakpoints
.
Handset
]).
subscribe
((
res
)
=>
{
this
.
breakpointObserver
.
observe
([
Breakpoints
.
Handset
]).
subscribe
((
res
)
=>
{
this
.
isSmallScreen
.
set
(
res
.
matches
);
this
.
isSmallScreen
.
set
(
res
.
matches
);
...
...
This diff is collapsed.
Click to expand it.
src/app/app.component.ts
View file @
5465e871
...
@@ -12,3 +12,60 @@ import { RouterOutlet } from '@angular/router';
...
@@ -12,3 +12,60 @@ import { RouterOutlet } from '@angular/router';
export
class
AppComponent
{
export
class
AppComponent
{
title
=
'Meu-template-CSR'
;
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;
// }
This diff is collapsed.
Click to expand it.
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