// ============================================================================ // Tamagotchi as a Service — Frontend Application // ============================================================================ const API_BASE = window.TAMAGOTCHI_API_URL || '/api'; const REFRESH_INTERVAL = 5000; // Refresh creature stats every 5 seconds // Creature type emoji map const TYPE_EMOJI = { dragon: '🐉', cat: '🐱', robot: '🤖', plant: '🌱', alien: '👽', }; // i18n translations const i18n = { en: { adopt_title: 'Adopt a Creature', name_label: 'Name', type_label: 'Type', cancel: 'Cancel', adopt_btn: 'Adopt! 🎉', hunger: 'Hunger', happiness: 'Happiness', energy: 'Energy', feed: '🍖 Feed', play: '🎮 Play', sleep: '💤 Sleep', revive: '✨ Revive', alive: 'Alive', dead: 'Dead', empty_title: 'No creatures yet!', empty_subtitle: 'Click the + button to adopt your first creature.', }, fr: { adopt_title: 'Adopter une Créature', name_label: 'Nom', type_label: 'Type', cancel: 'Annuler', adopt_btn: 'Adopter ! 🎉', hunger: 'Faim', happiness: 'Bonheur', energy: 'Énergie', feed: '🍖 Nourrir', play: '🎮 Jouer', sleep: '💤 Dormir', revive: '✨ Ressusciter', alive: 'Vivant', dead: 'Mort', empty_title: 'Pas encore de créatures !', empty_subtitle: 'Cliquez sur le bouton + pour adopter votre première créature.', }, }; let currentLang = 'en'; let creatures = []; // ---- i18n ---- function t(key) { return (i18n[currentLang] && i18n[currentLang][key]) || i18n.en[key] || key; } function setLang(lang) { currentLang = lang; document.querySelectorAll('.lang-btn').forEach(btn => { btn.classList.toggle('active', btn.dataset.lang === lang); }); document.querySelectorAll('[data-i18n]').forEach(el => { el.textContent = t(el.dataset.i18n); }); renderCreatures(); } // ---- API Calls ---- async function fetchCreatures() { try { const res = await fetch(`${API_BASE}/creatures`); if (!res.ok) throw new Error(`HTTP ${res.status}`); creatures = await res.json(); renderCreatures(); updateGlobalStats(); } catch (err) { console.error('Failed to fetch creatures:', err); } } async function fetchGlobalStats() { try { const res = await fetch(`${API_BASE}/stats`); if (!res.ok) throw new Error(`HTTP ${res.status}`); const stats = await res.json(); document.getElementById('aliveCount').textContent = stats.alive_count || 0; document.getElementById('deadCount').textContent = stats.dead_count || 0; document.getElementById('starvingCount').textContent = stats.starving_count || 0; } catch (err) { console.error('Failed to fetch stats:', err); } } function updateGlobalStats() { const alive = creatures.filter(c => c.is_alive).length; const dead = creatures.filter(c => !c.is_alive).length; const starving = creatures.filter(c => c.is_alive && c.hunger > 80).length; document.getElementById('aliveCount').textContent = alive; document.getElementById('deadCount').textContent = dead; document.getElementById('starvingCount').textContent = starving; } async function adoptCreature(name, type) { try { const res = await fetch(`${API_BASE}/creatures`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name, type }), }); if (!res.ok) throw new Error(`HTTP ${res.status}`); const creature = await res.json(); showToast(`${creature.name} ${TYPE_EMOJI[creature.type]} has been adopted!`); await fetchCreatures(); } catch (err) { showToast(`Failed to adopt creature: ${err.message}`); } } async function creatureAction(id, action) { try { const res = await fetch(`${API_BASE}/creatures/${id}/${action}`, { method: 'POST' }); if (!res.ok) { const data = await res.json(); showToast(data.error || `Action failed`); return; } const data = await res.json(); showToast(data.message); await fetchCreatures(); } catch (err) { showToast(`Action failed: ${err.message}`); } } // ---- Rendering ---- function getStatColor(stat, value) { if (stat === 'hunger') { if (value > 80) return 'var(--accent-red)'; if (value > 50) return 'var(--accent-orange)'; return 'var(--accent-green)'; } if (value < 20) return 'var(--accent-red)'; if (value < 50) return 'var(--accent-yellow)'; return stat === 'happiness' ? 'var(--accent-purple)' : 'var(--accent-cyan)'; } function renderCreatures() { const grid = document.getElementById('creaturesGrid'); if (creatures.length === 0) { grid.innerHTML = `
${t('empty_subtitle')}