Add PostgreSQL support with SQLite/Postgres database compatibility layer

- Add dbGet/dbAll helper functions for database-agnostic queries
- Add toDbBool/convertBooleansForDb for boolean type conversion
- Add toDbDate/getNow for timestamp type handling
- Add generateId that returns UUID for Postgres, nanoid for SQLite
- Update all routes to use compatibility helpers
- Add normalizeEvent to return clean number types from Postgres decimal
- Add formatPrice utility for consistent price display
- Add legal pages admin interface with RichTextEditor
- Update carousel images
- Add drizzle migration files for PostgreSQL
This commit is contained in:
Michilis
2026-02-02 03:46:35 +00:00
parent 9410e83b89
commit bafd1425c4
61 changed files with 5015 additions and 881 deletions

View File

@@ -16,8 +16,11 @@ export interface LegalPageMeta {
// Map file names to display titles
const titleMap: Record<string, { en: string; es: string }> = {
'privacy_policy': { en: 'Privacy Policy', es: 'Política de Privacidad' },
'privacy-policy': { en: 'Privacy Policy', es: 'Política de Privacidad' },
'terms_policy': { en: 'Terms & Conditions', es: 'Términos y Condiciones' },
'terms-policy': { en: 'Terms & Conditions', es: 'Términos y Condiciones' },
'refund_cancelation_policy': { en: 'Refund & Cancellation Policy', es: 'Política de Reembolso y Cancelación' },
'refund-cancelation-policy': { en: 'Refund & Cancellation Policy', es: 'Política de Reembolso y Cancelación' },
};
// Convert file name to URL-friendly slug
@@ -70,8 +73,8 @@ export function getAllLegalPagesMeta(locale: string = 'en'): LegalPageMeta[] {
});
}
// Get a specific legal page content
export function getLegalPage(slug: string, locale: string = 'en'): LegalPage | null {
// Get a specific legal page content from filesystem (fallback)
export function getLegalPageFromFilesystem(slug: string, locale: string = 'en'): LegalPage | null {
const legalDir = getLegalDir();
const fileName = slugToFileName(slug);
const filePath = path.join(legalDir, fileName);
@@ -82,7 +85,7 @@ export function getLegalPage(slug: string, locale: string = 'en'): LegalPage | n
const content = fs.readFileSync(filePath, 'utf-8');
const baseFileName = fileName.replace('.md', '');
const titles = titleMap[baseFileName];
const titles = titleMap[baseFileName] || titleMap[slug];
const title = titles ? titles[locale as 'en' | 'es'] || titles.en : baseFileName.replace(/_/g, ' ');
// Try to extract last updated date from content
@@ -96,3 +99,43 @@ export function getLegalPage(slug: string, locale: string = 'en'): LegalPage | n
lastUpdated,
};
}
// Get a specific legal page content - tries API first, falls back to filesystem
export async function getLegalPageAsync(slug: string, locale: string = 'en'): Promise<LegalPage | null> {
const apiUrl = process.env.NEXT_PUBLIC_API_URL || '';
// Try to fetch from API with locale parameter
try {
const response = await fetch(`${apiUrl}/api/legal-pages/${slug}?locale=${locale}`, {
next: { revalidate: 60 }, // Cache for 60 seconds
});
if (response.ok) {
const data = await response.json();
const page = data.page;
if (page) {
// Extract last updated from content or use updatedAt
const lastUpdatedMatch = page.contentMarkdown?.match(/Last updated:\s*(.+)/i);
const lastUpdated = lastUpdatedMatch ? lastUpdatedMatch[1].trim() : page.updatedAt;
return {
slug: page.slug,
title: page.title, // API already returns localized title with fallback
content: page.contentMarkdown, // API already returns localized content with fallback
lastUpdated,
};
}
}
} catch (error) {
console.warn('Failed to fetch legal page from API, falling back to filesystem:', error);
}
// Fallback to filesystem
return getLegalPageFromFilesystem(slug, locale);
}
// Legacy sync function for backwards compatibility
export function getLegalPage(slug: string, locale: string = 'en'): LegalPage | null {
return getLegalPageFromFilesystem(slug, locale);
}