bug-fix/filter dropdowns in dark mode

This commit is contained in:
Satyam-Rastogi
2026-05-15 18:59:12 +05:30
parent d2774b4a1e
commit 912967fa3a
@@ -60,6 +60,81 @@ function getProjectFinancials(project) {
const fmt = (amt) =>
new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 }).format(Number(amt) || 0);
// Dark-mode-aware dropdown — replaces native <select> so the option list
// doesn't render with the OS default white background in dark mode.
function FilterPopover({ id, value, onChange, options, allLabel, ariaLabel }) {
const [open, setOpen] = useState(false);
const boxRef = useRef(null);
useEffect(() => {
if (!open) return;
const onClick = (e) => {
if (boxRef.current && !boxRef.current.contains(e.target)) setOpen(false);
};
const onKey = (e) => { if (e.key === 'Escape') setOpen(false); };
document.addEventListener('mousedown', onClick);
document.addEventListener('keydown', onKey);
return () => {
document.removeEventListener('mousedown', onClick);
document.removeEventListener('keydown', onKey);
};
}, [open]);
const display = value === 'all' ? allLabel : value;
return (
<div className="relative" ref={boxRef}>
<button
id={id}
type="button"
aria-haspopup="listbox"
aria-expanded={open}
aria-label={ariaLabel}
onClick={() => setOpen(o => !o)}
className="w-full flex items-center justify-between gap-2 pl-3 pr-2 py-2 text-sm rounded-xl bg-zinc-100 dark:bg-black/40 border border-zinc-200 dark:border-white/10 text-zinc-900 dark:text-white outline-none focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500/40 transition-colors"
>
<span className="truncate text-left">{display}</span>
<ChevronDown size={14} className={`shrink-0 text-zinc-400 transition-transform ${open ? 'rotate-180' : ''}`} />
</button>
{open && (
<div
role="listbox"
className="absolute z-30 left-0 right-0 mt-1 rounded-xl bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-white/10 shadow-xl shadow-black/10 dark:shadow-black/50 overflow-hidden"
>
<div className="max-h-56 overflow-y-auto custom-scrollbar py-1">
<button
type="button"
role="option"
aria-selected={value === 'all'}
onClick={() => { onChange('all'); setOpen(false); }}
className={`w-full flex items-center justify-between px-3 py-2 text-sm text-left transition-colors ${value === 'all' ? 'text-emerald-600 dark:text-emerald-400 bg-emerald-50 dark:bg-emerald-500/10' : 'text-zinc-700 dark:text-zinc-200 hover:bg-zinc-50 dark:hover:bg-white/5'}`}
>
<span>{allLabel}</span>
{value === 'all' && <Check size={12} strokeWidth={2.5} className="shrink-0 opacity-70" />}
</button>
{options.map(opt => {
const isSelected = opt === value;
return (
<button
key={opt}
type="button"
role="option"
aria-selected={isSelected}
onClick={() => { onChange(opt); setOpen(false); }}
className={`w-full flex items-center justify-between px-3 py-2 text-sm text-left transition-colors ${isSelected ? 'text-emerald-600 dark:text-emerald-400 bg-emerald-50 dark:bg-emerald-500/10' : 'text-zinc-700 dark:text-zinc-200 hover:bg-zinc-50 dark:hover:bg-white/5'}`}
>
<span className="truncate">{opt}</span>
{isSelected && <Check size={12} strokeWidth={2.5} className="shrink-0 opacity-70" />}
</button>
);
})}
</div>
</div>
)}
</div>
);
}
const CommissionDistributionPanel = ({
ownerProjects,
orgCommissionDefaults,
@@ -173,9 +248,6 @@ const CommissionDistributionPanel = ({
setProjectQuery('');
};
const selectClass =
"appearance-none w-full pl-3 pr-8 py-2 text-sm rounded-xl bg-zinc-100 dark:bg-black/40 border border-zinc-200 dark:border-white/10 text-zinc-900 dark:text-white outline-none focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500/40 transition-colors cursor-pointer";
return (
<div className="flex flex-col gap-3">
{/* Header */}
@@ -220,21 +292,14 @@ const CommissionDistributionPanel = ({
</div>
{/* Role filter */}
<div className="relative">
<label htmlFor="commission-role-filter" className="sr-only">Filter by role</label>
<select
id="commission-role-filter"
value={roleFilter}
onChange={(e) => setRoleFilter(e.target.value)}
className={selectClass}
>
<option value="all">All Roles</option>
{roleOptions.map(r => (
<option key={r} value={r}>{r}</option>
))}
</select>
<ChevronDown size={14} className="absolute right-2.5 top-1/2 -translate-y-1/2 text-zinc-400 pointer-events-none" />
</div>
<FilterPopover
id="commission-role-filter"
ariaLabel="Filter by role"
value={roleFilter}
onChange={setRoleFilter}
options={roleOptions}
allLabel="All Roles"
/>
{/* Project searchable dropdown */}
<div className="relative" ref={projectBoxRef}>
@@ -295,21 +360,14 @@ const CommissionDistributionPanel = ({
</div>
{/* Commission Type filter */}
<div className="relative">
<label htmlFor="commission-type-filter" className="sr-only">Filter by commission type</label>
<select
id="commission-type-filter"
value={typeFilter}
onChange={(e) => setTypeFilter(e.target.value)}
className={selectClass}
>
<option value="all">All Commission Types</option>
{typeOptions.map(t => (
<option key={t} value={t}>{t}</option>
))}
</select>
<ChevronDown size={14} className="absolute right-2.5 top-1/2 -translate-y-1/2 text-zinc-400 pointer-events-none" />
</div>
<FilterPopover
id="commission-type-filter"
ariaLabel="Filter by commission type"
value={typeFilter}
onChange={setTypeFilter}
options={typeOptions}
allLabel="All Commission Types"
/>
{hasActiveFilters && (
<div className="sm:col-span-2 lg:col-span-4 flex justify-end">