queue-med/src_ref/pages/QrPoster.tsx

227 lines
8.9 KiB
TypeScript

import { useRef } from "react";
import { useParams, useLocation } from "wouter";
import { trpc } from "@/lib/trpc";
import { Button } from "@/components/ui/button";
import { ChevronLeft, Printer, Loader2, QrCode } from "lucide-react";
export default function QrPoster() {
const params = useParams<{ clinicId: string }>();
const [, navigate] = useLocation();
const clinicId = parseInt(params.clinicId || "0");
const printRef = useRef<HTMLDivElement>(null);
const clinicQuery = trpc.clinic.get.useQuery({ id: clinicId }, { enabled: !!clinicId });
const qrQuery = trpc.clinic.getQrCode.useQuery({ id: clinicId }, { enabled: !!clinicId });
const clinic = clinicQuery.data;
const qrDataUrl = qrQuery.data?.qrDataUrl;
const handlePrint = () => {
window.print();
};
if (clinicQuery.isLoading || qrQuery.isLoading) {
return (
<div className="min-h-screen flex items-center justify-center">
<Loader2 className="w-8 h-8 text-primary animate-spin" />
</div>
);
}
return (
<div className="min-h-screen">
{/* Controls — hidden on print */}
<div className="print:hidden relative z-10 max-w-2xl mx-auto px-4 py-6">
<div className="flex items-center justify-between mb-6">
<button
onClick={() => navigate(`/dashboard/queue/${clinicId}`)}
className="flex items-center gap-2 text-muted-foreground hover:text-foreground transition-colors text-sm"
>
<ChevronLeft className="w-4 h-4" />
Retour à la gestion
</button>
<Button
onClick={handlePrint}
className="bg-primary text-primary-foreground hover:bg-primary/90 glow-teal"
>
<Printer className="w-4 h-4 mr-2" />
Imprimer l'affiche
</Button>
</div>
<div className="glass-card rounded-2xl p-4 mb-6 flex items-start gap-3">
<QrCode className="w-5 h-5 text-primary flex-shrink-0 mt-0.5" />
<div className="text-sm text-muted-foreground">
<strong className="text-foreground">Conseils d'impression :</strong> Utilisez du papier A4, imprimez en couleur si possible.
Plastifiez l'affiche pour la durabilité. Placez-la à hauteur des yeux à l'entrée du cabinet.
</div>
</div>
</div>
{/* Printable poster */}
<div
ref={printRef}
className="print:m-0 max-w-2xl mx-auto px-4 pb-12 print:p-0 print:max-w-none"
>
<div
className="bg-white text-gray-900 rounded-3xl print:rounded-none overflow-hidden shadow-2xl print:shadow-none"
style={{ fontFamily: "'Inter', 'Segoe UI', sans-serif" }}
>
{/* Header band */}
<div style={{ background: "linear-gradient(135deg, #0d9488, #0f766e)", padding: "32px 40px" }}>
<div style={{ display: "flex", alignItems: "center", gap: "12px", marginBottom: "8px" }}>
<div style={{
width: "40px", height: "40px", borderRadius: "10px",
background: "rgba(255,255,255,0.2)", display: "flex",
alignItems: "center", justifyContent: "center"
}}>
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth="2.5">
<path d="M3 9h6V3H3v6zm2-4h2v2H5V5zm8-2v6h6V3h-6zm4 4h-2V5h2v2zM3 21h6v-6H3v6zm2-4h2v2H5v-2zm13-2h-3v2h2v2h-2v2h3v-3h2v-3h-2v2zm-5 6h2v-2h-2v2zm-3-6h2v2h-2v-2zm-2-2h2v2h-2v-2zm2-2h2v2h-2v-2zm2 2h2v2h-2v-2z"/>
</svg>
</div>
<span style={{ color: "white", fontSize: "22px", fontWeight: "800", letterSpacing: "-0.02em" }}>
QueueMed
</span>
</div>
<p style={{ color: "rgba(255,255,255,0.85)", fontSize: "14px", margin: 0 }}>
Salle d'attente virtuelle
</p>
</div>
{/* Main content */}
<div style={{ padding: "40px", textAlign: "center" }}>
<h1 style={{
fontSize: "28px", fontWeight: "800", color: "#0f172a",
marginBottom: "8px", lineHeight: "1.2"
}}>
{clinic?.name ?? "Cabinet médical"}
</h1>
{clinic?.address && (
<p style={{ color: "#64748b", fontSize: "14px", marginBottom: "32px" }}>
📍 {clinic.address}
</p>
)}
<p style={{
fontSize: "18px", fontWeight: "600", color: "#1e293b",
marginBottom: "8px"
}}>
Rejoignez la file d'attente sans attendre ici
</p>
<p style={{ color: "#64748b", fontSize: "14px", marginBottom: "32px" }}>
Scannez le QR code avec votre téléphone et suivez votre position en temps réel
</p>
{/* QR Code */}
<div style={{
display: "inline-block",
padding: "20px",
borderRadius: "20px",
border: "3px solid #e2e8f0",
background: "white",
marginBottom: "32px",
boxShadow: "0 8px 32px rgba(0,0,0,0.08)"
}}>
{qrDataUrl ? (
<img
src={qrDataUrl}
alt="QR Code file d'attente"
style={{ width: "220px", height: "220px", display: "block" }}
/>
) : (
<div style={{
width: "220px", height: "220px",
background: "#f1f5f9", borderRadius: "12px",
display: "flex", alignItems: "center", justifyContent: "center",
color: "#94a3b8", fontSize: "14px"
}}>
QR Code non disponible
</div>
)}
</div>
{/* Steps */}
<div style={{
display: "grid", gridTemplateColumns: "1fr 1fr 1fr",
gap: "16px", marginBottom: "32px"
}}>
{[
{ num: "1", icon: "📱", title: "Scannez", desc: "Ouvrez l'appareil photo et pointez vers le QR code" },
{ num: "2", icon: "👆", title: "Rejoignez", desc: "Appuyez sur le lien et entrez dans la file" },
{ num: "3", icon: "🔔", title: "Revenez", desc: "Vous serez alerté quand votre tour approche" },
].map(step => (
<div key={step.num} style={{
padding: "16px 12px",
borderRadius: "16px",
background: "#f8fafc",
border: "1px solid #e2e8f0"
}}>
<div style={{ fontSize: "28px", marginBottom: "8px" }}>{step.icon}</div>
<div style={{ fontSize: "13px", fontWeight: "700", color: "#0f172a", marginBottom: "4px" }}>
{step.title}
</div>
<div style={{ fontSize: "11px", color: "#64748b", lineHeight: "1.4" }}>
{step.desc}
</div>
</div>
))}
</div>
{/* Info box */}
<div style={{
padding: "14px 20px",
borderRadius: "12px",
background: "#f0fdf4",
border: "1px solid #bbf7d0",
display: "flex",
alignItems: "center",
gap: "10px",
textAlign: "left"
}}>
<span style={{ fontSize: "20px" }}></span>
<div>
<strong style={{ fontSize: "13px", color: "#166534" }}>
Aucune application à installer
</strong>
<p style={{ fontSize: "12px", color: "#15803d", margin: "2px 0 0 0" }}>
Fonctionne directement dans votre navigateur. Gratuit pour les patients.
</p>
</div>
</div>
{/* No smartphone note */}
<p style={{
marginTop: "20px", fontSize: "12px", color: "#94a3b8",
borderTop: "1px solid #f1f5f9", paddingTop: "16px"
}}>
Pas de smartphone ? Demandez un ticket imprimé à l'accueil.
</p>
</div>
{/* Footer */}
<div style={{
background: "#f8fafc", padding: "16px 40px",
display: "flex", justifyContent: "space-between",
alignItems: "center", borderTop: "1px solid #e2e8f0"
}}>
<span style={{ fontSize: "12px", color: "#94a3b8" }}>
Propulsé par QueueMed
</span>
<span style={{ fontSize: "12px", color: "#94a3b8" }}>
queuemed.fr
</span>
</div>
</div>
</div>
{/* Print styles */}
<style>{`
@media print {
body { background: white !important; }
.print\\:hidden { display: none !important; }
@page { margin: 0; size: A4; }
}
`}</style>
</div>
);
}