summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorivarlovlie <git@ivarlovlie.no>2022-08-05 12:58:54 +0200
committerivarlovlie <git@ivarlovlie.no>2022-08-05 12:58:54 +0200
commitbab0072e5cf709e6c1cf303f89348ee61a8007e4 (patch)
tree3c964d27224b18364f9a378f9ab6c01d207a9153
parentc1d0567a0c46be08826cf4fe556b680cb2efe53a (diff)
downloadgreatoffice-bab0072e5cf709e6c1cf303f89348ee61a8007e4.tar.xz
greatoffice-bab0072e5cf709e6c1cf303f89348ee61a8007e4.zip
feat: Add basic profile administration
-rw-r--r--apps/portal/src/app/pages/profile/index.svelte159
1 files changed, 155 insertions, 4 deletions
diff --git a/apps/portal/src/app/pages/profile/index.svelte b/apps/portal/src/app/pages/profile/index.svelte
index 0929c3c..00942ac 100644
--- a/apps/portal/src/app/pages/profile/index.svelte
+++ b/apps/portal/src/app/pages/profile/index.svelte
@@ -1,7 +1,90 @@
<script>
- import {push} from "svelte-spa-router";
- import {Bread, Crumb} from "$shared/components/breadcrumb/index";
- import Layout from "$app/pages/_layout@loggedin.svelte";
+ import {push} from "svelte-spa-router";
+ import {Bread, Crumb} from "$shared/components/breadcrumb/index";
+ import Layout from "$app/pages/_layout@loggedin.svelte";
+ import {update_profile} from "$shared/lib/api/user";
+ import Alert from "$shared/components/alert.svelte";
+ import Button from "$shared/components/button.svelte";
+ import {is_email} from "$shared/lib/helpers";
+ import {api_base} from "$shared/lib/configuration";
+ import {get_session_data} from "$shared/lib/session";
+
+ const archiveLink = api_base("_/api/account/archive");
+
+ let modal;
+ let understands = false;
+
+ let formIsLoading = false;
+ let formError;
+
+ let username = get_session_data()?.profile.username;
+ let usernameFieldMessage;
+ let usernameFieldMessageClass = "color-error";
+
+ let password;
+ let passwordFieldMessage;
+ let passwordFieldMessageClass = "color-error";
+
+ async function submit_form(e) {
+ e.preventDefault();
+ if (!username && !password) {
+ console.error("Not submitting because both values is empty");
+ return;
+ }
+
+ usernameFieldMessage = "";
+ passwordFieldMessage = "";
+
+ if (username && !is_email(username)) {
+ usernameFieldMessage = "Username has to be a valid email";
+ return;
+ }
+
+ if (password && password?.length < 6) {
+ passwordFieldMessage = "The new password must contain at least 6 characters";
+ return;
+ }
+
+ formIsLoading = true;
+
+ const response = await update_profile({
+ username,
+ password,
+ });
+
+ formIsLoading = false;
+
+ if (response.ok) {
+ if (password) {
+ passwordFieldMessage = "Successfully updated";
+ passwordFieldMessageClass = "color-success";
+ password = "";
+ }
+ if (username) {
+ usernameFieldMessage = "Successfully updated";
+ usernameFieldMessageClass = "color-success";
+ password = "";
+ }
+ } else {
+ formError = response.data.title ?? "An unknown error occured";
+ }
+ }
+
+ async function handle_delete_account_button_click() {
+ alert("Not implemented");
+ return;
+ if (understands && confirm("Are you absolutely sure that you want to delete your account?")) {
+ }
+ }
+
+ export const functions = {
+ open() {
+ modal.open();
+ },
+ close() {
+ // modal.close();
+ },
+ };
</script>
<Layout>
@@ -12,5 +95,73 @@
on:click={() => push("/")}/>
<Crumb name="Profile"/>
</Bread>
- <h1>Profile</h1>
+
+ <main class="max-width-sm">
+ <section class="margin-bottom-md">
+ <p class="text-md margin-bottom-sm">Update your information</p>
+ <form on:submit={submit_form}
+ autocomplete="new-password">
+ {#if formError}
+ <small class="color-danger">{formError}</small>
+ {/if}
+ <div class="margin-bottom-sm">
+ <label for="email"
+ class="form-label margin-bottom-xxs">New username</label>
+ <input type="email"
+ class="form-control width-100%"
+ id="email"
+ placeholder={username}
+ bind:value={username}/>
+ {#if usernameFieldMessage}
+ <small class={usernameFieldMessageClass}>{usernameFieldMessage}</small>
+ {/if}
+ </div>
+ <div class="margin-bottom-sm">
+ <label for="password"
+ class="form-label margin-bottom-xxs">New password</label>
+ <input type="password"
+ class="form-control width-100%"
+ id="password"
+ bind:value={password}/>
+ {#if passwordFieldMessage}
+ <small class={passwordFieldMessageClass}>{passwordFieldMessage}</small>
+ {/if}
+ </div>
+ <div class="flex justify-end">
+ <Button text="Save"
+ on:click={submit_form}
+ variant="primary"
+ loading={formIsLoading}/>
+ </div>
+ </form>
+ </section>
+ <section class="margin-bottom-md">
+ <p class="text-md margin-bottom-sm">Download your data</p>
+ <a class="btn btn--subtle"
+ href={archiveLink}
+ download>Click here to download your data</a>
+ </section>
+ <section>
+ <p class="text-md margin-bottom-sm">Delete account</p>
+ <div class="margin-bottom-sm">
+ <Alert
+ message="Deleting your account and data means that all of your data (entries, categories, etc.) will be unrecoverable forever.<br>You should probably download your data before continuing."
+ type="info"
+ />
+ </div>
+ <div class="form-check margin-bottom-sm">
+ <input type="checkbox"
+ class="checkbox"
+ id="the-consequences"
+ bind:checked={understands}/>
+ <label for="the-consequences">I understand the consequences of deleting my account and data.</label>
+ </div>
+ <div class="flex justify-end">
+ <Button text="Delete everything"
+ variant="accent"
+ disabled={!understands}
+ on:click={handle_delete_account_button_click}/>
+ </div>
+ </section>
+ </main>
</Layout>