diff --git a/package.json b/package.json index 4e775a5937..e6547805f7 100644 --- a/package.json +++ b/package.json @@ -107,6 +107,7 @@ "next": "15.3.3", "node-fetch": "^3.2.8", "npm-run-all": "^4.1.5", + "nuqs": "^2.4.3", "papaparse": "^5.5.3", "prisma": "6.7.0", "pure-rand": "^6.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6f5e4bef00..346aac4b70 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -131,6 +131,9 @@ importers: npm-run-all: specifier: ^4.1.5 version: 4.1.5 + nuqs: + specifier: ^2.4.3 + version: 2.4.3(next@15.3.3(@babel/core@7.28.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0) papaparse: specifier: ^5.5.3 version: 5.5.3 @@ -4912,6 +4915,9 @@ packages: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} engines: {node: '>= 8'} + mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} @@ -5017,6 +5023,24 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + nuqs@2.4.3: + resolution: {integrity: sha512-BgtlYpvRwLYiJuWzxt34q2bXu/AIS66sLU1QePIMr2LWkb+XH0vKXdbLSgn9t6p7QKzwI7f38rX3Wl9llTXQ8Q==} + peerDependencies: + '@remix-run/react': '>=2' + next: '>=14.2.0' + react: '>=18.2.0 || ^19.0.0-0' + react-router: ^6 || ^7 + react-router-dom: ^6 || ^7 + peerDependenciesMeta: + '@remix-run/react': + optional: true + next: + optional: true + react-router: + optional: true + react-router-dom: + optional: true + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -12073,6 +12097,8 @@ snapshots: minipass: 3.3.6 yallist: 4.0.0 + mitt@3.0.1: {} + mkdirp@1.0.4: {} mmdb-lib@2.2.1: {} @@ -12175,6 +12201,13 @@ snapshots: dependencies: boolbase: 1.0.0 + nuqs@2.4.3(next@15.3.3(@babel/core@7.28.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0): + dependencies: + mitt: 3.0.1 + react: 19.1.0 + optionalDependencies: + next: 15.3.3(@babel/core@7.28.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + object-assign@4.1.1: {} object-inspect@1.13.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 5e236fb7fb..f555e7a231 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,10 +1,13 @@ packages: - '**' + ignoredBuiltDependencies: - cypress - esbuild - sharp + onlyBuiltDependencies: - '@prisma/client' - '@prisma/engines' - prisma + - unrs-resolver diff --git a/src/app/(main)/teams/[teamId]/settings/team/TeamDetails.tsx b/src/app/(main)/teams/[teamId]/settings/team/TeamDetails.tsx index f3f258bde7..1a2df260e0 100644 --- a/src/app/(main)/teams/[teamId]/settings/team/TeamDetails.tsx +++ b/src/app/(main)/teams/[teamId]/settings/team/TeamDetails.tsx @@ -3,17 +3,21 @@ import { useLogin, useMessages } from '@/components/hooks'; import Icons from '@/components/icons'; import PageHeader from '@/components/layout/PageHeader'; import { ROLES } from '@/lib/constants'; -import { useContext, useState } from 'react'; +import { useContext } from 'react'; import { Flexbox, Item, Tabs } from 'react-basics'; import TeamLeaveButton from '@/app/(main)/settings/teams/TeamLeaveButton'; import TeamManage from './TeamManage'; import TeamEditForm from './TeamEditForm'; +import { useQueryState } from 'nuqs'; export function TeamDetails({ teamId }: { teamId: string }) { const team = useContext(TeamContext); const { formatMessage, labels } = useMessages(); const { user } = useLogin(); - const [tab, setTab] = useState('details'); + const [tab, setTab] = useQueryState('tab', { + defaultValue: 'details', + parse: value => value as 'details' | 'manage', + }); const isTeamOwner = !!team?.teamUser?.find(({ userId, role }) => role === ROLES.teamOwner && userId === user.id) && diff --git a/src/app/(main)/websites/[websiteId]/sessions/SessionsPage.tsx b/src/app/(main)/websites/[websiteId]/sessions/SessionsPage.tsx index 2ee044db6b..76ab1a8ed5 100644 --- a/src/app/(main)/websites/[websiteId]/sessions/SessionsPage.tsx +++ b/src/app/(main)/websites/[websiteId]/sessions/SessionsPage.tsx @@ -6,12 +6,13 @@ import SessionProperties from './SessionProperties'; import WorldMap from '@/components/metrics/WorldMap'; import { GridRow } from '@/components/layout/Grid'; import { Item, Tabs } from 'react-basics'; -import { useState } from 'react'; import { useMessages } from '@/components/hooks'; import SessionsWeekly from './SessionsWeekly'; +import { useQueryState } from 'nuqs'; export function SessionsPage({ websiteId }) { - const [tab, setTab] = useState('activity'); + const [tab, setTab] = useQueryState('tab', { defaultValue: 'activity' }); + const { formatMessage, labels } = useMessages(); return ( diff --git a/src/app/layout.tsx b/src/app/layout.tsx index e939f8c440..236307a46d 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -7,7 +7,7 @@ import '@fontsource/inter/700.css'; import 'react-basics/dist/styles.css'; import '@/styles/index.css'; import '@/styles/variables.css'; - +import { NuqsAdapter } from 'nuqs/adapters/next/app'; export default function ({ children }) { if (process.env.DISABLE_UI) { return ( @@ -32,7 +32,9 @@ export default function ({ children }) {
-