feat(frontend): inventory item-state filter — Any/Equipped/Not equipped radios, moved under Characters
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
4e1b9f4a1f
commit
71f235c8b1
17 changed files with 44 additions and 35 deletions
|
|
@ -32,7 +32,10 @@ export function ActiveChips({ search }: { search: InventorySearch }) {
|
|||
});
|
||||
}
|
||||
if (f.itemSet) chips.push({ label: `Set: ${f.itemSet}`, remove: () => update({ itemSet: '' }) });
|
||||
if (f.equippedOnly) chips.push({ label: 'Equipped', remove: () => update({ equippedOnly: false }) });
|
||||
if (f.equipStatus) chips.push({
|
||||
label: f.equipStatus === 'equipped' ? 'Equipped' : 'Not equipped',
|
||||
remove: () => update({ equipStatus: '' }),
|
||||
});
|
||||
if (f.bonded) chips.push({ label: 'Bonded', remove: () => update({ bonded: false }) });
|
||||
if (f.attuned) chips.push({ label: 'Attuned', remove: () => update({ attuned: false }) });
|
||||
if (f.rare) chips.push({ label: 'Rare', remove: () => update({ rare: false }) });
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ export function FilterSidebar({ search }: { search: InventorySearch }) {
|
|||
ratings: { ...f.ratings, [param]: v === '' ? '' : Number(v) },
|
||||
});
|
||||
const ratingCount = Object.values(f.ratings).filter(v => v !== '').length;
|
||||
const stateCount = [f.equippedOnly, f.bonded, f.attuned, f.rare].filter(Boolean).length;
|
||||
const stateCount = [f.equipStatus !== '', f.bonded, f.attuned, f.rare].filter(Boolean).length;
|
||||
const reqCount = [f.maxLevel, f.minValue, f.minWorkmanship, f.maxBurden].filter(v => v !== '').length;
|
||||
const types: Array<[ItemType, string]> = [['all', 'All items'], ['armor', 'Armor'],
|
||||
['jewelry', 'Jewelry'], ['weapon', 'Weapons'], ['clothing', 'Clothing'],
|
||||
|
|
@ -48,6 +48,20 @@ export function FilterSidebar({ search }: { search: InventorySearch }) {
|
|||
return (
|
||||
<div className="inv-sidebar">
|
||||
<CharacterFilter search={search} />
|
||||
<Group title="Item state" defaultOpen badge={stateCount || undefined}>
|
||||
{([['', 'Any'], ['equipped', 'Equipped'], ['unequipped', 'Not equipped']] as const).map(([v, label]) => (
|
||||
<label className="inv-fitem" key={label}>
|
||||
<input type="radio" name="inv-eq" checked={f.equipStatus === v}
|
||||
onChange={() => update({ equipStatus: v })} /> {label}
|
||||
</label>
|
||||
))}
|
||||
<label className="inv-fitem"><input type="checkbox" checked={f.bonded}
|
||||
onChange={e => update({ bonded: e.target.checked })} /> Bonded</label>
|
||||
<label className="inv-fitem"><input type="checkbox" checked={f.attuned}
|
||||
onChange={e => update({ attuned: e.target.checked })} /> Attuned</label>
|
||||
<label className="inv-fitem"><input type="checkbox" checked={f.rare}
|
||||
onChange={e => update({ rare: e.target.checked })} /> Rare</label>
|
||||
</Group>
|
||||
<Group title="Item type" defaultOpen badge={f.itemType !== 'all' ? 1 : undefined}>
|
||||
{types.map(([v, label]) => (
|
||||
<label className="inv-fitem" key={v}>
|
||||
|
|
@ -104,16 +118,6 @@ export function FilterSidebar({ search }: { search: InventorySearch }) {
|
|||
</label>
|
||||
))}
|
||||
</Group>
|
||||
<Group title="Item state" badge={stateCount || undefined}>
|
||||
<label className="inv-fitem"><input type="checkbox" checked={f.equippedOnly}
|
||||
onChange={e => update({ equippedOnly: e.target.checked })} /> Equipped only</label>
|
||||
<label className="inv-fitem"><input type="checkbox" checked={f.bonded}
|
||||
onChange={e => update({ bonded: e.target.checked })} /> Bonded</label>
|
||||
<label className="inv-fitem"><input type="checkbox" checked={f.attuned}
|
||||
onChange={e => update({ attuned: e.target.checked })} /> Attuned</label>
|
||||
<label className="inv-fitem"><input type="checkbox" checked={f.rare}
|
||||
onChange={e => update({ rare: e.target.checked })} /> Rare</label>
|
||||
</Group>
|
||||
<Group title="Reqs & value" badge={reqCount || undefined}>
|
||||
<div className="inv-range"><label>Wield lvl ≤</label>
|
||||
<input type="number" value={f.maxLevel} placeholder="max"
|
||||
|
|
|
|||
|
|
@ -45,7 +45,8 @@ export interface SearchFilters {
|
|||
/** min-rating param name -> value ('' = unset). */
|
||||
ratings: Record<string, number | ''>;
|
||||
itemSet: string; // set id, '' = none
|
||||
equippedOnly: boolean;
|
||||
/** '' = any, or the backend's equipment_status values. */
|
||||
equipStatus: '' | 'equipped' | 'unequipped';
|
||||
bonded: boolean;
|
||||
attuned: boolean;
|
||||
rare: boolean;
|
||||
|
|
@ -61,7 +62,7 @@ export interface SearchFilters {
|
|||
export const DEFAULT_FILTERS: SearchFilters = {
|
||||
text: '', characters: 'all', itemType: 'all', weaponType: '', slots: [],
|
||||
cantrips: [], spellContains: '', ratings: {}, itemSet: '',
|
||||
equippedOnly: false, bonded: false, attuned: false, rare: false,
|
||||
equipStatus: '', bonded: false, attuned: false, rare: false,
|
||||
maxLevel: '', minValue: '', minWorkmanship: '', maxBurden: '',
|
||||
sortBy: 'name', sortDir: 'asc', page: 1,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -53,7 +53,8 @@ function validateFilterValue(key: keyof SearchFilters, value: unknown): unknown
|
|||
case 'itemSet':
|
||||
case 'sortBy':
|
||||
return typeof value === 'string' ? value : undefined;
|
||||
case 'equippedOnly':
|
||||
case 'equipStatus':
|
||||
return value === '' || value === 'equipped' || value === 'unequipped' ? value : undefined;
|
||||
case 'bonded':
|
||||
case 'attuned':
|
||||
case 'rare':
|
||||
|
|
@ -111,7 +112,7 @@ export function buildParams(f: SearchFilters): URLSearchParams {
|
|||
if (f.spellContains) p.set('spell_contains', f.spellContains);
|
||||
for (const [param, v] of Object.entries(f.ratings)) if (v !== '') p.set(param, String(v));
|
||||
if (f.itemSet) p.set('item_set', f.itemSet);
|
||||
if (f.equippedOnly) p.set('equipment_status', 'equipped');
|
||||
if (f.equipStatus) p.set('equipment_status', f.equipStatus);
|
||||
if (f.bonded) p.set('bonded', 'true');
|
||||
if (f.attuned) p.set('attuned', 'true');
|
||||
if (f.rare) p.set('is_rare', 'true');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue