Skip to content

Commit

Permalink
feature: /wallet/me api 연결 (#14)
Browse files Browse the repository at this point in the history
* feat: 사용자 지갑 및 닉네임 호출 api 구현

* refactor: api 공통 로직 함수로 분리

* refactor: userStorage 추가

* feat: UserContext 사용하도록 변경

* fix: apply review
  • Loading branch information
Najeong-Kim authored Feb 8, 2025
1 parent b27bc17 commit c905c6c
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 1 deletion.
47 changes: 47 additions & 0 deletions src/app/api/[...path]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { NextRequest, NextResponse } from "next/server";

async function handleRequest(req: NextRequest, params: { path: string[] }) {
try {
const API_HOST = process.env.API_HOST;
if (!API_HOST) {
throw new Error("API_HOST is not defined");
}

const endpoint = params.path.join("/");
const fullUrl = `${API_HOST}/api/v1/${endpoint}`;

if (req.method === "POST") {
console.log("Proxying POST request to:", fullUrl);
}

const fetchOptions: RequestInit = {
method: req.method,
headers: {
"Content-Type": "application/json",
},
};

if (req.method === "POST") {
const body = await req.json();
fetchOptions.body = JSON.stringify(
req.cookies.get("token")
? { ...body, eoa: req.cookies.get("token")?.value }
: body
);
}

const res = await fetch(fullUrl, fetchOptions);
const data = await res.json();
return NextResponse.json(data, { status: res.status });
} catch (error: unknown) {
return NextResponse.json({ error: (error as Error).message }, { status: 500 });
}
}

export async function GET(req: NextRequest, { params }: { params: { path: string[] } }) {
return handleRequest(req, params);
}

export async function POST(req: NextRequest, { params }: { params: { path: string[] } }) {
return handleRequest(req, params);
}
5 changes: 5 additions & 0 deletions src/app/chat/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
'use client';

import { useContext } from 'react';
import QuestionRecommendation from './components/QuestionRecommendation';
import SearchBar from './components/SearchBar';
import UserContext from '@/contexts/UserContext';

export default function ChatPage() {
const { user } = useContext(UserContext);

console.log(user);
return (
<div className="relative size-full bg-gray-100">
<QuestionRecommendation />
Expand Down
5 changes: 4 additions & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import localFont from 'next/font/local';

import ResponsiveContainer from '@/components/common/ResponsiveContainer';
import { getInitialViewport } from '@/utils/viewport';
import { UserProvider } from '@/contexts/UserContext';

import './globals.css';

Expand All @@ -29,7 +30,9 @@ export default async function RootLayout({
<html lang="ko" suppressHydrationWarning className={`${pretendard.variable}`}>
<body>
<ThemeProvider attribute="class">
<ResponsiveContainer initialWidth={initialWidth}>{children}</ResponsiveContainer>
<UserProvider>
<ResponsiveContainer initialWidth={initialWidth}>{children}</ResponsiveContainer>
</UserProvider>
</ThemeProvider>
</body>
</html>
Expand Down
23 changes: 23 additions & 0 deletions src/contexts/UserContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use client';

import { useUser } from '@/hooks/useUser';
import { createContext } from 'react';

interface UserContextType {
user: {
token: string;
nickname: string;
} | null;
}

const UserContext = createContext<UserContextType>({
user: null,
});

export default UserContext;

export const UserProvider = ({ children }: { children: React.ReactNode }) => {
const { data: user } = useUser();

return <UserContext.Provider value={{ user }}>{children}</UserContext.Provider>;
};
57 changes: 57 additions & 0 deletions src/hooks/useUser.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { useEffect, useState } from 'react';

const STORAGE_KEY = 'for-the-block.storage';

const userStorage = {
getUserData: () => {
const saved = localStorage.getItem(STORAGE_KEY);
return saved ? JSON.parse(saved) : null;
},
saveUserData: (userData: { token: string; nickname: string }) => {
localStorage.setItem(STORAGE_KEY, JSON.stringify(userData));
},
};

export const useUser = () => {
const [data, setData] = useState<{
token: string;
nickname: string;
} | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);

useEffect(() => {
const fetchUser = async () => {
try {
const savedUser = userStorage.getUserData();
if (savedUser) {
setData(savedUser);
setIsLoading(false);
return;
}

const response = await fetch('/api/wallet/me');
if (!response.ok) {
throw new Error('Failed to fetch user data');
}

const fetchedData = await response.json();
const userData = {
token: fetchedData.ethereum_address,
nickname: fetchedData.nickname,
};

setData(userData);
userStorage.saveUserData(userData);
} catch (err: unknown) {
setError((err as Error).message);
} finally {
setIsLoading(false);
}
};

fetchUser();
}, []);

return { data, isLoading, error };
};

0 comments on commit c905c6c

Please sign in to comment.