Skip to content

Commit

Permalink
correct answer for EditChoiceItems
Browse files Browse the repository at this point in the history
  • Loading branch information
JandenMa committed Oct 27, 2021
1 parent f5300f8 commit ea880ba
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 48 deletions.
31 changes: 18 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,22 +267,27 @@ import { EditChoiceItems } from '@rinxun/custom-questions';

<h5>Choice Item Props</h5>

| Name | Type | Default | Required | Description |
| ----- | ------ | ---------- | -------- | ------------------------------------------------------------ |
| label | string | 'Choice x' | false | The label of the `Input`.<br />`x` is an index number. |
| name | string | | true | The name of the `Input`. <br />Also it is the unique id of the choice item. |
| value | string | | true | The value of the `Input`. |
| Name | Type | Default | Required | Description |
| ------------- | ------ | ---------- | -------- | ------------------------------------------------------------ |
| correctAnswer | bool | | false | If `true` that means this answer is the correct one.<br />Required when `needDefineCorrectAnswer` (in the next table) is `true`. |
| label | string | 'Choice x' | false | The label of the `Input`.<br />`x` is an index number. |
| name | string | | true | The name of the `Input`. <br />Also it is the unique id of the choice item. |
| value | string | | true | The value of the `Input`. |

<h5>Props</h5>

| Name | Type | Default | Required | Description |
| --------------- | ------------------------ | ------------------------------------ | -------- | ------------------------------------------------------------ |
| maxItems | number | | false | Maximum number of items to add, it must be greater than 2.<br />If `null` then unlimited. |
| maxItemsTipText | string | 'A maximum of x choices can be set!' | false | A warming tip to tell users the maximum number of items to add. Only be displayed when `maxItems` is not `null`.<br />`x` is the `maxItem` value. |
| onAddMore | func | | true | Callback fired when the Add More button is clicked.<br />**Signature:**<br/>`function() => void`<br/> |
| onChange | func | | true | Callback fired when the `Input` value is changed.<br />**Signature:**<br/>`function(name: string, value: string) => void`<br/>*name:* The name of the `Input` element.<br />*value:* The value of the `Input` element. |
| onRemove | func | 'Enter Question' | false | Callback fired when removed the choice item.<br />**Signature:**<br/>`function(name: string) => void`<br/>*name:* The name of the `Input` element. |
| options | Array\<ChoiceItemProps\> | | true | See **Choice Item Props** above.<br />The length of options must be greater than 2. |
| Name | Type | Default | Required | Description |
| ------------------------ | ------------------------ | ----------------------------------------- | -------- | ------------------------------------------------------------ |
| answerType | AnswerTypeEnum | | true | Which kind of component you want to render for the answer. |
| correctAnswerIconTipText | string | 'Toggle it as correct / incorrect answer' | false | The tooltip text of the tick icon button. |
| maxItems | number | | false | Maximum number of items to add, it must be greater than 2.<br />If `null` then unlimited. |
| maxItemsTipText | string | 'A maximum of x choices can be set!' | false | A warming tip to tell users the maximum number of items to add. Only be displayed when `maxItems` is not `null`.<br />`x` is the `maxItem` value. |
| needDefineCorrectAnswer | bool | | false | If `true` that means you have to define correct answers.<br />At this moment, `onToggleCorrectAnswer` and `correctAnswer` are required. |
| onAddMore | func | | true | Callback fired when the Add More button is clicked.<br />**Signature:**<br/>`function() => void`<br/> |
| onChange | func | | true | Callback fired when the `Input` value is changed.<br />**Signature:**<br/>`function(name: string, value: string) => void`<br/>*name:* The name of the `Input` element.<br />*value:* The value of the `Input` element. |
| onRemove | func | | true | Callback fired when removed the choice item.<br />**Signature:**<br/>`function(name: string) => void`<br/>*name:* The name of the `Input` element. |
| onToggleCorrectAnswer | func | | false | Callback fired when toggle the tick icon button at the end of the choice item.<br />**Signature:**<br/>`function(name: string) => void`<br/>*name:* The name of the `Input` element.<br />Required when `needDefineCorrectAnswer` is true. |
| options | Array\<ChoiceItemProps\> | | true | See **Choice Item Props** above.<br />The length of options must be greater than 2. |



Expand Down
133 changes: 98 additions & 35 deletions components/ChoiceAnswer/EditChoiceItems.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,42 @@
import { memo, useMemo } from 'react';
import Grid from '@mui/material/Grid';
import Button from '@mui/material/Button';
import Tooltip from '@mui/material/Tooltip';
import TextField from '@mui/material/TextField';
import IconButton from '@mui/material/IconButton';
import Typography from '@mui/material/Typography';
import InputAdornment from '@mui/material/InputAdornment';
import useTheme from '@mui/material/styles/useTheme';
import CheckIcon from '@mui/icons-material/Check';
import CloseIcon from '@mui/icons-material/Close';
import { AnswerTypeEnum } from '../../enums';

export interface EditChoiceItemsProps {
options: Array<{ value: string; name: string; label?: string }>;
options: Array<{ value: string; name: string; label?: string; correctAnswer?: boolean }>;
onChange: (name: string, value: string) => void;
onAddMore: () => void;
onRemove: (name: string) => void;
onToggleCorrectAnswer?: (name: string) => void;
answerType: AnswerTypeEnum;
needDefineCorrectAnswer?: boolean;
correctAnswerIconTipText?: string;
maxItems?: number;
maxItemsTipText?: string;
}

function EditChoiceItems(props: EditChoiceItemsProps) {
const { options, onAddMore, onChange, onRemove, maxItems, maxItemsTipText } = props;
const {
options,
onAddMore,
onChange,
onRemove,
onToggleCorrectAnswer,
needDefineCorrectAnswer,
correctAnswerIconTipText,
answerType,
maxItems,
maxItemsTipText
} = props;
const theme = useTheme();

const canAddMore = useMemo(
Expand All @@ -27,50 +45,95 @@ function EditChoiceItems(props: EditChoiceItemsProps) {
);

if (options.length < 2) {
console.error('EditChoiceItems: "options" should be an array with more than 2 items');
console.error('EditChoiceItems: "options" should be an array with more than 2 items.');
return <></>;
}
if (maxItems && maxItems <= 2) {
console.error('EditChoiceItems: "maxItems" should be greater than 2');
console.error('EditChoiceItems: "maxItems" should be greater than 2.');
return <></>;
}
if (needDefineCorrectAnswer) {
if (!onToggleCorrectAnswer) {
console.error(
`EditChoiceItems: "onToggleCorrectAnswer" can't be null or undefined when "needDefineCorrectAnswer" is true.`
);
return <></>;
}
const allHasCorrectAnswerVar = options.every(
(opt) => opt.correctAnswer !== undefined && opt.correctAnswer !== null
);
if (!allHasCorrectAnswerVar) {
console.error(
`EditChoiceItems: all options should include "correctAnswer" when "needDefineCorrectAnswer" is true.`
);
return <></>;
}
if (answerType === AnswerTypeEnum.singleChoice) {
const correctAnswers = options.filter((opt) => opt.correctAnswer);
if (correctAnswers.length > 1) {
console.error(`EditChoiceItems: For Single Choice, only 1 correct answer can be set.`);
return <></>;
}
}
}
return (
<>
<Grid container direction="row" justifyContent="flex-start" alignItems="center">
{options.map((opt, index) => {
const { label, value, name } = opt;
const { label, value, name, correctAnswer } = opt;
return (
<Grid item xs={12} md={10} lg={8} key={index}>
<TextField
fullWidth
required
size="small"
margin="dense"
variant="outlined"
label={label || `Choice ${index + 1}`}
name={name}
value={value}
onChange={(event) => {
event.preventDefault();
onChange(name, event.target.value);
}}
InputProps={{
endAdornment:
options.length > 2 ? (
<InputAdornment position="end">
<IconButton
color="error"
size="small"
onClick={() => {
onRemove(name);
}}
>
<CloseIcon fontSize="small" />
</IconButton>
</InputAdornment>
) : null
}}
/>
<Grid container direction="row" justifyContent="flex-start" alignItems="center">
<Grid item xs={needDefineCorrectAnswer ? 11 : 12}>
<TextField
fullWidth
required
size="small"
margin="dense"
variant="outlined"
label={label || `Choice ${index + 1}`}
name={name}
value={value}
onChange={(event) => {
event.preventDefault();
onChange(name, event.target.value);
}}
InputProps={{
endAdornment:
options.length > 2 ? (
<InputAdornment position="end">
<IconButton
color="error"
size="small"
onClick={() => {
onRemove(name);
}}
>
<CloseIcon fontSize="small" />
</IconButton>
</InputAdornment>
) : null
}}
/>
</Grid>
{needDefineCorrectAnswer && onToggleCorrectAnswer && (
<Grid item xs={1}>
<Tooltip
title={correctAnswerIconTipText || 'Toggle it as correct / incorrect answer'}
>
<IconButton
sx={{ color: correctAnswer ? 'forestgreen' : 'lightgray' }}
size="medium"
onClick={() => {
onToggleCorrectAnswer(name);
}}
>
<CheckIcon fontSize="medium" />
</IconButton>
</Tooltip>
</Grid>
)}
</Grid>
</Grid>
);
})}
Expand Down

0 comments on commit ea880ba

Please sign in to comment.