Packages

phoenix_kit

1.7.39
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 phoenix_kit_web live modules.html.heex
Raw

lib/phoenix_kit_web/live/modules.html.heex

<PhoenixKitWeb.Components.LayoutWrapper.app_layout
flash={@flash}
phoenix_kit_current_scope={assigns[:phoenix_kit_current_scope]}
page_title="{@project_title} Modules"
current_path={@url_path}
project_title={@project_title}
current_locale={@current_locale}
>
<div class="container flex flex-col mx-auto px-4 py-6">
<%!-- Header Section --%>
<header class="w-full mb-6">
<div class="mb-4">
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin")}
class="btn btn-outline btn-primary btn-sm"
>
<.icon name="hero-arrow-left" class="w-4 h-4 mr-2" /> Back to Dashboard
</.link>
</div>
<div class="text-center">
<h1 class="text-2xl sm:text-4xl font-bold text-base-content mb-3">Modules</h1>
<p class="text-base sm:text-lg text-base-content">Manage modules</p>
</div>
</header>
<div class="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
<%!-- Storage Module --%>
<%= if "storage" in @accessible_modules do %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Storage"
description="Distributed file storage system with multi-location redundancy and automatic failover"
icon="💾"
enabled={@storage_enabled}
toggle_event="storage_always_enabled"
show_toggle={false}
>
<:status_badges>
<span class="badge badge-success">Always Enabled</span>
<span class="badge badge-info">Core System</span>
</:status_badges>
<:action_buttons>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/media")}
class="btn btn-primary btn-sm"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Configure
</.link>
</:action_buttons>
<:stats>
<div class="grid grid-cols-2 gap-2 text-xs">
<div>
<span class="text-base-content/70">Total Buckets:</span>
<span class="font-medium">{@storage_buckets_count}</span>
</div>
<div>
<span class="text-base-content/70">Active:</span>
<span class="font-medium">{@storage_active_buckets_count}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Referral Codes Module --%>
<%= if "referrals" in @accessible_modules do %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Referral Codes"
description="Manage referral codes for user registration and monitoring"
icon="🎫"
enabled={@referral_codes_enabled}
toggle_event="toggle_referral_codes"
>
<:status_badges>
<span class={[
"badge",
if(@referral_codes_enabled, do: "badge-success", else: "badge-neutral")
]}>
{if @referral_codes_enabled, do: "Enabled", else: "Disabled"}
</span>
<%= if @referral_codes_enabled do %>
<span class="badge badge-outline ml-2 whitespace-nowrap">
{if @referral_codes_required, do: "Required", else: "Optional"}
</span>
<% end %>
</:status_badges>
<:action_buttons>
<%= if @referral_codes_enabled do %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/referral-codes")}
class="btn btn-primary btn-sm"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Configure
</.link>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/users/referral-codes")}
class="btn btn-outline btn-sm"
>
<.icon name="hero-users" class="w-4 h-4 mr-1" /> Manage Codes
</.link>
<% else %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/referral-codes")}
class="btn btn-outline btn-sm"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Configure
</.link>
<% end %>
</:action_buttons>
<:stats>
<div class="grid grid-cols-2 gap-2 text-xs">
<div>
<span class="text-base-content/70">Max per user:</span>
<span class="font-medium">{@max_codes_per_user}</span>
</div>
<div>
<span class="text-base-content/70">Max uses:</span>
<span class="font-medium">{@max_uses_per_code}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Email Module --%>
<%= if "emails" in @accessible_modules do %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Emails"
description="Track and analyze all outgoing emails with delivery events"
icon="📧"
enabled={@email_enabled}
toggle_event="toggle_emails"
>
<:status_badges>
<span class={[
"badge",
if(@email_enabled, do: "badge-success", else: "badge-neutral")
]}>
{if @email_enabled, do: "Enabled", else: "Disabled"}
</span>
<%= if @email_enabled do %>
<span class="badge badge-outline ml-2 whitespace-nowrap">
{if @email_save_body, do: "Body Saved", else: "Headers Only"}
</span>
<% end %>
</:status_badges>
<:action_buttons>
<div class="flex flex-col items-stretch space-y-2">
<%= if @email_enabled do %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/emails")}
class="btn btn-primary btn-sm"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Configure
</.link>
<div class="flex gap-2">
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/emails")}
class="btn btn-outline btn-sm flex-1"
>
<.icon name="hero-envelope" class="w-4 h-4 mr-1" /> Emails
</.link>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/emails/templates")}
class="btn btn-outline btn-sm flex-1"
>
<.icon name="hero-document-text" class="w-4 h-4 mr-1" /> Templates
</.link>
</div>
<% else %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/emails")}
class="btn btn-outline btn-sm"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Configure
</.link>
<% end %>
</div>
</:action_buttons>
<:stats>
<div class="grid grid-cols-2 gap-2 text-xs">
<div>
<span class="text-base-content/70">SES Events:</span>
<span class="font-medium">
{if @email_ses_events, do: "On", else: "Off"}
</span>
</div>
<div>
<span class="text-base-content/70">Retention:</span>
<span class="font-medium">{@email_retention_days} days</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Languages Module --%>
<%= if "languages" in @accessible_modules do %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Languages"
description="Manage language module and translations"
icon="🌐"
enabled={@languages_enabled}
toggle_event="toggle_languages"
>
<:status_badges>
<span class={[
"badge",
if(@languages_enabled, do: "badge-success", else: "badge-neutral")
]}>
{if @languages_enabled, do: "Enabled", else: "Disabled"}
</span>
<%= if @languages_enabled do %>
<span class="badge badge-outline ml-2 whitespace-nowrap">
{if @languages_default,
do: @languages_default["name"],
else: "No Default"}
</span>
<% end %>
</:status_badges>
<:action_buttons>
<%= if @languages_enabled do %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/languages")}
class="btn btn-primary btn-sm"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Configure
</.link>
<% else %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/languages")}
class="btn btn-outline btn-sm"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Configure
</.link>
<% end %>
</:action_buttons>
<:stats>
<div class="grid grid-cols-2 gap-2 text-xs">
<div>
<span class="text-base-content/70">Total languages:</span>
<span class="font-medium">{@languages_count}</span>
</div>
<div>
<span class="text-base-content/70">Enabled:</span>
<span class="font-medium">{@languages_enabled_count}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Entities Module --%>
<%= if "entities" in @accessible_modules do %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title={gettext("Entities")}
description={
gettext("Define custom content types with flexible fields — no migrations required")
}
icon="📦"
enabled={@entities_enabled}
toggle_event="toggle_entities"
>
<:status_badges>
<span class={[
"badge",
if(@entities_enabled, do: "badge-success", else: "badge-neutral")
]}>
{if @entities_enabled, do: gettext("Enabled"), else: gettext("Disabled")}
</span>
</:status_badges>
<:action_buttons>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/entities")}
class={[
"btn btn-sm",
if(@entities_enabled, do: "btn-primary", else: "btn-outline")
]}
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" />
{gettext("Configure")}
</.link>
</:action_buttons>
<:stats>
<div class="grid grid-cols-2 gap-2 text-xs">
<div>
<span class="text-base-content/70">{gettext("Total Entities:")}</span>
<span class="font-medium">{@entities_count}</span>
</div>
<div>
<span class="text-base-content/70">{gettext("Data Records:")}</span>
<span class="font-medium">{@entities_total_data}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Publishing Module --%>
<%= if "publishing" in @accessible_modules do %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Publishing"
description="Publish date-based blog posts and company updates with multi-language support"
icon="📰"
enabled={@publishing_enabled}
toggle_event="toggle_publishing"
>
<:status_badges>
<span class={[
"badge",
if(@publishing_enabled, do: "badge-success", else: "badge-neutral")
]}>
{if @publishing_enabled, do: gettext("Enabled"), else: gettext("Disabled")}
</span>
</:status_badges>
<:action_buttons>
<div class="flex flex-col gap-2 w-full">
<.link
navigate={
PhoenixKit.Utils.Routes.path("/admin/publishing",
locale: @current_locale || "en"
)
}
class={"btn btn-sm #{if @publishing_enabled, do: "btn-primary", else: "btn-outline"}"}
>
<.icon name="hero-document-text" class="w-4 h-4 mr-1" /> {gettext("Open")}
</.link>
<.link
navigate={
PhoenixKit.Utils.Routes.path("/admin/settings/publishing",
locale: @current_locale || "en"
)
}
class="btn btn-sm btn-outline"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> {gettext("Configure")}
</.link>
</div>
</:action_buttons>
<:stats>
<% url_prefix =
PhoenixKit.Config.get_url_prefix()
|> case do
"/" -> ""
prefix -> prefix
end
# Determine default language base code for URL display
default_lang_code =
if @languages_enabled && @languages_default do
@languages_default["code"]
|> PhoenixKit.Modules.Languages.DialectMapper.extract_base()
else
nil
end %>
<div class="space-y-1.5">
<div>
<span class="font-medium text-base-content">
{gettext("Post files on disk:")}
</span>
<code class="font-mono text-xs bg-base-300/60 rounded px-2 py-0.5 break-all">
priv/publishing/&lt;group&gt;/&lt;slug&gt;/&lt;locale&gt;.phk
</code>
</div>
<%= if @languages_enabled && default_lang_code do %>
<div>
<span class="font-medium text-base-content">
{gettext("Default language (%{lang}):", lang: default_lang_code)}
</span>
<code class="font-mono text-xs bg-base-300/60 rounded px-2 py-0.5 break-all">
{url_prefix}/:blog_slug/:post_slug
</code>
</div>
<div>
<span class="font-medium text-base-content">
{gettext("Other languages:")}
</span>
<code class="font-mono text-xs bg-base-300/60 rounded px-2 py-0.5 break-all">
{url_prefix}/:locale/:blog_slug/:post_slug
</code>
</div>
<% else %>
<div>
<span class="font-medium text-base-content">
{gettext("Public URL pattern:")}
</span>
<code class="font-mono text-xs bg-base-300/60 rounded px-2 py-0.5 break-all">
{url_prefix}/:blog_slug/:post_slug
</code>
</div>
<% end %>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Posts Module --%>
<%= if "posts" in @accessible_modules do %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Posts"
description="User-generated content with comments, likes, tags, and groups"
icon="📝"
enabled={@posts_enabled}
toggle_event="toggle_posts"
>
<:status_badges>
<span class={[
"badge",
if(@posts_enabled, do: "badge-success", else: "badge-neutral")
]}>
{if @posts_enabled, do: "Enabled", else: "Disabled"}
</span>
</:status_badges>
<:action_buttons>
<div class="flex flex-col gap-2 w-full">
<%= if @posts_enabled do %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/posts")}
class="btn btn-primary btn-sm"
>
<.icon name="hero-document-text" class="w-4 h-4 mr-1" /> Manage Posts
</.link>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/posts")}
class="btn btn-outline btn-sm"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Settings
</.link>
<% else %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/posts")}
class="btn btn-outline btn-sm"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Configure
</.link>
<% end %>
</div>
</:action_buttons>
<:stats>
<div class="grid grid-cols-3 gap-2 text-xs">
<div>
<span class="text-base-content/70">Total:</span>
<span class="font-medium">{@posts_total}</span>
</div>
<div>
<span class="text-base-content/70">Published:</span>
<span class="font-medium">{@posts_published}</span>
</div>
<div>
<span class="text-base-content/70">Drafts:</span>
<span class="font-medium">{@posts_draft}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Comments Module --%>
<%= if "comments" in @accessible_modules do %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Comments"
description="Threaded comments with likes, moderation, and reactions across all content types"
icon="💬"
enabled={@comments_enabled}
toggle_event="toggle_comments"
>
<:status_badges>
<span class={[
"badge",
if(@comments_enabled, do: "badge-success", else: "badge-neutral")
]}>
{if @comments_enabled, do: "Enabled", else: "Disabled"}
</span>
<%= if @comments_enabled and @comments_pending > 0 do %>
<span class="badge badge-warning ml-2 whitespace-nowrap">
{@comments_pending} pending
</span>
<% end %>
</:status_badges>
<:action_buttons>
<div class="flex flex-col gap-2 w-full">
<%= if @comments_enabled do %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/comments")}
class="btn btn-primary btn-sm"
>
<.icon name="hero-chat-bubble-left-right" class="w-4 h-4 mr-1" />
Manage Comments
</.link>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/comments")}
class="btn btn-outline btn-sm"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Settings
</.link>
<% else %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/comments")}
class="btn btn-outline btn-sm"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Configure
</.link>
<% end %>
</div>
</:action_buttons>
<:stats>
<div class="grid grid-cols-3 gap-2 text-xs">
<div>
<span class="text-base-content/70">Total:</span>
<span class="font-medium">{@comments_total}</span>
</div>
<div>
<span class="text-base-content/70">Published:</span>
<span class="font-medium">{@comments_published}</span>
</div>
<div>
<span class="text-base-content/70">Pending:</span>
<span class="font-medium">{@comments_pending}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Support Tickets Module --%>
<%= if "tickets" in @accessible_modules do %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Support Tickets"
description="Customer support ticketing system with internal notes and status tracking"
icon="🎫"
enabled={@tickets_enabled}
toggle_event="toggle_tickets"
>
<:status_badges>
<span class={[
"badge",
if(@tickets_enabled, do: "badge-success", else: "badge-neutral")
]}>
{if @tickets_enabled, do: "Enabled", else: "Disabled"}
</span>
<%= if @tickets_enabled and @tickets_open > 0 do %>
<span class="badge badge-warning ml-2 whitespace-nowrap">
{@tickets_open} open
</span>
<% end %>
</:status_badges>
<:action_buttons>
<div class="flex flex-col gap-2 w-full">
<%= if @tickets_enabled do %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/tickets")}
class="btn btn-primary btn-sm"
>
<.icon name="hero-ticket" class="w-4 h-4 mr-1" /> Manage Tickets
</.link>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/tickets")}
class="btn btn-outline btn-sm"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Settings
</.link>
<% else %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/tickets")}
class="btn btn-outline btn-sm"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Configure
</.link>
<% end %>
</div>
</:action_buttons>
<:stats>
<div class="grid grid-cols-3 gap-2 text-xs">
<div>
<span class="text-base-content/70">Total:</span>
<span class="font-medium">{@tickets_total}</span>
</div>
<div>
<span class="text-base-content/70">Open:</span>
<span class="font-medium">{@tickets_open}</span>
</div>
<div>
<span class="text-base-content/70">In Progress:</span>
<span class="font-medium">{@tickets_in_progress}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Connections Module --%>
<%= if "connections" in @accessible_modules do %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Connections"
description="Social relationships with one-way follows and mutual connections"
icon="🤝"
enabled={@connections_enabled}
toggle_event="toggle_connections"
>
<:status_badges>
<span class={[
"badge",
if(@connections_enabled, do: "badge-success", else: "badge-neutral")
]}>
{if @connections_enabled, do: "Enabled", else: "Disabled"}
</span>
</:status_badges>
<:action_buttons>
<div class="flex flex-col gap-2 w-full">
<%= if @connections_enabled do %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/connections")}
class="btn btn-primary btn-sm"
>
<.icon name="hero-users" class="w-4 h-4 mr-1" /> Overview
</.link>
<% else %>
<span class="text-xs text-base-content/50 text-center">
Enable module to manage connections
</span>
<% end %>
</div>
</:action_buttons>
<:stats>
<div class="grid grid-cols-3 gap-2 text-xs">
<div>
<span class="text-base-content/70">Follows:</span>
<span class="font-medium">{@connections_follows_count}</span>
</div>
<div>
<span class="text-base-content/70">Connections:</span>
<span class="font-medium">{@connections_connections_count}</span>
</div>
<div>
<span class="text-base-content/70">Blocks:</span>
<span class="font-medium">{@connections_blocks_count}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- SEO Module --%>
<%= if "seo" in @accessible_modules do %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="SEO"
description="Manage search engine optimization controls for your application"
icon="🔍"
enabled={@seo_module_enabled}
toggle_event="toggle_seo_module"
>
<:status_badges>
<span class={[
"badge",
if(@seo_module_enabled, do: "badge-success", else: "badge-neutral")
]}>
{if @seo_module_enabled, do: "Enabled", else: "Disabled"}
</span>
</:status_badges>
<:action_buttons>
<.link
navigate={
PhoenixKit.Utils.Routes.path("/admin/settings/seo",
locale: @current_locale || "en"
)
}
class={"btn btn-sm w-full #{if @seo_module_enabled, do: "btn-primary", else: "btn-outline"}"}
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Configure
</.link>
</:action_buttons>
<:stats>
<div class="text-sm">
<span class="text-base-content/70">Noindex:</span>
<span class="ml-2 font-medium">
{if @seo_no_index_enabled, do: "On", else: "Off"}
</span>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Sitemap Module --%>
<%= if "sitemap" in @accessible_modules do %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Sitemap"
description="Generate XML sitemaps for search engines with styled browser display"
icon="🗺️"
enabled={@sitemap_enabled}
toggle_event="toggle_sitemap"
>
<:status_badges>
<span class={[
"badge",
if(@sitemap_enabled, do: "badge-success", else: "badge-neutral")
]}>
{if @sitemap_enabled, do: "Enabled", else: "Disabled"}
</span>
<%= if @sitemap_enabled and @sitemap_schedule_enabled do %>
<span class="badge badge-outline ml-2 whitespace-nowrap">
Auto-regenerate
</span>
<% end %>
</:status_badges>
<:action_buttons>
<div class="flex flex-col gap-2 w-full">
<.link
navigate={
PhoenixKit.Utils.Routes.path("/admin/settings/sitemap",
locale: :none
)
}
class={"btn btn-sm #{if @sitemap_enabled, do: "btn-primary", else: "btn-outline"}"}
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Configure
</.link>
<%= if @sitemap_enabled do %>
<.link
href={PhoenixKit.Utils.Routes.path("/sitemap.xml", locale: :none)}
target="_blank"
class="btn btn-outline btn-sm"
>
<.icon name="hero-arrow-top-right-on-square" class="w-4 h-4 mr-1" /> Sitemap
</.link>
<% end %>
</div>
</:action_buttons>
<:stats>
<div class="grid grid-cols-2 gap-2 text-xs">
<div>
<span class="text-base-content/70">URLs:</span>
<span class="font-medium">{@sitemap_url_count}</span>
</div>
<div>
<span class="text-base-content/70">Last gen:</span>
<span class="font-medium">
{format_timestamp(@sitemap_last_generated)}
</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Billing Module --%>
<%= if "billing" in @accessible_modules do %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Billing"
description="Orders, invoices, billing profiles and multi-currency support"
icon="💰"
enabled={@billing_enabled}
toggle_event="toggle_billing"
>
<:status_badges>
<span class={[
"badge",
if(@billing_enabled, do: "badge-success", else: "badge-neutral")
]}>
{if @billing_enabled, do: "Enabled", else: "Disabled"}
</span>
</:status_badges>
<:action_buttons>
<div class="flex flex-col gap-2 w-full">
<%= if @billing_enabled do %>
<div class="flex gap-2">
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/billing")}
class="btn btn-primary btn-sm flex-1"
>
<.icon name="hero-banknotes" class="w-4 h-4 mr-1" /> Dashboard
</.link>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/billing")}
class="btn btn-outline btn-sm flex-1"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Settings
</.link>
</div>
<div class="flex gap-2">
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/billing/orders")}
class="btn btn-outline btn-sm flex-1"
>
<.icon name="hero-clipboard-document-list" class="w-4 h-4 mr-1" /> Orders
</.link>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/billing/invoices")}
class="btn btn-outline btn-sm flex-1"
>
<.icon name="hero-document-text" class="w-4 h-4 mr-1" /> Invoices
</.link>
</div>
<% else %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/billing")}
class="btn btn-outline btn-sm"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Configure
</.link>
<% end %>
</div>
</:action_buttons>
<:stats>
<div class="grid grid-cols-3 gap-2 text-xs">
<div>
<span class="text-base-content/70">Orders:</span>
<span class="font-medium">{@billing_orders_count}</span>
</div>
<div>
<span class="text-base-content/70">Invoices:</span>
<span class="font-medium">{@billing_invoices_count}</span>
</div>
<div>
<span class="text-base-content/70">Currencies:</span>
<span class="font-medium">{@billing_currencies_count}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- AI Module --%>
<%= if "ai" in @accessible_modules do %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="AI"
description="AI provider accounts and text processing with OpenRouter integration"
icon="🤖"
enabled={@ai_enabled}
toggle_event="toggle_ai"
>
<:status_badges>
<span class={[
"badge",
if(@ai_enabled, do: "badge-success", else: "badge-neutral")
]}>
{if @ai_enabled, do: "Enabled", else: "Disabled"}
</span>
<%= if @ai_enabled and @ai_endpoints_count > 0 do %>
<span class="badge badge-outline ml-2 whitespace-nowrap">
{@ai_endpoints_count} endpoint{if @ai_endpoints_count != 1, do: "s"}
</span>
<% end %>
</:status_badges>
<:action_buttons>
<div class="flex flex-col gap-2 w-full">
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/ai")}
class={"btn btn-sm #{if @ai_enabled, do: "btn-primary", else: "btn-outline"}"}
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Manage
</.link>
</div>
</:action_buttons>
<:stats>
<div class="grid grid-cols-2 gap-2 text-xs">
<div>
<span class="text-base-content/70">Endpoints:</span>
<span class="font-medium">{@ai_endpoints_count}</span>
</div>
<div>
<span class="text-base-content/70">Requests:</span>
<span class="font-medium">{@ai_total_requests}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Pages module remains disabled but code retained for future use --%>
<%!-- Under Construction (Maintenance Mode) Module --%>
<%= if "maintenance" in @accessible_modules do %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Maintenance Mode"
description="Show maintenance page to non-admin users while you work on the site"
icon="🚧"
enabled={@under_construction_module_enabled}
toggle_event="toggle_under_construction"
>
<:status_badges>
<span class={[
"badge",
if(@under_construction_module_enabled, do: "badge-success", else: "badge-neutral")
]}>
{if @under_construction_module_enabled, do: "Enabled", else: "Disabled"}
</span>
<%= if @under_construction_module_enabled do %>
<span class={[
"badge badge-outline ml-2 whitespace-nowrap",
if(@under_construction_enabled, do: "badge-warning", else: "badge-info")
]}>
{if @under_construction_enabled, do: "Maintenance Active", else: "Maintenance Off"}
</span>
<% end %>
</:status_badges>
<:action_buttons>
<div class="flex flex-col gap-2 w-full">
<%= if @under_construction_module_enabled do %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/maintenance")}
class="btn btn-sm btn-primary"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Configure
</.link>
<div class="text-xs text-base-content/70 mt-2">
<strong>Header:</strong>
{@under_construction_header}
</div>
<div class="text-xs text-base-content/70">
<strong>Message:</strong>
{@under_construction_subtext}
</div>
<% else %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/maintenance")}
class="btn btn-sm btn-outline"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Configure
</.link>
<% end %>
</div>
</:action_buttons>
<:stats>
<div class="text-xs text-base-content/70">
{if @under_construction_module_enabled,
do: "Activate maintenance mode in settings to block non-admin users",
else: "Enable module to access maintenance mode settings"}
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Sync Module --%>
<%= if "sync" in @accessible_modules do %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Sync"
description="Sync data between PhoenixKit instances in real-time"
icon="🔄"
enabled={@sync_enabled}
toggle_event="toggle_sync"
>
<:status_badges>
<span class={[
"badge",
if(@sync_enabled, do: "badge-success", else: "badge-neutral")
]}>
{if @sync_enabled, do: "Enabled", else: "Disabled"}
</span>
<%= if @sync_enabled and @sync_active_sessions > 0 do %>
<span class="badge badge-outline badge-warning ml-2 whitespace-nowrap">
{@sync_active_sessions} active
</span>
<% end %>
</:status_badges>
<:action_buttons>
<div class="flex flex-col gap-2 w-full">
<%= if @sync_enabled do %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/sync")}
class="btn btn-primary btn-sm"
>
<.icon name="hero-arrow-path" class="w-4 h-4 mr-1" /> Open Sync
</.link>
<% else %>
<span class="text-xs text-base-content/50 text-center">
Enable module to start syncing data
</span>
<% end %>
</div>
</:action_buttons>
<:stats>
<div class="text-xs text-base-content/70">
{if @sync_enabled,
do: "Sync data between dev, staging, and production environments",
else: "Enable to sync data between PhoenixKit sites"}
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- DB Module --%>
<%= if "db" in @accessible_modules do %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="DB"
description="Explore database tables and their contents"
icon="🗃️"
enabled={@db_explorer_enabled}
toggle_event="toggle_db_explorer"
stats_title="Current Stats"
>
<:status_badges>
<span class={[
"badge",
if(@db_explorer_enabled, do: "badge-success", else: "badge-neutral")
]}>
{if @db_explorer_enabled, do: "Enabled", else: "Disabled"}
</span>
</:status_badges>
<:action_buttons>
<div class="flex flex-col gap-2 w-full">
<%= if @db_explorer_enabled do %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/db")}
class="btn btn-primary btn-sm"
>
<.icon name="hero-table-cells" class="w-4 h-4 mr-1" /> Open DB
</.link>
<% else %>
<span class="text-xs text-base-content/50 text-center">
Enable module to browse database tables
</span>
<% end %>
</div>
</:action_buttons>
<:stats>
<div class="grid grid-cols-2 gap-2 text-xs">
<div>
<span class="text-base-content/70">Tables</span>
<div class="font-semibold">
<.formatted_number number={@db_explorer_table_count} />
</div>
</div>
<div>
<span class="text-base-content/70">Rows</span>
<div class="font-semibold">
<.formatted_number number={@db_explorer_total_rows} format={:short} />
</div>
</div>
<div>
<span class="text-base-content/70">Tables size</span>
<div class="font-semibold">
{format_bytes(@db_explorer_total_size)}
</div>
</div>
<div>
<span class="text-base-content/70">Database size</span>
<div class="font-semibold">
{format_bytes(@db_explorer_database_size)}
</div>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Jobs Module --%>
<%= if "jobs" in @accessible_modules do %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Jobs"
description="View-only dashboard for background job status and history"
icon="⚙️"
enabled={@jobs_enabled}
toggle_event="toggle_jobs"
>
<:status_badges>
<span class={[
"badge",
if(@jobs_enabled, do: "badge-success", else: "badge-neutral")
]}>
{if @jobs_enabled, do: "Enabled", else: "Disabled"}
</span>
<%= if @jobs_enabled and @jobs_stats.executing > 0 do %>
<span class="badge badge-outline badge-warning ml-2 whitespace-nowrap">
{@jobs_stats.executing} running
</span>
<% end %>
</:status_badges>
<:action_buttons>
<div class="flex flex-col gap-2 w-full">
<%= if @jobs_enabled do %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/jobs")}
class="btn btn-primary btn-sm"
>
<.icon name="hero-queue-list" class="w-4 h-4 mr-1" /> View Jobs
</.link>
<% else %>
<span class="text-xs text-base-content/50 text-center">
Enable module to view background jobs
</span>
<% end %>
</div>
</:action_buttons>
<:stats>
<div class="grid grid-cols-4 gap-2 text-xs">
<div>
<span class="text-base-content/70">Available:</span>
<span class="font-medium">{@jobs_stats.available}</span>
</div>
<div>
<span class="text-base-content/70">Completed:</span>
<span class="font-medium">{@jobs_stats.completed}</span>
</div>
<div>
<span class="text-base-content/70">Retryable:</span>
<span class="font-medium">{@jobs_stats.retryable}</span>
</div>
<div>
<span class="text-base-content/70">Discarded:</span>
<span class="font-medium">{@jobs_stats.discarded}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Legal Module --%>
<%= if "legal" in @accessible_modules do %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Legal"
description="GDPR/CCPA compliance with consent tracking, cookie banners, and legal page generation"
icon="⚖️"
enabled={@legal_enabled}
toggle_event="toggle_legal"
>
<:status_badges>
<span class={[
"badge",
if(@legal_enabled, do: "badge-success", else: "badge-neutral")
]}>
{if @legal_enabled, do: "Enabled", else: "Disabled"}
</span>
<%= if @legal_enabled and @publishing_enabled_for_legal do %>
<span class="badge badge-info ml-2">Publishing Ready</span>
<% end %>
</:status_badges>
<:action_buttons>
<%= if @legal_enabled do %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/legal")}
class="btn btn-primary btn-sm"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Configure
</.link>
<% else %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/legal")}
class="btn btn-outline btn-sm"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Configure
</.link>
<% end %>
</:action_buttons>
<:stats>
<div class="text-xs text-base-content/70">
<p>Privacy Policy • Terms of Service • Cookie Policy</p>
<p class="mt-1">CCPA Notice • Data Retention • Acceptable Use</p>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- E-Commerce Module --%>
<%= if "shop" in @accessible_modules do %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="E-Commerce"
description="Physical and digital products with cart and checkout"
icon="🛒"
enabled={@shop_enabled}
toggle_event="toggle_shop"
toggle_disabled={not @billing_enabled}
toggle_hint={if not @billing_enabled, do: "Billing Required"}
>
<:status_badges>
<span class={[
"badge",
if(@shop_enabled, do: "badge-success", else: "badge-neutral")
]}>
{if @shop_enabled, do: "Enabled", else: "Disabled"}
</span>
<%= if not @shop_enabled and @billing_enabled do %>
<span class="badge badge-info ml-2">Billing Ready</span>
<% end %>
</:status_badges>
<:action_buttons>
<div class="flex flex-col gap-2 w-full">
<%= if @shop_enabled do %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/shop")}
class="btn btn-primary btn-sm"
>
<.icon name="hero-shopping-bag" class="w-4 h-4 mr-1" /> Dashboard
</.link>
<div class="flex gap-2">
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/shop/products")}
class="btn btn-outline btn-sm flex-1"
>
<.icon name="hero-cube" class="w-4 h-4 mr-1" /> Products
</.link>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/shop/settings")}
class="btn btn-outline btn-sm flex-1"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Settings
</.link>
</div>
<% else %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/shop/settings")}
class="btn btn-outline btn-sm"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Configure
</.link>
<% end %>
</div>
</:action_buttons>
<:stats>
<div class="grid grid-cols-2 gap-2 text-xs">
<div>
<span class="text-base-content/70">Products:</span>
<span class="font-medium">{@shop_products_count}</span>
</div>
<div>
<span class="text-base-content/70">Categories:</span>
<span class="font-medium">{@shop_categories_count}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
</div>
<%!-- Future Modules Section --%>
<div class="mt-8">
<div class="card bg-base-100 shadow-xl border-2 border-dashed border-base-300">
<div class="card-body text-center py-8">
<div class="text-4xl mb-4 opacity-50">📦</div>
<h3 class="text-xl font-semibold text-base-content/60 mb-2">
More Modules Coming Soon
</h3>
<p class="text-base-content/50">
Additional system modules and extensions will be available here as they're developed.
Each module will have its own dedicated configuration page for scalable management.
</p>
</div>
</div>
</div>
<%!-- Module Management Help --%>
<div class="alert alert-info mt-6">
<.icon name="hero-information-circle" class="w-5 h-5" />
<div>
<h3 class="font-bold">Module Management</h3>
<p class="text-sm">
Each module can be enabled or disabled using the toggle switches above.
Click "Configure" to access detailed settings for each module on dedicated pages.
</p>
</div>
</div>
</div>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>