Skip to content
1 change: 0 additions & 1 deletion src/frontend/apps/web/src/entities/auth/index.ts

This file was deleted.

4 changes: 3 additions & 1 deletion src/frontend/apps/web/src/entities/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export type { AuthToken } from './auth';
export type { AuthToken } from './auth/model/auth-type';
export type { User } from './user/model/user-type';
export { useUserStore } from './user/model/user-store';
Empty file.
17 changes: 17 additions & 0 deletions src/frontend/apps/web/src/entities/user/model/user-store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { create } from 'zustand';
import { User } from './user-type';

type UserStore = {
user: User | null;
setUser: (user: User | null) => void;
};
export const useUserStore = create<UserStore>((set) => ({
user:
typeof window !== 'undefined'
? JSON.parse(localStorage.getItem('user') || 'null')
: null,
setUser: (user) => {
localStorage.setItem('user', JSON.stringify(user));
set(() => ({ user }));
},
}));
5 changes: 5 additions & 0 deletions src/frontend/apps/web/src/entities/user/model/user-type.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export type User = {
userId: number;
nickname: string;
profileImage: string;
};
14 changes: 12 additions & 2 deletions src/frontend/apps/web/src/features/auth/api/requestLogin.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,19 @@

import { postRequest } from '@/src/shared/services';
import { cookies } from 'next/headers';
import { AuthToken, User } from '@/src/entities';

type LoginRes = {
user: User;
token: AuthToken;
};
type LoginReq = {
platform: string;
redirectUri: string;
};

export const requestLogin = async (authorizationCode: string) => {
const { user, token } = await postRequest<any, any>(
const { user, token } = await postRequest<LoginRes, LoginReq>(
'gateway',
`/api/v1/user/login?authorizationCode=${authorizationCode}`,
{
Expand All @@ -16,7 +26,7 @@ export const requestLogin = async (authorizationCode: string) => {
const cookieOptions = {
secure: process.env.MODE === 'production',
};
cookies().set('userId', user.userId, cookieOptions);
cookies().set('userId', String(user.userId), cookieOptions);
cookies().set('accessToken', token.accessToken, cookieOptions);
cookies().set('refreshToken', token.refreshToken, cookieOptions);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@ import { useSearchParams } from 'next/navigation';
import { useRouter } from 'next/navigation';
import { useEffect } from 'react';
import { requestLogin } from '../api/requestLogin.api';
import { useUserStore } from '@/src/entities';

export const useLoginRedirect = () => {
const router = useRouter();
const searchParams = useSearchParams();
const code = searchParams.get('code');
const setUser = useUserStore((state) => state.setUser);

useEffect(() => {
if (!code) {
alert('인가 코드가 없습니다. 다시 로그인 해주세요.');
router.replace('/');
router.push('/');
return;
}

Expand All @@ -24,11 +26,12 @@ export const useLoginRedirect = () => {
throw new Error('사용자 정보가 없습니다.');
}
localStorage.setItem('user', JSON.stringify(user));
router.replace('/stock');
setUser(user);
router.push('/stock');
} catch (err) {
console.error('로그인 실패:', err);
alert('로그인에 실패했습니다. 다시 로그인 해주세요.');
router.replace('/');
router.push('/');
}
};

Expand Down
20 changes: 20 additions & 0 deletions src/frontend/apps/web/src/features/auth/model/use-logout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use client';

import { useUserStore } from '@/src/entities';
import { useRouter } from 'next/navigation';

export const useLogout = () => {
const router = useRouter();
const setUser = useUserStore((state) => state.setUser);

return () => {
localStorage.removeItem('user');
setUser(null);
document.cookie =
'accessToken=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
document.cookie =
'refreshToken=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
document.cookie = 'userId=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
router.push('/');
};
};
5 changes: 5 additions & 0 deletions src/frontend/apps/web/src/features/auth/ui/logout-button.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
'use client';

import { Button } from '@workspace/ui/components';
import { useLogout } from '../model/use-logout';

const LogoutButton = () => {
const handleLogout = useLogout();
return (
<Button
variant="outline"
size="sm"
className="w-full text-xs"
onClick={handleLogout}
>
LOGOUT
</Button>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
'use client';

import { useUserStore } from '@/src/entities';
import { Button, Input, Label } from '@workspace/ui/components';
import { Pencil } from 'lucide-react';

const ProfileNickname = () => {
//임시변수
const isNameEditMode = false;
const name = '공작새';
const nickname = useUserStore((state) => state.user?.nickname ?? '');

return (
<div className="flex w-full items-center space-x-2">
Expand All @@ -15,7 +15,7 @@ const ProfileNickname = () => {
id="name"
disabled={!isNameEditMode}
placeholder="Enter your name"
value={name}
value={nickname}
/>
<Button
variant="ghost"
Expand Down
17 changes: 11 additions & 6 deletions src/frontend/apps/web/src/features/user/ui/profile-picture.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
'use client';

import { Avatar, AvatarFallback, AvatarImage, Button, Input } from '@workspace/ui/components';
import { useUserStore } from '@/src/entities';
import {
Avatar,
AvatarFallback,
AvatarImage,
Button,
Input,
} from '@workspace/ui/components';

const ProfilePicture = () => {
//임시변수
const isPictureEditMode = false;
const pictureUrl = 'https://github.com/shadcn.png';

const profileImage = useUserStore((state) => state.user?.profileImage ?? '');
return (
<div className="w-full flex flex-col items-end">
<div className="w-full flex flex-col items-end gap-1">
{isPictureEditMode ? (
<Input
id="picture"
Expand All @@ -19,7 +24,7 @@ const ProfilePicture = () => {
variant="default"
className="w-full h-full"
>
<AvatarImage src={pictureUrl} />
<AvatarImage src={profileImage} />
<AvatarFallback>Profile Image</AvatarFallback>
</Avatar>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use client';

import {
Avatar,
AvatarFallback,
Expand All @@ -8,16 +10,18 @@ import {
} from '@workspace/ui/components';
import { CircleUserRound } from 'lucide-react';
import ProfilePopoverContent from './profile-popover-content';
import { useUserStore } from '@/src/entities';

const ProfilePopover = () => {
const profileImage = useUserStore((state) => state.user?.profileImage ?? '');
return (
<Popover>
<PopoverTrigger asChild>
<Avatar
variant="default"
className="cursor-pointer"
>
<AvatarImage src="https://github.com/shadcn.png" />
<AvatarImage src={profileImage} />
<AvatarFallback>
<CircleUserRound size={40} />
</AvatarFallback>
Expand Down