From 054c669f0152fb4bef6ec3211d945419c961fd22 Mon Sep 17 00:00:00 2001 From: Donghun Shin Date: Mon, 25 Sep 2023 14:27:50 +0900 Subject: [PATCH] =?UTF-8?q?release:=20=ED=94=84=EB=A1=A0=ED=8A=B8=EC=97=94?= =?UTF-8?q?=EB=93=9C=20v3.3=20(#515)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 지도 마커 및 음식점 카드 렌더링 시 깜빡임 현상 개선 (#497) * feat: Portal 컴포넌트 제작 * refactor: Modal 컴포넌트 Content와 합친 후 변경사항 대응 (#490) * Squashed commit of the following: commit 32a34b6a65e72630c5ec5f1973bc1ff1acb7841f Author: 황준승 <78203399+turtle601@users.noreply.github.com> Date: Wed Sep 20 14:40:45 2023 +0900 feat: 이미지 최적화 (#485) * feat: 사용하지 않는 .png 파일 제거 (#478) * refactor: Webpack 파일 리팩토링 (#478) * refactor: 불필요한 코드 구문 제거 (#478) 타입스크립트 컴파일은 ts loader로만으로도 충분 * refactor: devDependency vs Dependency 라이브러리 분리 (#478) * refactor: 불필요한 코드 삭제 (#478) Changed: 불필요한 optimize 구문 삭제' * feat: picture 태그를 활용한 이미지 최적화 (#478) * refactor: 불필요한 react.memo 제거 (#478) * feat: 이미지 url 관련 유틸함수 구현 (#478) * feat: 폰트 리로드 적용 (#478) * feat: video lazy로딩 적용 (#478) * fix: restaurants mock 데이터 수정(#478) Changed: .jpeg 삭제 * refactor: 불필요한 폰트 리로딩, lazy loading 제거 (#478) * fix: react-query-devtools 디펜던시 오류 해결 (#478) * fix: 빌드 시 lint 오류 해결 (#478) Changed: eslint 설정에 dependency 설정 끔 commit 276eec9f9fa225f08639947a037b8d2b5daebd74 Author: Minjae Kim Date: Wed Sep 20 14:38:43 2023 +0900 feat: loading 상태에 필요한 skeleton 제작 (#488) * feat: 데이터 추가 mock api 연결 * refactor: 인증 필요 없는 기능 client 변경 * feat: mse 동영상, 리뷰 기능 구현 (#472) * refactor: api 훅 함수로 분리, 적용 (#472) * refactor: 쓰지 않는 파일 삭제 (#472) * fix: console log 삭제 (#472) * Squashed commit of the following: commit 6e0068735b155b95ec45de7fd78eb241993dc513 Author: Jeremy <102432453+shackstack@users.noreply.github.com> Date: Fri Sep 15 17:18:33 2023 +0900 bug: 옵션관련 ux 개선 (#474) * fix: 검색창 옵션 수정 (#473) * fix: 지도 줌 limit 설정 (#473) * fix: 모바일 환경에서 거리순으로 설정 (#473) * design: 오버레이 마커 디자인 개선 (#473) * fix: 오류 수정 (#476) * refactor: useScrollBlock 보강 (#476) * refactor: 모바일 페이지 컴포넌트 분리 (#476) * refactor: 라우터 재설정 (#476) * fix: 잘못된 import 수정 (#476) * refactor: router 및 outlet 새로 설정 (#476) * feat: NavBar 관련 Skeleton 제작 (#480) * feat: NavBar 관련 Skeleton 제작 (#480) * refactor: navBarSkeleton의 NavItem 개수를 props로 받도록 설정 (#480) * refactor: Login 관련 Modal 자체 모달로 분리 (#490) * refactor: 리뷰 관련 모달 로직 수정 (#490) * Squashed commit of the following: commit ac40d18c9959fb488c8bded376ff554429bbf712 Author: 황준승 <78203399+turtle601@users.noreply.github.com> Date: Wed Sep 20 16:01:35 2023 +0900 [✨feat] 폰트 + 이미지 최적화 (#491) * feat: 사용하지 않는 .png 파일 제거 (#478) * refactor: Webpack 파일 리팩토링 (#478) * refactor: 불필요한 코드 구문 제거 (#478) 타입스크립트 컴파일은 ts loader로만으로도 충분 * refactor: devDependency vs Dependency 라이브러리 분리 (#478) * refactor: 불필요한 코드 삭제 (#478) Changed: 불필요한 optimize 구문 삭제' * feat: picture 태그를 활용한 이미지 최적화 (#478) * refactor: 불필요한 react.memo 제거 (#478) * feat: 이미지 url 관련 유틸함수 구현 (#478) * feat: 폰트 리로드 적용 (#478) * feat: video lazy로딩 적용 (#478) * fix: restaurants mock 데이터 수정(#478) Changed: .jpeg 삭제 * refactor: 불필요한 폰트 리로딩, lazy loading 제거 (#478) * feat: 폰트 preload 최적화 (#487) * refactor: devDependency 허용하는 eslint 설정 추가 (#487) * fix: webp이미지 불러오지 못하는 오류 해결 (#487) * refactor: 불필요한 코드 삭제 (#478) Changed: ${} 삭제 * refactor: url 전역 변수 선언 (#487) * refactor: React.MouseEvent 코드 컨벤션 수정 (#487) * fix: 이미지 .. 붙여지는 오류 해결 (#487) * fix: react-query devtools 디펜던시 lint 에러 해결 (#487) commit 32a34b6a65e72630c5ec5f1973bc1ff1acb7841f Author: 황준승 <78203399+turtle601@users.noreply.github.com> Date: Wed Sep 20 14:40:45 2023 +0900 feat: 이미지 최적화 (#485) * feat: 사용하지 않는 .png 파일 제거 (#478) * refactor: Webpack 파일 리팩토링 (#478) * refactor: 불필요한 코드 구문 제거 (#478) 타입스크립트 컴파일은 ts loader로만으로도 충분 * refactor: devDependency vs Dependency 라이브러리 분리 (#478) * refactor: 불필요한 코드 삭제 (#478) Changed: 불필요한 optimize 구문 삭제' * feat: picture 태그를 활용한 이미지 최적화 (#478) * refactor: 불필요한 react.memo 제거 (#478) * feat: 이미지 url 관련 유틸함수 구현 (#478) * feat: 폰트 리로드 적용 (#478) * feat: video lazy로딩 적용 (#478) * fix: restaurants mock 데이터 수정(#478) Changed: .jpeg 삭제 * refactor: 불필요한 폰트 리로딩, lazy loading 제거 (#478) * fix: react-query-devtools 디펜던시 오류 해결 (#478) * fix: 빌드 시 lint 오류 해결 (#478) Changed: eslint 설정에 dependency 설정 끔 commit 276eec9f9fa225f08639947a037b8d2b5daebd74 Author: Minjae Kim Date: Wed Sep 20 14:38:43 2023 +0900 feat: loading 상태에 필요한 skeleton 제작 (#488) * feat: 데이터 추가 mock api 연결 * refactor: 인증 필요 없는 기능 client 변경 * feat: mse 동영상, 리뷰 기능 구현 (#472) * refactor: api 훅 함수로 분리, 적용 (#472) * refactor: 쓰지 않는 파일 삭제 (#472) * fix: console log 삭제 (#472) * Squashed commit of the following: commit 6e0068735b155b95ec45de7fd78eb241993dc513 Author: Jeremy <102432453+shackstack@users.noreply.github.com> Date: Fri Sep 15 17:18:33 2023 +0900 bug: 옵션관련 ux 개선 (#474) * fix: 검색창 옵션 수정 (#473) * fix: 지도 줌 limit 설정 (#473) * fix: 모바일 환경에서 거리순으로 설정 (#473) * design: 오버레이 마커 디자인 개선 (#473) * fix: 오류 수정 (#476) * refactor: useScrollBlock 보강 (#476) * refactor: 모바일 페이지 컴포넌트 분리 (#476) * refactor: 라우터 재설정 (#476) * fix: 잘못된 import 수정 (#476) * refactor: router 및 outlet 새로 설정 (#476) * feat: NavBar 관련 Skeleton 제작 (#480) * feat: NavBar 관련 Skeleton 제작 (#480) * refactor: navBarSkeleton의 NavItem 개수를 props로 받도록 설정 (#480) * chore: lock 파일 변경 (#490) * fix: lint 에러 수정 (#490) * refactor: 낌빡임 문제 개선 (#493) * Merge commit '57d8e0a921e135ab059264663078c21bd8b6403f' * fix: 웹 폰트 로드 전 대체제 넣기 (#500) * fix: 웹 폰트 로드 전 대체제 넣기 (#499) * fix: loadingIndicator, header 겹침 현상 오류 해결(#498) * fix: webpack analyzer 적용(#499) * fix: 잘못된 api 인스턴스 수정 (#499) --------- Co-authored-by: Jeremy <102432453+shackstack@users.noreply.github.com> * fix: 잘못된 api 명세로 인한 코드 수정 (#504) * fix: 웹 폰트 로드 전 대체제 넣기 (#499) * fix: loadingIndicator, header 겹침 현상 오류 해결(#498) * fix: webpack analyzer 적용(#499) * fix: 잘못된 api 인스턴스 수정 (#499) * fix: api 명세 오류로 인한 코드 수정 (#503) * refactor: 불필요한 주석 제거 (#503) * refactor: root파일 트리 쉐이킹 적용(#503) * refactor: 번들 사이즈 최적화 (#507) * style: style import 통일 시키기 (#506) * refactor: Root 컴포넌트 lazy 적용 (#506) * fix: 머지과정에서 발생한 ci 오류 해결 (#506) * fix: conflict 충돌로 인한 코드 오류 수정 (#514) --------- Co-authored-by: Minjae Kim Co-authored-by: 황준승 <78203399+turtle601@users.noreply.github.com> Co-authored-by: Jeremy <102432453+shackstack@users.noreply.github.com> --- frontend/.webpack/webpack.config.js | 4 ++++ frontend/src/api/restaurant.ts | 15 ++++++++----- frontend/src/assets/fonts/font.css | 3 +++ .../src/components/@common/Footer/Footer.tsx | 2 +- .../@common/Header/MobileHeader.tsx | 2 +- .../@common/ImageCarousel/ImageCarousel.tsx | 2 +- .../@common/InfoButton/InfoButton.tsx | 2 +- .../@common/LoadingDots/LoadingDots.tsx | 2 +- .../LoadingIndicator/LoadingIndicator.tsx | 2 +- .../@common/LoginButton/LoginButton.tsx | 2 +- frontend/src/components/@common/Map/Map.tsx | 19 ++++++++++++++-- .../components/@common/Map/OverlayMarker.tsx | 13 ++++++++--- .../@common/Map/OverlayMarkerList.tsx | 18 +++++++++++---- .../@common/Map/OverlayMyLocation.tsx | 2 +- .../src/components/@common/Modal/Modal.tsx | 2 +- .../components/@common/NavItem/NavItem.tsx | 2 +- .../@common/NavItem/NavItemSkeleton.tsx | 2 +- .../@common/PageNationBar/PageNationBar.tsx | 2 +- .../@common/ProfileImage/ProfileImage.tsx | 2 ++ .../@common/WaterMarkImage/WaterMarkImage.tsx | 2 +- .../components/BottomNavBar/BottomNavBar.tsx | 2 +- .../components/BottomNavBar/FilterButton.tsx | 2 +- .../BottomNavBar/FilterOptionsModal.tsx | 2 +- .../components/BottomNavBar/UserButton.tsx | 2 +- .../CategoryNavbar/CategoryNavbar.tsx | 2 +- .../CelebDropDown/CelebDropDown.tsx | 2 +- .../FilterSelectBox/FilterSelectBox.tsx | 2 +- .../components/InfoDropDown/InfoDropDown.tsx | 2 +- .../InfoDropDown/InfoDropDownOption.tsx | 2 +- .../src/components/LoginModal/LoginModal.tsx | 2 +- .../components/LoginPageUI/LoginPageUI.tsx | 2 +- .../MainPageNavBar/MainPageNavBarSkeleton.tsx | 2 +- .../RestaurantCard/RestaurantCard.tsx | 15 ++++++++----- .../RestaurantCardList/RestaurantCardList.tsx | 22 ++++++++++--------- .../RestaurantReviewItem.tsx | 2 +- .../RestaurantReviewList.tsx | 2 +- .../RestaurantReviewWrapper.tsx | 2 +- .../src/components/ReviewForm/ReviewForm.tsx | 2 +- .../WithdrawalModalContent.tsx | 2 +- frontend/src/index.tsx | 9 +++++++- frontend/src/pages/OauthRedirectPage.tsx | 2 +- frontend/src/pages/PrivacyPolicyPage.tsx | 2 +- frontend/src/pages/RestaurantDetail.tsx | 22 ++++++++++++------- frontend/src/pages/SignUpPage.tsx | 2 +- frontend/src/pages/WishListPage.tsx | 2 +- frontend/src/router/Root.tsx | 22 ++++++++++++++++--- frontend/src/router/Router.tsx | 2 +- 47 files changed, 157 insertions(+), 77 deletions(-) diff --git a/frontend/.webpack/webpack.config.js b/frontend/.webpack/webpack.config.js index 9211b469b..5b242cb94 100644 --- a/frontend/.webpack/webpack.config.js +++ b/frontend/.webpack/webpack.config.js @@ -4,6 +4,7 @@ const commonConfig = require('./webpack.common.js'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); +const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const commonPlugins = [ new HtmlWebpackPlugin({ @@ -14,6 +15,9 @@ const commonPlugins = [ new MiniCssExtractPlugin({ filename: 'fonts/font.css', }), + // new BundleAnalyzerPlugin({ + // analyzerMode: 'static', + // }), ]; const commonRules = [ diff --git a/frontend/src/api/restaurant.ts b/frontend/src/api/restaurant.ts index f508feb77..ff53e187b 100644 --- a/frontend/src/api/restaurant.ts +++ b/frontend/src/api/restaurant.ts @@ -1,22 +1,25 @@ import getQueryString from '~/utils/getQueryString'; -import { apiClient } from './apiClient'; +import { apiClient, apiUserClient } from './apiClient'; import type { RestaurantListData } from '~/@types/api.types'; import type { RestaurantsQueryParams } from '~/@types/restaurant.types'; export const getRestaurants = async (queryParams: RestaurantsQueryParams) => { - const queryString = getQueryString(queryParams); - const response = await apiClient.get(`/restaurants?${queryString}`); + if (queryParams.boundary) { + const queryString = getQueryString(queryParams); + const response = await apiUserClient.get(`/restaurants?${queryString}`); - return response.data; + return response.data; + } + return null; }; export const getRestaurantDetail = async (restaurantId: string, celebId: string) => { - const response = await apiClient.get(`/restaurants/${restaurantId}?celebId=${celebId}`); + const response = await apiUserClient.get(`/restaurants/${restaurantId}?celebId=${celebId}`); return response.data; }; export const getNearByRestaurant = async (restaurantId: string) => { - const response = await apiClient.get(`/restaurants/${restaurantId}/nearby`); + const response = await apiUserClient.get(`/restaurants/${restaurantId}/nearby`); return response.data; }; diff --git a/frontend/src/assets/fonts/font.css b/frontend/src/assets/fonts/font.css index 476c8eb32..9fe96b1a7 100644 --- a/frontend/src/assets/fonts/font.css +++ b/frontend/src/assets/fonts/font.css @@ -3,6 +3,7 @@ font-weight: normal; font-style: normal; src: url('./SUIT-Regular.woff2') format('woff2'); + font-display: swap; } @font-face { @@ -10,6 +11,7 @@ font-weight: normal; font-style: normal; src: url('./SUIT-Medium.woff2') format('woff2'); + font-display: swap; } @font-face { @@ -17,4 +19,5 @@ font-weight: normal; font-style: normal; src: url('./SUIT-Bold.woff2') format('woff2'); + font-display: swap; } diff --git a/frontend/src/components/@common/Footer/Footer.tsx b/frontend/src/components/@common/Footer/Footer.tsx index 194c5e33c..3f11b5ccb 100644 --- a/frontend/src/components/@common/Footer/Footer.tsx +++ b/frontend/src/components/@common/Footer/Footer.tsx @@ -1,4 +1,4 @@ -import styled from 'styled-components'; +import { styled } from 'styled-components'; import { Link } from 'react-router-dom'; import Instagram from '~/assets/icons/instagram.svg'; import Github from '~/assets/icons/github.svg'; diff --git a/frontend/src/components/@common/Header/MobileHeader.tsx b/frontend/src/components/@common/Header/MobileHeader.tsx index 9d53aeac3..f250d2295 100644 --- a/frontend/src/components/@common/Header/MobileHeader.tsx +++ b/frontend/src/components/@common/Header/MobileHeader.tsx @@ -1,4 +1,4 @@ -import styled from 'styled-components'; +import { styled } from 'styled-components'; import { Link, useLocation } from 'react-router-dom'; import { Wrapper } from '@googlemaps/react-wrapper'; import { FONT_SIZE } from '~/styles/common'; diff --git a/frontend/src/components/@common/ImageCarousel/ImageCarousel.tsx b/frontend/src/components/@common/ImageCarousel/ImageCarousel.tsx index bf22c57db..b1f7a3651 100644 --- a/frontend/src/components/@common/ImageCarousel/ImageCarousel.tsx +++ b/frontend/src/components/@common/ImageCarousel/ImageCarousel.tsx @@ -1,5 +1,5 @@ import { useEffect, useRef, useState } from 'react'; -import styled, { css } from 'styled-components'; +import { styled, css } from 'styled-components'; import { RestaurantImage } from '~/@types/image.type'; import LeftBracket from '~/assets/icons/left-bracket.svg'; import RightBracket from '~/assets/icons/right-bracket.svg'; diff --git a/frontend/src/components/@common/InfoButton/InfoButton.tsx b/frontend/src/components/@common/InfoButton/InfoButton.tsx index b3f638801..e84dd32d6 100644 --- a/frontend/src/components/@common/InfoButton/InfoButton.tsx +++ b/frontend/src/components/@common/InfoButton/InfoButton.tsx @@ -1,4 +1,4 @@ -import styled, { css } from 'styled-components'; +import { styled, css } from 'styled-components'; import Menu from '~/assets/icons/etc/menu.svg'; import User from '~/assets/icons/etc/user.svg'; diff --git a/frontend/src/components/@common/LoadingDots/LoadingDots.tsx b/frontend/src/components/@common/LoadingDots/LoadingDots.tsx index b2efa0ce8..b792f84b7 100644 --- a/frontend/src/components/@common/LoadingDots/LoadingDots.tsx +++ b/frontend/src/components/@common/LoadingDots/LoadingDots.tsx @@ -1,4 +1,4 @@ -import styled, { keyframes } from 'styled-components'; +import { styled, keyframes } from 'styled-components'; import Dot from '~/assets/icons/dot.svg'; function LoadingDots() { diff --git a/frontend/src/components/@common/LoadingIndicator/LoadingIndicator.tsx b/frontend/src/components/@common/LoadingIndicator/LoadingIndicator.tsx index 8ad130c07..ff65aad75 100644 --- a/frontend/src/components/@common/LoadingIndicator/LoadingIndicator.tsx +++ b/frontend/src/components/@common/LoadingIndicator/LoadingIndicator.tsx @@ -1,4 +1,4 @@ -import styled, { keyframes } from 'styled-components'; +import { styled, keyframes } from 'styled-components'; import Cel from '~/assets/icons/celuveat_cel.svg'; import Luv from '~/assets/icons/celuveat_luv.svg'; import Eat from '~/assets/icons/celuveat_eat.svg'; diff --git a/frontend/src/components/@common/LoginButton/LoginButton.tsx b/frontend/src/components/@common/LoginButton/LoginButton.tsx index 77faa01e1..33b6c98e5 100644 --- a/frontend/src/components/@common/LoginButton/LoginButton.tsx +++ b/frontend/src/components/@common/LoginButton/LoginButton.tsx @@ -1,4 +1,4 @@ -import styled, { css } from 'styled-components'; +import { styled, css } from 'styled-components'; import React from 'react'; import { OAUTH_BUTTON_MESSAGE, OAUTH_LINK } from '~/constants/api'; diff --git a/frontend/src/components/@common/Map/Map.tsx b/frontend/src/components/@common/Map/Map.tsx index 1966bb458..1e70d461a 100644 --- a/frontend/src/components/@common/Map/Map.tsx +++ b/frontend/src/components/@common/Map/Map.tsx @@ -1,6 +1,6 @@ import { useState } from 'react'; import { Wrapper, Status } from '@googlemaps/react-wrapper'; -import { styled } from 'styled-components'; +import { styled, keyframes } from 'styled-components'; import { shallow } from 'zustand/shallow'; import MapContent from './MapContent'; import OverlayMyLocation from './OverlayMyLocation'; @@ -101,6 +101,8 @@ function Map({ toggleMapExpand }: MapProps) { toggleMapExpand(); }; + const setMapLoadingState = (state: boolean) => setLoading(state); + return ( - + {myPosition && } {loading && ( @@ -141,6 +143,17 @@ function Map({ toggleMapExpand }: MapProps) { export default Map; +const fadeIn = keyframes` + from { + scale: 0.8; + opacity: 0; + } + to { + scale:1; + opacity: 1; + } +`; + const StyledLoadingUI = styled.div` ${mapUIBase} position: absolute; @@ -149,6 +162,8 @@ const StyledLoadingUI = styled.div` width: 82px; height: 40px; + + animation: ${fadeIn} 0.4s ease-in; `; const StyledMyPositionButtonUI = styled.button` diff --git a/frontend/src/components/@common/Map/OverlayMarker.tsx b/frontend/src/components/@common/Map/OverlayMarker.tsx index 8abb13e0f..a0928587b 100644 --- a/frontend/src/components/@common/Map/OverlayMarker.tsx +++ b/frontend/src/components/@common/Map/OverlayMarker.tsx @@ -1,5 +1,5 @@ -import styled, { css, keyframes } from 'styled-components'; -import { MouseEvent, useRef, useState } from 'react'; +import { styled, css, keyframes } from 'styled-components'; +import { MouseEvent, memo, useRef, useState } from 'react'; import { Link } from 'react-router-dom'; import ProfileImage from '../ProfileImage'; import Overlay from './Overlay/Overlay'; @@ -86,7 +86,14 @@ function OverlayMarker({ celeb, restaurant, map, quadrant }: OverlayMarkerProps) ); } -export default OverlayMarker; +function areEqual(prevProps: OverlayMarkerProps, nextProps: OverlayMarkerProps) { + const { restaurant: prevRestaurant, celeb: prevCeleb } = prevProps; + const { restaurant: nextRestaurant, celeb: nextCeleb } = nextProps; + + return prevRestaurant.id === nextRestaurant.id && prevCeleb.id === nextCeleb.id; +} + +export default memo(OverlayMarker, areEqual); const StyledMarkerContainer = styled.div` position: relative; diff --git a/frontend/src/components/@common/Map/OverlayMarkerList.tsx b/frontend/src/components/@common/Map/OverlayMarkerList.tsx index dedbf3803..59c5db212 100644 --- a/frontend/src/components/@common/Map/OverlayMarkerList.tsx +++ b/frontend/src/components/@common/Map/OverlayMarkerList.tsx @@ -1,5 +1,6 @@ import { shallow } from 'zustand/shallow'; import { useQuery } from '@tanstack/react-query'; +import { useEffect } from 'react'; import getQuadrant from '~/utils/getQuadrant'; import OverlayMarker from './OverlayMarker'; import useRestaurantsQueryStringState from '~/hooks/store/useRestaurantsQueryStringState'; @@ -10,25 +11,34 @@ import type { Coordinate } from '~/@types/map.types'; interface OverlayMarkerListProps { center: Coordinate; map?: google.maps.Map; + setMapLoadingState: (state: boolean) => void; } -function OverlayMarkerList({ center, map }: OverlayMarkerListProps) { +function OverlayMarkerList({ center, map, setMapLoadingState }: OverlayMarkerListProps) { const [boundary, celebId, currentPage, restaurantCategory, sort] = useRestaurantsQueryStringState( state => [state.boundary, state.celebId, state.currentPage, state.restaurantCategory, state.sort], shallow, ); - const { data, isLoading } = useQuery({ + const { data, isFetching } = useQuery({ queryKey: ['restaurants', boundary, celebId, restaurantCategory, currentPage, sort], queryFn: () => getRestaurants({ boundary, celebId, category: restaurantCategory, page: currentPage, sort }), + keepPreviousData: true, }); - if (isLoading) return
로딩중입니다...
; + useEffect(() => { + if (isFetching) { + setMapLoadingState(true); + return; + } + setMapLoadingState(false); + }, [isFetching]); return ( map && - data.content?.map(({ celebs, ...restaurant }) => ( + data?.content?.map(({ celebs, ...restaurant }) => ( { name: string; @@ -13,6 +14,7 @@ function ProfileImage({ name = '셀럽', imageUrl, size, ...props }: ProfileImag export default ProfileImage; const StyledProfile = styled.img<{ size: string }>` + ${paintSkeleton} width: ${({ size }) => size || 'auto'}; height: ${({ size }) => size || 'auto'}; diff --git a/frontend/src/components/@common/WaterMarkImage/WaterMarkImage.tsx b/frontend/src/components/@common/WaterMarkImage/WaterMarkImage.tsx index afb205e93..3e936160b 100644 --- a/frontend/src/components/@common/WaterMarkImage/WaterMarkImage.tsx +++ b/frontend/src/components/@common/WaterMarkImage/WaterMarkImage.tsx @@ -1,4 +1,4 @@ -import styled, { css } from 'styled-components'; +import { styled, css } from 'styled-components'; import { BORDER_RADIUS, FONT_SIZE, paintSkeleton } from '~/styles/common'; import getImgUrl from '~/utils/image'; diff --git a/frontend/src/components/BottomNavBar/BottomNavBar.tsx b/frontend/src/components/BottomNavBar/BottomNavBar.tsx index fe2a960bf..2386cfd3f 100644 --- a/frontend/src/components/BottomNavBar/BottomNavBar.tsx +++ b/frontend/src/components/BottomNavBar/BottomNavBar.tsx @@ -1,5 +1,5 @@ import { useRef } from 'react'; -import styled from 'styled-components'; +import { styled } from 'styled-components'; import { useNavigate } from 'react-router-dom'; import NavItem from '../@common/NavItem'; import LoveIcon from '~/assets/icons/love.svg'; diff --git a/frontend/src/components/BottomNavBar/FilterButton.tsx b/frontend/src/components/BottomNavBar/FilterButton.tsx index e56dac781..4e25885cc 100644 --- a/frontend/src/components/BottomNavBar/FilterButton.tsx +++ b/frontend/src/components/BottomNavBar/FilterButton.tsx @@ -1,5 +1,5 @@ import { useQuery } from '@tanstack/react-query'; -import styled from 'styled-components'; +import { styled } from 'styled-components'; import NavItem from '../@common/NavItem'; import ProfileImage from '../@common/ProfileImage'; import CelebIcon from '~/assets/icons/celeb.svg'; diff --git a/frontend/src/components/BottomNavBar/FilterOptionsModal.tsx b/frontend/src/components/BottomNavBar/FilterOptionsModal.tsx index 821c758f3..735b25f6e 100644 --- a/frontend/src/components/BottomNavBar/FilterOptionsModal.tsx +++ b/frontend/src/components/BottomNavBar/FilterOptionsModal.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import styled from 'styled-components'; +import { styled } from 'styled-components'; import { shallow } from 'zustand/shallow'; import CelebIcon from '~/assets/icons/celeb.svg'; import TextButton from '../@common/Button'; diff --git a/frontend/src/components/BottomNavBar/UserButton.tsx b/frontend/src/components/BottomNavBar/UserButton.tsx index 650dbf68f..a75efcd93 100644 --- a/frontend/src/components/BottomNavBar/UserButton.tsx +++ b/frontend/src/components/BottomNavBar/UserButton.tsx @@ -1,6 +1,6 @@ import { useQuery } from '@tanstack/react-query'; import { useNavigate } from 'react-router-dom'; -import styled from 'styled-components'; +import { styled } from 'styled-components'; import UserIcon from '~/assets/icons/etc/user.svg'; import ProfileImage from '../@common/ProfileImage'; import NavItem from '../@common/NavItem'; diff --git a/frontend/src/components/CategoryNavbar/CategoryNavbar.tsx b/frontend/src/components/CategoryNavbar/CategoryNavbar.tsx index 65eeece81..033506abb 100644 --- a/frontend/src/components/CategoryNavbar/CategoryNavbar.tsx +++ b/frontend/src/components/CategoryNavbar/CategoryNavbar.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import styled from 'styled-components'; +import { styled } from 'styled-components'; import NavItem from '~/components/@common/NavItem/NavItem'; import { isEqual } from '~/utils/compare'; diff --git a/frontend/src/components/CelebDropDown/CelebDropDown.tsx b/frontend/src/components/CelebDropDown/CelebDropDown.tsx index 829a3c281..ac92725a2 100644 --- a/frontend/src/components/CelebDropDown/CelebDropDown.tsx +++ b/frontend/src/components/CelebDropDown/CelebDropDown.tsx @@ -1,4 +1,4 @@ -import styled, { css } from 'styled-components'; +import { styled, css } from 'styled-components'; import { MouseEvent, useState } from 'react'; import CelebIcon from '~/assets/icons/celeb.svg'; diff --git a/frontend/src/components/FilterSelectBox/FilterSelectBox.tsx b/frontend/src/components/FilterSelectBox/FilterSelectBox.tsx index ab5f09f9f..304dff455 100644 --- a/frontend/src/components/FilterSelectBox/FilterSelectBox.tsx +++ b/frontend/src/components/FilterSelectBox/FilterSelectBox.tsx @@ -1,5 +1,5 @@ import React, { ChangeEvent } from 'react'; -import styled from 'styled-components'; +import { styled } from 'styled-components'; import useRestaurantsQueryStringState from '~/hooks/store/useRestaurantsQueryStringState'; type SortingWay = 'distance' | 'like'; diff --git a/frontend/src/components/InfoDropDown/InfoDropDown.tsx b/frontend/src/components/InfoDropDown/InfoDropDown.tsx index e82f0a629..1b8927a06 100644 --- a/frontend/src/components/InfoDropDown/InfoDropDown.tsx +++ b/frontend/src/components/InfoDropDown/InfoDropDown.tsx @@ -1,6 +1,6 @@ import { useQuery } from '@tanstack/react-query'; import { useRef } from 'react'; -import styled from 'styled-components'; +import { styled } from 'styled-components'; import { ProfileData } from '~/@types/api.types'; import { getProfile } from '~/api/user'; diff --git a/frontend/src/components/InfoDropDown/InfoDropDownOption.tsx b/frontend/src/components/InfoDropDown/InfoDropDownOption.tsx index 7140d07da..dbe9aed7b 100644 --- a/frontend/src/components/InfoDropDown/InfoDropDownOption.tsx +++ b/frontend/src/components/InfoDropDown/InfoDropDownOption.tsx @@ -1,4 +1,4 @@ -import styled, { css } from 'styled-components'; +import { styled, css } from 'styled-components'; import useBooleanState from '~/hooks/useBooleanState'; interface InfoDropDownOptionProps { diff --git a/frontend/src/components/LoginModal/LoginModal.tsx b/frontend/src/components/LoginModal/LoginModal.tsx index f04c326cb..9c0b46847 100644 --- a/frontend/src/components/LoginModal/LoginModal.tsx +++ b/frontend/src/components/LoginModal/LoginModal.tsx @@ -1,4 +1,4 @@ -import styled from 'styled-components'; +import { styled } from 'styled-components'; import LoginButton from '~/components/@common/LoginButton'; import Modal from '../@common/Modal'; diff --git a/frontend/src/components/LoginPageUI/LoginPageUI.tsx b/frontend/src/components/LoginPageUI/LoginPageUI.tsx index 0515e6eef..f28920ec0 100644 --- a/frontend/src/components/LoginPageUI/LoginPageUI.tsx +++ b/frontend/src/components/LoginPageUI/LoginPageUI.tsx @@ -1,4 +1,4 @@ -import styled, { css } from 'styled-components'; +import { styled, css } from 'styled-components'; import useMediaQuery from '~/hooks/useMediaQuery'; diff --git a/frontend/src/components/MainPageNavBar/MainPageNavBarSkeleton.tsx b/frontend/src/components/MainPageNavBar/MainPageNavBarSkeleton.tsx index 6161d22c5..8595fd9a6 100644 --- a/frontend/src/components/MainPageNavBar/MainPageNavBarSkeleton.tsx +++ b/frontend/src/components/MainPageNavBar/MainPageNavBarSkeleton.tsx @@ -1,4 +1,4 @@ -import styled from 'styled-components'; +import { styled } from 'styled-components'; import { NavItemSkeleton } from '../@common/NavItem'; interface MainPageNavBarSkeletonProps { diff --git a/frontend/src/components/RestaurantCard/RestaurantCard.tsx b/frontend/src/components/RestaurantCard/RestaurantCard.tsx index 1fee4658c..f2620995c 100644 --- a/frontend/src/components/RestaurantCard/RestaurantCard.tsx +++ b/frontend/src/components/RestaurantCard/RestaurantCard.tsx @@ -1,5 +1,5 @@ import { styled } from 'styled-components'; -import { MouseEventHandler } from 'react'; +import { MouseEventHandler, memo } from 'react'; import { useNavigate } from 'react-router-dom'; import ImageCarousel from '../@common/ImageCarousel'; import Love from '~/assets/icons/love.svg'; @@ -27,9 +27,7 @@ function RestaurantCard({ restaurant, celebs, size, type = 'list', setHoveredId const onMouseEnter = () => setHoveredId(restaurant.id); const onMouseLeave = () => setHoveredId(null); - const onClick = () => { - navigate(`/restaurants/${id}?celebId=${celebs[0].id}`); - }; + const onClick = () => navigate(`/restaurants/${id}?celebId=${celebs[0].id}`); const toggle: MouseEventHandler = e => { e.stopPropagation(); @@ -71,7 +69,14 @@ function RestaurantCard({ restaurant, celebs, size, type = 'list', setHoveredId ); } -export default RestaurantCard; +function areEqual(prevProps: RestaurantCardProps, nextProps: RestaurantCardProps) { + const { restaurant: prevRestaurant, celebs: prevCelebs } = prevProps; + const { restaurant: nextRestaurant, celebs: nextCelebs } = nextProps; + + return prevRestaurant.id === nextRestaurant.id && prevCelebs[0].id === nextCelebs[0].id; +} + +export default memo(RestaurantCard, areEqual); const StyledContainer = styled.li` display: flex; diff --git a/frontend/src/components/RestaurantCardList/RestaurantCardList.tsx b/frontend/src/components/RestaurantCardList/RestaurantCardList.tsx index 637c49c29..9a58eb120 100644 --- a/frontend/src/components/RestaurantCardList/RestaurantCardList.tsx +++ b/frontend/src/components/RestaurantCardList/RestaurantCardList.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect } from 'react'; import { styled, css } from 'styled-components'; import { shallow } from 'zustand/shallow'; import { useQuery } from '@tanstack/react-query'; @@ -17,7 +17,6 @@ import { getRestaurants } from '~/api/restaurant'; function RestaurantCardList() { const { isMobile } = useMediaQuery(); - const [prevCardNumber, setPrevCardNumber] = useState(18); const [boundary, celebId, currentPage, restaurantCategory, setCurrentPage, sort, setSort] = useRestaurantsQueryStringState( state => [ @@ -32,9 +31,10 @@ function RestaurantCardList() { shallow, ); - const { data: restaurantDataList, isLoading } = useQuery({ + const { data: restaurantDataList } = useQuery({ queryKey: ['restaurants', boundary, celebId, restaurantCategory, currentPage, sort], queryFn: () => getRestaurants({ boundary, celebId, category: restaurantCategory, page: currentPage, sort }), + keepPreviousData: true, }); const [setHoveredId] = useHoveredRestaurantState(state => [state.setId]); @@ -53,14 +53,10 @@ function RestaurantCardList() { if (isMobile) setSort('distance'); }, []); - useEffect(() => { - if (restaurantDataList) setPrevCardNumber(restaurantDataList.currentElementsCount); - }, [restaurantDataList?.currentElementsCount]); - - if (isLoading) + if (!restaurantDataList) return ( - + ); @@ -76,7 +72,13 @@ function RestaurantCardList() { )} {restaurantDataList.content?.map(({ celebs, ...restaurant }: RestaurantData) => ( - + ))} diff --git a/frontend/src/pages/OauthRedirectPage.tsx b/frontend/src/pages/OauthRedirectPage.tsx index c440916e2..573555a8d 100644 --- a/frontend/src/pages/OauthRedirectPage.tsx +++ b/frontend/src/pages/OauthRedirectPage.tsx @@ -1,7 +1,7 @@ import { useMutation } from '@tanstack/react-query'; import React, { useEffect } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; -import styled from 'styled-components'; +import { styled } from 'styled-components'; import { getAccessToken } from '~/api/user'; import LoadingIndicator from '~/components/@common/LoadingIndicator'; diff --git a/frontend/src/pages/PrivacyPolicyPage.tsx b/frontend/src/pages/PrivacyPolicyPage.tsx index 8e4c56bbc..65d710e87 100644 --- a/frontend/src/pages/PrivacyPolicyPage.tsx +++ b/frontend/src/pages/PrivacyPolicyPage.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import styled from 'styled-components'; +import { styled } from 'styled-components'; import { FONT_SIZE } from '~/styles/common'; function PrivacyPolicyPage() { diff --git a/frontend/src/pages/RestaurantDetail.tsx b/frontend/src/pages/RestaurantDetail.tsx index 55cbe4bf3..1b6228242 100644 --- a/frontend/src/pages/RestaurantDetail.tsx +++ b/frontend/src/pages/RestaurantDetail.tsx @@ -1,4 +1,4 @@ -import { Suspense, useRef } from 'react'; +import { useRef } from 'react'; import { styled, css } from 'styled-components'; import { Wrapper } from '@googlemaps/react-wrapper'; import { useParams, useSearchParams } from 'react-router-dom'; @@ -98,7 +98,7 @@ function RestaurantDetail() { {isSuccessRestaurantDetail && ( <> - +

{name}

@@ -217,11 +217,10 @@ function RestaurantDetail() { )} - Loading...
}> - - - - + + + + {isSuccessRestaurantDetail && (
위치 확인하기
@@ -281,6 +280,7 @@ export default RestaurantDetail; const StyledMainRestaurantDetail = styled.main<{ isMobile: boolean }>` display: flex; flex-direction: column; + ${({ isMobile }) => isMobile ? css` @@ -295,7 +295,7 @@ const StyledMainRestaurantDetail = styled.main<{ isMobile: boolean }>` `} `; -const StyledDetailHeader = styled.section` +const StyledDetailHeader = styled.section<{ isMobile: boolean }>` display: flex; flex-direction: column; gap: 0.8rem 0; @@ -315,6 +315,12 @@ const StyledDetailHeader = styled.section` gap: 0 0.8rem; } } + + ${({ isMobile }) => + isMobile && + css` + margin-top: 4.4rem; + `} `; const StyledDetailAndLink = styled.section<{ isMobile: boolean }>` diff --git a/frontend/src/pages/SignUpPage.tsx b/frontend/src/pages/SignUpPage.tsx index c52628120..d3d5d6779 100644 --- a/frontend/src/pages/SignUpPage.tsx +++ b/frontend/src/pages/SignUpPage.tsx @@ -1,4 +1,4 @@ -import styled from 'styled-components'; +import { styled } from 'styled-components'; import LoginButton from '~/components/@common/LoginButton'; import LoginPageUI from '~/components/LoginPageUI'; diff --git a/frontend/src/pages/WishListPage.tsx b/frontend/src/pages/WishListPage.tsx index 24b1ee13f..b01afe1ea 100644 --- a/frontend/src/pages/WishListPage.tsx +++ b/frontend/src/pages/WishListPage.tsx @@ -1,4 +1,4 @@ -import styled, { css } from 'styled-components'; +import { styled, css } from 'styled-components'; import RestaurantWishList from '~/components/RestaurantWishList'; import LoginErrorHandleComponent from '~/components/@common/LoginErrorHandleComponent'; diff --git a/frontend/src/router/Root.tsx b/frontend/src/router/Root.tsx index 73596e31a..04c1f5867 100644 --- a/frontend/src/router/Root.tsx +++ b/frontend/src/router/Root.tsx @@ -1,17 +1,25 @@ -import { Suspense } from 'react'; +import { Suspense, lazy } from 'react'; +import { styled } from 'styled-components'; import { Outlet } from 'react-router-dom'; import Footer from '~/components/@common/Footer'; import { Header, MobileHeader } from '~/components/@common/Header'; import LoadingIndicator from '~/components/@common/LoadingIndicator'; -import Toast from '~/components/@common/Toast'; import useMediaQuery from '~/hooks/useMediaQuery'; +const Toast = lazy(() => import('~/components/@common/Toast')); + function Root() { const { isMobile } = useMediaQuery(); return ( <> - }> + + + + } + > {isMobile ? :
} {!isMobile &&