forked from RiseUP/riseup-squad18
- Avatar do paciente agora persiste após reload (adiciona timestamp para evitar cache) - Agendamento usa patient_id correto ao invés de user_id - Botão de download de PDF desbloqueado com logs detalhados
152 lines
5.9 KiB
TypeScript
152 lines
5.9 KiB
TypeScript
import React, { useState, useEffect } from "react";
|
|
import { Calendar, Clock, ArrowRight } from "lucide-react";
|
|
import { useNavigate } from "react-router-dom";
|
|
import { i18n } from "../i18n";
|
|
|
|
// Importar as imagens
|
|
import medico1 from "./images/medico1.jpg";
|
|
import medico2 from "./images/medico2.jpg";
|
|
import medico3 from "./images/medico3.jpg";
|
|
|
|
const images = [medico1, medico2, medico3];
|
|
|
|
export const HeroBanner: React.FC = () => {
|
|
const [currentImageIndex, setCurrentImageIndex] = useState(0);
|
|
const [nextImageIndex, setNextImageIndex] = useState(1);
|
|
const [isTransitioning, setIsTransitioning] = useState(false);
|
|
const navigate = useNavigate();
|
|
|
|
useEffect(() => {
|
|
// Rotacionar imagens a cada 5 segundos
|
|
const interval = setInterval(() => {
|
|
setIsTransitioning(true);
|
|
|
|
// Após 2 segundos (duração da transição), atualizar os índices
|
|
setTimeout(() => {
|
|
setCurrentImageIndex((prev) => (prev + 1) % images.length);
|
|
setNextImageIndex((prev) => (prev + 1) % images.length);
|
|
setIsTransitioning(false);
|
|
}, 2000);
|
|
}, 5000);
|
|
|
|
return () => clearInterval(interval);
|
|
}, []);
|
|
|
|
const handleCTA = (action: string, destination: string) => {
|
|
console.log(`CTA clicked: ${action} -> ${destination}`);
|
|
navigate(destination);
|
|
};
|
|
|
|
return (
|
|
<div className="relative text-center py-8 md:py-12 lg:py-16 text-white rounded-xl shadow-lg overflow-hidden">
|
|
{/* Background Images com Fade Transition */}
|
|
<div className="absolute inset-0">
|
|
{/* Imagem Atual */}
|
|
<div
|
|
className={`absolute inset-0 bg-cover bg-center transition-opacity duration-2000 ${
|
|
isTransitioning ? "opacity-0" : "opacity-100"
|
|
}`}
|
|
style={{
|
|
backgroundImage: `url(${images[currentImageIndex]})`,
|
|
transitionDuration: "2000ms",
|
|
}}
|
|
/>
|
|
|
|
{/* Próxima Imagem (para transição suave) */}
|
|
<div
|
|
className={`absolute inset-0 bg-cover bg-center transition-opacity duration-2000 ${
|
|
isTransitioning ? "opacity-100" : "opacity-0"
|
|
}`}
|
|
style={{
|
|
backgroundImage: `url(${images[nextImageIndex]})`,
|
|
transitionDuration: "2000ms",
|
|
}}
|
|
/>
|
|
|
|
{/* Overlay Azul Translúcido */}
|
|
<div className="absolute inset-0 bg-blue-800/50" />
|
|
|
|
{/* Decorative Pattern */}
|
|
<div className="absolute inset-0 opacity-10">
|
|
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
|
|
<defs>
|
|
<pattern
|
|
id="grid"
|
|
width="40"
|
|
height="40"
|
|
patternUnits="userSpaceOnUse"
|
|
>
|
|
<circle cx="20" cy="20" r="1" fill="white" />
|
|
</pattern>
|
|
</defs>
|
|
<rect width="100%" height="100%" fill="url(#grid)" />
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Conteúdo */}
|
|
<div className="relative z-10 px-4 max-w-4xl mx-auto">
|
|
<h1 className="text-3xl md:text-4xl lg:text-5xl font-bold mb-3 md:mb-4 drop-shadow-lg">
|
|
{i18n.t("home.hero.title")}
|
|
</h1>
|
|
<p className="text-base md:text-lg lg:text-xl opacity-95 mb-6 md:mb-8 max-w-2xl mx-auto drop-shadow-md">
|
|
{i18n.t("home.hero.subtitle")}
|
|
</p>
|
|
|
|
{/* CTAs */}
|
|
<div className="flex flex-col sm:flex-row gap-3 md:gap-4 justify-center items-center">
|
|
<button
|
|
onClick={() => handleCTA("Agendar consulta", "/paciente")}
|
|
className="group w-full sm:w-auto inline-flex items-center justify-center px-6 md:px-8 py-3 md:py-4 bg-white text-blue-700 rounded-lg font-semibold hover:bg-blue-50 hover:shadow-xl hover:scale-105 active:scale-95 transition-all duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-white/80 focus-visible:ring-offset-blue-600"
|
|
aria-label={i18n.t(
|
|
"home.actionCards.scheduleAppointment.ctaAriaLabel"
|
|
)}
|
|
>
|
|
<Calendar
|
|
className="w-5 h-5 mr-2 group-hover:scale-110 transition-transform"
|
|
aria-hidden="true"
|
|
/>
|
|
{i18n.t("home.hero.ctaPrimary")}
|
|
<ArrowRight
|
|
className="w-5 h-5 ml-2 group-hover:translate-x-1 transition-transform"
|
|
aria-hidden="true"
|
|
/>
|
|
</button>
|
|
|
|
<button
|
|
onClick={() => handleCTA("Ver próximas consultas", "/paciente")}
|
|
className="group w-full sm:w-auto inline-flex items-center justify-center px-6 md:px-8 py-3 md:py-4 bg-blue-700 text-white rounded-lg font-semibold hover:bg-blue-800 hover:shadow-xl hover:scale-105 active:scale-95 border-2 border-white/20 transition-all duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-white/80 focus-visible:ring-offset-blue-600"
|
|
aria-label="Ver lista de próximas consultas"
|
|
>
|
|
<Clock className="w-5 h-5 mr-2" aria-hidden="true" />
|
|
{i18n.t("home.hero.ctaSecondary")}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Indicadores de Imagem (opcionais - pequenos pontos na parte inferior) */}
|
|
<div className="absolute bottom-4 left-1/2 transform -translate-x-1/2 flex gap-2 z-20">
|
|
{images.map((_, index) => (
|
|
<button
|
|
key={index}
|
|
onClick={() => {
|
|
setIsTransitioning(true);
|
|
setTimeout(() => {
|
|
setCurrentImageIndex(index);
|
|
setNextImageIndex((index + 1) % images.length);
|
|
setIsTransitioning(false);
|
|
}, 2000);
|
|
}}
|
|
className={`w-2 h-2 rounded-full transition-all duration-300 ${
|
|
index === currentImageIndex
|
|
? "bg-white w-6"
|
|
: "bg-white/50 hover:bg-white/75"
|
|
}`}
|
|
aria-label={`Ir para imagem ${index + 1}`}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|