auto commit

This commit is contained in:
bangdk 2024-11-05 10:41:36 +09:00
parent 227efc7018
commit 130c1dcf1d
35 changed files with 991 additions and 32 deletions

View File

@ -30,6 +30,7 @@
"axios": "^1.7.7",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"critters": "^0.0.25",
"date-fns": "^4.1.0",
"jose": "^5.9.6",
"js-cookie": "^3.0.5",

View File

@ -0,0 +1,23 @@
"use client";
import React from "react";
import { Construction } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
export default function SystemPage() {
return (
<div className="container mx-auto py-8">
<Card className="border-2 border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<Construction className="h-16 w-16 text-muted-foreground mb-4" />
<h2 className="text-2xl font-semibold text-muted-foreground mb-2">
</h2>
<p className="text-sm text-muted-foreground">
.
</p>
</CardContent>
</Card>
</div>
);
}

View File

@ -0,0 +1,27 @@
import React from "react";
import { GeneralSidebar } from "@/components/general/GeneralSidebar";
import { GeneralHeader } from "@/components/general/GeneralHeader";
const GeneralLayout = ({ children }: { children: React.ReactNode }) => {
return (
<div className="h-screen flex">
{/* 왼쪽 사이드바 */}
<aside className="w-64 h-screen flex-shrink-0 bg-gray-800">
<GeneralSidebar />
</aside>
{/* 오른쪽 메인 영역 */}
<div className="flex-1 flex flex-col">
{/* 상단 헤더 */}
<header className="h-16 bg-white border-b">
<GeneralHeader />
</header>
{/* 메인 컨텐츠 영역 */}
<main className="flex-1 overflow-auto bg-gray-50 p-6">{children}</main>
</div>
</div>
);
};
export default GeneralLayout;

View File

@ -0,0 +1,23 @@
"use client";
import React from "react";
import { Construction } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
export default function SystemPage() {
return (
<div className="container mx-auto py-8">
<Card className="border-2 border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<Construction className="h-16 w-16 text-muted-foreground mb-4" />
<h2 className="text-2xl font-semibold text-muted-foreground mb-2">
</h2>
<p className="text-sm text-muted-foreground">
.
</p>
</CardContent>
</Card>
</div>
);
}

View File

@ -0,0 +1,23 @@
"use client";
import React from "react";
import { Construction } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
export default function SystemPage() {
return (
<div className="container mx-auto py-8">
<Card className="border-2 border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<Construction className="h-16 w-16 text-muted-foreground mb-4" />
<h2 className="text-2xl font-semibold text-muted-foreground mb-2">
</h2>
<p className="text-sm text-muted-foreground">
.
</p>
</CardContent>
</Card>
</div>
);
}

View File

@ -0,0 +1,23 @@
"use client";
import React from "react";
import { Construction } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
export default function SystemPage() {
return (
<div className="container mx-auto py-8">
<Card className="border-2 border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<Construction className="h-16 w-16 text-muted-foreground mb-4" />
<h2 className="text-2xl font-semibold text-muted-foreground mb-2">
</h2>
<p className="text-sm text-muted-foreground">
.
</p>
</CardContent>
</Card>
</div>
);
}

View File

@ -0,0 +1,23 @@
"use client";
import React from "react";
import { Construction } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
export default function SystemPage() {
return (
<div className="container mx-auto py-8">
<Card className="border-2 border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<Construction className="h-16 w-16 text-muted-foreground mb-4" />
<h2 className="text-2xl font-semibold text-muted-foreground mb-2">
</h2>
<p className="text-sm text-muted-foreground">
.
</p>
</CardContent>
</Card>
</div>
);
}

View File

@ -0,0 +1,27 @@
import React from "react";
import { GeneralSidebar } from "@/components/general/GeneralSidebar";
import { GeneralHeader } from "@/components/general/GeneralHeader";
const GeneralLayout = ({ children }: { children: React.ReactNode }) => {
return (
<div className="h-screen flex">
{/* 왼쪽 사이드바 */}
<aside className="w-64 h-screen flex-shrink-0 bg-gray-800">
<GeneralSidebar />
</aside>
{/* 오른쪽 메인 영역 */}
<div className="flex-1 flex flex-col">
{/* 상단 헤더 */}
<header className="h-16 bg-white border-b">
<GeneralHeader />
</header>
{/* 메인 컨텐츠 영역 */}
<main className="flex-1 overflow-auto bg-gray-50 p-6">{children}</main>
</div>
</div>
);
};
export default GeneralLayout;

View File

@ -0,0 +1,23 @@
"use client";
import React from "react";
import { Construction } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
export default function SystemPage() {
return (
<div className="container mx-auto py-8">
<Card className="border-2 border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<Construction className="h-16 w-16 text-muted-foreground mb-4" />
<h2 className="text-2xl font-semibold text-muted-foreground mb-2">
</h2>
<p className="text-sm text-muted-foreground">
.
</p>
</CardContent>
</Card>
</div>
);
}

View File

@ -0,0 +1,23 @@
"use client";
import React from "react";
import { Construction } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
export default function SystemPage() {
return (
<div className="container mx-auto py-8">
<Card className="border-2 border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<Construction className="h-16 w-16 text-muted-foreground mb-4" />
<h2 className="text-2xl font-semibold text-muted-foreground mb-2">
</h2>
<p className="text-sm text-muted-foreground">
.
</p>
</CardContent>
</Card>
</div>
);
}

View File

@ -1,5 +1,4 @@
// src/(equipment)/layout.tsx
import React from "react";
import { GeneralSidebar } from "@/components/general/GeneralSidebar";
import { GeneralHeader } from "@/components/general/GeneralHeader";

View File

@ -1 +1,25 @@
// src/(equipment)/maintenance/page.tsx
"use client";
import React from "react";
import { Construction } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
export default function SystemPage() {
return (
<div className="container mx-auto py-8">
<Card className="border-2 border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<Construction className="h-16 w-16 text-muted-foreground mb-4" />
<h2 className="text-2xl font-semibold text-muted-foreground mb-2">
</h2>
<p className="text-sm text-muted-foreground">
.
</p>
</CardContent>
</Card>
</div>
);
}

View File

@ -1 +1,25 @@
// src/(equipment)/monitoring/page.tsx
"use client";
import React from "react";
import { Construction } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
export default function SystemPage() {
return (
<div className="container mx-auto py-8">
<Card className="border-2 border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<Construction className="h-16 w-16 text-muted-foreground mb-4" />
<h2 className="text-2xl font-semibold text-muted-foreground mb-2">
</h2>
<p className="text-sm text-muted-foreground">
.
</p>
</CardContent>
</Card>
</div>
);
}

View File

@ -0,0 +1,23 @@
"use client";
import React from "react";
import { Construction } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
export default function SystemPage() {
return (
<div className="container mx-auto py-8">
<Card className="border-2 border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<Construction className="h-16 w-16 text-muted-foreground mb-4" />
<h2 className="text-2xl font-semibold text-muted-foreground mb-2">
</h2>
<p className="text-sm text-muted-foreground">
.
</p>
</CardContent>
</Card>
</div>
);
}

View File

@ -0,0 +1,23 @@
"use client";
import React from "react";
import { Construction } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
export default function SystemPage() {
return (
<div className="container mx-auto py-8">
<Card className="border-2 border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<Construction className="h-16 w-16 text-muted-foreground mb-4" />
<h2 className="text-2xl font-semibold text-muted-foreground mb-2">
</h2>
<p className="text-sm text-muted-foreground">
.
</p>
</CardContent>
</Card>
</div>
);
}

View File

@ -0,0 +1,23 @@
"use client";
import React from "react";
import { Construction } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
export default function SystemPage() {
return (
<div className="container mx-auto py-8">
<Card className="border-2 border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<Construction className="h-16 w-16 text-muted-foreground mb-4" />
<h2 className="text-2xl font-semibold text-muted-foreground mb-2">
</h2>
<p className="text-sm text-muted-foreground">
.
</p>
</CardContent>
</Card>
</div>
);
}

View File

@ -0,0 +1,23 @@
"use client";
import React from "react";
import { Construction } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
export default function SystemPage() {
return (
<div className="container mx-auto py-8">
<Card className="border-2 border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<Construction className="h-16 w-16 text-muted-foreground mb-4" />
<h2 className="text-2xl font-semibold text-muted-foreground mb-2">
</h2>
<p className="text-sm text-muted-foreground">
.
</p>
</CardContent>
</Card>
</div>
);
}

View File

@ -0,0 +1,23 @@
"use client";
import React from "react";
import { Construction } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
export default function SystemPage() {
return (
<div className="container mx-auto py-8">
<Card className="border-2 border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<Construction className="h-16 w-16 text-muted-foreground mb-4" />
<h2 className="text-2xl font-semibold text-muted-foreground mb-2">
</h2>
<p className="text-sm text-muted-foreground">
.
</p>
</CardContent>
</Card>
</div>
);
}

View File

@ -0,0 +1,23 @@
"use client";
import React from "react";
import { Construction } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
export default function SystemPage() {
return (
<div className="container mx-auto py-8">
<Card className="border-2 border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<Construction className="h-16 w-16 text-muted-foreground mb-4" />
<h2 className="text-2xl font-semibold text-muted-foreground mb-2">
</h2>
<p className="text-sm text-muted-foreground">
.
</p>
</CardContent>
</Card>
</div>
);
}

View File

@ -0,0 +1,28 @@
// src/(general)/layout.tsx
import React from "react";
import { GeneralSidebar } from "@/components/general/GeneralSidebar";
import { GeneralHeader } from "@/components/general/GeneralHeader";
const GeneralLayout = ({ children }: { children: React.ReactNode }) => {
return (
<div className="h-screen flex">
{/* 왼쪽 사이드바 */}
<aside className="w-64 h-screen flex-shrink-0 bg-gray-800">
<GeneralSidebar />
</aside>
{/* 오른쪽 메인 영역 */}
<div className="flex-1 flex flex-col">
{/* 상단 헤더 */}
<header className="h-16 bg-white border-b">
<GeneralHeader />
</header>
{/* 메인 컨텐츠 영역 */}
<main className="flex-1 overflow-auto bg-gray-50 p-6">{children}</main>
</div>
</div>
);
};
export default GeneralLayout;

View File

@ -0,0 +1,23 @@
"use client";
import React from "react";
import { Construction } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
export default function SystemPage() {
return (
<div className="container mx-auto py-8">
<Card className="border-2 border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<Construction className="h-16 w-16 text-muted-foreground mb-4" />
<h2 className="text-2xl font-semibold text-muted-foreground mb-2">
</h2>
<p className="text-sm text-muted-foreground">
.
</p>
</CardContent>
</Card>
</div>
);
}

View File

@ -0,0 +1,23 @@
"use client";
import React from "react";
import { Construction } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
export default function SystemPage() {
return (
<div className="container mx-auto py-8">
<Card className="border-2 border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<Construction className="h-16 w-16 text-muted-foreground mb-4" />
<h2 className="text-2xl font-semibold text-muted-foreground mb-2">
</h2>
<p className="text-sm text-muted-foreground">
.
</p>
</CardContent>
</Card>
</div>
);
}

View File

@ -0,0 +1,23 @@
"use client";
import React from "react";
import { Construction } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
export default function SystemPage() {
return (
<div className="container mx-auto py-8">
<Card className="border-2 border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<Construction className="h-16 w-16 text-muted-foreground mb-4" />
<h2 className="text-2xl font-semibold text-muted-foreground mb-2">
</h2>
<p className="text-sm text-muted-foreground">
.
</p>
</CardContent>
</Card>
</div>
);
}

View File

@ -0,0 +1,23 @@
"use client";
import React from "react";
import { Construction } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
export default function SystemPage() {
return (
<div className="container mx-auto py-8">
<Card className="border-2 border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<Construction className="h-16 w-16 text-muted-foreground mb-4" />
<h2 className="text-2xl font-semibold text-muted-foreground mb-2">
</h2>
<p className="text-sm text-muted-foreground">
.
</p>
</CardContent>
</Card>
</div>
);
}

View File

@ -0,0 +1,23 @@
"use client";
import React from "react";
import { Construction } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
export default function SystemPage() {
return (
<div className="container mx-auto py-8">
<Card className="border-2 border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<Construction className="h-16 w-16 text-muted-foreground mb-4" />
<h2 className="text-2xl font-semibold text-muted-foreground mb-2">
</h2>
<p className="text-sm text-muted-foreground">
.
</p>
</CardContent>
</Card>
</div>
);
}

View File

@ -0,0 +1,23 @@
"use client";
import React from "react";
import { Construction } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
export default function SystemPage() {
return (
<div className="container mx-auto py-8">
<Card className="border-2 border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<Construction className="h-16 w-16 text-muted-foreground mb-4" />
<h2 className="text-2xl font-semibold text-muted-foreground mb-2">
</h2>
<p className="text-sm text-muted-foreground">
.
</p>
</CardContent>
</Card>
</div>
);
}

View File

@ -0,0 +1,28 @@
// src/(general)/layout.tsx
import React from "react";
import { GeneralSidebar } from "@/components/general/GeneralSidebar";
import { GeneralHeader } from "@/components/general/GeneralHeader";
const GeneralLayout = ({ children }: { children: React.ReactNode }) => {
return (
<div className="h-screen flex">
{/* 왼쪽 사이드바 */}
<aside className="w-64 h-screen flex-shrink-0 bg-gray-800">
<GeneralSidebar />
</aside>
{/* 오른쪽 메인 영역 */}
<div className="flex-1 flex flex-col">
{/* 상단 헤더 */}
<header className="h-16 bg-white border-b">
<GeneralHeader />
</header>
{/* 메인 컨텐츠 영역 */}
<main className="flex-1 overflow-auto bg-gray-50 p-6">{children}</main>
</div>
</div>
);
};
export default GeneralLayout;

View File

@ -0,0 +1,23 @@
"use client";
import React from "react";
import { Construction } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
export default function SystemPage() {
return (
<div className="container mx-auto py-8">
<Card className="border-2 border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<Construction className="h-16 w-16 text-muted-foreground mb-4" />
<h2 className="text-2xl font-semibold text-muted-foreground mb-2">
</h2>
<p className="text-sm text-muted-foreground">
.
</p>
</CardContent>
</Card>
</div>
);
}

View File

@ -108,7 +108,7 @@ const menuItems = [
{
title: "지원/커뮤니티",
items: [
{ title: "도움말", href: "/help", icon: HelpCircle },
{ title: "도움말", href: "/faq", icon: HelpCircle },
{ title: "게시판", href: "/community/forum", icon: MessageSquare },
{ title: "뉴스", href: "/community/news", icon: Newspaper },
],

View File

@ -108,7 +108,7 @@ const menuItems = [
{
title: "지원/커뮤니티",
items: [
{ title: "도움말", href: "/help", icon: HelpCircle },
{ title: "도움말", href: "/faq", icon: HelpCircle },
{ title: "게시판", href: "/community/forum", icon: MessageSquare },
{ title: "뉴스", href: "/community/news", icon: Newspaper },
],

View File

@ -0,0 +1,162 @@
// src/components/headers/UnifiedHeader.tsx
"use client";
import { usePathname } from "next/navigation";
import { Button } from "@/components/ui/button";
import { useAuth } from "@/hooks/useAuth";
import {
Bell,
Search,
Settings,
HelpCircle,
LogOut,
User,
ChevronDown,
Download,
RefreshCw,
} from "lucide-react";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { DatePickerWithRange } from "@/components/ui/date-range-picker";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
const UnifiedHeader = () => {
const { user, logout } = useAuth();
const pathname = usePathname();
// 페이지에 따른 제목 설정
const pageTitles: { [key: string]: string } = {
"/monitoring/electricity": "전력 모니터링",
"/monitoring/gas": "가스 모니터링",
"/monitoring/water": "용수 모니터링",
"/monitoring/steam": "스팀 모니터링",
};
return (
<header className="h-16 border-b bg-white fixed top-0 right-0 left-64 z-50">
<div className="h-full px-4 flex items-center justify-between">
{/* 페이지 제목 */}
<h2 className="text-lg font-semibold">{pageTitles[pathname]}</h2>
{/* 필터 및 데이터 주기 설정 */}
<div className="flex items-center space-x-4">
<Select defaultValue="realtime">
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="데이터 주기" />
</SelectTrigger>
<SelectContent>
<SelectItem value="realtime"></SelectItem>
<SelectItem value="hourly"></SelectItem>
<SelectItem value="daily"></SelectItem>
<SelectItem value="monthly"></SelectItem>
</SelectContent>
</Select>
<DatePickerWithRange className="w-[300px]" />
<Button variant="outline" size="icon">
<RefreshCw className="h-4 w-4" />
</Button>
<Button variant="outline">
<Download className="mr-2 h-4 w-4" />
</Button>
</div>
{/* 검색, 알림, 도움말 및 사용자 메뉴 */}
<div className="flex items-center gap-3 ml-auto">
{/* 검색바 */}
<div className="relative">
<input
type="text"
placeholder="검색..."
className="h-9 w-64 px-4 pl-10 rounded-md bg-gray-50 border border-gray-200
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
/>
<Search className="h-4 w-4 text-gray-400 absolute left-3 top-1/2 -translate-y-1/2" />
</div>
{/* 알림 버튼 */}
<Button
variant="ghost"
size="icon"
className="relative text-gray-600 hover:text-gray-900"
>
<Bell className="h-5 w-5" />
<span className="absolute top-1 right-1 w-2 h-2 bg-red-500 rounded-full" />
</Button>
{/* 도움말 버튼 */}
<Button
variant="ghost"
size="icon"
className="text-gray-600 hover:text-gray-900"
>
<HelpCircle className="h-5 w-5" />
</Button>
{/* 사용자 프로필 드롭다운 */}
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
className="flex items-center gap-2 px-3 hover:bg-gray-100"
>
<div className="w-8 h-8 rounded-full bg-blue-100 text-blue-600 flex items-center justify-center font-medium">
{user?.name?.[0] || "U"}
</div>
<div className="flex items-center gap-2">
<div className="flex flex-col items-start">
<span className="text-sm font-medium text-gray-700">
{user?.name || "사용자"}
</span>
<span className="text-xs text-gray-500">
{user?.role || "관리자"}
</span>
</div>
<ChevronDown className="h-4 w-4 text-gray-500" />
</div>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-56">
<DropdownMenuLabel> </DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem>
<User className="mr-2 h-4 w-4" />
<span> </span>
</DropdownMenuItem>
<DropdownMenuItem>
<Settings className="mr-2 h-4 w-4" />
<span></span>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
onClick={logout}
className="text-red-600 focus:text-red-600"
>
<LogOut className="mr-2 h-4 w-4" />
<span></span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
</header>
);
};
export default UnifiedHeader;

View File

@ -1,8 +1,21 @@
// src/components/monitoring/MonitoringHeader.tsx
"use client";
import { usePathname } from "next/navigation";
import { Button } from "@/components/ui/button";
import { useAuth } from "@/hooks/useAuth";
import {
Bell,
Search,
Settings,
HelpCircle,
LogOut,
User,
ChevronDown,
Download,
RefreshCw,
} from "lucide-react";
import {
Select,
SelectContent,
@ -11,10 +24,20 @@ import {
SelectValue,
} from "@/components/ui/select";
import { DatePickerWithRange } from "@/components/ui/date-range-picker";
import { Download, RefreshCw } from "lucide-react";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
export function MonitoringHeader() {
const MonitoringHeader = () => {
const { user, logout } = useAuth();
const pathname = usePathname();
// 페이지에 따른 제목 설정
const pageTitles: { [key: string]: string } = {
"/monitoring/electricity": "전력 모니터링",
"/monitoring/gas": "가스 모니터링",
@ -23,10 +46,13 @@ export function MonitoringHeader() {
};
return (
<div className="border-b">
<div className="flex h-16 items-center px-4">
<header className="h-16 border-b bg-white fixed top-0 right-0 left-64 z-50">
<div className="h-full px-4 flex items-center justify-between">
{/* 페이지 제목 */}
<h2 className="text-lg font-semibold">{pageTitles[pathname]}</h2>
<div className="ml-auto flex items-center space-x-4">
{/* 필터 및 데이터 주기 설정 */}
<div className="flex items-center space-x-4">
<Select defaultValue="realtime">
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="데이터 주기" />
@ -50,7 +76,87 @@ export function MonitoringHeader() {
</Button>
</div>
{/* 검색, 알림, 도움말 및 사용자 메뉴 */}
<div className="flex items-center gap-3 ml-auto">
{/* 검색바 */}
<div className="relative">
<input
type="text"
placeholder="검색..."
className="h-9 w-64 px-4 pl-10 rounded-md bg-gray-50 border border-gray-200
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
/>
<Search className="h-4 w-4 text-gray-400 absolute left-3 top-1/2 -translate-y-1/2" />
</div>
{/* 알림 버튼 */}
<Button
variant="ghost"
size="icon"
className="relative text-gray-600 hover:text-gray-900"
>
<Bell className="h-5 w-5" />
<span className="absolute top-1 right-1 w-2 h-2 bg-red-500 rounded-full" />
</Button>
{/* 도움말 버튼 */}
<Button
variant="ghost"
size="icon"
className="text-gray-600 hover:text-gray-900"
>
<HelpCircle className="h-5 w-5" />
</Button>
{/* 사용자 프로필 드롭다운 */}
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
className="flex items-center gap-2 px-3 hover:bg-gray-100"
>
<div className="w-8 h-8 rounded-full bg-blue-100 text-blue-600 flex items-center justify-center font-medium">
{user?.name?.[0] || "U"}
</div>
<div className="flex items-center gap-2">
<div className="flex flex-col items-start">
<span className="text-sm font-medium text-gray-700">
{user?.name || "사용자"}
</span>
<span className="text-xs text-gray-500">
{user?.role || "관리자"}
</span>
</div>
<ChevronDown className="h-4 w-4 text-gray-500" />
</div>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-56">
<DropdownMenuLabel> </DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem>
<User className="mr-2 h-4 w-4" />
<span> </span>
</DropdownMenuItem>
<DropdownMenuItem>
<Settings className="mr-2 h-4 w-4" />
<span></span>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
onClick={logout}
className="text-red-600 focus:text-red-600"
>
<LogOut className="mr-2 h-4 w-4" />
<span></span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
</div>
</header>
);
}
};
export default MonitoringHeader;

View File

@ -106,7 +106,7 @@ const menuItems = [
{
title: "지원/커뮤니티",
items: [
{ title: "도움말", href: "/help", icon: HelpCircle },
{ title: "도움말", href: "/faq", icon: HelpCircle },
{ title: "게시판", href: "/community/forum", icon: MessageSquare },
{ title: "뉴스", href: "/community/news", icon: Newspaper },
],

View File

@ -1,21 +1,3 @@
// // src/lib/api.ts
// import axios from "axios";
// import { useAuthStore } from "@/stores/auth";
// export const api = axios.create({
// baseURL: process.env.NEXT_PUBLIC_API_URL,
// timeout: 10000,
// });
// api.interceptors.request.use((config) => {
// // localStorage 대신 Zustand store에서 직접 토큰을 가져옴
// const token = useAuthStore.getState().token;
// if (token) {
// config.headers.Authorization = `Bearer ${token}`;
// }
// return config;
// });
// src/lib/api.ts
import axios from "axios";
import { useAuthStore } from "@/stores/auth";

View File

@ -1064,6 +1064,11 @@ binary-extensions@^2.0.0:
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522"
integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==
boolbase@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@ -1119,7 +1124,7 @@ caniuse-lite@^1.0.30001579:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001676.tgz#fe133d41fe74af8f7cc93b8a714c3e86a86e6f04"
integrity sha512-Qz6zwGCiPghQXGJvgQAem79esjitvJ+CxSbSQkW9H/UX5hg8XM88d4lp2W+MEQ81j+Hip58Il+jGVdazk1z9cw==
chalk@^4.0.0:
chalk@^4.0.0, chalk@^4.1.0:
version "4.1.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
@ -1193,6 +1198,19 @@ concat-map@0.0.1:
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
critters@^0.0.25:
version "0.0.25"
resolved "https://registry.yarnpkg.com/critters/-/critters-0.0.25.tgz#8568e6add4a8f68d0b1dbe0c4839286947b37888"
integrity sha512-ROF/tjJyyRdM8/6W0VqoN5Ql05xAGnkf5b7f3sTEl1bI5jTQQf8O918RD/V9tEb9pRY/TKcvJekDbJtniHyPtQ==
dependencies:
chalk "^4.1.0"
css-select "^5.1.0"
dom-serializer "^2.0.0"
domhandler "^5.0.2"
htmlparser2 "^8.0.2"
postcss "^8.4.23"
postcss-media-query-parser "^0.2.3"
cross-spawn@^7.0.0, cross-spawn@^7.0.2:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
@ -1202,6 +1220,22 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2:
shebang-command "^2.0.0"
which "^2.0.1"
css-select@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/css-select/-/css-select-5.1.0.tgz#b8ebd6554c3637ccc76688804ad3f6a6fdaea8a6"
integrity sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==
dependencies:
boolbase "^1.0.0"
css-what "^6.1.0"
domhandler "^5.0.2"
domutils "^3.0.1"
nth-check "^2.0.1"
css-what@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4"
integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
cssesc@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
@ -1404,6 +1438,36 @@ dom-helpers@^5.0.1:
"@babel/runtime" "^7.8.7"
csstype "^3.0.2"
dom-serializer@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53"
integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==
dependencies:
domelementtype "^2.3.0"
domhandler "^5.0.2"
entities "^4.2.0"
domelementtype@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
domhandler@^5.0.2, domhandler@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31"
integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==
dependencies:
domelementtype "^2.3.0"
domutils@^3.0.1:
version "3.1.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.1.0.tgz#c47f551278d3dc4b0b1ab8cbb42d751a6f0d824e"
integrity sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==
dependencies:
dom-serializer "^2.0.0"
domelementtype "^2.3.0"
domhandler "^5.0.3"
eastasianwidth@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
@ -1427,6 +1491,11 @@ enhanced-resolve@^5.15.0:
graceful-fs "^4.2.4"
tapable "^2.2.0"
entities@^4.2.0, entities@^4.4.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
es-abstract@^1.17.5, es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.1, es-abstract@^1.23.2, es-abstract@^1.23.3:
version "1.23.3"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0"
@ -2058,6 +2127,16 @@ hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2:
dependencies:
function-bind "^1.1.2"
htmlparser2@^8.0.2:
version "8.0.2"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.2.tgz#f002151705b383e62433b5cf466f5b716edaec21"
integrity sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==
dependencies:
domelementtype "^2.3.0"
domhandler "^5.0.3"
domutils "^3.0.1"
entities "^4.4.0"
ignore@^5.2.0, ignore@^5.3.1:
version "5.3.2"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5"
@ -2579,6 +2658,13 @@ normalize-path@^3.0.0, normalize-path@~3.0.0:
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
nth-check@^2.0.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d"
integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==
dependencies:
boolbase "^1.0.0"
object-assign@^4.0.1, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
@ -2768,6 +2854,11 @@ postcss-load-config@^4.0.1:
lilconfig "^3.0.0"
yaml "^2.3.4"
postcss-media-query-parser@^0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244"
integrity sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==
postcss-nested@^6.0.1:
version "6.2.0"
resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.2.0.tgz#4c2d22ab5f20b9cb61e2c5c5915950784d068131"