import { supabase, getPlayers, addPlayer, getRecentGames, getHighScores } from './supabase.js'; import { SCORE_CATEGORIES, ALL_CATEGORIES, calculateTotals, isGameComplete, calculatePossibleScores } from './gameLogic.js'; import { renderScorecard, renderPlayerLeaderboard, renderRecentGames, renderHighScores } from './ui.js'; import { checkPassword, CORRECT_PASSWORD } from './auth.js'; // DOM-element const appContainer = document.getElementById('app'); const gameContainer = document.getElementById('game-container'); const startScreen = document.getElementById('start-screen'); const scorecardHead = document.getElementById('scorecard-head'); const scorecardBody = document.getElementById('scorecard-body'); const gameIdDisplay = document.getElementById('game-id-display'); const startGameModal = document.getElementById('start-game-modal'); const showStartModalBtn = document.getElementById('show-start-modal-btn'); const newGameBtn = document.getElementById('new-game-btn'); const backToStartBtn = document.getElementById('back-to-start-btn'); const endGameBtn = document.getElementById('end-game-btn'); const cancelStartGameBtn = document.getElementById('cancel-start-game-btn'); const addPlayerBtn = document.getElementById('add-player-btn'); const newPlayerNameInput = document.getElementById('new-player-name'); const newPlayerWinsInput = document.getElementById('new-player-wins'); const playerListContainer = document.getElementById('player-list'); const startGameBtn = document.getElementById('start-game-btn'); const alertModal = document.getElementById('alert-modal'); const alertModalTitle = document.getElementById('alert-modal-title'); const alertModalMessage = document.getElementById('alert-modal-message'); const scoreSelectModal = document.getElementById('score-select-modal'); const scoreModalTitle = document.getElementById('score-modal-title'); const scoreModalOptions = document.getElementById('score-modal-options'); const scoreModalCancelBtn = document.getElementById('score-modal-cancel-btn'); const themeToggle = document.getElementById('theme-toggle'); const themeIconLight = document.getElementById('theme-icon-light'); const themeIconDark = document.getElementById('theme-icon-dark'); const passwordModal = document.getElementById('password-modal'); const passwordInput = document.getElementById('password-input'); const passwordSubmitBtn = document.getElementById('password-submit-btn'); const passwordError = document.getElementById('password-error'); const confirmModal = document.getElementById('confirm-modal'); const diceContainer = document.getElementById('dice-container'); const rollDiceBtn = document.getElementById('roll-dice-btn'); // Global state let currentGameId = null; let currentGameData = null; let gameUnsubscribe = null; let selectedPlayersInOrder = []; let currentDice = [1, 1, 1, 1, 1]; // Standardvärden för tärningar let rollsLeft = 3; // Antal kast kvar const appId = 'yatzy-app'; // Funktion för att visa meddelanden function showAlert(message, title = 'Varning', onOkCallback = null) { alertModalTitle.textContent = title; alertModalMessage.innerHTML = message; alertModal.classList.remove('hidden'); const oldBtn = document.getElementById('alert-modal-close-btn'); const newBtn = oldBtn.cloneNode(true); oldBtn.parentNode.replaceChild(newBtn, oldBtn); newBtn.addEventListener('click', () => { alertModal.classList.add('hidden'); if (onOkCallback) onOkCallback(); }, { once: true }); } // Funktion för att visa bekräftelsedialog function showConfirm(onSave, onDelete) { confirmModal.classList.remove('hidden'); const saveBtn = document.getElementById('confirm-save-btn'); const deleteBtn = document.getElementById('confirm-delete-btn'); const cancelBtn = document.getElementById('confirm-cancel-btn'); const close = () => confirmModal.classList.add('hidden'); saveBtn.onclick = () => { close(); onSave(); }; deleteBtn.onclick = () => { close(); onDelete(); }; cancelBtn.onclick = () => close(); } // Funktion för att slå tärningar function rollDice() { if (rollsLeft <= 0) { showAlert("Du har inga kast kvar!", "Inga kast kvar"); return; } const lockedDice = Array.from(document.querySelectorAll('.dice.locked')); const lockedIndices = lockedDice.map(die => parseInt(die.dataset.index)); currentDice = currentDice.map((die, index) => { if (lockedIndices.includes(index)) { return die; } else { return Math.floor(Math.random() * 6) + 1; } }); rollsLeft--; updateDiceUI(); updateRollButton(); console.log(`Tärningar efter kast: ${currentDice}, Kast kvar: ${rollsLeft}`); } // Funktion för att uppdatera tärnings-UI function updateDiceUI() { diceContainer.innerHTML = currentDice.map((die, index) => `
Inga spelare hittades. Lägg till en ovan.
'; } else { playerListContainer.innerHTML = players.map(p => ` `).join(''); // Lägg till event listeners för checkboxarna const checkboxes = playerListContainer.querySelectorAll('input[type="checkbox"]'); checkboxes.forEach(checkbox => { checkbox.addEventListener('change', (e) => { const playerId = e.target.dataset.playerId; const playerName = e.target.dataset.playerName; if (e.target.checked) { if (!selectedPlayersInOrder.some(p => p.id === playerId)) { selectedPlayersInOrder.push({ id: playerId, name: playerName }); } } else { selectedPlayersInOrder = selectedPlayersInOrder.filter(p => p.id !== playerId); } updateStartGameButtonState(); console.log("Valda spelare:", selectedPlayersInOrder); }); }); } } catch (error) { console.error("Error loading players:", error); playerListContainer.innerHTML = `Kunde inte ladda spelare: ${error.message}
`; } } // Funktion för att uppdatera spelknappens status function updateStartGameButtonState() { console.log("Uppdaterar spelknappens status. Valda spelare:", selectedPlayersInOrder); startGameBtn.disabled = selectedPlayersInOrder.length === 0; } // Funktion för att öppna/stänga modaler function openStartGameModal() { selectedPlayersInOrder = []; loadPlayersForSelection(); startGameModal.classList.remove('hidden'); } function closeStartGameModal() { startGameModal.classList.add('hidden'); } // Funktion för att applicera tema function applyTheme(theme) { if (theme === 'dark') { document.documentElement.classList.add('dark'); themeIconLight.classList.add('hidden'); themeIconDark.classList.remove('hidden'); } else { document.documentElement.classList.remove('dark'); themeIconLight.classList.remove('hidden'); themeIconDark.classList.add('hidden'); } } // Funktion för att återställa till startsidan async function resetToStartScreen() { if (gameUnsubscribe) { gameUnsubscribe.unsubscribe(); gameUnsubscribe = null; } currentGameId = null; currentGameData = null; localStorage.removeItem(`yatzee-gameId-${appId}`); gameContainer.classList.add('hidden'); startScreen.classList.remove('hidden'); await renderAllLeaderboards(); } // Funktion för att rendera alla topplistor async function renderAllLeaderboards() { await Promise.all([ renderPlayerLeaderboard(), renderRecentGames(), renderHighScores() ]); } // Funktion för att lägga till standardspelare async function addDefaultPlayers() { const defaultPlayers = [ { name: "Emanuel", wins: 580 }, { name: "Mamma", wins: 555 }, { name: "Pappa", wins: 556 } ]; for (const player of defaultPlayers) { const { data, error } = await supabase .from('players') .select('name') .eq('name', player.name) .single(); if (!data) { const { error: insertError } = await supabase .from('players') .insert([player]); if (insertError) console.error(`Failed to add default player ${player.name}:`, insertError); else console.log(`Default player "${player.name}" added.`); } } } // Funktion för att skapa ett nytt spel async function createNewGame(selectedPlayers) { if (selectedPlayers.length === 0) { showAlert("Välj minst en spelare.", "Inmatningsfel"); return; } try { const initialScores = {}; const playersForGame = []; selectedPlayers.forEach(p => { playersForGame.push({ id: p.id, name: p.name }); initialScores[p.id] = { ...Object.fromEntries(ALL_CATEGORIES.map(c => [c.id, null])), }; }); const { data, error } = await supabase .from('games') .insert([{ players: playersForGame, scores: initialScores, isFinished: false, currentPlayerIndex: 0, currentDice: currentDice, rollsLeft: rollsLeft }]) .select() .single(); if (error) throw error; setCurrentGame(data.id); closeStartGameModal(); } catch (error) { console.error("Error creating new game:", error); showAlert(`Kunde inte skapa spel: ${error.message}`, "Databasfel"); } } // Funktion för att sätta det aktuella spelet function setCurrentGame(gameId) { if (gameUnsubscribe) { gameUnsubscribe.unsubscribe(); gameUnsubscribe = null; } currentGameId = gameId; localStorage.setItem(`yatzee-gameId-${appId}`, gameId); if (gameId) { gameUnsubscribe = supabase .channel(`game:${gameId}`) .on('postgres_changes', { event: 'UPDATE', schema: 'public', table: 'games', filter: `id=eq.${gameId}` }, payload => { currentGameData = payload.new; currentDice = payload.new.currentDice || [1, 1, 1, 1, 1]; rollsLeft = payload.new.rollsLeft || 3; renderGame(currentGameData); }) .subscribe(); // Initial fetch supabase.from('games').select('*').eq('id', gameId).single().then(({ data, error }) => { if (data) { currentGameData = data; currentDice = data.currentDice || [1, 1, 1, 1, 1]; rollsLeft = data.rollsLeft || 3; renderGame(currentGameData); } else { resetToStartScreen(); } }); } else { resetToStartScreen(); } } // Funktion för att rendera spelet function renderGame(gameData) { gameContainer.classList.remove('hidden'); startScreen.classList.add('hidden'); gameIdDisplay.textContent = currentGameId; if (isGameComplete(gameData) && !gameData.isFinished) { endGameBtn.classList.remove('hidden'); } else { endGameBtn.classList.add('hidden'); } renderScorecard(gameData, scorecardHead, scorecardBody); updateDiceUI(); updateRollButton(); } // Funktion för att visa modalen för att välja poäng function showScoreSelectModal(playerId, categoryId, possibleScores) { console.log(`Visar poängval för spelare ${playerId}, kategori ${categoryId}, möjliga poäng:`, possibleScores); const category = ALL_CATEGORIES.find(cat => cat.id === categoryId); scoreModalTitle.textContent = `Välj poäng för ${category.name}`; scoreModalOptions.innerHTML = possibleScores.map(score => ` `).join(''); scoreSelectModal.classList.remove('hidden'); // Lägg till event listeners för poängalternativen const scoreOptionButtons = document.querySelectorAll('.score-option'); scoreOptionButtons.forEach(button => { button.addEventListener('click', async (e) => { const score = e.currentTarget.dataset.score; const playerId = e.currentTarget.dataset.playerId; const categoryId = e.currentTarget.dataset.categoryId; console.log(`Poäng vald: Spelare ${playerId}, Kategori ${categoryId}, Poäng ${score}`); // Uppdatera poängen i databasen await updateScore(playerId, categoryId, parseInt(score)); scoreSelectModal.classList.add('hidden'); }); }); } // Funktion för att uppdatera poängen i databasen async function updateScore(playerId, categoryId, score) { try { const updatedScores = { ...currentGameData.scores }; updatedScores[playerId][categoryId] = score; const nextPlayerIndex = isGameComplete(currentGameData) ? currentGameData.currentPlayerIndex : (currentGameData.currentPlayerIndex + 1) % currentGameData.players.length; const { error } = await supabase .from('games') .update({ scores: updatedScores, currentPlayerIndex: nextPlayerIndex, rollsLeft: 3, currentDice: [1, 1, 1, 1, 1] }) .eq('id', currentGameId); if (error) { console.error("Fel vid uppdatering av poäng:", error); showAlert("Kunde inte uppdatera poängen. Försök igen.", "Fel"); } } catch (error) { console.error("Oväntat fel vid uppdatering av poäng:", error); showAlert("Ett oväntat fel uppstod. Försök igen.", "Fel"); } } // Funktion för att hantera klick på poängfälten function attachScorecardEventListeners() { const scoreCells = document.querySelectorAll('.score-cell:not(.filled):not(.score-cell-disabled)'); scoreCells.forEach(cell => { cell.addEventListener('click', async (e) => { const playerId = e.currentTarget.dataset.playerId; const currentPlayerId = currentGameData.players[currentGameData.currentPlayerIndex].id; if (playerId !== currentPlayerId) { showAlert("Det är inte din tur!", "Fel spelare"); return; } const categoryId = e.currentTarget.dataset.categoryId; console.log(`Poängfält klickat: Spelare ${playerId}, Kategori ${categoryId}`); // Hämta möjliga poäng för den valda kategorin const possibleScores = calculatePossibleScores({...currentGameData, currentDice}, playerId, categoryId); // Visa modal för att välja poäng showScoreSelectModal(playerId, categoryId, possibleScores); }); }); } // Funktion för att koppla event listeners function attachEventListeners() { if (showStartModalBtn) showStartModalBtn.addEventListener('click', openStartGameModal); if (newGameBtn) newGameBtn.addEventListener('click', openStartGameModal); if (cancelStartGameBtn) cancelStartGameBtn.addEventListener('click', closeStartGameModal); if (addPlayerBtn) addPlayerBtn.addEventListener('click', addPlayerHandler); if (scoreModalCancelBtn) scoreModalCancelBtn.addEventListener('click', () => scoreSelectModal.classList.add('hidden')); if (rollDiceBtn) rollDiceBtn.addEventListener('click', rollDice); if (newPlayerNameInput) { newPlayerNameInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') addPlayerHandler(); }); } if (themeToggle) { themeToggle.addEventListener('click', () => { const isDark = document.documentElement.classList.toggle('dark'); const newTheme = isDark ? 'dark' : 'light'; localStorage.setItem('theme', newTheme); applyTheme(newTheme); }); } if (passwordSubmitBtn) { passwordSubmitBtn.addEventListener('click', () => { checkPassword(passwordInput, passwordError, passwordModal, appContainer); }); } if (passwordInput) { passwordInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { checkPassword(passwordInput, passwordError, passwordModal, appContainer); } }); } if (startGameBtn) { startGameBtn.addEventListener('click', () => { console.log("Starta spel-knappen klickad! Valda spelare:", selectedPlayersInOrder); createNewGame(selectedPlayersInOrder); }); } } // Funktion för att starta appen (function() { const savedTheme = localStorage.getItem('theme') || 'light'; applyTheme(savedTheme); attachEventListeners(); if (sessionStorage.getItem('yatzy-authenticated') === 'true') { passwordModal.classList.add('hidden'); appContainer.classList.remove('hidden'); addDefaultPlayers().then(() => resetToStartScreen()); } else { passwordModal.classList.remove('hidden'); appContainer.classList.add('hidden'); } })();