From b6acb960af6a453fd56e262e047fb71a651389f0 Mon Sep 17 00:00:00 2001
From: Sinji
Date: Wed, 28 May 2025 16:26:39 +0900
Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=EC=BD=9C=EB=B0=B1=20=ED=8E=98?=
=?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EC=83=9D=EC=84=B1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/app/(auth)/callback/page.tsx | 3 +++
src/app/(auth)/layout.tsx | 14 ++++++++++----
2 files changed, 13 insertions(+), 4 deletions(-)
create mode 100644 src/app/(auth)/callback/page.tsx
diff --git a/src/app/(auth)/callback/page.tsx b/src/app/(auth)/callback/page.tsx
new file mode 100644
index 0000000..98ae6f7
--- /dev/null
+++ b/src/app/(auth)/callback/page.tsx
@@ -0,0 +1,3 @@
+export default function CallbackPage() {
+ return 콜백 페이지
;
+}
diff --git a/src/app/(auth)/layout.tsx b/src/app/(auth)/layout.tsx
index cb688f8..410f7f9 100644
--- a/src/app/(auth)/layout.tsx
+++ b/src/app/(auth)/layout.tsx
@@ -1,16 +1,22 @@
import { ReactNode } from 'react';
type Props = {
+ children: ReactNode;
image: ReactNode;
content: ReactNode;
};
-export default function AuthLayout({ content, image }: Props) {
+export default function AuthLayout({ children, content, image }: Props) {
return (
-
{content}
-
-
{image}
+ {children ? (
+
{children}
+ ) : (
+ <>
+
{content}
+
{image}
+ >
+ )}
);
}
From 7b055b0d9a9e9b1efd241d4fd8d29e2d80405d31 Mon Sep 17 00:00:00 2001
From: Sinji
Date: Wed, 28 May 2025 17:51:42 +0900
Subject: [PATCH 2/4] =?UTF-8?q?feat:=20=EC=86=8C=EC=85=9C=20=EB=A1=9C?=
=?UTF-8?q?=EA=B7=B8=EC=9D=B8=20API=20=EC=97=B0=EA=B2=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
next.config.ts | 2 +-
package.json | 1 +
src/app/(auth)/@content/login/page.tsx | 16 ++++++++++--
src/app/(auth)/callback/page.tsx | 3 ---
src/app/(auth)/layout.tsx | 13 +++-------
src/app/callback/page.tsx | 36 ++++++++++++++++++++++++++
src/utils/loginHandler.ts | 15 +++++++++++
yarn.lock | 8 ++++++
8 files changed, 78 insertions(+), 16 deletions(-)
delete mode 100644 src/app/(auth)/callback/page.tsx
create mode 100644 src/app/callback/page.tsx
create mode 100644 src/utils/loginHandler.ts
diff --git a/next.config.ts b/next.config.ts
index 189df27..6a574df 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -1,6 +1,6 @@
import type { NextConfig } from 'next';
-const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL;
+const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URI;
const nextConfig: NextConfig = {
reactStrictMode: true,
diff --git a/package.json b/package.json
index 90949a4..80a0928 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"@svgr/cli": "^8.1.0",
"@tanstack/react-query": "^5.75.5",
"clsx": "^2.1.1",
+ "js-base64": "^3.7.7",
"next": "15.2.4",
"react": "^19.0.0",
"react-dom": "^19.0.0",
diff --git a/src/app/(auth)/@content/login/page.tsx b/src/app/(auth)/@content/login/page.tsx
index 9d549bb..8b57c81 100644
--- a/src/app/(auth)/@content/login/page.tsx
+++ b/src/app/(auth)/@content/login/page.tsx
@@ -1,3 +1,5 @@
+'use client';
+
import { Spacing } from '@/components/ui/Spacing';
import Logo from '@/assets/logo.svg';
import IconKaKao from '@/assets/icons/icon-kakao.svg';
@@ -14,11 +16,21 @@ export default function LoginPage() {
{/* TODO : api 연결할 때 onClick 연결 필요 */}
-
}>
+
+
+ );
+}
diff --git a/src/utils/loginHandler.ts b/src/utils/loginHandler.ts
new file mode 100644
index 0000000..7020e3c
--- /dev/null
+++ b/src/utils/loginHandler.ts
@@ -0,0 +1,15 @@
+import { decode } from 'js-base64';
+
+export const handleLoginSuccess = (accessToken: string | null) => {
+ if (accessToken) {
+ const payload = accessToken.split('.')[1] || '';
+ const decodedPayload = decode(payload);
+ const payloadObject = JSON.parse(decodedPayload);
+ const { name: tokenName } = payloadObject;
+
+ const userInfo = { name: tokenName };
+
+ localStorage.setItem('token', accessToken);
+ localStorage.setItem('user', JSON.stringify(userInfo));
+ }
+};
diff --git a/yarn.lock b/yarn.lock
index 7265896..cbaf6d7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3876,6 +3876,7 @@ __metadata:
eslint-plugin-react: "npm:^7.37.5"
eslint-plugin-react-hooks: "npm:^5.2.0"
husky: "npm:^9.1.7"
+ js-base64: "npm:^3.7.7"
lint-staged: "npm:^15.5.0"
next: "npm:15.2.4"
postcss: "npm:^8.5.3"
@@ -4564,6 +4565,13 @@ __metadata:
languageName: node
linkType: hard
+"js-base64@npm:^3.7.7":
+ version: 3.7.7
+ resolution: "js-base64@npm:3.7.7"
+ checksum: 10c0/3c905a7e78b601e4751b5e710edd0d6d045ce2d23eb84c9df03515371e1b291edc72808dc91e081cb9855aef6758292a2407006f4608ec3705373dd8baf2f80f
+ languageName: node
+ linkType: hard
+
"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0":
version: 4.0.0
resolution: "js-tokens@npm:4.0.0"
From cd486133af98dddf8177b341d178893ff86b4e37 Mon Sep 17 00:00:00 2001
From: Sinji
Date: Wed, 28 May 2025 18:18:27 +0900
Subject: [PATCH 3/4] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20POST?=
=?UTF-8?q?=20API=20=EC=97=B0=EA=B2=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../(auth)/@content/sign-up/step3/page.tsx | 29 +++++++++++++++++--
src/hooks/users/useSignUp.ts | 7 +++++
src/services/users/postSignUp.ts | 14 +++++++++
3 files changed, 47 insertions(+), 3 deletions(-)
create mode 100644 src/hooks/users/useSignUp.ts
create mode 100644 src/services/users/postSignUp.ts
diff --git a/src/app/(auth)/@content/sign-up/step3/page.tsx b/src/app/(auth)/@content/sign-up/step3/page.tsx
index a6f48d2..ed2cf1f 100644
--- a/src/app/(auth)/@content/sign-up/step3/page.tsx
+++ b/src/app/(auth)/@content/sign-up/step3/page.tsx
@@ -6,6 +6,7 @@ import { Spacing } from '@/components/ui/Spacing';
import { Button } from '@/components/ui/Button';
import { StepBar } from '@/components/ui/StepBar';
import { useSignupStore } from '@/stores/signUpStore';
+import { useSignUp } from '@/hooks/users/useSignUp';
import IconArrowDown from '@/assets/icons/icon-arrow-down.svg';
import IconArrowBack from '@/assets/icons/icon-arrow-back.svg';
@@ -35,7 +36,8 @@ const category = [
export default function Step1() {
const router = useRouter();
- const { preferences, setPreferences, clearPreferences } = useSignupStore();
+ const { username, role, preferences, setPreferences, clearPreferences } = useSignupStore();
+ const { mutate: signUp } = useSignUp();
const [currentIndex, setCurrentIndex] = useState(0);
@@ -52,6 +54,14 @@ export default function Step1() {
router.push('/sign-up-complete');
};
+ const handleSignUp = () => {
+ signUp({
+ name: username,
+ job: role,
+ tags: preferences,
+ });
+ };
+
return (
@@ -111,11 +121,24 @@ export default function Step1() {
-
+ {
+ handleSkipBtn();
+ handleSignUp();
+ }}
+ >
건너뛰기
{preferences.length >= 3 ? (
-
+ {
+ handleNextBtn();
+ handleSignUp();
+ }}
+ >
다음으로
) : (
diff --git a/src/hooks/users/useSignUp.ts b/src/hooks/users/useSignUp.ts
new file mode 100644
index 0000000..134df54
--- /dev/null
+++ b/src/hooks/users/useSignUp.ts
@@ -0,0 +1,7 @@
+import { SignupRequest, userSignUp } from '@/services/users/postSignUp';
+import { useMutation } from '@tanstack/react-query';
+
+export const useSignUp = () =>
+ useMutation({
+ mutationFn: (data) => userSignUp(data),
+ });
diff --git a/src/services/users/postSignUp.ts b/src/services/users/postSignUp.ts
new file mode 100644
index 0000000..6482a4e
--- /dev/null
+++ b/src/services/users/postSignUp.ts
@@ -0,0 +1,14 @@
+import { customFetch } from '@/utils/customFetch';
+
+export interface SignupRequest {
+ name: string;
+ job: string;
+ tags: string[];
+}
+
+export const userSignUp = async (payload: SignupRequest): Promise => {
+ return customFetch('/users/sign-up', {
+ method: 'POST',
+ body: JSON.stringify(payload),
+ });
+};
From 952bdb4fe05b2d3aae5ec15fac32d2096397f82d Mon Sep 17 00:00:00 2001
From: Sinji
Date: Wed, 28 May 2025 18:44:48 +0900
Subject: [PATCH 4/4] =?UTF-8?q?fix:=20=ED=97=A4=EB=8D=94=20=EB=A0=8C?=
=?UTF-8?q?=EB=8D=94=EB=A7=81=20=EC=9D=B4=EC=8A=88=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/components/ui/Header/index.tsx | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/src/components/ui/Header/index.tsx b/src/components/ui/Header/index.tsx
index 6b0a34f..734431d 100644
--- a/src/components/ui/Header/index.tsx
+++ b/src/components/ui/Header/index.tsx
@@ -1,5 +1,6 @@
'use client';
+import { useEffect, useState } from 'react';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { cn } from '@/lib/utils';
@@ -8,6 +9,7 @@ import Logo from '@/assets/logo.svg';
export default function Header() {
const pathname = usePathname();
+ const [isLogin, setIsLogin] = useState(false);
const menus = [
{ label: '조언받기', href: '/advice' },
@@ -15,10 +17,11 @@ export default function Header() {
{ label: '보관함', href: '/archive' },
];
- {
- /* TODO : 쿠키에서 로그인 여부 받아서 수정할 수 있도록 하기 */
- }
- const isLogin = true;
+ useEffect(() => {
+ const token = localStorage.getItem('token');
+ const user = localStorage.getItem('user');
+ setIsLogin(!!(token && user));
+ }, []);
return (
@@ -29,7 +32,6 @@ export default function Header() {