ERP-node/frontend/components/admin/dashboard/DashboardSidebar.tsx

264 lines
8.1 KiB
TypeScript

"use client";
import React, { useState } from "react";
import { DragData, ElementType, ElementSubtype } from "./types";
import { ChevronDown, ChevronRight } from "lucide-react";
/**
* 대시보드 사이드바 컴포넌트
* - 드래그 가능한 차트/위젯 목록
* - 아코디언 방식으로 카테고리별 구분
*/
export function DashboardSidebar() {
const [expandedSections, setExpandedSections] = useState({
charts: true,
widgets: true,
operations: true,
});
// 섹션 토글
const toggleSection = (section: keyof typeof expandedSections) => {
setExpandedSections((prev) => ({ ...prev, [section]: !prev[section] }));
};
// 드래그 시작 처리
const handleDragStart = (e: React.DragEvent, type: ElementType, subtype: ElementSubtype) => {
const dragData: DragData = { type, subtype };
e.dataTransfer.setData("application/json", JSON.stringify(dragData));
e.dataTransfer.effectAllowed = "copy";
};
return (
<div className="w-[370px] overflow-y-auto border-l border-border bg-background p-5">
{/* 차트 섹션 */}
<div className="mb-5">
<button
onClick={() => toggleSection("charts")}
className="mb-3 flex w-full items-center justify-between px-1 py-2.5 text-xl font-bold text-foreground transition-colors hover:text-primary"
>
<span> </span>
{expandedSections.charts ? (
<ChevronDown className="h-5 w-5 text-muted-foreground transition-transform" />
) : (
<ChevronRight className="h-5 w-5 text-muted-foreground transition-transform" />
)}
</button>
{expandedSections.charts && (
<div className="space-y-2">
<DraggableItem
title="바 차트"
type="chart"
subtype="bar"
onDragStart={handleDragStart}
/>
<DraggableItem
title="수평 바 차트"
type="chart"
subtype="horizontal-bar"
onDragStart={handleDragStart}
/>
<DraggableItem
title="누적 바 차트"
type="chart"
subtype="stacked-bar"
onDragStart={handleDragStart}
/>
<DraggableItem
title="꺾은선 차트"
type="chart"
subtype="line"
onDragStart={handleDragStart}
/>
<DraggableItem
title="영역 차트"
type="chart"
subtype="area"
onDragStart={handleDragStart}
/>
<DraggableItem
title="원형 차트"
type="chart"
subtype="pie"
onDragStart={handleDragStart}
/>
<DraggableItem
title="도넛 차트"
type="chart"
subtype="donut"
onDragStart={handleDragStart}
/>
<DraggableItem
title="콤보 차트"
type="chart"
subtype="combo"
onDragStart={handleDragStart}
/>
</div>
)}
</div>
{/* 위젯 섹션 */}
<div className="mb-5">
<button
onClick={() => toggleSection("widgets")}
className="mb-3 flex w-full items-center justify-between px-1 py-2.5 text-xl font-bold text-foreground transition-colors hover:text-primary"
>
<span> </span>
{expandedSections.widgets ? (
<ChevronDown className="h-5 w-5 text-muted-foreground transition-transform" />
) : (
<ChevronRight className="h-5 w-5 text-muted-foreground transition-transform" />
)}
</button>
{expandedSections.widgets && (
<div className="space-y-2">
<DraggableItem
title="환율 위젯"
type="widget"
subtype="exchange"
onDragStart={handleDragStart}
/>
<DraggableItem
title="날씨 위젯"
type="widget"
subtype="weather"
onDragStart={handleDragStart}
/>
<DraggableItem
title="계산기 위젯"
type="widget"
subtype="calculator"
onDragStart={handleDragStart}
/>
<DraggableItem
title="시계 위젯"
type="widget"
subtype="clock"
onDragStart={handleDragStart}
/>
<DraggableItem
title="커스텀 지도 카드"
type="widget"
subtype="map-summary"
onDragStart={handleDragStart}
/>
{/* <DraggableItem
title="커스텀 목록 카드"
type="widget"
subtype="list-summary"
onDragStart={handleDragStart}
/> */}
<DraggableItem
title="리스크/알림 위젯"
type="widget"
subtype="risk-alert"
onDragStart={handleDragStart}
/>
<DraggableItem
title="To-Do / 긴급 지시"
type="widget"
subtype="todo"
onDragStart={handleDragStart}
/>
<DraggableItem
title="달력 위젯"
type="widget"
subtype="calendar"
onDragStart={handleDragStart}
/>
<DraggableItem
title="커스텀 상태 카드"
type="widget"
subtype="status-summary"
onDragStart={handleDragStart}
/>
</div>
)}
</div>
{/* 운영/작업 지원 섹션 */}
<div className="mb-5">
<button
onClick={() => toggleSection("operations")}
className="mb-3 flex w-full items-center justify-between px-1 py-2.5 text-xl font-bold text-foreground transition-colors hover:text-primary"
>
<span>/ </span>
{expandedSections.operations ? (
<ChevronDown className="h-5 w-5 text-muted-foreground transition-transform" />
) : (
<ChevronRight className="h-5 w-5 text-muted-foreground transition-transform" />
)}
</button>
{expandedSections.operations && (
<div className="space-y-2">
<DraggableItem
title="To-Do / 긴급 지시"
type="widget"
subtype="todo"
onDragStart={handleDragStart}
/>
<DraggableItem
title="예약 요청 알림"
type="widget"
subtype="booking-alert"
onDragStart={handleDragStart}
/>
{/* 정비 일정 관리 위젯 제거 - 커스텀 목록 카드로 대체 가능 */}
<DraggableItem
title="문서 다운로드"
type="widget"
subtype="document"
onDragStart={handleDragStart}
/>
<DraggableItem
title="리스트 위젯"
type="widget"
subtype="list"
onDragStart={handleDragStart}
/>
<DraggableItem
title="작업 이력"
type="widget"
subtype="work-history"
onDragStart={handleDragStart}
/>
<DraggableItem
title="커스텀 통계 카드"
type="widget"
subtype="transport-stats"
onDragStart={handleDragStart}
/>
</div>
)}
</div>
</div>
);
}
interface DraggableItemProps {
icon?: string;
title: string;
type: ElementType;
subtype: ElementSubtype;
className?: string;
onDragStart: (e: React.DragEvent, type: ElementType, subtype: ElementSubtype) => void;
}
/**
* 드래그 가능한 아이템 컴포넌트
*/
function DraggableItem({ title, type, subtype, className = "", onDragStart }: DraggableItemProps) {
return (
<div
draggable
className="cursor-move rounded-md border border-border bg-card px-4 py-2.5 text-sm font-medium text-card-foreground transition-all duration-150 hover:border-primary hover:bg-accent"
onDragStart={(e) => onDragStart(e, type, subtype)}
>
{title}
</div>
);
}