fix(web): preserve dashboard return path from skill details

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
This commit is contained in:
XiaoSeS 2026-09-03 09:42:00 +08:00
parent fc7c59534a
commit b62a487037
4 changed files with 107 additions and 8 deletions

View file

@ -1,7 +1,18 @@
import { describe, expect, it, vi } from 'vitest'
// @vitest-environment jsdom
import { createElement } from 'react'
import { fireEvent, render, screen } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
const navigate = vi.fn()
vi.mock('@tanstack/react-router', () => ({
useNavigate: () => vi.fn(),
useNavigate: () => navigate,
useLocation: () => ({
pathname: '/dashboard/stars',
searchStr: '?page=2',
hash: '#saved',
}),
}))
vi.mock('react-i18next', async () => {
@ -15,7 +26,7 @@ vi.mock('react-i18next', async () => {
})
vi.mock('@/features/skill/skill-card', () => ({
SkillCard: () => null,
SkillCard: ({ onClick }: { onClick?: () => void }) => createElement('button', { onClick }, 'skill-card'),
}))
vi.mock('@/shared/components/pagination', () => ({
@ -24,7 +35,12 @@ vi.mock('@/shared/components/pagination', () => ({
vi.mock('@/shared/hooks/use-user-queries', () => ({
useMyStarsPage: () => ({
data: { items: [], total: 0, page: 0, size: 12 },
data: {
items: [{ id: 1, namespace: 'team-a', slug: 'demo skill' }],
total: 1,
page: 0,
size: 12,
},
isLoading: false,
}),
}))
@ -40,7 +56,20 @@ vi.mock('@/shared/components/dashboard-page-header', () => ({
import { MyStarsPage } from './stars'
describe('MyStarsPage', () => {
beforeEach(() => navigate.mockClear())
it('exports a named component function', () => {
expect(typeof MyStarsPage).toBe('function')
})
it('preserves the favorites page when opening a skill', () => {
render(createElement(MyStarsPage))
fireEvent.click(screen.getByRole('button', { name: 'skill-card' }))
expect(navigate).toHaveBeenCalledWith({
to: '/space/team-a/demo%20skill',
search: { returnTo: '/dashboard/stars?page=2#saved' },
})
})
})

View file

@ -1,17 +1,19 @@
import { useState } from 'react'
import { useNavigate } from '@tanstack/react-router'
import { useLocation, useNavigate } from '@tanstack/react-router'
import { useTranslation } from 'react-i18next'
import { SkillCard } from '@/features/skill/skill-card'
import { Pagination } from '@/shared/components/pagination'
import { useMyStarsPage } from '@/shared/hooks/use-user-queries'
import { Card } from '@/shared/ui/card'
import { DashboardPageHeader } from '@/shared/components/dashboard-page-header'
import { buildReturnTo } from '@/shared/lib/auth-route'
const PAGE_SIZE = 12
export function MyStarsPage() {
const { t } = useTranslation()
const navigate = useNavigate()
const location = useLocation()
const [page, setPage] = useState(0)
const { data, isLoading } = useMyStarsPage({ page, size: PAGE_SIZE })
const skills = data?.items ?? []
@ -40,7 +42,10 @@ export function MyStarsPage() {
<SkillCard
key={skill.id}
skill={skill}
onClick={() => navigate({ to: `/space/${skill.namespace}/${encodeURIComponent(skill.slug)}` })}
onClick={() => navigate({
to: `/space/${skill.namespace}/${encodeURIComponent(skill.slug)}`,
search: { returnTo: buildReturnTo(location) },
})}
/>
))}
</div>

View file

@ -0,0 +1,60 @@
// @vitest-environment jsdom
import { createElement } from 'react'
import { fireEvent, render, screen } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
const navigate = vi.fn()
vi.mock('@tanstack/react-router', () => ({
useNavigate: () => navigate,
useLocation: () => ({
pathname: '/dashboard/subscriptions',
searchStr: '?page=1',
hash: '',
}),
}))
vi.mock('react-i18next', async () => {
const actual = await vi.importActual<typeof import('react-i18next')>('react-i18next')
return {
...actual,
useTranslation: () => ({ t: (key: string) => key }),
}
})
vi.mock('@/features/skill/skill-card', () => ({
SkillCard: ({ onClick }: { onClick?: () => void }) => createElement('button', { onClick }, 'skill-card'),
}))
vi.mock('@/shared/components/pagination', () => ({ Pagination: () => null }))
vi.mock('@/shared/hooks/use-user-queries', () => ({
useMySubscriptionsPage: () => ({
data: {
items: [{ id: 1, namespace: 'team-a', slug: 'demo-skill' }],
total: 1,
page: 0,
size: 12,
},
isLoading: false,
}),
}))
vi.mock('@/shared/ui/card', () => ({ Card: ({ children }: { children: unknown }) => children }))
vi.mock('@/shared/components/dashboard-page-header', () => ({ DashboardPageHeader: () => null }))
import { MySubscriptionsPage } from './subscriptions'
describe('MySubscriptionsPage', () => {
beforeEach(() => navigate.mockClear())
it('preserves the subscriptions page when opening a skill', () => {
render(createElement(MySubscriptionsPage))
fireEvent.click(screen.getByRole('button', { name: 'skill-card' }))
expect(navigate).toHaveBeenCalledWith({
to: '/space/team-a/demo-skill',
search: { returnTo: '/dashboard/subscriptions?page=1' },
})
})
})

View file

@ -1,17 +1,19 @@
import { useState } from 'react'
import { useNavigate } from '@tanstack/react-router'
import { useLocation, useNavigate } from '@tanstack/react-router'
import { useTranslation } from 'react-i18next'
import { SkillCard } from '@/features/skill/skill-card'
import { Pagination } from '@/shared/components/pagination'
import { useMySubscriptionsPage } from '@/shared/hooks/use-user-queries'
import { Card } from '@/shared/ui/card'
import { DashboardPageHeader } from '@/shared/components/dashboard-page-header'
import { buildReturnTo } from '@/shared/lib/auth-route'
const PAGE_SIZE = 12
export function MySubscriptionsPage() {
const { t } = useTranslation()
const navigate = useNavigate()
const location = useLocation()
const [page, setPage] = useState(0)
const { data, isLoading } = useMySubscriptionsPage({ page, size: PAGE_SIZE })
const skills = data?.items ?? []
@ -40,7 +42,10 @@ export function MySubscriptionsPage() {
<SkillCard
key={skill.id}
skill={skill}
onClick={() => navigate({ to: `/space/${skill.namespace}/${encodeURIComponent(skill.slug)}` })}
onClick={() => navigate({
to: `/space/${skill.namespace}/${encodeURIComponent(skill.slug)}`,
search: { returnTo: buildReturnTo(location) },
})}
/>
))}
</div>