Commit e84212cf authored by Mahmoud Aglan's avatar Mahmoud Aglan

feat(tournaments): detail view, registration, bracket placeholder, Arabic labels

- Tournament list with registration button for open tournaments
- Tournament detail view with player count, rounds, bracket area
- Register button with loading state and success feedback
- Arabic status labels (تسجيل مفتوح, جارية, منتهية)
- Format names in Arabic (سويسري, دوري, خروج المغلوب)
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 0f9efb00
import * as net from '../../../core/net.js';
import * as scene from '../../../core/scene.js';
import * as audio from '../../../core/audio.js';
import * as store from '../../../core/store.js';
import { t } from '../../../core/i18n.js';
export async function mountTournaments(el) {
el.innerHTML = `
<div style="padding:var(--s-4);display:flex;flex-direction:column;gap:var(--s-4);">
<div style="display:flex;align-items:center;gap:var(--s-3);">
<div style="padding:16px;display:flex;flex-direction:column;gap:16px;">
<div style="display:flex;align-items:center;gap:12px;">
<button class="btn btn-secondary" id="back-btn" style="width:36px;height:36px;padding:0;">←</button>
<h2 style="font-size:18px;font-weight:700;">${t('rank.tournaments')}</h2>
</div>
<div id="tournament-list">
<div class="skeleton" style="height:100px;margin-bottom:var(--s-3);"></div>
<div class="skeleton" style="height:100px;margin-bottom:12px;"></div>
<div class="skeleton" style="height:100px;"></div>
</div>
</div>
......@@ -24,42 +25,137 @@ export async function mountTournaments(el) {
const tournaments = data.tournaments || data || [];
renderTournaments(el, tournaments);
} catch (e) {
el.querySelector('#tournament-list').innerHTML = `<p style="color:var(--text-secondary);text-align:center;">${t('common.empty')}</p>`;
el.querySelector('#tournament-list').innerHTML = `<p style="color:#94a3b8;text-align:center;">${t('common.empty')}</p>`;
}
}
function renderTournaments(el, tournaments) {
const list = el.querySelector('#tournament-list');
if (tournaments.length === 0) {
list.innerHTML = `<p style="color:var(--text-secondary);text-align:center;padding:var(--s-8);">${t('common.empty')}</p>`;
list.innerHTML = `<p style="color:#94a3b8;text-align:center;padding:32px;">لا توجد بطولات حالياً</p>`;
return;
}
list.innerHTML = tournaments.map(tour => `
<div class="card" style="padding:var(--s-4);margin-bottom:var(--s-3);">
<div class="card tournament-card" data-id="${tour.id}" style="padding:16px;margin-bottom:12px;cursor:pointer;">
<div style="display:flex;justify-content:space-between;align-items:start;">
<div>
<div style="font-size:15px;font-weight:700;">${tour.name || tour.title || 'Tournament'}</div>
<div style="font-size:12px;color:var(--text-secondary);margin-top:2px;">${tour.game_key || 'chess'} · ${tour.format || 'swiss'}</div>
<div style="font-size:11px;color:var(--text-muted);margin-top:4px;">${tour.starts_at ? new Date(tour.starts_at).toLocaleDateString('ar') : ''}</div>
</div>
<div style="text-align:left;">
<span style="font-size:11px;padding:2px 8px;border-radius:var(--r-full);background:${getStatusColor(tour.status)};color:white;">${tour.status || 'upcoming'}</span>
<div style="font-size:15px;font-weight:700;">${tour.name || 'بطولة'}</div>
<div style="font-size:12px;color:#94a3b8;margin-top:2px;">${tour.game_key || 'chess'} · ${formatName(tour.format)}</div>
<div style="font-size:11px;color:#64748b;margin-top:4px;">${tour.starts_at ? new Date(tour.starts_at).toLocaleDateString('ar') : ''}</div>
</div>
<span style="font-size:10px;padding:3px 8px;border-radius:9999px;background:${getStatusColor(tour.status)};color:white;font-weight:600;">${getStatusLabel(tour.status)}</span>
</div>
<div style="display:flex;gap:var(--s-3);margin-top:var(--s-3);">
<span style="font-size:11px;color:var(--text-secondary);">👥 ${tour.player_count || 0}/${tour.max_players || 32}</span>
<span style="font-size:11px;color:var(--gold);">🏆 ${tour.prize_pool || 'N/A'}</span>
<div style="display:flex;gap:16px;margin-top:12px;padding-top:8px;border-top:1px solid rgba(255,255,255,0.05);">
<span style="font-size:11px;color:#94a3b8;">👥 ${tour.player_count || 0}/${tour.max_players || 32}</span>
<span style="font-size:11px;color:#E4AC38;">🏆 ${tour.prize_pool_coins ? tour.prize_pool_coins + ' عملة' : 'N/A'}</span>
${tour.entry_fee_coins ? `<span style="font-size:11px;color:#F87171;">💰 ${tour.entry_fee_coins}</span>` : ''}
</div>
${tour.status === 'registration' ? `<button class="btn btn-primary w-full register-btn" data-tid="${tour.id}" style="margin-top:12px;font-size:13px;">سجّل الآن</button>` : ''}
</div>
`).join('');
// Register button handlers
list.querySelectorAll('.register-btn').forEach(btn => {
btn.addEventListener('click', async (e) => {
e.stopPropagation();
audio.play('click');
const tid = btn.dataset.tid;
btn.disabled = true;
btn.textContent = 'جاري التسجيل...';
try {
await net.post('tournaments.php', { action: 'register', tournament_id: tid });
btn.textContent = '✅ تم التسجيل';
btn.style.background = '#34D399';
} catch (err) {
btn.textContent = err.message || 'فشل التسجيل';
btn.disabled = false;
}
});
});
// Card click → detail
list.querySelectorAll('.tournament-card').forEach(card => {
card.addEventListener('click', () => {
audio.play('click');
showTournamentDetail(el, card.dataset.id, tournaments.find(t => t.id === card.dataset.id));
});
});
}
async function showTournamentDetail(el, tournamentId, tour) {
const list = el.querySelector('#tournament-list');
list.innerHTML = `
<div style="margin-bottom:16px;">
<button class="btn btn-secondary" id="detail-back" style="font-size:12px;min-height:32px;padding:4px 12px;">← رجوع للقائمة</button>
</div>
<div class="card" style="padding:16px;">
<div style="font-size:18px;font-weight:700;margin-bottom:4px;">${tour?.name || 'بطولة'}</div>
<div style="font-size:12px;color:#94a3b8;margin-bottom:12px;">${formatName(tour?.format)} · ${tour?.game_key || 'chess'}</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:16px;">
<div style="background:#1a2440;padding:8px;border-radius:8px;text-align:center;">
<div style="font-size:16px;font-weight:700;color:#E4AC38;">${tour?.player_count || 0}</div>
<div style="font-size:10px;color:#64748b;">لاعبين</div>
</div>
<div style="background:#1a2440;padding:8px;border-radius:8px;text-align:center;">
<div style="font-size:16px;font-weight:700;color:#00FFFF;">${tour?.rounds_total || tour?.swiss_rounds || '?'}</div>
<div style="font-size:10px;color:#64748b;">جولات</div>
</div>
</div>
</div>
<div id="bracket-area" style="margin-top:12px;">
<div class="skeleton" style="height:200px;border-radius:8px;"></div>
</div>
`;
el.querySelector('#detail-back').addEventListener('click', () => {
audio.play('click');
mountTournaments(el);
});
// Load bracket/standings
try {
const data = await net.get('tournaments.php', { action: 'detail', id: tournamentId });
renderBracketOrStandings(el, data, tour?.format);
} catch (e) {
el.querySelector('#bracket-area').innerHTML = `<p style="color:#64748b;text-align:center;">لا توجد نتائج بعد</p>`;
}
}
function renderBracketOrStandings(el, data, format) {
const area = el.querySelector('#bracket-area');
if (!data || (!data.rounds && !data.brackets)) {
area.innerHTML = `<p style="color:#64748b;text-align:center;padding:16px;">لا توجد نتائج بعد</p>`;
return;
}
area.innerHTML = `
<div class="card" style="padding:12px;">
<div style="font-size:14px;font-weight:600;margin-bottom:8px;">النتائج</div>
<div style="font-size:12px;color:#94a3b8;">بيانات البطولة متاحة عند بدء الجولات</div>
</div>
`;
}
function getStatusColor(status) {
switch (status) {
case 'registration': return 'var(--success)';
case 'in_progress': return 'var(--orange)';
case 'completed': return 'var(--text-muted)';
default: return 'var(--blue)';
case 'registration': return '#34D399';
case 'in_progress': return '#E84D1E';
case 'completed': return '#64748b';
default: return '#2082F0';
}
}
function getStatusLabel(status) {
switch (status) {
case 'registration': return 'تسجيل مفتوح';
case 'in_progress': return 'جارية';
case 'completed': return 'منتهية';
case 'draft': return 'قريباً';
default: return status || 'قادمة';
}
}
function formatName(format) {
const names = { swiss: 'سويسري', round_robin: 'دوري', single_elimination: 'خروج المغلوب', double_elimination: 'خروج مزدوج', arena: 'أرينا' };
return names[format] || format || '';
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment