Operation.jsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  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 { yupResolver } from '@hookform/resolvers/yup';
  13. import { useQueryClient } from 'react-query'
  14. import { useForm, Controller } from "react-hook-form";
  15. import { Service } from '../../Utils/HTTP.js'
  16. import { useSelector } from 'react-redux'
  17. import { useFormik, Form, FormikProvider } from 'formik';
  18. import { AdapterDateFns as DateFnsUtils } from '@mui/x-date-pickers/AdapterDateFns';
  19. import { DesktopDatePicker } from '@mui/x-date-pickers/DesktopDatePicker';
  20. import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
  21. function Candidatos(props) {
  22. const CandidatoSchema = Yup.object().shape({
  23. nombres:
  24. Yup.string()
  25. .min(2, 'Demasiado corto!')
  26. .max(50, 'Demasiado largo!')
  27. .required('Ingresa un nombre válido'),
  28. apellidos:
  29. Yup.string()
  30. .min(2, 'Demasiado corto!')
  31. .max(50, 'Demasiado Largo!')
  32. .required('Ingresa un apellido válido'),
  33. mail:
  34. Yup.string()
  35. .required('Ingresa un email válido')
  36. .email("Correo no valido")
  37. });
  38. let { candidatos, add, remove } = props
  39. const formik = useFormik({
  40. initialValues: {
  41. nombres: "",
  42. apellidos: "",
  43. mail: "",
  44. },
  45. onSubmit: () => {
  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. 'id': -1,
  54. 'nombres': values.nombres,
  55. 'apellidos': values.apellidos,
  56. 'mail': values.mail,
  57. }
  58. add(user)
  59. resetForm();
  60. },
  61. validationSchema: CandidatoSchema,
  62. });
  63. var { errors, touched, handleSubmit, getFieldProps, values, resetForm, isValid } = formik;
  64. return (
  65. <FormikProvider style={{ padding: 25 }} value={formik}>
  66. <Typography style={{ padding: 5, marginBottom: 15 }}>Ingresa la informacion del candidato</Typography>
  67. <Divider />
  68. <Form autoComplete="off" noValidate onSubmit={handleSubmit}>
  69. <Stack spacing={3}>
  70. <Stack style={{ paddingTop: 15 }} direction={{ xs: 'column', sm: 'row' }} spacing={2}>
  71. <TextField
  72. label="Nombre"
  73. {...getFieldProps('nombres')}
  74. error={Boolean(touched.nombres && errors.nombres)}
  75. helperText={touched.nombres && errors.nombres}
  76. />
  77. <TextField
  78. label="Apellidos"
  79. {...getFieldProps('apellidos')}
  80. error={Boolean(touched.apellidos && errors.apellidos)}
  81. helperText={touched.apellidos && errors.apellidos}
  82. />
  83. </Stack>
  84. <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>
  85. <TextField
  86. fullWidth
  87. type="email"
  88. label="Correo Electronico"
  89. {...getFieldProps('mail')}
  90. error={Boolean(touched.mail && errors.mail)}
  91. helperText={touched.mail && errors.mail}
  92. />
  93. <Button type="submit">
  94. <AddCircle style={{ color: 'var(--main)' }} />
  95. </Button>
  96. </Stack>
  97. <MailTable
  98. remove={remove}
  99. users={candidatos}
  100. />
  101. </Stack>
  102. </Form>
  103. </FormikProvider>
  104. );
  105. }
  106. export function ModalEdit(props) {
  107. const auth = useSelector((state) => state.token)
  108. let { password, open, handleOpen } = props
  109. let { pwd, plz } = password
  110. return (
  111. <Dialog
  112. fullWidth="md"
  113. maxWidth="md"
  114. open={open}
  115. onClose={() => handleOpen(false)}
  116. aria-labelledby="alert-dialog-title"
  117. aria-describedby="alert-dialog-description"
  118. >
  119. <DialogContent>
  120. <ModalForm
  121. pwdinfo={{ pwd, plz }}
  122. closeModal={handleOpen}
  123. token={auth.token}
  124. />
  125. </DialogContent>
  126. </Dialog>
  127. )
  128. }
  129. export function Loading() {
  130. return (
  131. <CircularProgress style={{ color: 'var(--main)' }} />
  132. )
  133. }
  134. function ModalForm(props) {
  135. let { pwdinfo, closeModal } = props
  136. const auth = useSelector((state) => state.token)
  137. let [candidatos, setCandidatos] = React.useState([]);
  138. let [password, setPassword] = React.useState();
  139. const queryClient = useQueryClient()
  140. const pwdSchema = Yup.object().shape({
  141. pwd: Yup.string(),
  142. deadpwd: Yup.date('Escoge una fecha valida').required("Escoge una fecha valida"),
  143. state: Yup.boolean(),
  144. dateToActived: Yup.date('Escoge una fecha valida').required("Escoge una fecha valida"),
  145. })
  146. const { reset, control, register, handleSubmit, formState: { errors } } = useForm({
  147. resolver: yupResolver(pwdSchema),
  148. defaultValues: {
  149. pwd: 0,
  150. deadpwd: 0,
  151. state: false,
  152. dateToActived: 0,
  153. }
  154. });
  155. React.useEffect(() => {
  156. let { pwd, plz } = pwdinfo;
  157. let rest = new Service(`/contrasenia/${btoa(pwd)}/${plz}`)
  158. rest.getQuery(auth.token)
  159. .then(resp => {
  160. let json_data = resp;
  161. let mapCandi = resp.data.candidatospwds.map(pwd => {
  162. let { apellidos, nombre, mail,id } = pwd.candi
  163. return { nombres: nombre, apellidos, mail, id }
  164. })
  165. json_data.data['candidatospwds'] = mapCandi;
  166. let password = json_data.data
  167. setPassword(password)
  168. setCandidatos(password.candidatospwds)
  169. reset({
  170. pwd: password.pwd,
  171. deadpwd: password.deadpwd,
  172. state: parseInt(password.state) === 1,
  173. dateToActived: password.dateToActived,
  174. })
  175. })
  176. .catch(error => console.log(error))
  177. }, [auth.token, pwdinfo, reset])
  178. const saveCandidato = async (body) => {
  179. let rest = new Service('/passwordcandidato/candidato')
  180. return await rest.postQuery(body, auth.token)
  181. }
  182. function onSubmit(fields) {
  183. let candi_body = candidatos.map( c => {
  184. return {...c,
  185. 'nombrepuesto': 'test',
  186. 'nombreEmpresa' : 'dit',
  187. "idContrasenia" : password.id,
  188. "sendmail": 1,
  189. }
  190. })
  191. let rest = new Service('/contrasenia/create');
  192. let { deadpwd, dateToActived, pwd, state } = fields
  193. fields['pwd'] = pwd;
  194. fields['deadpwd'] = new Date(deadpwd).toISOString();
  195. fields['dateToActived'] = new Date(dateToActived).toISOString();
  196. fields['link'] = 'www.psicoadmin.ditaca.org'
  197. fields['state'] = state ? 1 : 0
  198. delete password['candidato_id'];
  199. delete password['tokensecurity'];
  200. delete password['candidatospwds'];
  201. let body_req = {
  202. ...password, ...fields
  203. }
  204. rest.putQuery(body_req, auth.token)
  205. .then( async result => {
  206. queryClient.invalidateQueries('passwords')
  207. //TODO: insert into passwordcanidato/candidato
  208. await saveCandidato(candi_body)
  209. setTimeout(() => {
  210. closeModal(false)
  211. }, 1000)
  212. toast.success("Contraseña Actualizada")
  213. })
  214. .catch(bad => {
  215. console.log('ERROR', bad)
  216. toast.error("Ocurrio un error")
  217. })
  218. }
  219. function removeCandidato(umail) {
  220. let without = candidatos.filter(user => user.mail !== umail)
  221. setCandidatos(without)
  222. }
  223. function addCandidato(candidato) {
  224. let temp = [...candidatos, candidato]
  225. setCandidatos(temp)
  226. }
  227. return (
  228. <Row>
  229. <Col>
  230. <form style={{ padding: 20, maxWidth: 950 }} onSubmit={handleSubmit(onSubmit)}>
  231. <Stack spacing={4}>
  232. <TextField
  233. {...register('pwd')}
  234. variant="filled"
  235. disabled
  236. type="text"
  237. label="Contraseña Cifrada"
  238. />
  239. <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>
  240. <TextField
  241. label="Nombre de la Contraseña"
  242. fullWidth
  243. variant="filled"
  244. value={password ? atob(password.pwd) : ""}
  245. type="text"
  246. disabled
  247. />
  248. <FormControlLabel
  249. label="Activo?"
  250. control={
  251. <Controller
  252. name="state"
  253. control={control}
  254. render={({ field: props }) =>
  255. <Checkbox
  256. style={{ color: 'var(--main)' }}
  257. checked={props.value}
  258. onChange={(e) => props.onChange(e.target.checked)}
  259. />
  260. }
  261. />
  262. }
  263. />
  264. </Stack>
  265. <LocalizationProvider dateAdapter={DateFnsUtils}>
  266. <Controller
  267. name="dateToActived"
  268. control={control}
  269. render={({ field }) =>
  270. <DesktopDatePicker
  271. {...field}
  272. label="Fecha de Activación"
  273. inputFormat="dd/MM/yyyy"
  274. fullWidth
  275. error={Boolean(errors?.dateToActived)}
  276. renderInput={(params) =>
  277. <TextField
  278. {...params}
  279. helperText={errors?.dateToActived?.message}
  280. />}
  281. />
  282. }
  283. >
  284. </Controller>
  285. </LocalizationProvider>
  286. <LocalizationProvider dateAdapter={DateFnsUtils}>
  287. <Controller
  288. name="deadpwd"
  289. control={control}
  290. render={({ field }) =>
  291. <DesktopDatePicker
  292. {...field}
  293. label="Fecha de Vencimiento"
  294. error={Boolean(errors?.deadpwd)}
  295. inputFormat="dd/MM/yyyy"
  296. renderInput={(params) =>
  297. <TextField
  298. {...params}
  299. helperText={errors?.deadpwd?.message}
  300. label="Fecha de Vencimiento"
  301. />}
  302. />
  303. }
  304. >
  305. </Controller>
  306. </LocalizationProvider>
  307. <DialogActions style={{ paddingTop: 25, 'justifyContent': "flex-start" }}>
  308. <Button onClick={() => closeModal(false)}>
  309. Cerrar
  310. </Button>
  311. <Button type="submit" style={{ color: 'white', background: 'var(--main)' }} >
  312. Guardar
  313. </Button>
  314. </DialogActions>
  315. </Stack>
  316. </form>
  317. <Toaster position="bottom-right" />
  318. </Col>
  319. <Col>
  320. <Candidatos
  321. add={addCandidato}
  322. remove={removeCandidato}
  323. candidatos={candidatos}
  324. />
  325. </Col>
  326. </Row>
  327. )
  328. }