Some checks failed
Build Frontend / build (push) Failing after 6s
Wrapped the widget settings modal content in a ScrollArea to improve usability when there are many settings, preventing overflow and keeping the modal compact.
295 lines
16 KiB
TypeScript
295 lines
16 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>, colSpan: number) => void
|
|
}
|
|
|
|
export function WidgetSettingsModal({ widget, open, onOpenChange, onSave }: WidgetSettingsModalProps) {
|
|
const [localSettings, setLocalSettings] = useState<Record<string, any>>({})
|
|
const [localColSpan, setLocalColSpan] = useState<number>(4)
|
|
|
|
// Initialize local settings when widget changes
|
|
const handleOpenChange = (isOpen: boolean) => {
|
|
if (isOpen && widget) {
|
|
setLocalSettings({ ...widget.settings })
|
|
setLocalColSpan(widget.colSpan || 4)
|
|
}
|
|
onOpenChange(isOpen)
|
|
}
|
|
|
|
const handleSave = () => {
|
|
if (widget) {
|
|
onSave(widget.id, localSettings, localColSpan)
|
|
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">
|
|
{/* Resize Selection */}
|
|
<div className="space-y-3 pb-6 border-b border-border/40">
|
|
<Label className="text-xs font-semibold text-muted-foreground uppercase tracking-wider">Widget Display</Label>
|
|
<div className="flex items-center justify-between">
|
|
<Label htmlFor="colSpan" className="text-sm font-medium">Widget Width</Label>
|
|
<Select
|
|
value={String(localColSpan)}
|
|
onValueChange={(v) => setLocalColSpan(parseInt(v))}
|
|
>
|
|
<SelectTrigger className="w-40">
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="1">Small (1/4)</SelectItem>
|
|
<SelectItem value="2">Medium (1/2)</SelectItem>
|
|
<SelectItem value="3">Large (3/4)</SelectItem>
|
|
<SelectItem value="4">Full Width</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
|
|
<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>
|
|
)
|
|
}
|