diff options
| author | ivarlovlie <git@ivarlovlie.no> | 2022-10-01 10:44:31 +0200 |
|---|---|---|
| committer | ivarlovlie <git@ivarlovlie.no> | 2022-10-01 10:44:31 +0200 |
| commit | 7a5ba5ea4aec0704070cfe8d63ba504a07d88cc6 (patch) | |
| tree | 683a6a121e02b4413774dcc36522c5d3817c9867 /apps/kit/src/routes/(main)/(public) | |
| parent | 33b5c5a72974af5bd8745298772fe7cc71b87b76 (diff) | |
| download | greatoffice-7a5ba5ea4aec0704070cfe8d63ba504a07d88cc6.tar.xz greatoffice-7a5ba5ea4aec0704070cfe8d63ba504a07d88cc6.zip | |
feat: Functionality complete public sites
Diffstat (limited to 'apps/kit/src/routes/(main)/(public)')
5 files changed, 177 insertions, 76 deletions
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> |
