Open all content filtered to the activity tab you were on

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Iqbal
2026-10-29 12:49:07 +07:00
parent d00561f75d
commit 5bc0915edf
3 changed files with 15 additions and 7 deletions

View File

@@ -1,6 +1,6 @@
import { useEffect, useMemo, useRef, useState, type ReactNode } from 'react'
import { renderToStaticMarkup } from 'react-dom/server'
import { Link } from 'react-router-dom'
import { Link, useSearchParams } from 'react-router-dom'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { AudioPlayer } from '../components/AudioPlayer'
import { Icon, KIND_ICON, type IconName } from '../components/Icon'
@@ -19,10 +19,15 @@ const STUDIO_URL: string = import.meta.env.VITE_STUDIO_URL
// Setup fields of roleplay and simulator content, in display order.
const FIELDS = ['description', 'topic', 'objective', 'learning_objectives', 'user_role', 'ai_character', 'difficulty', 'context'] as const
type StatusFilter = 'all' | 'review' | 'approved' | 'working' | 'failed'
const STATUS_GROUP: Record<MaterialStatus, StatusFilter> = {
// 'done' is everything no longer being made except failures, as the Production page counts it; the
// Production page links here with ?status=done or ?status=working.
const STATUS_FILTERS = ['all', 'done', 'review', 'approved', 'working', 'failed'] as const
type StatusFilter = typeof STATUS_FILTERS[number]
const STATUS_GROUP: Record<MaterialStatus, Exclude<StatusFilter, 'all' | 'done'>> = {
preparing: 'working', generating: 'working', ready: 'review', accepted: 'approved', failed: 'failed', rejected: 'failed',
}
const matchesStatus = (m: Material, status: StatusFilter) =>
status === 'all' || (status === 'done' ? !isWorking(m) && m.status !== 'failed' : STATUS_GROUP[m.status] === status)
const fmt = (iso: string) => new Intl.DateTimeFormat(locale(), { day: 'numeric', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit' }).format(new Date(iso))
@@ -35,14 +40,15 @@ export function ResultsPage() {
const [tab, setTab] = useState<'content' | 'research'>('content')
const [query, setQuery] = useState('')
const [kind, setKind] = useState<ContentKind | 'all'>('all')
const [status, setStatus] = useState<StatusFilter>('all')
const [params] = useSearchParams()
const [status, setStatus] = useState<StatusFilter>(() => STATUS_FILTERS.find(s => s === params.get('status')) ?? 'all')
const [openId, setOpenId] = useState<string | null>(null)
const materials = results.data?.materials ?? []
const sources = results.data?.sources ?? []
const kinds = useMemo(() => [...new Set(materials.map(m => m.kind))], [materials])
const needle = query.trim().toLowerCase()
const shownMaterials = materials.filter(m => (kind === 'all' || m.kind === kind) && (status === 'all' || STATUS_GROUP[m.status] === status)
const shownMaterials = materials.filter(m => (kind === 'all' || m.kind === kind) && matchesStatus(m, status)
&& (!needle || titleOf(m).toLowerCase().includes(needle)))
const shownSources = sources.filter(s => !needle || s.title.toLowerCase().includes(needle) || s.url?.toLowerCase().includes(needle))
const open = materials.find(m => materialKey(m) === openId) ?? null
@@ -73,7 +79,7 @@ export function ResultsPage() {
{kinds.map(k => <option key={k} value={k}>{kindLabel(k)}</option>)}
</select>
<select aria-label={t('res.filterStatus')} value={status} onChange={e => setStatus(e.target.value as StatusFilter)}>
{(['all', 'review', 'approved', 'working', 'failed'] as const).map(s => <option key={s} value={s}>{t(`res.status.${s}` as Key)}</option>)}
{STATUS_FILTERS.map(s => <option key={s} value={s}>{t(`res.status.${s}` as Key)}</option>)}
</select>
</>
)}