Files
ACVE/app/(public)/page.tsx
2026-03-15 13:52:11 +00:00

298 lines
13 KiB
TypeScript
Executable File

import Link from "next/link";
import { cn } from "@/lib/utils";
import { db } from "@/lib/prisma";
type ProgramCard = {
title: string;
description: string;
status: string;
href: string;
visualClass: string;
};
const fallbackPrograms: ProgramCard[] = [
{
title: "Introducción al Inglés Legal",
description:
"Una introducción estructurada al lenguaje jurídico en inglés para comprender y utilizar terminología clave con seguridad profesional.",
status: "Cohorte abierta",
href: "/courses",
visualClass: "from-[#ead9cb] via-[#f7ece3] to-[#fef8f2]",
},
{
title: "Common vs Civil Law",
description:
"Explora los dos sistemas jurídicos predominantes del mundo y aprende su lógica, diferencias y vocabulario aplicado a contextos internacionales.",
status: "Próximamente",
href: "/courses",
visualClass: "from-[#e4d4dd] via-[#f3e7ed] to-[#fff7fb]",
},
{
title: "Fundamentos de la Traducción Jurídica",
description:
"Aprende los fundamentos de la equivalencia jurídica entre distintos sistemas legales para traducir con claridad, rigor y contexto.",
status: "Próximamente",
href: "/courses",
visualClass: "from-[#e9ddd0] via-[#f7eee5] to-[#fefaf4]",
},
];
const events = [
{ title: "Networking virtual", date: "24", month: "MAR", mode: "Online", note: "Próximamente..." },
{ title: "Webinar", date: "03", month: "ABR", mode: "Streaming", note: "Próximamente..." },
{ title: "Sesión Q&A", date: "17", month: "ABR", mode: "En vivo", note: "Próximamente..." },
{ title: "Taller presencial", date: "09", month: "MAY", mode: "Monterrey", note: "Próximamente..." },
];
const caseStudies = [
{
title: "Miranda v. Arizona",
year: "1966",
summary:
"Caso central en derecho penal del que surgen los Miranda rights. Ideal para trabajar vocabulario procesal, derechos constitucionales y lenguaje judicial.",
},
{
title: "Marbury v. Madison",
year: "1803",
summary:
"Caso fundacional que establece el judicial review en Estados Unidos y permite comprender cómo opera el control constitucional del poder público.",
},
{
title: "Brown v. Board of Education",
year: "1954",
summary:
"Decisión emblemática en materia de derechos civiles que declaró inconstitucional la segregación racial en escuelas públicas.",
},
];
const challenges = [
{
title: "Desafío de traducción",
description: "Resuelve una traducción jurídica breve con foco en precisión terminológica y estilo profesional.",
href: "/practice",
},
{
title: "Reto de términos legales",
description: "Pon a prueba tu dominio de conceptos clave con ejercicios de uso contextual y equivalencia funcional.",
href: "/practice",
},
{
title: "Ejercicio de cláusulas",
description: "Analiza cláusulas reales y mejora tu capacidad de redacción y negociación en inglés jurídico.",
href: "/practice",
},
];
const visualPresets = [
"from-[#ead9cb] via-[#f7ece3] to-[#fef8f2]",
"from-[#e4d4dd] via-[#f3e7ed] to-[#fff7fb]",
"from-[#e9ddd0] via-[#f7eee5] to-[#fefaf4]",
"from-[#dfe4f1] via-[#ecf0f7] to-[#f8f9fd]",
"from-[#e7e1d6] via-[#f2ece4] to-[#fcfaf6]",
];
function getText(value: unknown): string {
if (!value) return "";
if (typeof value === "string") return value;
if (typeof value === "object") {
const record = value as Record<string, unknown>;
if (typeof record.es === "string") return record.es;
if (typeof record.en === "string") return record.en;
}
return "";
}
async function getAcademicCards(): Promise<ProgramCard[]> {
const publishedCourses = await db.course
.findMany({
where: { status: "PUBLISHED" },
orderBy: { updatedAt: "desc" },
take: 6,
select: {
slug: true,
title: true,
description: true,
},
})
.catch((error) => {
console.error("Failed to load featured courses for homepage.", error);
return [];
});
if (publishedCourses.length === 0) {
return fallbackPrograms;
}
return publishedCourses.map((course, index) => ({
title: getText(course.title) || "Programa académico ACVE",
description:
getText(course.description) ||
"Programa académico orientado al dominio del inglés jurídico con enfoque aplicado en contextos profesionales.",
status: "Disponible",
href: `/courses/${course.slug}`,
visualClass: visualPresets[index % visualPresets.length],
}));
}
export default async function HomePage() {
const programs = await getAcademicCards();
return (
<div className="acve-page">
<section className="acve-panel relative overflow-hidden px-6 py-10 md:px-10 md:py-14">
<div className="absolute inset-0 bg-[radial-gradient(circle_at_top_right,_rgba(152,20,63,0.18),_transparent_55%)]" />
<div className="relative">
<p className="acve-pill mb-5 w-fit text-sm">ACVE Centro de Estudios</p>
<h1 className="acve-heading max-w-4xl text-4xl leading-tight md:text-6xl">
Domina el inglés jurídico y ejerce a nivel internacional.
</h1>
<p className="mt-5 max-w-3xl text-base leading-relaxed text-muted-foreground md:text-lg">
Formación práctica para comprender, redactar y negociar documentos legales en inglés. Diseñada para abogados y estudiantes que desean
desenvolverse con solvencia en entornos académicos y profesionales globales.
</p>
<div className="mt-7 flex flex-wrap gap-3">
<Link className="acve-button-primary inline-flex items-center px-6 py-3 text-sm font-semibold hover:brightness-105" href="/courses">
Explorar programas
</Link>
<Link className="acve-button-secondary inline-flex items-center px-6 py-3 text-sm font-semibold hover:bg-accent" href="/case-studies">
Ver casos prácticos
</Link>
</div>
<div className="mt-8 grid gap-3 md:grid-cols-3">
{["Metodología aplicada", "Casos emblemáticos", "Comunidad jurídica"].map((item) => (
<div key={item} className="rounded-2xl border border-border/80 bg-card/90 px-4 py-3 text-sm font-semibold text-foreground shadow-sm">
{item}
</div>
))}
</div>
</div>
</section>
<section className="acve-panel px-6 py-8 md:px-10 md:py-10" id="formacion-academica">
<div className="max-w-3xl">
<h2 className="acve-heading text-3xl md:text-4xl">Formación Académica</h2>
<p className="mt-3 text-muted-foreground md:text-lg">
Programas impartidos por instructores de élite, con lecciones focalizadas y enfoque académico para una aplicación profesional real. Los
cursos publicados aparecen automáticamente en esta sección.
</p>
</div>
<div className="mt-8 grid gap-5 md:grid-cols-2 xl:grid-cols-3">
{programs.map((program) => (
<article key={program.title} className="rounded-2xl border border-border/80 bg-card p-4 shadow-sm">
<div className={cn("h-36 rounded-xl border border-border/70 bg-gradient-to-br p-4", program.visualClass)}>
<span className="inline-flex rounded-full border border-primary/20 bg-card/85 px-3 py-1 text-xs font-semibold text-primary">
{program.status}
</span>
</div>
<h3 className="mt-4 text-xl font-semibold text-foreground">{program.title}</h3>
<p className="mt-2 text-sm leading-relaxed text-muted-foreground">{program.description}</p>
<Link className="mt-4 inline-flex text-sm font-semibold text-primary hover:underline" href={program.href}>
Conocer más
</Link>
</article>
))}
</div>
</section>
<section className="acve-panel px-6 py-8 md:px-10 md:py-10" id="eventos">
<div className="max-w-3xl">
<h2 className="acve-heading text-3xl md:text-4xl">Próximos eventos</h2>
<p className="mt-3 text-muted-foreground md:text-lg">
Espacios para practicar inglés legal, fortalecer comunidad y mantenerte actualizado en tendencias jurídicas internacionales.
</p>
</div>
<div className="mt-7 grid gap-4 md:grid-cols-2 xl:grid-cols-4">
{events.map((event) => (
<article key={event.title} className="rounded-2xl border border-border/80 bg-card p-4 shadow-sm">
<div className="flex items-center gap-3">
<div className="rounded-xl border border-primary/20 bg-primary/10 px-2 py-2 text-center text-primary">
<p className="text-lg font-bold leading-none">{event.date}</p>
<p className="text-[11px] font-semibold tracking-wide">{event.month}</p>
</div>
<div>
<h3 className="text-base font-semibold text-foreground">{event.title}</h3>
<p className="text-xs uppercase tracking-wide text-muted-foreground">{event.mode}</p>
</div>
</div>
<p className="mt-4 text-sm text-muted-foreground">{event.note}</p>
</article>
))}
</div>
<div className="mt-6">
<Link className="acve-button-secondary inline-flex items-center px-5 py-2.5 text-sm font-semibold hover:bg-accent" href="/eventos">
Ver el calendario completo
</Link>
</div>
</section>
<section className="acve-panel px-6 py-8 md:px-10 md:py-10">
<div className="max-w-4xl">
<h2 className="acve-heading text-3xl md:text-4xl">Casos prácticos</h2>
<p className="mt-3 text-muted-foreground md:text-lg">
Pon a prueba tu nivel de inglés legal con los casos judiciales más emblemáticos de Estados Unidos y del mundo.
</p>
</div>
<div className="mt-8 grid gap-5 md:grid-cols-2 xl:grid-cols-3">
{caseStudies.map((entry) => (
<article key={entry.title} className="rounded-2xl border border-border/80 bg-card p-5 shadow-sm">
<p className="text-sm font-semibold uppercase tracking-wide text-primary">{entry.year}</p>
<h3 className="mt-1 text-xl font-semibold text-foreground">{entry.title}</h3>
<p className="mt-3 text-sm leading-relaxed text-muted-foreground">{entry.summary}</p>
<Link className="mt-4 inline-flex text-sm font-semibold text-primary hover:underline" href="/case-studies">
Read more
</Link>
</article>
))}
</div>
</section>
<section className="relative overflow-hidden rounded-3xl border border-primary/30 bg-gradient-to-r from-[#98143f] via-[#6f1737] to-[#3f1327] px-7 py-10 text-white shadow-xl md:px-10 md:py-12">
<div className="absolute inset-0 bg-[radial-gradient(circle_at_70%_30%,_rgba(255,255,255,0.24),_transparent_40%)]" />
<div className="relative max-w-3xl">
<p className="text-xs font-semibold uppercase tracking-[0.2em] text-white/80">Evento destacado</p>
<h2 className="mt-3 font-[var(--acve-heading-font)] text-3xl leading-tight md:text-4xl">Congreso Internacional de Inglés Jurídico ACVE 2026</h2>
<p className="mt-4 text-sm leading-relaxed text-white/90 md:text-base">
Una jornada intensiva con expertos en litigio, arbitraje y traducción jurídica para fortalecer tus competencias profesionales en contextos
multinacionales.
</p>
<div className="mt-6 flex flex-wrap gap-3">
<Link className="inline-flex rounded-full bg-white px-5 py-2.5 text-sm font-semibold text-[#6f1737] hover:bg-white/90" href="/auth/signup">
Reservar lugar
</Link>
<Link className="inline-flex rounded-full border border-white/50 px-5 py-2.5 text-sm font-semibold text-white hover:bg-white/10" href="/eventos">
Ver agenda preliminar
</Link>
</div>
</div>
</section>
<section className="acve-panel px-6 py-8 md:px-10 md:py-10">
<div className="max-w-3xl">
<h2 className="acve-heading text-3xl md:text-4xl">Retos</h2>
<p className="mt-3 text-muted-foreground md:text-lg">
Entrena tu precisión lingüística con ejercicios breves diseñados para el trabajo real de abogados y equipos legales bilingües.
</p>
</div>
<div className="mt-7 grid gap-4 md:grid-cols-2 xl:grid-cols-3">
{challenges.map((challenge) => (
<article key={challenge.title} className="rounded-2xl border border-border/80 bg-card p-5 shadow-sm">
<h3 className="text-xl font-semibold text-foreground">{challenge.title}</h3>
<p className="mt-3 text-sm leading-relaxed text-muted-foreground">{challenge.description}</p>
<Link className="acve-button-primary mt-5 inline-flex items-center px-5 py-2.5 text-sm font-semibold hover:brightness-105" href={challenge.href}>
Iniciar
</Link>
</article>
))}
</div>
</section>
</div>
);
}