0% found this document useful (0 votes)
13 views

Reportesform

Uploaded by

Dylan Chaos
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views

Reportesform

Uploaded by

Dylan Chaos
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 18

import React, { useEffect, useState, useContext } from "react";

import { storage, firestore, firebase, auth } from "../firebase";


import { Link } from "react-router-dom";
import Menu from "../components/Menu.js";
import { ResponsiveEmbed, Modal } from "react-bootstrap";
import LoadMap from "../components/Map";
import GoogleMap from "../components/Map";
import {
getEstados,
municipios as municipiosData,
} from "../components/estados";
import { Container, Col, Row, Button } from "react-bootstrap";
import Home from "../assets/home.svg";
import AddMobile from "../assets/add-mobile.svg";
import Back from "../assets/back.svg";
import { UserContext } from "../providers/userProvider";
import loader from "../assets/loader.svg";
import {
tiposDeApoyo,
allSecciones,
allColonias,
} from "../assets/reportesDatos";
import searchByNameArrayConstructor from "./searchByNameArray";
import wait from "waait";

const ReportesForm = (props) => {


const [show, setShow] = useState(false);
const [loading, setLoading] = useState(true);

const handleClose = () => setShow(false);


const handleShow = () => setShow(true);

const [position, setPosition] = useState({


lat: 25.6929549,
lng: -100.2363803,
});
const [imageFile, setImageFile] = useState();
const [imageFile2, setImageFile2] = useState();
const [capturista, setCapturista] = useState("");
const user = useContext(UserContext);

const initialFormData = props.location.formData


? props.location.formData
: {
estado: "Aguascalientes",
municipio: "Aguascalientes",
programa: "",
tipoDeApoyo: "",
comentarios: "",
fechaReporte: "",
prioridadReporte: "",
valoracionRecepcion: "",
nombre: "",
apellidoPaterno: "",
apellidoMaterno: "",
genero: "",
fechaNacimiento: "",
municipio: "",
calle: "",
numeroExterior: "",
numeroInterior: "",
colonia: "",
codigoPostal: "",
telefono: "",
celular: "",
correo: "",
facebook: "",
instagram: "",
twitter: "",
whatsapp: "",
metodoContacto: "",
horarioPreferido: "",
ine: "",
curp: "",
distritoFederal: "",
distritoLocal: "",
seccionElectoral: "",
areaRecepcion: "",
funcionarioRecepcion: "",
estatus: "",
entrecalles: "",
folio: "",
photo: "",
photo2: "",
geolocalizacion: "",
};

const [formData, setFormData] = useState(initialFormData);


const [programas, setProgramas] = useState([]);
const [campo, setCampo] = useState("");
const [estados, setEstados] = useState(getEstados());
const [currentMunicipios, setCurrentMunicipios] = useState(
municipiosData[formData.estado]
);
const [latitude, setLatitude] = useState();
const [longitude, setLongitude] = useState();

const { uid } = user || { uid: undefined };


const { role } = user || { role: "capturista" };
const { email, displayName } = user || {};

const setGeoPosition = (pos) => {


if (!pos) return;
setFormData({ ...formData, geolocalizacion: [pos.lat, pos.lng] });
};

// const getCurrentLocation = () => {


// navigator.geolocation.getCurrentPosition(
// function (position) {
// const lat = position.coords.latitude;
// const lng = position.coords.longitude;
// setFormData({ ...formData, geolocalizacion: [lat, lng] });
// return { lat, lng };
// },
// function (error) {
// console.error("Error Code = " + error.code + " - " + error.message);
// }
// );
// };

const getCurrentLocation = () => {


navigator.geolocation.getCurrentPosition(
function (position) {
const lat = position.coords.latitude;
const lng = position.coords.longitude;
setPosition({ lat, lng });

return { lat, lng };


},
function (error) {
console.error("Error Code = " + error.code + " - " + error.message);
},
{
enableHighAccuracy: true,
timeout: 15000,
maximumAge: 0,
}
);
};

useEffect(getCurrentLocation, []);

useEffect(() => {
setTimeout(() => setCapturista(displayName), 500);
}, [displayName, user]);

useEffect(() => {
firestore
.collection("programs")
.get()
.then((response) => {
let programasData = [];
response.forEach((doc) => {
if (doc.data()) {
programasData.push(doc.data());
}
});
setProgramas(programasData);
setLoading(false);
});
}, []);

useEffect(() => {
setCurrentMunicipios(municipiosData[formData.estado]);
}, [formData.estado]);

const toggleLoader = () => {


const loader = document.getElementById("loader");
loader.classList.toggle("d-none");
};
async function handleSubmitObject(e) {
e.preventDefault();
toggleLoader();
let validado = false;

let curpRef = firestore


.collection("curp")
.where("itemID", "==", formData.curp)
.onSnapshot((snapshot) => {
let itemID = snapshot.docs.map((doc) => ({
id: doc.id,
}));
validado = itemID.length > 0;
});

wait(500);
const reportesRef = firestore.collection("reportes");
//increment folio counter and get it
const foliosRef = reportesRef.doc("folios");

foliosRef.get().then(async (docFolio) => {


const { folio } = docFolio.data();
foliosRef.update({
folio: firebase.firestore.FieldValue.increment(1),
});

if (!docFolio.data().coloniasArray.includes(formData.colonia))
foliosRef.update({
coloniasArray: firebase.firestore.FieldValue.arrayUnion(
formData.colonia
),
});
if (!docFolio.data().municipiosArray.includes(formData.municipio))
foliosRef.update({
municipiosArray: firebase.firestore.FieldValue.arrayUnion(
formData.municipio
),
});
if (!docFolio.data().prioridadesArray.includes(formData.prioridadReporte))
foliosRef.update({
prioridadesArray: firebase.firestore.FieldValue.arrayUnion(
formData.prioridadReporte
),
});
if (!docFolio.data().seccionesArray.includes(formData.seccionElectoral))
foliosRef.update({
seccionesArray: firebase.firestore.FieldValue.arrayUnion(
formData.seccionElectoral
),
});

const { uid, email } = auth.currentUser;

const reporte = await reportesRef.add({


...formData,
created_at: new Date().setHours(0, 0, 1, 0),
user: { uid, email, displayName },
asignado: "SIN ASIGNAR",
estatus: "CAPTURADO",
estatus_updated: new Date().setHours(12, 0, 0, 0),
notas: [{}],
folio: folio,
searchByNameArray: searchByNameArrayConstructor(formData),
funcionarioRecepcion: displayName,
curpValidado: validado,
});
if (imageFile.files.length > 0) {
storage
.ref()
.child("reportes-photos")
.child(reporte.id)
.child(imageFile.files[0].name)
.put(imageFile.files[0])
.then((response) => response.ref.getDownloadURL())
.then((photo) => reportesRef.doc(reporte.id).update({ photo }));
}

if (imageFile2.files.length > 0) {
storage
.ref()
.child("reportes-photos")
.child(reporte.id)
.child(imageFile2.files[0].name)
.put(imageFile2.files[0])
.then((response) => response.ref.getDownloadURL())
.then((photo2) => reportesRef.doc(reporte.id).update({ photo2 }));
}
});

setImageFile();
setImageFile2();
toggleLoader();
alert("Registro Agregado Exitosamente");
props.history.goBack();
}

async function handleEditObject(e) {


e.preventDefault();
toggleLoader();
const reporte = formData;
const reportesRef = firestore.collection("reportes");
//update document
reportesRef
.doc(reporte.id)
.update({
...reporte,
reporte_updated_at: new Date(),
})
.then((reportDoc) => {
//TODO : get the old file and replace it for the new one
// here I'm just adding(put) and new file without deleting the old one
// then I replace this reference of the reporte
if (imageFile.files.length > 0) {
storage
.ref()
.child("reportes-photos")
.child(reporte.id)
.child(imageFile.files[0].name)
.put(imageFile.files[0])
.then((response) => response.ref.getDownloadURL())
.then((photo) => reportesRef.doc(reporte.id).update({ photo }));
}
setImageFile();
if (imageFile2.files.length > 0) {
storage
.ref()
.child("reportes-photos")
.child(reporte.id)
.child(imageFile2.files[0].name)
.put(imageFile2.files[0])
.then((response) => response.ref.getDownloadURL())
.then((photo2) => reportesRef.doc(reporte.id).update({ photo2 }));
}
});

setImageFile();
setImageFile2();
toggleLoader();
alert("Registro Editado Exitosamente");
props.history.goBack();
}

const handleOnchange = (e) => {


const name = e.target.name;
const value = e.target.value;
setFormData({ ...formData, [name]: value });
};

const addForm1 = (datoss, key) => {


var value = (
<label htmlFor={datoss["name"]} key={key}>
{datoss["label"]}
<input
type={datoss["type"] || "text"}
name={datoss["name"]}
id={datoss[datoss["name"]]}
onChange={handleOnchange}
value={formData[datoss["name"]] || ""}
ref={datoss["type"] === "file" ? (ref) => setImageFile(ref) : null}
/>
</label>
);
return value;
};

return (
<>
<Container fluid>
<Row className="main-row">
<Col md={2} className="p-0 menu-scroll d-none d-md-block">
<Menu />
</Col>
<Col xs={12} md={10} className="bg-form reportes-container">
<div className="forma-reportes mb-5" id="forma">
<div className="title-wrapper">
<h1 className="main-title">Agregar Registro</h1>
</div>
<form
className="reportes-form mt-5 mt-md-1 mb-5 pb-5"
onSubmit={
props.location.edit ? handleEditObject : handleSubmitObject
}
>
<div className="loader d-none position-fixed" id="loader">
<img src={loader} className="d-flex text-center w-50" />
</div>
<h3 className="form-title"> Informacion de programa</h3>
<div className="primera-parte">
<label htmlFor="programa">
Programa
<select
type="select"
name="programa"
id={"programa"}
onChange={handleOnchange}
value={formData["programa"] || ""}
disabled={loading}
>
<option className="option-programa" value="">
{loading ? "Cargando..." : "Seleccione"}
</option>
{programas.map((prog, idx) => (
<option
key={idx}
className="option-programa"
value={prog["titulo"]}
>
{prog["titulo"]}{" "}
</option>
))}
</select>
</label>
<label htmlFor="tipoDeApoyo">
Tipo de Apoyo
<input
type="text"
name="tipoDeApoyo"
id={"tipoDeApoyo"}
onChange={handleOnchange}
value={formData["tipoDeApoyo"]}
/>
{/* IF CLIENT PROVIDES A LIST OF TIPOS DE APOYO, CHANGE THOSE
IN ASSETS/REPORTESDATOS.JS
<select
type="select"
name="tipoDeApoyo"
id={"tipoDeApoyo"}
onChange={handleOnchange}
value={formData["tipoDeApoyo"]}
>
<option className="option-programa" value="">
Seleccione
</option>
{tiposDeApoyo.map((tipo, idx) => (
<option
key={idx}
className="option-programa"
value={tipo}
>
{tipo}{" "}
</option>
))}
</select> */}
</label>
<label htmlFor="comentarios">
Comentarios
<input
type="text"
name="comentarios"
id={"comentarios"}
onChange={handleOnchange}
value={formData["comentarios"] || ""}
/>
</label>

<label htmlFor="fechaReporte">
Fecha de Registro
<input
type="date"
id={"fechaReporte"}
onChange={handleOnchange}
name="fechaReporte"
value={formData["fechaReporte"] || ""}
/>
</label>
<label htmlFor="prioridadReporte">
Prioridad
<select
type="select"
name="prioridadReporte"
id={"prioridadReporte"}
onChange={handleOnchange}
value={formData["prioridadReporte"] || ""}
>
<option className="option-prioridad" value="">
Seleccione
</option>
<option className="option-prioridad" value="Prioridad 1">
Prioridad 1
</option>
<option className="option-prioridad" value="Prioridad 2">
Prioridad 2
</option>
<option className="option-prioridad" value="Prioridad 3">
Prioridad 3
</option>
<option className="option-prioridad" value="Prioridad 4">
Prioridad 4
</option>
</select>
</label>
<label htmlFor="valoracionRecepcion">
Valoración de Recepción
<select
type="select"
name="valoracionRecepcion"
id={"valoracionRecepcion"}
onChange={handleOnchange}
value={formData["valoracionRecepcion"] || ""}
>
<option className="option-valoracionRecepcion" value="">
Seleccione
</option>
<option
className="option-valoracionRecepcion"
value="Muy Bueno"
>
Muy Bueno
</option>
<option
className="option-valoracionRecepcion"
value="Bueno"
>
Bueno
</option>
<option
className="option-valoracionRecepcion"
value="Neutral"
>
Neutral
</option>
<option
className="option-valoracionRecepcion"
value="Malo"
>
Malo
</option>
<option
className="option-valoracionRecepcion"
value="Muy Malo"
>
Muy Malo
</option>
</select>
</label>
</div>
<h3 className="form-title"> Información del ciudadano</h3>
<div className="segunda-parte">
<label htmlFor="nombre">
Nombre(s)
<input
type="text"
name="nombre"
id={"nombre"}
onChange={handleOnchange}
value={formData["nombre"] || ""}
/>
</label>
<label htmlFor="apellidoPaterno">
Apellido Paterno
<input
type="text"
name="apellidoPaterno"
id={"apellidoPaterno"}
onChange={handleOnchange}
value={formData["apellidoPaterno"] || ""}
/>
</label>
<label htmlFor="apellidoMaterno">
Apellido Materno
<input
type="text"
name="apellidoMaterno"
id={"apellidoMaterno"}
onChange={handleOnchange}
value={formData["apellidoMaterno"] || ""}
/>
</label>

<label htmlFor="genero">
Género
<select
type="select"
name="genero"
id={"genero"}
onChange={handleOnchange}
value={formData["genero"] || ""}
>
<option className="option-genero" value="">
Seleccione
</option>
<option className="option-genero" value="Femenino">
Femenino
</option>
<option className="option-genero" value="Masculino">
Masculino
</option>
<option className="option-genero" value="Otro">
Otro
</option>
</select>
</label>

<label htmlFor="fechaNacimiento">
Fecha de Nacimiento
<input
type="date"
name="fechaNacimiento"
id={"fechaNacimiento"}
onChange={handleOnchange}
value={formData["fechaNacimiento"] || ""}
/>
</label>
<label htmlFor="geolocalizacion">
Geolocalización
<span
onClick={handleShow}
className="btn reportes-boton-enviar bg-warning1 mt-0"
>
Localización
</span>
</label>
<label htmlFor="estado" className="mt-4 mt-md-1">
Estado
<select
name="estado"
type="select"
id={"estado"}
onChange={handleOnchange}
value={formData.estado || ""}
>
<option value={estados[0]} htmlFor={"selected"}>
{estados[0]}
</option>
{estados.slice(1).map((estado, idx) => {
return (
<option key={idx} value={estado}>
{" "}
{estado}{" "}
</option>
);
})}
</select>
</label>

<label htmlFor="municipio">
Municipio
<select
name="municipio"
type="select"
id="municipio"
onChange={handleOnchange}
value={formData.municipio || ""}
>
{currentMunicipios.map((municipio, idx) => {
return (
<option key={idx} value={municipio}>
{municipio}
</option>
);
})}
</select>
</label>

<label htmlFor="calle">
Calle
<input
type="text"
name="calle"
id={"calle"}
onChange={handleOnchange}
value={formData["calle"] || ""}
/>
</label>
<label htmlFor="numeroExterior">
Número Exterior
<input
type="text"
name="numeroExterior"
id={"numeroExterior"}
onChange={handleOnchange}
value={formData["numeroExterior"] || ""}
/>
</label>
<label htmlFor="numeroInterior">
Número Interior
<input
type="text"
name="numeroInterior"
id={"numeroInterior"}
onChange={handleOnchange}
value={formData["numeroInterior"] || ""}
/>
</label>
<label htmlFor="colonia">
Colonia
<input
type="text"
name="colonia"
id={"colonia"}
onChange={handleOnchange}
value={formData["colonia"] || ""}
/>
{/* IF THE CUSTOMER PROVIDES US WITH A LIST OF COLONIAS, CHANGE
THE INPUT AVOBE FOR THIS ONE AND LOAD THE SECCIONES IN reportesDatos.js
<select
type="select"
name="colonia"
id={"colonia"}
onChange={handleOnchange}
value={formData["colonia"] || ""}
>
<option className="option-programa" value="">
Seleccione
</option>
{allColonias.map((col, idx) => (
<option
key={idx}
className="option-programa"
value={col}
>
{col}{" "}
</option>
))}
</select> */}
</label>
<label htmlFor="entrecalles">
Entrecalles
<input
type="text"
name="entrecalles"
id={"entrecalles"}
onChange={handleOnchange}
value={formData["entrecalles"] || "N/A"}
/>
</label>
<label htmlFor="codigoPostal">
C.P.
<input
type="text"
name="codigoPostal"
id={"codigoPostal"}
onChange={handleOnchange}
value={formData["codigoPostal"] || ""}
/>
</label>
<label htmlFor="telefono">
Teléfono
<input
type="tel"
id="telefono"
pattern="[0-9]{10}"
name="telefono"
onChange={handleOnchange}
value={formData["telefono"] || ""}
/>
</label>
<label htmlFor="celular">
Celular
<input
type="tel"
pattern="[0-9]{10}"
name="celular"
id={"celular"}
onChange={handleOnchange}
value={formData["celular"] || ""}
/>
</label>
<label htmlFor="correo">
E-mail
<input
type="email"
name="correo"
id={"correo"}
onChange={handleOnchange}
value={formData["correo"] || ""}
/>
</label>
<label htmlFor="metodoContacto">
Método de Contacto
<select
type="select"
name="metodoContacto"
id="metodoContacto"
onChange={handleOnchange}
value={formData["metodoContacto"] || ""}
>
<option className="option-metodo" value="">
Seleccione
</option>
<option className="option-metodo" value="Telefono">
Teléfono
</option>
<option className="option-metodo" value="Celular">
Celular
</option>
<option className="option-metodo" value="E-mail">
E-mail
</option>
<option className="option-metodo" value="Domicilio">
Domicilio
</option>
</select>
</label>
<label
htmlFor="horarioPreferido"
id={"horarioPreferido"}
onChange={handleOnchange}
>
Horario preferido para contactar
<select
type="select"
name="horarioPreferido"
id={"horarioPreferido"}
onChange={handleOnchange}
value={formData["horarioPreferido"] || ""}
>
<option className="option-horario" value="">
Seleccione
</option>
<option className="option-horario" value="Mañana">
Mañana
</option>
<option className="option-horario" value="Tarde">
Tarde
</option>
<option className="option-horario" value="Noche">
Noche
</option>
</select>
</label>
<label htmlFor="Whatsapp">
Whatsapp (10 dígitos)
<input
type="text"
name="whatsapp"
id={"whatsapp"}
onChange={handleOnchange}
value={formData["whatsapp"] || ""}
/>
</label>

<label htmlFor="facebook">
Facebook (usuario de facebook)
<input
type="text"
name="facebook"
id={"facebook"}
onChange={handleOnchange}
value={formData["facebook"] || ""}
placeholder="usuario"
/>
</label>
<label htmlFor="Twitter">
Twitter (escribirlo sin @)
<input
type="text"
name="twitter"
id={"twitter"}
onChange={handleOnchange}
value={formData["twitter"] || ""}
/>
</label>
<label htmlFor="Instagram">
Instagram (usuario de instagram)
<input
type="text"
name="instagram"
id={"instagram"}
onChange={handleOnchange}
value={formData["instagram"] || ""}
/>
</label>
</div>
<h3 className="form-title"> Identificación</h3>

<div className="tercera-parte">
<label htmlFor="ine">
Clave de Elector
<input
minlength="18"
maxlength="18"
type="text"
name="ine"
id={"ine"}
onChange={handleOnchange}
value={formData["ine"] || ""}
/>
</label>
<label htmlFor="curp">
CURP
<input
type="text"
name="curp"
id={"curp"}
onChange={handleOnchange}
value={formData["curp"] || ""}
/>
</label>
<label htmlFor="distritoFederal">
Distrito Federal
<input
type="text"
name="distritoFederal"
id={"distritoFederal"}
onChange={handleOnchange}
value={formData["distritoFederal"] || ""}
/>
</label>
<label htmlFor="distritoLocal">
Distrito Local
<input
type="text"
name="distritoLocal"
id={"distritoLocal"}
onChange={handleOnchange}
value={formData["distritoLocal"] || ""}
/>
</label>
<label htmlFor="seccionElectoral">
Sección Electoral
<input
type="text"
name="seccionElectoral"
id={"seccionElectoral"}
onChange={handleOnchange}
value={formData["seccionElectoral"] || ""}
/>
{/* IF THE CUSTOMER PROVIDES US WITH A LIST OF SECCIONES
ELECTORALES, CHANGE THE INPUT AVOBE FOR THIS ONE AND LOAD THE SECCIONES IN
reportesDatos.js
<select
type="select"
name="seccionElectoral"
id={"seccionElectoral"}
onChange={handleOnchange}
value={formData["seccionElectoral"] || ""}
>
<option className="option-programa" value="">
Seleccione
</option>
{allSecciones.map((secc, idx) => (
<option
key={idx}
className="option-programa"
value={secc}
>
{secc}{" "}
</option>
))}
</select> */}
</label>
</div>
<h3 className="form-title"> Información Adicional</h3>
<div className="cuarta-parte">
<label htmlFor="areaRecepcion">
Area de Recepción
<input
type="text"
name="areaRecepcion"
id="areaRecepcion"
onChange={handleOnchange}
value={formData["areaRecepcion"] || ""}
/>
</label>
<label htmlFor="funcionarioRecepcion" className="">
Funcionario Recepción
<input
type="text"
name="funcionarioRecepcion"
id="funcionarioRecepcion"
onChange={handleOnchange}
value={formData["funcionarioRecepcion"] || ""}
/>
</label>

<label htmlFor="folio">
<input
type="hidden"
name="folio"
id="folio"
onChange={handleOnchange}
value={formData["folio"] || ""}
/>
</label>

<label htmlFor="photo" className="mr-0 pr-0">


Fotografía 1
<input
className="pr-0 mr-0 "
type="file"
name="photo"
id="photo"
onChange={handleOnchange}
ref={(ref) => setImageFile(ref)}
/>
</label>
<label htmlFor="photo2" className="mr-0 pr-0">
Fotografía 2
<input
className="pr-0 mr-0 "
type="file"
name="photo2"
id="photo2"
onChange={handleOnchange}
ref={(ref) => setImageFile2(ref)}
/>
</label>
<label className="">
<input
className="reportes-boton-enviar"
type="submit"
value="enviar"
/>
</label>
</div>
</form>
<footer class="fixed-bottom user-welcome text-white p-0 menu-scroll
d-md-none d-block d-flex justify-items-between">
<Link to="/reportes">
<img alt="Reportes" src={Back} className="inicio" />
<span className="mx-2 text-white">Regresar</span>
</Link>
<Link to="/home">
<img alt="Inicio" src={Home} className="inicio" />
<span className="mx-2 text-white">Inicio</span>
</Link>
<Link to="/reportesform">
<img
className="agregar"
alt="agregar"
src={AddMobile}
className="inicio"
/>
<span className="mx-2 text-white ">Registros</span>
</Link>
</footer>
</div>
</Col>
</Row>
</Container>
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Geolocalización</Modal.Title>
</Modal.Header>

<Modal.Body>
{/* <LoadMap
height={window.screen.width > 800 ? "400px" : "50vh"}
width={window.screen.width > 800 ? "450px" : "85vw"}
setGeoPosition={setGeoPosition}
positions={[position]}
className="m-auto"
/> */}
<GoogleMap
height={window.screen.width > 800 ? "400px" : "50vh"}
width={window.screen.width > 800 ? "450px" : "85vw"}
setGeoPosition={setGeoPosition}
position={position}
/>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Cerrar
</Button>
<Button variant="primary" onClick={handleClose}>
Guardar
</Button>
</Modal.Footer>
</Modal>
</>
);
};

export default ReportesForm;

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy