Update CollectionSuggestions and GroupSuggestions to default to collapsed state; enhance GenresPanel with pagination and sorting improvements
Modified CollectionSuggestions and GroupSuggestions components to start in a collapsed state for better UI experience. Enhanced GenresPanel by implementing pagination and updating sorting functionality to ensure a more manageable display of genre data, improving overall usability.
This commit is contained in:
@@ -21,7 +21,9 @@ export function CollectionSuggestions() {
|
||||
const { t } = useTranslation()
|
||||
const queryClient = useQueryClient()
|
||||
const onError = useApiError()
|
||||
const [collapsed, setCollapsed] = useState(false)
|
||||
// Свёрнуто по умолчанию: предложения — подсказка, а не главное на экране, и развёрнутый
|
||||
// список из десятка строк отодвигал бы сам справочник за нижний край.
|
||||
const [collapsed, setCollapsed] = useState(true)
|
||||
const [showExisting, setShowExisting] = useState(false)
|
||||
|
||||
const { data, isLoading } = useQuery({
|
||||
|
||||
@@ -14,6 +14,7 @@ import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '
|
||||
import { Input } from '@/shared/ui/input'
|
||||
import { Label } from '@/shared/ui/label'
|
||||
import { sortRows, useTableSort } from '@/shared/lib/table-sort'
|
||||
import { Pager } from '@/shared/ui/pager'
|
||||
import { SortHeader } from '@/shared/ui/sortable'
|
||||
import { createGenre, deleteGenre, listGenres, updateGenre } from './api'
|
||||
|
||||
@@ -36,6 +37,13 @@ const editSchema = z.object({
|
||||
type CreateValues = z.infer<typeof createSchema>
|
||||
type EditValues = z.infer<typeof editSchema>
|
||||
|
||||
/**
|
||||
* Жанров бывает под сотню (базовый набор плюс заведённые руками), и все они грузятся одним
|
||||
* запросом — список нужен целиком селектам жанра по всей админке. Поэтому страницы режутся здесь,
|
||||
* а не на сервере: таблица остаётся читаемой, а пикеры продолжают получать полный справочник.
|
||||
*/
|
||||
const PAGE_SIZE = 20
|
||||
|
||||
/** Псевдонимы вводятся одной строкой через запятую — их редко больше десятка. */
|
||||
function parseAliases(value: string | undefined): string[] {
|
||||
return (value ?? '')
|
||||
@@ -52,6 +60,8 @@ export function GenresPanel() {
|
||||
queryFn: listGenres,
|
||||
})
|
||||
const { sort, toggle } = useTableSort('sortOrder', false)
|
||||
const [page, setPage] = useState(1)
|
||||
|
||||
const sortedGenres = sortRows(genres ?? [], sort, {
|
||||
sortOrder: (g) => g.sortOrder,
|
||||
name: (g) => g.name.toLowerCase(),
|
||||
@@ -59,6 +69,16 @@ export function GenresPanel() {
|
||||
showCount: (g) => g.showCount,
|
||||
})
|
||||
|
||||
// Страница может уехать за конец списка после удаления — тогда показываем последнюю.
|
||||
const totalPages = Math.max(1, Math.ceil(sortedGenres.length / PAGE_SIZE))
|
||||
const current = Math.min(page, totalPages)
|
||||
const visible = sortedGenres.slice((current - 1) * PAGE_SIZE, current * PAGE_SIZE)
|
||||
|
||||
const sortColumn = (key: string) => {
|
||||
setPage(1)
|
||||
toggle(key)
|
||||
}
|
||||
|
||||
const invalidate = () => queryClient.invalidateQueries({ queryKey: qk.genres.all })
|
||||
const reportError = useApiError()
|
||||
|
||||
@@ -145,26 +165,26 @@ export function GenresPanel() {
|
||||
label={t('admin.genres.order')}
|
||||
sortKey="sortOrder"
|
||||
sort={sort}
|
||||
onToggle={toggle}
|
||||
onToggle={sortColumn}
|
||||
/>
|
||||
<SortHeader
|
||||
label={t('admin.genres.name')}
|
||||
sortKey="name"
|
||||
sort={sort}
|
||||
onToggle={toggle}
|
||||
onToggle={sortColumn}
|
||||
/>
|
||||
<SortHeader
|
||||
label={t('admin.genres.slug')}
|
||||
sortKey="slug"
|
||||
sort={sort}
|
||||
onToggle={toggle}
|
||||
onToggle={sortColumn}
|
||||
/>
|
||||
<th className="px-4 py-2 font-medium">{t('admin.genres.aliases')}</th>
|
||||
<SortHeader
|
||||
label={t('admin.genres.usage')}
|
||||
sortKey="showCount"
|
||||
sort={sort}
|
||||
onToggle={toggle}
|
||||
onToggle={sortColumn}
|
||||
/>
|
||||
<th className="px-4 py-2 font-medium">{t('common.actions')}</th>
|
||||
</tr>
|
||||
@@ -177,7 +197,7 @@ export function GenresPanel() {
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
{sortedGenres.map((genre) => (
|
||||
{visible.map((genre) => (
|
||||
<tr key={genre.id} className="border-b border-border last:border-0">
|
||||
<td className="px-4 py-2 text-muted-foreground">{genre.sortOrder}</td>
|
||||
<td className="px-4 py-2">
|
||||
@@ -212,6 +232,8 @@ export function GenresPanel() {
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<Pager page={current} totalPages={totalPages} onChange={setPage} />
|
||||
|
||||
<Dialog open={createOpen} onOpenChange={setCreateOpen}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
|
||||
@@ -23,7 +23,9 @@ export function GroupSuggestions() {
|
||||
const { t } = useTranslation()
|
||||
const queryClient = useQueryClient()
|
||||
const onError = useApiError()
|
||||
const [collapsed, setCollapsed] = useState(false)
|
||||
// Свёрнуто по умолчанию: предложения — подсказка, а не главное на экране, и развёрнутый
|
||||
// список из десятка строк отодвигал бы сам справочник за нижний край.
|
||||
const [collapsed, setCollapsed] = useState(true)
|
||||
const [showExisting, setShowExisting] = useState(false)
|
||||
|
||||
const { data, isLoading } = useQuery({
|
||||
|
||||
Reference in New Issue
Block a user