diff --git a/attached_assets/스크린샷 2025-09-30 오전 3.44.56_1759171505632.png b/attached_assets/스크린샷 2025-09-30 오전 3.44.56_1759171505632.png new file mode 100644 index 0000000..8f28c9f Binary files /dev/null and b/attached_assets/스크린샷 2025-09-30 오전 3.44.56_1759171505632.png differ diff --git a/client/src/components/LoginModal.tsx b/client/src/components/LoginModal.tsx new file mode 100644 index 0000000..bcd31ad --- /dev/null +++ b/client/src/components/LoginModal.tsx @@ -0,0 +1,121 @@ +import { useState } from "react"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"; +import { useToast } from "@/hooks/use-toast"; +import { queryClient } from "@/lib/queryClient"; + +interface LoginModalProps { + isOpen: boolean; + onClose: () => void; +} + +export default function LoginModal({ isOpen, onClose }: LoginModalProps) { + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const [isLoading, setIsLoading] = useState(false); + const { toast } = useToast(); + + const handleLogin = async (e: React.FormEvent) => { + e.preventDefault(); + setIsLoading(true); + + try { + const response = await fetch("/api/login", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + credentials: "include", + body: JSON.stringify({ username, password }), + }); + + if (response.ok) { + const user = await response.json(); + toast({ + title: "로그인 성공", + description: `환영합니다, ${user.firstName}님!`, + }); + + // Invalidate auth queries to refresh user state + queryClient.invalidateQueries({ queryKey: ["/api/auth/user"] }); + + // Reset form and close modal + setUsername(""); + setPassword(""); + onClose(); + } else { + const error = await response.json(); + toast({ + title: "로그인 실패", + description: error.message || "잘못된 아이디 또는 비밀번호입니다.", + variant: "destructive", + }); + } + } catch (error) { + toast({ + title: "로그인 오류", + description: "로그인 중 오류가 발생했습니다.", + variant: "destructive", + }); + } finally { + setIsLoading(false); + } + }; + + return ( + + ); +} \ No newline at end of file diff --git a/client/src/pages/Home.tsx b/client/src/pages/Home.tsx index 0023cd9..47e7ea8 100644 --- a/client/src/pages/Home.tsx +++ b/client/src/pages/Home.tsx @@ -1,14 +1,41 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { useAuth } from "@/hooks/useAuth"; -import { Search, Settings } from "lucide-react"; +import { Search, Settings, User, LogOut } from "lucide-react"; +import { useState } from "react"; import MainContent from "@/components/MainContent"; +import LoginModal from "@/components/LoginModal"; +import { useToast } from "@/hooks/use-toast"; +import { queryClient } from "@/lib/queryClient"; export default function Home() { - const { user } = useAuth(); + const { user, isAuthenticated } = useAuth(); + const [isLoginModalOpen, setIsLoginModalOpen] = useState(false); + const { toast } = useToast(); - const handleLogout = () => { - window.location.href = "/api/logout"; + const handleLogout = async () => { + try { + const response = await fetch("/api/logout", { + method: "POST", + credentials: "include", + }); + + if (response.ok) { + toast({ + title: "로그아웃 완료", + description: "성공적으로 로그아웃되었습니다.", + }); + + // Invalidate auth queries to refresh user state + queryClient.invalidateQueries({ queryKey: ["/api/auth/user"] }); + } + } catch (error) { + toast({ + title: "로그아웃 오류", + description: "로그아웃 중 오류가 발생했습니다.", + variant: "destructive", + }); + } }; const handleAdminPage = () => { @@ -41,14 +68,43 @@ export default function Home() { /> - + {isAuthenticated && user ? ( + <> + + +