diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx index 0fda848..d02a19c 100644 --- a/apps/web/app/layout.tsx +++ b/apps/web/app/layout.tsx @@ -1,4 +1,5 @@ import { AuthProvider } from '@/providers/auth'; +import { ErrorProvider } from '@/providers/error'; import { QueryProvider } from '@/providers/query'; import { ThemeProvider } from '@/providers/theme-provider'; import { I18nProvider } from '@/utils/i18n/provider'; @@ -17,13 +18,15 @@ export default async function RootLayout({ children }: Readonly - - - - {children} - - - + + + + + {children} + + + + ); diff --git a/apps/web/providers/error.tsx b/apps/web/providers/error.tsx new file mode 100644 index 0000000..3ba3264 --- /dev/null +++ b/apps/web/providers/error.tsx @@ -0,0 +1,11 @@ +import { Toaster } from '@repo/ui/components/ui/sonner'; +import { type PropsWithChildren } from 'react'; + +export function ErrorProvider({ children }: Readonly) { + return ( + <> + + {children} + + ); +} diff --git a/apps/web/providers/query.tsx b/apps/web/providers/query.tsx index 8eb8748..445c3f8 100644 --- a/apps/web/providers/query.tsx +++ b/apps/web/providers/query.tsx @@ -1,7 +1,14 @@ 'use client'; +import { toast } from '@repo/ui/components/ui/sonner'; // Since QueryClientProvider relies on useContext under the hood, we have to put 'use client' on top -import { isServer, QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { + isServer, + MutationCache, + QueryCache, + QueryClient, + QueryClientProvider, +} from '@tanstack/react-query'; function makeQueryClient() { return new QueryClient({ @@ -12,6 +19,12 @@ function makeQueryClient() { staleTime: 60 * 1_000, }, }, + mutationCache: new MutationCache({ + onError: () => toast.error('Ошибка при отправке данных'), + }), + queryCache: new QueryCache({ + onError: () => toast.error('Ошибка при загрузке данных'), + }), }); } diff --git a/packages/ui/package.json b/packages/ui/package.json index a8a4e72..b30de15 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -51,8 +51,10 @@ "@radix-ui/react-scroll-area": "^1.2.2", "@radix-ui/react-select": "^2.1.4", "date-fns": "^4.1.0", + "next-themes": "^0.4.4", "react": "catalog:", "react-day-picker": "8.10.1", - "react-dom": "catalog:" + "react-dom": "catalog:", + "sonner": "^1.7.4" } } diff --git a/packages/ui/src/components/ui/sonner.tsx b/packages/ui/src/components/ui/sonner.tsx new file mode 100644 index 0000000..adf31a1 --- /dev/null +++ b/packages/ui/src/components/ui/sonner.tsx @@ -0,0 +1,31 @@ +'use client'; + +import { useTheme } from 'next-themes'; +import { Toaster as Sonner } from 'sonner'; + +type ToasterProps = React.ComponentProps; + +function Toaster({ ...props }: ToasterProps) { + const { theme = 'system' } = useTheme(); + + return ( + + ); +} + +export { Toaster }; + +export { toast } from 'sonner'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6984af5..2435c56 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -330,6 +330,9 @@ importers: date-fns: specifier: ^4.1.0 version: 4.1.0 + next-themes: + specifier: ^0.4.4 + version: 0.4.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react: specifier: 'catalog:' version: 19.0.0 @@ -339,6 +342,9 @@ importers: react-dom: specifier: 'catalog:' version: 19.0.0(react@19.0.0) + sonner: + specifier: ^1.7.4 + version: 1.7.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) devDependencies: '@radix-ui/react-slot': specifier: ^1.1.1 @@ -4615,6 +4621,7 @@ packages: lodash.get@4.4.2: resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + deprecated: This package is deprecated. Use the optional chaining (?.) operator instead. lodash.includes@4.3.0: resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} @@ -5660,6 +5667,12 @@ packages: snake-case@3.0.4: resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + sonner@1.7.4: + resolution: {integrity: sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -11703,7 +11716,7 @@ snapshots: normalize-package-data@2.5.0: dependencies: hosted-git-info: 2.8.9 - resolve: 1.22.8 + resolve: 1.22.10 semver: 5.7.2 validate-npm-package-license: 3.0.4 @@ -12482,6 +12495,11 @@ snapshots: dot-case: 3.0.4 tslib: 2.8.1 + sonner@1.7.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + dependencies: + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + source-map-js@1.2.1: {} source-map@0.6.1: {}