{"id":124,"date":"2025-07-07T11:45:16","date_gmt":"2025-07-07T11:45:16","guid":{"rendered":"https:\/\/santtucreations.com\/?page_id=124"},"modified":"2025-07-14T12:30:18","modified_gmt":"2025-07-14T12:30:18","slug":"todo","status":"publish","type":"page","link":"https:\/\/santtucreations.com\/?page_id=124","title":{"rendered":"todo"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"124\" class=\"elementor elementor-124\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ccca13f e-con-full e-flex e-con e-parent\" data-id=\"ccca13f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-dd9e5e4 elementor-widget elementor-widget-html\" data-id=\"dd9e5e4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!DOCTYPE html>\r\n<html lang=\"fi\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n    <title>Selv\u00e4 Suunta - Alkoholink\u00e4yt\u00f6n Seuranta<\/title>\r\n    <script src=\"https:\/\/cdn.tailwindcss.com\"><\/script>\r\n    <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/chart.js@3.7.1\/dist\/chart.min.js\"><\/script>\r\n    <link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700&display=swap\" rel=\"stylesheet\">\r\n    \r\n    <style>\r\n        body {\r\n            margin: 0 !important;\r\n            padding: 0 !important;\r\n            background-color: #111827 !important;\r\n        }\r\n        #selva-suunta-app-wrapper {\r\n            font-family: 'Inter', sans-serif !important;\r\n            background-color: #111827 !important;\r\n            color: #ffffff !important;\r\n            -webkit-font-smoothing: antialiased;\r\n            -moz-osx-font-smoothing: grayscale;\r\n            min-height: 100vh;\r\n        }\r\n        #selva-suunta-app-wrapper *,\r\n        #selva-suunta-app-wrapper *::before,\r\n        #selva-suunta-app-wrapper *::after {\r\n            box-sizing: border-box;\r\n        }\r\n        #selva-suunta-app-wrapper .chart-container {\r\n            position: relative;\r\n            height: 300px;\r\n            width: 100%;\r\n        }\r\n        #selva-suunta-app-wrapper .toast {\r\n            visibility: hidden; min-width: 250px; margin-left: -125px;\r\n            background-color: #e53e3e; color: #fff; text-align: center;\r\n            border-radius: 8px; padding: 16px; position: fixed;\r\n            z-index: 10000; left: 50%; bottom: 30px; font-size: 17px;\r\n            opacity: 0; transition: visibility 0s, opacity 0.5s linear;\r\n        }\r\n        #selva-suunta-app-wrapper .toast.success {\r\n             background-color: #4CAF50;\r\n        }\r\n        #selva-suunta-app-wrapper .toast.show { visibility: visible; opacity: 1; }\r\n        #selva-suunta-app-wrapper .task-item.done span { text-decoration: line-through; color: #6b7280; }\r\n        [v-cloak] { display: none; }\r\n        button:disabled, input:disabled {\r\n            opacity: 0.5;\r\n            cursor: not-allowed;\r\n        }\r\n        .modal-overlay {\r\n            position: fixed;\r\n            top: 0;\r\n            left: 0;\r\n            right: 0;\r\n            bottom: 0;\r\n            background-color: rgba(0, 0, 0, 0.7);\r\n            display: flex;\r\n            align-items: center;\r\n            justify-content: center;\r\n            z-index: 50;\r\n        }\r\n    <\/style>\r\n<\/head>\r\n<body>\r\n\r\n    <div id=\"selva-suunta-app-wrapper\">\r\n        \r\n        <!-- Login View -->\r\n        <div id=\"login-view\" class=\"flex flex-col items-center justify-center min-h-screen text-center p-4\">\r\n            <h1 class=\"text-4xl md:text-5xl font-bold text-cyan-400\">Selv\u00e4 Suunta<\/h1>\r\n            <p class=\"text-gray-400 mt-2 mb-8\">Kirjaudu sis\u00e4\u00e4n jatkaaksesi.<\/p>\r\n            <button id=\"login-btn\" class=\"bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded-lg transition duration-300 flex items-center gap-3\">\r\n                <svg class=\"w-6 h-6\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 48 48\"><path fill=\"#FFC107\" d=\"M43.611,20.083H42V20H24v8h11.303c-1.649,4.657-6.08,8-11.303,8c-6.627,0-12-5.373-12-12c0-6.627,5.373-12,12-12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C12.955,4,4,12.955,4,24c0,11.045,8.955,20,20,20c11.045,0,20-8.955,20-20C44,22.659,43.862,21.35,43.611,20.083z\"><\/path><path fill=\"#FF3D00\" d=\"M6.306,14.691l6.571,4.819C14.655,15.108,18.961,12,24,12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C16.318,4,9.656,8.337,6.306,14.691z\"><\/path><path fill=\"#4CAF50\" d=\"M24,44c5.166,0,9.86-1.977,13.409-5.192l-6.19-5.238C29.211,35.091,26.715,36,24,36c-5.202,0-9.619-3.317-11.283-7.946l-6.522,5.025C9.505,39.556,16.227,44,24,44z\"><\/path><path fill=\"#1976D2\" d=\"M43.611,20.083H42V20H24v8h11.303c-0.792,2.237-2.231,4.166-4.089,5.571l6.19,5.238C42.021,35.596,44,30.138,44,24C44,22.659,43.862,21.35,43.611,20.083z\"><\/path><\/svg>\r\n                Kirjaudu Google-tilill\u00e4\r\n            <\/button>\r\n        <\/div>\r\n\r\n        <!-- Main App View -->\r\n        <div id=\"app-view\" style=\"display: none;\">\r\n            <div id=\"selva-suunta-app\">\r\n                <div class=\"container mx-auto p-4 md:p-6 max-w-4xl\">\r\n                    \r\n                    <header class=\"text-center mb-8 relative\">\r\n                        <h1 class=\"text-4xl md:text-5xl font-bold text-cyan-400\">Selv\u00e4 Suunta<\/h1>\r\n                        <p class=\"text-gray-400 mt-2\">Tavoitteena terveellisempi el\u00e4m\u00e4, p\u00e4iv\u00e4 kerrallaan.<\/p>\r\n                        <div id=\"auth-info\" class=\"absolute top-0 right-0 text-right\">\r\n                             <p id=\"user-name\" class=\"text-sm text-gray-300\"><\/p>\r\n                             <button id=\"logout-btn\" class=\"text-xs text-cyan-400 hover:underline\">Kirjaudu ulos<\/button>\r\n                        <\/div>\r\n                    <\/header>\r\n\r\n                    <div id=\"loading-indicator\" class=\"text-center p-8\">\r\n                        <p class=\"text-lg\">Ladataan tietoja...<\/p>\r\n                    <\/div>\r\n\r\n                    <div id=\"app-content\" style=\"display: none;\">\r\n                        <main class=\"bg-gray-800 rounded-2xl shadow-lg p-6 mb-8\">\r\n                            <div class=\"flex flex-col md:flex-row items-center justify-between mb-6\">\r\n                                <h2 class=\"text-2xl font-semibold text-white mb-4 md:mb-0\">P\u00e4iv\u00e4n kirjaus<\/h2>\r\n                                <input type=\"date\" id=\"date-picker\" class=\"bg-gray-700 border border-gray-600 text-white rounded-lg p-2 focus:ring-cyan-500 focus:border-cyan-500\">\r\n                            <\/div>\r\n                            <div class=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\r\n                                <div>\r\n                                    <h3 class=\"font-semibold mb-3 text-lg\">Lis\u00e4\u00e4 juomia:<\/h3>\r\n                                    <div id=\"drink-buttons\" class=\"flex flex-wrap gap-2\">\r\n                                        <button onclick=\"App.addDrink('Olut (0.5l)', 1.5)\" class=\"bg-cyan-600 hover:bg-cyan-700 text-white font-bold py-2 px-4 rounded-lg transition duration-300\">\ud83c\udf7a Olut<\/button>\r\n                                        <button onclick=\"App.addDrink('Viini (16cl)', 1.5)\" class=\"bg-cyan-600 hover:bg-cyan-700 text-white font-bold py-2 px-4 rounded-lg transition duration-300\">\ud83c\udf77 Viini<\/button>\r\n                                        <button onclick=\"App.addDrink('V\u00e4kev\u00e4 (4cl)', 1.0)\" class=\"bg-cyan-600 hover:bg-cyan-700 text-white font-bold py-2 px-4 rounded-lg transition duration-300\">\ud83e\udd43 V\u00e4kev\u00e4<\/button>\r\n                                    <\/div>\r\n                                    <div id=\"daily-drinks\" class=\"mt-4 space-y-2\"><\/div>\r\n                                <\/div>\r\n                                <div>\r\n                                    <h3 class=\"font-semibold mb-3 text-lg\">T\u00e4m\u00e4nhetkinen paino:<\/h3>\r\n                                    <input type=\"number\" id=\"weight-input\" placeholder=\"Paino (kg)\" class=\"w-full bg-gray-700 border border-gray-600 rounded-lg p-2 text-white placeholder-gray-400 focus:ring-cyan-500 focus:border-cyan-500\">\r\n                                    <div class=\"mt-6 flex flex-col sm:flex-row gap-3\">\r\n                                        <button id=\"save-day\" class=\"w-full bg-green-600 hover:bg-green-700 text-white font-bold py-3 px-4 rounded-lg transition duration-300 text-lg\">\ud83d\udcbe Tallenna p\u00e4iv\u00e4<\/button>\r\n                                        <button id=\"sober-day\" class=\"w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-4 rounded-lg transition duration-300\">\ud83d\udc4d Juomaton p\u00e4iv\u00e4<\/button>\r\n                                    <\/div>\r\n                                <\/div>\r\n                            <\/div>\r\n                        <\/main>\r\n                        <section class=\"bg-gray-800 rounded-2xl shadow-lg p-6 mb-8\">\r\n                            <h2 class=\"text-2xl font-semibold mb-4\">Teht\u00e4v\u00e4t<\/h2>\r\n                            <div class=\"flex flex-col sm:flex-row gap-2 mb-4\">\r\n                                <input type=\"text\" id=\"todo-input\" placeholder=\"Lis\u00e4\u00e4 uusi teht\u00e4v\u00e4...\" class=\"flex-grow bg-gray-700 border border-gray-600 rounded-lg p-2 text-white placeholder-gray-400 focus:ring-cyan-500 focus:border-cyan-500\">\r\n                                <input type=\"date\" id=\"todo-date-input\" class=\"bg-gray-700 border border-gray-600 text-white rounded-lg p-2 focus:ring-cyan-500 focus:border-cyan-500\" title=\"Valitse teht\u00e4v\u00e4n p\u00e4iv\u00e4m\u00e4\u00e4r\u00e4\">\r\n                                <button id=\"add-todo-btn\" class=\"bg-cyan-600 hover:bg-cyan-700 text-white font-bold py-2 px-4 rounded-lg transition duration-300\">Lis\u00e4\u00e4<\/button>\r\n                            <\/div>\r\n                            <h3 class=\"text-xl font-semibold mb-3 mt-4\" id=\"current-day-tasks-title\">T\u00e4m\u00e4n p\u00e4iv\u00e4n teht\u00e4v\u00e4t<\/h3>\r\n                            <ul id=\"todo-list\" class=\"space-y-2\"><\/ul>\r\n                            <div id=\"upcoming-tasks-container\" class=\"mt-6\">\r\n                                <h3 class=\"text-xl font-semibold mb-3\">Tulevat Teht\u00e4v\u00e4t<\/h3>\r\n                                <ul id=\"upcoming-todo-list\" class=\"space-y-2\"><\/ul>\r\n                            <\/div>\r\n                        <\/section>\r\n                        <section class=\"mb-8\">\r\n                            <h2 class=\"text-2xl font-semibold text-center mb-6\">Edistyminen<\/h2>\r\n                            <div class=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4\">\r\n                                <div class=\"bg-gray-800 p-4 rounded-xl text-center shadow-lg\"><h3 class=\"font-semibold text-cyan-400\">Juomattomia p\u00e4ivi\u00e4<\/h3><p id=\"sober-days-count\" class=\"text-3xl font-bold\">0<\/p><\/div>\r\n                                <div class=\"bg-gray-800 p-4 rounded-xl text-center shadow-lg\"><h3 class=\"font-semibold text-cyan-400\">Pisin putki<\/h3><p id=\"sober-streak\" class=\"text-3xl font-bold\">0 pv<\/p><\/div>\r\n                                <div class=\"bg-gray-800 p-4 rounded-xl text-center shadow-lg\"><h3 class=\"font-semibold text-cyan-400\">S\u00e4\u00e4stetyt kalorit<\/h3><p id=\"calories-saved\" class=\"text-3xl font-bold\">0<\/p><\/div>\r\n                                <div class=\"bg-gray-800 p-4 rounded-xl text-center shadow-lg\"><h3 class=\"font-semibold text-cyan-400\">S\u00e4\u00e4stetyt eurot (\u20ac)<\/h3><p id=\"money-saved\" class=\"text-3xl font-bold\">0.00<\/p><\/div>\r\n                            <\/div>\r\n                        <\/section>\r\n                        <section class=\"grid grid-cols-1 lg:grid-cols-2 gap-8 mb-8\">\r\n                            <div class=\"bg-gray-800 p-6 rounded-2xl shadow-lg\"><h3 class=\"font-semibold mb-4 text-center text-xl\">Alkoholiannokset (viimeiset 7 p\u00e4iv\u00e4\u00e4)<\/h3><div class=\"chart-container\"><canvas id=\"units-chart\"><\/canvas><\/div><\/div>\r\n                            <div class=\"bg-gray-800 p-6 rounded-2xl shadow-lg\"><h3 class=\"font-semibold mb-4 text-center text-xl\">Painon kehitys<\/h3><div class=\"chart-container\"><canvas id=\"weight-chart\"><\/canvas><\/div><\/div>\r\n                        <\/section>\r\n                        <section class=\"bg-gray-800 rounded-2xl shadow-lg p-6\">\r\n                            <h2 class=\"text-2xl font-semibold mb-4\">Historia<\/h2>\r\n                            <div class=\"overflow-x-auto\"><table class=\"w-full text-left\"><thead class=\"border-b border-gray-600\"><tr><th class=\"p-3\">P\u00e4iv\u00e4m\u00e4\u00e4r\u00e4<\/th><th class=\"p-3\">Annosta<\/th><th class=\"p-3\">Paino (kg)<\/th><\/tr><\/thead><tbody id=\"history-table-body\"><\/tbody><\/table><\/div>\r\n                        <\/section>\r\n                        \r\n                        <!-- Delete Data Section -->\r\n                        <section class=\"mt-12 text-center\">\r\n                            <button id=\"delete-data-btn\" class=\"bg-red-600 hover:bg-red-700 text-white font-bold py-2 px-4 rounded-lg transition duration-300\">Poista kaikki tiedot<\/button>\r\n                        <\/section>\r\n                    <\/div>\r\n                <\/div>\r\n                <div id=\"toast\" class=\"toast\"><\/div>\r\n            <\/div>\r\n        <\/div>\r\n        \r\n        <!-- Confirmation Modal -->\r\n        <div id=\"confirmation-modal\" class=\"modal-overlay\" style=\"display: none;\">\r\n            <div class=\"bg-gray-800 p-8 rounded-lg shadow-xl text-center\">\r\n                <h3 class=\"text-xl font-bold mb-4\">Haluatko varmasti poistaa kaikki tietosi?<\/h3>\r\n                <p class=\"text-gray-400 mb-6\">T\u00e4t\u00e4 toimintoa ei voi perua.<\/p>\r\n                <div class=\"flex justify-center gap-4\">\r\n                    <button id=\"cancel-delete-btn\" class=\"bg-gray-600 hover:bg-gray-700 text-white font-bold py-2 px-6 rounded-lg\">Peruuta<\/button>\r\n                    <button id=\"confirm-delete-btn\" class=\"bg-red-600 hover:bg-red-700 text-white font-bold py-2 px-6 rounded-lg\">Poista<\/button>\r\n                <\/div>\r\n            <\/div>\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <script type=\"module\">\r\n        \/\/ Import Firebase modules\r\n        import { initializeApp } from \"https:\/\/www.gstatic.com\/firebasejs\/11.6.1\/firebase-app.js\";\r\n        import { getAuth, GoogleAuthProvider, signInWithPopup, onAuthStateChanged, signOut } from \"https:\/\/www.gstatic.com\/firebasejs\/11.6.1\/firebase-auth.js\";\r\n        import { getFirestore, doc, onSnapshot, setDoc } from \"https:\/\/www.gstatic.com\/firebasejs\/11.6.1\/firebase-firestore.js\";\r\n\r\n        \/\/ Your web app's Firebase configuration\r\n        const firebaseConfig = {\r\n            apiKey: \"AIzaSyBBoJZOD90uybVCFL4yfGmum7MHapznS5s\",\r\n            authDomain: \"drink-meter.firebaseapp.com\",\r\n            projectId: \"drink-meter\",\r\n            storageBucket: \"drink-meter.appspot.com\",\r\n            messagingSenderId: \"542036117538\",\r\n            appId: \"1:542036117538:web:ac7cb36d9d123b7168a27b\",\r\n            measurementId: \"G-55HYVT8TVE\"\r\n        };\r\n\r\n        \/\/ Initialize Firebase\r\n        const firebaseApp = initializeApp(firebaseConfig);\r\n        const auth = getAuth(firebaseApp);\r\n        const db = getFirestore(firebaseApp);\r\n        const provider = new GoogleAuthProvider();\r\n\r\n        \/\/ --- GLOBAL APP STATE ---\r\n        const App = {\r\n            \/\/ State\r\n            dailyData: {},\r\n            currentDate: new Date().toISOString().split('T')[0],\r\n            tempDrinks: [],\r\n            tempTodos: [],\r\n            unitsChart: null,\r\n            weightChart: null,\r\n            userId: null,\r\n            unsubscribe: null,\r\n\r\n            \/\/ DOM Elements\r\n            elements: {\r\n                loginView: document.getElementById('login-view'),\r\n                appView: document.getElementById('app-view'),\r\n                loadingIndicator: document.getElementById('loading-indicator'),\r\n                appContent: document.getElementById('app-content'),\r\n                loginBtn: document.getElementById('login-btn'),\r\n                logoutBtn: document.getElementById('logout-btn'),\r\n                userName: document.getElementById('user-name'),\r\n                datePicker: document.getElementById('date-picker'),\r\n                weightInput: document.getElementById('weight-input'),\r\n                dailyDrinksDiv: document.getElementById('daily-drinks'),\r\n                drinkButtons: document.getElementById('drink-buttons'),\r\n                historyTableBody: document.getElementById('history-table-body'),\r\n                todoInput: document.getElementById('todo-input'),\r\n                todoDateInput: document.getElementById('todo-date-input'),\r\n                addTodoBtn: document.getElementById('add-todo-btn'),\r\n                todoList: document.getElementById('todo-list'),\r\n                upcomingTodoList: document.getElementById('upcoming-todo-list'),\r\n                currentDayTasksTitle: document.getElementById('current-day-tasks-title'),\r\n                upcomingTasksContainer: document.getElementById('upcoming-tasks-container'),\r\n                soberDaysCount: document.getElementById('sober-days-count'),\r\n                soberStreak: document.getElementById('sober-streak'),\r\n                caloriesSaved: document.getElementById('calories-saved'),\r\n                moneySaved: document.getElementById('money-saved'),\r\n                unitsCanvas: document.getElementById('units-chart'),\r\n                weightCanvas: document.getElementById('weight-chart'),\r\n                toast: document.getElementById('toast'),\r\n                saveDay: document.getElementById('save-day'),\r\n                soberDay: document.getElementById('sober-day'),\r\n                deleteDataBtn: document.getElementById('delete-data-btn'),\r\n                confirmationModal: document.getElementById('confirmation-modal'),\r\n                confirmDeleteBtn: document.getElementById('confirm-delete-btn'),\r\n                cancelDeleteBtn: document.getElementById('cancel-delete-btn'),\r\n            },\r\n\r\n            \/\/ --- INITIALIZATION ---\r\n            init() {\r\n                this.elements.loginBtn.addEventListener('click', () => this.login());\r\n                this.elements.logoutBtn.addEventListener('click', () => this.logout());\r\n                this.handleAuthState();\r\n            },\r\n\r\n            \/\/ --- AUTHENTICATION ---\r\n            handleAuthState() {\r\n                onAuthStateChanged(auth, user => {\r\n                    if (user) {\r\n                        this.userId = user.uid;\r\n                        this.elements.userName.textContent = user.displayName || user.email;\r\n                        this.elements.loginView.style.display = 'none';\r\n                        this.elements.appView.style.display = 'block';\r\n                        this.loadData();\r\n                    } else {\r\n                        this.userId = null;\r\n                        this.elements.loginView.style.display = 'flex';\r\n                        this.elements.appView.style.display = 'none';\r\n                        if (this.unsubscribe) {\r\n                            this.unsubscribe();\r\n                        }\r\n                    }\r\n                });\r\n            },\r\n\r\n            login() {\r\n                signInWithPopup(auth, provider).catch(error => {\r\n                    console.error(\"Login failed:\", error);\r\n                    let message = \"Kirjautuminen ep\u00e4onnistui. Yrit\u00e4 uudelleen.\";\r\n                    if (error.code === 'auth\/popup-blocked') {\r\n                        message = \"Selain esti ponnahdusikkunan. Salli ponnahdusikkunat ja yrit\u00e4 uudelleen.\";\r\n                    } else if (error.code === 'auth\/unauthorized-domain') {\r\n                        message = \"Verkkotunnusta ei ole valtuutettu. Ota yhteytt\u00e4 sivuston yll\u00e4pitoon.\";\r\n                    }\r\n                    this.showToast(message, false);\r\n                });\r\n            },\r\n\r\n            logout() {\r\n                signOut(auth).catch(error => console.error(\"Logout failed:\", error));\r\n            },\r\n\r\n            \/\/ --- DATA HANDLING (FIRESTORE) ---\r\n            async saveData() {\r\n                if (!this.userId) return;\r\n                const docRef = doc(db, \"users\", this.userId);\r\n                try {\r\n                    await setDoc(docRef, { data: this.dailyData });\r\n                } catch (e) {\r\n                    console.error(\"Error saving document: \", e);\r\n                }\r\n            },\r\n\r\n            loadData() {\r\n                if (!this.userId) return;\r\n                this.elements.loadingIndicator.style.display = 'block';\r\n                this.elements.appContent.style.display = 'none';\r\n\r\n                const docRef = doc(db, \"users\", this.userId);\r\n                this.unsubscribe = onSnapshot(docRef, (docSnap) => {\r\n                    this.dailyData = (docSnap.exists() && docSnap.data().data) ? docSnap.data().data : {};\r\n                    \r\n                    this.elements.loadingIndicator.style.display = 'none';\r\n                    this.elements.appContent.style.display = 'block';\r\n                    \r\n                    if (!this.elements.datePicker.dataset.listener) {\r\n                        this.addAppEventListeners();\r\n                        this.elements.datePicker.dataset.listener = 'true';\r\n                    }\r\n\r\n                    this.elements.datePicker.value = this.currentDate;\r\n                    this.updateUIForDate(this.currentDate);\r\n                    this.checkAndShowNotifications();\r\n                });\r\n            },\r\n            \r\n            async deleteUserData() {\r\n                this.dailyData = {};\r\n                await this.saveData(); \/\/ Overwrites Firestore data with an empty object\r\n                this.elements.confirmationModal.style.display = 'none';\r\n                this.showToast(\"Kaikki tiedot on poistettu.\", true);\r\n            },\r\n\r\n            \/\/ --- EVENT LISTENERS (for the main app) ---\r\n            addAppEventListeners() {\r\n                this.elements.datePicker.addEventListener('change', (e) => {\r\n                    this.currentDate = e.target.value;\r\n                    this.updateUIForDate(this.currentDate);\r\n                });\r\n                this.elements.addTodoBtn.addEventListener('click', () => this.addTodo());\r\n                this.elements.todoInput.addEventListener('keypress', (e) => {\r\n                    if (e.key === 'Enter') this.addTodo();\r\n                });\r\n                this.elements.saveDay.addEventListener('click', () => this.saveCurrentDay());\r\n                this.elements.soberDay.addEventListener('click', () => this.saveSoberDay());\r\n                this.elements.deleteDataBtn.addEventListener('click', () => {\r\n                    this.elements.confirmationModal.style.display = 'flex';\r\n                });\r\n                this.elements.cancelDeleteBtn.addEventListener('click', () => {\r\n                    this.elements.confirmationModal.style.display = 'none';\r\n                });\r\n                this.elements.confirmDeleteBtn.addEventListener('click', () => this.deleteUserData());\r\n            },\r\n            \r\n            saveCurrentDay() {\r\n                this.saveDayData(false);\r\n                this.showToast(\"Tiedot tallennettu!\", true);\r\n            },\r\n\r\n            saveSoberDay() {\r\n                this.saveDayData(true);\r\n                this.showToast(\"Hienoa! Juomaton p\u00e4iv\u00e4 kirjattu.\", true);\r\n            },\r\n            \r\n            saveDayData(isSober) {\r\n                const weight = parseFloat(this.elements.weightInput.value);\r\n                const totalUnits = isSober ? 0 : this.tempDrinks.reduce((sum, drink) => sum + drink.units, 0);\r\n\r\n                if (!this.dailyData[this.currentDate]) {\r\n                    this.dailyData[this.currentDate] = { drinks: [], weight: null, totalUnits: 0, todos: [] };\r\n                }\r\n\r\n                this.dailyData[this.currentDate].drinks = isSober ? [] : [...this.tempDrinks];\r\n                this.dailyData[this.currentDate].weight = isNaN(weight) ? (this.dailyData[this.currentDate]?.weight || null) : weight;\r\n                this.dailyData[this.currentDate].totalUnits = totalUnits;\r\n                this.dailyData[this.currentDate].todos = [...this.tempTodos];\r\n                \r\n                this.saveData();\r\n            },\r\n\r\n            \/\/ --- UI UPDATE FUNCTIONS ---\r\n            setInputsDisabled(disabled) {\r\n                this.elements.weightInput.disabled = disabled;\r\n                this.elements.saveDay.disabled = disabled;\r\n                this.elements.soberDay.disabled = disabled;\r\n                this.elements.todoInput.disabled = disabled;\r\n                this.elements.addTodoBtn.disabled = disabled;\r\n                this.elements.todoDateInput.disabled = disabled;\r\n                this.elements.drinkButtons.querySelectorAll('button').forEach(btn => btn.disabled = disabled);\r\n                \r\n                this.elements.dailyDrinksDiv.querySelectorAll('button').forEach(btn => btn.disabled = disabled);\r\n            },\r\n\r\n            updateUIForDate(date) {\r\n                const data = this.dailyData[date] || {};\r\n                this.tempDrinks = data.drinks ? [...data.drinks] : [];\r\n                this.tempTodos = data.todos ? [...data.todos] : [];\r\n                this.elements.weightInput.value = data.weight || '';\r\n                \r\n                const todayStr = new Date().toISOString().split('T')[0];\r\n                const isEditable = (date >= todayStr);\r\n                \r\n                this.setInputsDisabled(!isEditable);\r\n                this.elements.todoDateInput.value = date;\r\n\r\n                this.elements.currentDayTasksTitle.textContent = date === todayStr ? \"T\u00e4m\u00e4n p\u00e4iv\u00e4n teht\u00e4v\u00e4t\" : `Teht\u00e4v\u00e4t p\u00e4iv\u00e4lle ${new Date(date).toLocaleDateString('fi-FI')}`;\r\n\r\n                this.renderAll();\r\n            },\r\n\r\n            addDrink(name, units) {\r\n                this.tempDrinks.push({ name, units });\r\n                this.renderTempDrinks();\r\n            },\r\n\r\n            renderTempDrinks() {\r\n                this.elements.dailyDrinksDiv.innerHTML = '';\r\n                let totalUnits = 0;\r\n                this.tempDrinks.forEach((drink, index) => {\r\n                    const drinkEl = document.createElement('div');\r\n                    drinkEl.className = 'flex justify-between items-center bg-gray-700 p-2 rounded-lg';\r\n                    drinkEl.innerHTML = `<span>${drink.name} (${drink.units} annosta)<\/span><button onclick=\"App.removeDrink(${index})\" class=\"text-red-400 hover:text-red-600 font-bold\">X<\/button>`;\r\n                    this.elements.dailyDrinksDiv.appendChild(drinkEl);\r\n                    totalUnits += drink.units;\r\n                });\r\n                if (this.tempDrinks.length > 0) {\r\n                    const totalEl = document.createElement('div');\r\n                    totalEl.className = 'font-bold mt-2 text-right';\r\n                    totalEl.textContent = `Yhteens\u00e4: ${totalUnits.toFixed(1)} annosta`;\r\n                    this.elements.dailyDrinksDiv.appendChild(totalEl);\r\n                }\r\n                const isEditable = (this.currentDate >= new Date().toISOString().split('T')[0]);\r\n                this.elements.dailyDrinksDiv.querySelectorAll('button').forEach(btn => btn.disabled = !isEditable);\r\n            },\r\n\r\n            removeDrink(index) {\r\n                this.tempDrinks.splice(index, 1);\r\n                this.renderTempDrinks();\r\n            },\r\n\r\n            addTodo() {\r\n                const taskText = this.elements.todoInput.value.trim();\r\n                const taskDate = this.elements.todoDateInput.value;\r\n\r\n                if (taskText && taskDate) {\r\n                    if (!this.dailyData[taskDate]) {\r\n                        this.dailyData[taskDate] = { drinks: [], weight: null, totalUnits: 0, todos: [] };\r\n                    }\r\n                    if(!this.dailyData[taskDate].todos) {\r\n                        this.dailyData[taskDate].todos = [];\r\n                    }\r\n                    this.dailyData[taskDate].todos.push({ text: taskText, done: false, notified: false });\r\n                    this.elements.todoInput.value = '';\r\n                    this.saveData();\r\n                    this.updateUIForDate(this.currentDate);\r\n                    this.showToast(`Teht\u00e4v\u00e4 lis\u00e4tty p\u00e4iv\u00e4lle ${new Date(taskDate).toLocaleDateString('fi-FI')}`, true);\r\n                }\r\n            },\r\n\r\n            renderTodos() {\r\n                this.elements.todoList.innerHTML = '';\r\n                const isEditable = (this.currentDate >= new Date().toISOString().split('T')[0]);\r\n\r\n                if (this.tempTodos.length === 0) {\r\n                    this.elements.todoList.innerHTML = `<li class=\"text-gray-500 italic\">Ei teht\u00e4vi\u00e4 t\u00e4lle p\u00e4iv\u00e4lle.<\/li>`;\r\n                } else {\r\n                    this.tempTodos.forEach((todo, index) => {\r\n                        const li = document.createElement('li');\r\n                        li.className = `task-item flex items-center justify-between bg-gray-700 p-3 rounded-lg ${todo.done ? 'done' : ''}`;\r\n                        li.innerHTML = `<div class=\"flex items-center flex-grow\"><input type=\"checkbox\" onchange=\"App.toggleTodo(${index})\" ${todo.done ? 'checked' : ''} ${!isEditable ? 'disabled' : ''} class=\"w-5 h-5 rounded bg-gray-600 border-gray-500 text-cyan-500 focus:ring-cyan-600\"><span class=\"ml-3 text-white\">${todo.text}<\/span><\/div>${isEditable ? `<button onclick=\"App.deleteTodo(${index})\" class=\"text-red-400 hover:text-red-600 font-bold text-lg\">X<\/button>` : ''}`;\r\n                        this.elements.todoList.appendChild(li);\r\n                    });\r\n                }\r\n            },\r\n\r\n            renderUpcomingTodos() {\r\n                this.elements.upcomingTodoList.innerHTML = '';\r\n                const todayStr = new Date().toISOString().split('T')[0];\r\n                const allUpcoming = [];\r\n                Object.keys(this.dailyData).forEach(date => {\r\n                    if (date > todayStr && this.dailyData[date].todos) {\r\n                        this.dailyData[date].todos.forEach(todo => {\r\n                            if (!todo.done) allUpcoming.push({ ...todo, date });\r\n                        });\r\n                    }\r\n                });\r\n                allUpcoming.sort((a, b) => new Date(a.date) - new Date(b.date));\r\n                \r\n                if (allUpcoming.length === 0) {\r\n                    this.elements.upcomingTasksContainer.style.display = 'none';\r\n                } else {\r\n                    this.elements.upcomingTasksContainer.style.display = 'block';\r\n                    allUpcoming.forEach(todo => {\r\n                        const li = document.createElement('li');\r\n                        li.className = `flex items-center justify-between bg-gray-700\/50 p-3 rounded-lg`;\r\n                        li.innerHTML = `<span class=\"text-gray-400\">${todo.text}<\/span><span class=\"text-sm text-gray-500 font-medium\">${new Date(todo.date).toLocaleDateString('fi-FI')}<\/span>`;\r\n                        this.elements.upcomingTodoList.appendChild(li);\r\n                    });\r\n                }\r\n            },\r\n\r\n            toggleTodo(index) {\r\n                this.tempTodos[index].done = !this.tempTodos[index].done;\r\n                this.dailyData[this.currentDate].todos = [...this.tempTodos];\r\n                this.saveData();\r\n            },\r\n\r\n            deleteTodo(index) {\r\n                this.tempTodos.splice(index, 1);\r\n                this.dailyData[this.currentDate].todos = [...this.tempTodos];\r\n                this.saveData();\r\n            },\r\n\r\n            \/\/ --- RENDER ALL & STATS ---\r\n            renderAll() {\r\n                this.renderTempDrinks();\r\n                this.renderTodos();\r\n                this.renderHistory();\r\n                this.renderStats();\r\n                this.renderCharts();\r\n                this.renderUpcomingTodos();\r\n            },\r\n\r\n            renderHistory() {\r\n                this.elements.historyTableBody.innerHTML = '';\r\n                const sortedDates = Object.keys(this.dailyData).sort((a, b) => new Date(b) - new Date(a));\r\n                sortedDates.slice(0, 30).forEach(date => {\r\n                    const data = this.dailyData[date];\r\n                    if(!data) return;\r\n                    const row = document.createElement('tr');\r\n                    row.className = 'border-b border-gray-700 hover:bg-gray-700\/50';\r\n                    row.innerHTML = `<td class=\"p-3\">${new Date(date).toLocaleDateString('fi-FI')}<\/td><td class=\"p-3\">${(data.totalUnits || 0).toFixed(1)}<\/td><td class=\"p-3\">${data.weight || '\u2013'}<\/td>`;\r\n                    this.elements.historyTableBody.appendChild(row);\r\n                });\r\n            },\r\n\r\n            renderStats() {\r\n                const dates = Object.keys(this.dailyData).sort((a, b) => new Date(a) - new Date(b));\r\n                let soberDays = 0, maxStreak = 0, currentStreak = 0;\r\n                dates.forEach(date => {\r\n                    if (this.dailyData[date] && this.dailyData[date].totalUnits === 0) {\r\n                        soberDays++; currentStreak++;\r\n                    } else {\r\n                        if (currentStreak > maxStreak) maxStreak = currentStreak;\r\n                        currentStreak = 0;\r\n                    }\r\n                });\r\n                if (currentStreak > maxStreak) maxStreak = currentStreak;\r\n\r\n                const AVG_DRINK_PRICE = 5.00;\r\n                const AVG_DRINK_CALORIES = 100;\r\n                this.elements.soberDaysCount.textContent = soberDays;\r\n                this.elements.soberStreak.textContent = `${maxStreak} pv`;\r\n                this.elements.caloriesSaved.textContent = Math.round(soberDays * AVG_DRINK_CALORIES * 1.5);\r\n                this.elements.moneySaved.textContent = (soberDays * AVG_DRINK_PRICE * 1.5).toFixed(2);\r\n            },\r\n\r\n            renderCharts() {\r\n                this.renderUnitsChart();\r\n                this.renderWeightChart();\r\n            },\r\n\r\n            renderUnitsChart() {\r\n                const labels = [], dataPoints = [];\r\n                for (let i = 6; i >= 0; i--) {\r\n                    const d = new Date();\r\n                    d.setDate(d.getDate() - i);\r\n                    const dateStr = d.toISOString().split('T')[0];\r\n                    labels.push(d.toLocaleDateString('fi-FI', { weekday: 'short' }));\r\n                    dataPoints.push(this.dailyData[dateStr]?.totalUnits || 0);\r\n                }\r\n                const data = { labels, datasets: [{ label: 'Alkoholiannokset', data: dataPoints, backgroundColor: 'rgba(56, 189, 248, 0.6)', borderColor: 'rgba(56, 189, 248, 1)', borderWidth: 2, borderRadius: 5 }] };\r\n                if (this.unitsChart) this.unitsChart.destroy();\r\n                this.unitsChart = new Chart(this.elements.unitsCanvas, { type: 'bar', data, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, ticks: { color: '#9ca3af' }, grid: { color: '#4b5563' } }, x: { ticks: { color: '#9ca3af' }, grid: { display: false } } }, plugins: { legend: { display: false } } } });\r\n            },\r\n\r\n            renderWeightChart() {\r\n                const sortedDates = Object.keys(this.dailyData).sort((a, b) => new Date(a) - new Date(b));\r\n                const labels = [], dataPoints = [];\r\n                sortedDates.forEach(date => {\r\n                    if (this.dailyData[date] && this.dailyData[date].weight) {\r\n                        labels.push(new Date(date).toLocaleDateString('fi-FI'));\r\n                        dataPoints.push(this.dailyData[date].weight);\r\n                    }\r\n                });\r\n                const data = { labels, datasets: [{ label: 'Paino (kg)', data: dataPoints, fill: false, borderColor: 'rgba(16, 185, 129, 1)', tension: 0.1, pointBackgroundColor: '#fff', pointRadius: 4 }] };\r\n                if (this.weightChart) this.weightChart.destroy();\r\n                this.weightChart = new Chart(this.elements.weightCanvas, { type: 'line', data, options: { responsive: true, maintainAspectRatio: false, scales: { y: { ticks: { color: '#9ca3af' }, grid: { color: '#4b5563' } }, x: { ticks: { color: '#9ca3af' }, grid: { display: false } } }, plugins: { legend: { display: false } } } });\r\n            },\r\n\r\n            \/\/ --- UTILITIES ---\r\n            checkAndShowNotifications() {\r\n                if (Notification.permission !== 'granted') return;\r\n                const tomorrow = new Date();\r\n                tomorrow.setDate(tomorrow.getDate() + 1);\r\n                const tomorrowDateStr = tomorrow.toISOString().split('T')[0];\r\n                const dataForTomorrow = this.dailyData[tomorrowDateStr];\r\n                if (dataForTomorrow && dataForTomorrow.todos) {\r\n                    let changed = false;\r\n                    dataForTomorrow.todos.forEach(todo => {\r\n                        if (!todo.done && !todo.notified) {\r\n                            new Notification('Selv\u00e4 Suunta - Muistutus', { body: `Huomenna on teht\u00e4v\u00e4n\u00e4: ${todo.text}`, icon: 'https:\/\/placehold.co\/64x64\/06b6d4\/ffffff?text=\ud83d\udd14' });\r\n                            todo.notified = true;\r\n                            changed = true;\r\n                        }\r\n                    });\r\n                    if (changed) this.saveData();\r\n                }\r\n            },\r\n            \r\n            showToast(message, isSuccess = false) {\r\n                this.elements.toast.textContent = message;\r\n                this.elements.toast.className = \"toast show\";\r\n                if(isSuccess) {\r\n                    this.elements.toast.classList.add('success');\r\n                } else {\r\n                    this.elements.toast.classList.remove('success');\r\n                }\r\n                setTimeout(() => { this.elements.toast.className = this.elements.toast.className.replace(\"show\", \"\"); }, 4000);\r\n            }\r\n        };\r\n\r\n        \/\/ Make App methods callable from inline HTML\r\n        window.App = App;\r\n\r\n        \/\/ Start the app\r\n        App.init();\r\n\r\n    <\/script>\r\n<\/body>\r\n<\/html>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Selv\u00e4 Suunta &#8211; Alkoholink\u00e4yt\u00f6n Seuranta Selv\u00e4 Suunta Kirjaudu sis\u00e4\u00e4n jatkaaksesi. Kirjaudu Google-tilill\u00e4 Selv\u00e4 Suunta Tavoitteena terveellisempi el\u00e4m\u00e4, p\u00e4iv\u00e4 kerrallaan. Kirjaudu ulos Ladataan tietoja&#8230; P\u00e4iv\u00e4n kirjaus Lis\u00e4\u00e4 juomia: \ud83c\udf7a Olut \ud83c\udf77 Viini \ud83e\udd43 V\u00e4kev\u00e4 T\u00e4m\u00e4nhetkinen paino: \ud83d\udcbe Tallenna p\u00e4iv\u00e4 \ud83d\udc4d Juomaton p\u00e4iv\u00e4 Teht\u00e4v\u00e4t Lis\u00e4\u00e4 T\u00e4m\u00e4n p\u00e4iv\u00e4n teht\u00e4v\u00e4t Tulevat Teht\u00e4v\u00e4t Edistyminen Juomattomia p\u00e4ivi\u00e4 0 Pisin putki 0 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_canvas","meta":{"footnotes":""},"class_list":["post-124","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/santtucreations.com\/index.php?rest_route=\/wp\/v2\/pages\/124","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/santtucreations.com\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/santtucreations.com\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/santtucreations.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/santtucreations.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=124"}],"version-history":[{"count":241,"href":"https:\/\/santtucreations.com\/index.php?rest_route=\/wp\/v2\/pages\/124\/revisions"}],"predecessor-version":[{"id":410,"href":"https:\/\/santtucreations.com\/index.php?rest_route=\/wp\/v2\/pages\/124\/revisions\/410"}],"wp:attachment":[{"href":"https:\/\/santtucreations.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=124"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}