Some checks failed
Build Frontend / build (push) Failing after 7s
Replaces imports from 'components/ui' with 'components/common' across the app and dashboard pages, and updates model and API imports to use new paths under 'lib'. Removes redundant authentication checks from several dashboard pages. Adds new dashboard components and utility files, and reorganizes hooks and services into the 'lib' directory for improved structure.
131 lines
3.9 KiB
TypeScript
131 lines
3.9 KiB
TypeScript
"use client"
|
|
|
|
import React, { useState } from "react"
|
|
import {
|
|
DndContext,
|
|
closestCenter,
|
|
KeyboardSensor,
|
|
PointerSensor,
|
|
useSensor,
|
|
useSensors,
|
|
DragEndEvent,
|
|
DragOverlay,
|
|
DragStartEvent,
|
|
} from "@dnd-kit/core"
|
|
import {
|
|
SortableContext,
|
|
sortableKeyboardCoordinates,
|
|
verticalListSortingStrategy,
|
|
arrayMove,
|
|
} from "@dnd-kit/sortable"
|
|
import { Button } from "@/components/common/button"
|
|
import { Edit3, X, Check, RotateCcw } from "lucide-react"
|
|
import { WidgetConfig } from "@/lib/types/dashboard"
|
|
import { motion, AnimatePresence } from "framer-motion"
|
|
|
|
interface DashboardEditorProps {
|
|
widgets: WidgetConfig[]
|
|
isEditMode: boolean
|
|
onToggleEditMode: () => void
|
|
onReorder: (activeId: string, overId: string) => void
|
|
onReset: () => void
|
|
children: React.ReactNode
|
|
}
|
|
|
|
export function DashboardEditor({
|
|
widgets,
|
|
isEditMode,
|
|
onToggleEditMode,
|
|
onReorder,
|
|
onReset,
|
|
children
|
|
}: DashboardEditorProps) {
|
|
const [activeId, setActiveId] = useState<string | null>(null)
|
|
|
|
const sensors = useSensors(
|
|
useSensor(PointerSensor, {
|
|
activationConstraint: {
|
|
distance: 8,
|
|
},
|
|
}),
|
|
useSensor(KeyboardSensor, {
|
|
coordinateGetter: sortableKeyboardCoordinates,
|
|
})
|
|
)
|
|
|
|
const handleDragStart = (event: DragStartEvent) => {
|
|
setActiveId(event.active.id as string)
|
|
}
|
|
|
|
const handleDragEnd = (event: DragEndEvent) => {
|
|
const { active, over } = event
|
|
|
|
if (over && active.id !== over.id) {
|
|
onReorder(active.id as string, over.id as string)
|
|
}
|
|
|
|
setActiveId(null)
|
|
}
|
|
|
|
const handleDragCancel = () => {
|
|
setActiveId(null)
|
|
}
|
|
|
|
return (
|
|
<DndContext
|
|
sensors={sensors}
|
|
collisionDetection={closestCenter}
|
|
onDragStart={handleDragStart}
|
|
onDragEnd={handleDragEnd}
|
|
onDragCancel={handleDragCancel}
|
|
>
|
|
<SortableContext
|
|
items={widgets.map(w => w.id)}
|
|
strategy={verticalListSortingStrategy}
|
|
>
|
|
{children}
|
|
</SortableContext>
|
|
|
|
{/* Edit Mode Banner */}
|
|
<AnimatePresence>
|
|
{isEditMode && (
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 50 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
exit={{ opacity: 0, y: 50 }}
|
|
className="fixed bottom-6 left-1/2 -translate-x-1/2 z-50"
|
|
>
|
|
<div className="flex items-center gap-3 bg-primary text-primary-foreground px-4 py-2.5 rounded-full shadow-lg border border-primary-foreground/20">
|
|
<span className="text-sm font-medium">
|
|
Editing Dashboard • Drag widgets to reorder
|
|
</span>
|
|
<div className="h-4 w-px bg-primary-foreground/30" />
|
|
<Button
|
|
variant="ghost"
|
|
size="sm"
|
|
className="h-7 px-2 hover:bg-primary-foreground/20"
|
|
onClick={onReset}
|
|
>
|
|
<RotateCcw className="h-3.5 w-3.5 mr-1" />
|
|
Reset
|
|
</Button>
|
|
<Button
|
|
variant="secondary"
|
|
size="sm"
|
|
className="h-7 px-3"
|
|
onClick={onToggleEditMode}
|
|
>
|
|
<Check className="h-3.5 w-3.5 mr-1" />
|
|
Done
|
|
</Button>
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
</AnimatePresence>
|
|
</DndContext>
|
|
)
|
|
}
|
|
|
|
|
|
|