aboutsummaryrefslogtreecommitdiff
path: root/packages/exchange-backoffice-ui/src/Dashboard.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'packages/exchange-backoffice-ui/src/Dashboard.tsx')
-rw-r--r--packages/exchange-backoffice-ui/src/Dashboard.tsx217
1 files changed, 173 insertions, 44 deletions
diff --git a/packages/exchange-backoffice-ui/src/Dashboard.tsx b/packages/exchange-backoffice-ui/src/Dashboard.tsx
index 9a0ba41d5..9be86c533 100644
--- a/packages/exchange-backoffice-ui/src/Dashboard.tsx
+++ b/packages/exchange-backoffice-ui/src/Dashboard.tsx
@@ -3,19 +3,26 @@ import {
ChevronDownIcon,
MagnifyingGlassIcon,
UserIcon,
+ XCircleIcon,
} from "@heroicons/react/20/solid";
import {
Bars3Icon,
BellIcon,
+ CheckCircleIcon,
Cog6ToothIcon,
XMarkIcon,
} from "@heroicons/react/24/outline";
import { ComponentChildren, Fragment, VNode, h } from "preact";
import { ForwardedRef, forwardRef } from "preact/compat";
-import { useRef, useState } from "preact/hooks";
+import { useEffect, useRef, useState } from "preact/hooks";
import { Pages } from "./pages.js";
import { Router, useCurrentLocation } from "./route.js";
import { InformationCircleIcon } from "@heroicons/react/24/solid";
+import {
+ useLocalStorage,
+ useMemoryStorage,
+ useNotifications,
+} from "@gnu-taler/web-util/browser";
/**
* references between forms
@@ -259,6 +266,7 @@ export function Dashboard({
setSidebarOpen(true);
}}
/>
+ <Notifications />
<main class="py-10 px-4 sm:px-6 lg:px-8">
<div class="mx-auto max-w-3xl">
<Router
@@ -355,6 +363,9 @@ function NavigationBar({
}
function TopBar({ onOpenSidebar }: { onOpenSidebar: () => void }) {
+ const password = useMemoryStorage("password");
+ const officer = useLocalStorage("officer");
+
return (
<div class="sticky top-0 z-40 flex h-16 shrink-0 items-center gap-x-4 border-b border-gray-200 bg-white px-4 shadow-sm sm:gap-x-6 sm:px-6 lg:px-8">
<button
@@ -402,60 +413,66 @@ function TopBar({ onOpenSidebar }: { onOpenSidebar: () => void }) {
aria-hidden="true"
/>
- {/* Profile dropdown */}
- <Menu
- as="div"
- /* @ts-ignore */
- class="relative"
- >
- <Menu.Button class="-m-1.5 flex items-center p-1.5">
- <span class="sr-only">Open user menu</span>
- <img
- class="h-8 w-8 rounded-full bg-gray-50"
- src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
- alt=""
- />
- <span class="hidden lg:flex lg:items-center">
- <span
- class="ml-4 text-sm font-semibold leading-6 text-gray-900"
- aria-hidden="true"
- >
- Tom Cook
- </span>
- <ChevronDownIcon
- class="ml-2 h-5 w-5 text-gray-400"
- aria-hidden="true"
- />
- </span>
- </Menu.Button>
- <Transition
- as={Fragment}
- enter="transition ease-out duration-100"
- enterFrom="transform opacity-0 scale-95"
- enterTo="transform opacity-100 scale-100"
- leave="transition ease-in duration-75"
- leaveFrom="transform opacity-100 scale-100"
- leaveTo="transform opacity-0 scale-95"
+ {officer.value === undefined ? (
+ <div />
+ ) : (
+ <Menu
+ as="div"
+ /* @ts-ignore */
+ class="relative"
>
- <Menu.Items class="absolute right-0 z-10 mt-2.5 w-32 origin-top-right rounded-md bg-white py-2 shadow-lg ring-1 ring-gray-900/5 focus:outline-none">
- {userNavigation.map((item) => (
- <Menu.Item key={item.name}>
+ <Menu.Button class="-m-1.5 flex items-center p-1.5">
+ <span class="sr-only">Open user menu</span>
+ <img
+ class="h-8 w-8 rounded-full bg-gray-50"
+ src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
+ alt=""
+ />
+ <span class="hidden lg:flex lg:items-center">
+ <span
+ class="ml-4 text-sm font-semibold leading-6 text-gray-900"
+ aria-hidden="true"
+ >
+ {/* Tom Cook */}
+ {officer.value?.substring(0, 6)}
+ </span>
+ <ChevronDownIcon
+ class="ml-2 h-5 w-5 text-gray-400"
+ aria-hidden="true"
+ />
+ </span>
+ </Menu.Button>
+ <Transition
+ as={Fragment}
+ enter="transition ease-out duration-100"
+ enterFrom="transform opacity-0 scale-95"
+ enterTo="transform opacity-100 scale-100"
+ leave="transition ease-in duration-75"
+ leaveFrom="transform opacity-100 scale-100"
+ leaveTo="transform opacity-0 scale-95"
+ >
+ <Menu.Items class="absolute right-0 z-10 mt-2.5 w-48 origin-top-right rounded-md bg-white py-2 shadow-lg ring-1 ring-gray-900/5 focus:outline-none">
+ <Menu.Item>
{({ active }: { active: boolean }) => (
<a
- href={item.href}
+ // href={item.href}
+ onClick={() => {
+ officer.reset();
+ password.reset();
+ }}
class={classNames(
active ? "bg-gray-50" : "",
"block px-3 py-1 text-sm leading-6 text-gray-900",
)}
>
- {item.name}
+ Forget account
</a>
)}
</Menu.Item>
- ))}
- </Menu.Items>
- </Transition>
- </Menu>
+ </Menu.Items>
+ </Transition>
+ </Menu>
+ )}
</div>
</div>
</div>
@@ -473,3 +490,115 @@ function Footer() {
</footer>
);
}
+
+function Notifications() {
+ const ns = useNotifications();
+
+ // useEffect(() => {
+ // if (ns.length) {
+ // // remove notifications after some timeout
+ // }
+ // }, []);
+ {
+ /* <!-- Global notification live region, render this permanently at the end of the document --> */
+ }
+ console.log("render", ns.length);
+ return (
+ <div
+ aria-live="assertive"
+ class="pointer-events-none fixed inset-0 flex items-end px-4 py-6 sm:items-start sm:p-6 z-50"
+ >
+ <div class="flex w-full flex-col items-center space-y-4 sm:items-end ">
+ {/* <!--
+ Notification panel, dynamically insert this into the live region when it needs to be displayed
+
+ Entering: "transform ease-out duration-300 transition"
+ From: "translate-y-2 opacity-0 sm:translate-y-0 sm:translate-x-2"
+ To: "translate-y-0 opacity-100 sm:translate-x-0"
+ Leaving: "transition ease-in duration-100"
+ From: "opacity-100"
+ To: "opacity-0"
+--> */}
+ {ns.map(({ message, remove }) => {
+ switch (message.type) {
+ case "error": {
+ return (
+ <div class="pointer-events-auto w-full max-w-sm overflow-hidden rounded-lg bg-white shadow-lg ring-1 ring-black ring-opacity-5 ">
+ <div class="p-4 ">
+ <div class="flex items-start ">
+ <div class="flex-shrink-0">
+ <XCircleIcon class="h-6 w-6 text-red-400" />
+ </div>
+ <div class="ml-3 w-0 flex-1 pt-0.5">
+ <p class="text-sm font-medium text-gray-900">
+ {message.title}
+ </p>
+ {message.description && (
+ <p class="mt-1 text-sm text-gray-500">
+ {message.description}
+ </p>
+ )}
+ </div>
+ <div class="ml-4 flex flex-shrink-0">
+ <button
+ type="button"
+ onClick={remove}
+ class="inline-flex rounded-md bg-white text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
+ >
+ <span class="sr-only">Close</span>
+ <svg
+ class="h-5 w-5"
+ viewBox="0 0 20 20"
+ fill="currentColor"
+ aria-hidden="true"
+ >
+ <path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" />
+ </svg>
+ </button>
+ </div>
+ </div>
+ </div>
+ </div>
+ );
+ }
+ case "info": {
+ return (
+ <div class="pointer-events-auto w-full max-w-sm overflow-hidden rounded-lg bg-white shadow-lg ring-1 ring-black ring-opacity-5 ">
+ <div class="p-4 ">
+ <div class="flex items-start ">
+ <div class="flex-shrink-0">
+ <CheckCircleIcon class="h-6 w-6 text-green-400" />
+ </div>
+ <div class="ml-3 w-0 flex-1 pt-0.5">
+ <p class="text-sm font-medium text-gray-900">
+ {message.title}
+ </p>
+ </div>
+ <div class="ml-4 flex flex-shrink-0">
+ <button
+ type="button"
+ onClick={remove}
+ class="inline-flex rounded-md bg-white text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
+ >
+ <span class="sr-only">Close</span>
+ <svg
+ class="h-5 w-5"
+ viewBox="0 0 20 20"
+ fill="currentColor"
+ aria-hidden="true"
+ >
+ <path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" />
+ </svg>
+ </button>
+ </div>
+ </div>
+ </div>
+ </div>
+ );
+ }
+ }
+ })}
+ </div>
+ </div>
+ );
+}