fix: changed resolve endpoint contract form get to post

This commit is contained in:
Тимур Городецкий
2026-08-03 14:37:42 +05:00
parent 788e046ebe
commit e6203e7093
22 changed files with 512 additions and 22 deletions
@@ -0,0 +1,33 @@
@import '../../../../../styles/design-tokens';
.panel {
margin-top: 16px;
padding: 24px;
background: $white;
border: 1px solid $gray-200;
border-radius: $r-lg;
box-shadow: $sh-1;
}
.title {
font-family: $font-serif;
font-size: 16px;
font-weight: 600;
color: $navy-900;
margin-bottom: 14px;
}
.actions {
display: flex;
gap: 10px;
flex-wrap: wrap;
margin-top: 16px;
}
.state {
margin-top: 16px;
padding: 24px;
color: $gray-500;
font-size: $fs-sm;
text-align: center;
}
@@ -0,0 +1,120 @@
import * as React from 'react';
import { useState, useEffect } from 'react';
import styles from './DecisionPanel.module.scss';
import { Button, Alert, FormField, TextArea, Icon } from '../../ui';
import { ApproverService, ApproverDecision } from '../approverDecision.service';
interface IDecisionPanelProps {
service: ApproverService;
/** Id заявки (элемент списка данных). */
requestId: number;
/** Уведомление после сохранения решения (например, обновить статус на экране). */
onDecided?: (status: string) => void;
}
// Панель решения согласующего: проверяет, его ли сейчас очередь, и если да —
// показывает комментарий и кнопки Согласовать / Вернуть / Отклонить.
export const DecisionPanel: React.FC<IDecisionPanelProps> = ({ service, requestId, onDecided }) => {
const [checking, setChecking] = useState<boolean>(true);
const [rowId, setRowId] = useState<number | undefined>(undefined);
const [comment, setComment] = useState<string>('');
const [submitting, setSubmitting] = useState<boolean>(false);
const [resultStatus, setResultStatus] = useState<string | undefined>(undefined);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
let alive = true;
setChecking(true);
service
.getPendingRowForCurrentUser(requestId)
.then((row) => {
if (alive) {
setRowId(row?.id);
setChecking(false);
}
})
.catch((e) => {
if (alive) {
setError(`Не удалось проверить очередь согласования: ${(e as Error).message}`);
setChecking(false);
}
});
return () => {
alive = false;
};
}, [requestId, service]);
async function decide(decision: ApproverDecision): Promise<void> {
if (rowId === undefined) {
return;
}
if ((decision === 'return' || decision === 'reject') && comment.trim().length === 0) {
setError('Для возврата или отклонения укажите комментарий.');
return;
}
setError(null);
setSubmitting(true);
try {
const status = await service.decide(requestId, rowId, decision, comment.trim());
setResultStatus(status);
setSubmitting(false);
if (onDecided) {
onDecided(status);
}
} catch (e) {
setError(`Не удалось сохранить решение: ${(e as Error).message}`);
setSubmitting(false);
}
}
if (checking) {
return <div className={styles.state}>Проверяем вашу очередь на согласование…</div>;
}
if (resultStatus) {
return (
<div className={styles.panel}>
<Alert variant="ok">Решение сохранено. Статус заявки: «{resultStatus}».</Alert>
</div>
);
}
if (rowId === undefined) {
return (
<div className={styles.panel}>
<Alert variant="warn">
Сейчас не ваша очередь на согласование, либо заявка уже обработана.
</Alert>
</div>
);
}
return (
<div className={styles.panel}>
<div className={styles.title}>Ваше решение</div>
{error && <Alert variant="err">{error}</Alert>}
<FormField label="Комментарий" htmlFor="decisionComment">
<TextArea
id="decisionComment"
value={comment}
onChange={setComment}
placeholder="Комментарий (обязателен при возврате или отклонении)"
/>
</FormField>
<div className={styles.actions}>
<Button variant="accent" disabled={submitting} onClick={() => decide('approve')}>
<Icon name="check" size="sm" />
Согласовать
</Button>
<Button variant="secondary" disabled={submitting} onClick={() => decide('return')}>
<Icon name="arrow-left" size="sm" />
Вернуть
</Button>
<Button variant="danger" disabled={submitting} onClick={() => decide('reject')}>
<Icon name="close" size="sm" />
Отклонить
</Button>
</div>
</div>
);
};