Skip to content

Commit

Permalink
[Team19][Json, Dico] Sidedish 2주차 PR (Final) (#73)
Browse files Browse the repository at this point in the history
* [#1] init: 🎉 개발 환경 구축

* [#3] feat: ✨ Header 만들기

* [#5] feat: ✨ BestTab UI 구현

- BestTab UI
- 상수 파일
    - const.js
- 재사용 컴포넌트
    - Label.jsx
    - ItemCard.jsx

* [#7] feat: ✨ Slide UI 구현

- App.jsx
    - SlideContainer import
- BestItem.jsx
    - 삭제 (미사용)
- BestItems.jsx
    - ItemCard prop 추가
- BestTab.jsx
    - 스타일 수정
- SlideContainer.jsx
    - UI 구현
- SlideItems.jsx
    - UI 구현
- SlideArrowBtn.jsx
    - UI 구현
- ItemCard.jsx
    - 스타일 수정
    - prop 추가
- Label.jsx
    - prop 추가
    - 기본 값 추가

* [#8] feat: ✨ ShowMoreBtn UI 구현

- App.js
    - ShowMoreBtn import
- ShowMoreBtn.jsx
    - UI 구현

* [#10] feat: ✨ Header Dropdown 구현

- App.js
    - Header 경로 수정
- Header.jsx
    - 경로 변경
    - HeaderLeft & Right 분리
- HeaderLeft.jsx
    - 컴포넌트화
    - Navigations 컴포넌트화
- HeaderRight.jsx
    - 컴포넌트화
- Navigations.jsx
    - 컴포넌트화
    - Dropdown 구현

* [#13] feat: ✨ API에 fetch 요청 로직 구현

* [#13] feat: ✨ API 요청, 베스트 기능구현
- BestItems.jsx
   - API 데이터 동기화
- BestTab.jsx
   - useState, useEffect, API 요청
- BestTabContainer.jsx
   - API 데이터 동기화
- BestTabNavigator.jsx
   - API 데이터 동기화
- ItemCard.jsx
   - prop 변경
- Label.jsx
  - COLOR변수 추가

* [#15] feat: ✨ 상세 modal 페이지 UI 구현
- App.js
   - PopUpContainer import
-  PopUpContainer.jsx
   - UI 구현
- PopUpImages.jsx
   - UI 구현
- PopUpInformations.jsx
   - UI 구현

* [#16] feat: ✨ 모달 페이지 이벤트 구현중

* [#16] feat: ✨ 수량정보 컴포넌트 분리

* [#19] refactor: 🔨 리팩토링, 부족한 부분 추가 구현
- 파일 및 폴더 구조 변경
   - common 폴더 생성
- Context.jsx
   - useContext 사용하여 prop drilling 개선
- 팝업 이벤트 구현
   - 수량 변경
   - 주문하기
   - 주문결과 안내 메시지 UI

* [#19] refactor: 🔨 리팩토링

* [#17] feat: ✨ dj-slider 폴더구조 구축

* [#17] feat: ✨ 슬라이드 1/2 구현 중

* [#23] refactor: 🔨 코드 리뷰 코멘트 반영 및 개선

* [#17] feat: ✨ 슬라이드 구현중/일부사항 수정
- util.js
   - price에 comma 붙이는 기능 구현
- PopUpItemCountContainer.jsx
   - price에 comma 붙이는 기능 import
- ItemCard.jsx
   - price에 comma 붙이는 기능 import
   - 이미지 background로 수정
- Label.jsx
   - 라벨 배경색상 적용

* [#17] feat: ✨ 슬라이드 구현중

- 모듈화
   - 시연을 위한 기능 구현을 위해 보류

* [#25] feat: ✨ 슬라이드 2/2 구현, API 데이터 동기화

- 슬라이드 명칭을 캐로셀로 변경
- API 데이터 동기화
- 캐로셀의 ItemCard를 children으로 변경
   - 모듈화를 위함!
- 아이템카드 mini, large 프로퍼티 추가
- 상세모달 캐로셀 추가
- 상세모달 스크롤 추가
- 모든 카테고리 보기 기능 구현

* [#27] feat: ✨ BestTab Skeleton UI 만들기

- Main.jsx
   - 시연을 위한 loop 설정 추가
- BestTab.jsx
   - SkeletonTab import
- BestTabNavigator.jsx
   - 주석 제거
- SkeletonTab.jsx
   - Skeleton UI 구현
- DicoJsonCarousel.jsx
   - Carousel 구현중

* [#29] feat: ✨ PopUp Skeleton UI 만들기

- Context.jsx
   - 주석 제거
- BestTab.jsx
   - 주석 제거
- PopUpContainer.jsx
   - Skeleton import
- PopUpItemsSlide.jsx
   - 주석 제거
- SkeletonPopUpContainerBody.jsx
   - Skeleton UI 구현

* feat: ✨ carousel loop 기능 구현

* [#31] feat: ✨ README.md 작성완료

Co-authored-by: kowoohyuk <kowoohyuk91@gmail.com>
  • Loading branch information
ha3158987 and kowoohyuk authored May 4, 2021
1 parent 9793aba commit ea521ee
Show file tree
Hide file tree
Showing 25 changed files with 2,044 additions and 41 deletions.
37 changes: 33 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,36 @@
# sidedish
# 🥑 sidedish
## Team19 (a.k.a DJ)
### 조원
Json
### Members
[Json😇](https://github.com/kowoohyuk), [Dico🌷](https://github.com/ha3158987)

----
## 📝 Table of Contents
- [Links](#links)
- [Customized NPM Module](#module)
- [Skeleton UI](#Skeleton)
- [UI](#ui)
----
## 🔗 [Links](#Links)
### [Git Strategy](https://github.com/ha3158987/sidedish/wiki/Git-Strategy-%F0%9F%8C%B3)
### [Naming Rule](https://github.com/ha3158987/sidedish/wiki/Naming-Rule-%F0%9F%8D%92)
### [Reference](https://github.com/ha3158987/sidedish/wiki/Reference-%F0%9F%93%94)
### Blueprint
- [Component](https://www.notion.so/Component-f3ea0a6769d14acf97b0f2bc13b63ca9)
- [Carousel](https://www.notion.so/DicoJsonCarousel-4a8ccb91cb9e4edb9b4e3bfffae1f7ca)
- [Notion](https://www.notion.so/Sidedish-Json-Dico-cb7c0605253840da922952c6e910ea60)

----
## 🎠 [Customized NPM Module](#module)
[dico-json-carousel NPM](https://npmjs.com/package/dico-json-carousel)
![Carousel](https://s3.us-west-2.amazonaws.com/secure.notion-static.com/1f61e9d5-f75b-428c-af74-52357bf1522f/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAT73L2G45O3KS52Y5%2F20210502%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20210502T134930Z&X-Amz-Expires=86400&X-Amz-Signature=e6c4ff35984ebe0977a127959b9494172e7c61802dfbac4029af6c88ab330ee3&X-Amz-SignedHeaders=host&response-content-disposition=filename%20%3D%22Untitled.png%22)

-----
## ☠️ [Skeleton UI](#Skeleton)
![Skeleton UI](https://s3.us-west-2.amazonaws.com/secure.notion-static.com/eadb8270-8871-4b16-b63e-f233ca888319/_2021_04_30_16_54_31_768.gif?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAT73L2G45O3KS52Y5%2F20210502%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20210502T134428Z&X-Amz-Expires=86400&X-Amz-Signature=6c68fa970a8b048efbf29f5166f9d224b9d355a0be969d6cad45081a68ed1ad7&X-Amz-SignedHeaders=host)

----
## 🏠 [UI](#ui)
![screencapture-localhost-3000-2021-05-02-22_42_10](https://user-images.githubusercontent.com/65105537/116815304-d52f7280-ab97-11eb-93c2-220afdd5c943.png)


Dico

17 changes: 6 additions & 11 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
import BestTab from "./component/bestTab/BestTab.jsx";
import Header from "./component/header/Header.jsx";
import PopUpContainer from "./component/popUp/PopUpContainer.jsx";
import ShowMoreBtn from "./component/ShowMoreBtn.jsx";
import SlideContainer from "./component/slideContainer/SlideContainer.jsx";
import GlobalStyle from "./style.js";
import Main from "./component/main/Main.jsx";
import GlobalStyle from "./common/style.js";
import { ContextProvider } from "./component/Context.jsx";

function App() {
return (
<>
<ContextProvider>
<GlobalStyle />
<Header />
<BestTab />
<SlideContainer />
<ShowMoreBtn />
<PopUpContainer/>
</>
<Main />
</ContextProvider>
);
}

Expand Down
28 changes: 28 additions & 0 deletions src/common/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const API = () => {
const URL = "https://codesquad-2021-api.herokuapp.com/sidedish";
const API = path => {
const req = {
method : 'GET',
headers: {
"Content-Type": "application/json",
}
};
return fetch(URL + path, req);
}
return async (path) => {
let json;
try {
const result = await API(path);
json = await result.json();
} catch(e) {
console.log(e);
} finally {
if(!json || json.length === 0) {
json = null;
}
}
return json;
}
}

export default API();
15 changes: 15 additions & 0 deletions src/common/const.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const TEXT = {
"bestTab-title": "후기가 증명하는 베스트 반찬",
"order" : {
true : {
"title": "주문 성공",
"content": "감사합니다! \r\n맛있게 준비해드릴게요!"
},
false : {
"title": "주문 실패",
"content": "재고가 부족합니다!"
}
}
};

export { TEXT };
27 changes: 27 additions & 0 deletions src/common/style.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { createGlobalStyle } from "styled-components";

const GlobalStyle = createGlobalStyle`
body {
overflow-x: hidden;
color: #333;
}
button {
background-color: transparent;
border:none;
cursor: pointer;
}
input {
border: none;
}
input:focus {
outline:none;
}
button:focus {
outline:none;
}
* {
box-sizing: border-box;
}
`;

export default GlobalStyle;
1 change: 1 addition & 0 deletions src/common/util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const addCommaToNumber = (number) => number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
82 changes: 82 additions & 0 deletions src/component/Context.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { createContext, useContext, useEffect, useState } from "react";
import API from "../common/api.js";

const DetailDataContext = createContext();
const PopUpToggleContext = createContext();
const OnFetchDetailDataContext = createContext();
const SetPopUpToggleContext = createContext();
const MainItemsContext = createContext();
const MainItemsActiveContext = createContext();
const SetMainItemsActiveContext = createContext();

export function ContextProvider({ children }) {
const [detailData, setDetailData] = useState(null);
const [popUpToggle, setPopUpToggle] = useState(false);
const [mainItems, setMainItems] = useState(null);
const [mainItemsActive, setMainItemsActive] = useState(false);

useEffect(() => {
if (!mainItems) {
(async () => {
const data = await API("/main");
setMainItems(data);
})();
}
return;
}, [mainItems]);

const onFetchDetailData = async (id) => {
setPopUpToggle(true);
setDetailData(null);
const data = await API(`/detail/${id}`);
if (data) {
setTimeout(() => setDetailData(data), 1000);
}
};

return (
<DetailDataContext.Provider value={detailData}>
<OnFetchDetailDataContext.Provider value={onFetchDetailData}>
<PopUpToggleContext.Provider value={popUpToggle}>
<SetPopUpToggleContext.Provider value={setPopUpToggle}>
<MainItemsContext.Provider value={mainItems}>
<MainItemsActiveContext.Provider value={mainItemsActive}>
<SetMainItemsActiveContext.Provider value={setMainItemsActive}>
{children}
</SetMainItemsActiveContext.Provider>
</MainItemsActiveContext.Provider>
</MainItemsContext.Provider>
</SetPopUpToggleContext.Provider>
</PopUpToggleContext.Provider>
</OnFetchDetailDataContext.Provider>
</DetailDataContext.Provider>
);
}

export function useDetailContext() {
return useContext(DetailDataContext);
}

export function useOnFetchDetailDataContext() {
return useContext(OnFetchDetailDataContext);
}

export function usePopUpToggleContext() {
return useContext(PopUpToggleContext);
}

export function useSetPopUpToggleContext() {
return useContext(SetPopUpToggleContext);
}

export function useMainItemsContext() {
return useContext(MainItemsContext);
}

export function useMainItemsActiveContext() {
return useContext(MainItemsActiveContext);
}

export function useSetMainItemsActiveContext() {
return useContext(SetMainItemsActiveContext);
}
78 changes: 78 additions & 0 deletions src/component/main/Main.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { useEffect, useState } from "react";
import BestTab from "./bestTab/BestTab.jsx";
import PopUpContainer from "./popUp/PopUpContainer.jsx";
import ShowMoreBtn from "./ShowMoreBtn.jsx";
import API from "../../common/api.js";
import { DicoJsonCarousel } from "../util/dj-slider/DicoJsonCarousel.jsx";
import ItemCard from "../util/ItemCard";
import styled from "styled-components";

import {
useMainItemsContext,
useMainItemsActiveContext,
useSetMainItemsActiveContext,
} from "../Context";

const CarouselContainer = styled.div`
margin-bottom: 5rem;
`;

export default function Main() {
const mainItems = useMainItemsContext();
const active = useMainItemsActiveContext();
const setActive = useSetMainItemsActiveContext();

const onShowMoreItems = () => {
setActive(true);
};
const getSalePrice = (price, discountRate) => {
return price - price * (discountRate / 100);
};
if (!mainItems) return null;
return (
<>
<BestTab />
{active ? (
mainItems.map((mainItem, id) => (
<CarouselContainer key={id}>
<h2>{mainItem.title}</h2>
<DicoJsonCarousel>
{mainItem.childs.map((item, idx) => (
<ItemCard
src={item.main_image}
title={item.title}
description={item.description}
salePrice={getSalePrice(item.price, item.discount)}
normalPrice={item.price}
labels={item.label}
key={idx}
id={item._id}
/>
))}
</DicoJsonCarousel>
</CarouselContainer>
))
) : (
<CarouselContainer>
<h2>{mainItems[0].title}</h2>
<DicoJsonCarousel options={{ loop: true }}>
{mainItems[0].childs.map((item, idx) => (
<ItemCard
src={item.main_image}
title={item.title}
description={item.description}
salePrice={getSalePrice(item.price, item.discount)}
normalPrice={item.price}
labels={item.label}
key={idx}
id={item._id}
/>
))}
</DicoJsonCarousel>
</CarouselContainer>
)}
<ShowMoreBtn active={active} onShowMoreItems={onShowMoreItems} />
<PopUpContainer />
</>
);
}
17 changes: 17 additions & 0 deletions src/component/main/ShowMoreBtn.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import styled from "styled-components";

const ShowMoreBtnStyle = styled.div`
margin: 0 -4rem;
font-size: 1.125rem;
font-weight: 600;
padding: 2.321225rem;
text-align: center;
background-color: #F5F5F7;
box-shadow: inset 0px 4px 4px rgba(0, 0, 0, 0.05);
cursor: pointer;
display: ${props => props.active ? 'none' : 'block'};
`;

export default function ShowMoreBtn({ active, onShowMoreItems }) {
return <ShowMoreBtnStyle active={active} onClick={onShowMoreItems}>모든 카테고리 보기</ShowMoreBtnStyle>;
}
42 changes: 42 additions & 0 deletions src/component/main/bestTab/BestItems.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import styled from "styled-components";
import ItemCard from "../../util/ItemCard";

const BestItemsStyle = styled.div`
background-color: #eef4fa;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 1.5rem;
padding: 2.5rem;
`;

export default function BestItems({ childs }) {
const getRandom = (n, max) => {
const set = new Set();
while (set.size < n) {
set.add(Math.floor(Math.random() * max));
}
return Array.from(set);
};

const getSalePrice = (price, discountRate) => {
return price - price * (discountRate / 100);
};

return (
<BestItemsStyle>
{getRandom(3, childs.length).map((idx) => (
<ItemCard
src={childs[idx].main_image}
title={childs[idx].title}
description={childs[idx].description}
salePrice={getSalePrice(childs[idx].price, childs[idx].discount)}
normalPrice={childs[idx].price}
labels={childs[idx].label}
key={idx}
id={childs[idx]._id}
large={true}
/>
))}
</BestItemsStyle>
);
}
Loading

0 comments on commit ea521ee

Please sign in to comment.