Packages

phoenix_kit

1.7.18
1.7.209 1.7.208 1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

Files

Jump to
phoenix_kit lib modules legal web settings.ex
Raw

lib/modules/legal/web/settings.ex

defmodule PhoenixKitWeb.Live.Modules.Legal.Settings do
@moduledoc """
LiveView for Legal module settings and page generation.
Route: {prefix}/admin/settings/legal
Sections:
1. Module enable/disable (with Blogging dependency check)
2. Compliance framework selection
3. Company information form
4. DPO contact form
5. Page generation controls
6. Generated pages list
"""
use PhoenixKitWeb, :live_view
use Gettext, backend: PhoenixKitWeb.Gettext
alias PhoenixKit.Billing.CountryData
alias PhoenixKit.Modules.Legal
alias PhoenixKit.Settings
alias PhoenixKit.Utils.Routes
@impl true
def mount(_params, _session, socket) do
config = Legal.get_config()
widget_config = Legal.get_consent_widget_config()
socket =
socket
|> assign(:project_title, Settings.get_setting("project_title", "PhoenixKit"))
|> assign(:page_title, gettext("Legal Settings"))
|> assign(
:current_path,
Routes.path("/admin/settings/legal", locale: socket.assigns[:current_locale_base])
)
|> assign(:blogging_enabled, config.blogging_enabled)
|> assign(:legal_enabled, config.enabled)
|> assign(:available_frameworks, Legal.available_frameworks())
|> assign(:available_page_types, Legal.available_page_types())
|> assign(:selected_frameworks, config.frameworks)
|> assign(:company_info, config.company_info)
|> assign(:countries, CountryData.countries_for_select())
|> assign(
:subdivision_label,
CountryData.get_subdivision_label(config.company_info["country"])
)
|> assign(:dpo_contact, config.dpo_contact)
|> assign(:generated_pages, config.generated_pages)
|> assign(:generating, false)
# Consent widget assigns (Phase 2)
|> assign(:consent_widget_enabled, widget_config.enabled)
|> assign(:consent_mode, widget_config.consent_mode)
|> assign(:hide_for_authenticated, widget_config.hide_for_authenticated)
|> assign(:icon_position, widget_config.icon_position)
|> assign(:policy_version, widget_config.policy_version)
|> assign(:google_consent_mode, widget_config.google_consent_mode)
|> assign(:show_consent_icon, widget_config.show_icon)
|> assign(:unpublished_pages, Legal.get_unpublished_required_pages())
{:ok, socket}
end
@impl true
def handle_params(_params, _uri, socket), do: {:noreply, socket}
@impl true
def handle_event("toggle_legal", _params, socket) do
if socket.assigns.legal_enabled do
case Legal.disable_system() do
{:ok, _} ->
{:noreply,
socket
|> assign(:legal_enabled, false)
|> put_flash(:info, gettext("Legal module disabled"))}
{:error, _} ->
{:noreply, put_flash(socket, :error, gettext("Failed to disable Legal module"))}
end
else
case Legal.enable_system() do
{:ok, _} ->
{:noreply,
socket
|> assign(:legal_enabled, true)
|> put_flash(:info, gettext("Legal module enabled"))}
{:error, :blogging_required} ->
{:noreply, put_flash(socket, :error, gettext("Please enable Blogging module first"))}
{:error, _} ->
{:noreply, put_flash(socket, :error, gettext("Failed to enable Legal module"))}
end
end
end
@impl true
def handle_event("toggle_framework", %{"id" => framework_id}, socket) do
current = socket.assigns.selected_frameworks
updated =
if framework_id in current do
List.delete(current, framework_id)
else
[framework_id | current]
end
case Legal.set_frameworks(updated) do
{:ok, _} ->
{:noreply, assign(socket, :selected_frameworks, updated)}
{:error, _} ->
{:noreply, put_flash(socket, :error, gettext("Failed to save frameworks"))}
end
end
@impl true
def handle_event("save_company_info", params, socket) do
company_info = build_company_info(params)
case Legal.update_company_info(company_info) do
{:ok, _} ->
{:noreply,
socket
|> assign(:company_info, company_info)
|> assign(:subdivision_label, CountryData.get_subdivision_label(company_info["country"]))
|> put_flash(:info, gettext("Company information saved"))}
{:error, _} ->
{:noreply, put_flash(socket, :error, gettext("Failed to save company information"))}
end
end
@impl true
def handle_event("update_country", %{"company_country" => country_code}, socket) do
{:noreply,
assign(socket, :subdivision_label, CountryData.get_subdivision_label(country_code))}
end
@impl true
def handle_event("save_dpo_contact", params, socket) do
dpo_contact = %{
"name" => params["dpo_name"] || "",
"email" => params["dpo_email"] || "",
"phone" => params["dpo_phone"] || "",
"address" => params["dpo_address"] || ""
}
case Legal.update_dpo_contact(dpo_contact) do
{:ok, _} ->
{:noreply,
socket
|> assign(:dpo_contact, dpo_contact)
|> put_flash(:info, gettext("DPO contact saved"))}
{:error, _} ->
{:noreply, put_flash(socket, :error, gettext("Failed to save DPO contact"))}
end
end
@impl true
def handle_event("generate_page", %{"page_type" => page_type}, socket) do
socket = assign(socket, :generating, true)
case Legal.generate_page(page_type, scope: socket.assigns[:current_scope]) do
{:ok, _post} ->
{:noreply,
socket
|> assign(:generating, false)
|> assign(:generated_pages, Legal.list_generated_pages())
|> assign(:unpublished_pages, Legal.get_unpublished_required_pages())
|> put_flash(:info, gettext("Page generated successfully"))}
{:error, reason} ->
{:noreply,
socket
|> assign(:generating, false)
|> put_flash(
:error,
gettext("Failed to generate page: %{reason}", reason: inspect(reason))
)}
end
end
@impl true
def handle_event("publish_page", %{"page_slug" => page_slug}, socket) do
case Legal.publish_page(page_slug, scope: socket.assigns[:current_scope]) do
{:ok, _post} ->
{:noreply,
socket
|> assign(:generated_pages, Legal.list_generated_pages())
|> assign(:unpublished_pages, Legal.get_unpublished_required_pages())
|> put_flash(:info, gettext("Page published successfully"))}
{:error, reason} ->
{:noreply,
put_flash(
socket,
:error,
gettext("Failed to publish page: %{reason}", reason: inspect(reason))
)}
end
end
@impl true
def handle_event("generate_all_pages", _params, socket) do
socket = assign(socket, :generating, true)
{:ok, results} = Legal.generate_all_pages(scope: socket.assigns[:current_scope])
success_count =
results
|> Enum.count(fn {_, result} -> match?({:ok, _}, result) end)
{:noreply,
socket
|> assign(:generating, false)
|> assign(:generated_pages, Legal.list_generated_pages())
|> assign(:unpublished_pages, Legal.get_unpublished_required_pages())
|> put_flash(:info, gettext("Generated %{count} pages", count: success_count))}
end
# ===================================
# CONSENT WIDGET EVENTS (Phase 2)
# ===================================
@impl true
def handle_event("toggle_consent_widget", _params, socket) do
if socket.assigns.consent_widget_enabled do
case Legal.disable_consent_widget() do
{:ok, _} ->
{:noreply,
socket
|> assign(:consent_widget_enabled, false)
|> assign(:show_consent_icon, false)
|> put_flash(:info, gettext("Cookie consent widget disabled"))}
{:error, _} ->
{:noreply, put_flash(socket, :error, gettext("Failed to update setting"))}
end
else
case Legal.enable_consent_widget() do
{:ok, _} ->
show_icon = Legal.has_opt_in_framework?()
{:noreply,
socket
|> assign(:consent_widget_enabled, true)
|> assign(:show_consent_icon, show_icon)
|> put_flash(:info, gettext("Cookie consent widget enabled"))}
{:error, _} ->
{:noreply, put_flash(socket, :error, gettext("Failed to update setting"))}
end
end
end
@impl true
def handle_event("save_consent_settings", params, socket) do
consent_mode = params["consent_mode"] || "strict"
hide_for_auth = params["hide_for_authenticated"] == "true"
with {:ok, _} <- Legal.update_consent_mode(consent_mode),
{:ok, _} <- Legal.update_hide_for_authenticated(hide_for_auth),
{:ok, _} <- Legal.update_icon_position(params["icon_position"] || "bottom-right"),
{:ok, _} <- update_google_consent_mode(params["google_consent_mode"]) do
# Recalculate show_icon based on new settings
show_icon = Legal.should_show_consent_icon?()
{:noreply,
socket
|> assign(:consent_mode, consent_mode)
|> assign(:hide_for_authenticated, hide_for_auth)
|> assign(:icon_position, params["icon_position"] || "bottom-right")
|> assign(:google_consent_mode, params["google_consent_mode"] == "true")
|> assign(:show_consent_icon, show_icon)
|> put_flash(:info, gettext("Consent widget settings saved"))}
else
{:error, _} ->
{:noreply, put_flash(socket, :error, gettext("Failed to save settings"))}
end
end
defp update_google_consent_mode("true"), do: Legal.enable_google_consent_mode()
defp update_google_consent_mode(_), do: Legal.disable_google_consent_mode()
# Helper to get edit URL for a legal page
defp get_edit_url(page_slug, generated_pages) do
case Enum.find(generated_pages, fn p -> p.slug == page_slug end) do
nil ->
Routes.path("/admin/blogging/legal")
page ->
Routes.path("/admin/blogging/legal/edit?path=#{URI.encode(page.path)}")
end
end
# Helper to check if a page is generated
defp page_generated?(page_slug, generated_pages) do
Enum.any?(generated_pages, fn p -> p.slug == page_slug end)
end
# Helper to get page status
defp get_page_status(page_slug, generated_pages) do
case Enum.find(generated_pages, fn p -> p.slug == page_slug end) do
nil -> nil
page -> page.status
end
end
# Helper to build company info map from params
defp build_company_info(params) do
%{
"name" => params["company_name"] || "",
"address_line1" => params["company_address_line1"] || "",
"address_line2" => params["company_address_line2"] || "",
"city" => params["company_city"] || "",
"state" => params["company_state"] || "",
"postal_code" => params["company_postal_code"] || "",
"country" => params["company_country"] || "",
"website_url" => params["company_website"] || "",
"registration_number" => params["registration_number"] || "",
"vat_number" => params["vat_number"] || ""
}
end
end