Add password reset functionality for admin users: implement ResetPassword endpoint, update AdminUserEndpoints to include password reset logic, and enhance user interface for password management. Update translations for new features and ensure proper error handling in the reset process.
This commit is contained in:
@@ -1,24 +1,42 @@
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { Link } from '@tanstack/react-router'
|
||||
import { useState } from 'react'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { HttpError } from '@/shared/api/client'
|
||||
import type { ShowKind } from '@/shared/api/types'
|
||||
import { Badge } from '@/shared/ui/badge'
|
||||
import { Button } from '@/shared/ui/button'
|
||||
import { Input } from '@/shared/ui/input'
|
||||
import { Pager } from '@/shared/ui/pager'
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/shared/ui/select'
|
||||
import { toast } from '@/shared/ui/toast-store'
|
||||
import { createShow, deleteShow, listShows } from './api'
|
||||
|
||||
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 [query, setQuery] = useState('')
|
||||
const [page, setPage] = useState(1)
|
||||
|
||||
const { data, isLoading } = useQuery({ queryKey: ['admin', 'shows'], queryFn: listShows })
|
||||
|
||||
// Список шоу обычно умещается в одну загрузку — фильтруем и листаем на клиенте (пикеры берут всё).
|
||||
const filtered = useMemo(() => {
|
||||
const q = query.trim().toLowerCase()
|
||||
const all = data ?? []
|
||||
if (!q) return all
|
||||
return all.filter(
|
||||
(s) =>
|
||||
s.name.toLowerCase().includes(q) || (s.originalName ?? '').toLowerCase().includes(q),
|
||||
)
|
||||
}, [data, query])
|
||||
const totalPages = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE))
|
||||
const pageItems = filtered.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE)
|
||||
const invalidate = () => queryClient.invalidateQueries({ queryKey: ['admin', 'shows'] })
|
||||
const onError = (error: unknown) =>
|
||||
toast.error(error instanceof HttpError ? error.detail : t('common.error'))
|
||||
@@ -70,6 +88,16 @@ export function ShowsPanel() {
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Input
|
||||
className="max-w-xs"
|
||||
placeholder={t('common.search')}
|
||||
value={query}
|
||||
onChange={(e) => {
|
||||
setPage(1)
|
||||
setQuery(e.target.value)
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="crt-panel overflow-x-auto rounded-md">
|
||||
<table className="w-full text-sm">
|
||||
<thead className="border-b border-border text-left text-muted-foreground">
|
||||
@@ -89,7 +117,7 @@ export function ShowsPanel() {
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
{data?.map((show) => (
|
||||
{pageItems.map((show) => (
|
||||
<tr key={show.id} className="border-b border-border last:border-0">
|
||||
<td className="px-4 py-2">
|
||||
<Link
|
||||
@@ -119,6 +147,8 @@ export function ShowsPanel() {
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<Pager page={page} totalPages={totalPages} onChange={setPage} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user