diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx index 0e4f8dd2..c1df5730 100644 --- a/apps/web/app/layout.tsx +++ b/apps/web/app/layout.tsx @@ -4,6 +4,7 @@ import { Geist, Geist_Mono } from "next/font/google"; import { ThemeProvider } from "@/components/theme-provider"; import { Toaster } from "@/components/ui/sonner"; import { cn } from "@/lib/utils"; +import { QueryProvider } from "@core/provider"; import { AuthInitializer } from "@/features/auth"; import { WSProvider } from "@/features/realtime"; import { ModalRegistry } from "@/features/modals"; @@ -67,11 +68,13 @@ export default async function RootLayout({ > - - {children} - - - + + + {children} + + + + diff --git a/apps/web/core/hooks.ts b/apps/web/core/hooks.ts new file mode 100644 index 00000000..cdfbc033 --- /dev/null +++ b/apps/web/core/hooks.ts @@ -0,0 +1,17 @@ +"use client"; + +import { useWorkspaceStore } from "@/features/workspace"; + +/** + * Returns the current workspace ID. + * + * Bridge hook: reads from Zustand workspace store now. + * Phase 3 will switch to core/workspace/store.ts — signature stays the same. + */ +export function useWorkspaceId(): string { + const workspaceId = useWorkspaceStore((s) => s.workspace?.id); + if (!workspaceId) { + throw new Error("useWorkspaceId: no workspace selected"); + } + return workspaceId; +} diff --git a/apps/web/core/index.ts b/apps/web/core/index.ts new file mode 100644 index 00000000..97d2430c --- /dev/null +++ b/apps/web/core/index.ts @@ -0,0 +1,3 @@ +export { createQueryClient } from "./query-client"; +export { QueryProvider } from "./provider"; +export { useWorkspaceId } from "./hooks"; diff --git a/apps/web/core/provider.tsx b/apps/web/core/provider.tsx new file mode 100644 index 00000000..41331d2e --- /dev/null +++ b/apps/web/core/provider.tsx @@ -0,0 +1,17 @@ +"use client"; + +import { useState } from "react"; +import { QueryClientProvider } from "@tanstack/react-query"; +import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; +import { createQueryClient } from "./query-client"; +import type { ReactNode } from "react"; + +export function QueryProvider({ children }: { children: ReactNode }) { + const [queryClient] = useState(createQueryClient); + return ( + + {children} + + + ); +} diff --git a/apps/web/core/query-client.ts b/apps/web/core/query-client.ts new file mode 100644 index 00000000..be5ebea0 --- /dev/null +++ b/apps/web/core/query-client.ts @@ -0,0 +1,18 @@ +import { QueryClient } from "@tanstack/react-query"; + +export function createQueryClient(): QueryClient { + return new QueryClient({ + defaultOptions: { + queries: { + staleTime: Infinity, + gcTime: 10 * 60 * 1000, // 10 minutes + refetchOnWindowFocus: false, + refetchOnReconnect: false, + retry: 1, + }, + mutations: { + retry: false, + }, + }, + }); +} diff --git a/apps/web/package.json b/apps/web/package.json index 3e777288..a0e0ec52 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -18,11 +18,12 @@ "@dnd-kit/utilities": "^3.2.2", "@emoji-mart/data": "^1.2.1", "@floating-ui/dom": "^1.7.6", + "@tanstack/react-query": "^5.96.2", + "@tanstack/react-query-devtools": "^5.96.2", "@tiptap/extension-code-block-lowlight": "^3.22.1", "@tiptap/extension-image": "^3.22.1", "@tiptap/extension-link": "^3.22.1", "@tiptap/extension-mention": "^3.22.1", - "@tiptap/suggestion": "^3.22.1", "@tiptap/extension-placeholder": "^3.22.1", "@tiptap/extension-table": "^3.22.1", "@tiptap/extension-table-cell": "^3.22.1", @@ -33,6 +34,7 @@ "@tiptap/pm": "^3.22.1", "@tiptap/react": "^3.22.1", "@tiptap/starter-kit": "^3.22.1", + "@tiptap/suggestion": "^3.22.1", "@types/linkify-it": "^5.0.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json index f969e523..9110908d 100644 --- a/apps/web/tsconfig.json +++ b/apps/web/tsconfig.json @@ -28,6 +28,9 @@ "paths": { "@/*": [ "./*" + ], + "@core/*": [ + "./core/*" ] }, "noEmit": true, diff --git a/apps/web/vitest.config.ts b/apps/web/vitest.config.ts index beb0e974..d24fbb00 100644 --- a/apps/web/vitest.config.ts +++ b/apps/web/vitest.config.ts @@ -13,6 +13,7 @@ export default defineConfig({ resolve: { alias: { "@": path.resolve(__dirname, "."), + "@core": path.resolve(__dirname, "core"), }, }, }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 27f5ad8c..6d84135b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -75,6 +75,12 @@ importers: '@floating-ui/dom': specifier: ^1.7.6 version: 1.7.6 + '@tanstack/react-query': + specifier: ^5.96.2 + version: 5.96.2(react@19.2.3) + '@tanstack/react-query-devtools': + specifier: ^5.96.2 + version: 5.96.2(@tanstack/react-query@5.96.2(react@19.2.3))(react@19.2.3) '@tiptap/extension-code-block-lowlight': specifier: ^3.22.1 version: 3.22.1(@tiptap/core@3.22.1(@tiptap/pm@3.22.1))(@tiptap/extension-code-block@3.22.1(@tiptap/core@3.22.1(@tiptap/pm@3.22.1))(@tiptap/pm@3.22.1))(@tiptap/pm@3.22.1)(highlight.js@11.11.1)(lowlight@3.3.0) @@ -1288,6 +1294,23 @@ packages: '@tailwindcss/postcss@4.2.2': resolution: {integrity: sha512-n4goKQbW8RVXIbNKRB/45LzyUqN451deQK0nzIeauVEqjlI49slUlgKYJM2QyUzap/PcpnS7kzSUmPb1sCRvYQ==} + '@tanstack/query-core@5.96.2': + resolution: {integrity: sha512-hzI6cTVh4KNRk8UtoIBS7Lv9g6BnJPXvBKsvYH1aGWvv0347jT3BnSvztOE+kD76XGvZnRC/t6qdW1CaIfwCeA==} + + '@tanstack/query-devtools@5.96.2': + resolution: {integrity: sha512-vBTB1Qhbm3nHSbEUtQwks/EdcAtFfEapr1WyBW4w2ExYKuXVi3jIxUIHf5MlSltiHuL7zNyUuanqT/7sI2sb6g==} + + '@tanstack/react-query-devtools@5.96.2': + resolution: {integrity: sha512-nTFKLGuTOFvmFRvcyZ3ArWC/DnMNPoBh6h/2yD6rsf7TCTJCQt+oUWOp2uKPTIuEPtF/vN9Kw5tl5mD1Kbposw==} + peerDependencies: + '@tanstack/react-query': ^5.96.2 + react: ^18 || ^19 + + '@tanstack/react-query@5.96.2': + resolution: {integrity: sha512-sYyzzJT4G0g02azzJ8o55VFFV31XvFpdUpG+unxS0vSaYsJnSPKGoI6WdPwUucJL1wpgGfwfmntNX/Ub1uOViA==} + peerDependencies: + react: ^18 || ^19 + '@testing-library/dom@10.4.1': resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} engines: {node: '>=18'} @@ -4917,6 +4940,21 @@ snapshots: postcss: 8.5.8 tailwindcss: 4.2.2 + '@tanstack/query-core@5.96.2': {} + + '@tanstack/query-devtools@5.96.2': {} + + '@tanstack/react-query-devtools@5.96.2(@tanstack/react-query@5.96.2(react@19.2.3))(react@19.2.3)': + dependencies: + '@tanstack/query-devtools': 5.96.2 + '@tanstack/react-query': 5.96.2(react@19.2.3) + react: 19.2.3 + + '@tanstack/react-query@5.96.2(react@19.2.3)': + dependencies: + '@tanstack/query-core': 5.96.2 + react: 19.2.3 + '@testing-library/dom@10.4.1': dependencies: '@babel/code-frame': 7.29.0