diff --git a/app/providers.tsx b/app/_query_provider.tsx
similarity index 81%
rename from app/providers.tsx
rename to app/_query_provider.tsx
index 1ff86a5..11bb85a 100644
--- a/app/providers.tsx
+++ b/app/_query_provider.tsx
@@ -2,7 +2,9 @@
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { useState } from "react";
-export default function Providers({ children }: { children: React.ReactNode }) {
+export default function CustomQueryClientProvider({
+ children,
+}: React.PropsWithChildren) {
const [queryClient] = useState(
() =>
new QueryClient({
diff --git a/app/layout.tsx b/app/layout.tsx
index d295c98..a60c976 100755
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,6 +1,7 @@
-import Providers from "@/app/providers";
+import CustomQueryClientProvider from "@/app/_query_provider";
import ThemedHtml from "@/app/theme";
import Sidebar from "@/components/layout/Sidebar";
+import ComposeChildren from "@/components/utils/ComposeChildren";
import GoogleAnalytics from "@/lib/tracking/GoogleAnalytics";
import UserInfoTracker from "@/lib/tracking/UserInfoTracker";
import YandexMetrika from "@/lib/tracking/YandexMetrika";
@@ -40,31 +41,38 @@ export const viewport: Viewport = {
export default function RootLayout({
children,
modal,
-}: {
- children: React.ReactNode;
- modal: React.ReactNode;
-}) {
+}: React.PropsWithChildren<{ modal: React.ReactNode }>) {
return (
+
+ {/* Trackers */}
+
+
+
+
-
-
-
-
+
+
+
+ {/* Providers */}
+
-
-
- {children}
-
-
- {modal}
-
+ {/* Content */}
+ <>
+
+
+ {children}
+
+
+ {modal}
+ >
+
);
diff --git a/components/utils/ComposeChildren.tsx b/components/utils/ComposeChildren.tsx
new file mode 100644
index 0000000..1ce8f50
--- /dev/null
+++ b/components/utils/ComposeChildren.tsx
@@ -0,0 +1,41 @@
+import { Children, createElement, isValidElement } from "react";
+
+/**
+ * Compose providers sequentially inside each other to avoid nesting.
+ *
+ * Example:
+ *
+ * ```tsx
+ *
+ *
+ *
+ *
+ * {children}
+ *
+ * ```
+ * equals to
+ * ```tsx
+ *
+ *
+ *
+ * {children}
+ *
+ *
+ *
+ * ```
+ */
+export default function ComposeChildren({ children }: React.PropsWithChildren) {
+ const array = Children.toArray(children);
+ const last = array.pop();
+ return (
+ <>
+ {array.reduceRight(
+ (child, element) =>
+ isValidElement(element)
+ ? createElement(element.type, element.props, child)
+ : child,
+ last,
+ )}
+ >
+ );
+}
diff --git a/lib/tracking/UserInfoTracker.tsx b/lib/tracking/UserInfoTracker.tsx
index b24b1a8..4079756 100644
--- a/lib/tracking/UserInfoTracker.tsx
+++ b/lib/tracking/UserInfoTracker.tsx
@@ -3,7 +3,7 @@ import { useUsersGetMe } from "@/lib/events";
import { ymUserParams } from "@/lib/tracking/YandexMetrika";
import { useEffect } from "react";
-export default function UserInfoTracker() {
+export default function UserInfoTracker({ children }: React.PropsWithChildren) {
const { data } = useUsersGetMe();
// Send user info to Yandex Metrika
@@ -17,5 +17,5 @@ export default function UserInfoTracker() {
}
}, [data]);
- return <>>;
+ return <>{children}>;
}