Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/api/auth/login.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type { AuthResponse, LoginRequest } from '../../types/auth';
import apiClient from '../apiClient';
import apiClient from '@/api/apiClient';
import type { LoginRequest, LoginResponse } from '@/types/auth';

export default async function login(data: LoginRequest): Promise<AuthResponse> {
const response = await apiClient.post<AuthResponse>('/auth/login', data);
export default async function login(
data: LoginRequest
): Promise<LoginResponse> {
const response = await apiClient.post<LoginResponse>('/auth/login', data);
return response.data;
}
7 changes: 7 additions & 0 deletions src/api/auth/logout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import apiClient from '@/api/apiClient';
import type { LogoutResponse } from '@/types/auth';

export default async function logout(): Promise<LogoutResponse> {
const response = await apiClient.post<LogoutResponse>('/auth/logout');
return response.data;
}
7 changes: 0 additions & 7 deletions src/api/auth/me.ts

This file was deleted.

20 changes: 12 additions & 8 deletions src/api/auth/signup.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import type { AuthResponse, SignUpRequest } from '../../types/auth';
import apiClient from '../apiClient';
import apiClient from '@/api/apiClient';
import type { SignUpRequest, SignUpResponse } from '@/types/auth';

export default async function signup(
data: SignUpRequest
): Promise<AuthResponse> {
): Promise<SignUpResponse> {
const formData = new FormData();

formData.append('username', data.username);
formData.append('password', data.password);
formData.append('email', data.email);
formData.append('name', data.name);
formData.append('password', data.password);

if (data.photo) {
formData.append('photo', data.photo); // λ°±μ—”λ“œ ν•„λ“œλͺ…κ³Ό 'photo' μΌμΉ˜μ‹œν‚€κΈ°
if (data.profileImage) {
formData.append('profileImage', data.profileImage);
}

const response = await apiClient.post<AuthResponse>('/auth/signup', formData);
const response = await apiClient.post<SignUpResponse>(
'/auth/signup',
formData
);

return response.data;
}
9 changes: 6 additions & 3 deletions src/api/auth/social.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import type { AuthResponse, SocialLoginRequest } from '../../types/auth';
import type { SocialLoginRequest, SocialLoginResponse } from '../../types/auth';
import apiClient from '../apiClient';

export default async function social(
data: SocialLoginRequest
): Promise<AuthResponse> {
const response = await apiClient.post<AuthResponse>('/auth/social', data);
): Promise<SocialLoginResponse> {
const response = await apiClient.post<SocialLoginResponse>(
'/auth/social',
data
);
return response.data;
}
7 changes: 7 additions & 0 deletions src/api/users/me.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import apiClient from '@/api/apiClient';
import type { GetMeResponse } from '@/types/users';

export default async function getMe(): Promise<GetMeResponse> {
const response = await apiClient.get('/auth/me');
return response.data;
}
23 changes: 9 additions & 14 deletions src/components/EventCardView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,29 @@ import {
ItemMedia,
ItemTitle,
} from '@/components/ui/item';
import type { Events } from '@/types/schema';
import type { Event } from '@/types/event';
import { getShortenedDate } from '@/utils/date';
import { ChevronRightIcon, Plus } from 'lucide-react';
import { Link } from 'react-router';
import { Button } from './ui/button';

type Event = Events & { guests: number; registration_start: string | null };

function getDateLabel(
startDateString: string | null,
endDateString: string | null
startEpoch: number | undefined,
endEpoch: number | undefined
) {
if (!endDateString) {
if (!endEpoch) {
return 'μƒμ‹œ λͺ¨μ§‘ 쀑';
}

const now = new Date();
const endDate = new Date(endDateString!);
const endDate = new Date(endEpoch);

if (startDateString && now < new Date(startDateString)) {
return `${getShortenedDate(startDateString)}λΆ€ν„° λͺ¨μ§‘`;
if (startEpoch && now < new Date(startEpoch)) {
return `${getShortenedDate(startEpoch)}λΆ€ν„° λͺ¨μ§‘`;
}

if (now <= endDate) {
return `${getShortenedDate(endDateString)}κΉŒμ§€ λͺ¨μ§‘`;
return `${getShortenedDate(endEpoch)}κΉŒμ§€ λͺ¨μ§‘`;
}

return 'λͺ¨μ§‘ 마감';
Expand Down Expand Up @@ -84,10 +82,7 @@ export default function EventCardView({ events }: { events: Event[] }) {
</h2>
</ItemTitle>
<ItemDescription>
{getDateLabel(
event.registration_start,
event.registration_deadline
)}
{getDateLabel(undefined, event.registrationDeadline)}
</ItemDescription>
</ItemContent>
<ItemActions>
Expand Down
15 changes: 3 additions & 12 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,8 @@ import ProfileButton from '@/components/ProfileButton';
import useAuth from '@/hooks/useAuth';
import { Link, NavLink } from 'react-router';

const userExample = {
id: 1,
email: 'user@example.com',
name: 'λ°•μ€€μ˜',
profileImage: 'https://github.com/shadcn.png',
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z',
};

export default function Header() {
const { isLoggedIn, handleLogout } = useAuth();
const { user, isLoggedIn, handleLogout } = useAuth();

const linkClassName = (isActive: boolean) => `
h-[42px] items-center px-4 py-2 rounded-md text-black font-semibold
Expand All @@ -26,7 +17,7 @@ export default function Header() {
λͺ¨μ΄μƒ€
</Link>
<div className="items-center space-x-2">
{!isLoggedIn ? (
{!isLoggedIn || !user ? (
<>
<NavLink
to="/login"
Expand All @@ -42,7 +33,7 @@ export default function Header() {
</NavLink>
</>
) : (
<ProfileButton user={userExample} handleLogout={handleLogout} />
<ProfileButton user={user} handleLogout={handleLogout} />
)}
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/ProfileButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import type { User } from '@/types/auth';
import type { User } from '@/types/user';

interface ProfileButtonProps {
user: User;
Expand Down
34 changes: 15 additions & 19 deletions src/hooks/useAuth.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { useNavigate } from 'react-router';
import loginApi from '../api/auth/login';
import getMeApi from '../api/auth/me';
import signupApi from '../api/auth/signup';
import socialApi from '../api/auth/social';
import loginApi from '@/api/auth/login';
import logoutApi from '@/api/auth/logout';
import signupApi from '@/api/auth/signup';
import socialApi from '@/api/auth/social';
import getMeApi from '@/api/users/me';
import useAuthStore from '@/hooks/useAuthStore';
import type {
LoginRequest,
SignUpRequest,
SocialLoginRequest,
} from '../types/auth';
import useAuthStore from './useAuthStore';
} from '@/types/auth';
import { useNavigate } from 'react-router';

export default function useAuth() {
const navigate = useNavigate();
Expand All @@ -20,7 +21,8 @@ export default function useAuth() {
// 1. 이메일 둜그인 둜직
const handleLogin = async (data: LoginRequest) => {
try {
const { user, token } = await loginApi(data);
const { token } = await loginApi(data);
const user = await getMeApi();
login(user, token); // Zustand μŠ€ν† μ–΄ μ—…λ°μ΄νŠΈ
navigate('/'); // 메인 νŽ˜μ΄μ§€λ‘œ 이동
} catch (error) {
Expand All @@ -32,9 +34,8 @@ export default function useAuth() {
// 2. 이메일 νšŒμ›κ°€μž… 둜직
const handleSignUp = async (data: SignUpRequest) => {
try {
const { user, token } = await signupApi(data);
login(user, token);
navigate('/');
await signupApi(data);
navigate('/login');
} catch (error) {
console.error('Signup failed:', error);
alert('νšŒμ›κ°€μž… 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.');
Expand All @@ -44,7 +45,7 @@ export default function useAuth() {
// 3. μ†Œμ…œ 둜그인 둜직
const handleSocialLogin = async (data: SocialLoginRequest) => {
try {
const { user, token } = await socialApi(data);
const { token, user } = await socialApi(data);
login(user, token);
navigate('/');
} catch (error) {
Expand All @@ -68,16 +69,12 @@ export default function useAuth() {
};

// 5. λ‘œκ·Έμ•„μ›ƒ 둜직
const handleLogout = () => {
const handleLogout = async () => {
await logoutApi();
logout(); // Zustand μƒνƒœ μ΄ˆκΈ°ν™”
navigate('/login');
};

// 6. κ΄€λ¦¬μž 확인
const isAdmin = (ownerId: number | undefined) => {
return isLoggedIn && user?.id === ownerId;
};

return {
user,
isLoggedIn,
Expand All @@ -86,6 +83,5 @@ export default function useAuth() {
handleSocialLogin,
refreshUser,
handleLogout,
isAdmin,
};
}
2 changes: 1 addition & 1 deletion src/hooks/useAuthStore.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { User } from '@/types/user';
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import type { User } from '../types/auth';

interface AuthState {
user: User | null;
Expand Down
44 changes: 12 additions & 32 deletions src/routes/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,18 @@ import { Link } from 'react-router';

const events = [
{
id: 1,
title: '제2회 기획 μ„Έλ―Έλ‚˜',
description:
'일정섀λͺ… 일정섀λͺ… 일정섀λͺ… 일정섀λͺ… 일정섀λͺ… 일정섀λͺ… 일정섀λͺ… 일정섀λͺ… 일정섀λͺ… 일정섀λͺ… 일정섀λͺ… 일정섀λͺ… 일정섀λͺ… 일정섀λͺ… 일정섀λͺ… 일정섀λͺ… ...',
location: 'μ„œμšΈλŒ€',
start_at: '2026-02-02T18:00:00Z',
end_at: '2026-02-02T20:00:00Z',
guests: 12,
capacity: 10,
waitlist_enabled: true,
registration_start: '2026-01-20T09:00:00Z',
registration_deadline: '2026-02-02T17:00:00Z',
created_by: 123,
created_at: '2026-01-14T00:00:00Z',
updated_at: '2026-01-14T00:00:00Z',
},
{
id: 2,
title: '2026 와컀톀',
description:
'κ·Έλ™μ•ˆ 각자의 μœ„μΉ˜μ—μ„œ λͺ°λ‘ν•΄ 온 μ—¬λŸ¬λΆ„λ“€μ΄ ν•œμžλ¦¬μ— λͺ¨μ—¬ 뜨거운 μ—λ„ˆμ§€λ₯Ό λ‚˜λˆ„κ³ , 무박 2일간 κ°œλ°œμ— μ§‘μ€‘ν•˜λ©° 즐길 수 μžˆλŠ” ν–‰μ‚¬μž…λ‹ˆλ‹€.',
location: 'μ„±μˆ˜ μ—˜λ¦¬μŠ€λž© λΌμš΄μ§€',
start_at: '2026-01-01T18:00:00Z',
end_at: '2026-02-13T20:00:00Z',
guests: 6,
capacity: 10,
waitlist_enabled: true,
registration_start: '2025-02-01T09:00:00Z',
registration_deadline: '2026-02-02T17:00:00Z',
created_by: 124,
created_at: '2026-01-14T00:00:00Z',
updated_at: '2026-01-14T00:00:00Z',
id: 0,
title: 'string',
description: 'string',
location: 'string',
startAt: 0,
endAt: 0,
capacity: 0,
waitlistEnabled: true,
registrationDeadline: 0,
createdBy: 0,
createdAt: 0,
updatedAt: 0,
},
];

Expand Down
12 changes: 6 additions & 6 deletions src/routes/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { GOOGLE_AUTH_URL, KAKAO_AUTH_URL } from '@/constants/auth';
import useAuth from '@/hooks/useAuth';
import { useState } from 'react';
import { Link } from 'react-router';
import { GOOGLE_AUTH_URL, KAKAO_AUTH_URL } from '../constants/auth';
import useAuth from '../hooks/useAuth';

export default function Login() {
const [username, setUsername] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const { handleLogin } = useAuth();

const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
handleLogin({ username, password });
handleLogin({ email, password });
};

return (
Expand All @@ -37,8 +37,8 @@ export default function Login() {
required
className="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-t-md focus:outline-none focus:ring-blue-500 focus:border-blue-500 focus:z-10 sm:text-sm"
placeholder="이메일 (아이디)"
value={username}
onChange={(e) => setUsername(e.target.value)}
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<div>
Expand Down
Loading