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,7 +3,7 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev --turbo",
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"lint": "next lint", "lint": "next lint",
@ -34,7 +34,7 @@
"lexorank": "^1.0.5", "lexorank": "^1.0.5",
"libphonenumber-js": "^1.12.10", "libphonenumber-js": "^1.12.10",
"mantine-react-table": "^2.0.0-beta.9", "mantine-react-table": "^2.0.0-beta.9",
"next": "15.3.3", "next": "15.4.7",
"react": "19.1.0", "react": "19.1.0",
"react-dom": "19.1.0", "react-dom": "19.1.0",
"react-imask": "^7.6.1", "react-imask": "^7.6.1",

View File

@ -3,19 +3,28 @@ import {
HydrationBoundary, HydrationBoundary,
QueryClient, QueryClient,
} from "@tanstack/react-query"; } from "@tanstack/react-query";
import PageBody from "@/app/deals/components/shared/PageBody/PageBody"; import { Suspense } from "react";
import { BoardsContextProvider } from "@/app/deals/contexts/BoardsContext"; import { Loader, Center } from "@mantine/core";
import { ProjectsContextProvider } from "@/app/deals/contexts/ProjectsContext"; import dynamic from "next/dynamic";
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 { import {
getBoardsOptions, getBoardsOptions,
getProjectsOptions, getProjectsOptions,
} from "@/lib/client/@tanstack/react-query.gen"; } from "@/lib/client/@tanstack/react-query.gen";
import { combineProviders } from "@/utils/combineProviders"; 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() { async function prefetchData() {
const queryClient = new QueryClient(); const queryClient = new QueryClient();
@ -44,12 +53,18 @@ export default async function DealsPage() {
return ( return (
<Providers> <Providers>
<PageContainer> <Suspense fallback={
<TopToolPanel /> <Center h="50vh">
<PageBlock> <Loader size="lg" />
<PageBody /> </Center>
</PageBlock> }>
</PageContainer> <PageContainer>
<TopToolPanel />
<PageBlock>
<PageBody />
</PageBlock>
</PageContainer>
</Suspense>
</Providers> </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({ new QueryClient({
defaultOptions: { defaultOptions: {
queries: { 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 { ReactNode } from "react";
import { Provider } from "react-redux"; import { Provider } from "react-redux";
import { PersistGate } from "redux-persist/integration/react"; import { PersistGate } from "redux-persist/integration/react";
import { Center, Loader } from "@mantine/core";
import { persistor, store } from "@/lib/store/store"; import { persistor, store } from "@/lib/store/store";
type Props = { type Props = {
@ -12,9 +13,12 @@ type Props = {
export default function ReduxProvider({ children }: Props) { export default function ReduxProvider({ children }: Props) {
return ( return (
<Provider store={store}> <Provider store={store}>
{" "}
<PersistGate <PersistGate
loading={null} loading={
<Center h="100vh">
<Loader size="sm" />
</Center>
}
persistor={persistor}> persistor={persistor}>
{children} {children}
</PersistGate> </PersistGate>

View File

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

115
yarn.lock
View File

@ -2967,65 +2967,65 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@next/env@npm:15.3.3": "@next/env@npm:15.4.7":
version: 15.3.3 version: 15.4.7
resolution: "@next/env@npm:15.3.3" resolution: "@next/env@npm:15.4.7"
checksum: 10c0/b47ef78c4194900f52a274270932a633ba21f39377fc6ad478839c3c1e3fffccb8ad25b286a1beb11f91fe9d09a299087ccb9c205a4e610ad95af65f24e49e5a checksum: 10c0/d2d817274a470543992e1a02963b450979a7aaafc105497a07a2a34b2920a1fc3e54edfe0a87d652ee3dfd038f6dbbc92fc7b22efd6d4b7d9645265d8d9bc2f7
languageName: node languageName: node
linkType: hard linkType: hard
"@next/swc-darwin-arm64@npm:15.3.3": "@next/swc-darwin-arm64@npm:15.4.7":
version: 15.3.3 version: 15.4.7
resolution: "@next/swc-darwin-arm64@npm:15.3.3" resolution: "@next/swc-darwin-arm64@npm:15.4.7"
conditions: os=darwin & cpu=arm64 conditions: os=darwin & cpu=arm64
languageName: node languageName: node
linkType: hard linkType: hard
"@next/swc-darwin-x64@npm:15.3.3": "@next/swc-darwin-x64@npm:15.4.7":
version: 15.3.3 version: 15.4.7
resolution: "@next/swc-darwin-x64@npm:15.3.3" resolution: "@next/swc-darwin-x64@npm:15.4.7"
conditions: os=darwin & cpu=x64 conditions: os=darwin & cpu=x64
languageName: node languageName: node
linkType: hard linkType: hard
"@next/swc-linux-arm64-gnu@npm:15.3.3": "@next/swc-linux-arm64-gnu@npm:15.4.7":
version: 15.3.3 version: 15.4.7
resolution: "@next/swc-linux-arm64-gnu@npm:15.3.3" resolution: "@next/swc-linux-arm64-gnu@npm:15.4.7"
conditions: os=linux & cpu=arm64 & libc=glibc conditions: os=linux & cpu=arm64 & libc=glibc
languageName: node languageName: node
linkType: hard linkType: hard
"@next/swc-linux-arm64-musl@npm:15.3.3": "@next/swc-linux-arm64-musl@npm:15.4.7":
version: 15.3.3 version: 15.4.7
resolution: "@next/swc-linux-arm64-musl@npm:15.3.3" resolution: "@next/swc-linux-arm64-musl@npm:15.4.7"
conditions: os=linux & cpu=arm64 & libc=musl conditions: os=linux & cpu=arm64 & libc=musl
languageName: node languageName: node
linkType: hard linkType: hard
"@next/swc-linux-x64-gnu@npm:15.3.3": "@next/swc-linux-x64-gnu@npm:15.4.7":
version: 15.3.3 version: 15.4.7
resolution: "@next/swc-linux-x64-gnu@npm:15.3.3" resolution: "@next/swc-linux-x64-gnu@npm:15.4.7"
conditions: os=linux & cpu=x64 & libc=glibc conditions: os=linux & cpu=x64 & libc=glibc
languageName: node languageName: node
linkType: hard linkType: hard
"@next/swc-linux-x64-musl@npm:15.3.3": "@next/swc-linux-x64-musl@npm:15.4.7":
version: 15.3.3 version: 15.4.7
resolution: "@next/swc-linux-x64-musl@npm:15.3.3" resolution: "@next/swc-linux-x64-musl@npm:15.4.7"
conditions: os=linux & cpu=x64 & libc=musl conditions: os=linux & cpu=x64 & libc=musl
languageName: node languageName: node
linkType: hard linkType: hard
"@next/swc-win32-arm64-msvc@npm:15.3.3": "@next/swc-win32-arm64-msvc@npm:15.4.7":
version: 15.3.3 version: 15.4.7
resolution: "@next/swc-win32-arm64-msvc@npm:15.3.3" resolution: "@next/swc-win32-arm64-msvc@npm:15.4.7"
conditions: os=win32 & cpu=arm64 conditions: os=win32 & cpu=arm64
languageName: node languageName: node
linkType: hard linkType: hard
"@next/swc-win32-x64-msvc@npm:15.3.3": "@next/swc-win32-x64-msvc@npm:15.4.7":
version: 15.3.3 version: 15.4.7
resolution: "@next/swc-win32-x64-msvc@npm:15.3.3" resolution: "@next/swc-win32-x64-msvc@npm:15.4.7"
conditions: os=win32 & cpu=x64 conditions: os=win32 & cpu=x64
languageName: node languageName: node
linkType: hard linkType: hard
@ -3508,13 +3508,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@swc/counter@npm:0.1.3":
version: 0.1.3
resolution: "@swc/counter@npm:0.1.3"
checksum: 10c0/8424f60f6bf8694cfd2a9bca45845bce29f26105cda8cf19cdb9fd3e78dc6338699e4db77a89ae449260bafa1cc6bec307e81e7fb96dbf7dcfce0eea55151356
languageName: node
linkType: hard
"@swc/helpers@npm:0.5.15": "@swc/helpers@npm:0.5.15":
version: 0.5.15 version: 0.5.15
resolution: "@swc/helpers@npm:0.5.15" resolution: "@swc/helpers@npm:0.5.15"
@ -5549,15 +5542,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"busboy@npm:1.6.0":
version: 1.6.0
resolution: "busboy@npm:1.6.0"
dependencies:
streamsearch: "npm:^1.1.0"
checksum: 10c0/fa7e836a2b82699b6e074393428b91ae579d4f9e21f5ac468e1b459a244341d722d2d22d10920cdd849743dbece6dca11d72de939fb75a7448825cf2babfba1f
languageName: node
linkType: hard
"c12@npm:2.0.1": "c12@npm:2.0.1":
version: 2.0.1 version: 2.0.1
resolution: "c12@npm:2.0.1" resolution: "c12@npm:2.0.1"
@ -6214,7 +6198,7 @@ __metadata:
lexorank: "npm:^1.0.5" lexorank: "npm:^1.0.5"
libphonenumber-js: "npm:^1.12.10" libphonenumber-js: "npm:^1.12.10"
mantine-react-table: "npm:^2.0.0-beta.9" mantine-react-table: "npm:^2.0.0-beta.9"
next: "npm:15.3.3" next: "npm:15.4.7"
postcss: "npm:^8.5.6" postcss: "npm:^8.5.6"
postcss-preset-mantine: "npm:1.17.0" postcss-preset-mantine: "npm:1.17.0"
postcss-simple-vars: "npm:^7.0.1" postcss-simple-vars: "npm:^7.0.1"
@ -10574,29 +10558,27 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"next@npm:15.3.3": "next@npm:15.4.7":
version: 15.3.3 version: 15.4.7
resolution: "next@npm:15.3.3" resolution: "next@npm:15.4.7"
dependencies: dependencies:
"@next/env": "npm:15.3.3" "@next/env": "npm:15.4.7"
"@next/swc-darwin-arm64": "npm:15.3.3" "@next/swc-darwin-arm64": "npm:15.4.7"
"@next/swc-darwin-x64": "npm:15.3.3" "@next/swc-darwin-x64": "npm:15.4.7"
"@next/swc-linux-arm64-gnu": "npm:15.3.3" "@next/swc-linux-arm64-gnu": "npm:15.4.7"
"@next/swc-linux-arm64-musl": "npm:15.3.3" "@next/swc-linux-arm64-musl": "npm:15.4.7"
"@next/swc-linux-x64-gnu": "npm:15.3.3" "@next/swc-linux-x64-gnu": "npm:15.4.7"
"@next/swc-linux-x64-musl": "npm:15.3.3" "@next/swc-linux-x64-musl": "npm:15.4.7"
"@next/swc-win32-arm64-msvc": "npm:15.3.3" "@next/swc-win32-arm64-msvc": "npm:15.4.7"
"@next/swc-win32-x64-msvc": "npm:15.3.3" "@next/swc-win32-x64-msvc": "npm:15.4.7"
"@swc/counter": "npm:0.1.3"
"@swc/helpers": "npm:0.5.15" "@swc/helpers": "npm:0.5.15"
busboy: "npm:1.6.0"
caniuse-lite: "npm:^1.0.30001579" caniuse-lite: "npm:^1.0.30001579"
postcss: "npm:8.4.31" postcss: "npm:8.4.31"
sharp: "npm:^0.34.1" sharp: "npm:^0.34.3"
styled-jsx: "npm:5.1.6" styled-jsx: "npm:5.1.6"
peerDependencies: peerDependencies:
"@opentelemetry/api": ^1.1.0 "@opentelemetry/api": ^1.1.0
"@playwright/test": ^1.41.2 "@playwright/test": ^1.51.1
babel-plugin-react-compiler: "*" babel-plugin-react-compiler: "*"
react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
@ -10631,7 +10613,7 @@ __metadata:
optional: true optional: true
bin: bin:
next: dist/bin/next next: dist/bin/next
checksum: 10c0/b519d348efd905ac63b2e5cb1e5a3d8e5d11d992aba436f4eef28c66f4555f155bb2bd489d0d029867e926539b31a3f14dd81b0ebca54ce9f3d65a883fb94d4b checksum: 10c0/2e7228cfb24d9f47f1a01cd9a1648a8e1a0d884bf06f1d1a13ce4958975094642517ae234254a892470a98e3e558ecd4bc51e989e7a7a40c9e725400435461b8
languageName: node languageName: node
linkType: hard linkType: hard
@ -12571,7 +12553,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"sharp@npm:^0.34.1, sharp@npm:^0.34.3": "sharp@npm:^0.34.3":
version: 0.34.3 version: 0.34.3
resolution: "sharp@npm:0.34.3" resolution: "sharp@npm:0.34.3"
dependencies: dependencies:
@ -12939,13 +12921,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"streamsearch@npm:^1.1.0":
version: 1.1.0
resolution: "streamsearch@npm:1.1.0"
checksum: 10c0/fbd9aecc2621364384d157f7e59426f4bfd385e8b424b5aaa79c83a6f5a1c8fd2e4e3289e95de1eb3511cb96bb333d6281a9919fafce760e4edb35b2cd2facab
languageName: node
linkType: hard
"string-length@npm:^4.0.2": "string-length@npm:^4.0.2":
version: 4.0.2 version: 4.0.2
resolution: "string-length@npm:4.0.2" resolution: "string-length@npm:4.0.2"