import type { LoaderFunctionArgs, MetaFunction } from "@remix-run/node"; import { Link, Links, Meta, Outlet, Scripts, ScrollRestoration, isRouteErrorResponse, useFetcher, useLoaderData, useNavigate, useRouteError, } from "@remix-run/react"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import { jwtDecode } from "jwt-decode"; import { useCallback, useEffect, useMemo, useState } from "react"; import { PreventFlashOnWrongTheme, Theme, ThemeProvider, useTheme } from "remix-themes"; import { Toaster } from "sonner"; import { Button } from "./components/ui/button"; import { useJWTPayload } from "./hooks/use-jwt-payload"; import { cn } from "./lib/clsx"; import { httpClient } from "./lib/http"; import { queryClientConfig } from "./lib/react-query"; import { authenticator } from "./sessions/auth.server"; import type { AuthJwtPayload } from "./types/constants/jwt-payload"; import "./tailwind.css"; export const meta: MetaFunction = () => { return [ { title: "Koperasi Produksi RSB" }, { name: "description", content: "Koperasi Produksi Rejeki Berkah adalah koperasi yang bergerak dalam bidang produksi dan distribusi hasil pertanian. Kami berkomitmen untuk memberikan kesejahteraan bagi anggota koperasi dan masyarakat sekitar melalui prinsip-prinsip koperasi.", }, { name: "keywords", content: "koperasi, produksi, pertanian, distribusi, kesejahteraan, kesehatan, masyarakat", }, ]; }; export async function loader({ request }: LoaderFunctionArgs) { // const { getTheme } = await themeSessionResolver(request); const token = await authenticator.isAuthenticated(request); return { theme: Theme.LIGHT, ENV: { API_BASE_URL: process.env.API_BASE_URL, WALLET_BASE_URL: process.env.WALLET_BASE_URL, }, token: token, }; } export function App() { const data = useLoaderData(); const [theme] = useTheme(); const [queryClient] = useState(() => new QueryClient(queryClientConfig)); const { setJWTPayload } = useJWTPayload(); const authHeader = data.token ? `Bearer ${data.token}` : undefined; const navigate = useNavigate(); const fetcher = useFetcher(); useMemo(() => { httpClient.defaults.headers.common.Authorization = authHeader; return () => { httpClient.defaults.headers.common.Authorization = undefined; }; }, [authHeader]); const handleUnauthorized = useCallback(() => { fetcher.submit({}, { method: "POST", action: "/action/logout" }); setJWTPayload({} as AuthJwtPayload); httpClient.defaults.headers.common.Authorization = undefined; navigate("/auth/login"); }, [setJWTPayload, navigate, fetcher]); useEffect(() => { if (authHeader) { const jwtPayload = jwtDecode(authHeader); setJWTPayload(jwtPayload); } window.addEventListener("UNAUTHORIZED", handleUnauthorized); return () => { setJWTPayload({} as AuthJwtPayload); window.removeEventListener("UNAUTHORIZED", handleUnauthorized); }; }, [handleUnauthorized, authHeader, setJWTPayload]); return (