From 1bbf3b164aaa4658fc5d8088113f20e9b19ab327 Mon Sep 17 00:00:00 2001
From: DrMint
Date: Tue, 16 Aug 2022 01:25:01 +0200
Subject: [PATCH] Use localStorage hook
---
src/components/AppLayout.tsx | 71 +++++++++---------
src/components/Inputs/Select.tsx | 11 +--
src/components/Library/PreviewCardCTAs.tsx | 4 +-
src/contexts/AppLayoutContext.tsx | 83 ++++++++++++++--------
src/hooks/useDarkMode.ts | 18 ++---
src/hooks/useSmartLanguage.ts | 2 +-
src/hooks/useStateWithLocalStorage.ts | 31 --------
src/hooks/useTernaryDarkMode.ts | 38 ----------
src/pages/library/index.tsx | 2 +-
9 files changed, 106 insertions(+), 154 deletions(-)
delete mode 100644 src/hooks/useStateWithLocalStorage.ts
delete mode 100644 src/hooks/useTernaryDarkMode.ts
diff --git a/src/components/AppLayout.tsx b/src/components/AppLayout.tsx
index cc06165..76ac09e 100644
--- a/src/components/AppLayout.tsx
+++ b/src/components/AppLayout.tsx
@@ -109,7 +109,7 @@ export const AppLayout = ({
onSwipedLeft: (SwipeEventData) => {
if (menuGestures) {
if (SwipeEventData.velocity < SENSIBILITY_SWIPE) return;
- if (mainPanelOpen === true) {
+ if (mainPanelOpen) {
setMainPanelOpen(false);
} else if (isDefined(subPanel) && isDefined(contentPanel)) {
setSubPanelOpen(true);
@@ -119,7 +119,7 @@ export const AppLayout = ({
onSwipedRight: (SwipeEventData) => {
if (menuGestures) {
if (SwipeEventData.velocity < SENSIBILITY_SWIPE) return;
- if (subPanelOpen === true) {
+ if (subPanelOpen) {
setSubPanelOpen(false);
} else {
setMainPanelOpen(true);
@@ -135,7 +135,7 @@ export const AppLayout = ({
useLayoutEffect(() => {
document.getElementsByTagName("html")[0].style.fontSize = `${
- (fontSize ?? 1) * 100
+ fontSize * 100
}%`;
}, [fontSize]);
@@ -159,18 +159,16 @@ export const AppLayout = ({
}, [currencyOptions, currencySelect, setCurrency]);
useEffect(() => {
- if (preferredLanguages) {
- if (preferredLanguages.length === 0) {
- if (isDefinedAndNotEmpty(router.locale) && router.locales) {
- setPreferredLanguages(
- getDefaultPreferredLanguages(router.locale, router.locales)
- );
- }
- } else if (router.locale !== preferredLanguages[0]) {
- router.replace(router.asPath, router.asPath, {
- locale: preferredLanguages[0],
- });
+ if (preferredLanguages.length === 0) {
+ if (isDefinedAndNotEmpty(router.locale) && router.locales) {
+ setPreferredLanguages(
+ getDefaultPreferredLanguages(router.locale, router.locales)
+ );
}
+ } else if (router.locale !== preferredLanguages[0]) {
+ router.replace(router.asPath, router.asPath, {
+ locale: preferredLanguages[0],
+ });
}
}, [
preferredLanguages,
@@ -182,11 +180,11 @@ export const AppLayout = ({
const gridCol = useMemo(() => {
if (isDefined(subPanel)) {
- if (mainPanelReduced === true) {
+ if (mainPanelReduced) {
return "grid-cols-[6rem_20rem_1fr]";
}
return "grid-cols-[20rem_20rem_1fr]";
- } else if (mainPanelReduced === true) {
+ } else if (mainPanelReduced) {
return "grid-cols-[6rem_0px_1fr]";
}
return "grid-cols-[20rem_0px_1fr]";
@@ -262,7 +260,7 @@ export const AppLayout = ({
`absolute inset-0 transition-[backdrop-filter] duration-500 [grid-area:content]
mobile:z-10`,
cIf(
- (mainPanelOpen === true || subPanelOpen === true) && isMobile,
+ (mainPanelOpen || subPanelOpen) && isMobile,
"[backdrop-filter:blur(2px)]",
"pointer-events-none touch-none"
)
@@ -272,7 +270,7 @@ export const AppLayout = ({
className={cJoin(
"absolute inset-0 bg-shade transition-opacity duration-500",
cIf(
- (mainPanelOpen === true || subPanelOpen === true) && isMobile,
+ (mainPanelOpen || subPanelOpen) && isMobile,
"opacity-60",
"opacity-0"
)
@@ -312,7 +310,7 @@ export const AppLayout = ({
mobile:border-r-0 mobile:border-l-[1px] mobile:[grid-area:content]`,
turnSubIntoContent
? "mobile:w-full mobile:border-l-0"
- : subPanelOpen === true
+ : subPanelOpen
? ""
: "mobile:translate-x-[100vw]"
)}
@@ -328,7 +326,7 @@ export const AppLayout = ({
transition-transform duration-300 [grid-area:main] [scrollbar-width:none]
webkit-scrollbar:w-0 mobile:z-10 mobile:w-[90%] mobile:justify-self-start
mobile:[grid-area:content]`,
- cIf(mainPanelOpen === false, "mobile:-translate-x-full")
+ cIf(!mainPanelOpen, "mobile:-translate-x-full")
)}
>
@@ -340,7 +338,7 @@ export const AppLayout = ({
border-t-[1px] border-dotted border-black bg-light [grid-area:navbar] desktop:hidden"
>
{
toggleMainPanelOpen();
@@ -365,7 +363,7 @@ export const AppLayout = ({
{isDefined(subPanel) && !turnSubIntoContent && (
{
toggleSubPanelOpen();
@@ -404,7 +402,7 @@ export const AppLayout = ({
setConfigPanelOpen(false)}
>
{langui.settings}
@@ -416,7 +414,7 @@ export const AppLayout = ({
{router.locales && (
{langui.languages}
- {preferredLanguages && preferredLanguages.length > 0 && (
+ {preferredLanguages.length > 0 && (
{
setSelectedThemeMode(false);
},
- active: selectedThemeMode === false,
+ active: selectedThemeMode,
text: langui.auto,
},
{
@@ -468,7 +466,7 @@ export const AppLayout = ({
setDarkMode(true);
setSelectedThemeMode(true);
},
- active: selectedThemeMode === true && darkMode === true,
+ active: selectedThemeMode && darkMode,
text: langui.dark,
},
]}
@@ -492,20 +490,17 @@ export const AppLayout = ({
setFontSize((fontSize ?? 1) / 1.05),
+ onClick: () => setFontSize(fontSize / 1.05),
icon: Icon.TextDecrease,
},
{
onClick: () => setFontSize(1),
- text: `${((fontSize ?? 1) * 100).toLocaleString(
- undefined,
- {
- maximumFractionDigits: 0,
- }
- )}%`,
+ text: `${(fontSize * 100).toLocaleString(undefined, {
+ maximumFractionDigits: 0,
+ })}%`,
},
{
- onClick: () => setFontSize((fontSize ?? 1) * 1.05),
+ onClick: () => setFontSize(fontSize * 1.05),
icon: Icon.TextIncrease,
},
]}
@@ -516,13 +511,13 @@ export const AppLayout = ({
{langui.font}
diff --git a/src/components/Inputs/Select.tsx b/src/components/Inputs/Select.tsx
index 203a6b2..2cd1279 100644
--- a/src/components/Inputs/Select.tsx
+++ b/src/components/Inputs/Select.tsx
@@ -1,5 +1,5 @@
-import { Fragment, useCallback } from "react";
-import { useBoolean } from "usehooks-ts";
+import { Fragment, useCallback, useRef } from "react";
+import { useBoolean, useOnClickOutside } from "usehooks-ts";
import { Ico, Icon } from "components/Ico";
import { cIf, cJoin } from "helpers/className";
@@ -37,11 +37,12 @@ export const Select = ({
if (optionCount > 1) toggleOpened();
}, [options.length, value, toggleOpened]);
+ const ref = useRef(null);
+ useOnClickOutside(ref, setClosed);
+
return (
{
- setClosed();
- }}
+ ref={ref}
className={cJoin(
"relative text-center transition-[filter]",
cIf(isOpened, "z-10 drop-shadow-shade-lg"),
diff --git a/src/components/Library/PreviewCardCTAs.tsx b/src/components/Library/PreviewCardCTAs.tsx
index ad42f00..432ee48 100644
--- a/src/components/Library/PreviewCardCTAs.tsx
+++ b/src/components/Library/PreviewCardCTAs.tsx
@@ -35,7 +35,7 @@ export const PreviewCardCTAs = ({
{
event.preventDefault();
setLibraryItemUserStatus((current) => {
@@ -53,7 +53,7 @@ export const PreviewCardCTAs = ({
{
event.preventDefault();
setLibraryItemUserStatus((current) => {
diff --git a/src/contexts/AppLayoutContext.tsx b/src/contexts/AppLayoutContext.tsx
index 27f4017..f5b6c69 100644
--- a/src/contexts/AppLayoutContext.tsx
+++ b/src/contexts/AppLayoutContext.tsx
@@ -1,64 +1,77 @@
import React, { ReactNode, useContext, useState } from "react";
+import { useLocalStorage } from "usehooks-ts";
import { isDefined } from "helpers/others";
import { LibraryItemUserStatus, RequiredNonNullable } from "helpers/types";
import { useDarkMode } from "hooks/useDarkMode";
-import { useStateWithLocalStorage } from "hooks/useStateWithLocalStorage";
interface AppLayoutState {
- subPanelOpen: boolean | undefined;
+ subPanelOpen: boolean;
toggleSubPanelOpen: () => void;
setSubPanelOpen: React.Dispatch<
React.SetStateAction
>;
- configPanelOpen: boolean | undefined;
+
+ configPanelOpen: boolean;
toggleConfigPanelOpen: () => void;
setConfigPanelOpen: React.Dispatch<
React.SetStateAction
>;
- searchPanelOpen: boolean | undefined;
+
+ searchPanelOpen: boolean;
toggleSearchPanelOpen: () => void;
setSearchPanelOpen: React.Dispatch<
React.SetStateAction
>;
- mainPanelReduced: boolean | undefined;
+
+ mainPanelReduced: boolean;
toggleMainPanelReduced: () => void;
setMainPanelReduced: React.Dispatch<
React.SetStateAction
>;
- mainPanelOpen: boolean | undefined;
+
+ mainPanelOpen: boolean;
toggleMainPanelOpen: () => void;
setMainPanelOpen: React.Dispatch<
React.SetStateAction
>;
- darkMode: boolean | undefined;
+
+ darkMode: boolean;
toggleDarkMode: () => void;
setDarkMode: React.Dispatch>;
- selectedThemeMode: boolean | undefined;
+
+ selectedThemeMode: boolean;
toggleSelectedThemeMode: () => void;
setSelectedThemeMode: React.Dispatch<
React.SetStateAction
>;
- fontSize: number | undefined;
+
+ fontSize: number;
setFontSize: React.Dispatch>;
- dyslexic: boolean | undefined;
+
+ dyslexic: boolean;
toggleDyslexic: () => void;
setDyslexic: React.Dispatch>;
- currency: string | undefined;
+
+ currency: string;
setCurrency: React.Dispatch>;
- playerName: string | undefined;
+
+ playerName: string;
setPlayerName: React.Dispatch<
React.SetStateAction
>;
- preferredLanguages: string[] | undefined;
+
+ preferredLanguages: string[];
setPreferredLanguages: React.Dispatch<
React.SetStateAction
>;
+
menuGestures: boolean;
toggleMenuGestures: () => void;
setMenuGestures: React.Dispatch<
React.SetStateAction
>;
- libraryItemUserStatus: Record | undefined;
+
+ libraryItemUserStatus: Record;
setLibraryItemUserStatus: React.Dispatch<
React.SetStateAction
>;
@@ -68,38 +81,51 @@ const initialState: RequiredNonNullable = {
subPanelOpen: false,
toggleSubPanelOpen: () => null,
setSubPanelOpen: () => null,
+
configPanelOpen: false,
setConfigPanelOpen: () => null,
toggleConfigPanelOpen: () => null,
+
searchPanelOpen: false,
setSearchPanelOpen: () => null,
toggleSearchPanelOpen: () => null,
+
mainPanelReduced: false,
setMainPanelReduced: () => null,
toggleMainPanelReduced: () => null,
+
mainPanelOpen: false,
toggleMainPanelOpen: () => null,
setMainPanelOpen: () => null,
+
darkMode: false,
toggleDarkMode: () => null,
setDarkMode: () => null,
+
selectedThemeMode: false,
toggleSelectedThemeMode: () => null,
setSelectedThemeMode: () => null,
+
fontSize: 1,
setFontSize: () => null,
+
dyslexic: false,
toggleDyslexic: () => null,
setDyslexic: () => null,
+
currency: "USD",
setCurrency: () => null,
+
playerName: "",
setPlayerName: () => null,
+
preferredLanguages: [],
setPreferredLanguages: () => null,
+
menuGestures: true,
toggleMenuGestures: () => null,
setMenuGestures: () => null,
+
libraryItemUserStatus: {},
setLibraryItemUserStatus: () => null,
};
@@ -113,22 +139,22 @@ interface Props {
}
export const AppContextProvider = (props: Props): JSX.Element => {
- const [subPanelOpen, setSubPanelOpen] = useStateWithLocalStorage(
+ const [subPanelOpen, setSubPanelOpen] = useLocalStorage(
"subPanelOpen",
initialState.subPanelOpen
);
- const [configPanelOpen, setConfigPanelOpen] = useStateWithLocalStorage(
+ const [configPanelOpen, setConfigPanelOpen] = useLocalStorage(
"configPanelOpen",
initialState.configPanelOpen
);
- const [mainPanelReduced, setMainPanelReduced] = useStateWithLocalStorage(
+ const [mainPanelReduced, setMainPanelReduced] = useLocalStorage(
"mainPanelReduced",
initialState.mainPanelReduced
);
- const [mainPanelOpen, setMainPanelOpen] = useStateWithLocalStorage(
+ const [mainPanelOpen, setMainPanelOpen] = useLocalStorage(
"mainPanelOpen",
initialState.mainPanelOpen
);
@@ -136,43 +162,42 @@ export const AppContextProvider = (props: Props): JSX.Element => {
const [darkMode, selectedThemeMode, setDarkMode, setSelectedThemeMode] =
useDarkMode("darkMode", initialState.darkMode);
- const [fontSize, setFontSize] = useStateWithLocalStorage(
+ const [fontSize, setFontSize] = useLocalStorage(
"fontSize",
initialState.fontSize
);
- const [dyslexic, setDyslexic] = useStateWithLocalStorage(
+ const [dyslexic, setDyslexic] = useLocalStorage(
"dyslexic",
initialState.dyslexic
);
- const [currency, setCurrency] = useStateWithLocalStorage(
+ const [currency, setCurrency] = useLocalStorage(
"currency",
initialState.currency
);
- const [playerName, setPlayerName] = useStateWithLocalStorage(
+ const [playerName, setPlayerName] = useLocalStorage(
"playerName",
initialState.playerName
);
- const [preferredLanguages, setPreferredLanguages] = useStateWithLocalStorage(
+ const [preferredLanguages, setPreferredLanguages] = useLocalStorage(
"preferredLanguages",
initialState.preferredLanguages
);
const [menuGestures, setMenuGestures] = useState(false);
- const [searchPanelOpen, setSearchPanelOpen] = useStateWithLocalStorage(
+ const [searchPanelOpen, setSearchPanelOpen] = useLocalStorage(
"searchPanelOpen",
initialState.searchPanelOpen
);
- const [libraryItemUserStatus, setLibraryItemUserStatus] =
- useStateWithLocalStorage(
- "libraryItemUserStatus",
- initialState.libraryItemUserStatus
- );
+ const [libraryItemUserStatus, setLibraryItemUserStatus] = useLocalStorage(
+ "libraryItemUserStatus",
+ initialState.libraryItemUserStatus
+ );
const toggleSubPanelOpen = () => {
setSubPanelOpen((current) => (isDefined(current) ? !current : current));
diff --git a/src/hooks/useDarkMode.ts b/src/hooks/useDarkMode.ts
index f0a1510..66db829 100644
--- a/src/hooks/useDarkMode.ts
+++ b/src/hooks/useDarkMode.ts
@@ -1,25 +1,25 @@
import { useEffect } from "react";
+import { useLocalStorage } from "usehooks-ts";
import { usePrefersDarkMode } from "./useMediaQuery";
-import { useStateWithLocalStorage } from "./useStateWithLocalStorage";
export const useDarkMode = (
key: string,
- initialValue: boolean | undefined
+ initialValue: boolean
): [
- boolean | undefined,
- boolean | undefined,
- React.Dispatch>,
- React.Dispatch>
+ boolean,
+ boolean,
+ React.Dispatch>,
+ React.Dispatch>
] => {
- const [darkMode, setDarkMode] = useStateWithLocalStorage(key, initialValue);
+ const [darkMode, setDarkMode] = useLocalStorage(key, initialValue);
const prefersDarkMode = usePrefersDarkMode();
- const [selectedThemeMode, setSelectedThemeMode] = useStateWithLocalStorage(
+ const [selectedThemeMode, setSelectedThemeMode] = useLocalStorage(
"selectedThemeMode",
false
);
useEffect(() => {
- if (selectedThemeMode === false) setDarkMode(prefersDarkMode);
+ if (!selectedThemeMode) setDarkMode(prefersDarkMode);
}, [selectedThemeMode, prefersDarkMode, setDarkMode]);
return [darkMode, selectedThemeMode, setDarkMode, setSelectedThemeMode];
diff --git a/src/hooks/useSmartLanguage.ts b/src/hooks/useSmartLanguage.ts
index 8ed5393..42242f0 100644
--- a/src/hooks/useSmartLanguage.ts
+++ b/src/hooks/useSmartLanguage.ts
@@ -42,7 +42,7 @@ export const useSmartLanguage = ({
useEffect(() => {
setSelectedTranslationIndex(
getPreferredLanguage(
- preferredLanguages ?? [router.locale],
+ preferredLanguages,
availableLocales
)
);
diff --git a/src/hooks/useStateWithLocalStorage.ts b/src/hooks/useStateWithLocalStorage.ts
deleted file mode 100644
index c78f533..0000000
--- a/src/hooks/useStateWithLocalStorage.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { useEffect, useState } from "react";
-import { isDefined } from "helpers/others";
-
-export const useStateWithLocalStorage = (
- key: string,
- initialValue: T
-): [T | undefined, React.Dispatch>] => {
- const [value, setValue] = useState(undefined);
- const [, setFromLocaleStorage] = useState(false);
-
- useEffect(() => {
- try {
- const item = localStorage.getItem(key);
- if (isDefined(item)) {
- setValue(JSON.parse(item) as T);
- } else {
- setValue(initialValue);
- }
- setFromLocaleStorage(true);
- } catch (error) {
- console.warn(`Error reading localStorage key “${key}”:`, error);
- setValue(initialValue);
- }
- }, [initialValue, key]);
-
- useEffect(() => {
- if (isDefined(value)) localStorage.setItem(key, JSON.stringify(value));
- }, [value, key]);
-
- return [value, setValue];
-};
diff --git a/src/hooks/useTernaryDarkMode.ts b/src/hooks/useTernaryDarkMode.ts
deleted file mode 100644
index d5edf6e..0000000
--- a/src/hooks/useTernaryDarkMode.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import { useMemo } from "react";
-import { usePrefersDarkMode } from "./useMediaQuery";
-import { useStateWithLocalStorage } from "./useStateWithLocalStorage";
-
-export enum TernaryDarkMode {
- Dark = "dark",
- Auto = "auto",
- Light = "light",
-}
-
-export const useTernaryDarkMode = (
- key: string,
- initialValue: TernaryDarkMode
-): {
- isDarkMode: boolean;
- ternaryDarkMode: TernaryDarkMode | undefined;
- setTernaryDarkMode: React.Dispatch<
- React.SetStateAction
- >;
-} => {
- const [ternaryDarkMode, setTernaryDarkMode] = useStateWithLocalStorage(
- key,
- initialValue
- );
- const prefersDarkMode = usePrefersDarkMode();
- const isDarkMode = useMemo(() => {
- switch (ternaryDarkMode) {
- case TernaryDarkMode.Light:
- return false;
- case TernaryDarkMode.Dark:
- return true;
- default:
- return prefersDarkMode;
- }
- }, [prefersDarkMode, ternaryDarkMode]);
-
- return { isDarkMode, ternaryDarkMode, setTernaryDarkMode };
-};
diff --git a/src/pages/library/index.tsx b/src/pages/library/index.tsx
index ddc28e0..d084741 100644
--- a/src/pages/library/index.tsx
+++ b/src/pages/library/index.tsx
@@ -120,7 +120,7 @@ const Library = ({
if (item.attributes.primary && !showPrimaryItems) return false;
if (!item.attributes.primary && !showSecondaryItems) return false;
- if (isDefined(filterUserStatus) && item.id && libraryItemUserStatus) {
+ if (isDefined(filterUserStatus) && item.id) {
if (isUntangibleGroupItem(item.attributes.metadata?.[0])) {
return false;
}