Packages
phoenix_kit
1.7.71
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
Current section
Files
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">
<.admin_page_header
back={PhoenixKit.Utils.Routes.path("/admin")}
title="Modules"
subtitle="Manage modules"
/>
<div class="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
<%!-- Storage Module --%>
<%= if "storage" in @accessible_modules do %>
<% cfg = @module_configs["storage"] || %{} %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Storage"
description="Distributed file storage system with multi-location redundancy and automatic failover"
icon="💾"
enabled={cfg[:module_enabled]}
toggle_event="toggle_module"
toggle_key="storage"
show_toggle={false}
>
<:status_badges>
<span class="badge badge-success z-0">Always Enabled</span>
<span class="badge badge-info z-0">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">{cfg[:buckets_count]}</span>
</div>
<div>
<span class="text-base-content/70">Active:</span>
<span class="font-medium">{cfg[:active_buckets_count]}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Referral Codes Module --%>
<%= if "referrals" in @accessible_modules do %>
<% cfg = @module_configs["referrals"] || %{} %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Referral Codes"
description="Manage referral codes for user registration and monitoring"
icon="🎫"
enabled={cfg[:enabled]}
toggle_event="toggle_module"
toggle_key="referrals"
>
<:status_badges>
<span class={[
"badge",
if(cfg[:enabled], do: "badge-success", else: "badge-neutral")
]}>
{if cfg[:enabled], do: "Enabled", else: "Disabled"}
</span>
<%= if cfg[:enabled] do %>
<span class="badge badge-outline ml-2 whitespace-nowrap">
{if cfg[:required], do: "Required", else: "Optional"}
</span>
<% end %>
</:status_badges>
<:action_buttons>
<%= if cfg[: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">{cfg[:max_codes_per_user]}</span>
</div>
<div>
<span class="text-base-content/70">Max uses:</span>
<span class="font-medium">{cfg[:max_uses_per_code]}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Email Module --%>
<%= if "emails" in @accessible_modules do %>
<% cfg = @module_configs["emails"] || %{} %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Emails"
description="Track and analyze all outgoing emails with delivery events"
icon="📧"
enabled={cfg[:enabled]}
toggle_event="toggle_module"
toggle_key="emails"
>
<:status_badges>
<span class={[
"badge",
if(cfg[:enabled], do: "badge-success", else: "badge-neutral")
]}>
{if cfg[:enabled], do: "Enabled", else: "Disabled"}
</span>
<%= if cfg[:enabled] do %>
<span class="badge badge-outline ml-2 whitespace-nowrap">
{if cfg[: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 cfg[: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 cfg[:ses_events], do: "On", else: "Off"}
</span>
</div>
<div>
<span class="text-base-content/70">Retention:</span>
<span class="font-medium">{cfg[:retention_days]} days</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Newsletters Module --%>
<%= if "newsletters" in @accessible_modules do %>
<% cfg = @module_configs["newsletters"] || %{} %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Newsletters"
description="Email broadcasts and subscription management"
icon="📨"
enabled={cfg[:enabled]}
toggle_event="toggle_module"
toggle_key="newsletters"
>
<:status_badges>
<span class={[
"badge",
if(cfg[:enabled], do: "badge-success", else: "badge-neutral")
]}>
{if cfg[:enabled], do: "Enabled", else: "Disabled"}
</span>
<%= unless mcfg(@module_configs, "emails", :enabled, false) do %>
<span class="badge badge-warning">Requires Emails</span>
<% end %>
</:status_badges>
<:action_buttons>
<%= if cfg[:enabled] do %>
<div class="flex gap-2">
<.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>
<.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
</.link>
</div>
<% end %>
</:action_buttons>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Languages Module --%>
<%= if "languages" in @accessible_modules do %>
<% cfg = @module_configs["languages"] || %{} %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Languages"
description="Manage language module and translations"
icon="🌐"
enabled={cfg[:enabled]}
toggle_event="toggle_module"
toggle_key="languages"
>
<:status_badges>
<span class={[
"badge",
if(cfg[:enabled], do: "badge-success", else: "badge-neutral")
]}>
{if cfg[:enabled], do: "Enabled", else: "Disabled"}
</span>
<%= if cfg[:enabled] do %>
<span class="badge badge-outline ml-2 whitespace-nowrap">
{if cfg[:default_language],
do: cfg[:default_language].name,
else: "No Default"}
</span>
<% end %>
</:status_badges>
<:action_buttons>
<%= if cfg[: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">{cfg[:language_count]}</span>
</div>
<div>
<span class="text-base-content/70">Enabled:</span>
<span class="font-medium">{cfg[:enabled_count]}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Entities Module --%>
<%= if "entities" in @accessible_modules do %>
<% cfg = @module_configs["entities"] || %{} %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title={gettext("Entities")}
description={
gettext("Define custom content types with flexible fields — no migrations required")
}
icon="📦"
enabled={cfg[:enabled]}
toggle_event="toggle_module"
toggle_key="entities"
>
<:status_badges>
<span class={[
"badge",
if(cfg[:enabled], do: "badge-success", else: "badge-neutral")
]}>
{if cfg[: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(cfg[: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">{cfg[:entity_count]}</span>
</div>
<div>
<span class="text-base-content/70">{gettext("Data Records:")}</span>
<span class="font-medium">{cfg[:total_data_count]}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Publishing Module --%>
<%= if "publishing" in @accessible_modules do %>
<% cfg = @module_configs["publishing"] || %{} %>
<% lang = @module_configs["languages"] || %{} %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Publishing"
description="Publish date-based blog posts and company updates with multi-language support"
icon="📰"
enabled={cfg[:enabled]}
toggle_event="toggle_module"
toggle_key="publishing"
>
<:status_badges>
<span class={[
"badge",
if(cfg[:enabled], do: "badge-success", else: "badge-neutral")
]}>
{if cfg[: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 cfg[: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 lang[:enabled] && lang[:default_language] do
lang[:default_language].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/<group>/<slug>/<locale>.phk
</code>
</div>
<%= if lang[: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 %>
<% cfg = @module_configs["posts"] || %{} %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Posts"
description="User-generated content with comments, likes, tags, and groups"
icon="📝"
enabled={cfg[:enabled]}
toggle_event="toggle_module"
toggle_key="posts"
>
<:status_badges>
<span class={[
"badge",
if(cfg[:enabled], do: "badge-success", else: "badge-neutral")
]}>
{if cfg[:enabled], do: "Enabled", else: "Disabled"}
</span>
</:status_badges>
<:action_buttons>
<div class="flex flex-col gap-2 w-full">
<%= if cfg[: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">{cfg[:total_posts]}</span>
</div>
<div>
<span class="text-base-content/70">Published:</span>
<span class="font-medium">{cfg[:published_posts]}</span>
</div>
<div>
<span class="text-base-content/70">Drafts:</span>
<span class="font-medium">{cfg[:draft_posts]}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Comments Module --%>
<%= if "comments" in @accessible_modules do %>
<% cfg = @module_configs["comments"] || %{} %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Comments"
description="Threaded comments with likes, moderation, and reactions across all content types"
icon="💬"
enabled={cfg[:enabled]}
toggle_event="toggle_module"
toggle_key="comments"
>
<:status_badges>
<span class={[
"badge",
if(cfg[:enabled], do: "badge-success", else: "badge-neutral")
]}>
{if cfg[:enabled], do: "Enabled", else: "Disabled"}
</span>
<%= if cfg[:enabled] and cfg[:pending_comments] > 0 do %>
<span class="badge badge-warning ml-2 whitespace-nowrap">
{cfg[:pending_comments]} pending
</span>
<% end %>
</:status_badges>
<:action_buttons>
<div class="flex flex-col gap-2 w-full">
<%= if cfg[: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">{cfg[:total_comments]}</span>
</div>
<div>
<span class="text-base-content/70">Published:</span>
<span class="font-medium">{cfg[:published_comments]}</span>
</div>
<div>
<span class="text-base-content/70">Pending:</span>
<span class="font-medium">{cfg[:pending_comments]}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Customer Service Module --%>
<%= if "customer_service" in @accessible_modules do %>
<% cfg = @module_configs["customer_service"] || %{} %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Customer Service"
description="Customer support ticketing system with internal notes and status tracking"
icon="🎫"
enabled={cfg[:enabled]}
toggle_event="toggle_module"
toggle_key="customer_service"
>
<:status_badges>
<span class={[
"badge",
if(cfg[:enabled], do: "badge-success", else: "badge-neutral")
]}>
{if cfg[:enabled], do: "Enabled", else: "Disabled"}
</span>
<%= if cfg[:enabled] and cfg[:open_tickets] > 0 do %>
<span class="badge badge-warning ml-2 whitespace-nowrap">
{cfg[:open_tickets]} open
</span>
<% end %>
</:status_badges>
<:action_buttons>
<div class="flex flex-col gap-2 w-full">
<%= if cfg[:enabled] do %>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/customer-service/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/customer-service")}
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/customer-service")}
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">{cfg[:total_tickets]}</span>
</div>
<div>
<span class="text-base-content/70">Open:</span>
<span class="font-medium">{cfg[:open_tickets]}</span>
</div>
<div>
<span class="text-base-content/70">In Progress:</span>
<span class="font-medium">{cfg[:in_progress_tickets]}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Connections Module --%>
<%= if "connections" in @accessible_modules do %>
<% cfg = @module_configs["connections"] || %{} %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Connections"
description="Social relationships with one-way follows and mutual connections"
icon="🤝"
enabled={cfg[:enabled]}
toggle_event="toggle_module"
toggle_key="connections"
>
<:status_badges>
<span class={[
"badge",
if(cfg[:enabled], do: "badge-success", else: "badge-neutral")
]}>
{if cfg[:enabled], do: "Enabled", else: "Disabled"}
</span>
</:status_badges>
<:action_buttons>
<div class="flex flex-col gap-2 w-full">
<%= if cfg[: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">{cfg[:follows_count]}</span>
</div>
<div>
<span class="text-base-content/70">Connections:</span>
<span class="font-medium">{cfg[:connections_count]}</span>
</div>
<div>
<span class="text-base-content/70">Blocks:</span>
<span class="font-medium">{cfg[:blocks_count]}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- SEO Module --%>
<%= if "seo" in @accessible_modules do %>
<% cfg = @module_configs["seo"] || %{} %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="SEO"
description="Manage search engine optimization controls for your application"
icon="🔍"
enabled={cfg[:module_enabled]}
toggle_event="toggle_module"
toggle_key="seo"
>
<:status_badges>
<span class={[
"badge",
if(cfg[:module_enabled], do: "badge-success", else: "badge-neutral")
]}>
{if cfg[: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 cfg[: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 cfg[: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 %>
<% cfg = @module_configs["sitemap"] || %{} %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Sitemap"
description="Generate XML sitemaps for search engines with styled browser display"
icon="🗺️"
enabled={cfg[:enabled]}
toggle_event="toggle_module"
toggle_key="sitemap"
>
<:status_badges>
<span class={[
"badge",
if(cfg[:enabled], do: "badge-success", else: "badge-neutral")
]}>
{if cfg[:enabled], do: "Enabled", else: "Disabled"}
</span>
<%= if cfg[:enabled] and cfg[: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 cfg[:enabled], do: "btn-primary", else: "btn-outline"}"}
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-1" /> Configure
</.link>
<%= if cfg[: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">{cfg[:url_count]}</span>
</div>
<div>
<span class="text-base-content/70">Last gen:</span>
<span class="font-medium">
{format_timestamp(cfg[:last_generated])}
</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Billing Module --%>
<%= if "billing" in @accessible_modules do %>
<% cfg = @module_configs["billing"] || %{} %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Billing"
description="Orders, invoices, billing profiles and multi-currency support"
icon="💰"
enabled={cfg[:enabled]}
toggle_event="toggle_module"
toggle_key="billing"
>
<:status_badges>
<span class={[
"badge",
if(cfg[:enabled], do: "badge-success", else: "badge-neutral")
]}>
{if cfg[:enabled], do: "Enabled", else: "Disabled"}
</span>
</:status_badges>
<:action_buttons>
<div class="flex flex-col gap-2 w-full">
<%= if cfg[: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">{cfg[:orders_count]}</span>
</div>
<div>
<span class="text-base-content/70">Invoices:</span>
<span class="font-medium">{cfg[:invoices_count]}</span>
</div>
<div>
<span class="text-base-content/70">Currencies:</span>
<span class="font-medium">{cfg[:currencies_count]}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- AI Module --%>
<%= if "ai" in @accessible_modules do %>
<% cfg = @module_configs["ai"] || %{} %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="AI"
description="AI provider accounts and text processing with OpenRouter integration"
icon="🤖"
enabled={cfg[:enabled]}
toggle_event="toggle_module"
toggle_key="ai"
>
<:status_badges>
<span class={[
"badge",
if(cfg[:enabled], do: "badge-success", else: "badge-neutral")
]}>
{if cfg[:enabled], do: "Enabled", else: "Disabled"}
</span>
<%= if cfg[:enabled] and cfg[:endpoints_count] > 0 do %>
<span class="badge badge-outline ml-2 whitespace-nowrap">
{cfg[:endpoints_count]} endpoint{if cfg[: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 cfg[: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">{cfg[:endpoints_count]}</span>
</div>
<div>
<span class="text-base-content/70">Requests:</span>
<span class="font-medium">{cfg[: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 %>
<% cfg = @module_configs["maintenance"] || %{} %>
<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={cfg[:module_enabled]}
toggle_event="toggle_module"
toggle_key="maintenance"
>
<:status_badges>
<span class={[
"badge",
if(cfg[:module_enabled], do: "badge-success", else: "badge-neutral")
]}>
{if cfg[:module_enabled], do: "Enabled", else: "Disabled"}
</span>
<%= if cfg[:module_enabled] do %>
<span class={[
"badge badge-outline ml-2 whitespace-nowrap",
if(cfg[:enabled], do: "badge-warning", else: "badge-info")
]}>
{if cfg[:enabled], do: "Maintenance Active", else: "Maintenance Off"}
</span>
<% end %>
</:status_badges>
<:action_buttons>
<div class="flex flex-col gap-2 w-full">
<%= if cfg[: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>
{cfg[:header]}
</div>
<div class="text-xs text-base-content/70">
<strong>Message:</strong>
{cfg[: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 cfg[: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 %>
<% cfg = @module_configs["sync"] || %{} %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Sync"
description="Sync data between PhoenixKit instances in real-time"
icon="🔄"
enabled={cfg[:enabled]}
toggle_event="toggle_module"
toggle_key="sync"
>
<:status_badges>
<span class={[
"badge",
if(cfg[:enabled], do: "badge-success", else: "badge-neutral")
]}>
{if cfg[:enabled], do: "Enabled", else: "Disabled"}
</span>
<%= if cfg[:enabled] and cfg[:active_sessions] > 0 do %>
<span class="badge badge-outline badge-warning ml-2 whitespace-nowrap">
{cfg[:active_sessions]} active
</span>
<% end %>
</:status_badges>
<:action_buttons>
<div class="flex flex-col gap-2 w-full">
<%= if cfg[: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 cfg[: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 %>
<% cfg = @module_configs["db"] || %{} %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="DB"
description="Explore database tables and their contents"
icon="🗃️"
enabled={cfg[:enabled]}
toggle_event="toggle_module"
toggle_key="db"
stats_title="Current Stats"
>
<:status_badges>
<span class={[
"badge",
if(cfg[:enabled], do: "badge-success", else: "badge-neutral")
]}>
{if cfg[:enabled], do: "Enabled", else: "Disabled"}
</span>
</:status_badges>
<:action_buttons>
<div class="flex flex-col gap-2 w-full">
<%= if cfg[: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={cfg[:table_count]} />
</div>
</div>
<div>
<span class="text-base-content/70">Rows</span>
<div class="font-semibold">
<.formatted_number number={cfg[:approx_rows]} format={:short} />
</div>
</div>
<div>
<span class="text-base-content/70">Tables size</span>
<div class="font-semibold">
{format_bytes(cfg[:total_size_bytes])}
</div>
</div>
<div>
<span class="text-base-content/70">Database size</span>
<div class="font-semibold">
{format_bytes(cfg[:database_size_bytes])}
</div>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Jobs Module --%>
<%= if "jobs" in @accessible_modules do %>
<% cfg = @module_configs["jobs"] || %{} %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Jobs"
description="View-only dashboard for background job status and history"
icon="⚙️"
enabled={cfg[:enabled]}
toggle_event="toggle_module"
toggle_key="jobs"
>
<:status_badges>
<span class={[
"badge",
if(cfg[:enabled], do: "badge-success", else: "badge-neutral")
]}>
{if cfg[:enabled], do: "Enabled", else: "Disabled"}
</span>
<%= if cfg[:enabled] and cfg[:stats].executing > 0 do %>
<span class="badge badge-outline badge-warning ml-2 whitespace-nowrap">
{cfg[:stats].executing} running
</span>
<% end %>
</:status_badges>
<:action_buttons>
<div class="flex flex-col gap-2 w-full">
<%= if cfg[: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">{cfg[:stats].available}</span>
</div>
<div>
<span class="text-base-content/70">Completed:</span>
<span class="font-medium">{cfg[:stats].completed}</span>
</div>
<div>
<span class="text-base-content/70">Retryable:</span>
<span class="font-medium">{cfg[:stats].retryable}</span>
</div>
<div>
<span class="text-base-content/70">Discarded:</span>
<span class="font-medium">{cfg[:stats].discarded}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- Legal Module --%>
<%= if "legal" in @accessible_modules do %>
<% cfg = @module_configs["legal"] || %{} %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="Legal"
description="GDPR/CCPA compliance with consent tracking, cookie banners, and legal page generation"
icon="⚖️"
enabled={cfg[:enabled]}
toggle_event="toggle_module"
toggle_key="legal"
>
<:status_badges>
<span class={[
"badge",
if(cfg[:enabled], do: "badge-success", else: "badge-neutral")
]}>
{if cfg[:enabled], do: "Enabled", else: "Disabled"}
</span>
<%= if cfg[:enabled] and cfg[:publishing_enabled] do %>
<span class="badge badge-info ml-2">Publishing Ready</span>
<% end %>
</:status_badges>
<:action_buttons>
<%= if cfg[: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 %>
<% cfg = @module_configs["shop"] || %{} %>
<% billing_cfg = @module_configs["billing"] || %{} %>
<PhoenixKitWeb.Components.Core.ModuleCard.module_card
title="E-Commerce"
description="Physical and digital products with cart and checkout"
icon="🛒"
enabled={cfg[:enabled]}
toggle_event="toggle_module"
toggle_key="shop"
toggle_disabled={not billing_cfg[:enabled]}
toggle_hint={if not billing_cfg[:enabled], do: "Billing Required"}
>
<:status_badges>
<span class={[
"badge",
if(cfg[:enabled], do: "badge-success", else: "badge-neutral")
]}>
{if cfg[:enabled], do: "Enabled", else: "Disabled"}
</span>
<%= if not cfg[:enabled] and billing_cfg[: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 cfg[: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">{cfg[:products_count]}</span>
</div>
<div>
<span class="text-base-content/70">Categories:</span>
<span class="font-medium">{cfg[:categories_count]}</span>
</div>
</div>
</:stats>
</PhoenixKitWeb.Components.Core.ModuleCard.module_card>
<% end %>
<%!-- External Modules (auto-discovered) --%>
<%= for ext <- @external_modules, ext.key in @accessible_modules do %>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<div class="flex items-center">
<div class="text-3xl px-3 mr-4">
<%= if String.starts_with?(ext.icon, "hero-") do %>
<.icon name={ext.icon} class="w-8 h-8" />
<% else %>
{ext.icon}
<% end %>
</div>
<div class="flex-1">
<h3 class="card-title text-xl">{ext.name}</h3>
<p class="text-base-content/70">{ext.description}</p>
</div>
<div class="flex flex-col items-end gap-1">
<input
type="checkbox"
class="toggle toggle-primary"
checked={ext.enabled}
phx-click="toggle_module"
phx-value-key={ext.key}
/>
</div>
</div>
<div class="divider my-2"></div>
<div class="flex items-center justify-between flex-wrap gap-2">
<div class="flex flex-wrap gap-1">
<span class={[
"badge",
if(ext.enabled, do: "badge-success", else: "badge-neutral")
]}>
{if ext.enabled, do: "Enabled", else: "Disabled"}
</span>
<span class="badge badge-outline">v{ext.version}</span>
<span class="badge badge-info badge-outline">External</span>
</div>
<span class="text-xs text-base-content/50">
{if ext.enabled, do: "Module is active", else: "Enable to activate"}
</span>
</div>
</div>
</div>
<% 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>