Reset Password (#1)
Implements reset password routes, views, and tests. Reviewed-on: #1
This commit is contained in:
@@ -40,6 +40,9 @@ public extension SiteRoute.View {
|
||||
case let .purchaseOrder(route):
|
||||
return try await route.view(isHtmxRequest: isHtmxRequest)
|
||||
|
||||
case let .resetPassword(route):
|
||||
return try await route.view(isHtmxRequest: isHtmxRequest)
|
||||
|
||||
case let .user(route):
|
||||
return try await route.view(isHtmxRequest: isHtmxRequest)
|
||||
|
||||
@@ -180,6 +183,22 @@ extension SiteRoute.View.PurchaseOrderRoute.Search {
|
||||
}
|
||||
}
|
||||
|
||||
extension SiteRoute.View.ResetPasswordRoute {
|
||||
|
||||
@Sendable
|
||||
func view(isHtmxRequest: Bool) async throws -> AnySendableHTML {
|
||||
@Dependency(\.database) var database
|
||||
switch self {
|
||||
case let .index(id: id):
|
||||
return UserForm(context: .resetPassword(id: id))
|
||||
case let .submit(id: id, request: request):
|
||||
try await database.users.resetPassword(id, request)
|
||||
let user = try await database.users.get(id)
|
||||
return UserDetail(user: user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension SiteRoute.View.UserRoute {
|
||||
|
||||
private func mainPage<C: HTML>(_ html: C) async throws -> AnySendableHTML where C: Sendable {
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user