feat: store notification filter state in localStorage
This commit is contained in:
parent
de6fe78004
commit
f9a5007104
@ -15,6 +15,8 @@ import dayjs from 'dayjs';
|
||||
import { Popup, usePopup } from 'shared/components/PopupMenu';
|
||||
import { CheckCircleOutline, Circle, CircleSolid, UserCircle } from 'shared/icons';
|
||||
import produce from 'immer';
|
||||
import { useLocalStorage } from 'shared/hooks/useStateWithLocalStorage';
|
||||
import localStorage from 'shared/utils/localStorage';
|
||||
|
||||
const ItemWrapper = styled.div`
|
||||
cursor: pointer;
|
||||
@ -403,7 +405,10 @@ type NotificationEntry = {
|
||||
};
|
||||
};
|
||||
const NotificationPopup: React.FC = ({ children }) => {
|
||||
const [filter, setFilter] = useState<NotificationFilter>(NotificationFilter.Unread);
|
||||
const [filter, setFilter] = useLocalStorage<NotificationFilter>(
|
||||
localStorage.NOTIFICATIONS_FILTER,
|
||||
NotificationFilter.Unread,
|
||||
);
|
||||
const [data, setData] = useState<{ nodes: Array<NotificationEntry>; hasNextPage: boolean; cursor: string }>({
|
||||
nodes: [],
|
||||
hasNextPage: false,
|
||||
|
@ -1,4 +1,14 @@
|
||||
import React from 'react';
|
||||
import React, { Dispatch, SetStateAction, useEffect, useState } from 'react';
|
||||
|
||||
// A wrapper for "JSON.parse()"" to support "undefined" value
|
||||
function parseJSON<T>(value: string | null): T | undefined {
|
||||
try {
|
||||
return value === 'undefined' ? undefined : JSON.parse(value ?? '');
|
||||
} catch (error) {
|
||||
console.log('parsing error on', { value });
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const useStateWithLocalStorage = (localStorageKey: string): [string, React.Dispatch<React.SetStateAction<string>>] => {
|
||||
const [value, setValue] = React.useState<string>(localStorage.getItem(localStorageKey) || '');
|
||||
@ -11,3 +21,78 @@ const useStateWithLocalStorage = (localStorageKey: string): [string, React.Dispa
|
||||
};
|
||||
|
||||
export default useStateWithLocalStorage;
|
||||
|
||||
type SetValue<T> = Dispatch<SetStateAction<T>>;
|
||||
|
||||
function useLocalStorage<T>(key: string, initialValue: T): [T, SetValue<T>] {
|
||||
// Get from local storage then
|
||||
// parse stored json or return initialValue
|
||||
const readValue = (): T => {
|
||||
// Prevent build error "window is undefined" but keep keep working
|
||||
if (typeof window === 'undefined') {
|
||||
return initialValue;
|
||||
}
|
||||
|
||||
try {
|
||||
const item = window.localStorage.getItem(key);
|
||||
return item ? (parseJSON(item) as T) : initialValue;
|
||||
} catch (error) {
|
||||
console.warn(`Error reading localStorage key “${key}”:`, error);
|
||||
return initialValue;
|
||||
}
|
||||
};
|
||||
|
||||
// State to store our value
|
||||
// Pass initial state function to useState so logic is only executed once
|
||||
const [storedValue, setStoredValue] = useState<T>(readValue);
|
||||
|
||||
// Return a wrapped version of useState's setter function that ...
|
||||
// ... persists the new value to localStorage.
|
||||
const setValue: SetValue<T> = (value) => {
|
||||
// Prevent build error "window is undefined" but keeps working
|
||||
if (typeof window === 'undefined') {
|
||||
console.warn(`Tried setting localStorage key “${key}” even though environment is not a client`);
|
||||
}
|
||||
|
||||
try {
|
||||
// Allow value to be a function so we have the same API as useState
|
||||
const newValue = value instanceof Function ? value(storedValue) : value;
|
||||
|
||||
// Save to local storage
|
||||
window.localStorage.setItem(key, JSON.stringify(newValue));
|
||||
|
||||
// Save state
|
||||
setStoredValue(newValue);
|
||||
|
||||
// We dispatch a custom event so every useLocalStorage hook are notified
|
||||
window.dispatchEvent(new Event('local-storage'));
|
||||
} catch (error) {
|
||||
console.warn(`Error setting localStorage key “${key}”:`, error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setStoredValue(readValue());
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const handleStorageChange = () => {
|
||||
setStoredValue(readValue());
|
||||
};
|
||||
|
||||
// this only works for other documents, not the current one
|
||||
window.addEventListener('storage', handleStorageChange);
|
||||
|
||||
// this is a custom event, triggered in writeValueToLocalStorage
|
||||
window.addEventListener('local-storage', handleStorageChange);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('storage', handleStorageChange);
|
||||
window.removeEventListener('local-storage', handleStorageChange);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return [storedValue, setValue];
|
||||
}
|
||||
|
||||
export { useLocalStorage };
|
||||
|
@ -1,4 +1,5 @@
|
||||
const localStorage = {
|
||||
NOTIFICATIONS_FILTER: 'notifications_filter',
|
||||
CARD_LABEL_VARIANT_STORAGE_KEY: 'card_label_variant',
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user