mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-14 00:19:16 +01:00
Feat/change request overview applied state (#2322)
* feat: review button * feat: add review button * fix: add to box * fix: separate function calls * fix: comment out reviewers * fix: type
This commit is contained in:
parent
147408045b
commit
d8db33ac7f
@ -22,7 +22,7 @@ export const ChangeRequestHeader: FC<{ changeRequest: IChangeRequest }> = ({
|
|||||||
<StyledHeader variant="h1">
|
<StyledHeader variant="h1">
|
||||||
Change request #{changeRequest.id}
|
Change request #{changeRequest.id}
|
||||||
</StyledHeader>
|
</StyledHeader>
|
||||||
<ChangeRequestStatusBadge state={changeRequest.state} />;
|
<ChangeRequestStatusBadge state={changeRequest.state} />
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
<StyledInnerContainer>
|
<StyledInnerContainer>
|
||||||
<Typography variant="body2" sx={{ margin: 'auto 0' }}>
|
<Typography variant="body2" sx={{ margin: 'auto 0' }}>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
import { styled } from '@mui/material';
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { Box, Button, Paper } from '@mui/material';
|
import { Box } from '@mui/material';
|
||||||
import { useChangeRequest } from 'hooks/api/getters/useChangeRequest/useChangeRequest';
|
import { useChangeRequest } from 'hooks/api/getters/useChangeRequest/useChangeRequest';
|
||||||
import { ChangeRequestHeader } from './ChangeRequestHeader/ChangeRequestHeader';
|
import { ChangeRequestHeader } from './ChangeRequestHeader/ChangeRequestHeader';
|
||||||
import { ChangeRequestTimeline } from './ChangeRequestTimeline/ChangeRequestTimeline';
|
import { ChangeRequestTimeline } from './ChangeRequestTimeline/ChangeRequestTimeline';
|
||||||
@ -10,11 +11,42 @@ import { useChangeRequestApi } from 'hooks/api/actions/useChangeRequestApi/useCh
|
|||||||
import { ChangeRequestReviewStatus } from './ChangeRequestReviewStatus/ChangeRequestReviewStatus';
|
import { ChangeRequestReviewStatus } from './ChangeRequestReviewStatus/ChangeRequestReviewStatus';
|
||||||
import useToast from 'hooks/useToast';
|
import useToast from 'hooks/useToast';
|
||||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||||
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
|
import Button from '@mui/material/Button';
|
||||||
|
import Paper from '@mui/material/Paper';
|
||||||
|
import { ReviewButton } from './ReviewButton/ReviewButton';
|
||||||
|
|
||||||
|
const StyledAsideBox = styled(Box)(({ theme }) => ({
|
||||||
|
width: '30%',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledPaper = styled(Paper)(({ theme }) => ({
|
||||||
|
marginTop: theme.spacing(2),
|
||||||
|
marginLeft: theme.spacing(2),
|
||||||
|
width: '70%',
|
||||||
|
padding: theme.spacing(1, 2),
|
||||||
|
borderRadius: theme.shape.borderRadiusLarge,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledButtonBox = styled(Box)(({ theme }) => ({
|
||||||
|
marginTop: theme.spacing(2),
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledInnerContainer = styled(Box)(({ theme }) => ({
|
||||||
|
padding: theme.spacing(2),
|
||||||
|
}));
|
||||||
|
|
||||||
export const ChangeRequestOverview: FC = () => {
|
export const ChangeRequestOverview: FC = () => {
|
||||||
const projectId = useRequiredPathParam('projectId');
|
const projectId = useRequiredPathParam('projectId');
|
||||||
const id = useRequiredPathParam('id');
|
const id = useRequiredPathParam('id');
|
||||||
const { data: changeRequest } = useChangeRequest(projectId, id);
|
const { data: changeRequest, refetchChangeRequest } = useChangeRequest(
|
||||||
|
projectId,
|
||||||
|
id
|
||||||
|
);
|
||||||
const { applyChanges } = useChangeRequestApi();
|
const { applyChanges } = useChangeRequestApi();
|
||||||
const { setToastData, setToastApiError } = useToast();
|
const { setToastData, setToastApiError } = useToast();
|
||||||
|
|
||||||
@ -25,10 +57,11 @@ export const ChangeRequestOverview: FC = () => {
|
|||||||
const onApplyChanges = async () => {
|
const onApplyChanges = async () => {
|
||||||
try {
|
try {
|
||||||
await applyChanges(projectId, id);
|
await applyChanges(projectId, id);
|
||||||
|
refetchChangeRequest();
|
||||||
setToastData({
|
setToastData({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
title: 'Success',
|
title: 'Success',
|
||||||
text: 'Changes appplied',
|
text: 'Changes applied',
|
||||||
});
|
});
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
setToastApiError(formatUnknownError(error));
|
setToastApiError(formatUnknownError(error));
|
||||||
@ -39,49 +72,36 @@ export const ChangeRequestOverview: FC = () => {
|
|||||||
<>
|
<>
|
||||||
<ChangeRequestHeader changeRequest={changeRequest} />
|
<ChangeRequestHeader changeRequest={changeRequest} />
|
||||||
<Box sx={{ display: 'flex' }}>
|
<Box sx={{ display: 'flex' }}>
|
||||||
<Box
|
<StyledAsideBox>
|
||||||
sx={{
|
|
||||||
width: '30%',
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ChangeRequestTimeline state={changeRequest.state} />
|
<ChangeRequestTimeline state={changeRequest.state} />
|
||||||
<ChangeRequestReviewers />
|
{/* <ChangeRequestReviewers /> */}
|
||||||
</Box>
|
</StyledAsideBox>
|
||||||
<Paper
|
<StyledPaper elevation={0}>
|
||||||
elevation={0}
|
<StyledInnerContainer>
|
||||||
sx={theme => ({
|
|
||||||
marginTop: theme.spacing(2),
|
|
||||||
marginLeft: theme.spacing(2),
|
|
||||||
width: '70%',
|
|
||||||
padding: 2,
|
|
||||||
borderRadius: theme =>
|
|
||||||
`${theme.shape.borderRadiusLarge}px`,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
sx={theme => ({
|
|
||||||
padding: theme.spacing(2),
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
Changes
|
Changes
|
||||||
<ChangeRequest changeRequest={changeRequest} />
|
<ChangeRequest changeRequest={changeRequest} />
|
||||||
<ChangeRequestReviewStatus
|
<ChangeRequestReviewStatus
|
||||||
approved={
|
state={changeRequest.state}
|
||||||
changeRequest.state === 'Approved' ||
|
|
||||||
changeRequest.state === 'Applied'
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<Button
|
<StyledButtonBox>
|
||||||
variant="contained"
|
<ConditionallyRender
|
||||||
sx={{ marginTop: 2 }}
|
condition={changeRequest.state === 'In review'}
|
||||||
onClick={onApplyChanges}
|
show={<ReviewButton />}
|
||||||
>
|
/>
|
||||||
Apply changes
|
<ConditionallyRender
|
||||||
</Button>
|
condition={changeRequest.state === 'Approved'}
|
||||||
</Box>
|
show={
|
||||||
</Paper>
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
onClick={onApplyChanges}
|
||||||
|
>
|
||||||
|
Apply changes
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</StyledButtonBox>
|
||||||
|
</StyledInnerContainer>
|
||||||
|
</StyledPaper>
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -3,7 +3,12 @@ import { Cancel, CheckCircle } from '@mui/icons-material';
|
|||||||
import { Box, Typography, Divider } from '@mui/material';
|
import { Box, Typography, Divider } from '@mui/material';
|
||||||
|
|
||||||
const styledComponentPropCheck = () => (prop: string) =>
|
const styledComponentPropCheck = () => (prop: string) =>
|
||||||
prop !== 'color' && prop !== 'sx' && prop !== 'approved';
|
prop !== 'color' &&
|
||||||
|
prop !== 'sx' &&
|
||||||
|
prop !== 'approved' &&
|
||||||
|
prop !== 'border' &&
|
||||||
|
prop !== 'bgColor' &&
|
||||||
|
prop !== 'svgColor';
|
||||||
|
|
||||||
export const StyledFlexAlignCenterBox = styled(Box)(({ theme }) => ({
|
export const StyledFlexAlignCenterBox = styled(Box)(({ theme }) => ({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -31,11 +36,9 @@ export const StyledOuterContainer = styled(Box)(({ theme }) => ({
|
|||||||
|
|
||||||
export const StyledButtonContainer = styled(Box, {
|
export const StyledButtonContainer = styled(Box, {
|
||||||
shouldForwardProp: styledComponentPropCheck(),
|
shouldForwardProp: styledComponentPropCheck(),
|
||||||
})<{ approved: boolean }>(({ theme, approved }) => ({
|
})<{ bgColor: string; svgColor: string }>(({ theme, bgColor, svgColor }) => ({
|
||||||
borderRadius: `${theme.shape.borderRadiusMedium}px`,
|
borderRadius: `${theme.shape.borderRadiusMedium}px`,
|
||||||
backgroundColor: approved
|
backgroundColor: bgColor,
|
||||||
? theme.palette.success.main
|
|
||||||
: theme.palette.tableHeaderBackground,
|
|
||||||
padding: theme.spacing(1, 2),
|
padding: theme.spacing(1, 2),
|
||||||
marginRight: theme.spacing(2),
|
marginRight: theme.spacing(2),
|
||||||
height: '45px',
|
height: '45px',
|
||||||
@ -44,9 +47,7 @@ export const StyledButtonContainer = styled(Box, {
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
['svg']: {
|
['svg']: {
|
||||||
color: approved
|
color: svgColor,
|
||||||
? theme.palette.tertiary.background
|
|
||||||
: theme.palette.neutral.main,
|
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -56,18 +57,16 @@ export const StyledDivider = styled(Divider)(({ theme }) => ({
|
|||||||
|
|
||||||
export const StyledReviewStatusContainer = styled(Box, {
|
export const StyledReviewStatusContainer = styled(Box, {
|
||||||
shouldForwardProp: styledComponentPropCheck(),
|
shouldForwardProp: styledComponentPropCheck(),
|
||||||
})<{ approved: boolean }>(({ theme, approved }) => ({
|
})<{ border: string }>(({ theme, border }) => ({
|
||||||
borderRadius: `${theme.shape.borderRadiusLarge}px`,
|
borderRadius: `${theme.shape.borderRadiusLarge}px`,
|
||||||
border: approved
|
border: border,
|
||||||
? `2px solid ${theme.palette.success.main}`
|
|
||||||
: `1px solid ${theme.palette.tertiary.main}`,
|
|
||||||
padding: theme.spacing(3),
|
padding: theme.spacing(3),
|
||||||
width: '100%',
|
width: '100%',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const StyledReviewTitle = styled(Typography, {
|
export const StyledReviewTitle = styled(Typography, {
|
||||||
shouldForwardProp: styledComponentPropCheck(),
|
shouldForwardProp: styledComponentPropCheck(),
|
||||||
})<{ approved: boolean }>(({ theme, approved }) => ({
|
})<{ color: string }>(({ theme, color }) => ({
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
color: approved ? theme.palette.success.main : theme.palette.error.main,
|
color,
|
||||||
}));
|
}));
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { Box, Typography } from '@mui/material';
|
import { Box, Theme, Typography, useTheme } from '@mui/material';
|
||||||
import { ReactComponent as ChangesAppliedIcon } from 'assets/icons/merge.svg';
|
import { ReactComponent as ChangesAppliedIcon } from 'assets/icons/merge.svg';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
|
||||||
import {
|
import {
|
||||||
StyledOuterContainer,
|
StyledOuterContainer,
|
||||||
StyledButtonContainer,
|
StyledButtonContainer,
|
||||||
@ -12,40 +11,98 @@ import {
|
|||||||
StyledReviewTitle,
|
StyledReviewTitle,
|
||||||
StyledDivider,
|
StyledDivider,
|
||||||
} from './ChangeRequestReviewStatus.styles';
|
} from './ChangeRequestReviewStatus.styles';
|
||||||
|
import { ChangeRequestState } from 'component/changeRequest/changeRequest.types';
|
||||||
interface ISuggestChangeReviewsStatusProps {
|
interface ISuggestChangeReviewsStatusProps {
|
||||||
approved: boolean;
|
state: ChangeRequestState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const resolveBorder = (state: ChangeRequestState, theme: Theme) => {
|
||||||
|
if (state === 'Approved') {
|
||||||
|
return `2px solid ${theme.palette.success.main}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state === 'Applied') {
|
||||||
|
return `2px solid ${theme.palette.primary.main}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `1px solid ${theme.palette.tertiary.main}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const resolveIconColors = (state: ChangeRequestState, theme: Theme) => {
|
||||||
|
if (state === 'Approved') {
|
||||||
|
return {
|
||||||
|
bgColor: theme.palette.success.main!,
|
||||||
|
svgColor: theme.palette.tertiary.background,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state === 'Applied') {
|
||||||
|
return {
|
||||||
|
bgColor: theme.palette.primary.main!,
|
||||||
|
svgColor: theme.palette.tertiary.background,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
bgColor: theme.palette.tableHeaderBackground,
|
||||||
|
svgColor: theme.palette.neutral.main!,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const ChangeRequestReviewStatus: FC<
|
export const ChangeRequestReviewStatus: FC<
|
||||||
ISuggestChangeReviewsStatusProps
|
ISuggestChangeReviewsStatusProps
|
||||||
> = ({ approved }) => {
|
> = ({ state }) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledOuterContainer>
|
<StyledOuterContainer>
|
||||||
<StyledButtonContainer approved={approved}>
|
<StyledButtonContainer {...resolveIconColors(state, theme)}>
|
||||||
<ChangesAppliedIcon
|
<ChangesAppliedIcon
|
||||||
style={{
|
style={{
|
||||||
transform: `scale(1.5)`,
|
transform: `scale(1.5)`,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</StyledButtonContainer>
|
</StyledButtonContainer>
|
||||||
<StyledReviewStatusContainer approved={approved}>
|
<StyledReviewStatusContainer border={resolveBorder(state, theme)}>
|
||||||
<ConditionallyRender
|
<ResolveComponent state={state} />
|
||||||
condition={approved}
|
|
||||||
show={<Approved approved={approved} />}
|
|
||||||
elseShow={<ReviewRequired approved={approved} />}
|
|
||||||
/>
|
|
||||||
</StyledReviewStatusContainer>
|
</StyledReviewStatusContainer>
|
||||||
</StyledOuterContainer>
|
</StyledOuterContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const Approved = ({ approved }: ISuggestChangeReviewsStatusProps) => {
|
interface IResolveComponentProps {
|
||||||
|
state: ChangeRequestState;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ResolveComponent = ({ state }: IResolveComponentProps) => {
|
||||||
|
if (!state) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state === 'Approved') {
|
||||||
|
return <Approved />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state === 'Applied') {
|
||||||
|
return <Applied />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state === 'Cancelled') {
|
||||||
|
return <Cancelled />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <ReviewRequired />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Approved = () => {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StyledFlexAlignCenterBox>
|
<StyledFlexAlignCenterBox>
|
||||||
<StyledSuccessIcon />
|
<StyledSuccessIcon />
|
||||||
<Box>
|
<Box>
|
||||||
<StyledReviewTitle approved={approved}>
|
<StyledReviewTitle color={theme.palette.success.main}>
|
||||||
Changed approved
|
Changed approved
|
||||||
</StyledReviewTitle>
|
</StyledReviewTitle>
|
||||||
<Typography>
|
<Typography>
|
||||||
@ -59,7 +116,7 @@ const Approved = ({ approved }: ISuggestChangeReviewsStatusProps) => {
|
|||||||
<StyledFlexAlignCenterBox>
|
<StyledFlexAlignCenterBox>
|
||||||
<StyledSuccessIcon />
|
<StyledSuccessIcon />
|
||||||
<Box>
|
<Box>
|
||||||
<StyledReviewTitle approved={approved}>
|
<StyledReviewTitle color={theme.palette.success.main}>
|
||||||
Changes are ready to be applied
|
Changes are ready to be applied
|
||||||
</StyledReviewTitle>
|
</StyledReviewTitle>
|
||||||
</Box>
|
</Box>
|
||||||
@ -68,13 +125,15 @@ const Approved = ({ approved }: ISuggestChangeReviewsStatusProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const ReviewRequired = ({ approved }: ISuggestChangeReviewsStatusProps) => {
|
const ReviewRequired = () => {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StyledFlexAlignCenterBox>
|
<StyledFlexAlignCenterBox>
|
||||||
<StyledErrorIcon />
|
<StyledErrorIcon />
|
||||||
<Box>
|
<Box>
|
||||||
<StyledReviewTitle approved={approved}>
|
<StyledReviewTitle color={theme.palette.error.main}>
|
||||||
Review required
|
Review required
|
||||||
</StyledReviewTitle>
|
</StyledReviewTitle>
|
||||||
<Typography>
|
<Typography>
|
||||||
@ -88,10 +147,44 @@ const ReviewRequired = ({ approved }: ISuggestChangeReviewsStatusProps) => {
|
|||||||
|
|
||||||
<StyledFlexAlignCenterBox>
|
<StyledFlexAlignCenterBox>
|
||||||
<StyledErrorIcon />
|
<StyledErrorIcon />
|
||||||
<StyledReviewTitle approved={approved}>
|
<StyledReviewTitle color={theme.palette.error.main}>
|
||||||
Apply changes is blocked
|
Apply changes is blocked
|
||||||
</StyledReviewTitle>
|
</StyledReviewTitle>
|
||||||
</StyledFlexAlignCenterBox>
|
</StyledFlexAlignCenterBox>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Applied = () => {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<StyledFlexAlignCenterBox>
|
||||||
|
<StyledSuccessIcon sx={{ color: theme.palette.primary.main }} />
|
||||||
|
<Box>
|
||||||
|
<StyledReviewTitle color={theme.palette.primary.main}>
|
||||||
|
Changes applied
|
||||||
|
</StyledReviewTitle>
|
||||||
|
</Box>
|
||||||
|
</StyledFlexAlignCenterBox>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Cancelled = () => {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<StyledFlexAlignCenterBox>
|
||||||
|
<StyledErrorIcon />
|
||||||
|
<Box>
|
||||||
|
<StyledReviewTitle color={theme.palette.error.main}>
|
||||||
|
Changes cancelled
|
||||||
|
</StyledReviewTitle>
|
||||||
|
</Box>
|
||||||
|
</StyledFlexAlignCenterBox>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
@ -0,0 +1,132 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
||||||
|
import { useChangeRequest } from 'hooks/api/getters/useChangeRequest/useChangeRequest';
|
||||||
|
import { useChangeRequestApi } from 'hooks/api/actions/useChangeRequestApi/useChangeRequestApi';
|
||||||
|
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||||
|
import useToast from 'hooks/useToast';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Grow,
|
||||||
|
Paper,
|
||||||
|
Popper,
|
||||||
|
MenuItem,
|
||||||
|
MenuList,
|
||||||
|
ClickAwayListener,
|
||||||
|
} from '@mui/material';
|
||||||
|
|
||||||
|
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
|
||||||
|
|
||||||
|
export const ReviewButton = () => {
|
||||||
|
const projectId = useRequiredPathParam('projectId');
|
||||||
|
const id = useRequiredPathParam('id');
|
||||||
|
const { refetchChangeRequest } = useChangeRequest(projectId, id);
|
||||||
|
const { setToastApiError, setToastData } = useToast();
|
||||||
|
|
||||||
|
const { changeState } = useChangeRequestApi();
|
||||||
|
|
||||||
|
const [open, setOpen] = React.useState(false);
|
||||||
|
const anchorRef = React.useRef<HTMLButtonElement>(null);
|
||||||
|
|
||||||
|
const onApprove = async () => {
|
||||||
|
try {
|
||||||
|
await changeState(projectId, Number(id), {
|
||||||
|
state: 'Approved',
|
||||||
|
});
|
||||||
|
refetchChangeRequest();
|
||||||
|
setToastData({
|
||||||
|
type: 'success',
|
||||||
|
title: 'Success',
|
||||||
|
text: 'Changes approved',
|
||||||
|
});
|
||||||
|
} catch (error: unknown) {
|
||||||
|
setToastApiError(formatUnknownError(error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onReject = async () => {
|
||||||
|
try {
|
||||||
|
await changeState(projectId, Number(id), {
|
||||||
|
state: 'Cancelled',
|
||||||
|
});
|
||||||
|
refetchChangeRequest();
|
||||||
|
setToastData({
|
||||||
|
type: 'success',
|
||||||
|
title: 'Success',
|
||||||
|
text: 'Changes rejected',
|
||||||
|
});
|
||||||
|
} catch (error: unknown) {
|
||||||
|
setToastApiError(formatUnknownError(error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onToggle = () => {
|
||||||
|
setOpen(prevOpen => !prevOpen);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onClose = (event: Event) => {
|
||||||
|
if (
|
||||||
|
anchorRef.current &&
|
||||||
|
anchorRef.current.contains(event.target as HTMLElement)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
aria-controls={open ? 'review-options-menu' : undefined}
|
||||||
|
aria-expanded={open ? 'true' : undefined}
|
||||||
|
aria-label="review changes"
|
||||||
|
aria-haspopup="menu"
|
||||||
|
onClick={onToggle}
|
||||||
|
ref={anchorRef}
|
||||||
|
endIcon={<ArrowDropDownIcon />}
|
||||||
|
>
|
||||||
|
Review changes
|
||||||
|
</Button>
|
||||||
|
<Popper
|
||||||
|
sx={{
|
||||||
|
zIndex: 1,
|
||||||
|
}}
|
||||||
|
open={open}
|
||||||
|
anchorEl={anchorRef.current}
|
||||||
|
role={undefined}
|
||||||
|
transition
|
||||||
|
disablePortal
|
||||||
|
>
|
||||||
|
{({ TransitionProps, placement }) => (
|
||||||
|
<Grow
|
||||||
|
{...TransitionProps}
|
||||||
|
style={{
|
||||||
|
transformOrigin:
|
||||||
|
placement === 'bottom'
|
||||||
|
? 'center top'
|
||||||
|
: 'center bottom',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Paper>
|
||||||
|
<ClickAwayListener onClickAway={onClose}>
|
||||||
|
<MenuList
|
||||||
|
id="review-options-menu"
|
||||||
|
autoFocusItem
|
||||||
|
>
|
||||||
|
<MenuItem onClick={onApprove}>
|
||||||
|
Approve changes
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem onClick={onReject}>
|
||||||
|
Reject changes
|
||||||
|
</MenuItem>
|
||||||
|
</MenuList>
|
||||||
|
</ClickAwayListener>
|
||||||
|
</Paper>
|
||||||
|
</Grow>
|
||||||
|
)}
|
||||||
|
</Popper>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
};
|
@ -35,10 +35,7 @@ export const ChangeRequestStatusBadge: VFC<IChangeRequestStatusBadgeProps> = ({
|
|||||||
);
|
);
|
||||||
case 'Cancelled':
|
case 'Cancelled':
|
||||||
return (
|
return (
|
||||||
<Badge
|
<Badge color="error" icon={<Close fontSize={'small'} />}>
|
||||||
color="error"
|
|
||||||
icon={<Close fontSize={'small'} sx={{ mr: 8 }} />}
|
|
||||||
>
|
|
||||||
Cancelled
|
Cancelled
|
||||||
</Badge>
|
</Badge>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user