diff --git a/src/app/router/Router.tsx b/src/app/router/Router.tsx
index 41a51031..dc9bd3f1 100644
--- a/src/app/router/Router.tsx
+++ b/src/app/router/Router.tsx
@@ -7,7 +7,7 @@ import {
AroundSearch,
TourList,
TourSearch,
- TourSingleInfo,
+ TourShare,
} from '@/app/router';
import { Home } from '@/pages/home';
import { GeoTrip } from '@/pages/tour/geotrip';
@@ -28,9 +28,8 @@ export default function Router() {
} />
}>
- } />
- } />
- } />
+ } />
+ } />
} />
} />
} />
diff --git a/src/app/router/lazyRoutes.ts b/src/app/router/lazyRoutes.ts
index d20ea25e..4112a1c3 100644
--- a/src/app/router/lazyRoutes.ts
+++ b/src/app/router/lazyRoutes.ts
@@ -9,6 +9,4 @@ export const AroundSearch = lazy(
);
export const TourList = lazy(() => import('@/pages/tour/tourList/TourList'));
export const TourSearch = lazy(() => import('@/pages/tour/search/TourSearch'));
-export const TourSingleInfo = lazy(
- () => import('@/pages/tour/geotrip/SingleTrip'),
-);
+export const TourShare = lazy(() => import('@/pages/tour/geotrip/Share'));
diff --git a/src/features/auth/ui/AuthButtonContainer.tsx b/src/features/auth/ui/AuthButtonContainer.tsx
index 59442a78..38fb5c2f 100644
--- a/src/features/auth/ui/AuthButtonContainer.tsx
+++ b/src/features/auth/ui/AuthButtonContainer.tsx
@@ -10,7 +10,7 @@ export default function AuthButtonContainer() {
mutation.mutate();
};
const handleGuestLogin = () => {
- navigate('/tour/geo-trip?distance=20000&tour-type=12');
+ navigate('/tour/geo');
};
return (
diff --git a/src/features/shared/index.ts b/src/features/shared/index.ts
new file mode 100644
index 00000000..03a8d531
--- /dev/null
+++ b/src/features/shared/index.ts
@@ -0,0 +1,2 @@
+export * from './lib';
+export * from './ui';
diff --git a/src/features/shared/lib/index.ts b/src/features/shared/lib/index.ts
new file mode 100644
index 00000000..2de0abe5
--- /dev/null
+++ b/src/features/shared/lib/index.ts
@@ -0,0 +1 @@
+export { default as useKakaoShare } from './useKakaoShare';
diff --git a/src/features/tour/ui/single/Single.tsx b/src/features/shared/ui/ShareTrip.tsx
similarity index 96%
rename from src/features/tour/ui/single/Single.tsx
rename to src/features/shared/ui/ShareTrip.tsx
index 373a0e74..b901ce25 100644
--- a/src/features/tour/ui/single/Single.tsx
+++ b/src/features/shared/ui/ShareTrip.tsx
@@ -5,7 +5,7 @@ import { tourQueries, type TourItem } from '@/entities/tour';
import { LoadingSpinner } from '@/shared/ui';
import { TourSlide } from '@/features/tourShort';
-export default function Single() {
+export default function ShareTrip() {
const { contentId } = useParams();
const navigate = useNavigate();
diff --git a/src/features/shared/ui/SharedButtonContainer.tsx b/src/features/shared/ui/SharedButtonContainer.tsx
index 23d3998a..4d32e447 100644
--- a/src/features/shared/ui/SharedButtonContainer.tsx
+++ b/src/features/shared/ui/SharedButtonContainer.tsx
@@ -9,7 +9,7 @@ interface SharedButtonContainerProps {
export default function SharedButtonContainer({
contentId,
}: SharedButtonContainerProps) {
- const link = `${window.location.origin}/tour/single/${contentId}`;
+ const link = `${window.location.origin}/tour/share/${contentId}`;
const { shareKakao } = useKakaoShare({ contentId, link });
return (
diff --git a/src/features/shared/ui/index.ts b/src/features/shared/ui/index.ts
new file mode 100644
index 00000000..a36efd3f
--- /dev/null
+++ b/src/features/shared/ui/index.ts
@@ -0,0 +1,2 @@
+export { default as ShareTrip } from './ShareTrip';
+export { default as SharedButtonContainer } from './SharedButtonContainer';
diff --git a/src/features/tourDetail/ui/TourOverview.tsx b/src/features/tourDetail/ui/TourOverview.tsx
index 41cbd17f..997483c1 100644
--- a/src/features/tourDetail/ui/TourOverview.tsx
+++ b/src/features/tourDetail/ui/TourOverview.tsx
@@ -1,10 +1,9 @@
import { useSuspenseQuery } from '@tanstack/react-query';
-import { commonSVG } from '@/assets';
-
import { BookmarkButtonContainer } from '@/features/bookmark';
import { tourQueries } from '@/entities/tour';
-import { TourTypeBadge, DistanceTimeInfo, getCopyClipBoard } from '@/shared';
+import { TourTypeBadge, DistanceTimeInfo } from '@/shared';
+import { SharedButtonContainer } from '@/features/shared';
interface TourCardProps {
distance: string;
@@ -37,10 +36,8 @@ export default function TourOverview({
- getCopyClipBoard(window.location.href)}
- />
+
+
diff --git a/src/features/tourShort/hook/index.ts b/src/features/tourShort/hook/index.ts
index 57b031a9..8586ad07 100644
--- a/src/features/tourShort/hook/index.ts
+++ b/src/features/tourShort/hook/index.ts
@@ -1,2 +1,2 @@
export * from './useInfiniteSwiperControl';
-export * from './usePersistSlideUrl';
+export * from './usePersistSlideStorage';
diff --git a/src/features/tourShort/hook/usePersistSlideStorage.ts b/src/features/tourShort/hook/usePersistSlideStorage.ts
new file mode 100644
index 00000000..b0f66866
--- /dev/null
+++ b/src/features/tourShort/hook/usePersistSlideStorage.ts
@@ -0,0 +1,43 @@
+import { useSessionStorage } from '@/shared';
+import { useCallback } from 'react';
+
+interface SlideState {
+ pageParam: number;
+ index: number;
+}
+
+export const usePersistSlideStorage = () => {
+ const [slideState, setSlideState] = useSessionStorage(
+ 'slideState',
+ {
+ index: 0,
+ pageParam: 1,
+ },
+ );
+
+ const setSlideParams = useCallback(
+ ({ index, pageParam }: SlideState) => {
+ setSlideState({ index: index % 10, pageParam });
+ },
+ [setSlideState],
+ );
+
+ const getSlideIndex = () => {
+ return slideState.index;
+ };
+
+ const getPageParam = () => {
+ return slideState.pageParam;
+ };
+
+ const slideReset = () => {
+ setSlideState({ index: 0, pageParam: 1 });
+ };
+
+ return {
+ setSlideParams,
+ getSlideIndex,
+ getPageParam,
+ slideReset,
+ };
+};
diff --git a/src/features/tourShort/hook/usePersistSlideUrl.ts b/src/features/tourShort/hook/usePersistSlideUrl.ts
deleted file mode 100644
index 729c109b..00000000
--- a/src/features/tourShort/hook/usePersistSlideUrl.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import { useCallback } from 'react';
-import { useSearchParams } from 'react-router-dom';
-
-interface handleSlideChangeProps {
- pageParam: number;
- index: number;
-}
-
-export const usePersistSlideUrl = () => {
- const [searchParams, setSearchParams] = useSearchParams();
-
- const setSlideParams = useCallback(
- ({ index, pageParam }: handleSlideChangeProps) => {
- searchParams.set('slide-index', (index % 10).toString());
- searchParams.set('page-param', pageParam.toString());
- setSearchParams(searchParams);
- },
- [],
- );
-
- const getSlideIndex = () => {
- const slideIndex = searchParams.get('slide-index');
- if (slideIndex === null) {
- return 0;
- }
- return Number(slideIndex);
- };
-
- const getPageParam = () => {
- const pageParam = searchParams.get('page-param');
- if (pageParam === null) {
- return 1;
- }
- return Number(pageParam);
- };
-
- const slideReset = () => {
- const nextParams = new URLSearchParams(searchParams);
- nextParams.delete('slide-index');
- nextParams.delete('page-param');
- setSearchParams(nextParams);
- };
-
- return {
- setSlideParams,
- getSlideIndex,
- getPageParam,
- slideReset,
- };
-};
diff --git a/src/features/tourShort/ui/TourSwiperContainer.tsx b/src/features/tourShort/ui/TourSwiperContainer.tsx
index e950cc5d..b61b62af 100644
--- a/src/features/tourShort/ui/TourSwiperContainer.tsx
+++ b/src/features/tourShort/ui/TourSwiperContainer.tsx
@@ -10,7 +10,7 @@ import {
TourSwiperView,
useTourSwiperInfiniteQuery,
useInfiniteSwiperControl,
- usePersistSlideUrl,
+ usePersistSlideStorage,
} from '@/features/tourShort';
import { getSuspenseLocation } from '@/shared';
@@ -18,7 +18,8 @@ import type { Swiper as SwiperType } from 'swiper/types';
import type { TourInjected } from '@/features/tour';
function TourSwiperContainer({ distance, contentTypeId }: TourInjected) {
- const { setSlideParams, getSlideIndex, getPageParam } = usePersistSlideUrl();
+ const { setSlideParams, getSlideIndex, getPageParam } =
+ usePersistSlideStorage();
const geoLocation = getSuspenseLocation();
const { slideEntries, fetchAppend, fetchPrepend } =
diff --git a/src/pages/tour/geotrip/SingleTrip.tsx b/src/pages/tour/geotrip/Share.tsx
similarity index 80%
rename from src/pages/tour/geotrip/SingleTrip.tsx
rename to src/pages/tour/geotrip/Share.tsx
index 867cc7a5..1de4f26c 100644
--- a/src/pages/tour/geotrip/SingleTrip.tsx
+++ b/src/pages/tour/geotrip/Share.tsx
@@ -1,24 +1,27 @@
-import SingleTrip from '@/features/tour/ui/single/Single';
-import { LoadingSpinner, QueryErrorBoundary } from '@/shared';
-import { BottomNavigationBar, Seo } from '@/widgets';
import { Suspense } from 'react';
import { useParams } from 'react-router-dom';
-export default function SingleTripPage() {
+import { BottomNavigationBar, Seo } from '@/widgets';
+
+import { ShareTrip } from '@/features/shared';
+
+import { LoadingSpinner, QueryErrorBoundary } from '@/shared';
+
+export default function ShareTripPage() {
const { contentId } = useParams();
return (
<>
}>
-
+
diff --git a/src/pages/tour/geotrip/index.ts b/src/pages/tour/geotrip/index.ts
index 0797c0b2..20640dc7 100644
--- a/src/pages/tour/geotrip/index.ts
+++ b/src/pages/tour/geotrip/index.ts
@@ -1,2 +1,2 @@
export { default as GeoTrip } from './GeoTrip';
-export { default as SingleTrip } from './SingleTrip';
+export { default as SingleTrip } from './Share';
diff --git a/src/shared/hooks/index.ts b/src/shared/hooks/index.ts
index c3eb0799..156ada1f 100644
--- a/src/shared/hooks/index.ts
+++ b/src/shared/hooks/index.ts
@@ -1,5 +1,6 @@
export * from './useSyncedState';
export * from './useDebouncedCallback';
export * from './useLocalStorage';
+export * from './useSessionStorage';
export * from './useFunnel';
export * from './useToggleState';
diff --git a/src/shared/hooks/useSessionStorage.ts b/src/shared/hooks/useSessionStorage.ts
new file mode 100644
index 00000000..bd777721
--- /dev/null
+++ b/src/shared/hooks/useSessionStorage.ts
@@ -0,0 +1,56 @@
+import { useCallback, useEffect, useRef, useState } from 'react';
+
+/**
+ * sessionStorage 값을 저장하고 불러오는 커스텀 훅입니다.
+ * dispatchEvent를 사용하여 다른 컴포넌트에서 sessionStorage의 변경을 감지할 수 있습니다.
+ *
+ * @param {string} key - sessionStorage에서 사용할 키
+ * @param {T} initialValue - 초기값
+ * @returns {[T, (value: T | ((val: T) => T)) => void]} - 저장된 값과 업데이트 함수를 반환합니다.
+ *
+ * @example
+ * //초기값에 의해, 스토리지에 저장된 정보가 없다면 자동으로 값을 저장합니다.
+ * const [value, setValue] = useLocalStorage('myKey', 'defaultValue');
+ */
+export const useSessionStorage =
(key: string, initialValue: T) => {
+ const readValue = useCallback((): T => {
+ try {
+ const item = window.sessionStorage.getItem(key);
+ return item ? JSON.parse(item) : initialValue;
+ } catch (error) {
+ throw new Error(`스토리지를 불러오는데 실패했습니다: ${error}`);
+ }
+ }, [key, initialValue]);
+
+ const [storedValue, setStoredValue] = useState(readValue);
+ const sessionStorageEventRef = useRef(new Event('session-storage'));
+
+ const setValue = (value: T | ((val: T) => T)) => {
+ try {
+ const valueToStore =
+ value instanceof Function ? value(storedValue) : value;
+ setStoredValue(valueToStore);
+ window.sessionStorage.setItem(key, JSON.stringify(valueToStore));
+
+ window.dispatchEvent(sessionStorageEventRef.current);
+ } catch (error) {
+ console.error(`Error setting sessionStorage key "${key}":`, error);
+ }
+ };
+
+ useEffect(() => {
+ const handleStorageChange = () => {
+ setStoredValue(readValue());
+ };
+
+ window.addEventListener('session-storage', handleStorageChange);
+ window.addEventListener('storage', handleStorageChange);
+
+ return () => {
+ window.removeEventListener('session-storage', handleStorageChange);
+ window.removeEventListener('storage', handleStorageChange);
+ };
+ }, [readValue]);
+
+ return [storedValue, setValue] as const;
+};
diff --git a/src/widgets/bottomNavigationBar/BottomNavigationBar.test.tsx b/src/widgets/bottomNavigationBar/BottomNavigationBar.test.tsx
index 191669d0..39601d12 100644
--- a/src/widgets/bottomNavigationBar/BottomNavigationBar.test.tsx
+++ b/src/widgets/bottomNavigationBar/BottomNavigationBar.test.tsx
@@ -48,7 +48,7 @@ describe('BottomNavigationBar 컴포넌트', () => {
await user.click(homeButton);
expect(mockNavigate).toHaveBeenCalledWith(
- expect.stringContaining('/tour/geo-trip'),
+ expect.stringContaining('/tour/geo'),
{ replace: true },
);
});
diff --git a/src/widgets/bottomNavigationBar/utils.ts b/src/widgets/bottomNavigationBar/utils.ts
index fd4332e5..b48607a4 100644
--- a/src/widgets/bottomNavigationBar/utils.ts
+++ b/src/widgets/bottomNavigationBar/utils.ts
@@ -19,9 +19,9 @@ export const createNavItems = ({ navigate }: createNavItemsParams) => {
{
id: 'home-navigation-tutorial',
icon: HomeIcon,
- path: '/tour/geo-trip',
+ path: '/tour/geo',
label: 'home Icon',
- onClick: () => navigateTo('/tour/geo-trip'),
+ onClick: () => navigateTo('/tour/geo'),
},
{
id: 'list-navigation-tutorial',