Отключаемый модуль (instance_settings.consent_policy): галочка + ссылка на публичную страницу регламента на форме регистрации, редактируемый в админке текст с типовым шаблоном по умолчанию (плейсхолдеры под организацию, не проходил юридическую проверку), версия текста растёт при каждой правке. Факт согласия хранится в users (consent_version, consent_given_at) — второй эшелон проверки на сервере, как и для отключаемых модулей ранее. Дефолт (выключено) сохраняет поведение существующих инсталляций, у уже зарегистрированных пользователей согласие не запрашивается.
62 lines
2.7 KiB
TypeScript
62 lines
2.7 KiB
TypeScript
import { Link } from 'react-router-dom'
|
||
import { useQuery } from '@tanstack/react-query'
|
||
import { getRegistrationOptions } from '@/api/auth'
|
||
import { AppFooter } from '@/components/layout/AppFooter'
|
||
import { LogoMark } from '@/components/ui/LogoMark'
|
||
import { ThemeToggle } from '@/components/ui/ThemeToggle'
|
||
import '@/styles/legal.css'
|
||
|
||
/**
|
||
* Публичная страница регламента обработки персональных данных
|
||
* (`/legal/personal-data-consent`) — ссылка рядом с галочкой согласия на
|
||
* форме регистрации (`RegisterPage`). Текст и номер редакции берутся из
|
||
* того же публичного `GET /auth/registration-options`, которым пользуется
|
||
* форма регистрации — отдельного эндпоинта под это специально не заводили.
|
||
*
|
||
* Страница доступна ВСЕГДА, независимо от `consent_required`: если модуль
|
||
* выключен, регламент просто не обязателен для регистрации, но ссылка на
|
||
* него не должна вести в никуда — администратор мог оставить текст
|
||
* заполненным про запас или для внешней ссылки.
|
||
*/
|
||
export function ConsentPolicyPage() {
|
||
const { data, isLoading } = useQuery({
|
||
queryKey: ['auth', 'registration-options'],
|
||
queryFn: getRegistrationOptions,
|
||
})
|
||
|
||
return (
|
||
<div className="legal-shell">
|
||
<header className="legal-topbar">
|
||
<Link to="/lobby" className="brand-mark">
|
||
<LogoMark /> VidConf
|
||
</Link>
|
||
<ThemeToggle />
|
||
</header>
|
||
|
||
<main className="legal-main">
|
||
<article className="legal-card">
|
||
<h1>Регламент обработки персональных данных</h1>
|
||
|
||
{isLoading && <p className="legal-empty">Загрузка…</p>}
|
||
|
||
{!isLoading && data && data.consent_text.trim() && (
|
||
<>
|
||
<span className="legal-version">Редакция №{data.consent_version}</span>
|
||
<div className="legal-text">{data.consent_text}</div>
|
||
</>
|
||
)}
|
||
|
||
{!isLoading && data && !data.consent_text.trim() && (
|
||
<p className="legal-empty">
|
||
Регламент обработки персональных данных для этого инстанса ещё не заполнен
|
||
администратором.
|
||
</p>
|
||
)}
|
||
</article>
|
||
</main>
|
||
|
||
<AppFooter />
|
||
</div>
|
||
)
|
||
}
|