Files
klz-cables.com/lib/data.ts
2026-01-13 19:25:39 +01:00

353 lines
9.9 KiB
TypeScript

/**
* Data utilities for Next.js WordPress migration
*/
import wordpressData from '../data/processed/wordpress-data.json';
import { getExcelTechnicalDataForProduct } from './excel-products';
export interface SiteInfo {
title: string;
description: string;
baseUrl: string;
defaultLocale: string;
locales: string[];
}
export interface TranslationReference {
locale: string;
id: number;
}
export interface Page {
id: number;
translationKey: string;
locale: string;
slug: string;
path: string;
title: string;
titleHtml: string;
contentHtml: string;
excerptHtml: string;
featuredImage: number | null;
updatedAt: string;
translation: TranslationReference | null;
}
export interface Post {
id: number;
translationKey: string;
locale: string;
slug: string;
path: string;
title: string;
titleHtml: string;
contentHtml: string;
excerptHtml: string;
featuredImage: number | null;
datePublished: string;
updatedAt: string;
translation: TranslationReference | null;
}
export interface Product {
id: number;
translationKey: string;
locale: string;
slug: string;
path: string;
name: string;
shortDescriptionHtml: string;
descriptionHtml: string;
images: string[];
featuredImage: string | null;
sku: string;
regularPrice: string;
salePrice: string;
currency: string;
stockStatus: string;
categories: Array<{ id: number; name: string; slug: string }>;
attributes: any[];
variations: any[];
updatedAt: string;
translation: TranslationReference | null;
// Excel-derived technical data
excelConfigurations?: string[];
excelAttributes?: Array<{
name: string;
options: string[];
}>;
}
export interface ProductCategory {
id: number;
translationKey: string;
locale: string;
slug: string;
name: string;
path: string;
description: string;
count: number;
translation: TranslationReference | null;
}
export interface Media {
id: number;
filename: string;
url: string;
localPath: string;
alt: string;
width: number | null;
height: number | null;
mimeType: string | null;
}
export interface Redirect {
source: string;
destination: string;
permanent: boolean;
locale: string;
}
export interface WordPressData {
site: SiteInfo;
content: {
pages: Page[];
posts: Post[];
products: Product[];
categories: ProductCategory[];
};
assets: {
media: Media[];
map: Record<string, string>;
};
redirects: Redirect[];
exportDate: string;
}
// Load data
// Use type assertion to handle the JSON import properly
const data = wordpressData as unknown as WordPressData;
// Data access functions
export const getSiteInfo = (): SiteInfo => data.site;
export const getAllPages = (): Page[] => data.content.pages;
export const getAllPosts = (): Post[] => data.content.posts;
export const getAllProducts = (): Product[] => data.content.products;
export const getAllCategories = (): ProductCategory[] => data.content.categories;
export const getMediaById = (id: number): Media | undefined => {
return data.assets.media.find(m => m.id === id);
};
export const getMediaByUrl = (url: string): Media | undefined => {
const localPath = data.assets.map[url];
if (!localPath) return undefined;
return data.assets.media.find(m => m.localPath === localPath);
};
export const getAssetMap = (): Record<string, string> => {
return data.assets?.map || {};
};
export const getRedirects = (): Redirect[] => data.redirects;
// Locale-specific queries
export const getPagesByLocale = (locale: string): Page[] => {
return data.content.pages.filter(p => p.locale === locale);
};
export const getPostsByLocale = (locale: string): Post[] => {
return data.content.posts.filter(p => p.locale === locale);
};
export const getProductsByLocale = (locale: string): Product[] => {
return data.content.products.filter(p => p.locale === locale);
};
export const getCategoriesByLocale = (locale: string): ProductCategory[] => {
return data.content.categories.filter(c => c.locale === locale);
};
// Single item queries
export const getPageBySlug = (slug: string, locale: string): Page | undefined => {
return data.content.pages.find(p => p.slug === slug && p.locale === locale);
};
export const getPostBySlug = (slug: string, locale: string): Post | undefined => {
return data.content.posts.find(p => p.slug === slug && p.locale === locale);
};
export const getProductBySlug = (slug: string, locale: string): Product | undefined => {
return data.content.products.find(p => p.slug === slug && p.locale === locale);
};
export const getCategoryBySlug = (slug: string, locale: string): ProductCategory | undefined => {
return data.content.categories.find(c => c.slug === slug && c.locale === locale);
};
// Translation helpers
export const getTranslation = <T extends { translationKey: string; locale: string }>(
item: T,
targetLocale: string
): T | undefined => {
const collection = [
...getAllPages(),
...getAllPosts(),
...getAllProducts(),
...getAllCategories()
];
const result = collection.find(
(i: any) => i.translationKey === item.translationKey && i.locale === targetLocale
);
return result as unknown as T | undefined;
};
// Asset URL replacement
export const replaceAssetUrls = (html: string): string => {
let result = html;
Object.entries(data.assets.map).forEach(([wpUrl, localPath]) => {
result = result.replace(new RegExp(wpUrl, 'g'), localPath);
});
return result;
};
// Additional functions for product categories
export const getProductCategory = (slug: string, locale: string): ProductCategory | undefined => {
return data.content.categories.find(c => c.slug === slug && c.locale === locale);
};
export const getProductsByCategory = (categoryId: number, locale: string): Product[] => {
return data.content.products.filter(p =>
p.locale === locale && p.categories.some(c => c.id === categoryId)
);
};
// Get products by category slug
export const getProductsByCategorySlug = (categorySlug: string, locale: string): Product[] => {
const category = getCategoryBySlug(categorySlug, locale);
if (!category) return [];
return getProductsByCategory(category.id, locale);
};
// Get related products (same category, excluding current product)
export const getRelatedProducts = (product: Product, locale: string, limit: number = 4): Product[] => {
if (product.categories.length === 0) return [];
// Get first category
const firstCategory = product.categories[0];
const categoryProducts = getProductsByCategory(firstCategory.id, locale);
// Filter out current product and limit results
return categoryProducts
.filter(p => p.id !== product.id)
.slice(0, limit);
};
// Get categories by slugs
export const getCategoriesBySlugs = (slugs: string[], locale: string): ProductCategory[] => {
return data.content.categories.filter(c =>
slugs.includes(c.slug) && c.locale === locale
);
};
// Locale-specific queries for static generation
export const getAllCategorySlugsForLocale = (locale: string): string[] => {
return [...new Set(data.content.categories.filter(c => c.locale === locale).map(c => c.slug))];
};
export const getAllPageSlugsForLocale = (locale: string): string[] => {
return [...new Set(data.content.pages.filter(p => p.locale === locale).map(p => p.slug))];
};
export const getAllPostSlugsForLocale = (locale: string): string[] => {
return [...new Set(data.content.posts.filter(p => p.locale === locale).map(p => p.slug))];
};
export const getAllProductSlugsForLocale = (locale: string): string[] => {
return [...new Set(data.content.products.filter(p => p.locale === locale).map(p => p.slug))];
};
// Get items for locale
export const getCategoriesForLocale = (locale: string): ProductCategory[] => {
return data.content.categories.filter(c => c.locale === locale);
};
export const getPagesForLocale = (locale: string): Page[] => {
return data.content.pages.filter(p => p.locale === locale);
};
export const getPostsForLocale = (locale: string): Post[] => {
return data.content.posts.filter(p => p.locale === locale);
};
export const getProductsForLocale = (locale: string): Product[] => {
return data.content.products.filter(p => p.locale === locale);
};
/**
* Enrich a product with Excel-derived technical data
* This function merges Excel data into the product's attributes
*/
export function enrichProductWithExcelData(product: Product): Product {
// Skip if already enriched
if (product.excelConfigurations || product.excelAttributes) {
return product;
}
const excelData = getExcelTechnicalDataForProduct({
name: product.name,
slug: product.slug,
sku: product.sku,
translationKey: product.translationKey,
});
if (!excelData) {
return product;
}
// Create a copy of the product with Excel data
const enrichedProduct: Product = {
...product,
excelConfigurations: excelData.configurations,
excelAttributes: excelData.attributes,
};
return enrichedProduct;
}
/**
* Get a single product by slug with Excel enrichment
*/
export function getProductBySlugWithExcel(slug: string, locale: string): Product | undefined {
const product = getProductBySlug(slug, locale);
if (!product) return undefined;
return enrichProductWithExcelData(product);
}
/**
* Get all products for a locale with Excel enrichment
*/
export function getProductsForLocaleWithExcel(locale: string): Product[] {
const products = getProductsForLocale(locale);
return products.map(p => enrichProductWithExcelData(p));
}
/**
* Get products by category with Excel enrichment
*/
export function getProductsByCategoryWithExcel(categoryId: number, locale: string): Product[] {
const products = getProductsByCategory(categoryId, locale);
return products.map(p => enrichProductWithExcelData(p));
}
/**
* Get products by category slug with Excel enrichment
*/
export function getProductsByCategorySlugWithExcel(categorySlug: string, locale: string): Product[] {
const products = getProductsByCategorySlug(categorySlug, locale);
return products.map(p => enrichProductWithExcelData(p));
}