diff --git a/src/components/common/InterestButton.tsx b/src/components/common/InterestButton.tsx
index 1aa47ed..5b55f4b 100644
--- a/src/components/common/InterestButton.tsx
+++ b/src/components/common/InterestButton.tsx
@@ -2,6 +2,7 @@ import { useSuspendedQuery } from '@/hooks/useSuspendedQuery';
import { api } from '@/libs/client/api';
import { useTypeSelector } from '@/store';
import type { CahootDetailType } from '@/types/cahoot';
+import type { MarketDetailType } from '@/types/market';
import type { Response } from '@/types/response';
import classNames from '@/utils/classnames';
import { useMutation, useQueryClient } from '@tanstack/react-query';
@@ -11,8 +12,9 @@ import Icon from './Icons';
interface InterestButtonProps {
id: number;
isInterest?: boolean;
- type: 'small' | 'large';
+ size: 'small' | 'large';
hideOnMobile?: boolean;
+ type: 'cahoot' | 'market';
}
type MutationBody = {
@@ -20,7 +22,13 @@ type MutationBody = {
vacationId: number;
};
-const InterestButton = ({ id, isInterest, type, hideOnMobile = false }: InterestButtonProps) => {
+const InterestButton = ({
+ id,
+ isInterest,
+ size,
+ hideOnMobile = false,
+ type,
+}: InterestButtonProps) => {
const token = useTypeSelector((state) => state.user.token);
const userId = useTypeSelector((state) => state.user.id);
const queryClient = useQueryClient();
@@ -29,6 +37,8 @@ const InterestButton = ({ id, isInterest, type, hideOnMobile = false }: Interest
queryClient.invalidateQueries({ queryKey: ['cahoot/interests'] });
queryClient.invalidateQueries({ queryKey: ['cahoot/detail', `${id}`] });
queryClient.invalidateQueries({ queryKey: ['market/list'] });
+ queryClient.invalidateQueries({ queryKey: ['market/detail', `${id}`] });
+ queryClient.invalidateQueries({ queryKey: ['market/interests'] });
};
const { mutate: addInterest } = useMutation
({
mutationFn: (body) =>
@@ -44,10 +54,15 @@ const InterestButton = ({ id, isInterest, type, hideOnMobile = false }: Interest
.json(),
onSuccess,
});
- const { data } = useSuspendedQuery>(
+ const { data: cahootDetailData } = useSuspendedQuery>(
['cahoot/detail', `${id}`],
() => api.get(`cahoots/${id}?info=detail`).json(),
- { enabled: type === 'large' }
+ { enabled: size === 'large' && type === 'cahoot' }
+ );
+ const { data: marketDetailData } = useSuspendedQuery>(
+ ['market/detail', `${id}`],
+ () => api.get(`markets/${id}`).json(),
+ { enabled: size === 'large' && type === 'market' }
);
const onBookmarkClick: React.MouseEventHandler = (e) => {
@@ -62,7 +77,7 @@ const InterestButton = ({ id, isInterest, type, hideOnMobile = false }: Interest
};
return userId ? (
- type === 'small' ? (
+ size === 'small' ? (
)
) : null;
diff --git a/src/components/common/Interests.tsx b/src/components/common/Interests.tsx
index acbe8f2..7be0669 100644
--- a/src/components/common/Interests.tsx
+++ b/src/components/common/Interests.tsx
@@ -59,7 +59,7 @@ const Interests = ({ scrollRef, type }: InterestsProps) => {
diff --git a/src/components/common/RouteGuard.tsx b/src/components/common/RouteGuard.tsx
new file mode 100644
index 0000000..9c32fbf
--- /dev/null
+++ b/src/components/common/RouteGuard.tsx
@@ -0,0 +1,26 @@
+import { useRouter } from 'next/router';
+
+import { useTypeSelector } from '@/store';
+
+interface LayoutProps {
+ children: React.ReactNode;
+}
+
+const RouteGuard = ({ children }: LayoutProps) => {
+ const router = useRouter();
+ const id = useTypeSelector((state) => state.user.id);
+
+ if (!id) {
+ router?.push({
+ pathname: '/login',
+ });
+ }
+
+ return (
+ <>
+ {id && children}
+ >
+ );
+};
+
+export default RouteGuard;
diff --git a/src/components/common/Table.tsx b/src/components/common/Table.tsx
deleted file mode 100644
index 00d0082..0000000
--- a/src/components/common/Table.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-interface PropsType {
- // table type
- printAllData: boolean;
- border?: boolean;
-}
-
-const Table = ({ printAllData, border }: PropsType) => {
- // TODO: 데이터 0개일때 처리
- return (
- <>
-
-
-
-
- 공모명 |
- 거래 시간 |
- 가격 |
- 수량(주) |
- 진행도 |
-
-
-
-
- 일본 유명 호스트 다나카와 함께 |
- 23-01-06 |
- {Number(28000).toLocaleString()} |
- 2 |
-
- 진행 중
- |
-
-
- 일본 유명 호스트 다나카와 함께 |
- 23-01-06 |
- {Number(28000).toLocaleString()} |
- 2 |
-
- 취소
- |
-
-
- 일본 유명 호스트 다나카와 함께 |
- 23-01-06 |
- {Number(28000).toLocaleString()} |
- 2 |
-
- 완료
- |
-
-
-
-
- {!printAllData && }
- >
- );
-};
-
-export default Table;
diff --git a/src/components/market/DetailHeader.tsx b/src/components/market/DetailHeader.tsx
new file mode 100644
index 0000000..67251a2
--- /dev/null
+++ b/src/components/market/DetailHeader.tsx
@@ -0,0 +1,80 @@
+import Image from 'next/image';
+import { useRouter } from 'next/router';
+
+import { useSuspendedQuery } from '@/hooks/useSuspendedQuery';
+import { api } from '@/libs/client/api';
+import { useTypeSelector } from '@/store';
+import type { MarketDetailType } from '@/types/market';
+import type { Response } from '@/types/response';
+
+import InterestButton from '../common/InterestButton';
+
+const DetailHeader = () => {
+ const {
+ query: { id },
+ } = useRouter();
+ const {
+ data: {
+ data: { title, location, expectedRateOfReturn, pictures, price, shortDescription, userIds },
+ },
+ } = useSuspendedQuery>(['market/detail', id], () =>
+ api.get(`markets/${id}`).json()
+ );
+ const userId = useTypeSelector((state) => state.user.id);
+
+ return (
+
+
+
+ {pictures[0] && (
+
+ )}
+
+
+
+
+
+
{title}
+
+ {location}
+
+
+
+ 소개
+ {shortDescription}
+
+
+
+ 예상 수익률
+ {expectedRateOfReturn}%
+
+
+ 현재가
+ {price.toLocaleString()}원
+
+ {userId && (
+
+ )}
+
+
+
+ );
+};
+
+export default DetailHeader;
diff --git a/src/components/mypage/ContestTable.tsx b/src/components/mypage/ContestTable.tsx
new file mode 100644
index 0000000..dee66d7
--- /dev/null
+++ b/src/components/mypage/ContestTable.tsx
@@ -0,0 +1,86 @@
+import Link from 'next/link';
+
+import { STATUS } from '@/constants/mypage';
+import { useSuspendedQuery } from '@/hooks/useSuspendedQuery';
+import { api } from '@/libs/client/api';
+import { useTypeSelector } from '@/store';
+import { Response } from '@/types/response';
+import { ParticipatedContestType } from '@/types/user';
+import classNames from '@/utils/classnames';
+
+interface PropsType {
+ printAllData: boolean;
+ border?: boolean;
+}
+
+// 공모 내역 테이블
+const ContestTable = ({ printAllData, border }: PropsType) => {
+ const token = useTypeSelector((state) => state.user.token);
+ const { data } = useSuspendedQuery>(
+ [`user/contest`],
+ () =>
+ api
+ .get(`auth/contestParticipation/me`, {
+ headers: { Authorization: `Bearer ${token}` },
+ })
+ .json>(),
+ { enabled: !!token }
+ );
+
+ if (!data || data?.data.result.length === 0) {
+ return 아직 참여한 공모가 없어요!
;
+ }
+
+ return (
+ <>
+
+
+
+
+ 공모명 |
+ 거래 시간 |
+ 가격 |
+ 수량(주) |
+ 진행도 |
+
+
+
+ {data?.data.result.map((item, idx) => {
+ if (printAllData || (!printAllData && idx < 3)) {
+ return (
+
+ {item.title} |
+ {item.createdAt.split('T')[0].substring(2)} |
+ {item.price.toLocaleString()} |
+ {item.amount.toLocaleString()} |
+
+
+ {STATUS[item.status as keyof typeof STATUS].TEXT}
+
+ |
+
+ );
+ }
+ })}
+
+
+
+ {!printAllData && data && data?.data.result.length > 3 && (
+
+
+
+ )}
+ >
+ );
+};
+
+export default ContestTable;
diff --git a/src/components/mypage/ParticipatedContest.tsx b/src/components/mypage/ParticipatedContest.tsx
index 62f0a33..623fc84 100644
--- a/src/components/mypage/ParticipatedContest.tsx
+++ b/src/components/mypage/ParticipatedContest.tsx
@@ -1,9 +1,11 @@
+import { Suspense } from 'react';
+
import Link from 'next/link';
import Icon from '@/components/common/Icons';
-import Table from '@/components/common/Table';
+import ContestTable from '@/components/mypage/ContestTable';
-const ParticapatedContest = () => {
+const ParticipatedContest = () => {
return (
<>
{/* only desktop */}
@@ -11,7 +13,9 @@ const ParticapatedContest = () => {
공모 내역
{/* only mobile */}
@@ -33,4 +37,4 @@ const ParticapatedContest = () => {
);
};
-export default ParticapatedContest;
+export default ParticipatedContest;
diff --git a/src/components/mypage/StockTable.tsx b/src/components/mypage/StockTable.tsx
new file mode 100644
index 0000000..92a6f34
--- /dev/null
+++ b/src/components/mypage/StockTable.tsx
@@ -0,0 +1,75 @@
+import Link from 'next/link';
+
+import { useSuspendedQuery } from '@/hooks/useSuspendedQuery';
+import { api } from '@/libs/client/api';
+import { useTypeSelector } from '@/store';
+import { Response } from '@/types/response';
+import { StocksType } from '@/types/user';
+
+interface PropsType {
+ printAllData: boolean;
+ border?: boolean;
+}
+
+// 자산 현황 테이블
+const StockTable = ({ printAllData, border }: PropsType) => {
+ const token = useTypeSelector((state) => state.user.token);
+ const { data } = useSuspendedQuery