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
10 changes: 10 additions & 0 deletions app/(business)/business/academy-detail/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { getAcademyMe } from 'entities/academy'
import { AcademyDetailPage } from 'pages/academy-detail'

const Page = async () => {
const academyDetail = await getAcademyMe()

return <AcademyDetailPage academyDetail={academyDetail} />
}

export default Page
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { JobPostApplicantManagementDetailPage as default } from 'pages/business-job-posting'
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { isAfter, parseISO } from 'date-fns'

import { getJobPost } from 'entities/job-post'
import { JobPostApplicantManagementListPage } from 'pages/business-job-posting'

type Params = {
jobPostId: string
}

const Page = async ({ params }: { params: Promise<Params> }) => {
const { jobPostId } = await params

const jobPost = await getJobPost({ jobPostId: Number(jobPostId) })

const isExpired = jobPost.dueDate
? isAfter(new Date(), parseISO(jobPost.dueDate))
: false

return (
<JobPostApplicantManagementListPage
title={jobPost.title}
jobPostId={Number(jobPostId)}
isExpired={isExpired}
/>
)
}

export default Page
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { getJobPost } from 'entities/job-post'
import { UpdateJobPostingDraftPage } from 'pages/business-job-posting'

type Params = {
jobPostId: string
}

const Page = async ({ params }: { params: Promise<Params> }) => {
const { jobPostId } = await params

const jobPost = await getJobPost({ jobPostId: Number(jobPostId) })

return (
<UpdateJobPostingDraftPage
jobPostId={Number(jobPostId)}
jobPostDetail={jobPost}
/>
)
}

export default Page

This file was deleted.

21 changes: 21 additions & 0 deletions app/(business)/business/job-posting/[jobPostId]/update/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { getJobPost } from 'entities/job-post'
import { UpdateJobPostingPage } from 'pages/business-job-posting'

type Params = {
jobPostId: string
}

const Page = async ({ params }: { params: Promise<Params> }) => {
const { jobPostId } = await params

const jobPost = await getJobPost({ jobPostId: Number(jobPostId) })

return (
<UpdateJobPostingPage
jobPostId={Number(jobPostId)}
jobPostDetail={jobPost}
/>
)
}

export default Page
69 changes: 42 additions & 27 deletions app/(business)/business/page.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,51 @@
import { colors } from 'shared/config'
import { Icon } from 'shared/ui'
import { getNullableBusinessSession } from 'entities/auth'
import { Button, Image } from 'shared/ui'
import { Layout } from 'shared/ui'

export default function BusinessPage() {
const BusinessPage = async () => {
const session = await getNullableBusinessSession()

const link = session ? '/business/job-posting/create' : '/business/sign-up'

return (
<Layout wide>
<div className="flex h-full flex-col items-center justify-center gap-8">
<Icon
name="ExclamationMark"
size="custom"
className="h-[150px] w-[150px]"
color={colors.blue[800]}
/>
<h2 className="display-medium font-medium text-gray-900">
현재{' '}
<mark className="bg-transparent font-bold text-blue-800">
페이지 준비중
</mark>
입니다.
</h2>
<div className="flex flex-col items-center gap-1">
<p className="title-medium text-gray-600">
이용에 불편을 드려 죄송합니다.
</p>
<p className="title-medium text-gray-600">
보다 나은 서비스 제공을 위하여 페이지 준비중에 있습니다.
</p>
<p className="title-medium text-gray-600">
빠른 시일 내에 준비하여 찾아뵙겠습니다.
</p>
<div
className="flex h-full max-h-[900px] min-h-[667px] flex-col items-center justify-between rounded-3xl"
style={{
background: 'linear-gradient(180deg, #FFFFFF 0%, #D9E8FF 100%)',
}}
>
<div className="flex w-full flex-col items-center">
<h2 className="display-large mt-10 text-center font-bold text-gray-900">
강사를 손쉽게 관리하고,
<br />
빠르게 채용하세요
</h2>
<div className="mt-6 w-fit text-center">
<p className="title-small font-normal text-gray-700">
학원에 맞는 원어민 강사를 찾고 계신가요?
</p>
<p className="title-small font-normal text-gray-700">
지금, Plus82와 시작하세요.
</p>
</div>
<Button as="a" href={link} size="large" className="mt-6 w-fit">
무료로 가입하기
</Button>
</div>

<Image
src="/images/business-banner.png"
useCDN={false}
alt="business-page-image"
fill={false}
width={700}
height={386}
className="border-none"
/>
</div>
</Layout>
)
}

export default BusinessPage
19 changes: 19 additions & 0 deletions app/(business)/business/setting/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Layout } from 'shared/ui'
import {
SettingSidebar,
SettingSidebarProvider,
businessItems,
} from 'widgets/sidebar'

const PageLayout = ({ children }: { children: React.ReactNode }) => {
return (
<Layout wide className="relative my-0 flex">
<SettingSidebarProvider>
<SettingSidebar items={businessItems} />
{children}
</SettingSidebarProvider>
</Layout>
)
}

export default PageLayout
1 change: 1 addition & 0 deletions app/(business)/business/setting/my-academy/page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { MyAcademyPage as default } from 'pages/my-academy'
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { ChangePasswordPage as default } from 'pages/my-academy'
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { getBusinessUserMe } from 'entities/user'
import { PersonalInformationPage } from 'pages/my-academy'

const Page = async () => {
const user = await getBusinessUserMe()

return <PersonalInformationPage user={user} />
}

export default Page
5 changes: 5 additions & 0 deletions app/(business)/business/setting/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { redirect } from 'next/navigation'

export default function SettingPage() {
redirect('/business/setting/my-academy')
}
4 changes: 3 additions & 1 deletion app/(user)/job-board/[jobPostId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ type Params = {
jobPostId: string
}

export const JobPostingDetailPage = async ({
const JobPostingDetailPage = async ({
params,
}: {
params: Promise<Params>
Expand Down Expand Up @@ -37,3 +37,5 @@ export const JobPostingDetailPage = async ({
/>
)
}

export default JobPostingDetailPage
4 changes: 2 additions & 2 deletions app/(user)/setting/(with-layout)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Layout } from 'shared/ui'
import { SettingSidebar, SettingSidebarProvider } from 'widgets/sidebar'
import { SettingSidebar, SettingSidebarProvider, items } from 'widgets/sidebar'

const PageLayout = ({ children }: { children: React.ReactNode }) => {
return (
<Layout wide className="relative my-0 flex">
<SettingSidebarProvider>
<SettingSidebar />
<SettingSidebar items={items} />
{children}
</SettingSidebarProvider>
</Layout>
Expand Down
Binary file added public/images/business-banner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions src/entities/academy/api/get-academy-me.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use server'

import { getBusinessSession } from 'entities/auth'
import { apiClient } from 'shared/api'

import { AcademyDetail } from '../model/academy-detail'

type GetAcademyMeResponse = AcademyDetail

export const getAcademyMe = async () => {
const { accessToken } = await getBusinessSession()

const response = await apiClient.get<GetAcademyMeResponse>({
endpoint: `/academies/me`,
option: {
authorization: `Bearer ${accessToken}`,
tags: ['academy-me'],
},
})

return response
}
12 changes: 12 additions & 0 deletions src/entities/academy/api/query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { queryOptions } from '@tanstack/react-query'

import { getAcademyMe } from './get-academy-me'

export const academyQueries = {
all: () => ['academy'],
me: () =>
queryOptions({
queryKey: [...academyQueries.all(), 'me'],
queryFn: () => getAcademyMe(),
}),
}
48 changes: 48 additions & 0 deletions src/entities/academy/api/update-academy-me.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
'use server'

import { revalidateTag } from 'next/cache'

import { getBusinessSession } from 'entities/auth'
import {
apiClient,
HttpError,
errorHandler,
ServerError,
ContentType,
} from 'shared/api'

import { UpdateAcademyDetail } from '../model/academy-detail'

const handleSuccess = () => {
revalidateTag('academy-me')
}

const handleError = (error: Error): ServerError => {
const isHttpError = error instanceof HttpError
if (!isHttpError) throw error

return errorHandler.toast('업데이트에 실패했어요', {
error,
})
}

export const updateAcademyMe = async (
updateAcademyDetail: UpdateAcademyDetail,
) => {
const { accessToken } = await getBusinessSession()

try {
await apiClient.put<null>({
endpoint: `/academies/me`,
option: {
contentType: ContentType.MULTIPART,
authorization: `Bearer ${accessToken}`,
},
body: updateAcademyDetail,
})

handleSuccess()
} catch (error) {
return handleError(error as Error)
}
}
8 changes: 7 additions & 1 deletion src/entities/academy/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
export { type AcademyDetail } from './model/academy-detail'
export {
type AcademyDetail,
type UpdateAcademyDetail,
} from './model/academy-detail'
export { academyQueries } from './api/query'
export { updateAcademyMe } from './api/update-academy-me'
export { getAcademyMe } from './api/get-academy-me'
7 changes: 7 additions & 0 deletions src/entities/academy/model/academy-detail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,10 @@ export type AcademyDetail = {
forAdult: boolean
imageUrls: string[]
}

export type UpdateAcademyDetail = Omit<
AcademyDetail,
'id' | 'imageUrls' | 'businessRegistrationNumber'
> & {
images: File[]
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ApplicationStatus } from '../model/status'

export type GetJobPostResumeRequest = PaginationParams<{
status?: ApplicationStatus
jobPostId?: number
}>

type GetJobPostResumeResponse = Pagination<JobPostRelation>
Expand Down
39 changes: 39 additions & 0 deletions src/entities/job-post/api/create-job-post-draft.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use server'

import { revalidateTag } from 'next/cache'

import { getBusinessSession } from 'entities/auth'
import { apiClient, errorHandler, HttpError } from 'shared/api'

import { CreateJobPost } from '../model/create-job-post'

const handleSuccess = () => {
revalidateTag('business-job-posts')
}

const handleError = (error: Error) => {
const isHttpError = error instanceof HttpError
if (!isHttpError) throw error

return errorHandler.toast('An error occurred while creating job post draft', {
error,
})
}

export const createJobPostDraft = async (jobPost: CreateJobPost) => {
const { accessToken } = await getBusinessSession()

try {
await apiClient.post<null, CreateJobPost>({
endpoint: '/job-posts/draft',
option: {
authorization: `Bearer ${accessToken}`,
},
body: jobPost,
})

handleSuccess()
} catch (error) {
return handleError(error as Error)
}
}
Loading