diff --git a/apps/web/src/design-preview/create-sheets.tsx b/apps/web/src/design-preview/create-sheets.tsx new file mode 100644 index 0000000..b86c015 --- /dev/null +++ b/apps/web/src/design-preview/create-sheets.tsx @@ -0,0 +1,194 @@ +import { useState } from 'react' +import type { CreateUserRequest } from '@authportal/shared' +import type { CreateOidcClientValues } from '@/components/reui-kit/create-oidc-client-sheet' +import { Button } from '@authportal/ui/components/button' +import { Field, FieldDescription, FieldError, FieldLabel } from '@authportal/ui/components/field' +import { Input } from '@authportal/ui/components/input' +import { Switch } from '@authportal/ui/components/switch' +import { Textarea } from '@authportal/ui/components/textarea' +import { PreviewSheet, SignalAlert } from './bits' + +/** Окно «Создать пользователя» по доске: email, имя, временный пароль, администратор и заметка про журнал. */ +export function CreateUserPreviewSheet({ + open, + onOpenChange, + onSubmit, +}: { + open: boolean + onOpenChange: (open: boolean) => void + onSubmit: (values: CreateUserRequest) => void +}) { + const [email, setEmail] = useState('') + const [name, setName] = useState('') + const [password, setPassword] = useState('') + const [admin, setAdmin] = useState(false) + const [touched, setTouched] = useState(false) + + const passwordError = password.length < 12 ? 'Минимум 12 символов' : null + const emailError = !/^\S+@\S+\.\S+$/.test(email) ? 'Укажите email' : null + const valid = !passwordError && !emailError + + function reset() { + setEmail('') + setName('') + setPassword('') + setAdmin(false) + setTouched(false) + } + + return ( + { + if (!o) reset() + onOpenChange(o) + }} + dirty={Boolean(email || name || password || admin)} + title="Создать пользователя" + description="После создания откроются права доступа" + footer={ + <> + + + + } + > + + + Email * + + setEmail(e.target.value)} /> + {touched && emailError ? {emailError} : Станет логином} + + + Имя + setName(e.target.value)} /> + + + + Временный пароль * + + setPassword(e.target.value)} /> + {touched && passwordError ? ✕ {passwordError} : Пользователь заменит его на passkey} + + + +
+ Администратор + Полный доступ к порталу и ко всем приложениям +
+
+ + Создание записывается в журнал «Изменения» с вашим именем и IP. + +
+ ) +} + +/** Окно «Создать OIDC-клиент» по доске: название, redirect URI, включён. */ +export function CreateOidcPreviewSheet({ + open, + onOpenChange, + onSubmit, +}: { + open: boolean + onOpenChange: (open: boolean) => void + onSubmit: (values: CreateOidcClientValues) => void +}) { + const [name, setName] = useState('') + const [uris, setUris] = useState('') + const [enabled, setEnabled] = useState(true) + const [touched, setTouched] = useState(false) + + const list = uris + .split('\n') + .map((x) => x.trim()) + .filter(Boolean) + const urisError = list.length === 0 || list.some((u) => !/^https:\/\/[^\s*]+$/.test(u)) ? 'Укажите точный https-адрес колбэка приложения.' : null + const nameError = name.trim() ? null : 'Введите название' + const valid = !urisError && !nameError + + function reset() { + setName('') + setUris('') + setEnabled(true) + setTouched(false) + } + + return ( + { + if (!o) reset() + onOpenChange(o) + }} + dirty={Boolean(name || uris)} + title="Создать OIDC-клиент" + description="Секрет будет показан один раз после создания" + footer={ + <> + + + + } + > + + + Название * + + setName(e.target.value)} /> + {touched && nameError ? {nameError} : null} + + + + Redirect URI * + +