diff options
Diffstat (limited to 'packages/taler-wallet-webextension')
13 files changed, 262 insertions, 53 deletions
diff --git a/packages/taler-wallet-webextension/src/background.ts b/packages/taler-wallet-webextension/src/background.ts index d0abd4805..ab572ea73 100644 --- a/packages/taler-wallet-webextension/src/background.ts +++ b/packages/taler-wallet-webextension/src/background.ts @@ -28,7 +28,7 @@ import firefoxAPI from "./platform/firefox.js"; import chromeAPI from "./platform/chrome.js"; import { wxMain } from "./wxBackend.js"; -const isFirefox = typeof (window as any)['InstallTrigger'] !== 'undefined' +const isFirefox = typeof (window as any) !== 'undefined' && typeof (window as any)['InstallTrigger'] !== 'undefined' // FIXME: create different entry point for any platform instead of // switching in runtime diff --git a/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx b/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx index 3804ab3d3..7dbb7723d 100644 --- a/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx +++ b/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx @@ -147,7 +147,7 @@ export const TicketWithAProductList = createExample(TestedComponent, { }, }); -export const AlreadyConfirmedWithFullfilment = createExample(TestedComponent, { +export const AlreadyConfirmedByOther = createExample(TestedComponent, { payStatus: { status: PreparePayResultType.AlreadyConfirmed, amountEffective: "USD:10", @@ -156,8 +156,6 @@ export const AlreadyConfirmedWithFullfilment = createExample(TestedComponent, { merchant: { name: "someone", }, - fulfillment_message: - "congratulations! you are looking at the fulfillment message! ", summary: "some beers", amount: "USD:10", } as Partial<ContractTerms> as any, @@ -167,28 +165,25 @@ export const AlreadyConfirmedWithFullfilment = createExample(TestedComponent, { }, }); -export const AlreadyConfirmedWithoutFullfilment = createExample( - TestedComponent, - { - payStatus: { - status: PreparePayResultType.AlreadyConfirmed, - amountEffective: "USD:10", - amountRaw: "USD:10", - contractTerms: { - merchant: { - name: "someone", - }, - summary: "some beers", - amount: "USD:10", - } as Partial<ContractTerms> as any, - contractTermsHash: "123456", - proposalId: "proposal1234", - paid: false, - }, +export const AlreadyPaidWithoutFulfillment = createExample(TestedComponent, { + payStatus: { + status: PreparePayResultType.AlreadyConfirmed, + amountEffective: "USD:10", + amountRaw: "USD:10", + contractTerms: { + merchant: { + name: "someone", + }, + summary: "some beers", + amount: "USD:10", + } as Partial<ContractTerms> as any, + contractTermsHash: "123456", + proposalId: "proposal1234", + paid: true, }, -); +}); -export const AlreadyPaid = createExample(TestedComponent, { +export const AlreadyPaidWithFulfillment = createExample(TestedComponent, { payStatus: { status: PreparePayResultType.AlreadyConfirmed, amountEffective: "USD:10", diff --git a/packages/taler-wallet-webextension/src/cta/Pay.tsx b/packages/taler-wallet-webextension/src/cta/Pay.tsx index 13fb69853..359625999 100644 --- a/packages/taler-wallet-webextension/src/cta/Pay.tsx +++ b/packages/taler-wallet-webextension/src/cta/Pay.tsx @@ -105,6 +105,23 @@ export function PayPage({ return { payStatus, balance }; }, [NotificationType.CoinWithdrawn]); + useEffect(() => { + const payStatus = + hook && !hook.hasError ? hook.response.payStatus : undefined; + if ( + payStatus && + payStatus.status === PreparePayResultType.AlreadyConfirmed && + payStatus.paid + ) { + const fu = payStatus.contractTerms.fulfillment_url; + if (fu) { + setTimeout(() => { + document.location.href = fu; + }, 3000); + } + } + }, []); + if (!hook) { return <Loading />; } @@ -172,20 +189,6 @@ export function PaymentRequestView({ let totalFees: AmountJson = Amounts.getZero(payStatus.amountRaw); const contractTerms: ContractTerms = payStatus.contractTerms; - useEffect(() => { - if ( - payStatus.status === PreparePayResultType.AlreadyConfirmed && - payStatus.paid - ) { - const fu = payStatus.contractTerms.fulfillment_url; - if (fu) { - setTimeout(() => { - document.location.href = fu; - }, 3000); - } - } - }); - if (!contractTerms) { return ( <ErrorMessage diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx index dee063637..eb18251fd 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx +++ b/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx @@ -136,9 +136,7 @@ export const TermsReviewingHTML = createExample(TestedComponent, { terms: { content: { type: "html", - href: new URL( - `data:text/html;base64,${Buffer.from(termsHtml).toString("base64")}`, - ), + href: new URL(`data:text/html;base64,${toBase64(termsHtml)}`), }, version: "", status: "new", @@ -146,6 +144,14 @@ export const TermsReviewingHTML = createExample(TestedComponent, { reviewing: true, }); +function toBase64(str: string): string { + return btoa( + encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) { + return String.fromCharCode(parseInt(p1, 16)); + }), + ); +} + export const TermsReviewingPDF = createExample(TestedComponent, { knownExchanges: exchangeList, exchangeBaseUrl: "exchange.demo.taler.net", @@ -166,9 +172,7 @@ export const TermsReviewingPDF = createExample(TestedComponent, { terms: { content: { type: "pdf", - location: new URL( - `data:text/html;base64,${Buffer.from(termsPdf).toString("base64")}`, - ), + location: new URL(`data:text/html;base64,${toBase64(termsPdf)}`), }, status: "new", version: "", diff --git a/packages/taler-wallet-webextension/src/cta/index.stories.ts b/packages/taler-wallet-webextension/src/cta/index.stories.ts new file mode 100644 index 000000000..225b784a6 --- /dev/null +++ b/packages/taler-wallet-webextension/src/cta/index.stories.ts @@ -0,0 +1,28 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import * as a1 from "./Deposit.stories.jsx"; +import * as a3 from "./Pay.stories.jsx"; +import * as a4 from "./Refund.stories.jsx"; +import * as a5 from "./Tip.stories.jsx"; +import * as a6 from "./Withdraw.stories.jsx"; + +export default [a1, a3, a4, a5, a6]; diff --git a/packages/taler-wallet-webextension/src/mui/TextField.stories.tsx b/packages/taler-wallet-webextension/src/mui/TextField.stories.tsx index 85550aabf..e46b7f46f 100644 --- a/packages/taler-wallet-webextension/src/mui/TextField.stories.tsx +++ b/packages/taler-wallet-webextension/src/mui/TextField.stories.tsx @@ -33,7 +33,7 @@ const Container = styled.div` display: flex; flex-direction: column; & > * { - margin: 20px; + margin-bottom: 20px !important; } `; diff --git a/packages/taler-wallet-webextension/src/mui/TextField.tsx b/packages/taler-wallet-webextension/src/mui/TextField.tsx index c79c21ced..1987e9f6b 100644 --- a/packages/taler-wallet-webextension/src/mui/TextField.tsx +++ b/packages/taler-wallet-webextension/src/mui/TextField.tsx @@ -54,7 +54,7 @@ export function TextField({ select, helperText, children, - variant = "standard", + variant = "filled", ...props }: Props): VNode { // htmlFor={id} id={inputLabelId} diff --git a/packages/taler-wallet-webextension/src/mui/input/FormControl.tsx b/packages/taler-wallet-webextension/src/mui/input/FormControl.tsx index 0f73f8c02..ef08e97b6 100644 --- a/packages/taler-wallet-webextension/src/mui/input/FormControl.tsx +++ b/packages/taler-wallet-webextension/src/mui/input/FormControl.tsx @@ -56,7 +56,7 @@ export function FormControl({ margin = "none", required = false, size = "medium", - variant = "standard", + variant = "filled", children, }: Partial<Props>): VNode { const [filled, setFilled] = useState(false); @@ -138,7 +138,7 @@ const defaultContextValue: FCCProps = { onFilled: () => null, onFocus: () => null, required: false, - variant: "outlined", + variant: "filled", }; function withoutUndefinedProperties(obj: any): any { diff --git a/packages/taler-wallet-webextension/src/mui/input/InputBase.tsx b/packages/taler-wallet-webextension/src/mui/input/InputBase.tsx index a71f11c5e..5284cdad5 100644 --- a/packages/taler-wallet-webextension/src/mui/input/InputBase.tsx +++ b/packages/taler-wallet-webextension/src/mui/input/InputBase.tsx @@ -61,7 +61,6 @@ const componentStyle = css` font: inherit; letter-spacing: inherit; color: currentColor; - padding: 4px 0 5px; border: 0px; box-sizing: content-box; background: none; @@ -128,6 +127,7 @@ export function InputBaseComponent({ size, multiline, type, + class: _class, ...props }: any): VNode { return ( @@ -136,6 +136,7 @@ export function InputBaseComponent({ type={type} class={[ componentStyle, + _class, disabled && componentDisabledStyle, size === "small" && componentSmallStyle, multiline && componentMultilineStyle, diff --git a/packages/taler-wallet-webextension/src/mui/input/InputFilled.tsx b/packages/taler-wallet-webextension/src/mui/input/InputFilled.tsx index 5c50a8b72..8d837980b 100644 --- a/packages/taler-wallet-webextension/src/mui/input/InputFilled.tsx +++ b/packages/taler-wallet-webextension/src/mui/input/InputFilled.tsx @@ -1,5 +1,170 @@ +import { css } from "@linaria/core"; import { h, VNode } from "preact"; +// eslint-disable-next-line import/extensions +import { Colors, theme } from "../style"; +import { useFormControl } from "./FormControl.js"; +import { InputBase, InputBaseComponent, InputBaseRoot } from "./InputBase.js"; -export function InputFilled(): VNode { - return <div />; +export interface Props { + autoComplete?: string; + autoFocus?: boolean; + color?: Colors; + defaultValue?: string; + disabled?: boolean; + disableUnderline?: boolean; + endAdornment?: VNode; + error?: boolean; + fullWidth?: boolean; + id?: string; + margin?: "dense" | "normal" | "none"; + maxRows?: number; + minRows?: number; + multiline?: boolean; + name?: string; + onChange?: (s: string) => void; + placeholder?: string; + readOnly?: boolean; + required?: boolean; + rows?: number; + startAdornment?: VNode; + type?: string; + value?: string; +} +export function InputFilled({ + type = "text", + multiline, + ...props +}: Props): VNode { + const fcs = useFormControl(props); + return ( + <InputBase + Root={Root} + Input={Input} + fullWidth={fcs.fullWidth} + multiline={multiline} + type={type} + {...props} + /> + ); +} + +const light = theme.palette.mode === "light"; +const bottomLineColor = light + ? "rgba(0, 0, 0, 0.42)" + : "rgba(255, 255, 255, 0.7)"; +const backgroundColor = light + ? "rgba(0, 0, 0, 0.06)" + : "rgba(255, 255, 255, 0.09)"; +const backgroundColorHover = light + ? "rgba(0, 0, 0, 0.09)" + : "rgba(255, 255, 255, 0.13)"; +const backgroundColorDisabled = light + ? "rgba(0, 0, 0, 0.12)" + : "rgba(255, 255, 255, 0.12)"; + +const formControlStyle = css` + label + & { + margin-top: 16px; + } +`; + +const filledRootStyle = css` + position: relative; + background-color: ${backgroundColor}; + border-top-left-radius: ${theme.shape.borderRadius}px; + border-top-right-radius: ${theme.shape.borderRadius}px; + transition: ${theme.transitions.create("background-color", { + duration: theme.transitions.duration.shorter, + easing: theme.transitions.easing.easeOut, + })}; + // when is not disabled underline + &:hover { + background-color: ${backgroundColorHover}; + @media (hover: none) { + background-color: ${backgroundColor}; + } + } + [data-focused] { + background-color: ${backgroundColor}; + } + [data-disabled] { + background-color: ${backgroundColorDisabled}; + } +`; + +const underlineStyle = css` + // when is not disabled underline + &:after { + border-bottom: 2px solid var(--color-main); + left: 0px; + bottom: 0px; + content: ""; + position: absolute; + right: 0px; + transform: scaleX(0); + transition: ${theme.transitions.create("transform", { + duration: theme.transitions.duration.shorter, + easing: theme.transitions.easing.easeOut, + })}; + pointer-events: none; + } + &[data-focused]:after { + transform: scaleX(1); + } + &[data-error]:after { + border-bottom-color: ${theme.palette.error.main}; + transform: scaleY(1); + } + &:before { + border-bottom: 1px solid + ${theme.palette.mode === "light" + ? "rgba(0, 0, 0, 0.42)" + : "rgba(255, 255, 255, 0.7)"}; + left: 0px; + bottom: 0px; + right: 0px; + content: "\\00a0"; + position: absolute; + transition: ${theme.transitions.create("border-bottom-color", { + duration: theme.transitions.duration.shorter, + })}; + pointer-events: none; + } + &:hover:not([data-disabled]:before) { + border-bottom: 2px solid var(--color-main); + @media (hover: none) { + border-bottom: 1px solid + ${theme.palette.mode === "light" + ? "rgba(0, 0, 0, 0.42)" + : "rgba(255, 255, 255, 0.7)"}; + } + } + &[data-disabled]:before { + border-bottom-style: solid; + } +`; + +function Root({ fullWidth, disabled, focused, error, children }: any): VNode { + return ( + <InputBaseRoot + disabled={disabled} + focused={focused} + fullWidth={fullWidth} + error={error} + class={[filledRootStyle, underlineStyle].join(" ")} + > + {children} + </InputBaseRoot> + ); +} + +const filledBaseStyle = css` + padding-top: 25px; + padding-right: 12px; + padding-bottom: 8px; + padding-left: 12px; +`; + +function Input(props: any): VNode { + return <InputBaseComponent class={[filledBaseStyle].join(" ")} {...props} />; } diff --git a/packages/taler-wallet-webextension/src/mui/input/InputStandard.tsx b/packages/taler-wallet-webextension/src/mui/input/InputStandard.tsx index 3eacd7984..bca6b0e80 100644 --- a/packages/taler-wallet-webextension/src/mui/input/InputStandard.tsx +++ b/packages/taler-wallet-webextension/src/mui/input/InputStandard.tsx @@ -50,6 +50,7 @@ export function InputStandard({ const rootStyle = css` position: relative; + padding: 4px 0 5px; `; const formControlStyle = css` label + & { @@ -57,6 +58,7 @@ const formControlStyle = css` } `; const underlineStyle = css` + // when is not disabled underline &:after { border-bottom: 2px solid var(--color-main); left: 0px; @@ -107,11 +109,12 @@ const underlineStyle = css` } `; -function Root({ disabled, focused, error, children }: any): VNode { +function Root({ fullWidth, disabled, focused, error, children }: any): VNode { return ( <InputBaseRoot disabled={disabled} focused={focused} + fullWidth={fullWidth} error={error} class={[rootStyle, formControlStyle, underlineStyle].join(" ")} > diff --git a/packages/taler-wallet-webextension/src/mui/style.tsx b/packages/taler-wallet-webextension/src/mui/style.tsx index 652a71d46..3ad1ab14e 100644 --- a/packages/taler-wallet-webextension/src/mui/style.tsx +++ b/packages/taler-wallet-webextension/src/mui/style.tsx @@ -147,6 +147,7 @@ function createTheme() { circularBorder: css` border-radius: 50%; `, + borderRadius: 4, }; ///////////////////// diff --git a/packages/taler-wallet-webextension/src/stories.tsx b/packages/taler-wallet-webextension/src/stories.tsx index b7e9b4184..e86240688 100644 --- a/packages/taler-wallet-webextension/src/stories.tsx +++ b/packages/taler-wallet-webextension/src/stories.tsx @@ -35,6 +35,7 @@ import * as mui from "./mui/index.stories.js"; import { PopupNavBar, WalletNavBar } from "./NavigationBar.js"; import * as popup from "./popup/index.stories.js"; import * as wallet from "./wallet/index.stories.js"; +import * as cta from "./cta/index.stories.js"; import * as components from "./components/index.stories.js"; import { strings } from "./i18n/strings.js"; @@ -112,7 +113,7 @@ function parseExampleImport(group: string, im: any): ComponentItem { }; } -const allExamples = Object.entries({ popup, wallet, mui, components }).map( +const allExamples = Object.entries({ popup, wallet, cta, mui, components }).map( ([title, value]) => ({ title, list: value.default.map((s) => parseExampleImport(title, s)), @@ -227,6 +228,14 @@ function getWrapperForGroup(group: string): FunctionComponent { </Fragment> ); }; + case "cta": + return function WalletWrapper({ children }: any) { + return ( + <Fragment> + <WalletBox>{children}</WalletBox> + </Fragment> + ); + }; default: return Fragment; } |