120 lines
3.1 KiB
TypeScript
120 lines
3.1 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useMemo } from 'react';
|
|
import shared from '../../styles/shared.module.css';
|
|
import styles from '../../styles/Items.module.css';
|
|
import QuantityCard from '../../components/QuantityCard';
|
|
import { Addon, getAddonIconUrl, randInRange } from './types';
|
|
|
|
type Props = {
|
|
addons: Addon[];
|
|
quantities: Record<string, number>;
|
|
randMin: number;
|
|
randMax: number;
|
|
onSetQty: (id: string, qty: number) => void;
|
|
};
|
|
|
|
export default function AddonGrid({
|
|
addons,
|
|
quantities,
|
|
randMin,
|
|
randMax,
|
|
onSetQty
|
|
}: Props) {
|
|
const [search, setSearch] = useState('');
|
|
const [roleFilter, setRoleFilter] = useState<'all' | 'killer' | 'survivor'>(
|
|
'all'
|
|
);
|
|
|
|
const filtered = useMemo(() => {
|
|
return addons.filter((addon) => {
|
|
if (roleFilter === 'killer' && addon.role !== 1) return false;
|
|
if (roleFilter === 'survivor' && addon.role !== 2) return false;
|
|
if (
|
|
search.trim() &&
|
|
!addon.name.toLowerCase().includes(search.toLowerCase())
|
|
)
|
|
return false;
|
|
return true;
|
|
});
|
|
}, [addons, search, roleFilter]);
|
|
|
|
const handleGive100Visible = () =>
|
|
filtered.forEach((a) => onSetQty(a.id, 100));
|
|
const handleRandVisible = () =>
|
|
filtered.forEach((a) => onSetQty(a.id, randInRange(randMin, randMax)));
|
|
const handleLockVisible = () => filtered.forEach((a) => onSetQty(a.id, 0));
|
|
|
|
const activeCount = Object.values(quantities).filter((q) => q > 0).length;
|
|
|
|
return (
|
|
<>
|
|
<div className={shared.toolbar}>
|
|
<input
|
|
className={shared.searchInput}
|
|
type='text'
|
|
placeholder='Search addons...'
|
|
value={search}
|
|
onChange={(e) => setSearch(e.target.value)}
|
|
/>
|
|
|
|
<div className={shared.roleFilter}>
|
|
<button
|
|
className={`${shared.roleBtn} ${roleFilter === 'all' ? shared.roleBtnActive : ''}`}
|
|
onClick={() => setRoleFilter('all')}
|
|
>
|
|
All
|
|
</button>
|
|
<button
|
|
className={`${shared.roleBtn} ${roleFilter === 'survivor' ? shared.roleBtnActive : ''}`}
|
|
onClick={() => setRoleFilter('survivor')}
|
|
>
|
|
Survivor
|
|
</button>
|
|
<button
|
|
className={`${shared.roleBtn} ${roleFilter === 'killer' ? shared.roleBtnActive : ''}`}
|
|
onClick={() => setRoleFilter('killer')}
|
|
>
|
|
Killer
|
|
</button>
|
|
</div>
|
|
|
|
<span className={shared.spacer} />
|
|
<span className={shared.resultCount}>
|
|
{filtered.length} shown · {activeCount} active out of {addons.length}{' '}
|
|
total
|
|
</span>
|
|
|
|
<button className={shared.unlockAllBtn} onClick={handleGive100Visible}>
|
|
Set all to 100
|
|
</button>
|
|
<button className={styles.randBtn} onClick={handleRandVisible}>
|
|
Randomize
|
|
</button>
|
|
<button className={shared.lockAllBtn} onClick={handleLockVisible}>
|
|
Remove all visible
|
|
</button>
|
|
</div>
|
|
|
|
{filtered.length === 0 ? (
|
|
<div className={shared.empty}>No addons match</div>
|
|
) : (
|
|
<div className={styles.grid}>
|
|
{filtered.map((addon) => (
|
|
<QuantityCard
|
|
key={addon.id}
|
|
id={addon.id}
|
|
name={addon.name}
|
|
iconUrl={getAddonIconUrl(addon.iconFilePath)}
|
|
qty={quantities[addon.id] ?? 0}
|
|
randMin={randMin}
|
|
randMax={randMax}
|
|
onSetQty={onSetQty}
|
|
/>
|
|
))}
|
|
</div>
|
|
)}
|
|
</>
|
|
);
|
|
}
|