Packages
phoenix_kit
1.7.113
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/settings.ex
defmodule PhoenixKitWeb.Live.Settings do
@moduledoc """
Admin settings management LiveView for PhoenixKit.
Provides interface for managing system-wide settings including timezone, date/time formats.
"""
use PhoenixKitWeb, :live_view
use Gettext, backend: PhoenixKitWeb.Gettext
alias PhoenixKit.Config.EndpointUrlSync
alias PhoenixKit.Modules.Storage.URLSigner
alias PhoenixKit.Settings
alias PhoenixKit.Settings.Events, as: SettingsEvents
alias PhoenixKit.Users.OAuthConfig
alias PhoenixKit.Utils.Date, as: UtilsDate
require Logger
def mount(_params, _session, socket) do
# Subscribe to settings changes for live updates (like entities does)
if connected?(socket) do
SettingsEvents.subscribe_to_settings()
end
# Load current settings from database
current_settings = Settings.list_all_settings()
defaults = Settings.get_defaults()
setting_options = Settings.get_setting_options()
# Merge defaults with current settings to ensure all keys exist
merged_settings = Map.merge(defaults, current_settings)
# Create form changeset
changeset = Settings.change_settings(merged_settings)
socket =
socket
|> assign(:page_title, "Settings")
|> assign(:settings, merged_settings)
# Track saved values separately
|> assign(:saved_settings, merged_settings)
|> assign(:setting_options, setting_options)
|> assign(:changeset, changeset)
|> assign(:saving, false)
|> assign(:show_media_selector, false)
|> assign(:media_selector_target, nil)
|> assign(
:project_title,
merged_settings["project_title"] || PhoenixKit.Config.get(:project_title, "PhoenixKit")
)
{:ok, socket}
end
def handle_params(_params, _url, socket) do
{:noreply, socket}
end
def handle_event("validate_settings", %{"settings" => settings_params}, socket) do
# Update the changeset with new values for validation
changeset = Settings.validate_settings(settings_params)
# Update the current settings to reflect the pending changes (but don't save to DB)
socket =
socket
|> assign(:settings, settings_params)
|> assign(:changeset, changeset)
{:noreply, socket}
end
def handle_event("save_settings", %{"settings" => settings_params}, socket) do
socket = assign(socket, :saving, true)
case Settings.update_settings(settings_params) do
{:ok, updated_settings} ->
handle_settings_saved(socket, settings_params, updated_settings)
{:error, errors} ->
handle_settings_error(socket, errors)
end
end
def handle_event("reset_to_defaults", _params, socket) do
# Get default settings
defaults = Settings.get_defaults()
# Update all settings to defaults in database
case Settings.update_settings(defaults) do
{:ok, updated_settings} ->
# Sync site_url to Endpoint after reset
EndpointUrlSync.sync()
# Update socket with default settings
changeset = Settings.change_settings(updated_settings)
socket =
socket
|> assign(:settings, updated_settings)
|> assign(:saved_settings, updated_settings)
|> assign(:changeset, changeset)
|> assign(
:project_title,
updated_settings["project_title"] ||
PhoenixKit.Config.get(:project_title, "PhoenixKit")
)
|> put_flash(:info, "Settings reset to defaults successfully")
{:noreply, socket}
{:error, errors} ->
error_msg = format_error_message(errors)
socket =
socket
|> put_flash(:error, error_msg)
{:noreply, socket}
end
end
def handle_event("open_media_selector", %{"target" => target}, socket) do
{:noreply,
socket
|> assign(:show_media_selector, true)
|> assign(:media_selector_target, target)}
end
def handle_event("clear_image", %{"target" => target}, socket) do
key = media_target_to_key(target)
settings = Map.put(socket.assigns.settings, key, "")
{:noreply, assign(socket, :settings, settings)}
end
## Media selector callbacks
def handle_info({:media_selected, file_uuids}, socket) do
file_uuid = List.first(file_uuids) || ""
key = media_target_to_key(socket.assigns.media_selector_target)
settings = Map.put(socket.assigns.settings, key, file_uuid)
{:noreply,
socket
|> assign(:settings, settings)
|> assign(:show_media_selector, false)
|> assign(:media_selector_target, nil)}
end
def handle_info({:media_selector_closed}, socket) do
{:noreply,
socket
|> assign(:show_media_selector, false)
|> assign(:media_selector_target, nil)}
end
# Catch-all for other settings changes (future-proof)
def handle_info({:setting_changed, _key, _value}, socket) do
{:noreply, socket}
end
defp media_target_to_key("logo"), do: "auth_logo_file_uuid"
defp media_target_to_key("site_icon"), do: "site_icon_file_uuid"
defp media_target_to_key(_), do: "auth_logo_file_uuid"
# Handle successful settings save
defp handle_settings_saved(socket, _settings_params_to_save, updated_settings) do
# Sync site_url to Endpoint and reload OAuth configuration
EndpointUrlSync.sync()
OAuthConfig.configure_providers()
# Update socket with new settings
changeset = Settings.change_settings(updated_settings)
socket =
socket
|> assign(:settings, updated_settings)
|> assign(:saved_settings, updated_settings)
|> assign(:changeset, changeset)
|> assign(:saving, false)
|> assign(
:project_title,
updated_settings["project_title"] || PhoenixKit.Config.get(:project_title, "PhoenixKit")
)
|> put_flash(:info, "Settings updated successfully")
{:noreply, socket}
end
# Handle settings save error
defp handle_settings_error(socket, errors) do
Logger.error("Settings save error: #{inspect(errors)}")
error_msg = format_error_message(errors)
socket =
socket
|> assign(:saving, false)
|> put_flash(:error, error_msg)
{:noreply, socket}
end
# Format error messages for display
defp format_error_message(%Ecto.Changeset{} = changeset) do
# Extract error messages from changeset
changeset
|> Ecto.Changeset.traverse_errors(fn {msg, opts} ->
Enum.reduce(opts, msg, fn {key, value}, acc ->
String.replace(acc, "%{#{key}}", to_string(value))
end)
end)
|> Map.values()
|> List.flatten()
|> Enum.join(", ")
end
# Helper functions for template to show dropdown labels
def get_timezone_label(value, setting_options) do
Settings.get_timezone_label(value, setting_options)
end
def get_option_label(value, options) do
Settings.get_option_label(value, options)
end
# Helper functions for template to show current format examples
def get_current_date_example(format) do
UtilsDate.format_date(Date.utc_today(), format)
end
def get_current_time_example(format) do
UtilsDate.format_time(Time.utc_now(), format)
end
def signed_preview_url(file_uuid, variant) do
URLSigner.signed_url(file_uuid, variant)
end
end