diff --git a/src/components/AppLayout.tsx b/src/components/AppLayout.tsx index f023d2c..c1d927e 100644 --- a/src/components/AppLayout.tsx +++ b/src/components/AppLayout.tsx @@ -24,6 +24,7 @@ import { useIs1ColumnLayout, useIsScreenAtLeast, } from "hooks/useContainerQuery"; +import { useOnResize } from "hooks/useOnResize"; /* * ╭─────────────╮ @@ -82,6 +83,9 @@ export const AppLayout = ({ setSubPanelOpen, toggleMainPanelOpen, toggleSubPanelOpen, + setScreenWidth, + setContentPanelWidth, + setSubPanelWidth, langui, currencies, languages, @@ -91,6 +95,10 @@ export const AppLayout = ({ const is1ColumnLayout = useIs1ColumnLayout(); const isScreenAtLeastXs = useIsScreenAtLeast("xs"); + useOnResize(AnchorIds.Body, (width) => setScreenWidth(width)); + useOnResize(AnchorIds.ContentPanel, (width) => setContentPanelWidth(width)); + useOnResize(AnchorIds.SubPanel, (width) => setSubPanelWidth(width)); + const handlers = useSwipeable({ onSwipedLeft: (SwipeEventData) => { if (menuGestures) { diff --git a/src/contexts/AppLayoutContext.tsx b/src/contexts/AppLayoutContext.tsx index 1850fcb..39c7607 100644 --- a/src/contexts/AppLayoutContext.tsx +++ b/src/contexts/AppLayoutContext.tsx @@ -5,16 +5,15 @@ import React, { useLayoutEffect, useState, } from "react"; -import { useLocalStorage } from "usehooks-ts"; import { useRouter } from "next/router"; +import { useLocalStorage } from "usehooks-ts"; import { isDefined, isDefinedAndNotEmpty } from "helpers/others"; import { LibraryItemUserStatus, RequiredNonNullable } from "helpers/types"; import { useDarkMode } from "hooks/useDarkMode"; import { Currencies, Languages, Langui } from "helpers/localData"; import { useCurrencies, useLanguages, useLangui } from "hooks/useLocalData"; import { getDefaultPreferredLanguages } from "helpers/locales"; -import { useOnResize } from "hooks/useOnResize"; -import { AnchorIds } from "hooks/useScrollTopOnChange"; +import { useStateWithLocalStorage } from "hooks/useStateWithLocalStorage"; interface AppLayoutState { subPanelOpen: boolean; @@ -29,12 +28,6 @@ interface AppLayoutState { React.SetStateAction >; - searchPanelOpen: boolean; - toggleSearchPanelOpen: () => void; - setSearchPanelOpen: React.Dispatch< - React.SetStateAction - >; - mainPanelReduced: boolean; toggleMainPanelReduced: () => void; setMainPanelReduced: React.Dispatch< @@ -89,8 +82,19 @@ interface AppLayoutState { >; screenWidth: number; + setScreenWidth: React.Dispatch< + React.SetStateAction + >; + contentPanelWidth: number; + setContentPanelWidth: React.Dispatch< + React.SetStateAction + >; + subPanelWidth: number; + setSubPanelWidth: React.Dispatch< + React.SetStateAction + >; langui: Langui; languages: Languages; @@ -106,10 +110,6 @@ const initialState: RequiredNonNullable = { setConfigPanelOpen: () => null, toggleConfigPanelOpen: () => null, - searchPanelOpen: false, - setSearchPanelOpen: () => null, - toggleSearchPanelOpen: () => null, - mainPanelReduced: false, setMainPanelReduced: () => null, toggleMainPanelReduced: () => null, @@ -150,8 +150,13 @@ const initialState: RequiredNonNullable = { setLibraryItemUserStatus: () => null, screenWidth: 0, + setScreenWidth: () => null, + contentPanelWidth: 0, + setContentPanelWidth: () => null, + subPanelWidth: 0, + setSubPanelWidth: () => null, currencies: [], languages: [], @@ -167,7 +172,9 @@ interface Props { } export const AppContextProvider = (props: Props): JSX.Element => { - const [subPanelOpen, setSubPanelOpen] = useLocalStorage( + const router = useRouter(); + + const [subPanelOpen, setSubPanelOpen] = useStateWithLocalStorage( "subPanelOpen", initialState.subPanelOpen ); @@ -182,7 +189,7 @@ export const AppContextProvider = (props: Props): JSX.Element => { initialState.mainPanelReduced ); - const [mainPanelOpen, setMainPanelOpen] = useLocalStorage( + const [mainPanelOpen, setMainPanelOpen] = useStateWithLocalStorage( "mainPanelOpen", initialState.mainPanelOpen ); @@ -217,11 +224,6 @@ export const AppContextProvider = (props: Props): JSX.Element => { const [menuGestures, setMenuGestures] = useState(false); - const [searchPanelOpen, setSearchPanelOpen] = useLocalStorage( - "searchPanelOpen", - initialState.searchPanelOpen - ); - const [libraryItemUserStatus, setLibraryItemUserStatus] = useLocalStorage( "libraryItemUserStatus", initialState.libraryItemUserStatus @@ -235,10 +237,6 @@ export const AppContextProvider = (props: Props): JSX.Element => { setConfigPanelOpen((current) => (isDefined(current) ? !current : current)); }; - const toggleSearchPanelOpen = () => { - setSearchPanelOpen((current) => (isDefined(current) ? !current : current)); - }; - const toggleMainPanelReduced = () => { setMainPanelReduced((current) => (isDefined(current) ? !current : current)); }; @@ -273,9 +271,7 @@ export const AppContextProvider = (props: Props): JSX.Element => { const languages = useLanguages(); const currencies = useCurrencies(); - const router = useRouter(); useEffect(() => { - console.log("I'm in preferredLanguages update"); if (preferredLanguages.length === 0) { if (isDefinedAndNotEmpty(router.locale) && router.locales) { setPreferredLanguages( @@ -283,10 +279,17 @@ export const AppContextProvider = (props: Props): JSX.Element => { ); } } else if (router.locale !== preferredLanguages[0]) { - console.log("I'm rerouting you"); - router.replace(router.asPath, router.asPath, { - locale: preferredLanguages[0], - }); + /* + * Using a timeout to the code getting stuck into a loop when reaching the website with a + * different preferredLanguages[0] from router.locale + */ + setTimeout( + async () => + router.replace(router.asPath, router.asPath, { + locale: preferredLanguages[0], + }), + 250 + ); } }, [ preferredLanguages, @@ -314,16 +317,11 @@ export const AppContextProvider = (props: Props): JSX.Element => { }%`; }, [fontSize]); - useOnResize(AnchorIds.Body, (width) => setScreenWidth(width)); - useOnResize(AnchorIds.ContentPanel, (width) => setContentPanelWidth(width)); - useOnResize(AnchorIds.SubPanel, (width) => setSubPanelWidth(width)); - return ( { subPanelWidth, setSubPanelOpen, setConfigPanelOpen, - setSearchPanelOpen, setMainPanelReduced, setMainPanelOpen, setDarkMode, @@ -354,13 +351,15 @@ export const AppContextProvider = (props: Props): JSX.Element => { setLibraryItemUserStatus, toggleSubPanelOpen, toggleConfigPanelOpen, - toggleSearchPanelOpen, toggleMainPanelReduced, toggleMainPanelOpen, toggleDarkMode, toggleMenuGestures, toggleSelectedThemeMode, toggleDyslexic, + setScreenWidth, + setContentPanelWidth, + setSubPanelWidth, languages, langui, currencies, diff --git a/src/helpers/formatters.ts b/src/helpers/formatters.ts index 01006f1..b10da19 100644 --- a/src/helpers/formatters.ts +++ b/src/helpers/formatters.ts @@ -239,10 +239,7 @@ export const prettyDuration = (seconds: number): string => { return result; }; -export const prettyLanguage = ( - code: string, - languages: Languages -): string => { +export const prettyLanguage = (code: string, languages: Languages): string => { let result = code; languages.forEach((language) => { if (language.attributes?.code === code) diff --git a/src/helpers/others.ts b/src/helpers/others.ts index 96996b0..cd30b36 100644 --- a/src/helpers/others.ts +++ b/src/helpers/others.ts @@ -112,12 +112,6 @@ export const iterateMap = ( return toList.map(([key, value], index) => callbackfn(key, value, index)); }; -export const mapMoveEntry = ( - map: Map, - sourceIndex: number, - targetIndex: number -): Map => new Map(arrayMove([...map], sourceIndex, targetIndex)); - export const arrayMove = ( arr: T[], sourceIndex: number, diff --git a/src/hooks/useDarkMode.ts b/src/hooks/useDarkMode.ts index 66db829..1ef4374 100644 --- a/src/hooks/useDarkMode.ts +++ b/src/hooks/useDarkMode.ts @@ -1,6 +1,6 @@ import { useEffect } from "react"; -import { useLocalStorage } from "usehooks-ts"; import { usePrefersDarkMode } from "./useMediaQuery"; +import { useStateWithLocalStorage } from "./useStateWithLocalStorage"; export const useDarkMode = ( key: string, @@ -11,9 +11,9 @@ export const useDarkMode = ( React.Dispatch>, React.Dispatch> ] => { - const [darkMode, setDarkMode] = useLocalStorage(key, initialValue); + const [darkMode, setDarkMode] = useStateWithLocalStorage(key, initialValue); const prefersDarkMode = usePrefersDarkMode(); - const [selectedThemeMode, setSelectedThemeMode] = useLocalStorage( + const [selectedThemeMode, setSelectedThemeMode] = useStateWithLocalStorage( "selectedThemeMode", false ); diff --git a/src/hooks/useStateWithLocalStorage.ts b/src/hooks/useStateWithLocalStorage.ts new file mode 100644 index 0000000..5bad2b2 --- /dev/null +++ b/src/hooks/useStateWithLocalStorage.ts @@ -0,0 +1,31 @@ +import { useEffect, useState } from "react"; +import { isDefined } from "helpers/others"; + +export const useStateWithLocalStorage = ( + key: string, + initialValue: T +): [T, React.Dispatch>] => { + const [value, setValue] = useState(initialValue); + const [isFromLocaleStorage, 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 (isFromLocaleStorage) localStorage.setItem(key, JSON.stringify(value)); + }, [value, key, isFromLocaleStorage]); + + return [value, setValue]; +}; diff --git a/src/pages/about-us/index.tsx b/src/pages/about-us/index.tsx index 896f855..ba5ad15 100644 --- a/src/pages/about-us/index.tsx +++ b/src/pages/about-us/index.tsx @@ -41,11 +41,7 @@ const AboutUs = (props: Props): JSX.Element => { url="/about-us/sharing-policy" border /> - + } {...props}