berrypod/lib/berrypod_web/newsletter_hook.ex

61 lines
1.9 KiB
Elixir
Raw Permalink Normal View History

defmodule BerrypodWeb.NewsletterHook do
@moduledoc """
LiveView on_mount hook for newsletter signup across all shop pages.
Uses `attach_hook/4` to intercept `newsletter_subscribe` events globally
without modifying individual shop LiveViews.
"""
import Phoenix.Component, only: [assign: 3]
import Phoenix.LiveView, only: [attach_hook: 4]
alias Berrypod.Newsletter
def on_mount(:mount_newsletter, _params, _session, socket) do
enabled = Newsletter.newsletter_enabled?()
socket =
socket
|> assign(:newsletter_enabled, enabled)
|> assign(:newsletter_state, :idle)
|> assign(:newsletter_ip_hash, hash_ip(socket))
|> attach_hook(:newsletter, :handle_event, &handle_newsletter_event/3)
{:cont, socket}
end
defp handle_newsletter_event("newsletter_subscribe", %{"email" => email}, socket) do
if socket.assigns.newsletter_enabled do
case Newsletter.subscribe(email,
consent_text: "Newsletter signup on website",
ip_hash: socket.assigns.newsletter_ip_hash
) do
{:ok, _} ->
{:halt, assign(socket, :newsletter_state, :submitted)}
{:already_confirmed, _} ->
{:halt, assign(socket, :newsletter_state, :submitted)}
{:error, _} ->
{:halt, assign(socket, :newsletter_state, :error)}
end
else
{:halt, assign(socket, :newsletter_state, :disabled)}
end
end
defp handle_newsletter_event(_event, _params, socket), do: {:cont, socket}
# connect_info is only available during mount, so we hash and store it early
defp hash_ip(socket) do
case Phoenix.LiveView.get_connect_info(socket, :peer_data) do
%{address: ip} ->
daily_salt = Date.utc_today() |> Date.to_iso8601()
:crypto.hash(:sha256, :inet.ntoa(ip) ++ [daily_salt]) |> Base.encode16(case: :lower)
_ ->
nil
end
end
end