[Glitch] Add useStorageState hook

Port f99c60a8f3 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
diondiondion
2026-02-11 14:30:53 +01:00
committed by Claire
parent 02a7f74976
commit f842ce2206
2 changed files with 80 additions and 13 deletions

View File

@@ -7,7 +7,7 @@ import {
useState,
} from 'react';
import { useStorage } from '@/flavours/glitch/hooks/useStorage';
import { useStorageState } from '@/flavours/glitch/hooks/useStorage';
interface AccountTimelineContextValue {
accountId: string;
@@ -26,30 +26,34 @@ export const AccountTimelineProvider: FC<{
accountId: string;
children: ReactNode;
}> = ({ accountId, children }) => {
const { getItem, setItem } = useStorage({
const storageOptions = {
type: 'session',
prefix: `filters-${accountId}:`,
});
const [boosts, setBoosts] = useState(
() => (getItem('boosts') === '0' ? false : true), // Default to enabled.
} as const;
const [boosts, setBoosts] = useStorageState<boolean>(
'boosts',
true,
storageOptions,
);
const [replies, setReplies] = useState(() =>
getItem('replies') === '1' ? true : false,
const [replies, setReplies] = useStorageState<boolean>(
'replies',
false,
storageOptions,
);
const handleSetBoosts = useCallback(
(value: boolean) => {
setBoosts(value);
setItem('boosts', value ? '1' : '0');
},
[setBoosts, setItem],
[setBoosts],
);
const handleSetReplies = useCallback(
(value: boolean) => {
setReplies(value);
setItem('replies', value ? '1' : '0');
},
[setReplies, setItem],
[setReplies],
);
const [showAllPinned, setShowAllPinned] = useState(false);

View File

@@ -1,9 +1,14 @@
import { useCallback, useMemo } from 'react';
import { useCallback, useMemo, useState } from 'react';
interface StorageOptions {
type?: 'local' | 'session';
prefix?: string;
}
export function useStorage({
type = 'local',
prefix = '',
}: { type?: 'local' | 'session'; prefix?: string } = {}) {
}: StorageOptions = {}) {
const storageType = type === 'local' ? 'localStorage' : 'sessionStorage';
const isAvailable = useMemo(
() => storageAvailable(storageType),
@@ -23,6 +28,7 @@ export function useStorage({
},
[isAvailable, storageType, prefix],
);
const setItem = useCallback(
(key: string, value: string) => {
if (!isAvailable) {
@@ -35,13 +41,52 @@ export function useStorage({
[isAvailable, storageType, prefix],
);
const removeItem = useCallback(
(key: string) => {
if (!isAvailable) {
return;
}
try {
window[storageType].removeItem(prefix ? `${prefix};${key}` : key);
} catch {}
},
[isAvailable, storageType, prefix],
);
return {
isAvailable,
getItem,
setItem,
removeItem,
};
}
export function useStorageState<T extends string | boolean>(
key: string,
initialState: T,
options?: StorageOptions,
) {
const { getItem, setItem, removeItem } = useStorage(options);
const [state, setState] = useState<T>(
() => (retrieveBooleanOrString(getItem(key)) as T | null) ?? initialState,
);
const handleSetState = useCallback(
(newValue: T) => {
setItem(key, castToString(newValue));
setState(newValue);
},
[key, setItem],
);
const removeState = useCallback(() => {
removeItem(key);
setState(initialState);
}, [initialState, key, removeItem]);
return [state, handleSetState, removeState] as const;
}
// Tests the storage availability for the given type. Taken from MDN:
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
export function storageAvailable(type: 'localStorage' | 'sessionStorage') {
@@ -62,3 +107,21 @@ export function storageAvailable(type: 'localStorage' | 'sessionStorage') {
);
}
}
function castToString(value: string | boolean) {
if (typeof value === 'boolean') {
return value ? '1' : '0';
} else {
return value;
}
}
function retrieveBooleanOrString(value: string | null) {
if (value === '1') {
return true;
} else if (value === '0') {
return false;
} else {
return value;
}
}