Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions src/entities/job-post-resume-relation/api/get-job-post-resume.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use server'

import { getTeacherSession } from 'entities/auth'
import { getBusinessSession, getTeacherSession } from 'entities/auth'
import { apiClient, Pagination, PaginationParams } from 'shared/api'

import { JobPostRelation } from '../model/application'
Expand All @@ -12,7 +12,7 @@ export type GetJobPostResumeRequest = PaginationParams<{

type GetJobPostResumeResponse = Pagination<JobPostRelation>

export const getJobPostResumeRelations = async (
export const getTeacherJobPostResumeRelations = async (
queryParams: GetJobPostResumeRequest,
) => {
const { accessToken } = await getTeacherSession()
Expand All @@ -27,3 +27,19 @@ export const getJobPostResumeRelations = async (

return response
}

export const getBusinessJobPostResumeRelations = async (
queryParams: GetJobPostResumeRequest,
) => {
const { accessToken } = await getBusinessSession()

const response = await apiClient.get<GetJobPostResumeResponse>({
endpoint: '/job-post-resume-relations',
queryParams,
option: {
authorization: `Bearer ${accessToken}`,
},
})

return response
}
10 changes: 8 additions & 2 deletions src/entities/job-post-resume-relation/api/query.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { queryOptions } from '@tanstack/react-query'

import {
getJobPostResumeRelations,
getBusinessJobPostResumeRelations,
getTeacherJobPostResumeRelations,
GetJobPostResumeRequest,
} from './get-job-post-resume'

Expand All @@ -11,6 +12,11 @@ export const jobPostResumeRelationQueries = {
list: (params: GetJobPostResumeRequest) =>
queryOptions({
queryKey: [...jobPostResumeRelationQueries.lists(), params],
queryFn: () => getJobPostResumeRelations(params),
queryFn: () => getTeacherJobPostResumeRelations(params),
}),
businessList: (params: GetJobPostResumeRequest) =>
queryOptions({
queryKey: [...jobPostResumeRelationQueries.lists(), params],
queryFn: () => getBusinessJobPostResumeRelations(params),
}),
}
2 changes: 1 addition & 1 deletion src/entities/job-post-resume-relation/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export { getJobPostResumeSummary } from './api/get-job-post-resume-summary'
export { getJobPostResumeByCode } from './api/get-job-post-resume-by-code'
export { jobPostResumeRelationQueries } from './api/query'
export type { ApplicationStatus, StatusSummary } from './model/status'
export { ApplicationStatus, type StatusSummary } from './model/status'
export type { JobPostRelationDetail } from './model/application'
export { HistoryPanel } from './ui/history-panel'
export { StatusPanel } from './ui/status-panel'
Expand Down
1 change: 1 addition & 0 deletions src/entities/job-post-resume-relation/model/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export type JobPostRelation = {
jobPostTitle: string
academyId: number
academyName: string
academyMemo: string | null
}

export type JobPostRelationDetail = {
Expand Down
28 changes: 28 additions & 0 deletions src/pages/applicant-management/api/use-job-post-relations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { keepPreviousData, useQuery } from '@tanstack/react-query'

import {
ApplicationStatus,
jobPostResumeRelationQueries,
} from 'entities/job-post-resume-relation'

export const useJobPostRelations = ({
status,
pageNumber,
}: {
status: ApplicationStatus
pageNumber: number
}) => {
const { data } = useQuery({
...jobPostResumeRelationQueries.businessList({
pageNumber,
rowCount: 10,
status,
}),
placeholderData: keepPreviousData,
})

return {
applications: data?.content ?? [],
totalPages: data?.totalPages === 0 ? 1 : data?.totalPages,
}
}
143 changes: 91 additions & 52 deletions src/pages/applicant-management/ui/applicant-management-list-page.tsx
Original file line number Diff line number Diff line change
@@ -1,83 +1,122 @@
'use client'

import { useRouter } from 'next/navigation'
import { useTranslations } from 'next-intl'
import { useState } from 'react'

import { ApplicationStatus } from 'entities/job-post-resume-relation'
import { cn } from 'shared/lib'
import { Layout, Tabs, Table, Pagination } from 'shared/ui'

const relations = [
{
id: 1,
firstName: '길동',
lastName: '홍',
jobPostTitle: '웹 프론트엔드 개발자',
memo: '메모',
submittedDate: '2024-01-01',
},
{
id: 2,
firstName: '길동',
lastName: '홍',
jobPostTitle: '웹 프론트엔드 개발자',
memo: '메모',
submittedDate: '2024-01-01',
},
]
import { useJobPostRelations } from '../api/use-job-post-relations'

export const ApplicantManagementListPage = () => {
const t = useTranslations('applicant-management-list')

const router = useRouter()

const [currentPage, setCurrentPage] = useState(0)
const [status, setStatus] = useState<ApplicationStatus>(
ApplicationStatus.SUBMITTED,
)

const { applications, totalPages } = useJobPostRelations({
status,
pageNumber: currentPage,
})

const hasNoApplications = applications.length === 0

const handlePageChange = ({ selected }: { selected: number }) => {
setCurrentPage(selected)
// API 호출 등 페이지 변경 로직
}

const handleStatusChange = (value: string) => {
setStatus(value as ApplicationStatus)
}

const handleItemClick = (id: number) => () => {
router.push(`/business/applicant-management/${id}`)
}

return (
<Layout wide>
<h1 className="display-small mb-10 text-center font-bold text-gray-900">
{t('title')}
</h1>
<Tabs.Root defaultValue="SUBMITTED" className="w-[480px]">
<Tabs.List size="small" width="full" variant="box" className="mb-4">
<Tabs.Root
defaultValue="SUBMITTED"
className="w-full"
onValueChange={handleStatusChange}
>
<Tabs.List
size="small"
width="full"
variant="box"
className="mb-4 w-[480px]"
>
<Tabs.Trigger value="SUBMITTED">{t('tabs.submitted')}</Tabs.Trigger>
<Tabs.Trigger value="REVIEWED">{t('tabs.reviewed')}</Tabs.Trigger>
<Tabs.Trigger value="ACCEPTED">{t('tabs.accepted')}</Tabs.Trigger>
<Tabs.Trigger value="REJECTED">{t('tabs.rejected')}</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value={status} className="w-full">
<div className="mb-10 h-[584px]">
<Table.Root className="w-full">
<Table.Header>
<Table.Row className={cn(hasNoApplications && 'border-none')}>
<Table.Head className="w-[240px]">
{t('table.applicant')}
</Table.Head>
<Table.Head className="w-[380px]">
{t('table.job-title')}
</Table.Head>
<Table.Head className="w-[300px]">
{t('table.memo')}
</Table.Head>
<Table.Head className="w-[140px]">
{t('table.application-date')}
</Table.Head>
</Table.Row>
</Table.Header>
{(() => {
if (hasNoApplications) {
return null
}

return (
<Table.Body>
{applications.map(application => (
<Table.Row
key={application.id}
onClick={handleItemClick(application.id)}
className="cursor-pointer"
>
<Table.Cell>
{application.resumeFirstName}{' '}
{application.resumeLastName}
</Table.Cell>
<Table.Cell>{application.jobPostTitle}</Table.Cell>
<Table.Cell>
{application?.academyMemo ?? ''}
</Table.Cell>
<Table.Cell>{application.submittedDate}</Table.Cell>
</Table.Row>
))}
</Table.Body>
)
})()}
</Table.Root>
{hasNoApplications && (
<p className="title-large mt-20 text-center font-medium text-gray-700">
{t('table.no-data')}
</p>
)}
</div>
</Tabs.Content>
</Tabs.Root>
<div className="mb-10 h-[584px]">
<Table.Root className="w-full">
<Table.Header>
<Table.Row>
<Table.Head className="w-[240px]">
{t('table.applicant')}
</Table.Head>
<Table.Head className="w-[380px]">
{t('table.job-title')}
</Table.Head>
<Table.Head className="w-[300px]">{t('table.memo')}</Table.Head>
<Table.Head className="w-[140px]">
{t('table.application-date')}
</Table.Head>
</Table.Row>
</Table.Header>
<Table.Body>
{relations.map(relation => (
<Table.Row key={relation.id}>
<Table.Cell>
{relation.firstName} {relation.lastName}
</Table.Cell>
<Table.Cell>{relation.jobPostTitle}</Table.Cell>
<Table.Cell>{relation.memo}</Table.Cell>
<Table.Cell>{relation.submittedDate}</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table.Root>
</div>
<Pagination
pageCount={10}
pageCount={totalPages}
currentPage={currentPage}
onPageChange={handlePageChange}
/>
Expand Down
2 changes: 2 additions & 0 deletions src/shared/api/pagination.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ type Pageable = {
}

export type Pagination<Content> = {
totalPages: number
totalElements: number
size: number
content: Content[]
number: number
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"applicant": "Applicant",
"job-title": "Job Title",
"memo": "Memo",
"application-date": "Application Date"
"application-date": "Application Date",
"no-data": "No applications have been received yet"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"applicant": "지원자",
"job-title": "공고 제목",
"memo": "메모",
"application-date": "지원 일자"
"application-date": "지원 일자",
"no-data": "아직 접수된 지원자가 없습니다"
}
}
}
6 changes: 3 additions & 3 deletions src/shared/ui/pagination/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import { cn } from 'shared/lib'
import { Icon } from '../icon'

interface PaginationProps {
pageCount: number
pageCount?: number
currentPage: number
onPageChange: (selectedItem: { selected: number }) => void
className?: string
}

export const Pagination = ({
pageCount,
pageCount = 1,
currentPage,
onPageChange,
className,
Expand All @@ -32,7 +32,7 @@ export const Pagination = ({
'body-large flex h-8 w-8 items-center justify-center rounded-md font-bold text-gray-900 transition-colors',
'hover:bg-gray-100',
)}
activeLinkClassName={cn('bg-blue-800 text-white', 'hover:bg-blue-700')}
activeLinkClassName={cn('bg-blue-800 text-white', 'hover:!bg-blue-700')}
previousLinkClassName={cn(
'flex h-8 w-8 items-center justify-center rounded-md text-gray-700',
'hover:bg-gray-100',
Expand Down
Loading