From 0b0c39a3a50dbf8c7faa3b757a5cd5dbf9a7bf55 Mon Sep 17 00:00:00 2001 From: TinsFox Date: Sat, 16 Aug 2025 21:50:58 +0800 Subject: [PATCH 1/3] feat: use nuqs to manange search params --- package.json | 1 + pnpm-lock.yaml | 33 +++++++++++++++++++ pnpm-workspace.yaml | 3 ++ .../[websiteId]/sessions/SessionsPage.tsx | 5 +-- src/app/layout.tsx | 6 ++-- 5 files changed, 44 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 4e775a59..e6547805 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 6f5e4bef..346aac4b 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 5e236fb7..f555e7a2 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)/websites/[websiteId]/sessions/SessionsPage.tsx b/src/app/(main)/websites/[websiteId]/sessions/SessionsPage.tsx index 2ee044db..d1e12542 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('activity', { defaultValue: 'activity' }); + const { formatMessage, labels } = useMessages(); return ( diff --git a/src/app/layout.tsx b/src/app/layout.tsx index e939f8c4..236307a4 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 }) { - {children} + + {children} + ); From 455c7ec07624767a932dacd45305a1d8f5a9e75d Mon Sep 17 00:00:00 2001 From: TinsFox Date: Sat, 16 Aug 2025 22:03:47 +0800 Subject: [PATCH 2/3] feat: use semantic naming --- src/app/(main)/websites/[websiteId]/sessions/SessionsPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/(main)/websites/[websiteId]/sessions/SessionsPage.tsx b/src/app/(main)/websites/[websiteId]/sessions/SessionsPage.tsx index d1e12542..76ab1a8e 100644 --- a/src/app/(main)/websites/[websiteId]/sessions/SessionsPage.tsx +++ b/src/app/(main)/websites/[websiteId]/sessions/SessionsPage.tsx @@ -11,7 +11,7 @@ import SessionsWeekly from './SessionsWeekly'; import { useQueryState } from 'nuqs'; export function SessionsPage({ websiteId }) { - const [tab, setTab] = useQueryState('activity', { defaultValue: 'activity' }); + const [tab, setTab] = useQueryState('tab', { defaultValue: 'activity' }); const { formatMessage, labels } = useMessages(); From 8946f32feba94db554354c0fc024e5e7343c3cfa Mon Sep 17 00:00:00 2001 From: TinsFox Date: Sat, 16 Aug 2025 22:04:32 +0800 Subject: [PATCH 3/3] feat: replace useState with useQueryState for tab management in TeamDetails --- .../(main)/teams/[teamId]/settings/team/TeamDetails.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/app/(main)/teams/[teamId]/settings/team/TeamDetails.tsx b/src/app/(main)/teams/[teamId]/settings/team/TeamDetails.tsx index f3f258bd..1a2df260 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) &&