Proyectos de Subversion LeadersLinked - Backend

Rev

Rev 14370 | Rev 14372 | Ir a la última revisión | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
12709 stevensc 1
/* eslint-disable no-mixed-spaces-and-tabs */
2
import React, { useState, useEffect } from 'react'
3
import axios from 'axios'
12733 stevensc 4
import parse from 'html-react-parser'
12709 stevensc 5
import { useForm } from 'react-hook-form'
6
import { useDispatch } from 'react-redux'
12710 stevensc 7
import { useHistory, useParams } from 'react-router-dom'
12709 stevensc 8
import { addNotification } from '../../../redux/notification/notification.actions'
9
import DescriptionInput from '../../../shared/DescriptionInput'
10
import SectionModal from '../components/SectionModal'
12993 stevensc 11
import DeleteModal from '../../../shared/DeleteModal'
12996 stevensc 12
import QuestionModal from '../components/QuestionModal'
13068 stevensc 13
import OptionModal from '../components/OptionModal'
12709 stevensc 14
 
15
const sectionTypeOptions = {
16
	open: 'Abierto',
13007 stevensc 17
	simple: 'Simple',
18
	multiple: 'Multiple'
12709 stevensc 19
}
20
 
13067 stevensc 21
const INITIAL_OPTION = {
22
	slug_section: '',
23
	slug_question: '',
24
	slug_option: '',
25
	text: '',
26
	checked: false,
27
	position: 0
28
}
29
 
12709 stevensc 30
const INITIAL_SECTION = {
31
	slug_section: '',
32
	name: '',
33
	text: '',
34
	position: 0,
35
	questions: [],
36
	status: 0
37
}
38
 
39
const INITIAL_QUESTION = {
40
	slug_section: '',
41
	slug_question: '',
42
	text: '',
43
	type: '',
44
	position: 0,
45
	maxlength: '0',
46
	multiline: '0',
47
	range: '0',
48
	options: [],
49
	answer: ''
50
}
51
 
52
const FormView = ({ actionLink }) => {
53
 
54
	// Hooks
55
	const history = useHistory()
12710 stevensc 56
	const { action } = useParams()
12709 stevensc 57
	const dispatch = useDispatch()
58
	const { register, setValue, watch, reset } = useForm()
59
 
60
	// Section modal states
61
	const [isShowSection, setIsShowSectionModal] = useState(false)
62
	const [sectionSelected, setSectionSelected] = useState(INITIAL_SECTION)
63
	const [sectionType, setSectionType] = useState('add')
64
 
13067 stevensc 65
	// Question modal states
12709 stevensc 66
	const [isShowQuestion, setIsShowQuestionModal] = useState(false)
67
	const [questionSelected, setQuestionSelected] = useState(INITIAL_QUESTION)
68
	const [questionType, setQuestionType] = useState('add')
69
 
13067 stevensc 70
	// Option modal states
71
	const [isShowOption, setIsShowOptionModal] = useState(false)
72
	const [optionSelected, setOptionSelected] = useState(INITIAL_OPTION)
73
	const [optionType, setOptionType] = useState('add')
74
 
12709 stevensc 75
	const [content, setContent] = useState([])
76
	const [status, setStatus] = useState('A')
12993 stevensc 77
	const [showDeleteModal, setShowDeleteModal] = useState(false)
78
	const [deleteType, setDeleteType] = useState('section')
13007 stevensc 79
	const deleteSlugsOptions = {
80
		section: sectionSelected.slug_section,
13069 stevensc 81
		question: questionSelected.slug_question,
82
		option: optionSelected.slug_option
13007 stevensc 83
	}
12709 stevensc 84
 
14370 kerby 85
	const [text,setText] = useState(' ')
86
	const [description,setDescription] = useState(' ')
14366 kerby 87
 
13067 stevensc 88
	// Section methods
12709 stevensc 89
	const showSectionModal = (section = INITIAL_SECTION, type = 'add') => {
90
		setSectionSelected(section)
91
		setSectionType(type)
13007 stevensc 92
		setIsShowSectionModal(true)
12709 stevensc 93
	}
94
 
95
	const closeSectionModal = () => {
96
		setIsShowSectionModal(false)
97
		setSectionSelected(INITIAL_SECTION)
98
	}
99
 
12991 stevensc 100
	const addSection = (name, text) => {
12836 stevensc 101
		const uuid = new Date().getTime()
12991 stevensc 102
		let position = content.length
103
		console.log(name)
104
		console.log(text)
12836 stevensc 105
 
12990 stevensc 106
		setContent(prev => [...prev, {
12836 stevensc 107
			slug_section: `section${uuid}`,
108
			name: name,
109
			text: text,
110
			position: position,
111
			questions: [],
112
			status: 0
12990 stevensc 113
		}])
12709 stevensc 114
	}
115
 
12991 stevensc 116
	const editSection = (name, text, slug) => {
12992 stevensc 117
		setContent(current =>
118
			current.map(currentSection => {
119
				if (currentSection.slug_section === slug) {
120
					return { ...currentSection, name: name, text: text }
121
				}
12991 stevensc 122
 
12992 stevensc 123
				return currentSection
124
			})
125
		)
12709 stevensc 126
	}
127
 
13067 stevensc 128
	const deleteSection = (slug) => {
129
		setContent(current =>
130
			current.filter(currentSection => {
131
				return currentSection.slug_section !== slug
132
			}),
133
		)
134
	}
135
 
136
	// Question methods
12709 stevensc 137
	const showQuestionModal = (question = INITIAL_QUESTION, type = 'add') => {
138
		setIsShowQuestionModal(true)
139
		setQuestionType(type)
140
		setQuestionSelected(question)
141
	}
142
 
143
	const closeQuestionModal = () => {
144
		setIsShowQuestionModal(false)
145
		setQuestionSelected(INITIAL_QUESTION)
146
	}
147
 
148
	const addQuestion = (question) => {
12996 stevensc 149
		const uuid = new Date().getTime()
150
 
13004 stevensc 151
		setContent(current =>
152
			current.map(currentSection => {
153
				if (currentSection.slug_section === sectionSelected.slug_section) {
154
					return {
155
						...currentSection,
156
						questions: [
157
							...currentSection.questions,
158
							{
159
								...question,
160
								slug_question: `question${uuid}`,
161
								slug_section: sectionSelected.slug_section,
162
							}
163
						]
164
					}
165
				}
13002 stevensc 166
 
13004 stevensc 167
				return currentSection
168
			})
169
		)
12709 stevensc 170
	}
171
 
172
	const editQuestion = (question) => {
13006 stevensc 173
		setContent(current =>
174
			current.map(currentSection => {
175
				if (currentSection.slug_section === sectionSelected.slug_section) {
13001 stevensc 176
 
13006 stevensc 177
					const newQuestions = currentSection.questions.map((currentQuestion) => {
178
						if (currentQuestion.slug_question === question.slug_question) {
179
							return question
180
						}
12709 stevensc 181
 
13006 stevensc 182
						return currentQuestion
183
					})
184
 
185
					return { ...currentSection, questions: newQuestions }
186
				}
13007 stevensc 187
 
13006 stevensc 188
				return currentSection
189
			})
190
		)
12709 stevensc 191
	}
192
 
13067 stevensc 193
	const deleteQuestion = (slug) => {
194
		setContent(current =>
195
			current.map(currentSection => {
196
				if (currentSection.slug_section === sectionSelected.slug_section) {
197
					return {
198
						...currentSection,
199
						questions: currentSection.questions.filter((currentQuestion) => currentQuestion.slug_question !== slug)
200
					}
201
				}
202
				return currentSection
203
			}),
204
		)
205
	}
206
 
207
	// Option methods
208
	const showOptionModal = (option = INITIAL_OPTION, type = 'add') => {
209
		setIsShowOptionModal(true)
210
		setOptionType(type)
211
		setOptionSelected(option)
212
	}
213
 
13068 stevensc 214
	const closeOptionModal = () => {
215
		setIsShowOptionModal(false)
216
		setOptionSelected(INITIAL_QUESTION)
217
	}
218
 
13067 stevensc 219
	const addOption = (option) => {
220
		const uuid = new Date().getTime()
221
 
222
		setContent(current =>
223
			current.map(currentSection => {
224
				if (currentSection.slug_section === sectionSelected.slug_section) {
225
 
13069 stevensc 226
					return {
227
						...currentSection,
228
						questions: currentSection.questions.map(currentQuestion => {
229
							if (currentQuestion.slug_question === questionSelected.slug_question) {
230
 
231
								return {
232
									...currentQuestion,
233
									options: [
234
										...currentQuestion.options,
235
										{
236
											...option,
237
											slug_question: questionSelected.slug_question,
238
											slug_section: sectionSelected.slug_section,
239
											slug_option: `option${uuid}`
240
										}
241
									]
242
								}
13067 stevensc 243
							}
244
 
13069 stevensc 245
							return currentQuestion
246
						})
247
					}
13067 stevensc 248
				}
249
				return currentSection
250
			})
251
		)
252
	}
253
 
13070 stevensc 254
	const editOption = (option) => {
255
 
256
		setContent(current =>
257
			current.map(currentSection => {
258
				if (currentSection.slug_section === sectionSelected.slug_section) {
259
 
260
					return {
261
						...currentSection,
262
						questions: currentSection.questions.map(currentQuestion => {
263
							if (currentQuestion.slug_question === questionSelected.slug_question) {
264
 
265
								return {
266
									...currentQuestion,
267
									options: currentQuestion.options.map(currentOption => {
268
										if (currentOption.slug_option === option.slug_option) {
269
											return option
270
										}
271
 
272
										return currentOption
273
									})
274
								}
275
							}
276
 
277
							return currentQuestion
278
						})
279
					}
280
				}
281
				return currentSection
282
			})
283
		)
284
	}
285
 
13067 stevensc 286
	const deleteOption = (slug) => {
287
		setContent(current =>
288
			current.map(currentSection => {
289
				if (currentSection.slug_section === sectionSelected.slug_section) {
290
 
13069 stevensc 291
					return {
292
						...currentSection,
293
						questions: currentSection.questions.map(question => {
13067 stevensc 294
 
13069 stevensc 295
							if (question.slug_question === questionSelected.slug_question) {
296
								return {
297
									...question,
298
									options: question.options.filter(option => option.slug_option !== slug)
299
								}
13067 stevensc 300
							}
301
 
13069 stevensc 302
							return question
303
						})
304
					}
13067 stevensc 305
				}
306
 
307
				return currentSection
308
			}),
309
		)
310
	}
311
 
312
	// General methods
313
	const deleteHandler = (type, slug) => {
314
		if (type === 'section') {
315
			return deleteSection(slug)
316
		}
317
		if (type === 'question') {
318
			return deleteQuestion(slug)
319
		}
320
		if (type === 'option') {
321
			return deleteOption(slug)
322
		}
323
	}
324
 
13071 stevensc 325
	const validate = () => {
13072 stevensc 326
		const sectionError = content.find(section => !section.questions.length)
13073 stevensc 327
 
13077 stevensc 328
		if (sectionError) {
13072 stevensc 329
			dispatch(addNotification({
330
				style: 'danger',
331
				msg: `La sección ${sectionError.name} no tiene preguntas`
332
			}))
12709 stevensc 333
 
13072 stevensc 334
			return false
14361 kerby 335
		}else{
336
			return true
13072 stevensc 337
		}
13078 stevensc 338
	}
13071 stevensc 339
 
13078 stevensc 340
	const onSubmit = () => {
12709 stevensc 341
 
13078 stevensc 342
		const isValid = validate()
13073 stevensc 343
 
13078 stevensc 344
		if (isValid) {
345
			const submitData = new FormData()
346
			submitData.append('name', watch('name'))
347
			submitData.append('description', watch('description'))
348
			submitData.append('text', watch('text'))
349
			submitData.append('status', status)
350
			submitData.append('content', JSON.stringify(content))
12709 stevensc 351
 
13078 stevensc 352
			axios.post(actionLink, submitData)
353
				.then(({ data }) => {
354
					if (!data.success) {
355
						return dispatch(addNotification({
356
							style: 'danger',
357
							msg: typeof data.data === 'string'
358
								? data.data
359
								: 'Ha ocurrido un error'
360
						}))
361
					}
13071 stevensc 362
 
13078 stevensc 363
					dispatch(addNotification({
364
						style: 'success',
365
						msg: data.data
366
					}))
367
				})
368
		}
13071 stevensc 369
	}
370
 
12709 stevensc 371
	const submitAndClose = () => {
372
		onSubmit()
373
		reset()
374
		history.goBack()
375
	}
376
 
377
	useEffect(() => {
13008 stevensc 378
		register('text')
379
		register('description')
14369 kerby 380
		setDescription('')
13008 stevensc 381
	}, [])
382
 
383
	useEffect(() => {
12726 stevensc 384
		if (action === 'edit') {
385
			axios.get(actionLink)
386
				.then(({ data }) => {
387
					if (!data.success) {
388
						return dispatch(addNotification({
389
							style: 'danger',
390
							msg: 'Ha ocurrido un error'
391
						}))
392
					}
12709 stevensc 393
 
13008 stevensc 394
					register('text')
395
					register('description')
396
 
397
					setContent(data.data.content)
398
					setStatus(data.data.status)
399
 
12726 stevensc 400
					setValue('name', data.data.name)
401
					setValue('description', data.data.description)
402
					setValue('text', data.data.description)
14366 kerby 403
					setDescription(data.data.description)
404
					setText(data.data.text)
12726 stevensc 405
				})
406
		}
12709 stevensc 407
	}, [actionLink])
408
 
409
	return (
410
		<>
411
			<section className="content">
412
				<div className="row" style={{ padding: 16 }}>
413
					<div className="col-xs-12 col-md-12">
414
						<div className="form-group">
415
							<label>Nombre</label>
416
							<input type="text" name="name" className='form-control' ref={register({ required: true, maxLength: 50 })} />
417
						</div>
418
						<div className="form-group">
419
							<label htmlFor="form-description">Descripción</label>
14371 kerby 420
							{(description) &&
12856 stevensc 421
							<DescriptionInput
14366 kerby 422
								defaultValue={description}
12709 stevensc 423
								name='description'
14366 kerby 424
								onChange={setDescription}
14371 kerby 425
							/>}
14367 kerby 426
 
12709 stevensc 427
						</div>
428
						<div className="form-group">
429
							<label htmlFor="form-description">Texto</label>
12856 stevensc 430
							<DescriptionInput
14366 kerby 431
								defaultValue={text}
12709 stevensc 432
								name='text'
14366 kerby 433
								onChange={setText}
12856 stevensc 434
							/>
12709 stevensc 435
						</div>
436
						<div className="form-group">
437
							<label htmlFor="form-status">Estatus</label>
438
							<select name="form-status" className="form-control" onChange={(e) => setStatus(e.target.value)} value={status}>
12728 stevensc 439
								<option value="A">Activo</option>
440
								<option value="I">Inactivo</option>
12709 stevensc 441
							</select>
442
						</div>
443
						<br />
444
						<div className="row">
445
							<div className="col-xs-12 col-md-12">
446
								<div className="panel-group" id="rows" >
447
									<div className="form-group">
448
										<div className="row">
449
											<div className="col-xs-12 col-md-12">
450
												<hr />
12994 stevensc 451
												<div className="d-flex justify-content-end">
452
													<button className='btn btn-primary' onClick={() => showSectionModal()}>
453
														<i className="fa fa-plus" />
454
														Agregar sección
455
													</button>
456
												</div>
12709 stevensc 457
												<br />
458
												<div className="panel-group" id="rows-job-competencies" >
459
													{
460
														content.length > 0
12836 stevensc 461
														&&
462
														content.map((section) => {
12709 stevensc 463
 
12836 stevensc 464
															return (
465
																<div className="panel panel-default" key={section.slug_section}>
466
																	<div className="panel-heading">
467
																		<h4 className="panel-title">
468
																			<a className="accordion-toggle" data-toggle="collapse" aria-expanded="true" data-parent={`panel-${section.slug_section}`} href={`#collapse-${section.slug_section}`}>
469
																				<span className={`section-name${section.slug_section}`}>
470
																					{section.name}
471
																				</span>
472
																			</a>
473
																		</h4>
474
																	</div>
13071 stevensc 475
																	<div id={`collapse-section${section.slug_section}`} className="panel-collapse in collapse show">
12836 stevensc 476
																		<div className="panel-body">
477
																			<div className="table-responsive">
478
																				<table className="table table-bordered">
479
																					<thead>
480
																						<tr>
481
																							<th style={{ width: '10%' }}>Elemento</th>
482
																							<th style={{ width: '50%' }}>Texto</th>
483
																							<th style={{ width: '10%' }}>Tipo</th>
484
																							<th style={{ width: '20%' }}>Acciones</th>
485
																						</tr>
486
																					</thead>
487
																					<tbody>
488
																						<tr className="tr-section">
489
																							<td className="text-left">Sección</td>
490
																							<td className="text-left">{section.name}</td>
491
																							<td />
492
																							<td>
493
																								<button className="btn btn-default" onClick={() => showSectionModal(section, 'edit')}>
494
																									<i className="fa fa-edit" />
495
																									Editar Sección
496
																								</button>
12994 stevensc 497
																								<button className="btn btn-default" onClick={() => {
13007 stevensc 498
																									setSectionSelected(section)
499
																									setDeleteType('section')
12993 stevensc 500
																									setShowDeleteModal(true)
501
																								}}>
12836 stevensc 502
																									<i className="fa fa-ban" />
503
																									Borrar Sección
504
																								</button>
13003 stevensc 505
																								<button className="btn btn-default" onClick={() => {
13007 stevensc 506
																									setSectionSelected(section)
13003 stevensc 507
																									showQuestionModal()
508
																								}}>
12836 stevensc 509
																									<i className="fa fa-plus" />
510
																									Agregar  Pregunta
511
																								</button>
512
																							</td>
513
																						</tr>
514
																						{
515
																							section.questions.map((question) => (
13067 stevensc 516
																								<>
517
																									<tr key={question.slug_question} className="tr-question">
518
																										<td className="text-left">Pregunta</td>
519
																										<td className="text-left">
520
																											{parse(question.text)}
521
																										</td>
522
																										<td className="text-capitalize">
523
																											{sectionTypeOptions[question.type]}
524
																										</td>
525
																										<td>
526
																											<button className="btn btn-default" onClick={() => {
527
																												setSectionSelected(section)
528
																												showQuestionModal(question, 'edit')
529
																											}}>
530
																												<i className="fa fa-edit" /> Editar Pregunta
12996 stevensc 531
																											</button>
13067 stevensc 532
																											<button className="btn btn-default" onClick={() => {
13070 stevensc 533
																												setSectionSelected(section)
13067 stevensc 534
																												setQuestionSelected(question)
535
																												setDeleteType('question')
536
																												setShowDeleteModal(true)
537
																											}}>
538
																												<i className="fa fa-ban" /> Borrar Pregunta
539
																											</button>
540
																											{
541
																												question.type !== 'open'
542
																												&&
13068 stevensc 543
																												<button className="btn btn-default" onClick={() => {
544
																													setSectionSelected(section)
545
																													setQuestionSelected(question)
546
																													showOptionModal()
547
																												}}>
13067 stevensc 548
																													<i className="fa fa-plus" /> Agregar opción
549
																												</button>
550
																											}
551
																										</td>
552
																									</tr>
553
																									{
554
																										question.options.map(option => (
555
																											<tr key={option.slug_question} className="tr-option">
13069 stevensc 556
																												<td className="text-left">Opción</td>
13067 stevensc 557
																												<td className="text-left">
558
																													{parse(option.text)}
559
																												</td>
560
																												<td />
561
																												<td>
562
																													<button className="btn btn-default" onClick={() => {
563
																														setSectionSelected(section)
564
																														setQuestionSelected(question)
565
																														showOptionModal(option, 'edit')
566
																													}}>
567
																														<i className="fa fa-edit" /> Editar opción
568
																													</button>
569
																													<button className="btn btn-default" onClick={() => {
570
																														setOptionSelected(option)
13070 stevensc 571
																														setSectionSelected(section)
13067 stevensc 572
																														setQuestionSelected(question)
573
																														setDeleteType('option')
574
																														setShowDeleteModal(true)
575
																													}}>
576
																														<i className="fa fa-ban" /> Borrar opción
577
																													</button>
578
																												</td>
579
																											</tr>
580
																										))
581
																									}
582
																								</>
12836 stevensc 583
																							))
584
																						}
13067 stevensc 585
 
12836 stevensc 586
																					</tbody>
587
																				</table>
588
																			</div>
589
																		</div>
590
																	</div>
591
																</div>
592
															)
593
														})
12709 stevensc 594
													}
595
												</div>
596
											</div>
597
										</div>
598
									</div>
599
								</div>
600
							</div>
601
						</div>
602
						<div className="d-flex" style={{ gap: '5px' }}>
603
							<button type="button" className="btn btn-info" onClick={onSubmit}>Guardar & Continuar</button>
604
							<button type="button" className="btn btn-primary" onClick={submitAndClose}>Guardar & Cerrar</button>
605
							<button type="button" className="btn btn-secondary" onClick={() => history.goBack()}>Cancelar</button>
606
						</div>
607
					</div>
608
				</div >
609
			</section >
610
			<SectionModal
611
				show={isShowSection}
12836 stevensc 612
				sectionType={sectionType}
12709 stevensc 613
				section={sectionSelected}
614
				closeModal={closeSectionModal}
615
				onSubmit={sectionType === 'add' ? addSection : editSection}
616
			/>
12996 stevensc 617
			<QuestionModal
618
				show={isShowQuestion}
619
				questionType={questionType}
620
				question={questionSelected}
621
				closeModal={closeQuestionModal}
622
				onSubmit={questionType === 'add' ? addQuestion : editQuestion}
623
			/>
13067 stevensc 624
			<OptionModal
625
				show={isShowOption}
13068 stevensc 626
				optionType={optionType}
627
				option={optionSelected}
13067 stevensc 628
				closeModal={closeOptionModal}
13070 stevensc 629
				onSubmit={optionType === 'add' ? addOption : editOption}
13067 stevensc 630
			/>
12993 stevensc 631
			<DeleteModal
632
				isOpen={showDeleteModal}
633
				closeModal={() => setShowDeleteModal(false)}
13007 stevensc 634
				onComplete={() => deleteHandler(deleteType, deleteSlugsOptions[deleteType])}
12993 stevensc 635
				message="Registro eliminado"
636
			/>
12709 stevensc 637
		</>
638
	)
639
}
640
 
641
export default FormView