|
@@ -0,0 +1,934 @@
|
|
|
|
|
+import React, { useEffect, useState } from "react";
|
|
|
|
|
+import {
|
|
|
|
|
+ Col,
|
|
|
|
|
+ Row,
|
|
|
|
|
+ Form,
|
|
|
|
|
+ Input,
|
|
|
|
|
+ Modal,
|
|
|
|
|
+ Table,
|
|
|
|
|
+ Select,
|
|
|
|
|
+ Button,
|
|
|
|
|
+ Upload,
|
|
|
|
|
+ Divider,
|
|
|
|
|
+ Checkbox,
|
|
|
|
|
+ DatePicker,
|
|
|
|
|
+ message,
|
|
|
|
|
+ Tooltip,
|
|
|
|
|
+} from "antd";
|
|
|
|
|
+import {
|
|
|
|
|
+ SaveOutlined,
|
|
|
|
|
+ UploadOutlined,
|
|
|
|
|
+ ArrowLeftOutlined,
|
|
|
|
|
+ PlusCircleOutlined,
|
|
|
|
|
+ MinusCircleOutlined,
|
|
|
|
|
+} from "@ant-design/icons";
|
|
|
|
|
+import "moment/locale/es-mx";
|
|
|
|
|
+import moment from "moment";
|
|
|
|
|
+import locale from "antd/es/date-picker/locale/es_ES";
|
|
|
|
|
+import { useHistory } from "react-router-dom";
|
|
|
|
|
+import { push, ref as refDatabase } from "firebase/database";
|
|
|
|
|
+import {
|
|
|
|
|
+ addDoc,
|
|
|
|
|
+ collection,
|
|
|
|
|
+ doc,
|
|
|
|
|
+ getDoc,
|
|
|
|
|
+ updateDoc,
|
|
|
|
|
+ onSnapshot,
|
|
|
|
|
+ query as firebseQuery,
|
|
|
|
|
+ getDocs,
|
|
|
|
|
+ where,
|
|
|
|
|
+} from "firebase/firestore";
|
|
|
|
|
+import {
|
|
|
|
|
+ ref as refStorage,
|
|
|
|
|
+ uploadBytes,
|
|
|
|
|
+ deleteObject,
|
|
|
|
|
+ getStorage,
|
|
|
|
|
+ getDownloadURL,
|
|
|
|
|
+} from "firebase/storage";
|
|
|
|
|
+
|
|
|
|
|
+import { useQuery } from "../../../hooks";
|
|
|
|
|
+import { ViewLoading } from "../../../components";
|
|
|
|
|
+import { DefaultLayout } from "../../../components/layouts";
|
|
|
|
|
+import { firestore, storage, database } from "../../../services/firebase";
|
|
|
|
|
+
|
|
|
|
|
+const EventosDetalle = () => {
|
|
|
|
|
+ const urlweb = "/administracion/eventos";
|
|
|
|
|
+ const query = useQuery();
|
|
|
|
|
+ const history = useHistory();
|
|
|
|
|
+ const { TextArea, Search } = Input;
|
|
|
|
|
+ const { Option } = Select;
|
|
|
|
|
+ const id = query.get("id");
|
|
|
|
|
+ const editando = !!id;
|
|
|
|
|
+ const [form] = Form.useForm();
|
|
|
|
|
+
|
|
|
|
|
+ const [evento, setEvento] = useState([]);
|
|
|
|
|
+ const [cargandoEvento, setCargandoEvento] = useState(true);
|
|
|
|
|
+ const [guadandoCargando, setGuardandoCargando] = useState(false);
|
|
|
|
|
+ const [sinFechaFin, setSinFechaFin] = useState(false);
|
|
|
|
|
+ const [visible, setVisible] = useState(false);
|
|
|
|
|
+ const [cargandoGrupos, setCargandoGrupos] = useState(true);
|
|
|
|
|
+ const [grupos, setGrupos] = useState([]);
|
|
|
|
|
+ const [filteredResults, setFilteredResults] = useState([]);
|
|
|
|
|
+ const [searchInput, setSearchInput] = useState("");
|
|
|
|
|
+ const [selectedGrupos, setSelectedGrupos] = useState([]);
|
|
|
|
|
+ const [selectedFile, setSelectedFile] = useState(null);
|
|
|
|
|
+ const [selectedFileList, setSelectedFileList] = useState([]);
|
|
|
|
|
+ const [previaImg, setPreviaImg] = useState(null);
|
|
|
|
|
+ const [redes, setRedes] = useState([]);
|
|
|
|
|
+
|
|
|
|
|
+ const defaultText = (prop) =>
|
|
|
|
|
+ prop || <span style={{ color: "#c7c3c3" }}>---</span>;
|
|
|
|
|
+
|
|
|
|
|
+ const multipleButtonData = [
|
|
|
|
|
+ {
|
|
|
|
|
+ text: "Volver",
|
|
|
|
|
+ to: () => history.goBack(),
|
|
|
|
|
+ icon: <ArrowLeftOutlined />,
|
|
|
|
|
+ props: { disabled: false, type: "primary" },
|
|
|
|
|
+ },
|
|
|
|
|
+ ];
|
|
|
|
|
+
|
|
|
|
|
+ const columns = [
|
|
|
|
|
+ {
|
|
|
|
|
+ title: "Nombre",
|
|
|
|
|
+ dataIndex: "nombre",
|
|
|
|
|
+ key: "nombre",
|
|
|
|
|
+ render: defaultText,
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ title: "Ciudad",
|
|
|
|
|
+ dataIndex: "ciudad",
|
|
|
|
|
+ key: "ciudad",
|
|
|
|
|
+ render: defaultText,
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ title: "Creado",
|
|
|
|
|
+ dataIndex: "timestamp",
|
|
|
|
|
+ key: "timestamp",
|
|
|
|
|
+ render: (_, item) =>
|
|
|
|
|
+ moment(item?.timestamp?.toDate()).format("DD-MM-YYYY"),
|
|
|
|
|
+ },
|
|
|
|
|
+ ];
|
|
|
|
|
+
|
|
|
|
|
+ const redesSociales = [
|
|
|
|
|
+ "Facebook",
|
|
|
|
|
+ "Twitter",
|
|
|
|
|
+ "Instagram",
|
|
|
|
|
+ "Whatsapp",
|
|
|
|
|
+ "YouTube",
|
|
|
|
|
+ "TikTok",
|
|
|
|
|
+ "Otro",
|
|
|
|
|
+ ];
|
|
|
|
|
+
|
|
|
|
|
+ const acciones = [
|
|
|
|
|
+ { id: 0, value: "Ver", label: "Ver", icon: "👁" },
|
|
|
|
|
+ { id: 1, value: "Me gusta", label: "Me gusta", icon: "👍" },
|
|
|
|
|
+ { id: 2, value: "Compartir", label: "Compartir", icon: "🔄" },
|
|
|
|
|
+ ];
|
|
|
|
|
+
|
|
|
|
|
+ const rowSelection = {
|
|
|
|
|
+ onChange: (selectedRowKeys, _) => {
|
|
|
|
|
+ setSelectedGrupos(selectedRowKeys);
|
|
|
|
|
+ },
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const obtenerUsuariosGrupo = async () => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const q = firebseQuery(
|
|
|
|
|
+ collection(firestore, "usuarios"),
|
|
|
|
|
+ where("grupos", "array-contains-any", selectedGrupos)
|
|
|
|
|
+ );
|
|
|
|
|
+ const querySnapshot = await getDocs(q);
|
|
|
|
|
+ const docs = [];
|
|
|
|
|
+
|
|
|
|
|
+ querySnapshot.forEach((doc) => {
|
|
|
|
|
+ const data = doc.data();
|
|
|
|
|
+ if (data?.estatus) {
|
|
|
|
|
+ docs.push({
|
|
|
|
|
+ grupos: data?.grupos,
|
|
|
|
|
+ facebook: data?.facebook,
|
|
|
|
|
+ twitter: data?.twitter,
|
|
|
|
|
+ instagram: data?.instagram,
|
|
|
|
|
+ telefono: data?.telefono,
|
|
|
|
|
+ nombre: data?.nombre,
|
|
|
|
|
+ uid: data?.uid,
|
|
|
|
|
+ id: doc.id,
|
|
|
|
|
+ facebookVerificado: data?.facebookVerificado,
|
|
|
|
|
+ instagramVerificado: data?.instagramVerificado,
|
|
|
|
|
+ twitterVerificado: data?.twitterVerificado,
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ return docs;
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.log("error al obtener grupos: ", error);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const normFile = (e) => {
|
|
|
|
|
+ if (Array.isArray(e)) {
|
|
|
|
|
+ return e;
|
|
|
|
|
+ }
|
|
|
|
|
+ return e && e.fileList;
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const dummyRequest = ({ onSuccess }) => {
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ onSuccess("ok");
|
|
|
|
|
+ }, 0);
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const onChangeFile = (info) => {
|
|
|
|
|
+ let src = URL.createObjectURL(info.file.originFileObj);
|
|
|
|
|
+ setPreviaImg(src);
|
|
|
|
|
+ switch (info.file.status) {
|
|
|
|
|
+ case "uploading":
|
|
|
|
|
+ setSelectedFileList([info.file]);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case "done":
|
|
|
|
|
+ setSelectedFile(info.file);
|
|
|
|
|
+ setSelectedFileList([info.file]);
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ setSelectedFile(null);
|
|
|
|
|
+ setSelectedFileList([]);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const eliminarImagen = async (fileRoute) => {
|
|
|
|
|
+ const storage = getStorage();
|
|
|
|
|
+ const desertRef = refStorage(storage, fileRoute);
|
|
|
|
|
+ deleteObject(desertRef)
|
|
|
|
|
+ .then((e) => {})
|
|
|
|
|
+ .catch((error) => {
|
|
|
|
|
+ console.log(error);
|
|
|
|
|
+ });
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const onSearch = (searchValue) => {
|
|
|
|
|
+ setSearchInput(searchValue);
|
|
|
|
|
+ if (searchValue !== "") {
|
|
|
|
|
+ const filteredData = grupos.filter((item) => {
|
|
|
|
|
+ return Object.values(item)
|
|
|
|
|
+ .join("")
|
|
|
|
|
+ .toLowerCase()
|
|
|
|
|
+ .includes(searchValue.toLowerCase());
|
|
|
|
|
+ });
|
|
|
|
|
+ setFilteredResults(filteredData);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ setFilteredResults(grupos);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const onFinish = async (values) => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const {
|
|
|
|
|
+ accion,
|
|
|
|
|
+ ciudad,
|
|
|
|
|
+ descripcion,
|
|
|
|
|
+ fechaFinal,
|
|
|
|
|
+ fechaInicio,
|
|
|
|
|
+ nombre,
|
|
|
|
|
+ redSocial,
|
|
|
|
|
+ url,
|
|
|
|
|
+ } = values;
|
|
|
|
|
+
|
|
|
|
|
+ setGuardandoCargando(true);
|
|
|
|
|
+
|
|
|
|
|
+ let file = selectedFile ? selectedFile.originFileObj : null;
|
|
|
|
|
+
|
|
|
|
|
+ if (!editando && !file) {
|
|
|
|
|
+ Modal.warning({
|
|
|
|
|
+ title: "Atención",
|
|
|
|
|
+ content: "Debes subir una imagen del evento.",
|
|
|
|
|
+ style: { marginTop: "20vh" },
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ let rutaFoto = evento?.fotoEvento;
|
|
|
|
|
+ let pathFirebase = evento?.pathFirebase;
|
|
|
|
|
+
|
|
|
|
|
+ if (file) {
|
|
|
|
|
+ if (editando) {
|
|
|
|
|
+ await eliminarImagen(evento?.fotoEvento);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const postListRef = refDatabase(database, "fotosEventos");
|
|
|
|
|
+ const newPostRef = push(postListRef);
|
|
|
|
|
+ rutaFoto = `fotosEventos/${newPostRef?.key}`;
|
|
|
|
|
+ const fotoRefStorage = refStorage(storage, rutaFoto);
|
|
|
|
|
+ try {
|
|
|
|
|
+ let res = await uploadBytes(fotoRefStorage, file);
|
|
|
|
|
+ pathFirebase = await getDownloadURL(res?.ref);
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.log("Error en el uploadbytes: ", error);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const docsUsuarios = await obtenerUsuariosGrupo();
|
|
|
|
|
+
|
|
|
|
|
+ let resultado = { ...evento?.resultado };
|
|
|
|
|
+ let usuarios = [];
|
|
|
|
|
+
|
|
|
|
|
+ for (let u = 0; u < docsUsuarios?.length; u++) {
|
|
|
|
|
+ if (resultado[docsUsuarios[u]?.uid] === undefined) {
|
|
|
|
|
+ resultado[docsUsuarios[u]?.uid] = [];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (resultado[docsUsuarios[u]?.uid]?.length < 1) {
|
|
|
|
|
+ resultado = {
|
|
|
|
|
+ ...resultado,
|
|
|
|
|
+ [docsUsuarios[u].uid]: [],
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ usuarios.push({
|
|
|
|
|
+ id: docsUsuarios[u]?.id,
|
|
|
|
|
+ uid: docsUsuarios[u]?.uid,
|
|
|
|
|
+ grupos: docsUsuarios[u]?.grupos,
|
|
|
|
|
+ nombre: docsUsuarios[u]?.nombre,
|
|
|
|
|
+ twitter: docsUsuarios[u]?.twitter,
|
|
|
|
|
+ telefono: docsUsuarios[u]?.telefono,
|
|
|
|
|
+ facebook: docsUsuarios[u]?.facebook,
|
|
|
|
|
+ instagram: docsUsuarios[u]?.instagram,
|
|
|
|
|
+ facebookVerificado: Boolean(docsUsuarios[u]?.facebookVerificado),
|
|
|
|
|
+ instagramVerificado: Boolean(docsUsuarios[u]?.instagramVerificado),
|
|
|
|
|
+ twitterVerificado: Boolean(docsUsuarios[u]?.twitterVerificado),
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ let body = {
|
|
|
|
|
+ accion: accion || [],
|
|
|
|
|
+ ciudad: ciudad || "",
|
|
|
|
|
+ descripcion: descripcion || "",
|
|
|
|
|
+ fechaFinal: fechaFinal?.toString() || "",
|
|
|
|
|
+ fechaInicio: fechaInicio?.toString(),
|
|
|
|
|
+ sinFechaFin: sinFechaFin,
|
|
|
|
|
+ nombre: nombre || "",
|
|
|
|
|
+ redSocial: redSocial || "",
|
|
|
|
|
+ url: url || "",
|
|
|
|
|
+ grupos: selectedGrupos,
|
|
|
|
|
+ fotoEvento: rutaFoto,
|
|
|
|
|
+ pathFirebase: pathFirebase,
|
|
|
|
|
+ timestamp: editando ? evento?.timestamp : new Date(),
|
|
|
|
|
+ estatus: editando ? evento?.estatus : true,
|
|
|
|
|
+ usuarios: usuarios,
|
|
|
|
|
+ redes: redes,
|
|
|
|
|
+ resultado: resultado,
|
|
|
|
|
+ sincronizado: null,
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const tag = makeid(8);
|
|
|
|
|
+
|
|
|
|
|
+ //Crear grupo de eventos
|
|
|
|
|
+ if (redes.length > 0) {
|
|
|
|
|
+ let grupoEvento = {
|
|
|
|
|
+ accion: accion,
|
|
|
|
|
+ ciudad: ciudad,
|
|
|
|
|
+ descripcion: descripcion,
|
|
|
|
|
+ fechaFinal: fechaFinal?.toString() || "",
|
|
|
|
|
+ fechaInicio: fechaInicio?.toString(),
|
|
|
|
|
+ sinFechaFin: sinFechaFin,
|
|
|
|
|
+ nombre: nombre || "",
|
|
|
|
|
+ grupos: selectedGrupos,
|
|
|
|
|
+ fotoEvento: rutaFoto,
|
|
|
|
|
+ pathFirebase: pathFirebase,
|
|
|
|
|
+ timestamp: editando ? evento?.timestamp : new Date(),
|
|
|
|
|
+ estatus: editando ? evento?.estatus : true,
|
|
|
|
|
+ tag: tag,
|
|
|
|
|
+ redes: redes,
|
|
|
|
|
+ usuarios: usuarios,
|
|
|
|
|
+ resultado: resultado,
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ await addDoc(collection(firestore, "gruposEvento"), grupoEvento);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (editando) {
|
|
|
|
|
+ await updateDoc(doc(firestore, "eventos", id), body);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for (let i = 0; i < redes?.length; i++) {
|
|
|
|
|
+ body = {
|
|
|
|
|
+ ...body,
|
|
|
|
|
+ redSocial: redes[i]?.redSocial,
|
|
|
|
|
+ url: redes[i]?.url,
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ if (!editando) {
|
|
|
|
|
+ body["tag"] = tag;
|
|
|
|
|
+ }
|
|
|
|
|
+ await addDoc(collection(firestore, "eventos"), body);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Modal.success({
|
|
|
|
|
+ title: "Éxito",
|
|
|
|
|
+ content: "Evento guardado correctamente",
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ history.push(urlweb);
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ Modal.warning({
|
|
|
|
|
+ title: "Atención",
|
|
|
|
|
+ content: "Hubo un problema al guardar, intentalo de nuevo.",
|
|
|
|
|
+ });
|
|
|
|
|
+ console.log("Error al guardar evento: ", error);
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ setGuardandoCargando(false);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const onFinishFailed = () => {
|
|
|
|
|
+ Modal.warning({
|
|
|
|
|
+ title: "Atención",
|
|
|
|
|
+ content: "Por favor revise los datos.",
|
|
|
|
|
+ style: { marginTop: "20vh" },
|
|
|
|
|
+ });
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ function makeid(length) {
|
|
|
|
|
+ let result = "";
|
|
|
|
|
+ const characters =
|
|
|
|
|
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
|
|
|
+ const charactersLength = characters.length;
|
|
|
|
|
+ for (var i = 0; i < length; i++) {
|
|
|
|
|
+ result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
|
|
|
|
+ }
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const agregarRedSocial = () => {
|
|
|
|
|
+ const key = makeid(6);
|
|
|
|
|
+ const datos = [...redes];
|
|
|
|
|
+
|
|
|
|
|
+ const url = form.getFieldValue("url");
|
|
|
|
|
+ const red = form.getFieldValue("redSocial");
|
|
|
|
|
+
|
|
|
|
|
+ if (!url) {
|
|
|
|
|
+ message.warning({
|
|
|
|
|
+ content: "Ingresa una URL",
|
|
|
|
|
+ });
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!red) {
|
|
|
|
|
+ message.warning({
|
|
|
|
|
+ content: "Selecciona una red social",
|
|
|
|
|
+ });
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ let existe = false;
|
|
|
|
|
+ for (let i = 0; i < redes.length; i++) {
|
|
|
|
|
+ if (redes[i]?.redSocial === red) existe = true;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (existe) {
|
|
|
|
|
+ message.warning({
|
|
|
|
|
+ content: "Esta red social ya existe, elige otra diferente.",
|
|
|
|
|
+ });
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ datos.push({
|
|
|
|
|
+ key: key,
|
|
|
|
|
+ url: url,
|
|
|
|
|
+ redSocial: red,
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ setRedes(datos);
|
|
|
|
|
+ form.setFieldsValue({
|
|
|
|
|
+ url: null,
|
|
|
|
|
+ redSocial: null,
|
|
|
|
|
+ });
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const quitarRedSocial = (key) => {
|
|
|
|
|
+ let data = [...redes];
|
|
|
|
|
+ for (let i = 0; i < data?.length; i++) {
|
|
|
|
|
+ if (redes[i].key === key) {
|
|
|
|
|
+ data.splice(i, 1);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ setRedes(data);
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const leerLink = (evento) => {
|
|
|
|
|
+ let link = evento?.target?.value;
|
|
|
|
|
+ const facebook =
|
|
|
|
|
+ /https?:\/\/(www\.)?facebook\.com\/[a-zA-Z0-9.-]+\/?/ ||
|
|
|
|
|
+ /https?:\/\/(www\.)?fb\.com\/[a-zA-Z0-9.-]+\/?/;
|
|
|
|
|
+ const twitter = /https?:\/\/(www\.)?twitter\.com\/[a-zA-Z0-9.-]+\/?/;
|
|
|
|
|
+ const instagram = /https?:\/\/(www\.)?instagram\.com\/[a-zA-Z0-9.-]+\/?/;
|
|
|
|
|
+ const whatsapp = /https?:\/\/(www\.)?wa\.me\/[a-zA-Z0-9.-]+\/?/;
|
|
|
|
|
+ const youtube = /https?:\/\/(www\.)?youtube\.com\/[a-zA-Z0-9.-]+\/?/g;
|
|
|
|
|
+ const ytShort = /https?:\/\/(www\.)?youtu\.be\/[a-zA-Z0-9.-]+\/?/g;
|
|
|
|
|
+ const tiktok = /https?:\/\/(?:www\.)?tiktok\.com\/.*?/g;
|
|
|
|
|
+
|
|
|
|
|
+ if (facebook.test(link)) {
|
|
|
|
|
+ form.setFieldsValue({ redSocial: "Facebook" });
|
|
|
|
|
+ } else if (twitter.test(link)) {
|
|
|
|
|
+ form.setFieldsValue({ redSocial: "Twitter" });
|
|
|
|
|
+ } else if (instagram.test(link)) {
|
|
|
|
|
+ form.setFieldsValue({ redSocial: "Instagram" });
|
|
|
|
|
+ } else if (whatsapp.test(link)) {
|
|
|
|
|
+ form.setFieldsValue({ redSocial: "Whatsapp" });
|
|
|
|
|
+ } else if (youtube.test(link) || ytShort.test(link)) {
|
|
|
|
|
+ form.setFieldsValue({ redSocial: "YouTube" });
|
|
|
|
|
+ } else if (tiktok.test(link)) {
|
|
|
|
|
+ form.setFieldsValue({ redSocial: "TikTok" });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ form.setFieldsValue({ redSocial: "Otro" });
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // Grupos
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ onSnapshot(collection(firestore, "grupos"), (querySnapshot) => {
|
|
|
|
|
+ const docs = [];
|
|
|
|
|
+ querySnapshot.forEach((doc) => {
|
|
|
|
|
+ if (doc.data()?.estatus) {
|
|
|
|
|
+ docs.push({ ...doc.data(), id: doc.id });
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ setGrupos(docs);
|
|
|
|
|
+ });
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.log("error al cargar grupos de firebase: ", error);
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ setCargandoGrupos(false);
|
|
|
|
|
+ }
|
|
|
|
|
+ }, []);
|
|
|
|
|
+
|
|
|
|
|
+ // Limpiar imagen
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ if (!selectedFile) {
|
|
|
|
|
+ setPreviaImg(null);
|
|
|
|
|
+ }
|
|
|
|
|
+ }, [selectedFile]);
|
|
|
|
|
+
|
|
|
|
|
+ // Obtener detalles del evento.
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ let mounted = true;
|
|
|
|
|
+ if (mounted && editando) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ setTimeout(async () => {
|
|
|
|
|
+ const docRef = doc(firestore, "eventos", id);
|
|
|
|
|
+ const docSnap = await getDoc(docRef);
|
|
|
|
|
+ setEvento(docSnap.data());
|
|
|
|
|
+ }, 0);
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.log("error al obtener evento: ", error);
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ setCargandoEvento(false);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return () => (mounted = false);
|
|
|
|
|
+ }, [editando, id]);
|
|
|
|
|
+
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ let mounted = true;
|
|
|
|
|
+ if (mounted && evento && editando) {
|
|
|
|
|
+ setPreviaImg(evento?.pathFirebase);
|
|
|
|
|
+ setSinFechaFin(evento?.sinFechaFin);
|
|
|
|
|
+ setSelectedGrupos(evento?.grupos);
|
|
|
|
|
+ form.setFieldsValue({
|
|
|
|
|
+ ...evento,
|
|
|
|
|
+ fechaFinal: moment(evento?.fechaFinal),
|
|
|
|
|
+ fechaInicio: moment(evento?.fechaInicio),
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ return () => (mounted = false);
|
|
|
|
|
+ }, [editando, evento, form]);
|
|
|
|
|
+
|
|
|
|
|
+ if (cargandoEvento && editando) return <ViewLoading />;
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <DefaultLayout multipleButtonData={multipleButtonData}>
|
|
|
|
|
+ <Modal
|
|
|
|
|
+ title="Agregar grupos"
|
|
|
|
|
+ centered
|
|
|
|
|
+ open={visible}
|
|
|
|
|
+ onOk={() => setVisible(false)}
|
|
|
|
|
+ onCancel={() => setVisible(false)}
|
|
|
|
|
+ okText="Guardar"
|
|
|
|
|
+ width={800}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Search
|
|
|
|
|
+ placeholder="Buscar..."
|
|
|
|
|
+ enterButton="Buscar"
|
|
|
|
|
+ size="large"
|
|
|
|
|
+ style={{ width: "100%" }}
|
|
|
|
|
+ onSearch={onSearch}
|
|
|
|
|
+ />
|
|
|
|
|
+ <Divider />
|
|
|
|
|
+ <Table
|
|
|
|
|
+ dataSource={searchInput?.length > 1 ? filteredResults : grupos}
|
|
|
|
|
+ rowKey="id"
|
|
|
|
|
+ pagination={{
|
|
|
|
|
+ pageSize: 5,
|
|
|
|
|
+ }}
|
|
|
|
|
+ rowSelection={{
|
|
|
|
|
+ type: "checkbox",
|
|
|
|
|
+ selectedRowKeys: selectedGrupos,
|
|
|
|
|
+ ...rowSelection,
|
|
|
|
|
+ }}
|
|
|
|
|
+ loading={cargandoGrupos}
|
|
|
|
|
+ columns={columns}
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ scroll={{ x: 700 }}
|
|
|
|
|
+ />
|
|
|
|
|
+ </Modal>
|
|
|
|
|
+ <Form
|
|
|
|
|
+ name="form"
|
|
|
|
|
+ form={form}
|
|
|
|
|
+ autoComplete="off"
|
|
|
|
|
+ layout="vertical"
|
|
|
|
|
+ onFinish={onFinish}
|
|
|
|
|
+ onFinishFailed={onFinishFailed}
|
|
|
|
|
+ >
|
|
|
|
|
+ {/* Imagen - Nombre - Ciudad - Descripción - Url - Red social */}
|
|
|
|
|
+ <Row gutter={10}>
|
|
|
|
|
+ {/* Columna 1 */}
|
|
|
|
|
+ <Col
|
|
|
|
|
+ className="gutter-row"
|
|
|
|
|
+ xs={{ span: 24 }}
|
|
|
|
|
+ sm={{ span: 24 }}
|
|
|
|
|
+ md={{ span: 8 }}
|
|
|
|
|
+ lg={{ span: 8 }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Row
|
|
|
|
|
+ gutter={10}
|
|
|
|
|
+ style={{
|
|
|
|
|
+ display: "flex",
|
|
|
|
|
+ flexDirection: "row",
|
|
|
|
|
+ height: "100%",
|
|
|
|
|
+ }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Col span={24}>
|
|
|
|
|
+ <Form.Item
|
|
|
|
|
+ name="upload"
|
|
|
|
|
+ label="Imagen del evento"
|
|
|
|
|
+ valuePropName="fileList"
|
|
|
|
|
+ rules={[
|
|
|
|
|
+ { required: editando ? false : true, message: "Requerido" },
|
|
|
|
|
+ ]}
|
|
|
|
|
+ getValueFromEvent={normFile}
|
|
|
|
|
+ extra={editando && evento ? evento?.fotoEvento : null}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Upload
|
|
|
|
|
+ accept="image/gif, image/jpeg, image/png"
|
|
|
|
|
+ fileList={selectedFileList}
|
|
|
|
|
+ customRequest={dummyRequest}
|
|
|
|
|
+ onChange={onChangeFile}
|
|
|
|
|
+ name="fotoEvento"
|
|
|
|
|
+ multiple={false}
|
|
|
|
|
+ maxCount={1}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Button icon={<UploadOutlined />}>Elegir imagen</Button>
|
|
|
|
|
+ </Upload>
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ </Col>
|
|
|
|
|
+
|
|
|
|
|
+ <Col span={24}>
|
|
|
|
|
+ {previaImg ? <img src={previaImg} width="100%" alt="" /> : null}
|
|
|
|
|
+ </Col>
|
|
|
|
|
+
|
|
|
|
|
+ <Col span={24} style={{ marginTop: 133 }}>
|
|
|
|
|
+ <Button
|
|
|
|
|
+ block
|
|
|
|
|
+ type="dashed"
|
|
|
|
|
+ icon={<PlusCircleOutlined />}
|
|
|
|
|
+ onClick={() => setVisible(true)}
|
|
|
|
|
+ >
|
|
|
|
|
+ Agregar grupos ({selectedGrupos?.length})
|
|
|
|
|
+ </Button>
|
|
|
|
|
+ </Col>
|
|
|
|
|
+ </Row>
|
|
|
|
|
+ </Col>
|
|
|
|
|
+
|
|
|
|
|
+ {/* Columna 2 */}
|
|
|
|
|
+ <Col
|
|
|
|
|
+ className="gutter-row"
|
|
|
|
|
+ xs={{ span: 24 }}
|
|
|
|
|
+ sm={{ span: 24 }}
|
|
|
|
|
+ md={{ span: 16 }}
|
|
|
|
|
+ lg={{ span: 16 }}
|
|
|
|
|
+ >
|
|
|
|
|
+ {/* Nombre evento - Ciuad */}
|
|
|
|
|
+ <Row gutter={10}>
|
|
|
|
|
+ <Col
|
|
|
|
|
+ className="gutter-row"
|
|
|
|
|
+ xs={{ span: 24 }}
|
|
|
|
|
+ sm={{ span: 24 }}
|
|
|
|
|
+ md={{ span: 12 }}
|
|
|
|
|
+ lg={{ span: 12 }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Form.Item
|
|
|
|
|
+ label="Nombre del evento"
|
|
|
|
|
+ name="nombre"
|
|
|
|
|
+ rules={[{ required: true, message: "Requerido" }]}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Input />
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ </Col>
|
|
|
|
|
+ <Col
|
|
|
|
|
+ className="gutter-row"
|
|
|
|
|
+ xs={{ span: 24 }}
|
|
|
|
|
+ sm={{ span: 24 }}
|
|
|
|
|
+ md={{ span: 12 }}
|
|
|
|
|
+ lg={{ span: 12 }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Form.Item
|
|
|
|
|
+ label="Ciudad"
|
|
|
|
|
+ name="ciudad"
|
|
|
|
|
+ rules={[{ required: true, message: "Requerido" }]}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Input />
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ </Col>
|
|
|
|
|
+ </Row>
|
|
|
|
|
+
|
|
|
|
|
+ {/* Descripción */}
|
|
|
|
|
+ <Row gutter={10}>
|
|
|
|
|
+ <Col className="gutter-row" span={24}>
|
|
|
|
|
+ <Form.Item
|
|
|
|
|
+ label="Descripción"
|
|
|
|
|
+ name="descripcion"
|
|
|
|
|
+ rules={[{ required: true, message: "Requerido" }]}
|
|
|
|
|
+ >
|
|
|
|
|
+ <TextArea placeholder="Ingrese una descripción..." rows={4} />
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ </Col>
|
|
|
|
|
+ </Row>
|
|
|
|
|
+ </Col>
|
|
|
|
|
+ </Row>
|
|
|
|
|
+
|
|
|
|
|
+ {/* Fecha de inicio - Fecha fin - sin fecha - Accion */}
|
|
|
|
|
+ <Row gutter={10} style={{ marginTop: 30 }}>
|
|
|
|
|
+ <Col
|
|
|
|
|
+ className="gutter-row"
|
|
|
|
|
+ xs={{ span: 24 }}
|
|
|
|
|
+ sm={{ span: 24 }}
|
|
|
|
|
+ md={{ span: 6 }}
|
|
|
|
|
+ lg={{ span: 6 }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Form.Item
|
|
|
|
|
+ rules={[{ required: true, message: "Requerido" }]}
|
|
|
|
|
+ label="Fecha de inicio"
|
|
|
|
|
+ name="fechaInicio"
|
|
|
|
|
+ >
|
|
|
|
|
+ <DatePicker
|
|
|
|
|
+ format="YYYY-MM-DD HH:mm"
|
|
|
|
|
+ style={{ width: "100%" }}
|
|
|
|
|
+ locale={locale}
|
|
|
|
|
+ showTime={{
|
|
|
|
|
+ defaultValue: moment("00:00", "HH:mm"),
|
|
|
|
|
+ }}
|
|
|
|
|
+ />
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ </Col>
|
|
|
|
|
+
|
|
|
|
|
+ <Col
|
|
|
|
|
+ className="gutter-row"
|
|
|
|
|
+ xs={{ span: 24 }}
|
|
|
|
|
+ sm={{ span: 24 }}
|
|
|
|
|
+ md={{ span: 6 }}
|
|
|
|
|
+ lg={{ span: 6 }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Form.Item
|
|
|
|
|
+ rules={[{ required: !sinFechaFin, message: "Requerido" }]}
|
|
|
|
|
+ label="Fecha de finalización"
|
|
|
|
|
+ name="fechaFinal"
|
|
|
|
|
+ >
|
|
|
|
|
+ <DatePicker
|
|
|
|
|
+ disabled={sinFechaFin}
|
|
|
|
|
+ format="YYYY-MM-DD HH:mm"
|
|
|
|
|
+ style={{ width: "100%" }}
|
|
|
|
|
+ locale={locale}
|
|
|
|
|
+ showTime={{
|
|
|
|
|
+ defaultValue: moment("00:00", "HH:mm"),
|
|
|
|
|
+ }}
|
|
|
|
|
+ />
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ </Col>
|
|
|
|
|
+
|
|
|
|
|
+ <Col
|
|
|
|
|
+ className="gutter-row"
|
|
|
|
|
+ xs={{ span: 24 }}
|
|
|
|
|
+ sm={{ span: 24 }}
|
|
|
|
|
+ md={{ span: 6 }}
|
|
|
|
|
+ lg={{ span: 6 }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Form.Item label=" ">
|
|
|
|
|
+ <Checkbox
|
|
|
|
|
+ checked={sinFechaFin}
|
|
|
|
|
+ onChange={(e) => setSinFechaFin(e.target.checked)}
|
|
|
|
|
+ >
|
|
|
|
|
+ Sin fecha de finalización
|
|
|
|
|
+ </Checkbox>
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ </Col>
|
|
|
|
|
+
|
|
|
|
|
+ <Col
|
|
|
|
|
+ className="gutter-row"
|
|
|
|
|
+ xs={{ span: 24 }}
|
|
|
|
|
+ sm={{ span: 24 }}
|
|
|
|
|
+ md={{ span: 6 }}
|
|
|
|
|
+ lg={{ span: 6 }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Form.Item label="Acción" name="accion">
|
|
|
|
|
+ <Select
|
|
|
|
|
+ mode="multiple"
|
|
|
|
|
+ style={{ width: "100%" }}
|
|
|
|
|
+ placeholder="Selecciona una o más opciones"
|
|
|
|
|
+ optionLabelProp="label"
|
|
|
|
|
+ >
|
|
|
|
|
+ {acciones?.map((item) => (
|
|
|
|
|
+ <Option
|
|
|
|
|
+ value={item?.value}
|
|
|
|
|
+ label={item?.label}
|
|
|
|
|
+ key={item?.id}
|
|
|
|
|
+ >
|
|
|
|
|
+ <div className="demo-option-label-item">
|
|
|
|
|
+ <span role="img" aria-label={item?.label}>
|
|
|
|
|
+ {item?.icon}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ {item?.label}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </Option>
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </Select>
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ </Col>
|
|
|
|
|
+ </Row>
|
|
|
|
|
+
|
|
|
|
|
+ {/* URL - Red Social - Agregar [+] */}
|
|
|
|
|
+ <Row gutter={10}>
|
|
|
|
|
+ <Col
|
|
|
|
|
+ className="gutter-row"
|
|
|
|
|
+ xs={{ span: 24 }}
|
|
|
|
|
+ sm={{ span: 24 }}
|
|
|
|
|
+ md={{ span: 12 }}
|
|
|
|
|
+ lg={{ span: 12 }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Form.Item label="URL" name="url">
|
|
|
|
|
+ <Input onChange={(v) => leerLink(v)} />
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ </Col>
|
|
|
|
|
+
|
|
|
|
|
+ <Col
|
|
|
|
|
+ className="gutter-row"
|
|
|
|
|
+ xs={{ span: 24 }}
|
|
|
|
|
+ sm={{ span: 24 }}
|
|
|
|
|
+ md={{ span: editando ? 12 : 9 }}
|
|
|
|
|
+ lg={{ span: editando ? 12 : 9 }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Form.Item label="Red social" name="redSocial">
|
|
|
|
|
+ <Select style={{ width: "100%" }} placeholder="Selecciona">
|
|
|
|
|
+ {redesSociales?.map((item) => (
|
|
|
|
|
+ <Option key={item} value={item}>
|
|
|
|
|
+ {item}
|
|
|
|
|
+ </Option>
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </Select>
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ </Col>
|
|
|
|
|
+
|
|
|
|
|
+ {!editando && (
|
|
|
|
|
+ <Col
|
|
|
|
|
+ className="gutter-row"
|
|
|
|
|
+ xs={{ span: 24 }}
|
|
|
|
|
+ sm={{ span: 24 }}
|
|
|
|
|
+ md={{ span: 3 }}
|
|
|
|
|
+ lg={{ span: 3 }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Form.Item label=" ">
|
|
|
|
|
+ <Button
|
|
|
|
|
+ type="primary"
|
|
|
|
|
+ icon={<PlusCircleOutlined />}
|
|
|
|
|
+ block
|
|
|
|
|
+ onClick={agregarRedSocial}
|
|
|
|
|
+ />
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ </Col>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </Row>
|
|
|
|
|
+
|
|
|
|
|
+ {redes.map((item) => (
|
|
|
|
|
+ <Row key={item.key} gutter={10}>
|
|
|
|
|
+ <Col
|
|
|
|
|
+ className="gutter-row"
|
|
|
|
|
+ xs={{ span: 24 }}
|
|
|
|
|
+ sm={{ span: 24 }}
|
|
|
|
|
+ md={{ span: 12 }}
|
|
|
|
|
+ lg={{ span: 12 }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Form.Item label=" ">
|
|
|
|
|
+ <Input readOnly value={item?.url} />
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ </Col>
|
|
|
|
|
+
|
|
|
|
|
+ <Col
|
|
|
|
|
+ className="gutter-row"
|
|
|
|
|
+ xs={{ span: 24 }}
|
|
|
|
|
+ sm={{ span: 24 }}
|
|
|
|
|
+ md={{ span: 9 }}
|
|
|
|
|
+ lg={{ span: 9 }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Form.Item label=" ">
|
|
|
|
|
+ <Input readOnly value={item?.redSocial} />
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ </Col>
|
|
|
|
|
+
|
|
|
|
|
+ <Col
|
|
|
|
|
+ className="gutter-row"
|
|
|
|
|
+ xs={{ span: 24 }}
|
|
|
|
|
+ sm={{ span: 24 }}
|
|
|
|
|
+ md={{ span: 3 }}
|
|
|
|
|
+ lg={{ span: 3 }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Form.Item label=" ">
|
|
|
|
|
+ <Tooltip title="Remover">
|
|
|
|
|
+ <Button
|
|
|
|
|
+ type="danger"
|
|
|
|
|
+ icon={<MinusCircleOutlined />}
|
|
|
|
|
+ block
|
|
|
|
|
+ onClick={() => quitarRedSocial(item?.key)}
|
|
|
|
|
+ />
|
|
|
|
|
+ </Tooltip>
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ </Col>
|
|
|
|
|
+ </Row>
|
|
|
|
|
+ ))}
|
|
|
|
|
+
|
|
|
|
|
+ <Row gutter={10}>
|
|
|
|
|
+ <Col
|
|
|
|
|
+ xs={{ span: 24 }}
|
|
|
|
|
+ sm={{ span: 24 }}
|
|
|
|
|
+ md={{ span: 12 }}
|
|
|
|
|
+ lg={{ span: 8 }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Button
|
|
|
|
|
+ type="primary"
|
|
|
|
|
+ htmlType="submit"
|
|
|
|
|
+ icon={<SaveOutlined />}
|
|
|
|
|
+ block
|
|
|
|
|
+ size="large"
|
|
|
|
|
+ loading={guadandoCargando}
|
|
|
|
|
+ >
|
|
|
|
|
+ Guardar
|
|
|
|
|
+ </Button>
|
|
|
|
|
+ </Col>
|
|
|
|
|
+ </Row>
|
|
|
|
|
+ </Form>
|
|
|
|
|
+ </DefaultLayout>
|
|
|
|
|
+ );
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+export default EventosDetalle;
|