diff options
author | Sebastian <sebasjm@gmail.com> | 2021-08-30 16:05:25 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2021-08-30 16:05:32 -0300 |
commit | ddd7e9cfb01924ce7e95161b56abd67162e827c6 (patch) | |
tree | 432a6f2dead5c4b74edcadd82bf7b5267326d2ce | |
parent | 80e45b024af196eaf97bbcdbc10118ada74c42ee (diff) | |
download | merchant-backoffice-ddd7e9cfb01924ce7e95161b56abd67162e827c6.tar.gz merchant-backoffice-ddd7e9cfb01924ce7e95161b56abd67162e827c6.tar.bz2 merchant-backoffice-ddd7e9cfb01924ce7e95161b56abd67162e827c6.zip |
head and body split, handle request params
-rw-r--r-- | packages/backend/rollup.config.js | 9 | ||||
-rw-r--r-- | packages/backend/src/pages/DepletedTip.tsx | 28 | ||||
-rw-r--r-- | packages/backend/src/pages/OfferRefund.stories.tsx | 1 | ||||
-rw-r--r-- | packages/backend/src/pages/OfferRefund.tsx | 77 | ||||
-rw-r--r-- | packages/backend/src/pages/OfferTip.stories.tsx | 2 | ||||
-rw-r--r-- | packages/backend/src/pages/OfferTip.tsx | 81 | ||||
-rw-r--r-- | packages/backend/src/pages/RequestPayment.stories.tsx | 2 | ||||
-rw-r--r-- | packages/backend/src/pages/RequestPayment.tsx | 77 | ||||
-rw-r--r-- | packages/backend/src/pages/ShowOrderDetails.stories.tsx | 6 | ||||
-rw-r--r-- | packages/backend/src/pages/ShowOrderDetails.tsx | 129 |
10 files changed, 256 insertions, 156 deletions
diff --git a/packages/backend/rollup.config.js b/packages/backend/rollup.config.js index aeb6077..f5227ba 100644 --- a/packages/backend/rollup.config.js +++ b/packages/backend/rollup.config.js @@ -30,7 +30,6 @@ import commonjs from "@rollup/plugin-commonjs"; const template = async ({ files, - title }) => { const scripts = (files.js || []).map(({ code }) => `<script>${code}</script>`).join('\n'); const css = (files.css || []).map(({ source }) => `<style>${source}</style>`).join('\n'); @@ -40,17 +39,13 @@ const template = async ({ <!doctype html> <html> <head> - <title>${title}</title> + ${page.head} ${css} </head> <script id="built_time_data"> </script> <body> - <div id="built_time_data" /> - <div id="container_without_js"> - ${page} - </div> - <div id="container_with_js"/> + ${page.body} ${scripts} <script>page.mount()</script> </body> diff --git a/packages/backend/src/pages/DepletedTip.tsx b/packages/backend/src/pages/DepletedTip.tsx index d8eae75..1e2e411 100644 --- a/packages/backend/src/pages/DepletedTip.tsx +++ b/packages/backend/src/pages/DepletedTip.tsx @@ -18,10 +18,15 @@ * * @author Sebastian Javier Marchano (sebasjm) */ -import { h, render, Fragment, VNode } from 'preact'; -import { Footer } from '../components/Footer'; -import { ShowOrderDetails } from './ShowOrderDetails'; +import { Fragment, h, render, VNode } from 'preact'; import { render as renderToString } from 'preact-render-to-string'; +import { Footer } from '../components/Footer'; +import "../css/pure-min.css"; +import "../css/style.css"; + +function Head(): VNode { + return <title>Status of your tip</title> +} export function DepletedTip(): VNode { return <Fragment> @@ -35,23 +40,18 @@ export function DepletedTip(): VNode { </Fragment> } -export function Title(): VNode { - return <title>Status of your tip</title> -} - - export function mount(): void { try { - const params = new URL(window.location.href).searchParams - render(<DepletedTip - // taler_refund_uri={params.get('taler_refund_uri') || undefined} - />, document.body); + render(<DepletedTip />, document.body); } catch (e) { console.error("got error", e); document.body.innerText = `Fatal error: "${e.message}". Please report this bug at https://bugs.gnunet.org/.`; } } -export function buildTimeRendering(): string { - return renderToString(<ShowOrderDetails />) +export function buildTimeRendering(): { head: string, body: string } { + return { + head: renderToString(<Head />), + body: renderToString(<DepletedTip />) + } } diff --git a/packages/backend/src/pages/OfferRefund.stories.tsx b/packages/backend/src/pages/OfferRefund.stories.tsx index f1b2f3a..4a5e9ab 100644 --- a/packages/backend/src/pages/OfferRefund.stories.tsx +++ b/packages/backend/src/pages/OfferRefund.stories.tsx @@ -37,4 +37,5 @@ function createExample<Props>(Component: FunctionalComponent<Props>, props: Part } export const Example = createExample(TestedComponent, { + refundURI: 'taler+http://refund/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0' }); diff --git a/packages/backend/src/pages/OfferRefund.tsx b/packages/backend/src/pages/OfferRefund.tsx index 7b35a54..88be378 100644 --- a/packages/backend/src/pages/OfferRefund.tsx +++ b/packages/backend/src/pages/OfferRefund.tsx @@ -18,15 +18,53 @@ * * @author Sebastian Javier Marchano (sebasjm) */ -import { render, h, Fragment, VNode } from 'preact'; +import { Fragment, h, render, VNode } from 'preact'; +import { render as renderToString } from 'preact-render-to-string'; import { useEffect } from 'preact/hooks'; import { Footer } from '../components/Footer'; -import { ShowOrderDetails } from './ShowOrderDetails'; -import { render as renderToString } from 'preact-render-to-string'; +import { QR } from '../components/QR'; +import "../css/pure-min.css"; +import "../css/style.css"; + +/** + * This page creates a refund offer QR code + * + * It will build into a mustache html template for server side rendering + * + * server side rendering params: + * - order_status_url + * - taler_refund_qrcode_svg + * - taler_refund_uri + * + * request params: + * - refund_uri + * - order_status_url + */ + +interface Props { + refundURI?: string; + order_status_url?: string; +} + +function Head({ order_summary }: { order_summary?: string }): VNode { + return <Fragment> + <meta http-equiv="content-type" content="text/html; UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <noscript> + <meta http-equiv="refresh" content="1" /> + </noscript> + <title>Refund available for {order_summary ? order_summary : `{{ order_summary }}`}</title> + </Fragment> +} -export function OfferRefund(): VNode { +export function OfferRefund({ refundURI, order_status_url }: Props): VNode { useEffect(() => { - const checkUrl = new URL("{{& order_status_url }}"); + let checkUrl: URL; + try { + checkUrl = new URL(order_status_url ? order_status_url : "{{& order_status_url }}"); + } catch (e) { + return; + } checkUrl.searchParams.set("await_refund_obtained", "yes"); const delayMs = 500; function check() { @@ -70,10 +108,10 @@ export function OfferRefund(): VNode { Scan this QR code with your Taler mobile wallet: </p> <div class="qr"> - {/* {{{taler_refund_qrcode_svg}}} */} + {refundURI ? <QR text={refundURI} /> : `{{{ taler_refund_qrcode_svg }}}`} </div> <p> - <a class="pure-button pure-button-active success" href='{{taler_refund_uri}}'> + <a class="pure-button pure-button-active success" href={refundURI ? refundURI : `{{ taler_refund_uri }}`}> Or open your Taller wallet </a> </p> @@ -87,15 +125,19 @@ export function OfferRefund(): VNode { </Fragment> } -export function Title(): VNode { - return <title>Refund available for {`{order_summary}`}</title> -} - export function mount(): void { try { - const params = new URL(window.location.href).searchParams + const fromLocation = new URL(window.location.href).searchParams + const os = fromLocation.get('order_summary') || undefined; + if (os) { + render(<Head order_summary={os} />, document.head); + } + + const ru = fromLocation.get('refund_uri') || undefined; + const osu = fromLocation.get('order_status_url') || undefined; + render(<OfferRefund - // taler_refund_uri={params.get('taler_refund_uri') || undefined} + refundURI={ru} order_status_url={osu} />, document.body); } catch (e) { console.error("got error", e); @@ -103,8 +145,9 @@ export function mount(): void { } } -export function buildTimeRendering(): string { - return renderToString(<ShowOrderDetails />) +export function buildTimeRendering(): { head: string, body: string } { + return { + head: renderToString(<Head />), + body: renderToString(<OfferRefund />) + } } - - diff --git a/packages/backend/src/pages/OfferTip.stories.tsx b/packages/backend/src/pages/OfferTip.stories.tsx index 6b35f5e..9685fea 100644 --- a/packages/backend/src/pages/OfferTip.stories.tsx +++ b/packages/backend/src/pages/OfferTip.stories.tsx @@ -37,5 +37,5 @@ function createExample<Props>(Component: FunctionalComponent<Props>, props: Part } export const Example = createExample(TestedComponent, { - + tipURI: 'taler+http://tip/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0', }); diff --git a/packages/backend/src/pages/OfferTip.tsx b/packages/backend/src/pages/OfferTip.tsx index 95e0c41..9132402 100644 --- a/packages/backend/src/pages/OfferTip.tsx +++ b/packages/backend/src/pages/OfferTip.tsx @@ -18,23 +18,56 @@ * * @author Sebastian Javier Marchano (sebasjm) */ -import { render, h, VNode, Fragment } from 'preact'; +import { Fragment, h, render, VNode } from 'preact'; +import { render as renderToString } from 'preact-render-to-string'; import { useEffect } from 'preact/hooks'; -import { styled } from "@linaria/react" -import "../css/pure-min.css" -import "../css/style.css" import { Footer } from '../components/Footer'; -import { ShowOrderDetails } from './ShowOrderDetails'; -import { render as renderToString } from 'preact-render-to-string'; import { QR } from '../components/QR'; +import "../css/pure-min.css"; +import "../css/style.css"; +import { ShowOrderDetails } from './ShowOrderDetails'; + + +/** + * This page creates a tip offer QR code + * + * It will build into a mustache html template for server side rendering + * + * server side rendering params: + * - tip_status_url + * - taler_tip_qrcode_svg + * - taler_tip_uri + * + * request params: + * - tip_uri + * - tip_status_url + */ interface Props { - taler_refund_uri?: string, + tipURI?: string, tip_status_url?: string, - taler_tip_qrcode_svg?: string, } -export function OfferTip({ taler_refund_uri, tip_status_url, taler_tip_qrcode_svg }: Props): VNode { + +export function Head(): VNode { + return <Fragment> + <meta http-equiv="content-type" content="text/html; UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <noscript> + <meta http-equiv="refresh" content="1" /> + </noscript> + <title>Tip available</title> + </Fragment> +} + +export function OfferTip({ tipURI, tip_status_url }: Props): VNode { useEffect(() => { + let checkUrl: URL; + try { + checkUrl = new URL(tip_status_url ? tip_status_url : "{{& tip_status_url }}"); + } catch (e) { + return; + } + const delayMs = 500; function check() { let retried = false; @@ -56,7 +89,7 @@ export function OfferTip({ taler_refund_uri, tip_status_url, taler_tip_qrcode_sv req.onerror = function () { setTimeout(retryOnce, delayMs); } - req.open("GET", taler_refund_uri || ''); + req.open("GET", checkUrl.href); req.send(); } @@ -70,10 +103,10 @@ export function OfferTip({ taler_refund_uri, tip_status_url, taler_tip_qrcode_sv Scan this QR code with your Taler mobile wallet: </p> <div class="qr"> - {taler_tip_qrcode_svg ? <QR text={taler_tip_qrcode_svg} /> : `{{taler_tip_qrcode_svg}}`} + {tipURI ? <QR text={tipURI} /> : `{{{ taler_tip_qrcode_svg }}}`} </div> <p> - <a class="pure-button pure-button-active success" href='{{taler_refund_uri}}'> + <a class="pure-button pure-button-active success" href={tipURI ? tipURI : `{{ taler_tip_uri }}`}> Or open your Taller wallet </a> </p> @@ -87,25 +120,23 @@ export function OfferTip({ taler_refund_uri, tip_status_url, taler_tip_qrcode_sv </Fragment> } - -export function Title(): VNode { - return <title>Tip available</title> -} - export function mount(): void { try { - const params = new URL(window.location.href).searchParams - render(<OfferTip - taler_refund_uri={params.get('taler_refund_uri') || undefined} - taler_tip_qrcode_svg={params.get('taler_tip_qrcode_svg') || undefined} - tip_status_url={params.get('tip_status_url') || undefined} - />, document.body); + const fromLocation = new URL(window.location.href).searchParams + + const tu = fromLocation.get('tip_uri') || undefined + const tsu = fromLocation.get('tip_status_url') || undefined + + render(<OfferTip tipURI={tu} tip_status_url={tsu} />, document.body); } catch (e) { console.error("got error", e); document.body.innerText = `Fatal error: "${e.message}". Please report this bug at https://bugs.gnunet.org/.`; } } -export function buildTimeRendering(): string { - return renderToString(<ShowOrderDetails />) +export function buildTimeRendering(): { head: string, body: string } { + return { + head: renderToString(<Head />), + body: renderToString(<ShowOrderDetails />) + } } diff --git a/packages/backend/src/pages/RequestPayment.stories.tsx b/packages/backend/src/pages/RequestPayment.stories.tsx index 6a757d2..8f5f734 100644 --- a/packages/backend/src/pages/RequestPayment.stories.tsx +++ b/packages/backend/src/pages/RequestPayment.stories.tsx @@ -37,5 +37,5 @@ function createExample<Props>(Component: FunctionalComponent<Props>, props: Part } export const Example = createExample(TestedComponent, { - taler_pay_qrcode_svg: 'this is an example' + payURI: 'taler+http://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0' }); diff --git a/packages/backend/src/pages/RequestPayment.tsx b/packages/backend/src/pages/RequestPayment.tsx index 7ebddcd..5f5032a 100644 --- a/packages/backend/src/pages/RequestPayment.tsx +++ b/packages/backend/src/pages/RequestPayment.tsx @@ -18,19 +18,58 @@ * * @author Sebastian Javier Marchano (sebasjm) */ -import { h, render, Fragment, VNode } from 'preact'; +import { Fragment, h, render, VNode } from 'preact'; +import { render as renderToString } from 'preact-render-to-string'; import { useEffect } from 'preact/hooks'; import { Footer } from '../components/Footer'; -import { render as renderToString } from 'preact-render-to-string'; import { QR } from '../components/QR'; +import "../css/pure-min.css"; +import "../css/style.css"; + + +/** + * This page creates a payment request QR code + * + * It will build into a mustache html template for server side rendering + * + * server side rendering params: + * - order_status_url + * - taler_pay_qrcode_svg + * - taler_pay_uri + * - order_summary + * + * request params: + * - pay_uri + * - order_summary + * - order_status_url + */ + interface Props { - taler_pay_qrcode_svg?: string, + payURI?: string, + order_status_url?: string, +} + +function Head({ order_summary }: { order_summary?: string }): VNode { + return <Fragment> + <meta http-equiv="content-type" content="text/html; UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <noscript> + <meta http-equiv="refresh" content="1" /> + </noscript> + <title>Payment requested for {order_summary ? order_summary : `{{ order_summary }}`}</title> + </Fragment> } -export function RequestPayment({ taler_pay_qrcode_svg }: Props): VNode { + +export function RequestPayment({ payURI, order_status_url }: Props): VNode { useEffect(() => { - const longpollDelayMs = 60000; - const checkUrl = new URL("{{& order_status_url }}"); + const longpollDelayMs = 60 * 1000; + let checkUrl: URL; + try { + checkUrl = new URL(order_status_url ? order_status_url : "{{& order_status_url }}"); + } catch (e) { + return; + } checkUrl.searchParams.set("timeout_ms", longpollDelayMs.toString()); function check() { let retried = false; @@ -96,10 +135,10 @@ export function RequestPayment({ taler_pay_qrcode_svg }: Props): VNode { Scan this QR code with your mobile wallet: </p> <div class="qr"> - {taler_pay_qrcode_svg ? <QR text={taler_pay_qrcode_svg} /> : `{{taler_pay_qrcode_svg}}`} + {payURI ? <QR text={payURI} /> : `{{{ taler_pay_qrcode_svg }}}`} </div> <p> - <a class="pure-button pure-button-active success" href={`{{ taler_refund_uri }}`}> + <a class="pure-button pure-button-active success" href={payURI ? payURI : `{{ taler_pay_uri }}`}> Or open your Taller wallet </a> </p> @@ -113,15 +152,20 @@ export function RequestPayment({ taler_pay_qrcode_svg }: Props): VNode { </Fragment> } -export function Title(): VNode { - return <title>Payment requested for {`{{ order_summary }}`}</title> -} export function mount(): void { try { - const params = new URL(window.location.href).searchParams + const fromLocation = new URL(window.location.href).searchParams + const os = fromLocation.get('order_summary') || undefined; + if (os) { + render(<Head order_summary={os} />, document.head); + } + + const pu = fromLocation.get('pay_uri') || undefined; + const osu = fromLocation.get('order_status_url') || undefined; + render(<RequestPayment - taler_pay_qrcode_svg={params.get('taler_pay_qrcode_svg') || undefined} + payURI={pu} order_status_url={osu} />, document.body); } catch (e) { console.error("got error", e); @@ -129,7 +173,10 @@ export function mount(): void { } } -export function buildTimeRendering(): string { - return renderToString(<RequestPayment />) +export function buildTimeRendering(): { head: string, body: string } { + return { + head: renderToString(<Head />), + body: renderToString(<RequestPayment />) + } } diff --git a/packages/backend/src/pages/ShowOrderDetails.stories.tsx b/packages/backend/src/pages/ShowOrderDetails.stories.tsx index 7550ab4..1a41c62 100644 --- a/packages/backend/src/pages/ShowOrderDetails.stories.tsx +++ b/packages/backend/src/pages/ShowOrderDetails.stories.tsx @@ -19,7 +19,7 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { h, VNode, FunctionalComponent } from 'preact'; +import { FunctionalComponent, h } from 'preact'; import { ShowOrderDetails as TestedComponent } from './ShowOrderDetails'; @@ -37,5 +37,7 @@ function createExample<Props>(Component: FunctionalComponent<Props>, props: Part } export const Example = createExample(TestedComponent, { - taler_pay_qrcode_svg: 'this is an example' + order_summary: 'here goes the order summary', + refund_amount: 'USR:10', + contract_terms: '' }); diff --git a/packages/backend/src/pages/ShowOrderDetails.tsx b/packages/backend/src/pages/ShowOrderDetails.tsx index 591b7ea..8ae08ab 100644 --- a/packages/backend/src/pages/ShowOrderDetails.tsx +++ b/packages/backend/src/pages/ShowOrderDetails.tsx @@ -18,83 +18,56 @@ * * @author Sebastian Javier Marchano (sebasjm) */ -import { Fragment, render, h, VNode } from 'preact'; -import { useEffect } from 'preact/hooks'; +import { Fragment, h, render, VNode } from 'preact'; import { render as renderToString } from 'preact-render-to-string'; +import "../css/pure-min.css"; +import "../css/style.css"; -export function ShowOrderDetails(): VNode { - useEffect(() => { - const longpollDelayMs = 60000; - const checkUrl = new URL("{{& order_status_url }}"); - checkUrl.searchParams.set("timeout_ms", longpollDelayMs.toString()); - function check() { - let retried = false; - function retryOnce() { - - if (!retried) { - retried = true; - check(); - } - } - const req = new XMLHttpRequest(); - req.onreadystatechange = function () { - if (req.readyState === XMLHttpRequest.DONE) { - if (req.status === 200) { - try { - const resp = JSON.parse(req.responseText); - if (resp.fulfillment_url) { - window.location.replace(resp.fulfillment_url); - } - } catch (e) { - console.error("could not parse response:", e); - } - } - if (req.status === 202) { - try { - const resp = JSON.parse(req.responseText); - if (resp.fulfillment_url) { - window.location.replace(resp.fulfillment_url); - } - } catch (e) { - console.error("could not parse response:", e); - } - } - if (req.status === 402) { - try { - const resp = JSON.parse(req.responseText); - if (resp.already_paid_order_id && resp.fulfillment_url) { - window.location.replace(resp.fulfillment_url); - } - } catch (e) { - console.error("could not parse response:", e); - } - } - setTimeout(retryOnce, 500); - } - }; - req.onerror = function () { - setTimeout(retryOnce, 500); - } - req.ontimeout = function () { - setTimeout(retryOnce, 500); - } - req.timeout = longpollDelayMs; - req.open("GET", checkUrl.href); - req.send(); - } - setTimeout(check, 500); - }) +/** + * This page creates a payment request QR code + * + * It will build into a mustache html template for server side rendering + * + * server side rendering params: + * - order_summary + * - contract_terms + * - refund_amount + * + * request params: + * - refund_amount + * - contract_terms + * - order_summary + */ + +interface Props { + order_summary?: string; + refund_amount?: string; + contract_terms?: string; +} + +function Head({ order_summary }: { order_summary?: string }): VNode { + return <Fragment> + <meta http-equiv="content-type" content="text/html; UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <noscript> + <meta http-equiv="refresh" content="1" /> + </noscript> + <title>Status of your order for {order_summary ? order_summary : `{{ order_summary }}`}</title> + </Fragment> +} + +export function ShowOrderDetails({ order_summary, refund_amount }: Props): VNode { return <Fragment> <h1>Order details</h1> <div> - This is the default status page for your order for <b>{`{{ order_summary }}`}</b>. + This is the default status page for your order for <b>{order_summary ? order_summary : `{{ order_summary }}`}</b>. </div> <h2>Refund status</h2> <div> - The merchant has granted you refunds on the purchase of <b>{`{{ refund_amount }}`}</b>. + The merchant has granted you refunds on the purchase of <b>{refund_amount ? refund_amount : `{{ refund_amount }}`}</b>. </div> <h2>Full contract details</h2> @@ -108,15 +81,20 @@ export function ShowOrderDetails(): VNode { } -function Title(): VNode { - return <title>Status of your order for {`{order_summary}`}</title> -} - export function mount(): void { try { - const params = new URL(window.location.href).searchParams + const fromLocation = new URL(window.location.href).searchParams + const os = fromLocation.get('order_summary') || undefined; + if (os) { + render(<Head order_summary={os} />, document.head); + } + + const ra = fromLocation.get('refund_amount') || undefined; + const ct = fromLocation.get('contract_terms') || undefined; + render(<ShowOrderDetails - // taler_refund_uri={params.get('taler_refund_uri') || undefined} + contract_terms={ct} + order_summary={os} refund_amount={ra} />, document.body); } catch (e) { @@ -125,6 +103,9 @@ export function mount(): void { } } -export function buildTimeRendering(): string { - return renderToString(<ShowOrderDetails />) +export function buildTimeRendering(): { head: string, body: string } { + return { + head: renderToString(<Head />), + body: renderToString(<ShowOrderDetails />) + } } |