finished login/registration

This commit is contained in:
2026-01-24 13:13:22 +11:00
parent ff0f61f534
commit c780050f8e
13 changed files with 164 additions and 92 deletions

View File

@@ -1,25 +1,42 @@
package form
templ RegisterForm(username, registerError string) {
{{ usernameErr := "Username is taken" }}
templ RegisterForm(username string) {
<form
hx-post="/register"
x-data={ templ.JSFuncCall(
"registerFormData", registerError, usernameErr,
).CallInline }
x-on:htmx:xhr:loadstart="submitted=true;buttontext='Loading...'"
hx-swap="none"
x-data={ templ.JSFuncCall("registerFormData").CallInline }
@submit="handleSubmit()"
@htmx:after-request="if(submitTimeout) clearTimeout(submitTimeout); if(!$event.detail.successful) { isSubmitting=false; buttontext='Register'; if($event.detail.xhr.status === 409) { errorMessage='Username is already taken'; isUnique=false; } else { errorMessage='An error occurred. Please try again.'; } }"
>
<script>
function registerFormData(err, usernameErr) {
function registerFormData() {
return {
submitted: false,
canSubmit: false,
buttontext: "Register",
errorMessage: err,
errUsername: err === usernameErr ? true : false,
errorMessage: "",
isChecking: false,
isUnique: false,
isEmpty: true,
isSubmitting: false,
submitTimeout: null,
resetErr() {
this.errorMessage = "";
this.errUsername = false;
this.isChecking = false;
this.isUnique = false;
},
enableSubmit() {
this.canSubmit = true;
},
handleSubmit() {
this.isSubmitting = true;
this.buttontext = 'Loading...';
// Set timeout for 10 seconds
this.submitTimeout = setTimeout(() => {
this.isSubmitting = false;
this.buttontext = 'Register';
this.errorMessage = 'Request timed out. Please try again.';
}, 10000);
}
};
}
</script>
@@ -32,48 +49,34 @@ templ RegisterForm(username, registerError string) {
type="text"
id="username"
name="username"
class="py-3 px-4 block w-full rounded-lg text-sm
focus:border-blue focus:ring-blue bg-base
disabled:opacity-50
disabled:pointer-events-none"
x-bind:class="{
'py-3 px-4 block w-full rounded-lg text-sm bg-base disabled:opacity-50 disabled:pointer-events-none border-2 outline-none': true,
'border-overlay0 focus:border-blue': !isUnique && !errorMessage,
'border-green focus:border-green': isUnique && !isChecking && !errorMessage,
'border-red focus:border-red': errorMessage && !isChecking
}"
required
aria-describedby="username-error"
value={ username }
@input="resetErr()"
@input="resetErr(); isEmpty = $el.value.trim() === ''; if(isEmpty) { errorMessage='Username is required'; isUnique=false; }"
hx-post="/htmx/isusernameunique"
hx-trigger="load delay:100ms, input changed delay:500ms"
hx-swap="none"
@htmx:before-request="if($el.value.trim() === '') { isEmpty=true; return; } isEmpty=false; isChecking=true; isUnique=false; errorMessage=''"
@htmx:after-request="isChecking=false; if($event.detail.successful) { isUnique=true; canSubmit=true; } else if($event.detail.xhr.status === 409) { errorMessage='Username is already taken'; isUnique=false; canSubmit=false; }"
/>
<div
class="absolute inset-y-0 end-0
pointer-events-none pe-3 pt-3"
x-show="errUsername"
x-cloak
>
<svg
class="size-5 text-red"
width="16"
height="16"
fill="currentColor"
viewBox="0 0 16 16"
aria-hidden="true"
>
<path
d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8
4a.905.905 0 0 0-.9.995l.35 3.507a.552.552 0 0
0 1.1 0l.35-3.507A.905.905 0 0 0 8 4zm.002 6a1
1 0 1 0 0 2 1 1 0 0 0 0-2z"
></path>
</svg>
</div>
<p
class="text-center text-xs text-red mt-2"
id="username-error"
x-show="errUsername"
x-show="errorMessage"
x-cloak
x-text="if (errUsername) return errorMessage;"
x-text="errorMessage"
></p>
</div>
</div>
<button
x-bind:disabled="submitted"
x-bind:disabled="isEmpty || !isUnique || isChecking || isSubmitting"
x-text="buttontext"
type="submit"
class="w-full py-3 px-4 inline-flex justify-center items-center