'use client' import { useState, useEffect } from 'react' import Link from 'next/link' import { useRouter } from 'next/navigation' import { multiTripIdentity } from '@/lib/multiTripIdentity' import DarkModeToggle from '@/components/DarkModeToggle' // Move currencies outside component to prevent hydration issues const commonCurrencies = [ { code: 'USD', symbol: '$', name: 'US Dollar' }, { code: 'EUR', symbol: '€', name: 'Euro' }, { code: 'GBP', symbol: '£', name: 'British Pound' }, { code: 'JPY', symbol: '¥', name: 'Japanese Yen' }, { code: 'CNY', symbol: '¥', name: 'Chinese Yuan' }, { code: 'INR', symbol: '₹', name: 'Indian Rupee' }, { code: 'AED', symbol: 'د.إ', name: 'UAE Dirham' }, { code: 'CAD', symbol: 'C$', name: 'Canadian Dollar' }, { code: 'AUD', symbol: 'A$', name: 'Australian Dollar' }, { code: 'CHF', symbol: 'Fr', name: 'Swiss Franc' }, { code: 'SEK', symbol: 'kr', name: 'Swedish Krona' }, { code: 'NOK', symbol: 'kr', name: 'Norwegian Krone' }, { code: 'DKK', symbol: 'kr', name: 'Danish Krone' }, { code: 'SGD', symbol: 'S$', name: 'Singapore Dollar' }, { code: 'HKD', symbol: 'HK$', name: 'Hong Kong Dollar' }, { code: 'NZD', symbol: 'NZ$', name: 'New Zealand Dollar' }, { code: 'MXN', symbol: '$', name: 'Mexican Peso' }, { code: 'BRL', symbol: 'R$', name: 'Brazilian Real' }, { code: 'ZAR', symbol: 'R', name: 'South African Rand' }, { code: 'KRW', symbol: '₩', name: 'South Korean Won' }, { code: 'THB', symbol: '฿', name: 'Thai Baht' }, { code: 'MYR', symbol: 'RM', name: 'Malaysian Ringgit' }, { code: 'PHP', symbol: '₱', name: 'Philippine Peso' }, { code: 'IDR', symbol: 'Rp', name: 'Indonesian Rupiah' }, { code: 'VND', symbol: '₫', name: 'Vietnamese Dong' }, ] export default function HomePage() { const router = useRouter() const [tripName, setTripName] = useState('') const [creatorName, setCreatorName] = useState('') const [currency, setCurrency] = useState('USD') const [password, setPassword] = useState('') const [isCreating, setIsCreating] = useState(false) const [createdTrip, setCreatedTrip] = useState(null) const [error, setError] = useState('') const [forceShowCreate, setForceShowCreate] = useState(false) const [mounted, setMounted] = useState(false) useEffect(() => { setMounted(true) }, []) useEffect(() => { // Check for URL parameters to force show create page if (typeof window !== 'undefined') { const urlParams = new URLSearchParams(window.location.search); const create = urlParams.get('create'); if (create === 'true') { console.log('URL parameter create=true, forcing show create page'); setForceShowCreate(true); return; } } // Only redirect to dashboard if user explicitly navigates to home page // and has existing trips, but hasn't just created a new trip console.log('=== PAGE LOAD DEBUG ==='); console.log('createdTrip state:', createdTrip); console.log('forceShowCreate:', forceShowCreate); console.log('Checking for existing trips...'); const existingTrips = multiTripIdentity.getAllTrips(); console.log('Found existing trips:', existingTrips); console.log('Number of existing trips:', existingTrips.length); if (!createdTrip && !forceShowCreate && existingTrips.length > 0) { console.log('Existing trips found and no force create, redirecting to dashboard'); router.push('/dashboard'); } else { console.log('Allowing access to home page'); } console.log('=== END DEBUG ==='); }, [router, createdTrip, forceShowCreate]) const handleCreateTrip = async (e: React.FormEvent) => { e.preventDefault() if (!tripName.trim() || !creatorName.trim()) { setError('Please fill in all required fields') return } setIsCreating(true) setError('') try { // Use relative URL to leverage Next.js API rewrite (works on mobile) const tripData = { name: tripName.trim(), creator_name: creatorName.trim(), currency_code: currency, password: password.trim() || undefined, // Only include if provided } // Use the API instance with configured baseURL const { createTrip } = await import('@/lib/api') const trip = await createTrip(tripData) console.log('Trip created response:', { id: trip.id, hasAccessToken: !!trip.access_token, requiresAuth: trip.requires_auth, passwordProvided: !!password.trim() }) // If trip has a password and we got an access token, store it if (trip.access_token && trip.id) { const { storeTripToken, getTripToken } = await import('@/lib/trip-auth') storeTripToken(trip.id, trip.access_token) // Verify it was stored const storedToken = getTripToken(trip.id) console.log('Stored access token for trip', trip.id, 'verified:', !!storedToken) } else if (trip.requires_auth || password.trim()) { // Trip requires auth but no token was returned - this shouldn't happen console.error('Trip requires auth but no access_token was returned', trip) setError('Trip created but authentication failed. Please use the password to access the trip.') } setCreatedTrip(trip) // Store identity using multi-trip manager multiTripIdentity.addTripIdentity(trip, creatorName.trim()) } catch (err) { setError('Failed to create trip. Please try again.') console.error(err) } finally { setIsCreating(false) } } const handleGoToTrip = async () => { if (!createdTrip) { return } const tripId = createdTrip.id // Step 1: Ensure token is stored (for password-protected trips) if (createdTrip.requires_auth || createdTrip.access_token) { const { getTripToken, storeTripToken } = await import('@/lib/trip-auth') let token = getTripToken(tripId) console.log('[handleGoToTrip] Trip ID:', tripId) console.log('[handleGoToTrip] Has access_token in response:', !!createdTrip.access_token) console.log('[handleGoToTrip] Token in localStorage:', !!token) if (!token && createdTrip.access_token) { // Token should have been stored, but if not, store it now console.log('[handleGoToTrip] Storing token before navigation...') storeTripToken(tripId, createdTrip.access_token) token = getTripToken(tripId) console.log('[handleGoToTrip] Re-stored access token, verified:', !!token) if (!token) { console.error('[handleGoToTrip] CRITICAL: Token storage failed!') setError('Failed to store authentication token. Please try again.') return } } else if (!token) { console.error('[handleGoToTrip] CRITICAL: No token available for password-protected trip') setError('Authentication token not found. Please try creating the trip again.') return } // Final verification const finalCheck = getTripToken(tripId) if (!finalCheck) { console.error('[handleGoToTrip] CRITICAL: Token lost before navigation!') setError('Authentication token was lost. Please try again.') return } } // Step 2: Store trip data in localStorage for immediate use (more reliable than sessionStorage) if (typeof window !== 'undefined') { const { storeRedirectTripData } = await import('@/lib/trip-redirect') // Prepare trip data (without sensitive fields) const tripDataToStore = { ...createdTrip } delete tripDataToStore.access_token // Don't store token in trip data delete tripDataToStore.requires_auth // Don't store this flag // Store in localStorage (more reliable than sessionStorage) storeRedirectTripData(tripId, tripDataToStore) // Verify it was stored const { getRedirectTripData } = await import('@/lib/trip-redirect') const stored = getRedirectTripData(tripId) if (!stored) { console.error('[handleGoToTrip] CRITICAL: Failed to store redirect trip data!') setError('Failed to prepare trip data. Please try again.') return } console.log('[handleGoToTrip] Stored redirect trip data, verified successfully') // Small delay to ensure localStorage is committed await new Promise(resolve => setTimeout(resolve, 100)) // Final verification before navigation const finalDataCheck = getRedirectTripData(tripId) if (!finalDataCheck) { console.error('[handleGoToTrip] CRITICAL: Redirect data lost before navigation!') setError('Trip data was lost. Please try again.') return } } console.log('[handleGoToTrip] All checks passed, navigating to trip page...') // Use Next.js router to preserve application state and avoid race conditions router.push(`/trip/${tripId}`) } if (createdTrip) { console.log('RENDERING SUCCESS SCREEN'); return (

Trip Created!

Your trip "{createdTrip.name}" is ready

Share this code with your group:

{createdTrip.share_code}

) } console.log('RENDERING HOME PAGE (NO TRIPS)'); return (
{/* Header with Dark Mode Toggle and Back Button */}
{/* Header */}

Juntete

Split expenses fairly with your group

{/* Create Trip Form */}

Start a New Trip

{error && (
{error}
)}
setTripName(e.target.value)} placeholder="Weekend in Paris, Project Alpha..." className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100" required />
setCreatorName(e.target.value)} placeholder="John Doe" className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100" required />
{mounted ? ( ) : ( )}
setPassword(e.target.value)} placeholder="Leave empty for public trip" className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100" />

Add a password to make this trip private. Only people with the password can access it.

{/* Join Trip Section */}

Join Existing Trip

Have a trip code? Enter it below to join.

Join Trip with Code
{/* Features */}
No login required Mobile-first Multi-currency
) }