diff --git a/src/components/app-sidebar.tsx b/src/components/app-sidebar.tsx index 5f90f3f122f098b3300c21622b2b4cd98408fadb..9db571b1bff6e35b7a80a73715099cb50348fca7 100644 --- a/src/components/app-sidebar.tsx +++ b/src/components/app-sidebar.tsx @@ -17,7 +17,6 @@ import { import { ProjectSwitcher } from '@/components/project-switcher'; const data = { - projects: ['aolda_edu', 'proxy_manager', 'blog'], menus: [ { title: '웹 프록시 서버', @@ -58,15 +57,15 @@ const data = { }; export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) { - const { token } = useAuthStore(); + const { token, selectedProject } = useAuthStore(); const location = useLocation(); const selected = location.pathname.split('/')[1] || ''; return ( <Sidebar className="top-(--header-height) h-[calc(100svh-var(--header-height))]!" {...props}> - {token ? ( + {token && selectedProject ? ( <SidebarHeader> - <ProjectSwitcher projects={data.projects} defaultProject={data.projects[0]} /> + <ProjectSwitcher /> </SidebarHeader> ) : null} <SidebarContent> @@ -78,7 +77,7 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) { {item.items.map((item) => ( <SidebarMenuItem key={item.title}> <SidebarMenuButton asChild isActive={selected === item.url}> - <Link to={item.url} aria-disabled={token === null}> + <Link to={item.url} aria-disabled={!token || !selectedProject}> <item.icon /> {item.title} </Link> diff --git a/src/components/project-switcher.tsx b/src/components/project-switcher.tsx index 485b5baabab982b380c8134e315ac272a7f3612d..1a78082c84386c71a7dab508668dae386fed3dd6 100644 --- a/src/components/project-switcher.tsx +++ b/src/components/project-switcher.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { useAuthStore } from '@/stores/authStore'; import { Check, ChevronsUpDown, GalleryVerticalEnd } from 'lucide-react'; import { DropdownMenu, @@ -8,8 +8,8 @@ import { } from '@/components/ui/dropdown-menu'; import { SidebarMenu, SidebarMenuButton, SidebarMenuItem } from '@/components/ui/sidebar'; -export function ProjectSwitcher({ projects, defaultProject }: { projects: string[]; defaultProject: string }) { - const [selectedProject, setSelectedProject] = React.useState(defaultProject); +export function ProjectSwitcher() { + const { projects, selectedProject, setSelectedProject } = useAuthStore(); return ( <SidebarMenu> @@ -24,16 +24,22 @@ export function ProjectSwitcher({ projects, defaultProject }: { projects: string <GalleryVerticalEnd className="size-4" /> </div> <div className="flex flex-col gap-0.5 leading-none"> - <span className="font-semibold">Project</span> - <span className="">{selectedProject}</span> + {selectedProject ? ( + <> + <span className="font-semibold">Project</span> + <span>{selectedProject.name}</span> + </> + ) : ( + <span className="text-muted-foreground">프로젝트를 선택해주세요</span> + )} </div> <ChevronsUpDown className="ml-auto" /> </SidebarMenuButton> </DropdownMenuTrigger> <DropdownMenuContent className="w-[--radix-dropdown-menu-trigger-width]" align="start"> {projects.map((project) => ( - <DropdownMenuItem key={project} onSelect={() => setSelectedProject(project)}> - {project} {project === selectedProject && <Check className="ml-auto" />} + <DropdownMenuItem key={project.id} onSelect={() => setSelectedProject(project)}> + {project.name} {project.id === selectedProject?.id && <Check className="ml-auto" />} </DropdownMenuItem> ))} </DropdownMenuContent> diff --git a/src/components/site-header.tsx b/src/components/site-header.tsx index ef6ec73708bf715616f6f585e07791d72b29ce93..908573040b7b803a935b62a536618907bfa1d939 100644 --- a/src/components/site-header.tsx +++ b/src/components/site-header.tsx @@ -16,7 +16,7 @@ import { export function SiteHeader() { const navigate = useNavigate(); const { toggleSidebar } = useSidebar(); - const { token, logout } = useAuthStore(); + const { token, username, logout } = useAuthStore(); const handleLogout = () => { logout(); @@ -36,11 +36,11 @@ export function SiteHeader() { <DropdownMenu> <DropdownMenuTrigger asChild className="ml-auto cursor-pointer"> <Avatar className="w-10 h-10 border"> - <AvatarFallback>{'admin'.charAt(0)}</AvatarFallback> + <AvatarFallback>{username.charAt(0)}</AvatarFallback> </Avatar> </DropdownMenuTrigger> <DropdownMenuContent align="end"> - <DropdownMenuLabel>닉네임</DropdownMenuLabel> + <DropdownMenuLabel>{username}</DropdownMenuLabel> <DropdownMenuSeparator /> <DropdownMenuItem onClick={handleLogout} className="cursor-pointer"> <LogOut /> diff --git a/src/stores/authStore.ts b/src/stores/authStore.ts index 28d337e6874565d7af2ff8df6b595d862c11e393..4dfbc7cdede37844816eb4941d0cfb72afcece69 100644 --- a/src/stores/authStore.ts +++ b/src/stores/authStore.ts @@ -1,8 +1,14 @@ import { create } from 'zustand'; import { persist } from 'zustand/middleware'; +import { Project } from '@/types/project'; export interface AuthStore { token: string | null; + username: string; + isAdmin: boolean; + projects: Project[]; + selectedProject: Project | null; + setSelectedProject: (project: Project) => void; login: (username: string, password: string) => void; logout: () => void; } @@ -11,6 +17,11 @@ export const useAuthStore = create<AuthStore>()( persist( (set) => ({ token: null, + username: '', + isAdmin: false, + projects: [], + selectedProject: null, + setSelectedProject: (project) => set({ selectedProject: project }), login: async (username, password) => { const response = await fetch('/api/auth/login', { method: 'POST', @@ -23,11 +34,11 @@ export const useAuthStore = create<AuthStore>()( } const token = response.headers.get('X-Subject-Token')!; - console.log(token); + const { isAdmin, projects } = await response.json(); - set({ token }); + set({ token, username, isAdmin, projects, selectedProject: projects[0] }); }, - logout: () => set({ token: null }), + logout: () => set({ token: null, username: '', isAdmin: false, projects: [], selectedProject: null }), }), { name: 'authStorage' } ) diff --git a/src/types/project.ts b/src/types/project.ts new file mode 100644 index 0000000000000000000000000000000000000000..d7e3291637346bfa44de48ecbf59fcb5e18263a5 --- /dev/null +++ b/src/types/project.ts @@ -0,0 +1,4 @@ +export interface Project { + id: string; + name: string; +}