DependenciaDetalle.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. import React, { useState, useEffect } from "react";
  2. import { Form, Button, Row, Col, Input, Modal, Table, Typography, Select } from "antd";
  3. import { SaveOutlined, PlusOutlined, CloseCircleOutlined } from "@ant-design/icons";
  4. import { useQuery, useModels } from "../../../hooks";
  5. import { useHistory } from "react-router-dom";
  6. import { firestore } from "../../../services/firebase";
  7. import { ViewLoading } from "../../../components";
  8. import { DefaultLayout } from "../../../components/layouts";
  9. import { addDoc, collection, doc, getDoc, updateDoc } from "firebase/firestore";
  10. import HttpService from "../../../services/httpService";
  11. const { Title } = Typography;
  12. const DependenciaDetalle = () => {
  13. const firebaseCollection = "dependencias";
  14. const query = useQuery();
  15. const history = useHistory();
  16. const { TextArea } = Input;
  17. const id = query.get("id");
  18. const editando = Boolean(id);
  19. const titulo = editando ? "Editar dependencia" : "Agregar dependencia";
  20. const url = "/administracion/dependencias";
  21. const [form] = Form.useForm();
  22. const [dependencia, setDependencia] = useState([]);
  23. const [cargandoDependencia, setCargandoDependencia] = useState(true);
  24. const [guadandoCargando, setGuardandoCargando] = useState(false);
  25. const [buscarValue, setBuscarValue] = useState('');
  26. const [requestUsuarios, setRequestUsuarios] = useState({});
  27. const [timer, setTimer] = useState(null);
  28. const [miembros, setMiembros] = useState([]);
  29. const [miembrosLoading, setMiembrosLoading] = useState(false);
  30. const [usuario, setUsuario] = useState(null);
  31. const [lideres, setLideres] = useState([]);
  32. const usuarioExtraParams = React.useMemo(() => ({ q: buscarValue }), [buscarValue])
  33. const usuariosParams = React.useMemo(() => ({
  34. name: 'v1/usuario',
  35. limite: 20,
  36. ordenar: 'nombre-asc',
  37. expand: 'grupos',
  38. extraParams: usuarioExtraParams
  39. }), [usuarioExtraParams])
  40. const [
  41. models,
  42. modelsLoading, , ,
  43. ] = useModels(requestUsuarios);
  44. const columnasMiembros = [
  45. { title: 'Nombre', dataIndex: 'nombre', key: 'nombre', },
  46. { title: 'Correo', dataIndex: 'email', key: 'email', },
  47. ]
  48. const columnasLideres = [
  49. { title: 'Nombre', dataIndex: 'nombre', key: 'nombre', },
  50. {
  51. title: '', dataIndex: 'uid', key: 'uid', render: (text) =>
  52. <Button
  53. danger
  54. icon={<CloseCircleOutlined />}
  55. onClick={() => setLideres(lideres.filter(l => l.uid !== text))}
  56. />
  57. },
  58. ]
  59. const onSearchUsuarios = (value) => {
  60. clearTimeout(timer);
  61. const newTimer = setTimeout(() => {
  62. setBuscarValue(value);
  63. }, 300);
  64. setTimer(newTimer);
  65. };
  66. React.useEffect(() => {
  67. setRequestUsuarios(usuariosParams);
  68. return () => setRequestUsuarios({});
  69. }, [usuariosParams]);
  70. React.useEffect(() => {
  71. if (editando && id) {
  72. const getMiembros = async () => {
  73. setMiembrosLoading(true);
  74. const response = await HttpService.get(`v1/usuario?ordenar=nombre-asc&idDependencia=${id}&limite=-1`);
  75. if (!response.isError) {
  76. setMiembros(response.resultado);
  77. setMiembrosLoading(false);
  78. }
  79. }
  80. getMiembros();
  81. }
  82. }, [editando, id]);
  83. const onFinish = async (values) => {
  84. try {
  85. setGuardandoCargando(true);
  86. let body = {
  87. ...values,
  88. timestamp: editando ? dependencia?.timestamp : new Date(),
  89. estatus: editando ? dependencia?.estatus : true,
  90. sincronizado: null,
  91. usuarios: lideres.map(l => ({
  92. uid: l.uid,
  93. nombre: l.nombre,
  94. })),
  95. };
  96. // comentario prueba
  97. // Agregamos o editamos el documento grupo
  98. if (editando) {
  99. await updateDoc(doc(firestore, firebaseCollection, id), body);
  100. } else {
  101. await addDoc(collection(firestore, firebaseCollection), body);
  102. }
  103. Modal.success({
  104. title: "Éxito",
  105. content: "Dependencia guardado correctamente",
  106. });
  107. history.push(url);
  108. } catch (error) {
  109. Modal.warning({
  110. title: "Atención",
  111. content: "Hubo un problema al guardar, intentalo de nuevo.",
  112. });
  113. console.log("Error al guardar: ", error);
  114. } finally {
  115. setGuardandoCargando(false);
  116. }
  117. };
  118. const onFinishFailed = () => {
  119. Modal.warning({
  120. title: "Atención",
  121. content: "Por favor revise los datos.",
  122. style: { marginTop: "20vh" },
  123. });
  124. };
  125. useEffect(() => {
  126. let mounted = true;
  127. if (mounted && editando) {
  128. try {
  129. setTimeout(async () => {
  130. const docRef = doc(firestore, "dependencias", id);
  131. const docSnap = await getDoc(docRef);
  132. setDependencia(docSnap.data());
  133. const { usuarios } = docSnap.data();
  134. if (usuarios?.length > 0) {
  135. setLideres(usuarios);
  136. }
  137. }, 0);
  138. } catch (error) {
  139. console.log("Error al obtener dependencia: ", error);
  140. } finally {
  141. setCargandoDependencia(false);
  142. }
  143. }
  144. return () => (mounted = false);
  145. }, [editando, id]);
  146. useEffect(() => {
  147. let mounted = true;
  148. if (mounted && editando) {
  149. form.setFieldsValue({
  150. ...dependencia,
  151. });
  152. }
  153. return () => (mounted = false);
  154. }, [dependencia, editando, form]);
  155. if (cargandoDependencia && editando) return <ViewLoading />;
  156. return (
  157. <DefaultLayout title={titulo} multipleButtonData={[]}>
  158. <Form
  159. name="form"
  160. form={form}
  161. autoComplete="off"
  162. layout="vertical"
  163. onFinish={onFinish}
  164. onFinishFailed={onFinishFailed}
  165. >
  166. {/* Nombre de la dependecia */}
  167. <Row gutter={10}>
  168. <Col
  169. className="gutter-row"
  170. xs={{ span: 24 }}
  171. sm={{ span: 24 }}
  172. md={{ span: 12 }}
  173. lg={{ span: 12 }}
  174. >
  175. <Form.Item
  176. label="Nombre de la dependencia"
  177. name="nombre"
  178. rules={[{ required: true, message: "Requerido" }]}
  179. >
  180. <Input placeholder="Ingresa un nombre..." />
  181. </Form.Item>
  182. </Col>
  183. </Row>
  184. {/* Descripción */}
  185. <Row gutter={10}>
  186. <Col className="gutter-row" span={24}>
  187. <Form.Item
  188. label="Descripción"
  189. name="descripcion"
  190. rules={[{ required: true, message: "Requerido" }]}
  191. >
  192. <TextArea rows={4} placeholder="Ingrese una Descripción" />
  193. </Form.Item>
  194. </Col>
  195. </Row>
  196. <Row gutter={10}>
  197. <Col className="gutter-row" span={12}>
  198. <Title level={4}>Miembros</Title>
  199. <Table
  200. columns={columnasMiembros}
  201. dataSource={miembros}
  202. loading={miembrosLoading}
  203. size="small"
  204. rowKey="id"
  205. scroll={{ y: 400 }}
  206. pagination={
  207. miembros.length > 10
  208. ? {
  209. pageSize: 10,
  210. position: ["bottomCenter"],
  211. showTotal: (total, range) => `${range[0]}-${range[1]} de ${total} registros`,
  212. } : false
  213. }
  214. />
  215. <br />
  216. </Col>
  217. <Col className="gutter-row" span={12}>
  218. <Row>
  219. <Col span={22}>
  220. <Title level={4}>Líderes</Title>
  221. <Form.Item
  222. label="Usuarios"
  223. rules={[{
  224. required: true,
  225. message: 'Selecciona un usuario!',
  226. }]}
  227. hasFeedback
  228. >
  229. <Select
  230. showSearch
  231. onSearch={onSearchUsuarios}
  232. allowClear
  233. placeholder="Elige a un usuario"
  234. optionFilterProp="children"
  235. filterOption={(input, option) => (option?.label ?? '').toLowerCase().includes(input.toLowerCase())}
  236. loading={modelsLoading}
  237. onChange={(_, item) => {
  238. setUsuario(item);
  239. console.log("item", item);
  240. }}
  241. options={models?.length > 0 && models?.map(i => ({
  242. ...i,
  243. value: i.uid,
  244. label: i.nombre
  245. }))}
  246. value={usuario}
  247. />
  248. </Form.Item>
  249. </Col>
  250. <Col span={2}>
  251. <Button
  252. type="default"
  253. icon={<PlusOutlined />}
  254. shape="circle"
  255. size="middle"
  256. style={{
  257. marginTop: 70,
  258. marginLeft: 10
  259. }}
  260. onClick={() => {
  261. if (usuario) {
  262. //agregar sólo si no existe en el array, con esto evitamos duplicados
  263. if (!lideres.find(i => i.uid === usuario.uid)) {
  264. setLideres([...lideres, usuario]);
  265. setUsuario(null);
  266. }
  267. }
  268. }}
  269. />
  270. </Col>
  271. </Row>
  272. <Table
  273. columns={columnasLideres}
  274. dataSource={lideres}
  275. size="small"
  276. rowKey="uid"
  277. pagination={
  278. lideres.length > 10
  279. ? {
  280. pageSize: 10,
  281. position: ["bottomCenter"],
  282. showTotal: (total, range) => `${range[0]}-${range[1]} de ${total} registros`,
  283. } : false
  284. }
  285. />
  286. </Col>
  287. </Row>
  288. <Row gutter={10}>
  289. <Col
  290. xs={{ span: 24 }}
  291. sm={{ span: 24 }}
  292. md={{ span: 12 }}
  293. lg={{ span: 8 }}
  294. >
  295. <Button
  296. type="primary"
  297. htmlType="submit"
  298. icon={<SaveOutlined />}
  299. block
  300. size="large"
  301. loading={guadandoCargando}
  302. >
  303. Guardar
  304. </Button>
  305. </Col>
  306. </Row>
  307. </Form>
  308. </DefaultLayout>
  309. )
  310. }
  311. export default DependenciaDetalle