From 836662e9cfa8c9a17c4a4db5a58abc288211182a Mon Sep 17 00:00:00 2001
From: kimdaye77 <63107805+kimdaye77@users.noreply.github.com>
Date: Tue, 22 Aug 2023 22:18:41 +0900
Subject: [PATCH 01/34] =?UTF-8?q?[ADD]=20=EB=B0=B0=EA=B2=BD=20=EC=A0=9C?=
=?UTF-8?q?=EA=B1=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
frontend/public/images/logo.svg | 28 +++++++++++++++++++---------
1 file changed, 19 insertions(+), 9 deletions(-)
diff --git a/frontend/public/images/logo.svg b/frontend/public/images/logo.svg
index c51734b..4d2f370 100644
--- a/frontend/public/images/logo.svg
+++ b/frontend/public/images/logo.svg
@@ -1,11 +1,21 @@
-
);
}
+
+export function NorthWest({ active, ...props }: ISvg) {
+ const color = active ? theme.color.white : theme.color.gray200;
+ return (
+
+
+
+ );
+}
diff --git a/frontend/src/components/searchBar/SearchBar.tsx b/frontend/src/components/searchBar/SearchBar.tsx
index d8b55fe..6e4c201 100644
--- a/frontend/src/components/searchBar/SearchBar.tsx
+++ b/frontend/src/components/searchBar/SearchBar.tsx
@@ -1,20 +1,69 @@
import { styled } from 'styled-components';
import { BodyKrRegular4 } from '../../styles/typefaces';
-import { SearchIcon } from '../common/icons/Icons';
+import { NorthWest, SearchIcon } from '../common/icons/Icons';
import React, { Dispatch, useCallback, useEffect, useRef, useState } from 'react';
+import { flexCenterCss } from '../../utils/commonStyle';
interface SearchBarProps extends React.HTMLAttributes {
value: string;
result: string[];
setQuery: Dispatch>;
}
+
+interface IKeyEvent {
+ [key: string]: () => void;
+}
export default function SearchBar({ value, result, setQuery, ...props }: SearchBarProps) {
+ const [focusIndex, setFocusIndex] = useState(-1);
+ const listRef = useRef(null);
const [visibleAutoBox, setVisibleAutoBox] = useState(true);
const searchBarRef = useRef(null);
const displayData = result.map((res, index) => (
- {res}
+
+ {res}
+
+
+
+
));
+ const KeyEvent: IKeyEvent = {
+ Enter: () => {
+ focusIndex >= 0 ? setQuery(result[focusIndex]) : setQuery(value);
+ setVisibleAutoBox(false);
+ },
+ ArrowDown: () => {
+ if (result.length === 0) {
+ return;
+ }
+ if (listRef.current && listRef.current.childElementCount === focusIndex + 1) {
+ setFocusIndex(() => 0);
+ return;
+ }
+ setFocusIndex((index) => index + 1);
+ },
+ ArrowUp: () => {
+ if (focusIndex === -1) {
+ return;
+ }
+ if (focusIndex === 0) {
+ setFocusIndex((index) => index - 1);
+ return;
+ }
+ setFocusIndex((index) => index - 1);
+ },
+ Escape: () => {
+ setFocusIndex(-1);
+ },
+ };
+
+ const handleKeyUp = (e: React.KeyboardEvent) => {
+ setVisibleAutoBox(true);
+ if (KeyEvent[e.key]) {
+ KeyEvent[e.key]();
+ }
+ };
+
const handleClick = useCallback(
(event: MouseEvent) => {
const target = event.target as HTMLInputElement;
@@ -28,6 +77,7 @@ export default function SearchBar({ value, result, setQuery, ...props }: SearchB
},
[setQuery]
);
+
useEffect(() => {
window.addEventListener('click', (e) => handleClick(e));
return () => {
@@ -35,19 +85,25 @@ export default function SearchBar({ value, result, setQuery, ...props }: SearchB
};
}, [handleClick]);
+ useEffect(() => {}, [focusIndex]);
+
useEffect(() => {
- if (!value) return;
- setVisibleAutoBox(true);
- }, [value]);
+ if (!value) {
+ setVisibleAutoBox(false);
+ return;
+ }
+
+ setFocusIndex(-1);
+ }, [value, visibleAutoBox, result]);
return (
-
+ handleKeyUp(e)} {...props} />
0 && visibleAutoBox}>
- {displayData}
+ {displayData}
);
@@ -73,11 +129,6 @@ const AutoSearchWrapper = styled.ul``;
const AutoSearchData = styled.li`
padding: 8px 16px;
width: 100%;
- &:hover {
- background-color: ${({ theme }) => theme.color.activeBlue2};
- color: ${({ theme }) => theme.color.white};
- cursor: pointer;
- }
`;
const Wrapper = styled.div`
position: relative;
@@ -106,9 +157,23 @@ const Input = styled.input.attrs(({ value }) => ({
color: ${({ theme }) => theme.color.gray600};
}
`;
-
+const ListItem = styled.div<{ $focus: boolean }>`
+ ${flexCenterCss}
+ background-color: ${({ $focus, theme }) => ($focus ? theme.color.activeBlue2 : 'transparent')};
+ color: ${({ $focus, theme }) => ($focus ? theme.color.white : theme.color.gray900)};
+ &:hover {
+ background-color: ${({ theme }) => theme.color.activeBlue2};
+ color: ${({ theme }) => theme.color.white};
+ opacity: 0.5;
+ cursor: pointer;
+ }
+`;
const Button = styled.button`
width: 67px;
height: 100%;
background-color: ${({ theme }) => theme.color.gray100};
`;
+
+const IconBtn = styled.button`
+ padding: 8px 16px;
+`;
From 2e1fcda769be76f10423f556b107fcf0a1a2a342 Mon Sep 17 00:00:00 2001
From: kimdaye77 <63107805+kimdaye77@users.noreply.github.com>
Date: Wed, 23 Aug 2023 12:09:57 +0900
Subject: [PATCH 08/34] =?UTF-8?q?[FIX]=20#409:=20result=20=EC=B4=88?=
=?UTF-8?q?=EA=B8=B0=ED=99=94?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
frontend/src/components/searchBar/SearchBar.tsx | 13 ++++++++++---
.../OptionSelectContainer/OptionSelectContainer.tsx | 1 +
.../OptionSelectContainer/SubOptionContainer.tsx | 1 -
3 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/frontend/src/components/searchBar/SearchBar.tsx b/frontend/src/components/searchBar/SearchBar.tsx
index 6e4c201..cb2ac32 100644
--- a/frontend/src/components/searchBar/SearchBar.tsx
+++ b/frontend/src/components/searchBar/SearchBar.tsx
@@ -8,12 +8,19 @@ interface SearchBarProps extends React.HTMLAttributes {
value: string;
result: string[];
setQuery: Dispatch>;
+ setResult: Dispatch>;
}
interface IKeyEvent {
[key: string]: () => void;
}
-export default function SearchBar({ value, result, setQuery, ...props }: SearchBarProps) {
+export default function SearchBar({
+ value,
+ result,
+ setQuery,
+ setResult,
+ ...props
+}: SearchBarProps) {
const [focusIndex, setFocusIndex] = useState(-1);
const listRef = useRef(null);
const [visibleAutoBox, setVisibleAutoBox] = useState(true);
@@ -89,12 +96,12 @@ export default function SearchBar({ value, result, setQuery, ...props }: SearchB
useEffect(() => {
if (!value) {
+ setResult([]);
setVisibleAutoBox(false);
return;
}
-
setFocusIndex(-1);
- }, [value, visibleAutoBox, result]);
+ }, [value, visibleAutoBox, result, setResult]);
return (
diff --git a/frontend/src/containers/OptionPage/OptionSelectContainer/OptionSelectContainer.tsx b/frontend/src/containers/OptionPage/OptionSelectContainer/OptionSelectContainer.tsx
index bbef524..c69404e 100644
--- a/frontend/src/containers/OptionPage/OptionSelectContainer/OptionSelectContainer.tsx
+++ b/frontend/src/containers/OptionPage/OptionSelectContainer/OptionSelectContainer.tsx
@@ -136,6 +136,7 @@ export default function OptionSelectContainer({
value={query}
result={result}
setQuery={setQuery}
+ setResult={setResult}
onChange={(e) => {
handleInputChange(e.currentTarget.value);
}}
diff --git a/frontend/src/containers/OptionPage/OptionSelectContainer/SubOptionContainer.tsx b/frontend/src/containers/OptionPage/OptionSelectContainer/SubOptionContainer.tsx
index f26e3ce..5562f12 100644
--- a/frontend/src/containers/OptionPage/OptionSelectContainer/SubOptionContainer.tsx
+++ b/frontend/src/containers/OptionPage/OptionSelectContainer/SubOptionContainer.tsx
@@ -110,7 +110,6 @@ export default function SubOptionContainer({
useEffect(() => {
if (!filteredByCategory || !query) {
setDisplayData(filteredByCategory);
-
return;
}
From 4e4f00dce034eb47e0c5c463cdb41a6d8b9d9143 Mon Sep 17 00:00:00 2001
From: kimdaye77 <63107805+kimdaye77@users.noreply.github.com>
Date: Wed, 23 Aug 2023 12:13:34 +0900
Subject: [PATCH 09/34] =?UTF-8?q?[REFACTOR]=20=ED=95=84=EC=9A=94=EC=97=86?=
=?UTF-8?q?=EB=8A=94=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
frontend/src/components/tabs/OptionTab.tsx | 23 ++++------------------
1 file changed, 4 insertions(+), 19 deletions(-)
diff --git a/frontend/src/components/tabs/OptionTab.tsx b/frontend/src/components/tabs/OptionTab.tsx
index c940d37..308de17 100644
--- a/frontend/src/components/tabs/OptionTab.tsx
+++ b/frontend/src/components/tabs/OptionTab.tsx
@@ -1,4 +1,4 @@
-import { Dispatch, HTMLAttributes, SetStateAction, useEffect, useRef, useState } from 'react';
+import { Dispatch, HTMLAttributes, SetStateAction, useEffect, useState } from 'react';
import { BodyKrMedium3, BodyKrRegular3, BodyKrRegular4 } from '../../styles/typefaces';
import styled, { css, useTheme } from 'styled-components';
import { ArrowLeft, ArrowRight } from '../common/icons/Icons';
@@ -17,8 +17,6 @@ export default function OptionTab({ options, setBannerInfo }: ISubOptionTab) {
const [page, setPage] = useState(0);
const arrowLeftColor = page <= 0 ? theme.color.gray200 : theme.color.gray600;
const arrowRightColor = page >= TAB_MAX_PAGE - 1 ? theme.color.gray200 : theme.color.gray600;
- const tabDivisionRef = useRef(null);
- const [tabDivisionWidth, setTabDivisionWidth] = useState(0);
const displayUnderline = (groupIndex: number, index: number) => {
return page === groupIndex && index === selectedIdx ? (
@@ -72,13 +70,6 @@ export default function OptionTab({ options, setBannerInfo }: ISubOptionTab) {
setPage(0);
}, [options]);
- useEffect(() => {
- if (tabDivisionRef.current) {
- const tabDivisionWidth = tabDivisionRef.current.offsetWidth;
- setTabDivisionWidth(tabDivisionWidth);
- }
- }, [tabDivisionRef]);
-
return (
<>
@@ -88,8 +79,8 @@ export default function OptionTab({ options, setBannerInfo }: ISubOptionTab) {
>
-
-
+
+ <>
{chunkedOptions.map((optionGroup: ISubOptionList[], groupIndex) => (
{optionGroup.map((option: ISubOptionList, index: number) => (
@@ -106,7 +97,7 @@ export default function OptionTab({ options, setBannerInfo }: ISubOptionTab) {
))}
))}
-
+ >
`
- /* display: flex; */
- /* transition: transform 0.4s ease; */
- /* transform: translateX(${({ $offset }) => $offset}px); */
-`;
const TabWrapperInner = styled.div`
- /* overflow: hidden; */
width: 408px;
height: 100%;
`;
From 4db141b1b79a25be811a88650a3ea1ad2ca8aa19 Mon Sep 17 00:00:00 2001
From: kimdaye77 <63107805+kimdaye77@users.noreply.github.com>
Date: Wed, 23 Aug 2023 12:23:47 +0900
Subject: [PATCH 10/34] =?UTF-8?q?[FIX]=20#418:=20key=20=EB=B6=80=EC=97=AC?=
=?UTF-8?q?=20=EB=B0=8F=20=EB=AC=B4=ED=95=9C=20=EB=A0=8C=EB=8D=94=EB=A7=81?=
=?UTF-8?q?=20=EC=A0=9C=EA=B1=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
frontend/src/components/searchBar/SearchBar.tsx | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/frontend/src/components/searchBar/SearchBar.tsx b/frontend/src/components/searchBar/SearchBar.tsx
index cb2ac32..79c2b14 100644
--- a/frontend/src/components/searchBar/SearchBar.tsx
+++ b/frontend/src/components/searchBar/SearchBar.tsx
@@ -26,8 +26,8 @@ export default function SearchBar({
const [visibleAutoBox, setVisibleAutoBox] = useState(true);
const searchBarRef = useRef(null);
const displayData = result.map((res, index) => (
-
- {res}
+
+ {res}
@@ -37,6 +37,7 @@ export default function SearchBar({
const KeyEvent: IKeyEvent = {
Enter: () => {
focusIndex >= 0 ? setQuery(result[focusIndex]) : setQuery(value);
+ setResult([]);
setVisibleAutoBox(false);
},
ArrowDown: () => {
@@ -101,7 +102,7 @@ export default function SearchBar({
return;
}
setFocusIndex(-1);
- }, [value, visibleAutoBox, result, setResult]);
+ }, [value, visibleAutoBox, setResult]);
return (
From ab18251b894965f21b3e535386eae03c9feaa398 Mon Sep 17 00:00:00 2001
From: kimdaye77 <63107805+kimdaye77@users.noreply.github.com>
Date: Wed, 23 Aug 2023 13:19:34 +0900
Subject: [PATCH 11/34] =?UTF-8?q?[STYLE]=20#420:=20=EB=AA=A8=EB=8D=B8=20?=
=?UTF-8?q?=ED=83=80=EC=9E=85=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EB=B0=8F=20?=
=?UTF-8?q?=EC=84=A4=EB=AA=85=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=88=98?=
=?UTF-8?q?=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../containers/ModelTypePage/ModelTypeBannerContainer.tsx | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/frontend/src/containers/ModelTypePage/ModelTypeBannerContainer.tsx b/frontend/src/containers/ModelTypePage/ModelTypeBannerContainer.tsx
index 7678da4..31784a5 100644
--- a/frontend/src/containers/ModelTypePage/ModelTypeBannerContainer.tsx
+++ b/frontend/src/containers/ModelTypePage/ModelTypeBannerContainer.tsx
@@ -86,11 +86,12 @@ export default function ModelTypePage() {
}
const OptionDesc = styled.p`
- width: 300px;
+ width: 400px;
color: ${({ theme }) => theme.color.gray800};
${BodyKrRegular4}
padding-top: 150px;
word-break: keep-all;
+ white-space: pre-wrap;
`;
const HmgDataSection = styled.div`
@@ -116,8 +117,8 @@ const ImgSection = styled.img`
position: absolute;
top: 0;
right: 0;
- width: 632px;
+ min-width: 632px;
height: 360px;
- object-fit: cover;
+ object-fit: contain;
object-position: center;
`;
From ab910446cb3fa82775e6f8afc6d4c83284520792 Mon Sep 17 00:00:00 2001
From: kimdaye77 <63107805+kimdaye77@users.noreply.github.com>
Date: Wed, 23 Aug 2023 13:29:33 +0900
Subject: [PATCH 12/34] =?UTF-8?q?[STYLE]=20#420:=20=EC=98=88=EC=82=B0=20?=
=?UTF-8?q?=EC=84=A4=EC=A0=95=EB=B0=94=20=EC=98=88=EC=82=B0=20=EC=8A=A4?=
=?UTF-8?q?=ED=83=80=EC=9D=BC=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../priceStaticBar/PriceStaticBar.tsx | 2 +-
.../priceStaticBar/PriceStaticSlider.tsx | 17 +++++++++++++++--
2 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/frontend/src/components/priceStaticBar/PriceStaticBar.tsx b/frontend/src/components/priceStaticBar/PriceStaticBar.tsx
index 846d46e..e37cf54 100644
--- a/frontend/src/components/priceStaticBar/PriceStaticBar.tsx
+++ b/frontend/src/components/priceStaticBar/PriceStaticBar.tsx
@@ -14,7 +14,7 @@ interface IOffset {
offsetY: string;
}
export default function PriceStaticBar({ ...props }: IPriceStaticBar) {
- const highestPrice = 80_000_000; //TODO : api 연동
+ const highestPrice = 80_000_000;
const { totalPrice, selectedItem } = useContext(ItemContext);
const { pathname } = useLocation();
const theme = useTheme();
diff --git a/frontend/src/components/priceStaticBar/PriceStaticSlider.tsx b/frontend/src/components/priceStaticBar/PriceStaticSlider.tsx
index 687763f..4f67c5c 100644
--- a/frontend/src/components/priceStaticBar/PriceStaticSlider.tsx
+++ b/frontend/src/components/priceStaticBar/PriceStaticSlider.tsx
@@ -25,7 +25,12 @@ export default function Slider({
return (
- 예산: {budget / TEN_THOUSAND_UNIT}만
+
+
+ 내가 설정한 예산은
+ {budget / TEN_THOUSAND_UNIT}만원이에요.
+
+
(
margin-top: -6px;
}
`;
+const BlueText = styled.span<{ $isover: boolean }>`
+ color: ${({ theme, $isover }) => ($isover ? theme.color.sand : theme.color.activeBlue2)};
+`;
const PriceInfo = styled.div<{ $isover: boolean }>`
${flexCenterCss};
From 83c45d3f76af99c4a32a6a88c8468e04a84c17c4 Mon Sep 17 00:00:00 2001
From: kimdaye77 <63107805+kimdaye77@users.noreply.github.com>
Date: Wed, 23 Aug 2023 13:38:23 +0900
Subject: [PATCH 13/34] =?UTF-8?q?[STYLE]=20#420:=20=EC=98=88=EC=82=B0=20?=
=?UTF-8?q?=EA=B0=80=EA=B2=A9=20=EC=A0=95=EB=B3=B4=20=EC=9C=84=EC=B9=98=20?=
=?UTF-8?q?=EC=A1=B0=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
frontend/src/components/priceStaticBar/PriceStaticSlider.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frontend/src/components/priceStaticBar/PriceStaticSlider.tsx b/frontend/src/components/priceStaticBar/PriceStaticSlider.tsx
index 4f67c5c..de5d502 100644
--- a/frontend/src/components/priceStaticBar/PriceStaticSlider.tsx
+++ b/frontend/src/components/priceStaticBar/PriceStaticSlider.tsx
@@ -70,7 +70,7 @@ const PriceBarWrapper = styled.div`
const BudgetInfo = styled.div`
${BodyKrRegular3}
position: absolute;
- top: -25px;
+ top: -34px;
right: 0px;
background-color: black;
opacity: 0.9;
From 5b23067260cbae28dafa65b064ab2dd662217f18 Mon Sep 17 00:00:00 2001
From: kimdaye77 <63107805+kimdaye77@users.noreply.github.com>
Date: Wed, 23 Aug 2023 14:11:35 +0900
Subject: [PATCH 14/34] =?UTF-8?q?[FEAT]=20#422:=20=EB=A1=9C=EC=BB=AC=20?=
=?UTF-8?q?=EC=8A=A4=ED=86=A0=EB=A6=AC=EC=A7=80=20=EC=A0=80=EC=9E=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
frontend/src/context/ItemProvider.tsx | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/frontend/src/context/ItemProvider.tsx b/frontend/src/context/ItemProvider.tsx
index 8b9627b..cfa7310 100644
--- a/frontend/src/context/ItemProvider.tsx
+++ b/frontend/src/context/ItemProvider.tsx
@@ -133,14 +133,26 @@ export default function ItemProvider({ children }: IItemProvider) {
const [totalPrice, setTotalPrice] = useState(0);
useEffect(() => {
- const { price: trimPrice } = selectedItem.trim;
- const { price: outerColorPrice } = selectedItem.outerColor;
- const { price: innerColorPrice } = selectedItem.innerColor;
+ const { id: trimId, price: trimPrice } = selectedItem.trim;
+ const { id: outerColorId, price: outerColorPrice } = selectedItem.outerColor;
+ const { id: innerColorId, price: innerColorPrice } = selectedItem.innerColor;
const { powerTrain, bodyType, operation } = selectedItem.modelType;
const modelTypePrice = powerTrain.price + bodyType.price + operation.price;
const optionsPrice = selectedItem.options.reduce((acc, option) => acc + option.price, 0);
const total = trimPrice + modelTypePrice + outerColorPrice + innerColorPrice + optionsPrice;
setTotalPrice(total);
+ const savedId = {
+ trimId: trimId,
+ modelTypeId: {
+ powerTrain: powerTrain.id,
+ bodyType: bodyType.id,
+ operation: operation.id,
+ },
+ outerColorId: outerColorId,
+ innerColorId: innerColorId,
+ optionId: selectedItem.options.map((option) => option.id),
+ };
+ localStorage.setItem('selectedItem', JSON.stringify(savedId));
}, [selectedItem]);
return (
From 28244ac1c5cec869450bd1dc3a04e9a0e7776b74 Mon Sep 17 00:00:00 2001
From: kimdaye77 <63107805+kimdaye77@users.noreply.github.com>
Date: Wed, 23 Aug 2023 16:41:23 +0900
Subject: [PATCH 15/34] =?UTF-8?q?[FEAT]=20#422:=20=EB=A1=9C=EC=BB=AC?=
=?UTF-8?q?=EC=8A=A4=ED=86=A0=EB=A6=AC=EC=A7=80=20=EA=B0=92=20=EB=B6=88?=
=?UTF-8?q?=EB=9F=AC=EC=99=80=EC=84=9C=20=EC=A0=80=EC=9E=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/components/common/banner/Banner.tsx | 2 +-
frontend/src/components/modal/GuideModal.tsx | 7 +-
frontend/src/context/ItemProvider.tsx | 126 +++++++++++++++++-
frontend/src/context/ProgressProvider.tsx | 10 +-
frontend/src/hooks/useSharedInfo.ts | 2 +-
5 files changed, 139 insertions(+), 8 deletions(-)
diff --git a/frontend/src/components/common/banner/Banner.tsx b/frontend/src/components/common/banner/Banner.tsx
index fb2319c..a7ab3f4 100644
--- a/frontend/src/components/common/banner/Banner.tsx
+++ b/frontend/src/components/common/banner/Banner.tsx
@@ -62,7 +62,7 @@ const InfoWrapper = styled.div`
position: absolute;
top: 72px;
width: 448px;
- overflow-x: hidden;
+ overflow: hidden;
`;
const SubTitle = styled.p`
diff --git a/frontend/src/components/modal/GuideModal.tsx b/frontend/src/components/modal/GuideModal.tsx
index 597c166..ae5ed99 100644
--- a/frontend/src/components/modal/GuideModal.tsx
+++ b/frontend/src/components/modal/GuideModal.tsx
@@ -14,7 +14,7 @@ export default function GuideModal({ ...props }: IGuideModal) {
const hmgDataBgRef = useRef(null);
const { visible, setVisible } = useContext(GuideModalContext);
const { pathname } = useLocation();
-
+ const isSelectedTrim = localStorage.getItem('isSelectedTrim');
const stopEvent: MouseEventHandler = (e) => {
e.stopPropagation();
};
@@ -23,7 +23,10 @@ export default function GuideModal({ ...props }: IGuideModal) {
if (!(pathname === PATH.home || pathname === PATH.trim)) {
setVisible(false);
}
- }, [pathname, setVisible]);
+ if (isSelectedTrim && isSelectedTrim === 'true') {
+ setVisible(false);
+ }
+ }, [pathname, setVisible, isSelectedTrim]);
return (
diff --git a/frontend/src/context/ItemProvider.tsx b/frontend/src/context/ItemProvider.tsx
index cfa7310..ba993c6 100644
--- a/frontend/src/context/ItemProvider.tsx
+++ b/frontend/src/context/ItemProvider.tsx
@@ -1,6 +1,8 @@
-import { ReactNode, createContext, useEffect, useReducer, useState } from 'react';
+import { ReactNode, createContext, useCallback, useEffect, useReducer, useState } from 'react';
import itemReducer, { actionType } from '../reducer/itemReducer';
import { OUTER_COLOR_FIRST_IDX } from '../utils/constants';
+import { SHARE_INFO_API } from '../utils/apis';
+import { ISharedInfo } from '../hooks/useSharedInfo';
export type defaultItemType = {
id: number;
@@ -118,7 +120,6 @@ const initialSelectedItem = {
displacement: '',
},
};
-
const initialItem: IItemContext = {
selectedItem: initialSelectedItem,
totalPrice: 0,
@@ -129,6 +130,48 @@ const initialItem: IItemContext = {
export const ItemContext = createContext(initialItem);
export default function ItemProvider({ children }: IItemProvider) {
+ const [data, setData] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const isSelectedTrim = localStorage.getItem('isSelectedTrim');
+ const savedItem = localStorage.getItem('selectedItem');
+ const getParams = useCallback(() => {
+ if (!isSelectedTrim || !savedItem || isSelectedTrim === 'false') return;
+ const params = {
+ carId: JSON.parse(savedItem).trimId,
+ powerTrainId: JSON.parse(savedItem).modelTypeId.powerTrain,
+ bodyTypeId: JSON.parse(savedItem).modelTypeId.bodyType,
+ operationId: JSON.parse(savedItem).modelTypeId.operation,
+ outerColorId: JSON.parse(savedItem).outerColorId,
+ innerColorId: JSON.parse(savedItem).innerColorId,
+ optionIdList: JSON.parse(savedItem).optionId ? JSON.parse(savedItem).optionId : [],
+ };
+ return params;
+ }, [isSelectedTrim, savedItem]);
+
+ useEffect(() => {
+ if (!isSelectedTrim || !savedItem || isSelectedTrim === 'false') return;
+ const params = getParams();
+ const fetchData = async () => {
+ try {
+ const res = await fetch(SHARE_INFO_API, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(params),
+ });
+ const jsonData = await res.json();
+ setData(jsonData);
+ } catch (e) {
+ setError(e as Error);
+ } finally {
+ setLoading(false);
+ }
+ };
+ fetchData();
+ }, [getParams, isSelectedTrim, savedItem]);
+
const [selectedItem, setSelectedItem] = useReducer(itemReducer, initialSelectedItem);
const [totalPrice, setTotalPrice] = useState(0);
@@ -155,6 +198,85 @@ export default function ItemProvider({ children }: IItemProvider) {
localStorage.setItem('selectedItem', JSON.stringify(savedId));
}, [selectedItem]);
+ useEffect(() => {
+ if (!data || loading || error) return;
+ setSelectedItem({
+ type: 'SET_TRIM',
+ value: {
+ id: data.carId,
+ name: data.trim,
+ price: data.carDefaultPrice,
+ },
+ });
+ setSelectedItem({
+ type: 'SET_POWER_TRAIN',
+ value: {
+ id: data.powerTrainId,
+ title: data.powerTrainTitle,
+ name: data.powerTrainName,
+ imgSrc: data.powerTrainImage,
+ price: data.powerTrainPrice,
+ },
+ });
+ setSelectedItem({
+ type: 'SET_BODY_TYPE',
+ value: {
+ id: data.bodyTypeId,
+ title: data.bodyTypeTitle,
+ name: data.bodyTypeName,
+ imgSrc: data.bodyTypeImage,
+ price: data.bodyTypePrice,
+ },
+ });
+ setSelectedItem({
+ type: 'SET_OPERATION',
+ value: {
+ id: data.operationId,
+ title: data.operationName,
+ name: data.operationImage,
+ imgSrc: data.operationImage,
+ price: data.operationPrice,
+ },
+ });
+
+ setSelectedItem({
+ type: 'SET_OUTER_COLOR',
+ value: {
+ id: data.colorOuterId,
+ name: data.colorOuterImageName,
+ title: data.colorOuterTitle,
+ price: data.colorOuterPrice,
+ carImgSrc: data.colorCarOuterImage,
+ imgSrc: data.colorOuterImage,
+ },
+ });
+ setSelectedItem({
+ type: 'SET_INNER_COLOR',
+ value: {
+ id: data.colorInnerId,
+ name: data.colorInnerImageName,
+ title: data.colorInnerTitle,
+ price: data.colorInnerPrice,
+ carImgSrc: data.colorCarInnerImage,
+ imgSrc: data.colorInnerImage,
+ },
+ });
+
+ const options = data.optionList
+ ? data.optionList.map((option) => ({
+ id: option.optionId,
+ name: option.optionName,
+ title: option.optionTitle,
+ price: option.optionPrice,
+ imgSrc: option.optionImage,
+ }))
+ : [];
+
+ setSelectedItem({
+ type: 'SET_OPTIONS',
+ value: options,
+ });
+ }, [data, error, loading]);
return (
{
+ const isSelectedTrim = localStorage.getItem('isSelectedTrim');
+ if (isSelectedTrim && isSelectedTrim === 'true') setNextStepAvailable(true);
+ }, []);
+ useEffect(() => {
+ localStorage.setItem('isSelectedTrim', nextStepAvailable.toString());
+ }, [nextStepAvailable]);
return {children};
}
diff --git a/frontend/src/hooks/useSharedInfo.ts b/frontend/src/hooks/useSharedInfo.ts
index fe02e34..4cba739 100644
--- a/frontend/src/hooks/useSharedInfo.ts
+++ b/frontend/src/hooks/useSharedInfo.ts
@@ -2,7 +2,7 @@ import { useSearchParams } from 'react-router-dom';
import { SHARE_INFO_API } from '../utils/apis';
import { useCallback, useEffect, useState } from 'react';
-interface ISharedInfo {
+export interface ISharedInfo {
carId: number;
trim: string;
carDefaultPrice: number;
From 94aa62cb056a32c7e9caf0cb9a949fcca1dbf8c9 Mon Sep 17 00:00:00 2001
From: kimdaye77 <63107805+kimdaye77@users.noreply.github.com>
Date: Wed, 23 Aug 2023 17:43:22 +0900
Subject: [PATCH 16/34] =?UTF-8?q?[FIX]=20#422:=20=EB=B2=84=EA=B7=B8=20?=
=?UTF-8?q?=ED=95=B4=EA=B2=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../components/modal/QuoteSummaryModal.tsx | 6 +--
frontend/src/context/ItemProvider.tsx | 46 ++++++++-----------
frontend/src/pages/ModelTypePage.tsx | 10 ++--
3 files changed, 28 insertions(+), 34 deletions(-)
diff --git a/frontend/src/components/modal/QuoteSummaryModal.tsx b/frontend/src/components/modal/QuoteSummaryModal.tsx
index d5be7ed..0fc5e03 100644
--- a/frontend/src/components/modal/QuoteSummaryModal.tsx
+++ b/frontend/src/components/modal/QuoteSummaryModal.tsx
@@ -125,9 +125,9 @@ export default function QuoteSummaryModal({ ...props }: IQuoteSummaryModal) {
function Detail({ title, name, price }: IDetail) {
return (
- {title}
- {name}
- + {price.toLocaleString()} 원
+ {title && {title}}
+ {name && {name}}
+ {price && + {price.toLocaleString()} 원}
);
}
diff --git a/frontend/src/context/ItemProvider.tsx b/frontend/src/context/ItemProvider.tsx
index ba993c6..d015c0d 100644
--- a/frontend/src/context/ItemProvider.tsx
+++ b/frontend/src/context/ItemProvider.tsx
@@ -1,4 +1,4 @@
-import { ReactNode, createContext, useCallback, useEffect, useReducer, useState } from 'react';
+import { ReactNode, createContext, useEffect, useReducer, useState } from 'react';
import itemReducer, { actionType } from '../reducer/itemReducer';
import { OUTER_COLOR_FIRST_IDX } from '../utils/constants';
import { SHARE_INFO_API } from '../utils/apis';
@@ -133,25 +133,11 @@ export default function ItemProvider({ children }: IItemProvider) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
- const isSelectedTrim = localStorage.getItem('isSelectedTrim');
- const savedItem = localStorage.getItem('selectedItem');
- const getParams = useCallback(() => {
- if (!isSelectedTrim || !savedItem || isSelectedTrim === 'false') return;
- const params = {
- carId: JSON.parse(savedItem).trimId,
- powerTrainId: JSON.parse(savedItem).modelTypeId.powerTrain,
- bodyTypeId: JSON.parse(savedItem).modelTypeId.bodyType,
- operationId: JSON.parse(savedItem).modelTypeId.operation,
- outerColorId: JSON.parse(savedItem).outerColorId,
- innerColorId: JSON.parse(savedItem).innerColorId,
- optionIdList: JSON.parse(savedItem).optionId ? JSON.parse(savedItem).optionId : [],
- };
- return params;
- }, [isSelectedTrim, savedItem]);
useEffect(() => {
- if (!isSelectedTrim || !savedItem || isSelectedTrim === 'false') return;
- const params = getParams();
+ const isSelectedTrim = localStorage.getItem('isSelectedTrim');
+ const params = localStorage.getItem('params');
+ if (!isSelectedTrim || !params || isSelectedTrim === 'false') return;
const fetchData = async () => {
try {
const res = await fetch(SHARE_INFO_API, {
@@ -159,9 +145,10 @@ export default function ItemProvider({ children }: IItemProvider) {
headers: {
'Content-Type': 'application/json',
},
- body: JSON.stringify(params),
+ body: params,
});
const jsonData = await res.json();
+
setData(jsonData);
} catch (e) {
setError(e as Error);
@@ -170,7 +157,7 @@ export default function ItemProvider({ children }: IItemProvider) {
}
};
fetchData();
- }, [getParams, isSelectedTrim, savedItem]);
+ }, []);
const [selectedItem, setSelectedItem] = useReducer(itemReducer, initialSelectedItem);
const [totalPrice, setTotalPrice] = useState(0);
@@ -184,18 +171,20 @@ export default function ItemProvider({ children }: IItemProvider) {
const optionsPrice = selectedItem.options.reduce((acc, option) => acc + option.price, 0);
const total = trimPrice + modelTypePrice + outerColorPrice + innerColorPrice + optionsPrice;
setTotalPrice(total);
+ const powerTrainId = powerTrain.id;
+ const bodyTypeId = bodyType.id;
+ const operationId = operation.id;
+ const optionIds = selectedItem.options.map((option) => option.id);
const savedId = {
- trimId: trimId,
- modelTypeId: {
- powerTrain: powerTrain.id,
- bodyType: bodyType.id,
- operation: operation.id,
- },
+ carId: trimId,
+ powerTrainId,
+ bodyTypeId,
+ operationId,
outerColorId: outerColorId,
innerColorId: innerColorId,
- optionId: selectedItem.options.map((option) => option.id),
+ optionIdList: optionIds ? optionIds : [],
};
- localStorage.setItem('selectedItem', JSON.stringify(savedId));
+ localStorage.setItem('params', JSON.stringify(savedId));
}, [selectedItem]);
useEffect(() => {
@@ -277,6 +266,7 @@ export default function ItemProvider({ children }: IItemProvider) {
value: options,
});
}, [data, error, loading]);
+
return (
-
-
-
+ {modelTypeData && !modelTypeLoading && (
+ <>
+
+
+
+ >
+ )}
>
);
}
From fc865d96ddfb5f229370bbc4c7902bb27210c38f Mon Sep 17 00:00:00 2001
From: kimdaye77 <63107805+kimdaye77@users.noreply.github.com>
Date: Wed, 23 Aug 2023 17:49:21 +0900
Subject: [PATCH 17/34] =?UTF-8?q?[REFACTOR]=20#421:=20=EB=B3=80=EC=88=98?=
=?UTF-8?q?=EB=AA=85=20=EC=9E=98=EB=AA=BB=EB=90=9C=20=EA=B1=B0=20=EB=B3=80?=
=?UTF-8?q?=EA=B2=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../ModelTypeSelectContainer.tsx | 28 +++++++++----------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/frontend/src/containers/ModelTypePage/ModelTypeSelectContainer.tsx b/frontend/src/containers/ModelTypePage/ModelTypeSelectContainer.tsx
index b17a78e..ce30631 100644
--- a/frontend/src/containers/ModelTypePage/ModelTypeSelectContainer.tsx
+++ b/frontend/src/containers/ModelTypePage/ModelTypeSelectContainer.tsx
@@ -93,14 +93,14 @@ export default function ModelTypelSelectContainer() {
{modelType[2].modelTypeName}
- {[modelType[2], modelType[3]].map((bodyType) => (
+ {[modelType[2], modelType[3]].map((operation) => (
handleSelectedOperation(bodyType.modelId)}
- active={isActive(bodyType.modelTypeName, bodyType.modelId)}
- percentage={bodyType.percentage}
- title={bodyType.modelName}
- price={bodyType.modelPrice}
+ key={operation.modelId}
+ onClick={() => handleSelectedOperation(operation.modelId)}
+ active={isActive(operation.modelTypeName, operation.modelId)}
+ percentage={operation.percentage}
+ title={operation.modelName}
+ price={operation.modelPrice}
/>
))}
@@ -111,14 +111,14 @@ export default function ModelTypelSelectContainer() {
{modelType[4].modelTypeName}
- {[modelType[4], modelType[5]].map((operation) => (
+ {[modelType[4], modelType[5]].map((bodyType) => (
handleSelectedBodyType(operation.modelId)}
- active={isActive(operation.modelTypeName, operation.modelId)}
- percentage={operation.percentage}
- title={operation.modelName}
- price={operation.modelPrice}
+ key={bodyType.modelId}
+ onClick={() => handleSelectedBodyType(bodyType.modelId)}
+ active={isActive(bodyType.modelTypeName, bodyType.modelId)}
+ percentage={bodyType.percentage}
+ title={bodyType.modelName}
+ price={bodyType.modelPrice}
/>
))}
From 43a04906a19cb2c5563ecf69ac10f3acac14c43c Mon Sep 17 00:00:00 2001
From: kimdaye77 <63107805+kimdaye77@users.noreply.github.com>
Date: Wed, 23 Aug 2023 20:59:15 +0900
Subject: [PATCH 18/34] =?UTF-8?q?[FEAT]=20#425:=20=EC=9C=A0=EC=82=AC=20?=
=?UTF-8?q?=EA=B2=AC=EC=A0=81=20=EC=98=88=EC=82=B0=20=EC=84=A4=EC=A0=95?=
=?UTF-8?q?=EB=B0=94=20UI=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../components/modal/SimilarQuoteModal.tsx | 2 +-
.../priceStaticBar/PriceStaticBar.tsx | 38 +------
.../priceStaticBar/PriceStaticSlider.tsx | 32 ++----
.../priceStaticBar/SimilarPriceBar.tsx | 101 ++++++++++++------
.../priceStaticBar/SimilarPriceSlider.tsx | 76 +++++++------
frontend/src/utils/constants.ts | 2 +
6 files changed, 130 insertions(+), 121 deletions(-)
diff --git a/frontend/src/components/modal/SimilarQuoteModal.tsx b/frontend/src/components/modal/SimilarQuoteModal.tsx
index f802e2a..dc22db5 100644
--- a/frontend/src/components/modal/SimilarQuoteModal.tsx
+++ b/frontend/src/components/modal/SimilarQuoteModal.tsx
@@ -43,7 +43,7 @@ export default function SimilarQuoteModal({ ...props }: ISimilarQuoteModal) {
내 견적과 해시태그 유사도가 높은 다른 사람들의 실제 출고 견적이에요.
-
+
diff --git a/frontend/src/components/priceStaticBar/PriceStaticBar.tsx b/frontend/src/components/priceStaticBar/PriceStaticBar.tsx
index e37cf54..42c88d3 100644
--- a/frontend/src/components/priceStaticBar/PriceStaticBar.tsx
+++ b/frontend/src/components/priceStaticBar/PriceStaticBar.tsx
@@ -1,20 +1,18 @@
import { ChangeEvent, useCallback, useContext, useEffect, useRef, useState } from 'react';
-import { css, styled, useTheme } from 'styled-components';
+import { styled, useTheme } from 'styled-components';
import { BodyKrRegular4, HeadingKrMedium6 } from '../../styles/typefaces';
import { ArrowUp, ArrowDown } from '../common/icons/Icons';
import React from 'react';
import { useLocation } from 'react-router-dom';
-import { PATH } from '../../utils/constants';
+import { HIGHEST_PRICE, PATH } from '../../utils/constants';
import PriceStaticSlider from './PriceStaticSlider';
import { ItemContext } from '../../context/ItemProvider';
-
interface IPriceStaticBar extends React.HTMLAttributes {}
interface IOffset {
offsetX: string;
offsetY: string;
}
export default function PriceStaticBar({ ...props }: IPriceStaticBar) {
- const highestPrice = 80_000_000;
const { totalPrice, selectedItem } = useContext(ItemContext);
const { pathname } = useLocation();
const theme = useTheme();
@@ -26,17 +24,14 @@ export default function PriceStaticBar({ ...props }: IPriceStaticBar) {
const [isOverBudget, setIsOverBudget] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const balance = ((isOverBudget ? -1 : 1) * (budget - totalPrice)).toLocaleString();
-
const getBudgetStatus = useCallback(() => {
const status = budget - totalPrice;
status >= 0 ? setIsOverBudget(false) : setIsOverBudget(true);
}, [budget, totalPrice]);
-
const handleChange = (event: ChangeEvent) => {
const newValue = Number(event.target.value);
setBudget(newValue);
};
-
const stopEvent = (event: React.MouseEvent) => {
event.stopPropagation();
};
@@ -45,7 +40,6 @@ export default function PriceStaticBar({ ...props }: IPriceStaticBar) {
const element = barRef.current!.getBoundingClientRect();
setStartOffset({ startX: clientX - element.left, startY: clientY - element.top });
};
-
const handleMouseMove = (event: MouseEvent, startX: number, startY: number) => {
if (!dragRef.current) {
return;
@@ -59,24 +53,20 @@ export default function PriceStaticBar({ ...props }: IPriceStaticBar) {
event.preventDefault();
setOffset({ offsetX: `${newLeft}px`, offsetY: `${newTop}px` });
};
-
const handleMouseUp = () => {
dragRef.current = false;
};
-
useEffect(() => {
- setBudget((selectedItem.trim.price + highestPrice) / 2);
+ setBudget((selectedItem.trim.price + HIGHEST_PRICE) / 2);
}, [selectedItem.trim.price]);
useEffect(() => {
getBudgetStatus();
}, [budget, getBudgetStatus]);
-
useEffect(() => {
window.addEventListener('mousemove', (event) =>
handleMouseMove(event, startOffset.startX, startOffset.startY)
);
window.addEventListener('mouseup', handleMouseUp);
-
return () => {
window.removeEventListener('mousemove', (event) =>
handleMouseMove(event, startOffset.startX, startOffset.startY)
@@ -84,11 +74,9 @@ export default function PriceStaticBar({ ...props }: IPriceStaticBar) {
window.removeEventListener('mouseup', handleMouseUp);
};
}, [startOffset]);
-
if (pathname === PATH.home || pathname === PATH.trim) {
return <>>;
}
-
return (
{balance}원
{isOverBudget ? ' 더 들었어요.' : ' 남았어요.'}
-
setIsOpen(!isOpen)}>
{isOpen ? : }
-
theme.color.primaryColor700};
-`;
-
-const overBudgetCss = css`
- background: rgba(0, 11, 25, 0.9);
-`;
-
const StatusBox = styled.div.attrs<{
$isover: boolean;
$isopen: boolean;
@@ -143,12 +120,11 @@ const StatusBox = styled.div.attrs<{
transform: $offset.offsetX === '50%' ? 'translateX(-50%)' : 'none',
},
}))`
- ${({ $isover }) => !$isover && withinBudgetCss}
- ${({ $isover }) => $isover && overBudgetCss}
+ background: ${({ theme, $isover }) =>
+ $isover ? 'rgba(0, 11, 25, 0.9)' : theme.color.primaryColor700};
position: fixed;
min-width: 343px;
z-index: 1000;
-
padding: 0px 16px;
border-radius: 10px;
backdrop-filter: blur(3px);
@@ -161,7 +137,6 @@ const StatusBox = styled.div.attrs<{
justify-content: space-between;
cursor: pointer;
`;
-
const StatusText = styled.div`
width: 100%;
min-height: 40px;
@@ -169,12 +144,10 @@ const StatusText = styled.div`
align-items: center;
justify-content: space-between;
`;
-
const StatusTitle = styled.p`
margin-right: 8px;
${HeadingKrMedium6}
`;
-
const StatusDesc = styled.p<{ $isover: boolean }>`
${BodyKrRegular4}
flex:1;
@@ -188,5 +161,4 @@ const AnimatedSection = styled.div<{ $isopen: boolean }>`
opacity: ${({ $isopen }) => ($isopen ? '1' : '0')};
transition: opacity 0.5s ease;
`;
-
const IconBtn = styled.button``;
diff --git a/frontend/src/components/priceStaticBar/PriceStaticSlider.tsx b/frontend/src/components/priceStaticBar/PriceStaticSlider.tsx
index de5d502..58763ae 100644
--- a/frontend/src/components/priceStaticBar/PriceStaticSlider.tsx
+++ b/frontend/src/components/priceStaticBar/PriceStaticSlider.tsx
@@ -3,18 +3,15 @@ import { flexCenterCss } from '../../utils/commonStyle';
import { BodyKrRegular3, BodyKrRegular5 } from '../../styles/typefaces';
import { ChangeEvent, useContext } from 'react';
import { ItemContext } from '../../context/ItemProvider';
-import { TEN_THOUSAND_UNIT } from '../../utils/constants';
+import { HIGHEST_PRICE, TEN_THOUSAND_UNIT } from '../../utils/constants';
import { theme } from '../../styles/theme';
-
interface ISlider extends React.HTMLAttributes {
- highestPrice: number;
isOverBudget: boolean;
budget: number;
handleChange: (event: ChangeEvent) => void;
stopEvent: (event: React.MouseEvent) => void;
}
export default function Slider({
- highestPrice,
isOverBudget,
budget,
handleChange,
@@ -26,28 +23,25 @@ export default function Slider({
-
- 내가 설정한 예산은
- {budget / TEN_THOUSAND_UNIT}만원이에요.
-
+ 내가 설정한 예산은
+ {budget / TEN_THOUSAND_UNIT}만원이에요.
@@ -56,12 +50,11 @@ export default function Slider({
{selectedItem.trim.price / TEN_THOUSAND_UNIT}만원
- {highestPrice / TEN_THOUSAND_UNIT}만원
+ {HIGHEST_PRICE / TEN_THOUSAND_UNIT}만원
);
}
-
const PriceBarWrapper = styled.div`
padding-top: 28px;
padding-bottom: 4px;
@@ -75,15 +68,10 @@ const BudgetInfo = styled.div`
background-color: black;
opacity: 0.9;
`;
-const Budget = styled.span`
- ${BodyKrRegular3}
-`;
-
const MarkerSvgWrapper = styled.div`
height: 100%;
position: relative;
`;
-
const MarkerSvg = styled.svg<{ $isover: boolean; $percent: number }>`
pointer-events: none;
position: absolute;
@@ -94,9 +82,8 @@ const MarkerSvg = styled.svg<{ $isover: boolean; $percent: number }>`
left: ${({ $percent }) => $percent}%;
transform: translate(-50%, -50%);
`;
-
const PriceBar = styled.input.attrs<{ $percent: number; $isover: boolean }>(
- ({ type, min, max, value, onChange, step, $percent, $isover }) => ({
+ ({ type, min, value, onChange, step, $percent, $isover }) => ({
style: {
background: `linear-gradient(
to right,
@@ -108,7 +95,7 @@ const PriceBar = styled.input.attrs<{ $percent: number; $isover: boolean }>(
},
type: type,
min: min,
- max: max,
+ max: HIGHEST_PRICE,
value: value,
onChange: onChange,
step: step,
@@ -122,14 +109,12 @@ const PriceBar = styled.input.attrs<{ $percent: number; $isover: boolean }>(
width: 100%;
height: 6px;
border-radius: 4px;
-
&::-webkit-slider-runnable-track {
cursor: pointer;
width: 100%;
height: 6px;
border-radius: 4px;
}
-
&::-webkit-slider-thumb {
cursor: pointer;
width: 20px;
@@ -145,7 +130,6 @@ const PriceBar = styled.input.attrs<{ $percent: number; $isover: boolean }>(
const BlueText = styled.span<{ $isover: boolean }>`
color: ${({ theme, $isover }) => ($isover ? theme.color.sand : theme.color.activeBlue2)};
`;
-
const PriceInfo = styled.div<{ $isover: boolean }>`
${flexCenterCss};
justify-content: space-between;
diff --git a/frontend/src/components/priceStaticBar/SimilarPriceBar.tsx b/frontend/src/components/priceStaticBar/SimilarPriceBar.tsx
index 36fcccb..8d27434 100644
--- a/frontend/src/components/priceStaticBar/SimilarPriceBar.tsx
+++ b/frontend/src/components/priceStaticBar/SimilarPriceBar.tsx
@@ -1,76 +1,80 @@
-import { ChangeEvent, useCallback, useEffect, useState } from 'react';
-import { css, styled } from 'styled-components';
+import { ChangeEvent, useCallback, useContext, useEffect, useState } from 'react';
+import { styled } from 'styled-components';
import { flexCenterCss } from '../../utils/commonStyle';
-import { BodyKrRegular4, HeadingKrMedium6 } from '../../styles/typefaces';
+import { BodyKrMedium5, BodyKrRegular4, HeadingKrMedium6 } from '../../styles/typefaces';
import React from 'react';
import SimilarPriceSlider from './SimilarPriceSlider';
+import { ItemContext } from '../../context/ItemProvider';
+import { HIGHEST_PRICE } from '../../utils/constants';
-interface ISimilarPrice extends React.HTMLAttributes {}
+interface ISimilarPriceBar extends React.HTMLAttributes {
+ similarPrice: number;
+}
+
+export default function SimilarPriceBar({ similarPrice, ...props }: ISimilarPriceBar) {
+ const { totalPrice, selectedItem } = useContext(ItemContext);
-export default function SimilarPrice({ ...props }: ISimilarPrice) {
- const lowestPrice = 3850; //단위: 만원
- const highestPrice = 4300;
- const total = 4100;
- const [budget, setBudget] = useState((lowestPrice + highestPrice) / 2);
+ const [budget, setBudget] = useState((selectedItem.trim.price + HIGHEST_PRICE) / 2);
const [isOverBudget, setIsOverBudget] = useState(false);
- const balance = ((isOverBudget ? -10000 : 10000) * (budget - total)).toLocaleString();
+ const balance = ((isOverBudget ? -1 : 1) * (budget - totalPrice)).toLocaleString();
const getBudgetStatus = useCallback(() => {
- const status = budget - total;
+ const status = budget - totalPrice;
status >= 0 ? setIsOverBudget(false) : setIsOverBudget(true);
- }, [budget]);
+ }, [budget, totalPrice]);
const handleChange = (event: ChangeEvent) => {
const newValue = Number(event.target.value);
setBudget(newValue);
};
-
useEffect(() => {
getBudgetStatus();
}, [budget, getBudgetStatus]);
-
return (
유사견적 가격
내 견적 보다
- {balance}원
+ {balance}원
{isOverBudget ? ' 비싸요.' : ' 싸요.'}
+
+
+
+ 내 견적
+
+
+
+ 유사 견적
+
+
+
);
}
-const withinBudgetCss = css`
- background: ${({ theme }) => theme.color.primaryColor700};
- #price-info {
- color: ${({ theme }) => theme.color.activeBlue2};
- }
-`;
-const overBudgetCss = css`
- background: rgba(0, 11, 25, 0.9);
- #price-info {
- color: ${({ theme }) => theme.color.sand};
- }
-`;
+const PriceInfo = styled.span``;
const StatusBox = styled.div<{ $isover: boolean }>`
- ${({ $isover }) => !$isover && withinBudgetCss}
- ${({ $isover }) => $isover && overBudgetCss}
+ background: ${({ theme, $isover }) =>
+ $isover ? 'rgba(0, 11, 25, 0.9)' : theme.color.primaryColor700};
min-width: 343px;
padding: 8px 16px;
border-radius: 10px;
backdrop-filter: blur(3px);
color: ${({ theme }) => theme.color.gray50};
+ ${PriceInfo} {
+ color: ${({ theme, $isover }) => ($isover ? theme.color.sand : theme.color.activeBlue2)};
+ }
`;
const StatusText = styled.div`
@@ -89,3 +93,34 @@ const StatusDesc = styled.span`
flex:1;
text-align: end;
`;
+
+const InfoWrapper = styled.div`
+ ${flexCenterCss}
+`;
+
+const InfoCaption = styled.div<{ $isover?: boolean }>`
+ display: flex;
+ align-items: center;
+ gap: 16px;
+ color: ${({ theme, $isover }) => ($isover ? theme.color.sand : theme.color.activeBlue2)};
+ ${BodyKrMedium5}
+`;
+
+const Ellipse = styled.div<{ $isover: boolean }>`
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background-color: ${({ theme, $isover }) =>
+ $isover ? theme.color.sand : theme.color.activeBlue2};
+`;
+
+const Info = styled.span`
+ ${flexCenterCss}
+ gap: 4px;
+ &:last-child {
+ color: white;
+ ${Ellipse} {
+ background-color: white;
+ }
+ }
+`;
diff --git a/frontend/src/components/priceStaticBar/SimilarPriceSlider.tsx b/frontend/src/components/priceStaticBar/SimilarPriceSlider.tsx
index 5a1d075..ed559da 100644
--- a/frontend/src/components/priceStaticBar/SimilarPriceSlider.tsx
+++ b/frontend/src/components/priceStaticBar/SimilarPriceSlider.tsx
@@ -1,70 +1,87 @@
import { styled } from 'styled-components';
import { flexCenterCss } from '../../utils/commonStyle';
-import { BodyKrRegular5 } from '../../styles/typefaces';
-import { ChangeEvent } from 'react';
-
-interface INonameS extends React.HTMLAttributes {
- lowestPrice: number;
- highestPrice: number;
+import { BodyKrRegular3, BodyKrRegular5 } from '../../styles/typefaces';
+import { ChangeEvent, useContext } from 'react';
+import { HIGHEST_PRICE, TEN_THOUSAND_UNIT } from '../../utils/constants';
+import { ItemContext } from '../../context/ItemProvider';
+interface ISimilarPriceSlider extends React.HTMLAttributes {
isOverBudget: boolean;
budget: number;
- total: number;
+ similarPrice: number;
percent: number;
handleChange: (event: ChangeEvent) => void;
}
-export default function NonameS({
- lowestPrice,
- highestPrice,
+export default function SimilarPriceSlider({
isOverBudget,
budget,
- total,
+ similarPrice,
percent,
handleChange,
...props
-}: INonameS) {
+}: ISimilarPriceSlider) {
+ const { totalPrice, selectedItem } = useContext(ItemContext);
return (
+
+ 내 차의 견적은 총
+ {totalPrice / TEN_THOUSAND_UNIT}만원이에요.
+
-
+
-
+
- {lowestPrice}만원
- {highestPrice}만원
+ {selectedItem.trim.price / TEN_THOUSAND_UNIT}만원
+ {HIGHEST_PRICE / TEN_THOUSAND_UNIT}만원
);
}
-
const PriceBarWrapper = styled.div`
margin: 0px 4px;
padding-top: 34px;
padding-bottom: 8px;
`;
-
+const BlueText = styled.span<{ $isover: boolean }>`
+ color: ${({ theme, $isover }) => ($isover ? theme.color.sand : theme.color.activeBlue2)};
+`;
+const BudgetInfo = styled.div`
+ ${BodyKrRegular3}
+ position: absolute;
+ top: -34px;
+ right: 0px;
+ background-color: black;
+ opacity: 0.9;
+`;
const MarkerSvgWrapper = styled.div`
height: 100%;
position: relative;
`;
-
-const MarkerSvg = styled.svg<{ $isover: boolean; $percent: number }>`
+const MarkerSvg = styled.svg<{ $isover?: boolean; $percent: number }>`
pointer-events: none;
position: absolute;
width: 9px;
@@ -74,12 +91,14 @@ const MarkerSvg = styled.svg<{ $isover: boolean; $percent: number }>`
left: ${({ $percent }) => $percent}%;
transform: translate(-50%, -50%);
`;
-
+const SimilarMarkerSvg = styled(MarkerSvg)`
+ fill: white;
+`;
const PriceBar = styled.input.attrs<{ $percent: number; $isover: boolean }>(
- ({ type, min, max, value, onChange, step }) => ({
+ ({ type, min, value, onChange, step }) => ({
type: type,
min: min,
- max: max,
+ max: HIGHEST_PRICE,
value: value,
onChange: onChange,
step: step,
@@ -93,15 +112,12 @@ const PriceBar = styled.input.attrs<{ $percent: number; $isover: boolean }>(
width: 100%;
height: 6px;
border-radius: 4px;
-
&::-webkit-slider-runnable-track {
- cursor: pointer;
width: 100%;
height: 6px;
border-radius: 4px;
}
`;
-
const PriceInfo = styled.div`
${flexCenterCss};
justify-content: space-between;
diff --git a/frontend/src/utils/constants.ts b/frontend/src/utils/constants.ts
index 4dafcc5..b84783b 100644
--- a/frontend/src/utils/constants.ts
+++ b/frontend/src/utils/constants.ts
@@ -4,6 +4,7 @@ export const DEBOUNCE_TIME = 200;
export const TEN_THOUSAND_UNIT = 10000;
export const PERCENTAGE_LIMIT_VALUE = 5;
export const MAX_TEXT_CNT = 16;
+export const HIGHEST_PRICE = 80_000_000;
export const PATH = {
home: '/',
trim: '/trim',
@@ -45,4 +46,5 @@ Object.freeze({
OUTER_COLOR_FIRST_IDX,
PERCENTAGE_LIMIT_VALUE,
MAX_TEXT_CNT,
+ HIGHEST_PRICE,
});
From c0dcbbfbdd4eca61d2943ec84af314d8ce56cea6 Mon Sep 17 00:00:00 2001
From: kimdaye77 <63107805+kimdaye77@users.noreply.github.com>
Date: Wed, 23 Aug 2023 21:28:00 +0900
Subject: [PATCH 19/34] =?UTF-8?q?[FIX]=20#427:=20=EC=95=84=EC=9D=B4?=
=?UTF-8?q?=EC=BD=98=20=EB=B3=80=EA=B2=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
frontend/src/components/common/navbar/NavBar.tsx | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/frontend/src/components/common/navbar/NavBar.tsx b/frontend/src/components/common/navbar/NavBar.tsx
index 3937b13..baebb79 100644
--- a/frontend/src/components/common/navbar/NavBar.tsx
+++ b/frontend/src/components/common/navbar/NavBar.tsx
@@ -2,7 +2,7 @@ import React, { useContext, useState } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import { css, styled, useTheme } from 'styled-components';
import { BodyKrMedium3, BodyKrRegular3, HeadingKrMedium6 } from '../../../styles/typefaces';
-import { ArrowDown, CancelIcon } from '../icons/Icons';
+import { ArrowDown, ArrowUp, CancelIcon } from '../icons/Icons';
import hyundaiLogo from '/images/logo.svg';
import { MESSAGE, PATH } from '../../../utils/constants';
import { CloseModalContext } from '../../../context/CloseModalProvider';
@@ -44,7 +44,11 @@ export default function NavBar() {
펠리세이드
-
+ {menuVisible ? (
+
+ ) : (
+
+ )}
Date: Wed, 23 Aug 2023 21:38:19 +0900
Subject: [PATCH 20/34] =?UTF-8?q?[FEAT]=20#427:=20=EC=95=A0=EB=8B=88?=
=?UTF-8?q?=EB=A9=94=EC=9D=B4=EC=85=98=20=EB=84=A3=EC=96=B4=EB=B4=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../components/common/navbar/CarSelectContainer.tsx | 11 ++++++++---
frontend/src/components/common/navbar/NavBar.tsx | 3 +++
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/frontend/src/components/common/navbar/CarSelectContainer.tsx b/frontend/src/components/common/navbar/CarSelectContainer.tsx
index 5b4c9f7..da18bd0 100644
--- a/frontend/src/components/common/navbar/CarSelectContainer.tsx
+++ b/frontend/src/components/common/navbar/CarSelectContainer.tsx
@@ -55,15 +55,20 @@ export default function CarSelectContainer({ visible }: ICarSelectContainer) {
>
);
}
-
const Wrapper = styled.div<{ $visible: boolean }>`
- display: ${({ $visible }) => ($visible ? 'block' : 'none')};
position: fixed;
top: 60px;
z-index: 99999999;
- height: 220px;
+ height: ${({ $visible }) => ($visible ? '220px' : '0')};
width: 100%;
background-color: ${({ theme }) => theme.color.white};
+ display: block;
+ opacity: ${({ $visible }) => ($visible ? '1' : '0')};
+ overflow: hidden;
+ visibility: ${({ $visible }) => ($visible ? 'visible' : 'hidden')};
+ transition:
+ height 0.5s ease,
+ opacity 0.5s ease;
`;
const CetnerWrapper = styled(CenterWrapper)``;
diff --git a/frontend/src/components/common/navbar/NavBar.tsx b/frontend/src/components/common/navbar/NavBar.tsx
index baebb79..82ffab6 100644
--- a/frontend/src/components/common/navbar/NavBar.tsx
+++ b/frontend/src/components/common/navbar/NavBar.tsx
@@ -42,6 +42,7 @@ export default function NavBar() {
+
펠리세이드
{menuVisible ? (
@@ -50,6 +51,7 @@ export default function NavBar() {
)}
+
handleNavItemClick(PATH.trim)}
@@ -88,6 +90,7 @@ export default function NavBar() {
+
);
From 7d3fbc49e9b4b7188bfc207337d385909917457e Mon Sep 17 00:00:00 2001
From: kimdaye77 <63107805+kimdaye77@users.noreply.github.com>
Date: Wed, 23 Aug 2023 21:45:46 +0900
Subject: [PATCH 21/34] =?UTF-8?q?[FIX]=20#427:=20=EB=94=A4=EB=93=9C=20?=
=?UTF-8?q?=EB=B0=B0=EA=B2=BD=20=EB=88=84=EB=A5=B4=EB=A9=B4=20=EC=97=86?=
=?UTF-8?q?=EC=96=B4=EC=A7=90?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../common/navbar/CarSelectContainer.tsx | 15 ++++++++-------
frontend/src/components/common/navbar/NavBar.tsx | 2 +-
2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/frontend/src/components/common/navbar/CarSelectContainer.tsx b/frontend/src/components/common/navbar/CarSelectContainer.tsx
index da18bd0..d5d7c28 100644
--- a/frontend/src/components/common/navbar/CarSelectContainer.tsx
+++ b/frontend/src/components/common/navbar/CarSelectContainer.tsx
@@ -2,7 +2,7 @@ import { styled } from 'styled-components';
import CenterWrapper from '../layout/CenterWrapper';
import { useFetch } from '../../../hooks/useFetch';
import { CAR_LIST_API, IMG_URL } from '../../../utils/apis';
-import { useState } from 'react';
+import { Dispatch, useState } from 'react';
import { flexCenterCss } from '../../../utils/commonStyle';
import { BodyKrMedium3, BodyKrMedium4 } from '../../../styles/typefaces';
import DefaultCardStyle from '../card/DefaultCardStyle';
@@ -16,9 +16,10 @@ interface ICar {
interface ICarSelectContainer {
visible: boolean;
+ setMenuVisible: Dispatch>;
}
-export default function CarSelectContainer({ visible }: ICarSelectContainer) {
+export default function CarSelectContainer({ visible, setMenuVisible }: ICarSelectContainer) {
const { data } = useFetch(CAR_LIST_API);
const [active, setActive] = useState(3); // 3: SUV
const categoryList = ['수소/전기차', 'N', '승용', 'SUV', 'MVP', '소형트럭/택시', '트럭', '버스'];
@@ -26,6 +27,9 @@ export default function CarSelectContainer({ visible }: ICarSelectContainer) {
const handleCategoryClick = (idx: number) => {
setActive(idx);
};
+ const handleDimmedClick = () => {
+ setMenuVisible((cur) => !cur);
+ };
const isActive = (idx: number) => idx === active;
const categoryItemComponents = categoryList?.map((category, idx) => {
@@ -51,7 +55,7 @@ export default function CarSelectContainer({ visible }: ICarSelectContainer) {
{carItemComponents}
-
+
>
);
}
@@ -65,10 +69,7 @@ const Wrapper = styled.div<{ $visible: boolean }>`
display: block;
opacity: ${({ $visible }) => ($visible ? '1' : '0')};
overflow: hidden;
- visibility: ${({ $visible }) => ($visible ? 'visible' : 'hidden')};
- transition:
- height 0.5s ease,
- opacity 0.5s ease;
+ transition: height 0.5s ease;
`;
const CetnerWrapper = styled(CenterWrapper)``;
diff --git a/frontend/src/components/common/navbar/NavBar.tsx b/frontend/src/components/common/navbar/NavBar.tsx
index 82ffab6..4b8e673 100644
--- a/frontend/src/components/common/navbar/NavBar.tsx
+++ b/frontend/src/components/common/navbar/NavBar.tsx
@@ -91,7 +91,7 @@ export default function NavBar() {