/**
* Copyright (c) 2025-present, Goldman Sachs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { observer } from 'mobx-react-lite';
import {
Box,
Typography,
Stepper,
Step,
StepLabel,
StepConnector,
stepConnectorClasses,
} from '@mui/material';
import { styled } from '@mui/material/styles';
import {
CheckCircleIcon,
CircleIcon,
TimesCircleIcon,
} from '@finos/legend-art';
import type { TerminalProductOrder } from '@finos/legend-server-marketplace';
import {
getOrderProgressSteps,
getStageActionDetails,
formatTimestamp,
WorkflowStage,
OrderProgressStatus,
} from '../../stores/orders/OrderHelpers.js';
interface ProgressTrackerProps {
order: TerminalProductOrder;
}
const CustomConnector = styled(StepConnector)(({ theme }) => ({
[`&.${stepConnectorClasses.alternativeLabel}`]: {
top: 10,
left: 'calc(-50% + 16px)',
right: 'calc(50% + 16px)',
},
[`&.${stepConnectorClasses.active}`]: {
[`& .${stepConnectorClasses.line}`]: {
borderColor: theme.palette.primary.main,
},
},
[`&.${stepConnectorClasses.completed}`]: {
[`& .${stepConnectorClasses.line}`]: {
borderColor: theme.palette.primary.main,
},
},
[`& .${stepConnectorClasses.line}`]: {
borderColor: theme.palette.grey[400],
borderTopWidth: 2,
borderRadius: 1,
},
}));
const StepIconComponent = (props: {
active: boolean;
completed: boolean;
rejected?: boolean;
}): React.ReactElement => {
const { active, completed, rejected } = props;
if (rejected) {
return (
);
}
if (completed) {
return (
);
}
if (active) {
return (
);
}
return (
);
};
export const ProgressTracker: React.FC = observer(
({ order }) => {
const steps = getOrderProgressSteps(order);
const activeIndex = steps.findIndex(
(step) =>
step.status === OrderProgressStatus.ACTIVE ||
step.status === OrderProgressStatus.PENDING,
);
const stepperActiveIndex =
activeIndex >= 0 ? activeIndex : steps.length - 1;
return (
}
>
{steps.map((step) => {
const isCompleted = step.status === OrderProgressStatus.COMPLETED;
const isActive = step.status === OrderProgressStatus.ACTIVE;
const isRejected = step.status === OrderProgressStatus.REJECTED;
const details = getStageActionDetails(order, step.label);
const hasDetails =
details !== undefined &&
(details.actionedBy !== null ||
details.actionedTimestamp !== null ||
details.action !== null ||
details.comment !== null);
return (
StepIconComponent({
active: isActive,
completed: isCompleted,
rejected: isRejected,
})
}
>
{step.label}
{hasDetails && (
{details.actionedBy && (
Actioned by: {details.actionedBy}
)}
{details.actionedTimestamp && (
Date:{' '}
{formatTimestamp(details.actionedTimestamp)}
)}
{details.action && (
Action: {details.action}
)}
{details.comment && (
Comments: {details.comment}
)}
)}
{(step.label === WorkflowStage.PENDING_FULFILLMENT ||
step.label === WorkflowStage.ORDER_FULFILLED) &&
order.workflow_details?.rpm_ticket_id && (
RPM Ticket:{' '}
{order.workflow_details.rpm_ticket_id}
)}
);
})}
);
},
);