Some checks failed
Build Frontend / build (push) Failing after 7s
Eliminated the ability to resize dashboard widgets by removing colSpan from WidgetConfig, related UI, and logic. Removed edit mode functionality and the EditDashboardButton, simplifying the dashboard layout and widget management. Updated drag-and-drop strategy to vertical list and incremented the storage key version.
272 lines
14 KiB
TypeScript
272 lines
14 KiB
TypeScript
"use client"
|
|
|
|
import { useState } from "react"
|
|
import { Button } from "@/components/ui/button"
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
} from "@/components/ui/dialog"
|
|
import { Label } from "@/components/ui/label"
|
|
import { Input } from "@/components/ui/input"
|
|
import { Switch } from "@/components/ui/switch"
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "@/components/ui/select"
|
|
import { WidgetConfig } from "@/hooks/useWidgetLayout"
|
|
import { Settings2 } from "lucide-react"
|
|
import { ScrollArea } from "@/components/ui/scroll-area"
|
|
|
|
interface WidgetSettingsModalProps {
|
|
widget: WidgetConfig | null
|
|
open: boolean
|
|
onOpenChange: (open: boolean) => void
|
|
onSave: (widgetId: string, settings: Record<string, any>) => void
|
|
}
|
|
|
|
export function WidgetSettingsModal({ widget, open, onOpenChange, onSave }: WidgetSettingsModalProps) {
|
|
const [localSettings, setLocalSettings] = useState<Record<string, any>>({})
|
|
|
|
// Initialize local settings when widget changes
|
|
const handleOpenChange = (isOpen: boolean) => {
|
|
if (isOpen && widget) {
|
|
setLocalSettings({ ...widget.settings })
|
|
}
|
|
onOpenChange(isOpen)
|
|
}
|
|
|
|
const handleSave = () => {
|
|
if (widget) {
|
|
onSave(widget.id, localSettings)
|
|
onOpenChange(false)
|
|
}
|
|
}
|
|
|
|
const updateSetting = (key: string, value: any) => {
|
|
setLocalSettings(prev => ({ ...prev, [key]: value }))
|
|
}
|
|
|
|
if (!widget) return null
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={handleOpenChange}>
|
|
<DialogContent className="sm:max-w-md">
|
|
<DialogHeader>
|
|
<DialogTitle className="flex items-center gap-2">
|
|
<Settings2 className="h-5 w-5" />
|
|
{widget.title} Settings
|
|
</DialogTitle>
|
|
<DialogDescription>
|
|
Customize how this widget displays on your dashboard.
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<ScrollArea className="max-h-[60vh] -mr-4 pr-4">
|
|
<div className="space-y-6 py-4">
|
|
|
|
<div className="space-y-4">
|
|
{/* Recent Activity Settings */}
|
|
{widget.id === "recent-activity" && (
|
|
<div className="space-y-4">
|
|
<div className="flex items-center justify-between">
|
|
<Label htmlFor="itemCount">Number of items</Label>
|
|
<Select
|
|
value={String(localSettings.itemCount || 10)}
|
|
onValueChange={(v) => updateSetting("itemCount", parseInt(v))}
|
|
>
|
|
<SelectTrigger className="w-24">
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="5">5</SelectItem>
|
|
<SelectItem value="10">10</SelectItem>
|
|
<SelectItem value="15">15</SelectItem>
|
|
<SelectItem value="20">20</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Top Products Settings */}
|
|
{widget.id === "top-products" && (
|
|
<div className="space-y-4">
|
|
<div className="flex items-center justify-between">
|
|
<Label htmlFor="itemCount">Number of products</Label>
|
|
<Select
|
|
value={String(localSettings.itemCount || 5)}
|
|
onValueChange={(v) => updateSetting("itemCount", parseInt(v))}
|
|
>
|
|
<SelectTrigger className="w-24">
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="3">3</SelectItem>
|
|
<SelectItem value="5">5</SelectItem>
|
|
<SelectItem value="10">10</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
<div className="flex items-center justify-between">
|
|
<Label htmlFor="showRevenue">Show revenue</Label>
|
|
<Switch
|
|
id="showRevenue"
|
|
checked={localSettings.showRevenue ?? true}
|
|
onCheckedChange={(checked) => updateSetting("showRevenue", checked)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Revenue Chart Settings */}
|
|
{widget.id === "revenue-chart" && (
|
|
<div className="space-y-4">
|
|
<div className="flex items-center justify-between">
|
|
<Label htmlFor="days">Time period</Label>
|
|
<Select
|
|
value={String(localSettings.days || 7)}
|
|
onValueChange={(v) => updateSetting("days", parseInt(v))}
|
|
>
|
|
<SelectTrigger className="w-32">
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="7">Last 7 days</SelectItem>
|
|
<SelectItem value="14">Last 14 days</SelectItem>
|
|
<SelectItem value="30">Last 30 days</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
<div className="flex items-center justify-between">
|
|
<Label htmlFor="showComparison">Show comparison</Label>
|
|
<Switch
|
|
id="showComparison"
|
|
checked={localSettings.showComparison ?? false}
|
|
onCheckedChange={(checked) => updateSetting("showComparison", checked)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Low Stock Settings */}
|
|
{widget.id === "low-stock" && (
|
|
<div className="space-y-4">
|
|
<div className="flex items-center justify-between">
|
|
<Label htmlFor="threshold">Stock threshold</Label>
|
|
<Input
|
|
id="threshold"
|
|
type="number"
|
|
className="w-24"
|
|
value={localSettings.threshold || 5}
|
|
onChange={(e) => updateSetting("threshold", parseInt(e.target.value) || 5)}
|
|
min={1}
|
|
max={100}
|
|
/>
|
|
</div>
|
|
<div className="flex items-center justify-between">
|
|
<Label htmlFor="itemCount">Max items to show</Label>
|
|
<Select
|
|
value={String(localSettings.itemCount || 5)}
|
|
onValueChange={(v) => updateSetting("itemCount", parseInt(v))}
|
|
>
|
|
<SelectTrigger className="w-24">
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="3">3</SelectItem>
|
|
<SelectItem value="5">5</SelectItem>
|
|
<SelectItem value="10">10</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Recent Customers Settings */}
|
|
{widget.id === "recent-customers" && (
|
|
<div className="space-y-4">
|
|
<div className="flex items-center justify-between">
|
|
<Label htmlFor="itemCount">Number of customers</Label>
|
|
<Select
|
|
value={String(localSettings.itemCount || 5)}
|
|
onValueChange={(v) => updateSetting("itemCount", parseInt(v))}
|
|
>
|
|
<SelectTrigger className="w-24">
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="3">3</SelectItem>
|
|
<SelectItem value="5">5</SelectItem>
|
|
<SelectItem value="10">10</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
<div className="flex items-center justify-between">
|
|
<Label htmlFor="showSpent">Show amount spent</Label>
|
|
<Switch
|
|
id="showSpent"
|
|
checked={localSettings.showSpent ?? true}
|
|
onCheckedChange={(checked) => updateSetting("showSpent", checked)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Pending Chats Settings */}
|
|
{widget.id === "pending-chats" && (
|
|
<div className="space-y-4">
|
|
<div className="flex items-center justify-between">
|
|
<Label htmlFor="showPreview">Show message preview</Label>
|
|
<Switch
|
|
id="showPreview"
|
|
checked={localSettings.showPreview ?? true}
|
|
onCheckedChange={(checked) => updateSetting("showPreview", checked)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Overview Settings */}
|
|
{widget.id === "overview" && (
|
|
<div className="space-y-4">
|
|
<div className="flex items-center justify-between">
|
|
<Label htmlFor="showChange">Show percentage change</Label>
|
|
<Switch
|
|
id="showChange"
|
|
checked={localSettings.showChange ?? false}
|
|
onCheckedChange={(checked) => updateSetting("showChange", checked)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Quick Actions - no settings */}
|
|
{widget.id === "quick-actions" && (
|
|
<p className="text-sm text-muted-foreground text-center py-4">
|
|
This widget has no customizable settings.
|
|
</p>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</ScrollArea>
|
|
|
|
<DialogFooter>
|
|
<Button variant="outline" onClick={() => onOpenChange(false)}>
|
|
Cancel
|
|
</Button>
|
|
<Button onClick={handleSave}>
|
|
Save Changes
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
)
|
|
}
|