import React, { useEffect, useState } from "react"; import { useParams } from "react-router-dom"; import { api } from "../api"; const A4_WIDTH_PX = (210 / 25.4) * 96; const A4_HEIGHT_PX = (297 / 25.4) * 96; // Anonymous read-only public CV at /cv/:slug. Renders the server-produced HTML in a sandboxed // iframe. noindex is enforced server-side (X-Robots-Tag) and reinforced with a meta tag here. export default function PublicCvPage() { const { slug } = useParams(); const pdfUrl = `${api.defaults.baseURL}/public-cv/${slug}/pdf`; const [html, setHtml] = useState(null); const [error, setError] = useState(null); const [frameScale, setFrameScale] = useState(1); const [frameHeight, setFrameHeight] = useState(A4_HEIGHT_PX); useEffect(() => { const meta = document.createElement("meta"); meta.name = "robots"; meta.content = "noindex, nofollow"; document.head.appendChild(meta); let alive = true; api.get<{ html: string; name: string }>(`/public-cv/${slug}`) .then((r) => { if (alive) { setHtml(r.data.html); if (r.data.name) document.title = `${r.data.name} — CV`; } }) .catch((err) => { if (!alive) return; // 404 = unknown slug or the owner made it private again. Anything else is a transient error. setError(err?.response?.status === 404 ? "This CV isn’t available. The link may be wrong, or the owner has made it private." : "This CV can’t be loaded right now. Please try again in a moment."); }); return () => { alive = false; document.head.removeChild(meta); }; }, [slug]); useEffect(() => { const updateScale = () => setFrameScale(Math.min(1, Math.max(0.1, (window.innerWidth - 32) / A4_WIDTH_PX))); updateScale(); window.addEventListener("resize", updateScale); return () => window.removeEventListener("resize", updateScale); }, []); if (error) { return (
{error}
); } if (html === null) { return (
Loading…
); } return (
Download PDF