<h2>Your passkeys</h2>

<p>This page is the plugin's, rendered through this application's
layout: <code>render =&gt; 'passkey_page'</code> in
<code>lib/PasskeyDemo.pm</code> replaces the built-in page with a
helper, and the helper is handed the rows.</p>

{% if keys %}
<ul class="keys">
{% for key in keys %}
  <li>
    <strong>{% key.label | default('a passkey') %}</strong>
    <code>{% key.credential_id %}</code>
    <button class="remove" data-id="{% key.credential_id %}">Remove</button>
  </li>
{% end %}
</ul>
{% else %}
<p>None yet.</p>
{% end %}

<p class="row">
  <button id="add">Add a passkey</button>
  <a href="/">Back</a>
</p>

<p class="try"><strong>Recovery.</strong> Enrol a second passkey on
another device before you need it. This application has no password and
no recovery codes, so the plugin will refuse to let you remove your last
credential - try it. An application that also has
L&lt;Punk::TOTP&gt; answers <code>has_other_factor</code> with true and
the last one becomes removable.</p>

<p id="err" class="bad" hidden></p>

<script src="/punk-passkey.js"></script>
<script>
(function () {
  var err = document.getElementById('err');
  function fail(e) {
    err.textContent = e && e.message ? e.message : 'that did not work';
    err.hidden = false;
  }

  document.getElementById('add').addEventListener('click', function () {
    err.hidden = true;
    PunkPasskey.register('/account/passkeys')
      .then(function () { location.reload() }, fail);
  });

  // Removal is a plain DELETE - no ceremony, so no helper needed. The
  // CSRF token would ride the same header the helper sends, if this
  // application had the csrf keyword on.
  Array.prototype.forEach.call(
    document.querySelectorAll('.remove'), function (b) {
      b.addEventListener('click', function () {
        err.hidden = true;
        fetch('/account/passkeys/' + encodeURIComponent(b.dataset.id), {
          method: 'DELETE', credentials: 'same-origin'
        }).then(function (r) {
          return r.json().then(function (j) {
            if (!r.ok) throw new Error(j.error || 'refused');
            location.reload();
          });
        }).catch(fail);
      });
    });
})();
</script>
