diff --git a/src/app/globals.css b/src/app/globals.css index f32cc13f..0154d024 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -66,4 +66,8 @@ body { .invitation-gradient { background: linear-gradient(180deg, rgba(33, 33, 36, 0%) 0%, #212124 30%); } + + .header-gradient { + background: linear-gradient(180deg, #212124 70%, rgba(33, 33, 36, 0%) 100%); + } } diff --git a/src/app/place/[placeId]/place-box.tsx b/src/app/place/[placeId]/place-box.tsx index 1cbcaed4..0f788762 100644 --- a/src/app/place/[placeId]/place-box.tsx +++ b/src/app/place/[placeId]/place-box.tsx @@ -23,6 +23,7 @@ import { formatDistance, getDistance } from '@/utils/location' import { roundToNthDecimal } from '@/utils/number' import { allowUserPositionStorage } from '@/utils/storage' import ProxyImage from '@/components/common/proxy-image' +import cn from '@/utils/cn' interface PlaceBoxProps { place: PlaceDetail @@ -39,7 +40,7 @@ const PlaceBox = ({ place, mapId }: PlaceBoxProps) => { const [isRecentlyLike, setIsRecentlyLike] = useState(null) const router = useSafeRouter() const [isAlreadyPick, setIsAlreadyPick] = useState(place.isRegisteredPlace) - const userLocation = useUserGeoLocation() + const { userLocation } = useUserGeoLocation() const isAllowPosition = allowUserPositionStorage.getValueOrNull() const diffDistance = getDistance( userLocation.latitude, @@ -52,6 +53,12 @@ const PlaceBox = ({ place, mapId }: PlaceBoxProps) => { key: ['user'], }) + const { data: mapInfo, isFetching } = useFetch(() => api.maps.id.get(mapId), { + enabled: !!mapId, + }) + const myRole = + mapInfo?.users.find((mapUser) => mapUser.id === user?.id)?.role ?? 'READ' + const numOfLikes = (() => { const likedUsersCount = place.likedUsers?.length ?? 0 @@ -214,25 +221,31 @@ const PlaceBox = ({ place, mapId }: PlaceBoxProps) => { -
-
- {isAlreadyPick ? ( - setIsDeleteModalOpen(true)} - onUnLikePlace={handleUnLikePlace} - /> - ) : ( - - )} -
-
+ {myRole !== 'READ' && !isFetching && ( +
+
+ {isAlreadyPick ? ( + setIsDeleteModalOpen(true)} + onUnLikePlace={handleUnLikePlace} + /> + ) : ( + + )} +
+
+ )} { const [chats, setChats] = useState([initialRecommendChat]) const [isFinish, setIsFinish] = useState(false) const [isLoading, setIsLoading] = useState(false) + const [, setIsOpenShowModal] = useState(false) const bottomChat = useRef(null) const router = useSafeRouter() @@ -179,23 +180,29 @@ const Recommendation = () => { return ( <>
-
- router.safeBack()} - /> - - AI 맛집 추천받기 - +
+
+ router.safeBack()} + /> + + AI 맛집 추천받기 + + setIsOpenShowModal(true)} + /> +
-
+
({ diff --git a/src/app/search/suggest-place-list.tsx b/src/app/search/suggest-place-list.tsx index d83e1f2c..47e89cd4 100644 --- a/src/app/search/suggest-place-list.tsx +++ b/src/app/search/suggest-place-list.tsx @@ -10,7 +10,7 @@ interface SuggestPlaceListProps { } const SuggestPlaceList = ({ places, query }: SuggestPlaceListProps) => { - const userLocation = useUserGeoLocation() + const { userLocation } = useUserGeoLocation() const isAllowPosition = allowUserPositionStorage.getValueOrNull() return ( diff --git a/src/app/test-design/page.tsx b/src/app/test-design/page.tsx index 5cb29e80..49f268ef 100644 --- a/src/app/test-design/page.tsx +++ b/src/app/test-design/page.tsx @@ -1,5 +1,6 @@ 'use client' +import BoardingDivider from '@/components/boarding-pass/boarding-divider' import Typography from '@/components/common/typography' const TestDesign = () => { @@ -33,6 +34,72 @@ const TestDesign = () => { 900 + + + + + 100 + + + 200 + + + 300 + + + 400 + + + 500 + + + weight-600 + + + weight-700 + + + 800 + + + 900 +
) diff --git a/src/components/kakao-map/gps-button.tsx b/src/components/kakao-map/gps-button.tsx index 8012dbb0..505b7e87 100644 --- a/src/components/kakao-map/gps-button.tsx +++ b/src/components/kakao-map/gps-button.tsx @@ -8,6 +8,7 @@ import useUserGeoLocation from '@/hooks/use-user-geo-location' import useWindowSize from '@/hooks/use-window-size' import { getCorners } from '@/utils/map' import { mapBoundSessionStorage } from '@/utils/storage' +import { notify } from '../common/custom-toast' const BUTTON_OFFSET_Y = 16 const BUTTON_HEIGHT = 11 @@ -16,7 +17,8 @@ interface GpsButtonProps { } const GpsButton = ({ topOfBottomBounds }: GpsButtonProps) => { - const userLocation = useUserGeoLocation() + const { userLocation, allowLocation, handleUserLocation } = + useUserGeoLocation() const [gpsBottomPositionY, setGpsBottomPositionY] = useState(BUTTON_OFFSET_Y) const [gpsMode, setGpsMode] = useState(false) const { height: windowHeight } = useWindowSize() @@ -25,6 +27,15 @@ const GpsButton = ({ topOfBottomBounds }: GpsButtonProps) => { const handleGpsClick = () => { if (!map) return + if (!allowLocation) { + const isAllowLocation = handleUserLocation({ + onError: () => { + notify.error('위치 권한을 허용해 주세요.') + }, + }) + if (!isAllowLocation) return + } + if (!gpsMode) { const location = new window.kakao.maps.LatLng( userLocation.latitude, diff --git a/src/components/kakao-map/kakao-map.tsx b/src/components/kakao-map/kakao-map.tsx index 5bcabaae..f2c17e2e 100644 --- a/src/components/kakao-map/kakao-map.tsx +++ b/src/components/kakao-map/kakao-map.tsx @@ -60,7 +60,7 @@ const KakaoMap = forwardRef( lat: (bounds.latitude1 + bounds.latitude2) / 2, lng: (bounds.longitude1 + bounds.longitude2) / 2, } - const userLocation = useUserGeoLocation() + const { userLocation } = useUserGeoLocation() const userLocationCenter = { lat: userLocation.latitude, lng: userLocation.longitude, diff --git a/src/components/place/place-action-buttons.tsx b/src/components/place/place-action-buttons.tsx index d79499dd..9cb2195a 100644 --- a/src/components/place/place-action-buttons.tsx +++ b/src/components/place/place-action-buttons.tsx @@ -1,10 +1,12 @@ import AccessibleIconButton from '@/components/common/accessible-icon-button' import Button from '@/components/common/button' import type { ClassName } from '@/models/common' +import type { MapRole } from '@/models/map' import cn from '@/utils/cn' interface PlaceActionButtonsProps extends ClassName { like?: boolean + role: MapRole onLikePlace: VoidFunction onUnLikePlace: VoidFunction onDeletePlace: VoidFunction @@ -13,6 +15,7 @@ interface PlaceActionButtonsProps extends ClassName { const PlaceActionButtons = ({ className, like, + role, onLikePlace, onUnLikePlace, onDeletePlace, @@ -35,9 +38,15 @@ const PlaceActionButtons = ({ onClick={like ? onUnLikePlace : onLikePlace} />
- + {role === 'READ' ? ( + + ) : ( + + )} ) } diff --git a/src/hooks/use-user-geo-location.ts b/src/hooks/use-user-geo-location.ts index d74e61c9..57301d64 100644 --- a/src/hooks/use-user-geo-location.ts +++ b/src/hooks/use-user-geo-location.ts @@ -1,4 +1,4 @@ -import { useState } from 'react' +import { useCallback, useState } from 'react' import { useIsomorphicLayoutEffect } from './use-isomorphic-layout-effect' @@ -22,23 +22,40 @@ const useUserGeoLocation = () => { const [location, setLocation] = useState( INITIAL_LATITUDE_LONGITUDE, ) + const [allowLocation, setAllowLocation] = useState(false) + + const handleUserLocation = useCallback( + (options?: { onError: (error: GeolocationPositionError) => void }) => { + let isAllow = false + try { + navigator.geolocation.getCurrentPosition( + ({ coords: { latitude, longitude } }) => { + allowUserPositionStorage.set(true) + setLocation({ latitude, longitude }) + setAllowLocation(true) + isAllow = true + }, + (err) => { + options?.onError(err) + setAllowLocation(false) + setLocation(INITIAL_LATITUDE_LONGITUDE) + }, + ) + } catch (err) { + allowUserPositionStorage.set(false) + setLocation(INITIAL_LATITUDE_LONGITUDE) + setAllowLocation(false) + } + return isAllow + }, + [], + ) useIsomorphicLayoutEffect(() => { - try { - navigator.geolocation.getCurrentPosition( - ({ coords: { latitude, longitude } }) => { - allowUserPositionStorage.set(true) - setLocation({ latitude, longitude }) - }, - () => setLocation(INITIAL_LATITUDE_LONGITUDE), - ) - } catch (err) { - allowUserPositionStorage.set(false) - setLocation(INITIAL_LATITUDE_LONGITUDE) - } + handleUserLocation() }, []) - return location + return { userLocation: location, allowLocation, handleUserLocation } } export default useUserGeoLocation diff --git a/src/models/map.ts b/src/models/map.ts index a5829ac4..93721700 100644 --- a/src/models/map.ts +++ b/src/models/map.ts @@ -3,7 +3,7 @@ import type { Creator, User } from './user' import type { IconKey } from '@/components/common/icon' -type MapRole = 'ADMIN' | 'READ' | 'WRITE' +export type MapRole = 'ADMIN' | 'READ' | 'WRITE' export interface MapMemberData { id: User['id']