Proyectos de Subversion LeadersLinked - Backend

Rev

Rev 14372 | Rev 14374 | 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')
14373 kerby 380
		if(action != 'edit'){
381
			setDescription(' ')
382
			setText(' ')
383
		}
384
 
13008 stevensc 385
	}, [])
386
 
387
	useEffect(() => {
12726 stevensc 388
		if (action === 'edit') {
389
			axios.get(actionLink)
390
				.then(({ data }) => {
391
					if (!data.success) {
392
						return dispatch(addNotification({
393
							style: 'danger',
394
							msg: 'Ha ocurrido un error'
395
						}))
396
					}
12709 stevensc 397
 
13008 stevensc 398
					register('text')
399
					register('description')
400
 
401
					setContent(data.data.content)
402
					setStatus(data.data.status)
403
 
12726 stevensc 404
					setValue('name', data.data.name)
405
					setValue('description', data.data.description)
406
					setValue('text', data.data.description)
14366 kerby 407
					setDescription(data.data.description)
408
					setText(data.data.text)
12726 stevensc 409
				})
410
		}
12709 stevensc 411
	}, [actionLink])
412
 
413
	return (
414
		<>
415
			<section className="content">
416
				<div className="row" style={{ padding: 16 }}>
417
					<div className="col-xs-12 col-md-12">
418
						<div className="form-group">
419
							<label>Nombre</label>
420
							<input type="text" name="name" className='form-control' ref={register({ required: true, maxLength: 50 })} />
421
						</div>
422
						<div className="form-group">
423
							<label htmlFor="form-description">Descripción</label>
14371 kerby 424
							{(description) &&
12856 stevensc 425
							<DescriptionInput
14366 kerby 426
								defaultValue={description}
12709 stevensc 427
								name='description'
14366 kerby 428
								onChange={setDescription}
14371 kerby 429
							/>}
14367 kerby 430
 
12709 stevensc 431
						</div>
432
						<div className="form-group">
433
							<label htmlFor="form-description">Texto</label>
14373 kerby 434
							{(text) &&
12856 stevensc 435
							<DescriptionInput
14366 kerby 436
								defaultValue={text}
12709 stevensc 437
								name='text'
14366 kerby 438
								onChange={setText}
14373 kerby 439
							/>}
12709 stevensc 440
						</div>
441
						<div className="form-group">
442
							<label htmlFor="form-status">Estatus</label>
443
							<select name="form-status" className="form-control" onChange={(e) => setStatus(e.target.value)} value={status}>
12728 stevensc 444
								<option value="A">Activo</option>
445
								<option value="I">Inactivo</option>
12709 stevensc 446
							</select>
447
						</div>
448
						<br />
449
						<div className="row">
450
							<div className="col-xs-12 col-md-12">
451
								<div className="panel-group" id="rows" >
452
									<div className="form-group">
453
										<div className="row">
454
											<div className="col-xs-12 col-md-12">
455
												<hr />
12994 stevensc 456
												<div className="d-flex justify-content-end">
457
													<button className='btn btn-primary' onClick={() => showSectionModal()}>
458
														<i className="fa fa-plus" />
459
														Agregar sección
460
													</button>
461
												</div>
12709 stevensc 462
												<br />
463
												<div className="panel-group" id="rows-job-competencies" >
464
													{
465
														content.length > 0
12836 stevensc 466
														&&
467
														content.map((section) => {
12709 stevensc 468
 
12836 stevensc 469
															return (
470
																<div className="panel panel-default" key={section.slug_section}>
471
																	<div className="panel-heading">
472
																		<h4 className="panel-title">
473
																			<a className="accordion-toggle" data-toggle="collapse" aria-expanded="true" data-parent={`panel-${section.slug_section}`} href={`#collapse-${section.slug_section}`}>
474
																				<span className={`section-name${section.slug_section}`}>
475
																					{section.name}
476
																				</span>
477
																			</a>
478
																		</h4>
479
																	</div>
13071 stevensc 480
																	<div id={`collapse-section${section.slug_section}`} className="panel-collapse in collapse show">
12836 stevensc 481
																		<div className="panel-body">
482
																			<div className="table-responsive">
483
																				<table className="table table-bordered">
484
																					<thead>
485
																						<tr>
486
																							<th style={{ width: '10%' }}>Elemento</th>
487
																							<th style={{ width: '50%' }}>Texto</th>
488
																							<th style={{ width: '10%' }}>Tipo</th>
489
																							<th style={{ width: '20%' }}>Acciones</th>
490
																						</tr>
491
																					</thead>
492
																					<tbody>
493
																						<tr className="tr-section">
494
																							<td className="text-left">Sección</td>
495
																							<td className="text-left">{section.name}</td>
496
																							<td />
497
																							<td>
498
																								<button className="btn btn-default" onClick={() => showSectionModal(section, 'edit')}>
499
																									<i className="fa fa-edit" />
500
																									Editar Sección
501
																								</button>
12994 stevensc 502
																								<button className="btn btn-default" onClick={() => {
13007 stevensc 503
																									setSectionSelected(section)
504
																									setDeleteType('section')
12993 stevensc 505
																									setShowDeleteModal(true)
506
																								}}>
12836 stevensc 507
																									<i className="fa fa-ban" />
508
																									Borrar Sección
509
																								</button>
13003 stevensc 510
																								<button className="btn btn-default" onClick={() => {
13007 stevensc 511
																									setSectionSelected(section)
13003 stevensc 512
																									showQuestionModal()
513
																								}}>
12836 stevensc 514
																									<i className="fa fa-plus" />
515
																									Agregar  Pregunta
516
																								</button>
517
																							</td>
518
																						</tr>
519
																						{
520
																							section.questions.map((question) => (
13067 stevensc 521
																								<>
522
																									<tr key={question.slug_question} className="tr-question">
523
																										<td className="text-left">Pregunta</td>
524
																										<td className="text-left">
525
																											{parse(question.text)}
526
																										</td>
527
																										<td className="text-capitalize">
528
																											{sectionTypeOptions[question.type]}
529
																										</td>
530
																										<td>
531
																											<button className="btn btn-default" onClick={() => {
532
																												setSectionSelected(section)
533
																												showQuestionModal(question, 'edit')
534
																											}}>
535
																												<i className="fa fa-edit" /> Editar Pregunta
12996 stevensc 536
																											</button>
13067 stevensc 537
																											<button className="btn btn-default" onClick={() => {
13070 stevensc 538
																												setSectionSelected(section)
13067 stevensc 539
																												setQuestionSelected(question)
540
																												setDeleteType('question')
541
																												setShowDeleteModal(true)
542
																											}}>
543
																												<i className="fa fa-ban" /> Borrar Pregunta
544
																											</button>
545
																											{
546
																												question.type !== 'open'
547
																												&&
13068 stevensc 548
																												<button className="btn btn-default" onClick={() => {
549
																													setSectionSelected(section)
550
																													setQuestionSelected(question)
551
																													showOptionModal()
552
																												}}>
13067 stevensc 553
																													<i className="fa fa-plus" /> Agregar opción
554
																												</button>
555
																											}
556
																										</td>
557
																									</tr>
558
																									{
559
																										question.options.map(option => (
560
																											<tr key={option.slug_question} className="tr-option">
13069 stevensc 561
																												<td className="text-left">Opción</td>
13067 stevensc 562
																												<td className="text-left">
563
																													{parse(option.text)}
564
																												</td>
565
																												<td />
566
																												<td>
567
																													<button className="btn btn-default" onClick={() => {
568
																														setSectionSelected(section)
569
																														setQuestionSelected(question)
570
																														showOptionModal(option, 'edit')
571
																													}}>
572
																														<i className="fa fa-edit" /> Editar opción
573
																													</button>
574
																													<button className="btn btn-default" onClick={() => {
575
																														setOptionSelected(option)
13070 stevensc 576
																														setSectionSelected(section)
13067 stevensc 577
																														setQuestionSelected(question)
578
																														setDeleteType('option')
579
																														setShowDeleteModal(true)
580
																													}}>
581
																														<i className="fa fa-ban" /> Borrar opción
582
																													</button>
583
																												</td>
584
																											</tr>
585
																										))
586
																									}
587
																								</>
12836 stevensc 588
																							))
589
																						}
13067 stevensc 590
 
12836 stevensc 591
																					</tbody>
592
																				</table>
593
																			</div>
594
																		</div>
595
																	</div>
596
																</div>
597
															)
598
														})
12709 stevensc 599
													}
600
												</div>
601
											</div>
602
										</div>
603
									</div>
604
								</div>
605
							</div>
606
						</div>
607
						<div className="d-flex" style={{ gap: '5px' }}>
608
							<button type="button" className="btn btn-info" onClick={onSubmit}>Guardar & Continuar</button>
609
							<button type="button" className="btn btn-primary" onClick={submitAndClose}>Guardar & Cerrar</button>
610
							<button type="button" className="btn btn-secondary" onClick={() => history.goBack()}>Cancelar</button>
611
						</div>
612
					</div>
613
				</div >
614
			</section >
615
			<SectionModal
616
				show={isShowSection}
12836 stevensc 617
				sectionType={sectionType}
12709 stevensc 618
				section={sectionSelected}
619
				closeModal={closeSectionModal}
620
				onSubmit={sectionType === 'add' ? addSection : editSection}
621
			/>
12996 stevensc 622
			<QuestionModal
623
				show={isShowQuestion}
624
				questionType={questionType}
625
				question={questionSelected}
626
				closeModal={closeQuestionModal}
627
				onSubmit={questionType === 'add' ? addQuestion : editQuestion}
628
			/>
13067 stevensc 629
			<OptionModal
630
				show={isShowOption}
13068 stevensc 631
				optionType={optionType}
632
				option={optionSelected}
13067 stevensc 633
				closeModal={closeOptionModal}
13070 stevensc 634
				onSubmit={optionType === 'add' ? addOption : editOption}
13067 stevensc 635
			/>
12993 stevensc 636
			<DeleteModal
637
				isOpen={showDeleteModal}
638
				closeModal={() => setShowDeleteModal(false)}
13007 stevensc 639
				onComplete={() => deleteHandler(deleteType, deleteSlugsOptions[deleteType])}
12993 stevensc 640
				message="Registro eliminado"
641
			/>
12709 stevensc 642
		</>
643
	)
644
}
645
 
646
export default FormView