168 lines
5.6 KiB
JavaScript
168 lines
5.6 KiB
JavaScript
import { Fragment } from 'react';
|
|
import { connect } from 'react-redux';
|
|
import { change, Field, formValueSelector } from 'redux-form';
|
|
import Button from 'react-bootstrap/Button';
|
|
import Form from 'react-bootstrap/Form';
|
|
import Alert from 'react-bootstrap/Alert';
|
|
import { FaPlus, FaTrashAlt, FaUndo } from 'react-icons/fa';
|
|
import FormTextArea from '../shared/forms/textarea';
|
|
import FormCheckbox from '../shared/forms/checkbox';
|
|
import Segment from '../shared/segment';
|
|
|
|
function FormOptions(props) {
|
|
const {
|
|
fields,
|
|
meta: { error },
|
|
change,
|
|
isIncorrectOption,
|
|
showOptionHints,
|
|
isHintOption
|
|
} = props;
|
|
|
|
return (
|
|
<div className='mt-4'>
|
|
<div>
|
|
<label className='text-large text-bold'>
|
|
{'گزینهها: '}
|
|
<span className='text-danger'>*</span>
|
|
</label>
|
|
</div>
|
|
{error && error.length && (
|
|
<Alert variant='danger' className='text-center'>
|
|
{error.map((e, index) => (
|
|
<p key={index} className='m-0'>
|
|
{index + 1}) {e}
|
|
</p>
|
|
))}
|
|
</Alert>
|
|
)}
|
|
|
|
{fields.map((member, index) => {
|
|
return (
|
|
<div key={index} className='my-3'>
|
|
<Segment>
|
|
<div className='d-flex justify-content-between align-items-baseline mb-0'>
|
|
<p className='text-bold'>{`گزینه ${index + 1}`}</p>
|
|
<div>
|
|
<Button
|
|
variant='outline-warning'
|
|
size='sm'
|
|
onClick={resetOption.bind(null, change, member)}
|
|
>
|
|
<FaUndo />
|
|
</Button>{' '}
|
|
<Button
|
|
variant='outline-danger'
|
|
size='sm'
|
|
onClick={fields.remove.bind(null, index)}
|
|
>
|
|
<FaTrashAlt />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
<Field
|
|
horizontal
|
|
required
|
|
name={`${member}.text`}
|
|
component={FormTextArea}
|
|
label='متن'
|
|
placeholder=''
|
|
disabled={isHintOption(index)}
|
|
/>
|
|
<Form.Row className='justify-content-between align-items-baseline'>
|
|
{!isIncorrectOption(index) && (
|
|
<Field
|
|
required
|
|
name={`${member}.isCorrect`}
|
|
component={FormCheckbox}
|
|
label='گزینه درست'
|
|
disabled={isIncorrectOption(index)}
|
|
/>
|
|
)}
|
|
<div className='ml-auto'>
|
|
{showOptionHints(index) &&
|
|
optionHints.map((optionHint, index) => (
|
|
<Fragment key={optionHint.id}>
|
|
{index > 0 && ' '}
|
|
<Button
|
|
variant='outline-secondary'
|
|
onClick={handleOptionHintClick.bind(null, change, member, optionHint)}
|
|
>
|
|
{optionHint.text}
|
|
</Button>
|
|
</Fragment>
|
|
))}
|
|
</div>
|
|
</Form.Row>
|
|
</Segment>
|
|
</div>
|
|
);
|
|
})}
|
|
<div className='mt-3 mb-5 text-center'>
|
|
<Button variant='outline-success' onClick={createNewOption.bind(null, fields)}>
|
|
{'افزودن گزینه جدید '}
|
|
<FaPlus />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const MIN_OPTIONS_COUNT = 2;
|
|
|
|
const optionHints = [
|
|
{ id: 1, text: 'هیچ', value: 'هیچکدام', weight: 0 },
|
|
{ id: 2, text: '1,2', value: 'گزینههای 1 و 2', weight: 20 },
|
|
{ id: 3, text: '1,3', value: 'گزینههای 1 و 3', weight: 20 },
|
|
{ id: 4, text: '2,3', value: 'گزینههای 2 و 3', weight: 20 },
|
|
{ id: 5, text: 'همه', value: 'همه موارد', weight: 10 }
|
|
];
|
|
const optionHintValues = optionHints.map(({ value }) => value);
|
|
|
|
function isRealOptionText(text) {
|
|
return !!text && !optionHintValues.includes(text);
|
|
}
|
|
|
|
function handleOptionHintClick(change, member, optionHint) {
|
|
change('create-card', `${member}.text`, optionHint.value);
|
|
change('create-card', `${member}.weight`, optionHint.weight);
|
|
}
|
|
|
|
function resetOption(change, member) {
|
|
change('create-card', `${member}.text`, '');
|
|
change('create-card', `${member}.weight`, 100);
|
|
change('create-card', `${member}.isCorrect`, false);
|
|
}
|
|
|
|
function createNewOption(fields) {
|
|
fields.push({ text: '', isCorrect: false, weight: 100 });
|
|
}
|
|
|
|
function isIncorrectOption(options, index) {
|
|
if (!options || options.length === 0) return false;
|
|
const firstCorrectOptionIndex = options.findIndex(option => option.isCorrect);
|
|
return firstCorrectOptionIndex >= 0 && !options[index].isCorrect;
|
|
}
|
|
|
|
function showOptionHints(options, index) {
|
|
if (!options || options.length === 0) return false;
|
|
const realOptionCount = options.filter(({ text }) => isRealOptionText(text)).length;
|
|
return realOptionCount >= MIN_OPTIONS_COUNT && !isRealOptionText(options[index].text);
|
|
}
|
|
|
|
function isHintOption(options, index) {
|
|
return optionHintValues.includes(options[index].text);
|
|
}
|
|
|
|
function mapStateToProps(state) {
|
|
const selector = formValueSelector('create-card');
|
|
const options = selector(state, 'options');
|
|
return {
|
|
showOptionHints: showOptionHints.bind(null, options),
|
|
isIncorrectOption: isIncorrectOption.bind(null, options),
|
|
isHintOption: isHintOption.bind(null, options)
|
|
};
|
|
}
|
|
|
|
export default connect(mapStateToProps, { change })(FormOptions);
|