diff --git a/assets/js/hooks.js b/assets/js/hooks.js index 10d8fb1..a4f79a9 100644 --- a/assets/js/hooks.js +++ b/assets/js/hooks.js @@ -204,6 +204,70 @@ export const mountStaticAidMaps = root => { } export const Hooks = { + CopyToClipboard: { + mounted() { + this.resetLabel = () => { + this.el.textContent = this.el.dataset.defaultLabel + } + + this.copy = async () => { + const value = this.el.dataset.copyValue || "" + + const fallbackCopy = () => { + const input = document.createElement("textarea") + input.value = value + input.setAttribute("readonly", "") + input.style.position = "fixed" + input.style.opacity = "0" + document.body.append(input) + input.select() + const copied = document.execCommand("copy") + input.remove() + + if (!copied) throw new Error("Clipboard copy failed") + } + + try { + if (navigator.clipboard?.writeText) { + await navigator.clipboard.writeText(value) + } else { + fallbackCopy() + } + this.el.textContent = this.el.dataset.copiedLabel + } catch (_error) { + try { + fallbackCopy() + this.el.textContent = this.el.dataset.copiedLabel + } catch (_fallbackError) { + this.el.textContent = this.el.dataset.errorLabel + } + } + + window.clearTimeout(this.labelTimer) + this.labelTimer = window.setTimeout(this.resetLabel, 1800) + } + + this.el.addEventListener("click", this.copy) + }, + destroyed() { + this.el.removeEventListener("click", this.copy) + window.clearTimeout(this.labelTimer) + } + }, + + HandoverCode: { + mounted() { + this.normalize = () => { + this.el.value = this.el.value.replace(/[^0-9]/g, "").slice(0, 6) + } + + this.el.addEventListener("input", this.normalize) + }, + destroyed() { + this.el.removeEventListener("input", this.normalize) + } + }, + AidMap: { mounted() { this.aidMap = createAidMap(this.el) diff --git a/lib/who_need_help/help.ex b/lib/who_need_help/help.ex index ad58e7b..49267c9 100644 --- a/lib/who_need_help/help.ex +++ b/lib/who_need_help/help.ex @@ -290,6 +290,8 @@ defmodule WhoNeedHelp.Help do end def verify_handover(%Scope{user: user}, assignment_id, code) do + code = normalize_handover_code(code) + with {:ok, assignment_id} <- cast_id(assignment_id), true <- valid_handover_code?(code), {:ok, _limit} <- Trust.authorize_action(Scope.for_user(user), :verify_handover) do @@ -619,6 +621,14 @@ defmodule WhoNeedHelp.Help do defp valid_handover_code?(_code), do: false + defp normalize_handover_code(code) when is_binary(code) do + code + |> String.slice(0, 64) + |> String.replace(~r/[^0-9]/u, "") + end + + defp normalize_handover_code(code), do: code + defp code_hash(code) when is_binary(code), do: :crypto.hash(:sha256, code) defp after_transition({:ok, assignment}) do diff --git a/lib/who_need_help_web/live/request_live/show.ex b/lib/who_need_help_web/live/request_live/show.ex index 4288507..d980f44 100644 --- a/lib/who_need_help_web/live/request_live/show.ex +++ b/lib/who_need_help_web/live/request_live/show.ex @@ -1010,9 +1010,22 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do
{Help.handover_code(@request.id)}
-