Use searchable combobox for collaborator selection

This commit is contained in:
dwindown
2026-02-03 17:36:43 +07:00
parent 8be40dc0f9
commit d58f597ba6

View File

@@ -12,9 +12,11 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@
import { Switch } from '@/components/ui/switch'; import { Switch } from '@/components/ui/switch';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from '@/components/ui/command';
import { toast } from '@/hooks/use-toast'; import { toast } from '@/hooks/use-toast';
import { Skeleton } from '@/components/ui/skeleton'; import { Skeleton } from '@/components/ui/skeleton';
import { Plus, Pencil, Trash2, Search, X, BookOpen } from 'lucide-react'; import { Plus, Pencil, Trash2, Search, X, BookOpen, ChevronsUpDown } from 'lucide-react';
import { RichTextEditor } from '@/components/RichTextEditor'; import { RichTextEditor } from '@/components/RichTextEditor';
import { formatIDR } from '@/lib/format'; import { formatIDR } from '@/lib/format';
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'; import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
@@ -91,7 +93,7 @@ export default function AdminProducts() {
const [filterType, setFilterType] = useState<string>('all'); const [filterType, setFilterType] = useState<string>('all');
const [filterStatus, setFilterStatus] = useState<string>('all'); const [filterStatus, setFilterStatus] = useState<string>('all');
const [collaborators, setCollaborators] = useState<CollaboratorProfile[]>([]); const [collaborators, setCollaborators] = useState<CollaboratorProfile[]>([]);
const [collaboratorSearch, setCollaboratorSearch] = useState(''); const [collaboratorPickerOpen, setCollaboratorPickerOpen] = useState(false);
useEffect(() => { useEffect(() => {
if (user && isAdmin) { if (user && isAdmin) {
@@ -133,12 +135,6 @@ export default function AdminProducts() {
// Get unique product types from actual products // Get unique product types from actual products
const productTypes = ['all', ...Array.from(new Set(products.map(p => p.type)))]; const productTypes = ['all', ...Array.from(new Set(products.map(p => p.type)))];
const filteredCollaborators = collaborators.filter((c) => {
const q = collaboratorSearch.trim().toLowerCase();
if (!q) return true;
return (c.name || '').toLowerCase().includes(q) || (c.email || '').toLowerCase().includes(q);
});
const clearFilters = () => { const clearFilters = () => {
setSearchQuery(''); setSearchQuery('');
setFilterType('all'); setFilterType('all');
@@ -170,14 +166,12 @@ export default function AdminProducts() {
profit_share_percentage: product.profit_share_percentage ?? 50, profit_share_percentage: product.profit_share_percentage ?? 50,
auto_grant_access: product.auto_grant_access ?? true, auto_grant_access: product.auto_grant_access ?? true,
}); });
setCollaboratorSearch('');
setDialogOpen(true); setDialogOpen(true);
}; };
const handleNew = () => { const handleNew = () => {
setEditingProduct(null); setEditingProduct(null);
setForm(emptyProduct); setForm(emptyProduct);
setCollaboratorSearch('');
setDialogOpen(true); setDialogOpen(true);
}; };
@@ -563,36 +557,52 @@ export default function AdminProducts() {
</div> </div>
{form.type === 'webinar' && ( {form.type === 'webinar' && (
<div className="space-y-4 border-2 border-border rounded-lg p-4"> <div className="space-y-4 border-2 border-border rounded-lg p-4">
<div className="space-y-2">
<Label>Cari Kolaborator</Label>
<Input
value={collaboratorSearch}
onChange={(e) => setCollaboratorSearch(e.target.value)}
placeholder="Cari nama atau email..."
className="border-2"
/>
</div>
<div className="space-y-2"> <div className="space-y-2">
<Label>Kolaborator (opsional)</Label> <Label>Kolaborator (opsional)</Label>
<Select <Popover open={collaboratorPickerOpen} onOpenChange={setCollaboratorPickerOpen}>
value={form.collaborator_user_id || '__none__'} <PopoverTrigger asChild>
onValueChange={(value) => setForm({ ...form, collaborator_user_id: value === '__none__' ? '' : value })} <Button variant="outline" role="combobox" className="w-full justify-between border-2">
> {form.collaborator_user_id
<SelectTrigger className="border-2"> ? (() => {
<SelectValue placeholder="Pilih kolaborator" /> const selected = collaborators.find((c) => c.id === form.collaborator_user_id);
</SelectTrigger> return selected ? `${selected.name || 'User'}${selected.email ? ` (${selected.email})` : ''}` : 'Pilih kolaborator';
<SelectContent> })()
<SelectItem value="__none__">Tanpa kolaborator (solo)</SelectItem> : 'Tanpa kolaborator (solo)'}
{filteredCollaborators.map((c) => ( <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
<SelectItem key={c.id} value={c.id}> </Button>
{(c.name || 'User') + (c.email ? ` (${c.email})` : '')} </PopoverTrigger>
</SelectItem> <PopoverContent className="w-[var(--radix-popover-trigger-width)] p-0">
))} <Command>
</SelectContent> <CommandInput placeholder="Cari nama atau email..." />
</Select> <CommandList>
{collaboratorSearch && filteredCollaborators.length === 0 && ( <CommandEmpty>Tidak ada kolaborator yang cocok.</CommandEmpty>
<p className="text-sm text-muted-foreground">Tidak ada kolaborator yang cocok.</p> <CommandGroup>
)} <CommandItem
value="Tanpa kolaborator (solo)"
onSelect={() => {
setForm({ ...form, collaborator_user_id: '' });
setCollaboratorPickerOpen(false);
}}
>
Tanpa kolaborator (solo)
</CommandItem>
{collaborators.map((c) => (
<CommandItem
key={c.id}
value={`${c.name || 'User'} ${c.email || ''}`}
onSelect={() => {
setForm({ ...form, collaborator_user_id: c.id });
setCollaboratorPickerOpen(false);
}}
>
{(c.name || 'User') + (c.email ? ` (${c.email})` : '')}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
</div> </div>
{!!form.collaborator_user_id && ( {!!form.collaborator_user_id && (