import React, { useState, useEffect } from 'react'; import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, LineChart, Line, PieChart, Pie, Cell } from 'recharts'; import { Calendar, TrendingUp, Target, Database, Calculator, Award, Plus, Download, Upload, RefreshCw, Save } from 'lucide-react'; const JamaicaLottoAnalyzer = () => { const [gameType, setGameType] = useState('lotto'); // 'lotto' or 'superlotto' const [historicalData, setHistoricalData] = useState({ lotto: [], superlotto: [] }); const [predictions, setPredictions] = useState([]); const [hotNumbers, setHotNumbers] = useState([]); const [coldNumbers, setColdNumbers] = useState([]); const [selectedNumbers, setSelectedNumbers] = useState([]); const [bonusNumber, setBonusNumber] = useState(null); const [analysis, setAnalysis] = useState(null); const [activeTab, setActiveTab] = useState('predictions'); const [isScrapingData, setIsScrapingData] = useState(false); const [scrapingStatus, setScrapingStatus] = useState(''); // Manual input states const [manualInputDate, setManualInputDate] = useState(''); const [manualInputNumbers, setManualInputNumbers] = useState([]); const [manualInputBonus, setManualInputBonus] = useState(''); const [manualInputJackpot, setManualInputJackpot] = useState(''); const [showManualInput, setShowManualInput] = useState(false); // Game configurations const gameConfig = { lotto: { name: 'Lotto', maxNumber: 38, numbersCount: 6, hasBonus: true, drawDays: 'Wed & Sat', ticketPrice: 'J$100', startingJackpot: 'J$25M' }, superlotto: { name: 'Super Lotto', maxNumber: 35, numbersCount: 6, hasBonus: false, drawDays: 'Wed & Sat', ticketPrice: 'J$200', startingJackpot: 'J$70M' } }; const getCurrentConfig = () => gameConfig[gameType]; // Enhanced mock data generation for both games const generateMockData = (type) => { const config = gameConfig[type]; const data = []; for (let i = 0; i < 150; i++) { const date = new Date(); date.setDate(date.getDate() - (i * 3.5)); const numbers = []; while (numbers.length < config.numbersCount) { const num = Math.floor(Math.random() * config.maxNumber) + 1; if (!numbers.includes(num)) { numbers.push(num); } } const bonus = config.hasBonus ? Math.floor(Math.random() * config.maxNumber) + 1 : null; data.push({ date: date.toLocaleDateString(), numbers: numbers.sort((a, b) => a - b), bonus: bonus, jackpot: Math.floor(Math.random() * 200000000) + (type === 'superlotto' ? 70000000 : 25000000) }); } return data.reverse(); }; const calculateFrequencies = (data) => { const config = getCurrentConfig(); const frequencies = {}; for (let i = 1; i <= config.maxNumber; i++) { frequencies[i] = 0; } data.forEach(draw => { draw.numbers.forEach(num => { frequencies[num]++; }); if (draw.bonus && config.hasBonus) { frequencies[draw.bonus] = (frequencies[draw.bonus] || 0) + 0.5; // Bonus counts as half } }); return frequencies; }; const getHotColdNumbers = (frequencies) => { const sorted = Object.entries(frequencies) .map(([num, freq]) => ({ number: parseInt(num), frequency: freq })) .sort((a, b) => b.frequency - a.frequency); return { hot: sorted.slice(0, 12), cold: sorted.slice(-12).reverse() }; }; const generatePredictions = (data) => { const config = getCurrentConfig(); const frequencies = calculateFrequencies(data); const { hot, cold } = getHotColdNumbers(frequencies); // Strategy 1: Balanced approach const balanced = [ ...hot.slice(0, Math.floor(config.numbersCount / 2)).map(n => n.number), ...cold.slice(0, Math.floor(config.numbersCount / 2)).map(n => n.number) ]; while (balanced.length < config.numbersCount) { const num = Math.floor(Math.random() * config.maxNumber) + 1; if (!balanced.includes(num)) balanced.push(num); } // Strategy 2: Hot numbers focus const hotFocus = hot.slice(0, config.numbersCount).map(n => n.number).sort((a, b) => a - b); // Strategy 3: Pattern analysis (odd/even distribution) const patternStrategy = []; const targetOdds = Math.floor(config.numbersCount / 2); let odds = 0, evens = 0; while (patternStrategy.length < config.numbersCount) { const num = Math.floor(Math.random() * config.maxNumber) + 1; if (!patternStrategy.includes(num)) { if (num % 2 === 1 && odds < targetOdds) { patternStrategy.push(num); odds++; } else if (num % 2 === 0 && evens < (config.numbersCount - targetOdds)) { patternStrategy.push(num); evens++; } } } // Strategy 4: Range distribution const ranges = []; const rangeSize = Math.ceil(config.maxNumber / config.numbersCount); for (let i = 0; i < config.numbersCount; i++) { const start = i * rangeSize + 1; const end = Math.min((i + 1) * rangeSize, config.maxNumber); ranges.push([start, end]); } const rangeStrategy = ranges.map(range => { return Math.floor(Math.random() * (range[1] - range[0] + 1)) + range[0]; }); return [ { name: 'Balanced Hot/Cold', numbers: balanced.sort((a, b) => a - b), confidence: 76 }, { name: 'Hot Numbers Focus', numbers: hotFocus, confidence: 72 }, { name: 'Pattern Analysis', numbers: patternStrategy.sort((a, b) => a - b), confidence: 74 }, { name: 'Range Distribution', numbers: rangeStrategy.sort((a, b) => a - b), confidence: 70 } ]; }; // Manual input functions const toggleManualNumber = (number) => { const config = getCurrentConfig(); if (manualInputNumbers.includes(number)) { setManualInputNumbers(manualInputNumbers.filter(n => n !== number)); } else if (manualInputNumbers.length < config.numbersCount) { setManualInputNumbers([...manualInputNumbers, number]); } }; const addManualEntry = () => { const config = getCurrentConfig(); if (manualInputNumbers.length !== config.numbersCount || !manualInputDate) { alert(`Please select exactly ${config.numbersCount} numbers and enter a date`); return; } const newEntry = { date: manualInputDate, numbers: manualInputNumbers.sort((a, b) => a - b), bonus: config.hasBonus ? parseInt(manualInputBonus) || null : null, jackpot: parseInt(manualInputJackpot.replace(/[^0-9]/g, '')) || 0 }; const updatedData = { ...historicalData }; updatedData[gameType] = [newEntry, ...updatedData[gameType]]; setHistoricalData(updatedData); // Reset manual input setManualInputDate(''); setManualInputNumbers([]); setManualInputBonus(''); setManualInputJackpot(''); setShowManualInput(false); alert('Entry added successfully!'); }; // Database scraping simulation const scrapeDatabase = async () => { setIsScrapingData(true); setScrapingStatus('Initializing scraper...'); // Simulate scraping process const steps = [ 'Connecting to Supreme Ventures...', 'Fetching Lotto historical data...', 'Parsing Lotto results...', 'Fetching Super Lotto data...', 'Parsing Super Lotto results...', 'Validating data integrity...', 'Generating CSV files...', 'Complete!' ]; for (let i = 0; i < steps.length; i++) { setScrapingStatus(steps[i]); await new Promise(resolve => setTimeout(resolve, 1000)); } // Generate fresh data for both games const newData = { lotto: generateMockData('lotto'), superlotto: generateMockData('superlotto') }; setHistoricalData(newData); setIsScrapingData(false); setScrapingStatus(''); alert('Database updated successfully! In live version, CSV files would be generated.'); }; // Export to CSV const exportToCSV = () => { const data = historicalData[gameType]; if (!data.length) { alert('No data to export'); return; } const config = getCurrentConfig(); const headers = ['Date', 'Numbers', config.hasBonus ? 'Bonus' : null, 'Jackpot'].filter(Boolean); const csvContent = [ headers.join(','), ...data.map(row => [ row.date, `"${row.numbers.join(' ')}"`, config.hasBonus ? row.bonus || '' : null, row.jackpot ].filter(cell => cell !== null).join(',')) ].join('\n'); const blob = new Blob([csvContent], { type: 'text/csv' }); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `${config.name.toLowerCase()}_results.csv`; a.click(); window.URL.revokeObjectURL(url); }; useEffect(() => { // Initialize with mock data const initialData = { lotto: generateMockData('lotto'), superlotto: generateMockData('superlotto') }; setHistoricalData(initialData); }, []); useEffect(() => { // Update analysis when game type changes const currentData = historicalData[gameType] || []; if (currentData.length > 0) { const frequencies = calculateFrequencies(currentData); const { hot, cold } = getHotColdNumbers(frequencies); setHotNumbers(hot); setColdNumbers(cold); setPredictions(generatePredictions(currentData)); } // Clear selections when changing game type setSelectedNumbers([]); setBonusNumber(null); }, [gameType, historicalData]); const analyzeSelectedNumbers = () => { const config = getCurrentConfig(); if (selectedNumbers.length !== config.numbersCount) return; const frequencies = calculateFrequencies(historicalData[gameType]); const analysis = selectedNumbers.map(num => ({ number: num, frequency: frequencies[num], lastSeen: findLastOccurrence(num) })); setAnalysis(analysis); }; const findLastOccurrence = (number) => { const data = historicalData[gameType]; for (let i = data.length - 1; i >= 0; i--) { if (data[i].numbers.includes(number) || data[i].bonus === number) { return data.length - i; } } return 'Never'; }; const toggleNumber = (number) => { const config = getCurrentConfig(); if (selectedNumbers.includes(number)) { setSelectedNumbers(selectedNumbers.filter(n => n !== number)); } else if (selectedNumbers.length < config.numbersCount) { setSelectedNumbers([...selectedNumbers, number]); } }; const renderNumberGrid = (isManualInput = false) => { const config = getCurrentConfig(); const grid = []; const currentNumbers = isManualInput ? manualInputNumbers : selectedNumbers; const toggleFunction = isManualInput ? toggleManualNumber : toggleNumber; for (let i = 1; i <= config.maxNumber; i++) { const isSelected = currentNumbers.includes(i); const isHot = hotNumbers.some(h => h.number === i); const isCold = coldNumbers.some(c => c.number === i); grid.push( <button key={i} onClick={() => toggleFunction(i)} className={` w-10 h-10 m-1 rounded-lg font-bold text-sm transition-all ${isSelected ? 'bg-blue-600 text-white' : 'bg-gray-100 text-gray-700'} ${isHot ? 'ring-2 ring-red-400' : ''} ${isCold ? 'ring-2 ring-blue-400' : ''} hover:scale-105 hover:shadow-md `} > {i} </button> ); } return grid; }; const renderTab = (tabName, icon, label) => ( <button onClick={() => setActiveTab(tabName)} className={` flex items-center px-4 py-2 rounded-lg font-medium transition-all ${activeTab === tabName ? 'bg-blue-600 text-white' : 'bg-gray-100 text-gray-700 hover:bg-gray-200' } `} > {icon} <span className="ml-2">{label}</span> </button> ); const currentConfig = getCurrentConfig(); const currentData = historicalData[gameType] || []; return ( <div className="max-w-7xl mx-auto p-6 bg-gradient-to-br from-blue-50 to-purple-50 min-h-screen"> <div className="bg-white rounded-xl shadow-2xl p-8"> <h1 className="text-4xl font-bold text-center mb-2 bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent"> Jamaica Lottery Analyzer Pro </h1> <p className="text-center text-gray-600 mb-8"> Advanced prediction system for Supreme Ventures games </p> {/* Game Type Selector */} <div className="flex justify-center mb-6"> <div className="bg-gray-100 rounded-lg p-1 flex"> <button onClick={() => setGameType('lotto')} className={`px-6 py-2 rounded-md font-medium transition-all ${ gameType === 'lotto' ? 'bg-blue-600 text-white shadow-md' : 'text-gray-600 hover:text-gray-800' }`} > Lotto (6/38) </button> <button onClick={() => setGameType('superlotto')} className={`px-6 py-2 rounded-md font-medium transition-all ${ gameType === 'superlotto' ? 'bg-purple-600 text-white shadow-md' : 'text-gray-600 hover:text-gray-800' }`} > Super Lotto (6/35) </button> </div> </div> {/* Game Info Bar */} <div className="bg-gradient-to-r from-blue-100 to-purple-100 rounded-lg p-4 mb-6"> <div className="flex flex-wrap justify-center gap-6 text-sm"> <span><strong>Game:</strong> {currentConfig.name}</span> <span><strong>Draw Days:</strong> {currentConfig.drawDays}</span> <span><strong>Ticket:</strong> {currentConfig.ticketPrice}</span> <span><strong>Starting Jackpot:</strong> {currentConfig.startingJackpot}</span> <span><strong>Total Draws:</strong> {currentData.length}</span> </div> </div> {/* Navigation Tabs */} <div className="flex flex-wrap gap-3 mb-8 justify-center"> {renderTab('predictions', <Target className="w-4 h-4" />, 'Predictions')} {renderTab('analysis', <TrendingUp className="w-4 h-4" />, 'Analysis')} {renderTab('selector', <Calculator className="w-4 h-4" />, 'Number Selector')} {renderTab('history', <Database className="w-4 h-4" />, 'Historical Data')} {renderTab('manual', <Plus className="w-4 h-4" />, 'Manual Input')} {renderTab('database', <Download className="w-4 h-4" />, 'Database')} </div> {/* Predictions Tab */} {activeTab === 'predictions' && ( <div className="space-y-6"> <h2 className="text-2xl font-bold flex items-center"> <Award className="mr-2 text-yellow-500" /> {currentConfig.name} Predictions </h2> <div className="grid md:grid-cols-2 gap-6"> {predictions.map((pred, index) => ( <div key={index} className={`rounded-xl p-6 text-white ${ gameType === 'lotto' ? 'bg-gradient-to-r from-blue-500 to-blue-700' : 'bg-gradient-to-r from-purple-500 to-purple-700' }`}> <h3 className="text-lg font-bold mb-3">{pred.name}</h3> <div className="flex flex-wrap gap-2 mb-3"> {pred.numbers.map(num => ( <span key={num} className="bg-white text-gray-800 px-3 py-1 rounded-full font-bold"> {num} </span> ))} </div> <div className="flex justify-between items-center"> <span className="text-sm opacity-90">Confidence Level</span> <span className="font-bold">{pred.confidence}%</span> </div> </div> ))} </div> </div> )} {/* Analysis Tab */} {activeTab === 'analysis' && ( <div className="space-y-6"> <div className="grid md:grid-cols-2 gap-8"> <div> <h3 className="text-xl font-bold mb-4 text-red-600">🔥 Hot Numbers (Most Frequent)</h3> <div className="space-y-2 max-h-64 overflow-y-auto"> {hotNumbers.map(item => ( <div key={item.number} className="flex justify-between items-center p-3 bg-red-50 rounded-lg"> <span className="font-bold text-lg">{item.number}</span> <span className="text-sm text-gray-600">{item.frequency.toFixed(1)} times</span> </div> ))} </div> </div> <div> <h3 className="text-xl font-bold mb-4 text-blue-600">❄️ Cold Numbers (Least Frequent)</h3> <div className="space-y-2 max-h-64 overflow-y-auto"> {coldNumbers.map(item => ( <div key={item.number} className="flex justify-between items-center p-3 bg-blue-50 rounded-lg"> <span className="font-bold text-lg">{item.number}</span> <span className="text-sm text-gray-600">{item.frequency.toFixed(1)} times</span> </div> ))} </div> </div> </div> {hotNumbers.length > 0 && ( <div> <h3 className="text-xl font-bold mb-4">Number Frequency Distribution</h3> <ResponsiveContainer width="100%" height={400}> <BarChart data={hotNumbers}> <CartesianGrid strokeDasharray="3 3" /> <XAxis dataKey="number" /> <YAxis /> <Tooltip /> <Bar dataKey="frequency" fill={gameType === 'lotto' ? '#3b82f6' : '#8b5cf6'} /> </BarChart> </ResponsiveContainer> </div> )} </div> )} {/* Number Selector Tab */} {activeTab === 'selector' && ( <div className="space-y-6"> <h2 className="text-2xl font-bold">Select Your {currentConfig.name} Numbers</h2> <p className="text-gray-600"> Choose {currentConfig.numbersCount} numbers (1-{currentConfig.maxNumber}). {currentConfig.hasBonus && ' Plus select a bonus number.'} <br /> <span className="text-red-500">Red rings</span> = Hot numbers, <span className="text-blue-500 ml-2">Blue rings</span> = Cold numbers </p> <div className="bg-gray-50 p-6 rounded-xl"> <div className="flex flex-wrap justify-center"> {renderNumberGrid()} </div> </div> {currentConfig.hasBonus && ( <div className="text-center"> <h3 className="text-lg font-bold mb-3">Bonus Number (Optional)</h3> <div className="flex flex-wrap justify-center gap-2 max-w-md mx-auto"> {Array.from({length: currentConfig.maxNumber}, (_, i) => i + 1).map(num => ( <button key={num} onClick={() => setBonusNumber(bonusNumber === num ? null : num)} className={` w-8 h-8 rounded-full text-sm font-bold transition-all ${bonusNumber === num ? 'bg-yellow-500 text-white' : 'bg-gray-200 text-gray-700 hover:bg-gray-300' } `} > {num} </button> ))} </div> </div> )} <div className="text-center"> <p className="text-lg mb-4"> Selected: <span className="font-bold text-blue-600">{selectedNumbers.join(', ')}</span> ({selectedNumbers.length}/{currentConfig.numbersCount}) {bonusNumber && <span className="text-yellow-600 ml-2">Bonus: {bonusNumber}</span>} </p> <button onClick={analyzeSelectedNumbers} disabled={selectedNumbers.length !== currentConfig.numbersCount} className="bg-blue-600 text-white px-6 py-3 rounded-lg font-bold disabled:bg-gray-300 hover:bg-blue-700 transition-colors" > Analyze Selection </button> </div> {analysis && ( <div className="bg-white border rounded-xl p-6"> <h3 className="text-xl font-bold mb-4">Selection Analysis</h3> <div className="grid md:grid-cols-3 gap-4"> {analysis.map(item => ( <div key={item.number} className="p-4 bg-gray-50 rounded-lg text-center"> <div className="text-2xl font-bold text-blue-600">{item.number}</div> <div className="text-sm text-gray-600">Appeared {item.frequency.toFixed(1)} times</div> <div className="text-sm text-gray-600">Last seen: {item.lastSeen} draws ago</div> </div> ))} </div> </div> )} </div> )} {/* History Tab */} {activeTab === 'history' && ( <div className="space-y-6"> <div className="flex justify-between items-center"> <h2 className="text-2xl font-bold">{currentConfig.name} Draw History</h2> <button onClick={exportToCSV} className="flex items-center bg-green-600 text-white px-4 py-2 rounded-lg hover:bg-green-700 transition-colors" > <Download className="w-4 h-4 mr-2" /> Export CSV </button> </div> <div className="overflow-x-auto"> <table className="w-full border-collapse"> <thead> <tr className="bg-gray-100"> <th className="border p-3 text-left">Date</th> <th className="border p-3 text-left">Winning Numbers</th> {currentConfig.hasBonus && <th className="border p-3 text-left">Bonus</th>} <th className="border p-3 text-left">Jackpot</th> </tr> </thead> <tbody> {currentData.slice(-25).reverse().map((draw, index) => ( <tr key={index} className="hover:bg-gray-50"> <td className="border p-3">{draw.date}</td> <td className="border p-3"> <div className="flex gap-1 flex-wrap"> {draw.numbers.map(num => ( <span key={num} className="bg-blue-100 px-2 py-1 rounded text-sm font-bold"> {num} </span> ))} </div> </td> {currentConfig.hasBonus && ( <td className="border p-3"> {draw.bonus && ( <span className="bg-yellow-100 px-2 py-1 rounded text-sm font-bold"> {draw.bonus} </span> )} </td> )} <td className="border p-3 font-bold">J${draw.jackpot.toLocaleString()}</td> </tr> ))} </tbody> </table> </div> </div> )} {/* Manual Input Tab */} {activeTab === 'manual' && ( <div className="space-y-6"> <h2 className="text-2xl font-bold flex items-center"> <Plus className="mr-2 text-green-500" /> Manual {currentConfig.name} Entry </h2> <div className="bg-gray-50 rounded-xl p-6"> <div className="grid md:grid-cols-2 gap-6 mb-6"> <div> <label className="block text-sm font-bold text-gray-700 mb-2">Draw Date</label> <input type="date" value={manualInputDate} onChange={(e) => setManualInputDate(e.target.value)} className="w-full p-3 border rounded-lg focus:ring-2 focus:ring-blue-500" /> </div> <div> <label className="block text-sm font-bold text-gray-700 mb-2">Jackpot Amount</label> <input type="text" placeholder="e.g., 50000000" value={manualInputJackpot} onChange={(e) => setManualInputJackpot(e.target.value)} className="w-full p-3 border rounded-lg focus:ring-2 focus:ring-blue-500" /> </div> </div> <div className="mb-6"> <label className="block text-sm font-bold text-gray-700 mb-2"> Winning Numbers (Select {currentConfig.numbersCount}) </label> <div className="flex flex-wrap justify-center bg-white p-4 rounded-lg"> {renderNumberGrid(true)} </div> <p className="text-center mt-2 text-sm text-gray-600"> Selected: {manualInputNumbers.join(', ')} ({manualInputNumbers.length}/{currentConfig.numbersCount}) </p> </div> {currentConfig.hasBonus && ( <div className="mb-6"> <label className="block text-sm font-bold text-gray-700 mb-2">Bonus Number</label> <input type="number" min="1" max={currentConfig.maxNumber} placeholder={`1-${currentConfig.maxNumber}`} value={manualInputBonus} onChange={(e) => setManualInputBonus(e.target.value)} className="w-full max-w-xs p-3 border rounded-lg focus:ring-2 focus:ring-blue-500" /> </div> )} <button onClick={addManualEntry} disabled={manualInputNumbers.length !== currentConfig.numbersCount || !manualInputDate} className="w-full bg-green-600 text-white py-3 px-6 rounded-lg font-bold hover:bg-green-700 disabled:bg-gray-300 transition-colors" > <Save className="w-4 h-4 inline mr-2" /> Add Entry to Database </button> </div> </div> )} {/* Database Tab */} {activeTab === 'database' && ( <div className="space-y-6"> <h2 className="text-2xl font-bold flex items-center"> <Database className="mr-2 text-purple-500" /> Database Management </h2> <div className="grid md:grid-cols-2 gap-6"> {/* Scraping Section */} <div className="bg-gradient-to-br from-purple-50 to-blue-50 rounded-xl p-6"> <h3 className="text-xl font-bold mb-4 text-purple-700">Auto Data Scraping</h3> <p className="text-gray-600 mb-4"> Automatically collect historical data from multiple sources including Supreme Ventures and Jamaica Index. This will update both Lotto and Super Lotto databases. </p> {isScrapingData ? ( <div className="text-center"> <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-purple-600 mx-auto mb-4"></div> <p className="text-purple-700 font-medium">{scrapingStatus}</p> </div> ) : ( <button onClick={scrapeDatabase} className="w-full bg-purple-600 text-white py-3 px-6 rounded-lg font-bold hover:bg-purple-700 transition-colors flex items-center justify-center" > <RefreshCw className="w-4 h-4 mr-2" /> Scrape & Update Database </button> )} <div className="mt-4 text-sm text-gray-500"> <h4 className="font-bold mb-2">Data Sources:</h4> <ul className="space-y-1"> <li>• Supreme Ventures Official Site</li> <li>• Jamaica Index Lottery Results</li> <li>• Historical Archives</li> <li>• Third-party Lottery APIs</li> </ul> </div> </div> {/* Export Section */} <div className="bg-gradient-to-br from-green-50 to-blue-50 rounded-xl p-6"> <h3 className="text-xl font-bold mb-4 text-green-700">Data Export</h3> <p className="text-gray-600 mb-4"> Export historical data to CSV format for external analysis, backup purposes, or integration with other tools. </p> <div className="space-y-3"> <button onClick={() => exportSpecificData('lotto')} className="w-full bg-blue-600 text-white py-2 px-4 rounded-lg font-medium hover:bg-blue-700 transition-colors" > <Download className="w-4 h-4 inline mr-2" /> Export Lotto Data ({historicalData.lotto?.length || 0} records) </button> <button onClick={() => exportSpecificData('superlotto')} className="w-full bg-purple-600 text-white py-2 px-4 rounded-lg font-medium hover:bg-purple-700 transition-colors" > <Download className="w-4 h-4 inline mr-2" /> Export Super Lotto Data ({historicalData.superlotto?.length || 0} records) </button> <button onClick={() => exportAllData()} className="w-full bg-green-600 text-white py-2 px-4 rounded-lg font-medium hover:bg-green-700 transition-colors" > <Download className="w-4 h-4 inline mr-2" /> Export All Data (Combined CSV) </button> </div> <div className="mt-4 text-sm text-gray-500"> <h4 className="font-bold mb-2">CSV Format Includes:</h4> <ul className="space-y-1"> <li>• Date of draw</li> <li>• Winning numbers</li> <li>• Bonus numbers (where applicable)</li> <li>• Jackpot amounts</li> <li>• Game type identifier</li> </ul> </div> </div> </div> {/* Database Statistics */} <div className="bg-white border rounded-xl p-6"> <h3 className="text-xl font-bold mb-4">Database Statistics</h3> <div className="grid md:grid-cols-4 gap-4"> <div className="text-center p-4 bg-blue-50 rounded-lg"> <div className="text-2xl font-bold text-blue-600">{historicalData.lotto?.length || 0}</div> <div className="text-sm text-gray-600">Lotto Records</div> </div> <div className="text-center p-4 bg-purple-50 rounded-lg"> <div className="text-2xl font-bold text-purple-600">{historicalData.superlotto?.length || 0}</div> <div className="text-sm text-gray-600">Super Lotto Records</div> </div> <div className="text-center p-4 bg-green-50 rounded-lg"> <div className="text-2xl font-bold text-green-600"> {((historicalData.lotto?.length || 0) + (historicalData.superlotto?.length || 0))} </div> <div className="text-sm text-gray-600">Total Records</div> </div> <div className="text-center p-4 bg-yellow-50 rounded-lg"> <div className="text-2xl font-bold text-yellow-600"> {historicalData.lotto?.length > 0 || historicalData.superlotto?.length > 0 ? new Date().toLocaleDateString() : 'N/A'} </div> <div className="text-sm text-gray-600">Last Updated</div> </div> </div> </div> {/* Import Section */} <div className="bg-gray-50 rounded-xl p-6"> <h3 className="text-xl font-bold mb-4">Import Data</h3> <p className="text-gray-600 mb-4"> Import historical data from CSV files or other sources. </p> <div className="flex gap-3"> <input type="file" accept=".csv" className="flex-1 p-3 border rounded-lg" onChange={handleFileImport} /> <button className="bg-gray-600 text-white px-6 py-3 rounded-lg font-medium hover:bg-gray-700 transition-colors"> <Upload className="w-4 h-4 inline mr-2" /> Import </button> </div> </div> {/* API Configuration (Future) */} <div className="bg-gray-100 rounded-xl p-6 opacity-75"> <h3 className="text-xl font-bold mb-4 text-gray-600">🚧 Future Features</h3> <div className="space-y-2 text-sm text-gray-500"> <p>• Real-time API integration with Supreme Ventures</p> <p>• Automated daily data updates</p> <p>• Advanced machine learning predictions</p> <p>• Mobile app synchronization</p> <p>• Social sharing of predictions</p> </div> </div> </div> )} {/* Footer */} <div className="mt-12 text-center text-gray-500 text-sm border-t pt-6"> <p>⚠️ This is for entertainment purposes only. Lottery games are random and no system can guarantee wins.</p> <div className="mt-2 flex justify-center gap-8 text-xs"> <span>Lotto: Wed & Sat 8:25 PM | Tickets: J$100</span> <span>Super Lotto: Wed & Sat 8:25 PM | Tickets: J$200</span> </div> <p className="mt-2">Always play responsibly within your means.</p> </div> </div> </div> ); // Additional helper functions function exportSpecificData(gameType) { const data = historicalData[gameType] || []; const config = gameConfig[gameType]; if (!data.length) { alert(`No ${config.name} data to export`); return; } const headers = ['Date', 'Numbers', config.hasBonus ? 'Bonus' : null, 'Jackpot', 'Game'].filter(Boolean); const csvContent = [ headers.join(','), ...data.map(row => [ row.date, `"${row.numbers.join(' ')}"`, config.hasBonus ? (row.bonus || '') : null, row.jackpot, config.name ].filter(cell => cell !== null).join(',')) ].join('\n'); downloadCSV(csvContent, `${config.name.toLowerCase().replace(' ', '_')}_results.csv`); } function exportAllData() { const allData = [ ...(historicalData.lotto || []).map(row => ({ ...row, game: 'Lotto' })), ...(historicalData.superlotto || []).map(row => ({ ...row, game: 'Super Lotto' })) ].sort((a, b) => new Date(b.date) - new Date(a.date)); if (!allData.length) { alert('No data to export'); return; } const headers = ['Date', 'Numbers', 'Bonus', 'Jackpot', 'Game']; const csvContent = [ headers.join(','), ...allData.map(row => [ row.date, `"${row.numbers.join(' ')}"`, row.bonus || '', row.jackpot, row.game ].join(',')) ].join('\n'); downloadCSV(csvContent, 'jamaica_lottery_complete_results.csv'); } function downloadCSV(content, filename) { const blob = new Blob([content], { type: 'text/csv;charset=utf-8;' }); const url = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = filename; link.style.display = 'none'; document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(url); } function handleFileImport(event) { const file = event.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = (e) => { try { const csv = e.target.result; const lines = csv.split('\n'); const headers = lines[0].split(','); // Basic CSV parsing (in production, use a proper CSV parser) const importedData = lines.slice(1) .filter(line => line.trim()) .map(line => { const values = line.split(','); return { date: values[0], numbers: values[1].replace(/"/g, '').split(' ').map(n => parseInt(n)).filter(n => !isNaN(n)), bonus: values[2] ? parseInt(values[2]) : null, jackpot: parseInt(values[3]) || 0 }; }) .filter(row => row.numbers.length > 0); if (importedData.length > 0) { // Merge with existing data const updatedData = { ...historicalData }; // Simple merge - in production, implement proper deduplication updatedData[gameType] = [...importedData, ...updatedData[gameType]]; setHistoricalData(updatedData); alert(`Successfully imported ${importedData.length} records`); } } catch (error) { alert('Error importing file. Please check the format.'); } }; reader.readAsText(file); } }; export default JamaicaLottoAnalyzer;