feat: exibir ultimos projetos dinamicamente na home
This commit is contained in:
@@ -1,11 +1,51 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { usePageContent } from "@/hooks/usePageContent";
|
import { usePageContent } from "@/hooks/usePageContent";
|
||||||
|
|
||||||
|
type PortfolioProject = {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
category: string;
|
||||||
|
coverImage: string | null;
|
||||||
|
galleryImages: string[];
|
||||||
|
status: string;
|
||||||
|
createdAt?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type FallbackProject = {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
category: string;
|
||||||
|
image: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const FALLBACK_PROJECTS: FallbackProject[] = [
|
||||||
|
{
|
||||||
|
id: "fallback-1",
|
||||||
|
title: "Projeto de Adequação - Coca-Cola",
|
||||||
|
category: "Engenharia Veicular",
|
||||||
|
image: "https://images.unsplash.com/photo-1616401784845-180882ba9ba8?q=80&w=2070&auto=format&fit=crop",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "fallback-2",
|
||||||
|
title: "Laudo de Guindaste Articulado",
|
||||||
|
category: "Inspeção Técnica",
|
||||||
|
image: "https://images.unsplash.com/photo-1581092335397-9583eb92d232?q=80&w=2070&auto=format&fit=crop",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "fallback-3",
|
||||||
|
title: "Dispositivo de Içamento Especial",
|
||||||
|
category: "Projeto Mecânico",
|
||||||
|
image: "https://images.unsplash.com/photo-1504917595217-d4dc5ebe6122?q=80&w=2070&auto=format&fit=crop",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
// Português é o idioma padrão - busca diretamente sem tradução
|
// Português é o idioma padrão - busca diretamente sem tradução
|
||||||
const { content, loading } = usePageContent('home', 'pt');
|
const { content, loading } = usePageContent('home', 'pt');
|
||||||
|
const [latestProjects, setLatestProjects] = useState<PortfolioProject[]>([]);
|
||||||
|
|
||||||
// Usar conteúdo do banco ou fallback
|
// Usar conteúdo do banco ou fallback
|
||||||
const hero = content?.hero || {
|
const hero = content?.hero || {
|
||||||
@@ -68,6 +108,52 @@ export default function Home() {
|
|||||||
button: 'Fale Conosco'
|
button: 'Fale Conosco'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let isMounted = true;
|
||||||
|
const controller = new AbortController();
|
||||||
|
|
||||||
|
const fetchProjects = async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/projects', {
|
||||||
|
method: 'GET',
|
||||||
|
cache: 'no-store',
|
||||||
|
credentials: 'same-origin',
|
||||||
|
signal: controller.signal,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Falha ao buscar projetos recentes (status ${response.status})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (isMounted && Array.isArray(data)) {
|
||||||
|
const published = data
|
||||||
|
.filter((project: PortfolioProject) => project.status !== 'Rascunho')
|
||||||
|
.sort((a, b) => {
|
||||||
|
const dateA = a.createdAt ? new Date(a.createdAt).getTime() : 0;
|
||||||
|
const dateB = b.createdAt ? new Date(b.createdAt).getTime() : 0;
|
||||||
|
return dateB - dateA;
|
||||||
|
})
|
||||||
|
.slice(0, 3);
|
||||||
|
|
||||||
|
setLatestProjects(published);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
if ((err as Error).name !== 'AbortError') {
|
||||||
|
console.error('Erro ao buscar projetos recentes:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchProjects();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
isMounted = false;
|
||||||
|
controller.abort();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="bg-white dark:bg-secondary transition-colors duration-300">
|
<main className="bg-white dark:bg-secondary transition-colors duration-300">
|
||||||
{/* Hero Section */}
|
{/* Hero Section */}
|
||||||
@@ -192,16 +278,20 @@ export default function Home() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||||
{[
|
{(latestProjects.length > 0
|
||||||
{ img: "https://images.unsplash.com/photo-1616401784845-180882ba9ba8?q=80&w=2070&auto=format&fit=crop", title: "Projeto de Adequação - Coca-Cola", cat: "Engenharia Veicular" },
|
? latestProjects.map((project) => ({
|
||||||
{ img: "https://images.unsplash.com/photo-1581092335397-9583eb92d232?q=80&w=2070&auto=format&fit=crop", title: "Laudo de Guindaste Articulado", cat: "Inspeção Técnica" },
|
id: project.id,
|
||||||
{ img: "https://images.unsplash.com/photo-1504917595217-d4dc5ebe6122?q=80&w=2070&auto=format&fit=crop", title: "Dispositivo de Içamento Especial", cat: "Projeto Mecânico" }
|
title: project.title,
|
||||||
].map((project, index) => (
|
category: project.category,
|
||||||
<div key={index} className="group relative overflow-hidden rounded-xl h-[400px] cursor-pointer">
|
image: project.coverImage || project.galleryImages?.[0] || FALLBACK_PROJECTS[0].image,
|
||||||
<div className="absolute inset-0 bg-cover bg-center transition-transform duration-500 group-hover:scale-110" style={{ backgroundImage: `url('${project.img}')` }}></div>
|
}))
|
||||||
|
: FALLBACK_PROJECTS
|
||||||
|
).map((project) => (
|
||||||
|
<div key={project.id} className="group relative overflow-hidden rounded-xl h-[400px] cursor-pointer">
|
||||||
|
<div className="absolute inset-0 bg-cover bg-center transition-transform duration-500 group-hover:scale-110" style={{ backgroundImage: `url('${project.image}')` }}></div>
|
||||||
<div className="absolute inset-0 bg-linear-to-t from-black/90 via-black/20 to-transparent opacity-80 group-hover:opacity-90 transition-opacity"></div>
|
<div className="absolute inset-0 bg-linear-to-t from-black/90 via-black/20 to-transparent opacity-80 group-hover:opacity-90 transition-opacity"></div>
|
||||||
<div className="absolute bottom-0 left-0 p-8 w-full transform translate-y-4 group-hover:translate-y-0 transition-transform">
|
<div className="absolute bottom-0 left-0 p-8 w-full transform translate-y-4 group-hover:translate-y-0 transition-transform">
|
||||||
<span className="text-primary font-bold text-sm uppercase tracking-wider mb-2 block">{project.cat}</span>
|
<span className="text-primary font-bold text-sm uppercase tracking-wider mb-2 block">{project.category}</span>
|
||||||
<h3 className="text-2xl font-bold font-headline text-white mb-2">{project.title}</h3>
|
<h3 className="text-2xl font-bold font-headline text-white mb-2">{project.title}</h3>
|
||||||
<div className="h-0 group-hover:h-auto overflow-hidden transition-all">
|
<div className="h-0 group-hover:h-auto overflow-hidden transition-all">
|
||||||
<span className="text-white/80 text-sm flex items-center gap-2 mt-4">
|
<span className="text-white/80 text-sm flex items-center gap-2 mt-4">
|
||||||
|
|||||||
Reference in New Issue
Block a user