Rev 14389 | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
/* eslint-disable no-mixed-spaces-and-tabs */
import React, { useState, useEffect } from 'react'
import axios from 'axios'
import parse from 'html-react-parser'
import { useForm } from 'react-hook-form'
import { useDispatch } from 'react-redux'
import { useHistory, useParams } from 'react-router-dom'
import { addNotification } from '../../../redux/notification/notification.actions'
import DescriptionInput from '../../../shared/DescriptionInput'
import SectionModal from '../components/SectionModal'
import DeleteModal from '../../../shared/DeleteModal'
import QuestionModal from '../components/QuestionModal'
import OptionModal from '../components/OptionModal'
const sectionTypeOptions = {
open: 'Abierto',
simple: 'Simple',
multiple: 'Multiple'
}
const INITIAL_OPTION = {
slug_section: '',
slug_question: '',
slug_option: '',
text: '',
checked: false,
position: 0
}
const INITIAL_SECTION = {
slug_section: '',
name: '',
text: '',
position: 0,
questions: [],
status: 0
}
const INITIAL_QUESTION = {
slug_section: '',
slug_question: '',
text: '',
type: '',
position: 0,
maxlength: '0',
multiline: '0',
range: '0',
options: [],
answer: ''
}
const FormView = ({ actionLink }) => {
// Hooks
const history = useHistory()
const { action } = useParams()
const dispatch = useDispatch()
const { register, setValue, watch, reset } = useForm()
// Section modal states
const [isShowSection, setIsShowSectionModal] = useState(false)
const [sectionSelected, setSectionSelected] = useState(INITIAL_SECTION)
const [sectionType, setSectionType] = useState('add')
// Question modal states
const [isShowQuestion, setIsShowQuestionModal] = useState(false)
const [questionSelected, setQuestionSelected] = useState(INITIAL_QUESTION)
const [questionType, setQuestionType] = useState('add')
// Option modal states
const [isShowOption, setIsShowOptionModal] = useState(false)
const [optionSelected, setOptionSelected] = useState(INITIAL_OPTION)
const [optionType, setOptionType] = useState('add')
const [content, setContent] = useState([])
const [status, setStatus] = useState('A')
const [showDeleteModal, setShowDeleteModal] = useState(false)
const [deleteType, setDeleteType] = useState('section')
const deleteSlugsOptions = {
section: sectionSelected.slug_section,
question: questionSelected.slug_question,
option: optionSelected.slug_option
}
const [text, setText] = useState((action != 'edit') ? ' ' : '')
const [description, setDescription] = useState((action != 'edit') ? ' ' : '')
// Section methods
const showSectionModal = (section = INITIAL_SECTION, type = 'add') => {
setSectionSelected(section)
setSectionType(type)
setIsShowSectionModal(true)
}
const closeSectionModal = () => {
setIsShowSectionModal(false)
setSectionSelected(INITIAL_SECTION)
}
const addSection = (name, text) => {
const uuid = new Date().getTime()
let position = content.length
console.log(name)
console.log(text)
setContent(prev => [...prev, {
slug_section: `section${uuid}`,
name: name,
text: text,
position: position,
questions: [],
status: 0
}])
}
const editSection = (name, text, slug) => {
setContent(current =>
current.map(currentSection => {
if (currentSection.slug_section === slug) {
return { ...currentSection, name: name, text: text }
}
return currentSection
})
)
}
const deleteSection = (slug) => {
setContent(current =>
current.filter(currentSection => {
return currentSection.slug_section !== slug
}),
)
}
// Question methods
const showQuestionModal = (question = INITIAL_QUESTION, type = 'add') => {
setIsShowQuestionModal(true)
setQuestionType(type)
setQuestionSelected(question)
}
const closeQuestionModal = () => {
setIsShowQuestionModal(false)
setQuestionSelected(INITIAL_QUESTION)
}
const addQuestion = (question) => {
const uuid = new Date().getTime()
setContent(current =>
current.map(currentSection => {
if (currentSection.slug_section === sectionSelected.slug_section) {
return {
...currentSection,
questions: [
...currentSection.questions,
{
...question,
slug_question: `question${uuid}`,
slug_section: sectionSelected.slug_section,
}
]
}
}
return currentSection
})
)
}
const editQuestion = (question) => {
setContent(current =>
current.map(currentSection => {
if (currentSection.slug_section === sectionSelected.slug_section) {
const newQuestions = currentSection.questions.map((currentQuestion) => {
if (currentQuestion.slug_question === question.slug_question) {
return question
}
return currentQuestion
})
return { ...currentSection, questions: newQuestions }
}
return currentSection
})
)
}
const deleteQuestion = (slug) => {
setContent(current =>
current.map(currentSection => {
if (currentSection.slug_section === sectionSelected.slug_section) {
return {
...currentSection,
questions: currentSection.questions.filter((currentQuestion) => currentQuestion.slug_question !== slug)
}
}
return currentSection
}),
)
}
// Option methods
const showOptionModal = (option = INITIAL_OPTION, type = 'add') => {
setIsShowOptionModal(true)
setOptionType(type)
setOptionSelected(option)
}
const closeOptionModal = () => {
setIsShowOptionModal(false)
setOptionSelected(INITIAL_QUESTION)
}
const addOption = (option) => {
const uuid = new Date().getTime()
setContent(current =>
current.map(currentSection => {
if (currentSection.slug_section === sectionSelected.slug_section) {
return {
...currentSection,
questions: currentSection.questions.map(currentQuestion => {
if (currentQuestion.slug_question === questionSelected.slug_question) {
return {
...currentQuestion,
options: [
...currentQuestion.options,
{
...option,
slug_question: questionSelected.slug_question,
slug_section: sectionSelected.slug_section,
slug_option: `option${uuid}`
}
]
}
}
return currentQuestion
})
}
}
return currentSection
})
)
}
const editOption = (option) => {
setContent(current =>
current.map(currentSection => {
if (currentSection.slug_section === sectionSelected.slug_section) {
return {
...currentSection,
questions: currentSection.questions.map(currentQuestion => {
if (currentQuestion.slug_question === questionSelected.slug_question) {
return {
...currentQuestion,
options: currentQuestion.options.map(currentOption => {
if (currentOption.slug_option === option.slug_option) {
return option
}
return currentOption
})
}
}
return currentQuestion
})
}
}
return currentSection
})
)
}
const deleteOption = (slug) => {
setContent(current =>
current.map(currentSection => {
if (currentSection.slug_section === sectionSelected.slug_section) {
return {
...currentSection,
questions: currentSection.questions.map(question => {
if (question.slug_question === questionSelected.slug_question) {
return {
...question,
options: question.options.filter(option => option.slug_option !== slug)
}
}
return question
})
}
}
return currentSection
}),
)
}
// General methods
const deleteHandler = (type, slug) => {
if (type === 'section') {
return deleteSection(slug)
}
if (type === 'question') {
return deleteQuestion(slug)
}
if (type === 'option') {
return deleteOption(slug)
}
}
const validate = () => {
const sectionError = content.find(section => !section.questions.length)
if (sectionError) {
dispatch(addNotification({
style: 'danger',
msg: `La sección ${sectionError.name} no tiene preguntas`
}))
return false
} else {
return true
}
}
const onSubmit = () => {
const isValid = validate()
if (isValid) {
const submitData = new FormData()
submitData.append('name', watch('name'))
submitData.append('description', watch('description'))
submitData.append('text', watch('text'))
submitData.append('status', status)
submitData.append('content', JSON.stringify(content))
axios.post(actionLink, submitData)
.then(({ data }) => {
if (!data.success) {
typeof data.data === 'string'
?
dispatch(addNotification({
style: 'danger',
msg: data.data
}))
: Object.entries(data.data).map(([key, value]) =>
value.map(err =>
dispatch(addNotification({
style: 'danger',
msg: `${key}: ${err}`
}))
)
)
return
}
dispatch(addNotification({
style: 'success',
msg: data.data
}))
})
}
}
const submitAndClose = () => {
onSubmit()
reset()
history.goBack()
}
useEffect(() => {
register('text')
register('description')
}, [])
useEffect(() => {
if (action === 'edit') {
axios.get(actionLink)
.then(({ data }) => {
if (!data.success) {
return dispatch(addNotification({
style: 'danger',
msg: 'Ha ocurrido un error'
}))
}
register('text')
register('description')
setContent(data.data.content)
setStatus(data.data.status)
setValue('name', data.data.name)
setValue('description', data.data.description)
setValue('text', data.data.description)
setDescription(data.data.description)
setText(data.data.text)
})
}
}, [actionLink])
return (
<>
<section className="content">
<div className="row" style={{ padding: 16 }}>
<div className="col-xs-12 col-md-12">
<div className="form-group">
<label>Nombre</label>
<input type="text" name="name" className='form-control' ref={register({ required: true, maxLength: 50 })} />
</div>
<div className="form-group">
<label htmlFor="form-description">Descripción</label>
{(description) &&
<DescriptionInput
defaultValue={description}
name="description"
onChange={setValue}
/>}
</div>
<div className="form-group">
<label htmlFor="form-description">Texto</label>
{(text) &&
<DescriptionInput
defaultValue={text}
name="text"
onChange={setValue}
/>}
</div>
<div className="form-group">
<label htmlFor="form-status">Estatus</label>
<select name="form-status" className="form-control" onChange={(e) => setStatus(e.target.value)} value={status}>
<option value="A">Activo</option>
<option value="I">Inactivo</option>
</select>
</div>
<br />
<div className="row">
<div className="col-xs-12 col-md-12">
<div className="panel-group" id="rows" >
<div className="form-group">
<div className="row">
<div className="col-xs-12 col-md-12">
<hr />
<div className="d-flex justify-content-end">
<button className='btn btn-primary' onClick={() => showSectionModal()}>
<i className="fa fa-plus" />
Agregar sección
</button>
</div>
<br />
<div className="panel-group" id="rows-job-competencies" >
{
content.length > 0
&&
content.map((section) => {
return (
<div className="panel panel-default" key={section.slug_section}>
<div className="panel-heading">
<h4 className="panel-title">
<a className="accordion-toggle" data-toggle="collapse" aria-expanded="true" data-parent={`panel-${section.slug_section}`} href={`#collapse-${section.slug_section}`}>
<span className={`section-name${section.slug_section}`}>
{section.name}
</span>
</a>
</h4>
</div>
<div id={`collapse-section${section.slug_section}`} className="panel-collapse in collapse show">
<div className="panel-body">
<div className="table-responsive">
<table className="table table-bordered">
<thead>
<tr>
<th style={{ width: '10%' }}>Elemento</th>
<th style={{ width: '50%' }}>Texto</th>
<th style={{ width: '10%' }}>Tipo</th>
<th style={{ width: '20%' }}>Acciones</th>
</tr>
</thead>
<tbody>
<tr className="tr-section">
<td className="text-left">Sección</td>
<td className="text-left">{section.name}</td>
<td />
<td>
<button className="btn btn-default" onClick={() => showSectionModal(section, 'edit')}>
<i className="fa fa-edit" />
Editar Sección
</button>
<button className="btn btn-default" onClick={() => {
setSectionSelected(section)
setDeleteType('section')
setShowDeleteModal(true)
}}>
<i className="fa fa-ban" />
Borrar Sección
</button>
<button className="btn btn-default" onClick={() => {
setSectionSelected(section)
showQuestionModal()
}}>
<i className="fa fa-plus" />
Agregar Pregunta
</button>
</td>
</tr>
{
section.questions.map((question) => (
<>
<tr key={question.slug_question} className="tr-question">
<td className="text-left">Pregunta</td>
<td className="text-left">
{parse(question.text)}
</td>
<td className="text-capitalize">
{sectionTypeOptions[question.type]}
</td>
<td>
<button className="btn btn-default" onClick={() => {
setSectionSelected(section)
showQuestionModal(question, 'edit')
}}>
<i className="fa fa-edit" /> Editar Pregunta
</button>
<button className="btn btn-default" onClick={() => {
setSectionSelected(section)
setQuestionSelected(question)
setDeleteType('question')
setShowDeleteModal(true)
}}>
<i className="fa fa-ban" /> Borrar Pregunta
</button>
{
question.type !== 'open'
&&
<button className="btn btn-default" onClick={() => {
setSectionSelected(section)
setQuestionSelected(question)
showOptionModal()
}}>
<i className="fa fa-plus" /> Agregar opción
</button>
}
</td>
</tr>
{
question.options.map(option => (
<tr key={option.slug_question} className="tr-option">
<td className="text-left">Opción</td>
<td className="text-left">
{parse(option.text)}
</td>
<td />
<td>
<button className="btn btn-default" onClick={() => {
setSectionSelected(section)
setQuestionSelected(question)
showOptionModal(option, 'edit')
}}>
<i className="fa fa-edit" /> Editar opción
</button>
<button className="btn btn-default" onClick={() => {
setOptionSelected(option)
setSectionSelected(section)
setQuestionSelected(question)
setDeleteType('option')
setShowDeleteModal(true)
}}>
<i className="fa fa-ban" /> Borrar opción
</button>
</td>
</tr>
))
}
</>
))
}
</tbody>
</table>
</div>
</div>
</div>
</div>
)
})
}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="d-flex" style={{ gap: '5px' }}>
{(action === 'edit') ? <button type="button" className="btn btn-info" onClick={onSubmit}>Guardar & Continuar</button> : <></>}
<button type="button" className="btn btn-primary" onClick={submitAndClose}>Guardar & Cerrar</button>
<button type="button" className="btn btn-secondary" onClick={() => history.goBack()}>Cancelar</button>
</div>
</div>
</div >
</section >
<SectionModal
show={isShowSection}
sectionType={sectionType}
section={sectionSelected}
closeModal={closeSectionModal}
onSubmit={sectionType === 'add' ? addSection : editSection}
/>
<QuestionModal
show={isShowQuestion}
questionType={questionType}
question={questionSelected}
closeModal={closeQuestionModal}
onSubmit={questionType === 'add' ? addQuestion : editQuestion}
/>
<OptionModal
show={isShowOption}
optionType={optionType}
option={optionSelected}
closeModal={closeOptionModal}
onSubmit={optionType === 'add' ? addOption : editOption}
/>
<DeleteModal
isOpen={showDeleteModal}
closeModal={() => setShowDeleteModal(false)}
onComplete={() => deleteHandler(deleteType, deleteSlugsOptions[deleteType])}
message="Registro eliminado"
/>
</>
)
}
export default FormView