ui settings view

This commit is contained in:
Sebastian 2023-08-07 06:51:10 -03:00
parent 8eb0183c78
commit 7d1621767c
No known key found for this signature in database
GPG Key ID: 173909D1A5F66069
10 changed files with 118 additions and 59 deletions

View File

@ -26,7 +26,7 @@ import {
} from "@gnu-taler/web-util/browser";
import { Fragment, h, VNode } from "preact";
import { route } from "preact-router";
import { useMemo } from "preact/hooks";
import { useMemo, useState } from "preact/hooks";
import { ApplicationReadyRoutes } from "./ApplicationReadyRoutes.js";
import { Loading } from "./components/exception/loading.js";
import {
@ -42,6 +42,7 @@ import { useBackendConfig } from "./hooks/backend.js";
import { strings } from "./i18n/strings.js";
import LoginPage from "./paths/login/index.js";
import { HttpStatusCode } from "@gnu-taler/taler-util";
import { Settings } from "./paths/settings/index.js";
export function Application(): VNode {
return (
@ -70,10 +71,19 @@ function ApplicationStatusRoutes(): VNode {
: { currency: "unknown", version: "unknown" };
const ctx = useMemo(() => ({ currency, version }), [currency, version]);
const [showSettings, setShowSettings] = useState(false)
if (showSettings) {
return <Fragment>
<NotYetReadyAppMenu onShowSettings={() => setShowSettings(true)} title="UI Settings" />
<Settings />
</Fragment>
}
if (!triedToLog) {
return (
<Fragment>
<NotYetReadyAppMenu title="Welcome!" />
<NotYetReadyAppMenu title="Welcome!" onShowSettings={() => setShowSettings(true)} />
<LoginPage onConfirm={updateLoginInfoAndGoToRoot} />
</Fragment>
);
@ -87,7 +97,7 @@ function ApplicationStatusRoutes(): VNode {
) {
return (
<Fragment>
<NotYetReadyAppMenu title="Login" />
<NotYetReadyAppMenu title="Login" onShowSettings={() => setShowSettings(true)} />
<LoginPage onConfirm={updateLoginInfoAndGoToRoot} />
</Fragment>
);
@ -98,7 +108,7 @@ function ApplicationStatusRoutes(): VNode {
) {
return (
<Fragment>
<NotYetReadyAppMenu title="Error" />
<NotYetReadyAppMenu title="Error" onShowSettings={() => setShowSettings(true)} />
<NotificationCard
notification={{
message: i18n.str`Server not found`,
@ -112,7 +122,7 @@ function ApplicationStatusRoutes(): VNode {
}
if (result.type === ErrorType.SERVER) {
<Fragment>
<NotYetReadyAppMenu title="Error" />
<NotYetReadyAppMenu title="Error" onShowSettings={() => setShowSettings(true)} />
<NotificationCard
notification={{
message: i18n.str`Server response with an error code`,
@ -125,7 +135,7 @@ function ApplicationStatusRoutes(): VNode {
}
if (result.type === ErrorType.UNREADABLE) {
<Fragment>
<NotYetReadyAppMenu title="Error" />
<NotYetReadyAppMenu title="Error" onShowSettings={() => setShowSettings(true)} />
<NotificationCard
notification={{
message: i18n.str`Response from server is unreadable, http status: ${result.status}`,
@ -138,7 +148,7 @@ function ApplicationStatusRoutes(): VNode {
}
return (
<Fragment>
<NotYetReadyAppMenu title="Error" />
<NotYetReadyAppMenu title="Error" onShowSettings={() => setShowSettings(true)} />
<NotificationCard
notification={{
message: i18n.str`Unexpected Error`,

View File

@ -33,6 +33,7 @@ import { InstanceRoutes } from "./InstanceRoutes.js";
import LoginPage from "./paths/login/index.js";
import { INSTANCE_ID_LOOKUP } from "./utils/constants.js";
import { HttpStatusCode } from "@gnu-taler/taler-util";
import { Settings } from "./paths/settings/index.js";
export function ApplicationReadyRoutes(): VNode {
const { i18n } = useTranslationContext();
@ -48,8 +49,15 @@ export function ApplicationReadyRoutes(): VNode {
clearAllTokens();
route("/");
};
const [showSettings, setShowSettings] = useState(false)
if (result.loading) return <NotYetReadyAppMenu title="Loading..." />;
if (showSettings) {
return <Fragment>
<NotYetReadyAppMenu onShowSettings={() => setShowSettings(true)} title="UI Settings" onLogout={clearTokenAndGoToRoot} />
<Settings/>
</Fragment>
}
if (result.loading) return <NotYetReadyAppMenu onShowSettings={() => setShowSettings(true)} title="Loading..." />;
let admin = true;
let instanceNameByBackendURL;
@ -61,7 +69,7 @@ export function ApplicationReadyRoutes(): VNode {
) {
return (
<Fragment>
<NotYetReadyAppMenu title="Login" onLogout={clearTokenAndGoToRoot} />
<NotYetReadyAppMenu onShowSettings={() => setShowSettings(true)} title="Login" onLogout={clearTokenAndGoToRoot} />
<NotificationCard
notification={{
message: i18n.str`Access denied`,
@ -81,7 +89,7 @@ export function ApplicationReadyRoutes(): VNode {
// does not match our pattern
return (
<Fragment>
<NotYetReadyAppMenu title="Error" onLogout={clearTokenAndGoToRoot} />
<NotYetReadyAppMenu onShowSettings={() => setShowSettings(true)} title="Error" onLogout={clearTokenAndGoToRoot} />
<NotificationCard
notification={{
message: i18n.str`Couldn't access the server.`,

View File

@ -68,6 +68,7 @@ import LoginPage from "./paths/login/index.js";
import NotFoundPage from "./paths/notfound/index.js";
import { Notification } from "./utils/types.js";
import { MerchantBackend } from "./declaration.js";
import { Settings } from "./paths/settings/index.js";
export enum InstancePaths {
// details = '/',
@ -100,6 +101,8 @@ export enum InstancePaths {
webhooks_list = "/webhooks",
webhooks_update = "/webhooks/:tid/update",
webhooks_new = "/webhooks/new",
settings = "/settings",
}
// eslint-disable-next-line @typescript-eslint/no-empty-function
@ -240,6 +243,9 @@ export function InstanceRoutes({
<Menu
instance={id}
admin={admin}
onShowSettings={() => {
route("/settings")
}}
path={path}
onLogout={clearTokenAndGoToRoot}
setInstanceName={setInstanceName}
@ -558,6 +564,7 @@ export function InstanceRoutes({
}}
/>
<Route path={InstancePaths.kyc} component={ListKYCPage} />
<Route path={InstancePaths.settings} component={Settings} />
{/**
* Example pages
*/}

View File

@ -229,7 +229,7 @@ export function LoginModal({ onConfirm, withMessage }: Props): VNode {
);
}
function AsyncButton({onClick, children}:{onClick: () => Promise<void>, children: ComponentChildren}):VNode {
function AsyncButton({ onClick, children }: { onClick: () => Promise<void>, children: ComponentChildren }): VNode {
const [running, setRunning] = useState(false)
return <button class="button is-info" disabled={running} onClick={() => {
setRunning(true)

View File

@ -20,7 +20,6 @@
*/
import { h, VNode } from "preact";
import { LangSelector } from "./LangSelector.js";
import logo from "../../assets/logo-2021.svg";
interface Props {
@ -65,7 +64,6 @@ export function NavigationBar({ onMobileMenu, title }: Props): VNode {
</a>
<div class="navbar-end">
<div class="navbar-item" style={{ paddingTop: 4, paddingBottom: 4 }}>
<LangSelector />
</div>
</div>
</div>

View File

@ -31,6 +31,7 @@ const VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : undefined;
interface Props {
onLogout: () => void;
onShowSettings: () => void;
mobile?: boolean;
instance: string;
admin?: boolean;
@ -40,6 +41,7 @@ interface Props {
export function Sidebar({
mobile,
instance,
onShowSettings,
onLogout,
admin,
mimic,
@ -78,21 +80,8 @@ export function Sidebar({
<div class="menu is-menu-main">
{instance ? (
<Fragment>
<p class="menu-label">
<i18n.Translate>Instance</i18n.Translate>
</p>
<ul class="menu-list">
<li>
<a href={"/update"} class="has-icon">
<span class="icon">
<i class="mdi mdi-square-edit-outline" />
</span>
<span class="menu-item-label">
<i18n.Translate>Settings</i18n.Translate>
</span>
</a>
</li>
<li>
<li>
<a href={"/orders"} class="has-icon">
<span class="icon">
<i class="mdi mdi-cash-register" />
@ -132,6 +121,31 @@ export function Sidebar({
</span>
</a>
</li>
{needKYC && (
<li>
<a href={"/kyc"} class="has-icon">
<span class="icon">
<i class="mdi mdi-account-check" />
</span>
<span class="menu-item-label">KYC Status</span>
</a>
</li>
)}
</ul>
<p class="menu-label">
<i18n.Translate>Configuration</i18n.Translate>
</p>
<ul class="menu-list">
<li>
<a href={"/update"} class="has-icon">
<span class="icon">
<i class="mdi mdi-square-edit-outline" />
</span>
<span class="menu-item-label">
<i18n.Translate>Account</i18n.Translate>
</span>
</a>
</li>
<li>
<a href={"/reserves"} class="has-icon">
<span class="icon">
@ -150,16 +164,6 @@ export function Sidebar({
</span>
</a>
</li>
{needKYC && (
<li>
<a href={"/kyc"} class="has-icon">
<span class="icon">
<i class="mdi mdi-account-check" />
</span>
<span class="menu-item-label">KYC Status</span>
</a>
</li>
)}
</ul>
</Fragment>
) : undefined}
@ -167,6 +171,18 @@ export function Sidebar({
<i18n.Translate>Connection</i18n.Translate>
</p>
<ul class="menu-list">
<li>
<a class="has-icon is-state-info is-hoverable"
onClick={(): void => onShowSettings()}
>
<span class="icon">
<i class="mdi mdi-newspaper" />
</span>
<span class="menu-item-label">
<i18n.Translate>Settings</i18n.Translate>
</span>
</a>
</li>
<li>
<div>
<span style={{ width: "3rem" }} class="icon">

View File

@ -75,6 +75,7 @@ interface MenuProps {
instance: string;
admin?: boolean;
onLogout?: () => void;
onShowSettings: () => void;
setInstanceName: (s: string) => void;
}
@ -93,6 +94,7 @@ function WithTitle({
export function Menu({
onLogout,
onShowSettings,
title,
instance,
path,
@ -121,6 +123,7 @@ export function Menu({
{onLogout && (
<Sidebar
onShowSettings={onShowSettings}
onLogout={onLogout}
admin={admin}
mimic={mimic}
@ -159,6 +162,7 @@ export function Menu({
interface NotYetReadyAppMenuProps {
title: string;
onLogout?: () => void;
onShowSettings: () => void;
}
interface NotifProps {
@ -199,6 +203,7 @@ export function NotificationCard({
export function NotYetReadyAppMenu({
onLogout,
onShowSettings,
title,
}: NotYetReadyAppMenuProps): VNode {
const [mobileOpen, setMobileOpen] = useState(false);
@ -217,7 +222,7 @@ export function NotYetReadyAppMenu({
title={title}
/>
{onLogout && (
<Sidebar onLogout={onLogout} instance="" mobile={mobileOpen} />
<Sidebar onShowSettings={onShowSettings} onLogout={onLogout} instance="" mobile={mobileOpen} />
)}
</div>
);

View File

@ -164,7 +164,7 @@ export function ListPage({
<div class="field has-addons">
{jumpToDate && (
<div class="control">
<a class="button" onClick={() => onSelectDate(undefined)}>
<a class="button is-fullwidth" onClick={() => onSelectDate(undefined)}>
<span
class="icon"
data-tooltip={i18n.str`clear date filter`}
@ -191,7 +191,7 @@ export function ListPage({
<div class="control">
<span class="has-tooltip-left" data-tooltip={dateTooltip}>
<a
class="button"
class="button is-fullwidth"
onClick={() => {
setPickDate(true);
}}

View File

@ -85,34 +85,34 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
template_contract: !state.template_contract
? undefined
: undefinedIfEmpty({
amount: !state.template_contract?.amount
? undefined
: !parsedPrice
amount: !state.template_contract?.amount
? undefined
: !parsedPrice
? i18n.str`not valid`
: Amounts.isZero(parsedPrice)
? i18n.str`must be greater than 0`
: undefined,
minimum_age:
state.template_contract.minimum_age < 0
? i18n.str`should be greater that 0`
? i18n.str`must be greater than 0`
: undefined,
pay_duration: !state.template_contract.pay_duration
? i18n.str`can't be empty`
: state.template_contract.pay_duration.d_us === "forever"
minimum_age:
state.template_contract.minimum_age < 0
? i18n.str`should be greater that 0`
: undefined,
pay_duration: !state.template_contract.pay_duration
? i18n.str`can't be empty`
: state.template_contract.pay_duration.d_us === "forever"
? undefined
: state.template_contract.pay_duration.d_us < 1000 * 1000 //less than one second
? i18n.str`to short`
: undefined,
} as Partial<MerchantTemplateContractDetails>),
? i18n.str`to short`
: undefined,
} as Partial<MerchantTemplateContractDetails>),
pos_key: !state.pos_key
? !state.pos_algorithm
? undefined
: i18n.str`required`
: !isBase32RFC3548Charset(state.pos_key)
? i18n.str`just letters and numbers from 2 to 7`
: state.pos_key.length !== 32
? i18n.str`size of the key should be 32`
: undefined,
? i18n.str`just letters and numbers from 2 to 7`
: state.pos_key.length !== 32
? i18n.str`size of the key should be 32`
: undefined,
};
const hasErrors = Object.keys(errors).some(
@ -139,7 +139,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
>
<InputWithAddon<Entity>
name="template_id"
addonBefore={`${backend.url}/instances/templates/`}
help={`${backend.url}/instances/templates/${state.template_id ?? ""}`}
label={i18n.str`Identifier`}
tooltip={i18n.str`Name of the template in URLs.`}
/>

View File

@ -0,0 +1,15 @@
import { VNode, h } from "preact";
export function Settings(): VNode {
return <div>
<section class="section is-main-section">
<div class="columns">
<div class="column" />
<div class="column is-four-fifths">
settings view
</div>
<div class="column" />
</div>
</section>
</div>
}