-
Notifications
You must be signed in to change notification settings - Fork 50
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
[Team23] 캐로셀 적용, 모달창 설계 및 구현, 상품 이미지 호버 적용 #30
Changes from all commits
c75cc1d
8e42c5f
1c99905
ccfab6b
ac9082b
27cd014
24fae61
c3b9535
7c86069
70a202a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { useEffect, useState } from 'react'; | ||
import styled from 'styled-components'; | ||
import Card from '../utils/Card'; | ||
import theme from '../utils/styles/theme'; | ||
|
||
const CarouselList = (props) => { | ||
const [products, setProducts] = useState([]); | ||
|
||
useEffect(() => { | ||
fetch( | ||
'https://h3rb9c0ugl.execute-api.ap-northeast-2.amazonaws.com/develop/baminchan/main' | ||
) | ||
.then((response) => response.json()) | ||
.then((result) => setProducts(result.body)) | ||
.then((error) => console.log('error', error)); | ||
}, []); | ||
|
||
return ( | ||
<StyledUl> | ||
{products.map((product) => ( | ||
<Card | ||
key={product.detail_hash} | ||
product={product} | ||
cardSize={theme.cardSizes.M} | ||
/> | ||
))} | ||
</StyledUl> | ||
); | ||
}; | ||
|
||
const StyledUl = styled.ul` | ||
display: flex; | ||
justify-content: space-evenly; | ||
`; | ||
|
||
export default CarouselList; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,134 @@ | ||
import { useEffect, useState } from "react"; | ||
import Card from "../utils/Card"; | ||
import theme from "../utils/styles/theme"; | ||
import { useEffect, useRef, useState } from 'react'; | ||
// import { mockData, temp } from "../utils/mockData.js"; | ||
import Card from '../utils/Card'; | ||
import styled from 'styled-components'; | ||
import IconButton from '../utils/button/IconButton'; | ||
import { CenterContainer } from '../utils/styles/common'; | ||
|
||
const CarouselSection = (props) => { | ||
const CarouselSection = ({ key, url, title, onModal }) => { | ||
const [products, setProducts] = useState([]); | ||
// const [products, setProducts] = useState(mockData); | ||
const [currentX, setX] = useState(0); | ||
const [currentIndex, setCurrentIndex] = useState(4); | ||
const [rightDisabled, setLeftDisabled] = useState(false); | ||
const [leftDisabled, setRightDisabled] = useState(true); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. left right disabled를 state로 갖지 않고, 슬라이드의 Index와 length로 충분히 처리할 수 있을 것 같습니다! |
||
const slides = useRef(); | ||
const slideCount = 4; | ||
const slideWidth = 320; | ||
const totalWidth = 320 * slideCount + 16; | ||
|
||
useEffect(() => { | ||
fetch( | ||
"https://h3rb9c0ugl.execute-api.ap-northeast-2.amazonaws.com/develop/baminchan/main" | ||
) | ||
.then((response) => response.json()) | ||
.then((result) => setProducts(result.body)) | ||
.then((error) => console.log("error", error)); | ||
(async () => { | ||
const response = await fetch(url); | ||
const result = await response.json(); | ||
setProducts(result.body); | ||
})(); | ||
}, []); | ||
|
||
const moveSlide = (speed, distance, nextIndex) => { | ||
slides.current.style.transition = `${speed}ms`; | ||
slides.current.style.transform = `translateX(${distance}px)`; | ||
setX(distance); | ||
setCurrentIndex(nextIndex); | ||
}; | ||
|
||
const moveRight = () => { | ||
const remainSlideCount = products.length - currentIndex; | ||
const distance = | ||
remainSlideCount >= slideCount | ||
? currentX - totalWidth | ||
: currentX - slideWidth * remainSlideCount; | ||
const nextIndex = | ||
remainSlideCount >= slideCount | ||
? currentIndex + slideCount | ||
: currentIndex + remainSlideCount; | ||
moveSlide(300, distance, nextIndex); | ||
distance && setRightDisabled(false); | ||
nextIndex >= products.length && setLeftDisabled(true); | ||
}; | ||
|
||
const moveLeft = () => { | ||
const remainSlideCount = currentIndex - slideCount; | ||
const distance = | ||
remainSlideCount >= slideCount | ||
? currentX + totalWidth | ||
: currentX + slideWidth * remainSlideCount; | ||
const nextIndex = | ||
remainSlideCount >= slideCount | ||
? currentIndex - slideCount | ||
: currentIndex - remainSlideCount; | ||
moveSlide(300, distance, nextIndex); | ||
!distance && setRightDisabled(true); | ||
nextIndex < products.length && setLeftDisabled(false); | ||
}; | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 동일한 로직에 좌우로만 차이가 있는데 이를 통합한 하나의 함수로 짜보는 건 어떨까요 ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 넵! 수정하겠습니다 |
||
return ( | ||
<ul> | ||
{products.map((product) => ( | ||
<Card | ||
key={product.detail_hash} | ||
product={product} | ||
cardSize={theme.cardSizes.M} | ||
/> | ||
))} | ||
</ul> | ||
<SectionContainer> | ||
<SectionBox> | ||
<SectionTitle>{title}</SectionTitle> | ||
<SectionContent> | ||
<CardList ref={slides}> | ||
{products.map((product) => ( | ||
<Card | ||
key={product.detail_hash} | ||
product={product} | ||
cardSize={(props) => props.theme.cardSizes.M} | ||
margin={8} | ||
onModal={onModal} | ||
/> | ||
))} | ||
</CardList> | ||
</SectionContent> | ||
</SectionBox> | ||
<SectionButton> | ||
<IconButton type="LEFT" fn={moveLeft} disabled={leftDisabled} /> | ||
<IconButton type="RIGHT" fn={moveRight} disabled={rightDisabled} /> | ||
</SectionButton> | ||
</SectionContainer> | ||
); | ||
}; | ||
|
||
const SectionContainer = styled(CenterContainer)` | ||
position: relative; | ||
margin: 30px 0; | ||
/*border: 1px solid blue;*/ | ||
width: 1320px; | ||
`; | ||
|
||
const SectionBox = styled.div` | ||
/*border: 1px solid violet;*/ | ||
`; | ||
|
||
const SectionContent = styled.div` | ||
position: relative; | ||
display: flex; | ||
margin: 20px 0; | ||
width: 1296px; /* 원래 1280 */ | ||
height: 500px; | ||
/*border: 1px solid black;*/ | ||
overflow: hidden; | ||
`; | ||
|
||
const CardList = styled(CenterContainer)` | ||
list-style: none; | ||
align-items: start; | ||
position: absolute; | ||
`; | ||
|
||
const SectionTitle = styled.div` | ||
font-size: ${(props) => props.theme.fontSizes.XL}; | ||
font-weight: bold; | ||
color: ${(props) => props.theme.darkGray}; | ||
margin: 20px 0; | ||
`; | ||
|
||
const SectionButton = styled.div` | ||
position: absolute; | ||
top: 50%; | ||
transform: translateY(-50%); | ||
width: 100%; | ||
display: flex; | ||
justify-content: space-between; | ||
`; | ||
|
||
export default CarouselSection; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,34 @@ | ||
const CarouselSectionList = (props) => <></>; | ||
import { useState } from 'react'; | ||
import { URLS } from '../utils/variables.js'; | ||
import CarouselSection from './CarouselSection.jsx'; | ||
import styled from 'styled-components'; | ||
import { CenterContainer } from '../utils/styles/common.jsx'; | ||
|
||
const CarouselSectionList = (props) => { | ||
const [sections, setSections] = useState([ | ||
{ id: 0, kind: 'main', title: '모두가 좋아하는 든든한 메인요리' }, | ||
{ id: 1, kind: 'soup', title: '정성이 담긴 뜨끈한 국물요리' }, | ||
{ id: 2, kind: 'side', title: '식탁을 풍성하게 하는 정갈한 밑반찬' }, | ||
]); | ||
|
||
return ( | ||
<CarouselContainer> | ||
{sections.map((section) => ( | ||
<CarouselSection | ||
key={section.id} | ||
url={URLS.base.concat(section.kind)} | ||
title={section.title} | ||
onModal={props.onModal} | ||
/> | ||
))} | ||
</CarouselContainer> | ||
); | ||
}; | ||
|
||
const CarouselContainer = styled(CenterContainer)` | ||
/*border: 1px solid red;*/ | ||
display: flex; | ||
flex-direction: column; | ||
`; | ||
|
||
export default CarouselSectionList; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,62 @@ | ||
import CarouselSection from "./CarouselSection"; | ||
import TabSection from "./tab/TabSection"; | ||
import TabSection from './tab/TabSection'; | ||
import CarouselSectionList from './CarouselSectionList'; | ||
import { useEffect, useState } from 'react'; | ||
import styled from 'styled-components'; | ||
import { CenterContainer } from '../utils/styles/common'; | ||
import Modal from './Modal'; | ||
|
||
const MainPage = (props) => { | ||
const [modalState, setModalState] = useState(false); | ||
const [modalData, setModalData] = useState({}); | ||
const [detailDataMap, setDetailDataMap] = useState(new Map()); | ||
|
||
useEffect(() => { | ||
fetch( | ||
'https://h3rb9c0ugl.execute-api.ap-northeast-2.amazonaws.com/develop/baminchan/detail' | ||
) | ||
.then((res) => res.json()) | ||
.then((response) => { | ||
response.body.forEach((e) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. e같은 추상적인 변수명보다는 구체적인 변수명이 좋습니다! |
||
setDetailDataMap(detailDataMap.set(e.hash, e.data)); | ||
}); | ||
}); | ||
}, []); | ||
|
||
const handleModal = (product) => { | ||
setModalState(true); | ||
const detailData = detailDataMap.get(product.detail_hash); | ||
setModalData({ ...product, ...detailData }); | ||
}; | ||
|
||
return ( | ||
<> | ||
<TabSection /> | ||
<CarouselSection /> | ||
<TabSection onModal={handleModal} /> | ||
<CarouselSectionList onModal={handleModal} /> | ||
{modalState && ( | ||
<ModalBackground> | ||
<ModalContainer> | ||
<Modal product={modalData} /> | ||
<button onClick={() => setModalState(false)}>X</button> | ||
</ModalContainer> | ||
</ModalBackground> | ||
)} | ||
</> | ||
); | ||
}; | ||
|
||
const ModalBackground = styled(CenterContainer)` | ||
position: fixed; | ||
top: 0; | ||
left: 0; | ||
background: rgba(0, 0, 0, 0.4); | ||
width: 100%; | ||
height: 100%; | ||
z-index: 5; | ||
`; | ||
|
||
const ModalContainer = styled.div` | ||
display: flex; | ||
align-items: flex-start; | ||
`; | ||
|
||
export default MainPage; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import styled from 'styled-components'; | ||
import Price from '../utils/Price'; | ||
import TextButton from '../utils/button/TextButton'; | ||
import { | ||
LabelList, | ||
StyledDescription, | ||
StyledTitle, | ||
} from '../utils/styles/common'; | ||
|
||
const Modal = ({ product }) => { | ||
console.log(product); | ||
return ( | ||
<ModalCard> | ||
<ProductImage> | ||
<img src={product.top_image} alt="product-thumbnail" /> | ||
<ThumbnailUL> | ||
{product.thumb_images.map((i) => ( | ||
<li> | ||
<Thumbnail src={i} /> | ||
</li> | ||
))} | ||
</ThumbnailUL> | ||
</ProductImage> | ||
<Information> | ||
<ProductMainInfo> | ||
<StyledTitle>{product.title}</StyledTitle> | ||
<StyledDescription>{product.description}</StyledDescription> | ||
<div> | ||
<LabelList /> | ||
<Price product={product} /> | ||
</div> | ||
</ProductMainInfo> | ||
<ProductBuyInfo> | ||
<div>적립금: {product.point}</div> | ||
<div>배송정보: {product.delivery_info}</div> | ||
<div>배송비 : {product.delivery_fee}</div> | ||
</ProductBuyInfo> | ||
<ProductCount></ProductCount> | ||
<ProductPrice> | ||
여기는 총 주문 금액이 들어갈 예정입니다. 카운트를 같이 계산해서.. | ||
</ProductPrice> | ||
<TextButton type="ORDER"></TextButton> | ||
</Information> | ||
</ModalCard> | ||
); | ||
}; | ||
|
||
const ModalCard = styled.div` | ||
background: white; | ||
width: 960px; | ||
height: 1076px; | ||
`; | ||
|
||
const ThumbnailUL = styled.div` | ||
display: flex; | ||
`; | ||
|
||
const Thumbnail = styled.img` | ||
width: 100px; | ||
height: 100px; | ||
`; | ||
|
||
const ProductImage = styled.div``; | ||
|
||
const Information = styled.div``; | ||
|
||
const ProductMainInfo = styled.div``; | ||
|
||
// const LabelList = styled.div``; | ||
|
||
const ProductBuyInfo = styled.div``; | ||
|
||
const ProductCount = styled.div``; | ||
|
||
const ProductPrice = styled.div``; | ||
|
||
export default Modal; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
자주 쓰는 API를 상수로 지정하거나 객체 형태로 모아서 쓰는 건 어떨까요 ?