Proyectos de Subversion LeadersLinked - Backend

Rev

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