From a32c7706e5eccbdd990043c439753bafd4c76c45 Mon Sep 17 00:00:00 2001 From: Hyeonsu Kim <86764406+borimong@users.noreply.github.com> Date: Fri, 30 Aug 2024 12:26:26 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B4=91=EA=B3=A0=20=EA=B5=AC=EC=A2=8C=20QA=20?= =?UTF-8?q?(#826)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * upgrade: api 업데이트 * feat: 피드 광고 인터랙션 추가, 캐러셀 요소 랜덤 순서로 보여주기, 하나의 캐러셀에 여러 링크 추가 * feat: 전체모임 페이지네이션 방식 변경 (첫 페이지 take 개수 변경) * fix: after loading 스크롤 복원 훅 fix --- src/__generated__/schema2.d.ts | 25 ++-- src/api/API_LEGACY/meeting/index.ts | 2 +- .../meetingList/Advertisement/AdCarousel.tsx | 115 +++++++++++------- .../page/meetingList/Advertisement/index.tsx | 8 +- src/components/page/meetingList/Grid/List.tsx | 8 +- src/hooks/useScrollRestoration.ts | 5 +- 6 files changed, 91 insertions(+), 72 deletions(-) diff --git a/src/__generated__/schema2.d.ts b/src/__generated__/schema2.d.ts index 3aa5f4c2..57469e4e 100644 --- a/src/__generated__/schema2.d.ts +++ b/src/__generated__/schema2.d.ts @@ -1853,26 +1853,25 @@ export interface components { /** @description 광고 구좌 조회 응답 Dto */ AdvertisementGetResponseDto: { /** @description 광고 구좌 이미지 객체 */ - advertisementImages: components["schemas"]["AdvertisementImageDto"][]; - /** - * @description 광고 구좌 링크 - * @example https://www.naver.com - */ - advertisementLink: string; + advertisements: components["schemas"]["AdvertisementImageDto"][]; }; /** @description 광고 구좌 이미지 Dto */ AdvertisementImageDto: { /** - * @description 광고 구좌 이미지 url - * @example [url 형식] + * @description [Desktop] 광고 구좌 이미지 url + * @example [pc 버전 url 형식] */ - imageUrl: string; + desktopImageUrl: string; /** - * Format: int32 - * @description 광고 이미지 순서, 서버에서 정렬해서 전달한다.
프론트에서 확인용으로 사용하기 위함 - * @example 2 + * @description [mobile] 광고 구좌 이미지 url + * @example [mobile 버전 url 형식] */ - imageOrder: number; + mobileImageUrl: string; + /** + * @description 광고 구좌 링크 + * @example https://www.naver.com + */ + advertisementLink: string; }; }; responses: never; diff --git a/src/api/API_LEGACY/meeting/index.ts b/src/api/API_LEGACY/meeting/index.ts index 21f8338d..06b85f36 100644 --- a/src/api/API_LEGACY/meeting/index.ts +++ b/src/api/API_LEGACY/meeting/index.ts @@ -156,7 +156,7 @@ export const fetchMeetingListOfAll = async ({ part, }: filterData) => { return api.get>( - `/meeting?${page ? `&page=${page}` : ''}${ + `/meeting?${page ? `&page=${page}` : ''}${page === 1 ? `&take=${11}` : `&take=${12}`}${ status?.length ? `&status=${status .map(item => parseStatusToNumber(item, RECRUITMENT_STATUS)) diff --git a/src/components/page/meetingList/Advertisement/AdCarousel.tsx b/src/components/page/meetingList/Advertisement/AdCarousel.tsx index d82dd35d..eb964e5f 100644 --- a/src/components/page/meetingList/Advertisement/AdCarousel.tsx +++ b/src/components/page/meetingList/Advertisement/AdCarousel.tsx @@ -1,4 +1,4 @@ -import React, { useCallback } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { EmblaOptionsType, EmblaCarouselType } from 'embla-carousel'; import { DotButton, useDotButton } from './AdCarouselDotBtn'; import { PrevButton, NextButton, usePrevNextButtons } from './AdCarouselArrowBtn'; @@ -10,13 +10,25 @@ import Link from 'next/link'; import { useDisplay } from '@hooks/useDisplay'; type PropType = { - slides: paths['/advertisement/v2']['get']['responses']['200']['content']['application/json;charset=UTF-8']['advertisementImages']; - link: paths['/advertisement/v2']['get']['responses']['200']['content']['application/json;charset=UTF-8']['advertisementLink']; + slides: paths['/advertisement/v2']['get']['responses']['200']['content']['application/json;charset=UTF-8']['advertisements']; options?: EmblaOptionsType; }; const AdCarousel: React.FC = props => { - const { slides, link, options } = props; + const { slides, options } = props; + + const shuffledSlides = useMemo(() => { + const shuffleArray = (array: typeof slides) => { + for (let i = array.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [array[i], array[j]] = [array[j], array[i]]; + } + return array; + }; + + return shuffleArray([...slides]); + }, [slides]); + const { isDesktop } = useDisplay(); const [emblaRef, emblaApi] = useEmblaCarousel(options, [Autoplay()]); @@ -37,51 +49,51 @@ const AdCarousel: React.FC = props => { ); return ( - -
- - - - {slides?.map((slide, index) => ( +
+ + + + {shuffledSlides?.map((slide, index) => ( + - + + + ))} + + + + {isDesktop ? ( + <> + e.preventDefault()}> + + + + e.preventDefault()}> + {scrollSnaps.map((_, index) => ( + onDotButtonClick(index)} + className={'embla__dot'.concat(index === selectedIndex ? ' embla__dot--selected' : '')} + /> ))} - - - - {isDesktop ? ( - <> - e.preventDefault()}> - - - - e.preventDefault()}> - {scrollSnaps.map((_, index) => ( - onDotButtonClick(index)} - className={'embla__dot'.concat(index === selectedIndex ? ' embla__dot--selected' : '')} - /> - ))} - - - ) : ( -
- e.preventDefault()}> - {scrollSnaps.map((_, index) => ( - onDotButtonClick(index)} - className={'embla__dot'.concat(index === selectedIndex ? ' embla__dot--selected' : '')} - /> - ))} - -
- )} -
-
- + + + ) : ( +
+ e.preventDefault()}> + {scrollSnaps.map((_, index) => ( + onDotButtonClick(index)} + className={'embla__dot'.concat(index === selectedIndex ? ' embla__dot--selected' : '')} + /> + ))} + +
+ )} +
+
); }; @@ -90,6 +102,7 @@ export default AdCarousel; export const Embla = styled('div', { width: '380px', height: '380px', + '@mobile': { width: '320px', height: '320px', @@ -98,11 +111,18 @@ export const Embla = styled('div', { width: '280px', height: '280px', }, + + transition: 'transform 0.3s ease', + '&:hover': { + transform: 'translateY(-10px)', + }, }); export const EmblaViewport = styled('div', { - overflow: 'hidden', borderRadius: '12px', + overflow: 'hidden', + '-webkit-backface-visibility': 'hidden', + '-webkit-transform': 'translate3d(0, 0, 0)', }); export const EmblaContainer = styled('div', { @@ -121,6 +141,7 @@ export const EmblaSlideImage = styled('img', { userSelect: 'none', width: '380px', height: '380px', + '@mobile': { width: '320px', height: '320px', diff --git a/src/components/page/meetingList/Advertisement/index.tsx b/src/components/page/meetingList/Advertisement/index.tsx index 7c4088f9..22916992 100644 --- a/src/components/page/meetingList/Advertisement/index.tsx +++ b/src/components/page/meetingList/Advertisement/index.tsx @@ -70,9 +70,7 @@ const RenderPostsWithAds = () => { ); })} - {postAds && ( - - )} + {postAds && } {postsData?.pages.slice(3).map(post => { if (!post) return; return ( @@ -142,9 +140,7 @@ const RenderPostsWithAds = () => { ); })} - {postAds && ( - - )} + {postAds && } {postsData?.pages.slice(3).map(post => { if (!post) return; diff --git a/src/components/page/meetingList/Grid/List.tsx b/src/components/page/meetingList/Grid/List.tsx index 364de235..ea564929 100644 --- a/src/components/page/meetingList/Grid/List.tsx +++ b/src/components/page/meetingList/Grid/List.tsx @@ -31,16 +31,16 @@ export function MeetingListOfAll() { ))} - {meetingAds && ( - + {meetingAds && meetingListData?.meta.page === 1 && ( + {isDesktop ? ( ) : ( )} diff --git a/src/hooks/useScrollRestoration.ts b/src/hooks/useScrollRestoration.ts index 0409af26..d3b22b19 100644 --- a/src/hooks/useScrollRestoration.ts +++ b/src/hooks/useScrollRestoration.ts @@ -36,7 +36,10 @@ export default function useScrollRestoration() { } export const restoreScrollPosition = (router: NextRouter) => { - const scrollPos = JSON.parse(sessionStorage.getItem(router.asPath) || '{"x": 0, "y": 0}'); + //const scrollPos = JSON.parse(sessionStorage.getItem(router.asPath) || '{"x": 0, "y": 0}'); + const scrollPos = JSON.parse('{"x": 0, "y": 0}'); // router.asPath 가 기록된 경우, 페이지 재진입 시 scroll 이 아래쪽으로 기억되어 있는 문제가 발생 + + console.log(scrollPos); window.scroll(scrollPos.x, scrollPos.y); };