From 276aa14dd3fe0e9b7f05d70b42dd8f59229e4305 Mon Sep 17 00:00:00 2001 From: eunjae Date: Sun, 9 Jun 2024 19:03:01 +0900 Subject: [PATCH 1/9] =?UTF-8?q?refactor:=20=EC=BD=98=EC=86=94=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hooks/useGetDetailedNotice.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/hooks/useGetDetailedNotice.tsx b/hooks/useGetDetailedNotice.tsx index 614f448..3eef042 100644 --- a/hooks/useGetDetailedNotice.tsx +++ b/hooks/useGetDetailedNotice.tsx @@ -50,7 +50,6 @@ export const useGetDetailedNotice = ( originalHourlyPay: resultItem.shop.item.originalHourlyPay, }, }); - console.log("datadata :::", data); } }; From 76447ffcd98f65828c90d0a5dc91bf14dd39a573 Mon Sep 17 00:00:00 2001 From: eunjae Date: Sun, 9 Jun 2024 21:47:40 +0900 Subject: [PATCH 2/9] =?UTF-8?q?design:=20=EC=82=AC=EC=9E=A5/=EC=95=8C?= =?UTF-8?q?=EB=B0=94=20=EA=B3=B5=EA=B3=A0=20=EC=83=81=EC=84=B8=20=EB=B0=98?= =?UTF-8?q?=EC=9D=91=ED=98=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/Shop/ShopView/index.tsx | 25 ++++++- .../NoticeDetailed/NoticeDetailed.module.scss | 7 +- .../DetailedMyShopNotice.module.scss | 69 +++++++++++++++++++ pages/my-shop/[noticeId]/index.tsx | 16 +++-- 4 files changed, 106 insertions(+), 11 deletions(-) diff --git a/components/Shop/ShopView/index.tsx b/components/Shop/ShopView/index.tsx index aced58c..43213a1 100644 --- a/components/Shop/ShopView/index.tsx +++ b/components/Shop/ShopView/index.tsx @@ -9,12 +9,14 @@ import { useRecoilValue } from "recoil"; import Spinner from "@/components/Spinner"; import { employerAtom } from "@/atoms/employerAtom"; import ShopNotice from "../ShopNotice"; +import { useRouter } from "next/router"; const cx = classNames.bind(styles); const ShopView: React.FC = ({ onEdit }) => { const [shopData, setShopData] = useState(null); const shopValue = useRecoilValue(employerAtom); + const router = useRouter(); useEffect(() => { const fetchAndSetShopData = async () => { @@ -31,6 +33,10 @@ const ShopView: React.FC = ({ onEdit }) => { fetchAndSetShopData(); }, [shopValue]); + const handleMoveInsertNotice = () => { + //router.push() + }; + if (!shopData) { return (
@@ -63,16 +69,29 @@ const ShopView: React.FC = ({ onEdit }) => {

{shopData.name}

- 위치 아이콘 + 위치 아이콘

{shopData.address1}

{shopData.description}

- -
diff --git a/components/notice/NoticeDetailed/NoticeDetailed.module.scss b/components/notice/NoticeDetailed/NoticeDetailed.module.scss index aaf9a18..0bd5f67 100644 --- a/components/notice/NoticeDetailed/NoticeDetailed.module.scss +++ b/components/notice/NoticeDetailed/NoticeDetailed.module.scss @@ -108,7 +108,7 @@ } .notice-info__img { - width: 632px; + width: 100%; height: 360px; } @@ -131,4 +131,9 @@ width: 310px; height: 178px; } + + .notice-info__intro { + height: auto; + overflow: visible; + } } diff --git a/pages/my-shop/[noticeId]/DetailedMyShopNotice.module.scss b/pages/my-shop/[noticeId]/DetailedMyShopNotice.module.scss index 9c7c1b2..39ec06c 100644 --- a/pages/my-shop/[noticeId]/DetailedMyShopNotice.module.scss +++ b/pages/my-shop/[noticeId]/DetailedMyShopNotice.module.scss @@ -1,3 +1,5 @@ +@import "@/styles/const.scss"; + @mixin flexBasicSet($direction: row, $gap: 0) { display: flex; flex-direction: $direction; @@ -13,6 +15,13 @@ border: 1px solid $color; color: $color; cursor: pointer; + + @media screen and (max-width: $MOBILE) { + padding: 8px 12px; + font-size: 12px; + font-weight: 400; + line-height: 16px; + } } @mixin stateLabel($backgroundColor, $fontColor) { @@ -24,6 +33,12 @@ font-size: 14px; line-height: 16.8px; border: none; + + @media screen and (max-width: $MOBILE) { + font-size: 12px; + font-weight: 400; + line-height: 16px; + } } .content-wrap { @@ -114,3 +129,57 @@ .state-approve { @include stateLabel(var(--blue10), var(--blue20)); } + +@media screen and (max-width: $TABLET) { + .content-wrap { + width: 680px; + } + .phone { + display: none; + } + + .list-header, + .list-content { + > div:nth-of-type(1) { + width: 200px; + } + > div:nth-of-type(2) { + width: 250px; + } + } +} +@media screen and (max-width: $MOBILE) { + .content-wrap { + width: 350px; + } + + .list-header, + .list-content { + > div:nth-of-type(1) { + width: 160px; + } + } + + .notice--head__name { + font-size: 20px; + line-height: 24px; + } + + .list-header { + background-color: var(--red10); + line-height: 16px; + height: 40px; + font-size: 12px; + font-weight: 400; + } + + .name { + line-height: 22px; + font-size: 14px; + font-weight: 400; + } + + .intro { + display: none; + } +} diff --git a/pages/my-shop/[noticeId]/index.tsx b/pages/my-shop/[noticeId]/index.tsx index 5b73a8e..2e3c824 100644 --- a/pages/my-shop/[noticeId]/index.tsx +++ b/pages/my-shop/[noticeId]/index.tsx @@ -18,9 +18,9 @@ const testNoticeId = "7f80319a-e354-4036-be58-6749227b13af"; const DetailedMyShopNotice = () => { // 페이지네이션 예시를 위해 잠시 남겨놓음 /*const router = useRouter(); - const { page = 1, noticeId } = router.query; + const { page = 1, testNoticeId } = router.query; const currentPage = parseInt(page as string, 10); - const postsPerPage = 5; + const postsPerPage = 2; const indexOfLastPost = currentPage * postsPerPage; const indexOfFirstPost = indexOfLastPost - postsPerPage; @@ -88,18 +88,20 @@ const DetailedMyShopNotice = () => {
  • 신청자
    -
    소개
    -
    전화번호
    +
    소개
    +
    전화번호
    상태
  • {applicantList && applicantList.map((applicant: IApplicant) => (
  • -
    {applicant.user.name}
    -
    +
    {applicant.user.name}
    +

    {applicant.user.bio}

    -
    {phoneInsertHyphen(applicant.user.phone)}
    +
    + {phoneInsertHyphen(applicant.user.phone)} +
    {applicant.status === "pending" && ( From 8179f4312c387bf46713498e4b51f2d4f16aa131 Mon Sep 17 00:00:00 2001 From: eunjae Date: Tue, 11 Jun 2024 11:23:23 +0900 Subject: [PATCH 3/9] =?UTF-8?q?feat:=20=EB=82=B4=EA=B0=80=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=ED=95=9C=20=EA=B3=B5=EA=B3=A0=20api=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/notice.ts | 19 +++++ components/Shop/ShopNotice/index.tsx | 70 ++++++++++++++++++- components/Shop/ShopView/ShopView.module.scss | 10 +++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/api/notice.ts b/api/notice.ts index 4b7acd4..665b71f 100644 --- a/api/notice.ts +++ b/api/notice.ts @@ -62,3 +62,22 @@ export const putApplicationStatus = async ( } return res; }; + +export interface FormData { + shopId: string; +} + +export const getMyNoticeList = async ( + shopId: string, + offset = 0, + limit = 6 +) => { + try { + const response = await axios.get( + `${BASE_API_URL}/shops/${shopId}/notices?offset=${offset}&limit=${limit}` + ); + return response; + } catch (error) { + throw new Error("Failed to fetch data"); + } +}; diff --git a/components/Shop/ShopNotice/index.tsx b/components/Shop/ShopNotice/index.tsx index 2da7747..3e59aa3 100644 --- a/components/Shop/ShopNotice/index.tsx +++ b/components/Shop/ShopNotice/index.tsx @@ -1,24 +1,90 @@ -import React from "react"; +import React, { useEffect, useRef, useState } from "react"; import styles from "../ShopView/ShopView.module.scss"; import classNames from "classnames/bind"; import Button from "@/components/Button"; +import Post from "@/components/Post"; +import { useRecoilValue } from "recoil"; +import { employerAtom } from "@/atoms/employerAtom"; +import { getMyNoticeList } from "@/api/notice"; +import { INoticeWithShopData } from "@/types/Notice"; const cx = classNames.bind(styles); const ShopNotice = () => { + const [target, setTarget] = useState(null); + const shopValue = useRecoilValue(employerAtom); + const [postList, setPostList] = useState([]); + + // useEffect(() => { + // if (!target) return; + // let observer = new IntersectionObserver(handleAddList, { threshold: 0 }); + + // observer.observe(target); + // } + // ); + // }, [target]); + + useEffect(() => { + if (!shopValue) return; + handleGetMyNoticeList(shopValue.shopId); + }, [shopValue]); + + const handleGetMyNoticeList = async (shopId: string) => { + // const formData = new FormData(); + // formData.append("shopId", shopId); + + const result = await getMyNoticeList(shopId); + + const resultNoticeList = result.data.items.map( + (element: { item: INoticeWithShopData; links: any[] }) => { + // element.item.shop = { + // id: string; + // name: string; + // category: string; + // address1: string; + // address2: string; + // description: string; + // imageUrl: string; + // originalHourlyPay: number; + // } + return element.item; + } + ); + console.log(resultNoticeList); + setPostList((prev) => { + return [...prev, resultNoticeList]; + }); + }; + return (

    등록한 공고

    -
    + {/*

    공고를 등록해 보세요.

    +
    */} +
    + {/* {postList.map((item) => { + return ( + + ); + })} */}
    + {/*
    엔드포인트
    */}
    ); }; diff --git a/components/Shop/ShopView/ShopView.module.scss b/components/Shop/ShopView/ShopView.module.scss index f7ed029..ba45771 100644 --- a/components/Shop/ShopView/ShopView.module.scss +++ b/components/Shop/ShopView/ShopView.module.scss @@ -170,3 +170,13 @@ width: 150px; } } + +.my-notice-list { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 14px; + overflow: hidden; + width: 100%; + transition: transform 0.5s ease; + justify-items: center; +} From 56924d8585cde898808f1ca3a01913729bdb59c0 Mon Sep 17 00:00:00 2001 From: eunjae Date: Tue, 11 Jun 2024 20:29:52 +0900 Subject: [PATCH 4/9] =?UTF-8?q?feat:=20=EB=82=B4=EA=B0=80=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=ED=95=9C=20=EA=B3=B5=EA=B3=A0=20=EB=AC=B4=ED=95=9C?= =?UTF-8?q?=EC=8A=A4=ED=81=AC=EB=A1=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/notice.ts | 21 +++-- atoms/employerAtom.ts | 2 +- .../Shop/ShopNotice/ShopNotice.module.scss | 10 +++ components/Shop/ShopNotice/index.tsx | 83 ++++++++++++------- components/Shop/ShopView/ShopView.module.scss | 10 --- 5 files changed, 79 insertions(+), 47 deletions(-) diff --git a/api/notice.ts b/api/notice.ts index e206ec1..5ceb133 100644 --- a/api/notice.ts +++ b/api/notice.ts @@ -2,11 +2,16 @@ import { BASE_URL, BASE_API_URL } from "@/constants/url"; import { INoticeLinks } from "@/types/Notice"; import axios from "axios"; -export const getNoticeDetailedData = async (shopId: string, noticeId: string) => { +export const getNoticeDetailedData = async ( + shopId: string, + noticeId: string +) => { let res; try { - res = await axios.get(`${BASE_API_URL}/shops/${shopId}/notices/${noticeId}`); + res = await axios.get( + `${BASE_API_URL}/shops/${shopId}/notices/${noticeId}` + ); } catch (error) { if (axios.isAxiosError(error)) { alert(error); @@ -19,7 +24,9 @@ export const getApplicantList = async (shopId: string, noticeId: string) => { let res; try { - res = await axios.get(`${BASE_API_URL}/shops/${shopId}/notices/${noticeId}/applications`); + res = await axios.get( + `${BASE_API_URL}/shops/${shopId}/notices/${noticeId}/applications` + ); } catch (error) { if (axios.isAxiosError(error)) { alert(error); @@ -52,7 +59,10 @@ export const postApplicant = async (shopId: string, noticeId: string) => { } }; -export const putApplicationStatus = async (status: string, idObj: { [key: string]: string }) => { +export const putApplicationStatus = async ( + status: string, + idObj: { [key: string]: string } +) => { const accessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJlMzFmNDkzMy1jNGJjLTQyYjItOTllMC1jNTg1OGNmMGM2NDciLCJpYXQiOjE3MTc4Mzk4Mzd9.EiuJoitWu9Onu0sp2sxkYgBWcu3DMAv1XIhsI8VBV1A"; let res; @@ -90,7 +100,8 @@ export const getMyNoticeList = async ( const response = await axios.get( `${BASE_API_URL}/shops/${shopId}/notices?offset=${offset}&limit=${limit}` ); - return response; + + return response.data; } catch (error) { throw new Error("Failed to fetch data"); } diff --git a/atoms/employerAtom.ts b/atoms/employerAtom.ts index eefa849..797a332 100644 --- a/atoms/employerAtom.ts +++ b/atoms/employerAtom.ts @@ -15,6 +15,6 @@ export const employerAtom = atom({ address2: "", description: "", imageUrl: "", - originalHourlyPay: "", + originalHourlyPay: 0, }, }); diff --git a/components/Shop/ShopNotice/ShopNotice.module.scss b/components/Shop/ShopNotice/ShopNotice.module.scss index 3de2bf4..0cf676b 100644 --- a/components/Shop/ShopNotice/ShopNotice.module.scss +++ b/components/Shop/ShopNotice/ShopNotice.module.scss @@ -66,3 +66,13 @@ display: flex; gap: 8px; } + +.my-notice-list { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 14px; + overflow: hidden; + width: 100%; + transition: transform 0.5s ease; + justify-items: center; +} diff --git a/components/Shop/ShopNotice/index.tsx b/components/Shop/ShopNotice/index.tsx index c37f621..12fd797 100644 --- a/components/Shop/ShopNotice/index.tsx +++ b/components/Shop/ShopNotice/index.tsx @@ -8,54 +8,69 @@ import { employerAtom } from "@/atoms/employerAtom"; import { getMyNoticeList } from "@/api/notice"; import { INoticeWithShopData } from "@/types/Notice"; import { NoticeEmptyProps } from "./ShopNotice.types"; +import { calculateIncreasePercent } from "@/utils/calculateIncreasePercent"; const cx = classNames.bind(styles); const ShopNotice = ({ onClick }: NoticeEmptyProps) => { - const [target, setTarget] = useState(null); + const targetRef = useRef(null); + const [hasNextData, setHasNextData] = useState(false); + const [offest, setOffset] = useState(); const shopValue = useRecoilValue(employerAtom); const [postList, setPostList] = useState([]); - // useEffect(() => { - // if (!target) return; - // let observer = new IntersectionObserver(handleAddList, { threshold: 0 }); - - // observer.observe(target); - // } - // ); - // }, [target]); - useEffect(() => { if (!shopValue) return; handleGetMyNoticeList(shopValue.shopId); }, [shopValue]); + useEffect(() => { + if (!targetRef.current || !shopValue) return; + + const observer = new IntersectionObserver( + ([entry]) => { + if (entry.isIntersecting && hasNextData) { + handleGetMyNoticeList(shopValue.shopId); + } + }, + { threshold: 0 } + ); + + observer.observe(targetRef.current); + + if (!hasNextData) observer.unobserve(targetRef.current); + + return () => observer.disconnect(); + }, [targetRef, hasNextData]); + const handleGetMyNoticeList = async (shopId: string) => { // const formData = new FormData(); // formData.append("shopId", shopId); - const result = await getMyNoticeList(shopId); - - const resultNoticeList = result.data.items.map( + const result = await getMyNoticeList(shopId, offest); + const resultNoticeList = result.items.map( (element: { item: INoticeWithShopData; links: any[] }) => { - // element.item.shop = { - // id: string; - // name: string; - // category: string; - // address1: string; - // address2: string; - // description: string; - // imageUrl: string; - // originalHourlyPay: number; - // } + element.item.shop = { + id: shopValue.id, + name: shopValue.name, + category: shopValue.category, + address1: shopValue.address1, + address2: shopValue.address2, + description: shopValue.description, + imageUrl: shopValue.imageUrl, + originalHourlyPay: shopValue.originalHourlyPay, + }; return element.item; } ); - console.log(resultNoticeList); + setPostList((prev) => { - return [...prev, resultNoticeList]; + return [...prev, ...resultNoticeList]; }); + setHasNextData(result.hasNext); + setOffset(result.offset + result.limit); }; + console.log(postList); return (
    @@ -71,21 +86,27 @@ const ShopNotice = ({ onClick }: NoticeEmptyProps) => {
    */}
    - {/* {postList.map((item) => { + {postList.map((item) => { + const increasePercent = calculateIncreasePercent( + item.shop?.originalHourlyPay, + item.hourlyPay + ); + return ( ); - })} */} + })}
    - {/*
    엔드포인트
    */} + {hasNextData &&
    엔드포인트
    }
    ); }; diff --git a/components/Shop/ShopView/ShopView.module.scss b/components/Shop/ShopView/ShopView.module.scss index 7960175..b6b38bb 100644 --- a/components/Shop/ShopView/ShopView.module.scss +++ b/components/Shop/ShopView/ShopView.module.scss @@ -184,13 +184,3 @@ width: 150px; } } - -.my-notice-list { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 14px; - overflow: hidden; - width: 100%; - transition: transform 0.5s ease; - justify-items: center; -} From 9cd4e33774767778f1b42f8caa5661812596366d Mon Sep 17 00:00:00 2001 From: MEGUMMY1 Date: Tue, 11 Jun 2024 20:38:47 +0900 Subject: [PATCH 5/9] =?UTF-8?q?test:=20CI=20=EB=B0=98=EC=98=81=20=ED=9B=84?= =?UTF-8?q?=20=EC=8B=A4=ED=97=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/my-shop/[noticeId]/index.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/pages/my-shop/[noticeId]/index.tsx b/pages/my-shop/[noticeId]/index.tsx index 5b73a8e..65226b1 100644 --- a/pages/my-shop/[noticeId]/index.tsx +++ b/pages/my-shop/[noticeId]/index.tsx @@ -17,6 +17,7 @@ const testNoticeId = "7f80319a-e354-4036-be58-6749227b13af"; const DetailedMyShopNotice = () => { // 페이지네이션 예시를 위해 잠시 남겨놓음 + // push 실험 /*const router = useRouter(); const { page = 1, noticeId } = router.query; const currentPage = parseInt(page as string, 10); @@ -40,13 +41,11 @@ const DetailedMyShopNotice = () => { const data = await getApplicantList(testShopId, testNoticeId); if (data.count > 0) { - const filteredItems = data.items.map( - ({ item }: IApplicantGetApiData) => ({ - id: item.id, - status: item.status, - user: item.user.item, - }) - ); + const filteredItems = data.items.map(({ item }: IApplicantGetApiData) => ({ + id: item.id, + status: item.status, + user: item.user.item, + })); setApplicantList(filteredItems); } From a4f42faeeaa8db59e2d3ef20c7f7d7910f1188ac Mon Sep 17 00:00:00 2001 From: MEGUMMY1 Date: Tue, 11 Jun 2024 21:32:36 +0900 Subject: [PATCH 6/9] =?UTF-8?q?chore:=20build=20error=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../layout/Header/HeaderButton/index.tsx | 22 +++++-------------- components/layout/Header/UiButton/index.tsx | 8 ++----- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/components/layout/Header/HeaderButton/index.tsx b/components/layout/Header/HeaderButton/index.tsx index ba2093a..e67a853 100644 --- a/components/layout/Header/HeaderButton/index.tsx +++ b/components/layout/Header/HeaderButton/index.tsx @@ -2,7 +2,7 @@ import React from "react"; import UiButton from "../UiButton"; import NotiButton from "../NotiButton"; import styles from "./HeaderButtons.module.scss"; -import { HeaderButtonsProps } from "./HeaderButton.types"; +import { HeaderButtonsProps } from "../types/HeaderButton.types"; export default function HeaderButtons({ userType, @@ -27,27 +27,15 @@ export default function HeaderButtons({ )} {userType === "employer" && ( <> - handleClickMovePage("my-shop")} - /> - handleClickMovePage("my-shop")} - /> + handleClickMovePage("my-shop")} /> + handleClickMovePage("my-shop")} /> )} {userType === "employee" && ( <> - handleClickMovePage("my-profile")} - /> - handleClickMovePage("my-shop")} - /> + handleClickMovePage("my-profile")} /> + handleClickMovePage("my-shop")} /> )} diff --git a/components/layout/Header/UiButton/index.tsx b/components/layout/Header/UiButton/index.tsx index ed49b0c..a3d9e62 100644 --- a/components/layout/Header/UiButton/index.tsx +++ b/components/layout/Header/UiButton/index.tsx @@ -1,6 +1,6 @@ import React from "react"; import styles from "./UiButton.module.scss"; -import { ButtonProps } from "./UiButton.types"; +import { ButtonProps } from "../types/UiButton.types"; export default function UiButton({ name, id, handleClickButton }: ButtonProps) { const handleClickMovePage = () => { @@ -8,11 +8,7 @@ export default function UiButton({ name, id, handleClickButton }: ButtonProps) { }; return ( - ); From 8df8af0d05d40afea5f34e9fd6e34fcc5e95cba2 Mon Sep 17 00:00:00 2001 From: MEGUMMY1 Date: Wed, 12 Jun 2024 00:23:52 +0900 Subject: [PATCH 7/9] =?UTF-8?q?feat:=20=EA=B3=B5=EA=B3=A0=20=EC=8B=A0?= =?UTF-8?q?=EC=B2=AD=EC=9E=90=20=EB=AA=A9=EB=A1=9D=20api=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0=20=EB=B0=8F=20=ED=8E=98=EC=9D=B4=EC=A7=80=EB=84=A4?= =?UTF-8?q?=EC=9D=B4=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/myShop.ts | 14 ++ api/notice.ts | 31 +-- components/Shop/ShopNotice/index.tsx | 25 +-- .../ApplicationList.module.scss | 185 ++++++++++++++++++ .../ApplicationList/ApplicationList.types.ts | 7 + components/notice/ApplicationList/index.tsx | 87 ++++++++ .../DetailedMyShopNotice.module.scss | 11 ++ .../[noticeId]/DetailedMyShopNotice.types.ts | 6 - pages/my-shop/[noticeId]/index.tsx | 121 +++--------- pages/my-shop/index.tsx | 17 +- types/User.ts | 6 + 11 files changed, 362 insertions(+), 148 deletions(-) create mode 100644 components/notice/ApplicationList/ApplicationList.module.scss create mode 100644 components/notice/ApplicationList/ApplicationList.types.ts create mode 100644 components/notice/ApplicationList/index.tsx diff --git a/api/myShop.ts b/api/myShop.ts index 47f1985..9e4e67a 100644 --- a/api/myShop.ts +++ b/api/myShop.ts @@ -44,3 +44,17 @@ export const updateShopDetails = async (shopId: string, data: FormData) => { throw error; } }; + +export const fetchUserInfo = async (token: string, userId: string) => { + try { + const response = await axios.get(`${BASE_URL}/users/${userId}`, { + headers: { + Authorization: `Bearer ${token}`, + }, + }); + return response.data; + } catch (error) { + console.error("Failed to fetch user info:", error); + return null; + } +}; diff --git a/api/notice.ts b/api/notice.ts index 5ceb133..f4cae74 100644 --- a/api/notice.ts +++ b/api/notice.ts @@ -2,16 +2,11 @@ import { BASE_URL, BASE_API_URL } from "@/constants/url"; import { INoticeLinks } from "@/types/Notice"; import axios from "axios"; -export const getNoticeDetailedData = async ( - shopId: string, - noticeId: string -) => { +export const getNoticeDetailedData = async (shopId: string, noticeId: string) => { let res; try { - res = await axios.get( - `${BASE_API_URL}/shops/${shopId}/notices/${noticeId}` - ); + res = await axios.get(`${BASE_API_URL}/shops/${shopId}/notices/${noticeId}`); } catch (error) { if (axios.isAxiosError(error)) { alert(error); @@ -21,18 +16,17 @@ export const getNoticeDetailedData = async ( }; export const getApplicantList = async (shopId: string, noticeId: string) => { - let res; - try { - res = await axios.get( - `${BASE_API_URL}/shops/${shopId}/notices/${noticeId}/applications` + const res = await axios.get( + `${BASE_API_URL}/shops/${shopId}/notices/${noticeId}/applications?limit=100` ); + return res; } catch (error) { if (axios.isAxiosError(error)) { - alert(error); + alert("데이터를 가져오는 중 오류가 발생했습니다."); } + throw error; } - return res?.data; }; export const postApplicant = async (shopId: string, noticeId: string) => { @@ -59,10 +53,7 @@ export const postApplicant = async (shopId: string, noticeId: string) => { } }; -export const putApplicationStatus = async ( - status: string, - idObj: { [key: string]: string } -) => { +export const putApplicationStatus = async (status: string, idObj: { [key: string]: string }) => { const accessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJlMzFmNDkzMy1jNGJjLTQyYjItOTllMC1jNTg1OGNmMGM2NDciLCJpYXQiOjE3MTc4Mzk4Mzd9.EiuJoitWu9Onu0sp2sxkYgBWcu3DMAv1XIhsI8VBV1A"; let res; @@ -91,11 +82,7 @@ export interface FormData { shopId: string; } -export const getMyNoticeList = async ( - shopId: string, - offset = 0, - limit = 6 -) => { +export const getMyNoticeList = async (shopId: string, offset = 0, limit = 6) => { try { const response = await axios.get( `${BASE_API_URL}/shops/${shopId}/notices?offset=${offset}&limit=${limit}` diff --git a/components/Shop/ShopNotice/index.tsx b/components/Shop/ShopNotice/index.tsx index 12fd797..274b7b2 100644 --- a/components/Shop/ShopNotice/index.tsx +++ b/components/Shop/ShopNotice/index.tsx @@ -9,6 +9,7 @@ import { getMyNoticeList } from "@/api/notice"; import { INoticeWithShopData } from "@/types/Notice"; import { NoticeEmptyProps } from "./ShopNotice.types"; import { calculateIncreasePercent } from "@/utils/calculateIncreasePercent"; +import Link from "next/link"; const cx = classNames.bind(styles); @@ -86,23 +87,25 @@ const ShopNotice = ({ onClick }: NoticeEmptyProps) => {
    */}
    - {postList.map((item) => { + {postList.map((item, i) => { const increasePercent = calculateIncreasePercent( item.shop?.originalHourlyPay, item.hourlyPay ); return ( - + + + ); })}
    diff --git a/components/notice/ApplicationList/ApplicationList.module.scss b/components/notice/ApplicationList/ApplicationList.module.scss new file mode 100644 index 0000000..39ec06c --- /dev/null +++ b/components/notice/ApplicationList/ApplicationList.module.scss @@ -0,0 +1,185 @@ +@import "@/styles/const.scss"; + +@mixin flexBasicSet($direction: row, $gap: 0) { + display: flex; + flex-direction: $direction; + gap: $gap; +} + +@mixin stateBtn($color) { + padding: 10px 20px; + border-radius: 6px; + background-color: var(--white); + font-weight: 700; + line-height: 17.53px; + border: 1px solid $color; + color: $color; + cursor: pointer; + + @media screen and (max-width: $MOBILE) { + padding: 8px 12px; + font-size: 12px; + font-weight: 400; + line-height: 16px; + } +} + +@mixin stateLabel($backgroundColor, $fontColor) { + padding: 6px 10px; + border-radius: 20px; + background-color: $backgroundColor; + color: $fontColor; + font-weight: 700; + font-size: 14px; + line-height: 16.8px; + border: none; + + @media screen and (max-width: $MOBILE) { + font-size: 12px; + font-weight: 400; + line-height: 16px; + } +} + +.content-wrap { + width: 964px; + margin: 0 auto; +} + +.applicant-list { + margin: 120px 0 120px; +} + +.notice--head__name { + font-size: 28px; + font-weight: 700; + line-height: 33.6px; +} + +.list-wrap { + margin-top: 32px; + border-radius: 10px; + border: 1px solid var(--gray20); +} + +.list-header, +.list-content { + @include flexBasicSet; + align-items: center; + height: 80px; + + > div { + padding: 20px 12px; + } + + > div:nth-of-type(1) { + width: 228px; + } + + > div:nth-of-type(2) { + width: 300px; + } + + > div:nth-of-type(3) { + width: 200px; + } +} + +.list-content { + line-height: 20px; + border-bottom: 1px solid var(--gray20); +} + +.list-header { + background-color: var(--red10); + border-radius: 10px 10px 0 0; + line-height: 22px; + height: 50px; +} + +.list-footer { + padding: 12px 0; +} + +.bio { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + text-overflow: ellipsis; + overflow: hidden; + word-break: break-word; +} + +.btn-wrap { + @include flexBasicSet($gap: 12px); +} + +.state-btn-reject { + @include stateBtn(var(--primary)); +} + +.state-btn-approve { + @include stateBtn(var(--blue20)); +} + +.state-reject { + @include stateLabel(var(--red10), var(--red40)); +} + +.state-approve { + @include stateLabel(var(--blue10), var(--blue20)); +} + +@media screen and (max-width: $TABLET) { + .content-wrap { + width: 680px; + } + .phone { + display: none; + } + + .list-header, + .list-content { + > div:nth-of-type(1) { + width: 200px; + } + > div:nth-of-type(2) { + width: 250px; + } + } +} +@media screen and (max-width: $MOBILE) { + .content-wrap { + width: 350px; + } + + .list-header, + .list-content { + > div:nth-of-type(1) { + width: 160px; + } + } + + .notice--head__name { + font-size: 20px; + line-height: 24px; + } + + .list-header { + background-color: var(--red10); + line-height: 16px; + height: 40px; + font-size: 12px; + font-weight: 400; + } + + .name { + line-height: 22px; + font-size: 14px; + font-weight: 400; + } + + .intro { + display: none; + } +} diff --git a/components/notice/ApplicationList/ApplicationList.types.ts b/components/notice/ApplicationList/ApplicationList.types.ts new file mode 100644 index 0000000..f13ce7c --- /dev/null +++ b/components/notice/ApplicationList/ApplicationList.types.ts @@ -0,0 +1,7 @@ +import { IApplicant } from "@/types/User"; + +export interface ApplicationListProps { + applicantList: IApplicant[]; + handleStatusClick: (status: string, applicationId: string) => void; + noticeId: string; +} diff --git a/components/notice/ApplicationList/index.tsx b/components/notice/ApplicationList/index.tsx new file mode 100644 index 0000000..fc5e234 --- /dev/null +++ b/components/notice/ApplicationList/index.tsx @@ -0,0 +1,87 @@ +import styles from "./ApplicationList.module.scss"; +import classNames from "classnames/bind"; +import Pagination from "@/components/Pagination"; +import phoneInsertHyphen from "@/utils/phoneInsertHyphen"; +import { ApplicationListProps } from "./ApplicationList.types"; +import { IApplicant } from "@/types/User"; +import { useRouter } from "next/router"; + +const cx = classNames.bind(styles); + +const ApplicationList = ({ applicantList, handleStatusClick, noticeId }: ApplicationListProps) => { + const router = useRouter(); + const { page = 1 } = router.query; + const currentPage = parseInt(page as string, 10); + const postsPerPage = 5; + + const indexOfLastPost = currentPage * postsPerPage; + const indexOfFirstPost = indexOfLastPost - postsPerPage; + const currentApplicants = applicantList.slice(indexOfFirstPost, indexOfLastPost); + + return ( +
    +

    신청자 목록

    +
      +
    • +
      신청자
      +
      소개
      +
      전화번호
      +
      상태
      +
    • + {currentApplicants && + currentApplicants.map((applicant: IApplicant) => ( +
    • +
      {applicant.user.name}
      +
      +

      {applicant.user.bio}

      +
      +
      {phoneInsertHyphen(applicant.user.phone)}
      +
      +
      + {applicant.status === "pending" && ( + <> + + + + )} + + {applicant.status === "accepted" && ( +
      승인 완료
      + )} + {applicant.status === "rejected" && ( +
      거절
      + )} +
      +
      +
    • + ))} + +
    • + +
    • +
    +
    + ); +}; + +export default ApplicationList; diff --git a/pages/my-shop/[noticeId]/DetailedMyShopNotice.module.scss b/pages/my-shop/[noticeId]/DetailedMyShopNotice.module.scss index 39ec06c..882bf4b 100644 --- a/pages/my-shop/[noticeId]/DetailedMyShopNotice.module.scss +++ b/pages/my-shop/[noticeId]/DetailedMyShopNotice.module.scss @@ -183,3 +183,14 @@ display: none; } } + +.no-applicants { + width: 100%; + height: 200px; + margin: 32px 0; + border-radius: 10px; + border: 1px solid var(--gray20); + display: flex; + align-items: center; + justify-content: center; +} diff --git a/pages/my-shop/[noticeId]/DetailedMyShopNotice.types.ts b/pages/my-shop/[noticeId]/DetailedMyShopNotice.types.ts index 7686371..f9d02e0 100644 --- a/pages/my-shop/[noticeId]/DetailedMyShopNotice.types.ts +++ b/pages/my-shop/[noticeId]/DetailedMyShopNotice.types.ts @@ -21,9 +21,3 @@ export interface IApplicantGetApiData { }; }; } - -export interface IApplicant { - id: string; - status: "pending" | "accepted" | "rejected" | "canceled"; - user: IUserData; -} diff --git a/pages/my-shop/[noticeId]/index.tsx b/pages/my-shop/[noticeId]/index.tsx index 8ac2520..951fe8d 100644 --- a/pages/my-shop/[noticeId]/index.tsx +++ b/pages/my-shop/[noticeId]/index.tsx @@ -1,35 +1,29 @@ import styles from "./DetailedMyShopNotice.module.scss"; import classNames from "classnames/bind"; import NoticeDetailed from "@/components/notice/NoticeDetailed"; -import Pagination from "@/components/Pagination"; import { useGetDetailedNotice } from "@/hooks/useGetDetailedNotice"; import { useEffect, useState } from "react"; import { getApplicantList, putApplicationStatus } from "@/api/notice"; -import phoneInsertHyphen from "@/utils/phoneInsertHyphen"; -import { IApplicant, IApplicantGetApiData } from "./DetailedMyShopNotice.types"; +import { IApplicantGetApiData } from "./DetailedMyShopNotice.types"; +import { IApplicant } from "@/types/User"; import { useModal } from "@/hooks/useModal"; +import ApplicationList from "@/components/notice/ApplicationList"; +import { useRecoilValue } from "recoil"; +import { employerAtom } from "@/atoms/employerAtom"; import { useRouter } from "next/router"; const cx = classNames.bind(styles); -const testShopId = "9091b6fc-c968-41c8-ba34-a4b90dd5a603"; -const testNoticeId = "7f80319a-e354-4036-be58-6749227b13af"; - const DetailedMyShopNotice = () => { - // 페이지네이션 예시를 위해 잠시 남겨놓음 - // push 실험 - /*const router = useRouter(); - const { page = 1, testNoticeId } = router.query; - const currentPage = parseInt(page as string, 10); - const postsPerPage = 2; - - const indexOfLastPost = currentPage * postsPerPage; - const indexOfFirstPost = indexOfLastPost - postsPerPage; - const currentApplicants = APPLICANT.slice(indexOfFirstPost, indexOfLastPost);*/ + const router = useRouter(); + const { noticeId } = router.query; + const noticeIdString = noticeId as string; + const shopValue = useRecoilValue(employerAtom); + const shopId = shopValue.shopId; - const { noticeShopData } = useGetDetailedNotice(testShopId, testNoticeId); + const { noticeShopData } = useGetDetailedNotice(shopId, noticeIdString); const { openModal, closeModal } = useModal(); - const [applicantList, setApplicantList] = useState(); + const [applicantList, setApplicantList] = useState([]); useEffect(() => { if (noticeShopData) { @@ -38,16 +32,18 @@ const DetailedMyShopNotice = () => { }, [noticeShopData]); const handleApplicantGetData = async () => { - const data = await getApplicantList(testShopId, testNoticeId); + const res = await getApplicantList(shopId, noticeIdString); - if (data.count > 0) { - const filteredItems = data.items.map(({ item }: IApplicantGetApiData) => ({ + if (res.data.count > 0) { + const filteredItems = res.data.items.map(({ item }: IApplicantGetApiData) => ({ id: item.id, status: item.status, user: item.user.item, })); setApplicantList(filteredItems); + } else { + setApplicantList([]); } }; @@ -63,8 +59,8 @@ const DetailedMyShopNotice = () => { const handleStateCallback = async (status: string, applicationId: string) => { const urlIdObj = { - shopId: testShopId, - noticeId: testNoticeId, + shopId: shopId, + noticeId: noticeIdString, applicationId: applicationId, }; @@ -81,76 +77,15 @@ const DetailedMyShopNotice = () => { <>
    - -
    -

    신청자 목록

    -
      -
    • -
      신청자
      -
      소개
      -
      전화번호
      -
      상태
      -
    • - {applicantList && - applicantList.map((applicant: IApplicant) => ( -
    • -
      {applicant.user.name}
      -
      -

      {applicant.user.bio}

      -
      -
      - {phoneInsertHyphen(applicant.user.phone)} -
      -
      -
      - {applicant.status === "pending" && ( - <> - - - - )} - - {applicant.status === "accepted" && ( -
      승인 완료
      - )} - {applicant.status === "rejected" && ( -
      거절
      - )} -
      -
      -
    • - ))} - -
    • - -
    • -
    -
    + {applicantList.length > 0 ? ( + + ) : ( +
    신청자가 없습니다.
    + )}
    ); diff --git a/pages/my-shop/index.tsx b/pages/my-shop/index.tsx index 210e9b8..7aa9001 100644 --- a/pages/my-shop/index.tsx +++ b/pages/my-shop/index.tsx @@ -3,25 +3,10 @@ import { useRecoilState } from "recoil"; import { employerAtom } from "@/atoms/employerAtom"; import ShopEmpty from "@/components/Shop/ShopEmpty"; import ShopForm from "@/components/Shop/ShopForm"; -import axios from "axios"; import { useState } from "react"; -import { BASE_URL } from "@/constants/constants"; import ShopView from "@/components/Shop/ShopView"; import ShopEdit from "@/components/Shop/ShopEdit"; - -const fetchUserInfo = async (token: string, userId: string) => { - try { - const response = await axios.get(`${BASE_URL}/users/${userId}`, { - headers: { - Authorization: `Bearer ${token}`, - }, - }); - return response.data; - } catch (error) { - console.error("Failed to fetch user info:", error); - return null; - } -}; +import { fetchUserInfo } from "@/api/myShop"; const MyShop = () => { const [showShopForm, setShowShopForm] = useState(false); diff --git a/types/User.ts b/types/User.ts index 609499c..abebd23 100644 --- a/types/User.ts +++ b/types/User.ts @@ -13,3 +13,9 @@ export interface IUserData { export interface IUserWithShopData extends IUserData { shop: IShopData; } + +export interface IApplicant { + id: string; + status: "pending" | "accepted" | "rejected" | "canceled"; + user: IUserData; +} From 5c6729c9cdb94c4871256a1ab6985c203d1dd150 Mon Sep 17 00:00:00 2001 From: eunjae Date: Wed, 12 Jun 2024 11:43:47 +0900 Subject: [PATCH 8/9] =?UTF-8?q?fix:=20=EB=AC=B4=ED=95=9C=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A1=A4=20=EC=88=98=EC=A0=95(=EB=AF=B8=EC=99=84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/notice.ts | 5 ++++- components/Shop/ShopNotice/index.tsx | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/api/notice.ts b/api/notice.ts index 5ceb133..8a99d4e 100644 --- a/api/notice.ts +++ b/api/notice.ts @@ -96,11 +96,14 @@ export const getMyNoticeList = async ( offset = 0, limit = 6 ) => { + console.log("offsest::", offset); try { const response = await axios.get( `${BASE_API_URL}/shops/${shopId}/notices?offset=${offset}&limit=${limit}` ); - + console.log( + `${BASE_API_URL}/shops/${shopId}/notices?offset=${offset}&limit=${limit}` + ); return response.data; } catch (error) { throw new Error("Failed to fetch data"); diff --git a/components/Shop/ShopNotice/index.tsx b/components/Shop/ShopNotice/index.tsx index 12fd797..400ab84 100644 --- a/components/Shop/ShopNotice/index.tsx +++ b/components/Shop/ShopNotice/index.tsx @@ -51,7 +51,7 @@ const ShopNotice = ({ onClick }: NoticeEmptyProps) => { const resultNoticeList = result.items.map( (element: { item: INoticeWithShopData; links: any[] }) => { element.item.shop = { - id: shopValue.id, + id: shopValue.shopId, name: shopValue.name, category: shopValue.category, address1: shopValue.address1, @@ -68,6 +68,7 @@ const ShopNotice = ({ onClick }: NoticeEmptyProps) => { return [...prev, ...resultNoticeList]; }); setHasNextData(result.hasNext); + console.log("result.offset + result.limit::", result.offset + result.limit); setOffset(result.offset + result.limit); }; console.log(postList); From 221ffe3c5a99edadadbea881d24d461658f84d78 Mon Sep 17 00:00:00 2001 From: eunjae Date: Wed, 12 Jun 2024 13:53:26 +0900 Subject: [PATCH 9/9] =?UTF-8?q?fix:=20=EB=93=B1=EB=A1=9D=ED=95=9C=20?= =?UTF-8?q?=EA=B3=B5=EA=B3=A0=20=EB=AC=B4=ED=95=9C=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A1=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/notice.ts | 6 +- components/Shop/ShopNotice/index.tsx | 94 +++++++++++++++----------- components/Spinner/Spinner.module.scss | 2 +- 3 files changed, 57 insertions(+), 45 deletions(-) diff --git a/api/notice.ts b/api/notice.ts index 32b8fd3..8c59926 100644 --- a/api/notice.ts +++ b/api/notice.ts @@ -95,15 +95,11 @@ export const getMyNoticeList = async ( offset = 0, limit = 6 ) => { - console.log("offsest::", offset); - try { const response = await axios.get( `${BASE_API_URL}/shops/${shopId}/notices?offset=${offset}&limit=${limit}` ); - console.log( - `${BASE_API_URL}/shops/${shopId}/notices?offset=${offset}&limit=${limit}` - ); + return response.data; } catch (error) { throw new Error("Failed to fetch data"); diff --git a/components/Shop/ShopNotice/index.tsx b/components/Shop/ShopNotice/index.tsx index 9fd5db9..f06c79c 100644 --- a/components/Shop/ShopNotice/index.tsx +++ b/components/Shop/ShopNotice/index.tsx @@ -10,19 +10,22 @@ import { INoticeWithShopData } from "@/types/Notice"; import { NoticeEmptyProps } from "./ShopNotice.types"; import { calculateIncreasePercent } from "@/utils/calculateIncreasePercent"; import Link from "next/link"; +import Spinner from "@/components/Spinner"; const cx = classNames.bind(styles); const ShopNotice = ({ onClick }: NoticeEmptyProps) => { const targetRef = useRef(null); const [hasNextData, setHasNextData] = useState(false); - const [offest, setOffset] = useState(); + const [offset, setOffset] = useState(0); const shopValue = useRecoilValue(employerAtom); const [postList, setPostList] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); useEffect(() => { if (!shopValue) return; - handleGetMyNoticeList(shopValue.shopId); + handleGetMyNoticeList(shopValue.shopId, offset); }, [shopValue]); useEffect(() => { @@ -31,7 +34,7 @@ const ShopNotice = ({ onClick }: NoticeEmptyProps) => { const observer = new IntersectionObserver( ([entry]) => { if (entry.isIntersecting && hasNextData) { - handleGetMyNoticeList(shopValue.shopId); + handleGetMyNoticeList(shopValue.shopId, offset); } }, { threshold: 0 } @@ -42,51 +45,62 @@ const ShopNotice = ({ onClick }: NoticeEmptyProps) => { if (!hasNextData) observer.unobserve(targetRef.current); return () => observer.disconnect(); - }, [targetRef, hasNextData]); + }, [targetRef, hasNextData, offset]); - const handleGetMyNoticeList = async (shopId: string) => { - // const formData = new FormData(); - // formData.append("shopId", shopId); - - const result = await getMyNoticeList(shopId, offest); - const resultNoticeList = result.items.map( - (element: { item: INoticeWithShopData; links: any[] }) => { - element.item.shop = { - id: shopValue.shopId, - name: shopValue.name, - category: shopValue.category, - address1: shopValue.address1, - address2: shopValue.address2, - description: shopValue.description, - imageUrl: shopValue.imageUrl, - originalHourlyPay: shopValue.originalHourlyPay, - }; - return element.item; - } - ); + const handleGetMyNoticeList = async ( + shopId: string, + currentOffset: number + ) => { + try { + setLoading(true); + const result = await getMyNoticeList(shopId, currentOffset); + const resultNoticeList = result.items.map( + (element: { item: INoticeWithShopData; links: any[] }) => { + element.item.shop = { + id: shopValue.shopId, + name: shopValue.name, + category: shopValue.category, + address1: shopValue.address1, + address2: shopValue.address2, + description: shopValue.description, + imageUrl: shopValue.imageUrl, + originalHourlyPay: shopValue.originalHourlyPay, + }; + return element.item; + } + ); - setPostList((prev) => { - return [...prev, ...resultNoticeList]; - }); - setHasNextData(result.hasNext); - console.log("result.offset + result.limit::", result.offset + result.limit); - setOffset(result.offset + result.limit); + setPostList((prev) => { + return [...prev, ...resultNoticeList]; + }); + setHasNextData(result.hasNext); + setOffset((prevOffset) => prevOffset + result.limit); + } catch (e) { + setError("Failed to fetch data"); + } finally { + setLoading(false); + } }; - console.log(postList); return (

    등록한 공고

    - {/*
    -
    -

    공고를 등록해 보세요.

    - + {postList.length === 0 && ( +
    +
    +

    공고를 등록해 보세요.

    + +
    -
    */} + )}
    {postList.map((item, i) => { const increasePercent = calculateIncreasePercent( @@ -110,7 +124,9 @@ const ShopNotice = ({ onClick }: NoticeEmptyProps) => { ); })}
    - {hasNextData &&
    엔드포인트
    } + {loading && } + {hasNextData &&
    } + {error &&
    {error}
    }
    ); }; diff --git a/components/Spinner/Spinner.module.scss b/components/Spinner/Spinner.module.scss index 89ae12d..6254355 100644 --- a/components/Spinner/Spinner.module.scss +++ b/components/Spinner/Spinner.module.scss @@ -1,5 +1,5 @@ .container { - height: 90vh; + height: 400px; display: flex; align-items: center; justify-content: center;