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 { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
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 { 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 { formatIDR } from '@/lib/format';
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
@@ -91,7 +93,7 @@ export default function AdminProducts() {
const [filterType, setFilterType] = useState<string>('all');
const [filterStatus, setFilterStatus] = useState<string>('all');
const [collaborators, setCollaborators] = useState<CollaboratorProfile[]>([]);
const [collaboratorSearch, setCollaboratorSearch] = useState('');
const [collaboratorPickerOpen, setCollaboratorPickerOpen] = useState(false);
useEffect(() => {
if (user && isAdmin) {
@@ -133,12 +135,6 @@ export default function AdminProducts() {
// Get unique product types from actual products
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 = () => {
setSearchQuery('');
setFilterType('all');
@@ -170,14 +166,12 @@ export default function AdminProducts() {
profit_share_percentage: product.profit_share_percentage ?? 50,
auto_grant_access: product.auto_grant_access ?? true,
});
setCollaboratorSearch('');
setDialogOpen(true);
};
const handleNew = () => {
setEditingProduct(null);
setForm(emptyProduct);
setCollaboratorSearch('');
setDialogOpen(true);
};
@@ -563,36 +557,52 @@ export default function AdminProducts() {
</div>
{form.type === 'webinar' && (
<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">
<Label>Kolaborator (opsional)</Label>
<Select
value={form.collaborator_user_id || '__none__'}
onValueChange={(value) => setForm({ ...form, collaborator_user_id: value === '__none__' ? '' : value })}
>
<SelectTrigger className="border-2">
<SelectValue placeholder="Pilih kolaborator" />
</SelectTrigger>
<SelectContent>
<SelectItem value="__none__">Tanpa kolaborator (solo)</SelectItem>
{filteredCollaborators.map((c) => (
<SelectItem key={c.id} value={c.id}>
{(c.name || 'User') + (c.email ? ` (${c.email})` : '')}
</SelectItem>
))}
</SelectContent>
</Select>
{collaboratorSearch && filteredCollaborators.length === 0 && (
<p className="text-sm text-muted-foreground">Tidak ada kolaborator yang cocok.</p>
)}
<Popover open={collaboratorPickerOpen} onOpenChange={setCollaboratorPickerOpen}>
<PopoverTrigger asChild>
<Button variant="outline" role="combobox" className="w-full justify-between border-2">
{form.collaborator_user_id
? (() => {
const selected = collaborators.find((c) => c.id === form.collaborator_user_id);
return selected ? `${selected.name || 'User'}${selected.email ? ` (${selected.email})` : ''}` : 'Pilih kolaborator';
})()
: 'Tanpa kolaborator (solo)'}
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-[var(--radix-popover-trigger-width)] p-0">
<Command>
<CommandInput placeholder="Cari nama atau email..." />
<CommandList>
<CommandEmpty>Tidak ada kolaborator yang cocok.</CommandEmpty>
<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>
{!!form.collaborator_user_id && (