Skip to content

Commit

Permalink
Merge pull request #110 from ablej-ssafy/feature/58-portfolio
Browse files Browse the repository at this point in the history
[#58]feat: 이력서 업로드 버튼 추가
  • Loading branch information
BHyeonKim authored Nov 17, 2024
2 parents febf6d0 + 46d79ed commit acb802f
Show file tree
Hide file tree
Showing 26 changed files with 732 additions and 158 deletions.
27 changes: 27 additions & 0 deletions src/actions/resume/changeResumeOrderAction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use server';

import {revalidatePath} from 'next/cache';
import {cookies} from 'next/headers';
import {redirect} from 'next/navigation';

import ableJ from '@/services/ableJ';
import {ChangeResumeOrderForm} from '@/types/ableJ';

const changeResumeOrderAction = async (data: ChangeResumeOrderForm) => {
const cookieStore = cookies();
const accessToken = cookieStore.get('accessToken')?.value;

if (!accessToken) {
redirect('/signin');
}

const {success} = await ableJ.changeResumeOrder(data, accessToken);

if (!success) {
console.error('포트폴리오 순서를 업데이트하는데 실패했습니다.');
}

revalidatePath('/portfolio');
};

export default changeResumeOrderAction;
27 changes: 27 additions & 0 deletions src/actions/resume/changeToAiParsedResumeAction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use server';
import {revalidatePath} from 'next/cache';
import {cookies} from 'next/headers';
import {redirect, RedirectType} from 'next/navigation';

import ableJ from '@/services/ableJ';

const changeToAiParsedResumeAction = async () => {
const cookieStore = cookies();
const accessToken = cookieStore.get('accessToken')?.value;

if (!accessToken) {
redirect('/signin');
}

const {success} = await ableJ.changeToAiParsedResume(accessToken);

if (!success) {
console.error('AI 포트폴리오로 교체하는데 실패했습니다');
return;
}

revalidatePath('/portfolio');
redirect('/portfolio', RedirectType.replace);
};

export default changeToAiParsedResumeAction;
20 changes: 20 additions & 0 deletions src/actions/resume/toggleResumeVisibilityAction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use server';

import {cookies} from 'next/headers';
import {redirect} from 'next/navigation';

import ableJ from '@/services/ableJ';

const toggleResumeVisibilityAction = async (isPrivate: boolean) => {
const accessToken = cookies().get('accessToken')?.value;

if (!accessToken) {
console.log('Access Token이 없습니다.');
redirect('/(.)signin');
}

const request = isPrivate ? ableJ.hideResume : ableJ.revealResume;
await request(accessToken as string);
};

export default toggleResumeVisibilityAction;
69 changes: 61 additions & 8 deletions src/app/(header)/portfolio/(view)/layout.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,54 @@

.sidebar {
position: fixed;
display: flex;
flex-direction: column;
grid-column: 3;
padding-top: 2.5rem;
align-items: center;
margin-top: 2.5rem;

.button-container {
padding: 2rem 1rem;
background-color: colors.$white;
border-radius: layout.$border_button;

.toggle-button {
display: flex;
align-items: center;
align-self: stretch;
justify-content: space-between;
padding: 0 20px;
font-size: 1.5rem;
font-weight: 500;
}

&:not(:first-child) {
margin-top: 10px;
background-color: transparent;
}
}

.template-button {
display: flex;
align-items: center;
justify-content: center;
width: 23rem;
height: 38px;
font-size: 1.4rem;
color: colors.$primary;
cursor: pointer;
background-color: colors.$white;
border: 1px solid colors.$primary;
border-radius: 4px;

&:not(:first-child) {
margin-top: 10px;
}

& input {
display: none;
}
}
}

.main {
Expand All @@ -27,15 +73,22 @@
&.active {
background-color: #efeef3;
}
}

&.loading::after {
@include loader.loader-animation;
.loading {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
backdrop-filter: blur(4px);

position: fixed;
top: 50%;
left: 50%;
content: '';
transform: translate(-50%, -50%);
.loading-description {
position: absolute;
font-size: 1.6rem;
color: colors.$gray4;
transform: translateY(calc(50% - 130px));
}
}
}
56 changes: 53 additions & 3 deletions src/app/(header)/portfolio/(view)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
import classNames from 'classnames/bind';
import {getCookie} from 'cookies-next';
import {useRouter} from 'next/navigation';
import {DragEvent, PropsWithChildren, useState} from 'react';
import {ChangeEvent, DragEvent, PropsWithChildren, useState} from 'react';
import toast from 'react-hot-toast';

import toggleResumeVisibilityAction from '@/actions/resume/toggleResumeVisibilityAction';
import LoadingSpinner from '@/components/common/LoadingSpinner';
import ToggleButton from '@/components/common/ToggleButton';
import DragAndDropMenu from '@/features/portfolio/components/DragAndDropMenu';
import useResumeInfo from '@/hooks/useResumeInfo';
import ableJ from '@/services/ableJ';

import styles from './layout.module.scss';
Expand All @@ -15,6 +19,7 @@ const cx = classNames.bind(styles);

const PortfolioLayout = ({children}: PropsWithChildren) => {
const router = useRouter();
const {resumeInfo, fetchResumeInfo} = useResumeInfo();
const [isActive, setIsActive] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const accessToken = getCookie('accessToken');
Expand Down Expand Up @@ -51,10 +56,27 @@ const PortfolioLayout = ({children}: PropsWithChildren) => {
router.push('/portfolio/auto');
};

const handleFileChange = async (event: ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (!file || file.type !== 'application/pdf') {
toast.error('PDF 파일만 업로드 가능합니다.');
return;
}
setIsLoading(true);
await ableJ.uploadResume(file, accessToken as string);
setIsLoading(false);
router.push('/portfolio/auto');
};

const handleVisibility = async () => {
await toggleResumeVisibilityAction(resumeInfo!.private);
await fetchResumeInfo();
};

return (
<div className={cx('container')}>
<main
className={cx('main', {active: isActive}, {loading: isLoading})}
className={cx('main', {active: isActive})}
onDragEnter={handleDragEnter}
onDragLeave={handleDragLeave}
onDragOver={handleDragOver}
Expand All @@ -63,8 +85,36 @@ const PortfolioLayout = ({children}: PropsWithChildren) => {
{children}
</main>
<aside className={cx('sidebar')}>
<DragAndDropMenu />
<div className={cx('button-container')}>
<div className={cx('toggle-button')}>
공개
<ToggleButton
onToggle={handleVisibility}
isToggled={!!resumeInfo?.private}
/>
</div>
<DragAndDropMenu />
</div>
<div className={cx('button-container')}>
<label className={cx('template-button')}>
이력서 업로드
<input
type="file"
accept="application/pdf"
onChange={handleFileChange}
/>
</label>
<button className={cx('template-button')}>템플릿 선택</button>
</div>
</aside>
{isLoading && (
<div className={cx('loading')}>
<p className={cx('loading-description')}>
이력서 데이터를 AI가 읽고 있습니다
</p>
<LoadingSpinner />
</div>
)}
</div>
);
};
Expand Down
5 changes: 2 additions & 3 deletions src/app/(header)/portfolio/auto/page.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,14 @@

.info {
position: fixed;
top: 100px;
left: 50%;
right: 20px;
bottom: 20px;
z-index: 1;
flex-direction: column;
gap: 16px;
padding: 24px 32px;
background-color: rgb(255 255 255 / 85%);
border-radius: 8px;
transform: translateX(-50%);

@include mixin.flex-default;

Expand Down
Loading

0 comments on commit acb802f

Please sign in to comment.