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

타이어 커스텀 페이지 구현 - 측면 디자인 close #23 #24

Merged
merged 8 commits into from
Feb 10, 2024
6 changes: 6 additions & 0 deletions src/context/color.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { atom } from 'recoil';

export const selectedColorIdState = atom<number>({
key: 'selectedColorIdState',
default: 0,
});
6 changes: 6 additions & 0 deletions src/context/font.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { atom } from 'recoil';

export const selectedFontIdState = atom<number>({
key: 'selectedFontIdState',
default: 0,
});
41 changes: 41 additions & 0 deletions src/hooks/useCustomData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Accessory } from '@api/accessory';
import { AccessoryData } from '@api/accessory.types';
import { Color } from '@api/color';
import { ColorData } from '@api/color.types';
import { Font } from '@api/font';
import { FontData } from '@api/font.types';
import { Pattern } from '@api/pattern';
import { PatternData } from '@api/pattern.types';
import { Wheel } from '@api/wheel';
import { WheelData } from '@api/wheel.types';
import { useEffect, useState } from 'react';

function useCustomData() {
const [pattern, setPattern] = useState<PatternData[]>([]);
const [wheel, setWheel] = useState<WheelData[]>([]);
const [font, setFont] = useState<FontData[]>([]);
const [color, setColor] = useState<ColorData[]>([]);
const [accessory, setAccessory] = useState<AccessoryData[]>([]);

useEffect(() => {
const getData = async () => {
const [patterns, wheels, fonts, colors, accessories] = await Promise.all([
Pattern.list(),
Wheel.list(),
Font.list(),
Color.list(),
Accessory.list(),
]);
setPattern(patterns);
setWheel(wheels);
setFont(fonts);
setColor(colors);
setAccessory(accessories);
};
getData();
}, []);

return { pattern, wheel, font, color, accessory };
}

export default useCustomData;
10 changes: 9 additions & 1 deletion src/pages/production/button-group/index.style.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import styled from 'styled-components';

export const Container = styled.div`
interface ContainerProps {
position?: 'default' | 'absolute';
}

export const Container = styled.div<ContainerProps>`
background-color: #cdd1d9;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
gap: 5px;

${({ position }) =>
position === 'absolute' &&
'position: absolute; bottom: 0; right: 0; height: 50px; background-color: #ffffff; width: 22%; margin: 30px;'}
`;
5 changes: 3 additions & 2 deletions src/pages/production/button-group/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import { useNavigate } from 'react-router';

interface ButtonGroupProps {
step: number;
position?: 'default' | 'absolute';
}

function ButtonGroup(props: ButtonGroupProps) {
const navigate = useNavigate();

return (
<Container>
<Container className="button_group" position={props.position}>
{props.step > 0 ? (
<Button text="이전" inversion onClick={() => navigate(`/production?step=${props.step - 1}`)} />
) : (
Expand All @@ -19,7 +20,7 @@ function ButtonGroup(props: ButtonGroupProps) {
<Button
text={props.step < 3 ? '다음 단계로' : '결과 확인하기'}
onClick={() => {
if (props.step < 1) navigate(`/production?step=${props.step + 1}`);
if (props.step < 2) navigate(`/production?step=${props.step + 1}`);
}}
/>
</Container>
Expand Down
7 changes: 6 additions & 1 deletion src/pages/production/content/index.style.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import styled from 'styled-components';

export const Container = styled.div`
interface ContainerProps {
direction?: 'row' | 'column';
}

export const Container = styled.div<ContainerProps>`
width: 100%;
display: flex;
flex-direction: ${({ direction }) => direction || 'row'};
justify-content: space-around;
align-items: center;
gap: 50px;
Expand Down
13 changes: 3 additions & 10 deletions src/pages/production/content/index.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
import Preview from '@pages/production/content/preview';
import { Container } from './index.style';
import Summary from '@pages/production/content/summary';
import { PatternData } from '@api/pattern.types';
import { WheelData } from '@api/wheel.types';
import { AccessoryData } from '@api/accessory.types';

interface ContentProps {
data: PatternData | WheelData | AccessoryData;
direction?: 'row' | 'column';
}

function Content(props: ContentProps) {
if (!props.data) {
return <div>Loading...</div>;
}

return (
<Container className="content">
<Container className="content" direction={props.direction}>
<Preview />
<Summary data={props.data} />
<Summary />
</Container>
);
}
Expand Down
6 changes: 6 additions & 0 deletions src/pages/production/content/summary/index.style.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,10 @@ export const Container = styled.div`
height: 450px;
border-radius: 50px;
background-color: #f1f6f9;
.font_example {
border: 1px solid #000000;
background-color: gray;
font-size: 70px;
font-weight: 600;
}
`;
88 changes: 68 additions & 20 deletions src/pages/production/content/summary/index.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,77 @@
import useCustomData from '@hooks/useCustomData';
import { Container, Explanation, Name, Price } from './index.style';
import { PatternData } from '@api/pattern.types';
import { WheelData } from '@api/wheel.types';
import { AccessoryData } from '@api/accessory.types';

interface SummaryProps {
data: PatternData | WheelData | AccessoryData;
}
import { useSearchParams } from 'react-router-dom';
import { selectedPatternIdState } from '@context/pattern';
import { useRecoilState } from 'recoil';
import { selectedWheelIdState } from '@context/wheel';
import { selectedFontIdState } from '@context/font';
import { selectedColorIdState } from '@context/color';

function formatCurrency(price: number) {
return '+ ' + price.toLocaleString('ko-KR') + '원';
}

function Summary(props: SummaryProps) {
return (
<Container className="summary">
<div className="top">
<Name>{props.data.name}</Name>
<Price>{formatCurrency(props.data.price)}</Price>
</div>
<hr className="sep" />
<Explanation>
<p>{props.data.explanation}</p>
</Explanation>
</Container>
);
function Summary() {
const [searchParams] = useSearchParams();
const step: number = Number(searchParams.get('step'));
const { pattern, wheel, font, color, accessory } = useCustomData();
const [selectedPattern] = useRecoilState(selectedPatternIdState);
const [selectedWheel] = useRecoilState(selectedWheelIdState);
const [selectedFont] = useRecoilState(selectedFontIdState);
const [selectedColor] = useRecoilState(selectedColorIdState);

if (!pattern.length || !wheel.length || !font.length || !color.length || !accessory.length) {
return <div>Loading...</div>;
}

switch (step) {
case 0:
return (
<Container className="summary">
<div className="top">
<Name>{pattern[selectedPattern].name}</Name>
<Price>{formatCurrency(pattern[selectedPattern].price)}</Price>
</div>
<hr className="sep" />
<Explanation>
<p>{pattern[selectedPattern].explanation}</p>
</Explanation>
</Container>
);
case 1:
return (
<Container className="summary">
<div className="top">
<Name>{wheel[selectedWheel].name}</Name>
<Price>{formatCurrency(wheel[selectedWheel].price)}</Price>
</div>
<hr className="sep" />
<Explanation>
<p>{wheel[selectedWheel].explanation}</p>
</Explanation>
</Container>
);
case 2:
return (
<Container className="summary">
<div className="top">
<Name>{`${font[selectedFont].name}/${color[selectedColor].name}`}</Name>
<Price>{formatCurrency(font[selectedFont].price)}</Price>
</div>
<hr className="sep" />
<Explanation>
<p
className="font_example"
style={{ color: color[selectedColor].name, fontFamily: font[selectedFont].name }}
>
Outfit Of Tire
</p>
</Explanation>
</Container>
);
default:
return <div>Error...</div>;
}
}

export default Summary;
26 changes: 22 additions & 4 deletions src/pages/production/index.style.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,30 @@ export const Container = styled.div`
height: 100vh;
display: flex;
flex-direction: column;
.content {
flex-grow: 1;
}
.footer {

.content_cntr {
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.content {
flex-grow: 1;
}
.footer {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
.side_cntr {
flex-grow: 1;
display: flex;
flex-direction: column;
gap: 50px;
}
}
}
.row {
flex-direction: row;
}
`;
64 changes: 16 additions & 48 deletions src/pages/production/index.tsx
Original file line number Diff line number Diff line change
@@ -1,72 +1,40 @@
import Header from '@components/header';
import { Container } from './index.style';
import { useEffect, useState } from 'react';
import { PatternData } from '@api/pattern.types';
import { Pattern } from '@api/pattern';
import TabMenu from './tab-menu';
import OptionSelector from './option-selector';
import { selectedPatternIdState } from '@context/pattern';
import Content from '@pages/production/content';
import { useRecoilState } from 'recoil';
import ButtonGroup from './button-group';
import { useSearchParams } from 'react-router-dom';
import { WheelData } from '@api/wheel.types';
import { FontData } from '@api/font.types';
import { ColorData } from '@api/color.types';
import { AccessoryData } from '@api/accessory.types';
import { Wheel } from '@api/wheel';
import { Font } from '@api/font';
import { Color } from '@api/color';
import { Accessory } from '@api/accessory';
import { selectedWheelIdState } from '@context/wheel';

function CustomPattern() {
const [searchParams] = useSearchParams();
const [patterns, setPatterns] = useState<PatternData[]>([]);
const [wheels, setWheels] = useState<WheelData[]>([]);
const [fonts, setFonts] = useState<FontData[]>([]);
const [colors, setColors] = useState<ColorData[]>([]);
const [accessories, setAccessories] = useState<AccessoryData[]>([]);
const [selectedPattern] = useRecoilState(selectedPatternIdState);
const [selectedWheel] = useRecoilState(selectedWheelIdState);
const step: number = Number(searchParams.get('step'));

if (step < 0 || step > 3) {
return <div>올바르지 않은 접근입니다.</div>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

올바르지 않은 접근일 때는 어떻게 처리가 되나요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

그냥 빈 화면에 "올바르지 않은 접근입니다."라고 출력돼서 나옵니다~

}

useEffect(() => {
const getData = async () => {
const [patterns, wheels, fonts, colors, accessories] = await Promise.all([
Pattern.list(),
Wheel.list(),
Font.list(),
Color.list(),
Accessory.list(),
]);
setPatterns(patterns);
setWheels(wheels);
setFonts(fonts);
setColors(colors);
setAccessories(accessories);
};
getData();
}, []);

return (
<>
<Container>
<Header />
<TabMenu step={step} />
{step === 0 && <Content data={patterns[selectedPattern]} />}
{step === 1 && <Content data={wheels[selectedWheel]} />}
<div className="footer">
{step === 0 && <OptionSelector type="square" data={patterns} />}
{step === 1 && <OptionSelector type="square" data={wheels} />}
{step === 2 && <OptionSelector type="circle" data={fonts} />}
{step === 2 && <OptionSelector type="circle" data={colors} />}
{step === 3 && <OptionSelector type="square" data={accessories} />}
<ButtonGroup step={step} />
<div className={`content_cntr ${step === 2 && 'row'}`}>
{step !== 2 && <Content direction="row" />}
{step === 2 && <Content direction="column" />}
<div className="footer">
{step === 0 && <OptionSelector shape="square" data={'pattern'} />}
{step === 1 && <OptionSelector shape="square" data={'wheel'} />}
{step === 2 && (
<div className="side_cntr">
<OptionSelector shape="circle" data={'font'} />
<OptionSelector shape="circle" data={'color'} />
<div>&nbsp;</div>
</div>
)}
{step === 3 && <OptionSelector shape="square" data={'accessory'} />}
{step === 2 ? <ButtonGroup step={step} position="absolute" /> : <ButtonGroup step={step} />}
</div>
</div>
</Container>
</>
Expand Down
Loading
Loading