start
This commit is contained in:
167
src/components/create-card/options.js
Normal file
167
src/components/create-card/options.js
Normal file
@@ -0,0 +1,167 @@
|
||||
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);
|
||||
Reference in New Issue
Block a user