Packages
phoenix_kit
1.3.0
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/users/settings.html.heex
<PhoenixKitWeb.Components.LayoutWrapper.app_layout
flash={@flash}
phoenix_kit_current_scope={assigns[:phoenix_kit_current_scope]}
page_title="Account Settings"
>
<div class="flex items-center justify-center py-8 min-h-[80vh]">
<div class="w-full max-w-lg px-4">
<div class="text-center mb-8">
<div class="flex items-center justify-center mb-4">
<PhoenixKitWeb.Components.Core.Icons.icon_settings class="w-12 h-12 text-primary" />
</div>
<h1 class="text-3xl font-bold mb-2">Account Settings</h1>
<p class="text-base-content/60 text-sm">
Manage your account email address and password settings
</p>
</div>
<div class="space-y-8">
<%!-- Email Settings Card --%>
<div class="card bg-base-100 shadow-2xl">
<div class="card-body">
<div class="flex items-center mb-4">
<PhoenixKitWeb.Components.Core.Icons.icon_email class="w-6 h-6 text-primary mr-3" />
<div>
<h2 class="text-xl font-bold">Email Address</h2>
<p class="text-sm text-base-content/60">Change your account email address</p>
</div>
</div>
<.simple_form
for={@email_form}
id="email_form"
phx-submit="update_email"
phx-change="validate_email"
>
<.input
field={@email_form[:email]}
type="email"
label="Email"
required
>
<:icon>
<PhoenixKitWeb.Components.Core.Icons.icon_email class="w-4 h-4 mr-2" />
</:icon>
</.input>
<.input
field={@email_form[:current_password]}
name="current_password"
id="current_password_for_email"
type="password"
label="Current password"
value={@email_form_current_password}
required
>
<:icon>
<PhoenixKitWeb.Components.Core.Icons.icon_lock class="w-4 h-4 mr-2" />
</:icon>
</.input>
<:actions>
<.button
phx-disable-with="Changing..."
class="btn-primary transition-all hover:scale-[1.02] active:scale-[0.98]"
>
<PhoenixKitWeb.Components.Core.Icons.icon_email class="w-5 h-5 mr-2" />
Change Email
</.button>
</:actions>
</.simple_form>
</div>
</div>
<%!-- Profile Settings Card --%>
<div class="card bg-base-100 shadow-2xl">
<div class="card-body">
<div class="flex items-center mb-4">
<PhoenixKitWeb.Components.Core.Icons.icon_user_profile class="w-6 h-6 text-primary mr-3" />
<div>
<h2 class="text-xl font-bold">Profile Information</h2>
<p class="text-sm text-base-content/60">
Update your personal information and timezone preference
</p>
</div>
</div>
<.simple_form
for={@profile_form}
id="profile_form"
phx-submit="update_profile"
phx-change="validate_profile"
>
<.input
field={@profile_form[:first_name]}
type="text"
label="First Name"
>
<:icon>
<PhoenixKitWeb.Components.Core.Icons.icon_user_profile class="w-4 h-4 mr-2" />
</:icon>
</.input>
<.input field={@profile_form[:last_name]} type="text" label="Last Name">
<:icon>
<PhoenixKitWeb.Components.Core.Icons.icon_user_profile class="w-4 h-4 mr-2" />
</:icon>
</.input>
<div id="timezone-detector">
<.select
field={@profile_form[:user_timezone]}
label="Personal Timezone"
options={@timezone_options}
/>
<%!-- Timezone Mismatch Warning --%>
<%= if assigns[:timezone_mismatch_warning] do %>
<div class="alert alert-warning text-sm mt-2">
<PhoenixKitWeb.Components.Core.Icons.icon_warning class="stroke-current shrink-0 h-5 w-5" />
<div>
<div class="font-semibold">Timezone Mismatch Detected</div>
<div class="text-xs">
{@timezone_mismatch_warning}
</div>
</div>
</div>
<% end %>
<%!-- Browser Timezone Info --%>
<%= if assigns[:browser_timezone_name] do %>
<div class="text-xs text-base-content/60 mt-1">
Browser detected: {@browser_timezone_name} ({@browser_timezone_offset})
</div>
<% end %>
<%!-- Debug button for timezone detection --%>
<div class="mt-2">
<button
type="button"
class="btn btn-sm btn-outline"
onclick="detectAndStoreTimezone(); return false;"
>
🐛 Detect Browser Timezone (Debug)
</button>
<div class="text-xs text-base-content/60 mt-1">
Click if timezone detection isn't working automatically
</div>
</div>
</div>
<:actions>
<.button
phx-disable-with="Updating..."
class="btn-primary transition-all hover:scale-[1.02] active:scale-[0.98]"
>
<PhoenixKitWeb.Components.Core.Icons.icon_user_profile class="w-5 h-5 mr-2" />
Update Profile
</.button>
</:actions>
</.simple_form>
</div>
</div>
<%!-- Password Settings Card --%>
<div class="card bg-base-100 shadow-2xl">
<div class="card-body">
<div class="flex items-center mb-4">
<PhoenixKitWeb.Components.Core.Icons.icon_lock class="w-6 h-6 text-primary mr-3" />
<div>
<h2 class="text-xl font-bold">Password</h2>
<p class="text-sm text-base-content/60">Update your account password</p>
</div>
</div>
<.simple_form
for={@password_form}
id="password_form"
action={Routes.path("/users/log-in?_action=password_updated")}
method="post"
phx-change="validate_password"
phx-submit="update_password"
phx-trigger-action={@trigger_submit}
>
<input
name={@password_form[:email].name}
type="hidden"
id="hidden_user_email"
value={@current_email}
/>
<.input
field={@password_form[:password]}
type="password"
label="New password"
required
>
<:icon>
<PhoenixKitWeb.Components.Core.Icons.icon_lock class="w-4 h-4 mr-2" />
</:icon>
</.input>
<.input
field={@password_form[:password_confirmation]}
type="password"
label="Confirm new password"
>
<:icon>
<PhoenixKitWeb.Components.Core.Icons.icon_lock class="w-4 h-4 mr-2" />
</:icon>
</.input>
<.input
field={@password_form[:current_password]}
name="current_password"
type="password"
label="Current password"
id="current_password_for_password"
value={@current_password}
required
>
<:icon>
<PhoenixKitWeb.Components.Core.Icons.icon_lock class="w-4 h-4 mr-2" />
</:icon>
</.input>
<:actions>
<.button
phx-disable-with="Changing..."
class="btn-primary transition-all hover:scale-[1.02] active:scale-[0.98]"
>
<PhoenixKitWeb.Components.Core.Icons.icon_lock class="w-5 h-5 mr-2" />
Change Password
</.button>
</:actions>
</.simple_form>
</div>
</div>
<%!-- Development Mode Notice --%>
<div :if={show_dev_notice?()} class="alert alert-info">
<PhoenixKitWeb.Components.Core.Icons.icon_info class="stroke-current shrink-0 h-6 w-6" />
<span>
Development mode: Check
<.link href="/dev/mailbox" class="font-semibold underline">mailbox</.link>
for confirmation emails
</span>
</div>
</div>
</div>
</div>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>
<script>
// Simple timezone detection - detect once and store in form
function detectAndStoreTimezone() {
try {
// Get browser timezone data
const timezoneName = Intl.DateTimeFormat().resolvedOptions().timeZone;
const now = new Date();
const offsetMinutes = now.getTimezoneOffset();
const offsetHours = Math.round(offsetMinutes / -60);
const offsetString = offsetHours === 0 ? "0" :
(offsetHours > 0 ? "+" + offsetHours : offsetHours.toString());
// Add hidden fields to the form
const form = document.querySelector('#profile_form');
if (form) {
// Remove any existing timezone inputs first
const existingInputs = form.querySelectorAll('input[name="browser_timezone_name"], input[name="browser_timezone_offset"]');
existingInputs.forEach(input => input.remove());
// Add new timezone inputs
const nameInput = document.createElement('input');
nameInput.type = 'hidden';
nameInput.name = 'browser_timezone_name';
nameInput.value = timezoneName;
nameInput.id = 'browser_timezone_name_input';
const offsetInput = document.createElement('input');
offsetInput.type = 'hidden';
offsetInput.name = 'browser_timezone_offset';
offsetInput.value = offsetString;
offsetInput.id = 'browser_timezone_offset_input';
form.appendChild(nameInput);
form.appendChild(offsetInput);
// Trigger form validation to send data to LiveView
const timezoneSelect = form.querySelector('select[name*="user_timezone"]');
if (timezoneSelect) {
const option = timezoneSelect.querySelector(`[value="${offsetString}"]`);
if (option) {
option.selected = true;
}
const changeEvent = new Event('input', { bubbles: true });
timezoneSelect.dispatchEvent(changeEvent);
}
return true;
}
} catch (error) {
// Silent fail - timezone detection is not critical
}
return false;
}
// Detect timezone when page loads
setTimeout(detectAndStoreTimezone, 500);
setTimeout(detectAndStoreTimezone, 1500);
</script>