// Yeni Deneme Ekleme Sayfası function NewExamPage({ settings, onSave }) { const { useState, useMemo } = React; const [denemeAdi, setDenemeAdi] = useState(''); const [denemeTarihi, setDenemeTarihi] = useState(new Date().toISOString().split('T')[0]); const [tyt, setTyt] = useState({ TURKCE: { correct: 0, wrong: 0 }, SOSYAL: { correct: 0, wrong: 0 }, // Aggregated Social Sciences MAT: { correct: 0, wrong: 0 }, FEN: { correct: 0, wrong: 0 }, // Aggregated Natural Sciences // Detailed Social Sciences subjects TARIH: { correct: 0, wrong: 0 }, COGRAFYA: { correct: 0, wrong: 0 }, FELSEFE: { correct: 0, wrong: 0 }, DIN: { correct: 0, wrong: 0 }, // Detailed Natural Sciences subjects FIZIK: { correct: 0, wrong: 0 }, KIMYA: { correct: 0, wrong: 0 }, BIYOLOJI: { correct: 0, wrong: 0 } }); const [say, setSay] = useState({ MAT2: { correct: 0, wrong: 0 }, FIZ: { correct: 0, wrong: 0 }, KIM: { correct: 0, wrong: 0 }, BIO: { correct: 0, wrong: 0 }, }); // QUESTION_LIMITS objesi (utils.js dosyasından kopyalandı) const QUESTION_LIMITS = { TURKCE: 40, SOSYAL: 20, MAT: 40, FEN: 20, MAT2: 40, FIZ: 14, KIM: 13, BIO: 13, TARIH: 5, COGRAFYA: 5, FELSEFE: 5, DIN: 5, FIZIK: 7, KIMYA: 7, BIYOLOJI: 6 }; // Helper functions (utils.js dosyasından kopyalandı) function round2(n) { return Math.round(n * 100) / 100; } function safeNum(n) { const v = Number(n); return Number.isFinite(v) ? v : 0; } function net(correct, wrong) { return correct - wrong / 4; } const [saving, setSaving] = useState(false); const [message, setMessage] = useState(''); // Kariyer.net modülünü kullanarak hesaplama const hesaplama = useMemo(() => { const tytNets = { TURKCE: KariyerNetYKS.net(tyt.TURKCE.correct, tyt.TURKCE.wrong), SOSYAL: KariyerNetYKS.net(tyt.SOSYAL.correct, tyt.SOSYAL.wrong), MAT: KariyerNetYKS.net(tyt.MAT.correct, tyt.MAT.wrong), FEN: KariyerNetYKS.net(tyt.FEN.correct, tyt.FEN.wrong) }; const aytSayNets = { MAT2: KariyerNetYKS.net(say.MAT2.correct, say.MAT2.wrong), FIZ: KariyerNetYKS.net(say.FIZ.correct, say.FIZ.wrong), KIM: KariyerNetYKS.net(say.KIM.correct, say.KIM.wrong), BIO: KariyerNetYKS.net(say.BIO.correct, say.BIO.wrong) }; const diploma = settings?.diploma_notu || 0; return KariyerNetYKS.calculate({ tytNets, aytSayNets, diploma }); }, [tyt, say, settings]); const diplomaKatkisi = hesaplama.obpKatkisi; const tytHamPuan = hesaplama.tyt.hamPuan; const tytPuan = hesaplama.tyt.yerlestirmePuani; const aytHamPuan = hesaplama.say.hamPuan; const aytPuan = hesaplama.say.yerlestirmePuani; // Net hesaplamaları const tytToplamNet = useMemo(() => { return KariyerNetYKS.round2( KariyerNetYKS.net(tyt.TURKCE.correct, tyt.TURKCE.wrong) + KariyerNetYKS.net(tyt.SOSYAL.correct, tyt.SOSYAL.wrong) + KariyerNetYKS.net(tyt.MAT.correct, tyt.MAT.wrong) + KariyerNetYKS.net(tyt.FEN.correct, tyt.FEN.wrong) ); }, [tyt]); const aytToplamNet = useMemo(() => { return KariyerNetYKS.round2( KariyerNetYKS.net(say.MAT2.correct, say.MAT2.wrong) + KariyerNetYKS.net(say.FIZ.correct, say.FIZ.wrong) + KariyerNetYKS.net(say.KIM.correct, say.KIM.wrong) + KariyerNetYKS.net(say.BIO.correct, say.BIO.wrong) ); }, [say]); // Detailed TYT subject nets const tytDetailedNets = useMemo(() => { return { TARIH: KariyerNetYKS.net(tyt.TARIH.correct, tyt.TARIH.wrong), COGRAFYA: KariyerNetYKS.net(tyt.COGRAFYA.correct, tyt.COGRAFYA.wrong), FELSEFE: KariyerNetYKS.net(tyt.FELSEFE.correct, tyt.FELSEFE.wrong), DIN: KariyerNetYKS.net(tyt.DIN.correct, tyt.DIN.wrong), FIZIK: KariyerNetYKS.net(tyt.FIZIK.correct, tyt.FIZIK.wrong), KIMYA: KariyerNetYKS.net(tyt.KIMYA.correct, tyt.KIMYA.wrong), BIYOLOJI: KariyerNetYKS.net(tyt.BIYOLOJI.correct, tyt.BIYOLOJI.wrong) }; }, [tyt]); // Calculate aggregated social sciences net const tytSosyalNet = useMemo(() => { // If user entered values for aggregated section, use those if (tyt.SOSYAL.correct > 0 || tyt.SOSYAL.wrong > 0) { return KariyerNetYKS.net(tyt.SOSYAL.correct, tyt.SOSYAL.wrong); } // Otherwise calculate from individual subjects return KariyerNetYKS.round2( tytDetailedNets.TARIH + tytDetailedNets.COGRAFYA + tytDetailedNets.FELSEFE + tytDetailedNets.DIN ); }, [tyt, tytDetailedNets]); // Calculate aggregated natural sciences net const tytFenNet = useMemo(() => { // If user entered values for aggregated section, use those if (tyt.FEN.correct > 0 || tyt.FEN.wrong > 0) { return KariyerNetYKS.net(tyt.FEN.correct, tyt.FEN.wrong); } // Otherwise calculate from individual subjects return KariyerNetYKS.round2( tytDetailedNets.FIZIK + tytDetailedNets.KIMYA + tytDetailedNets.BIYOLOJI ); }, [tyt, tytDetailedNets]); // Sıralama bilgileri const tytHamSiralama = hesaplama.tyt.hamSiralama; const tytYerlestirmeSiralama = hesaplama.tyt.yerlestirmeSiralama; const aytHamSiralama = hesaplama.say.hamSiralama; const aytYerlestirmeSiralama = hesaplama.say.yerlestirmeSiralama; const handleTyt = (name, field, val) => { setTyt((s) => { const newState = { ...s, [name]: { ...s[name], [field]: val } }; // Update SOSYAL when individual subjects are updated if (['TARIH', 'COGRAFYA', 'FELSEFE', 'DIN'].includes(name) && (field === 'correct' || field === 'wrong')) { // If any individual subject is being updated, update SOSYAL with sum of individual subjects const tarihCorrect = name === 'TARIH' && field === 'correct' ? val : s.TARIH.correct; const tarihWrong = name === 'TARIH' && field === 'wrong' ? val : s.TARIH.wrong; const cografyaCorrect = name === 'COGRAFYA' && field === 'correct' ? val : s.COGRAFYA.correct; const cografyaWrong = name === 'COGRAFYA' && field === 'wrong' ? val : s.COGRAFYA.wrong; const felsefeCorrect = name === 'FELSEFE' && field === 'correct' ? val : s.FELSEFE.correct; const felsefeWrong = name === 'FELSEFE' && field === 'wrong' ? val : s.FELSEFE.wrong; const dinCorrect = name === 'DIN' && field === 'correct' ? val : s.DIN.correct; const dinWrong = name === 'DIN' && field === 'wrong' ? val : s.DIN.wrong; newState.SOSYAL = { correct: tarihCorrect + cografyaCorrect + felsefeCorrect + dinCorrect, wrong: tarihWrong + cografyaWrong + felsefeWrong + dinWrong }; } // Update FEN when individual subjects are updated if (['FIZIK', 'KIMYA', 'BIYOLOJI'].includes(name) && (field === 'correct' || field === 'wrong')) { // If any individual subject is being updated, update FEN with sum of individual subjects const fizikCorrect = name === 'FIZIK' && field === 'correct' ? val : s.FIZIK.correct; const fizikWrong = name === 'FIZIK' && field === 'wrong' ? val : s.FIZIK.wrong; const kimyaCorrect = name === 'KIMYA' && field === 'correct' ? val : s.KIMYA.correct; const kimyaWrong = name === 'KIMYA' && field === 'wrong' ? val : s.KIMYA.wrong; const biyolojiCorrect = name === 'BIYOLOJI' && field === 'correct' ? val : s.BIYOLOJI.correct; const biyolojiWrong = name === 'BIYOLOJI' && field === 'wrong' ? val : s.BIYOLOJI.wrong; newState.FEN = { correct: fizikCorrect + kimyaCorrect + biyolojiCorrect, wrong: fizikWrong + kimyaWrong + biyolojiWrong }; } // Clear individual subjects when SOSYAL is updated if (name === 'SOSYAL' && (field === 'correct' || field === 'wrong')) { // If SOSYAL is being updated, clear individual subjects if they had values if (val > 0 && (s.TARIH.correct > 0 || s.TARIH.wrong > 0 || s.COGRAFYA.correct > 0 || s.COGRAFYA.wrong > 0 || s.FELSEFE.correct > 0 || s.FELSEFE.wrong > 0 || s.DIN.correct > 0 || s.DIN.wrong > 0)) { newState.TARIH = { correct: 0, wrong: 0 }; newState.COGRAFYA = { correct: 0, wrong: 0 }; newState.FELSEFE = { correct: 0, wrong: 0 }; newState.DIN = { correct: 0, wrong: 0 }; } } // Clear individual subjects when FEN is updated if (name === 'FEN' && (field === 'correct' || field === 'wrong')) { // If FEN is being updated, clear individual subjects if they had values if (val > 0 && (s.FIZIK.correct > 0 || s.FIZIK.wrong > 0 || s.KIMYA.correct > 0 || s.KIMYA.wrong > 0 || s.BIYOLOJI.correct > 0 || s.BIYOLOJI.wrong > 0)) { newState.FIZIK = { correct: 0, wrong: 0 }; newState.KIMYA = { correct: 0, wrong: 0 }; newState.BIYOLOJI = { correct: 0, wrong: 0 }; } } return newState; }); }; const handleSay = (name, field, val) => { setSay((s) => ({ ...s, [name]: { ...s[name], [field]: val } })); }; const handleSave = async () => { if (!denemeAdi.trim()) { setMessage('❌ Lütfen deneme adı girin'); return; } setSaving(true); setMessage(''); const hasAytData = Object.values(say).some(section => Number(section.correct) > 0 || Number(section.wrong) > 0); const examData = { deneme_adi: denemeAdi.trim() || 'İsimsiz Deneme', deneme_tarihi: denemeTarihi, // Turkish tyt_turkce_dogru: tyt.TURKCE.correct, tyt_turkce_yanlis: tyt.TURKCE.wrong, // Social Sciences - Individual Subjects tyt_tarih_dogru: tyt.TARIH.correct, tyt_tarih_yanlis: tyt.TARIH.wrong, tyt_cografya_dogru: tyt.COGRAFYA.correct, tyt_cografya_yanlis: tyt.COGRAFYA.wrong, tyt_felsefe_dogru: tyt.FELSEFE.correct, tyt_felsefe_yanlis: tyt.FELSEFE.wrong, tyt_din_dogru: tyt.DIN.correct, tyt_din_yanlis: tyt.DIN.wrong, // Social Sciences - Aggregated tyt_sosyal_dogru: tyt.SOSYAL.correct > 0 || tyt.SOSYAL.wrong > 0 ? tyt.SOSYAL.correct : tyt.TARIH.correct + tyt.COGRAFYA.correct + tyt.FELSEFE.correct + tyt.DIN.correct, tyt_sosyal_yanlis: tyt.SOSYAL.correct > 0 || tyt.SOSYAL.wrong > 0 ? tyt.SOSYAL.wrong : tyt.TARIH.wrong + tyt.COGRAFYA.wrong + tyt.FELSEFE.wrong + tyt.DIN.wrong, // Mathematics tyt_mat_dogru: tyt.MAT.correct, tyt_mat_yanlis: tyt.MAT.wrong, // Natural Sciences - Individual Subjects tyt_fizik_dogru: tyt.FIZIK.correct, tyt_fizik_yanlis: tyt.FIZIK.wrong, tyt_kimya_dogru: tyt.KIMYA.correct, tyt_kimya_yanlis: tyt.KIMYA.wrong, tyt_biyoloji_dogru: tyt.BIYOLOJI.correct, tyt_biyoloji_yanlis: tyt.BIYOLOJI.wrong, // Natural Sciences - Aggregated tyt_fen_dogru: tyt.FEN.correct > 0 || tyt.FEN.wrong > 0 ? tyt.FEN.correct : tyt.FIZIK.correct + tyt.KIMYA.correct + tyt.BIYOLOJI.correct, tyt_fen_yanlis: tyt.FEN.correct > 0 || tyt.FEN.wrong > 0 ? tyt.FEN.wrong : tyt.FIZIK.wrong + tyt.KIMYA.wrong + tyt.BIYOLOJI.wrong, // AYT Subjects ayt_mat_dogru: say.MAT2.correct, ayt_mat_yanlis: say.MAT2.wrong, ayt_fizik_dogru: say.FIZ.correct, ayt_fizik_yanlis: say.FIZ.wrong, ayt_kimya_dogru: say.KIM.correct, ayt_kimya_yanlis: say.KIM.wrong, ayt_biyoloji_dogru: say.BIO.correct, ayt_biyoloji_yanlis: say.BIO.wrong, tyt_ham_puan: tytHamPuan, tyt_puan: tytPuan, ayt_ham_puan: hasAytData ? aytHamPuan : 0, ayt_puan: hasAytData ? aytPuan : 0, hesaplama_modu: hasAytData ? 'kariyernet_ayt' : 'kariyernet_tyt', tahmini_siralama: hasAytData ? aytYerlestirmeSiralama : tytYerlestirmeSiralama, }; const result = await apiCall('/exam.php', { method: 'POST', body: JSON.stringify(examData), }); if (result.success) { setMessage('✅ Deneme başarıyla kaydedildi!'); setTimeout(() => { onSave(); }, 1500); } else { setMessage('❌ Hata: ' + result.message); } setSaving(false); }; return (

✏️ Yeni Deneme Ekle

{/* Genel Bilgiler */}
setDenemeAdi(e.target.value)} placeholder="örn: ÖZDEBİR" className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-gray-700 input-field" />
setDenemeTarihi(e.target.value)} className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-gray-700 input-field" />
{/* TYT Netleri */}

📘 TYT Netleri

{/* Main TYT Subjects */}
{/* Social Sciences Section */}

🌍 Sosyal Bilimler

{/* Aggregated Social Sciences Input */}
{/* Detailed Social Sciences Subjects */}
{/* Aggregated Social Sciences Display */} {/*
Sosyal Bilimler Toplam (Kullanılan) {tytSosyalNet} net
{tyt.SOSYAL.correct > 0 || tyt.SOSYAL.wrong > 0 ? "Toplam değeri doğrudan girildi" : "Detaylı derslerden hesaplandı"}
*/}
{/* Natural Sciences Section */}

🔬 Fen Bilimleri

{/* Aggregated Natural Sciences Input */}
{/* Detailed Natural Sciences Subjects */}
{/* Aggregated Natural Sciences Display */} {/*
Fen Bilimleri Toplam (Kullanılan) {tytFenNet} net
{tyt.FEN.correct > 0 || tyt.FEN.wrong > 0 ? "Toplam değeri doğrudan girildi" : "Detaylı derslerden hesaplandı"}
*/}
TYT Toplam Net
{tytToplamNet}
TYT Ham Puan
{KariyerNetYKS.round3(tytHamPuan)}
Sıralama: {tytHamSiralama?.toLocaleString('tr-TR')}
TYT Yerleştirme Puanı
{KariyerNetYKS.round3(tytPuan)}
(Ham + OBP)
🎯 TYT Sıralaması
{tytYerlestirmeSiralama?.toLocaleString('tr-TR')}
(2024 verileri)
{/* AYT-SAY Netleri */}

📗 AYT-SAY Netleri

{/* Ana Sonuçlar */}
AYT Toplam Net
{aytToplamNet}
Ham Puan
{KariyerNetYKS.round3(aytHamPuan)}
Sıralama: {aytHamSiralama?.toLocaleString('tr-TR')}
Yerleştirme Puanı
{KariyerNetYKS.round3(aytPuan)}
(Ham + OBP)
🎯 Sıralama (SAY)
{aytYerlestirmeSiralama?.toLocaleString('tr-TR')}
2024 Gerçek Veriler
{/* Kaydet */}
{message && (
{message}
)}
); } function SectionRow({ label, name, value, onChange, disabled = false, questionLimits }) { // Check if limit exists for this name const limit = questionLimits ? questionLimits[name] || 0 : 0; // Don't use safeNum for displaying in inputs to avoid showing "0" by default const c = value.correct || ''; const w = value.wrong || ''; // Only use safeNum for calculations const correctNum = safeNum(value.correct); const wrongNum = safeNum(value.wrong); // Calculate blank questions with safety check const b = limit > 0 ? Math.max(0, limit - correctNum - wrongNum) : 0; const n = round2(net(correctNum, wrongNum)); // More robust overflow check const overflow = limit > 0 && (correctNum + wrongNum) > limit; return (
{label} (max {limit})
0 ? limit : undefined} placeholder="0" onChange={(e) => onChange(name, "correct", e.target.value === '' ? '' : Number(e.target.value))} disabled={disabled} />
0 ? limit : undefined} placeholder="0" onChange={(e) => onChange(name, "wrong", e.target.value === '' ? '' : Number(e.target.value))} disabled={disabled} />
Boş
{b}
Net
{n}
); } // İstatistikler Sayfası function StatisticsPage() { const { useState, useEffect, useRef } = React; const [stats, setStats] = useState(null); const [loading, setLoading] = useState(true); const chartRef = useRef(null); const chartInstance = useRef(null); const tytChartRef = useRef(null); const tytChartInstance = useRef(null); useEffect(() => { loadStatistics(); }, []); useEffect(() => { if (stats && stats.trend && stats.trend.length > 0) { renderChart(); } else if (chartInstance.current) { chartInstance.current.destroy(); chartInstance.current = null; } if (stats && stats.tyt_trend && stats.tyt_trend.length > 0) { renderTytChart(); } else if (tytChartInstance.current) { tytChartInstance.current.destroy(); tytChartInstance.current = null; } return () => { if (chartInstance.current) { chartInstance.current.destroy(); chartInstance.current = null; } if (tytChartInstance.current) { tytChartInstance.current.destroy(); tytChartInstance.current = null; } }; }, [stats]); const loadStatistics = async () => { setLoading(true); const result = await apiCall('/statistics.php'); if (result.success) { setStats(result.data); } setLoading(false); }; const renderChart = () => { if (!chartRef.current || !stats.trend || stats.trend.length === 0) return; if (chartInstance.current) { chartInstance.current.destroy(); } const ctx = chartRef.current.getContext('2d'); chartInstance.current = new Chart(ctx, { type: 'line', data: { labels: stats.trend.map(t => t.deneme_tarihi), datasets: [ { label: 'TYT Puan', data: stats.trend.map(t => t.tyt_puan), borderColor: 'rgb(45, 55, 72)', backgroundColor: 'rgba(45, 55, 72, 0.1)', tension: 0.4, fill: true, pointRadius: 5, pointBackgroundColor: 'rgb(45, 55, 72)', pointBorderColor: '#fff', pointBorderWidth: 2 }, { label: 'AYT Puan', data: stats.trend.map(t => t.ayt_puan), borderColor: 'rgb(34, 197, 94)', backgroundColor: 'rgba(34, 197, 94, 0.1)', tension: 0.4, fill: true, pointRadius: 5, pointBackgroundColor: 'rgb(34, 197, 94)', pointBorderColor: '#fff', pointBorderWidth: 2 }, ], }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'top', labels: { font: { size: 12, family: "'Inter', sans-serif" } } }, title: { display: true, text: 'Puan Gelişim', font: { size: 16, family: "'Inter', sans-serif", weight: 'bold' } }, }, scales: { y: { beginAtZero: false, grid: { color: 'rgba(0, 0, 0, 0.05)' }, ticks: { font: { family: "'Inter', sans-serif" } } }, x: { grid: { color: 'rgba(0, 0, 0, 0.05)' }, ticks: { font: { family: "'Inter', sans-serif" } } } }, interaction: { mode: 'index', intersect: false }, plugins: { tooltip: { backgroundColor: 'rgba(255, 255, 255, 0.9)', titleColor: '#333', bodyColor: '#666', borderColor: 'rgba(0, 0, 0, 0.1)', borderWidth: 1, padding: 10, usePointStyle: true, callbacks: { label: function(context) { return `${context.dataset.label}: ${context.parsed.y.toFixed(2)}`; } } } } }, }); }; const renderTytChart = () => { if (!tytChartRef.current || !stats.tyt_trend || stats.tyt_trend.length === 0) return; if (tytChartInstance.current) { tytChartInstance.current.destroy(); } const ctx = tytChartRef.current.getContext('2d'); tytChartInstance.current = new Chart(ctx, { type: 'line', data: { labels: stats.tyt_trend.map(t => t.deneme_tarihi), datasets: [ { label: 'TYT Puan', data: stats.tyt_trend.map(t => t.tyt_puan), borderColor: 'rgb(37, 99, 235)', backgroundColor: 'rgba(37, 99, 235, 0.15)', tension: 0.4, fill: true, pointRadius: 5, pointBackgroundColor: 'rgb(37, 99, 235)', pointBorderColor: '#fff', pointBorderWidth: 2 } ], }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'top', labels: { font: { size: 12, family: "'Inter', sans-serif" } } }, title: { display: true, text: 'TYT Puan Gelişimi', font: { size: 16, family: "'Inter', sans-serif", weight: 'bold' } }, tooltip: { backgroundColor: 'rgba(255, 255, 255, 0.9)', titleColor: '#333', bodyColor: '#666', borderColor: 'rgba(0, 0, 0, 0.1)', borderWidth: 1, padding: 10, usePointStyle: true, callbacks: { label: function(context) { return `${context.dataset.label}: ${context.parsed.y.toFixed(2)}`; } } } }, scales: { y: { beginAtZero: false, grid: { color: 'rgba(59, 130, 246, 0.08)' }, ticks: { font: { family: "'Inter', sans-serif" } } }, x: { grid: { color: 'rgba(59, 130, 246, 0.08)' }, ticks: { font: { family: "'Inter', sans-serif" } } } }, interaction: { mode: 'index', intersect: false } }, }); }; if (loading) { return
Yükleniyor...
; } if (!stats || !stats.genel || stats.genel.toplam_deneme === 0) { return (
📊

Henüz istatistik yok

Deneme ekleyerek istatistiklerinizi görüntüleyin!

➕ Yeni Deneme Ekle
); } return (

📈 İstatistikler ve İlerleme

Deneme performansınızı detaylı şekilde inceleyin

{/* Genel İstatistikler */}

🎯 Genel Performans

{/* İlerleme */} {stats.ilerleme && stats.ilerleme.ilk_deneme && (

📊 İlerlemeniz

TYT Net Artışı
{stats.ilerleme.tyt_net_artis > 0 ? '+' : ''}{round2(stats.ilerleme.tyt_net_artis)}
{round2(stats.ilerleme.ilk_deneme.tyt_toplam_net)} → {round2(stats.ilerleme.son_deneme.tyt_toplam_net)}
AYT Net Artışı
{stats.ilerleme.ayt_net_artis > 0 ? '+' : ''}{round2(stats.ilerleme.ayt_net_artis)}
{round2(stats.ilerleme.ilk_deneme.ayt_toplam_net)} → {round2(stats.ilerleme.son_deneme.ayt_toplam_net)}
)} {/* Ders Bazında Ortalamalar */}

📚 Ders Bazında Ortalamalar

{/* Genel Puan Grafiği */} {stats.trend && stats.trend.length > 0 && (

📈 Genel Puan Gelişimi

)} {/* TYT Puan Grafiği ve Listesi */} {stats.tyt_trend && stats.tyt_trend.length > 0 && (

📘 TYT Puan Gelişim Grafiği

📋 TYT Denemeleri

{stats.tyt_trend.slice().reverse().map((exam, index) => (
{exam.deneme_adi || `TYT Denemesi ${index + 1}`}
{exam.deneme_tarihi}
{round2(exam.tyt_puan)} puan
Toplam Net: {round2(exam.tyt_toplam_net)} Puan: {round2(exam.tyt_puan)}
))}
)}
); } function DersNetCard({ label, avg, max, color, textColor }) { return (
{label}
{round2(avg || 0)}
En yüksek: {round2(max || 0)}
); } function StatCard({ title, value, suffix = '', icon, color }) { return (
{icon} {value}{suffix}

{title}

); } // Export the StatisticsPage component so it can be imported in app.jsx window.StatisticsPage = StatisticsPage;