Skip to content

Commit

Permalink
feat: bid list API, change auction detail UI (#95)
Browse files Browse the repository at this point in the history
* feat: impl bid list API

* feat: change API schema and query reset

* fix: change ui to accordion and tooltip

* feat: change UI to friendly

* refactor: component decomposition

* refactor: decomposition accordion component
  • Loading branch information
2yunseong authored Jun 6, 2024
1 parent eb720f2 commit 796d20d
Show file tree
Hide file tree
Showing 9 changed files with 206 additions and 71 deletions.
17 changes: 17 additions & 0 deletions src/apis/auctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,20 @@ export const patchAuctionPrice = async (
const response = await https.patch('/auction', request);
return response.data;
};

interface GetAuctionBidListRequest {
auctionId: number;
}

interface GetAuctionBidListResponse {
bids: Array<{
nickname: string;
price: number;
}>;
}
export const getAuctionBidList = async ({
auctionId,
}: GetAuctionBidListRequest) => {
const response = await https.get(`/auction/${auctionId}/bid`);
return response.data.response as GetAuctionBidListResponse;
};
19 changes: 19 additions & 0 deletions src/components/Auction/AuctionAccordionHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { AccordionButton, AccordionIcon, Text } from '@chakra-ui/react';
import { PropsWithChildren } from 'react';

interface AuctionAccordionHeaderProps extends PropsWithChildren {
title: string;
}

const AuctionAccordionHeader = ({ title }: AuctionAccordionHeaderProps) => {
return (
<AccordionButton>
<Text fontSize="x-large" fontWeight="600" flex="1" textAlign="left">
{title}
</Text>
<AccordionIcon />
</AccordionButton>
);
};

export default AuctionAccordionHeader;
39 changes: 39 additions & 0 deletions src/components/Auction/AuctionBidList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Box, Table, Tbody, Td, Th, Thead, Tr } from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';
import { getAuctionBidList } from 'src/apis/auctions';

interface AuctionBidListProps {
auctionId: number;
}
const AuctionBidList = ({ auctionId }: AuctionBidListProps) => {
const { data, status } = useQuery({
queryKey: ['auctionBidList', auctionId],
queryFn: () => getAuctionBidList({ auctionId }),
});

if (status === 'error') return <>에러 상태</>;
if (status === 'pending') return <>로딩 중 ...</>;

return (
<Box>
<Table size="sm">
<Thead>
<Tr>
<Th>입찰자 닉네임</Th>
<Th>입찰 가격</Th>
</Tr>
</Thead>
<Tbody>
{data.bids.map((bid, index) => (
<Tr key={index}>
<Td>{bid.nickname}</Td>
<Td>{bid.price.toLocaleString('ko-KR')}</Td>
</Tr>
))}
</Tbody>
</Table>
</Box>
);
};

export default AuctionBidList;
18 changes: 2 additions & 16 deletions src/components/Auction/AuctionPurchase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,6 @@ import { useQuery } from '@tanstack/react-query';
import { AuctionPurchaseDetails } from './AuctionPurchaseDetails';
import { useParams } from 'react-router-dom';

export interface AuctionPurchaseProps {
imageNames: string[];
itemType: string;
productName: string;
bidCount: number;
startAt: string;
endAt: string;
startPrice: number;
nowPrice: number;
writer: string;
description: string;
defect: string;
priceUnit: number;
}

export const AuctionPurchase = () => {
const { id } = useParams();
const auctionId = Number(id);
Expand All @@ -36,7 +21,7 @@ export const AuctionPurchase = () => {
<Box w="100%">
<Flex justifyContent="start" alignItems="center">
<Text fontSize="xx-large" fontWeight="600" mr="2rem">
기자재 거래
기자재 경매
</Text>
<Text fontSize="larger">상품 카테고리 : {auction.itemType}</Text>
</Flex>
Expand All @@ -56,6 +41,7 @@ export const AuctionPurchase = () => {
description={auction.description}
defect={auction.defect}
priceUnit={auction.priceUnit}
auctionId={auctionId}
/>
</Box>
</Flex>
Expand Down
133 changes: 87 additions & 46 deletions src/components/Auction/AuctionPurchaseDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,38 @@
import { Flex, Text, Box, Divider, Button } from '@chakra-ui/react';
import {
Flex,
Text,
Box,
Button,
Accordion,
AccordionItem,
AccordionPanel,
Tooltip,
} from '@chakra-ui/react';
import { DescriptionBox } from '../Purchase/DescriptionBox';
import { AuctionPurchaseImages } from './AuctionPurchaseImages';
import { AuctionPurchaseProps } from './AuctionPurchase';
import { theme } from '@chakra-ui/react';
import { AuctionPurchaseModal } from './AuctionPurchaseModal';
import { useAuction } from '@/hooks/Auction/useAuction';
import { AuctionTime } from './AuctionTime';
import AuctionBidList from './AuctionBidList';
import CurrentPriceStat from './CurrentPriceStat';
import AuctionAccordionHeader from './AuctionAccordionHeader';

interface AuctionPurchaseDetailProps {
imageNames: string[];
itemType: string;
productName: string;
bidCount: number;
startAt: string;
endAt: string;
startPrice: number;
nowPrice: number;
writer: string;
description: string;
defect: string;
priceUnit: number;
auctionId: number;
}

export const AuctionPurchaseDetails = ({
imageNames,
Expand All @@ -19,65 +46,79 @@ export const AuctionPurchaseDetails = ({
description,
defect,
priceUnit,
}: AuctionPurchaseProps) => {
auctionId,
}: AuctionPurchaseDetailProps) => {
const { isModalOpen, openModal, closeModal } = useAuction();

const priceFormatter = (price: number) => {
return price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
};

return (
<Flex flexDirection="column" w="100%" m="2.25rem 2.25rem 0 0">
<Text fontSize="xx-large" fontWeight="500" mb="1.25rem">
{productName}
</Text>
<Flex justifyContent="space-between" alignItems="center">
<Box fontSize="2.5rem" fontWeight="600">
현재 가격 : {priceFormatter(nowPrice)}
</Box>
<Text fontSize="larger" mb="1.25rem">
{writer}
</Text>
</Flex>
<Divider orientation="horizontal" mb="1rem" />
<Flex flexDirection="column" w="100%">
<Box>
<AuctionPurchaseImages imageNames={imageNames} />
<Flex justifyContent="space-between" marginBottom="4rem">
<Flex flexDirection="column">
<Box fontSize="1.5rem" color={theme.colors.gray[500]}>
<Flex gap={10} mb={8}>
<AuctionPurchaseImages imageNames={imageNames} />
<Flex flexDirection="column" justifyContent="center">
<Text fontSize="2.5rem" fontWeight="500">
{productName}
</Text>
<Text fontSize="larger" mb={4} color={theme.colors.gray[400]}>
판매자: {writer}
</Text>
<Text mb={2} color={theme.colors.gray[400]}>
시작가격 : {priceFormatter(startPrice)}
</Text>
<Box mb={4}>
<CurrentPriceStat nowPrice={nowPrice} startPrice={startPrice} />
</Box>
<Box fontSize="2rem" fontWeight="600">
<Box fontSize="larger" fontWeight="600">
입찰 건수 : {bidCount}
</Box>
<Button
px={28}
py={6}
color="white"
bgColor={theme.colors.orange[300]}
float="right"
marginTop="2rem"
onClick={() => {
openModal();
}}
<AuctionTime startAt={startAt} endAt={endAt} />
<Tooltip
hasArrow
label="입찰 및 낙찰 시에는 취소가 되지 않으니 상품 문의 시에는 입찰전
고객센터를 통해 문의 후 입찰 부탁드립니다."
bg="red.600"
padding={4}
>
입찰 하기
</Button>
<Box color="red" fontSize="1rem" mt="2rem">
입찰 및 낙찰 시에는 취소가 되지 않으니 상품 문의 시에는 입찰전
고객센터를 통해 문의 후 입찰 부탁드립니다
</Box>
<Button
px={28}
py={6}
color="white"
bgColor={theme.colors.orange[300]}
float="right"
marginTop="2rem"
onClick={() => {
openModal();
}}
>
입찰 하기
</Button>
</Tooltip>
</Flex>
<AuctionTime startAt={startAt} endAt={endAt} />
</Flex>
<Text fontSize="x-large" fontWeight="600" marginBottom="2rem">
설명
</Text>
<DescriptionBox description={description} />
<Text fontSize="x-large" fontWeight="600" marginBottom="2rem">
결함
</Text>
<DescriptionBox description={defect} />
<Accordion defaultIndex={[0, 1, 2]} mb={4} allowMultiple>
<AccordionItem>
<AuctionAccordionHeader title="입찰 현황" />
<AccordionPanel>
<AuctionBidList auctionId={auctionId} />
</AccordionPanel>
</AccordionItem>
<AccordionItem>
<AuctionAccordionHeader title="설명" />
<AccordionPanel>
<DescriptionBox description={description} />
</AccordionPanel>
</AccordionItem>
<AccordionItem>
<AuctionAccordionHeader title="결함" />
<AccordionPanel>
<DescriptionBox description={defect} />
</AccordionPanel>
</AccordionItem>
</Accordion>
</Box>
{isModalOpen && (
<AuctionPurchaseModal
Expand Down
9 changes: 7 additions & 2 deletions src/components/Auction/AuctionPurchaseModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import {
import { patchAuctionPrice } from 'src/apis/auctions';
import { useAuction } from '@/hooks/Auction/useAuction';
import { useParams } from 'react-router-dom';
import { useMutation } from '@tanstack/react-query';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { LS_MEMBER_ID } from 'src/constants/lsKey';

interface AuctionPurchaseModalProps {
priceUnit: number;
Expand All @@ -25,15 +26,19 @@ export const AuctionPurchaseModal = ({
nowPrice,
closeModal,
}: AuctionPurchaseModalProps) => {
const memberId = localStorage.getItem('userId');
const memberId = localStorage.getItem(LS_MEMBER_ID);
const { id } = useParams();
const auctionId = Number(id);
const { addedPrice, addPriceUnit, subtractPriceUnit } = useAuction();
const queryClient = useQueryClient();
const { mutate } = useMutation({
mutationKey: ['auction'],
mutationFn: patchAuctionPrice,
onSuccess: () => {
alert('입찰에 성공했습니다.');
queryClient.invalidateQueries({
queryKey: ['auctionBidList'],
});
closeModal();
},
onError: () => {
Expand Down
10 changes: 5 additions & 5 deletions src/components/Auction/AuctionTime.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, Flex } from '@chakra-ui/react';
import { Flex, Text, theme } from '@chakra-ui/react';
import { useState, useEffect } from 'react';
import { useAuction } from '@/hooks/Auction/useAuction';

Expand All @@ -18,10 +18,10 @@ export const AuctionTime = ({ startAt, endAt }: AuctionTimeProps) => {
}, [restTime]);

return (
<Flex flexDirection="column">
<Box>시작 시간 : {timeFormatter(startAt)}</Box>
<Box>종료 시간 : {timeFormatter(endAt)}</Box>
<Box>남은 시간 : {restTime}</Box>
<Flex flexDirection="column" color={theme.colors.gray[400]}>
<Text fontSize="small">시작 시간 : {timeFormatter(startAt)}</Text>
<Text fontSize="small">종료 시간 : {timeFormatter(endAt)}</Text>
<Text fontSize="small">남은 시간 : {restTime}</Text>
</Flex>
);
};
29 changes: 29 additions & 0 deletions src/components/Auction/CurrentPriceStat.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {
Stat,
StatArrow,
StatHelpText,
StatLabel,
StatNumber,
Tooltip,
} from '@chakra-ui/react';

interface CurrentPriceStatProps {
nowPrice: number;
startPrice: number;
}
const CurrentPriceStat = ({ nowPrice, startPrice }: CurrentPriceStatProps) => {
return (
<Stat>
<StatLabel>현재 가격</StatLabel>
<StatNumber>{nowPrice.toLocaleString('ko-KR')}원</StatNumber>
<Tooltip padding={2} label="시작가 대비 얼마나 올랐는지 알려드려요.">
<StatHelpText>
<StatArrow type="increase" />
{(((nowPrice - startPrice) / startPrice) * 100).toFixed(2)}%
</StatHelpText>
</Tooltip>
</Stat>
);
};

export default CurrentPriceStat;
3 changes: 1 addition & 2 deletions src/components/Purchase/DescriptionBox.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, Divider, Text } from '@chakra-ui/react';
import { Box, Text } from '@chakra-ui/react';

interface DescriptionBoxProps {
description: string;
Expand All @@ -10,7 +10,6 @@ export const DescriptionBox = ({ description }: DescriptionBoxProps) => {
<Text mb="2rem" p="2rem">
{description}
</Text>
<Divider orientation="horizontal" />
</Box>
);
};

0 comments on commit 796d20d

Please sign in to comment.