aboutsummaryrefslogtreecommitdiffstats
path: root/code/frontend/src/routes/(main)/(public)/reset-password
diff options
context:
space:
mode:
authorivar <i@oiee.no>2024-04-28 22:37:30 +0200
committerivar <i@oiee.no>2024-04-28 22:37:30 +0200
commitced66c5807575cd29f6aa5632e8ad02b38c8448a (patch)
tree01760648ee293a2aef2288328014b5747d2192b4 /code/frontend/src/routes/(main)/(public)/reset-password
parent691ad60d7bff5934053d87267c4e303ef3ed5f97 (diff)
downloadgreatoffice-ced66c5807575cd29f6aa5632e8ad02b38c8448a.tar.xz
greatoffice-ced66c5807575cd29f6aa5632e8ad02b38c8448a.zip
WIP new frontend
Diffstat (limited to 'code/frontend/src/routes/(main)/(public)/reset-password')
-rw-r--r--code/frontend/src/routes/(main)/(public)/reset-password/+page.svelte81
-rw-r--r--code/frontend/src/routes/(main)/(public)/reset-password/+page.ts11
-rw-r--r--code/frontend/src/routes/(main)/(public)/reset-password/[id]/+page.server.ts11
-rw-r--r--code/frontend/src/routes/(main)/(public)/reset-password/[id]/+page.svelte82
-rw-r--r--code/frontend/src/routes/(main)/(public)/reset-password/[id]/+page.ts11
5 files changed, 196 insertions, 0 deletions
diff --git a/code/frontend/src/routes/(main)/(public)/reset-password/+page.svelte b/code/frontend/src/routes/(main)/(public)/reset-password/+page.svelte
new file mode 100644
index 0000000..a45ccdd
--- /dev/null
+++ b/code/frontend/src/routes/(main)/(public)/reset-password/+page.svelte
@@ -0,0 +1,81 @@
+<script lang="ts">
+ import { Alert, Input, Button } from "$components";
+ import LL from "$i18n/i18n-svelte";
+ import { FormError } from "$models/internal/FormError";
+ import { PasswordResetService } from "$services/password-reset-service";
+
+ const formData = {
+ email: {
+ value: "",
+ errors: [],
+ },
+ };
+
+ const formError = new FormError();
+ const passwordResetService = PasswordResetService.resolve();
+
+ let loading = false;
+ let showSuccessAlert = false;
+ let showErrorAlert = false;
+
+ async function submit_form_async() {
+ formError.set();
+ showSuccessAlert = false;
+ showErrorAlert = false;
+ loading = true;
+ const response = await passwordResetService.create_request_async(formData.email.value);
+ loading = false;
+ if (response.isCreated) {
+ showSuccessAlert = true;
+ } else if (response.knownProblem) {
+ formError.set_from_known_problem(response.knownProblem);
+ for (const error of Object.entries(response.knownProblem.errors)) {
+ if (error[0] === "email") {
+ let errors = [];
+ error[1].forEach((e) => errors.push(e));
+ formData.email.errors = errors;
+ }
+ }
+ } else {
+ formError.set($LL.unexpectedError(), $LL.tryAgainSoon());
+ }
+ showErrorAlert = formError.has_error() && !showSuccessAlert;
+ }
+</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 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-sm text-gray-600">
+ {$LL.or().toLowerCase()}
+ <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" on:submit|preventDefault={submit_form_async}>
+ {#if showErrorAlert}
+ <Alert title={formError.title} message={formError.subtitle} type="error" />
+ {:else if showSuccessAlert}
+ <Alert type="success" title={$LL.success()} message={$LL.resetPasswordPage.requestSentMessage()} />
+ {/if}
+ <Input
+ id="email"
+ name="email"
+ type="email"
+ autocomplete="email"
+ errors={formData.email.errors}
+ bind:value={formData.email.value}
+ required
+ label={$LL.emailAddress()}
+ />
+ <Button text={$LL.submit()} type="submit" {loading} fullWidth />
+ </form>
+ </div>
+ </div>
+</div>
diff --git a/code/frontend/src/routes/(main)/(public)/reset-password/+page.ts b/code/frontend/src/routes/(main)/(public)/reset-password/+page.ts
new file mode 100644
index 0000000..c0859e0
--- /dev/null
+++ b/code/frontend/src/routes/(main)/(public)/reset-password/+page.ts
@@ -0,0 +1,11 @@
+import LL from '$i18n/i18n-svelte';
+import { get } from 'svelte/store';
+import type { PageLoad } from './$types';
+
+const l = get(LL);
+
+export const load: PageLoad = async () => {
+ return {
+ title: l.resetPasswordPage.title(),
+ };
+}; \ No newline at end of file
diff --git a/code/frontend/src/routes/(main)/(public)/reset-password/[id]/+page.server.ts b/code/frontend/src/routes/(main)/(public)/reset-password/[id]/+page.server.ts
new file mode 100644
index 0000000..9e24736
--- /dev/null
+++ b/code/frontend/src/routes/(main)/(public)/reset-password/[id]/+page.server.ts
@@ -0,0 +1,11 @@
+import { is_guid } from "$utils/validators";
+import { redirect } from "@sveltejs/kit";
+import type { PageServerLoad } from "./$types";
+
+export const load: PageServerLoad = async ({ params }) => {
+ const resetRequestId = params.id ?? "";
+ if (!is_guid(resetRequestId)) throw redirect(302, "/reset-password");
+ return {
+ resetRequestId,
+ };
+}; \ No newline at end of file
diff --git a/code/frontend/src/routes/(main)/(public)/reset-password/[id]/+page.svelte b/code/frontend/src/routes/(main)/(public)/reset-password/[id]/+page.svelte
new file mode 100644
index 0000000..27a1af5
--- /dev/null
+++ b/code/frontend/src/routes/(main)/(public)/reset-password/[id]/+page.svelte
@@ -0,0 +1,82 @@
+<script lang="ts">
+ import { onMount } from "svelte";
+ import LL from "$i18n/i18n-svelte";
+ import { Alert, Input, Button } from "$components";
+ import type { PageServerData } from "./$types";
+ import { goto } from "$app/navigation";
+ import { SignInPageMessage, signInPageMessageQueryKey } from "$routes/(main)/(public)/sign-in";
+ import { PasswordResetService } from "$services/password-reset-service";
+
+ export let data: PageServerData;
+ const passwordResetService = PasswordResetService.resolve();
+
+ const formData = {
+ newPassword: {
+ value: "",
+ errors: [],
+ },
+ };
+
+ let finishedPreliminaryLoading = false;
+ let loading = false;
+ let canSubmit = true;
+ let requestIsInvalid = false;
+
+ async function submitFormAsync() {
+ if (!canSubmit) return;
+ loading = true;
+ const request = await passwordResetService.fulfill_request_async(data.resetRequestId, formData.newPassword.value);
+ if (request.isFulfilled) {
+ goto("/sign-in?" + signInPageMessageQueryKey + "=" + SignInPageMessage.AFTER_PASSWORD_RESET);
+ } else if (request.knownProblem) {
+ }
+ loading = false;
+ }
+
+ onMount(async () => {
+ const response = await passwordResetService.request_is_valid_async(data.resetRequestId);
+ requestIsInvalid = !response.isValid;
+ 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 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-sm text-gray-600">
+ {$LL.or().toLowerCase()}
+ <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" on:submit|preventDefault={submitFormAsync}>
+ {#if requestIsInvalid}
+ <Alert
+ title={$LL.resetPasswordPage.invalidRequestTitle()}
+ message={$LL.resetPasswordPage.invalidRequestMessage()}
+ />
+ {/if}
+ <Input
+ id="password"
+ name="password"
+ type="password"
+ autocomplete="new-password"
+ required
+ bind:value={formData.newPassword.value}
+ label={$LL.resetPasswordPage.newPassword()}
+ />
+ <Button text={$LL.submit()} type="submit" {loading} fullWidth />
+ </form>
+ </div>
+ </div>
+ {:else}
+ <p>Checking your request...</p>
+ {/if}
+</div>
diff --git a/code/frontend/src/routes/(main)/(public)/reset-password/[id]/+page.ts b/code/frontend/src/routes/(main)/(public)/reset-password/[id]/+page.ts
new file mode 100644
index 0000000..3252b7a
--- /dev/null
+++ b/code/frontend/src/routes/(main)/(public)/reset-password/[id]/+page.ts
@@ -0,0 +1,11 @@
+import LL from '$i18n/i18n-svelte';
+import { get } from 'svelte/store';
+import type { PageLoad } from './$types';
+
+const l = get(LL);
+
+export const load: PageLoad = async () => {
+ return {
+ title: l.resetPasswordPage.fulfillTitle(),
+ };
+}; \ No newline at end of file