diff --git a/package-lock.json b/package-lock.json index f1c2e1b..cbffc3f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "react-router-dom": "^6.4.2", "react-scripts": "5.0.1", "styled-components": "^5.3.6", + "styled-reset": "^4.4.2", "web-vitals": "^2.1.4" }, "devDependencies": { @@ -15277,6 +15278,21 @@ "node": ">=4" } }, + "node_modules/styled-reset": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/styled-reset/-/styled-reset-4.4.2.tgz", + "integrity": "sha512-VzVhEZHpO/CD/F5ZllqTAY+GTaKlNDZt5mTrtPf/kXZSe85+wMkhRIiPARgvCP9/HQMk+ZGaEWk1IkdP2SYAUQ==", + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "type": "ko-fi", + "url": "https://ko-fi.com/zacanger" + }, + "peerDependencies": { + "styled-components": ">=4.0.0 || >=5.0.0" + } + }, "node_modules/stylehacks": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", @@ -28076,6 +28092,12 @@ } } }, + "styled-reset": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/styled-reset/-/styled-reset-4.4.2.tgz", + "integrity": "sha512-VzVhEZHpO/CD/F5ZllqTAY+GTaKlNDZt5mTrtPf/kXZSe85+wMkhRIiPARgvCP9/HQMk+ZGaEWk1IkdP2SYAUQ==", + "requires": {} + }, "stylehacks": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", diff --git a/package.json b/package.json index 513f9cb..718c88f 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "react-router-dom": "^6.4.2", "react-scripts": "5.0.1", "styled-components": "^5.3.6", + "styled-reset": "^4.4.2", "web-vitals": "^2.1.4" }, "scripts": { diff --git a/public/index.html b/public/index.html index 1684344..51b2a60 100644 --- a/public/index.html +++ b/public/index.html @@ -3,6 +3,12 @@ + + + diff --git a/src/App.js b/src/App.js deleted file mode 100644 index 491dfe5..0000000 --- a/src/App.js +++ /dev/null @@ -1,5 +0,0 @@ -function App() { - return

Hello React!

; -} - -export default App; diff --git a/src/App.jsx b/src/App.jsx new file mode 100644 index 0000000..4477dd2 --- /dev/null +++ b/src/App.jsx @@ -0,0 +1,14 @@ +import Providers from "./context/Providers"; +import AppRouter from "./routes/AppRouter"; +import GlobalStyle from "./styles/globalStyles"; + +function App() { + return ( + + + + + ); +} + +export default App; diff --git a/src/api/carAPI.js b/src/api/carAPI.js new file mode 100644 index 0000000..0356de1 --- /dev/null +++ b/src/api/carAPI.js @@ -0,0 +1,70 @@ +import { CAR_API_URL, CAR_FUELTYPE, CAR_SEGMENT } from "./constant"; +import { createInstance } from "./createInstance"; + +const BASE_URL = "https://preonboarding.platdev.net/api"; + +class carAPI { + #API; + #instance; + #fuelType; + #segment; + + constructor() { + this.#instance = createInstance({ + url: BASE_URL, + config: { + timeout: 3000, + }, + }); + this.#API = CAR_API_URL; + this.#fuelType = CAR_FUELTYPE; + this.#segment = CAR_SEGMENT; + } + + getAllCar() { + return this.#instance.get(this.#API.cars); + } + + getFuelTypeSegmentCars({ fuelType, segment }) { + return this.#instance.get(this.#API.cars, { + params: { + fuelType, + segment, + }, + }); + } + + getFuelTypeCars({ fuleType }) { + return this.#instance.get(this.#API.cars, { + params: { + fuleType, + }, + }); + } + + async getSegmentCars({ segment }) { + return this.#instance.get(this.#API.cars, { + params: { + segment, + }, + }); + } + + async getSmallCars() { + return this.getSegmentCars({ segment: this.#segment.small }); + } + + async getMediumCars() { + return this.getSegmentCars({ segment: this.#segment.medium }); + } + + async getLargeCars() { + return this.getSegmentCars({ segment: this.#segment.large }); + } + + async getSuvCars() { + return this.getSegmentCars({ segment: this.#segment.suv }); + } +} + +export default new carAPI(); diff --git a/src/api/constant.js b/src/api/constant.js new file mode 100644 index 0000000..8752a63 --- /dev/null +++ b/src/api/constant.js @@ -0,0 +1,16 @@ +export const CAR_API_URL = { + cars: "/cars", +}; + +export const CAR_FUELTYPE = { + gasiline: "gasoline", + hybrid: "hybrid", + ev: "ev", +}; + +export const CAR_SEGMENT = { + small: "C", + medium: "D", + large: "E", + suv: "SUV", +}; diff --git a/src/api/createInstance.js b/src/api/createInstance.js new file mode 100644 index 0000000..d50c6a0 --- /dev/null +++ b/src/api/createInstance.js @@ -0,0 +1,8 @@ +import axios from "axios"; + +export const createInstance = ({ url, config }) => { + return axios.create({ + baseURL: url, + ...config, + }); +}; diff --git a/src/assets/icons/iconBack.png b/src/assets/icons/iconBack.png new file mode 100644 index 0000000..56a68b8 Binary files /dev/null and b/src/assets/icons/iconBack.png differ diff --git a/src/components/CarDetail/CarAdditionalProducts.jsx b/src/components/CarDetail/CarAdditionalProducts.jsx new file mode 100644 index 0000000..b740558 --- /dev/null +++ b/src/components/CarDetail/CarAdditionalProducts.jsx @@ -0,0 +1,23 @@ +import React from "react"; +import { formatAmout } from "../../utils/formatAmount"; +import DetailInfo from "../common/DetailInfo"; +import SubHeader from "../common/SubHeader"; + +const CarAdditionalProducts = ({ additionalProducts }) => { + return ( +
+ +
+ {additionalProducts && + additionalProducts.map((element) => { + const { name, amount } = element; + return ( + + ); + })} +
+
+ ); +}; + +export default CarAdditionalProducts; diff --git a/src/components/CarDetail/CarDetail.jsx b/src/components/CarDetail/CarDetail.jsx new file mode 100644 index 0000000..05db0d5 --- /dev/null +++ b/src/components/CarDetail/CarDetail.jsx @@ -0,0 +1,55 @@ +import React from "react"; +import styled from "styled-components"; +import { useLocation } from "../../../node_modules/react-router-dom/dist/index"; +import CarAdditionalProducts from "./CarAdditionalProducts"; +import CarInfo from "./CarInfo"; +import CarInsurance from "./CarInsurance"; +import CarMainDetail from "./CarMainDetail"; + +const CarDetail = () => { + const { + state: { + state: { + startDate, + amount, + attribute: { brand, name, segment, fuelType, imageUrl }, + insurance, + additionalProducts, + }, + }, + } = useLocation(); + + return ( +
+ + {name} + + + + + + + +
+ ); +}; + +const S = { + CarImg: styled.div` + width: 100%; + min-height: 20rem; + display: flex; + justify-content: center; + position: relative; + background-color: ${({ theme }) => theme.color.gray}; + img { + max-width: 200px; + width: 100%; + } + `, + Detail: styled.div` + display: flex; + flex-direction: column; + `, +}; +export default CarDetail; diff --git a/src/components/CarDetail/CarDetailHeader.jsx b/src/components/CarDetail/CarDetailHeader.jsx new file mode 100644 index 0000000..b01c728 --- /dev/null +++ b/src/components/CarDetail/CarDetailHeader.jsx @@ -0,0 +1,35 @@ +import styled from "styled-components"; +import { useNavigate } from "../../../node_modules/react-router-dom/dist/index"; +import icon from "../../assets/icons/iconBack.png"; +const CarDetailHeader = () => { + const navigate = useNavigate(); + return ( + + navigate(-1)}> + back_button + +

차량상세

+
+ ); +}; + +const S = { + Header: styled.div` + padding: 2rem 15rem; + text-align: center; + position: relative; + h1 { + min-width: 6.4rem; + max-height: 6rem; + font-weight: 700; + font-size: 17px; + line-height: 21px; + color: ${({ theme }) => theme.black}; + } + `, + BackButon: styled.button` + position: absolute; + left: 5%; + `, +}; +export default CarDetailHeader; diff --git a/src/components/CarDetail/CarInfo.jsx b/src/components/CarDetail/CarInfo.jsx new file mode 100644 index 0000000..63f1f24 --- /dev/null +++ b/src/components/CarDetail/CarInfo.jsx @@ -0,0 +1,27 @@ +import React from "react"; +import styled from "styled-components"; +import DetailInfo from "../common/DetailInfo"; +import SubHeader from "../common/SubHeader"; + +//TODO: utls로 분리 +const day = ["월", "화", "수", "목", "금", "토", "일"]; +const startDateFormat = (stringDate) => { + const date = new Date(stringDate); + return `${date.getMonth() + 1} 월 ${date.getDate()}일 (${day[date.getDay()]}) 부터 `; +}; + +const CarInfo = ({ segment, fuelType, startDate }) => { + return ( + + + + + + + ); +}; + +const S = { + CarInfo: styled.div``, +}; +export default CarInfo; diff --git a/src/components/CarDetail/CarInsurance.jsx b/src/components/CarDetail/CarInsurance.jsx new file mode 100644 index 0000000..dd0b01d --- /dev/null +++ b/src/components/CarDetail/CarInsurance.jsx @@ -0,0 +1,20 @@ +import React from "react"; +import DetailInfo from "../common/DetailInfo"; +import SubHeader from "../common/SubHeader"; + +const CarInsurance = ({ insurance }) => { + return ( +
+ +
+ {insurance && + insurance.map((element) => { + const { name, description } = element; + return ; + })} +
+
+ ); +}; + +export default CarInsurance; diff --git a/src/components/CarDetail/CarMainDetail.jsx b/src/components/CarDetail/CarMainDetail.jsx new file mode 100644 index 0000000..7b7ab85 --- /dev/null +++ b/src/components/CarDetail/CarMainDetail.jsx @@ -0,0 +1,45 @@ +import React from "react"; +import styled from "styled-components"; +import { formatAmout } from "../../utils/formatAmount"; + +const CarMainDetail = ({ brand, name, amount }) => { + return ( + + {brand} + {name} + +

월 {formatAmout(amount)} 원

+
+
+ ); +}; + +const S = { + MainDetail: styled.div` + display: flex; + flex-direction: column; + gap: 0.2rem; + font-size: inherit; + padding: 2rem; + strong { + font-weight: 700; + font-size: 1.4rem; + } + > :first-child { + font-size: 2rem; + } + + > :nth-child(2) { + font-size: 2.4rem; + margin-bottom: 0.8rem; + } + `, + + AmountContainer: styled.span` + text-align: right; + font-weight: 400; + font-size: 1.7rem; + `, +}; + +export default CarMainDetail; diff --git a/src/components/CarMain.jsx/CarHeader.jsx b/src/components/CarMain.jsx/CarHeader.jsx new file mode 100644 index 0000000..1ea76cc --- /dev/null +++ b/src/components/CarMain.jsx/CarHeader.jsx @@ -0,0 +1,24 @@ +import styled from "styled-components"; + +const CarHeader = () => { + return ( + +

전체 차량

+
+ ); +}; + +const S = { + Header: styled.div` + padding: 2rem 16rem; + text-align: center; + h1 { + min-width: 6.4rem; + font-weight: 700; + font-size: 17px; + line-height: 21px; + color: ${({ theme }) => theme.black}; + } + `, +}; +export default CarHeader; diff --git a/src/components/CarMain.jsx/CarItem.jsx b/src/components/CarMain.jsx/CarItem.jsx new file mode 100644 index 0000000..144905f --- /dev/null +++ b/src/components/CarMain.jsx/CarItem.jsx @@ -0,0 +1,65 @@ +import React from "react"; +import styled from "styled-components"; +import { carModel } from "../../utils/carModel"; +import { formatAmout } from "../../utils/formatAmount"; +import New from "../common/New"; + +const inDay = (date) => { + const today = new Date(); + const day = new Date(date); + return today.getFullYear() === day.getFullYear() && today.getDate() >= day.getDate(); +}; + +const CarItem = ({ brand, name, segment, fuelType, amount, imageUrl, createdAt }) => { + return ( + + + {brand} + {name} +

{`${segment} / ${carModel.fuelType[fuelType]}`}

+

월 {formatAmout(amount)} 부터

+
+ + {{`${name}사진`}} {inDay(createdAt) ? : null} + +
+ ); +}; + +const S = { + CarItemContainer: styled.li` + width: 100%; + height: 120px; + color: ${({ theme }) => theme.black}; + border-bottom: 1px solid ${({ theme }) => theme.black}; + padding: 1.25em 1.55em; + display: flex; + justify-content: space-between; + font-size: 1.2rem; + `, + CarInfo: styled.div` + display: flex; + flex-direction: column; + gap: 0.2rem; + font-size: inherit; + strong { + font-weight: 700; + font-size: 1.4rem; + } + > :nth-child(2) { + margin-bottom: 0.8rem; + } + `, + + CarImg: styled.div` + position: relative; + width: 20rem; + background-color: ${({ theme }) => theme.color.gray}; + img { + max-width: 200px; + width: 100%; + } + `, +}; + +export default CarItem; diff --git a/src/components/CarMain.jsx/CarList.jsx b/src/components/CarMain.jsx/CarList.jsx new file mode 100644 index 0000000..aaf5e62 --- /dev/null +++ b/src/components/CarMain.jsx/CarList.jsx @@ -0,0 +1,45 @@ +import React from "react"; +import styled from "styled-components"; +import { Link } from "../../../node_modules/react-router-dom/dist/index"; +import CarItem from "./CarItem"; +import Message from "../common/Message"; + +const CarList = ({ carInfo, isLoading }) => { + if (isLoading) return ; + + return ( + + {carInfo.length > 0 ? ( + carInfo.map((car) => { + const { + id, + amount, + createdAt, + attribute: { brand, name, segment, fuelType, imageUrl }, + } = car; + return ( + + + + ); + }) + ) : ( + + )} + + ); +}; + +const S = { + CarListContainer: styled.ul``, +}; + +export default CarList; diff --git a/src/components/CarMain.jsx/Category.jsx b/src/components/CarMain.jsx/Category.jsx new file mode 100644 index 0000000..2527b4c --- /dev/null +++ b/src/components/CarMain.jsx/Category.jsx @@ -0,0 +1,31 @@ +import React from "react"; +import styled from "styled-components"; +import { useTags } from "../../hooks/useTags"; +import Tag from "../common/Tag"; + +const Category = ({ setAllCar }) => { + const { tags, handleClick } = useTags(setAllCar); + + return ( + + {tags + ? tags.map((tag) => ( + + )) + : null} + + ); +}; + +const S = { + Category: styled.ul` + display: flex; + align-items: center; + justify-content: flex-start; + gap: 0.8rem; + padding: 0.6rem; + border-top: 1px solid ${({ theme }) => theme.black}; + border-bottom: 1px solid ${({ theme }) => theme.black}; + `, +}; +export default Category; diff --git a/src/components/Layout.jsx b/src/components/Layout.jsx new file mode 100644 index 0000000..794525c --- /dev/null +++ b/src/components/Layout.jsx @@ -0,0 +1,17 @@ +import React from "react"; +import styled from "styled-components"; +import { Outlet } from "../../node_modules/react-router-dom/dist/index"; + +const Layout = () => { + return ( + + + + ); +}; + +const Wrraper = styled.div` + width: 100%; + max-width: 450px; +`; +export default Layout; diff --git a/src/components/common/Button.jsx b/src/components/common/Button.jsx new file mode 100644 index 0000000..96feada --- /dev/null +++ b/src/components/common/Button.jsx @@ -0,0 +1,25 @@ +import React from "react"; +import styled from "styled-components"; + +const Button = ({ label, onClick, color = "primary" }) => { + return ( + + + + ); +}; + +export const ButtonContainer = styled.button` + padding: 0.5em 1.8em; + color: ${({ theme, color }) => theme.fontColor[color]}; + background-color: ${({ theme, color }) => theme.bgColor[color]}; + border-radius: 62px; + width: 100%; + min-width: 6.2rem; + min-height: 27px; + font-size: 1.4rem; + text-align: center; + box-sizing: border-box; +`; + +export default Button; diff --git a/src/components/common/DetailInfo.jsx b/src/components/common/DetailInfo.jsx new file mode 100644 index 0000000..c9885eb --- /dev/null +++ b/src/components/common/DetailInfo.jsx @@ -0,0 +1,35 @@ +import React from "react"; +import styled from "styled-components"; + +const DetailInfo = ({ name, description }) => { + return ( + + + {name} +

{description}

+
+
+ ); +}; + +const S = { + Info: styled.div` + display: flex; + flex-direction: column; + gap: 2rem; + padding: 1.2rem 2rem; + span { + display: flex; + justify-content: space-between; + } + strong { + font-weight: 700; + font-size: 1.7rem; + } + p { + font-weight: 400; + font-size: 1.7rem; + } + `, +}; +export default DetailInfo; diff --git a/src/components/common/Message.jsx b/src/components/common/Message.jsx new file mode 100644 index 0000000..e7d7b9e --- /dev/null +++ b/src/components/common/Message.jsx @@ -0,0 +1,26 @@ +import React from "react"; +import styled from "styled-components"; + +const Message = ({ message }) => { + return ( + +

{message}

+
+ ); +}; + +const S = { + Container: styled.div` + display: flex; + align-items: center; + justify-content: center; + height: 50vh; + text-align: center; + h1 { + font-weight: 700; + font-size: 1.7rem; + } + `, +}; + +export default Message; diff --git a/src/components/common/New.jsx b/src/components/common/New.jsx new file mode 100644 index 0000000..4027c7b --- /dev/null +++ b/src/components/common/New.jsx @@ -0,0 +1,25 @@ +import React from "react"; +import styled from "styled-components"; +import { ButtonContainer } from "./Button"; + +const New = () => { + return ( + + + + ); +}; + +const S = { + New: styled(ButtonContainer)` + max-width: 5.2rem; + max-height: 2.2rem; + position: absolute; + top: 0; + right: 0; + transform: translate(20%, -50%); + padding: 0.4rem 0.3rem; + `, +}; + +export default New; diff --git a/src/components/common/SubHeader.jsx b/src/components/common/SubHeader.jsx new file mode 100644 index 0000000..e160ce4 --- /dev/null +++ b/src/components/common/SubHeader.jsx @@ -0,0 +1,24 @@ +import React from "react"; +import styled from "styled-components"; + +const SubHeader = ({ title }) => { + return ( + +

{title}

+
+ ); +}; + +const S = { + SubHeader: styled.div` + padding: 2rem; + display: flex; + align-items: center; + height: 4.8rem; + font-weight: 700; + font-size: 1.7rem; + background-color: ${({ theme }) => theme.bgColor["tertiary"]}; + color: ${({ theme }) => theme.fontColor["tertiary"]}; + `, +}; +export default SubHeader; diff --git a/src/components/common/Tag.jsx b/src/components/common/Tag.jsx new file mode 100644 index 0000000..9479688 --- /dev/null +++ b/src/components/common/Tag.jsx @@ -0,0 +1,12 @@ +import React from "react"; +import Button from "./Button"; + +const Tag = ({ label, isActive, onClick }) => { + return ( +
  • +
  • + ); +}; + +export default Tag; diff --git a/src/context/CarProvider.jsx b/src/context/CarProvider.jsx new file mode 100644 index 0000000..eee93ee --- /dev/null +++ b/src/context/CarProvider.jsx @@ -0,0 +1,55 @@ +import { createContext, useContext, useMemo, useState } from "react"; +import carAPI from "../api/carAPI"; + +const CarInfoValueContext = createContext(null); +const CarInfoActionContext = createContext(null); + +const useCarInfo = () => { + const value = useContext(CarInfoValueContext); + if (value === null) { + throw new Error("useCarInfo should be used within TodosProvider"); + } + return value; +}; + +const useCarInfoActions = () => { + const value = useContext(CarInfoActionContext); + if (value === null) { + throw new Error("useCarInfoActions should be used within TodosProvider"); + } + return value; +}; + +const CarInfoProvider = ({ children }) => { + const [carInfo, setCarInfo] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const actions = useMemo( + () => ({ + async getAllCar() { + setIsLoading(true); + const { + data: { payload }, + } = await carAPI.getAllCar(); + setIsLoading(false); + setCarInfo(payload); + }, + async setAllCar(fetchData) { + setIsLoading(true); + const { + data: { payload }, + } = await fetchData(); + setIsLoading(false); + setCarInfo(payload); + }, + }), + [], + ); + + return ( + + {children} + + ); +}; + +export { useCarInfo, useCarInfoActions, CarInfoProvider }; diff --git a/src/context/ColorProvider.jsx b/src/context/ColorProvider.jsx new file mode 100644 index 0000000..a084bea --- /dev/null +++ b/src/context/ColorProvider.jsx @@ -0,0 +1,8 @@ +import { ThemeProvider } from "styled-components"; +import theme from "../styles/theme"; + +const ColorProvider = ({ children }) => { + return {children}; +}; + +export { ColorProvider }; diff --git a/src/context/Providers.jsx b/src/context/Providers.jsx new file mode 100644 index 0000000..fc2d21e --- /dev/null +++ b/src/context/Providers.jsx @@ -0,0 +1,12 @@ +import { CarInfoProvider } from "./CarProvider"; +import { ColorProvider } from "./ColorProvider"; + +const Providers = ({ children }) => { + return ( + + {children} + + ); +}; + +export default Providers; diff --git a/src/hooks/useTags.js b/src/hooks/useTags.js new file mode 100644 index 0000000..1b8b2f1 --- /dev/null +++ b/src/hooks/useTags.js @@ -0,0 +1,57 @@ +import { useState } from "react"; +import carAPI from "../api/carAPI"; +import { carModel } from "../utils/carModel"; + +const initalTags = [ + { + label: "전체", + isActive: true, + handleClick: () => carAPI.getAllCar(), + }, + { + label: carModel.segment.C, + isActive: false, + handleClick: () => carAPI.getSmallCars(), + }, + { + label: carModel.segment.D, + isActive: false, + handleClick: () => carAPI.getMediumCars(), + }, + { + label: carModel.segment.E, + isActive: false, + handleClick: () => carAPI.getLargeCars(), + }, +]; + +export const useTags = (setAllCar) => { + const [tags, setTags] = useState(initalTags); + + const toggle = (findIndex) => { + const newTags = tags.map((tag, index) => { + if (findIndex === index) + return { + isActive: !tag.isActive, + label: tag.label, + handleClick: tag.handleClick, + }; + else + return { + isActive: false, + label: tag.label, + handleClick: tag.handleClick, + }; + }); + setTags(newTags); + }; + + const handleClick = async (e) => { + const curLabel = e.target.innerText; + const findIndex = tags.findIndex((tag) => tag.label === curLabel); + toggle(findIndex); + setAllCar(await tags[findIndex].handleClick); + }; + + return { tags, handleClick }; +}; diff --git a/src/index.css b/src/index.css deleted file mode 100644 index 714ab0e..0000000 --- a/src/index.css +++ /dev/null @@ -1,11 +0,0 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", - "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; -} diff --git a/src/index.js b/src/index.jsx similarity index 89% rename from src/index.js rename to src/index.jsx index a64e7d5..71a354b 100644 --- a/src/index.js +++ b/src/index.jsx @@ -1,6 +1,5 @@ import React from "react"; import ReactDOM from "react-dom/client"; -import "./index.css"; import App from "./App"; const root = ReactDOM.createRoot(document.getElementById("root")); diff --git a/src/pages/CarDetailPage.jsx b/src/pages/CarDetailPage.jsx new file mode 100644 index 0000000..0b847d0 --- /dev/null +++ b/src/pages/CarDetailPage.jsx @@ -0,0 +1,19 @@ +import React from "react"; +import styled from "styled-components"; +import CarDetail from "../components/CarDetail/CarDetail"; +import CarDetailHeader from "../components/CarDetail/CarDetailHeader"; + +const CarDetailPage = () => { + return ( + + + + + ); +}; + +const S = { + DetailContainer: styled.div``, +}; + +export default CarDetailPage; diff --git a/src/pages/MainCarPage.jsx b/src/pages/MainCarPage.jsx new file mode 100644 index 0000000..a3457ca --- /dev/null +++ b/src/pages/MainCarPage.jsx @@ -0,0 +1,30 @@ +import React, { useEffect } from "react"; +import styled from "styled-components"; +import Category from "../components/CarMain.jsx/Category"; +import CarHeader from "../components/CarMain.jsx/CarHeader"; +import CarList from "../components/CarMain.jsx/CarList"; +import { useCarInfo, useCarInfoActions } from "../context/CarProvider"; + +const CarMain = () => { + const { carInfo, isLoading } = useCarInfo(); + + const { getAllCar, setAllCar } = useCarInfoActions(); + + useEffect(() => { + getAllCar(); + }, [getAllCar]); + + return ( + + + + + + ); +}; + +export default CarMain; + +const S = { + CarContainer: styled.div``, +}; diff --git a/src/pages/NotFoundPage.jsx b/src/pages/NotFoundPage.jsx new file mode 100644 index 0000000..75f177c --- /dev/null +++ b/src/pages/NotFoundPage.jsx @@ -0,0 +1,7 @@ +import React from "react"; + +const NotFound = () => { + return
    NotFound
    ; +}; + +export default NotFound; diff --git a/src/routes/AppRouter.jsx b/src/routes/AppRouter.jsx new file mode 100644 index 0000000..8de81a5 --- /dev/null +++ b/src/routes/AppRouter.jsx @@ -0,0 +1,21 @@ +import React from "react"; +import { BrowserRouter, Route, Routes } from "../../node_modules/react-router-dom/dist/index"; +import Layout from "../components/Layout"; +import { routes } from "./routePath"; + +const AppRouter = () => { + return ( + + + }> + {routes.map((route) => { + const { path, element } = route; + return ; + })} + + + + ); +}; + +export default AppRouter; diff --git a/src/routes/routePath.js b/src/routes/routePath.js new file mode 100644 index 0000000..a662ff2 --- /dev/null +++ b/src/routes/routePath.js @@ -0,0 +1,24 @@ +import NotFoundPage from "../pages/NotFoundPage"; +import CarDetailPage from "../pages/CarDetailPage"; +import CarMainPage from "../pages/MainCarPage"; + +export const routePath = { + carMainPage: "/", + carDetailPage: "detail/:id", + notFoundPage: "*", +}; + +export const routes = [ + { + path: routePath.carMainPage, + element: , + }, + { + path: routePath.carDetailPage, + element: , + }, + { + path: routePath.notFoundPage, + element: , + }, +]; diff --git a/src/styles/globalStyles.js b/src/styles/globalStyles.js new file mode 100644 index 0000000..a632707 --- /dev/null +++ b/src/styles/globalStyles.js @@ -0,0 +1,19 @@ +import { createGlobalStyle } from "styled-components"; +import reset from "styled-reset"; +const GlobalStyle = createGlobalStyle` + ${reset} + html { font-size: 62.5%; + font-family: 'Inter', sans-serif; + } + button,a {all:unset} + div,li{ + box-sizing: border-box; + } + + #root{ + display:flex ; + justify-content:center ; + } +`; + +export default GlobalStyle; diff --git a/src/styles/theme.js b/src/styles/theme.js new file mode 100644 index 0000000..8c3a2b0 --- /dev/null +++ b/src/styles/theme.js @@ -0,0 +1,26 @@ +const color = { + black: "#000000", + gray: "#d9d9d9", + blue: "#0094ff", + white: "#FFFFFF", +}; + +const bgColor = { + primary: color.black, + secondary: color.gray, + tertiary: color.blue, +}; + +const fontColor = { + primary: color.white, + secondary: color.black, + tertiary: color.white, +}; + +const theme = { + color, + bgColor, + fontColor, +}; + +export default theme; diff --git a/src/utils/carModel.js b/src/utils/carModel.js new file mode 100644 index 0000000..01623cf --- /dev/null +++ b/src/utils/carModel.js @@ -0,0 +1,20 @@ +export const carModel = { + fuelType: { + gasoline: "가솔린", + ev: "전기", + hybid: "하이브리드", + }, + segment: { + C: "소형", + D: "중형", + E: "대형", + }, +}; + +export const getCarSegment = () => { + return Object.values(carModel.segment); +}; + +export const getCarFuelType = () => { + return Object.values(carModel.fuelType); +}; diff --git a/src/utils/formatAmount.js b/src/utils/formatAmount.js new file mode 100644 index 0000000..8467bb8 --- /dev/null +++ b/src/utils/formatAmount.js @@ -0,0 +1,3 @@ +export const formatAmout = (amount) => { + return amount.toString().replace(/\B(?