frontend/app/CreateBundle/CreateBundleDialogContent.tsx (204 lines of code) (raw):
import React, { useEffect, useState } from "react";
import { parseISO } from "date-fns";
import axios from "axios";
import {
Button,
CircularProgress,
Dialog,
DialogActions,
DialogContent,
Typography,
} from "@material-ui/core";
import { Check } from "@material-ui/icons";
import CustomDialogTitle from "../CustomDialogTitle";
import { useHistory } from "react-router-dom";
import { Alert } from "@material-ui/lab";
import { format } from "date-fns/fp";
import { createProjectDeliverable } from "./CreateBundleService";
interface CreateBundleDialogContentProps {
projectid: number;
didComplete: () => void;
}
const CreateBundleDialogContent: React.FC<CreateBundleDialogContentProps> = (
props
) => {
const [projectTitle, setProjectTitle] = useState<string | undefined>(
undefined
);
const [projectStatus, setProjectStatus] = useState<string | undefined>(
undefined
);
const [projectCreated, setProjectCreated] = useState<Date | undefined>(
undefined
);
const [projectOwner, setProjectOwner] = useState<string | undefined>(
undefined
);
const [projectCommission, setProjectCommission] = useState<
number | undefined
>(undefined);
const [lastError, setLastError] = useState<string | undefined>(undefined);
const [canComplete, setCanComplete] = useState(false);
const [loading, setLoading] = useState(true);
const history = useHistory();
const safeDate = (from: string): Date | undefined => {
try {
return parseISO(from);
} catch (err) {
console.error("Date string ", from, " could not be parsed: ", err);
return undefined;
}
};
const formattedCreateTime = (): string => {
if (projectCreated) {
try {
return format("E do LLL yyyy", projectCreated);
} catch (err) {
console.error("could not format date ", projectCreated, ": ", err);
return "(unknown)";
}
} else {
return "(unknown)";
}
};
//validate that we have the right information for the create bundle call to succeed, and if so allow the user to complete
useEffect(() => {
const newValue =
props.projectid !== undefined &&
projectTitle !== undefined &&
projectCommission !== undefined;
console.log(`checking if we have enough data: ${newValue}...`);
if (!canComplete && newValue) {
console.log("all values present to create a bundle");
setLastError(undefined);
setCanComplete(newValue);
}
if (!newValue && !lastError) {
console.info(
"can't create a bundle as some data is missing: projectid=",
props.projectid,
" projectTitle=",
projectTitle,
" projectCommission=",
projectCommission
);
setLastError(
"Did not get the right data from pluto-core. Please report this to multimediatech."
);
setCanComplete(false);
}
}, [projectTitle, projectCommission, props.projectid]);
const loadProjectInfo = async () => {
setLoading(true);
try {
const response = await axios.get(
`/pluto-core/api/project/${props.projectid}`
);
if (response.data && response.data.result) {
setProjectTitle(response.data.result.title);
setProjectStatus(response.data.result.status);
setProjectCreated(safeDate(response.data.result.created));
setProjectOwner(response.data.result.user);
setProjectCommission(response.data.result.commissionId);
} else {
setLastError(
"Could not understand server response, please report this to multimediatech"
);
}
setLoading(false);
} catch (err) {
setLoading(false);
if (err.response) {
switch (err.response.status) {
case 404:
setLastError("This project does not exist");
break;
case 502 | 503 | 504:
setLastError("pluto-core is not responding, retrying...");
window.setTimeout(() => loadProjectInfo(), 3000);
break;
default:
if (err.response && err.response.data && err.response.data.detail) {
setLastError(
`There was a server error: ${err.response.data.detail}, please go back and try again.`
);
} else {
setLastError(
`There was a server error, please go back and try again.`
);
}
console.log(
"pluto-core responded with ",
err.response.status,
": ",
err.response.data
);
break;
}
}
}
};
useEffect(() => {
loadProjectInfo();
}, [props.projectid]);
const createBundle = () => {
if (projectCommission && projectTitle) {
createProjectDeliverable(props.projectid, projectCommission, projectTitle)
.then((_) => props.didComplete())
.catch((err) => {
console.error("could not complete bundle creation: ", err);
setLastError("Deliverable bundle create failed, please try again.");
});
} else {
setLastError(
"Did not have enough information to complete, this is a bug."
);
}
};
return (
<>
<CustomDialogTitle
id="create-bundle-title"
onClose={() => history.goBack()}
>
Add deliverables to project
</CustomDialogTitle>
<DialogContent>
{loading ? (
<CircularProgress id="spinner" />
) : (
<>
{lastError ? (
<Alert severity="error" id="error-text">
{lastError}
</Alert>
) : (
<>
<Typography>
You are about to add deliverables to {projectTitle} for the
first time. Are you sure you want to continue?
</Typography>
<Typography>
This project is currently {projectStatus} and was created by{" "}
{projectOwner} on {formattedCreateTime()}
</Typography>
</>
)}
</>
)}
</DialogContent>
<DialogActions>
<Button variant="outlined" onClick={() => history.goBack()}>
Go back
</Button>
<Button
id="create-button"
variant="contained"
color="primary"
disabled={!canComplete}
startIcon={<Check />}
onClick={createBundle}
>
Create
</Button>
</DialogActions>
</>
);
};
export default CreateBundleDialogContent;