Proyectos de Subversion LeadersLinked - Backend

Rev

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