Уведомления назначенным пользователям (#9)
Co-authored-by: gorbenko.pavel <gorbenko.pavel@tansu.kz> Reviewed-on: http://git.tnsu.kz/gorbenko.pavel/tnsu-approval-route/pulls/9
This commit was merged in pull request #9.
This commit is contained in:
@@ -180,6 +180,8 @@ export const ManageRequestsScreen: React.FC<IManageRequestsScreenProps> = ({ api
|
||||
const [modal, setModal] = React.useState<ManagedApprovalRow | undefined>();
|
||||
const [deleteRow, setDeleteRow] = React.useState<ManagedApprovalRow | undefined>();
|
||||
const [saveError, setSaveError] = React.useState<string | undefined>();
|
||||
const [notifyResult, setNotifyResult] = React.useState<{ message: string; kind: 'ok' | 'err' } | undefined>();
|
||||
const [notifyingRowId, setNotifyingRowId] = React.useState<number | undefined>();
|
||||
// Отрицательные Id — «призрачные» строки: добавлены на клиенте, ответ сервера
|
||||
// (и настоящий Id из SharePoint) ещё не долетел. Реальные Id списка всегда
|
||||
// положительные, поэтому пересечься эти диапазоны не могут.
|
||||
@@ -347,6 +349,18 @@ export const ManageRequestsScreen: React.FC<IManageRequestsScreenProps> = ({ api
|
||||
const openReassign = (row: ManagedApprovalRow): void => setModal(row);
|
||||
const closeModal = (): void => setModal(undefined);
|
||||
|
||||
// Кого нельзя выбрать при переназначении — все остальные согласующие/
|
||||
// исполнители ТОЙ ЖЕ фазы (сама строка modal исключена, иначе нельзя было
|
||||
// бы оставить текущего человека на месте). Один человек не может стоять в
|
||||
// фазе дважды — та же гарантия, что и addableEmployees в
|
||||
// ManageRequestsPhaseTable для добавления нового шага.
|
||||
const reassignExcludedEmails = matrix && modal
|
||||
? matrix.rows
|
||||
.filter(r => r.phase === modal.phase && r.id !== modal.id)
|
||||
.map(r => r.approverEmail.toLowerCase())
|
||||
.filter(Boolean)
|
||||
: [];
|
||||
|
||||
// Переназначение — тоже оптимистично: patch конкретной строки сразу по ответу
|
||||
// сервера, без похода за всей матрицей заново. approverName берём из уже
|
||||
// загруженного справочника сотрудников (тот же источник, что подставляет
|
||||
@@ -459,6 +473,19 @@ export const ManageRequestsScreen: React.FC<IManageRequestsScreenProps> = ({ api
|
||||
});
|
||||
};
|
||||
|
||||
// Отправка уведомления — по явному клику (в отличие от request-portal, где
|
||||
// это происходит автоматически после решения), поэтому здесь показываем
|
||||
// пользователю результат, а не глушим ошибку молча.
|
||||
const handleNotify = (row: ManagedApprovalRow): void => {
|
||||
if (!matrix || !requestType) return;
|
||||
setNotifyingRowId(row.id);
|
||||
requestManage
|
||||
.notifyRow(requestType.id, matrix, row.id)
|
||||
.then(() => setNotifyResult({ message: texts.manageRequests.notifySuccess, kind: 'ok' }))
|
||||
.catch((e: Error) => setNotifyResult({ message: reportError(e, 'handleNotify: notifyRow'), kind: 'err' }))
|
||||
.finally(() => setNotifyingRowId(undefined));
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Breadcrumbs items={[{ label: texts.common.home }, { label: texts.manageRequests.breadcrumb }]} />
|
||||
@@ -522,6 +549,8 @@ export const ManageRequestsScreen: React.FC<IManageRequestsScreenProps> = ({ api
|
||||
statusVariant={statusVariant}
|
||||
onReassign={openReassign}
|
||||
onRemove={askDelete}
|
||||
onNotify={handleNotify}
|
||||
notifyingRowId={notifyingRowId}
|
||||
employees={employees.items}
|
||||
employeesLoading={employees.isLoading}
|
||||
addPlaceholder={texts.manageRequests.addApproverPlaceholder}
|
||||
@@ -536,6 +565,8 @@ export const ManageRequestsScreen: React.FC<IManageRequestsScreenProps> = ({ api
|
||||
statusVariant={statusVariant}
|
||||
onReassign={openReassign}
|
||||
onRemove={askDelete}
|
||||
onNotify={handleNotify}
|
||||
notifyingRowId={notifyingRowId}
|
||||
employees={employees.items}
|
||||
employeesLoading={employees.isLoading}
|
||||
addPlaceholder={texts.manageRequests.addExecutorPlaceholder}
|
||||
@@ -553,6 +584,7 @@ export const ManageRequestsScreen: React.FC<IManageRequestsScreenProps> = ({ api
|
||||
initialEmail={modal.approverEmail}
|
||||
employees={employees.items}
|
||||
employeesLoading={employees.isLoading}
|
||||
excludedEmails={reassignExcludedEmails}
|
||||
onSave={saveModal}
|
||||
onClose={closeModal}
|
||||
/>
|
||||
@@ -571,6 +603,14 @@ export const ManageRequestsScreen: React.FC<IManageRequestsScreenProps> = ({ api
|
||||
{saveError && (
|
||||
<Toast message={`${texts.manageRequests.saveError}: ${saveError}`} onClose={() => setSaveError(undefined)} />
|
||||
)}
|
||||
|
||||
{notifyResult && (
|
||||
<Toast
|
||||
message={notifyResult.kind === 'ok' ? notifyResult.message : `${texts.manageRequests.notifyError}: ${notifyResult.message}`}
|
||||
kind={notifyResult.kind}
|
||||
onClose={() => setNotifyResult(undefined)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user