Packages

phoenix_kit

1.2.8
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 users user_form_live.html.heex
Raw

lib/phoenix_kit_web/users/user_form_live.html.heex

<PhoenixKitWeb.Components.LayoutWrapper.app_layout
flash={@flash}
phoenix_kit_current_scope={assigns[:phoenix_kit_current_scope]}
page_title={@page_title}
current_path={@current_path}
>
<div class="container flex-col mx-auto px-4 py-6">
<%!-- Header Section --%>
<header class="w-full relative mb-6">
<%!-- Back Button (Left aligned) --%>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/users")}
class="btn btn-outline btn-primary btn-sm absolute left-0 top-0 -mb-12"
>
<PhoenixKitWeb.Components.Core.Icons.icon_arrow_left />
Back to Users
</.link>
<%!-- Title Section --%>
<div class="text-center">
<h1 class="text-4xl font-bold text-base-content mb-3">{@page_title}</h1>
<p class="text-lg text-base-content">
<%= if @mode == :new do %>
Create a new user account
<% else %>
Edit user information
<% end %>
</p>
</div>
</header>
<%!-- User Form --%>
<div class="max-w-2xl mx-auto">
<div class="bg-base-100 rounded-lg shadow-md p-6">
<.form
:let={form}
for={@changeset}
id="user_form"
phx-submit="save_user"
phx-change="validate_user"
class="space-y-6"
>
<div class="space-y-4">
<%!-- Email --%>
<div class="w-full">
<.input
field={form[:email]}
type="email"
label="Email *"
placeholder="user@example.com"
required
/>
</div>
<%!-- Username --%>
<div class="w-full">
<.input
field={form[:username]}
type="text"
label="Username"
placeholder="unique_username"
/>
<div class="text-xs text-base-content/60 mt-2">
Unique username (3-30 characters, letters, numbers, and underscores only)
</div>
</div>
<%!-- Password (only for new users) --%>
<%= if @mode == :new do %>
<div class="w-full">
<.input
field={form[:password]}
type="password"
label="Password *"
placeholder="Minimum 8 characters"
required
/>
</div>
<% end %>
<%!-- Name Fields --%>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<%!-- First Name --%>
<div class="w-full">
<.input
field={form[:first_name]}
type="text"
label="First Name"
placeholder="Optional"
/>
</div>
<%!-- Last Name --%>
<div class="w-full">
<.input
field={form[:last_name]}
type="text"
label="Last Name"
placeholder="Optional"
/>
</div>
</div>
</div>
<%!-- Password Change Section (Edit mode, Admin/Owner only) --%>
<%= if @mode == :edit and (PhoenixKit.Users.Auth.Scope.admin?(@phoenix_kit_current_scope) or PhoenixKit.Users.Auth.Scope.owner?(@phoenix_kit_current_scope)) do %>
<div class="form-control">
<label class="label">
<span class="label-text font-semibold">Password Management</span>
</label>
<div class="flex items-center gap-4 mt-2">
<button
type="button"
phx-click="toggle_password_field"
class="btn btn-outline btn-sm"
>
<%= if @show_password_field do %>
Hide Password Field
<% else %>
Change Password
<% end %>
</button>
<span class="text-sm text-base-content/70">
Set a new password for this user (Admin privilege required)
</span>
</div>
</div>
<%!-- Inline Password Field --%>
<%= if @show_password_field do %>
<div class="w-full mt-4">
<.input
field={form[:password]}
type="password"
label="New Password *"
placeholder="Enter new password (minimum 8 characters)"
required
/>
<div class="text-xs text-base-content/60 mt-2">
<svg class="w-4 h-4 inline mr-1" fill="currentColor" viewBox="0 0 20 20">
<path
fill-rule="evenodd"
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"
clip-rule="evenodd"
/>
</svg>
<strong>Note:</strong>
This will immediately invalidate all current sessions for this user.
</div>
</div>
<% end %>
<% end %>
<%= if @mode == :new do %>
<div class="divider">Additional Information</div>
<div class="bg-base-200 p-4 rounded-lg">
<div class="flex items-start gap-3">
<svg class="w-5 h-5 mt-0.5 text-info" fill="currentColor" viewBox="0 0 20 20">
<path
fill-rule="evenodd"
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"
clip-rule="evenodd"
>
</path>
</svg>
<div class="text-sm">
<p class="font-medium">Default Settings:</p>
<ul class="mt-1 text-base-content/70">
<li>• User will be assigned default "User" role</li>
<li>• Account will be active by default</li>
<li>• Confirmation email will be sent automatically</li>
<li>• User can update their profile after first login</li>
</ul>
</div>
</div>
</div>
<% end %>
<%!-- Form Actions --%>
<div class="flex justify-end gap-3 pt-6 border-t border-base-300">
<button
type="submit"
class="btn btn-primary"
phx-disable-with={
if @mode == :new, do: "Creating user...", else: "Updating user..."
}
>
<%= if @mode == :new do %>
Create User
<% else %>
Update User
<% end %>
</button>
<button
type="button"
phx-click="cancel"
class="btn btn-outline"
>
Cancel
</button>
</div>
</.form>
</div>
<%!-- Password Reset via Email Section (Edit mode only) --%>
<%= if @mode == :edit do %>
<div class="bg-yellow-50 border border-yellow-200 dark:bg-warning/10 dark:border-warning/30 rounded-lg p-6 mt-6">
<div class="flex items-start gap-3">
<svg
class="w-6 h-6 text-yellow-600 dark:text-warning mt-0.5"
fill="currentColor"
viewBox="0 0 20 20"
>
<path
fill-rule="evenodd"
d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z"
clip-rule="evenodd"
/>
</svg>
<div class="flex-1">
<h3 class="font-semibold text-yellow-800 dark:text-warning mb-2">
Password Reset via Email
</h3>
<p class="text-sm text-yellow-700 dark:text-base-content/80 mb-6">
Send a password reset email to this user. They will receive a secure link to create a new password.
<strong class="text-yellow-800 dark:text-warning">
This action cannot be undone
</strong>
and will invalidate their current password immediately.
</p>
<button
type="button"
phx-click="show_reset_password_modal"
class="btn btn-warning btn-sm mt-3"
>
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"
/>
</svg>
Reset User Password
</button>
</div>
</div>
</div>
<% end %>
</div>
<%!-- Reset Password Confirmation Modal --%>
<%= if @mode == :edit && @show_reset_password_modal do %>
<div class="modal modal-open">
<div class="modal-box max-w-lg">
<div class="flex items-center gap-3 mb-4">
<svg class="w-8 h-8 text-error" fill="currentColor" viewBox="0 0 20 20">
<path
fill-rule="evenodd"
d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z"
clip-rule="evenodd"
/>
</svg>
<h3 class="font-bold text-xl text-error">Confirm Password Reset</h3>
</div>
<div class="space-y-4 mb-6">
<div class="bg-error/10 border border-error/20 rounded-lg p-4">
<p class="text-sm"><strong>Warning:</strong> This action cannot be undone!</p>
</div>
<div class="space-y-2 text-sm">
<p>You are about to reset the password for:</p>
<div class="bg-base-200 p-3 rounded font-mono text-primary">
{@user.email || "Unknown user"}
</div>
</div>
<div class="space-y-2 text-sm text-base-content/80">
<p><strong>What will happen:</strong></p>
<ul class="list-disc list-inside space-y-1 ml-4">
<li>Their current password will be immediately invalidated</li>
<li>They will receive an email with reset instructions</li>
<li>They must create a new password using the emailed link</li>
<li>The reset link expires in 1 hour</li>
</ul>
</div>
<div class="bg-info/10 border border-info/20 rounded-lg p-4">
<p class="text-sm">
<svg class="w-4 h-4 inline mr-1" fill="currentColor" viewBox="0 0 20 20">
<path
fill-rule="evenodd"
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 0 100-2v-3a1 1 0 00-1-1H9z"
clip-rule="evenodd"
/>
</svg>
<strong>Note:</strong>
Make sure the user has access to their email account before proceeding.
</p>
</div>
</div>
<div class="modal-action">
<button
type="button"
phx-click="hide_reset_password_modal"
class="btn btn-outline"
>
Cancel
</button>
<button
type="button"
phx-click="admin_reset_password"
class="btn btn-error"
phx-disable-with="Sending email..."
>
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"
/>
</svg>
Yes, Reset Password
</button>
</div>
</div>
</div>
<% end %>
</div>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>