+
매도할 주식이 없어요
@@ -135,14 +136,14 @@ export default function SellSection({ code, detailInfo }: SellSectionProps) {
<>
);
diff --git a/FE/src/components/TopFive/SkeletonCard.tsx b/FE/src/components/TopFive/SkeletonCard.tsx
index 79b9066..8f70747 100644
--- a/FE/src/components/TopFive/SkeletonCard.tsx
+++ b/FE/src/components/TopFive/SkeletonCard.tsx
@@ -1,12 +1,21 @@
export function SkeletonCard() {
return (
-
-
-
+
);
}
diff --git a/FE/src/components/TopFive/SkeletonList.tsx b/FE/src/components/TopFive/SkeletonList.tsx
new file mode 100644
index 0000000..577681a
--- /dev/null
+++ b/FE/src/components/TopFive/SkeletonList.tsx
@@ -0,0 +1,72 @@
+import { SkeletonCard } from './SkeletonCard.tsx';
+
+export const SkeletonList = () => {
+ return (
+
+ {/* Nav 영역 스켈레톤 */}
+
+
+
+ {/* 급상승 리스트 */}
+
+ {/* 제목 */}
+
+
+ {/* 헤더 */}
+
+
+ {/* 카드 리스트 */}
+
+ {Array.from({ length: 5 }).map((_, index) => (
+ -
+
+
+ ))}
+
+
+
+ {/* 급하락 리스트 */}
+
+ {/* 제목 */}
+
+
+ {/* 헤더 */}
+
+
+ {/* 카드 리스트 */}
+
+ {Array.from({ length: 5 }).map((_, index) => (
+ -
+
+
+ ))}
+
+
+
+
+ );
+};
diff --git a/FE/src/components/TopFive/index.tsx b/FE/src/components/TopFive/index.tsx
index acb3a6a..1ebd80a 100644
--- a/FE/src/components/TopFive/index.tsx
+++ b/FE/src/components/TopFive/index.tsx
@@ -10,28 +10,20 @@ export default function TopFive() {
const [searchParams] = useSearchParams();
const currentMarket = (searchParams.get('top') || '전체') as MarketType;
- const { data, isLoading } = useQuery({
+ const { data } = useQuery({
queryKey: ['topfive', currentMarket],
queryFn: () => getTopFiveStocks(stockIndexMap[currentMarket]),
keepPreviousData: true,
staleTime: 1000,
cacheTime: 30000,
- // refetchInterval: 1000,
+ suspense: true,
});
return (
);
diff --git a/FE/src/hooks/useOrder.ts b/FE/src/hooks/useOrder.ts
index 6d4f73f..3575466 100644
--- a/FE/src/hooks/useOrder.ts
+++ b/FE/src/hooks/useOrder.ts
@@ -1,4 +1,5 @@
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
+import Toast from 'components/Toast';
import {
deleteOrder,
getOrders,
@@ -11,6 +12,7 @@ export default function useOrders() {
const orderQuery = useQuery(['account', 'order'], () => getOrders(), {
staleTime: 1000,
+ suspense: true,
});
const removeOrder = useMutation((id: number) => deleteOrder(id), {
@@ -20,15 +22,28 @@ export default function useOrders() {
const orderBuy = useMutation(
({ code, price, count }: { code: string; price: number; count: number }) =>
orderBuyStock(code, price, count),
- { onSuccess: () => queryClient.invalidateQueries(['detail', 'cash']) },
+ {
+ onSuccess: () => {
+ queryClient.invalidateQueries(['detail', 'cash']);
+ Toast({
+ message: '매수 요청되었습니다.',
+ type: 'success',
+ });
+ },
+ },
);
const orderSell = useMutation(
({ code, price, count }: { code: string; price: number; count: number }) =>
orderSellStock(code, price, count),
{
- onSuccess: (_, { code }) =>
- queryClient.invalidateQueries(['detail', 'sellPosiible', code]),
+ onSuccess: (_, { code }) => {
+ queryClient.invalidateQueries(['detail', 'sellPosiible', code]);
+ Toast({
+ message: '매도 요청되었습니다.',
+ type: 'success',
+ });
+ },
},
);
diff --git a/FE/src/hooks/useUser.ts b/FE/src/hooks/useUser.ts
index 77513a4..d2b38c1 100644
--- a/FE/src/hooks/useUser.ts
+++ b/FE/src/hooks/useUser.ts
@@ -7,11 +7,12 @@ export default function useUser() {
const userQuery = useQuery(['myInfo', 'profile'], () => getMyProfile(), {
staleTime: 1000,
+ suspense: true,
});
const updateNickame = useMutation((nickname: string) => rename(nickname), {
onSuccess: () => queryClient.invalidateQueries(['myInfo', 'profile']),
});
- return { userQuery, updateNickame };
+ return { userQuery, updateNickname: updateNickame };
}
diff --git a/FE/src/main.tsx b/FE/src/main.tsx
index 99fbaf0..08dac63 100644
--- a/FE/src/main.tsx
+++ b/FE/src/main.tsx
@@ -8,7 +8,8 @@ import {
QueryErrorResetBoundary,
} from '@tanstack/react-query';
import { ErrorBoundary } from 'react-error-boundary';
-import FallbackUI from 'components/FallbackUI.tsx';
+import { HelmetProvider } from 'react-helmet-async';
+import GlobalErrorFallback from 'components/GlobalErrorFallback.tsx';
const queryClient = new QueryClient({
defaultOptions: {
@@ -21,13 +22,18 @@ const queryClient = new QueryClient({
createRoot(document.getElementById('root')!).render(
-
- {({ reset }) => (
-
-
-
- )}
-
+
+
+ {({ reset }) => (
+
+
+
+ )}
+
+
,
);
diff --git a/FE/src/page/Home.tsx b/FE/src/page/Home.tsx
index d62a960..fba441a 100644
--- a/FE/src/page/Home.tsx
+++ b/FE/src/page/Home.tsx
@@ -1,13 +1,28 @@
import TopFive from 'components/TopFive';
import StockIndex from 'components/StockIndex/index.tsx';
import News from 'components/News/News.tsx';
+import { Helmet } from 'react-helmet-async';
+import { Suspense } from 'react';
+import { StockIndexSkeleton } from '../components/StockIndex/StockIndexSekleton.tsx';
+import { SkeletonList } from '../components/TopFive/SkeletonList.tsx';
+import { NewsSkeleton } from '../components/News/NewsSkeleton.tsx';
export default function Home() {
return (
<>
-
-
-
+
+
+ JuGa
+
+
}>
+
+
+
}>
+
+
+
}>
+
+
>
);
}
diff --git a/FE/src/page/MyPage.tsx b/FE/src/page/MyPage.tsx
index a5e3526..fbeb116 100644
--- a/FE/src/page/MyPage.tsx
+++ b/FE/src/page/MyPage.tsx
@@ -3,22 +3,55 @@ import BookMark from 'components/Mypage/BookMark';
import MyInfo from 'components/Mypage/MyInfo';
import Nav from 'components/Mypage/Nav';
import Order from 'components/Mypage/Order';
-import { useSearchParams } from 'react-router-dom';
+import { useNavigate, useSearchParams } from 'react-router-dom';
+import { Helmet } from 'react-helmet-async';
+import useAuthStore from '../store/useAuthStore.ts';
+import { Suspense } from 'react';
+import { AccountSkeleton } from '../components/Mypage/AccountSkeleton.tsx';
+import { BookmarkSkeleton } from '../components/Mypage/BookMarkSkeleton.tsx';
+import { OrderSkeleton } from '../components/Mypage/OrderSkeleton.tsx';
+import { MyInfoSkeleton } from '../components/Mypage/MyInfoSkeleton.tsx';
export default function MyPage() {
const [searchParams] = useSearchParams();
const currentPage = searchParams.get('section') || 'account';
+ const navigate = useNavigate();
+ const { isLogin } = useAuthStore();
+ if (!isLogin) {
+ navigate('/');
+ }
+
return (
+
+
+ JuGa | MyPage
+
{
{
- account:
,
- order:
,
- bookmark:
,
- info:
,
+ account: (
+
}>
+
+
+ ),
+ order: (
+
}>
+
+
+ ),
+ bookmark: (
+
}>
+
+
+ ),
+ info: (
+
}>
+
+
+ ),
}[currentPage]
}
diff --git a/FE/src/page/Rank.tsx b/FE/src/page/Rank.tsx
index a6476f9..35c5fa7 100644
--- a/FE/src/page/Rank.tsx
+++ b/FE/src/page/Rank.tsx
@@ -2,18 +2,22 @@ import Nav from 'components/Rank/Nav.tsx';
import List from '../components/Rank/List.tsx';
import { getRanking } from '../service/ranking.ts';
import { useQuery } from '@tanstack/react-query';
+import { Helmet } from 'react-helmet-async';
export default function Rank() {
- const { data, isLoading, isError } = useQuery({
+ const { data, isError } = useQuery({
queryKey: ['Rank'],
queryFn: () => getRanking(),
+ suspense: true,
});
- if (isLoading) return
Loading...
;
if (isError) return
Error!!
;
-
return (
-
+
+
+
+ JuGa | Ranking
+
diff --git a/FE/src/page/StocksDetail.tsx b/FE/src/page/StocksDetail.tsx
index 42e336e..c7b49d9 100644
--- a/FE/src/page/StocksDetail.tsx
+++ b/FE/src/page/StocksDetail.tsx
@@ -5,6 +5,9 @@ import PriceSection from 'components/StocksDetail/PriceSection';
import TradeSection from 'components/StocksDetail/TradeSection';
import { useParams } from 'react-router-dom';
import { getStocksByCode } from 'service/stocks';
+import { Helmet } from 'react-helmet-async';
+import { Suspense } from 'react';
+import ChartSkeleton from 'components/StocksDetail/ChartSkeleton.tsx';
export default function StocksDetail() {
const params = useParams();
@@ -22,10 +25,16 @@ export default function StocksDetail() {
return (
+
+
+ {`${(+data.stck_prpr).toLocaleString()}원 ${+data.prdy_ctrt}% | ${data.hts_kor_isnm}`}
+