feat: Add dialog to post detail page

This commit is contained in:
jhynsoo 2023-11-07 00:54:44 +09:00
parent e85ea41398
commit 0a05a0c6eb
14 changed files with 711 additions and 2286 deletions

2855
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,12 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@mui/material": "^5.14.16",
"@mui/styled-engine-sc": "^6.0.0-alpha.4",
"@toss/error-boundary": "^1.4.4", "@toss/error-boundary": "^1.4.4",
"@toss/use-overlay": "^1.3.6",
"axios": "^1.5.0", "axios": "^1.5.0",
"chart.js": "^4.4.0", "chart.js": "^4.4.0",
"qs": "^6.11.2", "qs": "^6.11.2",
@ -20,7 +25,7 @@
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-query": "^3.39.3", "react-query": "^3.39.3",
"react-router-dom": "^6.16.0", "react-router-dom": "^6.16.0",
"styled-components": "^6.0.8", "styled-components": "^6.1.0",
"zustand": "^4.4.1" "zustand": "^4.4.1"
}, },
"devDependencies": { "devDependencies": {

View File

@ -1,8 +1,9 @@
import { QueryClient, QueryClientProvider } from 'react-query'; import { QueryClient, QueryClientProvider } from 'react-query';
import Router from './Router'; import Router from './Router';
import GlobalStyle from './styles/global'; import GlobalStyle from './styles/Global';
import { ThemeProvider } from 'styled-components'; import { ThemeProvider } from 'styled-components';
import theme from './styles/Themes.styles'; import theme from './styles/Themes.styles';
import { OverlayProvider } from '@toss/use-overlay';
const queryClient = new QueryClient(); const queryClient = new QueryClient();
@ -10,8 +11,10 @@ const App = () => {
return ( return (
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>
<OverlayProvider>
<GlobalStyle /> <GlobalStyle />
<Router /> <Router />
</OverlayProvider>
</QueryClientProvider> </QueryClientProvider>
</ThemeProvider> </ThemeProvider>
); );

View File

@ -12,8 +12,6 @@ import Login from './pages/Login';
import Logout from './pages/Logout'; import Logout from './pages/Logout';
import Signup from './pages/Signup'; import Signup from './pages/Signup';
import WriteSteps from './pages/WriteSteps'; import WriteSteps from './pages/WriteSteps';
import CurrencyInput from './components/CurrencyInput';
import { useState } from 'react';
import MyPage from './pages/MyPage'; import MyPage from './pages/MyPage';
import PasswordChanger from './pages/PasswordChanger'; import PasswordChanger from './pages/PasswordChanger';
import MyPost from './pages/MyPost'; import MyPost from './pages/MyPost';

View File

@ -69,6 +69,7 @@ const ProductPriceGraph = ({ id }) => {
} }
return min; return min;
}, graphData[0]?.price); }, graphData[0]?.price);
const minPriceString = minPrice?.toLocaleString() || '-';
return ( return (
<S.ProductPriceGraph className="priceGraph"> <S.ProductPriceGraph className="priceGraph">
@ -78,7 +79,9 @@ const ProductPriceGraph = ({ id }) => {
data={graphStyleData} data={graphStyleData}
></Line> ></Line>
</S.GraphArea> </S.GraphArea>
<S.Text>최근 6개월 최저가: {minPrice}</S.Text> <S.Text>
최근 6개월간 최저 <span>{minPriceString}</span>
</S.Text>
</S.ProductPriceGraph> </S.ProductPriceGraph>
); );
}; };

View File

@ -0,0 +1,34 @@
import * as S from '../../styles/Pagination.styles';
function Pagination({ page, lastPage, setPage }) {
return (
<S.Pagination>
<S.PaginationButton
disabled={page === 1}
onClick={() => setPage(1)}
>
처음
</S.PaginationButton>
<S.PaginationButton
disabled={page === 1}
onClick={() => setPage(page - 1)}
>
이전
</S.PaginationButton>
<S.PaginationButton
disabled={page === lastPage}
onClick={() => setPage(page + 1)}
>
다음
</S.PaginationButton>
<S.PaginationButton
disabled={page === lastPage}
onClick={() => setPage(lastPage)}
>
마지막
</S.PaginationButton>
</S.Pagination>
);
}
export default Pagination;

View File

@ -9,10 +9,54 @@ import PanelLayout, {
} from '../../components/PanelLayout'; } from '../../components/PanelLayout';
import ProductPriceGraph from '../../components/Graph/ProductPriceGraph'; import ProductPriceGraph from '../../components/Graph/ProductPriceGraph';
import { SubTitle } from '../../styles/Common.styles'; import { SubTitle } from '../../styles/Common.styles';
import ButtonArea from '../../components/ButtonArea';
import Button from '../../components/Button';
import Spacer from '../../components/Spacer';
import { useOverlay } from '@toss/use-overlay';
import { Dialog, Slide } from '@mui/material';
import React, { Suspense } from 'react';
const Transition = React.forwardRef(function Transition(props, ref) {
return (
<Slide
direction="up"
ref={ref}
{...props}
/>
);
});
const PostDetail = () => { const PostDetail = () => {
const overlay = useOverlay();
const { id } = useParams(); const { id } = useParams();
const { data } = usePost(id); const { data } = usePost(id);
const openOverlay = () => {
overlay.open(({ isOpen, close }) => (
<Dialog
open={isOpen}
onClose={close}
TransitionComponent={Transition}
PaperProps={{
style: {
padding: '8px 24px 24px 24px',
borderRadius: '20px',
},
}}
slotProps={{
backdrop: {
style: {
backdropFilter: 'blur(5px)',
},
},
}}
>
<SubTitle>최근 거래 가격</SubTitle>
<Suspense fallback={<></>}>
<ProductPriceGraph id={data.product.id} />
</Suspense>
</Dialog>
));
};
return ( return (
<S.PostDetail> <S.PostDetail>
@ -25,16 +69,17 @@ const PostDetail = () => {
<S.WrittenTime>{data.written_at}</S.WrittenTime> <S.WrittenTime>{data.written_at}</S.WrittenTime>
<PanelLayout> <PanelLayout>
<LeftPanel> <LeftPanel>
<SubTitle>최근 거래 가격</SubTitle>
<ProductPriceGraph id={data.product.id} />
<S.Text>{data.text}</S.Text> <S.Text>{data.text}</S.Text>
<S.Price>가격 {data.price.toLocaleString()}</S.Price>
</LeftPanel> </LeftPanel>
<RightPanel> <RightPanel>
<SubTitle>제품 사진</SubTitle> <SubTitle>제품 사진</SubTitle>
<ImageViewer images={data?.images?.map((image) => image.image)} /> <ImageViewer images={data?.images?.map((image) => image.image)} />
</RightPanel> </RightPanel>
</PanelLayout> </PanelLayout>
<ButtonArea>
<S.Price>가격 {data.price.toLocaleString()}</S.Price>
<Button onClick={openOverlay}>최근 가격 보기</Button>
</ButtonArea>
</S.PostDetail> </S.PostDetail>
); );
}; };

View File

@ -27,6 +27,7 @@ export const Button = {
background-color: ${({ theme }) => theme.colors.primary}; background-color: ${({ theme }) => theme.colors.primary};
`, `,
secondary: styled(BaseButton)` secondary: styled(BaseButton)`
background-color: ${({ theme }) => theme.colors.gray400}; background-color: ${({ theme }) => theme.colors.gray300};
color: ${({ theme }) => theme.colors.gray800};
`, `,
}; };

View File

@ -7,6 +7,7 @@ export const Title = styled.h1`
margin: 0; margin: 0;
user-select: none; user-select: none;
box-sizing: border-box; box-sizing: border-box;
color: ${({ theme }) => theme.colors.gray900};
`; `;
export const SubTitle = styled.h2` export const SubTitle = styled.h2`
@ -16,6 +17,7 @@ export const SubTitle = styled.h2`
margin: 0; margin: 0;
user-select: none; user-select: none;
box-sizing: border-box; box-sizing: border-box;
color: ${({ theme }) => theme.colors.gray900};
`; `;
export const Input = styled.input` export const Input = styled.input`

View File

@ -11,7 +11,7 @@ export const Header = styled.header`
border-bottom: ${({ theme }) => `1px solid ${theme.colors.gray200}`}; border-bottom: ${({ theme }) => `1px solid ${theme.colors.gray200}`};
text-align: center; text-align: center;
user-select: none; user-select: none;
z-index: 9999; z-index: 999;
.content { .content {
${({ theme }) => theme.maxWidth}; ${({ theme }) => theme.maxWidth};
@ -46,7 +46,7 @@ export const Nav = styled.nav`
background-color: #fff; background-color: #fff;
position: sticky; position: sticky;
top: 0; top: 0;
z-index: 9998; z-index: 998;
& > .left, & > .left,
& > .right { & > .right {

View File

@ -0,0 +1,8 @@
import styled from 'styled-components';
export const Pagination = styled.div`
display: flex;
justify-content: center;
`;
export const PaginationButton = styled.button``;

View File

@ -32,7 +32,9 @@ export const Text = styled.p`
`; `;
export const Price = styled.div` export const Price = styled.div`
margin-top: 8px; display: flex;
align-items: center;
width: 100%;
font-size: 18px; font-size: 18px;
line-height: 1.7; line-height: 1.7;
font-weight: bold; font-weight: bold;

View File

@ -22,5 +22,11 @@ export const GraphArea = styled.div`
export const Text = styled.div` export const Text = styled.div`
font-size: 16px; font-size: 16px;
font-weight: 600;
margin-left: 16px; margin-left: 16px;
color: ${({ theme }) => theme.colors.gray900};
& > span {
color: ${({ theme }) => theme.colors.primary};
}
`; `;

View File

@ -20,8 +20,7 @@ const colors = {
const boxShadow = css` const boxShadow = css`
padding: 20px; padding: 20px;
border-radius: 10px; border-radius: 10px;
border: 1px solid ${({ theme }) => theme.colors.gray200}; box-shadow: 0px 2px 10px 0px #2060ee1a;
box-shadow: 0px 4px 20px 0px #2060ee1a;
background-color: ${({ theme }) => theme.colors.background}; background-color: ${({ theme }) => theme.colors.background};
transition: all 0.3s ease; transition: all 0.3s ease;
`; `;