Files
HexUnlockedWeb/app/items/OfferingGrid.tsx
T
2026-06-19 04:29:24 -03:00

120 lines
3.2 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 { Offering, OfferingRole, getOfferingIconUrl } from './types';
import { randInRange } from '@/lib/utils';
type Props = {
offerings: Offering[];
quantities: Record<string, number>;
randMin: number;
randMax: number;
onSetQty: (id: string, qty: number) => void;
};
const ROLE_LABELS: Record<OfferingRole, string> = {
all: 'All',
shared: 'Shared',
killer: 'Killer',
survivor: 'Survivor'
};
const roleMatches = (offeringRole: number, filter: OfferingRole) => {
if (filter === 'all') return true;
if (filter === 'shared') return offeringRole === 0;
if (filter === 'killer') return offeringRole === 1;
if (filter === 'survivor') return offeringRole === 2;
return true;
};
export default function OfferingGrid({
offerings,
quantities,
randMin,
randMax,
onSetQty
}: Props) {
const [search, setSearch] = useState('');
const [roleFilter, setRoleFilter] = useState<OfferingRole>('all');
const filtered = useMemo(() => {
return offerings.filter((o) => {
if (!roleMatches(o.role, roleFilter)) return false;
if (search.trim() && !o.name.toLowerCase().includes(search.toLowerCase()))
return false;
return true;
});
}, [offerings, roleFilter, search]);
const handleGive100Visible = () =>
filtered.forEach((o) => onSetQty(o.id, 100));
const handleRandVisible = () =>
filtered.forEach((o) => onSetQty(o.id, randInRange(randMin, randMax)));
const handleLockVisible = () => filtered.forEach((o) => onSetQty(o.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 offerings...'
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
<div className={shared.roleFilter}>
{(Object.keys(ROLE_LABELS) as OfferingRole[]).map((r) => (
<button
key={r}
className={`${shared.roleBtn} ${roleFilter === r ? shared.roleBtnActive : ''}`}
onClick={() => setRoleFilter(r)}
>
{ROLE_LABELS[r]}
</button>
))}
</div>
<span className={shared.spacer} />
<span className={shared.resultCount}>
{filtered.length} shown · {activeCount} active
</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 offerings match</div>
) : (
<div className={styles.grid}>
{filtered.map((offering) => (
<QuantityCard
key={offering.id}
id={offering.id}
name={offering.name}
iconUrl={getOfferingIconUrl(offering.iconFilePath)}
qty={quantities[offering.id] ?? 0}
randMin={randMin}
randMax={randMax}
onSetQty={onSetQty}
/>
))}
</div>
)}
</>
);
}