Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
7167dcf
refactor(graduate): 홈페이지 lazy loading 적용
yummjin Dec 30, 2025
ff22d9c
refactor(graduate): 홈 페이지 lazy loading 적용
yummjin Jan 13, 2026
e4e870d
refactor(graduate): 홈화면 텍스트 변경
yummjin Jan 13, 2026
ab4f387
feat(graduate): 상수 변경, 홈 페이지 텍스트 구조 변경
yummjin Jan 13, 2026
e0433e0
feat(graduate): 홈 페이지 컴포넌트 분리 및 유틸 함수 추가
yummjin Jan 13, 2026
4b207c5
refactor(graduate): pdf.worker.min.js 파일 포매팅
yummjin Jan 13, 2026
cf36d4c
feat(graduate): 자격증 제출 페이지 UI 소폭 변경 및 API 연동, 컴포넌트 분리
yummjin Jan 13, 2026
d5975cc
style(graduate): 내 상태 페이지 padding 조절
yummjin Jan 13, 2026
30d974a
feat(graduate): 논문 제출 페이지 API 연동 및 컴포넌트화
yummjin Jan 13, 2026
bc8e12e
style(graduate): 홈 UI 간격 소폭 변경
yummjin Jan 13, 2026
7478971
style(graduate): 졸업 상태 지정 페이지 간격 소폭 변경
yummjin Jan 13, 2026
7a85238
feat(graduate): apply-confirm 페이지 추가
yummjin Jan 21, 2026
72bd158
feat(graduate): apply-confirm 페이지 연결
yummjin Jan 21, 2026
50c4a8f
feat(graduate): apply-confirm 페이지 api 연동
yummjin Jan 21, 2026
b988e22
feat(graduate): 공지 페이지 레이아웃
yummjin Jan 21, 2026
31b9e45
feat(graduate): 공지 테이블 구현
yummjin Jan 21, 2026
9945b21
feat(graduate): 공지 상세 조회 페이지 추가
yummjin Jan 21, 2026
a8646bf
refactor(graduate): 사용하지 않는 컴포넌트 가져오기 제거
yummjin Jan 21, 2026
e4fb431
feat(graduate): table row 선택시 상세 페이지로 이동
yummjin Jan 21, 2026
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
61,682 changes: 61,681 additions & 1 deletion apps/graduate/public/pdf.worker.min.js

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions apps/graduate/src/pages/client/apply/api/submitConfirmEmail.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useMutation } from '@tanstack/react-query';

import { patch } from '~/shared/api';
import { END_POINT } from '~/shared/constants';

const submitConfirmEmail = async (email: string) => {
const response = await patch({
request: END_POINT.USER.CONFIRM_EMAIL,
data: { email },
});
return response.data;
};

export const useSubmitConfirmEmail = () => {
return useMutation({
mutationFn: submitConfirmEmail,
});
};
105 changes: 105 additions & 0 deletions apps/graduate/src/pages/client/apply/styles/ApplyConfirmPage.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { style } from '@vanilla-extract/css';

import { vars } from '~/vars.css';

export const container = style({
display: 'grid',
placeItems: 'center',
width: '100%',
maxWidth: '768px',
margin: 'auto',
gap: vars.spacing.xl,
paddingRight: vars.spacing.lg,
paddingLeft: vars.spacing.lg,
boxSizing: 'border-box',
});

export const wrapper = style({
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
});

export const iconWrapper = style({
width: '80px',
height: '80px',
backgroundColor: '#E6F0FF',
borderRadius: '50%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: '#006AE4',
marginBottom: '24px',
});

export const title = style({
fontSize: '24px',
fontVariationSettings: `'wght' ${vars.font.weight.semibold}`,
color: '#111827',
marginBottom: '12px',
letterSpacing: '-0.02em',
});

export const description = style({
fontSize: '16px',
color: '#6B7280',
lineHeight: '1.6',
marginBottom: '32px',
});

export const inputSection = style({
width: '100%',
display: 'flex',
flexDirection: 'column',
gap: '8px',
marginBottom: '32px',
textAlign: 'left',
});

export const label = style({
fontSize: '14px',
fontWeight: 600,
color: '#374151',
marginLeft: '4px',
});

export const input = style({
width: '100%',
height: '52px',
padding: '0 16px',
borderRadius: '12px',
border: '1px solid #E5E7EB',
fontSize: '15px',
backgroundColor: '#F9FAFB',
transition: 'all 0.2s ease',
boxSizing: 'border-box',

':focus': {
outline: 'none',
borderColor: '#006AE4',
backgroundColor: '#FFFFFF',
},
});

export const button = style({
width: '100%',
height: '56px',
backgroundColor: '#006AE4',
color: '#FFFFFF',
borderRadius: '16px',
fontSize: '16px',
fontWeight: 700,
border: 'none',
cursor: 'pointer',
transition: 'all 0.2s ease',

':hover': {
backgroundColor: '#0054B3',
transform: 'translateY(-2px)',
boxShadow: '0 6px 20px rgba(0, 106, 228, 0.3)',
},
':active': {
transform: 'translateY(0)',
},
});
50 changes: 35 additions & 15 deletions apps/graduate/src/pages/client/apply/styles/ApplyPage.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,64 @@ import { style } from '@vanilla-extract/css';
import { vars } from '~/vars.css';

export const container = style({
display: 'grid',
placeItems: 'center',
display: 'flex',
flexDirection: 'column',
width: '100%',
maxWidth: '768px',
margin: 'auto',
maxWidth: '800px',
margin: '0 auto',
gap: vars.spacing.xl,
padding: vars.spacing.xl,
backgroundColor: vars.colors.white,
borderRadius: vars.radius.xl,
boxShadow: '0 4px 24px rgba(0, 0, 0, 0.06)',
border: `1px solid ${vars.colors.subHover}`,
boxSizing: 'border-box',
});

export const button = style({
width: '100%',
padding: vars.spacing.lg,
height: '56px',
borderRadius: vars.radius.lg,
fontSize: vars.font.size.lg,
fontWeight: 700,
marginTop: vars.spacing.lg,
});

export const optionButton = style({
width: '100%',
padding: vars.spacing.lg,
height: '100px',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
borderRadius: vars.radius.lg,
backgroundColor: vars.colors.white,
border: `1px solid ${vars.colors.border}`,
border: `1px solid ${vars.colors.subHover}`,
color: vars.colors.subDark,
fontVariationSettings: `'wght' ${vars.font.weight.medium}`,
transition: 'all 0.2s ease',
fontWeight: 500,
cursor: 'pointer',
':hover': {
backgroundColor: vars.colors.sub,
transform: 'translateY(-2px)',
},
});

export const activeOptionButton = style({
width: '100%',
padding: vars.spacing.lg,
height: '100px',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
borderRadius: vars.radius.lg,
backgroundColor: vars.colors.mainXLight,
border: `1px solid ${vars.colors.main}`,
color: vars.colors.subText,
fontVariationSettings: `'wght' ${vars.font.weight.medium}`,
':hover': {
backgroundColor: vars.colors.sub,
},
border: `2px solid ${vars.colors.main}`,
color: vars.colors.main,
transition: 'all 0.2s ease',
fontWeight: 700,
boxShadow: '0 4px 12px rgba(0, 106, 228, 0.1)',
cursor: 'pointer',
});

export const drawer = style({
Expand Down
78 changes: 78 additions & 0 deletions apps/graduate/src/pages/client/apply/ui/ApplyConfirmPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { useNavigate } from '@tanstack/react-router';
import { message } from 'antd';
import { Check } from 'lucide-react';
import { useState } from 'react';

import { ROUTE } from '~/shared/constants';

import { useSubmitConfirmEmail } from '../api/submitConfirmEmail';
import * as styles from '../styles/ApplyConfirmPage.css';

export default function ApplyConfirmPage() {
const navigate = useNavigate();
const [email, setEmail] = useState('');
const { mutate: submitConfirmEmail, isPending: isSubmitting } =
useSubmitConfirmEmail();

const handleComplete = () => {
if (email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
message.error('올바른 이메일 형식을 입력해주세요.');
return;
}

if (email) {
submitConfirmEmail(email, {
onSuccess: () => {
message.success(`${email}로 알림 설정을 완료했습니다.`);
navigate({ to: ROUTE.HOME });
},
onError: () => {
message.error('이메일 등록에 실패했습니다. 다시 시도해주세요.');
},
});
} else {
message.success('신청이 완료되었습니다.');
navigate({ to: ROUTE.HOME });
}
};

return (
<div className={styles.container}>
<div className={styles.wrapper}>
<div className={styles.iconWrapper}>
<Check size={40} strokeWidth={3} />
</div>

<h1 className={styles.title}>신청이 완료되었습니다</h1>
<p className={styles.description}>
졸업 요건 취득 방식 신청이 정상적으로 접수되었습니다.
<br />
학사 승인까지 영업일 기준 3~5일이 소요될 수 있습니다.
</p>

<div className={styles.inputSection}>
<label htmlFor='email' className={styles.label}>
알림 받을 이메일 (선택)
</label>
<input
id='email'
type='email'
placeholder='[email protected]'
className={styles.input}
value={email}
onChange={e => setEmail(e.target.value)}
disabled={isSubmitting}
/>
</div>

<button
className={styles.button}
onClick={handleComplete}
disabled={isSubmitting}
>
{isSubmitting ? '처리 중...' : '홈으로 돌아가기'}
</button>
</div>
</div>
);
}
22 changes: 10 additions & 12 deletions apps/graduate/src/pages/client/apply/ui/ApplyDrawer.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Link, useRouter } from '@tanstack/react-router';
import { useRouter } from '@tanstack/react-router';
import { Button, Drawer, Steps } from 'antd';

import { type GraduationType, ROUTE } from '~/shared/constants';
Expand Down Expand Up @@ -48,17 +48,15 @@ export default function ApplyDrawer({
className={styles.drawerDescription}
/>

<Link to={ROUTE.HOME}>
<Button
onClick={submitGraduationType}
loading={isSubmitting}
size='large'
className={styles.submitButton}
type='primary'
>
제출하기
</Button>
</Link>
<Button
onClick={submitGraduationType}
loading={isSubmitting}
size='large'
className={styles.submitButton}
type='primary'
>
제출하기
</Button>
</Drawer>
);
}
Loading
Loading