Skip to content

Commit

Permalink
Merge pull request #261 from boostcampwm-2024/front/main
Browse files Browse the repository at this point in the history
[FE] 브랜치 병합
  • Loading branch information
dannysir authored Dec 4, 2024
2 parents aee7d39 + 1c96da8 commit 1184a00
Show file tree
Hide file tree
Showing 106 changed files with 1,712 additions and 1,011 deletions.
61 changes: 55 additions & 6 deletions FE/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions FE/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-error-boundary": "^4.1.2",
"react-helmet-async": "^2.0.5",
"react-router-dom": "^6.27.0",
"react-toastify": "^10.0.6",
"socket.io-client": "^4.8.1",
Expand All @@ -27,6 +28,7 @@
"@types/node": "^22.9.1",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/react-helmet": "^6.1.11",
"@vitejs/plugin-react": "^4.3.3",
"autoprefixer": "^10.4.20",
"eslint": "^9.13.0",
Expand Down
2 changes: 2 additions & 0 deletions FE/public/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
user-agent: *
allow: /
31 changes: 30 additions & 1 deletion FE/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import MyPage from 'page/MyPage';
import Rank from 'page/Rank.tsx';
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import { Helmet } from 'react-helmet-async';
import { Suspense } from 'react';
import { RankingSkeleton } from './components/Rank/RankingSkeleton.tsx';

function App() {
return (
Expand All @@ -23,7 +26,14 @@ function App() {
<Route index element={<Home />} />
<Route path='stocks/:id' element={<StocksDetail />} />
<Route path='mypage' element={<MyPage />} />
<Route path='rank' element={<Rank />} />
<Route
path='rank'
element={
<Suspense fallback={<RankingSkeleton />}>
<Rank />
</Suspense>
}
/>
</Route>
</Routes>
</Router>
Expand All @@ -35,6 +45,25 @@ export default App;
function Layout() {
return (
<>
<Helmet>
<meta charSet='utf-8' />
<meta
name='description'
content='실시간 주식 데이터를 활용한 모의투자 경험을 통해 주식 투자에 대해 배울 수 있는 서비스.'
/>
<meta property='og:title' content='JuGa' />
<meta property='og:url' content='https://juga.kro.kr/' />
<meta
property='og:image'
content='https://juga.kro.kr/assets/logo-BUoSezEL.webp'
/>
<meta property='og:image:alt' content='JuGa Logo' />
<meta
property='og:description'
content='실시간 주식 데이터를 활용한 모의투자 경험을 통해 주식 투자에 대해 배울 수 있는 서비스.'
/>
<title>JuGa</title>
</Helmet>
<Header />
<main className='mt-[60px] flex flex-col gap-4'>
<Outlet />
Expand Down
14 changes: 0 additions & 14 deletions FE/src/components/FallbackUI.tsx

This file was deleted.

31 changes: 31 additions & 0 deletions FE/src/components/GlobalErrorFallback.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { FallbackProps } from 'react-error-boundary';
import logoPng from 'assets/logo.png';
import logoWebp from 'assets/logo.webp';

export default function GlobalErrorFallback({ error }: FallbackProps) {
return (
<div className='flex flex-col items-center justify-center mt-40 text-gray-800'>
<div className='flex items-center mb-6'>
<picture>
<source srcSet={logoWebp} type='image/webp' />
<img src={logoPng} alt='Logo' className='h-48' />
</picture>
</div>
<h1 className='mb-4 text-2xl font-bold'>오류가 발생했습니다!</h1>
<p className='mb-6 text-lg text-center'>
문제가 지속적으로 발생하면 관리자에게 문의해주세요.
</p>
<pre className='w-full max-w-lg p-4 mb-6 text-sm text-left bg-gray-200 rounded-md shadow-md'>
{error.message}
</pre>
<div className='flex space-x-4'>
<a
href='/'
className='px-6 py-2 font-medium text-white transition bg-blue-500 rounded-md shadow hover:bg-blue-600'
>
Home으로 돌아가기
</a>
</div>
</div>
);
}
27 changes: 16 additions & 11 deletions FE/src/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { Link, useLocation, useNavigate } from 'react-router-dom';
import useAuthStore from 'store/authStore';
import useAuthStore from 'store/useAuthStore.ts';
import useLoginModalStore from 'store/useLoginModalStore';
import useSearchModalStore from '../store/useSearchModalStore.ts';
import useSearchInputStore from '../store/useSearchInputStore.ts';
import useSearchModalStore from 'store/useSearchModalStore.ts';
import useSearchInputStore from 'store/useSearchInputStore.ts';
import logoPng from 'assets/logo.png';
import logoWebp from 'assets/logo.webp';
import { checkAuth, logout } from 'service/auth.ts';
import { useEffect } from 'react';
import Toast from './Toast';

export default function Header() {
const { toggleModal } = useLoginModalStore();
Expand All @@ -18,9 +19,12 @@ export default function Header() {

useEffect(() => {
const check = async () => {
const res = await checkAuth();
if (res.ok) setIsLogin(true);
else setIsLogin(false);
try {
const res = await checkAuth();
setIsLogin(res.isLogin);
} catch (error) {
console.log(error);
}
};

check();
Expand All @@ -29,6 +33,7 @@ export default function Header() {
const handleLogout = () => {
logout().then(() => {
setIsLogin(false);
Toast({ message: '로그아웃 되었습니다!', type: 'success' });
});
};

Expand All @@ -40,7 +45,7 @@ export default function Header() {
};

return (
<header className='fixed left-0 top-0 h-[60px] w-full bg-white'>
<header className='fixed left-0 top-0 z-50 h-[60px] w-full bg-white'>
<div className='mx-auto flex h-full max-w-[1280px] items-center justify-between px-8'>
<Link to={'/'} className='flex items-center gap-2'>
<picture>
Expand All @@ -49,7 +54,7 @@ export default function Header() {
type='image/webp'
className={'h-[32px]'}
/>
<img src={logoPng} className={'h-[32px]'} />
<img src={logoPng} alt={'Logo'} className={'h-[32px]'} />
</picture>
<h1 className='text-xl font-bold text-juga-grayscale-black'>JuGa</h1>
</Link>
Expand All @@ -58,20 +63,20 @@ export default function Header() {
<nav className='flex items-center gap-6 text-sm font-bold text-juga-grayscale-500'>
<div
onClick={() => handleLink('/')}
className='cursor-pointer px-1 py-2'
className='px-1 py-2 cursor-pointer'
>
</div>
<div
onClick={() => handleLink('/rank')}
className='cursor-pointer px-1 py-2'
className='px-1 py-2 cursor-pointer'
>
랭킹
</div>
{isLogin && (
<div
onClick={() => handleLink('/mypage')}
className='cursor-pointer px-1 py-2'
className='px-1 py-2 cursor-pointer'
>
마이페이지
</div>
Expand Down
33 changes: 16 additions & 17 deletions FE/src/components/Login/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,32 @@ import Input from './Input';
import { ChatBubbleOvalLeftIcon, XMarkIcon } from '@heroicons/react/16/solid';
import { FormEvent, useEffect, useState } from 'react';
import { login } from 'service/auth';
import useAuthStore from 'store/authStore';
import useAuthStore from 'store/useAuthStore.ts';
import Overay from '../ModalOveray.tsx';
import Toast from 'components/Toast.tsx';

export default function Login() {
const { isOpen, toggleModal } = useLoginModalStore();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const { setIsLogin } = useAuthStore();
const [errorCode, setErrorCode] = useState<number>(200);

useEffect(() => {
setEmail('');
setPassword('');
setEmail('jindding');
setPassword('1234');
}, [isOpen]);

if (!isOpen) return;

const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
const res = await login(email, password);
if ('message' in res) {
let message = '';
if (res.statusCode === 401) message = '존재하지 않는 사용자입니다.';
else if (res.statusCode === 400) message = '잘못된 입력형식입니다.';

if ('error' in res) {
setErrorCode(res.statusCode);
Toast({ message, type: 'error' });
return;
}

Expand All @@ -40,8 +43,12 @@ export default function Login() {
import.meta.env.VITE_TEST_PW,
);

if ('error' in res) {
setErrorCode(res.statusCode);
if ('message' in res) {
let message = '';
if (res.statusCode === 401) message = '존재하지 않는 사용자입니다.';
else if (res.statusCode === 400) message = '잘못된 입력형식입니다.';

Toast({ message, type: 'error' });
return;
}

Expand All @@ -58,15 +65,7 @@ export default function Login() {
<>
<Overay onClick={() => toggleModal()} />
<section className='fixed left-1/2 top-1/2 flex w-[500px] -translate-x-1/2 -translate-y-1/2 flex-col rounded-2xl bg-white p-20 shadow-lg'>
<h2 className='text-3xl font-bold'>JuGa</h2>
<p className='h-5 my-3 text-sm font-semibold text-juga-red-60'>
{
{
'401': '존재하지 않는 사용자입니다.',
'400': '잘못된 입력형식입니다.',
}[errorCode]
}
</p>
<h2 className='mb-5 text-3xl font-bold'>JuGa</h2>
<form className='flex flex-col mb-2' onSubmit={handleSubmit}>
<div className='flex flex-col gap-2 my-10'>
<Input
Expand Down
Loading

0 comments on commit 1184a00

Please sign in to comment.