Reac front end for psicometric app

Operation.jsx 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. import * as React from 'react';
  2. import {
  3. Button, Dialog, DialogActions, DialogContent,
  4. FormControlLabel, Checkbox, Stack,
  5. TextField, CircularProgress, Divider, Typography
  6. } from '@mui/material'
  7. import { AddCircle } from '@mui/icons-material/';
  8. import { MailTable } from './Steps/MailTable';
  9. import { Col, Row } from 'react-bootstrap'
  10. import toast, { Toaster } from 'react-hot-toast';
  11. import * as Yup from 'yup';
  12. import { useQueryClient } from 'react-query'
  13. import { Service } from '../../Utils/HTTP.js'
  14. import { useSelector } from 'react-redux'
  15. import { useFormik, Form, FormikProvider } from 'formik';
  16. import { AdapterDateFns as DateFnsUtils } from '@mui/x-date-pickers/AdapterDateFns';
  17. import { DesktopDatePicker } from '@mui/x-date-pickers/DesktopDatePicker';
  18. import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
  19. function Candidatos(props) {
  20. const CandidatoSchema = Yup.object().shape({
  21. nombres:
  22. Yup.string()
  23. .min(2, 'Demasiado corto!')
  24. .max(50, 'Demasiado largo!'),
  25. apellidos:
  26. Yup.string()
  27. .min(2, 'Demasiado corto!').max(50, 'Demasiado Largo!'),
  28. mail:
  29. Yup.string()
  30. .email("Correo no valido")
  31. });
  32. let { candidatos, add , remove } = props
  33. const formik = useFormik({
  34. initialValues: {
  35. nombres: "",
  36. apellidos: "",
  37. mail: "",
  38. },
  39. onSubmit: () => {
  40. console.log('submited')
  41. },
  42. validationSchema: CandidatoSchema,
  43. });
  44. var { errors, touched, handleSubmit, getFieldProps, values, resetForm, isValid } = formik;
  45. const addToList = () => {
  46. if (!values.nombres || !values.apellidos || !values.mail) {
  47. return toast.error("Completa la informacion del candidato")
  48. }
  49. if (!isValid) {
  50. return toast.error("Completa la informacion del candidato")
  51. }
  52. let user = {
  53. 'nombres': values.nombres,
  54. 'apellidos': values.apellidos,
  55. 'mail': values.mail,
  56. }
  57. add(user)
  58. resetForm();
  59. }
  60. return (
  61. <FormikProvider style={{ padding: 25 }} value={formik}>
  62. <Typography style={{ padding: 5, marginBottom: 15 }}>Ingresa la informacion del candidato</Typography>
  63. <Divider />
  64. <Form autoComplete="off" noValidate onSubmit={handleSubmit}>
  65. <Stack spacing={3}>
  66. <Stack style={{ paddingTop: 15 }} direction={{ xs: 'column', sm: 'row' }} spacing={2}>
  67. <TextField
  68. label="Nombre"
  69. fullWidth
  70. {...getFieldProps('nombres')}
  71. error={Boolean(touched.nombres && errors.nombres)}
  72. helperText={touched.nombres && errors.nombres}
  73. />
  74. <TextField
  75. label="Apellidos"
  76. fullWidth
  77. {...getFieldProps('apellidos')}
  78. error={Boolean(touched.apellidos && errors.apellidos)}
  79. helperText={touched.apellidos && errors.apellidos}
  80. />
  81. </Stack>
  82. <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>
  83. <TextField
  84. fullWidth
  85. type="email"
  86. label="Correo Electronico"
  87. {...getFieldProps('mail')}
  88. error={Boolean(touched.mail && errors.mail)}
  89. helperText={touched.mail && errors.mail}
  90. />
  91. <Button onClick={addToList}>
  92. <AddCircle style={{ color: 'var(--main)' }} />
  93. </Button>
  94. </Stack>
  95. <MailTable
  96. remove={remove}
  97. users={candidatos}
  98. />
  99. </Stack>
  100. <Toaster position="top-right" />
  101. </Form>
  102. </FormikProvider>
  103. );
  104. }
  105. export function ModalEdit(props) {
  106. //TODO:
  107. //se debe crear un objeto de estado que almacena los nuevos cambios de la password
  108. //enviar por props las utilizades de edicion y eliminar
  109. const auth = useSelector((state) => state.token)
  110. let [data, setData] = React.useState(null)
  111. let { password, open, handleOpen } = props
  112. let { pwd, plz } = password
  113. React.useEffect(() => {
  114. let rest = new Service(`/contrasenia/${btoa(pwd)}/${plz}`)
  115. rest.getQuery(auth.token)
  116. .then(resp => setData(resp.data))
  117. .catch(error => console.log(error))
  118. }, [auth.token, pwd, plz])
  119. return (
  120. <Dialog
  121. fullWidth="md"
  122. maxWidth="md"
  123. open={open}
  124. onClose={() => handleOpen(false)}
  125. aria-labelledby="alert-dialog-title"
  126. aria-describedby="alert-dialog-description"
  127. >
  128. <DialogContent>
  129. {
  130. data ?
  131. <ModalForm
  132. password={data}
  133. handleOpen={handleOpen}
  134. token={auth.token}
  135. /> : <Loading />
  136. }
  137. </DialogContent>
  138. </Dialog>
  139. )
  140. }
  141. function Loading() {
  142. return (
  143. <CircularProgress style={{ color: 'var(--main)' }} />
  144. )
  145. }
  146. function ModalForm(props) {
  147. let [candidatos,setCandidatos] = React.useState(null);
  148. const pwdSchema = Yup.object().shape({
  149. id: Yup.number(),
  150. pwd: Yup.string().required("Escoge un nombre valido"),
  151. deadpwd: Yup.date().required("Escoge una fecha valida"),
  152. state: Yup.number(),
  153. dateToActived: Yup.date('Escoge una fecha valida').required("Escoge una fecha valida"),
  154. })
  155. const queryClient = useQueryClient();
  156. let { password } = props
  157. React.useEffect(() => {
  158. let mapCandi = password.candidatospwds.map(pwd => {
  159. let { apellidos, nombre, mail } = pwd.candi
  160. return { nombres: nombre, apellidos, mail }
  161. })
  162. setCandidatos(mapCandi)
  163. },[password.candidatospwds])
  164. function removeCandidato (umail) {
  165. console.log('remove:', umail)
  166. let without = candidatos.filter( user => user.mail !== umail )
  167. setCandidatos(without)
  168. }
  169. function addCandidato (candidato) {
  170. setCandidatos([...candidatos, candidato ])
  171. }
  172. const formik = useFormik({
  173. initialValues: {
  174. state: 1,
  175. pwd: atob(password.pwd),
  176. deadpwd: password.deadpwd,
  177. dateToActived: password.dateToActived,
  178. },
  179. onSubmit: (fields) => {
  180. let rest = new Service('/contrasenia/create');
  181. let { deadpwd, dateToActived, pwd } = fields
  182. fields['pwd'] = btoa(pwd);
  183. fields['deadpwd'] = new Date(deadpwd).toISOString();
  184. fields['dateToActived'] = new Date(dateToActived).toISOString();
  185. fields['candidato_id'] = props.initialValues.candidato_id
  186. fields['plaza_id'] = props.initialValues.plaza_id
  187. rest.put(fields, props.token)
  188. .then(result => {
  189. queryClient.invalidateQueries('passwords')
  190. setTimeout(() => {
  191. props.handleOpen(false)
  192. }, 1000)
  193. toast.success("Contraseña Actualizada")
  194. })
  195. .catch(bad => {
  196. console.log('ERROR', bad)
  197. toast.error("Ocurrio un error")
  198. })
  199. },
  200. validationSchema: pwdSchema,
  201. })
  202. const { errors, touched, handleSubmit, getFieldProps, values, setValues } = formik;
  203. return (
  204. <Row>
  205. <Col>
  206. <FormikProvider value={formik}>
  207. <Form style={{ padding: 20, maxWidth: 950 }} autoComplete="off" noValidate onSubmit={handleSubmit}>
  208. <Stack spacing={4}>
  209. <TextField
  210. value={btoa(values.pwd)}
  211. variant="filled"
  212. disabled
  213. fullWidth
  214. type="text"
  215. label="Contraseña Cifrada"
  216. />
  217. <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>
  218. <TextField
  219. type="text"
  220. label="Contraseña"
  221. {...getFieldProps('pwd')}
  222. error={Boolean(touched.pwd && errors.pwd)}
  223. helperText={touched.pwd && errors.pwd}
  224. />
  225. <FormControlLabel
  226. control={
  227. <Checkbox
  228. checked={values.state === 1}
  229. onChange={(event) => {
  230. let check = event.target.checked;
  231. setValues({
  232. ...values,
  233. state: check ? 1 : 0
  234. })
  235. }}
  236. />
  237. }
  238. label="Activa"
  239. />
  240. </Stack>
  241. <LocalizationProvider
  242. dateAdapter={DateFnsUtils}>
  243. <DesktopDatePicker
  244. label="Fecha de Activación"
  245. fullWidth
  246. inputFormat="dd/MM/yyyy"
  247. value={values.dateToActived}
  248. onChange={(val) => setValues({ ...values, dateToActived: val })}
  249. renderInput={(params) =>
  250. <TextField
  251. {...getFieldProps('dateToActived')}
  252. error={Boolean(touched.dateToActived && errors.dateToActived)}
  253. helperText={touched.dateToActived && errors.dateToActived}
  254. disabled={true}
  255. label="Fecha de Activación"
  256. fullWidth
  257. {...params}
  258. />}
  259. />
  260. </LocalizationProvider>
  261. <LocalizationProvider
  262. dateAdapter={DateFnsUtils}>
  263. <DesktopDatePicker
  264. label="Fecha de Vencimiento"
  265. fullWidth
  266. inputFormat="dd/MM/yyyy"
  267. {...getFieldProps('deadpwd')}
  268. value={values.deadpwd}
  269. onChange={(val) => setValues({ ...values, deadpwd: new Date(val) })
  270. }
  271. renderInput={(params) =>
  272. <TextField
  273. error={Boolean(touched.deadpwd && errors.deadpwd)}
  274. helperText={touched.deadpwd && errors.deadpwd}
  275. disabled={true}
  276. label="Fecha de Vencimiento"
  277. fullWidth
  278. {...params}
  279. />}
  280. />
  281. </LocalizationProvider>
  282. </Stack>
  283. </Form>
  284. <Toaster position="bottom-right" />
  285. </FormikProvider >
  286. </Col>
  287. <Col>
  288. <Candidatos
  289. add={addCandidato}
  290. remove={removeCandidato}
  291. candidatos={candidatos}
  292. />
  293. </Col>
  294. <DialogActions>
  295. <Button onClick={() => props.handleOpen(false)}>
  296. Cerrar
  297. </Button>
  298. <Button
  299. type="submit"
  300. className="registerBtn"
  301. style={{ color: 'white' }}
  302. >
  303. Guardar
  304. </Button>
  305. </DialogActions>
  306. </Row>
  307. )
  308. }