diff options
| author | ivarlovlie <git@ivarlovlie.no> | 2022-09-20 09:24:27 +0200 |
|---|---|---|
| committer | ivarlovlie <git@ivarlovlie.no> | 2022-09-20 09:24:27 +0200 |
| commit | a9072370ca1eb9a5cce928b1d487db0f307edea6 (patch) | |
| tree | 59c3c23df930a8b5f888dc7813923abf4ceefed4 /apps/portal/src/app | |
| parent | 56fa963a1d63cbe0bf28e29e717cceaa417c45c1 (diff) | |
| download | greatoffice-a9072370ca1eb9a5cce928b1d487db0f307edea6.tar.xz greatoffice-a9072370ca1eb9a5cce928b1d487db0f307edea6.zip | |
feat: Move old apps into it's own directory
Diffstat (limited to 'apps/portal/src/app')
| -rw-r--r-- | apps/portal/src/app/components/user-menu.svelte | 70 | ||||
| -rw-r--r-- | apps/portal/src/app/index.d.ts | 48 | ||||
| -rw-r--r-- | apps/portal/src/app/index.scss | 27 | ||||
| -rw-r--r-- | apps/portal/src/app/index.svelte | 87 | ||||
| -rw-r--r-- | apps/portal/src/app/index.ts | 14 | ||||
| -rw-r--r-- | apps/portal/src/app/pages/_layout.svelte | 62 | ||||
| -rw-r--r-- | apps/portal/src/app/pages/_layout@loggedin.svelte | 75 | ||||
| -rw-r--r-- | apps/portal/src/app/pages/admin/index.svelte | 18 | ||||
| -rw-r--r-- | apps/portal/src/app/pages/forgot.svelte | 102 | ||||
| -rw-r--r-- | apps/portal/src/app/pages/home.svelte | 103 | ||||
| -rw-r--r-- | apps/portal/src/app/pages/login.svelte | 142 | ||||
| -rw-r--r-- | apps/portal/src/app/pages/profile/index.svelte | 167 | ||||
| -rw-r--r-- | apps/portal/src/app/pages/reset-password.svelte | 138 | ||||
| -rw-r--r-- | apps/portal/src/app/pages/sign-up.svelte | 131 |
14 files changed, 0 insertions, 1184 deletions
diff --git a/apps/portal/src/app/components/user-menu.svelte b/apps/portal/src/app/components/user-menu.svelte deleted file mode 100644 index b0cfc8a..0000000 --- a/apps/portal/src/app/components/user-menu.svelte +++ /dev/null @@ -1,70 +0,0 @@ -<script> - import {end_session} from "$shared/lib/session"; - import {onMount} from "svelte"; - import {Menu, MenuItem, MenuItemSeparator} from "$shared/components/menu"; - import {replace} from "svelte-spa-router"; - - let userMenuTrigger; - let showUserMenu = false; - - export let avatar = ""; - export let name; - export let secondary = ""; - let userMenuId; - - async function on_logout() { - await end_session(() => { - replace("/login"); - }); - } - - onMount(() => { - userMenuTrigger = document.getElementById("open-user-menu"); - }); -</script> - -<button class="reset user-menu-control" - id="open-user-menu" - aria-controls="{userMenuId}" - on:click={() => showUserMenu = true}> - {#if avatar} - <figure class="user-menu-control__img-wrapper radius-50%"> - <img class="user-menu-control__img" - src="{avatar}" - alt="Avatar"> - </figure> - {/if} - - <div class="margin-x-xs user-menu__meta"> - <p class="user-menu__meta-title text-sm line-height-1 padding-y-xxxxs font-semibold color-contrast-higher text-truncate">{name}</p> - {#if secondary} - <p class="text-xs color-contrast-medium line-height-1 padding-bottom-xxxxs">{secondary}</p> - {/if} - </div> - - <svg class="icon icon--xxs" - aria-hidden="true" - viewBox="0 0 12 12"> - <polyline points="1 4 6 9 11 4" - fill="none" - stroke="currentColor" - stroke-linecap="round" - stroke-linejoin="round" - stroke-width="2"/> - </svg> -</button> - -<Menu trigger={userMenuTrigger} - bind:id={userMenuId} - bind:show="{showUserMenu}"> - <div slot="options"> - <MenuItem on:click={() => replace("/profile")}> - <span>Profile</span> - </MenuItem> - <MenuItemSeparator/> - <MenuItem danger="true" - on:click={() => on_logout()}> - Logout - </MenuItem> - </div> -</Menu> diff --git a/apps/portal/src/app/index.d.ts b/apps/portal/src/app/index.d.ts deleted file mode 100644 index c044583..0000000 --- a/apps/portal/src/app/index.d.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* Use this file to declare any custom file extensions for importing */ -/* Use this folder to also add/extend a package d.ts file, if needed. */ - -/* CSS MODULES */ -declare module "*.module.css" { - const classes: { [key: string]: string }; - export default classes; -} -declare module "*.module.scss" { - const classes: { [key: string]: string }; - export default classes; -} - -/* CSS */ -declare module "*.css"; -declare module "*.scss"; - -/* IMAGES */ -declare module "*.svg" { - const ref: string; - export default ref; -} -declare module "*.bmp" { - const ref: string; - export default ref; -} -declare module "*.gif" { - const ref: string; - export default ref; -} -declare module "*.jpg" { - const ref: string; - export default ref; -} -declare module "*.jpeg" { - const ref: string; - export default ref; -} -declare module "*.png" { - const ref: string; - export default ref; -} - -/* CUSTOM: ADD YOUR OWN HERE */ -declare module "*.svelte" { - const value: any; - export default value; -} diff --git a/apps/portal/src/app/index.scss b/apps/portal/src/app/index.scss deleted file mode 100644 index 718adf2..0000000 --- a/apps/portal/src/app/index.scss +++ /dev/null @@ -1,27 +0,0 @@ -@use '../../web-shared/src/styles/base'as * with ($breakpoints: ('xs': "768px", - 'sm': "768px", - 'md': "1200px", - 'lg': "1200px", - 'xl': "1600px", - ), - $grid-columns: 12); - -@use '../../web-shared/src/styles/custom-style/colors'; -@use '../../web-shared/src/styles/custom-style/spacing'; -@use '../../web-shared/src/styles/custom-style/shared-styles'; -@use '../../web-shared/src/styles/custom-style/typography'; -@use '../../web-shared/src/styles/custom-style/icons'; -@use '../../web-shared/src/styles/custom-style/buttons'; -@use '../../web-shared/src/styles/custom-style/forms'; -@use '../../web-shared/src/styles/custom-style/util'; - -@use '../../web-shared/src/styles/components/radios-checkboxes'; -@use '../../web-shared/src/styles/components/btn-states'; -@use '../../web-shared/src/styles/components/alert'; -@use '../../web-shared/src/styles/components/details'; -@use '../../web-shared/src/styles/components/light-dark-switch'; -@use '../../web-shared/src/styles/components/link-card'; -@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/index.svelte b/apps/portal/src/app/index.svelte deleted file mode 100644 index af2b6d0..0000000 --- a/apps/portal/src/app/index.svelte +++ /dev/null @@ -1,87 +0,0 @@ -<svelte:options immutable={true}/> -<svelte:window bind:online={online}/> - -<script> - import Router, {replace} from "svelte-spa-router"; - import {wrap} from "svelte-spa-router/wrap"; - import {is_active} from "$shared/lib/session"; - import SignUp from "$app/pages/sign-up.svelte"; - import Login from "$app/pages/login.svelte"; - import Forgot from "$app/pages/forgot.svelte"; - import Reset from "$app/pages/reset-password.svelte"; - import Home from "$app/pages/home.svelte"; - import ProfileHome from "$app/pages/profile/index.svelte"; - import AdminHome from "$app/pages/admin/index.svelte"; - import PreHeader from "$shared/components/pre-header.svelte"; - - let online = true; - - const publicRoutes = ["/login", "/signup", "/reset-password", "/forgot"]; - const guardedRoutes = ["/", "/home", "/profile", "/admin"]; - - async function user_is_logged_in(event) { - const isActive = await is_active(); - if (!isActive && !publicRoutes.includes(event.route)) { - return false; - } - if (isActive && !guardedRoutes.includes(event.route)) { - await replace("/"); - } - return true; - } - - function route_guarded(event) { - if (!publicRoutes.includes(event.detail.route)) { - replace("/login"); - } - } - - const routes = { - "/login": wrap({ - component: Login, - conditions: [user_is_logged_in], - }), - "/home": wrap({ - component: Home, - conditions: [user_is_logged_in], - }), - "/admin": wrap({ - component: AdminHome, - conditions: [user_is_logged_in], - }), - "/profile": wrap({ - component: ProfileHome, - conditions: [user_is_logged_in], - }), - "/": wrap({ - component: Home, - conditions: [user_is_logged_in], - }), - "/signup": wrap({ - component: SignUp, - conditions: [user_is_logged_in], - }), - "/reset-password": wrap({ - component: Reset, - conditions: [user_is_logged_in], - }), - "/forgot": wrap({ - component: Forgot, - conditions: [user_is_logged_in], - }) - }; -</script> - -<PreHeader show="{!online}">You seem to be offline, please check your internet connection.</PreHeader> - -<Router - {routes} - restoreScrollState={true} - on:conditionsFailed={route_guarded} - on:routeLoading={() => { - document.getElementById("loader").style.display = "inline-block"; - }} - on:routeLoaded={() => { - document.getElementById("loader").style.display = "none"; - }} -/> diff --git a/apps/portal/src/app/index.ts b/apps/portal/src/app/index.ts deleted file mode 100644 index 0bfb30d..0000000 --- a/apps/portal/src/app/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import App from "./index.svelte"; -import "./index.scss"; -import {is_debug, is_development} from "$shared/lib/configuration"; -import {noop} from "$shared/lib/helpers"; - -if (!is_development() && !is_debug()) { - console.log("%c Production; Suppressing logs", "background-color:yellow;color:black;font-size:18px;"); - console.log = noop; -} - -// @ts-ignore -export default new App({ - target: document.getElementById("root"), -}); diff --git a/apps/portal/src/app/pages/_layout.svelte b/apps/portal/src/app/pages/_layout.svelte deleted file mode 100644 index 8c75cb9..0000000 --- a/apps/portal/src/app/pages/_layout.svelte +++ /dev/null @@ -1,62 +0,0 @@ -<script> - import BlowoutToolbelt from "$shared/components/blowout-toolbelt.svelte"; -</script> - -<style> - #decoration { - position: absolute; - top: 0; - left: 0; - pointer-events: none; - width: 100%; - height: 100%; - overflow: hidden; - z-index: 1; - } - - #decoration svg { - position: absolute; - top: 0; - left: 50%; - -webkit-transform: translateX(-50%); - transform: translateX(-50%); - width: 134%; - min-width: 1280px; - max-width: 1920px; - height: auto; - } -</style> -<BlowoutToolbelt/> - -<main class="container-fluid padding-x-xs padding-x-xxl@xs padding-y-md padding-y-lg@md max-width-sm"> - <div class="z-index-2 position-relative"> - <slot/> - </div> - - <figure id="decoration" - class="z-index-1" - aria-hidden="true"> - <svg class="color-contrast-higher opacity-10%" - viewBox="0 0 1920 450" - fill="none"> - <g stroke="currentColor" - stroke-width="2" - stroke-linejoin="round" - stroke-linecap="round"> - <path d="M1449 94.9993V3L1354 48.9995L1259 3V94.9993L1354 140.999L1449 94.9993Z"/> - <path d="M1639 94.9993V3L1544 48.9995L1449 3V94.9993L1544 140.999L1639 94.9993Z"/> - <path d="M1354 49.0002V141"/> - <path d="M1544 49.0002V141"/> - <path d="M1449 94.9995L1544 140.999L1449 186.999L1354 140.999L1449 94.9995Z"/> - <path d="M1544 141V232.999L1449 278.999L1354 232.999V141"/> - <path d="M1449 187V279"/> - <path d="M1544 264L1639 310L1544 355.999L1449 310L1544 264Z"/> - <path d="M1639 310V402L1544 447.999L1449 402V310"/> - <path d="M1544 356.001V448"/> - <path d="M1639 94.9995L1734 140.999L1639 186.999L1544 140.999L1639 94.9995Z"/> - <path d="M1734 141V232.999L1639 278.999L1544 232.999V141"/> - <path d="M1639 187V279"/> - </g> - </svg> - </figure> -</main> diff --git a/apps/portal/src/app/pages/_layout@loggedin.svelte b/apps/portal/src/app/pages/_layout@loggedin.svelte deleted file mode 100644 index 44e2e4a..0000000 --- a/apps/portal/src/app/pages/_layout@loggedin.svelte +++ /dev/null @@ -1,75 +0,0 @@ -<script> - import BlowoutToolbelt from "$shared/components/blowout-toolbelt.svelte"; - import {end_session, get_session_data} from "$shared/lib/session"; - import {replace} from "svelte-spa-router"; - - const session = get_session_data(); -</script> - -<style> - #decoration { - position: absolute; - top: 0; - left: 0; - pointer-events: none; - width: 100%; - height: 100%; - overflow: hidden; - z-index: 1; - } - - #decoration svg { - position: absolute; - top: 0; - left: 50%; - -webkit-transform: translateX(-50%); - transform: translateX(-50%); - width: 134%; - min-width: 1280px; - max-width: 1920px; - 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 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" - class="z-index-1" - aria-hidden="true"> - <svg class="color-contrast-higher opacity-10%" - viewBox="0 0 1920 450" - fill="none"> - <g stroke="currentColor" - stroke-width="2" - stroke-linejoin="round" - stroke-linecap="round"> - <path d="M1449 94.9993V3L1354 48.9995L1259 3V94.9993L1354 140.999L1449 94.9993Z"/> - <path d="M1639 94.9993V3L1544 48.9995L1449 3V94.9993L1544 140.999L1639 94.9993Z"/> - <path d="M1354 49.0002V141"/> - <path d="M1544 49.0002V141"/> - <path d="M1449 94.9995L1544 140.999L1449 186.999L1354 140.999L1449 94.9995Z"/> - <path d="M1544 141V232.999L1449 278.999L1354 232.999V141"/> - <path d="M1449 187V279"/> - <path d="M1544 264L1639 310L1544 355.999L1449 310L1544 264Z"/> - <path d="M1639 310V402L1544 447.999L1449 402V310"/> - <path d="M1544 356.001V448"/> - <path d="M1639 94.9995L1734 140.999L1639 186.999L1544 140.999L1639 94.9995Z"/> - <path d="M1734 141V232.999L1639 278.999L1544 232.999V141"/> - <path d="M1639 187V279"/> - </g> - </svg> - </figure> -</main> diff --git a/apps/portal/src/app/pages/admin/index.svelte b/apps/portal/src/app/pages/admin/index.svelte deleted file mode 100644 index f9b91d2..0000000 --- a/apps/portal/src/app/pages/admin/index.svelte +++ /dev/null @@ -1,18 +0,0 @@ -<script> - import Layout from "../_layout@loggedin.svelte"; - import {Bread, Crumb} from "$shared/components/breadcrumb"; - import {push} from "svelte-spa-router"; - -</script> - -<Layout> - <Bread> - <Crumb name="Home" - withArrow="true" - isLink="true" - on:click={() => push("/")}/> - <Crumb name="Organisation"/> - </Bread> - - <main class="max-width-sm"></main> -</Layout> diff --git a/apps/portal/src/app/pages/forgot.svelte b/apps/portal/src/app/pages/forgot.svelte deleted file mode 100644 index 156deab..0000000 --- a/apps/portal/src/app/pages/forgot.svelte +++ /dev/null @@ -1,102 +0,0 @@ -<script> - import {onMount} from "svelte"; - import {link} from "svelte-spa-router"; - import {create_forgot_password_request} from "$shared/lib/api/user"; - import {is_email} from "$shared/lib/helpers"; - import Alert from "$shared/components/alert.svelte"; - import Button from "$shared/components/button.svelte"; - import Tile from "$shared/components/tile.svelte"; - import Layout from "./_layout.svelte"; - - let isLoading = false; - let username; - - const alert = { - title: "", - type: "", - message: "", - isVisible: false, - show(type, obj) { - alert.title = obj.title; - alert.message = obj.text; - alert.type = type; - alert.isVisible = true; - isLoading = false; - }, - hide() { - alert.isVisible = false; - alert.title = ""; - alert.message = ""; - alert.type = ""; - isLoading = false; - }, - }; - - function is_valid() { - return is_email(username); - } - - async function submit_form() { - if (isLoading) { - return; - } - if (is_valid()) { - isLoading = true; - const response = await create_forgot_password_request(username); - if (response.ok) { - alert.show("success", { - title: "Request is sent", - text: "If we find an account associated with this email address, you will receive an email with a reset link very soon.", - }); - } else { - console.error(response.data); - alert.show("error", { - title: response.data?.title ?? "An error occured", - text: response.data?.text ?? "Please try again soon", - }); - } - } - } - - onMount(() => { - document.addEventListener("DOMContentLoaded", () => { - document.getElementById("email-address").focus(); - }); - }); -</script> - -<Layout> - <Tile> - <form on:submit|preventDefault={submit_form} - class="max-width-xxs"> - <fieldset> - <legend class="form-legend"> - <span class="margin-bottom-xs text-xl">Send reset link</span> <br/> - <span class="text-sm">... or <a href="/login" - use:link>log in</a></span> - </legend> - <div class="margin-bottom-xs"> - <p>Provide your email address, and we'll send you a link to set your new password.</p> - </div> - <div class="margin-bottom-xxs max-width-xxs"> - <Alert visible={alert.isVisible} - title={alert.title} - message={alert.message} - type={alert.type}/> - </div> - <div class="margin-bottom-xs"> - <input type="email" - id="email-address" - placeholder="Email address" - class="form-control width-100%" - bind:value={username}/> - </div> - <div class="flex justify-end"> - <Button text="Send reset link" - type="primary" - loading={isLoading}/> - </div> - </fieldset> - </form> - </Tile> -</Layout> diff --git a/apps/portal/src/app/pages/home.svelte b/apps/portal/src/app/pages/home.svelte deleted file mode 100644 index 0e325ee..0000000 --- a/apps/portal/src/app/pages/home.svelte +++ /dev/null @@ -1,103 +0,0 @@ -<script> - import {projects_base} from "$shared/lib/configuration"; - import {get_session_data} from "$shared/lib/session"; - import {push} from "svelte-spa-router"; - import Layout from "./_layout@loggedin.svelte"; - import LinkCard from "$shared/components/link-card.svelte"; - import Alert from "$shared/components/alert.svelte"; - import {UserIcon, UsersIcon, WatchIcon, SendIcon, ListIcon} from "svelte-feather-icons"; - - let showUsers = true; - const session = get_session_data(); -</script> - -<Layout> - <div class="grid gap-md"> - <div class="row"> - <Alert closeable="true" - closeableCooldown="~" - id="welcome-note" - title="Hello {session.profile?.username}" - message="This is your portal to Greatoffice, here you will find all your great apps and management options."/> - </div> - <div class="row"> - <h2 class="margin-bottom-xs">Apps</h2> - <div class="grid-auto-md gap-sm"> - <LinkCard name="Projects" - description="The home for your projects" - text="Open in a new tab" - title="Open Projects" - href="{projects_base()}"> - <figure slot="icon"> - <div class="bg-primary bg-opacity-10% padding-xs border-left border-primary border-2"> - <WatchIcon size="42" - class="color-primary" - strokeWidth="1.2"/> - </div> - </figure> - </LinkCard> - <LinkCard name="Tickets" - description="The home for your tickets" - class="c-disabled user-select-none" - text="Coming soon" - title="Open Tickets" - href="{projects_base()}"> - <figure slot="icon"> - <div class="bg-primary bg-opacity-10% padding-xs border-left border-primary border-2"> - <SendIcon size="42" - class="color-primary" - strokeWidth="1.2"/> - </div> - </figure> - </LinkCard> - <LinkCard name="Todo" - description="The home for your todos" - class="c-disabled user-select-none" - text="Coming soon" - title="Open Todo" - href="{projects_base()}"> - <figure slot="icon"> - <div class="bg-primary bg-opacity-10% padding-xs border-left border-primary border-2"> - <ListIcon size="42" - class="color-primary" - strokeWidth="1.2"/> - </div> - </figure> - </LinkCard> - </div> - </div> - <div class="row"> - <h2 class="margin-bottom-xs">Manage</h2> - <div class="grid-auto-md gap-sm"> - <LinkCard name="Profile" - description="Manage your profile" - text="Open" - title="Go to your profile management page" - on:click={() => push("/profile")}> - <figure slot="icon"> - <div class="bg-primary bg-opacity-10% padding-xs border-left border-primary border-2"> - <UserIcon size="42" - class="color-primary" - strokeWidth="1.2"/> - </div> - </figure> - </LinkCard> - {#if showUsers} - <LinkCard name="Organisation" - description="Manage your organisation" - title="Go to your organisations management page" - text="Open" - on:click={() => push("/admin")}> - <figure slot="icon"> - <div class="bg-primary bg-opacity-10% padding-xs border-left border-primary border-2"> - <UsersIcon size="42" - class="color-primary" - strokeWidth="1.2"/> - </div> - </figure> - </LinkCard> - {/if} - </div> - </div> - </div> -</Layout> diff --git a/apps/portal/src/app/pages/login.svelte b/apps/portal/src/app/pages/login.svelte deleted file mode 100644 index 1ca6b61..0000000 --- a/apps/portal/src/app/pages/login.svelte +++ /dev/null @@ -1,142 +0,0 @@ -<script> - import {onMount} from "svelte"; - import {link, replace, querystring} from "svelte-spa-router"; - import {api_base, IconNames, frontpage_base} from "$shared/lib/configuration"; - import Button from "$shared/components/button.svelte"; - import Alert from "$shared/components/alert.svelte"; - import Tile from "$shared/components/tile.svelte"; - import {login} from "$shared/lib/api/user"; - import {is_email} from "$shared/lib/helpers"; - import Layout from "./_layout.svelte"; - - const loginForm = { - loading: false, - values: { - username: "", - password: "", - persist: true - }, - alert: { - title: "", - type: "", - message: "", - isVisible: false, - show(type, obj) { - loginForm.alert.title = obj.title; - loginForm.alert.message = obj.text; - loginForm.alert.type = type; - loginForm.alert.isVisible = true; - loginForm.loading = false; - }, - hide() { - loginForm.alert.isVisible = false; - loginForm.alert.title = ""; - loginForm.alert.message = ""; - loginForm.alert.type = ""; - }, - }, - is_valid() { - return is_email(loginForm.values.username) && loginForm.values.password.length > 0; - }, - async submit_form() { - if (loginForm.loading) { - return; - } - if (loginForm.is_valid()) { - loginForm.alert.hide(); - loginForm.loading = true; - try { - const response = await login(loginForm.values); - if (response.ok) { - await replace("#/home"); - } else { - if (response.data.title || response.data.text) { - loginForm.alert.show("error", { - title: response.data.title ?? "", - text: response.data.text ?? "", - }); - } else { - loginForm.alert.show("error", { - title: "An unknown error occured", - text: "Try again soon", - }); - } - } - } catch (e) { - loginForm.alert.show("error", { - title: "An error occured", - text: "Could not connect to server, please check your internet connection", - }); - } - } else { - loginForm.alert.show("error", { - title: "Invalid form", - }); - } - }, - }; - - onMount(() => { - if ($querystring === "deleted") { - loginForm.alert.show("info", { - title: "Account deleted", - text: "Your account and all its data was successfully deleted.", - }); - } - if ($querystring === "expired") { - loginForm.alert.show("info", { - title: "Session expired", - text: "Your session has expired, feel free to log in again.", - }); - } - }); -</script> - -<Layout> - <a href="{frontpage_base()}" class="block margin-bottom-xs">Go to {frontpage_base()}</a> - <Tile> - <form on:submit|preventDefault={loginForm.submit_form} - class="max-width-xxs"> - <fieldset> - <legend class="form-legend"> - <span class="margin-bottom-xs text-xl">Log into your account</span> - <br/> - <span class="text-sm">... or <a href="/signup" - use:link>create a new one</a></span> - </legend> - <div class="margin-bottom-xxs max-width-xxs"> - <Alert visible={loginForm.alert.isVisible} - title={loginForm.alert.title} - message={loginForm.alert.message} - type={loginForm.alert.type}/> - </div> - <div class="margin-bottom-xxs"> - <input type="email" - placeholder="Email address" - class="form-control width-100%" - id="username" - bind:value={loginForm.values.username}/> - </div> - <div class="margin-bottom-xxs"> - <input type="password" - placeholder="Password" - id="password" - class="form-control width-100%" - bind:value={loginForm.values.password}/> - <div class="flex justify-end"> - <a tabindex="-1" - class="text-sm" - href="/forgot" - use:link>Reset password</a> - </div> - </div> - <div class="flex justify-between"> - <Button text="Login" - type="submit" - variant="primary" - loading={loginForm.loading}/> - </div> - </fieldset> - </form> - </Tile> -</Layout> diff --git a/apps/portal/src/app/pages/profile/index.svelte b/apps/portal/src/app/pages/profile/index.svelte deleted file mode 100644 index a7291d6..0000000 --- a/apps/portal/src/app/pages/profile/index.svelte +++ /dev/null @@ -1,167 +0,0 @@ -<script> - 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("_/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> - <Bread> - <Crumb name="Home" - withArrow="true" - isLink="true" - on:click={() => push("/")}/> - <Crumb name="Profile"/> - </Bread> - - <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> diff --git a/apps/portal/src/app/pages/reset-password.svelte b/apps/portal/src/app/pages/reset-password.svelte deleted file mode 100644 index dabf5c9..0000000 --- a/apps/portal/src/app/pages/reset-password.svelte +++ /dev/null @@ -1,138 +0,0 @@ -<script> - import {querystring, link} from "svelte-spa-router"; - import {check_forgot_password_request, fulfill_forgot_password_request} from "$shared/lib/api/user"; - import Alert from "$shared/components/alert.svelte"; - import Button from "$shared/components/button.svelte"; - import Tile from "$shared/components/tile.svelte"; - import Layout from "./_layout.svelte"; - - const requestId = new URLSearchParams($querystring).get("id"); - let isLoading = false; - let newPassword; - let newPasswordError; - let alert = { - title: "", - type: "", - message: "", - isVisible: false, - show(type, obj) { - alert.title = obj.title; - alert.message = obj.text; - alert.type = type; - alert.isVisible = true; - isLoading = false; - }, - hide() { - alert.isVisible = false; - alert.title = ""; - alert.message = ""; - alert.type = ""; - isLoading = false; - }, - }; - - function is_valid() { - let isValid = true; - if (!newPassword.length > 5) { - newPasswordError = "The new password must be at least 5 characters"; - isValid = false; - } - return isValid; - } - - async function submit() { - if (isLoading) { - return; - } - if (is_valid()) { - isLoading = true; - const response = await fulfill_forgot_password_request(requestId, newPassword); - if (response.ok) { - alert.show("success", { - title: "Your new password is set", - text: "<a href='/#/login'>Click here to log in</a>", - }); - } else { - console.error(response.data); - alert.show("error", { - title: response.data?.title ?? "An error occured", - text: response.data?.text ?? "Please try again soon", - }); - } - } - } - - async function is_valid_password_reset_request() { - const response = await check_forgot_password_request(requestId); - if (response.ok) { - return response.data === true; - } - return false; - } -</script> - -<Layout> - <Tile> - <form on:submit|preventDefault={submit} - class="max-width-xxs {isLoading ? 'c-disabled loading' : ''}"> - {#if requestId} - {#await is_valid_password_reset_request()} - <p>Checking your request...</p> - <a href="/login" - use:link>cancel</a> - {:then isActive} - {#if isActive === true} - <fieldset> - <legend class="form-legend"> - <span class="margin-bottom-xs text-xl">Set your new password</span> <br/> - <span class="text-sm"> - ... or - <a href="/login" - use:link> log in </a> - </span> - </legend> - <div class="margin-bottom-xxs max-width-xxs"> - <Alert visible={alert.isVisible} - title={alert.title} - message={alert.message} - type={alert.type}/> - </div> - <div class="margin-bottom-xs"> - <input - type="password" - id="new-password" - placeholder="New password" - class="form-control width-100%" - bind:value={newPassword} - /> - {#if newPasswordError} - <small class="color-danger">{newPasswordError}</small> - {/if} - </div> - <div class="flex justify-end"> - <Button text="Set new password" - type="primary" - loading={isLoading} - on:click={submit}/> - </div> - </fieldset> - {:else} - <Alert title="This request is expired" - message="Please submit the forgot password form again" - type="warning"/> - <div class="flex justify-between width-100% margin-y-sm"> - <a href="/forgot" - use:link>Go to forgot form</a> - <a href="/login" - use:link>Go to login form</a> - </div> - {/if} - {:catch _} - <Alert title="An error occured" - message="Please try again soon" - type="error"/> - {/await} - {/if} - </form> - </Tile> -</Layout> diff --git a/apps/portal/src/app/pages/sign-up.svelte b/apps/portal/src/app/pages/sign-up.svelte deleted file mode 100644 index 3bcab6d..0000000 --- a/apps/portal/src/app/pages/sign-up.svelte +++ /dev/null @@ -1,131 +0,0 @@ -<script> - import {create_account} from "$shared/lib/api/user"; - import {frontpage_base} from "$shared/lib/configuration"; - import {is_email} from "$shared/lib/helpers"; - import Alert from "$shared/components/alert.svelte"; - import Button from "$shared/components/button.svelte"; - import Tile from "$shared/components/tile.svelte"; - import {link} from "svelte-spa-router"; - import Layout from "./_layout.svelte"; - - const signupForm = { - loading: false, - values: { - username: "", - password: "", - }, - alert: { - title: "", - type: "", - message: "", - isVisible: false, - show(type, obj) { - signupForm.alert.title = obj.title; - signupForm.alert.message = obj.text; - signupForm.alert.type = type; - signupForm.alert.isVisible = true; - signupForm.loading = false; - }, - hide() { - signupForm.alert.isVisible = false; - signupForm.alert.title = ""; - signupForm.alert.message = ""; - signupForm.alert.type = ""; - }, - }, - is_valid() { - return ( - is_email(signupForm.values.username) && - signupForm.values.password.length > 0 - ); - }, - async submit_form() { - if (signupForm.loading) { - return; - } - if (signupForm.is_valid()) { - signupForm.alert.hide(); - signupForm.loading = true; - try { - const response = await create_account(signupForm.values); - if (response.ok) { - location.reload(); - } else { - if (response.data.title || response.data.text) { - signupForm.alert.show("error", { - title: response.data.title ?? "", - text: response.data.text ?? "", - }); - } else { - signupForm.alert.show("error", { - title: "An unknown error occured", - text: "Try again soon", - }); - } - } - } catch (e) { - console.error(e); - signupForm.alert.show("error", { - title: "An error occured", - text: "Could not connect to server, please check your internet connection", - }); - } - } else { - signupForm.alert.show("error", { - title: "Invalid form", - }); - } - }, - }; -</script> - -<Layout> - <a href="{frontpage_base()}" - class="block margin-bottom-xs">Go to {frontpage_base()}</a> - <Tile> - <form on:submit|preventDefault={signupForm.submit_form} - class="max-width-xxs"> - <fieldset> - <legend class="form-legend"> - <span class="margin-bottom-xs text-xl">Create your account</span> <br/> - <span class="text-sm" - >... or <a href="/login" - use:link>log in</a></span - > - </legend> - <div class="margin-bottom-xs"> - <p>Provide an email and password to get immediate access to your new environment (30 days full access, no billing details required, no promotion emails).</p> - </div> - <div class="margin-bottom-xxs max-width-xxs"> - <Alert visible={signupForm.alert.isVisible} - title={signupForm.alert.title} - message={signupForm.alert.message} - type={signupForm.alert.type} - /> - </div> - <div class="margin-bottom-xxs"> - <input type="email" - placeholder="Email address" - class="form-control width-100%" - id="email-address" - bind:value={signupForm.values.username} - /> - </div> - <div class="margin-bottom-xxs"> - <input type="password" - placeholder="Password" - class="form-control width-100%" - bind:value={signupForm.values.password} - /> - </div> - <div class="flex justify-end"> - <Button class="margin-bottom-xs" - text="Create account" - type="primary" - loading={signupForm.loading} - /> - </div> - </fieldset> - </form> - </Tile> -</Layout> |
