import { supabase } from '@/lib/supabase'; const MAX_FILE_SIZE = 20 * 1024 * 1024; const ALLOWED_FILE_TYPES = [ 'image/jpeg', 'image/jpg', 'image/png', 'image/webp', 'image/heic', 'image/heif', 'image/avif', 'image/tiff', 'image/bmp', ]; export function validateEmail(email: string): boolean { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); } export function sanitizeInput(input: string): string { return input.trim().substring(0, 500); } export function cleanInstagramUsername(username: string): string { return username.trim().replace(/^@+/, '').substring(0, 30); } export function validateCameraFile(file: File): string | null { if (file.size > MAX_FILE_SIZE) { return 'Junwon: My database can only take photos that are smaller than 20MB 😅. Would you take a small photo by using a smartphone?'; } if (!ALLOWED_FILE_TYPES.includes(file.type)) { return "Hmm. This file does not seem to be a photo. If it is, but you are getting this error, please send it to me on Instagram (@palacejunwon) and I'll fix the photo processing problem for everyone!"; } return null; } export function validateFormData(formData: FormData): { valid: boolean; message?: string } { const email = formData.get('email')?.toString(); const honeypot = formData.get('website')?.toString(); const realName = formData.get('realName')?.toString(); if (honeypot) { return { valid: false, message: 'Robot detected.' }; } if (!realName) { return { valid: false, message: 'You forgot to sign the petition! 😅' }; } if (!email) { return { valid: false, message: 'Would you provide your email address? This ensures you can delete your submissions in the future if you ever want to.', }; } if (!validateEmail(email)) { return { valid: false, message: 'I think you have a typo in your email!' }; } return { valid: true }; } export async function uploadCameraFile(file: File, signatureId: string): Promise { try { const fileExt = file.name.split('.').pop()?.toLowerCase(); const fileName = `${signatureId}-${Date.now()}.${fileExt}`; const filePath = `${fileName}`; const { error } = await supabase.storage.from('unesco-petition').upload(filePath, file, { cacheControl: '3600', upsert: false, contentType: file.type, }); if (error) { return null; } return `/media/unesco-petition/${filePath}`; } catch (error) { return null; } } export interface SignatureData { email: string; workos_user_id?: string; ip_address?: string; user_agent?: string; real_name?: string; home_location?: string; instagram_username?: string; photo_proof_url?: string; } export function buildSignatureData( email: string, workosUserId: string | null, clientAddress: string, userAgent: string | null, realName?: string, location?: string, instagramUsername?: string ): SignatureData { const signatureData: SignatureData = { email: sanitizeInput(email).toLowerCase(), workos_user_id: workosUserId || undefined, ip_address: clientAddress, user_agent: userAgent || undefined, real_name: realName ? sanitizeInput(realName) : undefined, }; if (location) { signatureData.home_location = sanitizeInput(location); } if (instagramUsername) { signatureData.instagram_username = cleanInstagramUsername(instagramUsername); } return signatureData; }