"use client";
import { motion, AnimatePresence } from "framer-motion";
import { X, MapPin, Calendar, Leaf, CheckCircle2, Factory, Presentation, Image as ImageIcon } from "lucide-react";
import Image from "next/image";
import { useEffect, useState } from "react";
import { useTranslations } from "next-intl";
export interface CaseStudyData {
id: string;
title: string;
location: string;
nodeType: string;
application: string;
stats: string;
mediaFileName?: string | null;
projectOverview?: string | null;
energySavings?: string | null;
galleryJson?: string | null;
eventDate?: string | null;
}
interface ModalProps {
isOpen: boolean;
onClose: () => void;
data: CaseStudyData | null;
}
function nodeToSlug(title: string): string {
return title.toLowerCase().trim().replace(/[^\w\s-]/g, '').replace(/[\s_-]+/g, '-').replace(/^-+|-+$/g, '');
}
const renderMarkdown = (text: string) => {
if (!text) return null;
const lines = text.split('\n');
const elements: React.ReactNode[] = [];
let listItems: React.ReactNode[] = [];
let isOrderedList = false;
let inTable = false;
let tableHeaders: string[] = [];
let tableRows: string[][] = [];
const pushTable = () => {
if (inTable) {
elements.push(
{tableHeaders.map((th, i) => (
|
{parseInline(th)}
|
))}
{tableRows.map((row, rIdx) => (
{row.map((cell, cIdx) => (
|
{parseInline(cell)}
|
))}
))}
);
inTable = false;
tableHeaders = [];
tableRows = [];
}
};
const pushList = () => {
if (listItems.length > 0) {
elements.push(
isOrderedList ? (
{listItems}
) : (
)
);
listItems = [];
}
};
const parseInline = (str: string) => {
const boldRegex = /\*\*(.*?)\*\*/g;
const italicRegex = /\*(.*?)\*/g;
let parts = str.split(boldRegex);
return parts.map((part, i) => {
if (i % 2 === 1) return {part};
let subParts = part.split(italicRegex);
return subParts.map((subPart, j) => {
if (j % 2 === 1) return {subPart};
return subPart;
});
});
};
lines.forEach((line, idx) => {
const trimmed = line.trim();
if (!trimmed) {
pushList(); pushTable();
return;
}
if (trimmed.startsWith('|') && trimmed.endsWith('|')) {
pushList();
const cells = trimmed.split('|').filter((_, i, arr) => i !== 0 && i !== arr.length - 1).map(c => c.trim());
if (!inTable) { inTable = true; tableHeaders = cells; }
else if (cells.every(c => c.match(/^[-:]+$/))) { }
else { tableRows.push(cells); }
return;
} else {
pushTable();
}
const imgMatch = trimmed.match(/^!\[(.*?)\]\((.*?)\)$/);
if (imgMatch) {
pushList(); pushTable();
elements.push(
);
return;
}
const h3Match = trimmed.match(/^###\s*(.*)/);
if (h3Match) { pushList(); pushTable(); elements.push({parseInline(h3Match[1])}
); return; }
const h2Match = trimmed.match(/^##\s*(.*)/);
if (h2Match) { pushList(); pushTable(); elements.push({parseInline(h2Match[1])}
); return; }
const h1Match = trimmed.match(/^#\s*(.*)/);
if (h1Match) { pushList(); pushTable(); elements.push({parseInline(h1Match[1])}
); return; }
const quoteMatch = trimmed.match(/^>\s*(.*)/);
if (quoteMatch) {
pushList(); pushTable();
elements.push(
{parseInline(quoteMatch[1])}
);
return;
}
const ulMatch = trimmed.match(/^[-*]\s+(.*)/);
if (ulMatch) { isOrderedList = false; listItems.push({parseInline(ulMatch[1])}); return; }
const olMatch = trimmed.match(/^\d+\.\s*(.*)/);
if (olMatch) { isOrderedList = true; listItems.push({parseInline(olMatch[1])}); return; }
pushList();
elements.push({parseInline(trimmed)}
);
});
pushList();
pushTable();
return <>{elements}>;
};
export default function CaseStudyModal({ isOpen, onClose, data }: ModalProps) {
const [gallery, setGallery] = useState([]);
const t = useTranslations("CaseStudyModal");
useEffect(() => {
if (isOpen) document.body.style.overflow = "hidden";
else document.body.style.overflow = "unset";
return () => { document.body.style.overflow = "unset"; };
}, [isOpen]);
useEffect(() => {
if (data?.galleryJson) {
try {
setGallery(JSON.parse(data.galleryJson));
} catch (e) {
setGallery([]);
}
} else {
setGallery([]);
}
}, [data]);
if (!data) return null;
const isEvent = data.nodeType === "event";
const isHQ = data.nodeType === "hq";
const nodeSlug = nodeToSlug(data.title);
const coverImage = data.mediaFileName ? `/cases/${nodeSlug}/${data.mediaFileName}` : null;
let formattedDate = null;
let isUpcoming = false;
if (data.eventDate) {
const eventD = new Date(data.eventDate);
formattedDate = eventD.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
isUpcoming = eventD > new Date();
}
return (
{isOpen && (
{coverImage ? (
) : (
)}
{isEvent ?
: isHQ ?
:
}
{isEvent ? t("typeEvent") : isHQ ? t("typeHQ") : t("typeInstall")}
{data.application.replace("-", " ")}
{data.title}
{data.location}
{formattedDate && (
{formattedDate} {isUpcoming && "(Upcoming)"}
)}
{isEvent ? t("keyHighlight") : t("keyMetric")}
{data.stats}
{data.energySavings && (
{isEvent ? : }
{isEvent ? t("locationStand") : t("energyImpact")}
{data.energySavings}
)}
{t("systemStatus")}
{/* š„ AQUĆ ESTABA EL ERROR: Simplificamos la lógica š„ */}
{isEvent ? (isUpcoming ? t("scheduled") : t("concluded")) : t("operational")}
{data.projectOverview ? (
{isEvent ? t("eventOverview") : t("projectChronicle")}
{renderMarkdown(data.projectOverview)}
) : (
)}
{gallery.length > 0 && (
{t("mediaGallery")}
{gallery.map((imgSrc, idx) => (
))}
)}
)}
);
}