Files
2022-08-10 23:23:37 +00:00

243 lines
6.8 KiB
TypeScript

import React, { FC, useEffect, useState } from "react";
import { FieldValue, FieldValues, useForm } from "react-hook-form";
import { ExclamationCircleIcon } from "@heroicons/react/outline";
import { useHistory } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { gql } from "@apollo/client";
import {
Question,
QuestionCreateInput,
QuestionStatus,
} from "../../../__generated__/graphql-schema";
import { formatInput } from "../formatInputs";
import { validateQuestionInputs } from "../../../utils/questions/questionValidations";
import { RootState } from "../../../services/store";
import { FormProvider } from "./FormContext";
import { SteppedForm, Step } from "./SteppedForm";
import {
EnunciationFormStep,
EnunciationFragment,
AnswerFormStep,
AnswerFragment,
DistractorsFormStep,
DistractorsFragment,
FeaturesFormStep,
FeaturesFragment,
} from "./steps";
import {
Button,
Dialog,
AlertV2Props,
AlertV2,
List,
ListItem,
} from "../../../components";
import { QuestionRoutePaths } from "../../../routes";
import { turnOff, turnOn } from "../../../services/store/unsavedChanges";
export const FormFragments = gql`
${EnunciationFragment}
${AnswerFragment}
${DistractorsFragment}
${FeaturesFragment}
fragment FormFields on Question {
...EnunciationFields
...AnswerFields
...DistractorsFields
...FeaturesFields
status
}
`;
type Props = {
question?: Question;
onSubmit?: (inputs: any) => void;
onDraftSubmit?: (inputs: any) => void;
alert?: AlertV2Props;
};
export const Form: FC<Props> = ({
question,
onSubmit,
onDraftSubmit,
alert,
}) => {
const [validationErrors, setValidationErrors] = useState<string[]>([]);
const [confirmSaveDialogIsOpen, setConfirmFinishDialogIsOpen] =
useState(false);
const [leaveDialogIsOpen, setLeaveDialogIsOpen] = useState(false);
const formHooks = useForm<FieldValues>({
defaultValues: {
authorship: question?.authorship ?? "UNIFESO",
authorshipType: question?.authorship === "UNIFESO" ? "UNIFESO" : (question?.authorship ?? "OTHER"),
authorshipYear: new Date().getFullYear().toString(),
difficulty: question?.difficulty,
checkType: question?.checkType,
bloomTaxonomy: question?.bloomTaxonomy,
intention: question?.intention,
},
});
const { getValues, reset, formState } = formHooks;
const [currentStep, setCurrentStep] = useState(0);
const unsavedChanges = useSelector(
(state: RootState) => state.unsavedChanges
);
const history = useHistory();
const dispatch = useDispatch();
const minStep = 0;
const maxStep = 3;
const onFirstStep = currentStep === minStep;
const onLastStep = currentStep === maxStep;
useEffect(() => {
if (formState.isDirty) {
dispatch(turnOn());
}
}, [formState.isDirty, dispatch, turnOn]);
const handleNextStep = () => {
if (onLastStep) return;
setCurrentStep(currentStep + 1);
};
const handlePreviousStep = () => {
if (onFirstStep) return;
setCurrentStep(currentStep - 1);
};
const getFormattedInputValues = () => formatInput(getValues());
const handleCancel = () => {
if (unsavedChanges && !leaveDialogIsOpen) {
setLeaveDialogIsOpen(true);
} else {
history.push(QuestionRoutePaths.index);
}
};
const handleDraftSave = () => {
if (onDraftSubmit) {
onDraftSubmit({
...getFormattedInputValues(),
status: QuestionStatus.Draft,
} as QuestionCreateInput);
reset(getValues());
dispatch(turnOff());
}
};
const handleSave = () => {
const inputs = {
...getFormattedInputValues(),
status: QuestionStatus.WaitingReview,
} as QuestionCreateInput;
const errors = validateQuestionInputs(inputs);
setConfirmFinishDialogIsOpen(false);
if (onSubmit && !errors.length) {
dispatch(turnOff());
onSubmit(inputs);
} else {
setValidationErrors(errors);
}
reset(getValues());
};
return (
<FormProvider props={{ question, hooks: formHooks }}>
{alert && <AlertV2 severity={alert.severity} text={alert.text}></AlertV2>}
<Dialog
isOpen={leaveDialogIsOpen}
setIsOpen={setLeaveDialogIsOpen}
onConfirmation={handleCancel}
title="Modificações não Salvas"
text="Todas as alterações serão descartadas. Deseja continuar?"
/>
<Dialog
isOpen={confirmSaveDialogIsOpen}
setIsOpen={setConfirmFinishDialogIsOpen}
onConfirmation={handleSave}
title="Modificações não Salvas"
text="Ao finalizar a questão, o revisor receberá uma notificação para revisá-la. Deseja continuar?"
/>
<Dialog
isOpen={!!validationErrors.length}
setIsOpen={() => setValidationErrors([])}
onConfirmation={() => setValidationErrors([])}
title="Falha de Validação"
type="notice"
text={
<>
<List>
{validationErrors?.map((errorMessage) => (
<ListItem
key={errorMessage}
icon={<ExclamationCircleIcon className="w-5 text-gray-800" />}
text={errorMessage}
/>
))}
</List>
</>
}
/>
<form className="m-auto max-w-screen-md">
<SteppedForm currentStep={currentStep} className="mb-3">
<Step step={0}>
<EnunciationFormStep />
</Step>
<Step step={1}>
<AnswerFormStep />
</Step>
<Step step={2}>
<DistractorsFormStep />
</Step>
<Step step={3}>
<FeaturesFormStep />
</Step>
</SteppedForm>
<div className="mx-3 sm:mx-0 flex justify-items-center flex-col-reverse sm:flex-row justify-end space-x-0 sm:space-x-2">
<Button className={"mb-3 sm:mb-0"} onClick={handleCancel}>
Cancelar
</Button>
<Button
className={`mb-3 sm:mb-0 ${onFirstStep ? "hidden" : ""}`}
onClick={handlePreviousStep}
>
Retornar
</Button>
{(question?.status === QuestionStatus.Draft ||
question?.status === undefined) && (
<Button className={"mb-3 sm:mb-0"} onClick={handleDraftSave}>
Salvar Rascunho
</Button>
)}
<Button
type="primary"
className={`mb-3 sm:mb-0 ${onLastStep ? "hidden" : ""}`}
onClick={handleNextStep}
>
Prosseguir
</Button>
{onLastStep && (
<Button
type="primary"
className="mb-3 sm:mb-0"
onClick={handleSave}
>
Finalizar
</Button>
)}
</div>
</form>
</FormProvider>
);
};