112 lines
3.1 KiB
TypeScript
112 lines
3.1 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);
|
|
|
|
let parsedContent = content;
|
|
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,
|
|
}));
|
|
}
|