All checks were successful
Deploy Development / deploy (push) Successful in 42s
Test Suite / pytest-backend (push) Successful in 41s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 12s
Test Suite / k6 /health Baseline (push) Successful in 33s
Test Suite / playwright-tests (push) Successful in 1m18s
- Introduced new CSS styles for exercise cards and selection sections, improving visual feedback for selected exercises. - Updated ExerciseListCard to support a new `selectionPinned` prop, allowing for a badge display on selected exercises. - Refactored selection handling in ExercisesListPageRoot to manage selected entries more effectively, replacing the previous Set-based approach. - Enhanced SaveSelectedExercisesAsModuleModal to support appending exercises to existing modules, improving module management capabilities. - Updated session state handling to include selected entries, ensuring persistence across sessions.
52 lines
1.8 KiB
JavaScript
52 lines
1.8 KiB
JavaScript
import { INITIAL_EXERCISE_LIST_FILTERS, mergeExerciseListPrefsFromApi } from '../constants/exerciseListFilters'
|
|
import { normalizeSelectedEntries } from './exerciseListSelection'
|
|
|
|
const STORAGE_KEY = 'shinkan.exerciseList.session.v1'
|
|
|
|
function safeParse(raw) {
|
|
if (!raw) return null
|
|
try {
|
|
return JSON.parse(raw)
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
/** @returns {{ filters: object, searchInput: string, aiSearchInput: string, mineOnly: boolean, selectedEntries: object[] } | null} */
|
|
export function readExerciseListSessionState() {
|
|
if (typeof sessionStorage === 'undefined') return null
|
|
const parsed = safeParse(sessionStorage.getItem(STORAGE_KEY))
|
|
if (!parsed || typeof parsed !== 'object') return null
|
|
|
|
const filters =
|
|
parsed.filters && typeof parsed.filters === 'object'
|
|
? mergeExerciseListPrefsFromApi(parsed.filters)
|
|
: { ...INITIAL_EXERCISE_LIST_FILTERS }
|
|
|
|
return {
|
|
filters,
|
|
searchInput: typeof parsed.searchInput === 'string' ? parsed.searchInput : '',
|
|
aiSearchInput: typeof parsed.aiSearchInput === 'string' ? parsed.aiSearchInput : '',
|
|
mineOnly: !!parsed.mineOnly,
|
|
selectedEntries: normalizeSelectedEntries(parsed.selectedEntries),
|
|
}
|
|
}
|
|
|
|
export function writeExerciseListSessionState(state) {
|
|
if (typeof sessionStorage === 'undefined' || !state || typeof state !== 'object') return
|
|
try {
|
|
sessionStorage.setItem(
|
|
STORAGE_KEY,
|
|
JSON.stringify({
|
|
filters: state.filters ?? { ...INITIAL_EXERCISE_LIST_FILTERS },
|
|
searchInput: typeof state.searchInput === 'string' ? state.searchInput : '',
|
|
aiSearchInput: typeof state.aiSearchInput === 'string' ? state.aiSearchInput : '',
|
|
mineOnly: !!state.mineOnly,
|
|
selectedEntries: normalizeSelectedEntries(state.selectedEntries),
|
|
})
|
|
)
|
|
} catch {
|
|
/* quota / private mode */
|
|
}
|
|
}
|