{"id":1735,"date":"2026-09-27T11:04:19","date_gmt":"2026-09-27T11:04:19","guid":{"rendered":"https:\/\/www.kuvaukset.com\/kuvaukset\/?page_id=1735"},"modified":"2026-09-27T11:04:20","modified_gmt":"2026-09-27T11:04:20","slug":"kirjaudu","status":"publish","type":"page","link":"https:\/\/www.kuvaukset.com\/kuvaukset\/kirjaudu\/","title":{"rendered":"Kirjaudu"},"content":{"rendered":"    <div id=\"kc-login-widget\">\n      <div id=\"kc-login-loading\">Ladataan\u2026<\/div>\n\n      <div id=\"kc-login-logged-out\" style=\"display:none;\">\n        <h3>Kirjaudu sis\u00e4\u00e4n<\/h3>\n        <div id=\"kc-login-verify-status\" style=\"display:none; margin-bottom:12px;\"><\/div>\n\n        <label>S\u00e4hk\u00f6posti<br>\n          <input type=\"email\" id=\"kc-login-email\" autocomplete=\"username\" style=\"width:100%; max-width:320px; padding:8px;\">\n        <\/label>\n\n        <div id=\"kc-login-mode-link\" style=\"margin-top:10px;\">\n          <button type=\"button\" id=\"kc-login-send-link\" style=\"padding:8px 16px; background:#2563eb; color:#fff; border:none; border-radius:6px; cursor:pointer;\">L\u00e4het\u00e4 kirjautumislinkki<\/button>\n          <div id=\"kc-login-link-status\" style=\"margin-top:10px;\"><\/div>\n          <p style=\"margin-top:14px;\"><a href=\"#\" id=\"kc-login-show-password\" style=\"color:#2563eb; text-decoration:underline;\">Kirjaudu salasanalla<\/a><\/p>\n        <\/div>\n\n        <div id=\"kc-login-mode-password\" style=\"display:none; margin-top:10px;\">\n          <label>Salasana<br>\n            <input type=\"password\" id=\"kc-login-pw-password\" autocomplete=\"current-password\" style=\"width:100%; max-width:320px; padding:8px;\">\n          <\/label>\n          <div style=\"margin-top:10px;\">\n            <button type=\"button\" id=\"kc-login-pw-submit\" style=\"padding:8px 16px; background:#2563eb; color:#fff; border:none; border-radius:6px; cursor:pointer;\">Kirjaudu<\/button>\n          <\/div>\n          <div id=\"kc-login-pw-status\" style=\"margin-top:10px; color:#c00;\"><\/div>\n          <p style=\"margin-top:14px;\"><a href=\"#\" id=\"kc-login-show-link\" style=\"color:#2563eb; text-decoration:underline;\">L\u00e4het\u00e4 kirjautumislinkki s\u00e4hk\u00f6postiin<\/a><\/p>\n          <p style=\"margin-top:6px;\"><a href=\"#\" id=\"kc-login-forgot\" style=\"color:#2563eb; text-decoration:underline;\">Unohditko salasanasi?<\/a><\/p>\n          <div id=\"kc-login-forgot-status\" style=\"margin-top:8px;\"><\/div>\n        <\/div>\n      <\/div>\n\n      <div id=\"kc-login-reset-box\" style=\"display:none;\">\n        <h3>Aseta uusi salasana<\/h3>\n        <label>Uusi salasana (v\u00e4h. 8 merkki\u00e4)<br>\n          <input type=\"password\" id=\"kc-login-reset-pw1\" autocomplete=\"new-password\" style=\"width:100%; max-width:320px; padding:8px;\">\n        <\/label>\n        <label style=\"display:block; margin-top:10px;\">Uusi salasana uudelleen<br>\n          <input type=\"password\" id=\"kc-login-reset-pw2\" autocomplete=\"new-password\" style=\"width:100%; max-width:320px; padding:8px;\">\n        <\/label>\n        <div style=\"margin-top:10px;\">\n          <button type=\"button\" id=\"kc-login-reset-submit\" style=\"padding:8px 16px; background:#2563eb; color:#fff; border:none; border-radius:6px; cursor:pointer;\">Tallenna salasana<\/button>\n        <\/div>\n        <div id=\"kc-login-reset-status\" style=\"margin-top:10px; color:#c00;\"><\/div>\n      <\/div>\n\n      <div id=\"kc-login-logged-in\" style=\"display:none;\">\n        <h3>Tervetuloa, <span id=\"kc-login-user-name\" style=\"color:inherit;\"><\/span><\/h3>\n        <p id=\"kc-login-user-company\" style=\"color:#666;\"><\/p>\n\n                  <p style=\"margin:12px 0;\"><a id=\"kc-login-go-chat\" href=\"https:\/\/www.kuvaukset.com\/kuvaukset\/varaa\/\" style=\"display:inline-block; padding:8px 16px; background:#2563eb; color:#fff; border-radius:6px; text-decoration:none;\">Varaa kuvausaika<\/a><\/p>\n        \n        <div id=\"kc-login-password-saved\" style=\"display:none; margin:12px 0; padding:10px 14px; border:1px solid #16a34a; background:#f0fdf4; color:#166534; border-radius:8px; font-size:14px;\">\n          Salasana tallennettu. Voit jatkossa kirjautua sis\u00e4\u00e4n s\u00e4hk\u00f6postilla ja salasanalla ilman linkki\u00e4.\n        <\/div>\n\n        <div id=\"kc-login-session-warning\" style=\"display:none; margin:12px 0; padding:10px 14px; border:1px solid #f59e0b; background:#fffbeb; border-radius:8px; font-size:14px;\"><\/div>\n\n        <div id=\"kc-login-set-password-box\" style=\"display:none; margin-top:12px; border:1px solid #ddd; border-radius:8px; padding:12px;\">\n          <p>Aseta salasana, niin voit jatkossa kirjautua ilman s\u00e4hk\u00f6postilinkki\u00e4.<\/p>\n          <input type=\"password\" id=\"kc-login-new-password\" autocomplete=\"new-password\" placeholder=\"Uusi salasana (v\u00e4h. 8 merkki\u00e4)\" style=\"padding:8px; max-width:320px; width:100%;\">\n          <div style=\"margin-top:8px;\">\n            <button type=\"button\" id=\"kc-login-save-password\" style=\"padding:8px 16px; background:#2563eb; color:#fff; border:none; border-radius:6px; cursor:pointer;\">Tallenna salasana<\/button>\n          <\/div>\n          <div id=\"kc-login-save-password-status\" style=\"margin-top:8px;\"><\/div>\n        <\/div>\n\n        <div style=\"margin-top:16px;\">\n          <button type=\"button\" id=\"kc-login-logout\" style=\"padding:8px 16px; border:1px solid #999; background:#fff; color:#333; border-radius:6px; cursor:pointer;\">Kirjaudu ulos<\/button>\n        <\/div>\n      <\/div>\n    <\/div>\n\n    <script>\n    (function() {\n      const REST_BASE = \"https:\\\/\\\/www.kuvaukset.com\\\/kuvaukset\\\/wp-json\\\/kuvaukse\\\/v1\";\n\n      function api(path, opts) {\n        opts = opts || {};\n        const method = (opts.method || 'GET').toUpperCase();\n        const headers = Object.assign({ 'Content-Type': 'application\/json' }, opts.headers || {});\n\n        \/\/ Login state depends on a cookie, so a cached response would be\n        \/\/ wrong. Any GET gets a unique URL; state checks use POST, which no\n        \/\/ browser or hosting layer caches.\n        let url = REST_BASE + path;\n        if (method === 'GET') {\n          url += (url.indexOf('?') === -1 ? '?' : '&') + '_=' + Date.now();\n        }\n\n        return fetch(url, Object.assign({ credentials: 'same-origin', cache: 'no-store' }, opts, { headers: headers }))\n          .then(function(res) {\n            return res.json().catch(function() { return {}; }).then(function(data) {\n              if (!res.ok) throw (data && data.error) ? data.error : 'Virhe.';\n              return data;\n            });\n          });\n      }\n\n      const loadingEl = document.getElementById('kc-login-loading');\n      const loggedOutEl = document.getElementById('kc-login-logged-out');\n      const loggedInEl = document.getElementById('kc-login-logged-in');\n      const verifyStatusEl = document.getElementById('kc-login-verify-status');\n      const sessionWarningEl = document.getElementById('kc-login-session-warning');\n      const emailEl = document.getElementById('kc-login-email');\n      const passwordEl = document.getElementById('kc-login-pw-password');\n      const modeLinkEl = document.getElementById('kc-login-mode-link');\n      const modePasswordEl = document.getElementById('kc-login-mode-password');\n\n      const TOKEN_ERRORS = {\n        token_used: 'T\u00e4m\u00e4 kirjautumislinkki on jo k\u00e4ytetty \u2014 jokainen linkki toimii vain kerran. Jos et ole kirjautuneena, pyyd\u00e4 uusi linkki alta.',\n        token_expired: 'Kirjautumislinkki on vanhentunut (se on voimassa 5 minuuttia). Pyyd\u00e4 uusi linkki alta.',\n        invalid_token: 'Kirjautumislinkki ei kelpaa. Pyyd\u00e4 uusi linkki alta.'\n      };\n\n      \/\/ One email field serves both ways of logging in; this only switches\n      \/\/ which action is shown underneath it.\n      function setMode(mode) {\n        modeLinkEl.style.display = (mode === 'link') ? '' : 'none';\n        modePasswordEl.style.display = (mode === 'password') ? '' : 'none';\n      }\n\n      function showLoggedIn(user) {\n        loadingEl.style.display = 'none';\n        loggedOutEl.style.display = 'none';\n        loggedInEl.style.display = '';\n        document.getElementById('kc-login-user-name').textContent = user.name;\n        document.getElementById('kc-login-user-company').textContent = user.company || '';\n        document.getElementById('kc-login-set-password-box').style.display = user.hasPassword ? 'none' : '';\n      }\n\n      function showLoggedOut() {\n        loadingEl.style.display = 'none';\n        loggedInEl.style.display = 'none';\n        loggedOutEl.style.display = '';\n        passwordEl.value = '';\n        setMode('link');\n      }\n\n      \/\/ A WordPress customer is sent on to their own page (the old calendar, the image upload); someone whose rules\n      \/\/ say \"new calendar\" but who is not on the booking calendar's customer list is told to contact the photographer.\n      function afterLogin(data, messageEl) {\n        if (data && data.redirect) { window.location.href = data.redirect; return true; }\n        if (data && data.noCalendar) {\n          loadingEl.style.display = 'none';\n          loggedOutEl.style.display = '';\n          messageEl.style.display = '';\n          messageEl.style.color = '#c00';\n          messageEl.textContent = 'Olet kirjautunut, mutta tunnuksellasi ei ole viel\u00e4 k\u00e4ytt\u00f6oikeutta varauskalenteriin. Ota yhteytt\u00e4 kuvaajaan.';\n          return true;\n        }\n        return false;\n      }\n\n      function whoAmI() {\n        return api('\/auth\/me', { method: 'POST', body: '{}' });\n      }\n\n      function checkSession() {\n        whoAmI().then(function(data) {\n          if (data.loggedIn) { showLoggedIn(data); } else { showLoggedOut(); }\n        }).catch(function() {\n          showLoggedOut();\n        });\n      }\n\n      \/\/ Right after a login we already know who the user is (the server said\n      \/\/ so). Double-check the browser really kept the session, and if not,\n      \/\/ say so plainly instead of silently looking logged-out later.\n      function verifySessionPersisted() {\n        whoAmI().then(function(me) {\n          if (me.loggedIn) return;\n          sessionWarningEl.style.display = '';\n          sessionWarningEl.textContent =\n            'Kirjautuminen onnistui, mutta selain ei s\u00e4ilytt\u00e4nyt istuntoa \u2014 sivun p\u00e4ivitys kirjaisi sinut ulos. ' +\n            '(Ev\u00e4ste saapui palvelimelle: ' + (me.cookiePresent ? 'kyll\u00e4' : 'ei') + '. Versio: ' + (me.version || 'tuntematon') + '.) ' +\n            'Kerro t\u00e4m\u00e4 yll\u00e4pit\u00e4j\u00e4lle.';\n        }).catch(function() {});\n      }\n\n      const urlParams = new URLSearchParams(window.location.search);\n      const loginToken = urlParams.get('kc_login_token');\n      const resetToken = urlParams.get('kc_reset');\n\n      document.getElementById('kc-login-forgot').addEventListener('click', function(e) {\n        e.preventDefault();\n        const email = emailEl.value.trim();\n        const statusEl = document.getElementById('kc-login-forgot-status');\n        statusEl.style.color = '#c00';\n        if (!email) { statusEl.textContent = 'Kirjoita ensin s\u00e4hk\u00f6postiosoitteesi yll\u00e4 olevaan kentt\u00e4\u00e4n.'; return; }\n        statusEl.style.color = '';\n        statusEl.textContent = 'L\u00e4hetet\u00e4\u00e4n\u2026';\n        api('\/auth\/request-reset', { method: 'POST', body: JSON.stringify({ email: email }) }).then(function() {\n          statusEl.textContent = 'Jos s\u00e4hk\u00f6posti l\u00f6ytyy j\u00e4rjestelm\u00e4st\u00e4, ohje salasanan vaihtoon on l\u00e4hetetty. Tarkista s\u00e4hk\u00f6postisi (my\u00f6s roskaposti).';\n        }, function() {\n          statusEl.style.color = '#c00';\n          statusEl.textContent = 'Jotain meni pieleen. Tarkista s\u00e4hk\u00f6postiosoite ja yrit\u00e4 uudelleen.';\n        });\n      });\n\n      document.getElementById('kc-login-reset-submit').addEventListener('click', function() {\n        const p1 = document.getElementById('kc-login-reset-pw1').value;\n        const p2 = document.getElementById('kc-login-reset-pw2').value;\n        const statusEl = document.getElementById('kc-login-reset-status');\n        statusEl.textContent = '';\n        if (p1.length < 8) { statusEl.textContent = 'Salasanan pit\u00e4\u00e4 olla v\u00e4hint\u00e4\u00e4n 8 merkki\u00e4 pitk\u00e4.'; return; }\n        if (p1 !== p2) { statusEl.textContent = 'Salasanat eiv\u00e4t t\u00e4sm\u00e4\u00e4.'; return; }\n        api('\/auth\/reset-password', { method: 'POST', body: JSON.stringify({ token: resetToken, password: p1 }) }).then(function() {\n          window.history.replaceState({}, '', window.location.pathname);\n          document.getElementById('kc-login-reset-box').style.display = 'none';\n          showLoggedOut();\n          setMode('password');\n          loggedOutEl.style.display = '';\n          verifyStatusEl.style.display = '';\n          verifyStatusEl.style.color = '#166534';\n          verifyStatusEl.textContent = 'Salasana on vaihdettu. Kirjaudu sis\u00e4\u00e4n uudella salasanalla.';\n        }, function(err) {\n          statusEl.textContent = (err === 'password_too_short') ? 'Salasanan pit\u00e4\u00e4 olla v\u00e4hint\u00e4\u00e4n 8 merkki\u00e4 pitk\u00e4.'\n            : 'Linkki ei kelpaa tai se on vanhentunut. Palaa kirjautumissivulle ja valitse \"Unohditko salasanasi?\" uudelleen.';\n        });\n      });\n\n      if (resetToken) {\n        loadingEl.style.display = 'none';\n        document.getElementById('kc-login-reset-box').style.display = '';\n      } else if (loginToken) {\n        loggedOutEl.style.display = '';\n        loadingEl.style.display = 'none';\n        verifyStatusEl.style.display = '';\n        verifyStatusEl.textContent = 'Kirjaudutaan sis\u00e4\u00e4n\u2026';\n\n        api('\/auth\/verify-login', {\n          method: 'POST',\n          body: JSON.stringify({ token: loginToken })\n        }).then(function(data) {\n          window.history.replaceState({}, '', window.location.pathname);\n          verifyStatusEl.style.display = 'none';\n          if (afterLogin(data, verifyStatusEl)) return;\n          showLoggedIn(data.user);\n          verifySessionPersisted();\n        }, function(err) {\n          verifyStatusEl.style.color = '#c00';\n          verifyStatusEl.textContent = TOKEN_ERRORS[err] || 'Kirjautuminen ep\u00e4onnistui. Pyyd\u00e4 uusi linkki alta.';\n        });\n      } else {\n        checkSession();\n      }\n\n      document.getElementById('kc-login-show-password').addEventListener('click', function(e) {\n        e.preventDefault();\n        setMode('password');\n        passwordEl.focus();\n      });\n\n      document.getElementById('kc-login-show-link').addEventListener('click', function(e) {\n        e.preventDefault();\n        setMode('link');\n      });\n\n      emailEl.addEventListener('keydown', function(e) {\n        if (e.key !== 'Enter') return;\n        e.preventDefault();\n        if (modePasswordEl.style.display !== 'none') { passwordEl.focus(); }\n        else { document.getElementById('kc-login-send-link').click(); }\n      });\n\n      passwordEl.addEventListener('keydown', function(e) {\n        if (e.key !== 'Enter') return;\n        e.preventDefault();\n        document.getElementById('kc-login-pw-submit').click();\n      });\n\n      document.getElementById('kc-login-send-link').addEventListener('click', function() {\n        const email = emailEl.value.trim();\n        const statusEl = document.getElementById('kc-login-link-status');\n        if (!email) { statusEl.textContent = 'Kirjoita s\u00e4hk\u00f6postiosoitteesi.'; return; }\n        statusEl.textContent = 'L\u00e4hetet\u00e4\u00e4n\u2026';\n        api('\/auth\/request-login', {\n          method: 'POST',\n          body: JSON.stringify({ email: email })\n        }).then(function() {\n          statusEl.textContent = 'Jos s\u00e4hk\u00f6posti l\u00f6ytyy j\u00e4rjestelm\u00e4st\u00e4, kirjautumislinkki on l\u00e4hetetty. Tarkista s\u00e4hk\u00f6postisi.';\n        }, function() {\n          statusEl.textContent = 'Jotain meni pieleen. Yrit\u00e4 uudelleen.';\n        });\n      });\n\n      document.getElementById('kc-login-pw-submit').addEventListener('click', function() {\n        const email = emailEl.value.trim();\n        const password = passwordEl.value;\n        const statusEl = document.getElementById('kc-login-pw-status');\n        statusEl.textContent = '';\n        if (!email || !password) { statusEl.textContent = 'Kirjoita s\u00e4hk\u00f6posti ja salasana.'; return; }\n\n        api('\/auth\/login', {\n          method: 'POST',\n          body: JSON.stringify({ email: email, password: password })\n        }).then(function(data) {\n          passwordEl.value = '';\n          if (afterLogin(data, statusEl)) return;\n          showLoggedIn(data.user);\n          verifySessionPersisted();\n        }, function(err) {\n          statusEl.textContent = (err === 'invalid_credentials')\n            ? 'V\u00e4\u00e4r\u00e4 s\u00e4hk\u00f6posti tai salasana.'\n            : (err === 'too_many_attempts' ? 'Liian monta yrityst\u00e4. Yrit\u00e4 uudelleen vartin kuluttua tai k\u00e4yt\u00e4 kirjautumislinkki\u00e4.' : 'Kirjautuminen ep\u00e4onnistui. Yrit\u00e4 uudelleen.');\n        });\n      });\n\n      document.getElementById('kc-login-save-password').addEventListener('click', function() {\n        const password = document.getElementById('kc-login-new-password').value;\n        const statusEl = document.getElementById('kc-login-save-password-status');\n        statusEl.style.color = '#c00';\n        statusEl.textContent = '';\n        api('\/auth\/set-password', {\n          method: 'POST',\n          body: JSON.stringify({ password: password })\n        }).then(function() {\n          document.getElementById('kc-login-new-password').value = '';\n          document.getElementById('kc-login-set-password-box').style.display = 'none';\n          document.getElementById('kc-login-password-saved').style.display = '';\n        }, function(err) {\n          const messages = {\n            password_too_short: 'Salasanan pit\u00e4\u00e4 olla v\u00e4hint\u00e4\u00e4n 8 merkki\u00e4 pitk\u00e4.',\n            not_logged_in: 'Istunto on p\u00e4\u00e4ttynyt. Kirjaudu sis\u00e4\u00e4n uudelleen.'\n          };\n          statusEl.textContent = messages[err] || 'Tallennus ep\u00e4onnistui. Yrit\u00e4 uudelleen.';\n        });\n      });\n\n      document.getElementById('kc-login-logout').addEventListener('click', function() {\n        api('\/auth\/logout', { method: 'POST', body: '{}' }).then(function() {\n          document.getElementById('kc-login-password-saved').style.display = 'none';\n          sessionWarningEl.style.display = 'none';\n          showLoggedOut();\n        });\n      });\n    })();\n    <\/script>\n    \n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-1735","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.kuvaukset.com\/kuvaukset\/wp-json\/wp\/v2\/pages\/1735","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.kuvaukset.com\/kuvaukset\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.kuvaukset.com\/kuvaukset\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.kuvaukset.com\/kuvaukset\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.kuvaukset.com\/kuvaukset\/wp-json\/wp\/v2\/comments?post=1735"}],"version-history":[{"count":1,"href":"https:\/\/www.kuvaukset.com\/kuvaukset\/wp-json\/wp\/v2\/pages\/1735\/revisions"}],"predecessor-version":[{"id":1737,"href":"https:\/\/www.kuvaukset.com\/kuvaukset\/wp-json\/wp\/v2\/pages\/1735\/revisions\/1737"}],"wp:attachment":[{"href":"https:\/\/www.kuvaukset.com\/kuvaukset\/wp-json\/wp\/v2\/media?parent=1735"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}