Управление заявками (#7)
Tests / frontend-test (push) Successful in 43s
Tests / backend-test (push) Successful in 2m36s

Co-authored-by: gorbenko.pavel <gorbenko.pavel@tansu.kz>
Reviewed-on: http://git.tnsu.kz/gorbenko.pavel/tnsu-approval-route/pulls/7
This commit was merged in pull request #7.
This commit is contained in:
2026-08-07 09:49:38 +00:00
parent 9d9f390548
commit 0ffa032ade
42 changed files with 2436 additions and 65 deletions
@@ -0,0 +1,47 @@
@import '../../../../styles/design-tokens';
// position: fixed относительно viewport — веб-часть встроена в страницу
// SharePoint, а не в отдельное модальное окно, поэтому уголок экрана, а не
// уголок какого-то контейнера.
.toast {
position: fixed;
right: 20px;
bottom: 20px;
z-index: 1000;
display: flex;
align-items: flex-start;
gap: 10px;
max-width: 380px;
padding: 14px 16px;
border-radius: $r-md;
background: $red-50;
color: $red-500;
border: 1px solid #FECACA;
box-shadow: $sh-3;
font-size: 12.5px;
line-height: 1.5;
animation: toastIn .15s ease-out;
}
.message {
flex: 1;
}
.close {
flex-shrink: 0;
border: none;
background: none;
cursor: pointer;
color: inherit;
opacity: .6;
font-size: 16px;
line-height: 1;
padding: 0;
&:hover { opacity: 1; }
}
@keyframes toastIn {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
@@ -0,0 +1,33 @@
import * as React from 'react';
import styles from './Toast.module.scss';
import { Icon } from './Icon';
export interface IToastProps {
message: string;
onClose: () => void;
}
const AUTO_HIDE_MS = 6000;
/**
* Всплывающее сообщение об ошибке в углу экрана — для действий, которые не
* ломают уже отрисованный экран (переназначение/перестановка/добавление шага):
* пользователь и так видит, что изменение не применилось (см. reloadMatrix
* после ошибки в ManageRequestsScreen), поэтому постоянный Alert-блок сверху
* страницы был бы избыточен. Автоматически прячется через AUTO_HIDE_MS, либо
* закрывается вручную.
*/
export const Toast: React.FC<IToastProps> = ({ message, onClose }) => {
React.useEffect(() => {
const timer = window.setTimeout(onClose, AUTO_HIDE_MS);
return () => window.clearTimeout(timer);
}, [message, onClose]);
return (
<div className={styles.toast} role="alert">
<Icon name="warning" size="sm" />
<span className={styles.message}>{message}</span>
<button type="button" className={styles.close} onClick={onClose} aria-label="Закрыть">×</button>
</div>
);
};
@@ -3,6 +3,7 @@ export * from './Button';
export * from './IconButton';
export * from './Badge';
export * from './Alert';
export * from './Toast';
export * from './Panel';
export * from './Breadcrumbs';
export * from './PageHeader';