kandimat/redaktions-app/src/components/QuestionList.tsx
Christoph Lienhard fc8bc6724b
#11 Refactor: Introduce apollo reactive variables for global state
Use it to streamline entangle the delete dialog(s) from the list(s)
2020-12-30 18:26:19 +01:00

172 lines
6 KiB
TypeScript

import {Paper, Typography} from "@material-ui/core";
import React, {useState} from "react";
import {makeStyles} from "@material-ui/core/styles";
import {useMutation, useQuery} from "@apollo/client";
import AddCard from "./AddCard";
import AccordionWithEdit from "./AccordionWithEdit";
import {
BasicQuestionFragment,
BasicQuestionResponse,
GET_ALL_QUESTIONS,
GetAllQuestionsResponse
} from "../backend/queries/question";
import ChangeQuestionDialog, {ChangeQuestionDialogContent} from "./ChangeQuestionDialog";
import {GET_ALL_CATEGORIES, GetAllCategoriesResponse} from "../backend/queries/category";
import {
ADD_QUESTION,
AddQuestionResponse,
AddQuestionVariables,
EDIT_QUESTION,
EditQuestionResponse,
EditQuestionVariables
} from "../backend/mutations/question";
import {useSnackbar} from 'notistack';
import DeleteQuestionDialog, {deleteQuestionDialogId, deleteQuestionDialogOpen, deleteQuestionDialogTitle} from "./DeleteQuestionDialog";
const useStyles = makeStyles((theme) => ({
root: {
width: '100%',
padding: theme.spacing(1),
marginBottom: theme.spacing(3),
},
}));
const emptyChangeQuestionDialog: ChangeQuestionDialogContent = {
id: "",
title: "",
details: "",
categoryId: null,
}
export default function QuestionList() {
const [changeDialogOpen, setChangeDialogOpen] = useState(false);
const [dialogTitle, setDialogTitle] = useState("");
const [dialogConfirmButtonText, setDialogConfirmButtonText] = useState("");
const [changeDialogContent, setChangeDialogContent] = useState(emptyChangeQuestionDialog);
const {enqueueSnackbar} = useSnackbar();
const questions = useQuery<GetAllQuestionsResponse, null>(GET_ALL_QUESTIONS).data?.allQuestions.nodes;
const categories = useQuery<GetAllCategoriesResponse, null>(GET_ALL_CATEGORIES).data?.allCategories.nodes;
const [editQuestion, {loading: editLoading}] = useMutation<EditQuestionResponse, EditQuestionVariables>(EDIT_QUESTION, {
onError: (e) => enqueueSnackbar(`Ein Fehler ist aufgetreten: ${e.message}`, {variant: "error"}),
onCompleted: (response) => {
if (response.updateQuestion) {
enqueueSnackbar("Frage erfolgreich geändert.", {variant: "success"})
setChangeDialogOpen(false);
} else {
enqueueSnackbar("Ein Fehler ist aufgetreten, versuche es erneut.", {variant: "error"})
}
}
});
const [addQuestion, {loading: addLoading}] = useMutation<AddQuestionResponse, AddQuestionVariables>(ADD_QUESTION, {
onError: (e) => enqueueSnackbar(`Ein Fehler ist aufgetreten: ${e.message}`, {variant: "error"}),
onCompleted: (response) => {
if (response.createQuestion) {
enqueueSnackbar("Frage erfolgreich hinzugefügt.", {variant: "success"})
setChangeDialogOpen(false);
} else {
enqueueSnackbar("Ein Fehler ist aufgetreten, versuche es erneut.", {variant: "error"})
}
},
update: (cache, {data}) => {
cache.modify({
fields: {
allQuestions(existingQuestions = {nodes: []}) {
const newQuestionRef = cache.writeFragment<BasicQuestionResponse | undefined>({
data: data?.createQuestion?.question,
fragment: BasicQuestionFragment,
fragmentName: "BasicQuestionFragment",
});
return {nodes: [...existingQuestions.nodes, newQuestionRef]};
}
}
});
}
});
const classes = useStyles();
const loading = editLoading || addLoading;
const handleAddClick = () => {
setDialogTitle("Neue Frage erstellen");
setDialogConfirmButtonText("Erstellen");
if (changeDialogContent.id !== "") {
setChangeDialogContent(emptyChangeQuestionDialog);
}
setChangeDialogOpen(true);
}
const handleEditButtonClick = (question: BasicQuestionResponse) => {
setDialogTitle("Frage bearbeiten");
setDialogConfirmButtonText("Speichern")
if (changeDialogContent.id !== question.id) {
setChangeDialogContent({
id: question.id,
title: question.title,
details: question.description,
categoryId: question.categoryByCategoryRowId ? question.categoryByCategoryRowId.rowId : null,
})
}
setChangeDialogOpen(true);
};
const handleDeleteButtonClick = (question: BasicQuestionResponse) => {
deleteQuestionDialogTitle(question.title);
deleteQuestionDialogId(question.id);
deleteQuestionDialogOpen(true);
}
const handleDialogContentChange = (content: ChangeQuestionDialogContent) => {
setChangeDialogContent(content)
}
const handleChangeConfirmButtonClick = () => {
if (changeDialogContent.id !== "") {
editQuestion({
variables: {
id: changeDialogContent.id,
title: changeDialogContent.title,
description: changeDialogContent.details,
categoryRowId: changeDialogContent.categoryId,
}
})
} else {
addQuestion({
variables: {
title: changeDialogContent.title,
description: changeDialogContent.details,
categoryRowId: changeDialogContent.categoryId,
}
})
}
};
return (
<Paper className={classes.root}>
<Typography component={"h2"} variant="h6" color="primary" gutterBottom>Fragen</Typography>
{questions?.map(question => <AccordionWithEdit
key={question.id}
title={question.title}
subTitle={question.categoryByCategoryRowId?.title}
description={question.description}
onEditButtonClick={() => handleEditButtonClick(question)}
onDeleteButtonClick={() => handleDeleteButtonClick(question)}
/>
)}
<AddCard handleClick={handleAddClick}/>
<ChangeQuestionDialog
title={dialogTitle}
confirmButtonText={dialogConfirmButtonText}
open={changeDialogOpen}
content={changeDialogContent}
categories={categories}
loading={loading}
handleContentChange={handleDialogContentChange}
handleConfirmButtonClick={handleChangeConfirmButtonClick}
handleClose={() => setChangeDialogOpen(false)}
/>
<DeleteQuestionDialog/>
</Paper>
)
}