diff options
author | Sebastian <sebasjm@gmail.com> | 2022-06-01 15:47:47 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2022-06-01 15:47:47 -0300 |
commit | af7b107f455b01e136db2211c357cc59a506139a (patch) | |
tree | d1a4596fba17b9db06d50a76f7ecfa403449faca | |
parent | 2aade8e7aed485577576f91e61474f69b4366060 (diff) |
mui button impl
37 files changed, 476 insertions, 367 deletions
diff --git a/packages/taler-wallet-webextension/src/components/Banner.stories.tsx b/packages/taler-wallet-webextension/src/components/Banner.stories.tsx index f91d94d0f..c8a7a5eef 100644 --- a/packages/taler-wallet-webextension/src/components/Banner.stories.tsx +++ b/packages/taler-wallet-webextension/src/components/Banner.stories.tsx @@ -77,8 +77,8 @@ export const BasicExample = (): VNode => ( ]} confirm={{ label: "turn on wifi", - action: () => { - return null; + action: async () => { + return; }, }} /> diff --git a/packages/taler-wallet-webextension/src/components/Banner.tsx b/packages/taler-wallet-webextension/src/components/Banner.tsx index 88b36430b..c1f216f05 100644 --- a/packages/taler-wallet-webextension/src/components/Banner.tsx +++ b/packages/taler-wallet-webextension/src/components/Banner.tsx @@ -15,7 +15,7 @@ interface Props extends JSX.HTMLAttributes<HTMLDivElement> { }[]; confirm?: { label: string; - action: () => void; + action: () => Promise<void>; }; } diff --git a/packages/taler-wallet-webextension/src/components/Checkbox.tsx b/packages/taler-wallet-webextension/src/components/Checkbox.tsx index 2e14f3367..5b782c628 100644 --- a/packages/taler-wallet-webextension/src/components/Checkbox.tsx +++ b/packages/taler-wallet-webextension/src/components/Checkbox.tsx @@ -18,7 +18,7 @@ import { h, VNode } from "preact"; interface Props { enabled?: boolean; - onToggle?: () => void; + onToggle?: () => Promise<void>; label: VNode; name: string; description?: VNode; diff --git a/packages/taler-wallet-webextension/src/components/CheckboxOutlined.tsx b/packages/taler-wallet-webextension/src/components/CheckboxOutlined.tsx index 1b38935c0..a596ba94d 100644 --- a/packages/taler-wallet-webextension/src/components/CheckboxOutlined.tsx +++ b/packages/taler-wallet-webextension/src/components/CheckboxOutlined.tsx @@ -19,7 +19,7 @@ import { h, VNode } from "preact"; interface Props { enabled: boolean; - onToggle: () => void; + onToggle: () => Promise<void>; label: VNode; name: string; } diff --git a/packages/taler-wallet-webextension/src/components/MultiActionButton.tsx b/packages/taler-wallet-webextension/src/components/MultiActionButton.tsx index c4ccaa696..3bc6ba400 100644 --- a/packages/taler-wallet-webextension/src/components/MultiActionButton.tsx +++ b/packages/taler-wallet-webextension/src/components/MultiActionButton.tsx @@ -1,16 +1,14 @@ +import { getUnpackedSettings } from "http2"; import { h, VNode } from "preact"; -import arrowDown from "../svg/chevron-down.svg"; -import { - ButtonBoxPrimary, - ButtonPrimary, - ParagraphClickable, -} from "./styled/index.js"; import { useState } from "preact/hooks"; +import { Button } from "../mui/Button.js"; +import arrowDown from "../svg/chevron-down.svg"; +import { ParagraphClickable } from "./styled/index.js"; export interface Props { label: (s: string) => VNode; actions: string[]; - onClick: (s: string) => void; + onClick: (s: string) => Promise<void>; } /** @@ -43,9 +41,9 @@ export function MultiActionButton({ if (!canChange) { return ( - <ButtonPrimary onClick={() => doClick(selected)}> + <Button variant="contained" onClick={() => doClick(selected)}> {label(selected)} - </ButtonPrimary> + </Button> ); } @@ -73,40 +71,44 @@ export function MultiActionButton({ ))} </div> )} - <ButtonBoxPrimary + <Button + variant="contained" onClick={() => doClick(selected)} style={{ borderTopRightRadius: 0, borderBottomRightRadius: 0, marginRight: 0, - maxWidth: 170, + // maxWidth: 170, overflowX: "hidden", textOverflow: "ellipsis", }} > {label(selected)} - </ButtonBoxPrimary> + </Button> - <ButtonPrimary - onClick={() => setOpened((s) => !s)} + <Button + variant="outlined" + onClick={async () => setOpened((s) => !s)} style={{ marginLeft: 0, borderTopLeftRadius: 0, borderBottomLeftRadius: 0, - width: 36, - padding: 4, - height: 36, - fill: "white", + paddingLeft: 4, + paddingRight: 4, + minWidth: "unset", }} > <div style={{ height: 24, width: 24, + marginLeft: 4, + marginRight: 4, + // fill: "white", }} dangerouslySetInnerHTML={{ __html: arrowDown }} /> - </ButtonPrimary> + </Button> </div> ); } diff --git a/packages/taler-wallet-webextension/src/context/devContext.ts b/packages/taler-wallet-webextension/src/context/devContext.ts index 1ce483d8d..ec79f22d8 100644 --- a/packages/taler-wallet-webextension/src/context/devContext.ts +++ b/packages/taler-wallet-webextension/src/context/devContext.ts @@ -25,11 +25,11 @@ import { useLocalStorage } from "../hooks/useLocalStorage.js"; interface Type { devMode: boolean; - toggleDevMode: () => void; + toggleDevMode: () => Promise<void>; } const Context = createContext<Type>({ devMode: false, - toggleDevMode: () => null, + toggleDevMode: async () => { return; }, }); export const useDevContext = (): Type => useContext(Context); @@ -44,8 +44,8 @@ export const DevContextProviderForTesting = ({ return h(Context.Provider, { value: { devMode: value, - toggleDevMode: () => { - null; + toggleDevMode: async () => { + return; }, }, children, @@ -55,7 +55,7 @@ export const DevContextProviderForTesting = ({ export const DevContextProvider = ({ children }: { children: any }): VNode => { const [value, setter] = useLocalStorage("devMode"); const devMode = value === "true"; - const toggleDevMode = (): void => setter((v) => (!v ? "true" : undefined)); + const toggleDevMode = async (): Promise<void> => setter((v) => (!v ? "true" : undefined)); children = children.length === 1 && typeof children === "function" ? children({ devMode }) diff --git a/packages/taler-wallet-webextension/src/cta/Deposit.tsx b/packages/taler-wallet-webextension/src/cta/Deposit.tsx index 2fc7cbc41..3cbd46e30 100644 --- a/packages/taler-wallet-webextension/src/cta/Deposit.tsx +++ b/packages/taler-wallet-webextension/src/cta/Deposit.tsx @@ -44,13 +44,14 @@ import { } from "../components/styled/index.js"; import { useTranslationContext } from "../context/translation.js"; import { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; +import { Button } from "../mui/Button.js"; import { ButtonHandler } from "../mui/handlers.js"; import * as wxApi from "../wxApi.js"; interface Props { talerDepositUri?: string; amount: AmountString; - goBack: () => void; + goBack: () => Promise<void>; } type State = Loading | Ready | Completed; @@ -206,11 +207,15 @@ export function View({ state }: ViewProps): VNode { /> </section> <section> - <ButtonSuccess upperCased onClick={state.confirm.onClick}> + <Button + variant="contained" + color="success" + onClick={state.confirm.onClick} + > <i18n.Translate> Deposit {<Amount value={state.effective} />} </i18n.Translate> - </ButtonSuccess> + </Button> </section> </WalletAction> ); diff --git a/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx b/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx index 76bfa3ab3..04b44fcda 100644 --- a/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx +++ b/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx @@ -33,6 +33,10 @@ export default { argTypes: {}, }; +const noop = async (): Promise<void> => { + return; +}; + export const NoBalance = createExample(TestedComponent, { state: { status: "ready", @@ -61,8 +65,8 @@ export const NoBalance = createExample(TestedComponent, { amountRaw: "USD:10", }, }, - goBack: () => null, - goToWalletManualWithdraw: () => null, + goBack: noop, + goToWalletManualWithdraw: noop, }); export const NoEnoughBalance = createExample(TestedComponent, { @@ -97,8 +101,8 @@ export const NoEnoughBalance = createExample(TestedComponent, { amountRaw: "USD:10", }, }, - goBack: () => null, - goToWalletManualWithdraw: () => null, + goBack: noop, + goToWalletManualWithdraw: noop, }); export const EnoughBalanceButRestricted = createExample(TestedComponent, { @@ -133,8 +137,8 @@ export const EnoughBalanceButRestricted = createExample(TestedComponent, { amountRaw: "USD:10", }, }, - goBack: () => null, - goToWalletManualWithdraw: () => null, + goBack: noop, + goToWalletManualWithdraw: noop, }); export const PaymentPossible = createExample(TestedComponent, { @@ -172,8 +176,8 @@ export const PaymentPossible = createExample(TestedComponent, { proposalId: "proposal1234", }, }, - goBack: () => null, - goToWalletManualWithdraw: () => null, + goBack: noop, + goToWalletManualWithdraw: noop, }); export const PaymentPossibleWithFee = createExample(TestedComponent, { @@ -211,8 +215,8 @@ export const PaymentPossibleWithFee = createExample(TestedComponent, { proposalId: "proposal1234", }, }, - goBack: () => null, - goToWalletManualWithdraw: () => null, + goBack: noop, + goToWalletManualWithdraw: noop, }); import beer from "../../static-dev/beer.png"; @@ -271,8 +275,8 @@ export const TicketWithAProductList = createExample(TestedComponent, { proposalId: "proposal1234", }, }, - goBack: () => null, - goToWalletManualWithdraw: () => null, + goBack: noop, + goToWalletManualWithdraw: noop, }); export const AlreadyConfirmedByOther = createExample(TestedComponent, { @@ -309,8 +313,8 @@ export const AlreadyConfirmedByOther = createExample(TestedComponent, { paid: false, }, }, - goBack: () => null, - goToWalletManualWithdraw: () => null, + goBack: noop, + goToWalletManualWithdraw: noop, }); export const AlreadyPaidWithoutFulfillment = createExample(TestedComponent, { @@ -347,8 +351,8 @@ export const AlreadyPaidWithoutFulfillment = createExample(TestedComponent, { paid: true, }, }, - goBack: () => null, - goToWalletManualWithdraw: () => null, + goBack: noop, + goToWalletManualWithdraw: noop, }); export const AlreadyPaidWithFulfillment = createExample(TestedComponent, { @@ -387,6 +391,6 @@ export const AlreadyPaidWithFulfillment = createExample(TestedComponent, { paid: true, }, }, - goBack: () => null, - goToWalletManualWithdraw: () => null, + goBack: noop, + goToWalletManualWithdraw: noop, }); diff --git a/packages/taler-wallet-webextension/src/cta/Pay.tsx b/packages/taler-wallet-webextension/src/cta/Pay.tsx index 4f44ebab2..59e26c40e 100644 --- a/packages/taler-wallet-webextension/src/cta/Pay.tsx +++ b/packages/taler-wallet-webextension/src/cta/Pay.tsx @@ -60,13 +60,14 @@ import { } from "../components/styled/index.js"; import { useTranslationContext } from "../context/translation.js"; import { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; +import { Button } from "../mui/Button.js"; import { ButtonHandler } from "../mui/handlers.js"; import * as wxApi from "../wxApi.js"; interface Props { talerPayUri?: string; - goToWalletManualWithdraw: (currency?: string) => void; - goBack: () => void; + goToWalletManualWithdraw: (currency?: string) => Promise<void>; + goBack: () => Promise<void>; } type State = Loading | Ready | Confirmed; @@ -265,8 +266,8 @@ export function View({ goToWalletManualWithdraw, }: { state: Ready | Confirmed; - goToWalletManualWithdraw: (currency?: string) => void; - goBack: () => void; + goToWalletManualWithdraw: (currency?: string) => Promise<void>; + goBack: () => Promise<void>; }): VNode { const { i18n } = useTranslationContext(); const contractTerms: ContractTerms = state.payStatus.contractTerms; @@ -522,7 +523,7 @@ function ButtonsSection({ goToWalletManualWithdraw, }: { state: Ready | Confirmed; - goToWalletManualWithdraw: (currency: string) => void; + goToWalletManualWithdraw: (currency: string) => Promise<void>; }): VNode { const { i18n } = useTranslationContext(); if (state.status === "ready") { @@ -531,11 +532,15 @@ function ButtonsSection({ return ( <Fragment> <section> - <ButtonSuccess upperCased onClick={state.payHandler.onClick}> + <Button + variant="contained" + color="success" + onClick={state.payHandler.onClick} + > <i18n.Translate> Pay {<Amount value={payStatus.amountEffective} />} </i18n.Translate> - </ButtonSuccess> + </Button> </section> <PayWithMobile state={state} /> </Fragment> @@ -560,12 +565,13 @@ function ButtonsSection({ <WarningBox>{BalanceMessage}</WarningBox> </section> <section> - <ButtonSuccess - upperCased + <Button + variant="contained" + color="success" onClick={() => goToWalletManualWithdraw(state.amount.currency)} > <i18n.Translate>Withdraw digital cash</i18n.Translate> - </ButtonSuccess> + </Button> </section> <PayWithMobile state={state} /> </Fragment> diff --git a/packages/taler-wallet-webextension/src/cta/Refund.tsx b/packages/taler-wallet-webextension/src/cta/Refund.tsx index 5387a1782..004a8604b 100644 --- a/packages/taler-wallet-webextension/src/cta/Refund.tsx +++ b/packages/taler-wallet-webextension/src/cta/Refund.tsx @@ -40,6 +40,7 @@ import { } from "../components/styled/index.js"; import { useTranslationContext } from "../context/translation.js"; import { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; +import { Button } from "../mui/Button.js"; import { ButtonHandler } from "../mui/handlers.js"; import * as wxApi from "../wxApi.js"; import { ProductList } from "./Pay.js"; @@ -188,9 +189,9 @@ export function View({ state }: ViewProps): VNode { </section> ) : undefined} <section> - <ButtonSuccess onClick={state.accept.onClick}> + <Button variant="contained" onClick={state.accept.onClick}> <i18n.Translate>Confirm refund</i18n.Translate> - </ButtonSuccess> + </Button> </section> </WalletAction> ); diff --git a/packages/taler-wallet-webextension/src/cta/TermsOfServiceSection.tsx b/packages/taler-wallet-webextension/src/cta/TermsOfServiceSection.tsx index 057144866..7092468cd 100644 --- a/packages/taler-wallet-webextension/src/cta/TermsOfServiceSection.tsx +++ b/packages/taler-wallet-webextension/src/cta/TermsOfServiceSection.tsx @@ -2,14 +2,13 @@ import { Fragment, h, VNode } from "preact"; import { CheckboxOutlined } from "../components/CheckboxOutlined.js"; import { ExchangeXmlTos } from "../components/ExchangeToS.js"; import { - ButtonSuccess, - ButtonWarning, LinkSuccess, TermsOfService, WarningBox, WarningText, } from "../components/styled/index.js"; import { useTranslationContext } from "../context/translation.js"; +import { Button } from "../mui/Button.js"; import { TermsState } from "../utils/index.js"; export interface Props { @@ -58,20 +57,28 @@ export function TermsOfServiceSection({ )} {terms.status === "new" && ( <section> - <ButtonSuccess upperCased onClick={() => onReview(true)}> + <Button + variant="contained" + color="success" + onClick={async () => onReview(true)} + > <i18n.Translate> Review exchange terms of service </i18n.Translate> - </ButtonSuccess> + </Button> </section> )} {terms.status === "changed" && ( <section> - <ButtonWarning upperCased onClick={() => onReview(true)}> + <Button + variant="contained" + color="success" + onClick={async () => onReview(true)} + > <i18n.Translate> Review new version of terms of service </i18n.Translate> - </ButtonWarning> + </Button> </section> )} </Fragment> @@ -95,7 +102,7 @@ export function TermsOfServiceSection({ I accept the exchange terms of service </i18n.Translate> } - onToggle={() => { + onToggle={async () => { onAccept(!reviewed); if (ableToReviewTermsOfService) onReview(false); }} @@ -154,7 +161,7 @@ export function TermsOfServiceSection({ I accept the exchange terms of service </i18n.Translate> } - onToggle={() => { + onToggle={async () => { onAccept(!reviewed); if (ableToReviewTermsOfService) onReview(false); }} diff --git a/packages/taler-wallet-webextension/src/cta/Tip.tsx b/packages/taler-wallet-webextension/src/cta/Tip.tsx index dc4757b33..156d4f5a3 100644 --- a/packages/taler-wallet-webextension/src/cta/Tip.tsx +++ b/packages/taler-wallet-webextension/src/cta/Tip.tsx @@ -210,9 +210,13 @@ export function View({ state }: { state: State }): VNode { /> </section> <section> - <ButtonSuccess onClick={state.accept.onClick}> + <Button + variant="contained" + color="success" + onClick={state.accept.onClick} + > <i18n.Translate>Accept tip</i18n.Translate> - </ButtonSuccess> + </Button> <Button onClick={state.ignore.onClick}> <i18n.Translate>Ignore</i18n.Translate> </Button> diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw.tsx index c4bc3457a..4b8aeccd0 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw.tsx +++ b/packages/taler-wallet-webextension/src/cta/Withdraw.tsx @@ -33,8 +33,6 @@ import { LogoHeader } from "../components/LogoHeader.js"; import { Part } from "../components/Part.js"; import { SelectList } from "../components/SelectList.js"; import { - ButtonSuccess, - ButtonWarning, Input, LinkSuccess, SubTitle, @@ -43,19 +41,14 @@ import { } from "../components/styled/index.js"; import { useTranslationContext } from "../context/translation.js"; import { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; +import { Button } from "../mui/Button.js"; +import { ButtonHandler, SelectFieldHandler } from "../mui/handlers.js"; import { buildTermsOfServiceState } from "../utils/index.js"; -import { - ButtonHandler, - SelectFieldHandler, - ToggleHandler, -} from "../mui/handlers.js"; import * as wxApi from "../wxApi.js"; import { Props as TermsOfServiceSectionProps, TermsOfServiceSection, } from "./TermsOfServiceSection.js"; -import { startOfWeekYear } from "date-fns/esm"; -import { Checkbox } from "../components/Checkbox.js"; interface Props { talerWithdrawUri?: string; @@ -527,22 +520,24 @@ export function View({ state }: { state: State }): VNode { <section> {(state.tosProps.terms.status === "accepted" || (state.mustAcceptFirst && state.tosProps.reviewed)) && ( - <ButtonSuccess - upperCased + <Button + variant="contained" + color="success" disabled={!state.doWithdrawal.onClick} onClick={state.doWithdrawal.onClick} > <i18n.Translate>Confirm withdrawal</i18n.Translate> - </ButtonSuccess> + </Button> )} {state.tosProps.terms.status === "notfound" && ( - <ButtonWarning - upperCased + <Button + variant="contained" + color="warning" disabled={!state.doWithdrawal.onClick} onClick={state.doWithdrawal.onClick} > <i18n.Translate>Withdraw anyway</i18n.Translate> - </ButtonWarning> + </Button> )} </section> ) : ( diff --git a/packages/taler-wallet-webextension/src/mui/Alert.stories.tsx b/packages/taler-wallet-webextension/src/mui/Alert.stories.tsx index 12b2a8625..a2c8576c7 100644 --- a/packages/taler-wallet-webextension/src/mui/Alert.stories.tsx +++ b/packages/taler-wallet-webextension/src/mui/Alert.stories.tsx @@ -68,18 +68,22 @@ export const WithTitle = (): VNode => ( </Wrapper> ); +const showSomething = async function (): Promise<void> { + alert("closed"); +}; + export const WithAction = (): VNode => ( <Wrapper> - <Alert title="Warning" severity="warning" onClose={() => alert("closed")}> + <Alert title="Warning" severity="warning" onClose={showSomething}> this is an warning </Alert> - <Alert title="Error" severity="error" onClose={() => alert("closed")}> + <Alert title="Error" severity="error" onClose={showSomething}> this is an error </Alert> - <Alert title="Success" severity="success" onClose={() => alert("closed")}> + <Alert title="Success" severity="success" onClose={showSomething}> this is an success </Alert> - <Alert title="Info" severity="info" onClose={() => alert("closed")}> + <Alert title="Info" severity="info" onClose={showSomething}> this is an info </Alert> </Wrapper> diff --git a/packages/taler-wallet-webextension/src/mui/Alert.tsx b/packages/taler-wallet-webextension/src/mui/Alert.tsx index 7d0ce55d0..b2ea1f5d7 100644 --- a/packages/taler-wallet-webextension/src/mui/Alert.tsx +++ b/packages/taler-wallet-webextension/src/mui/Alert.tsx @@ -49,7 +49,7 @@ interface Props { title?: string; variant?: "filled" | "outlined" | "standard"; role?: string; - onClose?: () => void; + onClose?: () => Promise<void>; // icon: VNode; severity?: "info" | "warning" | "success" | "error"; children: ComponentChildren; diff --git a/packages/taler-wallet-webextension/src/mui/Button.tsx b/packages/taler-wallet-webextension/src/mui/Button.tsx index 451b1d48d..3f8702f88 100644 --- a/packages/taler-wallet-webextension/src/mui/Button.tsx +++ b/packages/taler-wallet-webextension/src/mui/Button.tsx @@ -1,7 +1,7 @@ import { ComponentChildren, h, VNode, JSX } from "preact"; import { css } from "@linaria/core"; // eslint-disable-next-line import/extensions -import { theme, ripple, Colors } from "./style"; +import { theme, ripple, Colors, rippleOutlined } from "./style"; // eslint-disable-next-line import/extensions import { alpha } from "./colors/manipulation"; @@ -31,12 +31,13 @@ interface Props { disableFocusRipple?: boolean; endIcon?: string | VNode; fullWidth?: boolean; + style?: h.JSX.CSSProperties; href?: string; size?: "small" | "medium" | "large"; startIcon?: VNode | string; variant?: "contained" | "outlined" | "text"; color?: Colors; - onClick?: () => void; + onClick?: () => Promise<void>; } const button = css` @@ -199,6 +200,7 @@ export function Button({ fullWidth, variant = "text", size = "medium", + style: parentStyle, color = "primary", onClick, }: Props): VNode { @@ -267,12 +269,15 @@ export function Button({ colorVariant[variant], sizeVariant[variant][size], ].join(" ")} + containedRipple={variant === "contained"} onClick={onClick} style={{ + ...parentStyle, "--color-main": theme.palette[color].main, "--color-contrastText": theme.palette[color].contrastText, "--color-main-alpha-half": alpha(theme.palette[color].main, 0.5), "--color-dark": theme.palette[color].dark, + "--color-light": theme.palette[color].light, "--color-main-alpha-opacity": alpha( theme.palette[color].main, theme.palette.action.hoverOpacity, @@ -295,13 +300,15 @@ export function Button({ interface BaseProps extends JSX.HTMLAttributes<HTMLButtonElement> { class: string; - onClick?: () => void; + onClick?: () => Promise<void>; + containedRipple?: boolean; children?: ComponentChildren; } function ButtonBase({ class: _class, children, + containedRipple, onClick, dangerouslySetInnerHTML, ...rest @@ -309,7 +316,11 @@ function ButtonBase({ function doClick(): void { if (onClick) onClick(); } - const classNames = [buttonBaseStyle, _class, ripple].join(" "); + const classNames = [ + buttonBaseStyle, + _class, + containedRipple ? ripple : rippleOutlined, + ].join(" "); if (dangerouslySetInnerHTML) { return ( <button @@ -332,7 +343,7 @@ export function IconButton({ onClick, }: { svg: any; - onClick?: () => void; + onClick?: () => Promise<void>; }): VNode { return ( <ButtonBase diff --git a/packages/taler-wallet-webextension/src/mui/style.tsx b/packages/taler-wallet-webextension/src/mui/style.tsx index 3ad1ab14e..49904f7f3 100644 --- a/packages/taler-wallet-webextension/src/mui/style.tsx +++ b/packages/taler-wallet-webextension/src/mui/style.tsx @@ -46,13 +46,33 @@ export const theme = createTheme(); export const ripple = css` background-position: center; - transition: background 0.5s; - &:hover { - background: #eeeeee radial-gradient(circle, transparent 1%, #eeeeee 1%) + transition: background 0.2s; + + &:hover:enabled { + background: var(--color-main) + radial-gradient(circle, transparent 1%, var(--color-dark) 1%) + center/15000%; + } + &:active:enabled { + background-color: var(--color-main); + background-size: 100%; + transition: background 0s; + } +`; + +export const rippleOutlined = css` + background-position: center; + + transition: background 0.2s; + + &:hover:enabled { + background: var(--color-contrastText) + radial-gradient(circle, transparent 1%, var(--color-light) 1%) center/15000%; } - &:active { - background-color: currentColor; + + &:active:enabled { + background-color: var(--color-contrastText); background-size: 100%; transition: background 0s; } @@ -680,15 +700,15 @@ function createTheme() { function getDefaultSecondary(mode = "light") { if (mode === "dark") { return { - main: purple[200], - light: purple[50], - dark: purple[400], + main: grey[200], + light: grey[50], + dark: grey[400], }; } return { - main: purple[500], - light: purple[300], - dark: purple[700], + main: grey[300], + light: grey[100], + dark: grey[600], }; } diff --git a/packages/taler-wallet-webextension/src/popup/Application.tsx b/packages/taler-wallet-webextension/src/popup/Application.tsx index 72579b05b..ba2886a41 100644 --- a/packages/taler-wallet-webextension/src/popup/Application.tsx +++ b/packages/taler-wallet-webextension/src/popup/Application.tsx @@ -61,7 +61,7 @@ export function Application(): VNode { <IoCProviderForRuntime> <PendingTransactions goToTransaction={(txId: string) => - route(Pages.balance_transaction.replace(":tid", txId)) + redirectTo(Pages.balance_transaction.replace(":tid", txId)) } /> <Match> @@ -74,15 +74,19 @@ export function Application(): VNode { path={Pages.balance} component={BalancePage} goToWalletManualWithdraw={() => - route( + redirectTo( Pages.balance_manual_withdraw.replace(":currency?", ""), ) } goToWalletDeposit={(currency: string) => - route(Pages.balance_deposit.replace(":currency", currency)) + redirectTo( + Pages.balance_deposit.replace(":currency", currency), + ) } goToWalletHistory={(currency: string) => - route(Pages.balance_history.replace(":currency?", currency)) + redirectTo( + Pages.balance_history.replace(":currency?", currency), + ) } /> @@ -96,7 +100,7 @@ export function Application(): VNode { url={decodeURIComponent(action)} onDismiss={() => { setDismissed(true); - route(Pages.balance); + return redirectTo(Pages.balance); }} /> ); @@ -106,16 +110,12 @@ export function Application(): VNode { <Route path={Pages.backup} component={BackupPage} - onAddProvider={() => { - route(Pages.backup_provider_add); - }} + onAddProvider={() => redirectTo(Pages.backup_provider_add)} /> <Route path={Pages.backup_provider_detail} component={ProviderDetailPage} - onBack={() => { - route(Pages.backup); - }} + onBack={() => redirectTo(Pages.backup)} /> <Route @@ -175,6 +175,10 @@ function RedirectToWalletPage(): VNode { ); } +async function redirectTo(location: string): Promise<void> { + route(location); +} + function Redirect({ to }: { to: string }): null { useEffect(() => { route(to, true); diff --git a/packages/taler-wallet-webextension/src/popup/BalancePage.tsx b/packages/taler-wallet-webextension/src/popup/BalancePage.tsx index 966782bbe..ea202681c 100644 --- a/packages/taler-wallet-webextension/src/popup/BalancePage.tsx +++ b/packages/taler-wallet-webextension/src/popup/BalancePage.tsx @@ -22,17 +22,17 @@ import { JustInDevMode } from "../components/JustInDevMode.js"; import { Loading } from "../components/Loading.js"; import { LoadingError } from "../components/LoadingError.js"; import { MultiActionButton } from "../components/MultiActionButton.js"; -import { ButtonBoxPrimary, ButtonPrimary } from "../components/styled/index.js"; import { useTranslationContext } from "../context/translation.js"; import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; +import { Button } from "../mui/Button.js"; import { AddNewActionView } from "../wallet/AddNewActionView.js"; import * as wxApi from "../wxApi.js"; import { NoBalanceHelp } from "./NoBalanceHelp.js"; export interface Props { - goToWalletDeposit: (currency: string) => void; - goToWalletHistory: (currency: string) => void; - goToWalletManualWithdraw: () => void; + goToWalletDeposit: (currency: string) => Promise<void>; + goToWalletHistory: (currency: string) => Promise<void>; + goToWalletManualWithdraw: () => Promise<void>; } export function BalancePage({ goToWalletManualWithdraw, @@ -65,7 +65,7 @@ export function BalancePage({ } if (addingAction) { - return <AddNewActionView onCancel={() => setAddingAction(false)} />; + return <AddNewActionView onCancel={async () => setAddingAction(false)} />; } return ( @@ -74,16 +74,16 @@ export function BalancePage({ goToWalletManualWithdraw={goToWalletManualWithdraw} goToWalletDeposit={goToWalletDeposit} goToWalletHistory={goToWalletHistory} - goToAddAction={() => setAddingAction(true)} + goToAddAction={async () => setAddingAction(true)} /> ); } export interface BalanceViewProps { balances: Balance[]; - goToWalletManualWithdraw: () => void; - goToAddAction: () => void; - goToWalletDeposit: (currency: string) => void; - goToWalletHistory: (currency: string) => void; + goToWalletManualWithdraw: () => Promise<void>; + goToAddAction: () => Promise<void>; + goToWalletDeposit: (currency: string) => Promise<void>; + goToWalletHistory: (currency: string) => Promise<void>; } export function BalanceView({ @@ -113,22 +113,20 @@ export function BalanceView({ /> </section> <footer style={{ justifyContent: "space-between" }}> - <ButtonPrimary onClick={goToWalletManualWithdraw}> + <Button variant="contained" onClick={goToWalletManualWithdraw}> <i18n.Translate>Withdraw</i18n.Translate> - </ButtonPrimary> + </Button> {currencyWithNonZeroAmount.length > 0 && ( <MultiActionButton - label={(s) => ( - <i18n.Translate>Deposit {<span>{s}</span>}</i18n.Translate> - )} + label={(s) => <i18n.Translate>Deposit {s}</i18n.Translate>} actions={currencyWithNonZeroAmount} onClick={(c) => goToWalletDeposit(c)} /> )} <JustInDevMode> - <ButtonBoxPrimary onClick={goToAddAction}> + <Button onClick={goToAddAction}> <i18n.Translate>Enter URI</i18n.Translate> - </ButtonBoxPrimary> + </Button> </JustInDevMode> </footer> </Fragment> diff --git a/packages/taler-wallet-webextension/src/popup/NoBalanceHelp.tsx b/packages/taler-wallet-webextension/src/popup/NoBalanceHelp.tsx index ddce93cd8..20f44b5dc 100644 --- a/packages/taler-wallet-webextension/src/popup/NoBalanceHelp.tsx +++ b/packages/taler-wallet-webextension/src/popup/NoBalanceHelp.tsx @@ -8,7 +8,7 @@ import { Typography } from "../mui/Typography.js"; export function NoBalanceHelp({ goToWalletManualWithdraw, }: { - goToWalletManualWithdraw: () => void; + goToWalletManualWithdraw: () => Promise<void>; }): VNode { return ( <Paper diff --git a/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx b/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx index 2cf546af6..215180366 100644 --- a/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx +++ b/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx @@ -28,16 +28,17 @@ import { Title, } from "../components/styled/index.js"; import { useTranslationContext } from "../context/translation.js"; +import { Button } from "../mui/Button.js"; export interface Props { url: string; - onDismiss: () => void; + onDismiss: () => Promise<void>; } export function TalerActionFound({ url, onDismiss }: Props): VNode { const uriType = classifyTalerUri(url); const { i18n } = useTranslationContext(); - function redirectToWallet(): void { + async function redirectToWallet(): Promise<void> { platform.openWalletURIFromPopup(url); } return ( @@ -51,9 +52,13 @@ export function TalerActionFound({ url, onDismiss }: Props): VNode { <p> <i18n.Translate>This page has pay action.</i18n.Translate> </p> - <ButtonSuccess onClick={redirectToWallet}> + <Button + variant="contained" + color="success" + onClick={redirectToWallet} + > <i18n.Translate>Open pay page</i18n.Translate> - </ButtonSuccess> + </Button> </div> )} {uriType === TalerUriType.TalerWithdraw && ( @@ -63,9 +68,13 @@ export function TalerActionFound({ url, onDismiss }: Props): VNode { This page has a withdrawal action. </i18n.Translate> </p> - <ButtonSuccess onClick={redirectToWallet}> + <Button + variant="contained" + color="success" + onClick={redirectToWallet} + > <i18n.Translate>Open withdraw page</i18n.Translate> - </ButtonSuccess> + </Button> </div> )} {uriType === TalerUriType.TalerTip && ( @@ -73,9 +82,13 @@ export function TalerActionFound({ url, onDismiss }: Props): VNode { <p> <i18n.Translate>This page has a tip action.</i18n.Translate> </p> - <ButtonSuccess onClick={redirectToWallet}> + <Button + variant="contained" + color="success" + onClick={redirectToWallet} + > <i18n.Translate>Open tip page</i18n.Translate> - </ButtonSuccess> + </Button> </div> )} {uriType === TalerUriType.TalerNotifyReserve && ( @@ -85,9 +98,13 @@ export function TalerActionFound({ url, onDismiss }: Props): VNode { This page has a notify reserve action. </i18n.Translate> </p> - <ButtonSuccess onClick={redirectToWallet}> + <Button + variant="contained" + color="success" + onClick={redirectToWallet} + > <i18n.Translate>Notify</i18n.Translate> - </ButtonSuccess> + </Button> </div> )} {uriType === TalerUriType.TalerRefund && ( @@ -95,9 +112,13 @@ export function TalerActionFound({ url, onDismiss }: Props): VNode { <p> <i18n.Translate>This page has a refund action.</i18n.Translate> </p> - <ButtonSuccess onClick={redirectToWallet}> + <Button + variant="contained" + color="success" + onClick={redirectToWallet} + > <i18n.Translate>Open refund page</i18n.Translate> - </ButtonSuccess> + </Button> </div> )} {uriType === TalerUriType.Unknown && ( @@ -113,10 +134,9 @@ export function TalerActionFound({ url, onDismiss }: Props): VNode { </section> <footer> <div /> - <ButtonPrimary onClick={() => onDismiss()}> - {" "} - <i18n.Translate>Dismiss</i18n.Translate>{" "} - </ButtonPrimary> + <Button variant="contained" onClick={onDismiss}> + <i18n.Translate>Dismiss</i18n.Translate> + </Button> </footer> </Fragment> ); diff --git a/packages/taler-wallet-webextension/src/wallet/AddNewActionView.tsx b/packages/taler-wallet-webextension/src/wallet/AddNewActionView.tsx index c4daf458a..cd1fa0763 100644 --- a/packages/taler-wallet-webextension/src/wallet/AddNewActionView.tsx +++ b/packages/taler-wallet-webextension/src/wallet/AddNewActionView.tsx @@ -2,15 +2,12 @@ import { classifyTalerUri, TalerUriType } from "@gnu-taler/taler-util"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { platform } from "../platform/api.js"; -import { - Button, - ButtonSuccess, - InputWithLabel, -} from "../components/styled/index.js"; +import { InputWithLabel } from "../components/styled/index.js"; import { useTranslationContext } from "../context/translation.js"; +import { Button } from "../mui/Button.js"; export interface Props { - onCancel: () => void; + onCancel: () => Promise<void>; } export function AddNewActionView({ onCancel }: Props): VNode { @@ -18,7 +15,7 @@ export function AddNewActionView({ onCancel }: Props): VNode { const uriType = classifyTalerUri(url); const { i18n } = useTranslationContext(); - function redirectToWallet(): void { + async function redirectToWallet(): Promise<void> { platform.openWalletURIFromPopup(url); } @@ -41,11 +38,15 @@ export function AddNewActionView({ onCancel }: Props): VNode { </InputWithLabel> </section> <footer> - <Button onClick={onCancel}> + <Button variant="contained" color="secondary" onClick={onCancel}> <i18n.Translate>Cancel</i18n.Translate> </Button> {uriType !== TalerUriType.Unknown && ( - <ButtonSuccess onClick={redirectToWallet}> + <Button + variant="contained" + color="success" + onClick={redirectToWallet} + > {(() => { switch (uriType) { case TalerUriType.TalerNotifyReserve: @@ -61,7 +62,7 @@ export function AddNewActionView({ onCancel }: Props): VNode { } return <Fragment />; })()} - </ButtonSuccess> + </Button> )} </footer> </Fragment> diff --git a/packages/taler-wallet-webextension/src/wallet/Application.tsx b/packages/taler-wallet-webextension/src/wallet/Application.tsx index 6a7f62c6c..37ea80d96 100644 --- a/packages/taler-wallet-webextension/src/wallet/Application.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Application.tsx @@ -94,7 +94,9 @@ export function Application(): VNode { > <PendingTransactions goToTransaction={(txId: string) => - route(Pages.balance_transaction.replace(":tid", txId)) + redirectTo( + Pages.balance_transaction.replace(":tid", txId), + ) } /> </div> @@ -123,10 +125,12 @@ export function Application(): VNode { path={Pages.balance_history} component={HistoryPage} goToWalletDeposit={(currency: string) => - route(Pages.balance_deposit.replace(":currency", currency)) + redirectTo( + Pages.balance_deposit.replace(":currency", currency), + ) } goToWalletManualWithdraw={(currency?: string) => - route( + redirectTo( Pages.balance_manual_withdraw.replace( ":currency?", currency || "", @@ -137,29 +141,31 @@ export function Application(): VNode { <Route path={Pages.balance_transaction} component={TransactionPage} - goToWalletHistory={(currency?: string) => { - route( + goToWalletHistory={(currency?: string) => + redirectTo( Pages.balance_history.replace(":currency?", currency || ""), - ); - }} + ) + } /> <Route path={Pages.balance_manual_withdraw} component={ManualWithdrawPage} - onCancel={() => { - route(Pages.balance); - }} + onCancel={() => redirectTo(Pages.balance)} /> <Route path={Pages.balance_deposit} component={DepositPage} onCancel={(currency: string) => { - route(Pages.balance_history.replace(":currency?", currency)); + redirectTo( + Pages.balance_history.replace(":currency?", currency), + ); }} onSuccess={(currency: string) => { - route(Pages.balance_history.replace(":currency?", currency)); + redirectTo( + Pages.balance_history.replace(":currency?", currency), + ); setGlobalNotification( <i18n.Translate> All done, your transaction is in progress @@ -178,23 +184,17 @@ export function Application(): VNode { <Route path={Pages.backup} component={BackupPage} - onAddProvider={() => { - route(Pages.backup_provider_add); - }} + onAddProvider={() => redirectTo(Pages.backup_provider_add)} /> <Route path={Pages.backup_provider_detail} component={ProviderDetailPage} - onBack={() => { - route(Pages.backup); - }} + onBack={() => redirectTo(Pages.backup)} /> <Route path={Pages.backup_provider_add} component={ProviderAddPage} - onBack={() => { - route(Pages.backup); - }} + onBack={() => redirectTo(Pages.backup)} /> {/** @@ -203,9 +203,7 @@ export function Application(): VNode { <Route path={Pages.settings_exchange_add} component={ExchangeAddPage} - onBack={() => { - route(Pages.balance); - }} + onBack={() => redirectTo(Pages.balance)} /> {/** @@ -221,14 +219,14 @@ export function Application(): VNode { path={Pages.cta_pay} component={PayPage} goToWalletManualWithdraw={(currency?: string) => - route( + redirectTo( Pages.balance_manual_withdraw.replace( ":currency?", currency || "", ), ) } - goBack={() => route(Pages.balance)} + goBack={() => redirectTo(Pages.balance)} /> <Route path={Pages.cta_refund} component={RefundPage} /> <Route path={Pages.cta_tips} component={TipPage} /> @@ -258,9 +256,12 @@ export function Application(): VNode { ); } +async function redirectTo(location: string): Promise<void> { + route(location); +} + function Redirect({ to }: { to: string }): null { useEffect(() => { - console.log("got some wrong route", to); route(to, true); }); return null; diff --git a/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx b/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx index 505aa600b..1f23be856 100644 --- a/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx +++ b/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx @@ -31,8 +31,6 @@ import { Loading } from "../components/Loading.js"; import { LoadingError } from "../components/LoadingError.js"; import { BoldLight, - ButtonPrimary, - ButtonSuccess, Centered, CenteredBoldText, CenteredText, @@ -42,11 +40,12 @@ import { } from "../components/styled/index.js"; import { useTranslationContext } from "../context/translation.js"; import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; +import { Button } from "../mui/Button.js"; import { Pages } from "../NavigationBar.js"; import * as wxApi from "../wxApi.js"; interface Props { - onAddProvider: () => void; + onAddProvider: () => Promise<void>; } export function BackupPage({ onAddProvider }: Props): VNode { @@ -87,7 +86,7 @@ export function BackupPage({ onAddProvider }: Props): VNode { export interface ViewProps { providers: ProviderInfo[]; - onAddProvider: () => void; + onAddProvider: () => Promise<void>; onSyncAll: () => Promise<void>; } @@ -121,9 +120,9 @@ export function BackupView({ <BoldLight> <i18n.Translate>No backup providers configured</i18n.Translate> </BoldLight> - <ButtonSuccess onClick={onAddProvider}> + <Button variant="contained" color="success" onClick={onAddProvider}> <i18n.Translate>Add provider</i18n.Translate> - </ButtonSuccess> + </Button> </Centered> )} </section> @@ -131,16 +130,16 @@ export function BackupView({ <footer> <div /> <div> - <ButtonPrimary onClick={onSyncAll}> + <Button variant="contained" onClick={onSyncAll}> {providers.length > 1 ? ( <i18n.Translate>Sync all backups</i18n.Translate> ) : ( <i18n.Translate>Sync now</i18n.Translate> )} - </ButtonPrimary> - <ButtonSuccess onClick={onAddProvider}> + </Button> + <Button variant="contained" color="success" onClick={onAddProvider}> <i18n.Translate>Add provider</i18n.Translate> - </ButtonSuccess> + </Button> </div> </footer> )} diff --git a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx index 11bade6f5..502e9f8ad 100644 --- a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx +++ b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx @@ -21,14 +21,12 @@ */ import { AmountJson, Amounts } from "@gnu-taler/taler-util"; -import { TalerError } from "@gnu-taler/taler-wallet-core"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { ErrorMessage } from "../components/ErrorMessage.js"; import { SelectList } from "../components/SelectList.js"; import { BoldLight, - ButtonPrimary, Centered, Input, InputWithLabel, @@ -37,6 +35,7 @@ import { SubTitle, } from "../components/styled/index.js"; import { useTranslationContext } from "../context/translation.js"; +import { Button } from "../mui/Button.js"; import { SelectFieldHandler, TextFieldHandler } from "../mui/handlers.js"; import { Pages } from "../NavigationBar.js"; @@ -270,12 +269,13 @@ export function CreateManualWithdraw({ </section> <footer> <div /> - <ButtonPrimary + <Button + variant="contained" disabled={!state.parsedAmount || !state.exchange.value} onClick={() => onCreate(state.exchange.value, state.parsedAmount!)} > <i18n.Translate>Start withdrawal</i18n.Translate> - </ButtonPrimary> + </Button> </footer> </Fragment> ); diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage.tsx b/packages/taler-wallet-webextension/src/wallet/DepositPage.tsx index 9b8008175..1546674f1 100644 --- a/packages/taler-wallet-webextension/src/wallet/DepositPage.tsx +++ b/packages/taler-wallet-webextension/src/wallet/DepositPage.tsx @@ -23,8 +23,6 @@ import { Loading } from "../components/Loading.js"; import { LoadingError } from "../components/LoadingError.js"; import { SelectList } from "../components/SelectList.js"; import { - Button, - ButtonPrimary, ErrorText, Input, InputWithLabel, @@ -33,6 +31,7 @@ import { } from "../components/styled/index.js"; import { useTranslationContext } from "../context/translation.js"; import { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; +import { Button } from "../mui/Button.js"; import { ButtonHandler, SelectFieldHandler, @@ -275,7 +274,11 @@ export function View({ state }: ViewProps): VNode { </p> </WarningBox> <footer> - <Button onClick={state.cancelHandler.onClick}> + <Button + variant="contained" + color="secondary" + onClick={state.cancelHandler.onClick} + > <i18n.Translate>Cancel</i18n.Translate> </Button> </footer> @@ -345,20 +348,24 @@ export function View({ state }: ViewProps): VNode { } </section> <footer> - <Button onClick={state.cancelHandler.onClick}> + <Button + variant="contained" + color="secondary" + onClick={state.cancelHandler.onClick} + > <i18n.Translate>Cancel</i18n.Translate> </Button> {!state.depositHandler.onClick ? ( - <ButtonPrimary disabled> + <Button variant="contained" disabled> <i18n.Translate>Deposit</i18n.Translate> - </ButtonPrimary> + </Button> ) : ( - <ButtonPrimary onClick={state.depositHandler.onClick}> + <Button variant="contained" onClick={state.depositHandler.onClick}> <i18n.Translate> Deposit {Amounts.stringifyValue(state.totalToDeposit)}{" "} {state.currency} </i18n.Translate> - </ButtonPrimary> + </Button> )} </footer> </Fragment> diff --git a/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx b/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx index c4725a8d7..e71ea48f0 100644 --- a/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx +++ b/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx @@ -30,6 +30,9 @@ import { Time } from "../components/Time.js"; import { useTranslationContext } from "../context/translation.js"; import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; import { useDiagnostics } from "../hooks/useDiagnostics.js"; +import { Button } from "../mui/Button.js"; +import { Grid } from "../mui/Grid.js"; +import { Paper } from "../mui/Paper.js"; import * as wxApi from "../wxApi.js"; export function DeveloperPage(): VNode { @@ -133,7 +136,6 @@ export function View({ const money_by_exchange = coins.reduce( (prev, cur) => { const denom = Amounts.parseOrThrow(cur.denom_value); - console.log(cur); if (!prev[cur.exchange_base_url]) { prev[cur.exchange_base_url] = []; currencies[cur.exchange_base_url] = denom.currency; @@ -154,57 +156,72 @@ export function View({ [exchange_name: string]: CalculatedCoinfInfo[]; }, ); - + function Item({ children }: any) { + return <div>{children}</div>; + } return ( <div> <p> <i18n.Translate>Debug tools</i18n.Translate>: </p> - <button - onClick={() => - confirmReset( - i18n.str`Do you want to IRREVOCABLY DESTROY everything inside your wallet and LOSE ALL YOUR COINS?`, - wxApi.resetDb, - ) - } - > - <i18n.Translate>reset</i18n.Translate> - </button> - <button - onClick={() => - confirmReset( - i18n.str`TESTING: This may delete all your coin, proceed with caution`, - wxApi.runGarbageCollector, - ) - } - > - <i18n.Translate>run gc</i18n.Translate> - </button> - <br /> - <button onClick={() => fileRef?.current?.click()}> - <i18n.Translate>import database</i18n.Translate> - </button> - <input - ref={fileRef} - style={{ display: "none" }} - type="file" - onChange={async (e) => { - const f: FileList | null = e.currentTarget.files; - if (!f || f.length != 1) { - return Promise.reject(); - } - const buf = await f[0].arrayBuffer(); - const str = new Uint8Array(buf).reduce( - (data, byte) => data + String.fromCharCode(byte), - "", - ); - return onImportDatabase(str); - }} - /> - <br /> - <button onClick={onExportDatabase}> - <i18n.Translate>export database</i18n.Translate> - </button> + <Grid container justifyContent="space-between" spacing={1}> + <Grid item> + <Button + variant="contained" + onClick={() => + confirmReset( + i18n.str`Do you want to IRREVOCABLY DESTROY everything inside your wallet and LOSE ALL YOUR COINS?`, + wxApi.resetDb, + ) + } + > + <i18n.Translate>reset</i18n.Translate> + </Button> + </Grid> + <Grid item> + <Button + variant="contained" + onClick={() => + confirmReset( + i18n.str`TESTING: This may delete all your coin, proceed with caution`, + wxApi.runGarbageCollector, + ) + } + > + <i18n.Translate>run gc</i18n.Translate> + </Button> + </Grid> + <Grid item> + <Button + variant="contained" + onClick={async () => fileRef?.current?.click()} + > + <i18n.Translate>import database</i18n.Translate> + </Button> + </Grid> + <Grid item> + <input + ref={fileRef} + style={{ display: "none" }} + type="file" + onChange={async (e) => { + const f: FileList | null = e.currentTarget.files; + if (!f || f.length != 1) { + return Promise.reject(); + } + const buf = await f[0].arrayBuffer(); + const str = new Uint8Array(buf).reduce( + (data, byte) => data + String.fromCharCode(byte), + "", + ); + return onImportDatabase(str); + }} + /> + <Button variant="contained" onClick={onExportDatabase}> + <i18n.Translate>export database</i18n.Translate> + </Button> + </Grid> + </Grid> {downloadedDatabase && ( <div> <i18n.Translate> diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.tsx b/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.tsx index 135cf68d8..6f6e7a1ba 100644 --- a/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.tsx +++ b/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.tsx @@ -1,21 +1,17 @@ import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; -import { - Button, - ButtonSuccess, - ButtonWarning, - Title, -} from "../components/styled/index.js"; +import { Title } from "../components/styled/index.js"; import { useTranslationContext } from "../context/translation.js"; import { TermsOfServiceSection } from "../cta/TermsOfServiceSection.js"; import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; +import { Button } from "../mui/Button.js"; import { buildTermsOfServiceState, TermsState } from "../utils/index.js"; import * as wxApi from "../wxApi.js"; export interface Props { url: string; - onCancel: () => void; - onConfirm: () => void; + onCancel: () => Promise<void>; + onConfirm: () => Promise<void>; } export function ExchangeAddConfirmPage({ @@ -71,8 +67,8 @@ export interface ViewProps { url: string; terms: TermsState | undefined; onAccept: (b: boolean) => Promise<void>; - onCancel: () => void; - onConfirm: () => void; + onCancel: () => Promise<void>; + onConfirm: () => Promise<void>; } export function View({ @@ -114,30 +110,35 @@ export function View({ )} <footer> - <Button onClick={onCancel}> + <Button variant="contained" color="secondary" onClick={onCancel}> <i18n.Translate>Cancel</i18n.Translate> </Button> {!terms && ( - <Button disabled> + <Button variant="contained" disabled> <i18n.Translate>Loading terms..</i18n.Translate> </Button> )} {terms && ( <Fragment> {needsReview && !reviewed && ( - <ButtonSuccess disabled upperCased onClick={onConfirm}> + <Button + variant="contained" + color="success" + disabled + onClick={onConfirm} + > <i18n.Translate>Add exchange</i18n.Translate> - </ButtonSuccess> + </Button> )} {(terms.status === "accepted" || (needsReview && reviewed)) && ( - <ButtonSuccess upperCased onClick={onConfirm}> + <Button variant="contained" color="success" onClick={onConfirm}> <i18n.Translate>Add exchange</i18n.Translate> - </ButtonSuccess> + </Button> )} {terms.status === "notfound" && ( - <ButtonWarning upperCased onClick={onConfirm}> + <Button variant="contained" color="warning" onClick={onConfirm}> <i18n.Translate>Add exchange anyway</i18n.Translate> - </ButtonWarning> + </Button> )} </Fragment> )} diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeAddPage.tsx b/packages/taler-wallet-webextension/src/wallet/ExchangeAddPage.tsx index df423bb2b..42a5b4c9c 100644 --- a/packages/taler-wallet-webextension/src/wallet/ExchangeAddPage.tsx +++ b/packages/taler-wallet-webextension/src/wallet/ExchangeAddPage.tsx @@ -28,7 +28,7 @@ import { ExchangeSetUrlPage } from "./ExchangeSetUrl.js"; interface Props { currency?: string; - onBack: () => void; + onBack: () => Promise<void>; } export function ExchangeAddPage({ currency, onBack }: Props): VNode { diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeSetUrl.tsx b/packages/taler-wallet-webextension/src/wallet/ExchangeSetUrl.tsx index ad8cb7db0..755cf425f 100644 --- a/packages/taler-wallet-webextension/src/wallet/ExchangeSetUrl.tsx +++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSetUrl.tsx @@ -6,8 +6,6 @@ import { Fragment, h, VNode } from "preact"; import { useEffect, useState } from "preact/hooks"; import { ErrorMessage } from "../components/ErrorMessage.js"; import { - Button, - ButtonPrimary, Input, LightText, SubTitle, @@ -15,11 +13,12 @@ import { WarningBox, } from "../components/styled/index.js"; import { useTranslationContext } from "../context/translation.js"; +import { Button } from "../mui/Button.js"; export interface Props { initialValue?: string; expectedCurrency?: string; - onCancel: () => void; + onCancel: () => Promise<void>; onVerify: (s: string) => Promise<TalerConfigResponse | undefined>; onConfirm: (url: string) => Promise<string | undefined>; withError?: string; @@ -64,7 +63,7 @@ function useEndpointStatus<T>( } }, 500); setHandler(h); - }, [value, setHandler, handler, onVerify]); + }, [value, setHandler, onVerify]); return { error: dirty ? error : undefined, @@ -172,10 +171,11 @@ export function ExchangeSetUrlPage({ </p> </section> <footer> - <Button onClick={onCancel}> + <Button variant="contained" color="secondary" onClick={onCancel}> <i18n.Translate>Cancel</i18n.Translate> </Button> - <ButtonPrimary + <Button + variant="contained" disabled={ !result || !!error || @@ -189,7 +189,7 @@ export function ExchangeSetUrlPage({ }} > <i18n.Translate>Next</i18n.Translate> - </ButtonPrimary> + </Button> </footer> </Fragment> ); diff --git a/packages/taler-wallet-webextension/src/wallet/History.tsx b/packages/taler-wallet-webextension/src/wallet/History.tsx index 59f245522..1ab879195 100644 --- a/packages/taler-wallet-webextension/src/wallet/History.tsx +++ b/packages/taler-wallet-webextension/src/wallet/History.tsx @@ -26,7 +26,6 @@ import { Loading } from "../components/Loading.js"; import { LoadingError } from "../components/LoadingError.js"; import { ButtonBoxPrimary, - ButtonPrimary, CenteredBoldText, CenteredText, DateSeparator, @@ -36,13 +35,14 @@ import { Time } from "../components/Time.js"; import { TransactionItem } from "../components/TransactionItem.js"; import { useTranslationContext } from "../context/translation.js"; import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; +import { Button } from "../mui/Button.js"; import { NoBalanceHelp } from "../popup/NoBalanceHelp.js"; import * as wxApi from "../wxApi.js"; interface Props { currency?: string; - goToWalletDeposit: (currency: string) => void; - goToWalletManualWithdraw: (currency?: string) => void; + goToWalletDeposit: (currency: string) => Promise<void>; + goToWalletManualWithdraw: (currency?: string) => Promise<void>; } export function HistoryPage({ currency, @@ -101,8 +101,8 @@ export function HistoryView({ goToWalletManualWithdraw, goToWalletDeposit, }: { - goToWalletDeposit: (currency: string) => void; - goToWalletManualWithdraw: (currency?: string) => void; + goToWalletDeposit: (currency: string) => Promise<void>; + goToWalletManualWithdraw: (currency?: string) => Promise<void>; defaultCurrency?: string; transactions: Transaction[]; balances: Balance[]; @@ -198,19 +198,22 @@ export function HistoryView({ )} </div> <div> - <ButtonPrimary - style={{ marginLeft: 0, marginTop: 8 }} + <Button + variant="contained" + // style={{ marginLeft: 0, marginTop: 8 }} onClick={() => goToWalletManualWithdraw(selectedCurrency)} > <i18n.Translate>Withdraw</i18n.Translate> - </ButtonPrimary> + </Button> {currencyAmount && Amounts.isNonZero(currencyAmount) && ( - <ButtonBoxPrimary - style={{ marginLeft: 0, marginTop: 8 }} + <Button + variant="outlined" + color="primary" + // style={{ marginLeft: 0, marginTop: 8 }} onClick={() => goToWalletDeposit(selectedCurrency)} > <i18n.Translate>Deposit</i18n.Translate> - </ButtonBoxPrimary> + </Button> )} </div> </div> diff --git a/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx b/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx index daa46086e..05ac9cf7f 100644 --- a/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx +++ b/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx @@ -34,7 +34,7 @@ import { ReserveCreated } from "./ReserveCreated.js"; interface Props { currency?: string; - onCancel: () => void; + onCancel: () => Promise<void>; } export function ManualWithdrawPage({ currency, onCancel }: Props): VNode { diff --git a/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx b/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx index ed4a91f12..7e8dc6589 100644 --- a/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx +++ b/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx @@ -25,8 +25,6 @@ import { useEffect, useState } from "preact/hooks"; import { Checkbox } from "../components/Checkbox.js"; import { ErrorMessage } from "../components/ErrorMessage.js"; import { - Button, - ButtonPrimary, Input, LightText, SmallLightText, @@ -34,12 +32,13 @@ import { Title, } from "../components/styled/index.js"; import { useTranslationContext } from "../context/translation.js"; +import { Button } from "../mui/Button.js"; import { queryToSlashConfig } from "../utils/index.js"; import * as wxApi from "../wxApi.js"; interface Props { currency: string; - onBack: () => void; + onBack: () => Promise<void>; } export function ProviderAddPage({ onBack }: Props): VNode { @@ -67,11 +66,13 @@ export function ProviderAddPage({ onBack }: Props): VNode { <ConfirmProviderView provider={verifying.provider} url={verifying.url} - onCancel={() => { + onCancel={async () => { setVerifying(undefined); }} onConfirm={() => { - wxApi.addBackupProvider(verifying.url, verifying.name).then(onBack); + return wxApi + .addBackupProvider(verifying.url, verifying.name) + .then(onBack); }} /> ); @@ -79,7 +80,7 @@ export function ProviderAddPage({ onBack }: Props): VNode { export interface SetUrlViewProps { initialValue?: string; - onCancel: () => void; + onCancel: () => Promise<void>; onVerify: (s: string) => Promise<BackupBackupProviderTerms | undefined>; onConfirm: (url: string, name: string) => Promise<string | undefined>; withError?: string; @@ -161,10 +162,11 @@ export function SetUrlView({ </p> </section> <footer> - <Button onClick={onCancel}> + <Button variant="contained" color="secondary" onClick={onCancel}> <i18n.Translate>Cancel</i18n.Translate> </Button> - <ButtonPrimary + <Button + variant="contained" disabled={!value && !urlError} onClick={() => { const url = canonicalizeBaseUrl(value); @@ -174,7 +176,7 @@ export function SetUrlView({ }} > <i18n.Translate>Next</i18n.Translate> - </ButtonPrimary> + </Button> </footer> </Fragment> ); @@ -183,8 +185,8 @@ export function SetUrlView({ export interface ConfirmProviderViewProps { provider: BackupBackupProviderTerms; url: string; - onCancel: () => void; - onConfirm: () => void; + onCancel: () => Promise<void>; + onConfirm: () => Promise<void>; } export function ConfirmProviderView({ url, @@ -236,17 +238,17 @@ export function ConfirmProviderView({ <Checkbox label={<i18n.Translate>Accept terms of service</i18n.Translate>} name="terms" - onToggle={() => setAccepted((old) => !old)} + onToggle={async () => setAccepted((old) => !old)} enabled={accepted} /> </section> <footer> - <Button onClick={onCancel}> + <Button variant="contained" color="secondary" onClick={onCancel}> <i18n.Translate>Cancel</i18n.Translate> </Button> - <ButtonPrimary disabled={!accepted} onClick={onConfirm}> + <Button variant="contained" disabled={!accepted} onClick={onConfirm}> <i18n.Translate>Add provider</i18n.Translate> - </ButtonPrimary> + </Button> </footer> </Fragment> ); diff --git a/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx b/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx index bf9f55b10..7ea29286b 100644 --- a/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx +++ b/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx @@ -25,21 +25,16 @@ import { Fragment, h, VNode } from "preact"; import { ErrorMessage } from "../components/ErrorMessage.js"; import { Loading } from "../components/Loading.js"; import { LoadingError } from "../components/LoadingError.js"; -import { - Button, - ButtonDestructive, - ButtonPrimary, - PaymentStatus, - SmallLightText, -} from "../components/styled/index.js"; +import { PaymentStatus, SmallLightText } from "../components/styled/index.js"; import { Time } from "../components/Time.js"; import { useTranslationContext } from "../context/translation.js"; import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; +import { Button } from "../mui/Button.js"; import * as wxApi from "../wxApi.js"; interface Props { pid: string; - onBack: () => void; + onBack: () => Promise<void>; } export function ProviderDetailPage({ pid: providerURL, onBack }: Props): VNode { @@ -77,10 +72,10 @@ export function ProviderDetailPage({ pid: providerURL, onBack }: Props): VNode { <ProviderView url={providerURL} info={state.response} - onSync={async () => wxApi.syncOneProvider(providerURL)} - onDelete={async () => wxApi.removeProvider(providerURL).then(onBack)} + onSync={() => wxApi.syncOneProvider(providerURL)} + onDelete={() => wxApi.removeProvider(providerURL).then(onBack)} onBack={onBack} - onExtend={() => { + onExtend={async () => { null; }} /> @@ -90,10 +85,10 @@ export function ProviderDetailPage({ pid: providerURL, onBack }: Props): VNode { export interface ViewProps { url: string; info: ProviderInfo | null; - onDelete: () => void; - onSync: () => void; - onBack: () => void; - onExtend: () => void; + onDelete: () => Promise<void>; + onSync: () => Promise<void>; + onBack: () => Promise<void>; + onExtend: () => Promise<void>; } export function ProviderView({ @@ -116,7 +111,7 @@ export function ProviderView({ </p> </section> <footer> - <Button onClick={onBack}> + <Button variant="contained" color="secondary" onClick={onBack}> <i18n.Translate>See providers</i18n.Translate> </Button> <div /> @@ -149,9 +144,9 @@ export function ProviderView({ </b>{" "} <Time timestamp={lb} format="dd MMMM yyyy" /> </p> - <ButtonPrimary onClick={onSync}> + <Button variant="contained" onClick={onSync}> <i18n.Translate>Back up</i18n.Translate> - </ButtonPrimary> + </Button> {info.terms && ( <Fragment> <p> @@ -164,9 +159,9 @@ export function ProviderView({ </Fragment> )} <p>{descriptionByStatus(info.paymentStatus, i18n)}</p> - <ButtonPrimary disabled onClick={onExtend}> + <Button variant="contained" disabled onClick={onExtend}> <i18n.Translate>Extend</i18n.Translate> - </ButtonPrimary> + </Button> {info.paymentStatus.type === ProviderPaymentType.TermsChanged && ( <div> @@ -212,13 +207,13 @@ export function ProviderView({ )} </section> <footer> - <Button onClick={onBack}> + <Button variant="contained" color="secondary" onClick={onBack}> <i18n.Translate>See providers</i18n.Translate> </Button> <div> - <ButtonDestructive onClick={onDelete}> + <Button variant="contained" color="error" onClick={onDelete}> <i18n.Translate>Remove provider</i18n.Translate> - </ButtonDestructive> + </Button> </div> </footer> </Fragment> diff --git a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx index 02d8fe6a8..ad6bdb9cc 100644 --- a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx +++ b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx @@ -4,18 +4,15 @@ import { Amount } from "../components/Amount.js"; import { BankDetailsByPaytoType } from "../components/BankDetailsByPaytoType.js"; import { ErrorMessage } from "../components/ErrorMessage.js"; import { QR } from "../components/QR.js"; -import { - ButtonDestructive, - Title, - WarningBox, -} from "../components/styled/index.js"; +import { Title, WarningBox } from "../components/styled/index.js"; import { useTranslationContext } from "../context/translation.js"; +import { Button } from "../mui/Button.js"; export interface Props { reservePub: string; paytoURI: PaytoUri | undefined; exchangeBaseUrl: string; amount: AmountJson; - onCancel: () => void; + onCancel: () => Promise<void>; } export function ReserveCreated({ @@ -82,9 +79,9 @@ export function ReserveCreated({ </section> <footer> <div /> - <ButtonDestructive onClick={onCancel}> + <Button variant="contained" color="error" onClick={onCancel}> <i18n.Translate>Cancel withdrawal</i18n.Translate> - </ButtonDestructive> + </Button> </footer> </Fragment> ); diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.tsx b/packages/taler-wallet-webextension/src/wallet/Settings.tsx index 83ce76ade..be75c1eac 100644 --- a/packages/taler-wallet-webextension/src/wallet/Settings.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Settings.tsx @@ -66,7 +66,7 @@ export interface ViewProps { setDeviceName: (s: string) => Promise<void>; permissionToggle: ToggleHandler; developerMode: boolean; - toggleDeveloperMode: () => void; + toggleDeveloperMode: () => Promise<void>; knownExchanges: Array<ExchangeListItem>; } diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx index 1170c9222..b78039ddd 100644 --- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx @@ -21,7 +21,6 @@ import { Location, NotificationType, parsePaytoUri, - parsePayUri, PaytoUri, stringifyPaytoUri, TalerProtocolTimestamp, @@ -47,17 +46,11 @@ import { Loading } from "../components/Loading.js"; import { LoadingError } from "../components/LoadingError.js"; import { Kind, Part, PartCollapsible, PartPayto } from "../components/Part.js"; import { - Button, - ButtonBox, - ButtonDestructive, - ButtonPrimary, CenteredDialog, - HistoryRow, InfoBox, ListOfProducts, Overlay, Row, - RowBorderGray, SmallLightText, SubTitle, WarningBox, @@ -65,12 +58,13 @@ import { import { Time } from "../components/Time.js"; import { useTranslationContext } from "../context/translation.js"; import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; +import { Button } from "../mui/Button.js"; import { Pages } from "../NavigationBar.js"; import * as wxApi from "../wxApi.js"; interface Props { tid: string; - goToWalletHistory: (currency?: string) => void; + goToWalletHistory: (currency?: string) => Promise<void>; } async function getTransaction(tid: string): Promise<Transaction> { @@ -122,7 +116,7 @@ export function TransactionPage({ tid, goToWalletHistory }: Props): VNode { onRetry={() => wxApi.retryTransaction(tid).then(() => goToWalletHistory(currency)) } - onRefund={(id) => wxApi.applyRefundFromPurchaseId(id)} + onRefund={(id) => wxApi.applyRefundFromPurchaseId(id).then()} onBack={() => goToWalletHistory(currency)} /> ); @@ -130,10 +124,10 @@ export function TransactionPage({ tid, goToWalletHistory }: Props): VNode { export interface WalletTransactionProps { transaction: Transaction; - onDelete: () => void; - onRetry: () => void; - onRefund: (id: string) => void; - onBack: () => void; + onDelete: () => Promise<void>; + onRetry: () => Promise<void>; + onRefund: (id: string) => Promise<void>; + onBack: () => Promise<void>; } const PurchaseDetailsTable = styled.table` @@ -152,7 +146,7 @@ export function TransactionView({ }: WalletTransactionProps): VNode { const [confirmBeforeForget, setConfirmBeforeForget] = useState(false); - function doCheckBeforeForget(): void { + async function doCheckBeforeForget(): Promise<void> { if ( transaction.pending && transaction.type === TransactionType.Withdrawal @@ -198,13 +192,17 @@ export function TransactionView({ <div /> <div> {showRetry ? ( - <ButtonPrimary onClick={onRetry}> + <Button variant="contained" onClick={onRetry}> <i18n.Translate>Retry</i18n.Translate> - </ButtonPrimary> + </Button> ) : null} - <ButtonDestructive onClick={doCheckBeforeForget}> + <Button + variant="contained" + color="error" + onClick={doCheckBeforeForget} + > <i18n.Translate>Forget</i18n.Translate> - </ButtonDestructive> + </Button> </div> </footer> </Fragment> @@ -229,13 +227,17 @@ export function TransactionView({ </i18n.Translate> </section> <footer> - <Button onClick={() => setConfirmBeforeForget(false)}> + <Button + variant="contained" + color="secondary" + onClick={async () => setConfirmBeforeForget(false)} + > <i18n.Translate>Cancel</i18n.Translate> </Button> - <ButtonDestructive onClick={onDelete}> + <Button variant="contained" color="error" onClick={onDelete}> <i18n.Translate>Confirm</i18n.Translate> - </ButtonDestructive> + </Button> </footer> </CenteredDialog> </Overlay> @@ -387,9 +389,12 @@ export function TransactionView({ <div> <div /> <div> - <ButtonPrimary onClick={() => onRefund(transaction.proposalId)}> + <Button + variant="contained" + onClick={() => onRefund(transaction.proposalId)} + > <i18n.Translate>Accept</i18n.Translate> - </ButtonPrimary> + </Button> </div> </div> </InfoBox> |