dmencu 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/dist/client/client/client.js +372 -0
  2. package/dist/client/client/css/form-data-signals-2.styl +11 -0
  3. package/dist/client/client/css/form-data-signals.styl +68 -0
  4. package/dist/client/client/css/menu.styl +6 -0
  5. package/dist/client/client/img/ba_etiqueta.jpg +0 -0
  6. package/dist/client/client/img/logo_etiqueta.jpg +0 -0
  7. package/dist/client/client/img/mandatory.png +0 -0
  8. package/dist/client/client/img/optativo.png +0 -0
  9. package/dist/client/client/img/pk-mandatory.png +0 -0
  10. package/dist/client/client/img/wait4this.png +0 -0
  11. package/dist/client/client/menu.js +3 -0
  12. package/dist/client/client/tsconfig.json +14 -0
  13. package/dist/client/unlogged/abrir-formulario.js +99 -0
  14. package/dist/client/unlogged/bypass-formulario.js +1141 -0
  15. package/dist/client/unlogged/css/Roboto-Regular.ttf +0 -0
  16. package/dist/client/unlogged/css/bootstrap.min.css +7 -0
  17. package/dist/client/unlogged/css/formulario-react.styl +756 -0
  18. package/dist/client/unlogged/img/PREJU_2022-logo-dm-192.png +0 -0
  19. package/dist/client/unlogged/img/PREJU_2022-logo-dm-192_capa.png +0 -0
  20. package/dist/client/unlogged/img/PREJU_2022-logo-dm-192_test.png +0 -0
  21. package/dist/client/unlogged/img/PREJU_2022-logo-dm-32.png +0 -0
  22. package/dist/client/unlogged/img/PREJU_2022-logo-dm-32_capa.png +0 -0
  23. package/dist/client/unlogged/img/PREJU_2022-logo-dm-32_test.png +0 -0
  24. package/dist/client/unlogged/img/PREJU_2022-logo-dm-48.png +0 -0
  25. package/dist/client/unlogged/img/PREJU_2022-logo-dm-48_capa.png +0 -0
  26. package/dist/client/unlogged/img/PREJU_2022-logo-dm-48_test.png +0 -0
  27. package/dist/client/unlogged/img/PREJU_2022-logo-dm-512.png +0 -0
  28. package/dist/client/unlogged/img/PREJU_2022-logo-dm-512_capa.png +0 -0
  29. package/dist/client/unlogged/img/PREJU_2022-logo-dm-512_test.png +0 -0
  30. package/dist/client/unlogged/img/PREJU_2022-logo-dm-64.png +0 -0
  31. package/dist/client/unlogged/img/PREJU_2022-logo-dm-64_capa.png +0 -0
  32. package/dist/client/unlogged/img/PREJU_2022-logo-dm-64_test.png +0 -0
  33. package/dist/client/unlogged/img/PREJU_2022-logo-dm-72.png +0 -0
  34. package/dist/client/unlogged/img/PREJU_2022-logo-dm-72_capa.png +0 -0
  35. package/dist/client/unlogged/img/PREJU_2022-logo-dm-72_test.png +0 -0
  36. package/dist/client/unlogged/img/_login-logo-icon.png +0 -0
  37. package/dist/client/unlogged/img/_logo-128.png +0 -0
  38. package/dist/client/unlogged/img/_logo.png +0 -0
  39. package/dist/client/unlogged/img/borrar-valor.pdn +0 -0
  40. package/dist/client/unlogged/img/borrar-valor.png +0 -0
  41. package/dist/client/unlogged/img/fondo-salteado-crudo.pdn +0 -0
  42. package/dist/client/unlogged/img/fondo-salteado-error.png +0 -0
  43. package/dist/client/unlogged/img/fondo-salteado.pdn +0 -0
  44. package/dist/client/unlogged/img/fondo-salteado.png +0 -0
  45. package/dist/client/unlogged/img/img-logo-dgeyc_blanco.png +0 -0
  46. package/dist/client/unlogged/img/login-logo-icon.png +0 -0
  47. package/dist/client/unlogged/img/logo-128.png +0 -0
  48. package/dist/client/unlogged/img/logo.png +0 -0
  49. package/dist/client/unlogged/img/logos-gcbs-blanco-150x57.png +0 -0
  50. package/dist/client/unlogged/offline.jade +10 -0
  51. package/dist/client/unlogged/redux-formulario.js +315 -0
  52. package/dist/client/unlogged/render-formulario.tsx +2103 -0
  53. package/dist/client/unlogged/render-general.tsx +228 -0
  54. package/dist/client/unlogged/tipos.js +19 -0
  55. package/dist/client/unlogged/tsconfig.json +15 -0
  56. package/dist/server/server/app-dmencu.js +641 -0
  57. package/dist/server/server/def-config.js +108 -0
  58. package/dist/server/server/procedures-dmencu.js +759 -0
  59. package/dist/server/server/server-dmencu.js +23 -0
  60. package/dist/server/server/table-areas.js +121 -0
  61. package/dist/server/server/table-comunas.js +29 -0
  62. package/dist/server/server/table-control_campo.js +100 -0
  63. package/dist/server/server/table-control_resumen.js +19 -0
  64. package/dist/server/server/table-encuestadores.js +19 -0
  65. package/dist/server/server/table-hogares.js +157 -0
  66. package/dist/server/server/table-hogares_sup.js +192 -0
  67. package/dist/server/server/table-lotes.js +44 -0
  68. package/dist/server/server/table-mis_encuestadores.js +78 -0
  69. package/dist/server/server/table-mis_tareas.js +19 -0
  70. package/dist/server/server/table-mis_tareas_areas.js +19 -0
  71. package/dist/server/server/table-mis_tareas_tem.js +19 -0
  72. package/dist/server/server/table-no_rea.js +33 -0
  73. package/dist/server/server/table-no_rea_sup.js +33 -0
  74. package/dist/server/server/table-operaciones.js +31 -0
  75. package/dist/server/server/table-parametros.js +40 -0
  76. package/dist/server/server/table-permisos.js +32 -0
  77. package/dist/server/server/table-personal.js +63 -0
  78. package/dist/server/server/table-personal_rol.js +43 -0
  79. package/dist/server/server/table-personas.js +449 -0
  80. package/dist/server/server/table-personas_sup.js +94 -0
  81. package/dist/server/server/table-recepcionistas.js +19 -0
  82. package/dist/server/server/table-recuperadores.js +19 -0
  83. package/dist/server/server/table-resultados_tarea.js +29 -0
  84. package/dist/server/server/table-roles.js +33 -0
  85. package/dist/server/server/table-roles_permisos.js +36 -0
  86. package/dist/server/server/table-roles_subordinados.js +33 -0
  87. package/dist/server/server/table-semanas.js +42 -0
  88. package/dist/server/server/table-sincronizaciones.js +31 -0
  89. package/dist/server/server/table-supervisores.js +19 -0
  90. package/dist/server/server/table-tareas.js +47 -0
  91. package/dist/server/server/table-tareas_areas.js +68 -0
  92. package/dist/server/server/table-tareas_tem.js +148 -0
  93. package/dist/server/server/table-tem.js +187 -0
  94. package/dist/server/server/table-tem_recepcion.js +19 -0
  95. package/dist/server/server/table-usuarios.js +59 -0
  96. package/dist/server/server/table-visitas.js +92 -0
  97. package/dist/server/server/table-visitas_sup.js +92 -0
  98. package/dist/server/server/table-viviendas.js +300 -0
  99. package/dist/server/server/types-dmencu.js +24 -0
  100. package/dist/server/unlogged/tipos.js +19 -0
  101. package/dist/unlogged/unlogged/abrir-formulario.js +99 -0
  102. package/dist/unlogged/unlogged/adapt.js +8 -0
  103. package/dist/unlogged/unlogged/bypass-formulario.js +1141 -0
  104. package/dist/unlogged/unlogged/css/Roboto-Regular.ttf +0 -0
  105. package/dist/unlogged/unlogged/css/bootstrap.min.css +7 -0
  106. package/dist/unlogged/unlogged/css/formulario-react.styl +756 -0
  107. package/dist/unlogged/unlogged/img/PREJU_2022-logo-dm-192.png +0 -0
  108. package/dist/unlogged/unlogged/img/PREJU_2022-logo-dm-192_capa.png +0 -0
  109. package/dist/unlogged/unlogged/img/PREJU_2022-logo-dm-192_test.png +0 -0
  110. package/dist/unlogged/unlogged/img/PREJU_2022-logo-dm-32.png +0 -0
  111. package/dist/unlogged/unlogged/img/PREJU_2022-logo-dm-32_capa.png +0 -0
  112. package/dist/unlogged/unlogged/img/PREJU_2022-logo-dm-32_test.png +0 -0
  113. package/dist/unlogged/unlogged/img/PREJU_2022-logo-dm-48.png +0 -0
  114. package/dist/unlogged/unlogged/img/PREJU_2022-logo-dm-48_capa.png +0 -0
  115. package/dist/unlogged/unlogged/img/PREJU_2022-logo-dm-48_test.png +0 -0
  116. package/dist/unlogged/unlogged/img/PREJU_2022-logo-dm-512.png +0 -0
  117. package/dist/unlogged/unlogged/img/PREJU_2022-logo-dm-512_capa.png +0 -0
  118. package/dist/unlogged/unlogged/img/PREJU_2022-logo-dm-512_test.png +0 -0
  119. package/dist/unlogged/unlogged/img/PREJU_2022-logo-dm-64.png +0 -0
  120. package/dist/unlogged/unlogged/img/PREJU_2022-logo-dm-64_capa.png +0 -0
  121. package/dist/unlogged/unlogged/img/PREJU_2022-logo-dm-64_test.png +0 -0
  122. package/dist/unlogged/unlogged/img/PREJU_2022-logo-dm-72.png +0 -0
  123. package/dist/unlogged/unlogged/img/PREJU_2022-logo-dm-72_capa.png +0 -0
  124. package/dist/unlogged/unlogged/img/PREJU_2022-logo-dm-72_test.png +0 -0
  125. package/dist/unlogged/unlogged/img/_login-logo-icon.png +0 -0
  126. package/dist/unlogged/unlogged/img/_logo-128.png +0 -0
  127. package/dist/unlogged/unlogged/img/_logo.png +0 -0
  128. package/dist/unlogged/unlogged/img/borrar-valor.pdn +0 -0
  129. package/dist/unlogged/unlogged/img/borrar-valor.png +0 -0
  130. package/dist/unlogged/unlogged/img/fondo-salteado-crudo.pdn +0 -0
  131. package/dist/unlogged/unlogged/img/fondo-salteado-error.png +0 -0
  132. package/dist/unlogged/unlogged/img/fondo-salteado.pdn +0 -0
  133. package/dist/unlogged/unlogged/img/fondo-salteado.png +0 -0
  134. package/dist/unlogged/unlogged/img/img-logo-dgeyc_blanco.png +0 -0
  135. package/dist/unlogged/unlogged/img/login-logo-icon.png +0 -0
  136. package/dist/unlogged/unlogged/img/logo-128.png +0 -0
  137. package/dist/unlogged/unlogged/img/logo.png +0 -0
  138. package/dist/unlogged/unlogged/img/logos-gcbs-blanco-150x57.png +0 -0
  139. package/dist/unlogged/unlogged/offline.jade +10 -0
  140. package/dist/unlogged/unlogged/redux-formulario.js +315 -0
  141. package/dist/unlogged/unlogged/render-formulario.js +1485 -0
  142. package/dist/unlogged/unlogged/render-formulario.tsx +2103 -0
  143. package/dist/unlogged/unlogged/render-general.js +185 -0
  144. package/dist/unlogged/unlogged/render-general.tsx +228 -0
  145. package/dist/unlogged/unlogged/tipos.js +19 -0
  146. package/dist/unlogged/unlogged/tsconfig.json +15 -0
  147. package/dist/unlogged/unlogged/unlogged.js +180 -0
  148. package/package.json +91 -0
@@ -0,0 +1,2103 @@
1
+ import * as React from "react";
2
+ import * as ReactDOM from "react-dom";
3
+ import {
4
+ RenderPrincipal,
5
+ adaptarTipoVarCasillero,
6
+ ICON,
7
+ focusToId,
8
+ scrollToTop,
9
+ scrollToBottom,
10
+ materialIoIconsSvgPath
11
+ } from "./render-general";
12
+ import {Bloque, BotonFormulario,
13
+ CasilleroBase, CasoState, ConjuntoPreguntas, Consistencia,
14
+ EstadoCarga, Filtro, ForPk, ForPkRaiz, Formulario,
15
+ IdFormulario, IdPregunta, IdTarea, IdVariable, InfoFormulario,
16
+ HojaDeRuta,
17
+ ModoDespliegue,
18
+ Opcion, OpcionMultiple, PlainForPk,
19
+ Pregunta, PreguntaConOpciones, PreguntaSimple,
20
+ Respuestas, RespuestasRaiz, Valor, TEM, IdCarga, Carga, IdFin, IdUnidadAnalisis,
21
+ ModoAlmacenamiento,
22
+ toPlainForPk,
23
+ IdCasillero,
24
+ PreguntaConSiNo,
25
+ Texto, Estructura, InformacionHdr, DatosHdrUaPpal, ConfiguracionSorteoFormulario, ResumenEstado, DatosByPassPersistibles, IdOperativo, IdEnc
26
+ } from "./tipos";
27
+ import{
28
+ accion_abrir_formulario,
29
+ accion_borrar_formulario,
30
+ calcularActualBF,
31
+ calcularDisabledBF,
32
+ calcularPermiteBorrarBF,
33
+ calcularResumenVivienda,
34
+ getDatosByPass,
35
+ getFormulariosForIdVivienda,
36
+ getMainFormForVivienda,
37
+ intentarBackup,
38
+ setCalcularVariables
39
+ } from "./bypass-formulario"
40
+ import { dmTraerDatosFormulario, dispatchers,
41
+ gotoSincronizar,
42
+ getCacheVersion,
43
+ gotoConsistir,
44
+ } from "./redux-formulario";
45
+ import { useState, useEffect, useLayoutEffect } from "react";
46
+ import { useSelector, useDispatch } from "react-redux";
47
+ import { strict as likeAr, beingArray } from "like-ar";
48
+ import {sleep, coalesce} from "best-globals";
49
+ import { unexpected } from "cast-error";
50
+
51
+ import {
52
+ AppBar, ButtonGroup, CircularProgress, Checkbox,
53
+ Dialog, DialogActions, DialogContent, DialogContentText,
54
+ DialogTitle, Divider, Fab, IconButton,
55
+ Menu, MenuItem, Paper, Popover,
56
+ Table, TableBody, TableCell, TableHead, TableRow, Toolbar
57
+ } from "@material-ui/core";
58
+ import { EstadoVariable, FormStructureState } from "row-validator";
59
+ import { CSSProperties } from "@material-ui/core/styles/withStyles";
60
+
61
+ import {
62
+ registrarElemento, setAttrDistinto, setValorDistinto, dispatchByPass,
63
+ getDirty, getHojaDeRuta, getFeedbackRowValidator,
64
+ getFuncionHabilitar,
65
+ getEstructura,
66
+ defOperativo,
67
+ volcadoInicialElementosRegistrados,
68
+ numberOrStringIncIfArray,
69
+ calcularElementoEnfocado,
70
+ accion_registrar_respuesta,
71
+ accion_id_pregunta,
72
+ accion_agregar_formulario,
73
+ NO_CAMBIAR__VERIFICAR_SI_ES_NECESARIO,
74
+ NO_CAMBIAR__SOLO_TRAER_STATUS
75
+ } from "./bypass-formulario"
76
+
77
+ import {arrange, html, HtmlTag} from "js-to-html";
78
+
79
+ function breakeableText(text:string|null):string|undefined;
80
+ function breakeableText(text:string|null, diccionario?:{[clave:string]:React.ReactNode}){
81
+ if(typeof text != "string") return undefined;
82
+ text = text.replace(/\//g,"/\u2063").replace(/\/\u2063(\w)\b/g,'/$1');
83
+ text = text.replace(/___*/g,(todo)=>`[${todo}]`).replace(/\@\w+\@/g,(todo)=>`[${todo}]`);
84
+ if(!diccionario || true) return text;
85
+ /*
86
+ return <span>{partes.map((parte:string, i:number) => <span style={i%2==1?{textDecoration:"underline"}:{}}> {parte+" "} </span>)}</span>
87
+ */
88
+ }
89
+
90
+ const VER_DOMINIO = false; // el encuestador no necesita ver el dominio en cada encuesta porque el dominio depende del área y se deduce del primer dígito del número de encuesta
91
+ // no poner VER_DOMINIO en true, cambiar por una variable que se fije si el DM está en modo prueba o en modo "diseño conceptual"
92
+
93
+ var debeSaltar:boolean = false;
94
+
95
+ window.addEventListener('load', ()=>{
96
+ /*
97
+ window.addEventListener('keydown', (ev:KeyboardEvent)=>{
98
+ debeSaltar = ev.key == 'Enter' || ev.keyCode == 13;
99
+ })
100
+ */
101
+ window.addEventListener('click', ()=>{
102
+ debeSaltar = false;
103
+ })
104
+ })
105
+
106
+ // /*
107
+
108
+ type CommonAttributes = {className?:string,style?:CSSProperties,id?:string, tabIndex?:number} // CSSProperties
109
+ type ColorValues = 'primary'|'secondary'|'default'|'inherit'
110
+
111
+ const Button = ({variant, onClick, disabled, children, className, color, size,
112
+ disableElevation, disableFocusRipple, disableRipple, fullWidth,
113
+ ...other
114
+ }:{
115
+ variant?:string,
116
+ color?:ColorValues,
117
+ onClick?:React.MouseEventHandler<HTMLButtonElement>, // (event:MouseEvent/* <HTMLButtonElement, MouseEvent>*/)=>void,
118
+ disabled?:boolean
119
+ children:any,
120
+ className?:string,
121
+ size?:'small',
122
+ disableElevation?:any, disableFocusRipple?:any, disableRipple?:any,
123
+ } & CommonAttributes)=><button
124
+ {...other}
125
+ className={`btn btn${variant=='contained'?'':'-'+(variant=='outlined'?'outline':variant)}-${(color=='default' || color=='inherit'?'secondary':color=='secondary'?'danger':color)||'secondary'} ${className||''} ${size=='small'?'btn-sm':''}`}
126
+ disabled={disabled}
127
+ onClick={onClick}
128
+ >{children}</button>;
129
+
130
+ const Button2 = ({variant, onClick, disabled, children, className, color, size, ...other}:{
131
+ variant?:string,
132
+ color?:ColorValues,
133
+ onClick?:()=>void,
134
+ disabled?:boolean
135
+ children:any,
136
+ className?:string,
137
+ size?:'small',
138
+ $attrs?:{}
139
+ } & CommonAttributes)=>html.button({
140
+ ...other,
141
+ class: `btn btn${variant=='contained'?'':'-'+(variant=='outlined'?'outline':variant)}-${(color=='default' || color=='inherit'?'secondary':color=='secondary'?'danger':color)||'secondary'} ${className||''} ${size=='small'?'btn-sm':''}`,
142
+ disabled,
143
+ $on:{click:onClick}
144
+ }, children);
145
+
146
+
147
+ const TextField = (props:{
148
+ id:string,
149
+ disabled?:boolean,
150
+ className?:string,
151
+ autoFocus?:boolean,
152
+ fullWidth:boolean
153
+ inputProps?:any,
154
+ value?:any,
155
+ type:any,
156
+ label?:string,
157
+ error?:boolean,
158
+ helperText?:string,
159
+ multiline?:boolean,
160
+ onChange?:(event:any)=>void,
161
+ onFocus?:(event:any)=>void,
162
+ onBlur?:(event:any, valor:any)=>void,
163
+ onKeyDown?:(event:KeyboardEvent)=>void
164
+ })=><input
165
+ id={props.id}
166
+ disabled={props.disabled}
167
+ className={props.className}
168
+ autoFocus={props.autoFocus}
169
+ value={props.value}
170
+ type={props.type}
171
+ onChange={props.onChange}
172
+ onFocus={props.onFocus}
173
+ onBlur={(evt)=>props.onBlur?.(evt, evt.target.value)}
174
+ onKeyDown={props.onKeyDown}
175
+ placeholder={props.label}
176
+ />;
177
+
178
+ const Typography = ({children, ...others}:{
179
+ children:any,
180
+ component?:string
181
+ variant?:'h6'
182
+ }&CommonAttributes)=>React.createElement(others.variant||others.component||'div',others,children);
183
+
184
+ function Grid(props:{
185
+ container?:boolean,
186
+ spacing?:number,
187
+ item?:boolean,
188
+ wrap?:'wrap'|'nowrap',
189
+ direction?:'row'|'column'
190
+ alignItems?:'stretch' | 'flex-start' | 'flex-end' | 'center' | 'baseline',
191
+ children:any,
192
+ xs?:number,
193
+ sm?:number,
194
+ }&CommonAttributes){
195
+ var {container, item, wrap, direction, alignItems, children, className, xs, sm, spacing, ...other} = props;
196
+ return <div
197
+ {...other}
198
+ className={`${className||''} ${xs!=null?'grid-xs-'+xs:''} ${sm!=null?'grid-sm-'+sm:''}`}
199
+ style={container?{
200
+ display:'flex',
201
+ flexWrap:wrap,
202
+ flexDirection:direction,
203
+ alignItems:alignItems,
204
+ margin:spacing!=null?spacing*8+'px':undefined
205
+ }:{
206
+ }}
207
+ >{children}</div>
208
+ }
209
+
210
+ var p12 = 'p12' as IdVariable;
211
+ var sp2 = 'sp2' as IdVariable;
212
+ var sp3 = 'sp3' as IdVariable;
213
+ var sp4 = 'sp4' as IdVariable;
214
+ var sp5 = 'sp5' as IdVariable;
215
+
216
+ var diccionario = {}
217
+
218
+ /*
219
+ // const takeElementOrDefault<K, T extends [K in], D>()
220
+ function isIn<V, T>(k:keyof T, object:T): object[k] is V{
221
+ return true
222
+ }
223
+ */
224
+ function takeElementOrDefault<V,K extends string,KO extends string>(k:K, object:{[k in KO]:V}, defaultValue:V):V{
225
+ return k in object ?
226
+ // @ts-expect-error por alguna razón TS no quiere entender que si k está en object, object[k] existe
227
+ object[k]
228
+ : defaultValue
229
+ }
230
+
231
+ function DespliegueEncabezado(props:{casillero:CasilleroEncabezable, leer?:boolean}){
232
+ const forPkNull={} as ForPk;
233
+ return <EncabezadoDespliegue casillero={props.casillero} leer={props.leer} forPk={forPkNull}/>;
234
+ }
235
+
236
+ function subirHasta(elemento:HTMLElement|null, fun:(elemento:HTMLElement)=>boolean):HTMLElement|null{
237
+ if(elemento == null) return null;
238
+ if(fun(elemento)) return elemento;
239
+ return subirHasta(elemento.parentElement, fun);
240
+ }
241
+
242
+ var elementoConSennialBorrar:HTMLElement|null = null;
243
+
244
+ function BotonBorrar({id, variable, forPk, valorOpcion}:{id:string, variable:IdVariable, forPk:ForPk, valorOpcion?:any}){
245
+ var handleClickBorrar=()=>{
246
+ dispatchByPass(accion_registrar_respuesta, {respuesta:null, variable:variable, forPk:forPk})
247
+ };
248
+ return <div className="boton-borrar">
249
+ <Button
250
+ id={id}
251
+ mi-variable={variable}
252
+ valor-opcion={valorOpcion}
253
+ variant="outlined"
254
+ className="boton-opcion boton-opcion-borrar"
255
+ onClick={handleClickBorrar}
256
+ >
257
+ <ICON.DeleteForever/>
258
+ </Button>
259
+ </div>
260
+ }
261
+
262
+ function SaltoDespliegue({casillero,prefijo}:{casillero:Pregunta|Opcion|Filtro, prefijo?:string}){
263
+ return casillero.salto?
264
+ <div className="pase">
265
+ {prefijo?<span className="prefijo">{prefijo} </span>:null}
266
+ <ICON.TrendingFlat /><span>{casillero.salto}</span>
267
+ </div>
268
+ :null
269
+ }
270
+
271
+ function OpcionDespliegue(props:{casillero:Opcion, valorOpcion:number, variable:IdVariable, forPk:ForPk, leer:boolean, conBotonBorrar:boolean}){
272
+ const {casillero} = props;
273
+ var dispatch = useDispatch();
274
+ var saltoAutomatico = useSelector((state:CasoState)=>state.opciones.saltoAutomatico);
275
+ var handleClick:React.MouseEventHandler<HTMLButtonElement> = async (event)=>{
276
+ var container = subirHasta(event.target as HTMLElement, elemento=>elemento.classList.contains('pregunta') || elemento.classList.contains('multiple')) || document.getElementById('main_layout')!;
277
+ var tiene = container.getAttribute('estoy-borrando');
278
+ container.setAttribute('estoy-borrando','NO');
279
+ if(elementoConSennialBorrar){
280
+ elementoConSennialBorrar.setAttribute('estoy-borrando','NO');
281
+ elementoConSennialBorrar = null;
282
+ }
283
+ var {recentModified, siguienteVariable} = dispatchByPass(accion_registrar_respuesta, {respuesta:props.valorOpcion, variable:props.variable, forPk:props.forPk});
284
+ if(!recentModified){
285
+ container.setAttribute('estoy-borrando',tiene=='SI'?'NO':'SI');
286
+ if(tiene!='SI'){
287
+ elementoConSennialBorrar=container;
288
+ }
289
+ }else{
290
+ if(siguienteVariable && saltoAutomatico){
291
+ var botonStyle = (event.target as HTMLElement)?.style;
292
+ if(botonStyle) botonStyle.color = 'green';
293
+ await sleep(100);
294
+ if(botonStyle) botonStyle.color = 'blue';
295
+ await sleep(100);
296
+ if(botonStyle) botonStyle.color = 'green';
297
+ await sleep(100);
298
+ if(botonStyle) botonStyle.color = '';
299
+ enfocarElementoDeVariable(siguienteVariable);
300
+ }
301
+ }
302
+ };
303
+ return <Grid className="opcion">
304
+ {props.conBotonBorrar?<BotonBorrar
305
+ id={`opcion-var-${props.variable}-${props.valorOpcion}-borrar`}
306
+ forPk={props.forPk}
307
+ variable={props.variable}
308
+ valorOpcion={props.valorOpcion}
309
+ />:null}
310
+ <Button
311
+ id={`opcion-var-${props.variable}-${props.valorOpcion}`}
312
+ mi-variable={props.variable}
313
+ valor-opcion={props.valorOpcion}
314
+ variant="outlined"
315
+ className="boton-opcion boton-opcion-seleccion"
316
+ onClick={handleClick}
317
+ tabIndex={-1}
318
+ >
319
+ <Grid container wrap="nowrap">
320
+ <Grid className="id">
321
+ {casillero.ver_id || casillero.casillero}
322
+ </Grid>
323
+ <Grid className="opcion-texto">
324
+ <Typography debe-leer={casillero.leer?'SI':casillero.leer===false?'NO':props.leer?'SI':'NO'}>{breakeableText(casillero.nombre)}</Typography>
325
+ {casillero.aclaracion?
326
+ <Typography className='aclaracion'>{breakeableText(casillero.aclaracion)}</Typography>
327
+ :null}
328
+ </Grid>
329
+ </Grid>
330
+ </Button>
331
+ <SaltoDespliegue casillero={casillero}/>
332
+ </Grid>
333
+ }
334
+ interface IcasilleroConOpciones{
335
+ var_name:IdVariable,
336
+ despliegueContenido:'vertical'|'horizontal'|null,
337
+ casilleros:Opcion[]
338
+ }
339
+
340
+
341
+ function SiNoDespliegue(props:{casilleroConOpciones:IcasilleroConOpciones, forPk:ForPk, despliegueContenido:'vertical'|'horizontal'}){
342
+ return <OpcionesDespliegue
343
+ casilleroConOpciones={props.casilleroConOpciones}
344
+ forPk={props.forPk}
345
+ leer={false}
346
+ despliegueContenido={props.despliegueContenido}
347
+ />
348
+ }
349
+
350
+ function registradorDeVariable(pregunta:Pregunta|OpcionMultiple|ConjuntoPreguntas){
351
+ return (
352
+ respuestas:Respuestas, feedbackForm: FormStructureState<IdVariable, Valor, IdFin>, elemento:HTMLDivElement
353
+ )=>{
354
+ var valorActual = pregunta.var_name == null ? null : respuestas[pregunta.var_name];
355
+ var feedbackRow = feedbackForm.feedback;
356
+ var feedbackVar = pregunta.var_name == null ? null : feedbackRow[pregunta.var_name];
357
+ var tieneValor=valorActual!=null && feedbackVar!=null?(feedbackVar.conProblema?'invalido':'valido'):'NO';
358
+ var estado:EstadoVariable;
359
+ if(pregunta.tipovar){
360
+ estado=feedbackVar?.estado!;
361
+ }else{
362
+ var feedbackMulti = pregunta.casilleros.filter(c=>c.var_name!=null).reduce((pv, om)=>{
363
+ var fb=feedbackRow?.[om.var_name!]!
364
+ return {
365
+ tieneActual: pv.tieneActual || fb.estado=='actual',
366
+ estaSalteada: pv.estaSalteada && (fb.estado=='salteada' || fb.estado=='fuera_de_flujo_por_salto')
367
+ }
368
+ }, {tieneActual:false, estaSalteada:true});
369
+ estado=feedbackMulti.tieneActual?'actual':feedbackMulti.estaSalteada?'salteada':'todavia_no'
370
+ }
371
+ setAttrDistinto(elemento, 'nuestro-validator', estado);
372
+ setAttrDistinto(elemento, 'tiene-valor', tieneValor);
373
+ setAttrDistinto(elemento, 'esta-inhabilitada', feedbackVar?.inhabilitada?'SI':'NO');
374
+ if(pregunta.var_name){
375
+ var opciones:HTMLButtonElement[] = Array.prototype.slice.call(elemento.querySelectorAll(`.boton-opcion[mi-variable="${pregunta.var_name}"]`),0);
376
+ var elementoOpcion:HTMLButtonElement;
377
+ for(elementoOpcion of opciones){
378
+ var valorOpcion = elementoOpcion.getAttribute('valor-opcion');
379
+ setAttrDistinto(elementoOpcion, 'opcion-seleccionada', valorOpcion == valorActual ? "SI": "NO")
380
+ }
381
+ var elementosInput:HTMLInputElement[] = Array.prototype.slice.call(elemento.querySelectorAll('.variable'));
382
+ var elementoInput:HTMLInputElement;
383
+ for(elementoInput of elementosInput){
384
+ setValorDistinto(elementoInput, 'value', valorActual == null ? '' : valorActual.toString());
385
+ }
386
+ var botonNsNc = document.getElementById("nsnc-pregunta-"+pregunta.var_name)!;
387
+ setAttrDistinto(botonNsNc, 'opcion-seleccionada', valorActual == (pregunta.valor_ns_nc ?? -9) ? "SI" : "NO")
388
+ }
389
+ }
390
+ }
391
+
392
+ function OpcionMultipleDespliegue(props:{opcionM:OpcionMultiple, forPk:ForPk}){
393
+ const {opcionM} = props;
394
+ var id = `opcionM-${opcionM.id_casillero}`;
395
+ registrarElemento({
396
+ id,
397
+ direct:true,
398
+ fun: registradorDeVariable(opcionM)
399
+ })
400
+ return <DesplegarCasillero
401
+ id={id}
402
+ casillero={opcionM}
403
+ despliegueEncabezado='lateral'
404
+ >
405
+ <EncabezadoDespliegue
406
+ casillero={opcionM}
407
+ verIdGuion={true}
408
+ leer={opcionM.leer!==false}
409
+ forPk={props.forPk}
410
+ />
411
+ <SiNoDespliegue
412
+ casilleroConOpciones={opcionM}
413
+ forPk={props.forPk}
414
+ despliegueContenido={props.opcionM.despliegueContenido??'horizontal'}
415
+ />
416
+ </DesplegarCasillero>
417
+ }
418
+
419
+ type CasilleroEncabezable = Formulario|Bloque|Filtro|ConjuntoPreguntas|Pregunta|OpcionMultiple|PreguntaSimple|Consistencia|Texto
420
+
421
+ function EncabezadoDespliegue(props:{casillero:CasilleroEncabezable, verIdGuion?:boolean, leer?:boolean, forPk:ForPk}){
422
+ var {casillero, forPk} = props;
423
+ var conCampoOpciones = useSelector((state:CasoState)=>state.opciones.conCampoOpciones)
424
+ var handleClickBorrar=()=>{
425
+ dispatchByPass(accion_registrar_respuesta, {respuesta:null, variable:casillero.var_name as IdVariable, forPk:forPk})
426
+ };
427
+ var ver_id = casillero.ver_id ?? casillero.casillero;
428
+ // @ts-ignore no está en todos los casilleros pero acá para el despliegue de metadatos no importa
429
+ var calculada = casillero.calculada;
430
+ var id = `id-div-${casillero.var_name||casillero.casillero}`;
431
+ var idAcciones = "acciones-"+id;
432
+ return <div
433
+ className="encabezado"
434
+ debe-leer={props.leer?'SI':'NO'}
435
+ >
436
+ <div id={id} className="id-div" title={`${casillero.casillero} - ${casillero.var_name}`}
437
+ onClick={()=>{
438
+ var div = document.getElementById(idAcciones);
439
+ div!.setAttribute("accion-visible", (1-Number(div!.getAttribute("accion-visible"))).toString());
440
+ // TODO. Ver qué hacemos cuando se toca el ID de la pregutna
441
+ dispatchByPass(accion_id_pregunta, {pregunta: casillero.casillero as IdPregunta, forPk});
442
+ }}
443
+ >
444
+ <div className="id">
445
+ {ver_id}
446
+ </div>
447
+ {(casillero.tipovar=="si_no"||casillero.tipovar=="opciones")?<Campo disabled={false} pregunta={casillero} forPk={forPk} mini={true} hidden={!conCampoOpciones && 'quitar'}/>:null}
448
+ <div className="acciones-pregunta" id={idAcciones} accion-visible="0">
449
+ {casillero.var_name?<div><Button
450
+ id={"borrar-pregunta-"+casillero.var_name}
451
+ mi-variable={casillero.var_name}
452
+ variant="outlined"
453
+ className="boton-pregunta-borrar"
454
+ onClick={handleClickBorrar}
455
+ >
456
+ <ICON.DeleteForever/>
457
+ </Button></div>:null}
458
+ {casillero.var_name?<div><Button
459
+ id={"nsnc-pregunta-"+casillero.var_name}
460
+ mi-variable={casillero.var_name}
461
+ variant="outlined"
462
+ className="boton-pregunta-nsnc"
463
+ onClick={()=>{
464
+ dispatchByPass(accion_registrar_respuesta, {respuesta:casillero.valor_ns_nc??-9, variable:casillero.var_name as IdVariable, forPk:forPk})
465
+ }}
466
+ >
467
+ NS/NC
468
+ </Button></div>:null}
469
+ </div>
470
+ </div>
471
+ <div className="nombre-div">
472
+ <div className="nombre">{breakeableText(casillero.nombre)}</div>
473
+ {casillero.aclaracion?
474
+ <div className="aclaracion">
475
+ {casillero.salto && casillero.tipoc=='FILTRO'?
476
+ <SaltoDespliegue casillero={casillero} prefijo={breakeableText(casillero.aclaracion)}/>
477
+ :
478
+ breakeableText(casillero.aclaracion)
479
+ }
480
+ </div>
481
+ :null}
482
+ <div los-metadatos="si">
483
+ <span el-metadato="variable">{casillero.var_name}</span>
484
+ {casillero.tipovar && casillero.tipovar!='opciones' && casillero.tipovar!='si_no'?
485
+ <span el-metadato="tipovar">{casillero.tipovar}</span>
486
+ :null}
487
+ { //@ts-ignore una opción múltiple nunca lo a a ser, no tiene el campo, no importa
488
+ casillero.optativo?<span el-metadato="optativa">optativa</span>:null
489
+ }
490
+ {calculada?<span el-metadato="calculada">calculada</span>:null}
491
+ {casillero.despliegueOculta?<span el-metadato="oculta">oculta</span>:null}
492
+ {casillero.expresion_habilitar?<span el-metadato="expresion_habilitar">habilita: {casillero.expresion_habilitar}</span>:null}
493
+ { //@ts-ignore altunos casilleros no tienen especial, no importa, es solo para poner los metadatos
494
+ casillero.especial?.autoing?<span el-metadato="expresion_autoing">autoing: {casillero.especial?.autoing}</span>:null
495
+ }
496
+ </div>
497
+ </div>
498
+ </div>
499
+ }
500
+
501
+ function DesplegarConfirmarBorrarRespuesta(props:{forPk:ForPk, variableBorrar:IdVariable}){
502
+ var [open, setOpen] = useState(!!props.variableBorrar)
503
+ var dispatch = useDispatch();
504
+ const handleClose = () => {
505
+ dispatch(dispatchers.CONFIRMAR_BORRAR_RESPUESTA({forPk:props.forPk, variable:null}));
506
+ setOpen(false);
507
+ }
508
+ return <Popover
509
+ id={"popover-confirmar"}
510
+ open={open}
511
+ onClose={handleClose}
512
+ anchorOrigin={{
513
+ vertical: 'bottom',
514
+ horizontal: 'center',
515
+ }}
516
+ transformOrigin={{
517
+ vertical: 'top',
518
+ horizontal: 'left',
519
+ }}
520
+ >
521
+ <Typography>La pregunta tiene registrada una respuesta que no fue detectada como errónea</Typography>
522
+ <div className="confirma-botones">
523
+ <Button color="secondary" variant="outlined" onClick={()=>{
524
+ if(props.variableBorrar){
525
+ dispatchByPass(accion_registrar_respuesta, {forPk:props.forPk, variable:props.variableBorrar, respuesta:null})
526
+ }
527
+ handleClose();
528
+ }}>borrar respuesta</Button>
529
+ <Button color="primary" variant="outlined" onClick={handleClose}>volver sin borrar</Button>
530
+ </div>
531
+ </Popover>;
532
+ }
533
+
534
+ function calcularNuestraLongitud(longitud:string |null){
535
+ return longitud;
536
+ }
537
+
538
+ function enfocarElementoDeVariable(siguienteVariable:IdVariable|IdFin){
539
+ debeSaltar = false;
540
+ var {top, enfocado, elementoInputVariable} = calcularElementoEnfocado(siguienteVariable);
541
+ if(top != null && top>0 && !enfocado){
542
+ window.scrollTo({top, left:0, behavior:'smooth'});
543
+ }
544
+ elementoInputVariable?.focus();
545
+ }
546
+
547
+ function Campo(props:{disabled:boolean, pregunta:PreguntaSimple|PreguntaConOpciones|PreguntaConSiNo|OpcionMultiple, forPk:ForPk, mini?:boolean, hidden?:boolean|'quitar'}){
548
+ var {pregunta, disabled, mini } = props;
549
+ var {saltoAutomatico, conCampoOpciones} = useSelector((state:CasoState)=>state.opciones);
550
+ const longitud = mini ? pregunta.casilleros.reduce((acum, o)=>Math.max(o.casillero.toString().length, acum), 0) :
551
+ // @ts-ignore mini es para los otros
552
+ pregunta.longitud;
553
+ // var [valor, setValor] = useState(props.valor);
554
+ var [editando, setEditando] = useState(false);
555
+ // useEffect(() => {
556
+ // setValor(props.valor)
557
+ // }, [props.valor]);
558
+ const inputProps = {
559
+ maxLength: longitud,
560
+ };
561
+ const onChange=(nuevoValor:Valor|typeof NO_CAMBIAR__VERIFICAR_SI_ES_NECESARIO)=>{
562
+ var {siguienteVariable} = dispatchByPass(accion_registrar_respuesta, {forPk:props.forPk, variable:pregunta.var_name, respuesta:nuevoValor});
563
+ if(siguienteVariable && debeSaltar){
564
+ enfocarElementoDeVariable(siguienteVariable);
565
+ }
566
+ };
567
+ var nuestraLongitud = calcularNuestraLongitud(longitud)
568
+ return <div className="campo" nuestra-longitud={nuestraLongitud} style={props.hidden=='quitar'?{display:'none'}:props.hidden?{visibility:'hidden'}:undefined}>
569
+ {mini?null:<BotonBorrar
570
+ id={`borrar-abierta-${pregunta.var_name}`}
571
+ variable={pregunta.var_name}
572
+ forPk={props.forPk}
573
+ />}
574
+ <div className="input-campo">
575
+ <TextField
576
+ id={`var-${pregunta.var_name}`}
577
+ disabled={disabled}
578
+ className="variable"
579
+ //var-length={pregunta.longitud}
580
+ fullWidth={true}
581
+ inputProps={inputProps}
582
+ type={pregunta.despliegueTipoInput??adaptarTipoVarCasillero(pregunta.tipovar)}
583
+ onKeyDown={(event:KeyboardEvent)=>{
584
+ var esEnter = (event.key == 'Enter' || event.keyCode == 13)
585
+ debeSaltar = esEnter && (saltoAutomatico || conCampoOpciones);
586
+ if(esEnter){
587
+ if(event.target instanceof HTMLElement){
588
+ event.target.blur();
589
+ }
590
+ event.preventDefault();
591
+ }
592
+ }}
593
+ onFocus={(_event)=>setEditando(true)}
594
+ onBlur={(event, valor)=>{
595
+ if(event?.relatedTarget?.getAttribute('boton-confirmar')){
596
+ debeSaltar = true;
597
+ }
598
+ onChange(valor);
599
+ setEditando(false)
600
+ }}
601
+ />
602
+ </div>
603
+ {disabled || mini?null:
604
+ <div className="boton-confirmar-campo">
605
+ <Button variant={editando?"contained":'outlined'} size="small" color={editando?'primary':'default'}
606
+ boton-confirmar={pregunta.var_name}
607
+ tabIndex={-1}
608
+ onClick={()=>{
609
+ onChange(NO_CAMBIAR__VERIFICAR_SI_ES_NECESARIO);
610
+ setEditando(false)
611
+ }}
612
+ ><ICON.Check/></Button>
613
+ </div>
614
+ }
615
+ </div>
616
+ }
617
+
618
+ interface IcasilleroConOpciones{
619
+ var_name:IdVariable,
620
+ casilleros:Opcion[]
621
+ }
622
+
623
+ function OpcionesDespliegue(
624
+ {casilleroConOpciones, forPk, leer, despliegueContenido}:
625
+ {casilleroConOpciones:IcasilleroConOpciones, forPk:ForPk, leer:boolean, despliegueContenido:'vertical'|'horizontal'}
626
+ ){
627
+ const desplegarOtros = (opcion:Opcion, soloParaDespliegue:'vertical'|'horizontal'|null) => opcion.casilleros.map((subPregunta:Pregunta)=>(
628
+ soloParaDespliegue == null || soloParaDespliegue == subPregunta.despliegueContenido ?
629
+ <div className="otros-especificar" key={subPregunta.id_casillero}>
630
+ <PreguntaDespliegue
631
+ pregunta={subPregunta}
632
+ forPk={forPk}
633
+ despliegueEncabezado='superior'
634
+ />
635
+ </div>:null
636
+ ))
637
+ return <div className="contenido">
638
+ <div className="opciones" despliegue-contenido={despliegueContenido??'vertical'}>
639
+ {casilleroConOpciones.casilleros.map((opcion:Opcion, i:number)=>
640
+ <Grid key={opcion.id_casillero} item
641
+ ocultar-salteada={opcion.despliegueOculta?(opcion.expresion_habilitar_js?'INHABILITAR':'SI'):'NO'}
642
+ >
643
+ <OpcionDespliegue
644
+ casillero={opcion}
645
+ variable={casilleroConOpciones.var_name}
646
+ valorOpcion={opcion.casillero}
647
+ forPk={forPk}
648
+ leer={leer}
649
+ conBotonBorrar={i==0 || despliegueContenido!='horizontal'}
650
+ />
651
+ {despliegueContenido=='horizontal'?null:desplegarOtros(opcion,null)}
652
+ </Grid>
653
+ )}
654
+ </div>
655
+ {despliegueContenido=='horizontal'?casilleroConOpciones.casilleros.map((opcion:Opcion)=>
656
+ desplegarOtros(opcion,null)
657
+ ):null}
658
+ </div>
659
+ }
660
+
661
+ const nombreCasillero={
662
+ F: 'formulario',
663
+ B: 'bloque',
664
+ P: 'pregunta',
665
+ CP: 'conjuntopreguntas',
666
+ O: 'opcion',
667
+ OM: 'multiple',
668
+ FILTRO: 'filtro',
669
+ CONS: 'consistencia',
670
+ BF: 'botonformulario',
671
+ TEXTO: 'aclaracionsuperior',
672
+ }
673
+
674
+ function DesplegarCasillero(props:{
675
+ casillero:Pregunta|Bloque|Filtro|ConjuntoPreguntas|BotonFormulario|Consistencia|OpcionMultiple|Texto,
676
+ id?:string,
677
+ style?:React.CSSProperties,
678
+ despliegueEncabezado?:'lateral'|'superior'
679
+ children:React.ReactNode|Element[],
680
+ "ocultar-salteada"?:boolean
681
+ }){
682
+ return <div
683
+ key={`${props.casillero.tipoc}-${props.id||props.casillero.id_casillero}`}
684
+ className={`casillero ${nombreCasillero[props.casillero.tipoc]}`}
685
+ id={props.id}
686
+ style={props.style}
687
+ despliegue-encabezado={props.casillero.despliegueEncabezado??props.despliegueEncabezado??'superior'}
688
+ ocultar-salteada={props["ocultar-salteada"]}
689
+ >{props.children}</div>
690
+ }
691
+
692
+ function PreguntaDespliegue(props:{
693
+ pregunta:Pregunta,
694
+ forPk:ForPk,
695
+ despliegueEncabezado:'lateral'|'superior'
696
+ }){
697
+ var {pregunta} = props;
698
+ var dispatch=useDispatch();
699
+ var estado:EstadoVariable;
700
+ var id = `pregunta-${pregunta.id_casillero}`
701
+ registrarElemento({
702
+ id,
703
+ direct:true,
704
+ fun: registradorDeVariable(pregunta)
705
+ })
706
+ return <DesplegarCasillero
707
+ id={id}
708
+ casillero={pregunta}
709
+ nuestro-tipovar={pregunta.tipovar||"multiple"}
710
+ ocultar-salteada={pregunta.despliegueOculta?(pregunta.expresion_habilitar_js?'INHABILITAR':'SI'):'NO'}
711
+ despliegueEncabezado={props.despliegueEncabezado}
712
+ >
713
+ <EncabezadoDespliegue
714
+ casillero={pregunta}
715
+ leer={pregunta.leer!==false}
716
+ forPk={props.forPk}
717
+ />
718
+ <div className="contenido">{
719
+ pregunta.tipovar=="si_no"?<Grid container>
720
+ <SiNoDespliegue
721
+ casilleroConOpciones={pregunta}
722
+ forPk={props.forPk}
723
+ despliegueContenido={props.pregunta.despliegueContenido??'vertical'}
724
+ />
725
+ </Grid>:
726
+ pregunta.tipovar=="opciones" ?
727
+ <OpcionesDespliegue
728
+ casilleroConOpciones={pregunta}
729
+ forPk={props.forPk}
730
+ leer={!!pregunta.leer}
731
+ despliegueContenido={pregunta.despliegueContenido??'vertical'}
732
+ />:
733
+ pregunta.tipovar==null?
734
+ (pregunta.casilleros as (OpcionMultiple|Consistencia)[]).map((opcionMultiple)=>
735
+ opcionMultiple.tipoc=='OM'?
736
+ <OpcionMultipleDespliegue
737
+ key={opcionMultiple.id_casillero}
738
+ opcionM={opcionMultiple}
739
+ forPk={props.forPk}
740
+ />
741
+ : //las consistencias pueden ser hermanas de OM
742
+ <ConsistenciaDespliegue
743
+ key={opcionMultiple.id_casillero}
744
+ casillero={opcionMultiple}
745
+ forPk={props.forPk}
746
+ />
747
+ )
748
+ :
749
+ ((preguntaSimple:PreguntaSimple)=>
750
+ <Campo
751
+ disabled={preguntaSimple.calculada?true:false}
752
+ pregunta={preguntaSimple}
753
+ forPk={props.forPk}
754
+ />
755
+ )(pregunta)
756
+ }</div>
757
+ <div className="pie-pregunta">
758
+ <SaltoDespliegue
759
+ casillero={pregunta}
760
+ prefijo={pregunta.tipovar=="opciones"?(
761
+ pregunta.casilleros.some(opcion=>opcion.salto)?"resto de las opciones":"todas las opciones"
762
+ ):""}
763
+ />
764
+ </div>
765
+ </DesplegarCasillero>
766
+ }
767
+
768
+ var calcularDisabledBFAgregarListo = (configSorteoFormulario:ConfiguracionSorteoFormulario|null, formulario:IdFormulario)=>
769
+ !!(configSorteoFormulario && configSorteoFormulario.id_formulario_individual == formulario)
770
+
771
+ function botonesDelFormulario(r:Respuestas, unidad_analisis:IdUnidadAnalisis, estructura:Estructura, forPkPadre:ForPk, feedbackAll:{[formulario in PlainForPk]:FormStructureState<IdVariable, Valor, IdFin>}):HtmlTag<HTMLDivElement>{
772
+ var formsVivienda = getFormulariosForIdVivienda(forPkPadre.vivienda!);
773
+ var uaDef = estructura.unidades_analisis[unidad_analisis];
774
+ var arrayEstructuraFormularios = (likeAr(estructura.formularios)).array();
775
+ var x = likeAr(uaDef.hijas).filter(uaHija=>
776
+ formsVivienda.includes(
777
+ arrayEstructuraFormularios.find((infoFormulario)=>
778
+ infoFormulario.casilleros.unidad_analisis == uaHija?.unidad_analisis)
779
+ ?.casilleros.id_casillero as IdFormulario
780
+ )
781
+ ).map(uaHija=>(
782
+ uaHija == null ? null :
783
+ html.div({class:'ua-hijas'},[
784
+ html.div(uaHija.unidad_analisis),
785
+ html.div(
786
+ likeAr(r[uaHija.unidad_analisis]||[]).map((respuestasHija, i)=>{
787
+ var num = Number(i)+1
788
+ var forPkHijaParcial = {...forPkPadre, [uaHija.pk_agregada]: num};
789
+ var configSorteoFormulario = estructura.configSorteo?estructura.configSorteo[getMainFormForVivienda(forPkPadre.vivienda!)]:null
790
+ return html.div({class:'numerador-ua'}, [
791
+ html.div({class:'botones-ua'},[
792
+ html.div({class:'numero-ua'},num.toString()),
793
+ ...likeAr(estructura.formularios)
794
+ .filter(formDef=>formDef.casilleros.unidad_analisis == uaHija.unidad_analisis )
795
+ .map((_formDef, formulario)=>{
796
+ var forPk = {...forPkHijaParcial, formulario};
797
+ var feedbackForm = feedbackAll[toPlainForPk(forPk)];
798
+ return feedbackForm ? html.div({},[
799
+ // html.button((uaHija!).pk_agregada+" ok: "+(Number(i)+1)),
800
+ botonFormularioConResumen(
801
+ {
802
+ forPk,
803
+ num,
804
+ actual: true || calcularActualBF(configSorteoFormulario, num, null, formulario, r), //REVISAR true para que no se grisen
805
+ previo:false,
806
+ disabled: calcularDisabledBF(configSorteoFormulario, num, formulario, r)
807
+ },
808
+ feedbackForm,
809
+ r,
810
+ {despliegueOculta:false, expresion_habilitar_js:'', nombre:formulario, aclaracion:null, salto:formulario},
811
+ forPkPadre,
812
+ "boton-ir-resumen-formulario",
813
+ estructura.formularios[formulario].casilleros
814
+ )
815
+ ]) : null
816
+ }).array().map(x=>x == null ? null : x),
817
+ ])
818
+ ,botonesDelFormulario(respuestasHija, uaHija.unidad_analisis, estructura, forPkHijaParcial, feedbackAll)
819
+ ])
820
+ }).array().map(x=>x == null ? null : x)
821
+ )
822
+ ])
823
+ )).array().map(x=>x == null ? null : x);
824
+ return html.div(/*{style:'display:flex; flex-direction:row'},*/x);
825
+ }
826
+
827
+ function TextoDespliegue(props:{casillero:Texto, forPk:ForPk}){
828
+ var {casillero, forPk} = props;
829
+ var dispatch = useDispatch();
830
+ var habilitador = casillero.expresion_habilitar_js?getFuncionHabilitar(casillero.expresion_habilitar_js):()=>true;
831
+ var {modoDespliegue} = useSelectorVivienda(forPk);
832
+ var id = `texto-${casillero.id_casillero}`;
833
+ registrarElemento({id, style:'display', fun:(r:Respuestas)=>habilitador(r) || modoDespliegue=='metadatos'?'block':'none'})
834
+ var esResumenFormulario = casillero.casillero=='ResFor' as IdCasillero; // TODO: Cambia esto que está jarcodeado.
835
+ if(esResumenFormulario){
836
+ registrarElemento({id, direct:true,
837
+ fun:(
838
+ r:Respuestas,
839
+ _feedbackForm: FormStructureState<IdVariable, Valor, IdFin>,
840
+ elemento:HTMLDivElement,
841
+ feedbackAll:{[formulario in PlainForPk]:FormStructureState<IdVariable,Valor, IdFin>},
842
+ estructura:Estructura
843
+ )=>{
844
+ elemento.style.display='';
845
+ //@ts-ignore las respuestas son respuestasRaiz porque ResFor está en el form ppal
846
+ if(r['resumenEstado'] as ResumenEstado == 'vacio'){
847
+ elemento.textContent = "relevamiento sin empezar";
848
+ }else{
849
+ elemento.textContent = "relevamiento empezado";
850
+ var {unidad_analisis} = estructura.formularios[forPk.formulario].casilleros;
851
+ elemento.innerHTML="";
852
+ elemento.appendChild(botonesDelFormulario(r, unidad_analisis, estructura, forPk, feedbackAll).create());
853
+ }
854
+ }
855
+ })
856
+ }
857
+ var ir = (defBoton:DefinicionFormularioAbrir)=>{
858
+ // var nuevaForPk={...forPk, formulario:idFormularioDestino};
859
+ // nuevaForPk[nuevoCampoPk] = defBoton.num
860
+ dispatch(dispatchers.CAMBIAR_FORMULARIO({forPk:defBoton.forPk, apilarVuelta:true}));
861
+ }
862
+ return <DesplegarCasillero
863
+ id={`${id}-externo`}
864
+ casillero={casillero}
865
+ >
866
+ <EncabezadoDespliegue casillero={casillero} leer={false} forPk={forPk}/>
867
+ <div id={id} style={{display:'none'}}></div>
868
+ {esResumenFormulario?
869
+ <Button className="special-button" id="boton-ir-resumen-formulario" style={{display:'none'}}
870
+ onClick={(event)=>{
871
+ ir(JSON.parse((event.target! as unknown as HTMLButtonElement).getAttribute('def-button')!))
872
+ }}
873
+ >ir (interno)</Button>
874
+ :null}
875
+
876
+ </DesplegarCasillero>
877
+ }
878
+
879
+ function FiltroDespliegue(props:{filtro:Filtro, forPk:ForPk}){
880
+ var {filtro} = props;
881
+ return <DesplegarCasillero casillero={filtro}>
882
+ <DespliegueEncabezado casillero={filtro}/>
883
+ </DesplegarCasillero>
884
+ }
885
+
886
+ function ConsistenciaDespliegue(props:{casillero:Consistencia, forPk:ForPk}){
887
+ var {casillero, forPk} = props;
888
+ var habilitador = casillero.expresion_habilitar_js?getFuncionHabilitar(casillero.expresion_habilitar_js):()=>true;
889
+ var {modoDespliegue} = useSelectorVivienda(forPk);
890
+ var id = `consistencia-${casillero.id_casillero}`;
891
+ registrarElemento({id, style:'display', fun:(r:Respuestas)=>habilitador(r) || modoDespliegue=='metadatos'?'block':'none'})
892
+ return <DesplegarCasillero
893
+ id={id}
894
+ casillero={casillero}
895
+ style={{display:'none'}}
896
+ >
897
+ <EncabezadoDespliegue casillero={casillero} leer={false} forPk={forPk}/>
898
+ </DesplegarCasillero>
899
+ }
900
+
901
+ type DefinicionFormularioAbrir=
902
+ ({forPk:ForPk, num:number, actual:boolean, previo:boolean} |
903
+ {forPk:ForPk, num:number, actual:boolean, previo:false, esAgregar:true} |
904
+ {forPk:ForPk, num:number, actual:boolean, previo:false, esConfirmar:true} |
905
+ {forPk:ForPk, num:number, actual:boolean, previo:false, permiteBorrar:boolean} |
906
+ {forPk:ForPk, num:false, actual:boolean, previo:true, unico:true})
907
+ & {esConfirmar?:true, esAgregar?:true, permiteBorrar?:boolean, disabled?:boolean|undefined};
908
+
909
+
910
+ var botonFormularioConResumen = (
911
+ defBoton:DefinicionFormularioAbrir,
912
+ feedbackForm:FormStructureState<IdVariable, Valor, IdFin>,
913
+ respuestasAumentadas:Respuestas,
914
+ casillero:{despliegueOculta?:boolean|null, expresion_habilitar_js?:string, aclaracion:string|null, expresion_habilitar?:string, nombre?:string, salto:string|null, especial?:any},
915
+ forPkPadre: ForPk,
916
+ idButton:string,
917
+ formularioAAbrir:Formulario
918
+ )=>{
919
+ var forPk:ForPk = defBoton.forPk;
920
+ var sufijoIdElemento = toPlainForPk(forPk)+(defBoton.esConfirmar?'-listo':'');
921
+ var id = `div-boton-formulario-${sufijoIdElemento}`;
922
+ var estado = feedbackForm.resumen;
923
+ return html.div({
924
+ id,
925
+ class:"seccion-boton-formulario" ,
926
+ $attrs:{
927
+ "nuestro-validator":defBoton.actual?'actual':defBoton.previo?'valida':'todavia_no',
928
+ "ocultar-salteada":casillero.despliegueOculta?(casillero.expresion_habilitar_js?'INHABILITAR':'SI'):'NO',
929
+ "tiene-valor":"NO",
930
+ "def-button":JSON.stringify(defBoton)
931
+ }
932
+ }, [
933
+ casillero.aclaracion || html.div({class:"aclaracion"}, [breakeableText(casillero.aclaracion)??null]),
934
+ html.div([
935
+ Button2({
936
+ // id:`var-${idVariable}`,
937
+ id:`boton-formulario-${sufijoIdElemento}`,
938
+ variant:"outlined",
939
+ disabled: defBoton.disabled,
940
+ color:"inherit",
941
+ onClick:()=>{
942
+ if(defBoton.esConfirmar){
943
+ if(defBoton.num != null){
944
+ dispatchByPass(accion_registrar_respuesta,{forPk:forPkPadre, variable:casillero.expresion_habilitar as IdVariable, respuesta:defBoton.num as Valor});
945
+ }
946
+ }else{
947
+ var button = document.getElementById(idButton)! as HTMLButtonElement;
948
+ button.setAttribute('def-button', JSON.stringify(defBoton));
949
+ button.click();
950
+ }
951
+ },
952
+ $attrs:{
953
+ "resumen-estado":estado!='vacio'?estado: defBoton.actual?'actual':defBoton.previo?estado:'todavia_no',
954
+ }
955
+ , children:[
956
+ (defBoton.esAgregar?'agregar':defBoton.esConfirmar?'Listo':casillero.nombre + ' ' + (defBoton.num||'')),
957
+ html.svg({class:"MuiSvgIcon-root", focusable:false, viewbox:"0 0 24 24", "aria-hidden":"true"},[
958
+ html.path({d:(defBoton.esAgregar?materialIoIconsSvgPath.Add:defBoton.esConfirmar?materialIoIconsSvgPath.Check:casillero.salto?materialIoIconsSvgPath.Forward:materialIoIconsSvgPath.ExitToApp)})
959
+ ])
960
+ ]
961
+ }),
962
+ (defBoton.permiteBorrar?
963
+ Button2({
964
+ className:"boton-borrar-ua-vacia",
965
+ color:"default",
966
+ variant:"outlined",
967
+ children:
968
+ html.svg({class:"MuiSvgIcon-root", focusable:false, viewbox:"0 0 24 24", "aria-hidden":"true"},[
969
+ html.path({d:materialIoIconsSvgPath.DeleteForever})
970
+ ]),
971
+ onClick:()=>accion_borrar_formulario({forPk, forPkPadre})})
972
+ :null),
973
+ (defBoton.num !== false && !defBoton.esAgregar && !defBoton.esConfirmar?
974
+ html.span((casillero.especial?.camposResumen??[defBoton.num.toString()]).map(
975
+ (campo:string)=>respuestasAumentadas[formularioAAbrir.unidad_analisis][defBoton.num-1][campo as IdVariable]
976
+ ).join(', ') )
977
+ :null)
978
+ // html.div({class:'inline-dialog', $attrs:{"inline-dialog-open": confirmarForzarIr == defBoton.num?'visible':'hidden'}},[ ])
979
+ ])
980
+ /*
981
+ {defBoton.esAgregar?<> <span> </span> <Button
982
+ variant="outlined"
983
+ color="inherit"
984
+ onClick={()=>{
985
+ }}
986
+ ><ICON.Check/></Button></>:null}
987
+ </div>
988
+ */
989
+ ]).create()
990
+ }
991
+
992
+
993
+ function BotonFormularioDespliegue(props:{casillero:BotonFormulario, formulario:Formulario, forPk:ForPk}){
994
+ var {casillero, forPk} = props;
995
+ var habilitador = casillero.expresion_habilitar_js?getFuncionHabilitar(casillero.expresion_habilitar_js):()=>true;
996
+ var {opciones} = useSelectorVivienda(forPk);
997
+ //var idFormularioDestino = 'F:'+casillero.salto! as IdFormulario; //original
998
+ var armoNomSalto=casillero.salto!.substr(0,2)=='F:'?casillero.salto.slice(2):casillero.salto;
999
+ //console.log('BotonFormularioDespliegue armoNomSalto ' +armoNomSalto);
1000
+ var idFormularioDestino = 'F:'+armoNomSalto! as IdFormulario;
1001
+ var estructura = getEstructura();
1002
+ var {formularioAAbrir} = useSelector((state:CasoState)=>({
1003
+ formularioAAbrir:estructura.formularios[idFormularioDestino].casilleros,
1004
+ }));
1005
+ var sufijoIdElemento = toPlainForPk(forPk);
1006
+ /*
1007
+ registrarElemento({
1008
+ id:`div-boton-formulario-${sufijoIdElemento}`,
1009
+ attr:'esta-inhabilitada',
1010
+ // fun: (r:Respuestas)=>habilitador(r)?'SI':'NO'
1011
+ fun: (_r:Respuestas)=>'NO'
1012
+ });
1013
+ registrarElemento<HTMLButtonElement>({
1014
+ id:`boton-formulario-${sufijoIdElemento}`,
1015
+ prop:'disabled',
1016
+ // fun: (r:Respuestas)=>!habilitador(r)
1017
+ fun: (_r:Respuestas)=>false
1018
+ });
1019
+ */
1020
+ var dispatch = useDispatch();
1021
+ var [confirmarForzarIr, setConfirmarForzarIr] = useState<DefinicionFormularioAbrir|false|null>(null);
1022
+ var multipleFormularios=formularioAAbrir.unidad_analisis != props.formulario.unidad_analisis;
1023
+ var nuevoCampoPk = defOperativo.defUA[formularioAAbrir.unidad_analisis].pk;
1024
+ // var var_name='$B.'+casillero.salto; //original
1025
+ var var_name='$B.F:'+armoNomSalto;
1026
+ var idSeccion=`seccion-boton-formulario-${var_name}`;
1027
+ var idButton=`special-button-${idSeccion}`;
1028
+ registrarElemento<HTMLDivElement>({
1029
+ id:idSeccion,
1030
+ direct:true,
1031
+ fun: (respuestasAumentadas:Respuestas, feedbackRow: FormStructureState<IdVariable, Valor, IdFin>, div:HTMLDivElement,
1032
+ feedbackAll:{
1033
+ [formulario in PlainForPk]:FormStructureState<IdVariable, Valor, IdFin> // resultado del rowValidator para estado.forPk
1034
+ }
1035
+ )=>{
1036
+ try{
1037
+ var listaDeBotonesAbrir:DefinicionFormularioAbrir[] = [];
1038
+ // var esVarActual = feedbackRow.actual == '$B.F:'+casillero.salto; //original
1039
+ var esVarActual = feedbackRow.actual == '$B.F:'+armoNomSalto;
1040
+ // console.log('BotonFormularioDespliegue esVarActual ' +esVarActual );
1041
+ if(multipleFormularios && casillero.salto!=null){
1042
+ // let defFormulario:InfoFormulario = estructura.formularios['F:'+casillero.salto as IdFormulario]; //original
1043
+ let defFormulario:InfoFormulario = estructura.formularios['F:'+armoNomSalto as IdFormulario];
1044
+ let defUA = estructura.unidades_analisis[defFormulario.casilleros.unidad_analisis!];
1045
+ let conjunto = respuestasAumentadas[defFormulario.casilleros.unidad_analisis!];
1046
+ let cantidadEsperada = respuestasAumentadas[casillero.expresion_habilitar as IdVariable];
1047
+ var numActual:number|null = null;
1048
+ // var estadoDelBoton = feedbackRow.feedback['$B.F:'+casillero.salto as IdVariable].estado //original
1049
+ var estadoDelBoton = feedbackRow.feedback['$B.F:'+armoNomSalto as IdVariable].estado
1050
+ // console.log('BotonFormularioDespliegue estadoDelBoton ' +estadoDelBoton );
1051
+ var configSorteoFormulario = estructura.configSorteo?estructura.configSorteo[getMainFormForVivienda(forPk.vivienda!)]:null
1052
+ listaDeBotonesAbrir = likeAr(conjunto).map((_, i)=>{
1053
+ let num:number = numberOrStringIncIfArray(i, conjunto) as number;
1054
+ let forPk={...props.forPk, formulario:idFormularioDestino, [nuevoCampoPk]:num};
1055
+ var feedback = feedbackAll[toPlainForPk(forPk)];
1056
+ if(numActual == null && feedback.resumen == "vacio" && estadoDelBoton =='valida'){
1057
+ numActual = num;
1058
+ }
1059
+ return {
1060
+ forPk,
1061
+ resumen:null,
1062
+ num,
1063
+ actual: calcularActualBF(configSorteoFormulario, num, numActual, idFormularioDestino, respuestasAumentadas),
1064
+ previo: numActual == null,
1065
+ permiteBorrar: likeAr(conjunto).array().length == Number(i) + 1 &&
1066
+ feedback.resumen == 'vacio' &&
1067
+ calcularPermiteBorrarBF(configSorteoFormulario,idFormularioDestino),
1068
+ disabled: calcularDisabledBF(configSorteoFormulario, num, idFormularioDestino, respuestasAumentadas)
1069
+ }
1070
+ }).array();
1071
+ if("puede agregar //TODO VER ESTO" && (conjunto instanceof Array || conjunto == null)){
1072
+ let nuevoValorPk=(conjunto==null ? 0 : conjunto.length) + 1;
1073
+ let forPk={...props.forPk, formulario:idFormularioDestino, [nuevoCampoPk]:nuevoValorPk};
1074
+ let debeAgregarOlisto = numActual == null && (cantidadEsperada == null || cantidadEsperada != (conjunto !=null && conjunto.length))
1075
+ && (estadoDelBoton =='valida' || esVarActual);
1076
+ listaDeBotonesAbrir.push({
1077
+ forPk,
1078
+ num:nuevoValorPk,
1079
+ esAgregar:true,
1080
+ actual:debeAgregarOlisto,
1081
+ previo: false,
1082
+ disabled: calcularDisabledBFAgregarListo(configSorteoFormulario,idFormularioDestino)
1083
+ });
1084
+ listaDeBotonesAbrir.push({
1085
+ forPk,
1086
+ num:nuevoValorPk - 1,
1087
+ esConfirmar:true,
1088
+ actual:debeAgregarOlisto && (!casillero.longitud || nuevoValorPk > Number(casillero.longitud)),
1089
+ previo: false,
1090
+ disabled: calcularDisabledBFAgregarListo(configSorteoFormulario,idFormularioDestino)
1091
+ });
1092
+ }
1093
+ }else{
1094
+ let forPk={...props.forPk, formulario:idFormularioDestino};
1095
+ listaDeBotonesAbrir = [{forPk, num:false, unico:true, actual:esVarActual, previo:true}]
1096
+ }
1097
+ var todosLosBotones = listaDeBotonesAbrir.map(defBoton=>
1098
+ botonFormularioConResumen(defBoton, feedbackAll[toPlainForPk(defBoton.forPk)]??{resumen:'vacio'}, respuestasAumentadas,
1099
+ casillero, props.forPk, idButton, formularioAAbrir
1100
+ )
1101
+ )
1102
+ var htmlSeccion=document.getElementById(idSeccion)!;
1103
+ htmlSeccion.innerHTML="";
1104
+ htmlSeccion.appendChild(html.div(todosLosBotones).create());
1105
+ //arrange(document.getElementById(idSeccion)!, todosLosBotones);
1106
+ }catch(err){
1107
+ var error = unexpected(err);
1108
+ console.log("entra al catch")
1109
+ div.textContent='esto, FALLÉ '+error.message;
1110
+ }
1111
+ }
1112
+ });
1113
+ const ir = (defBoton:DefinicionFormularioAbrir)=>{
1114
+ if(!casillero.salto){
1115
+ opciones.modoDirecto?
1116
+ null
1117
+ :
1118
+ dispatch(dispatchers.VOLVER_HDR({}));
1119
+ }else{
1120
+ var nuevaForPk={...forPk, formulario:idFormularioDestino};
1121
+ if(multipleFormularios){
1122
+ // @ts-ignore forPk y sus componentes
1123
+ nuevaForPk[nuevoCampoPk] = defBoton.num
1124
+ if(defBoton.esAgregar){
1125
+ dispatchByPass(accion_agregar_formulario,{forPk:nuevaForPk});
1126
+ }else{
1127
+ dispatchByPass(accion_abrir_formulario,{forPk:nuevaForPk});
1128
+ }
1129
+ }
1130
+ dispatch(dispatchers.CAMBIAR_FORMULARIO({forPk:nuevaForPk, apilarVuelta:true}));
1131
+ }
1132
+ if(confirmarForzarIr){setConfirmarForzarIr(false)}
1133
+ };
1134
+ return <DesplegarCasillero casillero={casillero}>
1135
+ <div id={idSeccion}>
1136
+ </div>
1137
+ <Button className="special-button" id={idButton}
1138
+ onClick={(event)=>{
1139
+ ir(JSON.parse((event.target! as unknown as HTMLButtonElement).getAttribute('def-button')!))
1140
+ }}
1141
+ >ir (interno)</Button>
1142
+ <Dialog
1143
+ className="nuestro-dialogo"
1144
+ open={!!confirmarForzarIr}
1145
+ onClose={()=>setConfirmarForzarIr(null)}
1146
+ >
1147
+ <div className="nuestro-dialogo">
1148
+ <Typography>No se puede avanzar al siguiente formulario.</Typography>
1149
+ <Typography>Quizás no terminó de contestar las preguntas correspondientes</Typography>
1150
+ <Typography>Quizás no corresponde en base a las respuestas obtenidas</Typography>
1151
+ </div>
1152
+ <Button color="secondary" onClick={()=>confirmarForzarIr && ir(confirmarForzarIr)}>forzar</Button>
1153
+ <Button color="primary" variant="contained" onClick={()=>setConfirmarForzarIr(null)}>Entendido</Button>
1154
+ </Dialog>
1155
+ </DesplegarCasillero>
1156
+ }
1157
+
1158
+ function CasilleroDesconocido(props:{casillero:CasilleroBase, forPk:ForPk}){
1159
+ return <DesplegarCasillero
1160
+ id={`casillerodesconocido-${props.casillero.id_casillero}`}
1161
+ casillero={props.casillero as Bloque}
1162
+ style={{display:'none'}}
1163
+ >
1164
+ <Typography>Tipo de casillero no implementado: "{props.casillero.tipoc}" para "{props.casillero.casillero}"</Typography>
1165
+ <EncabezadoDespliegue casillero={props.casillero as CasilleroEncabezable} leer={false} forPk={props.forPk}/>
1166
+ </DesplegarCasillero>
1167
+ }
1168
+
1169
+ function useSelectorVivienda(forPk:ForPk){
1170
+ return useSelector((state:CasoState)=>{
1171
+ var estructura = getEstructura();
1172
+ return {
1173
+ formulario: estructura.formularios[forPk.formulario].casilleros,
1174
+ modoDespliegue: true || state.modo.demo?state.opciones.modoDespliegue:'relevamiento',
1175
+ modo: state.modo,
1176
+ opciones: state.opciones,
1177
+ }
1178
+ })
1179
+ }
1180
+
1181
+ function ConjuntoPreguntasDespliegue(props:{casillero:ConjuntoPreguntas, formulario:Formulario, forPk:ForPk}){
1182
+ let {casillero, forPk} = props;
1183
+ var id = `conjunto-preguntas-${casillero.id_casillero}`;
1184
+ registrarElemento({
1185
+ id,
1186
+ direct:true,
1187
+ fun: registradorDeVariable(casillero)
1188
+ })
1189
+ let modoDespliegue = "normal";
1190
+ let habilitado = true;
1191
+ return habilitado || modoDespliegue=='metadatos'?<DesplegarCasillero id={id} casillero={casillero}>
1192
+ <EncabezadoDespliegue casillero={casillero} forPk={forPk} leer={casillero.leer!==false}/>
1193
+ <DesplegarContenidoInternoBloqueOFormulario bloqueOFormulario={casillero} formulario={props.formulario} forPk={forPk} multiple={false}/>
1194
+ </DesplegarCasillero>:null;
1195
+ }
1196
+
1197
+ function DesplegarContenidoInternoBloqueOFormulario(props:{bloqueOFormulario:Bloque|Formulario|ConjuntoPreguntas, formulario:Formulario, forPk:ForPk, multiple:boolean}){
1198
+ var parcializable = props.bloqueOFormulario.tipoc=='F';
1199
+ const [verTodo, setVerTodo] = useState(!parcializable);
1200
+ const [forPkActual, setForPkActual] = useState<IdCasillero|null>(null);
1201
+ if(parcializable){
1202
+ if(forPkActual != props.bloqueOFormulario.casillero){
1203
+ setVerTodo(false)
1204
+ setForPkActual(props.bloqueOFormulario.casillero)
1205
+ }
1206
+ useEffect(()=>{
1207
+ var timer:NodeJS.Timeout|null = setTimeout(()=>{
1208
+ setVerTodo(true);
1209
+ },250)
1210
+ return ()=>{
1211
+ if(timer){
1212
+ clearTimeout(timer);
1213
+ }
1214
+ }
1215
+ })
1216
+ }
1217
+ const limiteNoVerTodo = 3;
1218
+ useEffect(()=>{
1219
+ if(props.bloqueOFormulario.tipoc=='F'){
1220
+ volcadoInicialElementosRegistrados(props.forPk);
1221
+ }
1222
+ },[toPlainForPk(props.forPk),verTodo])
1223
+ useLayoutEffect(() => {
1224
+ if(props.bloqueOFormulario.tipoc=='F' && verTodo){
1225
+ var {siguienteVariable, variableActual} = dispatchByPass(accion_registrar_respuesta, {respuesta:null, variable:NO_CAMBIAR__SOLO_TRAER_STATUS, forPk:props.forPk});
1226
+ if(variableActual || siguienteVariable){
1227
+ enfocarElementoDeVariable(coalesce(variableActual as string|null,siguienteVariable as string|null) as IdVariable)
1228
+ }else{
1229
+ var feedbackRowValidator = getFeedbackRowValidator()
1230
+ if(feedbackRowValidator[toPlainForPk(props.forPk)].resumen=='ok'){
1231
+ scrollToTop()
1232
+ }else{
1233
+ scrollToTop()
1234
+ }
1235
+ }
1236
+ }
1237
+ });
1238
+ return <div className="contenido">
1239
+ {verTodo?null:<div style={{height:"500px", textAlign:'center', verticalAlign:'middle', width:'100%', position:"fixed", backgroundColor: 'rgba(100,100,100,0.3)', fontSize:'200%'}} >cargando...</div>}
1240
+ {props.bloqueOFormulario.casilleros.map((casillero, i)=>{
1241
+ var key = casillero.tipoc+'-'+casillero.id_casillero+'-'+i;
1242
+ return (verTodo || i < limiteNoVerTodo?
1243
+ (
1244
+ casillero.tipoc == "P"?<PreguntaDespliegue key={key} pregunta={casillero} forPk={props.forPk} despliegueEncabezado={casillero.despliegueEncabezado??(props.bloqueOFormulario.tipoc=='CP'?'lateral':'superior')}/>:
1245
+ casillero.tipoc == "B"?<BloqueDespliegue key={key} bloque={casillero} formulario={props.formulario} forPk={props.forPk}/>:
1246
+ casillero.tipoc == "FILTRO"?<FiltroDespliegue key={key} filtro={casillero} forPk={props.forPk}/>:
1247
+ casillero.tipoc == "BF"?<BotonFormularioDespliegue key={key} casillero={casillero} formulario={props.formulario} forPk={props.forPk}/>:
1248
+ casillero.tipoc == "CONS"?<ConsistenciaDespliegue key={key} casillero={casillero} forPk={props.forPk}/>:
1249
+ casillero.tipoc == "CP"?<ConjuntoPreguntasDespliegue key={key} casillero={casillero} formulario={props.formulario} forPk={props.forPk}/>:
1250
+ casillero.tipoc == "TEXTO"?<TextoDespliegue key={key} casillero={casillero} forPk={props.forPk}/>:
1251
+ <CasilleroDesconocido key={key} casillero={casillero} forPk={props.forPk}/>
1252
+ )
1253
+ :i==limiteNoVerTodo?
1254
+ <div key='$spinner' className="spinner-border" role="status">
1255
+ <span>cargando bloque...</span>
1256
+ </div>
1257
+ :null
1258
+ )
1259
+ })
1260
+ }</div>
1261
+ }
1262
+
1263
+ function BloqueDespliegue(props:{bloque:Bloque, formulario:Formulario, forPk:ForPk}){
1264
+ var {bloque, forPk} = props;
1265
+ var key=bloque.ver_id!='-' && bloque.ver_id || bloque.casillero;
1266
+ var activeStep=0;
1267
+ var multiple = !!bloque.unidad_analisis;
1268
+ var lista = [{forPk, key:0, multiple:false}];
1269
+ var habilitador = bloque.expresion_habilitar_js?getFuncionHabilitar(bloque.expresion_habilitar_js):()=>true;
1270
+ var {modoDespliegue} = useSelectorVivienda(forPk);
1271
+ if(multiple){
1272
+ // TODO: GENERALIZAR
1273
+ // @ts-ignore
1274
+ // lista=respuestas.personas.map((_persona, i)=>(
1275
+ // {forPk:{...forPk, persona:i+1}, key:i+1, multiple:true}
1276
+ // ))
1277
+ }
1278
+ var id = `bloque-${bloque.id_casillero}`;
1279
+ registrarElemento({
1280
+ id,
1281
+ style:'display',
1282
+ fun: (respuestas:Respuestas)=> habilitador(respuestas) || modoDespliegue=='metadatos'?'unset':'none'
1283
+ })
1284
+ return <DesplegarCasillero casillero={bloque} nuestro-bloque={bloque.id_casillero} es-multiple={multiple?'SI':'NO'} id={id}>
1285
+ <EncabezadoDespliegue casillero={bloque} forPk={forPk}/>
1286
+ {lista.map(({key, forPk, multiple})=>
1287
+ <DesplegarContenidoInternoBloqueOFormulario key={key} bloqueOFormulario={bloque} formulario={props.formulario} forPk={forPk} multiple={multiple}/>
1288
+ )}
1289
+ </DesplegarCasillero>;
1290
+ }
1291
+
1292
+ const FormularioEncabezado = DespliegueEncabezado;
1293
+
1294
+ function MenuLetra(props:{tamannio:number, denominacion:string}){
1295
+ const cambiarLetra = (tamannio:number)=>{
1296
+ var root = document.documentElement;
1297
+ root.style.fontSize=tamannio+"px";
1298
+ }
1299
+ return <MenuItem
1300
+ onClick={()=>cambiarLetra(props.tamannio)} style={{fontSize:props.tamannio+'px'}}
1301
+ >letra {props.denominacion}</MenuItem>
1302
+ }
1303
+
1304
+ function FastSettup(){
1305
+ const [anchorEl, setAnchorEl] = React.useState(null);
1306
+ const [open, setOpen] = React.useState(false);
1307
+ const handleClick = (event:any) => {
1308
+ setAnchorEl(event.currentTarget);
1309
+ setOpen((prev) => !prev);
1310
+ };
1311
+ const dispatch = useDispatch();
1312
+ const cambiar = (modoDespliegue:ModoDespliegue)=>{
1313
+ dispatch(dispatchers.MODO_DESPLIEGUE({modoDespliegue}));
1314
+ setOpen(false)
1315
+ }
1316
+ const opciones = useSelector((state:CasoState)=>state.opciones)
1317
+ return <>
1318
+ <Button onClick={handleClick}>
1319
+ <ICON.Settings/>
1320
+ </Button>
1321
+ <Menu open={open} anchorEl={anchorEl} onClose={()=>setOpen(false)}>
1322
+ <MenuItem onClick={()=>cambiar("relevamiento")}>normal</MenuItem>
1323
+ <MenuItem onClick={()=>cambiar("PDF" )}>PDF para relevamiento</MenuItem>
1324
+ <MenuItem onClick={()=>cambiar("metadatos" )}>revisar metadatos</MenuItem>
1325
+ <Divider/>
1326
+ <MenuLetra tamannio={12} denominacion = "muy chica"/>
1327
+ <MenuLetra tamannio={14} denominacion = "chica"/>
1328
+ <MenuLetra tamannio={16} denominacion = "normal"/>
1329
+ <MenuLetra tamannio={19} denominacion = "grande"/>
1330
+ <MenuLetra tamannio={22} denominacion = "enorme"/>
1331
+ <Divider/>
1332
+ <MenuItem><label><Checkbox checked={opciones.conCampoOpciones} onChange={
1333
+ ()=>dispatch(dispatchers.SET_OPCION({opcion:'conCampoOpciones', valor:!opciones.conCampoOpciones}))
1334
+ } inputProps={{ 'aria-label': 'primary checkbox' }}/>campo opciones</label></MenuItem>
1335
+ <MenuItem><label><Checkbox checked={opciones.saltoAutomatico} onChange={
1336
+ ()=>dispatch(dispatchers.SET_OPCION({opcion:'saltoAutomatico', valor:!opciones.saltoAutomatico}))
1337
+ } inputProps={{ 'aria-label': 'primary checkbox' }}/>salto automático</label></MenuItem>
1338
+ </Menu>
1339
+ </>;
1340
+ }
1341
+
1342
+ function BarraDeNavegacion(props:{forPk:ForPk, soloLectura:boolean, modoDirecto:boolean}){
1343
+ const dispatch = useDispatch();
1344
+ const forPk = props.forPk;
1345
+ const {opciones} = useSelectorVivienda(forPk);
1346
+ const [confirmaCerrar, setConfirmaCerrar] = useState<boolean|null>(false);
1347
+ var dominio = getDatosByPass().informacionHdr[forPk.vivienda!].tem.dominio;
1348
+ var cerrarDirecto = async function(){
1349
+ removeCSSById(BOOTSTRAP_5_1_3_SRC);
1350
+ var estructura = getEstructura();
1351
+ gotoConsistir(
1352
+ estructura.operativo as IdOperativo,
1353
+ getDatosByPass().informacionHdr[forPk.vivienda!].tarea.tarea,
1354
+ forPk.vivienda?.toString() as IdEnc
1355
+ );
1356
+ //var hash=new URLSearchParams(location.hash?.replace(/^\#/,'').split('&autoproced')[0]);
1357
+ ////hash.delete('autoproced')
1358
+ //close();
1359
+ //location.hash=hash.toString();
1360
+ }
1361
+ var botonesFormulario=[];
1362
+ if(!opciones.modoDirecto){
1363
+ botonesFormulario.push({que: 'hdr' , abr:'HdR', label:'hoja de ruta', retroceso:0})
1364
+ }
1365
+ opciones.pilaForPk.forEach((forPk,i)=>
1366
+ botonesFormulario.push({que:'volver', abr:forPk.formulario.replace(/^F:/,''), label:forPk.formulario, retroceso:opciones.pilaForPk.length-i})
1367
+ )
1368
+ botonesFormulario.push({que:'', abr:forPk.formulario.replace(/^F:/,''), label:forPk.formulario, retroceso:0});
1369
+ return <>
1370
+ <ButtonGroup key="formularios" className="barra-navegacion" solo-lectura={props.soloLectura?'si':'no'} >
1371
+ {botonesFormulario.map((b,i)=>
1372
+ <Button color={b.que==forPk.formulario?"primary":"inherit"} variant="outlined"
1373
+ key={`${i}-${b.que}-${b.retroceso}`}
1374
+ disabled={!b.que}
1375
+ onClick={()=>
1376
+ dispatch(
1377
+ b.que=='hdr'?dispatchers.VOLVER_HDR({}):
1378
+ dispatchers.VOLVER_DE_FORMULARIO({magnitudRetroceso:b.retroceso})
1379
+ )
1380
+ }
1381
+ >
1382
+ <span className="abr">{b.abr}</span>
1383
+ <span className="label">{b.label}</span>
1384
+ </Button>
1385
+ )}
1386
+ </ButtonGroup>
1387
+ {props.soloLectura?<Typography component="span" style={{margin:'0 10px'}}> (Solo Lectura) </Typography>:null}
1388
+ {props.modoDirecto?
1389
+ <>
1390
+ <ButtonGroup key="volver_y_grabar" style={{margin:'0 0 0 30px'}}>
1391
+ <Button
1392
+ color="inherit"
1393
+ variant="outlined"
1394
+ onClick={async ()=>{
1395
+ if(props.soloLectura || !getDirty()){
1396
+ cerrarDirecto();
1397
+ }else{
1398
+ setConfirmaCerrar(true)
1399
+ }
1400
+ }}
1401
+ >
1402
+ <ICON.ExitToApp/>
1403
+ </Button>
1404
+ <Dialog
1405
+ open={!!confirmaCerrar}
1406
+ //hace que no se cierre el mensaje
1407
+ onClose={()=>setConfirmaCerrar(false)}
1408
+ aria-labelledby="alert-dialog-title"
1409
+ aria-describedby="alert-dialog-description"
1410
+ >
1411
+ <DialogTitle id="alert-dialog-title">Confirme cierre de encuesta</DialogTitle>
1412
+ <DialogContent>
1413
+ <DialogContentText id="alert-dialog-description">
1414
+ Está por salir de la encuesta, se perderán los cambios no guardados.
1415
+ </DialogContentText>
1416
+ </DialogContent>
1417
+ <DialogActions>
1418
+ <Button
1419
+ onClick={()=>{
1420
+ cerrarDirecto()
1421
+ }}
1422
+ color="secondary"
1423
+ variant="outlined"
1424
+ >
1425
+ descartar cambios y cerrar
1426
+ </Button>
1427
+ <Button
1428
+ onClick={()=>{
1429
+ setConfirmaCerrar(false)
1430
+ }}
1431
+ color="primary"
1432
+ variant="contained"
1433
+ >
1434
+ continuar editando encuesta
1435
+ </Button>
1436
+
1437
+ </DialogActions>
1438
+ </Dialog>
1439
+ {props.soloLectura?null:
1440
+ <Button
1441
+ id={"save-button"}
1442
+ color="inherit"
1443
+ variant="outlined"
1444
+ disabled={true}
1445
+ onClick={async ()=>true}
1446
+ >
1447
+ <ICON.Save/>
1448
+ </Button>
1449
+ }
1450
+ </ButtonGroup>
1451
+ </>
1452
+ :null}
1453
+ <Typography className="mostrar-forPk" component="span" style={{margin:'0 10px'}}>
1454
+ {VER_DOMINIO?<div key={dominio}><span>dominio</span><span>{dominio}</span></div>:''}
1455
+ {likeAr(props.forPk).filter((_,k)=>k!='formulario').map((v,k)=>
1456
+ <div key={k}><span>{k}</span><span>{v}</span></div>
1457
+ ).array()}
1458
+ </Typography>
1459
+ <FastSettup/>
1460
+ </>
1461
+ }
1462
+
1463
+ function BotonVolverEnDiv({id}:{id:string}){
1464
+ var {opciones} = useSelector((state:CasoState)=>({opciones:state.opciones}));
1465
+ const dispatch = useDispatch();
1466
+ return <div className="div-boton-volver">
1467
+ {opciones.pilaForPk.length>0?
1468
+ <Button id={id} className="boton-volver"
1469
+ onClick={()=>dispatch(dispatchers.VOLVER_DE_FORMULARIO({magnitudRetroceso:1}))}
1470
+ > <ICON.ChevronLeft/> Volver</Button>
1471
+ :null}
1472
+ </div>
1473
+ }
1474
+
1475
+ function FormularioDespliegue(props:{forPk:ForPk}){
1476
+ var forPk = props.forPk;
1477
+ var {formulario, modoDespliegue, modo, opciones}
1478
+ = useSelectorVivienda(props.forPk);
1479
+ var soloLectura = getDatosByPass().soloLectura;
1480
+ const dispatch = useDispatch();
1481
+ useEffect(()=>{
1482
+ var controlScroll=()=>{
1483
+ var arriba = document.getElementById('fab-activo-arriba');
1484
+ if(arriba){
1485
+ setValorDistinto(arriba.style, 'visibility',
1486
+ // @ts-ignore
1487
+ arriba.elTopVisibilizar !=null && arriba.elTopVisibilizar + 10
1488
+ < document.documentElement.scrollTop ? 'visible' : 'hidden'
1489
+ );
1490
+ }
1491
+ var abajo = document.getElementById('fab-activo-abajo');
1492
+ if(abajo){
1493
+ setValorDistinto(abajo.style, 'visibility',
1494
+ // @ts-ignore
1495
+ abajo.elBottomVisibilizar != null && abajo.elBottomVisibilizar - 20
1496
+ > document.documentElement.scrollTop + window.innerHeight * 0.7 ? 'visible' : 'hidden'
1497
+ );
1498
+ }
1499
+ }
1500
+ window.addEventListener('scroll', controlScroll);
1501
+ controlScroll();
1502
+ return ()=>{
1503
+ window.removeEventListener('scroll', controlScroll);
1504
+ }
1505
+ })
1506
+ // TODO Volver a poner el movimiento a la actual
1507
+ var actual:any
1508
+ var completo:any
1509
+ var onClickSaltarActual = ()=>{
1510
+ var {variableActual} = dispatchByPass(accion_registrar_respuesta, {respuesta:null, variable:NO_CAMBIAR__SOLO_TRAER_STATUS, forPk:props.forPk});
1511
+ if(variableActual){
1512
+ enfocarElementoDeVariable(variableActual)
1513
+ }
1514
+ }
1515
+ var listaModos:ModoDespliegue[]=['metadatos','relevamiento','PDF'];
1516
+ ['boton-volver-1', 'boton-volver-2'].forEach(id=>{
1517
+ registrarElemento({id, attr:'resumen-estado', fun:(_:Respuestas, feedbackForm: FormStructureState<IdVariable, Valor, IdFin>)=>(
1518
+ feedbackForm.resumen
1519
+ )})
1520
+ })
1521
+ return (
1522
+ <>
1523
+ <AppBar position="fixed" color={soloLectura?'secondary':'primary'}>
1524
+ <Toolbar>
1525
+ <BarraDeNavegacion forPk={forPk} soloLectura={soloLectura || false} modoDirecto={opciones.modoDirecto}/>
1526
+ </Toolbar>
1527
+ <div id="mini-console"></div>
1528
+ </AppBar>
1529
+ <main>
1530
+ <Paper className="formulario" modo-despliegue={modoDespliegue} ver-num-opciones={opciones.conCampoOpciones?'SI':'NO'}>
1531
+ {modo.demo?<div>
1532
+ <Typography component="span">Modo de despliegue:</Typography>
1533
+ <ButtonGroup>
1534
+ {listaModos.map(modo=>
1535
+ <Button key={modo} variant={modo==modoDespliegue?"contained":"outlined"} onClick={
1536
+ ()=>dispatch(dispatchers.MODO_DESPLIEGUE({modoDespliegue:modo}))
1537
+ }>{modo}</Button>
1538
+ )}
1539
+ </ButtonGroup>
1540
+ </div>:null}
1541
+ <BotonVolverEnDiv id="boton-volver-1"/>
1542
+ <FormularioEncabezado casillero={formulario}/>
1543
+ <DesplegarContenidoInternoBloqueOFormulario bloqueOFormulario={formulario} formulario={formulario} forPk={forPk} multiple={false}/>
1544
+ <BotonVolverEnDiv id="boton-volver-2"/>
1545
+ </Paper>
1546
+ <Fab id='fab-activo-arriba' color="primary" aria-label="add" onClick={onClickSaltarActual}>
1547
+ <ICON.KeyboardArrowUp />
1548
+ </Fab>
1549
+ <Fab id='fab-activo-abajo' color="primary" aria-label="add" onClick={onClickSaltarActual}>
1550
+ <ICON.KeyboardArrowDown />
1551
+ </Fab>
1552
+ <Fab id='fab-error-arriba' variant="extended" color="secondary" aria-label="edit">
1553
+ <ICON.Navigation />
1554
+ Error
1555
+ </Fab>
1556
+ <Fab id='fab-error-abajo' variant="extended" color="secondary" aria-label="edit">
1557
+ <ICON.NavigationDown />
1558
+ Error
1559
+ </Fab>
1560
+ <div className='espacio-final-formulario'></div>
1561
+ {opciones.modoBorrarRespuesta && opciones.forPk?<DesplegarConfirmarBorrarRespuesta forPk={opciones.forPk} variableBorrar={opciones.modoBorrarRespuesta}/>:null}
1562
+ </main>
1563
+ </>
1564
+ );
1565
+ }
1566
+
1567
+ export function Atributo(props:{nombre:string, valor:any}){
1568
+ return props.valor!=null && props.valor!=''?<span className="atributo-par">
1569
+ {props.nombre?<span className="atributo-nombre">{props.nombre}</span>:null}
1570
+ <span className="atributo-valor">{props.valor.toString()}</span>
1571
+ </span>:null
1572
+ }
1573
+
1574
+ const listaEstadosCarga:EstadoCarga[]=['resumen','relevamiento','recibo'];
1575
+ var resumidores = [
1576
+ {nombre:'REA' , f:(rr:RespuestasRaiz)=>rr.resumenEstado=="ok" },
1577
+ {nombre:'Cita pactada', f:(rr:RespuestasRaiz)=>rr.resumenEstado=="cita pactada"},
1578
+ {nombre:'Pendientes' , f:(rr:RespuestasRaiz)=>rr.resumenEstado=="vacio" },
1579
+ ];
1580
+
1581
+ resumidores.push(
1582
+ {nombre:'Otros', f:resumidores.reduce((g,r)=>(rr=>!r.f(rr) && g(rr) ),(_:RespuestasRaiz)=>true) }
1583
+ )
1584
+
1585
+ export function DesplegarLineaResumenUAPrincipal(props:{
1586
+ numVivienda:number,
1587
+ formPrincipal:IdFormulario,
1588
+ tarea: string,
1589
+ respuestas:RespuestasRaiz,
1590
+ }){
1591
+ const {numVivienda, respuestas, formPrincipal, tarea} = props;
1592
+ const id='viv-'+numVivienda;
1593
+ const forPk:ForPk={formulario:formPrincipal, vivienda:Number(numVivienda)};
1594
+ var tem = getDatosByPass().informacionHdr[numVivienda].tem;
1595
+ var dispatch = useDispatch();
1596
+ useEffect(()=>{
1597
+ volcadoInicialElementosRegistrados(forPk);
1598
+ intentarBackup(forPk)
1599
+ })
1600
+ registrarElemento({id, direct:true,
1601
+ fun:(
1602
+ r:Respuestas,
1603
+ _feedbackForm: FormStructureState<IdVariable, Valor, IdFin>,
1604
+ elemento:HTMLDivElement,
1605
+ feedbackAll:{[formulario in PlainForPk]:FormStructureState<IdVariable, Valor, IdFin>},
1606
+ _estructura:Estructura
1607
+ )=>{
1608
+ //pregunto si es la misma vivienda porque la funcion se dispara
1609
+ //con todas las combinaciones de respuestas para cada forPk
1610
+ //@ts-ignore vivienda existe
1611
+ if(r.vivienda == forPk.vivienda){
1612
+ elemento.setAttribute('resumen-estado',calcularResumenVivienda(forPk, feedbackAll, r).resumenEstado);
1613
+ }
1614
+ }
1615
+
1616
+ })
1617
+ return <TableRow key={numVivienda}>
1618
+ <TableCell>
1619
+ {tem?
1620
+ <>
1621
+ <DesplegarTem tem={tem}/>
1622
+ {respuestas['resumenEstado' as IdVariable]=="cita pactada"?
1623
+ <DesplegarCitaPactada respuestas={respuestas}/>
1624
+ :
1625
+ <DesplegarCitaPactadaYSeleccionadoAnteriorTem tem={tem}/>
1626
+ }
1627
+ </>
1628
+ :null}
1629
+ </TableCell>
1630
+ <TableCell>
1631
+ {tarea}
1632
+ </TableCell>
1633
+ <TableCell>
1634
+ <Button id={id} onClick={()=>
1635
+ dispatch(dispatchers.CAMBIAR_FORMULARIO({forPk, apilarVuelta:false}))
1636
+ }>
1637
+ {numVivienda.toString()}
1638
+ </Button>
1639
+ </TableCell>
1640
+ </TableRow>
1641
+ }
1642
+
1643
+ export function DesplegarCarga(props:{
1644
+ carga:Carga,
1645
+ idCarga:IdCarga,
1646
+ posicion:number,
1647
+ informacionHdr:InformacionHdr,
1648
+ respuestas: Respuestas,
1649
+ feedbackRowValidator:{
1650
+ [formulario in PlainForPk]:FormStructureState<IdVariable, Valor, IdFin>
1651
+ }
1652
+ }){
1653
+ const {carga, idCarga, informacionHdr, respuestas} = props;
1654
+ return <Paper className="carga">
1655
+ <div className="informacion-carga">
1656
+ <div className="carga">Área: {idCarga}</div>
1657
+ <div className="observaciones">{carga.observaciones}</div>
1658
+ </div>
1659
+ <div className="informacion-carga">
1660
+ <div className="fecha">{carga.fecha}</div>
1661
+ {/*
1662
+ <ButtonGroup>
1663
+ {listaEstadosCarga.map(estado_carga=>
1664
+ <Button key={estado_carga} variant={estado_carga==carga.estado_carga?"contained":"outlined"} onClick={
1665
+ ()=>dispatch(dispatchers.ESTADO_CARGA({idCarga, estado_carga}))
1666
+ }>{estado_carga}</Button>
1667
+ )}
1668
+ </ButtonGroup>
1669
+ */}
1670
+ </div>
1671
+ {carga.estado_carga==null && !props.posicion || carga.estado_carga=='relevamiento'?
1672
+ <Table className="tabla-carga-hoja-de-ruta">
1673
+ <colgroup>
1674
+ <col style={{width:"75%"}}/>
1675
+ <col style={{width:"10%"}}/>
1676
+ <col style={{width:"15%"}}/>
1677
+ </colgroup>
1678
+ <TableHead style={{fontSize: "1.2rem"}}>
1679
+ <TableRow className="tr-carga">
1680
+ <TableCell>domicilio</TableCell>
1681
+ <TableCell>tarea</TableCell>
1682
+ <TableCell>enc</TableCell>
1683
+ </TableRow>
1684
+ </TableHead>
1685
+ <TableBody>
1686
+ {beingArray(informacionHdr).filter((informacion:DatosHdrUaPpal, _numVivienda:number)=>informacion.tem.carga==idCarga).map((informacion:DatosHdrUaPpal, numVivienda:number)=>
1687
+ <DesplegarLineaResumenUAPrincipal
1688
+ key={numVivienda}
1689
+ numVivienda={numVivienda}
1690
+ tarea={informacion.tarea.tarea}
1691
+ formPrincipal={informacion.tarea.main_form}
1692
+ respuestas={respuestas.viviendas[numVivienda]}
1693
+ />
1694
+ ).array()}
1695
+ </TableBody>
1696
+ </Table>:
1697
+ <Table>
1698
+ <TableHead style={{fontSize: "1.2rem"}}>
1699
+ <TableRow className="tr-carga">
1700
+ {resumidores.map((resumidor: typeof resumidores[0], i:number)=>
1701
+ <TableCell key={i}>
1702
+ {resumidor.nombre}
1703
+ </TableCell>
1704
+ )}
1705
+ </TableRow>
1706
+ </TableHead>
1707
+ </Table>
1708
+ }
1709
+ </Paper>
1710
+ }
1711
+ export function DesplegarCitaPactada(props:{respuestas:Respuestas}){
1712
+ const {respuestas} = props;
1713
+ return <div className="cita-pactada">
1714
+ <div><Atributo nombre="Cita pactada con " valor={respuestas[p12]}/></div>
1715
+ <div><Atributo nombre="Cel.:" valor={respuestas[sp2]}/></div>
1716
+ <div><Atributo nombre="Tel.:" valor={respuestas[sp3]}/></div>
1717
+ <div><Atributo nombre="Fecha:" valor={respuestas[sp4]}/></div>
1718
+ <div><Atributo nombre="Hora:" valor={respuestas[sp5]}/></div>
1719
+ </div>
1720
+ }
1721
+
1722
+ export function DesplegarCitaPactadaYSeleccionadoAnteriorTem(props:{tem:TEM}){
1723
+ const {tem} = props;
1724
+ return <div>
1725
+ <div className="tem-cita">
1726
+ <Atributo nombre="Cita:" valor={tem.cita}/>
1727
+ </div>
1728
+ </div>
1729
+ }
1730
+
1731
+ export function DesplegarTem(props:{tem:TEM}){
1732
+ const {tem} = props;
1733
+ return <div>
1734
+ <div className="tem-domicilio">{tem.nomcalle} {tem.nrocatastral} <Atributo nombre="piso" valor={tem.piso}/> <Atributo nombre="dpto" valor={tem.departamento}/> </div>
1735
+ <div>
1736
+ <Atributo nombre="sector" valor={tem.sector}/>
1737
+ <Atributo nombre="edificio" valor={tem.edificio}/>
1738
+ <Atributo nombre="casa" valor={tem.casa}/>
1739
+ <Atributo nombre="entrada" valor={tem.entrada}/>
1740
+ <Atributo nombre="habitacion" valor={tem.habitacion}/>
1741
+ </div>
1742
+ <div className="tem-observaciones">
1743
+ {tem.observaciones}
1744
+ </div>
1745
+ </div>
1746
+ }
1747
+
1748
+ export function HojaDeRutaDespliegue(){
1749
+ var {cargas, num_sincro, informacionHdr, respuestas} = getDatosByPass();
1750
+ var {modo} = useSelector((state:CasoState)=>({modo:state.modo}));
1751
+ var feedbackRowValidator = getFeedbackRowValidator()
1752
+ var dispatch = useDispatch();
1753
+ const updateOnlineStatus = function(){
1754
+ setOnline(window.navigator.onLine);
1755
+ }
1756
+ const appVersion = getCacheVersion();
1757
+ const [online, setOnline] = useState(window.navigator.onLine);
1758
+ window.addEventListener('online', updateOnlineStatus);
1759
+ window.addEventListener('offline', updateOnlineStatus);
1760
+ return (
1761
+ <>
1762
+ <AppBar position="fixed">
1763
+ <Toolbar>
1764
+ <Typography variant="h6">
1765
+ Hoja de ruta
1766
+ </Typography>
1767
+ {
1768
+ //<IconButton style={{marginTop:'3px'}}
1769
+ // color="inherit"
1770
+ // //onClick={/*dispatch que lleva a pantalla opciones*/}
1771
+ //>
1772
+ // <ICON.Settings/>
1773
+ //</IconButton>
1774
+ }
1775
+ {online?
1776
+ <>
1777
+ <IconButton
1778
+ color="inherit"
1779
+ onClick={()=>{
1780
+ gotoSincronizar()
1781
+ }}
1782
+ >
1783
+ <ICON.SyncAlt/>
1784
+ </IconButton>
1785
+ </>
1786
+ :null}
1787
+ </Toolbar>
1788
+ </AppBar>
1789
+ <div className="hoja-de-ruta">
1790
+ {modo.demo?<div>
1791
+ <Typography>Modo demo </Typography>
1792
+ <Button variant="outlined" color="secondary"
1793
+ onClick={()=>dispatch(dispatchers.REINICIAR_DEMO({}))}
1794
+ >
1795
+ reiniciar
1796
+ </Button>
1797
+ </div>:null}
1798
+ <div className="nombre-version">
1799
+ <div>Dirección General de Estadística y Censos - C.A.B.A.</div>
1800
+ <div>{my.getLocalVar('app-version')} sincro {num_sincro} - versión {appVersion}</div>
1801
+ </div>
1802
+ {likeAr(cargas).map((carga: Carga, idCarga: IdCarga, _, posicion:number)=>
1803
+ <DesplegarCarga key={idCarga} carga={carga} idCarga={idCarga} posicion={posicion} informacionHdr={informacionHdr} feedbackRowValidator={feedbackRowValidator} respuestas={respuestas}/>
1804
+ ).array()}
1805
+ </div>
1806
+ </>
1807
+ );
1808
+ }
1809
+
1810
+ export function ListaTextos(props:{textos:string[]}){
1811
+ return <ul>
1812
+ {props.textos.map(t=><li><Typography>{t}</Typography></li>)}
1813
+ </ul>;
1814
+ }
1815
+
1816
+ export function BienvenidaDespliegue(props:{modo:CasoState["modo"]}){
1817
+ var dispatch=useDispatch();
1818
+ return <Paper className="bienvenida">
1819
+ {props.modo.demo?
1820
+ <>
1821
+ <Typography>DEMO del sistema de relevamiento de DMENCU</Typography>
1822
+ <Typography>En esta demo:</Typography>
1823
+ <ListaTextos textos={[
1824
+ "Algunas viviendas aparecen relevadas (el botón está de color) sirven de ejemplo",
1825
+ "Lo que se carguen se guardan localmente pero no se trasmiten a la base de datos",
1826
+ "Se puede volver a la versión inicial (o sea borrar lo que se guardó localmente) desde la hoja de ruta boton [reiniciar demo]",
1827
+ "Todavía hay cosas que faltan o pueden cambiar",
1828
+ ]} />
1829
+ </>
1830
+ :<>
1831
+ <Typography>Encuesta de Seroprevalencia de COVID-19</Typography>
1832
+ </>
1833
+ }
1834
+ <Button
1835
+ variant="contained"
1836
+ color="secondary"
1837
+ onClick={()=>{ gotoSincronizar(); }}
1838
+ >
1839
+ <span>Sincronizar </span> <ICON.SyncAlt/>
1840
+ </Button>
1841
+ <Button
1842
+ variant="contained"
1843
+ color="primary"
1844
+ onClick={()=>dispatch(dispatchers.SET_OPCION({opcion:'bienvenido', valor:true}))}
1845
+ >
1846
+ <span>Continuar </span> <ICON.Send/>
1847
+ </Button>
1848
+ </Paper>
1849
+ }
1850
+
1851
+ //CONTROL DE PESTAÑAS
1852
+ var allOpenedTabs:{[x:string]:number}={};
1853
+ var infoOpenedTabs={
1854
+ allOpenedTabs,
1855
+ myId:'calculando...',
1856
+ otherTabsNames:''
1857
+ }
1858
+
1859
+ export function OpenedTabs(){
1860
+ const [tabs, setTabs] = useState(infoOpenedTabs.otherTabsNames);
1861
+ var {modoDirecto} = useSelector((state:CasoState)=>({modoDirecto:state.opciones.modoDirecto}));
1862
+ const updateTabsStatus = function(){
1863
+ setTabs(infoOpenedTabs.otherTabsNames);
1864
+ }
1865
+ useEffect(()=>{
1866
+ window.addEventListener('my-tabs',updateTabsStatus);
1867
+ return () => window.removeEventListener('my-tabs',updateTabsStatus);
1868
+ },[])
1869
+ return modoDirecto?null:(tabs)?
1870
+ <div className="tab-counter tab-error">¡ATENCIÓN! Hay más de una ventana abierta. Se pueden perder datos: {tabs}</div>
1871
+ :
1872
+ <div className="tab-counter">✔</div>
1873
+ }
1874
+
1875
+ export function AppDmEncu(){
1876
+ var {forPk, bienvenido, modo} = useSelector((state:CasoState)=>({...state.opciones, ...state.modo, ...state}));
1877
+ if(!bienvenido){
1878
+ return <BienvenidaDespliegue modo={modo}/>
1879
+ }else if(forPk==null){
1880
+ return <HojaDeRutaDespliegue />
1881
+ }else{
1882
+ return <FormularioDespliegue forPk={forPk}/>
1883
+ }
1884
+ }
1885
+
1886
+ function PantallaInicialSinCarga(_props:{}){
1887
+ const updateOnlineStatus = function(){
1888
+ setOnline(window.navigator.onLine);
1889
+ }
1890
+ const [online, setOnline] = useState(window.navigator.onLine);
1891
+ window.addEventListener('online', updateOnlineStatus);
1892
+ window.addEventListener('offline', updateOnlineStatus);
1893
+ const paragraphStyles={fontSize:"1.2rem", fontWeight:600, padding: "5px 10px"};
1894
+ return (
1895
+ <>
1896
+ <AppBar position="fixed">
1897
+ <Typography variant="h6" style={{margin:25}}>
1898
+ Dispositivo sin carga
1899
+ </Typography>
1900
+ </AppBar>
1901
+ <main>
1902
+ <Paper style={{height:'600px', padding:"15px", marginTop:75}}>
1903
+ <div>
1904
+ {online?
1905
+ <>
1906
+ <Typography component="p" style={paragraphStyles}>
1907
+ Sincronizar dispositivo
1908
+ <span style={{padding:'5px'}}>
1909
+ <Button
1910
+ color="primary"
1911
+ variant="contained"
1912
+ onClick={()=>{
1913
+ gotoSincronizar()
1914
+ }}
1915
+ >
1916
+ <ICON.SyncAlt/>
1917
+ </Button>
1918
+ </span>
1919
+ </Typography>
1920
+ </>
1921
+ :
1922
+ <Typography component="p" style={paragraphStyles}>
1923
+ No hay conexión a internet, por favor conécte el dispositivo a una red para sincronizar una hoja de ruta.
1924
+ </Typography>
1925
+ }
1926
+ </div>
1927
+ </Paper>
1928
+ </main>
1929
+ </>
1930
+ );
1931
+ }
1932
+
1933
+ export function PantallaInicial(){
1934
+ var {forPk, bienvenido, modo} = useSelector((state:CasoState)=>({...state.opciones, ...state.modo, ...state}));
1935
+ if(!bienvenido){
1936
+ return <BienvenidaDespliegue modo={modo}/>
1937
+ }else if(forPk==null){
1938
+ return <HojaDeRutaDespliegue />
1939
+ }else{
1940
+ return <FormularioDespliegue forPk={forPk}/>
1941
+ }
1942
+ }
1943
+
1944
+ export async function dmPantallaInicialSinCarga(){
1945
+ try{
1946
+ await loadCSS(BOOTSTRAP_5_1_3_SRC);
1947
+ }catch(err){
1948
+ throw(err)
1949
+ }
1950
+ ReactDOM.render(
1951
+ <PantallaInicialSinCarga/>,
1952
+ document.getElementById('main_layout')
1953
+ )
1954
+ }
1955
+
1956
+ export async function desplegarFormularioActual(opts:{modoDemo:boolean, forPkRaiz?:ForPkRaiz}){
1957
+ // traer los metadatos en una "estructura"
1958
+ // traer los datos de localStorage
1959
+ // verificar el main Layout
1960
+ const store = await dmTraerDatosFormulario(opts)
1961
+ try{
1962
+ await loadCSS(BOOTSTRAP_5_1_3_SRC);
1963
+ }catch(err){
1964
+ throw(err)
1965
+ }
1966
+ ReactDOM.render(
1967
+ <RenderPrincipal store={store} dispatchers={dispatchers} mensajeRetorno={opts.forPkRaiz?"Volver al formulario":"Volver a la hoja de ruta"}>
1968
+ <OpenedTabs/>
1969
+ <AppDmEncu/>
1970
+ </RenderPrincipal>,
1971
+ document.getElementById('main_layout')
1972
+ )
1973
+ }
1974
+
1975
+ if(typeof window !== 'undefined'){
1976
+ // @ts-ignore para hacerlo
1977
+ window.desplegarFormularioActual = desplegarFormularioActual;
1978
+ // @ts-ignore para hacerlo
1979
+ window.dmPantallaInicialSinCarga = dmPantallaInicialSinCarga;
1980
+ }
1981
+
1982
+
1983
+ function loadInstance(){
1984
+ if(typeof BroadcastChannel === 'undefined'){
1985
+ return;
1986
+ }
1987
+ var bc = new BroadcastChannel('contador');
1988
+ var myId=String.fromCodePoint(100+Math.floor(Math.random()*1000))+Math.floor(Math.random()*100)//+'-'+new Date().getTime();
1989
+ allOpenedTabs[myId]=1;
1990
+ infoOpenedTabs.myId=myId;
1991
+ var event = new Event('my-tabs');
1992
+ bc.onmessage=function(ev){
1993
+ if(ev.data.que=='soy'){
1994
+ if(!allOpenedTabs[ev.data.id]){
1995
+ allOpenedTabs[ev.data.id]=0;
1996
+ }
1997
+ allOpenedTabs[ev.data.id]++;
1998
+ }
1999
+ if(ev.data.que=='unload'){
2000
+ delete allOpenedTabs[ev.data.id];
2001
+ }
2002
+ if(ev.data.que=='load'){
2003
+ allOpenedTabs[ev.data.id]=1;
2004
+ bc.postMessage({que:'soy',id:myId});
2005
+ }
2006
+ infoOpenedTabs.otherTabsNames=likeAr(allOpenedTabs).filter((_,id)=>id!=myId).join(',');
2007
+ window.dispatchEvent(event);
2008
+ };
2009
+ bc.postMessage({que:'load',id:myId});
2010
+ window.dispatchEvent(event);
2011
+ window.addEventListener('unload',function(){
2012
+ bc.postMessage({que:'unload',id:myId});
2013
+ window.dispatchEvent(event);
2014
+ })
2015
+ //mostrarQuienesSomos();
2016
+ }
2017
+
2018
+ setCalcularVariables((respuestasRaiz:RespuestasRaiz, forPk:ForPk)=>{
2019
+ //TODO GENERALIZAR
2020
+ var uasIterar:{
2021
+ [key in IdUnidadAnalisis]:{
2022
+ uaPersonas: IdUnidadAnalisis,
2023
+ varSexoPersona: IdVariable,
2024
+ varLosNombres: IdVariable
2025
+ }
2026
+ } = {
2027
+ hogares: {
2028
+ uaPersonas: 'personas',
2029
+ varSexoPersona: 'sexo' as IdVariable,
2030
+ varNombrePersona: 'nombre' as IdVariable,
2031
+ varLosNombres: "los_nombres" as IdVariable
2032
+ },
2033
+ //@ts-ignore es unidad de analisis
2034
+ hogares_sup: {
2035
+ uaPersonas: 'personas_sup' as IdUnidadAnalisis,
2036
+ varSexoPersona: 'sexo_sup' as IdVariable,
2037
+ varNombrePersona: 'nombre_sup' as IdVariable,
2038
+ varLosNombres: "nombres_componentes_sup" as IdVariable
2039
+ }
2040
+ }
2041
+ likeAr(uasIterar).forEach((configHogares,uaHogares)=>{
2042
+ for(var respuestasHogar of respuestasRaiz[uaHogares]||[]){
2043
+ if(!respuestasHogar[configHogares.uaPersonas] || respuestasHogar[configHogares.uaPersonas].length==0 || respuestasHogar[configHogares.uaPersonas][0][configHogares.varSexoPersona] == null){
2044
+ if(respuestasHogar[configHogares.varLosNombres]){
2045
+ if(!respuestasHogar[configHogares.uaPersonas]){
2046
+ respuestasHogar[configHogares.uaPersonas]=[];
2047
+ }
2048
+ respuestasHogar[configHogares.varLosNombres].split(',').forEach((nombre, i)=>{
2049
+ respuestasHogar[configHogares.uaPersonas][i] = respuestasHogar[configHogares.uaPersonas][i] || {};
2050
+ respuestasHogar[configHogares.uaPersonas][i][configHogares.varNombrePersona] = nombre.trim();
2051
+ })
2052
+ }
2053
+ }
2054
+ }
2055
+ })
2056
+ respuestasRaiz.vdominio=getDatosByPass().informacionHdr[forPk.vivienda].tem.dominio;
2057
+ if(forPk.formulario == 'F:S1_SUP' as IdFormulario){
2058
+ let hogar = forPk.hogar as number - 1;
2059
+ if(respuestasRaiz.hogares && respuestasRaiz.hogares[hogar]){
2060
+ let respuestasHogarSup = respuestasRaiz.hogares_sup[hogar];
2061
+ let respuestasHogar = respuestasRaiz.hogares[hogar];
2062
+ respuestasHogarSup.resp_indi_sup = respuestasHogar.msnombre;
2063
+ if(respuestasHogar.personas && respuestasHogar.personas instanceof Array){
2064
+ respuestasHogarSup.resp_comp_ed_sup = respuestasHogar.personas[0]?.edad;
2065
+ respuestasHogarSup.resp_comp_sup = respuestasHogar.personas[0]?.nombre;
2066
+ respuestasHogarSup.resp_indi_ed_sup =
2067
+ respuestasHogar.cr_num_miembro?
2068
+ respuestasHogar.personas[respuestasHogar.cr_num_miembro -1]?.edad
2069
+ :null;
2070
+ }
2071
+ }
2072
+ }
2073
+ })
2074
+
2075
+ window.addEventListener('load', function(){
2076
+ loadInstance()
2077
+ })
2078
+ //FIN CONTROL PESTAÑAS
2079
+
2080
+ function loadCSS(cssURL:string, id?:string):Promise<void>{
2081
+ return new Promise(( resolve, reject )=>{
2082
+ var link = document.createElement( 'link' );
2083
+ link.rel = 'stylesheet';
2084
+ link.href = cssURL;
2085
+ link.id = id || cssURL;
2086
+ document.head.appendChild( link );
2087
+ link.onload = ()=>{
2088
+ resolve();
2089
+ console.log(`trae ${cssURL}`);
2090
+ };
2091
+ link.onerror=(err)=>{
2092
+ console.log('error cargando el estilo', err)
2093
+ reject(new Error(`problema cargando estilo ${cssURL}`))
2094
+ }
2095
+ });
2096
+ }
2097
+
2098
+ function removeCSSById(id:string){
2099
+ var linkNode = document.getElementById(id);
2100
+ linkNode?.parentNode?.removeChild(linkNode);
2101
+ }
2102
+
2103
+ const BOOTSTRAP_5_1_3_SRC = 'css/bootstrap.min.css';