"use client";
import Image from "next/image";
import React, { useEffect, useState } from "react";
export type EditorJsBlock = {
id: string;
type: string;
data: {
text?: string;
level?: number;
style?: "ordered" | "unordered";
items?: string[];
};
};
type DealerItem = {
image: string;
url: string;
description: string;
title: string;
};
// Helper function to decode HTML entities
function decodeHtmlEntities(text: string): string {
const textarea =
typeof document !== "undefined" ? document.createElement("textarea") : null;
if (textarea) {
textarea.innerHTML = text;
return textarea.value;
}
// Fallback for server-side rendering
return text
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/&/g, "&")
.replace(/"/g, '"')
.replace(/'/g, "'")
.replace(/ /g, " ");
}
// Helper function to check if text contains HTML table elements
function isTableFragment(text: string): boolean {
const tablePatterns = [
/
/i,
//i,
//i,
//i,
/| /i,
/ | /i,
//i,
/ pattern.test(text));
}
// Helper function to parse table HTML and extract dealer data
function parseTableToDealers(html: string): DealerItem[] {
if (typeof document === "undefined") return [];
const parser = new DOMParser();
const doc = parser.parseFromString(html, "text/html");
const rows = doc.querySelectorAll("tr");
const dealers: DealerItem[] = [];
rows.forEach((row) => {
const cells = row.querySelectorAll("td");
if (cells.length >= 2) {
const firstCell = cells[0];
const secondCell = cells[1];
const thirdCell = cells[2];
// Extract image
const img = firstCell.querySelector("img");
const imgSrc = img?.getAttribute("src") || "";
// Extract URL and description from second cell
const link = secondCell.querySelector("a");
const url = link?.getAttribute("href") || "";
const description = secondCell.textContent?.trim() || "";
const title = thirdCell?.textContent?.trim() || "";
if (imgSrc && url) {
dealers.push({
image: imgSrc,
url: url,
description: description,
title: title,
});
}
}
});
return dealers;
}
// Helper function to merge table fragments
function mergeTableBlocks(blocks: EditorJsBlock[]): EditorJsBlock[] {
const merged: EditorJsBlock[] = [];
let tableBuffer: string[] = [];
let tableStartId: string | null = null;
let isInTable = false;
for (let i = 0; i < blocks.length; i++) {
const block = blocks[i];
const text = block.data?.text || "";
const decodedText = decodeHtmlEntities(text);
// Check if this starts a table
if (/ tags and preserve whitespace
const cleanedText = decodedText
.replace(/ /gi, "")
.replace(/^\s+|\s+$/g, "");
if (cleanedText) {
tableBuffer.push(cleanedText);
}
// Check if this closes the table
if (/<\/table>/i.test(decodedText)) {
isInTable = false;
// Create merged table block
const mergedHTML = tableBuffer.join("");
merged.push({
id: tableStartId || block.id,
type: "table",
data: {
text: mergedHTML,
},
});
tableBuffer = [];
tableStartId = null;
}
} else {
// If we have accumulated table content, create a merged block
if (tableBuffer.length > 0 && tableStartId) {
const mergedHTML = tableBuffer.join("");
merged.push({
id: tableStartId,
type: "table",
data: {
text: mergedHTML,
},
});
tableBuffer = [];
tableStartId = null;
isInTable = false;
}
// Add the non-table block
merged.push(block);
}
}
// Handle any remaining table content
if (tableBuffer.length > 0 && tableStartId) {
const mergedHTML = tableBuffer.join("");
merged.push({
id: tableStartId,
type: "table",
data: {
text: mergedHTML,
},
});
}
return merged;
}
function DealersList({ blockId, html }: { blockId: string; html: string }) {
const [dealers, setDealers] = useState([]);
useEffect(() => {
const parsedDealers = parseTableToDealers(html);
setDealers(parsedDealers);
}, [html]);
if (dealers.length === 0) {
return null;
}
return (
{dealers.map((dealer, index) => (
{/* Image Container - Fixed size */}
{/* Content Container */}
))}
);
}
export default function OnlineDealersRenderer({
content,
}: {
content: string | null | undefined;
}) {
let blocks: EditorJsBlock[] = [];
if (content) {
try {
const parsed = JSON.parse(content);
if (Array.isArray(parsed?.blocks)) {
blocks = parsed.blocks as EditorJsBlock[];
}
} catch (_) {}
}
if (!blocks.length) {
return (
Data Not available
);
}
// Merge table fragments before rendering
const mergedBlocks = mergeTableBlocks(blocks);
const renderBlock = (block: EditorJsBlock) => {
const { type, data } = block;
const html = decodeHtmlEntities(data?.text || "");
switch (type) {
case "table":
return (
);
case "header": {
const level = Math.min(Math.max(Number(data?.level) || 3, 1), 6);
return React.createElement(`h${level}`, {
key: block.id,
className: "text-2xl font-semibold leading-8 tracking-[-0.06px] my-6",
dangerouslySetInnerHTML: { __html: html },
});
}
case "list": {
const style = data?.style || "unordered";
const items = Array.isArray(data?.items) ? data.items : [];
const ListTag = style === "ordered" ? "ol" : "ul";
const listClassName =
style === "ordered"
? "list-none my-4 space-y-2 text-lg leading-7 tracking-[-0.045px]"
: "list-none my-4 space-y-2 text-lg leading-7 tracking-[-0.045px]";
return (
{items.map((item, idx) => (
))}
);
}
case "paragraph":
default:
// Check if this paragraph contains table HTML that wasn't merged
if (isTableFragment(html)) {
return ;
}
return (
);
}
};
return (
<>
{mergedBlocks.map(renderBlock)}
>
);
}
|