From 2c4b8269b49e235562c1d883419e7fad5a7bae3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A2=E1=84=92=E1=85=A1?= Date: Sun, 15 Oct 2023 19:48:14 +0900 Subject: [PATCH 1/8] =?UTF-8?q?feat:=20=ED=95=9C=EA=B5=AD=EB=86=8D?= =?UTF-8?q?=EC=88=98=EC=82=B0=EC=8B=9D=ED=92=88=EC=9C=A0=ED=86=B5=EA=B3=B5?= =?UTF-8?q?=EC=82=AC=EC=9D=98=20=EC=A0=84=ED=86=B5=EC=A3=BC=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EB=A5=BC=20=EA=B0=80=EC=A0=B8=EC=98=A4=EB=8A=94=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../useGetDrinkRecommendationListService.ts | 22 +++++++++++ apps/jurumarble/src/lib/apis/drink.ts | 38 +++++++++++++++++++ apps/jurumarble/src/lib/constants.tsx | 2 + apps/jurumarble/src/lib/queryKeys.ts | 1 + 4 files changed, 63 insertions(+) create mode 100644 apps/jurumarble/src/app/main/services/useGetDrinkRecommendationListService.ts diff --git a/apps/jurumarble/src/app/main/services/useGetDrinkRecommendationListService.ts b/apps/jurumarble/src/app/main/services/useGetDrinkRecommendationListService.ts new file mode 100644 index 00000000..3c962bf1 --- /dev/null +++ b/apps/jurumarble/src/app/main/services/useGetDrinkRecommendationListService.ts @@ -0,0 +1,22 @@ +import { useQuery } from "@tanstack/react-query"; +import { getDrinkRecommendationListAPI } from "lib/apis/drink"; +import { queryKeys } from "lib/queryKeys"; + +type GetDrinkRecommendationListProps = Exclude< + Parameters[0], + undefined +>; + +const getDrinkRecommendationListQueryKey = (params: GetDrinkRecommendationListProps) => [ + queryKeys.TODAY_DRINK_RECOMMENDATION, + { ...params }, +]; + +export default function useGetDrinkRecommendationListService( + params: GetDrinkRecommendationListProps, +) { + const { data } = useQuery(getDrinkRecommendationListQueryKey(params), () => + getDrinkRecommendationListAPI(params), + ); + return data?.data; +} diff --git a/apps/jurumarble/src/lib/apis/drink.ts b/apps/jurumarble/src/lib/apis/drink.ts index e7b7c8fe..366df215 100644 --- a/apps/jurumarble/src/lib/apis/drink.ts +++ b/apps/jurumarble/src/lib/apis/drink.ts @@ -1,3 +1,5 @@ +import axios from "axios"; +import { DATA_GO_API_KEY } from "lib/constants"; import { DrinkInfoSortType } from "src/types/common"; import { DrinkListResponse, DrinkMapResponse } from "src/types/drink"; import { baseApi } from "./http/base"; @@ -102,3 +104,39 @@ export const getDrinkInfo = async (drinkId: number) => { const response = await baseApi.get(`api/drinks/${drinkId}`); return response.data; }; + +interface GetDrinkRecommendationListRequest { + page: number; + perPage: number; + returnType?: "json" | "xml"; +} + +interface GetDrinkRecommendationListResponse { + currentCount: number; + data: Data[]; + matchCount: number; + page: number; + perPage: number; + totalCount: number; +} + +interface Data { + 규격: string; + 도수: string; + 전통주명: string; + 제조사: string; + 주원료: string; +} + +export const getDrinkRecommendationListAPI = async (params: GetDrinkRecommendationListRequest) => { + const response = await axios.get( + "https://api.odcloud.kr/api/15048755/v1/uddi:fec53d3a-2bef-4494-b50e-f4e566f403e0", + { + params: { + ...params, + serviceKey: DATA_GO_API_KEY, + }, + }, + ); + return response.data; +}; diff --git a/apps/jurumarble/src/lib/constants.tsx b/apps/jurumarble/src/lib/constants.tsx index 27f1bc05..a68cb2e6 100644 --- a/apps/jurumarble/src/lib/constants.tsx +++ b/apps/jurumarble/src/lib/constants.tsx @@ -24,6 +24,8 @@ export const NAVER_LOGIN_REDIRECT_URL = ? `http://localhost:3000${Path.NAVER_LOGIN_PROCESS}` : `${CLIENT_URL}${Path.NAVER_LOGIN_PROCESS}`; +export const DATA_GO_API_KEY = process.env.NEXT_PUBLIC_DATA_GO_API_KEY || ""; + export const REGION_LIST = [ { value: "SEOUL", label: "서울", lat: 37.53391, long: 126.9775 }, { value: "INCHEON", label: "인천", lat: 37.45323333333334, long: 126.70735277777779 }, diff --git a/apps/jurumarble/src/lib/queryKeys.ts b/apps/jurumarble/src/lib/queryKeys.ts index fe5f6fac..9e42fef0 100644 --- a/apps/jurumarble/src/lib/queryKeys.ts +++ b/apps/jurumarble/src/lib/queryKeys.ts @@ -24,6 +24,7 @@ export const queryKeys = { DRINKS_INFO: "drinksInfo" as const, NOTIFICATION_LIST: "notificationList" as const, LOGIN_INFO: "loginInfo" as const, + TODAY_DRINK_RECOMMENDATION: "todayDrinkRecommendation" as const, }; export const reactQueryKeys = { From 76d33c42a6b99d563fdd0de0a3282f816f0f50db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A2=E1=84=92=E1=85=A1?= Date: Sun, 15 Oct 2023 19:57:28 +0900 Subject: [PATCH 2/8] =?UTF-8?q?feat:=20=EC=98=A4=EB=8A=98=EC=9D=98=20?= =?UTF-8?q?=EC=9A=B0=EB=A6=AC=EC=88=A0=20=EC=B6=94=EC=B2=9C=EC=9D=84=20?= =?UTF-8?q?=EB=B3=B4=EC=97=AC=EC=A3=BC=EB=8A=94=20=EC=8A=AC=EB=9D=BC?= =?UTF-8?q?=EC=9D=B4=EB=8D=94=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/TodayDrinkRecommendation.tsx | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 apps/jurumarble/src/app/main/components/TodayDrinkRecommendation.tsx diff --git a/apps/jurumarble/src/app/main/components/TodayDrinkRecommendation.tsx b/apps/jurumarble/src/app/main/components/TodayDrinkRecommendation.tsx new file mode 100644 index 00000000..919af196 --- /dev/null +++ b/apps/jurumarble/src/app/main/components/TodayDrinkRecommendation.tsx @@ -0,0 +1,100 @@ +import { useEffect, useRef, useState } from "react"; +import { SvgStamp } from "src/assets/icons/components"; +import styled, { css, useTheme } from "styled-components"; +import useGetDrinkRecommendationListService from "../services/useGetDrinkRecommendationListService"; + +const SLIDE_MOVE_COUNT = 1; +const ORIGINAL_IMAGE_LENGTH = 10; +const IMAGE_HEIGHT = 18; + +const getRandom = (min: number, max: number) => Math.floor(Math.random() * (max - min + 1) + min); + +function TodayDrinkRecommendation() { + const theme = useTheme(); + const slideRef = useRef(null); + const [currentSlide, setCurrentSlide] = useState(1); + const [isAnimation, setIsAnimation] = useState(true); + const [isFlowing, setIsFlowing] = useState(true); + + const date = new Date(); + const drinkRecommendationList = useGetDrinkRecommendationListService({ + page: date.getDate(), + perPage: 10, + }); + + useEffect(() => { + if (!slideRef.current) return; + + if (currentSlide === ORIGINAL_IMAGE_LENGTH + 1) { + setTimeout(() => { + setIsAnimation(false); + slideRef.current!.style.transform = `translateY(-${ + IMAGE_HEIGHT * ORIGINAL_IMAGE_LENGTH + }px)`; + setCurrentSlide(1); + }, 500); + + setTimeout(() => { + setIsAnimation(true); + }, 600); + } + slideRef.current.style.transform = `translateY(-${IMAGE_HEIGHT * (currentSlide - 1)}px)`; + }, [currentSlide]); + + useEffect(() => { + let intervalId: NodeJS.Timeout; + if (isFlowing) { + intervalId = setInterval(() => { + setCurrentSlide((prev) => prev + SLIDE_MOVE_COUNT); + }, 3500); + } + return () => clearTimeout(intervalId); + }, [isFlowing, currentSlide]); + + return ( + +

+ + 오늘의 우리술 추천 +

+ + {drinkRecommendationList?.map(({ 전통주명 }) => { + return {전통주명}; + })} + +
+ ); +} + +const Container = styled.div` + display: flex; + align-items: center; + overflow: hidden; + padding: 0 20px; + margin-top: 8px; +`; + +const Slider = styled.div<{ isAnimation: boolean }>` + display: flex; + flex-direction: column; + height: 18px; + transition: transform 0.5s ease-in-out; + ${({ isAnimation }) => isAnimation && `transform: translateY(-${IMAGE_HEIGHT}px);`} +`; + +const H3 = styled.h3` + ${({ theme }) => css` + ${theme.typography.body01}; + color: ${theme.colors.main_01}; + display: flex; + align-items: center; + gap: 2px; + `}; +`; + +const DrinkName = styled.span` + ${({ theme }) => theme.typography.body03}; + margin-left: 8px; +`; + +export default TodayDrinkRecommendation; From 4cdc78c67476b4a14bd8b806c59daefc62c6587d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A2=E1=84=92=E1=85=A1?= Date: Sun, 15 Oct 2023 19:59:37 +0900 Subject: [PATCH 3/8] =?UTF-8?q?feat:=20=EB=B0=B0=EB=84=88=20=ED=85=8D?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/app/main/components/Banner.tsx | 46 +++++++++++++++++++ apps/jurumarble/src/app/page.tsx | 18 ++------ 2 files changed, 50 insertions(+), 14 deletions(-) create mode 100644 apps/jurumarble/src/app/main/components/Banner.tsx diff --git a/apps/jurumarble/src/app/main/components/Banner.tsx b/apps/jurumarble/src/app/main/components/Banner.tsx new file mode 100644 index 00000000..2864e860 --- /dev/null +++ b/apps/jurumarble/src/app/main/components/Banner.tsx @@ -0,0 +1,46 @@ +import styled, { css } from "styled-components"; +import Image from "next/image"; +import { MainBannerImage } from "public/images"; + +function Banner() { + return ( + + 배너 + + 여행의 즐거움을 우리술과 함께 레벨업! + + 여행지에서 우리술이 고민된다면
주루마블에서 해결해보세요 +
+
+
+ ); +} + +const Container = styled.div` + position: relative; + margin-top: 12px; + aspect-ratio: 16 / 9; +`; + +const BannerText = styled.div` + position: relative; + display: flex; + flex-direction: column; + justify-content: center; + height: 100%; + padding: 20px; +`; + +const MainText = styled.div` + ${({ theme }) => css` + ${theme.typography.headline03} + `}; +`; + +const SubText = styled.div` + ${({ theme }) => css` + ${theme.typography.body_long03} + margin-top: 8px; + `}; +`; +export default Banner; diff --git a/apps/jurumarble/src/app/page.tsx b/apps/jurumarble/src/app/page.tsx index 382acfd0..d651d314 100644 --- a/apps/jurumarble/src/app/page.tsx +++ b/apps/jurumarble/src/app/page.tsx @@ -3,24 +3,20 @@ import BottomBar from "components/BottomBar"; import DivideLine from "components/DivideLine"; import Header from "components/Header"; -import { KAKAO_MAP_API_KEY } from "lib/constants"; -import Image from "next/image"; -import Script from "next/script"; -import { MainBannerImage } from "public/images"; import styled from "styled-components"; +import Banner from "./main/components/Banner"; import HotDrinkContainer from "./main/components/HotDrinkContainer"; import HotDrinkVoteContainer from "./main/components/HotDrinkVoteContainer"; import SearchInputWrapper from "./main/components/SearchInputWrapper"; +import TodayDrinkRecommendation from "./main/components/TodayDrinkRecommendation"; function MainPage() { return ( <>
- + - - 배너 - + @@ -37,12 +33,6 @@ const TopSection = styled.section` padding: 0 20px; `; -const BannerImageWrapper = styled.div` - position: relative; - margin-top: 36px; - aspect-ratio: 16 / 9; -`; - const BottomSection = styled.section` padding: 0 20px 96px; // 64(BottomBar height) + 32(margin) = 96 margin-top: 8px; From aaa337164b33ff0cf6564aee1404d01e6014e17f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A2=E1=84=92=E1=85=A1?= Date: Sun, 15 Oct 2023 22:09:00 +0900 Subject: [PATCH 4/8] =?UTF-8?q?feat:=20=EC=9D=B4=EC=A0=84=20=EB=8B=A4?= =?UTF-8?q?=EC=9D=8C=20=EC=95=84=EC=9D=B4=EC=BD=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/assets/icons/components/IcNext.tsx | 45 ++++++++++++++++ .../assets/icons/components/IcPrevious.tsx | 53 +++++++++++-------- .../src/assets/icons/components/index.ts | 1 + 3 files changed, 77 insertions(+), 22 deletions(-) create mode 100644 apps/jurumarble/src/assets/icons/components/IcNext.tsx diff --git a/apps/jurumarble/src/assets/icons/components/IcNext.tsx b/apps/jurumarble/src/assets/icons/components/IcNext.tsx new file mode 100644 index 00000000..9b7717b8 --- /dev/null +++ b/apps/jurumarble/src/assets/icons/components/IcNext.tsx @@ -0,0 +1,45 @@ +import type { SVGProps } from "react"; +const SvgNext = (props: SVGProps) => ( + + + + + + + + + + +); +export default SvgNext; diff --git a/apps/jurumarble/src/assets/icons/components/IcPrevious.tsx b/apps/jurumarble/src/assets/icons/components/IcPrevious.tsx index eaf7f7b1..a25a6a69 100644 --- a/apps/jurumarble/src/assets/icons/components/IcPrevious.tsx +++ b/apps/jurumarble/src/assets/icons/components/IcPrevious.tsx @@ -1,33 +1,42 @@ import type { SVGProps } from "react"; -const SvgIcPrevious = (props: SVGProps) => ( +const SvgPrevious = (props: SVGProps) => ( - - - - - + + + + + + + ); -export default SvgIcPrevious; +export default SvgPrevious; diff --git a/apps/jurumarble/src/assets/icons/components/index.ts b/apps/jurumarble/src/assets/icons/components/index.ts index e4a1e98e..897ec1f8 100644 --- a/apps/jurumarble/src/assets/icons/components/index.ts +++ b/apps/jurumarble/src/assets/icons/components/index.ts @@ -26,3 +26,4 @@ export { default as SvgIcThunder } from "./IcThunder"; export { default as SvgWarningIcon } from "./IcWarningIcon"; export { default as SvgNotificationCheck } from "./IcNotificationCheck"; export { default as SvgInfo } from "./IcInfo"; +export { default as SvgNext } from "./IcNext"; From a1433477a929ffc65cc1ab5d3b768827a17be48a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A2=E1=84=92=E1=85=A1?= Date: Sun, 15 Oct 2023 22:09:30 +0900 Subject: [PATCH 5/8] =?UTF-8?q?fix:=20=ED=82=A4=EA=B0=92=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/TodayDrinkRecommendation.tsx | 23 ++++++++++--------- .../app/map/components/RegionBottomsheet.tsx | 1 - 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/jurumarble/src/app/main/components/TodayDrinkRecommendation.tsx b/apps/jurumarble/src/app/main/components/TodayDrinkRecommendation.tsx index 919af196..b35cf607 100644 --- a/apps/jurumarble/src/app/main/components/TodayDrinkRecommendation.tsx +++ b/apps/jurumarble/src/app/main/components/TodayDrinkRecommendation.tsx @@ -5,9 +5,7 @@ import useGetDrinkRecommendationListService from "../services/useGetDrinkRecomme const SLIDE_MOVE_COUNT = 1; const ORIGINAL_IMAGE_LENGTH = 10; -const IMAGE_HEIGHT = 18; - -const getRandom = (min: number, max: number) => Math.floor(Math.random() * (max - min + 1) + min); +const MOVE_DISTANCE = 20; function TodayDrinkRecommendation() { const theme = useTheme(); @@ -29,7 +27,7 @@ function TodayDrinkRecommendation() { setTimeout(() => { setIsAnimation(false); slideRef.current!.style.transform = `translateY(-${ - IMAGE_HEIGHT * ORIGINAL_IMAGE_LENGTH + MOVE_DISTANCE * ORIGINAL_IMAGE_LENGTH }px)`; setCurrentSlide(1); }, 500); @@ -38,7 +36,7 @@ function TodayDrinkRecommendation() { setIsAnimation(true); }, 600); } - slideRef.current.style.transform = `translateY(-${IMAGE_HEIGHT * (currentSlide - 1)}px)`; + slideRef.current.style.transform = `translateY(-${MOVE_DISTANCE * (currentSlide - 1)}px)`; }, [currentSlide]); useEffect(() => { @@ -58,9 +56,9 @@ function TodayDrinkRecommendation() { 오늘의 우리술 추천 - {drinkRecommendationList?.map(({ 전통주명 }) => { - return {전통주명}; - })} + {drinkRecommendationList?.map(({ 전통주명 }) => ( + {전통주명} + ))} ); @@ -69,9 +67,10 @@ function TodayDrinkRecommendation() { const Container = styled.div` display: flex; align-items: center; - overflow: hidden; padding: 0 20px; margin-top: 8px; + gap: 8px; + overflow: hidden; `; const Slider = styled.div<{ isAnimation: boolean }>` @@ -79,7 +78,8 @@ const Slider = styled.div<{ isAnimation: boolean }>` flex-direction: column; height: 18px; transition: transform 0.5s ease-in-out; - ${({ isAnimation }) => isAnimation && `transform: translateY(-${IMAGE_HEIGHT}px);`} + gap: 2px; + ${({ isAnimation }) => isAnimation && `transform: translateY(-${MOVE_DISTANCE}px);`} `; const H3 = styled.h3` @@ -89,12 +89,13 @@ const H3 = styled.h3` display: flex; align-items: center; gap: 2px; + overflow: hidden; + white-space: nowrap; `}; `; const DrinkName = styled.span` ${({ theme }) => theme.typography.body03}; - margin-left: 8px; `; export default TodayDrinkRecommendation; diff --git a/apps/jurumarble/src/app/map/components/RegionBottomsheet.tsx b/apps/jurumarble/src/app/map/components/RegionBottomsheet.tsx index 8b3bcbf8..ee9f5931 100644 --- a/apps/jurumarble/src/app/map/components/RegionBottomsheet.tsx +++ b/apps/jurumarble/src/app/map/components/RegionBottomsheet.tsx @@ -1,7 +1,6 @@ import { Button, Portal } from "components/index"; import { REGION_LIST } from "lib/constants"; import { transitions } from "lib/styles"; -import Image from "next/image"; import React from "react"; import { SvgIcPrev, SvgIcX } from "src/assets/icons/components"; import styled, { css } from "styled-components"; From 25bcb460ab70777f4653ae686bf495a073d91959 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A2=E1=84=92=E1=85=A1?= Date: Sun, 15 Oct 2023 22:19:30 +0900 Subject: [PATCH 6/8] =?UTF-8?q?fix:=20=ED=9B=85=EC=9D=98=20=EA=B7=9C?= =?UTF-8?q?=EC=B9=99=EC=9D=84=20=EC=9C=84=EB=B0=98=ED=95=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/app/main/components/HotDrinkVoteContainer.tsx | 8 ++++---- .../src/app/main/services/useGetHotDrinkVoteService.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/jurumarble/src/app/main/components/HotDrinkVoteContainer.tsx b/apps/jurumarble/src/app/main/components/HotDrinkVoteContainer.tsx index 5935a8ab..bf05e57a 100644 --- a/apps/jurumarble/src/app/main/components/HotDrinkVoteContainer.tsx +++ b/apps/jurumarble/src/app/main/components/HotDrinkVoteContainer.tsx @@ -5,16 +5,16 @@ import styled, { css } from "styled-components"; import useGetHotDrinkVoteService from "../services/useGetHotDrinkVoteService"; function HotDrinkVoteContainer() { - const { data: hotDrinkVote } = useGetHotDrinkVoteService(); + const router = useRouter(); + + const { hotDrinkVote } = useGetHotDrinkVoteService(); if (!hotDrinkVote) { - return null; + return; } const { voteId, voteTitle, drinkAImage, drinkBImage } = hotDrinkVote; const nowTime = new Date().getHours(); - const router = useRouter(); - return ( <>

diff --git a/apps/jurumarble/src/app/main/services/useGetHotDrinkVoteService.ts b/apps/jurumarble/src/app/main/services/useGetHotDrinkVoteService.ts index 52bf713e..0e484036 100644 --- a/apps/jurumarble/src/app/main/services/useGetHotDrinkVoteService.ts +++ b/apps/jurumarble/src/app/main/services/useGetHotDrinkVoteService.ts @@ -5,7 +5,7 @@ import { queryKeys } from "lib/queryKeys"; const getQueryKey = () => [queryKeys.HOT_DRINK_VOTE]; export default function useGetHotDrinkVoteService() { - const { data } = useQuery(getQueryKey(), getHotDrinkVote); + const { data: hotDrinkVote } = useQuery(getQueryKey(), getHotDrinkVote); - return { data }; + return { hotDrinkVote }; } From de127fe8cea4790af23a23c74153b6187fe5b776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A2=E1=84=92=E1=85=A1?= Date: Sun, 15 Oct 2023 22:19:52 +0900 Subject: [PATCH 7/8] =?UTF-8?q?feat:=20=EC=BA=90=EB=9F=AC=EC=85=80=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=EC=9D=84=20=ED=81=B4=EB=A6=AD=ED=95=98?= =?UTF-8?q?=EC=97=AC=20=EC=A1=B0=EC=9E=91=ED=95=A0=20=EC=88=98=20=EC=9E=88?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/app/main/components/Carousel.tsx | 157 +++++++++++++++--- apps/jurumarble/src/app/page.tsx | 11 +- 2 files changed, 139 insertions(+), 29 deletions(-) diff --git a/apps/jurumarble/src/app/main/components/Carousel.tsx b/apps/jurumarble/src/app/main/components/Carousel.tsx index db0286e0..c9350f90 100644 --- a/apps/jurumarble/src/app/main/components/Carousel.tsx +++ b/apps/jurumarble/src/app/main/components/Carousel.tsx @@ -3,6 +3,12 @@ import Path from "lib/Path"; import Image from "next/image"; import { useRouter } from "next/navigation"; import styled, { css } from "styled-components"; +import { useCallback, useEffect, useRef, useState } from "react"; +import { SvgIcPrevious, SvgNext } from "src/assets/icons/components"; + +const SLIDE_MOVE_COUNT = 1; +const ORIGINAL_IMAGE_LENGTH = 10; +const MOVE_DISTANCE = 300; interface Props { hotDrinkList: GetHotDrinkResponse[]; @@ -10,42 +16,112 @@ interface Props { function Carousel({ hotDrinkList }: Props) { const router = useRouter(); + const slideRef = useRef(null); + const [currentSlide, setCurrentSlide] = useState(1); + const [isAnimation, setIsAnimation] = useState(true); + const [isFlowing, setIsFlowing] = useState(true); + + const onNextSlide = useCallback(() => { + setCurrentSlide((prev) => prev + SLIDE_MOVE_COUNT); + }, [currentSlide]); + + const onPrevSlide = useCallback(() => { + setCurrentSlide((prev) => prev - SLIDE_MOVE_COUNT); + }, [currentSlide]); + + useEffect(() => { + if (!slideRef.current) return; + + if (currentSlide === ORIGINAL_IMAGE_LENGTH + 1) { + setTimeout(() => { + setIsAnimation(false); + slideRef.current!.style.transform = `translateX(-${ + MOVE_DISTANCE * ORIGINAL_IMAGE_LENGTH + }px)`; + setCurrentSlide(1); + }, 500); + + setTimeout(() => { + setIsAnimation(true); + }, 600); + } else if (currentSlide === 0) { + setTimeout(() => { + setIsAnimation(false); + slideRef.current!.style.transform = `translateX(+${MOVE_DISTANCE}px)`; + setCurrentSlide(ORIGINAL_IMAGE_LENGTH); + }, 500); + + setTimeout(() => { + setIsAnimation(true); + }, 600); + } + slideRef.current.style.transform = `translateX(-${MOVE_DISTANCE * (currentSlide - 1)}px)`; + }, [currentSlide]); + + useEffect(() => { + let intervalId: NodeJS.Timeout; + if (isFlowing) { + intervalId = setInterval(() => { + setCurrentSlide((prev) => prev + SLIDE_MOVE_COUNT); + }, 3500); + } + return () => clearTimeout(intervalId); + }, [isFlowing, currentSlide]); + return ( - - - {hotDrinkList.map((hotDrink: GetHotDrinkResponse, index: number) => { - const { drinkId, image, name, manufactureAddress } = hotDrink; - return ( - router.push(`${Path.DRINK_INFO_PAGE}/${drinkId}`)}> - - - {index + 1} - 전통주 - - - {name} - {manufactureAddress} - - - - ); - })} - - + <> + + + {hotDrinkList.map((hotDrink: GetHotDrinkResponse, index: number) => { + const { drinkId, image, name, manufactureAddress } = hotDrink; + return ( + router.push(`${Path.DRINK_INFO_PAGE}/${drinkId}`)} + > + + + {index + 1} + 전통주 + + + {name} + {manufactureAddress} + + + + ); + })} + + + + + + + + + + + + + + ); } const Container = styled.div` - height: 188px; margin-top: 32px; + overflow: hidden; `; -const Slides = styled.ol` +const Slides = styled.ol<{ isAnimation: boolean }>` display: flex; - height: 168px; - overflow-x: auto; - scroll-snap-type: x mandatory; + /* overflow-x: auto; + scroll-snap-type: x mandatory; */ gap: 8px; + transition: transform 0.5s ease-in-out; + ${({ isAnimation }) => isAnimation && `transform: translateX(-${MOVE_DISTANCE}px);`} + /** @Todo 모바일에서는 보이게 하기 **/ @@ -60,7 +136,7 @@ const Slide = styled.li` width: 292px; height: 120px; padding-top: 20px; - scroll-snap-align: start; + /* scroll-snap-align: start; */ cursor: pointer; `; @@ -120,4 +196,31 @@ const AreaName = styled.span` `} `; +const CarouselControlContainer = styled.div` + margin-top: 28px; + display: flex; + align-items: center; + gap: 20px; +`; + +const DivideLine = styled.div` + ${({ theme }) => css` + background-color: ${theme.colors.line_01}; + height: 2px; + width: 100%; + `} +`; + +const SlideButtonContainer = styled.div` + display: flex; + gap: 10px; +`; + +const SlideButton = styled.button` + border-radius: 100px; + border: 1px solid ${({ theme }) => theme.colors.line_01}; + width: 40px; + height: 40px; +`; + export default Carousel; diff --git a/apps/jurumarble/src/app/page.tsx b/apps/jurumarble/src/app/page.tsx index d651d314..c2239b55 100644 --- a/apps/jurumarble/src/app/page.tsx +++ b/apps/jurumarble/src/app/page.tsx @@ -1,9 +1,8 @@ "use client"; import BottomBar from "components/BottomBar"; -import DivideLine from "components/DivideLine"; import Header from "components/Header"; -import styled from "styled-components"; +import styled, { css } from "styled-components"; import Banner from "./main/components/Banner"; import HotDrinkContainer from "./main/components/HotDrinkContainer"; import HotDrinkVoteContainer from "./main/components/HotDrinkVoteContainer"; @@ -39,4 +38,12 @@ const BottomSection = styled.section` overflow: auto; `; +const DivideLine = styled.div` + ${({ theme }) => css` + background-color: ${theme.colors.bg_01}; + height: 8px; + margin: 40px 0 8px 0; + `} +`; + export default MainPage; From 32d433510b2fef1ad8101d6b32d04fb2e8203e25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=A2=E1=84=92=E1=85=A1?= Date: Sun, 15 Oct 2023 22:24:25 +0900 Subject: [PATCH 8/8] =?UTF-8?q?fix:=20undefined=20=EC=B2=98=EB=A6=AC?= =?UTF-8?q?=EB=90=98=EC=96=B4=20=EC=97=90=EB=9F=AC=EB=82=98=EB=8D=98=20?= =?UTF-8?q?=EA=B2=83=20null=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/app/main/components/HotDrinkVoteContainer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/jurumarble/src/app/main/components/HotDrinkVoteContainer.tsx b/apps/jurumarble/src/app/main/components/HotDrinkVoteContainer.tsx index bf05e57a..790b540b 100644 --- a/apps/jurumarble/src/app/main/components/HotDrinkVoteContainer.tsx +++ b/apps/jurumarble/src/app/main/components/HotDrinkVoteContainer.tsx @@ -9,7 +9,7 @@ function HotDrinkVoteContainer() { const { hotDrinkVote } = useGetHotDrinkVoteService(); if (!hotDrinkVote) { - return; + return null; } const { voteId, voteTitle, drinkAImage, drinkBImage } = hotDrinkVote;