Add settings endpoints and registration status check: implement new API endpoints for settings management, including registration status retrieval, and update the registration command handler to enforce registration rules based on site settings.
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { HttpError } from '@/shared/api/client'
|
||||
import { Button } from '@/shared/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/shared/ui/card'
|
||||
import { toast } from '@/shared/ui/toast-store'
|
||||
import { getSiteSettings, updateSiteSettings } from './api'
|
||||
|
||||
export function SettingsPanel() {
|
||||
const { t } = useTranslation()
|
||||
const queryClient = useQueryClient()
|
||||
const [registrationEnabled, setRegistrationEnabled] = useState(false)
|
||||
|
||||
const { data, isLoading } = useQuery({
|
||||
queryKey: ['admin', 'settings'],
|
||||
queryFn: getSiteSettings,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (data) setRegistrationEnabled(data.registrationEnabled)
|
||||
}, [data])
|
||||
|
||||
const save = useMutation({
|
||||
mutationFn: () => updateSiteSettings({ registrationEnabled }),
|
||||
onSuccess: () => {
|
||||
toast.success(t('settings.saved'))
|
||||
void queryClient.invalidateQueries({ queryKey: ['admin', 'settings'] })
|
||||
},
|
||||
onError: (error: unknown) =>
|
||||
toast.error(error instanceof HttpError ? error.detail : t('common.error')),
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<h2 className="crt-glow text-xl font-semibold">{t('admin.settings.title')}</h2>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>{t('admin.settings.registration')}</CardTitle>
|
||||
<CardDescription>{t('admin.settings.registrationHint')}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
<label className="flex items-center gap-2 text-sm">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={registrationEnabled}
|
||||
disabled={isLoading}
|
||||
onChange={(e) => setRegistrationEnabled(e.target.checked)}
|
||||
/>
|
||||
{t('admin.settings.registrationLabel')}
|
||||
</label>
|
||||
<div>
|
||||
<Button size="sm" disabled={isLoading || save.isPending} onClick={() => save.mutate()}>
|
||||
{t('common.save')}
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { apiRequest } from '@/shared/api/client'
|
||||
import type { SiteSettings } from '@/shared/api/types'
|
||||
|
||||
export function getSiteSettings() {
|
||||
return apiRequest<SiteSettings>('/admin/settings')
|
||||
}
|
||||
|
||||
export function updateSiteSettings(body: SiteSettings) {
|
||||
return apiRequest<void>('/admin/settings', { method: 'PUT', body })
|
||||
}
|
||||
@@ -1,7 +1,12 @@
|
||||
import { apiRequest, setAccessToken } from '@/shared/api/client'
|
||||
import type { AuthResponse, CurrentUser } from '@/shared/api/types'
|
||||
import type { AuthResponse, CurrentUser, RegistrationStatus } from '@/shared/api/types'
|
||||
import { useAuthStore } from './store'
|
||||
|
||||
/** Публично: включена ли открытая регистрация (для страниц входа/регистрации). */
|
||||
export function fetchRegistrationStatus() {
|
||||
return apiRequest<RegistrationStatus>('/auth/registration')
|
||||
}
|
||||
|
||||
export function login(userName: string, password: string) {
|
||||
return apiRequest<AuthResponse>('/auth/login', { method: 'POST', body: { userName, password } })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user