mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 15:31:13 -05:00
116 lines
3.0 KiB
TypeScript
116 lines
3.0 KiB
TypeScript
/**
|
|
* Photo Helpers
|
|
* Utilities for normalizing and validating photo data from different sources
|
|
*/
|
|
|
|
import type { PhotoItem, NormalizedPhoto, PhotoDataSource } from '@/types/photos';
|
|
import type { PhotoSubmissionItem } from '@/types/photo-submissions';
|
|
|
|
/**
|
|
* Type guard: Check if data is a photo submission item
|
|
*/
|
|
export function isPhotoSubmissionItem(data: any): data is PhotoSubmissionItem {
|
|
return (
|
|
data &&
|
|
typeof data === 'object' &&
|
|
'cloudflare_image_id' in data &&
|
|
'cloudflare_image_url' in data &&
|
|
'order_index' in data
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Type guard: Check if content is a review with photos
|
|
*/
|
|
export function isReviewWithPhotos(content: any): boolean {
|
|
return (
|
|
content &&
|
|
typeof content === 'object' &&
|
|
Array.isArray(content.photos) &&
|
|
content.photos.length > 0 &&
|
|
content.photos[0]?.url
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
* Normalize photo data from any source to PhotoItem[]
|
|
*/
|
|
export function normalizePhotoData(source: PhotoDataSource): PhotoItem[] {
|
|
switch (source.type) {
|
|
case 'review':
|
|
return source.photos.map((photo, index) => ({
|
|
id: `review-${index}`,
|
|
url: photo.url,
|
|
filename: photo.filename || `Review photo ${index + 1}`,
|
|
caption: photo.caption,
|
|
size: photo.size,
|
|
type: photo.type,
|
|
}));
|
|
|
|
case 'submission_jsonb':
|
|
return source.photos.map((photo, index) => ({
|
|
id: `jsonb-${index}`,
|
|
url: photo.url,
|
|
filename: photo.filename || `Photo ${index + 1}`,
|
|
caption: photo.caption,
|
|
title: photo.title,
|
|
size: photo.size,
|
|
type: photo.type,
|
|
}));
|
|
|
|
case 'submission_items':
|
|
return source.items.map((item) => ({
|
|
id: item.id,
|
|
url: item.cloudflare_image_url,
|
|
filename: item.filename || `Photo ${item.order_index + 1}`,
|
|
caption: item.caption,
|
|
title: item.title,
|
|
date_taken: item.date_taken,
|
|
}));
|
|
|
|
default:
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convert PhotoSubmissionItem[] to NormalizedPhoto[]
|
|
*/
|
|
export function normalizePhotoSubmissionItems(
|
|
items: PhotoSubmissionItem[]
|
|
): NormalizedPhoto[] {
|
|
return items.map((item) => ({
|
|
id: item.id,
|
|
url: item.cloudflare_image_url,
|
|
filename: item.filename || `Photo ${item.order_index + 1}`,
|
|
caption: item.caption || undefined,
|
|
title: item.title || undefined,
|
|
date_taken: item.date_taken || undefined,
|
|
order_index: item.order_index,
|
|
}));
|
|
}
|
|
|
|
/**
|
|
* Validate photo URL is from Cloudflare Images
|
|
* Supports both old imagedelivery.net and new CDN URLs
|
|
*/
|
|
export function isValidCloudflareUrl(url: string): boolean {
|
|
try {
|
|
const urlObj = new URL(url);
|
|
return urlObj.hostname.includes('imagedelivery.net') ||
|
|
urlObj.hostname === 'cdn.thrillwiki.com';
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate photo alt text from available metadata
|
|
*/
|
|
export function generatePhotoAlt(photo: PhotoItem | NormalizedPhoto): string {
|
|
if (photo.title) return photo.title;
|
|
if (photo.caption) return photo.caption;
|
|
return photo.filename || 'Photo';
|
|
}
|