-
Notifications
You must be signed in to change notification settings - Fork 20
[김희진] sprint 6 #55
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
The head ref may contain hidden characters: "React-\uAE40\uD76C\uC9C4-sprint2"
[김희진] sprint 6 #55
Changes from all commits
e0095ff
5b3348b
a556efc
3b5ce2f
ceaba3b
d66cbf8
038cd0f
d66f007
911bb74
b0399b3
243851d
81bb4ca
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,62 @@ | ||
| import * as S from "./FileInput.styles"; | ||
| import x from "../../assets/icons/delete.svg"; | ||
| import plus from "../../assets/icons/plus.svg"; | ||
| import { useState, useRef } from "react"; | ||
|
|
||
| export default function FileInput({ lable, images, setValues }) { | ||
| const [preview, setPreview] = useState(null); | ||
| const inputRef = useRef(); | ||
|
|
||
| const handleImageChange = (e) => { | ||
| const file = e.target.files[0]; | ||
|
|
||
| if (file) { | ||
| setValues((prevState) => ({ | ||
| ...prevState, | ||
| images: file, | ||
| })); | ||
|
|
||
| const fileUrl = URL.createObjectURL(file); | ||
| setPreview(fileUrl); | ||
| } | ||
| }; | ||
|
|
||
| const handleImageDelete = () => { | ||
| if (!inputRef.current) return; | ||
| inputRef.current.value = ""; | ||
| setValues((prevState) => ({ | ||
| ...prevState, | ||
| images: null, | ||
| })); | ||
| setPreview(null); | ||
| }; | ||
|
|
||
| return ( | ||
| <> | ||
| <S.FileContainer> | ||
| <S.Label>{lable}</S.Label> | ||
| <S.File htmlFor="images"> | ||
| <S.Div> | ||
| <S.PlusIcon src={plus} /> | ||
| <S.AddImg>이미지 등록</S.AddImg> | ||
| </S.Div> | ||
| </S.File> | ||
| <input | ||
| id="images" | ||
| name="images" | ||
| type="file" | ||
| accept="image/jpeg, image/png" | ||
| style={{ display: "none" }} | ||
| onChange={handleImageChange} | ||
| ref={inputRef} | ||
| /> | ||
| </S.FileContainer> | ||
| {images && ( | ||
| <S.Preview> | ||
| <S.PreviewImg src={preview} /> | ||
| <S.DeleteImg src={x} onClick={handleImageDelete} /> | ||
| </S.Preview> | ||
| )} | ||
| </> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| import { styled } from "styled-components"; | ||
|
|
||
| export const FileContainer = styled.div` | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 16px; | ||
| `; | ||
|
|
||
| export const Label = styled.div` | ||
| font-size: 18px; | ||
| font-weight: 700; | ||
| line-height: 26px; | ||
| color: var(--gray800); | ||
| `; | ||
|
|
||
| export const File = styled.label` | ||
| width: 282px; | ||
| height: 282px; | ||
| display: flex; | ||
| justify-content: center; | ||
| align-items: center; | ||
| background-color: var(--gray100); | ||
| border-radius: 12px; | ||
| cursor: pointer; | ||
|
|
||
| @media (max-width: 1199px) { | ||
| width: 168px; | ||
| height: 168px; | ||
| } | ||
| `; | ||
|
|
||
| export const Div = styled.div` | ||
| width: 74px; | ||
| height: 86px; | ||
| display: flex; | ||
| flex-direction: column; | ||
| justify-content: space-between; | ||
| align-items: center; | ||
| `; | ||
|
|
||
| export const PlusIcon = styled.img` | ||
| width: 48px; | ||
| height: 48px; | ||
| `; | ||
|
|
||
| export const AddImg = styled.div` | ||
| font-size: 16px; | ||
| font-weight: 400; | ||
| line-height: 26px; | ||
| color: var(--gray400); | ||
| `; | ||
|
|
||
| export const Preview = styled.div` | ||
| display: flex; | ||
| position: relative; | ||
| `; | ||
|
|
||
| export const PreviewImg = styled.img` | ||
| width: 282px; | ||
| height: 282px; | ||
| border-radius: 12px; | ||
|
|
||
| @media (max-width: 1199px) { | ||
| width: 168px; | ||
| height: 168px; | ||
| } | ||
| `; | ||
|
|
||
| export const DeleteImg = styled.img` | ||
| width: 22px; | ||
| height: 24px; | ||
| position: absolute; | ||
| right: 10px; | ||
| top: 10px; | ||
| cursor: pointer;: | ||
| `; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,39 +1,92 @@ | ||
| import * as S from "./AllItems.styles"; | ||
| import { useEffect, useState } from "react"; | ||
| import { Link } from "react-router-dom"; | ||
| import ItemCard from "../ItemCard/ItemCard"; | ||
| import Dropdown from "../../common/Dropdown/Dropdown"; | ||
| import { Link } from "react-router-dom"; | ||
| import Search from "../../Search/Search"; | ||
| import NoneItem from "../../NoneItem/NoneItem"; | ||
| import { getProducts } from "../../../api/products"; | ||
| import Paging from "../../Paging/Paging"; | ||
|
|
||
| const LIST = ["최신순", "좋아요순"]; | ||
|
|
||
| export default function AllItems() { | ||
| const [items, setItems] = useState([]); | ||
| const [currentPage, setCurrentPage] = useState(1); | ||
| const [pageSize, setPageSize] = useState(10); | ||
| const [sortOption, setSortOption] = useState("최신순"); | ||
| const [keyword, setKeyword] = useState(""); | ||
| const [totalItems, setTotalItems] = useState(0); | ||
|
|
||
| const orderByValue = sortOption === "최신순" ? "recent" : "favorite"; | ||
|
|
||
| const updateItems = () => { | ||
| if (window.innerWidth <= 767) { | ||
| setPageSize(4); | ||
| } else if (window.innerWidth >= 768 && window.innerWidth <= 1199) { | ||
| setPageSize(6); | ||
| } else { | ||
| setPageSize(10); | ||
| } | ||
| }; | ||
|
|
||
| useEffect(() => { | ||
| getProducts({ | ||
| page: currentPage, | ||
| pageSize: pageSize, | ||
| orderBy: orderByValue, | ||
| keyword: keyword, | ||
| }).then((result) => { | ||
| if (!result) return; | ||
| setItems(result.list); | ||
| setTotalItems(result.totalCount); | ||
| }); | ||
| }, [currentPage, pageSize, orderByValue, keyword]); | ||
|
|
||
| useEffect(() => { | ||
| updateItems(); | ||
| window.addEventListener("resize", updateItems); | ||
|
|
||
| return () => { | ||
| window.removeEventListener("resize", updateItems); | ||
| }; | ||
| }, []); | ||
|
|
||
| const list = ["최신순", "좋아요순"]; | ||
| const handleChangeClick = (sortOption) => { | ||
| setSortOption(sortOption); | ||
| }; | ||
|
|
||
| export default function AllItems({ items, sortOption, onChange, setKeyword }) { | ||
| return ( | ||
| <S.AllContainer> | ||
| <S.AllHeader> | ||
| <S.Div> | ||
| <S.Title>전체 상품</S.Title> | ||
| <Link to="/addItem"> | ||
| <S.AddBtnForMedia>상품 등록하기</S.AddBtnForMedia> | ||
| </Link> | ||
| </S.Div> | ||
| <S.Filter> | ||
| <Search onSearch={setKeyword} /> | ||
| <Link to="/addItem"> | ||
| <S.AddBtn>상품 등록하기</S.AddBtn> | ||
| </Link> | ||
| <Dropdown sortOption={sortOption} list={list} onChange={onChange} /> | ||
| </S.Filter> | ||
| </S.AllHeader> | ||
| {items.length !== 0 ? ( | ||
| <S.ItemCardContainer> | ||
| {items.map((items, idx) => ( | ||
| <ItemCard key={idx} list="all" {...items} /> | ||
| ))} | ||
| </S.ItemCardContainer> | ||
| ) : ( | ||
| <NoneItem /> | ||
| <S.AllItems> | ||
| <S.AllContainer> | ||
| <S.AllHeader> | ||
| <S.Div> | ||
| <S.Title>전체 상품</S.Title> | ||
| <Link to="/addItem"> | ||
| <S.AddBtnForMedia>상품 등록하기</S.AddBtnForMedia> | ||
| </Link> | ||
| </S.Div> | ||
| <S.Filter> | ||
| <Search onSearch={setKeyword} /> | ||
| <Link to="/addItem"> | ||
| <S.AddBtn>상품 등록하기</S.AddBtn> | ||
| </Link> | ||
| <Dropdown sortOption={sortOption} list={LIST} onChange={handleChangeClick} /> | ||
| </S.Filter> | ||
| </S.AllHeader> | ||
| {items.length !== 0 ? ( | ||
| <S.ItemCardContainer> | ||
| {items.map((items, idx) => ( | ||
| <ItemCard key={idx} list="all" {...items} /> | ||
| ))} | ||
| </S.ItemCardContainer> | ||
| ) : ( | ||
| <NoneItem /> | ||
| )} | ||
| </S.AllContainer> | ||
| {items.length !== 0 && ( | ||
| <Paging currentPage={currentPage} pageSize={pageSize} totalItemsCount={totalItems} setPage={setCurrentPage} /> | ||
| )} | ||
| </S.AllContainer> | ||
| </S.AllItems> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,37 @@ | ||
| import * as S from "./BestItems.styles"; | ||
| import { useState, useEffect, useCallback } from "react"; | ||
| import ItemCard from "../ItemCard/ItemCard"; | ||
| import { useEffect } from "react"; | ||
| import { getProducts } from "../../../api/products"; | ||
|
|
||
| export default function BestItems() { | ||
| const [bestItems, setBestItems] = useState([]); | ||
| const [showItems, setShowItems] = useState(4); | ||
|
|
||
| useEffect(() => { | ||
| getProducts({ | ||
| page: 1, | ||
| pageSize: showItems, | ||
| orderBy: "favorite", | ||
| keyword: "", | ||
| }).then((result) => { | ||
| if (!result) return; | ||
| const sortedBestItems = [...result.list].slice(0, 4); | ||
| setBestItems(sortedBestItems); | ||
| }); | ||
| }, [showItems]); | ||
|
|
||
| const updateBestItems = useCallback(() => { | ||
| if (window.innerWidth <= 767) { | ||
| setShowItems(1); | ||
| } else if (window.innerWidth >= 768 && window.innerWidth <= 1199) { | ||
| setShowItems(2); | ||
| } else { | ||
| setShowItems(4); | ||
| } | ||
| }, []); | ||
|
Comment on lines
+23
to
+31
Collaborator
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. (제안/의견)
|
||
|
|
||
| const responsiveItems = bestItems.slice(0, showItems); | ||
|
|
||
| export default function BestItems({ bestItems, updateBestItems }) { | ||
| useEffect(() => { | ||
| updateBestItems(); | ||
| window.addEventListener("resize", updateBestItems); | ||
|
|
@@ -16,7 +45,7 @@ export default function BestItems({ bestItems, updateBestItems }) { | |
| <S.BestContainer> | ||
| <S.Title>베스트 상품</S.Title> | ||
| <S.ItemCardContainer> | ||
| {bestItems.map((items, idx) => ( | ||
| {responsiveItems.map((items, idx) => ( | ||
| <ItemCard key={idx} list="best" {...items} /> | ||
| ))} | ||
| </S.ItemCardContainer> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import * as S from "./Tag.styles"; | ||
| import x from "../../assets/icons/delete.svg"; | ||
|
|
||
| export default function Tag({ tag, onClick }) { | ||
| return ( | ||
| <S.TagContainer> | ||
| <S.Tag> | ||
| <S.TagName>#{tag}</S.TagName> | ||
| <S.DeleteTag src={x} onClick={onClick} /> | ||
| </S.Tag> | ||
| </S.TagContainer> | ||
| ); | ||
| } |
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.
오타 발견 ! 🔎