Files
flashmed-uploader/src/components/create-card/options.js
2026-08-08 18:53:36 +03:30

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);