Skip to content

Commit

Permalink
Merge pull request #257 from boostcampwm-2024/optimization/front-#254
Browse files Browse the repository at this point in the history
[FE] 웹 최적화 & Suspense를 이용해 Skeleton UI 적용
  • Loading branch information
dannysir authored Dec 3, 2024
2 parents 1549e84 + fe35690 commit 1068fb8
Show file tree
Hide file tree
Showing 37 changed files with 781 additions and 200 deletions.
74 changes: 37 additions & 37 deletions FE/package-lock.json

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

3 changes: 2 additions & 1 deletion FE/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-error-boundary": "^4.1.2",
"react-helmet": "^6.1.0",
"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 @@ -28,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
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>
);
}
10 changes: 6 additions & 4 deletions FE/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ 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 @@ -29,6 +30,7 @@ export default function Header() {
const handleLogout = () => {
logout().then(() => {
setIsLogin(false);
Toast({ message: '로그아웃 되었습니다!', type: 'success' });
});
};

Expand All @@ -49,7 +51,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 +60,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
15 changes: 5 additions & 10 deletions FE/src/components/Mypage/Account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,13 @@ import { getAssets } from 'service/assets';
import { isWithinTimeRange } from 'utils/common';

export default function Account() {
const { data, isLoading, isError } = useQuery(
['account', 'assets'],
() => getAssets(),
{
staleTime: 1000,
refetchInterval: isWithinTimeRange('09:00', '15:30') ? 5000 : false,
},
);
const { data } = useQuery(['account', 'assets'], () => getAssets(), {
staleTime: 1000,
refetchInterval: isWithinTimeRange('09:00', '15:30') ? 5000 : false,
suspense: true,
});

if (isLoading) return <div>loading</div>;
if (!data) return <div>No data</div>;
if (isError) return <div>error</div>;

const { asset, stocks } = data;

Expand Down
61 changes: 61 additions & 0 deletions FE/src/components/Mypage/AccountSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
const AccountConditionSkeleton = () => {
return (
<div className='flex flex-col gap-4 rounded-lg bg-white p-4'>
<div className='flex items-center justify-between'>
{/* 계좌 정보 타이틀 */}
<div className='h-6 w-24 animate-pulse rounded bg-gray-200' />
{/* 날짜 정보 */}
<div className='h-5 w-32 animate-pulse rounded bg-gray-200' />
</div>

<div className='flex flex-col gap-2'>
{/* 총자산, 수익률 등의 정보 */}
<div className='flex items-center justify-between'>
<div className='h-5 w-20 animate-pulse rounded bg-gray-200' />
<div className='h-7 w-32 animate-pulse rounded bg-gray-200' />
</div>
<div className='flex items-center justify-between'>
<div className='h-5 w-20 animate-pulse rounded bg-gray-200' />
<div className='h-7 w-32 animate-pulse rounded bg-gray-200' />
</div>
</div>
</div>
);
};

const MyStocksListSkeleton = () => {
return (
<div className='flex flex-col gap-2 rounded-lg bg-white p-4'>
{/* 보유종목 타이틀 */}
<div className='mb-2 h-6 w-24 animate-pulse rounded bg-gray-200' />

{/* 테이블 헤더 */}
<div className='flex items-center justify-between border-b pb-2'>
<div className='h-4 w-32 animate-pulse rounded bg-gray-200' />
<div className='h-4 w-20 animate-pulse rounded bg-gray-200' />
<div className='h-4 w-24 animate-pulse rounded bg-gray-200' />
</div>

{/* 보유주식 리스트 */}
{Array.from({ length: 5 }).map((_, index) => (
<div
key={index}
className='flex items-center justify-between border-b py-3'
>
<div className='h-5 w-40 animate-pulse rounded bg-gray-200' />
<div className='h-5 w-24 animate-pulse rounded bg-gray-200' />
<div className='h-5 w-28 animate-pulse rounded bg-gray-200' />
</div>
))}
</div>
);
};

export const AccountSkeleton = () => {
return (
<div className='flex min-h-[500px] flex-col gap-3'>
<AccountConditionSkeleton />
<MyStocksListSkeleton />
</div>
);
};
Loading

0 comments on commit 1068fb8

Please sign in to comment.