← back to Handbag Auth Nextjs

arbitrage/arbitrage.html

725 lines

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>LUXVAULT Arbitrage Calculator - Japan → USA/HK</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            padding: 20px;
        }

        .container {
            max-width: 1400px;
            margin: 0 auto;
        }

        header {
            text-align: center;
            color: white;
            margin-bottom: 30px;
        }

        h1 {
            font-size: 3em;
            margin-bottom: 10px;
            text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
        }

        .subtitle {
            font-size: 1.2em;
            opacity: 0.9;
        }

        .exchange-rates {
            background: rgba(255,255,255,0.2);
            padding: 15px;
            border-radius: 10px;
            color: white;
            text-align: center;
            margin: 20px 0;
        }

        .exchange-rates strong {
            font-size: 1.1em;
            margin: 0 15px;
        }

        .grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 20px;
            margin-bottom: 30px;
        }

        @media (max-width: 1024px) {
            .grid {
                grid-template-columns: 1fr;
            }
        }

        .card {
            background: white;
            border-radius: 15px;
            padding: 25px;
            box-shadow: 0 10px 30px rgba(0,0,0,0.2);
        }

        .card h2 {
            color: #667eea;
            margin-bottom: 20px;
            font-size: 1.8em;
            border-bottom: 2px solid #667eea;
            padding-bottom: 10px;
        }

        .form-group {
            margin-bottom: 20px;
        }

        label {
            display: block;
            margin-bottom: 5px;
            font-weight: 600;
            color: #333;
        }

        input, select {
            width: 100%;
            padding: 12px;
            border: 2px solid #e0e0e0;
            border-radius: 8px;
            font-size: 16px;
            transition: border-color 0.3s;
        }

        input:focus, select:focus {
            outline: none;
            border-color: #667eea;
        }

        .row {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 15px;
        }

        .btn {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border: none;
            padding: 15px 30px;
            font-size: 1.1em;
            border-radius: 8px;
            cursor: pointer;
            transition: transform 0.2s, box-shadow 0.2s;
            width: 100%;
            margin-top: 10px;
        }

        .btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
        }

        .result {
            margin-top: 20px;
            padding: 20px;
            background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
            border-radius: 10px;
            display: none;
        }

        .result.show {
            display: block;
            animation: fadeIn 0.5s;
        }

        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(-10px); }
            to { opacity: 1; transform: translateY(0); }
        }

        .result-header {
            font-size: 1.5em;
            font-weight: bold;
            margin-bottom: 15px;
            text-align: center;
        }

        .result-grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 15px;
            margin-top: 15px;
        }

        .result-box {
            background: white;
            padding: 15px;
            border-radius: 8px;
            border-left: 4px solid #667eea;
        }

        .result-box h4 {
            color: #667eea;
            margin-bottom: 10px;
            font-size: 0.9em;
            text-transform: uppercase;
        }

        .result-box .value {
            font-size: 1.8em;
            font-weight: bold;
            color: #333;
        }

        .profit-positive {
            color: #10b981;
        }

        .profit-negative {
            color: #ef4444;
        }

        .recommendation {
            text-align: center;
            padding: 15px;
            border-radius: 8px;
            font-size: 1.3em;
            font-weight: bold;
            margin-top: 15px;
        }

        .recommendation.excellent {
            background: linear-gradient(135deg, #10b981 0%, #059669 100%);
            color: white;
        }

        .recommendation.good {
            background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
            color: white;
        }

        .recommendation.marginal {
            background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
            color: white;
        }

        .recommendation.skip {
            background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
            color: white;
        }

        .opportunities-list {
            margin-top: 20px;
        }

        .opportunity-card {
            background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
            padding: 20px;
            border-radius: 10px;
            margin-bottom: 15px;
            cursor: pointer;
            transition: transform 0.2s, box-shadow 0.2s;
        }

        .opportunity-card:hover {
            transform: translateY(-3px);
            box-shadow: 0 5px 15px rgba(0,0,0,0.2);
        }

        .opportunity-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 10px;
        }

        .opportunity-brand {
            font-size: 1.3em;
            font-weight: bold;
            color: #333;
        }

        .opportunity-margin {
            font-size: 1.5em;
            font-weight: bold;
            padding: 5px 15px;
            border-radius: 20px;
            background: white;
        }

        .opportunity-details {
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            gap: 10px;
            margin-top: 10px;
        }

        .opportunity-detail {
            text-align: center;
        }

        .opportunity-detail-label {
            font-size: 0.8em;
            color: #666;
            margin-bottom: 3px;
        }

        .opportunity-detail-value {
            font-size: 1.1em;
            font-weight: bold;
            color: #333;
        }

        .stats-grid {
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            gap: 15px;
            margin-bottom: 20px;
        }

        .stat-card {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 20px;
            border-radius: 10px;
            text-align: center;
        }

        .stat-value {
            font-size: 2em;
            font-weight: bold;
            margin-bottom: 5px;
        }

        .stat-label {
            font-size: 0.9em;
            opacity: 0.9;
        }

        .loading {
            text-align: center;
            padding: 40px;
            color: #666;
        }

        .tabs {
            display: flex;
            gap: 10px;
            margin-bottom: 20px;
        }

        .tab {
            flex: 1;
            padding: 15px;
            background: #e0e0e0;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            font-size: 1.1em;
            transition: all 0.3s;
        }

        .tab.active {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
        }

        .tab-content {
            display: none;
        }

        .tab-content.active {
            display: block;
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1><i class="fas fa-yen-sign"></i> LUXVAULT Arbitrage Calculator</h1>
            <p class="subtitle">Find profitable luxury handbag deals: Japan → USA / Hong Kong</p>
        </header>

        <div class="exchange-rates" id="exchangeRates">
            <i class="fas fa-sync-alt fa-spin"></i> Loading exchange rates...
        </div>

        <div class="tabs">
            <button class="tab active" onclick="switchTab('calculator')">
                <i class="fas fa-calculator"></i> Calculator
            </button>
            <button class="tab" onclick="switchTab('opportunities')">
                <i class="fas fa-list"></i> Opportunities
            </button>
        </div>

        <div id="calculator" class="tab-content active">
            <div class="grid">
                <!-- Calculator Form -->
                <div class="card">
                    <h2><i class="fas fa-calculator"></i> Calculate Arbitrage</h2>
                    <form id="arbitrageForm">
                        <div class="form-group">
                            <label>Brand</label>
                            <input type="text" id="brand" placeholder="e.g., Hermès" required>
                        </div>

                        <div class="form-group">
                            <label>Model</label>
                            <input type="text" id="model" placeholder="e.g., Birkin 30" required>
                        </div>

                        <div class="form-group">
                            <label>Condition</label>
                            <select id="condition">
                                <option value="new">New</option>
                                <option value="excellent" selected>Excellent</option>
                                <option value="good">Good</option>
                                <option value="fair">Fair</option>
                            </select>
                        </div>

                        <div class="form-group">
                            <label>Japan Price (¥)</label>
                            <input type="number" id="japanPrice" placeholder="e.g., 350000" required>
                        </div>

                        <div class="row">
                            <div class="form-group">
                                <label>USA Price ($) <small>(optional)</small></label>
                                <input type="number" id="usaPrice" placeholder="e.g., 4200">
                            </div>

                            <div class="form-group">
                                <label>HK Price (HK$) <small>(optional)</small></label>
                                <input type="number" id="hkPrice" placeholder="e.g., 32000">
                            </div>
                        </div>

                        <div class="row">
                            <div class="form-group">
                                <label>Shipping</label>
                                <select id="shipping">
                                    <option value="economy">Economy ($50)</option>
                                    <option value="express">Express ($100)</option>
                                </select>
                            </div>

                            <div class="form-group">
                                <label>Selling Platform</label>
                                <select id="platform">
                                    <option value="ebay">eBay (13%)</option>
                                    <option value="fashionphile" selected>Fashionphile (15%)</option>
                                    <option value="therealreal">TheRealReal (20%)</option>
                                    <option value="rebag">Rebag (18%)</option>
                                </select>
                            </div>
                        </div>

                        <div class="form-group">
                            <label>
                                <input type="checkbox" id="includeAuth" checked>
                                Include Authentication ($50)
                            </label>
                        </div>

                        <button type="submit" class="btn">
                            <i class="fas fa-chart-line"></i> Calculate Profit
                        </button>
                    </form>
                </div>

                <!-- Results -->
                <div class="card">
                    <h2><i class="fas fa-chart-bar"></i> Results</h2>
                    <div id="results" class="result">
                        <!-- Results will be displayed here -->
                    </div>
                    <div id="noResults" style="text-align: center; padding: 60px; color: #999;">
                        <i class="fas fa-calculator" style="font-size: 4em; margin-bottom: 20px;"></i>
                        <p>Enter details and click "Calculate Profit" to see results</p>
                    </div>
                </div>
            </div>
        </div>

        <div id="opportunities" class="tab-content">
            <div class="card">
                <h2><i class="fas fa-list"></i> Top Arbitrage Opportunities</h2>

                <div class="stats-grid" id="statsGrid">
                    <div class="stat-card">
                        <div class="stat-value" id="totalOpportunities">-</div>
                        <div class="stat-label">Total Opportunities</div>
                    </div>
                    <div class="stat-card">
                        <div class="stat-value" id="avgProfit">-</div>
                        <div class="stat-label">Avg Profit</div>
                    </div>
                    <div class="stat-card">
                        <div class="stat-value" id="avgMargin">-</div>
                        <div class="stat-label">Avg Margin</div>
                    </div>
                    <div class="stat-card">
                        <div class="stat-value" id="topBrand">-</div>
                        <div class="stat-label">Top Brand</div>
                    </div>
                </div>

                <div class="opportunities-list" id="opportunitiesList">
                    <div class="loading">
                        <i class="fas fa-spinner fa-spin" style="font-size: 2em;"></i>
                        <p>Loading opportunities...</p>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script>
        const API_BASE = 'http://45.61.58.125:7600/api/arbitrage';
        let exchangeRates = {};

        // Load exchange rates
        async function loadExchangeRates() {
            try {
                const response = await fetch(`${API_BASE}/rates`);
                const data = await response.json();
                if (data.success) {
                    exchangeRates = data.rates;
                    document.getElementById('exchangeRates').innerHTML = `
                        <strong>JPY/USD:</strong> ¥${(1/data.rates.JPYUSD).toFixed(2)}/$1 &nbsp; | &nbsp;
                        <strong>HKD/USD:</strong> HK$${(1/data.rates.HKDUSD).toFixed(2)}/$1 &nbsp; | &nbsp;
                        <small>Updated: ${new Date(data.rates.lastUpdated).toLocaleString()}</small>
                    `;
                }
            } catch (error) {
                console.error('Failed to load exchange rates:', error);
            }
        }

        // Calculate arbitrage
        document.getElementById('arbitrageForm').addEventListener('submit', async (e) => {
            e.preventDefault();

            const data = {
                brand: document.getElementById('brand').value,
                model: document.getElementById('model').value,
                condition: document.getElementById('condition').value,
                japanPriceJPY: parseFloat(document.getElementById('japanPrice').value),
                usaPriceUSD: parseFloat(document.getElementById('usaPrice').value) || null,
                hkPriceHKD: parseFloat(document.getElementById('hkPrice').value) || null,
                shippingType: document.getElementById('shipping').value,
                sellingPlatform: document.getElementById('platform').value,
                includeAuth: document.getElementById('includeAuth').checked
            };

            try {
                const response = await fetch(`${API_BASE}/calculate`, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify(data)
                });

                const result = await response.json();
                if (result.success) {
                    displayResults(result.data);
                }
            } catch (error) {
                console.error('Calculation failed:', error);
                alert('Failed to calculate arbitrage. Please try again.');
            }
        });

        function displayResults(data) {
            const resultsDiv = document.getElementById('results');
            const noResultsDiv = document.getElementById('noResults');

            noResultsDiv.style.display = 'none';
            resultsDiv.classList.add('show');

            const cost = data.costBreakdown;
            const usa = data.usa;
            const hk = data.hongkong;
            const best = data.bestRoute;

            let html = `
                <div class="result-header">
                    ${data.product.brand} ${data.product.model}
                </div>

                <div class="result-box">
                    <h4>Japan Purchase</h4>
                    <div class="value">¥${cost.japan.purchaseJPY.toLocaleString()}</div>
                    <small>- Tax Refund: ¥${cost.japan.taxRefundJPY.toLocaleString()}</small><br>
                    <small>= Net: $${cost.japan.purchaseUSD.toLocaleString()}</small>
                </div>

                <div class="result-box">
                    <h4>Additional Costs</h4>
                    <div class="value">$${cost.totalCostUSD.toLocaleString()}</div>
                    <small>Shipping: $${cost.additionalCosts.shipping} | Duties: $${cost.additionalCosts.duties.toFixed(0)} | Fees: $${cost.additionalCosts.paymentFees.toFixed(0)} | Auth: $${cost.additionalCosts.authentication}</small>
                </div>
            `;

            if (usa) {
                html += `
                    <div class="result-box">
                        <h4>USA Market</h4>
                        <div class="value">$${usa.sellPrice.toLocaleString()}</div>
                        <small>- Selling Fee: $${usa.sellingFee.toFixed(0)} = Net: $${usa.netRevenue.toLocaleString()}</small>
                    </div>

                    <div class="result-box">
                        <h4>USA Profit</h4>
                        <div class="value ${usa.profitable ? 'profit-positive' : 'profit-negative'}">
                            $${usa.profit.toLocaleString()} (${usa.profitMargin.toFixed(1)}%)
                        </div>
                    </div>
                `;
            }

            if (hk) {
                html += `
                    <div class="result-box">
                        <h4>Hong Kong Market</h4>
                        <div class="value">$${hk.sellPrice.toLocaleString()}</div>
                        <small>HK$${hk.sellPriceHKD.toLocaleString()} | Fee: $${hk.sellingFee.toFixed(0)}</small>
                    </div>

                    <div class="result-box">
                        <h4>HK Profit</h4>
                        <div class="value ${hk.profitable ? 'profit-positive' : 'profit-negative'}">
                            $${hk.profit.toLocaleString()} (${hk.profitMargin.toFixed(1)}%)
                        </div>
                    </div>
                `;
            }

            if (best) {
                const recClass = best.recommendation.toLowerCase();
                html += `
                    <div class="recommendation ${recClass}">
                        <i class="fas fa-${best.recommendation === 'EXCELLENT' ? 'star' : (best.recommendation === 'GOOD' ? 'thumbs-up' : (best.recommendation === 'MARGINAL' ? 'hand-point-right' : 'times-circle'))}"></i>
                        ${best.recommendation}: Best route is ${best.market}
                        <br>
                        Profit: $${best.profit.toLocaleString()} (${best.profitMargin.toFixed(1)}% margin)
                    </div>
                `;
            }

            resultsDiv.innerHTML = html;
        }

        // Load opportunities
        async function loadOpportunities() {
            try {
                const [oppsResponse, statsResponse] = await Promise.all([
                    fetch(`${API_BASE}/opportunities?minMargin=0&limit=20`),
                    fetch(`${API_BASE}/stats`)
                ]);

                const oppsData = await oppsResponse.json();
                const statsData = await statsResponse.json();

                if (statsData.success) {
                    displayStats(statsData.stats);
                }

                if (oppsData.success) {
                    displayOpportunities(oppsData.data);
                }
            } catch (error) {
                console.error('Failed to load opportunities:', error);
            }
        }

        function displayStats(stats) {
            document.getElementById('totalOpportunities').textContent = stats.totalOpportunities;
            document.getElementById('avgProfit').textContent = '$' + stats.avgProfit.toLocaleString();
            document.getElementById('avgMargin').textContent = stats.avgMargin.toFixed(1) + '%';
            document.getElementById('topBrand').textContent = stats.topBrand.brand;
        }

        function displayOpportunities(opportunities) {
            const listDiv = document.getElementById('opportunitiesList');

            if (opportunities.length === 0) {
                listDiv.innerHTML = '<div class="loading">No opportunities found</div>';
                return;
            }

            let html = '';
            opportunities.forEach(opp => {
                const marginClass = opp.profit_margin_pct >= 40 ? 'profit-positive' : (opp.profit_margin_pct >= 25 ? 'profit-positive' : '');

                html += `
                    <div class="opportunity-card">
                        <div class="opportunity-header">
                            <div class="opportunity-brand">
                                ${opp.brand} ${opp.model}
                            </div>
                            <div class="opportunity-margin ${marginClass}">
                                ${opp.profit_margin_pct.toFixed(1)}%
                            </div>
                        </div>
                        <div class="opportunity-details">
                            <div class="opportunity-detail">
                                <div class="opportunity-detail-label">Japan Price</div>
                                <div class="opportunity-detail-value">¥${opp.japan_price_jpy.toLocaleString()}</div>
                            </div>
                            <div class="opportunity-detail">
                                <div class="opportunity-detail-label">USA Price</div>
                                <div class="opportunity-detail-value">$${opp.usa_price_usd ? opp.usa_price_usd.toLocaleString() : 'N/A'}</div>
                            </div>
                            <div class="opportunity-detail">
                                <div class="opportunity-detail-label">Profit</div>
                                <div class="opportunity-detail-value profit-positive">$${opp.potential_profit_usd ? opp.potential_profit_usd.toLocaleString() : 'N/A'}</div>
                            </div>
                            <div class="opportunity-detail">
                                <div class="opportunity-detail-label">Source</div>
                                <div class="opportunity-detail-value">${opp.japan_source || 'Manual'}</div>
                            </div>
                        </div>
                    </div>
                `;
            });

            listDiv.innerHTML = html;
        }

        function switchTab(tab) {
            // Update tab buttons
            document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
            event.target.closest('.tab').classList.add('active');

            // Update content
            document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
            document.getElementById(tab).classList.add('active');

            // Load opportunities if switching to that tab
            if (tab === 'opportunities') {
                loadOpportunities();
            }
        }

        // Initialize
        loadExchangeRates();
        setInterval(loadExchangeRates, 60000); // Refresh every minute
    </script>
</body>
</html>