Reset Password (#1)

Implements reset password routes, views, and tests.

Reviewed-on: #1
This commit is contained in:
2025-01-27 14:07:37 +00:00
parent 1f2bb900ca
commit 9478fae371
16 changed files with 250 additions and 7 deletions

View File

@@ -8,6 +8,11 @@ extension HTMLAttribute.hx {
get(SiteRoute.View.router.path(for: route))
}
@Sendable
static func patch(route: SiteRoute.View) -> HTMLAttribute {
patch(SiteRoute.View.router.path(for: route))
}
@Sendable
static func post(route: SiteRoute.View) -> HTMLAttribute {
post(SiteRoute.View.router.path(for: route))

View File

@@ -9,6 +9,7 @@ struct UserDetail: HTML, Sendable {
let user: User?
var content: some HTML {
// TODO: Need a reset password form.
Float(shouldDisplay: user != nil, resetURL: .user(.index)) {
if let user {
form(
@@ -46,6 +47,13 @@ struct UserDetail: HTML, Sendable {
.toggleContent(.float), .setWindowLocation(to: .user(.index))
)
)
// TODO: trigger the reset password route.
button(
.class("btn-primary"),
.hx.target(.id(.float)),
.hx.get(route: .resetPassword(.index(id: user.id))),
.hx.trigger(.event(.click))
) { "Reset Password" }
}
}
}

View File

@@ -7,7 +7,7 @@ struct UserForm: HTML, Sendable {
let context: Context
var content: some HTML {
if context == .create {
if context.isFloat {
Float(shouldDisplay: true) {
makeForm()
}
@@ -20,20 +20,22 @@ struct UserForm: HTML, Sendable {
form(
.id(.user(.form)),
.class("user-form"),
.hx.post(route: context.targetURL),
context.isResetPassword ? .hx.patch(route: context.targetURL) : .hx.post(route: context.targetURL),
.hx.pushURL(context.pushURL),
.hx.target(context.target),
.hx.swap(context == .create ? .afterBegin.transition(true).swap("0.5s") : .outerHTML),
.hx.on(
.afterRequest,
.ifSuccessful(.resetForm, .toggleContent(.float))
context.toggleContent ? .ifSuccessful(.resetForm, .toggleContent(.float)) : .ifSuccessful(.resetForm)
)
) {
if case let .login(next) = context, let next {
input(.type(.hidden), .name("next"), .value(next))
}
div(.class("row")) {
input(.type(.text), .id("username"), .name("username"), .placeholder("Username"), .autofocus, .required)
if context.showUsername {
div(.class("row")) {
input(.type(.text), .id("username"), .name("username"), .placeholder("Username"), .autofocus, .required)
}
}
if context.showEmailInput {
div(.class("row")) {
@@ -61,11 +63,41 @@ struct UserForm: HTML, Sendable {
enum Context: Equatable, Sendable {
case create
case login(next: String?)
case resetPassword(id: User.ID)
var isResetPassword: Bool {
guard case .resetPassword = self else { return false }
return true
}
var isFloat: Bool {
switch self {
case .create,
.resetPassword:
return true
case .login:
return false
}
}
var toggleContent: Bool {
guard case .resetPassword = self else { return true }
return false
}
var showUsername: Bool {
switch self {
case .create: return true
case .login: return true
case .resetPassword: return false
}
}
var showConfirmPassword: Bool {
switch self {
case .create: return true
case .login: return false
case .resetPassword: return true
}
}
@@ -73,6 +105,7 @@ struct UserForm: HTML, Sendable {
switch self {
case .create: return true
case .login: return false
case .resetPassword: return false
}
}
@@ -80,6 +113,7 @@ struct UserForm: HTML, Sendable {
switch self {
case .create: return false
case .login: return true
case .resetPassword: return false
}
}
@@ -89,6 +123,8 @@ struct UserForm: HTML, Sendable {
return "Create"
case .login:
return "Login"
case .resetPassword:
return "Reset"
}
}
@@ -98,6 +134,8 @@ struct UserForm: HTML, Sendable {
return .id(.user(.table))
case .login:
return .body
case .resetPassword:
return .id(.float)
}
}
@@ -107,6 +145,8 @@ struct UserForm: HTML, Sendable {
return .user(.index)
case .login:
return .login(.index())
case let .resetPassword(id: id):
return .resetPassword(.index(id: id))
}
}
}