Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: refactor common selects #603

Merged
merged 14 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 32 additions & 86 deletions frontend/src/components/admin/assessment-creation/BasicInformation.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import React from "react";
import React, { type ReactElement, useMemo } from "react";
import type {
Control,
FieldErrorsImpl,
UseFormClearErrors,
UseFormRegister,
UseFormSetValue,
UseFormWatch,
} from "react-hook-form";
import { Controller } from "react-hook-form";
import countryList from "react-select-country-list";
Expand All @@ -20,53 +17,28 @@ import {
Text,
VStack,
} from "@chakra-ui/react";
import type { SingleValue } from "chakra-react-select";
import { Select } from "chakra-react-select";

import type { TestRequest } from "../../../APIClients/types/TestClientTypes";
import { UseCase } from "../../../types/AssessmentTypes";
import type {
GradeOption,
StringOption,
} from "../../../types/SelectInputTypes";
import { gradeOptions } from "../../../utils/AssessmentUtils";
import ControlledSelect from "../../common/form/ControlledSelect";
import FormRadio from "../../common/form/FormRadio";
import ErrorToast from "../../common/info/toasts/ErrorToast";

interface BasicInformationProps {
register: UseFormRegister<TestRequest>;
setValue: UseFormSetValue<TestRequest>;
watch: UseFormWatch<TestRequest>;
control: Control<TestRequest, unknown>;
errors: Partial<FieldErrorsImpl<TestRequest>>;
errorMessage: string;
clearErrors: UseFormClearErrors<TestRequest>;
}

const BasicInformation = ({
register,
setValue,
watch,
jfdoming marked this conversation as resolved.
Show resolved Hide resolved
control,
errors,
errorMessage,
clearErrors,
}: BasicInformationProps): React.ReactElement => {
const handleGradeChange = (option: SingleValue<GradeOption>) => {
if (option) {
setValue("grade", option.value);
clearErrors("grade");
}
};

const handleCountryChange = (option: SingleValue<StringOption>) => {
if (option) {
setValue("curriculumCountry", option.value);
clearErrors("curriculumCountry");
}
};

const countryOptions = React.useMemo(() => countryList().getData(), []);
}: BasicInformationProps): ReactElement => {
const countryOptions = useMemo(() => countryList().getData(), []);

return (
<Box width="100%">
Expand All @@ -85,30 +57,16 @@ const BasicInformation = ({
</FormControl>

<Box width="50%">
<Controller
control={control}
name="grade"
render={({ field: { name }, fieldState: { error } }) => (
<FormControl isInvalid={Boolean(error)} isRequired>
<FormLabel color="grey.400">Grade Level</FormLabel>
<Select
name={name}
onChange={handleGradeChange}
options={gradeOptions}
placeholder="Select a grade"
selectedOptionStyle="check"
useBasicStyles
value={
gradeOptions.find(
(option) => option.value === watch("grade"),
) || undefined
}
/>
<FormErrorMessage>{error?.message}</FormErrorMessage>
</FormControl>
)}
rules={{ required: "Please select a grade" }}
/>
<FormControl isInvalid={!!errors.grade} isRequired>
<FormLabel color="grey.400">Grade Level</FormLabel>
<ControlledSelect
isRequired="Please select a grade"
name="grade"
options={gradeOptions}
placeholder="Select a grade"
/>
<FormErrorMessage>{errors.grade?.message}</FormErrorMessage>
</FormControl>
jfdoming marked this conversation as resolved.
Show resolved Hide resolved
</Box>

<Box width="50%">
Expand Down Expand Up @@ -152,37 +110,25 @@ const BasicInformation = ({
Curriculum
</Text>
<HStack alignItems="flex-start" width="100%">
<Controller
control={control}
name="curriculumCountry"
render={({ field: { name }, fieldState: { error } }) => (
<FormControl
isInvalid={Boolean(error)}
isRequired
mr={2}
variant="paragraph"
>
<FormLabel color="grey.400">Country</FormLabel>
<Select
name={name}
onChange={handleCountryChange}
options={countryOptions}
placeholder="Select a country"
useBasicStyles
value={
countryOptions.find(
(option) => option.value === watch("curriculumCountry"),
) || undefined
}
/>
<FormErrorMessage>{error?.message}</FormErrorMessage>
</FormControl>
)}
rules={{ required: "Please select a country" }}
/>

<FormControl
isInvalid={Boolean(errors.curriculumRegion)}
isInvalid={!!errors.curriculumCountry?.message}
isRequired
mr={2}
variant="paragraph"
>
<FormLabel color="grey.400">Country</FormLabel>
<ControlledSelect
isRequired="Please select a country"
name="curriculumCountry"
options={countryOptions}
placeholder="Select a country"
/>
<FormErrorMessage>
{errors.curriculumCountry?.message}
</FormErrorMessage>
</FormControl>
<FormControl
isInvalid={!!errors.curriculumRegion}
isRequired
variant="paragraph"
>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useEffect, useState } from "react";
import { FormControl, FormErrorMessage, FormLabel } from "@chakra-ui/react";
import { FormControl, FormLabel } from "@chakra-ui/react";

import type { FractionMetadata } from "../../../../../../types/QuestionMetadataTypes";
import type { FractionType } from "../../../../../../types/QuestionTypes";
Expand Down Expand Up @@ -34,6 +34,7 @@ const FractionModal = ({

useEffect(() => {
if (!isOpen) {
setError(false);
return;
}

Expand All @@ -42,11 +43,6 @@ const FractionModal = ({
setDenominator(String(data?.denominator ?? ""));
}, [data, isOpen]);

const handleClose = () => {
setError(false);
onClose();
};

const handleConfirm = () => {
const castedWholeNumber =
fractionType === "regular" ? null : stringToInt(wholeNumber);
Expand All @@ -58,7 +54,7 @@ const FractionModal = ({
typeof castedDenominator === "undefined"
) {
setError(true);
throw new FormValidationError("One or more fields are invalid");
throw new FormValidationError("Please provide all parts of the fraction");
}
onConfirm({
wholeNumber: castedWholeNumber,
Expand All @@ -73,7 +69,7 @@ const FractionModal = ({
header="Create fraction question"
isOpen={isOpen}
onBack={onBack}
onClose={handleClose}
onClose={onClose}
onSubmit={handleConfirm}
showDefaultToasts={false}
>
Expand All @@ -95,7 +91,6 @@ const FractionModal = ({
}
wholeNumber={fractionType === "mixed" ? wholeNumber : null}
/>
<FormErrorMessage>Enter a value before confirming.</FormErrorMessage>
</FormControl>
</Modal>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ const MultiOptionModal = ({
resetErrors();
if (optionCount === 0) {
setOptionCountError(true);
throw new FormValidationError("Please add an option");
throw new FormValidationError("Please select a number of options");
} else if (!options.every((option) => option.value)) {
setEmptyOptionError(true);
throw new FormValidationError("Please ensure all fields are filled");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import React from "react";
import {
FormControl,
FormErrorMessage,
FormLabel,
Select,
} from "@chakra-ui/react";
import { FormControl, FormLabel } from "@chakra-ui/react";
import { v4 as uuidv4 } from "uuid";

import type { MultiOptionData } from "../../../../../../types/QuestionTypes";
import Select from "../../../../../common/form/Select";

interface SelectOptionCountProps {
optionCount: number;
Expand All @@ -34,15 +30,20 @@ const SelectOptionCount = ({
setOptions((prevOptions) => prevOptions.slice(0, n));
};

const handleSelectCount = (event: React.ChangeEvent<HTMLSelectElement>) => {
const count = parseInt(event.target.value, 10);
const countDiff = count - optionCount;
const handleSelectCount = (value: number | null) => {
if (value == null) {
setOptions([]);
setOptionCount(0);
return;
}

const countDiff = value - optionCount;
if (countDiff > 0) {
addOptions(countDiff);
} else {
removeOptions(countDiff);
}
setOptionCount(count);
setOptionCount(value);
};

return (
Expand All @@ -51,20 +52,20 @@ const SelectOptionCount = ({
How many options would you like?
</FormLabel>
<Select
onChange={(e) => handleSelectCount(e)}
chakraStyles={{
container: (provided) => ({
...provided,
width: "50%",
}),
}}
onChange={handleSelectCount}
options={[...Array(4)].map((_, i) => ({
label: String(i + 1),
value: i + 1,
}))}
placeholder="Select Input"
value={optionCount}
width="50%"
>
<option disabled value={0}>
Select Input
</option>
{[...Array(4)].map((i, count) => (
<option key={count + 1} value={count + 1}>
{count + 1}
</option>
))}
</Select>
<FormErrorMessage>Select a value before confirming.</FormErrorMessage>
/>
jfdoming marked this conversation as resolved.
Show resolved Hide resolved
</FormControl>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import React, { useEffect, useState } from "react";
import {
FormControl,
FormErrorMessage,
FormLabel,
Input,
} from "@chakra-ui/react";
import { FormControl, FormLabel, Input } from "@chakra-ui/react";

import type { ShortAnswerMetadata } from "../../../../../../types/QuestionMetadataTypes";
import {
Expand Down Expand Up @@ -53,7 +48,7 @@ const ShortAnswerModal = ({
onConfirm({ answer: castedAnswer });
} else {
setError(true);
throw new FormValidationError("One or more fields are invalid");
throw new FormValidationError("Please enter a correct answer");
}
};

Expand All @@ -77,7 +72,6 @@ const ShortAnswerModal = ({
value={answer}
width="50%"
/>
<FormErrorMessage>Enter a value before confirming.</FormErrorMessage>
</FormControl>
</Modal>
);
Expand Down
11 changes: 4 additions & 7 deletions frontend/src/components/auth/student-login/NameSelection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,14 @@ import {
FormErrorMessage,
FormLabel,
} from "@chakra-ui/react";
import type { SingleValue } from "chakra-react-select";
import { Select } from "chakra-react-select";

import { GET_TESTABLE_STUDENTS_BY_TEST_SESSION } from "../../../APIClients/queries/ClassQueries";
import type { StudentResponse } from "../../../APIClients/types/ClassClientTypes";
import type { TestSessionSetupData } from "../../../APIClients/types/TestSessionClientTypes";
import { STUDENT_SIGNUP_IMAGE } from "../../../assets/images";
import { HOME_PAGE, STUDENT_LANDING_PAGE } from "../../../constants/Routes";
import AuthContext from "../../../contexts/AuthContext";
import type { StudentOption } from "../../../types/SelectInputTypes";
import Select from "../../common/form/Select";
import AuthWrapper from "../AuthWrapper";
import NavigationButtons from "../teacher-signup/NavigationButtons";

Expand All @@ -37,9 +35,9 @@ const NameSelection = ({
data?.testableStudentsByTestSessionId.students ?? [];
const className = data?.testableStudentsByTestSessionId.className ?? "";

const [selectedStudent, setSelectedStudent] = useState<StudentOption>();
const [selectedStudent, setSelectedStudent] = useState<StudentResponse>();
const [error, setError] = useState(false);
const handleStudentChange = (option: SingleValue<StudentOption>) => {
const handleStudentChange = (option: StudentResponse | null) => {
jfdoming marked this conversation as resolved.
Show resolved Hide resolved
if (option) {
setSelectedStudent(option);
setError(false);
Expand All @@ -65,7 +63,6 @@ const NameSelection = ({
: `${student.firstName} ${student.lastName}`,
}))}
placeholder="Search for your name by typing it in the field"
useBasicStyles
value={selectedStudent}
/>
<FormErrorMessage>Please select your name</FormErrorMessage>
Expand All @@ -81,7 +78,7 @@ const NameSelection = ({
setError(true);
} else {
setAuthenticatedUser({
...selectedStudent.value,
...selectedStudent,
role: "Student",
});
history.push({
Expand Down
Loading
Loading