Skip to content

Commit

Permalink
Merge pull request #86 from Eagle2gle/dev
Browse files Browse the repository at this point in the history
[release] 3차 배포
  • Loading branch information
YuriKwon authored Mar 5, 2023
2 parents 0060dcd + 2fc267b commit 38d662e
Show file tree
Hide file tree
Showing 27 changed files with 900 additions and 239 deletions.
2 changes: 1 addition & 1 deletion src/components/cahoot/DetailBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const DetailBody = ({ id }: DetailBodyProps) => {

return (
<>
<InterestButton id={id} type="large" isInterest={isInterest} />
<InterestButton type="cahoot" id={id} size="large" isInterest={isInterest} />
<TabButton tabs={TABS} currentTab={tab} onTabClick={onTabClick} />
<div className={classNames(tab === '정보' ? 'flex flex-col' : 'hidden', 'gap-[inherit]')}>
<DetailInfo />
Expand Down
3 changes: 2 additions & 1 deletion src/components/cahoot/DetailHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ const DetailHeader = () => {
</div>
{status === 'CAHOOTS_ONGOING' && <Order />}
<InterestButton
type="large"
type="cahoot"
size="large"
isInterest={isInterest}
id={parseInt(String(id))}
hideOnMobile
Expand Down
2 changes: 1 addition & 1 deletion src/components/cahoot/ListItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ const ListItems = ({ keyword }: ListItemsProps) => {
{title}
</span>
<div className="absolute right-3 top-1 md:top-auto">
<InterestButton type="small" id={id} isInterest={isInterest} />
<InterestButton type="cahoot" size="small" id={id} isInterest={isInterest} />
</div>
</div>
<div className="flex flex-col gap-1 md:flex-row md:gap-4">
Expand Down
36 changes: 27 additions & 9 deletions src/components/common/InterestButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -11,16 +12,23 @@ import Icon from './Icons';
interface InterestButtonProps {
id: number;
isInterest?: boolean;
type: 'small' | 'large';
size: 'small' | 'large';
hideOnMobile?: boolean;
type: 'cahoot' | 'market';
}

type MutationBody = {
userId: number;
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();
Expand All @@ -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<Response, Error, MutationBody>({
mutationFn: (body) =>
Expand All @@ -44,10 +54,15 @@ const InterestButton = ({ id, isInterest, type, hideOnMobile = false }: Interest
.json(),
onSuccess,
});
const { data } = useSuspendedQuery<Response<CahootDetailType>>(
const { data: cahootDetailData } = useSuspendedQuery<Response<CahootDetailType>>(
['cahoot/detail', `${id}`],
() => api.get(`cahoots/${id}?info=detail`).json(),
{ enabled: type === 'large' }
{ enabled: size === 'large' && type === 'cahoot' }
);
const { data: marketDetailData } = useSuspendedQuery<Response<MarketDetailType>>(
['market/detail', `${id}`],
() => api.get(`markets/${id}`).json(),
{ enabled: size === 'large' && type === 'market' }
);

const onBookmarkClick: React.MouseEventHandler<HTMLButtonElement> = (e) => {
Expand All @@ -62,7 +77,7 @@ const InterestButton = ({ id, isInterest, type, hideOnMobile = false }: Interest
};

return userId ? (
type === 'small' ? (
size === 'small' ? (
<button
onClick={onBookmarkClick}
className={classNames(
Expand All @@ -75,15 +90,18 @@ const InterestButton = ({ id, isInterest, type, hideOnMobile = false }: Interest
) : (
<button
className={classNames(
'btn-ghost btn mx-4 gap-1 border-grey',
data?.data.isInterest ? 'fill-main text-main' : 'fill-none',
'btn-ghost btn mx-4 gap-1 border-grey md:mx-0',
isInterest ? 'fill-main text-main' : 'fill-none',
hideOnMobile ? 'hidden md:flex' : 'md:hidden'
)}
onClick={onBookmarkClick}
>
<Icon.Bookmark />
<span className="font-medium">관심상품</span>
<span>{data?.data.interestCount.toLocaleString()}</span>
<span className="font-medium text-black">관심상품</span>
<span className="text-black">
{cahootDetailData?.data.interestCount.toLocaleString() ??
marketDetailData?.data.userIds.length.toLocaleString()}
</span>
</button>
)
) : null;
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/Interests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const Interests = ({ scrollRef, type }: InterestsProps) => {
<div className="relative flex h-24 w-52 items-center justify-center break-keep rounded bg-gradient-to-br from-blue-start to-blue-end p-6 text-center text-sm text-white">
{title}
<div className="absolute right-1 top-1">
<InterestButton type="small" id={vacationId} isInterest />
<InterestButton type={type} size="small" id={vacationId} isInterest />
</div>
</div>
</Link>
Expand Down
26 changes: 26 additions & 0 deletions src/components/common/RouteGuard.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<>
<div>{id && children}</div>
</>
);
};

export default RouteGuard;
62 changes: 0 additions & 62 deletions src/components/common/Table.tsx

This file was deleted.

80 changes: 80 additions & 0 deletions src/components/market/DetailHeader.tsx
Original file line number Diff line number Diff line change
@@ -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<Response<MarketDetailType>>(['market/detail', id], () =>
api.get(`markets/${id}`).json()
);
const userId = useTypeSelector((state) => state.user.id);

return (
<div className="mx-4 mt-4 flex gap-3 md:mx-0 md:gap-5">
<div className="avatar">
<div className="relative h-36 w-full bg-grey md:h-80">
{pictures[0] && (
<Image
alt="image"
src={pictures[0]}
className="object-contain"
fill
placeholder="blur"
blurDataURL={pictures[0]}
sizes="(max-width: 768px) 100vw,
(max-width: 1200px) 50vw,
33vw"
/>
)}
</div>
</div>
<div className="border-l border-black/50"></div>
<div className="flex w-full flex-col justify-between text-lg font-bold">
<div className="flex flex-col gap-1">
<span className="underline underline-offset-2">{title}</span>
<div className="flex flex-col-reverse gap-1 md:flex-col">
<span className="text-xs font-medium md:text-lg">{location}</span>
</div>
</div>
<div className="hidden flex-col text-black md:flex">
소개
<span className="text-sm font-medium">{shortDescription}</span>
</div>
<div className="relative flex flex-col gap-2 text-xs md:text-lg">
<div className="flex justify-between text-black/50">
예상 수익률
<span className="text-black">{expectedRateOfReturn}%</span>
</div>
<div className="flex justify-between text-black/50">
현재가
<span className="text-black">{price.toLocaleString()}</span>
</div>
{userId && (
<InterestButton
size="large"
isInterest={userIds.includes(userId)}
id={parseInt(String(id))}
hideOnMobile
type="market"
/>
)}
</div>
</div>
</div>
);
};

export default DetailHeader;
86 changes: 86 additions & 0 deletions src/components/mypage/ContestTable.tsx
Original file line number Diff line number Diff line change
@@ -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<Response<ParticipatedContestType>>(
[`user/contest`],
() =>
api
.get(`auth/contestParticipation/me`, {
headers: { Authorization: `Bearer ${token}` },
})
.json<Response<ParticipatedContestType>>(),
{ enabled: !!token }
);

if (!data || data?.data.result.length === 0) {
return <div className="ml-auto mr-auto w-48 py-8 font-bold">아직 참여한 공모가 없어요!</div>;
}

return (
<>
<div
className={`${
border ? 'rounded border border-grey' : ''
} w-full max-w-4xl overflow-x-auto text-xs`}
>
<table className={`table-compact table w-full text-center`}>
<thead className={`${border ? 'border-b border-grey' : ''}`}>
<tr className="text-bold text-dark-grey">
<th className="bg-white px-5">공모명</th>
<th className="bg-white px-5">거래 시간</th>
<th className="bg-white px-5">가격</th>
<th className="bg-white px-5">수량(주)</th>
<th className="bg-white px-5">진행도</th>
</tr>
</thead>
<tbody>
{data?.data.result.map((item, idx) => {
if (printAllData || (!printAllData && idx < 3)) {
return (
<tr key={idx}>
<td className="w-full truncate">{item.title}</td>
<td>{item.createdAt.split('T')[0].substring(2)}</td>
<td>{item.price.toLocaleString()}</td>
<td>{item.amount.toLocaleString()}</td>
<td>
<div
className={classNames(
'badge w-full border-transparent text-white',
STATUS[item.status as keyof typeof STATUS].COLOR
)}
>
{STATUS[item.status as keyof typeof STATUS].TEXT}
</div>
</td>
</tr>
);
}
})}
</tbody>
</table>
</div>
{!printAllData && data && data?.data.result.length > 3 && (
<Link href="/mypage/cahoots" className="font-medium">
<button className="btn-primary btn-block btn-sm btn">More</button>
</Link>
)}
</>
);
};

export default ContestTable;
Loading

0 comments on commit 38d662e

Please sign in to comment.