import { TransactionLogger } from './TransactionLogger' import { getPaymentMode } from '../lib/paymentMode' export interface CustomerData { first_name?: string last_name?: string name?: string email?: string phone?: string address?: string city?: string postal_code?: string country_code?: string } export interface SanitizedCustomerData { name: string email: string phone?: string address?: string } export class CustomerDataHandler { static sanitizeCustomerData(customer: CustomerData): SanitizedCustomerData { const mode = getPaymentMode() try { // Combine first_name and last_name if available, otherwise use name const name = customer.name || (customer.first_name && customer.last_name ? `${customer.first_name} ${customer.last_name}` : customer.first_name || customer.last_name || 'Unknown') // Basic email validation const email = customer.email?.toLowerCase().trim() if (!email || !this.isValidEmail(email)) { TransactionLogger.log(mode, 'customer.data.warning', { field: 'email', reason: 'invalid_or_missing' }) } // Sanitize phone number (remove non-numeric characters except +) const phone = customer.phone?.replace(/[^\d+]/g, '') // Create sanitized address if available const address = this.buildAddressString(customer) const sanitized: SanitizedCustomerData = { name: name.trim(), email: email || '', phone, address } TransactionLogger.log(mode, 'customer.data.sanitized', { hasName: !!sanitized.name, hasEmail: !!sanitized.email, hasPhone: !!sanitized.phone, hasAddress: !!sanitized.address }) return sanitized } catch (error) { TransactionLogger.log(mode, 'customer.data.sanitization.error', { error: error instanceof Error ? error.message : String(error) }) // Return minimal safe data on error return { name: 'Unknown Customer', email: '', phone: customer.phone, address: customer.address } } } static validateCustomerData(customer: CustomerData): { isValid: boolean; errors: string[] } { const errors: string[] = [] if (!customer.name && !customer.first_name && !customer.last_name) { errors.push('Name is required') } if (!customer.email) { errors.push('Email is required') } else if (!this.isValidEmail(customer.email)) { errors.push('Invalid email format') } if (!customer.phone) { errors.push('Phone number is required') } return { isValid: errors.length === 0, errors } } static buildAddressString(customer: CustomerData): string | undefined { const parts: string[] = [] if (customer.address) parts.push(customer.address) if (customer.city) parts.push(customer.city) if (customer.postal_code) parts.push(customer.postal_code) if (customer.country_code) parts.push(customer.country_code) return parts.length > 0 ? parts.join(', ') : undefined } private static isValidEmail(email: string): boolean { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ return emailRegex.test(email) } static formatForMidtrans(customer: SanitizedCustomerData) { // Format customer data for Midtrans API (both Core and Snap) return { first_name: customer.name.split(' ')[0] || '', last_name: customer.name.split(' ').slice(1).join(' ') || '', email: customer.email, phone: customer.phone || '', address: customer.address || '', city: '', postal_code: '', country_code: 'IDN' } } }