refactor(ui): modulariza App.jsx y unifica branding y caché PWA
- Extrae App.jsx en módulos reutilizables: constants/ (categorias, provincias), utils/geo, styles/shared, hooks/usePwaInstall y components/ (StarRating, LocalCard, CampoUbicacion, BannerMovil, CategoriaBadge) - AdminPanel reutiliza constantes y componentes compartidos y corrige la limpieza de suscripciones de Firebase al desmontar - Añade logos de marca (logo-localesp.png + @2x) y regenera los iconos PWA con tamaños menores - sw.js: sube la caché del shell a v2 e incluye los nuevos iconos y logos
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
import CategoriaBadge from "./CategoriaBadge.jsx";
|
||||
import StarRating from "./StarRating.jsx";
|
||||
|
||||
function formatearFecha(fecha) {
|
||||
if (!fecha) return null;
|
||||
const date = new Date(fecha);
|
||||
if (Number.isNaN(date.getTime())) return null;
|
||||
return date.toLocaleDateString("es-ES", { day: "numeric", month: "long", year: "numeric" });
|
||||
}
|
||||
|
||||
export default function LocalCard({ local }) {
|
||||
const gmUrl = local.enlaceGoogleMaps || (local.direccion
|
||||
? `https://www.google.com/maps/search/${encodeURIComponent(`${local.nombre} ${local.direccion}`)}`
|
||||
: null);
|
||||
const fechaFormateada = formatearFecha(local.fecha);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{ background: "var(--color-background-primary)", border: "0.5px solid var(--color-border-tertiary)", borderRadius: "var(--border-radius-lg)", padding: "1rem 1.25rem", display: "flex", flexDirection: "column", gap: 8, transition: "border-color 0.2s" }}
|
||||
onMouseEnter={(e) => { e.currentTarget.style.borderColor = "var(--color-border-secondary)"; }}
|
||||
onMouseLeave={(e) => { e.currentTarget.style.borderColor = "var(--color-border-tertiary)"; }}
|
||||
>
|
||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
|
||||
<div style={{ flex: 1, minWidth: 0 }}>
|
||||
<p style={{ fontWeight: 500, fontSize: 16, margin: 0 }}>{local.nombre}</p>
|
||||
{local.provincia && <p style={{ fontSize: 13, color: "var(--color-text-secondary)", margin: "2px 0 0" }}>{local.provincia}</p>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<CategoriaBadge categoria={local.categoria} subcategoria={local.subcategoria} />
|
||||
|
||||
{local.direccion && (
|
||||
<div style={{ display: "flex", alignItems: "flex-start", gap: 6 }}>
|
||||
<i className="ti ti-map-pin" aria-hidden="true" style={{ fontSize: 14, color: "var(--color-text-tertiary)", marginTop: 1, flexShrink: 0 }}></i>
|
||||
<span style={{ fontSize: 13, color: "var(--color-text-secondary)" }}>{local.direccion}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{gmUrl && (
|
||||
<a href={gmUrl} target="_blank" rel="noopener noreferrer"
|
||||
style={{ display: "inline-flex", alignItems: "center", gap: 5, fontSize: 12, color: "#1A73E8", textDecoration: "none", width: "fit-content", background: "#E8F0FE", padding: "4px 10px", borderRadius: "var(--border-radius-md)", fontWeight: 500 }}>
|
||||
<i className="ti ti-brand-google-maps" aria-hidden="true" style={{ fontSize: 14 }}></i>
|
||||
Ver en Google Maps
|
||||
</a>
|
||||
)}
|
||||
|
||||
<StarRating value={local.puntuacion} readOnly />
|
||||
|
||||
{local.descripcion && (
|
||||
<p style={{ fontSize: 13, color: "var(--color-text-secondary)", margin: 0, fontStyle: "italic" }}>"{local.descripcion}"</p>
|
||||
)}
|
||||
|
||||
{fechaFormateada && (
|
||||
<p style={{ fontSize: 11, color: "var(--color-text-tertiary)", margin: 0 }}>Publicado {fechaFormateada}</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user