Files
tnsu-approval-route/frontend/src/webparts/approvalAdmin/components/screens/RouteStepsScreen.tsx
T
2026-07-29 17:08:52 +05:00

149 lines
4.8 KiB
TypeScript

import * as React from 'react';
import { RouteStepFormModal } from './RouteStepFormModal';
import { ApprovalRouteApi } from '../../services/api';
import { RouteStepStatus, TemplateRoute, TemplateRouteStep } from '../../models';
import { routeStepStatusLabels, routeTypeLabels, texts } from '../../texts';
import { describeStepExecutor } from '../../utils/stepExecutor';
import { useRouteSteps } from '../../hooks/useRouteSteps';
import { useDeleteTarget } from '../../hooks/useDeleteTarget';
import {
ActionsCell,
Alert,
Badge,
Breadcrumbs,
Button,
ConfirmDialog,
DataTable,
IconButton,
PageHeader,
PrimaryCell
} from '../ui';
export interface IRouteStepsScreenProps {
api: ApprovalRouteApi;
route: TemplateRoute;
requestTypeName: string;
onBack: () => void;
}
export const RouteStepsScreen: React.FC<IRouteStepsScreenProps> = ({ api, route, requestTypeName, onBack }) => {
const steps = useRouteSteps(api, route.id);
const [savedWarning, setSavedWarning] = React.useState<string | undefined>();
const [editing, setEditing] = React.useState<TemplateRouteStep | undefined>();
const [showForm, setShowForm] = React.useState(false);
const deleteTarget = useDeleteTarget<TemplateRouteStep>(
item => api.templateRouteSteps.remove(route.id, item.id),
steps.reload
);
const openCreate = (): void => {
setEditing(undefined);
setShowForm(true);
};
const openEdit = (item: TemplateRouteStep): void => {
setEditing(item);
setShowForm(true);
};
const handleSaved = (savedStep: TemplateRouteStep): void => {
setSavedWarning(savedStep.warning ?? undefined);
steps.reload();
};
const nextOrderNo = steps.items.length > 0 ? Math.max(...steps.items.map(s => s.orderNo)) + 1 : 1;
return (
<div>
<Breadcrumbs
items={[
{ label: texts.common.home },
{ label: texts.routes.breadcrumb, onClick: onBack },
{ label: texts.routeSteps.breadcrumb(route.id) }
]}
/>
<PageHeader
icon="flag-check"
subtitle={texts.routeSteps.subtitle(requestTypeName, routeTypeLabels[route.routeType])}
title={texts.routeSteps.title(route.id)}
actions={
<>
<Button variant="ghost" icon="arrow-left" onClick={onBack}>{texts.routeSteps.back}</Button>
<Button variant="accent" icon="plus" onClick={openCreate}>{texts.routeSteps.add}</Button>
</>
}
/>
{savedWarning && <Alert kind="warn">{savedWarning}</Alert>}
{steps.error && <Alert kind="err">{steps.error}</Alert>}
{deleteTarget.error && <Alert kind="err">{deleteTarget.error}</Alert>}
<DataTable
columns={[
{ key: 'order', header: texts.routeSteps.columnOrderNo, width: '50px', render: r => r.orderNo },
{
key: 'executor',
header: texts.routeSteps.columnExecutor,
render: r => <PrimaryCell>{describeStepExecutor(r)}</PrimaryCell>
},
{
key: 'status',
header: texts.routeSteps.columnStatus,
render: r => (
<Badge variant={r.status === RouteStepStatus.Approval ? 'gold' : 'blue'}>
{routeStepStatusLabels[r.status]}
</Badge>
)
},
{
key: 'reassign',
header: texts.routeSteps.columnReassign,
align: 'center',
render: r => (r.allowReassignToOtherApprovers ? <Badge variant="ok">{texts.routeSteps.reassignAllowed}</Badge> : <Badge variant="neutral">{texts.common.no}</Badge>)
},
{
key: 'actions',
header: '',
width: '100px',
align: 'right',
sticky: true,
render: r => (
<ActionsCell>
<IconButton icon="edit" label={texts.common.edit} onClick={() => openEdit(r)} />
<IconButton icon="trash" label={texts.common.remove} danger onClick={() => deleteTarget.ask(r)} />
</ActionsCell>
)
}
]}
rows={steps.items}
keyOf={r => r.id}
emptyMessage={steps.isLoading ? texts.common.loading : texts.routeSteps.emptyList}
/>
{showForm && (
<RouteStepFormModal
api={api}
route={route}
editing={editing}
nextOrderNo={nextOrderNo}
onSaved={handleSaved}
onClose={() => setShowForm(false)}
/>
)}
{deleteTarget.target && (
<ConfirmDialog
title={texts.routeSteps.deleteTitle}
text={texts.routeSteps.deleteText(deleteTarget.target.orderNo)}
confirmLabel={texts.common.remove}
busy={deleteTarget.isBusy}
onCancel={deleteTarget.cancel}
onConfirm={deleteTarget.confirm}
/>
)}
</div>
);
};