feat: loading and error pages

This commit is contained in:
2025-08-30 23:46:46 +04:00
parent 26c7209de0
commit ab7ef1e753
8 changed files with 123 additions and 89 deletions

View File

@ -3,19 +3,28 @@ import {
HydrationBoundary,
QueryClient,
} from "@tanstack/react-query";
import PageBody from "@/app/deals/components/shared/PageBody/PageBody";
import { BoardsContextProvider } from "@/app/deals/contexts/BoardsContext";
import { ProjectsContextProvider } from "@/app/deals/contexts/ProjectsContext";
import { StatusesContextProvider } from "@/app/deals/contexts/StatusesContext";
import { ViewContextProvider } from "@/app/deals/contexts/ViewContext";
import PageBlock from "@/components/layout/PageBlock/PageBlock";
import PageContainer from "@/components/layout/PageContainer/PageContainer";
import { Suspense } from "react";
import { Loader, Center } from "@mantine/core";
import dynamic from "next/dynamic";
import {
getBoardsOptions,
getProjectsOptions,
} from "@/lib/client/@tanstack/react-query.gen";
import { combineProviders } from "@/utils/combineProviders";
import TopToolPanel from "./components/desktop/TopToolPanel/TopToolPanel";
// Dynamic imports for better code splitting
const PageBody = dynamic(() => import("@/app/deals/components/shared/PageBody/PageBody"), {
loading: () => <Center h={400}><Loader /></Center>
});
const BoardsContextProvider = dynamic(() => import("@/app/deals/contexts/BoardsContext").then(mod => ({ default: mod.BoardsContextProvider })));
const ProjectsContextProvider = dynamic(() => import("@/app/deals/contexts/ProjectsContext").then(mod => ({ default: mod.ProjectsContextProvider })));
const StatusesContextProvider = dynamic(() => import("@/app/deals/contexts/StatusesContext").then(mod => ({ default: mod.StatusesContextProvider })));
const ViewContextProvider = dynamic(() => import("@/app/deals/contexts/ViewContext").then(mod => ({ default: mod.ViewContextProvider })));
const PageBlock = dynamic(() => import("@/components/layout/PageBlock/PageBlock"));
const PageContainer = dynamic(() => import("@/components/layout/PageContainer/PageContainer"));
const TopToolPanel = dynamic(() => import("./components/desktop/TopToolPanel/TopToolPanel"), {
loading: () => <div style={{ height: 60 }} />
});
async function prefetchData() {
const queryClient = new QueryClient();
@ -44,12 +53,18 @@ export default async function DealsPage() {
return (
<Providers>
<PageContainer>
<TopToolPanel />
<PageBlock>
<PageBody />
</PageBlock>
</PageContainer>
<Suspense fallback={
<Center h="50vh">
<Loader size="lg" />
</Center>
}>
<PageContainer>
<TopToolPanel />
<PageBlock>
<PageBody />
</PageBlock>
</PageContainer>
</Suspense>
</Providers>
);
}

23
src/app/error.tsx Normal file
View File

@ -0,0 +1,23 @@
"use client";
import { Button, Center, Stack, Text } from "@mantine/core";
export default function Error({
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<Center h="100vh">
<Stack align="center">
<Text
size="lg"
fw={500}>
Что-то пошло не так
</Text>
<Button onClick={reset}>Попробовать снова</Button>
</Stack>
</Center>
);
}

9
src/app/loading.tsx Normal file
View File

@ -0,0 +1,9 @@
import { Center, Loader } from "@mantine/core";
export default function Loading() {
return (
<Center h="100vh">
<Loader size="lg" />
</Center>
);
}

View File

@ -13,7 +13,14 @@ export function ReactQueryProvider({ children }: Props) {
new QueryClient({
defaultOptions: {
queries: {
staleTime: 3 * 60 * 1000,
staleTime: 5 * 60 * 1000, // 5 minutes
gcTime: 10 * 60 * 1000, // 10 minutes
retry: 1,
refetchOnWindowFocus: false,
refetchOnMount: false,
},
mutations: {
retry: 1,
},
},
})

View File

@ -3,6 +3,7 @@
import { ReactNode } from "react";
import { Provider } from "react-redux";
import { PersistGate } from "redux-persist/integration/react";
import { Center, Loader } from "@mantine/core";
import { persistor, store } from "@/lib/store/store";
type Props = {
@ -12,9 +13,12 @@ type Props = {
export default function ReduxProvider({ children }: Props) {
return (
<Provider store={store}>
{" "}
<PersistGate
loading={null}
loading={
<Center h="100vh">
<Loader size="sm" />
</Center>
}
persistor={persistor}>
{children}
</PersistGate>

View File

@ -19,6 +19,7 @@ const radius = "md";
const font = Roboto({
subsets: ["latin"],
weight: ["400"],
preload: true,
});
export const theme = createTheme({