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:
Leonid Pershin
2026-07-25 19:49:08 +03:00
parent d44aa44d95
commit 1f6fa6f1ae
30 changed files with 1755 additions and 58 deletions
+9 -2
View File
@@ -206,11 +206,18 @@ export type ChannelAdDto = {
export type OverrideShowDto = { showId: string; showName: string; weight: number }
export type OverrideRecurrence = 'OneTime' | 'Weekly'
export type ProgrammingOverrideDto = {
id: string
mode: OverrideMode
startsAtUtc: string
endsAtUtc: string
recurrence: OverrideRecurrence
startsAtUtc: string | null
endsAtUtc: string | null
/** Weekly: день недели 0=Вс..6=Сб; окно минут суток (UTC). */
dayOfWeek: number | null
startMinute: number | null
endMinute: number | null
shows: OverrideShowDto[]
}
+38
View File
@@ -27,6 +27,8 @@ const resources = {
confirm: 'Подтвердить',
search: 'Поиск',
actions: 'Действия',
prevPage: 'Предыдущая страница',
nextPage: 'Следующая страница',
yes: 'Да',
no: 'Нет',
},
@@ -105,6 +107,10 @@ const resources = {
active: 'Активен',
block: 'Заблокировать',
unblock: 'Разблокировать',
resetPassword: 'Пароль',
resetPasswordFor: 'Сменить пароль: {{name}}',
newPassword: 'Новый пароль',
passwordReset: 'Пароль изменён',
filterAll: 'Все роли',
createTitle: 'Создать пользователя',
password: 'Пароль',
@@ -288,6 +294,19 @@ const resources = {
noAds: 'Пул рекламы пуст',
overrides: 'Марафоны / override',
modes: { Exclusive: 'Эксклюзив', Boost: 'Буст' },
overrideRecurrence: 'Повтор',
recurrenceOneTime: 'Разово',
recurrenceWeekly: 'Еженедельно',
weekday: 'День недели',
weekdays: {
0: 'Вс',
1: 'Пн',
2: 'Вт',
3: 'Ср',
4: 'Чт',
5: 'Пт',
6: 'Сб',
},
from: 'С',
to: 'По',
noOverrides: 'Override не заданы',
@@ -368,6 +387,8 @@ const resources = {
confirm: 'Confirm',
search: 'Search',
actions: 'Actions',
prevPage: 'Previous page',
nextPage: 'Next page',
yes: 'Yes',
no: 'No',
},
@@ -446,6 +467,10 @@ const resources = {
active: 'Active',
block: 'Block',
unblock: 'Unblock',
resetPassword: 'Password',
resetPasswordFor: 'Reset password: {{name}}',
newPassword: 'New password',
passwordReset: 'Password changed',
filterAll: 'All roles',
createTitle: 'Create user',
password: 'Password',
@@ -629,6 +654,19 @@ const resources = {
noAds: 'Ad pool is empty',
overrides: 'Marathons / overrides',
modes: { Exclusive: 'Exclusive', Boost: 'Boost' },
overrideRecurrence: 'Repeat',
recurrenceOneTime: 'One-time',
recurrenceWeekly: 'Weekly',
weekday: 'Weekday',
weekdays: {
0: 'Sun',
1: 'Mon',
2: 'Tue',
3: 'Wed',
4: 'Thu',
5: 'Fri',
6: 'Sat',
},
from: 'From',
to: 'To',
noOverrides: 'No overrides set',
+42
View File
@@ -0,0 +1,42 @@
import { useTranslation } from 'react-i18next'
import { Button } from './button'
/** Простой пейджер «‹ N / M ›». Ничего не рисует, если страница одна. */
export function Pager({
page,
totalPages,
onChange,
}: {
page: number
totalPages: number
onChange: (page: number) => void
}) {
const { t } = useTranslation()
if (totalPages <= 1) return null
return (
<div className="flex items-center justify-center gap-2 text-sm">
<Button
size="sm"
variant="outline"
disabled={page <= 1}
onClick={() => onChange(page - 1)}
aria-label={t('common.prevPage')}
>
</Button>
<span className="tabular-nums text-muted-foreground">
{page} / {totalPages}
</span>
<Button
size="sm"
variant="outline"
disabled={page >= totalPages}
onClick={() => onChange(page + 1)}
aria-label={t('common.nextPage')}
>
</Button>
</div>
)
}