refactor: Optimize localStorage by stripping card definitions from packs and lands, and clear available lands state in cube manager.

This commit is contained in:
2025-12-17 16:43:06 +01:00
parent 60c012cbb5
commit 0b374c7630
2 changed files with 35 additions and 7 deletions

View File

@@ -39,15 +39,28 @@ export const App: React.FC = () => {
React.useEffect(() => { React.useEffect(() => {
try { try {
localStorage.setItem('generatedPacks', JSON.stringify(generatedPacks)); // Optimiziation: Strip 'definition' (ScryfallCard) from cards to save huge amount of space
// We only need the properties mapped to DraftCard for the UI and Game
const optimizedPacks = generatedPacks.map(p => ({
...p,
cards: p.cards.map(c => {
const { definition, ...rest } = c;
return rest;
})
}));
localStorage.setItem('generatedPacks', JSON.stringify(optimizedPacks));
} catch (e) { } catch (e) {
console.error("Failed to save packs to storage", e); console.error("Failed to save packs to storage (Quota likely exceeded)", e);
} }
}, [generatedPacks]); }, [generatedPacks]);
React.useEffect(() => { React.useEffect(() => {
try { try {
localStorage.setItem('availableLands', JSON.stringify(availableLands)); const optimizedLands = availableLands.map(l => {
const { definition, ...rest } = l;
return rest;
});
localStorage.setItem('availableLands', JSON.stringify(optimizedLands));
} catch (e) { } catch (e) {
console.error("Failed to save lands to storage", e); console.error("Failed to save lands to storage", e);
} }

View File

@@ -72,7 +72,9 @@ export const CubeManager: React.FC<CubeManagerProps> = ({ packs, setPacks, avail
}); });
// UI State // UI State
const [viewMode, setViewMode] = useState<'list' | 'grid' | 'stack'>('list'); const [viewMode, setViewMode] = useState<'list' | 'grid' | 'stack'>(() => {
return (localStorage.getItem('cube_viewMode') as 'list' | 'grid' | 'stack') || 'list';
});
// Generation Settings // Generation Settings
const [genSettings, setGenSettings] = useState<PackGenerationSettings>(() => { const [genSettings, setGenSettings] = useState<PackGenerationSettings>(() => {
@@ -100,7 +102,9 @@ export const CubeManager: React.FC<CubeManagerProps> = ({ packs, setPacks, avail
}); });
const [searchTerm, setSearchTerm] = useState(''); const [searchTerm, setSearchTerm] = useState('');
const [gameTypeFilter, setGameTypeFilter] = useState<'all' | 'paper' | 'digital'>('all'); // Filter state const [gameTypeFilter, setGameTypeFilter] = useState<'all' | 'paper' | 'digital'>(() => {
return (localStorage.getItem('cube_gameTypeFilter') as 'all' | 'paper' | 'digital') || 'all';
});
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;
@@ -119,6 +123,8 @@ export const CubeManager: React.FC<CubeManagerProps> = ({ packs, setPacks, avail
useEffect(() => localStorage.setItem('cube_selectedSets', JSON.stringify(selectedSets)), [selectedSets]); useEffect(() => localStorage.setItem('cube_selectedSets', JSON.stringify(selectedSets)), [selectedSets]);
useEffect(() => localStorage.setItem('cube_numBoxes', numBoxes.toString()), [numBoxes]); useEffect(() => localStorage.setItem('cube_numBoxes', numBoxes.toString()), [numBoxes]);
useEffect(() => localStorage.setItem('cube_cardWidth', cardWidth.toString()), [cardWidth]); useEffect(() => localStorage.setItem('cube_cardWidth', cardWidth.toString()), [cardWidth]);
useEffect(() => localStorage.setItem('cube_viewMode', viewMode), [viewMode]);
useEffect(() => localStorage.setItem('cube_gameTypeFilter', gameTypeFilter), [gameTypeFilter]);
const fileInputRef = useRef<HTMLInputElement>(null); const fileInputRef = useRef<HTMLInputElement>(null);
@@ -183,6 +189,11 @@ export const CubeManager: React.FC<CubeManagerProps> = ({ packs, setPacks, avail
if (sourceMode === 'set' && selectedSets.length === 0) return; if (sourceMode === 'set' && selectedSets.length === 0) return;
if (sourceMode === 'upload' && !inputText) return; if (sourceMode === 'upload' && !inputText) return;
if (sourceMode === 'set' && numBoxes > 10) {
showToast("Maximum limit is 10 Boxes (360 Packs) to avoid instability.", "error");
return;
}
setLoading(true); setLoading(true);
setPacks([]); // Clear old packs to avoid confusion setPacks([]); // Clear old packs to avoid confusion
@@ -427,11 +438,15 @@ export const CubeManager: React.FC<CubeManagerProps> = ({ packs, setPacks, avail
setInputText(''); setInputText('');
setRawScryfallData(null); setRawScryfallData(null);
setProcessedData(null); setProcessedData(null);
setProcessedData(null); setAvailableLands([]);
setSelectedSets([]); setSelectedSets([]);
localStorage.removeItem('cube_inputText'); localStorage.removeItem('cube_inputText');
localStorage.removeItem('cube_rawScryfallData'); localStorage.removeItem('cube_rawScryfallData');
localStorage.removeItem('cube_selectedSets'); localStorage.removeItem('cube_selectedSets');
localStorage.removeItem('cube_viewMode');
localStorage.removeItem('cube_gameTypeFilter');
setViewMode('list');
setGameTypeFilter('all');
// We keep filters and settings as they are user preferences // We keep filters and settings as they are user preferences
} }
}; };
@@ -686,7 +701,7 @@ export const CubeManager: React.FC<CubeManagerProps> = ({ packs, setPacks, avail
<input <input
type="number" type="number"
min={1} min={1}
max={20} max={10}
value={numBoxes} value={numBoxes}
onChange={(e) => setNumBoxes(parseInt(e.target.value))} onChange={(e) => setNumBoxes(parseInt(e.target.value))}
className="w-16 bg-slate-700 border-none rounded p-1 text-center text-white font-mono" className="w-16 bg-slate-700 border-none rounded p-1 text-center text-white font-mono"