frontend/app/Master/GuardianMaster.tsx (253 lines of code) (raw):
import React, { useEffect, useState } from "react";
import { Helmet } from "react-helmet";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
Divider,
makeStyles,
TextField,
Tooltip,
Typography,
} from "@material-ui/core";
import { RouteComponentProps, useHistory } from "react-router-dom";
import { validPrimaryTones, validProductionOffices } from "../utils/constants";
import FormSelect from "../Form/FormSelect";
import CommonMaster from "./CommonMaster";
import {
createGNMDeliverable,
deleteGNMDeliverable,
getDeliverableGNM,
requestResync,
resyncToPublished,
updateGNMDeliverable,
} from "../utils/master-api-service";
import {
SystemNotification,
SystemNotifcationKind,
} from "@guardian/pluto-headers";
import DeleteIcon from "@material-ui/icons/Delete";
import GuardianMasterForm from "./GuardianMasterForm";
import { metadataStyles } from "./MetadataStyles";
// const useStyles = makeStyles({
// root: {
// display: "flex",
// flexDirection: "column",
// alignItems: "center",
// "& form": {
// display: "flex",
// width: "100%",
// maxWidth: "800px",
// flexDirection: "column",
// alignItems: "flex-start",
// },
// "& .MuiAutocomplete-root": {
// width: "100%",
// },
// "& .MuiTextField-root": {
// width: "100%",
// marginBottom: "1rem",
// },
// "& .MuiFormControl-root": {
// width: "100%",
// marginBottom: "1rem",
// },
// "& .metadata-info": {
// width: "100%",
// "& .MuiTypography-subtitle1": {
// display: "inline-block",
// },
// "& a": {
// marginLeft: "10px",
// },
// },
// "& .MuiDivider-root": {
// marginTop: "3px",
// },
// "& .atom-tool-warning": {
// paddingTop: "20px",
// },
// },
// formButtons: {
// display: "flex",
// marginTop: "1rem",
// width: "100%",
// "& .cancel": {
// marginLeft: "1rem",
// },
// "& .delete": {
// marginLeft: "auto",
// },
// "& .resync": {
// marginLeft: "auto",
// },
// },
// dialog: {
// "& .MuiDialogActions-root.MuiDialogActions-spacing": {
// justifyContent: "flex-start",
// "& .MuiButtonBase-root.MuiButton-root.MuiButton-contained:not(.MuiButton-containedSecondary)": {
// marginLeft: "auto",
// },
// },
// },
// loading: {
// display: "flex",
// flexDirection: "column",
// width: "100%",
// alignItems: "center",
// },
// });
interface GuardianMasterProps
extends RouteComponentProps<{
projectid: string;
assetid: string;
}> {
isAdmin: boolean;
}
const GuardianMaster: React.FC<GuardianMasterProps> = (props) => {
const classes = metadataStyles();
const history = useHistory();
const [master, setMaster] = useState<GuardianMaster>({
upload_status: "",
production_office: "",
tags: [],
publication_date: "",
website_title: "",
website_description: "",
primary_tone: "",
publication_status: "",
});
const [isEditing, setIsEditing] = useState<boolean>(false);
const [isReadOnly, setIsReadOnly] = useState<boolean>(false);
const [isDirty, setIsDirty] = useState<boolean>(false);
const [openDialog, setOpenDialog] = useState<boolean>(false);
const [isLoading, setIsLoading] = useState<boolean>(false);
const { projectid, assetid } = props.match.params;
useEffect(() => {
setIsReadOnly(!props.isAdmin);
}, [props.isAdmin]);
useEffect(() => {
const loadGNMWebsite = async () => {
try {
const gnmDeliverable = await getDeliverableGNM(projectid, assetid);
setIsEditing(true);
setMaster(gnmDeliverable);
} catch (error) {
if (error) {
console.error("Failed to load GNM Deliverable", error);
}
}
setIsLoading(false);
};
setIsLoading(true);
loadGNMWebsite();
}, []);
const onProjectSubmit = async (
event: React.FormEvent<HTMLFormElement>
): Promise<void> => {
event.preventDefault();
setIsDirty(true);
const validForm = !!(master.production_office && master.website_title);
if (!validForm) {
console.warn("Could not submit the form because the form is invalid.");
return;
}
try {
if (isEditing) {
await updateGNMDeliverable(projectid, assetid, master);
SystemNotification.open(
SystemNotifcationKind.Success,
`Successfully Updated GNM Website!`
);
navigateBack();
} else {
await createGNMDeliverable(projectid, assetid, master);
SystemNotification.open(
SystemNotifcationKind.Success,
`Successfully Created GNM Website!`
);
navigateBack();
}
} catch (error) {
console.error(error);
SystemNotification.open(
SystemNotifcationKind.Error,
`Failed to ${isEditing ? "Update" : "Create"} GNM Website.`
);
}
};
const navigateBack = (): void => {
history.push(`/project/${projectid}`);
};
const deleteGNM = async () => {
try {
await deleteGNMDeliverable(projectid, assetid);
SystemNotification.open(
SystemNotifcationKind.Success,
`Successfully deleted website information`
);
navigateBack();
} catch (error) {
SystemNotification.open(
SystemNotifcationKind.Error,
`Failed to delete website information`
);
}
};
const closeDialog = () => {
setOpenDialog(false);
};
const fieldChanged = (
event: React.ChangeEvent<
| HTMLTextAreaElement
| HTMLInputElement
| HTMLSelectElement
| { name?: string; value: any }
>,
field: keyof GuardianMaster
): void => {
setMaster({ ...master, [field]: event.target.value });
};
const onCommonMasterChanged = (event: any, property: string) => {
if (property === "tags") {
setMaster({ ...master, tags: event });
return;
}
fieldChanged(event, property as keyof GuardianMaster);
};
if (isLoading) {
return (
<div className={classes.loading}>
<Typography variant="h4">Loading...</Typography>
</div>
);
}
return (
<>
<Helmet>
<title>
Website information{" "}
{master.website_title == "" ? "" : `– ${master.website_title}`}
</title>
</Helmet>
<form onSubmit={onProjectSubmit} noValidate autoComplete="off">
<Typography variant="h4">
{isEditing ? "Edit" : "Create"} GNM website
</Typography>
<GuardianMasterForm
isEditing={isEditing}
master={master}
isReadOnly={isReadOnly}
fieldChanged={fieldChanged}
isDirty={isDirty}
onCommonMasterChanged={onCommonMasterChanged}
/>
<div className={classes.formButtons}>
<Button
disabled={isReadOnly}
type="submit"
color="primary"
variant="contained"
>
{isEditing ? "Save" : "Create"}
</Button>
<Button
className="cancel"
variant="contained"
onClick={() => history.goBack()}
>
Cancel
</Button>
{!isReadOnly && isEditing && (
<Button
className="delete"
variant="contained"
color="secondary"
startIcon={<DeleteIcon />}
onClick={() => setOpenDialog(true)}
>
Delete
</Button>
)}
<Tooltip title="Update the GNM website data from the published atom">
<Button
className="resync"
variant="outlined"
onClick={() =>
requestResync(
props.match.params.projectid,
props.match.params.assetid
)
}
>
Resync
</Button>
</Tooltip>
</div>
</form>
<Dialog
className={classes.dialog}
open={openDialog}
onClose={closeDialog}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">Delete GNM Website</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Are you sure you want to delete this GNM Website?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
variant="contained"
color="secondary"
startIcon={<DeleteIcon />}
onClick={() => {
setOpenDialog(false);
deleteGNM();
}}
>
Delete
</Button>
<Button variant="contained" onClick={closeDialog}>
Cancel
</Button>
</DialogActions>
</Dialog>
</>
);
};
export default GuardianMaster;