kandimat/redaktions-app/src/components/EditAnswerSection.tsx
2021-06-13 12:55:54 +02:00

160 lines
4.7 KiB
TypeScript

import React from "react";
import { CandidatePosition } from "./CandidatePositionLegend";
import { useMutation, useQuery } from "@apollo/client";
import {
FullAnswerResponse,
GET_ANSWER_BY_QUESTION_AND_PERSON,
GetAnswerByQuestionAndPersonResponse,
GetAnswerByQuestionAndPersonVariables,
QuestionAnswerResponse,
} from "../backend/queries/answer";
import { useSnackbar } from "notistack";
import {
ADD_ANSWER,
AddAnswerResponse,
AddAnswerVariables,
EDIT_ANSWER,
EditAnswerResponse,
EditAnswerVariables,
updateCacheAfterAddingAnswer,
} from "../backend/mutations/answer";
import ToggleButtonGroupAnswerPosition from "./ToggleButtonGroupAnswerPosition";
import EditAnswerText from "./EditAnswerText";
interface EditAnswerSectionProps {
loggedInPersonRowId: number;
question: QuestionAnswerResponse;
}
export default function EditAnswerSection(
props: EditAnswerSectionProps
): React.ReactElement {
const { enqueueSnackbar } = useSnackbar();
const { data } = useQuery<
GetAnswerByQuestionAndPersonResponse,
GetAnswerByQuestionAndPersonVariables
>(GET_ANSWER_BY_QUESTION_AND_PERSON, {
variables: {
personRowId: props.loggedInPersonRowId,
questionRowId: props.question.rowId,
},
});
const remoteAnswer = data?.answerByQuestionRowIdAndPersonRowId;
const [editAnswer, { loading: editAnswerLoading }] = useMutation<
EditAnswerResponse,
EditAnswerVariables
>(EDIT_ANSWER, {
onError: (e) =>
enqueueSnackbar(`Ein Fehler ist aufgetreten: ${e.message}`, {
variant: "error",
}),
});
const [addAnswer, { loading: addAnswerLoading }] = useMutation<
AddAnswerResponse,
AddAnswerVariables
>(ADD_ANSWER, {
onError: (e) =>
enqueueSnackbar(`Ein Fehler ist aufgetreten: ${e.message}`, {
variant: "error",
}),
update: (cache, fetchResult) =>
updateCacheAfterAddingAnswer(cache, fetchResult, props.question),
});
const parsePosition = (position?: CandidatePosition): CandidatePosition => {
return position !== undefined ? position : CandidatePosition.skipped;
};
const changeAnswer = async (
position?: CandidatePosition,
text?: string
): Promise<FullAnswerResponse | undefined> => {
if (remoteAnswer) {
const optimisticResponseAnswer = {
...remoteAnswer,
...(position !== undefined && { position }),
...(text !== undefined && { text }),
};
const response = await editAnswer({
variables: {
id: remoteAnswer.id,
position,
text,
},
optimisticResponse: {
updateAnswer: {
__typename: "UpdateAnswerPayload",
answer: optimisticResponseAnswer,
},
},
});
return response.data?.updateAnswer?.answer;
} else {
const savePosition = parsePosition(position);
const response = await addAnswer({
variables: {
personRowId: props.loggedInPersonRowId,
questionRowId: props.question.rowId,
position: savePosition,
text: text,
},
optimisticResponse: {
createAnswer: {
__typename: "CreateAnswerPayload",
answer: {
id: "somethingIntermediate",
position: savePosition,
text: text || null,
personRowId: props.loggedInPersonRowId,
questionRowId: props.question.rowId,
__typename: "Answer",
},
},
},
});
return response.data?.createAnswer?.answer;
}
};
const handleSaveText = async (text: string) => {
const newAnswer = await changeAnswer(undefined, text);
if (newAnswer) {
enqueueSnackbar("Antwort erfolgreich gespeichert.", {
variant: "success",
});
} else {
enqueueSnackbar("Ein Fehler ist aufgetreten, versuche es erneut.", {
variant: "error",
});
}
};
const handlePositionChange = async (
e: React.MouseEvent<HTMLElement>,
newPosition: CandidatePosition
) => {
const newAnswer = await changeAnswer(newPosition);
if (!newAnswer) {
enqueueSnackbar("Ein Fehler ist aufgetreten, versuche es erneut.", {
variant: "error",
});
}
};
const loading = editAnswerLoading || addAnswerLoading;
const position = parsePosition(remoteAnswer?.position);
return remoteAnswer === undefined ? (
<div>Antwort laden...</div>
) : (
<React.Fragment>
<ToggleButtonGroupAnswerPosition
position={position}
onPositionChange={handlePositionChange}
loading={loading}
/>
<EditAnswerText
remoteText={remoteAnswer?.text}
onSaveClick={handleSaveText}
loading={loading}
/>
</React.Fragment>
);
}