user panel updates: wallet and account infos

Laurin Weger 3 months ago
parent 87c9925ea9
commit e320e80b79
No known key found for this signature in database
GPG Key ID: 9B372BB0B792770F
  1. 4
      ng-app/src/App.svelte
  2. 389
      ng-app/src/routes/AccountInfo.svelte
  3. 113
      ng-app/src/routes/User.svelte
  4. 1
      ng-app/src/routes/WalletCreate.svelte
  5. 351
      ng-app/src/routes/WalletInfo.svelte
  6. 1
      ng-app/src/routes/WalletLogin.svelte

@ -29,11 +29,13 @@
import WalletCreate from "./routes/WalletCreate.svelte"; import WalletCreate from "./routes/WalletCreate.svelte";
import Invitation from "./routes/Invitation.svelte"; import Invitation from "./routes/Invitation.svelte";
import WalletLogin from "./routes/WalletLogin.svelte"; import WalletLogin from "./routes/WalletLogin.svelte";
import WalletInfo from "./routes/WalletInfo.svelte";
import User from "./routes/User.svelte"; import User from "./routes/User.svelte";
import UserRegistered from "./routes/UserRegistered.svelte"; import UserRegistered from "./routes/UserRegistered.svelte";
import Install from "./lib/Install.svelte"; import Install from "./lib/Install.svelte";
import ng from "./api"; import ng from "./api";
import AccountInfo from "./routes/AccountInfo.svelte";
const routes = new Map(); const routes = new Map();
routes.set("/", Home); routes.set("/", Home);
@ -43,6 +45,8 @@
routes.set("/i/:invitation", Invitation); routes.set("/i/:invitation", Invitation);
routes.set("/user", User); routes.set("/user", User);
routes.set("/user/registered", UserRegistered); routes.set("/user/registered", UserRegistered);
routes.set("/wallet", WalletInfo);
routes.set("/user/account", AccountInfo);
if (import.meta.env.NG_APP_WEB) routes.set("/install", Install); if (import.meta.env.NG_APP_WEB) routes.set("/install", Install);
routes.set(/^\/ng(.*)/i, URI); routes.set(/^\/ng(.*)/i, URI);
routes.set("*", NotFound); routes.set("*", NotFound);

@ -0,0 +1,389 @@
<!--
// Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers
// All rights reserved.
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
-->
<!--
@component
"Account Info" user panel sub menu.
Provides info about wallet, broker, etc. and download option.
-->
<script lang="ts">
import { link, push } from "svelte-spa-router";
import CenteredLayout from "../lib/CenteredLayout.svelte";
import {
ArrowLeft,
DeviceTablet,
GlobeAlt,
ServerStack,
} from "svelte-heros-v2";
import { onMount, tick } from "svelte";
import { Sidebar, SidebarGroup, SidebarWrapper } from "flowbite-svelte";
import {
active_session,
active_wallet,
connections,
reconnect,
} from "../store";
import { default as ng } from "../api";
import { each } from "svelte/internal";
let error;
let nonActiveClass =
"flex items-center p-2 text-base font-normal text-gray-900 rounded-lg dark:text-white hover:bg-gray-200 dark:hover:bg-gray-700";
let top;
async function scrollToTop() {
await tick();
top.scrollIntoView();
}
onMount(async () => {
if (!$active_session) {
push("#/");
} else {
await scrollToTop();
}
});
$: wallet_unlocked = $active_wallet?.wallet?.V0;
$: personal_site_id = wallet_unlocked?.personal_site_id;
/**
* brokers:
ZBY5Y8DTyhMo5xfo5K4FCsJHVaN3O15vKeQBwZxr76YA: [
ServerV0:
can_forward: true
can_verify: false
peer_id: Object { Ed25519PubKey: (32) [] }
server_type: Object {
Domain
Localhost: 1440 // if domain not exist
BoxPrivate // What are they for? rs type Vec<BindAddress>
Public // What are they for? rs type Vec<BindAddress>
BoxPublicDyn // What are they for? rs type Vec<BindAddress>
}
]
*/
/*
* Connections Is a record of string to those objects:
error: undefined
server_id: "ZBY5Y8DTyhMo5xfo5K4FCsJHVaN3O15vKeQBwZxr76YA"
server_ip: "ws://localhost:1440"
since: Date Fri Jul 05 2024 09:46:30 GMT+0200 (Central European Summer Time)
*/
// let connections;
/**
* bootstraps: Array [ {} ]
* cores: Array [ (2) […] ]
* id: Object { Ed25519PubKey: (32) [] }
* name: "Personal"
* private: Object { id: {}, store_type: "Private" }
* protected: Object { id: {}, store_type: "Protected" }
* public: Object { id: {}, store_type: "Public" }
* site_type: Object { Individual: (2) [] } // Some key data as well
*/
$: walletSites = wallet_unlocked?.sites;
/** Type:
* client_type: "Web"
* details: '{"browser":{"name":"Firefox","version":"127.0","appVersion":"5.0 (X11)","arch":"Linux x86_64","vendor":"","ua":"Mozilla/5.0 (X11; Linux x86_64; rv:127.0) Gecko/20100101 Firefox/127.0"},"os":{"name":"Linux"},"platform":{"type":"desktop"},"engine":{"name":"Gecko","version":"20100101","sdk":"0.1.0-preview.1"}}'
* timestamp_install: 0
* timestamp_updated: 0
* version: "0.1.0"
*/
var device_info;
$: display_sites = Object.entries(walletSites || {})
?.map(([user_id, site]) => {
// Try to extract device details (for now only of the connected device).
// TODO: API for all devices
const devices = (!device_info ? [] : [device_info.V0]).map((device) => {
let device_details;
try {
device_details = JSON.parse(device.details);
} catch (ex) {
device_details = device.details;
}
return {
name: device.name, // TODO: API device.name is not provided
peer_id: device.id, // TODO: API device id is is not provided
version: device.version,
details: device_details,
type: device.client_type,
};
});
return {
id: user_id,
name: site.name,
connection: $connections[user_id], // error, server_id, server_ip, since
devices,
};
})
.filter((site) => site.id === personal_site_id);
$: display_brokers = Object.entries(wallet_unlocked?.brokers || {}).map(
([broker_id, [broker]]) => {
return {
id: broker_id,
can_forward: broker.ServerV0.can_forward,
can_verify: broker.ServerV0.can_verify,
address:
broker.ServerV0.server_type.Domain ||
`localhost:${broker.ServerV0.server_type.Localhost}`,
last_connected: new Date("1970-01-01T00:00:00Z").toLocaleString(), // TODO: API
};
}
);
$: console.debug(
"info",
device_info,
"walletSites",
walletSites,
"wallet",
$active_wallet,
"connections",
$connections,
"display_brokers",
display_brokers,
"display_sites",
display_sites
);
onMount(async () => {
ng.client_info().then((res) => {
device_info = res;
});
});
</script>
<CenteredLayout>
<div class="container3" bind:this={top}>
<div class="row mb-20">
<Sidebar {nonActiveClass}>
<SidebarWrapper
divClass="bg-gray-60 overflow-y-auto py-4 px-3 rounded dark:bg-gray-800"
>
<!-- Go Back-->
<SidebarGroup ulClass="space-y-2">
<li>
<h2 class="text-xl mb-6">Account Info</h2>
</li>
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<li
tabindex="0"
class="flex items-center p-2 text-base font-normal text-gray-900 clickable rounded-lg dark:text-white hover:bg-gray-200 dark:hover:bg-gray-700"
on:keypress={() => window.history.go(-1)}
on:click={() => window.history.go(-1)}
>
<ArrowLeft
tabindex="-1"
class="w-7 h-7 text-black transition duration-75 dark:text-white group-hover:text-gray-900 dark:group-hover:text-white"
/>
<span class="ml-3">Back</span>
</li>
</SidebarGroup>
<!-- For now this will only consist of the `Personal` one-->
{#each display_sites as site}
<li
class="flex items-center p-2 text-base font-normal text-gray-900"
>
<h3
class="flex items-center mt-2 text-lg font-normal text-gray-600"
>
{site.name}
</h3>
</li>
<!-- Device Details -->
<SidebarGroup ulClass="space-y-1">
<li
class="flex items-center p-2 text-base font-normal text-gray-900"
>
<h4
class="flex items-center mt-2 text-base font-normal text-gray-600"
>
Devices
</h4>
</li>
{#each site.devices as device, index}
<li
class="flex items-center p-2 text-base font-normal text-gray-900 bg-white shadow-md rounded-lg"
class:border-b={index !== site.devices.length - 1}
>
<div>
{#if device.type == "Web"}
<GlobeAlt
tabindex="-1"
class="w-7 h-7 text-black transition duration-75 dark:text-white group-hover:text-gray-900 dark:group-hover:text-white"
/>
{:else}
<DeviceTablet
tabindex="-1"
class="w-7 h-7 text-black transition duration-75 dark:text-white group-hover:text-gray-900 dark:group-hover:text-white"
/>
{/if}
</div>
<div
class="flex flex-col ml-3 items-start text-left overflow-auto"
>
<div>
<label class="text-gray-500">Name</label>
<span>{device.name}</span>
</div>
<div>
<label class="text-gray-500">Id</label>
<span>{device.peer_id}</span>
</div>
<div>
<label class="text-gray-500">Version</label>
<span>{device.version}</span>
</div>
<div>
<label class="text-gray-500">Device Type</label>
<span>
{`${device.details?.browser?.name} - ${device.details?.browser.arch}`}</span
>
</div>
</div>
</li>
{/each}
</SidebarGroup>
<!-- Broker Details -->
<SidebarGroup ulClass="space-y-1">
<li
class="flex items-center p-2 text-base font-normal text-gray-900"
>
<h4
class="flex items-center mt-2 text-base font-normal text-gray-600"
>
Brokers
</h4>
</li>
{#if display_brokers.length > 0}
{#each Object.values(display_brokers) as broker, index}
<!--
(peerId, IP/port or domain, last time connected)
-->
<li
class="flex items-center p-2 text-base font-normal text-gray-900 bg-white shadow-md rounded-lg"
class:border-b={index !== display_brokers.length - 1}
>
<div>
<ServerStack
tabindex="-1"
class="w-7 h-7 text-black transition duration-75 dark:text-white group-hover:text-gray-900 dark:group-hover:text-white"
/>
</div>
<div
class="flex flex-col ml-3 items-start text-left overflow-auto"
>
<div>
<label class="text-gray-500">Address</label>
<span>{broker.address}</span>
</div>
<div>
<label class="text-gray-500">Last Connected</label>
<span>{broker.last_connected}</span>
</div>
<div>
<label class="text-gray-500">ID</label>
<span>{broker.id}</span>
</div>
<div>
<label class="text-gray-500">Can Forward?</label>
<span>{broker.can_forward}</span>
</div>
<div>
<label class="text-gray-500">Can Verify?</label>
<span>{broker.can_verify}</span>
</div>
</div>
</li>
{/each}
{:else}
<li
class="flex items-center p-2 text-base font-normal text-gray-900"
>
<span class="ml-3">No brokers connected</span>
</li>
{/if}
</SidebarGroup>
{/each}
</SidebarWrapper>
</Sidebar>
</div>
{#if error}
<div class=" max-w-6xl lg:px-8 mx-auto px-4 text-red-800">
<svg
class="animate-bounce mt-10 h-16 w-16 mx-auto"
fill="none"
stroke="currentColor"
stroke-width="1.5"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"
/>
</svg>
{#if error == "AlreadyExists"}
<p class="max-w-xl md:mx-auto lg:max-w-2xl mb-5">
The user is already registered with the selected broker.<br /> Try logging
in instead
</p>
<a use:link href="/">
<button
tabindex="-1"
class="text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-700/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55 mb-2"
>
Login
</button>
</a>
{:else}
<p class="max-w-xl md:mx-auto lg:max-w-2xl mb-5">
An error occurred:<br />{error}
</p>
<a use:link href="/">
<button
tabindex="-1"
class="text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-700/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55 mb-2"
>
Go back to homepage
</button>
</a>
{/if}
</div>
{/if}
</div>
</CenteredLayout>
<style>
li.clickable {
cursor: pointer;
}
.site-cnx-details {
@apply mt-0 !important;
}
</style>

@ -12,7 +12,7 @@
<!-- <!--
@component @component
"User Panel" page. "User Panel" page.
Provides wallet download, logout, offline/online switch, and other user actions. Provides wallet, logout, offline/online switch, and other user actions.
--> -->
<script> <script>
@ -95,30 +95,6 @@
push("#/wallet/login"); push("#/wallet/login");
} }
let downloading = false;
let wallet_file_ready = false;
let download_link = false;
let download_error = false;
async function download_wallet() {
try {
downloading = true;
let file = await ng.wallet_get_file($active_wallet.id);
// @ts-ignore
wallet_file_ready = "wallet-" + $active_wallet.id + ".ngw";
if (!tauri_platform) {
const blob = new Blob([file], {
type: "application/octet-stream",
});
// @ts-ignore
download_link = URL.createObjectURL(blob);
} else {
download_link = true;
}
} catch (e) {
download_error = e;
}
}
$: personal_site = $active_wallet?.wallet?.V0.personal_site_id; $: personal_site = $active_wallet?.wallet?.V0.personal_site_id;
$: personal_site_id = $active_wallet?.wallet?.V0.personal_site; $: personal_site_id = $active_wallet?.wallet?.V0.personal_site;
@ -210,78 +186,13 @@
/> />
<span class="ml-3">Switch wallet</span> <span class="ml-3">Switch wallet</span>
</li> --> </li> -->
{#if !downloading}
<li <SidebarItem
tabindex="0" label="Settings"
role="menuitem" href="#/user/settings"
class="flex items-center p-2 text-base font-normal text-gray-900 clickable rounded-lg dark:text-white hover:bg-gray-200 dark:hover:bg-gray-700" class="p-2 opacity-50 pointer-events-none"
on:keypress={download_wallet} disabled
on:click={download_wallet} >
>
<DocumentArrowDown
tabindex="-1"
class="w-7 h-7 text-black transition duration-75 dark:text-white group-hover:text-gray-900 dark:group-hover:text-white"
/>
<span class="ml-3">Download wallet file</span>
</li>
{:else if download_error}
<li
tabindex="-1"
class="flex items-center p-2 text-base font-normal text-red-700 rounded-lg dark:text-white hover:bg-gray-200 dark:hover:bg-gray-700"
>
<NoSymbol
tabindex="-1"
class="w-7 h-7 text-red-700 transition duration-75 dark:text-white group-hover:text-gray-900 dark:group-hover:text-white"
/>
<span class="ml-3 text-left"
>Download failed:<br /> {download_error}</span
>
</li>
{:else if !wallet_file_ready}
<li
tabindex="-1"
class="flex items-center p-2 text-base font-normal text-blue-700 rounded-lg dark:text-white hover:bg-gray-200 dark:hover:bg-gray-700"
>
<DocumentArrowDown
tabindex="-1"
class="w-7 h-7 text-blue-700 transition duration-75 dark:text-white group-hover:text-gray-900 dark:group-hover:text-white"
/>
<span class="ml-3 text-left">Download in progress...</span>
</li>
{:else if download_link === true}
<li
tabindex="-1"
class="flex p-2 text-sm text-left break-all font-normal text-blue-700 rounded-lg dark:text-white hover:bg-gray-200 dark:hover:bg-gray-700"
>
<span
>You will find the file named "{wallet_file_ready}" <br />in
your Downloads folder</span
>
</li>
{:else}
<li
tabindex="-1"
class="flex items-center text-base font-normal text-gray-900 clickable rounded-lg dark:text-white hover:bg-gray-200 dark:hover:bg-gray-700"
>
<a
href={download_link}
target="_blank"
download={wallet_file_ready}
>
<button
tabindex="-1"
class=" text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-700/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55"
>
<DocumentArrowDown
tabindex="-1"
class="w-14 h-14 transition duration-75 dark:text-white dark:group-hover:text-white"
/>
Click here to download the wallet file
</button>
</a>
</li>
{/if}
<SidebarItem label="Settings" href="#/user/settings" class="p-2">
<svelte:fragment slot="icon"> <svelte:fragment slot="icon">
<Cog6Tooth <Cog6Tooth
tabindex="-1" tabindex="-1"
@ -297,7 +208,11 @@
/> />
</svelte:fragment> </svelte:fragment>
</SidebarItem> </SidebarItem>
<SidebarItem label="Admin" href="#/user/admin" class="p-2"> <SidebarItem
label="Admin"
href="#/user/admin"
class="p-2 opacity-50 pointer-events-none"
>
<svelte:fragment slot="icon"> <svelte:fragment slot="icon">
<Key <Key
tabindex="-1" tabindex="-1"
@ -305,7 +220,7 @@
/> />
</svelte:fragment> </svelte:fragment>
</SidebarItem> </SidebarItem>
<SidebarItem label="Accounts" href="#/user/accounts" class="p-2"> <SidebarItem label="Accounts" href="#/user/account" class="p-2">
<svelte:fragment slot="icon"> <svelte:fragment slot="icon">
<User <User
tabindex="-1" tabindex="-1"

@ -1781,7 +1781,6 @@
<button class="m-2 bg-primary-700 text-white" <button class="m-2 bg-primary-700 text-white"
>Yes, I did</button >Yes, I did</button
> >
<!-- todo: blue button-->
</a> </a>
</div> </div>
</Modal> </Modal>

@ -0,0 +1,351 @@
<!--
// Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers
// All rights reserved.
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
-->
<!--
@component
"Wallet Info" user panel sub menu.
Provides info about wallet, broker, etc. and download option.
-->
<script>
import { Modal } from "flowbite-svelte";
import { link, push } from "svelte-spa-router";
import CenteredLayout from "../lib/CenteredLayout.svelte";
import {
ArrowLeft,
Trash,
DocumentArrowDown,
NoSymbol,
QrCode,
Link,
ArrowDownOnSquare,
} from "svelte-heros-v2";
import { onMount, tick } from "svelte";
import { Sidebar, SidebarGroup, SidebarWrapper } from "flowbite-svelte";
import { close_active_wallet, active_session, active_wallet } from "../store";
import { default as ng } from "../api";
let tauri_platform = import.meta.env.TAURI_PLATFORM;
let error;
let nonActiveClass =
"flex items-center p-2 text-base font-normal text-gray-900 rounded-lg dark:text-white hover:bg-gray-200 dark:hover:bg-gray-700";
let top;
async function scrollToTop() {
await tick();
top.scrollIntoView();
}
onMount(async () => {
if (!$active_session) {
push("#/");
} else {
await scrollToTop();
}
});
let downloading = false;
let wallet_file_ready = false;
let download_link = false;
let download_error = false;
async function download_wallet() {
try {
downloading = true;
let file = await ng.wallet_get_file($active_wallet.id);
// @ts-ignore
wallet_file_ready = "wallet-" + $active_wallet.id + ".ngw";
if (!tauri_platform) {
const blob = new Blob([file], {
type: "application/octet-stream",
});
// @ts-ignore
download_link = URL.createObjectURL(blob);
} else {
download_link = true;
}
} catch (e) {
download_error = e;
}
}
let wallet_remove_modal_open = false;
async function remove_wallet_clicked() {
wallet_remove_modal_open = true;
}
// TODO: WTF, this does not close the modal???
const close_modal = () => {
wallet_remove_modal_open = false;
};
async function remove_wallet_confirmed() {
if (!active_wallet) return;
// TODO: Wait for implementation
// ng.wallet_remove($active_wallet.id);
close_active_wallet();
}
</script>
<CenteredLayout>
<div class="container3" bind:this={top}>
<div class="row mb-20">
<Sidebar {nonActiveClass}>
<SidebarWrapper
divClass="bg-gray-60 overflow-y-auto py-4 px-3 rounded dark:bg-gray-800"
>
<SidebarGroup ulClass="space-y-2">
<li>
<h2 class="text-xl mb-6">Wallet Info</h2>
</li>
<!-- Go Back -->
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<li
tabindex="0"
class="text-left text-left flex items-center p-2 text-base font-normal text-gray-900 clickable rounded-lg dark:text-white hover:bg-gray-200 dark:hover:bg-gray-700"
on:keypress={() => window.history.go(-1)}
on:click={() => window.history.go(-1)}
>
<ArrowLeft
tabindex="-1"
class="w-7 h-7 text-black transition duration-75 dark:text-white group-hover:text-gray-900 dark:group-hover:text-white"
/>
<span class="ml-3">Back</span>
</li>
<!-- Download Wallet -->
{#if !downloading}
<li
tabindex="0"
role="menuitem"
class="flex items-center p-2 text-base font-normal text-gray-900 clickable rounded-lg dark:text-white hover:bg-gray-200 dark:hover:bg-gray-700"
on:keypress={download_wallet}
on:click={download_wallet}
>
<div>
<DocumentArrowDown
tabindex="-1"
class="w-7 h-7 text-black transition duration-75 dark:text-white group-hover:text-gray-900 dark:group-hover:text-white"
/>
</div>
<span class="ml-3">Download Wallet File</span>
</li>
{:else if download_error}
<li
tabindex="-1"
class="flex items-center p-2 text-base font-normal text-red-700 rounded-lg dark:text-white hover:bg-gray-200 dark:hover:bg-gray-700"
>
<div>
<NoSymbol
tabindex="-1"
class="w-7 h-7 text-red-700 transition duration-75 dark:text-white group-hover:text-gray-900 dark:group-hover:text-white"
/>
</div>
<span class="ml-3 text-left"
>Download failed:<br /> {download_error}</span
>
</li>
{:else if !wallet_file_ready}
<li
tabindex="-1"
class="flex items-center p-2 text-base font-normal text-blue-700 rounded-lg dark:text-white hover:bg-gray-200 dark:hover:bg-gray-700"
>
<div>
<DocumentArrowDown
tabindex="-1"
class="w-7 h-7 text-blue-700 transition duration-75 dark:text-white group-hover:text-gray-900 dark:group-hover:text-white"
/>
</div>
<span class="ml-3 text-left">Download in progress...</span>
</li>
{:else if download_link === true}
<li
tabindex="-1"
class="flex p-2 text-sm text-left break-all font-normal text-blue-700 rounded-lg dark:text-white hover:bg-gray-200 dark:hover:bg-gray-700"
>
<span
>You will find the file named "{wallet_file_ready}" <br />in
your Downloads folder</span
>
</li>
{:else}
<li
tabindex="-1"
class="flex items-center text-base font-normal text-gray-900 clickable rounded-lg dark:text-white hover:bg-gray-200 dark:hover:bg-gray-700"
>
<a
href={download_link}
target="_blank"
download={wallet_file_ready}
>
<button
tabindex="-1"
class=" text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-700/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55"
>
<div>
<DocumentArrowDown
tabindex="-1"
class="w-14 h-14 transition duration-75 dark:text-white dark:group-hover:text-white"
/>
</div>
Click here to download the wallet file
</button>
</a>
</li>
{/if}
<!-- Remove Wallet -->
<li
tabindex="0"
class="text-left flex items-center p-2 text-base font-normal text-gray-900 clickable rounded-lg dark:text-white hover:bg-gray-200 dark:hover:bg-gray-700"
on:keypress={remove_wallet_clicked}
on:click={remove_wallet_clicked}
>
<div>
<Trash
tabindex="-1"
class="w-7 h-7 text-black transition duration-75 dark:text-white group-hover:text-gray-900 dark:group-hover:text-white"
/>
</div>
<span class="ml-3">Remove Wallet from Device</span>
<Modal
autoclose
outsideclose
bind:open={wallet_remove_modal_open}
title="Remove Wallet"
>
<p class="mt-4">
Are you sure you want to remove this wallet from your device?
</p>
<div class="mt-4 flex justify-end">
<button on:click={close_modal}> Cancel </button>
<button
class="mr-2 bg-primary-700 text-white"
on:click={remove_wallet_confirmed}
>
Remove
</button>
</div>
</Modal>
</li>
<!-- TODO: Show QR-Code -->
{#if false}
<li
tabindex="0"
class="text-left flex items-center p-2 text-base font-normal text-gray-900 clickable rounded-lg dark:text-white hover:bg-gray-200 dark:hover:bg-gray-700"
>
<div>
<QrCode
tabindex="-1"
class="w-7 h-7 text-black transition duration-75 dark:text-white group-hover:text-gray-900 dark:group-hover:text-white"
/>
</div>
<span class="ml-3">Wallet QR-Code</span>
<Modal autoclose outsideclose title="My Wallet QR-Code"
>Use this QR-Code to log in with your wallet on new devices.
</Modal>
</li>
{/if}
<!-- TODO: Copy Wallet Link -->
{#if false}
<li
tabindex="0"
class="text-left flex items-center p-2 text-base font-normal text-gray-900 clickable rounded-lg dark:text-white hover:bg-gray-200 dark:hover:bg-gray-700"
>
<div>
<Link
tabindex="-1"
class="w-7 h-7 text-black transition duration-75 dark:text-white group-hover:text-gray-900 dark:group-hover:text-white"
/>
</div>
<span class="ml-3">Copy Wallet Link</span>
</li>
{/if}
<!-- TODO: Save to Device -->
{#if false}
<li
tabindex="0"
class="text-left flex items-center p-2 text-base font-normal text-gray-900 clickable rounded-lg dark:text-white hover:bg-gray-200 dark:hover:bg-gray-700"
>
<!-- TODO: Same as with the trash icon, this is not same-sized as the others. -->
<ArrowDownOnSquare
tabindex="-1"
class="w-7 h-7 text-black transition duration-75 dark:text-white group-hover:text-gray-900 dark:group-hover:text-white"
/>
<span class="ml-3">Save to Device for Future Logins</span>
</li>
{/if}
</SidebarGroup>
</SidebarWrapper>
</Sidebar>
</div>
{#if error}
<div class=" max-w-6xl lg:px-8 mx-auto px-4 text-red-800">
<svg
class="animate-bounce mt-10 h-16 w-16 mx-auto"
fill="none"
stroke="currentColor"
stroke-width="1.5"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"
/>
</svg>
{#if error == "AlreadyExists"}
<p class="max-w-xl md:mx-auto lg:max-w-2xl mb-5">
The user is already registered with the selected broker.<br /> Try logging
in instead
</p>
<a use:link href="/">
<button
tabindex="-1"
class="text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-700/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55 mb-2"
>
Login
</button>
</a>
{:else}
<p class="max-w-xl md:mx-auto lg:max-w-2xl mb-5">
An error occurred:<br />{error}
</p>
<a use:link href="/">
<button
tabindex="-1"
class="text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-700/50 font-medium rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55 mb-2"
>
Go back to homepage
</button>
</a>
{/if}
</div>
{/if}
</div>
</CenteredLayout>
<style>
li.clickable {
cursor: pointer;
}
.site-cnx-details {
@apply mt-0 !important;
}
</style>

@ -10,6 +10,7 @@
--> -->
<!-- <!--
@component
"Select a wallet to login with" page. "Select a wallet to login with" page.
This page is usually the first page the user sees when they visit the app. This page is usually the first page the user sees when they visit the app.
It allows the user to select a wallet to login with, create, or import a wallet. It allows the user to select a wallet to login with, create, or import a wallet.

Loading…
Cancel
Save