diff options
| -rw-r--r-- | apps/kit/src/app.d.ts | 2 | ||||
| -rw-r--r-- | apps/kit/src/lib/components/alert.svelte | 4 | ||||
| -rw-r--r-- | apps/kit/src/lib/components/button.svelte | 12 | ||||
| -rw-r--r-- | apps/kit/src/lib/components/checkbox.svelte | 2 | ||||
| -rw-r--r-- | apps/kit/src/lib/i18n/en/index.ts | 41 | ||||
| -rw-r--r-- | apps/kit/src/lib/i18n/i18n-types.ts | 252 | ||||
| -rw-r--r-- | apps/kit/src/lib/models/LoginPayload.ts | 3 | ||||
| -rw-r--r-- | apps/kit/src/routes/(main)/(public)/+layout.svelte | 18 | ||||
| -rw-r--r-- | apps/kit/src/routes/(main)/(public)/reset-password/+page.svelte | 16 | ||||
| -rw-r--r-- | apps/kit/src/routes/(main)/(public)/reset-password/[id]/+page.svelte | 79 | ||||
| -rw-r--r-- | apps/kit/src/routes/(main)/(public)/sign-in/+page.svelte | 79 | ||||
| -rw-r--r-- | apps/kit/src/routes/(main)/(public)/sign-up/+page.svelte | 61 | ||||
| -rw-r--r-- | apps/kit/src/routes/(main)/+layout.svelte | 7 |
13 files changed, 425 insertions, 151 deletions
diff --git a/apps/kit/src/app.d.ts b/apps/kit/src/app.d.ts index 4ab4e43..220ddc1 100644 --- a/apps/kit/src/app.d.ts +++ b/apps/kit/src/app.d.ts @@ -6,4 +6,4 @@ declare namespace App { interface Platform {} interface PrivateEnv {} interface PublicEnv {} -} +}
\ No newline at end of file diff --git a/apps/kit/src/lib/components/alert.svelte b/apps/kit/src/lib/components/alert.svelte index 5bcb3ae..fa36a63 100644 --- a/apps/kit/src/lib/components/alert.svelte +++ b/apps/kit/src/lib/components/alert.svelte @@ -193,7 +193,9 @@ </script> {#if visible} - <div class="rounded-md bg-{colorClassPart}-50 p-4 "> + <div + class="rounded-md bg-{colorClassPart}-50 p-4 {$$restProps.class ?? ''}" + > <div class="flex"> <div class="flex-shrink-0"> <svelte:component diff --git a/apps/kit/src/lib/components/button.svelte b/apps/kit/src/lib/components/button.svelte index 95dba5c..323c7ad 100644 --- a/apps/kit/src/lib/components/button.svelte +++ b/apps/kit/src/lib/components/button.svelte @@ -13,7 +13,7 @@ export let tabindex: string | undefined = undefined; export let style: string | undefined = undefined; export let title: string | undefined = undefined; - export let disabled = false; + export let disabled: boolean | null = false; export let href: string | undefined = undefined; export let text: string; export let loading = false; @@ -78,8 +78,9 @@ on:click class="{sizeClasses} {kindClasses} {loading ? 'disabled:' - : ''} {$$restProps.class ?? - ''} {fullWidth ? 'w-full justify-center': ''} inline-flex items-center border font-medium rounded shadow-sm focus:outline-none focus:ring-2" + : ''} {$$restProps.class ?? ''} {fullWidth + ? 'w-full justify-center' + : ''} inline-flex items-center border font-medium rounded shadow-sm focus:outline-none focus:ring-2" > {#if loading} <Spinner class={spinnerTextClasses + " " + spinnerMarginClasses} /> @@ -89,8 +90,9 @@ {:else} <button {...shared_props} - class="{sizeClasses} {kindClasses} {$$restProps.class ?? - ''} {fullWidth ? 'w-full justify-center': ''} inline-flex items-center border font-medium rounded shadow-sm focus:outline-none focus:ring-2" + class="{sizeClasses} {kindClasses} {$$restProps.class ?? ''} {fullWidth + ? 'w-full justify-center' + : ''} inline-flex items-center border font-medium rounded shadow-sm focus:outline-none focus:ring-2" > {#if loading} <Spinner class={spinnerTextClasses + " " + spinnerMarginClasses} /> diff --git a/apps/kit/src/lib/components/checkbox.svelte b/apps/kit/src/lib/components/checkbox.svelte index bb22215..311d154 100644 --- a/apps/kit/src/lib/components/checkbox.svelte +++ b/apps/kit/src/lib/components/checkbox.svelte @@ -5,6 +5,7 @@ export let id: string | undefined = "input__" + random_string(4); export let name: string | undefined = undefined; export let disabled: boolean | null = null; + export let checked: boolean; </script> <div class="flex items-center"> @@ -13,6 +14,7 @@ {disabled} {id} type="checkbox" + bind:checked class="h-4 w-4 text-teal-600 focus:ring-teal-500 border-gray-300 rounded" /> <label for={id} class="ml-2 block text-sm text-gray-900">{label}</label> diff --git a/apps/kit/src/lib/i18n/en/index.ts b/apps/kit/src/lib/i18n/en/index.ts index 003de0d..e084a6c 100644 --- a/apps/kit/src/lib/i18n/en/index.ts +++ b/apps/kit/src/lib/i18n/en/index.ts @@ -12,16 +12,39 @@ const en: BaseTranslation = { submit: "Submit", success: "Success", tryAgainSoon: "Try again soon", + createANewAccount: "Create a new account", unexpectedError: "An unexpected error occured", - requestAPasswordReset: "Request a password reset", - signIntoYourAccount: "sign into your account", - requestSentMessage: "If we find your email address in our systems, you will receive an email with instructions on how to set a new password for your account.", - signIn: "Sign In", - createANewAccount: "create a new account", - notMyComputer: "This is not my computer", - resetPassword: "Reset password", - createYourNewAccount: "Create your new account", - newPassword: "New password" + notFound: "Not found", + documentation: "Documentation", + tos: "Terms of service", + privacyPolicy: "Privacy policy", + signIntoYourAccount: "Sign into your account", + signInPage: { + notMyComputer: "This is not my computer", + resetPassword: "Reset password", + yourPasswordIsUpdated: "Your password is updated", + signIn: "Sign In", + yourNewPasswordIsApplied: "Your new password is applied", + signInBelow: "Sign in below", + yourAccountIsDisabled: "Your account is disabled", + contactYourAdminIfDisabled: "Contact your administrator if this feels wrong", + youHaveReachedInactivityLimit: "You've reached the hidden inactivity limit", + feelFreeToSignInAgain: "Feel free to sign in again" + }, + signUpPage: { + createYourNewAccount: "Create your new account", + }, + resetPasswordPage: { + setANewPassword: "Set a new password", + expired: "Expired", + requestHasExpired: "Your request has expired", + requestANewReset: "Request a new reset", + newPassword: "New password", + requestSentMessage: "If we find your email address in our systems, you will receive an email with instructions on how to set a new password for your account.", + requestAPasswordReset: "Request a password reset", + requestNotFound: "Your request was not found", + submitANewRequestBelow: "Submit a new reset request below" + } }; export default en; diff --git a/apps/kit/src/lib/i18n/i18n-types.ts b/apps/kit/src/lib/i18n/i18n-types.ts index aedf48b..2d76cef 100644 --- a/apps/kit/src/lib/i18n/i18n-types.ts +++ b/apps/kit/src/lib/i18n/i18n-types.ts @@ -64,45 +64,119 @@ type RootTranslation = { */ tryAgainSoon: string /** - * An unexpected error occured - */ - unexpectedError: string - /** - * Request a password reset + * Create a new account */ - requestAPasswordReset: string - /** - * sign into your account - */ - signIntoYourAccount: string - /** - * If we find your email address in our systems, you will receive an email with instructions on how to set a new password for your account. - */ - requestSentMessage: string + createANewAccount: string /** - * Sign In + * An unexpected error occured */ - signIn: string + unexpectedError: string /** - * create a new account + * Not found */ - createANewAccount: string + notFound: string /** - * This is not my computer + * Documentation */ - notMyComputer: string + documentation: string /** - * Reset password + * Terms of service */ - resetPassword: string + tos: string /** - * Create your new account + * Privacy policy */ - createYourNewAccount: string + privacyPolicy: string /** - * New password + * Sign into your account */ - newPassword: string + signIntoYourAccount: string + signInPage: { + /** + * This is not my computer + */ + notMyComputer: string + /** + * Reset password + */ + resetPassword: string + /** + * Your password is updated + */ + yourPasswordIsUpdated: string + /** + * Sign In + */ + signIn: string + /** + * Your new password is applied + */ + yourNewPasswordIsApplied: string + /** + * Sign in below + */ + signInBelow: string + /** + * Your account is disabled + */ + yourAccountIsDisabled: string + /** + * Contact your administrator if this feels wrong + */ + contactYourAdminIfDisabled: string + /** + * You've reached the hidden inactivity limit + */ + youHaveReachedInactivityLimit: string + /** + * Feel free to sign in again + */ + feelFreeToSignInAgain: string + } + signUpPage: { + /** + * Create your new account + */ + createYourNewAccount: string + } + resetPasswordPage: { + /** + * Set a new password + */ + setANewPassword: string + /** + * Expired + */ + expired: string + /** + * Your request has expired + */ + requestHasExpired: string + /** + * Request a new reset + */ + requestANewReset: string + /** + * New password + */ + newPassword: string + /** + * If we find your email address in our systems, you will receive an email with instructions on how to set a new password for your account. + */ + requestSentMessage: string + /** + * Request a password reset + */ + requestAPasswordReset: string + /** + * Your request was not found + */ + requestNotFound: string + /** + * Submit a new reset request below + */ + submitANewRequestBelow: string + } } export type NamespaceAppTranslation = { @@ -473,45 +547,119 @@ export type TranslationFunctions = { */ tryAgainSoon: () => LocalizedString /** - * An unexpected error occured - */ - unexpectedError: () => LocalizedString - /** - * Request a password reset + * Create a new account */ - requestAPasswordReset: () => LocalizedString - /** - * sign into your account - */ - signIntoYourAccount: () => LocalizedString - /** - * If we find your email address in our systems, you will receive an email with instructions on how to set a new password for your account. - */ - requestSentMessage: () => LocalizedString + createANewAccount: () => LocalizedString /** - * Sign In + * An unexpected error occured */ - signIn: () => LocalizedString + unexpectedError: () => LocalizedString /** - * create a new account + * Not found */ - createANewAccount: () => LocalizedString + notFound: () => LocalizedString /** - * This is not my computer + * Documentation */ - notMyComputer: () => LocalizedString + documentation: () => LocalizedString /** - * Reset password + * Terms of service */ - resetPassword: () => LocalizedString + tos: () => LocalizedString /** - * Create your new account + * Privacy policy */ - createYourNewAccount: () => LocalizedString + privacyPolicy: () => LocalizedString /** - * New password + * Sign into your account */ - newPassword: () => LocalizedString + signIntoYourAccount: () => LocalizedString + signInPage: { + /** + * This is not my computer + */ + notMyComputer: () => LocalizedString + /** + * Reset password + */ + resetPassword: () => LocalizedString + /** + * Your password is updated + */ + yourPasswordIsUpdated: () => LocalizedString + /** + * Sign In + */ + signIn: () => LocalizedString + /** + * Your new password is applied + */ + yourNewPasswordIsApplied: () => LocalizedString + /** + * Sign in below + */ + signInBelow: () => LocalizedString + /** + * Your account is disabled + */ + yourAccountIsDisabled: () => LocalizedString + /** + * Contact your administrator if this feels wrong + */ + contactYourAdminIfDisabled: () => LocalizedString + /** + * You've reached the hidden inactivity limit + */ + youHaveReachedInactivityLimit: () => LocalizedString + /** + * Feel free to sign in again + */ + feelFreeToSignInAgain: () => LocalizedString + } + signUpPage: { + /** + * Create your new account + */ + createYourNewAccount: () => LocalizedString + } + resetPasswordPage: { + /** + * Set a new password + */ + setANewPassword: () => LocalizedString + /** + * Expired + */ + expired: () => LocalizedString + /** + * Your request has expired + */ + requestHasExpired: () => LocalizedString + /** + * Request a new reset + */ + requestANewReset: () => LocalizedString + /** + * New password + */ + newPassword: () => LocalizedString + /** + * If we find your email address in our systems, you will receive an email with instructions on how to set a new password for your account. + */ + requestSentMessage: () => LocalizedString + /** + * Request a password reset + */ + requestAPasswordReset: () => LocalizedString + /** + * Your request was not found + */ + requestNotFound: () => LocalizedString + /** + * Submit a new reset request below + */ + submitANewRequestBelow: () => LocalizedString + } app: { nav: { /** diff --git a/apps/kit/src/lib/models/LoginPayload.ts b/apps/kit/src/lib/models/LoginPayload.ts index ccd9bed..beb96cf 100644 --- a/apps/kit/src/lib/models/LoginPayload.ts +++ b/apps/kit/src/lib/models/LoginPayload.ts @@ -1,4 +1,5 @@ export interface LoginPayload { username: string, - password: string + password: string, + persist: boolean } diff --git a/apps/kit/src/routes/(main)/(public)/+layout.svelte b/apps/kit/src/routes/(main)/(public)/+layout.svelte new file mode 100644 index 0000000..69c29c5 --- /dev/null +++ b/apps/kit/src/routes/(main)/(public)/+layout.svelte @@ -0,0 +1,18 @@ +<script> + import LL from "$lib/i18n/i18n-svelte"; +</script> + +<slot /> +<footer + class="grid sm:gap-5 grid-flow-row sm:justify-center px-2 sm:grid-flow-col" +> + <a href="https://greatoffice.life/privacy" class="link"> + {$LL.privacyPolicy()} + </a> + <a href="https://greatoffice.life/tos" class="link"> + {$LL.tos()} + </a> + <a href="https://greatoffice.life/documentation" class="link"> + {$LL.documentation()} + </a> +</footer> diff --git a/apps/kit/src/routes/(main)/(public)/reset-password/+page.svelte b/apps/kit/src/routes/(main)/(public)/reset-password/+page.svelte index 9ee4a83..aa26892 100644 --- a/apps/kit/src/routes/(main)/(public)/reset-password/+page.svelte +++ b/apps/kit/src/routes/(main)/(public)/reset-password/+page.svelte @@ -37,16 +37,14 @@ </script> <div class="min-h-full flex flex-col justify-center py-12 sm:px-6 lg:px-8"> - <div class="sm:mx-auto sm:w-full sm:max-w-md"> - <h2 - class="mt-6 text-center text-3xl tracking-tight font-bold text-gray-900" - > - {$LL.requestAPasswordReset()} + <div class="sm:mx-auto sm:w-full p-2 sm:p-0 sm:max-w-md"> + <h2 class="mt-6 text-3xl tracking-tight font-bold text-gray-900"> + {$LL.resetPasswordPage.requestAPasswordReset()} </h2> - <p class="mt-2 text-center text-sm text-gray-600"> + <p class="mt-2 text-sm text-gray-600"> {$LL.or().toLowerCase()} <a href="/sign-in" class="link"> - {$LL.signIntoYourAccount()} + {$LL.signIntoYourAccount().toLowerCase()} </a> </p> </div> @@ -64,7 +62,7 @@ <Alert type="success" title={$LL.success()} - message={$LL.requestSentMessage()} + message={$LL.resetPasswordPage.requestSentMessage()} visible={showSuccessAlert} /> @@ -77,7 +75,7 @@ bind:value={formData.email} label={$LL.emailAddress()} /> - <Button text={$LL.submit()} type="submit" fullWidth /> + <Button text={$LL.submit()} type="submit" {loading} fullWidth /> </form> </div> </div> diff --git a/apps/kit/src/routes/(main)/(public)/reset-password/[id]/+page.svelte b/apps/kit/src/routes/(main)/(public)/reset-password/[id]/+page.svelte index 7b46d2d..562d902 100644 --- a/apps/kit/src/routes/(main)/(public)/reset-password/[id]/+page.svelte +++ b/apps/kit/src/routes/(main)/(public)/reset-password/[id]/+page.svelte @@ -9,6 +9,7 @@ import type { PageServerData } from "./$types"; import type { ErrorResult } from "$lib/models/ErrorResult"; import { goto } from "$app/navigation"; + import { Message, messageQueryKey } from "../../sign-in/+page.svelte"; export let data: PageServerData; @@ -16,18 +17,15 @@ newPassword: "", }; - $: showErrorAlert = - (errorData?.text.length ?? 0 + errorData?.title.length ?? 0) > 0 && - !showSuccessAlert; - const errorData = { text: "", title: "", } as ErrorResult; + let errorState: undefined | "expired" | "404" | "unknown"; + let finishedPreliminaryLoading = false; let loading = false; - let showSuccessAlert = false; let canSubmit = true; async function submitFormAsync() { @@ -38,39 +36,48 @@ formData.newPassword ); if (request.ok) { - goto("/sign-in?m=1"); + goto( + "/sign-in?" + + messageQueryKey + + "=" + + Message.AFTER_PASSWORD_RESET + ); } loading = false; } onMount(async () => { + errorState = undefined; const isValidRequest = await check_forgot_password_request( data.resetRequestId ); - if (!isValidRequest.ok) { - errorData.text = isValidRequest.data?.text ?? $LL.tryAgainSoon(); - errorData.title = - isValidRequest.data?.title ?? $LL.unexpectedError(); + if (!isValidRequest.ok && isValidRequest.status !== 404) { + errorState = "unknown"; + canSubmit = false; + } + if (isValidRequest.status === 404) { + errorState = "404"; + canSubmit = false; + } + if (isValidRequest.ok && isValidRequest.data !== true) { + errorState = "expired"; canSubmit = false; } - if (isValidRequest.status === 404) goto("/reset-password"); finishedPreliminaryLoading = true; }); </script> <div class="min-h-full flex flex-col justify-center py-12 sm:px-6 lg:px-8"> {#if finishedPreliminaryLoading} - <div class="sm:mx-auto sm:w-full sm:max-w-md"> - <h2 - class="mt-6 text-center text-3xl tracking-tight font-bold text-gray-900" - > - {$LL.requestAPasswordReset()} + <div class="sm:mx-auto sm:w-full p-2 sm:p-0 sm:max-w-md"> + <h2 class="mt-6 text-3xl tracking-tight font-bold text-gray-900"> + {$LL.resetPasswordPage.setANewPassword()} </h2> - <p class="mt-2 text-center text-sm text-gray-600"> + <p class="mt-2 text-sm text-gray-600"> {$LL.or().toLowerCase()} <a href="/sign-in" class="link"> - {$LL.signIntoYourAccount()} + {$LL.signIntoYourAccount().toLowerCase()} </a> </p> </div> @@ -81,21 +88,24 @@ class="space-y-6" on:submit|preventDefault={submitFormAsync} > - <Alert - title={errorData.title} - message={errorData.text} - type="error" - visible={showErrorAlert} - /> - - <Alert - type="success" - title={$LL.success()} - message={$LL.requestSentMessage()} - rightLinkHref="/sign-in" - rightLinkText="Sign in" - visible={showSuccessAlert} - /> + {#if errorState === "404"} + <Alert + title={$LL.notFound()} + message={$LL.resetPasswordPage.requestNotFound()} + /> + {:else if errorState === "expired"} + <Alert + title={$LL.resetPasswordPage.expired()} + message={$LL.resetPasswordPage.requestHasExpired()} + rightLinkHref="/reset-password" + rightLinkText={$LL.resetPasswordPage.requestANewReset()} + /> + {:else if errorState === "unknown"} + <Alert + title={$LL.unexpectedError()} + message={$LL.tryAgainSoon()} + /> + {/if} <Input id="password" @@ -104,8 +114,9 @@ autocomplete="new-password" required bind:value={formData.newPassword} - label={$LL.newPassword()} + label={$LL.resetPasswordPage.newPassword()} /> + <Button text={$LL.submit()} type="submit" diff --git a/apps/kit/src/routes/(main)/(public)/sign-in/+page.svelte b/apps/kit/src/routes/(main)/(public)/sign-in/+page.svelte index c431e0d..07ed0e0 100644 --- a/apps/kit/src/routes/(main)/(public)/sign-in/+page.svelte +++ b/apps/kit/src/routes/(main)/(public)/sign-in/+page.svelte @@ -1,25 +1,28 @@ <script context="module" lang="ts"> - export type Message = - | "after-password-reset" - | "user-inactivity" - | "user-disabled"; + export enum Message { + AFTER_PASSWORD_RESET = "after-password-reset", + USER_INACTIVITY = "user-inactivity", + USER_DISABLED = "user-disabled", + } + export const messageQueryKey = "m"; </script> <script lang="ts"> import { goto } from "$app/navigation"; import { login } from "$lib/api/user"; - import Button from "$lib/components/button.svelte"; - import Checkbox from "$lib/components/checkbox.svelte"; - import Input from "$lib/components/input.svelte"; + import { Button, Checkbox, Input, Alert } from "$lib/components"; import LL from "$lib/i18n/i18n-svelte"; import type { ErrorResult } from "$lib/models/ErrorResult"; import type { LoginPayload } from "$lib/models/LoginPayload"; + import { onMount } from "svelte"; let loading = false; + let messageType: Message | undefined = undefined; const data = { username: "", password: "", + persist: true, } as LoginPayload; let error = { @@ -27,9 +30,23 @@ title: "", } as ErrorResult; + onMount(() => { + const searcher = new URLSearchParams(window.location.search); + if (searcher.get(messageQueryKey)) { + messageType = searcher.get(messageQueryKey) as Message; + searcher.delete(messageQueryKey); + history.replaceState( + null, + "", + window.location.origin + window.location.pathname + ); + } + }); + async function submitFormAsync() { error = { text: "", title: "" }; loading = true; + data.persist = !data.persist; const loginResponse = await login(data); if (loginResponse.ok) { await goto("/home"); @@ -42,15 +59,38 @@ </script> <div class="min-h-full flex flex-col justify-center py-12 sm:px-6 lg:px-8"> - <div class="sm:mx-auto sm:w-full sm:max-w-md"> - <h2 - class="mt-6 text-center text-3xl tracking-tight font-bold text-gray-900" - > - {$LL.signIn()} + {#if messageType} + <div class="sm:max-w-md sm:mx-auto sm:w-full"> + {#if messageType === "after-password-reset"} + <Alert + title={$LL.signInPage.yourNewPasswordIsApplied()} + message={$LL.signInPage.signInBelow()} + closeable + /> + {:else if messageType === "user-disabled"} + <Alert + title={$LL.signInPage.yourAccountIsDisabled()} + message={$LL.signInPage.contactYourAdminIfDisabled()} + closeable + /> + {:else if messageType === "user-inactivity"} + <Alert + title={$LL.signInPage.youHaveReachedInactivityLimit()} + message={$LL.signInPage.feelFreeToSignInAgain()} + closeable + /> + {/if} + </div> + {/if} + <div class="sm:mx-auto sm:w-full p-2 sm:p-0 sm:max-w-md"> + <h2 class="mt-6 text-3xl tracking-tight font-bold text-gray-900"> + {$LL.signInPage.signIn()} </h2> - <p class="mt-2 text-center text-sm text-gray-600"> + <p class="mt-2 text-sm text-gray-600"> {$LL.or().toLowerCase()} - <a href="/sign-up" class="link">{$LL.createANewAccount()}</a> + <a href="/sign-up" class="link" + >{$LL.createANewAccount().toLowerCase()}</a + > </p> </div> <div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md"> @@ -76,7 +116,7 @@ type="email" label={$LL.emailAddress()} required - value={data.username} + bind:value={data.username} /> <Input @@ -86,23 +126,24 @@ label={$LL.password()} autocomplete="current-password" required - value={data.password} + bind:value={data.password} /> <div class="flex items-center justify-between"> <Checkbox id="remember-me" name="remember-me" - label={$LL.notMyComputer()} + bind:checked={data.persist} + label={$LL.signInPage.notMyComputer()} /> <div class="text-sm"> <a href="/reset-password" class="link"> - {$LL.resetPassword()} + {$LL.signInPage.resetPassword()} </a> </div> </div> - <Button text={$LL.signIn()} fullWidth type="submit" {loading} /> + <Button text={$LL.submit()} fullWidth type="submit" {loading} /> </form> </div> </div> diff --git a/apps/kit/src/routes/(main)/(public)/sign-up/+page.svelte b/apps/kit/src/routes/(main)/(public)/sign-up/+page.svelte index 8b89190..0dfa41a 100644 --- a/apps/kit/src/routes/(main)/(public)/sign-up/+page.svelte +++ b/apps/kit/src/routes/(main)/(public)/sign-up/+page.svelte @@ -1,29 +1,62 @@ -<script> - import { Button, Input } from "$lib/components"; +<script lang="ts"> + import { goto } from "$app/navigation"; + import { create_account } from "$lib/api/user"; + import { Button, Input, Alert } from "$lib/components"; import LL from "$lib/i18n/i18n-svelte"; + import type { CreateAccountPayload } from "$lib/models/CreateAccountPayload"; + import type { ErrorResult } from "$lib/models/ErrorResult"; const formData = { - emailAddress: "", + username: "", password: "", - }; + } as CreateAccountPayload; + + const errorData = { + text: "", + title: "", + } as ErrorResult; + let loading = false; + $: showErrorAlert = + (errorData?.text.length ?? 0 + errorData?.title.length ?? 0) > 0; + + async function submitFormAsync() { + loading = true; + errorData.text = ""; + errorData.title = ""; + const response = await create_account(formData); + loading = false; + if (response.ok) { + await goto("/home"); + return; + } + errorData.title = response.data?.title ?? $LL.unexpectedError(); + errorData.text = response.data?.text ?? $LL.tryAgainSoon(); + } </script> <div class="min-h-full flex flex-col justify-center py-12 sm:px-6 lg:px-8"> - <div class="sm:mx-auto sm:w-full sm:max-w-md"> - <h2 - class="mt-6 text-center text-3xl tracking-tight font-bold text-gray-900" - > - {$LL.createYourNewAccount()} + <div class="sm:mx-auto sm:w-full p-2 sm:p-0 sm:max-w-md"> + <h2 class="mt-6 text-3xl tracking-tight font-bold text-gray-900"> + {$LL.signUpPage.createYourNewAccount()} </h2> - <p class="mt-2 text-center text-sm text-gray-600"> + <p class="mt-2 text-sm text-gray-600"> {$LL.or().toLowerCase()} - <a href="/sign-in" class="link">{$LL.signIntoYourAccount()}</a> + <a href="/sign-in" class="link"> + {$LL.signIntoYourAccount().toLowerCase()} + </a> </p> </div> <div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md"> <div class="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10"> - <form class="space-y-6" action="#"> + <Alert + title={errorData.title} + message={errorData.text} + type="error" + class="mb-2" + visible={showErrorAlert} + /> + <form class="space-y-6" on:submit|preventDefault={submitFormAsync}> <Input label={$LL.emailAddress()} id="email" @@ -31,7 +64,7 @@ autocomplete="email" required type="email" - bind:value={formData.emailAddress} + bind:value={formData.username} /> <Input @@ -42,7 +75,7 @@ type="password" bind:value={formData.password} /> - <Button type="submit" text={$LL.submit()} fullWidth /> + <Button type="submit" text={$LL.submit()} {loading} fullWidth /> </form> </div> </div> diff --git a/apps/kit/src/routes/(main)/+layout.svelte b/apps/kit/src/routes/(main)/+layout.svelte index 3107861..9787e17 100644 --- a/apps/kit/src/routes/(main)/+layout.svelte +++ b/apps/kit/src/routes/(main)/+layout.svelte @@ -1,16 +1,11 @@ <script lang="ts"> import "../../app.pcss"; import { setLocale } from "$lib/i18n/i18n-svelte"; - import { onMount } from "svelte"; import type { LayoutData } from "./$types"; - import LocaleSwitcher from "$lib/components/locale-switcher.svelte"; export let data: LayoutData; - onMount(async () => { - setLocale(data.locale); - }); + setLocale(data.locale); </script> -<LocaleSwitcher /> <slot /> |
