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

[Team19][Json, Dico] Sidedish 2주차 PR (Final) #73

Merged
merged 42 commits into from
May 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
e8f1390
[#1] init: :tada: 개발 환경 구축
ha3158987 Apr 19, 2021
c7655be
Merge pull request #2 from ha3158987/team19/1
ha3158987 Apr 19, 2021
c0aa248
[#3] feat: :sparkles: Header 만들기
kowoohyuk Apr 20, 2021
72df72f
Merge pull request #4 from ha3158987/team19/3
kowoohyuk Apr 20, 2021
875b6d6
[#5] feat: :sparkles: BestTab UI 구현
kowoohyuk Apr 20, 2021
d48fb37
Merge pull request #6 from ha3158987/team19/5
kowoohyuk Apr 20, 2021
05f641c
[#7] feat: :sparkles: Slide UI 구현
kowoohyuk Apr 21, 2021
2b7ab1a
[#8] feat: :sparkles: ShowMoreBtn UI 구현
kowoohyuk Apr 21, 2021
65ec0e1
Merge pull request #9 from ha3158987/team19/7
kowoohyuk Apr 21, 2021
a819c98
[#10] feat: :sparkles: Header Dropdown 구현
kowoohyuk Apr 21, 2021
a2ca5f7
Merge pull request #11 from ha3158987/team19/10
kowoohyuk Apr 21, 2021
a9858a0
[#13] feat: :sparkles: API에 fetch 요청 로직 구현
ha3158987 Apr 22, 2021
64fe99d
[#13] feat: :sparkles: API 요청, 베스트 기능구현
ha3158987 Apr 22, 2021
968ecc8
Merge pull request #14 from ha3158987/team19/13
ha3158987 Apr 22, 2021
f81d4f2
[#15] feat: :sparkles: 상세 modal 페이지 UI 구현
ha3158987 Apr 26, 2021
23f093c
Merge pull request #18 from ha3158987/team19/15
ha3158987 Apr 26, 2021
2e4ac0e
[#16] feat: :sparkles: 모달 페이지 이벤트 구현중
ha3158987 Apr 26, 2021
f2f604b
[#16] feat: :sparkles: 수량정보 컴포넌트 분리
ha3158987 Apr 27, 2021
470f167
Merge pull request #20 from ha3158987/team19/16
ha3158987 Apr 27, 2021
b6c0f1f
[#19] refactor: :hammer: 리팩토링, 부족한 부분 추가 구현
ha3158987 Apr 27, 2021
8415588
[#19] refactor: :hammer: 리팩토링
ha3158987 Apr 27, 2021
a7b68cc
Merge pull request #22 from ha3158987/team19/19
ha3158987 Apr 27, 2021
66a24ee
[#17] feat: :sparkles: dj-slider 폴더구조 구축
ha3158987 Apr 27, 2021
3360398
[#17] feat: :sparkles: 슬라이드 1/2 구현 중
ha3158987 Apr 28, 2021
7071ea4
Merge branch 'team19/17' of https://github.com/ha3158987/sidedish int…
kowoohyuk Apr 28, 2021
7be6a0e
[#23] refactor: :hammer: 코드 리뷰 코멘트 반영 및 개선
ha3158987 Apr 29, 2021
732e74f
Merge pull request #24 from ha3158987/team19/23
ha3158987 Apr 29, 2021
83ad42c
[#17] feat: :sparkles: 슬라이드 구현중/일부사항 수정
ha3158987 Apr 29, 2021
5680059
[#17] feat: :sparkles: 슬라이드 구현중
kowoohyuk Apr 29, 2021
e951ead
Merge branch 'team19/17' of https://github.com/ha3158987/sidedish int…
kowoohyuk Apr 29, 2021
3be4a7c
[#25] feat: :sparkles: 슬라이드 2/2 구현, API 데이터 동기화
kowoohyuk Apr 29, 2021
ed90c4d
Merge pull request #26 from ha3158987/team19/25
kowoohyuk Apr 29, 2021
1f85635
Merge branch 'team-19' of https://github.com/ha3158987/sidedish into …
kowoohyuk Apr 30, 2021
266cb39
[#27] feat: :sparkles: BestTab Skeleton UI 만들기
kowoohyuk Apr 30, 2021
8337c41
Merge pull request #28 from ha3158987/team19/27
kowoohyuk Apr 30, 2021
d06246c
[#29] feat: ✨ PopUp Skeleton UI 만들기
kowoohyuk Apr 30, 2021
96ae43b
Merge pull request #30 from ha3158987/team19/29
kowoohyuk Apr 30, 2021
ebb234a
feat: :sparkles: carousel loop 기능 구현
ha3158987 May 2, 2021
ff16e70
Merge pull request #32 from ha3158987/team19/17
ha3158987 May 2, 2021
3f66aa9
[#31] feat: :sparkles: README.md 작성완료
ha3158987 May 2, 2021
0dbfff7
Merge pull request #33 from ha3158987/team19/31
ha3158987 May 2, 2021
044d89a
Merge branch 'DJ' into team-19
ha3158987 May 2, 2021
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
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 = () => {
Copy link

Choose a reason for hiding this comment

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

이런건 만드는건 아주 좋고요.
다음 프로젝트에서도 사용하면서 업그레이드 계속 해보세요.

const URL = "https://codesquad-2021-api.herokuapp.com/sidedish";
Copy link

Choose a reason for hiding this comment

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

url이 소스코드에 있는건 위험하긴해요.
빌드타이밍에 소스코드에 개발환경에 따라 동적으로 URL을 주입시키는 방법을 찾아보실래요?

CRA Replace url 이런키워드 검색~

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>
Comment on lines +38 to +52
Copy link

Choose a reason for hiding this comment

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

어머나.
학습차원에서 Context API로 모든 상태관리를 한것이라고 짐작은 하고 있지만. 그럼에도 피드백 남깁니다.

먼저 Context 를 여러개 지정하는 것이 반드시 필요할까? 생각해봐야하고요.
다시말해서 해당 컴포넌트에서 정의해서 써도 되거나 props로 전달하는 방식을 해도 되지 않을까?

두번째로 Context정의를 최상단 root 영역에서 해야만하는가?
하위 컴포넌트에서 하는 것도 좋지 않을까? 생각해보세요.

);
}

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

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

export function usePopUpToggleContext() {
return useContext(PopUpToggleContext);
}
Comment on lines +64 to +66
Copy link

Choose a reason for hiding this comment

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

이렇게 useContext 를 반환하는 함수를 사용하는 경우가 있더군요.
제 생각엔 해당 컴포넌트에서 표현해도 크게 다를거 같진 않고요.


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";
Comment on lines +5 to +6
Copy link

Choose a reason for hiding this comment

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

요거만 보면
util은 왜 common 이 아니지? 라고 생각할 수도 있을거 같아요.

팀이 정하기 나름인데, 얼핏봐도 두 개가 어떤 차이가 있는지 구별이 되도록 이름 지으면 더 좋을 거 같아요.

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;
Copy link

Choose a reason for hiding this comment

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

이렇게 빨리 반환하는거 아주 좋네요.

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>
Comment on lines +39 to +52
Copy link

Choose a reason for hiding this comment

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

이렇게 사용되는 구조만 보면 직관적이고 꽤 편리해보이네요.

</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();
Copy link

Choose a reason for hiding this comment

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

set과 array의 차이도 알아두시면 좋죠.

while (set.size < n) {
set.add(Math.floor(Math.random() * max));
}
return Array.from(set);
Copy link

Choose a reason for hiding this comment

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

return [...set] 도 될거에요.
spread operator는 iterable objects 인 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