using Htmx.ApiDemo.Data; using Immediate.Apis.Shared; using Immediate.Handlers.Shared; using Microsoft.AspNetCore.Antiforgery; using Microsoft.AspNetCore.Mvc; namespace Htmx.ApiDemo.Templates; public sealed class Register : RegisterBase { private readonly byte[] _errorData; private readonly byte[] _afTokenData; public Register(string? errorMessage = null, string? afToken = null) { _errorData = string.IsNullOrEmpty(errorMessage) ? [] : $"""
{System.Web.HttpUtility.HtmlEncode(errorMessage)}
""".ToUtf8Bytes(); _afTokenData = string.IsNullOrEmpty(afToken) ? [] : $"""""".ToUtf8Bytes(); } protected override void RenderErrorMessage(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_errorData); protected override void RenderAntiforgeryToken(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_afTokenData); } [Handler] [MapGet("/register")] public static partial class GetRegisterHandler { public record Query; private static ValueTask HandleAsync( Query _, IHttpContextAccessor httpContextAccessor, IAntiforgery antiforgery, CancellationToken token) { var ctx = httpContextAccessor.HttpContext ?? throw new InvalidOperationException("HttpContext is not available."); if (ctx.User.Identity?.IsAuthenticated == true) { ctx.Response.Redirect("/"); return ValueTask.CompletedTask; } var afTokens = antiforgery.GetAndStoreTokens(ctx); ctx.WriteHtmxPage(new Register(afToken: afTokens.RequestToken), title: "Register", appName: "HtmxApp", pageTitle: "Create account"); return ValueTask.CompletedTask; } } [Handler] [MapPost("/register")] public static partial class PostRegisterHandler { public record Command( [property: FromForm] string Email, [property: FromForm] string Password, [property: FromForm] string ConfirmPassword, [property: FromForm] string? DisplayName ); private static async ValueTask HandleAsync( [AsParameters] Command command, IHttpContextAccessor httpContextAccessor, IAntiforgery antiforgery, AuthService authService, CancellationToken token) { var ctx = httpContextAccessor.HttpContext ?? throw new InvalidOperationException("HttpContext is not available."); if (command.Password != command.ConfirmPassword) { var afTokens1 = antiforgery.GetAndStoreTokens(ctx); ctx.WriteHtmxPage(new Register("Passwords do not match.", afToken: afTokens1.RequestToken), title: "Register", appName: "HtmxApp", pageTitle: "Create account"); return; } var (success, error) = await authService.RegisterAsync(command.Email, command.Password, command.DisplayName); if (success) { ctx.Response.Redirect("/"); return; } var afTokens2 = antiforgery.GetAndStoreTokens(ctx); ctx.WriteHtmxPage(new Register(error, afToken: afTokens2.RequestToken), title: "Register", appName: "HtmxApp", pageTitle: "Create account"); } }