diff options
| author | ivarlovlie <git@ivarlovlie.no> | 2022-08-05 13:00:16 +0200 |
|---|---|---|
| committer | ivarlovlie <git@ivarlovlie.no> | 2022-08-05 13:00:16 +0200 |
| commit | fae5653b9d6c6a318e49217eb4d565252013a904 (patch) | |
| tree | b7bc9c656e0b26fc6289a16a2357462c85e285e1 /apps/portal/src/app | |
| parent | 6187962d0aad866edc7cd4ef3f2b828fa84ce670 (diff) | |
| parent | 7f4545d78d4e49ff0dee79e71b71ad7d5d6bacdc (diff) | |
| download | greatoffice-fae5653b9d6c6a318e49217eb4d565252013a904.tar.xz greatoffice-fae5653b9d6c6a318e49217eb4d565252013a904.zip | |
Merge branch 'tailwind'
Diffstat (limited to 'apps/portal/src/app')
| -rw-r--r-- | apps/portal/src/app/index.scss | 1 | ||||
| -rw-r--r-- | apps/portal/src/app/pages/_layout@loggedin.svelte | 15 | ||||
| -rw-r--r-- | apps/portal/src/app/pages/profile/index.svelte | 159 |
3 files changed, 166 insertions, 9 deletions
diff --git a/apps/portal/src/app/index.scss b/apps/portal/src/app/index.scss index 8633a7d..718adf2 100644 --- a/apps/portal/src/app/index.scss +++ b/apps/portal/src/app/index.scss @@ -24,3 +24,4 @@ @use '../../web-shared/src/styles/components/auto-sized-grid'; @use '../../web-shared/src/styles/components/menu'; @use '../../web-shared/src/styles/components/user-menu'; +@use '../../web-shared/src/styles/components/breadcrumbs'; diff --git a/apps/portal/src/app/pages/_layout@loggedin.svelte b/apps/portal/src/app/pages/_layout@loggedin.svelte index ea56f73..44e2e4a 100644 --- a/apps/portal/src/app/pages/_layout@loggedin.svelte +++ b/apps/portal/src/app/pages/_layout@loggedin.svelte @@ -1,7 +1,7 @@ <script> import BlowoutToolbelt from "$shared/components/blowout-toolbelt.svelte"; - import UserMenu from "$app/components/user-menu.svelte"; - import {get_session_data} from "$shared/lib/session"; + import {end_session, get_session_data} from "$shared/lib/session"; + import {replace} from "svelte-spa-router"; const session = get_session_data(); </script> @@ -30,15 +30,20 @@ height: auto; } </style> - <BlowoutToolbelt/> <main class="container max-width-xl padding-x-xs padding-x-xxl@xs padding-y-md padding-y-lg@md"> <div class="z-index-2 position-relative"> <slot/> </div> - <div class="flex flex-row gap-xs position-fixed right-0 top-0 margin-md z-index-2"> - <UserMenu name="{session?.profile?.username}"/> + <div class="flex flex-row gap-xs position-fixed left-0 top-0 margin-md z-index-2"> + <span on:click={async () => { + if (confirm("Are you sure?")) await end_session(() => { + replace("/login"); + }) + }} class="btn btn--sm"> + Logout + </span> </div> <figure id="decoration" 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> |
