Proyectos de Subversion LeadersLinked - Backend

Rev

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