Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HOT FIX: 기본옵션 상세정보 반환 시 오류 해결 #267

Merged
merged 14 commits into from
Aug 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,22 @@ public List<SubOptionDto> getSubOptionList(@Parameter(description = "차량 트
return optionService.getSubOptionList(carId);
}

@Operation(summary = "옵션 상세정보 조회", description = "옵션 데이터 상세정보 및 이미지, HMG가 존재한다면(비어있다면 비어있는 부분을 Null) 보냄")
@Operation(summary = "추가옵션 상세정보 조회", description = "추가옵션 데이터 상세정보 및 이미지, HMG가 존재한다면(비어있다면 비어있는 부분을 Null) 보냄")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "조회 성공", content = @Content(schema = @Schema(implementation = OptionDetailDto.class)))
})
@GetMapping("/optiondetail")
public OptionDetailDto getOptionDetail(@Parameter(description = "차량 트림 ID") @RequestParam("carid") int carId, @Parameter(description = "옵션 ID") @RequestParam("optionid") int optionId) {
return optionService.getOptionDetailData(carId, optionId);
@GetMapping("/sub/detail")
public OptionDetailDto getSubOptionDetail(@Parameter(description = "차량 트림 ID") @RequestParam("carid") int carId, @Parameter(description = "옵션 ID") @RequestParam("optionid") int optionId) {
return optionService.getOptionDetailData(carId, optionId, false);
}

@Operation(summary = "기본옵션 상세정보 조회", description = "기본옵션 데이터 상세정보 및 이미지, HMG가 존재한다면(비어있다면 비어있는 부분을 Null) 보냄")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "조회 성공", content = @Content(schema = @Schema(implementation = OptionDetailDto.class)))
})
@GetMapping("/default/detail")
public OptionDetailDto getDefaultOptionDetail(@Parameter(description = "차량 트림 ID") @RequestParam("carid") int carId, @Parameter(description = "옵션 ID") @RequestParam("optionid") int optionId) {
return optionService.getOptionDetailData(carId, optionId, true);
}

@Operation(summary = "기본 옵션 리스트 조회", description = "기본 옵션 데이터와 및 HMG 데이터 존재 여부 List 제공")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ public List<DefaultOptionDto> getDefaultOptionList(int carId) {
}

//TODO: RuntimeException 처리
public OptionDetailDto getOptionDetailData(int carId, int optionId) {
OptionDetailMappedDto detail = optionRepository.findOptionDetail(carId, optionId, false).orElseThrow(() -> new RuntimeException("데이터가 존재하지 않습니다."));
public OptionDetailDto getOptionDetailData(int carId, int optionId, boolean isDefault) {
OptionDetailMappedDto detail = optionRepository.findOptionDetail(carId, optionId, isDefault).orElseThrow(() -> new RuntimeException("데이터가 존재하지 않습니다."));

List<OptionDetailMappedDto> packageSubOptions = optionRepository.findPackageSubOptions(optionId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ void getOptionDetail() throws Exception {
.subOptionList(subOptions)
.build();

given(optionService.getOptionDetailData(carId, optionWithHmg)).willReturn(expected1);
given(optionService.getOptionDetailData(carId, optionPackage)).willReturn(expected2);
given(optionService.getOptionDetailData(carId, optionWithHmg, false)).willReturn(expected1);
given(optionService.getOptionDetailData(carId, optionPackage, false)).willReturn(expected2);

ResultActions singleOption = mockMvc.perform(MockMvcRequestBuilders.get("/api/options/optiondetail").param("carid", String.valueOf(carId)).param("optionid", String.valueOf(optionWithHmg)));
ResultActions packageOption = mockMvc.perform(MockMvcRequestBuilders.get("/api/options/optiondetail").param("carid", String.valueOf(carId)).param("optionid", String.valueOf(optionPackage)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,8 @@ void getOptionDetail() {
when(optionRepository.findPackageSubOptions(packageOption)).thenReturn(subPackages);
when(carRepository.findCarBoughtCountByCarId(carId)).thenReturn(Optional.of(150000L));

OptionDetailDto singleResult = optionService.getOptionDetailData(carId, singleOption);
OptionDetailDto packageResult = optionService.getOptionDetailData(carId, packageOption);
OptionDetailDto singleResult = optionService.getOptionDetailData(carId, singleOption, false);
OptionDetailDto packageResult = optionService.getOptionDetailData(carId, packageOption, false);

softAssertions.assertThat(singleResult).usingRecursiveComparison().isEqualTo(expected1);
softAssertions.assertThat(packageResult).usingRecursiveComparison().isEqualTo(expected2);
Expand Down
19 changes: 12 additions & 7 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
import { BrowserRouter } from 'react-router-dom';
import NavBar from './components/layout/NavBar';
import Providers from './components/contextProviders/Providers';
import PriceStaticBar from './components/priceStaticBar/PriceStaticBar';
import CustomRouter from './components/router/CustomRouter';
import ModalContainer from './containers/Modal/ModalContainer';
import CloseModalProvider from './context/CloseModalContext';
import SimilarQuoteModalProvider from './context/SimilarQuoteModalContext';
import GuideModalProvider from './context/GuideMoadlContext';
import Providers from './components/contextProviders/Providers';
import CloseModalProvider from './context/CloseModalProvider';
import SimilarQuoteModalProvider from './context/SimilarQuoteModalProvider';
import GuideModalProvider from './context/GuideModalProvider';
import ItemProvider from './context/ItemProvider';

function App() {
const modalProviders = [CloseModalProvider, SimilarQuoteModalProvider, GuideModalProvider];
const globalProviders = [
CloseModalProvider,
SimilarQuoteModalProvider,
GuideModalProvider,
ItemProvider,
];
return (
<Providers contexts={modalProviders}>
<Providers contexts={globalProviders}>
<BrowserRouter>
<NavBar />
<PriceStaticBar />
Expand All @@ -23,4 +29,3 @@ function App() {
}

export default App;

2 changes: 1 addition & 1 deletion frontend/src/components/histogram/BarHistogram.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import HmgTag from '../common/hmgTag/HmgTag';
import { BodyKrMedium2, BodyKrRegular3, HeadingKrMedium6 } from '../../styles/typefaces';
import { flexCenterCss } from '../../utils/commonStyle';
import { useContext } from 'react';
import { SimilarQuoteModalContext } from '../../context/SimilarQuoteModalContext';
import { SimilarQuoteModalContext } from '../../context/SimilarQuoteModalProvider';

export default function BarHistogram() {
const { setVisible: setSimilarQuoteModalVisible } = useContext(SimilarQuoteModalContext);
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/layout/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { BodyKrMedium3, BodyKrRegular3, HeadingKrMedium6 } from '../../styles/ty
import { ArrowDown, CancelIcon } from '../common/icons/Icons';
import hyundaiLogo from '/images/logo.svg';
import { PATH } from '../../utils/constants';
import { CloseModalContext } from '../../context/CloseModalContext';
import { CloseModalContext } from '../../context/CloseModalProvider';

interface INavItem extends React.HTMLAttributes<HTMLLIElement> {
active: boolean;
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/modal/CloseModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { flexCenterCss } from '../../utils/commonStyle';
import RectButton from '../common/buttons/RectButton';
import { HYUNDAI_URL } from '../../utils/constants';
import { DimmedBackground } from './DimmedBackground';
import { CloseModalContext } from '../../context/CloseModalContext';
import { CloseModalContext } from '../../context/CloseModalProvider';

interface ICloseModal extends HTMLAttributes<HTMLDivElement> {}

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/modal/GuideModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Bubble, CloseIcon } from '../common/icons/Icons';
import { BodyKrRegular3, HeadingKrMedium7 } from '../../styles/typefaces';
import CenterWrapper from '../layout/CenterWrapper';
import { DimmedBackground } from './DimmedBackground';
import { GuideModalContext } from '../../context/GuideMoadlContext';
import { GuideModalContext } from '../../context/GuideModalProvider';
import { useLocation } from 'react-router-dom';
import { PATH } from '../../utils/constants';

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/modal/SimilarQuoteModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import ExtraOptionCard from '../cards/ExtraOptionCard';
import HmgTag from '../common/hmgTag/HmgTag';
import RectButton from '../common/buttons/RectButton';
import { DimmedBackground } from './DimmedBackground';
import { SimilarQuoteModalContext } from '../../context/SimilarQuoteModalContext';
import { SimilarQuoteModalContext } from '../../context/SimilarQuoteModalProvider';
import SimilarPriceBar from '../priceStaticBar/SimilarPriceBar';

interface ISimilarQuoteModal extends HTMLAttributes<HTMLDivElement> {}
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/components/priceStaticBar/PriceStaticBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export default function PriceStaticBar({ ...props }: IPriceStaticBar) {
const maxY = window.innerHeight - (barRef.current?.offsetHeight || 0);
const newLeft = Math.min(Math.max(minX, event.clientX - startX), maxX);
const newTop = Math.min(Math.max(minY, event.clientY - startY), maxY);

event.preventDefault();
setOffset({ offsetX: `${newLeft}px`, offsetY: `${newTop}px` });
};

Expand All @@ -71,14 +71,14 @@ export default function PriceStaticBar({ ...props }: IPriceStaticBar) {
}, [budget, getBudgetStatus]);

useEffect(() => {
window.addEventListener('mousemove', (e) =>
handleMouseMove(e, startOffset.startX, startOffset.startY)
window.addEventListener('mousemove', (event) =>
handleMouseMove(event, startOffset.startX, startOffset.startY)
);
window.addEventListener('mouseup', handleMouseUp);

return () => {
window.removeEventListener('mousemove', (e) =>
handleMouseMove(e, startOffset.startX, startOffset.startY)
window.removeEventListener('mousemove', (event) =>
handleMouseMove(event, startOffset.startX, startOffset.startY)
);
window.removeEventListener('mouseup', handleMouseUp);
};
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/router/CustomRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import ResultPage from '../../pages/ResultPage';
import TrimPage from '../../pages/TrimPage';
import ModelTypePage from '../../pages/ModelTypePage';
import { PATH } from '../../utils/constants';
import TrimProvider from '../../context/TrimContext';
import TrimProvider from '../../context/TrimProvider';
import ModelTypeProvider from '../../context/ModelTypeProvider';

export default function CustomRouter() {
Expand Down
8 changes: 5 additions & 3 deletions frontend/src/components/summary/PriceSummary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ import RectButton from '../common/buttons/RectButton';
import RoundButton from '../common/buttons/RoundButton';
import { BodyKrRegular4, HeadingKrMedium2 } from '../../styles/typefaces';
import { useNavigate } from 'react-router-dom';
import { useContext } from 'react';
import { ItemContext } from '../../context/ItemProvider';

interface IPriceSummary extends React.HTMLAttributes<HTMLDivElement> {
nextPagePath: string;
}

export default function PriceSummary({ nextPagePath, ...props }: IPriceSummary) {
const total = 43_560_000;
const { totalPrice } = useContext(ItemContext);
const navigate = useNavigate();
const handleButtonClick = (price: number) => {
price; // Todo. price 누적 값 저장
Expand All @@ -20,10 +22,10 @@ export default function PriceSummary({ nextPagePath, ...props }: IPriceSummary)
<InfoWrapper>
<RoundButton type="price">견적 요약</RoundButton>
<TotalPriceText>
현재 총 가격<HighLightText>{total.toLocaleString()} 원</HighLightText>
현재 총 가격<HighLightText>{totalPrice.toLocaleString()} 원</HighLightText>
</TotalPriceText>
</InfoWrapper>
<RectButton type="price" onClick={() => handleButtonClick(total)}>
<RectButton type="price" onClick={() => handleButtonClick(totalPrice)}>
다음
</RectButton>
</SummaryWrapper>
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/containers/Modal/ModalContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { useContext } from 'react';
import CloseModal from '../../components/modal/CloseModal';
import GuideModal from '../../components/modal/GuideModal';
import SimilarQuoteModal from '../../components/modal/SimilarQuoteModal';
import { GuideModalContext } from '../../context/GuideMoadlContext';
import { SimilarQuoteModalContext } from '../../context/SimilarQuoteModalContext';
import { CloseModalContext } from '../../context/CloseModalContext';
import { GuideModalContext } from '../../context/GuideModalProvider';
import { SimilarQuoteModalContext } from '../../context/SimilarQuoteModalProvider';
import { CloseModalContext } from '../../context/CloseModalProvider';

export default function ModalContainer() {
const { setVisible: setCloseModalVisible } = useContext(CloseModalContext);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default function ModelTypelSelectContainer() {
<ModelTypeCard
onClick={() => {
setCurrentModelTypeIdx(el.modelId);
handleSelectedIdx(el.modelTypeName, el.modelId);
handleSelectedIdx(modelTypeToEn[el.modelTypeName], el.modelId);
}}
active={selectedModelTypeIdx[modelTypeToEn[el.modelTypeName]] === el.modelId}
desc={el.percentage + '%의 선택'}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/containers/TrimPage/TrimBannerContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { IMG_URL } from '../../utils/apis';
import CenterWrapper from '../../components/layout/CenterWrapper';
import Banner from '../../components/common/banner/Banner';
import HmgTag from '../../components/common/hmgTag/HmgTag';
import { ICartype, TrimContext } from '../../context/TrimContext';
import { ICartype, TrimContext } from '../../context/TrimProvider';
import Loading from '../../components/loading/Loading';

export default function TrimBannerContainer() {
Expand Down
53 changes: 38 additions & 15 deletions frontend/src/containers/TrimPage/TrimSelectContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,39 +7,62 @@ import {
HeadingKrMedium6,
HeadingKrMedium7,
} from '../../styles/typefaces';
import { PATH } from '../../utils/constants';
import { MESSAGE, PATH } from '../../utils/constants';
import CenterWrapper from '../../components/layout/CenterWrapper';
import DefaultCardStyle from '../../components/common/card/DefaultCardStyle';
import RectButton from '../../components/common/buttons/RectButton';
import { TrimContext } from '../../context/TrimContext';
import { TrimContext } from '../../context/TrimProvider';
import { ItemContext } from '../../context/ItemProvider';

export default function TrimSelectContainer() {
const {
selectedTrimIdx,
data: trimData,
loading,
setSelectedTrimIdx,
setSelectedImgIdx,
} = useContext(TrimContext);
const { setSelectedItem, setTotalPrice } = useContext(ItemContext);
const selectedTrim = trimData && trimData[selectedTrimIdx];
const navigate = useNavigate();
const { selectedTrimIdx, setSelectedTrimIdx, data, loading, setSelectedImgIdx } =
useContext(TrimContext);
const selectedData = data && data[selectedTrimIdx];

const handleSelectedIdx = (idx: number) => {
setSelectedTrimIdx(idx);
setSelectedImgIdx(0);
};
const handleButtonClick = (price: number) => {
price; // Todo. price 누적 값 저장
const isAcitve = (idx: number) => selectedTrimIdx === idx;
const handleNextButtonClick = (idx: number) => {
if (!isAcitve(idx)) {
return;
}
if (!selectedTrim) {
alert(MESSAGE.trimSelectRequired);
return;
}
setSelectedItem({
type: 'SET_TRIM',
value: {
id: selectedTrimIdx,
name: selectedTrim.trim,
price: selectedTrim.carDefaultPrice,
},
});
setTotalPrice(selectedTrim.carDefaultPrice);
navigate(PATH.modelType);
};

const displayTrimCards = () => {
if (!(selectedData && !loading)) {
if (!(selectedTrim && !loading)) {
return <></>;
}

const cardIndices = Array.from({ length: data.length }, (_, index) => index);
const cardIndices = Array.from({ length: trimData.length }, (_, index) => index);
return cardIndices.map((idx) => (
<TrimCard key={idx} onClick={() => handleSelectedIdx(idx)} active={selectedTrimIdx === idx}>
<TrimDesc>{data[idx].carDescription}</TrimDesc>
<TrimTitle>{data[idx].trim}</TrimTitle>
<TrimPrice>{data[idx].carDefaultPrice.toLocaleString()} 원</TrimPrice>
<TrimButton type={'trim'} onClick={() => handleButtonClick(data[idx].carDefaultPrice)}>
<TrimCard key={idx} onClick={() => handleSelectedIdx(idx)} active={isAcitve(idx)}>
<TrimDesc>{trimData[idx].carDescription}</TrimDesc>
<TrimTitle>{trimData[idx].trim}</TrimTitle>
<TrimPrice>{trimData[idx].carDefaultPrice.toLocaleString()} 원</TrimPrice>
<TrimButton type={'trim'} onClick={() => handleNextButtonClick(idx)}>
선택하기
</TrimButton>
</TrimCard>
Expand All @@ -48,7 +71,7 @@ export default function TrimSelectContainer() {

return (
<>
{data ? (
{trimData ? (
<Wrapper>
<Title>트림을 선택해주세요.</Title>
<TrimSection>{displayTrimCards()}</TrimSection>
Expand Down
Loading