From ab7ef1e753a38e98d15e96185ca930efdce8d1fd Mon Sep 17 00:00:00 2001 From: AlexSserb Date: Sat, 30 Aug 2025 23:46:46 +0400 Subject: [PATCH] feat: loading and error pages --- package.json | 4 +- src/app/deals/page.tsx | 43 ++++++---- src/app/error.tsx | 23 ++++++ src/app/loading.tsx | 9 +++ src/providers/ReactQueryProvider.tsx | 9 ++- src/providers/ReduxProvider.tsx | 8 +- src/theme.ts | 1 + yarn.lock | 115 +++++++++++---------------- 8 files changed, 123 insertions(+), 89 deletions(-) create mode 100644 src/app/error.tsx create mode 100644 src/app/loading.tsx diff --git a/package.json b/package.json index 9ff7447..dc07a84 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "private": true, "scripts": { - "dev": "next dev", + "dev": "next dev --turbo", "build": "next build", "start": "next start", "lint": "next lint", @@ -34,7 +34,7 @@ "lexorank": "^1.0.5", "libphonenumber-js": "^1.12.10", "mantine-react-table": "^2.0.0-beta.9", - "next": "15.3.3", + "next": "15.4.7", "react": "19.1.0", "react-dom": "19.1.0", "react-imask": "^7.6.1", diff --git a/src/app/deals/page.tsx b/src/app/deals/page.tsx index 75e24b8..e820813 100644 --- a/src/app/deals/page.tsx +++ b/src/app/deals/page.tsx @@ -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: () =>
+}); +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: () =>
+}); async function prefetchData() { const queryClient = new QueryClient(); @@ -44,12 +53,18 @@ export default async function DealsPage() { return ( - - - - - - + + + + }> + + + + + + + ); } diff --git a/src/app/error.tsx b/src/app/error.tsx new file mode 100644 index 0000000..ae473f1 --- /dev/null +++ b/src/app/error.tsx @@ -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 ( +
+ + + Что-то пошло не так + + + +
+ ); +} diff --git a/src/app/loading.tsx b/src/app/loading.tsx new file mode 100644 index 0000000..eb62715 --- /dev/null +++ b/src/app/loading.tsx @@ -0,0 +1,9 @@ +import { Center, Loader } from "@mantine/core"; + +export default function Loading() { + return ( +
+ +
+ ); +} diff --git a/src/providers/ReactQueryProvider.tsx b/src/providers/ReactQueryProvider.tsx index c216446..1d4e51f 100644 --- a/src/providers/ReactQueryProvider.tsx +++ b/src/providers/ReactQueryProvider.tsx @@ -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, }, }, }) diff --git a/src/providers/ReduxProvider.tsx b/src/providers/ReduxProvider.tsx index 49d8f88..a452e40 100644 --- a/src/providers/ReduxProvider.tsx +++ b/src/providers/ReduxProvider.tsx @@ -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 ( - {" "} + + + } persistor={persistor}> {children} diff --git a/src/theme.ts b/src/theme.ts index 7a3aab0..0f11177 100644 --- a/src/theme.ts +++ b/src/theme.ts @@ -19,6 +19,7 @@ const radius = "md"; const font = Roboto({ subsets: ["latin"], weight: ["400"], + preload: true, }); export const theme = createTheme({ diff --git a/yarn.lock b/yarn.lock index d592082..41fb077 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2967,65 +2967,65 @@ __metadata: languageName: node linkType: hard -"@next/env@npm:15.3.3": - version: 15.3.3 - resolution: "@next/env@npm:15.3.3" - checksum: 10c0/b47ef78c4194900f52a274270932a633ba21f39377fc6ad478839c3c1e3fffccb8ad25b286a1beb11f91fe9d09a299087ccb9c205a4e610ad95af65f24e49e5a +"@next/env@npm:15.4.7": + version: 15.4.7 + resolution: "@next/env@npm:15.4.7" + checksum: 10c0/d2d817274a470543992e1a02963b450979a7aaafc105497a07a2a34b2920a1fc3e54edfe0a87d652ee3dfd038f6dbbc92fc7b22efd6d4b7d9645265d8d9bc2f7 languageName: node linkType: hard -"@next/swc-darwin-arm64@npm:15.3.3": - version: 15.3.3 - resolution: "@next/swc-darwin-arm64@npm:15.3.3" +"@next/swc-darwin-arm64@npm:15.4.7": + version: 15.4.7 + resolution: "@next/swc-darwin-arm64@npm:15.4.7" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@next/swc-darwin-x64@npm:15.3.3": - version: 15.3.3 - resolution: "@next/swc-darwin-x64@npm:15.3.3" +"@next/swc-darwin-x64@npm:15.4.7": + version: 15.4.7 + resolution: "@next/swc-darwin-x64@npm:15.4.7" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@next/swc-linux-arm64-gnu@npm:15.3.3": - version: 15.3.3 - resolution: "@next/swc-linux-arm64-gnu@npm:15.3.3" +"@next/swc-linux-arm64-gnu@npm:15.4.7": + version: 15.4.7 + resolution: "@next/swc-linux-arm64-gnu@npm:15.4.7" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@next/swc-linux-arm64-musl@npm:15.3.3": - version: 15.3.3 - resolution: "@next/swc-linux-arm64-musl@npm:15.3.3" +"@next/swc-linux-arm64-musl@npm:15.4.7": + version: 15.4.7 + resolution: "@next/swc-linux-arm64-musl@npm:15.4.7" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@next/swc-linux-x64-gnu@npm:15.3.3": - version: 15.3.3 - resolution: "@next/swc-linux-x64-gnu@npm:15.3.3" +"@next/swc-linux-x64-gnu@npm:15.4.7": + version: 15.4.7 + resolution: "@next/swc-linux-x64-gnu@npm:15.4.7" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@next/swc-linux-x64-musl@npm:15.3.3": - version: 15.3.3 - resolution: "@next/swc-linux-x64-musl@npm:15.3.3" +"@next/swc-linux-x64-musl@npm:15.4.7": + version: 15.4.7 + resolution: "@next/swc-linux-x64-musl@npm:15.4.7" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@next/swc-win32-arm64-msvc@npm:15.3.3": - version: 15.3.3 - resolution: "@next/swc-win32-arm64-msvc@npm:15.3.3" +"@next/swc-win32-arm64-msvc@npm:15.4.7": + version: 15.4.7 + resolution: "@next/swc-win32-arm64-msvc@npm:15.4.7" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@next/swc-win32-x64-msvc@npm:15.3.3": - version: 15.3.3 - resolution: "@next/swc-win32-x64-msvc@npm:15.3.3" +"@next/swc-win32-x64-msvc@npm:15.4.7": + version: 15.4.7 + resolution: "@next/swc-win32-x64-msvc@npm:15.4.7" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -3508,13 +3508,6 @@ __metadata: languageName: node 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": version: 0.5.15 resolution: "@swc/helpers@npm:0.5.15" @@ -5549,15 +5542,6 @@ __metadata: languageName: node 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": version: 2.0.1 resolution: "c12@npm:2.0.1" @@ -6214,7 +6198,7 @@ __metadata: lexorank: "npm:^1.0.5" libphonenumber-js: "npm:^1.12.10" 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-preset-mantine: "npm:1.17.0" postcss-simple-vars: "npm:^7.0.1" @@ -10574,29 +10558,27 @@ __metadata: languageName: node linkType: hard -"next@npm:15.3.3": - version: 15.3.3 - resolution: "next@npm:15.3.3" +"next@npm:15.4.7": + version: 15.4.7 + resolution: "next@npm:15.4.7" dependencies: - "@next/env": "npm:15.3.3" - "@next/swc-darwin-arm64": "npm:15.3.3" - "@next/swc-darwin-x64": "npm:15.3.3" - "@next/swc-linux-arm64-gnu": "npm:15.3.3" - "@next/swc-linux-arm64-musl": "npm:15.3.3" - "@next/swc-linux-x64-gnu": "npm:15.3.3" - "@next/swc-linux-x64-musl": "npm:15.3.3" - "@next/swc-win32-arm64-msvc": "npm:15.3.3" - "@next/swc-win32-x64-msvc": "npm:15.3.3" - "@swc/counter": "npm:0.1.3" + "@next/env": "npm:15.4.7" + "@next/swc-darwin-arm64": "npm:15.4.7" + "@next/swc-darwin-x64": "npm:15.4.7" + "@next/swc-linux-arm64-gnu": "npm:15.4.7" + "@next/swc-linux-arm64-musl": "npm:15.4.7" + "@next/swc-linux-x64-gnu": "npm:15.4.7" + "@next/swc-linux-x64-musl": "npm:15.4.7" + "@next/swc-win32-arm64-msvc": "npm:15.4.7" + "@next/swc-win32-x64-msvc": "npm:15.4.7" "@swc/helpers": "npm:0.5.15" - busboy: "npm:1.6.0" caniuse-lite: "npm:^1.0.30001579" postcss: "npm:8.4.31" - sharp: "npm:^0.34.1" + sharp: "npm:^0.34.3" styled-jsx: "npm:5.1.6" peerDependencies: "@opentelemetry/api": ^1.1.0 - "@playwright/test": ^1.41.2 + "@playwright/test": ^1.51.1 babel-plugin-react-compiler: "*" 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 @@ -10631,7 +10613,7 @@ __metadata: optional: true bin: next: dist/bin/next - checksum: 10c0/b519d348efd905ac63b2e5cb1e5a3d8e5d11d992aba436f4eef28c66f4555f155bb2bd489d0d029867e926539b31a3f14dd81b0ebca54ce9f3d65a883fb94d4b + checksum: 10c0/2e7228cfb24d9f47f1a01cd9a1648a8e1a0d884bf06f1d1a13ce4958975094642517ae234254a892470a98e3e558ecd4bc51e989e7a7a40c9e725400435461b8 languageName: node linkType: hard @@ -12571,7 +12553,7 @@ __metadata: languageName: node linkType: hard -"sharp@npm:^0.34.1, sharp@npm:^0.34.3": +"sharp@npm:^0.34.3": version: 0.34.3 resolution: "sharp@npm:0.34.3" dependencies: @@ -12939,13 +12921,6 @@ __metadata: languageName: node 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": version: 4.0.2 resolution: "string-length@npm:4.0.2"