start with
@@ -80,7 +107,7 @@ export default function LoginPage() {
/>
{recentPlatform === '카카오' && (
@@ -96,7 +123,7 @@ export default function LoginPage() {
/>
{recentPlatform === '구글' && (
@@ -105,14 +132,18 @@ export default function LoginPage() {
-
+
비회원 로그인
+
{/* 안내문 */}
-
- 비회원은 스탬프 저장과 공유 기능을 사용할 수 없습니다.
-
+
+
비회원은 스탬프 저장과 공유 기능을 사용할 수 없습니다.
+
);
diff --git a/src/shared/api/auth.ts b/src/shared/api/auth.ts
new file mode 100644
index 0000000..a8887d0
--- /dev/null
+++ b/src/shared/api/auth.ts
@@ -0,0 +1,17 @@
+import { apiAuth } from '@/shared/api/instance';
+import type { ApiResponse, TokenData } from '@/shared/types/authtypes';
+import { setTokens } from '@/shared/utils/token';
+
+export const exchangeTempToken = async (tempToken: string) => {
+ const { data } = await apiAuth.post
>(
+ '/api/auth/temp-token/exchange',
+ { tempToken },
+ );
+
+ if (data.success) {
+ const { accessToken, refreshToken } = data.data;
+ setTokens(accessToken, refreshToken);
+ }
+
+ return data;
+};
diff --git a/src/shared/api/instance.ts b/src/shared/api/instance.ts
index a1e6cd1..49f8f12 100644
--- a/src/shared/api/instance.ts
+++ b/src/shared/api/instance.ts
@@ -6,7 +6,7 @@ import {
setTokens,
clearTokens,
} from '@/shared/utils/token';
-import type { ApiResponse, TokenData } from '@/shared/api/types';
+import type { ApiResponse, TokenData } from '@/shared/types/authtypes';
const BASE_URL = process.env.NEXT_PUBLIC_BACKEND_URL;
@@ -50,7 +50,9 @@ const processQueue = (error: unknown, token: string | null = null) => {
apiWithToken.interceptors.response.use(
(response) => response,
async (error: AxiosError>) => {
- const originalRequest = error.config as InternalAxiosRequestConfig & { _retry?: boolean };
+ const originalRequest = error.config as InternalAxiosRequestConfig & {
+ _retry?: boolean;
+ };
if (error.response?.status === 401 && !originalRequest._retry) {
if (isRefreshing) {
diff --git a/src/pages/auth/components/LoginButton.tsx b/src/shared/components/auth/LoginButton.tsx
similarity index 55%
rename from src/pages/auth/components/LoginButton.tsx
rename to src/shared/components/auth/LoginButton.tsx
index 990fe77..9d5d4ac 100644
--- a/src/pages/auth/components/LoginButton.tsx
+++ b/src/shared/components/auth/LoginButton.tsx
@@ -1,67 +1,91 @@
-// SVGO 해결후 Image → Icon으로 교체 예정
-'use client';
-import Image from 'next/image';
-import { cva, type VariantProps } from 'class-variance-authority';
-import { cn } from '@/shared/lib';
-
-
-const loginButtonVariants = cva(
- `
- flex justify-center items-center flex-shrink-0
- w-[5rem] h-[5rem] rounded-full
- shadow-[0_0_4px_rgba(0,0,0,0.30)]
- transition-all duration-150 active:scale-95
- `,
- {
- variants: {
- platform: {
- google: 'bg-white',
- kakao: 'bg-[#FEE500]',
- },
- },
- defaultVariants: {
- platform: 'google',
- },
- }
-);
-
-interface LoginButtonProps extends VariantProps {
- onClick: () => void;
- className?: string;
-}
-
-export default function LoginButton({
- onClick,
- platform,
- className,
-}: LoginButtonProps) {
- const iconData = {
- google: {
- src: '/svgs/GoogleIcon.svg',
- alt: 'Google Logo',
- width: 36,
- height: 36,
- label: '구글 로그인',
- },
- kakao: {
- src: '/svgs/KakaoIcon.svg',
- alt: 'Kakao Logo',
- width: 28,
- height: 28,
- label: '카카오 로그인',
- },
- };
-
- const { src, alt, width, height, label } = iconData[platform ?? 'google'];
-
- return (
-
- );
-}
+'use client';
+import Image from 'next/image';
+import { cva, type VariantProps } from 'class-variance-authority';
+import { cn } from '@/shared/lib';
+
+const loginButtonVariants = cva(
+ `
+ flex justify-center items-center flex-shrink-0
+ w-[5rem] h-[5rem] rounded-full
+ shadow-[0_0_4px_rgba(0,0,0,0.30)]
+ transition-all duration-150 active:scale-95
+ `,
+ {
+ variants: {
+ platform: {
+ google: 'bg-white',
+ kakao: 'bg-[#FEE500]',
+ },
+ },
+ defaultVariants: {
+ platform: 'google',
+ },
+ },
+);
+
+interface LoginButtonProps extends VariantProps {
+ onClick?: () => void;
+ className?: string;
+}
+
+export default function LoginButton({
+ onClick,
+ platform,
+ className,
+}: LoginButtonProps) {
+ const iconData = {
+ google: {
+ src: '/assets/GoogleIcon.svg',
+ alt: 'Google Logo',
+ width: 36,
+ height: 36,
+ label: '구글 로그인',
+ },
+ kakao: {
+ src: '/assets/KakaoIcon.svg',
+ alt: 'Kakao Logo',
+ width: 28,
+ height: 28,
+ label: '카카오 로그인',
+ },
+ };
+
+ if (!platform || !(platform in iconData)) {
+ if (process.env.NODE_ENV === 'development') {
+ console.error(`Invalid platform: ${platform}. Falling back to google.`);
+ }
+ platform = 'google';
+ }
+ const { src, alt, width, height, label } =
+ iconData[platform as keyof typeof iconData];
+
+ const handleClick = () => {
+ if (onClick) return onClick();
+ const base = process.env.NEXT_PUBLIC_BACKEND_URL;
+ if (!base) {
+ const message = 'NEXT_PUBLIC_BACKEND_URL is not defined';
+ if (process.env.NODE_ENV === 'development') {
+ throw new Error(message);
+ }
+ console.error(message);
+ return;
+ }
+ const url =
+ platform === 'kakao'
+ ? `${base}/oauth2/authorization/kakao`
+ : `${base}/oauth2/authorization/google`;
+
+ window.location.href = url;
+ };
+
+ return (
+
+ );
+}
diff --git a/src/pages/auth/components/RecentLoginBubble.tsx b/src/shared/components/auth/RecentLoginBubble.tsx
similarity index 96%
rename from src/pages/auth/components/RecentLoginBubble.tsx
rename to src/shared/components/auth/RecentLoginBubble.tsx
index c8429ed..f4e0e5b 100644
--- a/src/pages/auth/components/RecentLoginBubble.tsx
+++ b/src/shared/components/auth/RecentLoginBubble.tsx
@@ -1,29 +1,29 @@
-'use client';
-import { cva } from 'class-variance-authority';
-import { cn } from '@/shared/lib';
-
-interface RecentLoginBubbleProps {
- className?: string;
-}
-
-const bubbleVariants = cva(
- 'relative inline-flex justify-center items-center px-[0.8rem] py-[0.4rem] bg-pink-200 rounded-[2rem]',
-);
-
-const RecentLoginBubble = ({ className }: RecentLoginBubbleProps) => {
- return (
-
-
최근 로그인
- {/* 말풍선 꼬리 */}
-
-
- );
-};
-
-export default RecentLoginBubble;
+'use client';
+import { cva } from 'class-variance-authority';
+import { cn } from '@/shared/lib';
+
+interface RecentLoginBubbleProps {
+ className?: string;
+}
+
+const bubbleVariants = cva(
+ 'relative inline-flex justify-center items-center px-[0.8rem] py-[0.4rem] bg-pink-200 rounded-[2rem]',
+);
+
+const RecentLoginBubble = ({ className }: RecentLoginBubbleProps) => {
+ return (
+
+
최근 로그인
+ {/* 말풍선 꼬리 */}
+
+
+ );
+};
+
+export default RecentLoginBubble;
diff --git a/src/shared/hooks/useRecentLogin.ts b/src/shared/hooks/useRecentLogin.ts
new file mode 100644
index 0000000..3b47745
--- /dev/null
+++ b/src/shared/hooks/useRecentLogin.ts
@@ -0,0 +1,21 @@
+'use client';
+import { useEffect, useState } from 'react';
+
+const RECENT_LOGIN_KEY = 'recentLoginPlatform';
+
+export function useRecentLogin() {
+ const [recentPlatform, setRecentPlatform] = useState(null);
+
+ useEffect(() => {
+ if (typeof window === 'undefined') return;
+ const saved = localStorage.getItem(RECENT_LOGIN_KEY);
+ if (saved) setRecentPlatform(saved);
+ }, []);
+
+ const saveRecentPlatform = (platform: string) => {
+ localStorage.setItem(RECENT_LOGIN_KEY, platform);
+ setRecentPlatform(platform);
+ };
+
+ return { recentPlatform, saveRecentPlatform };
+}
diff --git a/src/shared/icons/iconNames.ts b/src/shared/icons/iconNames.ts
index 8c5ca55..23fca9f 100644
--- a/src/shared/icons/iconNames.ts
+++ b/src/shared/icons/iconNames.ts
@@ -12,6 +12,9 @@ export const iconNames = [
"HouseSimple",
"KakaoIcon",
"ListButton",
+ "Logo",
+ "LogoMint",
+ "LogoPink",
"MapPin",
"MapPin_",
"NextButton",
diff --git a/src/shared/icons/index.ts b/src/shared/icons/index.ts
index 835330b..a50e17a 100644
--- a/src/shared/icons/index.ts
+++ b/src/shared/icons/index.ts
@@ -1,4 +1,5 @@
// 이 파일은 자동 생성 파일입니다. (직접 수정 금지)
+import './source/backto.svg';
import './source/CalendarBlank.svg';
import './source/Caret.svg';
import './source/ChatCircle.svg';
@@ -11,6 +12,9 @@ import './source/HeartStraight.svg';
import './source/HouseSimple.svg';
import './source/KakaoIcon.svg';
import './source/ListButton.svg';
+import './source/Logo.svg';
+import './source/LogoMint.svg';
+import './source/LogoPink.svg';
import './source/MapPin.svg';
import './source/MapPin_.svg';
import './source/NextButton.svg';
@@ -18,7 +22,6 @@ import './source/PressStamp.svg';
import './source/Save.svg';
import './source/Stamp.svg';
import './source/User.svg';
-import './source/backto.svg';
import './source/x.svg';
export { Icon } from './components/icon';
diff --git a/src/shared/icons/source/CalendarBlank.svg b/src/shared/icons/source/CalendarBlank.svg
index 8ab3820..0851db2 100644
--- a/src/shared/icons/source/CalendarBlank.svg
+++ b/src/shared/icons/source/CalendarBlank.svg
@@ -1 +1 @@
-
+
\ No newline at end of file
diff --git a/src/shared/icons/source/Caret.svg b/src/shared/icons/source/Caret.svg
index 4db0a90..fb33445 100644
--- a/src/shared/icons/source/Caret.svg
+++ b/src/shared/icons/source/Caret.svg
@@ -1 +1 @@
-
+
\ No newline at end of file
diff --git a/src/shared/icons/source/ChatCircle.svg b/src/shared/icons/source/ChatCircle.svg
index e73465d..b289096 100644
--- a/src/shared/icons/source/ChatCircle.svg
+++ b/src/shared/icons/source/ChatCircle.svg
@@ -1 +1 @@
-
+
\ No newline at end of file
diff --git a/src/shared/icons/source/Check.svg b/src/shared/icons/source/Check.svg
index c4939b8..5e50825 100644
--- a/src/shared/icons/source/Check.svg
+++ b/src/shared/icons/source/Check.svg
@@ -1 +1 @@
-
+
\ No newline at end of file
diff --git a/src/shared/icons/source/CopySimple.svg b/src/shared/icons/source/CopySimple.svg
index 58c1c6a..099b89c 100644
--- a/src/shared/icons/source/CopySimple.svg
+++ b/src/shared/icons/source/CopySimple.svg
@@ -1 +1 @@
-
+
\ No newline at end of file
diff --git a/src/shared/icons/source/Export.svg b/src/shared/icons/source/Export.svg
index 02f8aa9..089855a 100644
--- a/src/shared/icons/source/Export.svg
+++ b/src/shared/icons/source/Export.svg
@@ -1 +1 @@
-
+
\ No newline at end of file
diff --git a/src/shared/icons/source/FadersHorizontal.svg b/src/shared/icons/source/FadersHorizontal.svg
index 0f7b09b..7270ce9 100644
--- a/src/shared/icons/source/FadersHorizontal.svg
+++ b/src/shared/icons/source/FadersHorizontal.svg
@@ -1 +1 @@
-
+
\ No newline at end of file
diff --git a/src/shared/icons/source/GoogleIcon.svg b/src/shared/icons/source/GoogleIcon.svg
index 41a6676..7c56b0e 100644
--- a/src/shared/icons/source/GoogleIcon.svg
+++ b/src/shared/icons/source/GoogleIcon.svg
@@ -1 +1 @@
-
+
\ No newline at end of file
diff --git a/src/shared/icons/source/HeartStraight.svg b/src/shared/icons/source/HeartStraight.svg
index 0985d2b..e9e427b 100644
--- a/src/shared/icons/source/HeartStraight.svg
+++ b/src/shared/icons/source/HeartStraight.svg
@@ -1 +1 @@
-
+
\ No newline at end of file
diff --git a/src/shared/icons/source/HouseSimple.svg b/src/shared/icons/source/HouseSimple.svg
index 13fc140..f064541 100644
--- a/src/shared/icons/source/HouseSimple.svg
+++ b/src/shared/icons/source/HouseSimple.svg
@@ -1 +1 @@
-
+
\ No newline at end of file
diff --git a/src/shared/icons/source/KakaoIcon.svg b/src/shared/icons/source/KakaoIcon.svg
index 07d40a9..4831b35 100644
--- a/src/shared/icons/source/KakaoIcon.svg
+++ b/src/shared/icons/source/KakaoIcon.svg
@@ -1 +1 @@
-
+
\ No newline at end of file
diff --git a/src/shared/icons/source/ListButton.svg b/src/shared/icons/source/ListButton.svg
index 18792d2..b87320b 100644
--- a/src/shared/icons/source/ListButton.svg
+++ b/src/shared/icons/source/ListButton.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/shared/icons/source/Logo.svg b/src/shared/icons/source/Logo.svg
new file mode 100644
index 0000000..bb90a59
--- /dev/null
+++ b/src/shared/icons/source/Logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/shared/icons/source/LogoMint.svg b/src/shared/icons/source/LogoMint.svg
new file mode 100644
index 0000000..7ee4e8b
--- /dev/null
+++ b/src/shared/icons/source/LogoMint.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/shared/icons/source/LogoPink.svg b/src/shared/icons/source/LogoPink.svg
new file mode 100644
index 0000000..1e5e5d0
--- /dev/null
+++ b/src/shared/icons/source/LogoPink.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/shared/icons/source/MapPin.svg b/src/shared/icons/source/MapPin.svg
index 9f33716..3a11e82 100644
--- a/src/shared/icons/source/MapPin.svg
+++ b/src/shared/icons/source/MapPin.svg
@@ -1 +1 @@
-
+
\ No newline at end of file
diff --git a/src/shared/icons/source/MapPin_.svg b/src/shared/icons/source/MapPin_.svg
index 27a0199..3e9f7c4 100644
--- a/src/shared/icons/source/MapPin_.svg
+++ b/src/shared/icons/source/MapPin_.svg
@@ -1 +1 @@
-
+
\ No newline at end of file
diff --git a/src/shared/icons/source/NextButton.svg b/src/shared/icons/source/NextButton.svg
index d2a6493..46ac6e8 100644
--- a/src/shared/icons/source/NextButton.svg
+++ b/src/shared/icons/source/NextButton.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/shared/icons/source/PressStamp.svg b/src/shared/icons/source/PressStamp.svg
index 2b0612b..e06a427 100644
--- a/src/shared/icons/source/PressStamp.svg
+++ b/src/shared/icons/source/PressStamp.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/shared/icons/source/Save.svg b/src/shared/icons/source/Save.svg
index 83d6194..a2a33c3 100644
--- a/src/shared/icons/source/Save.svg
+++ b/src/shared/icons/source/Save.svg
@@ -1 +1 @@
-
+
\ No newline at end of file
diff --git a/src/shared/icons/source/Stamp.svg b/src/shared/icons/source/Stamp.svg
index ec6116e..5b43245 100644
--- a/src/shared/icons/source/Stamp.svg
+++ b/src/shared/icons/source/Stamp.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/shared/icons/source/User.svg b/src/shared/icons/source/User.svg
index 0fbb539..91cbec4 100644
--- a/src/shared/icons/source/User.svg
+++ b/src/shared/icons/source/User.svg
@@ -1 +1 @@
-
+
\ No newline at end of file
diff --git a/src/shared/icons/source/backto.svg b/src/shared/icons/source/backto.svg
index 40ca826..6891eb3 100644
--- a/src/shared/icons/source/backto.svg
+++ b/src/shared/icons/source/backto.svg
@@ -1 +1 @@
-
+
\ No newline at end of file
diff --git a/src/shared/icons/source/x.svg b/src/shared/icons/source/x.svg
index 435b208..4c3dc61 100644
--- a/src/shared/icons/source/x.svg
+++ b/src/shared/icons/source/x.svg
@@ -1 +1 @@
-
+
\ No newline at end of file
diff --git a/src/shared/api/types.ts b/src/shared/types/authtypes.ts
similarity index 100%
rename from src/shared/api/types.ts
rename to src/shared/types/authtypes.ts