diff --git a/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestHeader/ChangeRequestHeader.tsx b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestHeader/ChangeRequestHeader.tsx
index 90073d82f3..dad381f18f 100644
--- a/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestHeader/ChangeRequestHeader.tsx
+++ b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestHeader/ChangeRequestHeader.tsx
@@ -22,7 +22,7 @@ export const ChangeRequestHeader: FC<{ changeRequest: IChangeRequest }> = ({
Change request #{changeRequest.id}
- ;
+
diff --git a/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestOverview.tsx b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestOverview.tsx
index cea58f9821..4dbbfc9a0e 100644
--- a/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestOverview.tsx
+++ b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestOverview.tsx
@@ -1,5 +1,6 @@
+import { styled } from '@mui/material';
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 { ChangeRequestHeader } from './ChangeRequestHeader/ChangeRequestHeader';
import { ChangeRequestTimeline } from './ChangeRequestTimeline/ChangeRequestTimeline';
@@ -10,11 +11,42 @@ import { useChangeRequestApi } from 'hooks/api/actions/useChangeRequestApi/useCh
import { ChangeRequestReviewStatus } from './ChangeRequestReviewStatus/ChangeRequestReviewStatus';
import useToast from 'hooks/useToast';
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 = () => {
const projectId = useRequiredPathParam('projectId');
const id = useRequiredPathParam('id');
- const { data: changeRequest } = useChangeRequest(projectId, id);
+ const { data: changeRequest, refetchChangeRequest } = useChangeRequest(
+ projectId,
+ id
+ );
const { applyChanges } = useChangeRequestApi();
const { setToastData, setToastApiError } = useToast();
@@ -25,10 +57,11 @@ export const ChangeRequestOverview: FC = () => {
const onApplyChanges = async () => {
try {
await applyChanges(projectId, id);
+ refetchChangeRequest();
setToastData({
type: 'success',
title: 'Success',
- text: 'Changes appplied',
+ text: 'Changes applied',
});
} catch (error: unknown) {
setToastApiError(formatUnknownError(error));
@@ -39,49 +72,36 @@ export const ChangeRequestOverview: FC = () => {
<>
-
+
-
-
- ({
- marginTop: theme.spacing(2),
- marginLeft: theme.spacing(2),
- width: '70%',
- padding: 2,
- borderRadius: theme =>
- `${theme.shape.borderRadiusLarge}px`,
- })}
- >
- ({
- padding: theme.spacing(2),
- })}
- >
+ {/* */}
+
+
+
Changes
-
-
-
+
+ }
+ />
+
+ Apply changes
+
+ }
+ />
+
+
+
>
);
diff --git a/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestReviewStatus/ChangeRequestReviewStatus.styles.ts b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestReviewStatus/ChangeRequestReviewStatus.styles.ts
index 55081e7e59..31c0fcc432 100644
--- a/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestReviewStatus/ChangeRequestReviewStatus.styles.ts
+++ b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestReviewStatus/ChangeRequestReviewStatus.styles.ts
@@ -3,7 +3,12 @@ import { Cancel, CheckCircle } from '@mui/icons-material';
import { Box, Typography, Divider } from '@mui/material';
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 }) => ({
display: 'flex',
@@ -31,11 +36,9 @@ export const StyledOuterContainer = styled(Box)(({ theme }) => ({
export const StyledButtonContainer = styled(Box, {
shouldForwardProp: styledComponentPropCheck(),
-})<{ approved: boolean }>(({ theme, approved }) => ({
+})<{ bgColor: string; svgColor: string }>(({ theme, bgColor, svgColor }) => ({
borderRadius: `${theme.shape.borderRadiusMedium}px`,
- backgroundColor: approved
- ? theme.palette.success.main
- : theme.palette.tableHeaderBackground,
+ backgroundColor: bgColor,
padding: theme.spacing(1, 2),
marginRight: theme.spacing(2),
height: '45px',
@@ -44,9 +47,7 @@ export const StyledButtonContainer = styled(Box, {
alignItems: 'center',
justifyContent: 'center',
['svg']: {
- color: approved
- ? theme.palette.tertiary.background
- : theme.palette.neutral.main,
+ color: svgColor,
},
}));
@@ -56,18 +57,16 @@ export const StyledDivider = styled(Divider)(({ theme }) => ({
export const StyledReviewStatusContainer = styled(Box, {
shouldForwardProp: styledComponentPropCheck(),
-})<{ approved: boolean }>(({ theme, approved }) => ({
+})<{ border: string }>(({ theme, border }) => ({
borderRadius: `${theme.shape.borderRadiusLarge}px`,
- border: approved
- ? `2px solid ${theme.palette.success.main}`
- : `1px solid ${theme.palette.tertiary.main}`,
+ border: border,
padding: theme.spacing(3),
width: '100%',
}));
export const StyledReviewTitle = styled(Typography, {
shouldForwardProp: styledComponentPropCheck(),
-})<{ approved: boolean }>(({ theme, approved }) => ({
+})<{ color: string }>(({ theme, color }) => ({
fontWeight: 'bold',
- color: approved ? theme.palette.success.main : theme.palette.error.main,
+ color,
}));
diff --git a/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestReviewStatus/ChangeRequestReviewStatus.tsx b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestReviewStatus/ChangeRequestReviewStatus.tsx
index b8e87ad0a1..533759ba32 100644
--- a/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestReviewStatus/ChangeRequestReviewStatus.tsx
+++ b/frontend/src/component/changeRequest/ChangeRequestOverview/ChangeRequestReviewStatus/ChangeRequestReviewStatus.tsx
@@ -1,7 +1,6 @@
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 { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import {
StyledOuterContainer,
StyledButtonContainer,
@@ -12,40 +11,98 @@ import {
StyledReviewTitle,
StyledDivider,
} from './ChangeRequestReviewStatus.styles';
+import { ChangeRequestState } from 'component/changeRequest/changeRequest.types';
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<
ISuggestChangeReviewsStatusProps
-> = ({ approved }) => {
+> = ({ state }) => {
+ const theme = useTheme();
+
return (
-
+
-
- }
- elseShow={}
- />
+
+
);
};
-const Approved = ({ approved }: ISuggestChangeReviewsStatusProps) => {
+interface IResolveComponentProps {
+ state: ChangeRequestState;
+}
+
+const ResolveComponent = ({ state }: IResolveComponentProps) => {
+ if (!state) {
+ return null;
+ }
+
+ if (state === 'Approved') {
+ return ;
+ }
+
+ if (state === 'Applied') {
+ return ;
+ }
+
+ if (state === 'Cancelled') {
+ return ;
+ }
+
+ return ;
+};
+
+const Approved = () => {
+ const theme = useTheme();
+
return (
<>
-
+
Changed approved
@@ -59,7 +116,7 @@ const Approved = ({ approved }: ISuggestChangeReviewsStatusProps) => {
-
+
Changes are ready to be applied
@@ -68,13 +125,15 @@ const Approved = ({ approved }: ISuggestChangeReviewsStatusProps) => {
);
};
-const ReviewRequired = ({ approved }: ISuggestChangeReviewsStatusProps) => {
+const ReviewRequired = () => {
+ const theme = useTheme();
+
return (
<>
-
+
Review required
@@ -88,10 +147,44 @@ const ReviewRequired = ({ approved }: ISuggestChangeReviewsStatusProps) => {
-
+
Apply changes is blocked
>
);
};
+
+const Applied = () => {
+ const theme = useTheme();
+
+ return (
+ <>
+
+
+
+
+ Changes applied
+
+
+
+ >
+ );
+};
+
+const Cancelled = () => {
+ const theme = useTheme();
+
+ return (
+ <>
+
+
+
+
+ Changes cancelled
+
+
+
+ >
+ );
+};
diff --git a/frontend/src/component/changeRequest/ChangeRequestOverview/ReviewButton/ReviewButton.tsx b/frontend/src/component/changeRequest/ChangeRequestOverview/ReviewButton/ReviewButton.tsx
new file mode 100644
index 0000000000..3c4af76c49
--- /dev/null
+++ b/frontend/src/component/changeRequest/ChangeRequestOverview/ReviewButton/ReviewButton.tsx
@@ -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(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 (
+
+ }
+ >
+ Review changes
+
+
+ {({ TransitionProps, placement }) => (
+
+
+
+
+
+
+
+ )}
+
+
+ );
+};
diff --git a/frontend/src/component/changeRequest/ChangeRequestStatusBadge/ChangeRequestStatusBadge.tsx b/frontend/src/component/changeRequest/ChangeRequestStatusBadge/ChangeRequestStatusBadge.tsx
index 26ddd79145..13e7d7ec08 100644
--- a/frontend/src/component/changeRequest/ChangeRequestStatusBadge/ChangeRequestStatusBadge.tsx
+++ b/frontend/src/component/changeRequest/ChangeRequestStatusBadge/ChangeRequestStatusBadge.tsx
@@ -35,10 +35,7 @@ export const ChangeRequestStatusBadge: VFC = ({
);
case 'Cancelled':
return (
- }
- >
+ }>
Cancelled
);