remember me, password reset

This commit is contained in:
2026-01-30 10:08:41 +01:00
parent 4e5c25adbf
commit 20ce18ca74
18 changed files with 457 additions and 25 deletions
+1 -1
View File
@@ -36,7 +36,7 @@
</div>
<% end %>
<%= form_with model: @user, url: accept_invitation_path(params[:token]), method: :patch, local: true, class: "space-y-5" do |form| %>
<%= form_with model: @user, url: accept_invitation_path(params[:token]), method: :patch, local: true, data: { turbo: false }, class: "space-y-5" do |form| %>
<div>
<%= form.label :password, "Set Your Password", class: "block text-sm font-medium text-slate-700 mb-2" %>
<%= form.password_field :password,
@@ -0,0 +1,130 @@
<!DOCTYPE html>
<html>
<head>
<meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
line-height: 1.6;
color: #334155;
max-width: 640px;
margin: 0 auto;
padding: 20px;
}
.header {
background: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%);
color: white;
padding: 30px;
border-radius: 8px 8px 0 0;
text-align: center;
}
.header h1 {
margin: 0;
font-size: 28px;
font-weight: 700;
}
.header p {
margin: 8px 0 0 0;
opacity: 0.9;
}
.content {
background: white;
border: 1px solid #e2e8f0;
border-top: none;
padding: 30px;
border-radius: 0 0 8px 8px;
}
.greeting {
font-size: 18px;
font-weight: 600;
margin-bottom: 16px;
color: #1e293b;
}
.button {
display: inline-block;
background: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%);
color: white;
padding: 14px 32px;
text-decoration: none;
border-radius: 8px;
font-weight: 600;
margin: 24px 0;
text-align: center;
}
.button:hover {
background: linear-gradient(135deg, #4f46e5 0%, #4338ca 100%);
}
.footer {
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid #e2e8f0;
font-size: 14px;
color: #64748b;
}
.expiry-notice {
background: #fef3c7;
border-left: 4px solid #f59e0b;
padding: 12px;
margin: 16px 0;
font-size: 14px;
border-radius: 4px;
}
.warning-box {
background: #fef2f2;
border-left: 4px solid #ef4444;
padding: 16px;
margin: 20px 0;
border-radius: 4px;
}
</style>
</head>
<body>
<div class="header">
<h1>Sanasto Wiki</h1>
<p>Password Reset Request</p>
</div>
<div class="content">
<p class="greeting">Hello <%= @user.name %>,</p>
<p>
We received a request to reset your password for your Sanasto Wiki account.
</p>
<p>
If you made this request, click the button below to set a new password:
</p>
<div style="text-align: center;">
<%= link_to "Reset My Password", @reset_url, class: "button" %>
</div>
<div class="expiry-notice">
This password reset link will expire on <strong><%= @expires_at.strftime("%B %d, %Y at %I:%M %p %Z") %></strong>.
</div>
<p>
You can also copy and paste this link into your browser:
</p>
<p style="word-break: break-all; color: #6366f1; font-size: 14px;">
<%= @reset_url %>
</p>
<div class="warning-box">
<strong>Didn't request a password reset?</strong>
<p style="margin: 8px 0 0 0;">
If you didn't make this request, you can safely ignore this email. Your password will remain unchanged.
</p>
</div>
<div class="footer">
<p>
For security reasons, this link will only work once and will expire in 1 hour.
</p>
<p style="margin-top: 12px;">
Questions? Reply to this email.
</p>
</div>
</div>
</body>
</html>
+60
View File
@@ -0,0 +1,60 @@
<% content_for :title, "Set New Password" %>
<div class="min-h-screen flex flex-col">
<header class="bg-white border-b border-slate-200">
<div class="max-w-7xl mx-auto px-4">
<div class="h-16 flex items-center">
<%= link_to root_path, class: "flex items-center gap-2" do %>
<span class="text-xl font-bold tracking-tight text-indigo-600">Sanasto</span>
<span class="text-xl font-light text-slate-400">Wiki</span>
<% end %>
</div>
</div>
</header>
<div class="flex-1 flex items-center justify-center px-4 py-12 bg-slate-50">
<div class="w-full max-w-md">
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 p-8">
<div class="mb-8">
<h1 class="text-2xl font-bold text-slate-900 mb-2">Set new password</h1>
<p class="text-sm text-slate-600">Enter your new password below.</p>
</div>
<% if flash[:alert] %>
<div class="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-lg mb-6" role="alert">
<%= flash[:alert] %>
</div>
<% end %>
<%= form_with url: password_reset_path(params[:token]), method: :patch, local: true, data: { turbo: false }, class: "space-y-5" do |form| %>
<div>
<%= form.label :password, "New Password", class: "block text-sm font-medium text-slate-700 mb-2" %>
<%= form.password_field :password,
autofocus: true,
autocomplete: "new-password",
required: true,
minlength: 8,
placeholder: "••••••••••••",
class: "block w-full px-4 py-3 bg-white border border-slate-200 rounded-lg shadow-sm focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition" %>
<p class="mt-1 text-xs text-slate-500">Minimum 8 characters</p>
</div>
<div>
<%= form.label :password_confirmation, "Confirm New Password", class: "block text-sm font-medium text-slate-700 mb-2" %>
<%= form.password_field :password_confirmation,
autocomplete: "new-password",
required: true,
minlength: 8,
placeholder: "••••••••••••",
class: "block w-full px-4 py-3 bg-white border border-slate-200 rounded-lg shadow-sm focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition" %>
</div>
<div class="pt-2">
<%= form.submit "Reset Password",
class: "w-full bg-indigo-600 text-white px-4 py-3 rounded-lg text-sm font-semibold hover:bg-indigo-700 transition cursor-pointer" %>
</div>
<% end %>
</div>
</div>
</div>
</div>
+57
View File
@@ -0,0 +1,57 @@
<% content_for :title, "Reset Password" %>
<div class="min-h-screen flex flex-col">
<header class="bg-white border-b border-slate-200">
<div class="max-w-7xl mx-auto px-4">
<div class="h-16 flex items-center">
<%= link_to root_path, class: "flex items-center gap-2" do %>
<span class="text-xl font-bold tracking-tight text-indigo-600">Sanasto</span>
<span class="text-xl font-light text-slate-400">Wiki</span>
<% end %>
</div>
</div>
</header>
<div class="flex-1 flex items-center justify-center px-4 py-12 bg-slate-50">
<div class="w-full max-w-md">
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 p-8">
<div class="mb-8">
<h1 class="text-2xl font-bold text-slate-900 mb-2">Reset your password</h1>
<p class="text-sm text-slate-600">Enter your email address and we'll send you a link to reset your password.</p>
</div>
<% if flash[:alert] %>
<div class="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-lg mb-6" role="alert">
<%= flash[:alert] %>
</div>
<% end %>
<%= form_with url: password_resets_path, method: :post, local: true, data: { turbo: false }, class: "space-y-5" do |form| %>
<div>
<%= form.label :email, "Email", class: "block text-sm font-medium text-slate-700 mb-2" %>
<%= form.email_field :email,
autofocus: true,
autocomplete: "email",
required: true,
placeholder: "you@example.com",
class: "block w-full px-4 py-3 bg-white border border-slate-200 rounded-lg shadow-sm focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition" %>
</div>
<div class="pt-2">
<%= form.submit "Send Reset Instructions",
class: "w-full bg-indigo-600 text-white px-4 py-3 rounded-lg text-sm font-semibold hover:bg-indigo-700 transition cursor-pointer" %>
</div>
<% end %>
<div class="mt-6 text-center space-y-3">
<%= link_to login_path, class: "text-sm text-slate-600 hover:text-indigo-600 transition inline-flex items-center gap-1" do %>
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
</svg>
Back to Sign In
<% end %>
</div>
</div>
</div>
</div>
</div>
+10 -2
View File
@@ -26,7 +26,7 @@
</div>
<% end %>
<%= form_with url: login_path, method: :post, local: true, class: "space-y-5" do |form| %>
<%= form_with url: login_path, method: :post, local: true, data: { turbo: false }, class: "space-y-5" do |form| %>
<div>
<%= form.label :email, "Email", class: "block text-sm font-medium text-slate-700 mb-2" %>
<%= form.email_field :email,
@@ -38,7 +38,10 @@
</div>
<div>
<%= form.label :password, "Password", class: "block text-sm font-medium text-slate-700 mb-2" %>
<div class="flex justify-between items-center mb-2">
<%= form.label :password, "Password", class: "block text-sm font-medium text-slate-700" %>
<%= link_to "Forgot password?", new_password_reset_path, class: "text-xs text-indigo-600 hover:text-indigo-700 font-medium" %>
</div>
<%= form.password_field :password,
autocomplete: "current-password",
required: true,
@@ -46,6 +49,11 @@
class: "block w-full px-4 py-3 bg-white border border-slate-200 rounded-lg shadow-sm focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition" %>
</div>
<div class="flex items-center">
<%= check_box_tag :remember_me, "1", false, class: "w-4 h-4 text-indigo-600 border-slate-300 rounded focus:ring-2 focus:ring-indigo-500" %>
<%= label_tag :remember_me, "Remember me for 2 weeks", class: "ml-2 text-sm text-slate-600" %>
</div>
<div class="pt-2">
<%= form.submit "Sign In",
class: "w-full bg-indigo-600 text-white px-4 py-3 rounded-lg text-sm font-semibold hover:bg-indigo-700 transition cursor-pointer" %>