feat: Implement game type filter for expansion selection in Cube Manager, adding 'digital' property to Scryfall sets and corresponding UI.
Some checks failed
Build and Deploy / build (push) Failing after 58s
Some checks failed
Build and Deploy / build (push) Failing after 58s
This commit is contained in:
@@ -31,3 +31,4 @@
|
|||||||
- [Server-Side Caching](./devlog/2025-12-16-235900_server_side_caching.md): Completed. Implemented logic to cache images and metadata on the server upon bulk parsing, and updated client to use local assets.
|
- [Server-Side Caching](./devlog/2025-12-16-235900_server_side_caching.md): Completed. Implemented logic to cache images and metadata on the server upon bulk parsing, and updated client to use local assets.
|
||||||
- [Peasant Algorithm Implementation](./devlog/2025-12-16-225700_peasant_algorithm.md): Completed. Implemented Peasant-specific pack generation rules including slot logic for commons, uncommons, lands, and wildcards.
|
- [Peasant Algorithm Implementation](./devlog/2025-12-16-225700_peasant_algorithm.md): Completed. Implemented Peasant-specific pack generation rules including slot logic for commons, uncommons, lands, and wildcards.
|
||||||
- [Multi-Expansion Selection](./devlog/2025-12-16-230500_multi_expansion_selection.md): Completed. Implemented searchable multi-select interface for "From Expansion" pack generation, allowing mixed-set drafts.
|
- [Multi-Expansion Selection](./devlog/2025-12-16-230500_multi_expansion_selection.md): Completed. Implemented searchable multi-select interface for "From Expansion" pack generation, allowing mixed-set drafts.
|
||||||
|
- [Game Type Filter](./devlog/2025-12-16-231000_game_type_filter.md): Completed. Added Paper/Digital filter to the expansion selection list.
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# Game Type Filter for Expansion Selection
|
||||||
|
|
||||||
|
## Objective
|
||||||
|
Add a filter to the "From Expansion" set selection to easily distinguish between Paper and Digital (MTGA/MTGO) sets.
|
||||||
|
|
||||||
|
## Implementation Details
|
||||||
|
1. **ScryfallService Update**: Updated `ScryfallSet` interface to include the `digital` boolean property and mapped it in `fetchSets`.
|
||||||
|
2. **CubeManager UI**: Added a toggle filter bar above the set list with three options:
|
||||||
|
* **All**: Shows all sets.
|
||||||
|
* **Paper**: Shows only sets where `digital` is false.
|
||||||
|
* **Digital**: Shows only sets where `digital` is true.
|
||||||
|
3. **Filter Logic**: Integrated the game type filter into the existing search filter logic in `CubeManager`.
|
||||||
|
|
||||||
|
## Status
|
||||||
|
Completed. Users can now filter the expansion list by game type.
|
||||||
@@ -96,7 +96,9 @@ export const CubeManager: React.FC<CubeManagerProps> = ({ packs, setPacks, onGoT
|
|||||||
const saved = localStorage.getItem('cube_selectedSets');
|
const saved = localStorage.getItem('cube_selectedSets');
|
||||||
return saved ? JSON.parse(saved) : [];
|
return saved ? JSON.parse(saved) : [];
|
||||||
});
|
});
|
||||||
|
|
||||||
const [searchTerm, setSearchTerm] = useState('');
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
|
const [gameTypeFilter, setGameTypeFilter] = useState<'all' | 'paper' | 'digital'>('all'); // Filter state
|
||||||
const [numBoxes, setNumBoxes] = useState<number>(() => {
|
const [numBoxes, setNumBoxes] = useState<number>(() => {
|
||||||
const saved = localStorage.getItem('cube_numBoxes');
|
const saved = localStorage.getItem('cube_numBoxes');
|
||||||
return saved ? parseInt(saved) : 3;
|
return saved ? parseInt(saved) : 3;
|
||||||
@@ -440,14 +442,47 @@ export const CubeManager: React.FC<CubeManagerProps> = ({ packs, setPacks, onGoT
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Game Type Filter */}
|
||||||
|
<div className="flex border-b border-slate-700 bg-slate-900">
|
||||||
|
<button
|
||||||
|
onClick={() => setGameTypeFilter('all')}
|
||||||
|
className={`flex-1 py-1.5 text-[10px] font-bold uppercase tracking-wider transition-colors ${gameTypeFilter === 'all' ? 'bg-slate-700 text-white' : 'text-slate-500 hover:text-slate-300 hover:bg-slate-800'}`}
|
||||||
|
>
|
||||||
|
All
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setGameTypeFilter('paper')}
|
||||||
|
className={`flex-1 py-1.5 text-[10px] font-bold uppercase tracking-wider transition-colors ${gameTypeFilter === 'paper' ? 'bg-emerald-900/40 text-emerald-400' : 'text-slate-500 hover:text-emerald-400 hover:bg-slate-800'}`}
|
||||||
|
title="Show only Paper sets"
|
||||||
|
>
|
||||||
|
Paper
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setGameTypeFilter('digital')}
|
||||||
|
className={`flex-1 py-1.5 text-[10px] font-bold uppercase tracking-wider transition-colors ${gameTypeFilter === 'digital' ? 'bg-blue-900/40 text-blue-400' : 'text-slate-500 hover:text-blue-400 hover:bg-slate-800'}`}
|
||||||
|
title="Show only Digital sets (Arena/MTGO)"
|
||||||
|
>
|
||||||
|
Digital
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* List */}
|
{/* List */}
|
||||||
<div className="max-h-60 overflow-y-auto custom-scrollbar p-1 space-y-0.5">
|
<div className="max-h-60 overflow-y-auto custom-scrollbar p-1 space-y-0.5">
|
||||||
{availableSets
|
{availableSets
|
||||||
.filter(s =>
|
.filter(s => {
|
||||||
!searchTerm ||
|
// Search Filter
|
||||||
|
const matchesSearch = !searchTerm ||
|
||||||
s.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
s.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||||
s.code.toLowerCase().includes(searchTerm.toLowerCase())
|
s.code.toLowerCase().includes(searchTerm.toLowerCase());
|
||||||
)
|
|
||||||
|
// Game Type Filter
|
||||||
|
const matchesType =
|
||||||
|
gameTypeFilter === 'all' ? true :
|
||||||
|
gameTypeFilter === 'paper' ? !s.digital :
|
||||||
|
gameTypeFilter === 'digital' ? s.digital : true;
|
||||||
|
|
||||||
|
return matchesSearch && matchesType;
|
||||||
|
})
|
||||||
.map(s => {
|
.map(s => {
|
||||||
const isSelected = selectedSets.includes(s.code);
|
const isSelected = selectedSets.includes(s.code);
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -168,7 +168,8 @@ export class ScryfallService {
|
|||||||
name: s.name,
|
name: s.name,
|
||||||
set_type: s.set_type,
|
set_type: s.set_type,
|
||||||
released_at: s.released_at,
|
released_at: s.released_at,
|
||||||
icon_svg_uri: s.icon_svg_uri
|
icon_svg_uri: s.icon_svg_uri,
|
||||||
|
digital: s.digital
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -226,4 +227,5 @@ export interface ScryfallSet {
|
|||||||
set_type: string;
|
set_type: string;
|
||||||
released_at: string;
|
released_at: string;
|
||||||
icon_svg_uri: string;
|
icon_svg_uri: string;
|
||||||
|
digital: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user