Files
papercrate/frontend/src/app/useDocumentsPreferences.ts
T
2025-11-13 01:07:55 +01:00

122 lines
4.2 KiB
TypeScript

import { useCallback, useEffect, useRef, useState } from 'react';
import {
DEFAULT_SORT_DIRECTION,
DEFAULT_SORT_FIELD,
SORT_FIELD_VALUES,
} from './appLayoutUtils';
const VIEW_MODE_STORAGE_KEY = 'papercrate_view_mode';
const SORT_FIELD_STORAGE_KEY = 'papercrate_sort_field';
const SORT_DIRECTION_STORAGE_KEY = 'papercrate_sort_direction';
const INCLUDE_DESCENDANTS_STORAGE_KEY = 'papercrate_include_descendants';
const readSessionStorage = (key: string): string | null => {
try {
return window.sessionStorage.getItem(key);
} catch (error) {
console.warn(`[session-storage] failed to read ${key}`, error);
return null;
}
};
const writeSessionStorage = (key: string, value: string): void => {
try {
window.sessionStorage.setItem(key, value);
} catch (error) {
console.warn(`[session-storage] failed to persist ${key}`, error);
}
};
export const useDocumentsPreferences = () => {
const [documentsViewMode, setDocumentsViewModeState] = useState<'list' | 'grid' | 'desk'>(() => {
const stored = readSessionStorage(VIEW_MODE_STORAGE_KEY);
if (stored === 'grid' || stored === 'desk') {
return stored;
}
return 'list';
});
const lastNonDeskViewRef = useRef<'list' | 'grid'>((documentsViewMode === 'desk' ? 'list' : documentsViewMode) as 'list' | 'grid');
const setDocumentsViewMode = useCallback((mode: string) => {
const next = mode === 'grid' ? 'grid' : mode === 'desk' ? 'desk' : 'list';
setDocumentsViewModeState((previous) => {
if (next !== previous) {
writeSessionStorage(VIEW_MODE_STORAGE_KEY, next);
}
return next;
});
}, []);
const handleDeskExit = useCallback(() => {
const fallback = lastNonDeskViewRef.current && lastNonDeskViewRef.current !== 'desk'
? lastNonDeskViewRef.current
: 'list';
setDocumentsViewMode(fallback);
}, [setDocumentsViewMode]);
const [documentsSortField, setDocumentsSortField] = useState(() => {
const stored = readSessionStorage(SORT_FIELD_STORAGE_KEY);
return SORT_FIELD_VALUES.includes(stored) ? stored : DEFAULT_SORT_FIELD;
});
const documentsSortFieldRef = useRef(documentsSortField);
useEffect(() => {
documentsSortFieldRef.current = documentsSortField;
writeSessionStorage(SORT_FIELD_STORAGE_KEY, documentsSortField);
}, [documentsSortField]);
const [documentsSortDirection, setDocumentsSortDirection] = useState(() => {
const stored = readSessionStorage(SORT_DIRECTION_STORAGE_KEY);
return stored === 'desc' || stored === 'asc' ? stored : DEFAULT_SORT_DIRECTION;
});
const documentsSortDirectionRef = useRef(documentsSortDirection);
useEffect(() => {
documentsSortDirectionRef.current = documentsSortDirection;
writeSessionStorage(SORT_DIRECTION_STORAGE_KEY, documentsSortDirection);
}, [documentsSortDirection]);
const handleDocumentsSortFieldChange = useCallback((field: string) => {
const nextField = SORT_FIELD_VALUES.includes(field) ? field : DEFAULT_SORT_FIELD;
setDocumentsSortField((previous) => (previous === nextField ? previous : nextField));
}, []);
const handleDocumentsSortDirectionToggle = useCallback(() => {
setDocumentsSortDirection((previous) => (previous === 'asc' ? 'desc' : 'asc'));
}, []);
const [searchIncludeDescendants, setSearchIncludeDescendants] = useState(() => {
const stored = readSessionStorage(INCLUDE_DESCENDANTS_STORAGE_KEY);
if (stored === 'true') return true;
if (stored === 'false') return false;
return true;
});
useEffect(() => {
writeSessionStorage(
INCLUDE_DESCENDANTS_STORAGE_KEY,
searchIncludeDescendants ? 'true' : 'false',
);
}, [searchIncludeDescendants]);
const toggleSearchIncludeDescendants = useCallback(() => {
setSearchIncludeDescendants((previous) => !previous);
}, []);
const sortRefreshReadyRef = useRef(false);
return {
documentsViewMode,
handleDocumentsViewModeChange: setDocumentsViewMode,
handleDeskExit,
documentsSortField,
documentsSortDirection,
documentsSortFieldRef,
documentsSortDirectionRef,
handleDocumentsSortFieldChange,
handleDocumentsSortDirectionToggle,
searchIncludeDescendants,
setSearchIncludeDescendants,
toggleSearchIncludeDescendants,
sortRefreshReadyRef,
};
};