Proyectos de Subversion LeadersLinked - Backend

Rev

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