const { useEffect, useMemo, useState } = React;
const API = "./api";
const districts = ["Miraflores", "Surco", "San Isidro", "San Miguel", "La Molina", "Jesus Maria", "Magdalena", "Barranco", "Lince", "Pueblo Libre"];
const urgencyOptions = ["baja", "media", "alta"];
const requestStatuses = ["new", "reviewed", "contacted", "closed"];
const categoryInsights = {
Carpinteria: {
range: "Desde S/ 80 a S/ 350 segun ajuste, reparacion o instalacion.",
includes: ["Ajuste de puertas y bisagras", "Reparacion de muebles", "Instalacion de repisas o accesorios"],
tip: "Envia fotos del mueble o puerta para que el tecnico estime materiales y tiempo antes de visitarte.",
},
Cerrajeria: {
range: "Desde S/ 60 a S/ 220 segun apertura, cambio de chapa o nivel de seguridad.",
includes: ["Apertura de puertas", "Cambio de chapas", "Mejora de seguridad domestica"],
tip: "Indica si la cerradura es simple, multipunto o digital para evitar cotizaciones incompletas.",
},
Electricidad: {
range: "Desde S/ 70 a S/ 300 segun punto electrico, luminaria o tablero.",
includes: ["Instalacion de tomacorrientes", "Cambio de luminarias", "Revision de llaves y tableros"],
tip: "Si hay chispas, olor a quemado o cortes recurrentes, solicita atencion prioritaria.",
},
Gasfiteria: {
range: "Desde S/ 70 a S/ 280 segun fuga, griferia, desatoro o conexion.",
includes: ["Reparacion de fugas", "Cambio de griferias", "Desatoros y conexiones de agua"],
tip: "Cierra la llave de paso si hay fuga activa y comparte una foto o video corto del problema.",
},
Limpieza: {
range: "Desde S/ 90 a S/ 300 segun area, profundidad y horas requeridas.",
includes: ["Limpieza profunda", "Mantenimiento por horas", "Apoyo para mudanza o post obra"],
tip: "Indica metraje aproximado, cantidad de ambientes y si necesitas insumos incluidos.",
},
"Mantenimiento general": {
range: "Desde S/ 80 a S/ 320 segun cantidad de tareas y complejidad.",
includes: ["Ajustes menores del hogar", "Instalaciones simples", "Revision preventiva"],
tip: "Agrupa varias tareas pequenas en una sola visita para aprovechar mejor el costo de traslado.",
},
Pintura: {
range: "Desde S/ 180 por ambiente pequeno; varia por metraje, resanes y acabado.",
includes: ["Pintado de ambientes", "Resanes menores", "Acabados y retoques"],
tip: "Define si necesitas solo mano de obra o tambien materiales para comparar cotizaciones de forma justa.",
},
"Reparaciones menores": {
range: "Desde S/ 60 a S/ 200 segun tiempo, herramientas y materiales.",
includes: ["Ajustes rapidos", "Instalaciones pequenas", "Correcciones de uso diario"],
tip: "Describe cada tarea por separado para que el tecnico confirme si puede resolverlas en una visita.",
},
};
const experienceOptions = [
{ label: "0 a 5 anos", value: "0" },
{ label: "5 a 10 anos", value: "5" },
{ label: "Mas de 10 anos", value: "10" },
];
const dayOptions = ["Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado", "Domingo"];
const scheduleOptions = ["Manana", "Tarde", "Noche", "Horario completo", "Emergencias", "Previa coordinacion"];
function apiUrl(path) {
return `${API}/${path}`;
}
async function requestJson(path, options = {}) {
const response = await fetch(apiUrl(path), {
headers: { "Content-Type": "application/json", ...(options.headers || {}) },
credentials: "include",
...options,
});
const data = await response.json();
if (!response.ok || data.success === false) {
throw new Error(data.message || "No se pudo completar la accion.");
}
return data;
}
function formatExperience(value) {
const found = experienceOptions.find((item) => item.value === String(value));
return found ? found.label : `${value} anos`;
}
function MultiSelect({ label, options, selected, onChange, placeholder = "Buscar y seleccionar" }) {
const [open, setOpen] = useState(false);
const [query, setQuery] = useState("");
const filteredOptions = options.filter((option) => option.toLowerCase().includes(query.toLowerCase()));
function toggle(option) {
if (selected.includes(option)) {
onChange(selected.filter((item) => item !== option));
return;
}
onChange([...selected, option]);
}
return (
);
}
function ServiceGlyph({ name }) {
const key = (name || "").toLowerCase();
const common = { fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" };
let paths = (
<>
>
);
if (key.includes("gasf")) {
paths = <>>;
} else if (key.includes("elect")) {
paths = <>>;
} else if (key.includes("pint")) {
paths = <>>;
} else if (key.includes("cerra")) {
paths = <>>;
} else if (key.includes("limp")) {
paths = <>>;
} else if (key.includes("carp")) {
paths = <>>;
} else if (key.includes("mantenimiento")) {
paths = <>>;
} else if (key.includes("repar")) {
paths = <>>;
}
return ;
}
function Header() {
return (
);
}
function SiteFooter() {
return (
);
}
function Hero({ categories, filters, setFilters, onRequest }) {
return (
Servicios para cuidar tu hogar, en un solo lugar
Encuentra tecnicos confiables para tu hogar en minutos
Gasfiteros, electricistas, pintores y especialistas verificados cerca de ti.
);
}
function CategoryDescriptionModal({ category, onClose, onExplore }) {
if (!category) return null;
const insight = categoryInsights[category.name] || {
range: "El costo depende del alcance, materiales y urgencia del servicio.",
includes: ["Revision del problema", "Cotizacion segun alcance", "Coordinacion directa con el tecnico"],
tip: "Describe el problema con detalle y adjunta fotos cuando contactes al tecnico.",
};
return (
event.stopPropagation()}>
Servicio
{category.name}
{category.description}
Referencia{insight.range}
Suele incluir
{insight.includes.map((item) =>
{item}
)}
Consejo rapido
{insight.tip}
);
}
function CategoryGrid({ categories, onExploreCategory }) {
const [selectedCategory, setSelectedCategory] = useState(null);
const steps = [
"Describe tu problema.",
"Elige servicio, distrito y fecha.",
"Te conectamos con un tecnico disponible.",
"Recibe el servicio y califica la experiencia.",
];
return (