Files
klz-cables.com/lib/products.ts
Marc Mintel 3cbb4ba700
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 8s
Build & Deploy / 🧪 QA (push) Successful in 52s
Build & Deploy / 🏗️ Build (push) Successful in 1m58s
Build & Deploy / 🚀 Deploy (push) Failing after 14s
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 1s
fix(mdx): resolve React-PDF SVG typings and next-mdx-remote parsing issues for pages/products
2026-06-09 19:21:22 +02:00

118 lines
3.4 KiB
TypeScript

import fs from 'fs/promises';
import path from 'path';
import matter from 'gray-matter';
import { config } from '@/lib/config';
export interface ProductFrontmatter {
title: string;
sku: string;
description: string;
categories: string[];
images: string[];
focalX?: number;
focalY?: number;
isFallback?: boolean;
}
export interface ProductData {
slug: string;
frontmatter: ProductFrontmatter;
content: any; // Lexical AST from Payload
application?: any; // Lexical AST for Application field
}
export async function getProductMetadata(
slug: string,
locale: string,
): Promise<Partial<ProductData> | null> {
const p = await getProductBySlug(slug, locale);
if (!p) return null;
return {
slug: p.slug,
frontmatter: p.frontmatter,
};
}
export async function getProductBySlug(slug: string, locale: string): Promise<ProductData | null> {
try {
const filePath = path.join(process.cwd(), 'content', 'products', `${slug}.mdx`);
const fileContent = await fs.readFile(filePath, 'utf-8');
const { data, content } = matter(fileContent);
// Fix MDX data props dropped by next-mdx-remote
// Payload serializes as data={{"items":...}} which Acorn treats as a Block statement.
const fixedContent = content.replace(/data=\{\{([\s\S]*?)\}\}/g, (match, p1) => {
return 'data="{' + p1.replace(/"/g, '&quot;') + '}"';
});
let parsedContent = fixedContent;
try {
if (content.trim().startsWith('{')) {
parsedContent = JSON.parse(content);
}
} catch (e) {
// Not JSON
}
// Filter images
const resolvedImages = ((data.images as any[]) || [])
.map((img) => (typeof img === 'string' ? img : img?.url))
.filter(Boolean);
if (resolvedImages.length === 0) return null;
return {
slug,
frontmatter: {
title: data.title || '',
sku: data.sku || '',
description: data.description || '',
categories: Array.isArray(data.categories)
? data.categories.map((c: any) => c?.category || c)
: [],
images: resolvedImages,
focalX: data.focalX || 50,
focalY: data.focalY || 50,
},
content: parsedContent,
application: data.application,
};
} catch (error) {
console.error(`getProductBySlug failed for ${slug}:`, error);
return null;
}
}
export async function getAllProductSlugs(locale: string): Promise<string[]> {
try {
const dir = path.join(process.cwd(), 'content', 'products');
const files = await fs.readdir(dir);
return files.filter((f) => f.endsWith('.mdx')).map((f) => f.replace('.mdx', ''));
} catch (error) {
console.error(`getAllProductSlugs failed for ${locale}:`, error);
return [];
}
}
export async function getAllProducts(locale: string): Promise<ProductData[]> {
try {
const slugs = await getAllProductSlugs(locale);
const products = await Promise.all(slugs.map((slug) => getProductBySlug(slug, locale)));
return products.filter(
(p): p is ProductData =>
p !== null && p.frontmatter.images && p.frontmatter.images.length > 0,
);
} catch (error) {
console.error(`getAllProducts failed for ${locale}:`, error);
return [];
}
}
export async function getAllProductsMetadata(locale: string): Promise<Partial<ProductData>[]> {
const products = await getAllProducts(locale);
return products.map((p) => ({
slug: p.slug,
frontmatter: p.frontmatter,
}));
}