Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
at main 88 lines 3.0 kB view raw
1import { CheckCircleIcon, XCircleIcon } from "@heroicons/react/24/solid"; 2import { MeVariables } from "@hey/data/constants"; 3import { useMeQuery } from "@hey/indexer"; 4import { useIsClient } from "@uidotdev/usehooks"; 5import { memo, useCallback, useEffect } from "react"; 6import { Outlet, useLocation } from "react-router"; 7import { Toaster, type ToasterProps } from "sonner"; 8import FullPageLoader from "@/components/Shared/FullPageLoader"; 9import GlobalAlerts from "@/components/Shared/GlobalAlerts"; 10import GlobalModals from "@/components/Shared/GlobalModals"; 11import Navbar from "@/components/Shared/Navbar"; 12import BottomNavigation from "@/components/Shared/Navbar/BottomNavigation"; 13import { Spinner } from "@/components/Shared/UI"; 14import reloadAllTabs from "@/helpers/reloadAllTabs"; 15import { useTheme } from "@/hooks/useTheme"; 16import { useAccountStore } from "@/store/persisted/useAccountStore"; 17import { hydrateAuthTokens, signOut } from "@/store/persisted/useAuthStore"; 18import { useBetaStore } from "@/store/persisted/useBetaStore"; 19import { useProStore } from "@/store/persisted/useProStore"; 20import ReloadTabsWatcher from "./ReloadTabsWatcher"; 21 22const Layout = () => { 23 const { pathname } = useLocation(); 24 const { theme } = useTheme(); 25 const { currentAccount, setCurrentAccount } = useAccountStore(); 26 const { setProBannerDismissed } = useProStore(); 27 const { setBetaBannerDismissed } = useBetaStore(); 28 const isMounted = useIsClient(); 29 const { accessToken } = hydrateAuthTokens(); 30 31 useEffect(() => { 32 window.scrollTo(0, 0); 33 }, [pathname]); 34 35 const onError = useCallback(() => { 36 signOut(); 37 reloadAllTabs(); 38 }, []); 39 40 const { loading } = useMeQuery({ 41 onCompleted: ({ me, proBanner, betaBanner }) => { 42 setCurrentAccount(me.loggedInAs.account); 43 if (proBanner?.__typename === "Post") { 44 setProBannerDismissed(proBanner.operations?.dismissed ?? false); 45 } 46 if (betaBanner?.__typename === "Post") { 47 setBetaBannerDismissed(betaBanner.operations?.dismissed ?? false); 48 } 49 }, 50 onError, 51 skip: !accessToken, 52 variables: MeVariables 53 }); 54 55 const accountLoading = !currentAccount && loading; 56 57 if (accountLoading || !isMounted) { 58 return <FullPageLoader />; 59 } 60 61 return ( 62 <> 63 <Toaster 64 icons={{ 65 error: <XCircleIcon className="size-5" />, 66 loading: <Spinner size="xs" />, 67 success: <CheckCircleIcon className="size-5" /> 68 }} 69 position="bottom-right" 70 theme={theme as ToasterProps["theme"]} 71 toastOptions={{ 72 className: "font-sofia-pro", 73 style: { boxShadow: "none", fontSize: "16px" } 74 }} 75 /> 76 <GlobalModals /> 77 <GlobalAlerts /> 78 <ReloadTabsWatcher /> 79 <div className="mx-auto flex w-full max-w-6xl items-start gap-x-8 px-0 md:px-5"> 80 <Navbar /> 81 <Outlet /> 82 <BottomNavigation /> 83 </div> 84 </> 85 ); 86}; 87 88export default memo(Layout);