Refactor admin panels to utilize CreateNameDialog for creating new entities
Updated the BumpersPanel, ChannelsPanel, CollectionsPanel, GroupsPanel, ClipGroupPanel, and ShowsPanel components to replace direct input fields with a CreateNameDialog for creating new items. This change enhances user experience by centralizing the creation process and improving UI consistency. Localization strings were also updated to reflect new dialog titles and labels in both English and Russian.
This commit is contained in:
@@ -1,15 +1,10 @@
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { Link } from '@tanstack/react-router'
|
||||
import { Plus } from 'lucide-react'
|
||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { qk } from '@/shared/api/query-keys'
|
||||
import {
|
||||
AUDIENCE_UNSET,
|
||||
SHOW_AUDIENCES,
|
||||
type ShowAudience,
|
||||
type ShowKind,
|
||||
type ShowSummaryDto,
|
||||
} from '@/shared/api/types'
|
||||
import type { ShowKind, ShowSummaryDto } from '@/shared/api/types'
|
||||
import { useApiError } from '@/shared/lib/use-api-error'
|
||||
import { Badge } from '@/shared/ui/badge'
|
||||
import { Button } from '@/shared/ui/button'
|
||||
@@ -19,7 +14,8 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@
|
||||
import { sortRows, useTableSort } from '@/shared/lib/table-sort'
|
||||
import { SortHeader } from '@/shared/ui/sortable'
|
||||
import { listGenres } from '@/features/admin/genres/api'
|
||||
import { createShow, deleteShow, listShows } from './api'
|
||||
import { deleteShow, listShows } from './api'
|
||||
import { CreateShowDialog } from './CreateShowDialog'
|
||||
import { DeleteShowDialog } from './DeleteShowDialog'
|
||||
import { BulkTagBar } from './BulkTagBar'
|
||||
|
||||
@@ -28,11 +24,7 @@ const PAGE_SIZE = 20
|
||||
export function ShowsPanel() {
|
||||
const { t } = useTranslation()
|
||||
const queryClient = useQueryClient()
|
||||
const [name, setName] = useState('')
|
||||
const [originalName, setOriginalName] = useState('')
|
||||
const [kind, setKind] = useState<ShowKind>('Series')
|
||||
// Новое шоу заводится без рейтинга: проставят метаданные либо админ руками.
|
||||
const [audience, setAudience] = useState<ShowAudience | null>(null)
|
||||
const [creating, setCreating] = useState(false)
|
||||
const [query, setQuery] = useState('')
|
||||
const [page, setPage] = useState(1)
|
||||
const { sort, toggle } = useTableSort('name', false)
|
||||
@@ -97,21 +89,6 @@ export function ShowsPanel() {
|
||||
current.includes(showId) ? current.filter((id) => id !== showId) : [...current, showId],
|
||||
)
|
||||
|
||||
const createMutation = useMutation({
|
||||
mutationFn: () =>
|
||||
createShow({
|
||||
name: name.trim(),
|
||||
kind,
|
||||
originalName: originalName.trim() || undefined,
|
||||
audience,
|
||||
}),
|
||||
onSuccess: () => {
|
||||
setName('')
|
||||
setOriginalName('')
|
||||
invalidate()
|
||||
},
|
||||
onError,
|
||||
})
|
||||
// Шоу к удалению: сначала спрашиваем про файлы, и только потом удаляем.
|
||||
const [toDelete, setToDelete] = useState<ShowSummaryDto | null>(null)
|
||||
const deleteMutation = useMutation({
|
||||
@@ -133,52 +110,10 @@ export function ShowsPanel() {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<h2 className="crt-glow text-xl font-semibold">{t('admin.shows.title')}</h2>
|
||||
|
||||
<div className="flex flex-wrap items-end gap-2">
|
||||
<Input
|
||||
className="max-w-xs"
|
||||
placeholder={t('admin.shows.name')}
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
className="max-w-xs"
|
||||
placeholder={t('admin.shows.originalName')}
|
||||
value={originalName}
|
||||
onChange={(e) => setOriginalName(e.target.value)}
|
||||
/>
|
||||
<Select value={kind} onValueChange={(v) => setKind(v as ShowKind)}>
|
||||
<SelectTrigger className="w-40">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="Series">{t('admin.shows.kinds.Series')}</SelectItem>
|
||||
<SelectItem value="Single">{t('admin.shows.kinds.Single')}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Select
|
||||
value={audience ?? AUDIENCE_UNSET}
|
||||
onValueChange={(v) => setAudience(v === AUDIENCE_UNSET ? null : (v as ShowAudience))}
|
||||
>
|
||||
{/* Та же ширина, что у селекта на карточке шоу: расшифровки рейтингов длинные. */}
|
||||
<SelectTrigger className="w-64 whitespace-nowrap">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value={AUDIENCE_UNSET}>{t('admin.shows.audienceUnset')}</SelectItem>
|
||||
{SHOW_AUDIENCES.map((value) => (
|
||||
<SelectItem key={value} value={value}>
|
||||
{t(`admin.shows.audiences.${value}`)}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button
|
||||
size="sm"
|
||||
disabled={!name.trim() || createMutation.isPending}
|
||||
onClick={() => createMutation.mutate()}
|
||||
>
|
||||
<div className="flex flex-wrap items-center justify-between gap-2">
|
||||
<h2 className="crt-glow text-xl font-semibold">{t('admin.shows.title')}</h2>
|
||||
<Button size="sm" onClick={() => setCreating(true)}>
|
||||
<Plus className="h-4 w-4" />
|
||||
{t('common.create')}
|
||||
</Button>
|
||||
</div>
|
||||
@@ -340,6 +275,8 @@ export function ShowsPanel() {
|
||||
|
||||
<Pager page={page} totalPages={totalPages} onChange={setPage} />
|
||||
|
||||
{creating && <CreateShowDialog onClose={() => setCreating(false)} onCreated={invalidate} />}
|
||||
|
||||
{toDelete && (
|
||||
<DeleteShowDialog
|
||||
show={toDelete}
|
||||
|
||||
Reference in New Issue
Block a user