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.
274 lines
14 KiB
TypeScript
274 lines
14 KiB
TypeScript
"use client"
|
|
|
|
import { useState } from "react"
|
|
import { Button } from "@/components/common/button"
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
} from "@/components/common/dialog"
|
|
import { Label } from "@/components/common/label"
|
|
import { Input } from "@/components/common/input"
|
|
import { Switch } from "@/components/common/switch"
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "@/components/common/select"
|
|
import { WidgetConfig } from "@/lib/types/dashboard"
|
|
import { Settings2 } from "lucide-react"
|
|
import { ScrollArea } from "@/components/common/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>
|
|
)
|
|
}
|
|
|
|
|