diff --git a/lib/modules/sitemap/sources/router_discovery.ex b/lib/modules/sitemap/sources/router_discovery.ex
index 2ad50ce63..9d144b869 100644
--- a/lib/modules/sitemap/sources/router_discovery.ex
+++ b/lib/modules/sitemap/sources/router_discovery.ex
@@ -90,6 +90,7 @@ defmodule PhoenixKit.Modules.Sitemap.Sources.RouterDiscovery do
# Internal/functional pages - not for search engine indexing
"/checkout",
"/cart",
+ "/newsletters/unsubscribe",
"/health",
"/ready",
# Infrastructure
diff --git a/lib/phoenix_kit/module_registry.ex b/lib/phoenix_kit/module_registry.ex
index 485af648d..64b9314cd 100644
--- a/lib/phoenix_kit/module_registry.ex
+++ b/lib/phoenix_kit/module_registry.ex
@@ -431,6 +431,7 @@ defmodule PhoenixKit.ModuleRegistry do
[
%{
module: PhoenixKit.Newsletters,
+ key: "newsletters",
hex_package: "phoenix_kit_newsletters",
name: "Newsletters",
description:
diff --git a/lib/phoenix_kit_web/live/modules.ex b/lib/phoenix_kit_web/live/modules.ex
index 985bcd526..8eaabf201 100644
--- a/lib/phoenix_kit_web/live/modules.ex
+++ b/lib/phoenix_kit_web/live/modules.ex
@@ -32,6 +32,7 @@ defmodule PhoenixKitWeb.Live.Modules do
external_modules = load_external_modules(module_configs)
dep_warnings = ModuleRegistry.dependency_warnings()
not_installed = ModuleRegistry.not_installed_packages()
+ not_installed_keys = not_installed |> Enum.map(& &1.key) |> MapSet.new()
socket =
socket
@@ -42,6 +43,7 @@ defmodule PhoenixKitWeb.Live.Modules do
|> assign(:external_modules, external_modules)
|> assign(:dep_warnings, dep_warnings)
|> assign(:not_installed_packages, not_installed)
+ |> assign(:not_installed_keys, not_installed_keys)
{:ok, socket}
end
@@ -458,9 +460,23 @@ defmodule PhoenixKitWeb.Live.Modules do
icon: (perm && perm[:icon]) || "hero-puzzle-piece",
description: (perm && perm[:description]) || "External module",
enabled: config[:enabled] || false,
- version: if(function_exported?(mod, :version, 0), do: mod.version(), else: "0.0.0")
+ version: if(function_exported?(mod, :version, 0), do: mod.version(), else: "0.0.0"),
+ required_modules:
+ if(function_exported?(mod, :required_modules, 0), do: mod.required_modules(), else: []),
+ admin_links: extract_admin_links(mod)
}
end)
|> Enum.sort_by(& &1.name)
end
+
+ defp extract_admin_links(mod) do
+ if Code.ensure_loaded?(mod) and function_exported?(mod, :admin_tabs, 0) do
+ mod.admin_tabs()
+ |> Enum.filter(fn tab -> tab.live_view != nil and tab.visible != false end)
+ |> Enum.take(3)
+ |> Enum.map(fn tab -> %{label: tab.label, path: "/admin/" <> tab.path, icon: tab.icon} end)
+ else
+ []
+ end
+ end
end
diff --git a/lib/phoenix_kit_web/live/modules.html.heex b/lib/phoenix_kit_web/live/modules.html.heex
index d1bcf1570..003a3926c 100644
--- a/lib/phoenix_kit_web/live/modules.html.heex
+++ b/lib/phoenix_kit_web/live/modules.html.heex
@@ -211,50 +211,6 @@
<% end %>
- <%!-- Newsletters Module --%>
- <%= if "newsletters" in @accessible_modules do %>
- <% cfg = @module_configs["newsletters"] || %{} %>
-
- <:status_badges>
-
- {if cfg[:enabled], do: "Enabled", else: "Disabled"}
-
- <%= unless mcfg(@module_configs, "emails", :enabled, false) do %>
- Requires Emails
- <% end %>
-
-
- <:action_buttons>
- <%= if cfg[:enabled] do %>
-
- <.link
- navigate={PhoenixKit.Utils.Routes.path("/admin/newsletters/broadcasts")}
- class="btn btn-outline btn-sm flex-1"
- >
- <.icon name="hero-paper-airplane" class="w-4 h-4 mr-1" /> Broadcasts
-
- <.link
- navigate={PhoenixKit.Utils.Routes.path("/admin/newsletters/lists")}
- class="btn btn-outline btn-sm flex-1"
- >
- <.icon name="hero-list-bullet" class="w-4 h-4 mr-1" /> Lists
-
-
- <% end %>
-
-
- <% end %>
-
<%!-- Languages Module --%>
<%= if "languages" in @accessible_modules do %>
<% cfg = @module_configs["languages"] || %{} %>
@@ -1412,11 +1368,34 @@
v{ext.version}
External
+ <%= for req_mod <- ext.required_modules do %>
+ <%= unless mcfg(@module_configs, req_mod, :enabled, false) do %>
+
+ Requires {String.capitalize(req_mod)}
+
+ <% end %>
+ <% end %>
{if ext.enabled, do: "Module is active", else: "Enable to activate"}
+
+ <%= if ext.enabled and ext.admin_links != [] do %>
+
+ <%= for link <- ext.admin_links do %>
+ <.link
+ navigate={PhoenixKit.Utils.Routes.path(link.path)}
+ class="btn btn-outline btn-sm flex-1"
+ >
+ <%= if link.icon do %>
+ <.icon name={link.icon} class="w-4 h-4 mr-1" />
+ <% end %>
+ {link.label}
+
+ <% end %>
+
+ <% end %>
<% end %>
diff --git a/lib/phoenix_kit_web/live/settings/authorization.html.heex b/lib/phoenix_kit_web/live/settings/authorization.html.heex
index 8c36bb9f6..d46c4697e 100644
--- a/lib/phoenix_kit_web/live/settings/authorization.html.heex
+++ b/lib/phoenix_kit_web/live/settings/authorization.html.heex
@@ -274,10 +274,22 @@
name="settings[magic_link_registration_enabled]"
type="checkbox"
value="true"
- checked={@settings["magic_link_registration_enabled"] == "true"}
+ checked={
+ @settings["magic_link_registration_enabled"] == "true" and
+ @settings["allow_registration"] == "true"
+ }
+ disabled={@settings["allow_registration"] != "true"}
class="checkbox checkbox-primary"
/>
- Enable Magic Link for registration
+
+ Enable Magic Link for registration
+ <%= if @settings["allow_registration"] != "true" do %>
+ (registration disabled)
+ <% end %>
+
diff --git a/lib/phoenix_kit_web/users/magic_link_registration_request.ex b/lib/phoenix_kit_web/users/magic_link_registration_request.ex
index 9941edbd7..8c2d4d1f6 100644
--- a/lib/phoenix_kit_web/users/magic_link_registration_request.ex
+++ b/lib/phoenix_kit_web/users/magic_link_registration_request.ex
@@ -8,6 +8,7 @@ defmodule PhoenixKitWeb.Users.MagicLinkRegistrationRequest do
use PhoenixKitWeb, :live_view
alias Phoenix.LiveView.JS
+ alias PhoenixKit.Settings
alias PhoenixKit.Users.MagicLinkRegistration
alias PhoenixKit.Utils.Routes
alias PhoenixKitWeb.Users.Auth
@@ -19,17 +20,29 @@ defmodule PhoenixKitWeb.Users.MagicLinkRegistrationRequest do
{:ok, socket}
:cont ->
- # Get project title from settings (with Config fallback)
- project_title = PhoenixKit.Settings.get_project_title()
+ if Settings.get_boolean_setting("allow_registration", true) do
+ # Get project title from settings (with Config fallback)
+ project_title = PhoenixKit.Settings.get_project_title()
- {:ok,
- socket
- |> assign(:page_title, "Register via Magic Link")
- |> assign(:project_title, project_title)
- |> assign(:email, "")
- |> assign(:email_sent, false)
- |> assign(:error_message, nil)
- |> assign(:loading, false)}
+ {:ok,
+ socket
+ |> assign(:page_title, "Register via Magic Link")
+ |> assign(:project_title, project_title)
+ |> assign(:email, "")
+ |> assign(:email_sent, false)
+ |> assign(:error_message, nil)
+ |> assign(:loading, false)}
+ else
+ socket =
+ socket
+ |> put_flash(
+ :error,
+ "User registration is currently disabled. Please contact an administrator."
+ )
+ |> redirect(to: Routes.path("/users/log-in"))
+
+ {:ok, socket}
+ end
end
end