f1tness_parser/frontend/js/user-dialog.js

99 lines
4.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Modal with the form for creating and editing a user
import { alert, api, h } from './common.js';
import { openModal } from './modal.js';
const ROLES = { trainee: 'Тренирующийся', trainer: 'Тренер' };
const jsonRequest = (method, body) => ({
method,
headers: { 'Content-Type': 'application/json' },
body: body === undefined ? undefined : JSON.stringify(body),
});
function field(label, input, className = 'col-12 col-md-6') {
return h('div', { class: className }, h('label', { class: 'form-label small text-muted mb-1' }, label), input);
}
function errorText(error) {
if (error.status === 409) return 'Пользователь с таким email уже есть.';
if (error.status === 422) return 'Проверьте поля: email должен быть корректным, пароль — не короче 8 символов.';
if (error.status === 404) return 'Пользователь не найден.';
return error.message;
}
/** user is null for a new user; onChange() is called after it was saved or deleted */
function userForm(user, { onDone, onCancel }) {
const isNew = !user;
const input = (name, attrs) => h('input', { class: 'form-control', name, ...attrs });
const status = h('div', { class: 'mt-3' });
const save = h('button', { type: 'submit', class: 'btn btn-primary' }, isNew ? 'Создать' : 'Сохранить');
const cancel = h('button', { type: 'button', class: 'btn btn-outline-secondary' }, 'Отмена');
cancel.addEventListener('click', onCancel);
const remove = isNew ? null : h('button', { type: 'button', class: 'btn btn-outline-danger ms-auto' }, 'Удалить');
const role = h('select', { class: 'form-select', name: 'role' },
...Object.entries(ROLES).map(([value, title]) =>
h('option', { value, selected: (user?.role || 'trainee') === value }, title)));
const form = h('form', {},
h('div', { class: 'row g-3' },
field('Email', input('email', { type: 'email', required: true, maxlength: 254, value: user?.email || '', autocomplete: 'off' })),
field(isNew ? 'Пароль' : 'Новый пароль', input('password', {
type: 'password', minlength: 8, maxlength: 128, required: isNew, autocomplete: 'new-password',
placeholder: isNew ? 'не короче 8 символов' : 'оставьте пустым, чтобы не менять',
})),
field('Имя', input('first_name', { type: 'text', maxlength: 100, value: user?.first_name || '' })),
field('Фамилия', input('last_name', { type: 'text', maxlength: 100, value: user?.last_name || '' })),
field('Роль', role),
isNew ? null : h('div', { class: 'col-12 col-md-6 d-flex align-items-end' },
h('div', { class: 'form-check mb-2' },
h('input', { type: 'checkbox', class: 'form-check-input', name: 'is_active', id: 'user-is-active', checked: user.is_active }),
h('label', { class: 'form-check-label', for: 'user-is-active' }, 'Активен')))),
h('div', { class: 'd-flex gap-2 align-items-center mt-4' }, save, cancel, remove),
status);
form.addEventListener('submit', async (event) => {
event.preventDefault();
const { elements } = form;
const data = {
email: elements.email.value,
first_name: elements.first_name.value,
last_name: elements.last_name.value,
role: elements.role.value,
};
if (elements.password.value) data.password = elements.password.value;
save.disabled = true;
try {
if (isNew) {
await api('/users/', jsonRequest('POST', data));
} else {
data.is_active = elements.is_active.checked;
await api(`/users/${user.id}/`, jsonRequest('PATCH', data));
}
onDone();
} catch (error) {
status.replaceChildren(alert('danger', `Не удалось сохранить: ${errorText(error)}`));
save.disabled = false;
}
});
remove?.addEventListener('click', async () => {
if (!confirm(`Удалить пользователя ${user.email}?`)) return;
try {
await api(`/users/${user.id}/`, jsonRequest('DELETE'));
onDone();
} catch (error) {
status.replaceChildren(alert('danger', `Не удалось удалить: ${errorText(error)}`));
}
});
return form;
}
/** Opens the form; user is the existing user to edit or null to create one. */
export function openUserDialog(user, onChange) {
const { body, hide } = openModal(user ? 'Редактирование пользователя' : 'Новый пользователь');
body.replaceChildren(userForm(user, { onDone: () => { hide(); onChange(); }, onCancel: hide }));
}