83 lines
2.3 KiB
TypeScript
83 lines
2.3 KiB
TypeScript
|
|
'use client';
|
||
|
|
|
||
|
|
import { useState } from 'react';
|
||
|
|
|
||
|
|
import { Button } from '@/components/ui/button';
|
||
|
|
import {
|
||
|
|
Dialog,
|
||
|
|
DialogContent,
|
||
|
|
DialogFooter,
|
||
|
|
DialogHeader,
|
||
|
|
DialogTitle,
|
||
|
|
} from '@/components/ui/dialog';
|
||
|
|
import { Input } from '@/components/ui/input';
|
||
|
|
import { Label } from '@/components/ui/label';
|
||
|
|
import { useSavedViews } from '@/hooks/use-saved-views';
|
||
|
|
|
||
|
|
interface SaveViewDialogProps {
|
||
|
|
open: boolean;
|
||
|
|
onOpenChange: (open: boolean) => void;
|
||
|
|
entityType: string;
|
||
|
|
currentFilters: Record<string, unknown>;
|
||
|
|
currentSort?: { field: string; direction: 'asc' | 'desc' };
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Standalone save-view dialog. Lifted out of SavedViewsDropdown so the
|
||
|
|
* "Save current view" affordance can live inside the column picker
|
||
|
|
* (where the rep is already configuring the table) instead of as a
|
||
|
|
* top-level button. SavedViewsDropdown now only handles browsing and
|
||
|
|
* applying existing views — the save and read concerns are split.
|
||
|
|
*/
|
||
|
|
export function SaveViewDialog({
|
||
|
|
open,
|
||
|
|
onOpenChange,
|
||
|
|
entityType,
|
||
|
|
currentFilters,
|
||
|
|
currentSort,
|
||
|
|
}: SaveViewDialogProps) {
|
||
|
|
const { saveCurrentView } = useSavedViews(entityType);
|
||
|
|
const [viewName, setViewName] = useState('');
|
||
|
|
const [isSaving, setIsSaving] = useState(false);
|
||
|
|
|
||
|
|
async function handleSave() {
|
||
|
|
if (!viewName.trim()) return;
|
||
|
|
setIsSaving(true);
|
||
|
|
try {
|
||
|
|
await saveCurrentView(viewName.trim(), currentFilters, currentSort);
|
||
|
|
onOpenChange(false);
|
||
|
|
setViewName('');
|
||
|
|
} finally {
|
||
|
|
setIsSaving(false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
||
|
|
<DialogContent className="sm:max-w-sm">
|
||
|
|
<DialogHeader>
|
||
|
|
<DialogTitle>Save view</DialogTitle>
|
||
|
|
</DialogHeader>
|
||
|
|
<div className="space-y-2">
|
||
|
|
<Label>View name</Label>
|
||
|
|
<Input
|
||
|
|
value={viewName}
|
||
|
|
onChange={(e) => setViewName(e.target.value)}
|
||
|
|
placeholder="My custom view"
|
||
|
|
onKeyDown={(e) => e.key === 'Enter' && handleSave()}
|
||
|
|
autoFocus
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
<DialogFooter>
|
||
|
|
<Button variant="outline" onClick={() => onOpenChange(false)}>
|
||
|
|
Cancel
|
||
|
|
</Button>
|
||
|
|
<Button onClick={handleSave} disabled={!viewName.trim() || isSaving}>
|
||
|
|
Save
|
||
|
|
</Button>
|
||
|
|
</DialogFooter>
|
||
|
|
</DialogContent>
|
||
|
|
</Dialog>
|
||
|
|
);
|
||
|
|
}
|