diff --git a/src/components/cahoot/DetailBody.tsx b/src/components/cahoot/DetailBody.tsx index c9d5faa..302b041 100644 --- a/src/components/cahoot/DetailBody.tsx +++ b/src/components/cahoot/DetailBody.tsx @@ -34,7 +34,7 @@ const DetailBody = ({ id }: DetailBodyProps) => { return ( <> - +
diff --git a/src/components/cahoot/DetailHeader.tsx b/src/components/cahoot/DetailHeader.tsx index 3193b14..aadef2c 100644 --- a/src/components/cahoot/DetailHeader.tsx +++ b/src/components/cahoot/DetailHeader.tsx @@ -64,7 +64,8 @@ const DetailHeader = () => {
{status === 'CAHOOTS_ONGOING' && } { {title}
- +
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) => {
{title}
- +
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] && ( + image + )} +
+
+
+
+
+ {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>( + [`user/stock`], + () => + api + .get(`auth/stocks/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 ( + + + + + + + + ); + } + })} + +
공모명수익률1주당 가격평단가수량(주)
{item.title}{item.profitRate}{item.currentPrice.toLocaleString()}{item.pricePerStock.toLocaleString()}{item.totalAmount}
+
+ {!printAllData && data && data?.data.result.length > 3 && ( + + + + )} + + ); +}; + +export default StockTable; diff --git a/src/components/mypage/Stocks.tsx b/src/components/mypage/Stocks.tsx index a73a6a0..89ef4cb 100644 --- a/src/components/mypage/Stocks.tsx +++ b/src/components/mypage/Stocks.tsx @@ -1,7 +1,9 @@ +import { Suspense } from 'react'; + import Link from 'next/link'; import Icon from '@/components/common/Icons'; -import Table from '@/components/common/Table'; +import StockTable from '@/components/mypage/StockTable'; const Stocks = () => { return ( @@ -11,7 +13,9 @@ const Stocks = () => {

자산 현황


- + 로딩...

}> + +
{/* only mobile */} diff --git a/src/components/mypage/TransactionTable.tsx b/src/components/mypage/TransactionTable.tsx new file mode 100644 index 0000000..49a2e43 --- /dev/null +++ b/src/components/mypage/TransactionTable.tsx @@ -0,0 +1,90 @@ +import Link from 'next/link'; + +import { TRANSACTION_TYPE } from '@/constants/mypage'; +import { useSuspendedQuery } from '@/hooks/useSuspendedQuery'; +import { api } from '@/libs/client/api'; +import { useTypeSelector } from '@/store'; +import { Response } from '@/types/response'; +import { TransactionsType } from '@/types/user'; +import classNames from '@/utils/classnames'; + +interface PropsType { + printAllData: boolean; + border?: boolean; +} + +// 거래 현황 테이블 +const TransactionTable = ({ printAllData, border }: PropsType) => { + const token = useTypeSelector((state) => state.user.token); + const { data } = useSuspendedQuery>( + [`user/transactions`], + () => + api + .get(`auth/transactions/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.vacationName}{item.transactionTime}{item.price.toLocaleString()}{item.amount.toLocaleString()} +
+ { + TRANSACTION_TYPE[item.transactionType as keyof typeof TRANSACTION_TYPE] + .TEXT + } +
+
+
+ {!printAllData && data && data?.data.result.length > 3 && ( + + + + )} + + ); +}; + +export default TransactionTable; diff --git a/src/components/mypage/Transactions.tsx b/src/components/mypage/Transactions.tsx index fddda94..a790b09 100644 --- a/src/components/mypage/Transactions.tsx +++ b/src/components/mypage/Transactions.tsx @@ -1,7 +1,7 @@ import Link from 'next/link'; import Icon from '@/components/common/Icons'; -import Table from '@/components/common/Table'; +import TransactionTable from '@/components/mypage/TransactionTable'; const Transactions = () => { return ( @@ -11,7 +11,7 @@ const Transactions = () => {

거래 현황


- + {/* only mobile */} diff --git a/src/components/mypage/UserInfo.tsx b/src/components/mypage/UserInfo.tsx index 471d305..d07a36d 100644 --- a/src/components/mypage/UserInfo.tsx +++ b/src/components/mypage/UserInfo.tsx @@ -1,35 +1,70 @@ import Link from 'next/link'; import Icon from '@/components/common/Icons'; +import { PROVIDER_TYPE, ROLE, RANK } from '@/constants/mypage'; +import { useSuspendedQuery } from '@/hooks/useSuspendedQuery'; +import { api } from '@/libs/client/api'; +import { useTypeSelector } from '@/store'; +import { Response } from '@/types/response'; +import { UserInfoType } from '@/types/user'; const UserInfo = () => { + const token = useTypeSelector((state) => state.user.token); + const { data } = useSuspendedQuery>( + [`user/info`], + () => + api + .get(`auth/users/me`, { + headers: { Authorization: `Bearer ${token}` }, + }) + .json>(), + { enabled: !!token } + ); + return ( <> {/* only desktop */}
-

홍길동님

+

{data?.data.username}님


보유 캐쉬: - {Number(4000000).toLocaleString()}원 + + {Number(data?.data.cash).toLocaleString()}원 +

총 지분 가치: - {Number(4000000).toLocaleString()}원 + + {Number(data?.data.value).toLocaleString()}원 +

Email:
- test@gmail.com - 구글 연동 + {data?.data.email} + + {data + ? PROVIDER_TYPE[data?.data.providerType as keyof typeof PROVIDER_TYPE].TEXT + : '소셜'}{' '} + 연동 +

권한: - 사용자 - + {data ? ROLE[data?.data.role as keyof typeof ROLE].TEXT : ''} + + 등급: {data ? RANK[data?.data.rank as keyof typeof RANK].TEXT : '남작'} +

+ {/*

+ 등급: + + {data ? RANK[data?.data.rank as keyof typeof RANK].TEXT : '남작'} + +

*/}
{/* only mobile */} @@ -37,12 +72,12 @@ const UserInfo = () => {

- 홍길동님 + {data?.data.username}님

-

test@gmail.com

+

{data?.data.email}

@@ -54,7 +89,7 @@ const UserInfo = () => { - {Number(4000000).toLocaleString()}원 + {Number(data?.data.cash).toLocaleString()}원


@@ -64,7 +99,7 @@ const UserInfo = () => { - {Number(4000000).toLocaleString()}원 + {Number(data?.data.value).toLocaleString()}원

diff --git a/src/components/mypage/UserInfoManagement.tsx b/src/components/mypage/UserInfoManagement.tsx new file mode 100644 index 0000000..4583163 --- /dev/null +++ b/src/components/mypage/UserInfoManagement.tsx @@ -0,0 +1,90 @@ +import Image from 'next/image'; + +import { PROVIDER_TYPE, ROLE, RANK } from '@/constants/mypage'; +import { useSuspendedQuery } from '@/hooks/useSuspendedQuery'; +import { api } from '@/libs/client/api'; +import { useTypeSelector } from '@/store'; +import { Response } from '@/types/response'; +import { UserInfoType } from '@/types/user'; + +const UserInfoManagement = () => { + const token = useTypeSelector((state) => state.user.token); + const { data } = useSuspendedQuery>( + [`user/info`], + () => + api + .get(`auth/users/me`, { + headers: { Authorization: `Bearer ${token}` }, + }) + .json>(), + { enabled: !!token } + ); + + return ( +
+
+

기본 정보 관리

+
+
+ {/* {images[0] && ( */} + + {/* )} */} +
+ {/* 이름 */} +
+ +

+ {data?.data.username} +

+
+ {/* 가입 이메일 */} +
+ +

+ + {data?.data.email} + + + {data + ? PROVIDER_TYPE[data?.data.providerType as keyof typeof PROVIDER_TYPE].TEXT + : '소셜'}{' '} + 연동 + +

+
+ {/* 등급 */} +
+ +

+ {data ? RANK[data?.data.rank as keyof typeof RANK].TEXT : '남작'} +

+
+

권한 관리

+ {/* 권한 */} +
+ +

+ {data ? ROLE[data?.data.role as keyof typeof ROLE].TEXT : ''} +

+
+ +
+
+ ); +}; + +export default UserInfoManagement; diff --git a/src/constants/mypage.ts b/src/constants/mypage.ts new file mode 100644 index 0000000..ea80b21 --- /dev/null +++ b/src/constants/mypage.ts @@ -0,0 +1,60 @@ +export const PROVIDER_TYPE = { + GOOGLE: { + TEXT: '구글', + }, +} as const; + +export const ROLE = { + ADMIN: { + TEXT: '관리자', + }, + USER: { + TEXT: '일반 사용자', + }, +} as const; + +// 공모 진행도 +export const STATUS = { + CAHOOTS_BEFORE: { + COLOR: 'bg-red', + TEXT: '취소', + }, + CAHOOTS_ONGOING: { + COLOR: 'bg-main', + TEXT: '진행 중', + }, + CAHOOTS_CLOSE: { + COLOR: 'bg-blue', + TEXT: '완료', + }, +}; + +// 거래 유형 +export const TRANSACTION_TYPE = { + BUY: { + COLOR: 'bg-red', + TEXT: '매수', + }, + SELL: { + COLOR: 'bg-blue', + TEXT: '매도', + }, +}; + +export const RANK = { + NAMJAK: { + TEXT: '남작', + }, + JAJAK: { + TEXT: '자작', + }, + BAEKJAK: { + TEXT: '백작', + }, + WHOJAK: { + TEXT: '후작', + }, + GONGJAK: { + TEXT: '공작', + }, +}; diff --git a/src/pages/cahoots/detail/[id].tsx b/src/pages/cahoots/detail/[id].tsx index 1b01fd2..8c49342 100644 --- a/src/pages/cahoots/detail/[id].tsx +++ b/src/pages/cahoots/detail/[id].tsx @@ -7,7 +7,7 @@ import Layout from '@/components/common/Layout'; import { api } from '@/libs/client/api'; import wrapper from '@/store'; import { ErrorBoundary } from '@sentry/nextjs'; -import { QueryClient } from '@tanstack/react-query'; +import { dehydrate, QueryClient } from '@tanstack/react-query'; import type { InferGetServerSidePropsType } from 'next'; @@ -53,6 +53,7 @@ export const getServerSideProps = wrapper.getServerSideProps<{ id: number }>( return { props: { id: parseInt(id), + dehydratedState: dehydrate(queryClient), }, }; } diff --git a/src/pages/markets/detail/[id].tsx b/src/pages/markets/detail/[id].tsx new file mode 100644 index 0000000..be8e00f --- /dev/null +++ b/src/pages/markets/detail/[id].tsx @@ -0,0 +1,52 @@ +import { Suspense } from 'react'; + +import Layout from '@/components/common/Layout'; +import DetailHeader from '@/components/market/DetailHeader'; +import { api } from '@/libs/client/api'; +import wrapper from '@/store'; +import { ErrorBoundary } from '@sentry/nextjs'; +import { dehydrate, QueryClient } from '@tanstack/react-query'; + +const MarketDetail = () => { + return ( + +
+ ( + <> +

{error.message}

+ + + )} + > + 로딩...

}> + +
+
+
+
+ ); +}; + +export default MarketDetail; + +export const getServerSideProps = wrapper.getServerSideProps(() => async (context) => { + const { id } = context.query; + if (typeof id !== 'string' || !parseInt(id)) return { notFound: true }; + + const queryClient = new QueryClient(); + try { + await queryClient.fetchQuery(['market/detail', id], () => api.get(`markets/${id}`).json()); + } catch (e) { + return { + notFound: true, + }; + } + + return { + props: { + id: parseInt(id), + dehydratedState: dehydrate(queryClient), + }, + }; +}); diff --git a/src/pages/mypage/cahoots.tsx b/src/pages/mypage/cahoots.tsx index 993e874..e3cf373 100644 --- a/src/pages/mypage/cahoots.tsx +++ b/src/pages/mypage/cahoots.tsx @@ -1,5 +1,8 @@ +import { Suspense } from 'react'; + import Icon from '@/components/common/Icons'; -import Table from '@/components/common/Table'; +import ContestTable from '@/components/mypage/ContestTable'; +import wrapper from '@/store'; export default function Cahoots() { return ( @@ -13,8 +16,25 @@ export default function Cahoots() {
-
+ 로딩...

}> + +
); } + +export const getServerSideProps = wrapper.getServerSideProps((state) => async () => { + const { id } = state.getState().user; + if (!id) { + return { + redirect: { + destination: '/login', + permanent: false, + }, + }; + } + return { + props: {}, + }; +}); diff --git a/src/pages/mypage/index.tsx b/src/pages/mypage/index.tsx index b88f38f..838998f 100644 --- a/src/pages/mypage/index.tsx +++ b/src/pages/mypage/index.tsx @@ -1,103 +1,122 @@ import { Suspense } from 'react'; -import { GetServerSideProps } from 'next'; import Image from 'next/image'; import Link from 'next/link'; import Layout from '@/components/common/Layout'; -import ParticapatedContest from '@/components/mypage/ParticipatedContest'; +import RouteGuard from '@/components/common/RouteGuard'; +import ParticipatedContest from '@/components/mypage/ParticipatedContest'; import Stocks from '@/components/mypage/Stocks'; import Transactions from '@/components/mypage/Transactions'; import UserInfo from '@/components/mypage/UserInfo'; +import wrapper, { useTypeDispatch } from '@/store'; +import { logout } from '@/store/modules/user'; import { ErrorBoundary } from '@sentry/nextjs'; const Mypage = () => { + const dispatch = useTypeDispatch(); + + const onLogoutClick = () => { + dispatch(logout()); + }; + return ( - -
- 로딩...

}> - ( - <> -

{error.message}

- - - )} - > -
-
-

마이페이지

-
-
- {/* {images[0] && ( */} - - {/* )} */} + + +
+ 로딩...

}> + ( + <> +

{error.message}

+ + + )} + > +
+
+

마이페이지

+
+
+ {/* {images[0] && ( */} + + {/* )} */} +
+
    +
    +
  • + + 내 정보 + +
  • +
  • + + 공모 내역 + +
  • +
  • + + 거래 현황 + +
  • +
  • + + 자산 현황 + +
  • +
  • + + 공모 등록 + +
  • +
    +
  • + + 로그아웃 + +
  • +
+
+
+ + + + + + 공모 등록하러가기 {'>'} +
-
    -
    -
  • - - 내 정보 - -
  • -
  • - - 공모 내역 - -
  • -
  • - - 거래 현황 - -
  • -
  • - - 자산 현황 - -
  • -
  • - - 공모 등록 - -
  • -
    -
  • - - 로그아웃 - -
  • -
-
-
- - - - - - 공모 등록하러가기 {'>'} -
-
- - -
- + + +
+ + ); }; -export const getServerSideProps: GetServerSideProps = async () => { +export const getServerSideProps = wrapper.getServerSideProps((state) => async () => { + const { id } = state.getState().user; + if (!id) { + return { + redirect: { + destination: '/login', + permanent: false, + }, + }; + } return { props: {}, }; -}; +}); export default Mypage; diff --git a/src/pages/mypage/management.tsx b/src/pages/mypage/management.tsx index d3fdd32..be62359 100644 --- a/src/pages/mypage/management.tsx +++ b/src/pages/mypage/management.tsx @@ -1,6 +1,8 @@ -import Image from 'next/image'; +import { Suspense } from 'react'; import Icon from '@/components/common/Icons'; +import UserInfoManagement from '@/components/mypage/UserInfoManagement'; +import wrapper from '@/store'; export default function Management() { return ( @@ -13,57 +15,24 @@ export default function Management() {

개인정보 관리


-
-
-

기본 정보 관리

-
-
- {/* {images[0] && ( */} - - {/* )} */} -
- {/* 이름 */} -
- -

- 권유리 -

-
- {/* 가입 이메일 */} -
- -

- - test@gmail.com - - - 구글 연동 - -

-
-

권한 관리

- {/* 권한 */} -
- -

- 일반 사용자 -

-
- -
-
+ 로딩...

}> + +
); } + +export const getServerSideProps = wrapper.getServerSideProps((state) => async () => { + const { id } = state.getState().user; + if (!id) { + return { + redirect: { + destination: '/login', + permanent: false, + }, + }; + } + return { + props: {}, + }; +}); diff --git a/src/pages/mypage/stocks.tsx b/src/pages/mypage/stocks.tsx index bc61b59..cff389b 100644 --- a/src/pages/mypage/stocks.tsx +++ b/src/pages/mypage/stocks.tsx @@ -1,5 +1,8 @@ +import { Suspense } from 'react'; + import Icon from '@/components/common/Icons'; -import Table from '@/components/common/Table'; +import StockTable from '@/components/mypage/StockTable'; +import wrapper from '@/store'; export default function Cahoots() { return ( @@ -13,8 +16,25 @@ export default function Cahoots() {
-
+ 로딩...

}> + +
); } + +export const getServerSideProps = wrapper.getServerSideProps((state) => async () => { + const { id } = state.getState().user; + if (!id) { + return { + redirect: { + destination: '/login', + permanent: false, + }, + }; + } + return { + props: {}, + }; +}); diff --git a/src/pages/mypage/transactions.tsx b/src/pages/mypage/transactions.tsx index 3fa63cb..b4d0565 100644 --- a/src/pages/mypage/transactions.tsx +++ b/src/pages/mypage/transactions.tsx @@ -1,5 +1,8 @@ +import { Suspense } from 'react'; + import Icon from '@/components/common/Icons'; -import Table from '@/components/common/Table'; +import TransactionTable from '@/components/mypage/TransactionTable'; +import wrapper from '@/store'; export default function Transactions() { return ( @@ -13,8 +16,25 @@ export default function Transactions() {
-
+ 로딩...

}> + +
); } + +export const getServerSideProps = wrapper.getServerSideProps((state) => async () => { + const { id } = state.getState().user; + if (!id) { + return { + redirect: { + destination: '/login', + permanent: false, + }, + }; + } + return { + props: {}, + }; +}); diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts index 1d80727..62b08aa 100644 --- a/src/store/modules/user.ts +++ b/src/store/modules/user.ts @@ -5,14 +5,14 @@ import { createSlice, createAction } from '@reduxjs/toolkit'; import type { PayloadAction } from '@reduxjs/toolkit'; type UserState = { - id: number | undefined; - token: string | undefined; + id: number | null; + token: string | null; }; const hydrate = createAction(HYDRATE); const initialState: UserState = { - id: undefined, - token: undefined, + id: null, + token: null, }; const userSlice = createSlice({ name: 'user', @@ -25,8 +25,8 @@ const userSlice = createSlice({ state.id = action.payload; }, logout: (state) => { - state.token = undefined; - state.id = undefined; + state.token = null; + state.id = null; }, }, extraReducers: (builder) => { diff --git a/src/types/market.d.ts b/src/types/market.d.ts index f2c4bcb..83f2056 100644 --- a/src/types/market.d.ts +++ b/src/types/market.d.ts @@ -10,3 +10,11 @@ export type MarketType = { export type MarketListType = { result: MarketType[]; }; + +export type MarketDetailType = Omit & { + title: string; + location: string; + expectedRateOfReturn: number; + pictures: string[]; + userIds: number[]; +}; diff --git a/src/types/user.d.ts b/src/types/user.d.ts new file mode 100644 index 0000000..cb06b30 --- /dev/null +++ b/src/types/user.d.ts @@ -0,0 +1,45 @@ +export type UserInfoType = { + username: string; + cash: number; + value: number; + email: string; + providerType: string; + role: string; + rank: string; +}; + +type ContestType = { + title: string; + createdAt: string; + price: number; + amount: number; + status: string; +}; + +type TransactionType = { + vacationName: string; + transactionTime: string; + price: number; + amount: number; + transactionType: string; +}; + +type StockType = { + title: string; + profitRate: number; + currentPrice: number; + pricePerStock: number; + totalAmount: number; +}; + +export type ParticipatedContestType = { + result: ContestType[]; +}; + +export type TransactionsType = { + result: TransactionType[]; +}; + +export type StocksType = { + result: StockType[]; +};