added example of withdrawal use cases
This commit is contained in:
parent
be8e3f4b1d
commit
b8d03b6b2a
@ -51,7 +51,7 @@ check: compile
|
|||||||
webextension: compile
|
webextension: compile
|
||||||
cd ./packages/taler-wallet-webextension/ && ./pack.sh
|
cd ./packages/taler-wallet-webextension/ && ./pack.sh
|
||||||
|
|
||||||
.PHONY: dev-view
|
.PHONY: webextension-dev-view
|
||||||
webextension-dev-view: compile
|
webextension-dev-view: compile
|
||||||
pnpm run --filter @gnu-taler/taler-wallet-webextension storybook
|
pnpm run --filter @gnu-taler/taler-wallet-webextension storybook
|
||||||
|
|
||||||
|
@ -35,6 +35,405 @@ export default {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const termsHtml = `<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<title>Terms Of Service — Taler Terms of Service</title>
|
||||||
|
</head><body>
|
||||||
|
<div>
|
||||||
|
Terms of service
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
A complete separated html with it's own design
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`
|
||||||
|
const termsPlain = `
|
||||||
|
Terms Of Service
|
||||||
|
****************
|
||||||
|
|
||||||
|
Last Updated: 12.4.2019
|
||||||
|
|
||||||
|
Welcome! Taler Systems SA (“we,” “our,” or “us”) provides a payment
|
||||||
|
service through our Internet presence (collectively the “Services”).
|
||||||
|
Before using our Services, please read the Terms of Service (the
|
||||||
|
“Terms” or the “Agreement”) carefully.
|
||||||
|
|
||||||
|
|
||||||
|
Overview
|
||||||
|
========
|
||||||
|
|
||||||
|
This section provides a brief summary of the highlights of this
|
||||||
|
Agreement. Please note that when you accept this Agreement, you are
|
||||||
|
accepting all of the terms and conditions and not just this section.
|
||||||
|
We and possibly other third parties provide Internet services which
|
||||||
|
interact with the Taler Wallet’s self-hosted personal payment
|
||||||
|
application. When using the Taler Wallet to interact with our
|
||||||
|
Services, you are agreeing to our Terms, so please read carefully.
|
||||||
|
|
||||||
|
|
||||||
|
Highlights:
|
||||||
|
-----------
|
||||||
|
|
||||||
|
* You are responsible for keeping the data in your Taler Wallet at
|
||||||
|
all times under your control. Any losses arising from you not
|
||||||
|
being in control of your private information are your problem.
|
||||||
|
|
||||||
|
* We will try to transfer funds we hold in escrow for our users to
|
||||||
|
any legal recipient to the best of our ability within the
|
||||||
|
limitations of the law and our implementation. However, the
|
||||||
|
Services offered today are highly experimental and the set of
|
||||||
|
recipients of funds is severely restricted.
|
||||||
|
|
||||||
|
* For our Services, we may charge transaction fees. The specific
|
||||||
|
fee structure is provided based on the Taler protocol and should
|
||||||
|
be shown to you when you withdraw electronic coins using a Taler
|
||||||
|
Wallet. You agree and understand that the Taler protocol allows
|
||||||
|
for the fee structure to change.
|
||||||
|
|
||||||
|
* You agree to not intentionally overwhelm our systems with
|
||||||
|
requests and follow responsible disclosure if you find security
|
||||||
|
issues in our services.
|
||||||
|
|
||||||
|
* We cannot be held accountable for our Services not being
|
||||||
|
available due to circumstances beyond our control. If we modify
|
||||||
|
or terminate our services, we will try to give you the
|
||||||
|
opportunity to recover your funds. However, given the
|
||||||
|
experimental state of the Services today, this may not be
|
||||||
|
possible. You are strongly advised to limit your use of the
|
||||||
|
Service to small-scale experiments expecting total loss of all
|
||||||
|
funds.
|
||||||
|
|
||||||
|
These terms outline approved uses of our Services. The Services and
|
||||||
|
these Terms are still at an experimental stage. If you have any
|
||||||
|
questions or comments related to this Agreement, please send us a
|
||||||
|
message to legal@taler-systems.com. If you do not agree to this
|
||||||
|
Agreement, you must not use our Services.
|
||||||
|
|
||||||
|
|
||||||
|
How you accept this policy
|
||||||
|
==========================
|
||||||
|
|
||||||
|
By sending funds to us (to top-up your Taler Wallet), you acknowledge
|
||||||
|
that you have read, understood, and agreed to these Terms. We reserve
|
||||||
|
the right to change these Terms at any time. If you disagree with the
|
||||||
|
change, we may in the future offer you with an easy option to recover
|
||||||
|
your unspent funds. However, in the current experimental period you
|
||||||
|
acknowledge that this feature is not yet available, resulting in your
|
||||||
|
funds being lost unless you accept the new Terms. If you continue to
|
||||||
|
use our Services other than to recover your unspent funds, your
|
||||||
|
continued use of our Services following any such change will signify
|
||||||
|
your acceptance to be bound by the then current Terms. Please check
|
||||||
|
the effective date above to determine if there have been any changes
|
||||||
|
since you have last reviewed these Terms.
|
||||||
|
|
||||||
|
|
||||||
|
Services
|
||||||
|
========
|
||||||
|
|
||||||
|
We will try to transfer funds that we hold in escrow for our users to
|
||||||
|
any legal recipient to the best of our ability and within the
|
||||||
|
limitations of the law and our implementation. However, the Services
|
||||||
|
offered today are highly experimental and the set of recipients of
|
||||||
|
funds is severely restricted. The Taler Wallet can be loaded by
|
||||||
|
exchanging fiat currencies against electronic coins. We are providing
|
||||||
|
this exchange service. Once your Taler Wallet is loaded with
|
||||||
|
electronic coins they can be spent for purchases if the seller is
|
||||||
|
accepting Taler as a means of payment. We are not guaranteeing that
|
||||||
|
any seller is accepting Taler at all or a particular seller. The
|
||||||
|
seller or recipient of deposits of electronic coins must specify the
|
||||||
|
target account, as per the design of the Taler protocol. They are
|
||||||
|
responsible for following the protocol and specifying the correct bank
|
||||||
|
account, and are solely liable for any losses that may arise from
|
||||||
|
specifying the wrong account. We will allow the government to link
|
||||||
|
wire transfers to the underlying contract hash. It is the
|
||||||
|
responsibility of recipients to preserve the full contracts and to pay
|
||||||
|
whatever taxes and charges may be applicable. Technical issues may
|
||||||
|
lead to situations where we are unable to make transfers at all or
|
||||||
|
lead to incorrect transfers that cannot be reversed. We will only
|
||||||
|
refuse to execute transfers if the transfers are prohibited by a
|
||||||
|
competent legal authority and we are ordered to do so.
|
||||||
|
|
||||||
|
|
||||||
|
Fees
|
||||||
|
====
|
||||||
|
|
||||||
|
You agree to pay the fees for exchanges and withdrawals completed via
|
||||||
|
the Taler Wallet ("Fees") as defined by us, which we may change from
|
||||||
|
time to time. With the exception of wire transfer fees, Taler
|
||||||
|
transaction fees are set for any electronic coin at the time of
|
||||||
|
withdrawal and fixed throughout the validity period of the respective
|
||||||
|
electronic coin. Your wallet should obtain and display applicable fees
|
||||||
|
when withdrawing funds. Fees for coins obtained as change may differ
|
||||||
|
from the fees applicable to the original coin. Wire transfer fees that
|
||||||
|
are independent from electronic coins may change annually. You
|
||||||
|
authorize us to charge or deduct applicable fees owed in connection
|
||||||
|
with deposits, exchanges and withdrawals following the rules of the
|
||||||
|
Taler protocol. We reserve the right to provide different types of
|
||||||
|
rewards to users either in the form of discount for our Services or in
|
||||||
|
any other form at our discretion and without prior notice to you.
|
||||||
|
|
||||||
|
|
||||||
|
Eligibility
|
||||||
|
===========
|
||||||
|
|
||||||
|
To be eligible to use our Services, you must be able to form legally
|
||||||
|
binding contracts or have the permission of your legal guardian. By
|
||||||
|
using our Services, you represent and warrant that you meet all
|
||||||
|
eligibility requirements that we outline in these Terms.
|
||||||
|
|
||||||
|
|
||||||
|
Financial self-responsibility
|
||||||
|
=============================
|
||||||
|
|
||||||
|
You will be responsible for maintaining the availability, integrity
|
||||||
|
and confidentiality of the data stored in your wallet. When you setup
|
||||||
|
a Taler Wallet, you are strongly advised to follow the precautionary
|
||||||
|
measures offered by the software to minimize the chances to losse
|
||||||
|
access to or control over your Wallet data. We will not be liable for
|
||||||
|
any loss or damage arising from your failure to comply with this
|
||||||
|
paragraph.
|
||||||
|
|
||||||
|
|
||||||
|
Copyrights and trademarks
|
||||||
|
=========================
|
||||||
|
|
||||||
|
The Taler Wallet is released under the terms of the GNU General Public
|
||||||
|
License (GNU GPL). You have the right to access, use, and share the
|
||||||
|
Taler Wallet, in modified or unmodified form. However, the GPL is a
|
||||||
|
strong copyleft license, which means that any derivative works must be
|
||||||
|
distributed under the same license terms as the original software. If
|
||||||
|
you have any questions, you should review the GNU GPL’s full terms and
|
||||||
|
conditions at https://www.gnu.org/licenses/gpl-3.0.en.html. “Taler”
|
||||||
|
itself is a trademark of Taler Systems SA. You are welcome to use the
|
||||||
|
name in relation to processing payments using the Taler protocol,
|
||||||
|
assuming your use is compatible with an official release from the GNU
|
||||||
|
Project that is not older than two years.
|
||||||
|
|
||||||
|
|
||||||
|
Your use of our services
|
||||||
|
========================
|
||||||
|
|
||||||
|
When using our Services, you agree to not take any action that
|
||||||
|
intentionally imposes an unreasonable load on our infrastructure. If
|
||||||
|
you find security problems in our Services, you agree to first report
|
||||||
|
them to security@taler-systems.com and grant us the right to publish
|
||||||
|
your report. We warrant that we will ourselves publicly disclose any
|
||||||
|
issues reported within 3 months, and that we will not prosecute anyone
|
||||||
|
reporting security issues if they did not exploit the issue beyond a
|
||||||
|
proof-of-concept, and followed the above responsible disclosure
|
||||||
|
practice.
|
||||||
|
|
||||||
|
|
||||||
|
Limitation of liability & disclaimer of warranties
|
||||||
|
==================================================
|
||||||
|
|
||||||
|
You understand and agree that we have no control over, and no duty to
|
||||||
|
take any action regarding: Failures, disruptions, errors, or delays in
|
||||||
|
processing that you may experience while using our Services; The risk
|
||||||
|
of failure of hardware, software, and Internet connections; The risk
|
||||||
|
of malicious software being introduced or found in the software
|
||||||
|
underlying the Taler Wallet; The risk that third parties may obtain
|
||||||
|
unauthorized access to information stored within your Taler Wallet,
|
||||||
|
including, but not limited to your Taler Wallet coins or backup
|
||||||
|
encryption keys. You release us from all liability related to any
|
||||||
|
losses, damages, or claims arising from:
|
||||||
|
|
||||||
|
1. user error such as forgotten passwords, incorrectly constructed
|
||||||
|
transactions;
|
||||||
|
|
||||||
|
2. server failure or data loss;
|
||||||
|
|
||||||
|
3. unauthorized access to the Taler Wallet application;
|
||||||
|
|
||||||
|
4. bugs or other errors in the Taler Wallet software; and
|
||||||
|
|
||||||
|
5. any unauthorized third party activities, including, but not limited
|
||||||
|
to, the use of viruses, phishing, brute forcing, or other means of
|
||||||
|
attack against the Taler Wallet. We make no representations
|
||||||
|
concerning any Third Party Content contained in or accessed through
|
||||||
|
our Services.
|
||||||
|
|
||||||
|
Any other terms, conditions, warranties, or representations associated
|
||||||
|
with such content, are solely between you and such organizations
|
||||||
|
and/or individuals.
|
||||||
|
|
||||||
|
|
||||||
|
Limitation of liability
|
||||||
|
=======================
|
||||||
|
|
||||||
|
To the fullest extent permitted by applicable law, in no event will we
|
||||||
|
or any of our officers, directors, representatives, agents, servants,
|
||||||
|
counsel, employees, consultants, lawyers, and other personnel
|
||||||
|
authorized to act, acting, or purporting to act on our behalf
|
||||||
|
(collectively the “Taler Parties”) be liable to you under contract,
|
||||||
|
tort, strict liability, negligence, or any other legal or equitable
|
||||||
|
theory, for:
|
||||||
|
|
||||||
|
1. any lost profits, data loss, cost of procurement of substitute
|
||||||
|
goods or services, or direct, indirect, incidental, special,
|
||||||
|
punitive, compensatory, or consequential damages of any kind
|
||||||
|
whatsoever resulting from:
|
||||||
|
|
||||||
|
1. your use of, or conduct in connection with, our services;
|
||||||
|
|
||||||
|
2. any unauthorized use of your wallet and/or private key due to
|
||||||
|
your failure to maintain the confidentiality of your wallet;
|
||||||
|
|
||||||
|
3. any interruption or cessation of transmission to or from the
|
||||||
|
services; or
|
||||||
|
|
||||||
|
4. any bugs, viruses, trojan horses, or the like that are found in
|
||||||
|
the Taler Wallet software or that may be transmitted to or
|
||||||
|
through our services by any third party (regardless of the
|
||||||
|
source of origination), or
|
||||||
|
|
||||||
|
2. any direct damages.
|
||||||
|
|
||||||
|
These limitations apply regardless of legal theory, whether based on
|
||||||
|
tort, strict liability, breach of contract, breach of warranty, or any
|
||||||
|
other legal theory, and whether or not we were advised of the
|
||||||
|
possibility of such damages. Some jurisdictions do not allow the
|
||||||
|
exclusion or limitation of liability for consequential or incidental
|
||||||
|
damages, so the above limitation may not apply to you.
|
||||||
|
|
||||||
|
|
||||||
|
Warranty disclaimer
|
||||||
|
===================
|
||||||
|
|
||||||
|
Our services are provided "as is" and without warranty of any kind. To
|
||||||
|
the maximum extent permitted by law, we disclaim all representations
|
||||||
|
and warranties, express or implied, relating to the services and
|
||||||
|
underlying software or any content on the services, whether provided
|
||||||
|
or owned by us or by any third party, including without limitation,
|
||||||
|
warranties of merchantability, fitness for a particular purpose,
|
||||||
|
title, non-infringement, freedom from computer virus, and any implied
|
||||||
|
warranties arising from course of dealing, course of performance, or
|
||||||
|
usage in trade, all of which are expressly disclaimed. In addition, we
|
||||||
|
do not represent or warrant that the content accessible via the
|
||||||
|
services is accurate, complete, available, current, free of viruses or
|
||||||
|
other harmful components, or that the results of using the services
|
||||||
|
will meet your requirements. Some states do not allow the disclaimer
|
||||||
|
of implied warranties, so the foregoing disclaimers may not apply to
|
||||||
|
you. This paragraph gives you specific legal rights and you may also
|
||||||
|
have other legal rights that vary from state to state.
|
||||||
|
|
||||||
|
|
||||||
|
Indemnity
|
||||||
|
=========
|
||||||
|
|
||||||
|
To the extent permitted by applicable law, you agree to defend,
|
||||||
|
indemnify, and hold harmless the Taler Parties from and against any
|
||||||
|
and all claims, damages, obligations, losses, liabilities, costs or
|
||||||
|
debt, and expenses (including, but not limited to, attorney’s fees)
|
||||||
|
arising from: (a) your use of and access to the Services; (b) any
|
||||||
|
feedback or submissions you provide to us concerning the Taler Wallet;
|
||||||
|
(c) your violation of any term of this Agreement; or (d) your
|
||||||
|
violation of any law, rule, or regulation, or the rights of any third
|
||||||
|
party.
|
||||||
|
|
||||||
|
|
||||||
|
Time limitation on claims
|
||||||
|
=========================
|
||||||
|
|
||||||
|
You agree that any claim you may have arising out of or related to
|
||||||
|
your relationship with us must be filed within one year after such
|
||||||
|
claim arises, otherwise, your claim in permanently barred.
|
||||||
|
|
||||||
|
|
||||||
|
Governing law
|
||||||
|
=============
|
||||||
|
|
||||||
|
No matter where you’re located, the laws of Switzerland will govern
|
||||||
|
these Terms. If any provisions of these Terms are inconsistent with
|
||||||
|
any applicable law, those provisions will be superseded or modified
|
||||||
|
only to the extent such provisions are inconsistent. The parties agree
|
||||||
|
to submit to the ordinary courts in Zurich, Switzerland for exclusive
|
||||||
|
jurisdiction of any dispute arising out of or related to your use of
|
||||||
|
the Services or your breach of these Terms.
|
||||||
|
|
||||||
|
|
||||||
|
Termination
|
||||||
|
===========
|
||||||
|
|
||||||
|
In the event of termination concerning your use of our Services, your
|
||||||
|
obligations under this Agreement will still continue.
|
||||||
|
|
||||||
|
|
||||||
|
Discontinuance of services
|
||||||
|
==========================
|
||||||
|
|
||||||
|
We may, in our sole discretion and without cost to you, with or
|
||||||
|
without prior notice, and at any time, modify or discontinue,
|
||||||
|
temporarily or permanently, any portion of our Services. We will use
|
||||||
|
the Taler protocol’s provisions to notify Wallets if our Services are
|
||||||
|
to be discontinued. It is your responsibility to ensure that the Taler
|
||||||
|
Wallet is online at least once every three months to observe these
|
||||||
|
notifications. We shall not be held responsible or liable for any loss
|
||||||
|
of funds in the event that we discontinue or depreciate the Services
|
||||||
|
and your Taler Wallet fails to transfer out the coins within a three
|
||||||
|
months notification period.
|
||||||
|
|
||||||
|
|
||||||
|
No waiver
|
||||||
|
=========
|
||||||
|
|
||||||
|
Our failure to exercise or delay in exercising any right, power, or
|
||||||
|
privilege under this Agreement shall not operate as a waiver; nor
|
||||||
|
shall any single or partial exercise of any right, power, or privilege
|
||||||
|
preclude any other or further exercise thereof.
|
||||||
|
|
||||||
|
|
||||||
|
Severability
|
||||||
|
============
|
||||||
|
|
||||||
|
If it turns out that any part of this Agreement is invalid, void, or
|
||||||
|
for any reason unenforceable, that term will be deemed severable and
|
||||||
|
limited or eliminated to the minimum extent necessary.
|
||||||
|
|
||||||
|
|
||||||
|
Force majeure
|
||||||
|
=============
|
||||||
|
|
||||||
|
We shall not be held liable for any delays, failure in performance, or
|
||||||
|
interruptions of service which result directly or indirectly from any
|
||||||
|
cause or condition beyond our reasonable control, including but not
|
||||||
|
limited to: any delay or failure due to any act of God, act of civil
|
||||||
|
or military authorities, act of terrorism, civil disturbance, war,
|
||||||
|
strike or other labor dispute, fire, interruption in
|
||||||
|
telecommunications or Internet services or network provider services,
|
||||||
|
failure of equipment and/or software, other catastrophe, or any other
|
||||||
|
occurrence which is beyond our reasonable control and shall not affect
|
||||||
|
the validity and enforceability of any remaining provisions.
|
||||||
|
|
||||||
|
|
||||||
|
Assignment
|
||||||
|
==========
|
||||||
|
|
||||||
|
You agree that we may assign any of our rights and/or transfer, sub-
|
||||||
|
contract, or delegate any of our obligations under these Terms.
|
||||||
|
|
||||||
|
|
||||||
|
Entire agreement
|
||||||
|
================
|
||||||
|
|
||||||
|
This Agreement sets forth the entire understanding and agreement as to
|
||||||
|
the subject matter hereof and supersedes any and all prior
|
||||||
|
discussions, agreements, and understandings of any kind (including,
|
||||||
|
without limitation, any prior versions of this Agreement) and every
|
||||||
|
nature between us. Except as provided for above, any modification to
|
||||||
|
this Agreement must be in writing and must be signed by both parties.
|
||||||
|
|
||||||
|
|
||||||
|
Questions or comments
|
||||||
|
=====================
|
||||||
|
|
||||||
|
We welcome comments, questions, concerns, or suggestions. Please send
|
||||||
|
us a message on our contact page at legal@taler-systems.com.
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
const termsXml = `<?xml version="1.0" encoding="utf-8"?>
|
const termsXml = `<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!DOCTYPE document PUBLIC "+//IDN docutils.sourceforge.net//DTD Docutils Generic//EN//XML" "http://docutils.sourceforge.net/docs/ref/docutils.dtd">
|
<!DOCTYPE document PUBLIC "+//IDN docutils.sourceforge.net//DTD Docutils Generic//EN//XML" "http://docutils.sourceforge.net/docs/ref/docutils.dtd">
|
||||||
<!-- Generated by Docutils 0.14 -->
|
<!-- Generated by Docutils 0.14 -->
|
||||||
@ -381,7 +780,7 @@ const termsXml = `<?xml version="1.0" encoding="utf-8"?>
|
|||||||
</document>
|
</document>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const WithdrawNewTermsXML = createExample(TestedComponent, {
|
export const NewTerms = createExample(TestedComponent, {
|
||||||
knownExchanges: [{
|
knownExchanges: [{
|
||||||
currency: 'USD',
|
currency: 'USD',
|
||||||
exchangeBaseUrl: 'exchange.demo.taler.net',
|
exchangeBaseUrl: 'exchange.demo.taler.net',
|
||||||
@ -417,7 +816,134 @@ export const WithdrawNewTermsXML = createExample(TestedComponent, {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export const WithdrawNewTermsReviewingXML = createExample(TestedComponent, {
|
export const TermsReviewingPLAIN = createExample(TestedComponent, {
|
||||||
|
knownExchanges: [{
|
||||||
|
currency: 'USD',
|
||||||
|
exchangeBaseUrl: 'exchange.demo.taler.net',
|
||||||
|
paytoUris: ['asd'],
|
||||||
|
},{
|
||||||
|
currency: 'USD',
|
||||||
|
exchangeBaseUrl: 'exchange.test.taler.net',
|
||||||
|
paytoUris: ['asd'],
|
||||||
|
}],
|
||||||
|
details: {
|
||||||
|
exchangeInfo: {
|
||||||
|
baseUrl: 'exchange.demo.taler.net'
|
||||||
|
} as ExchangeRecord,
|
||||||
|
withdrawFee: {
|
||||||
|
currency: 'USD',
|
||||||
|
fraction: 0,
|
||||||
|
value: 0
|
||||||
|
},
|
||||||
|
} as ExchangeWithdrawDetails,
|
||||||
|
amount: {
|
||||||
|
currency: 'USD',
|
||||||
|
value: 2,
|
||||||
|
fraction: 10000000
|
||||||
|
},
|
||||||
|
|
||||||
|
onSwitchExchange: async () => { },
|
||||||
|
terms: {
|
||||||
|
value: {
|
||||||
|
type: 'plain',
|
||||||
|
content: termsPlain
|
||||||
|
},
|
||||||
|
status: 'new'
|
||||||
|
},
|
||||||
|
reviewing: true
|
||||||
|
})
|
||||||
|
|
||||||
|
export const TermsReviewingHTML = createExample(TestedComponent, {
|
||||||
|
knownExchanges: [{
|
||||||
|
currency: 'USD',
|
||||||
|
exchangeBaseUrl: 'exchange.demo.taler.net',
|
||||||
|
paytoUris: ['asd'],
|
||||||
|
},{
|
||||||
|
currency: 'USD',
|
||||||
|
exchangeBaseUrl: 'exchange.test.taler.net',
|
||||||
|
paytoUris: ['asd'],
|
||||||
|
}],
|
||||||
|
details: {
|
||||||
|
exchangeInfo: {
|
||||||
|
baseUrl: 'exchange.demo.taler.net'
|
||||||
|
} as ExchangeRecord,
|
||||||
|
withdrawFee: {
|
||||||
|
currency: 'USD',
|
||||||
|
fraction: 0,
|
||||||
|
value: 0
|
||||||
|
},
|
||||||
|
} as ExchangeWithdrawDetails,
|
||||||
|
amount: {
|
||||||
|
currency: 'USD',
|
||||||
|
value: 2,
|
||||||
|
fraction: 10000000
|
||||||
|
},
|
||||||
|
|
||||||
|
onSwitchExchange: async () => { },
|
||||||
|
terms: {
|
||||||
|
value: {
|
||||||
|
type: 'html',
|
||||||
|
href: new URL(`data:text/html;base64,${Buffer.from(termsHtml).toString('base64')}`),
|
||||||
|
},
|
||||||
|
status: 'new'
|
||||||
|
},
|
||||||
|
reviewing: true
|
||||||
|
})
|
||||||
|
|
||||||
|
const termsPdf = `
|
||||||
|
%PDF-1.2
|
||||||
|
9 0 obj << >>
|
||||||
|
stream
|
||||||
|
BT/ 9 Tf(This is the Exchange TERMS OF SERVICE)' ET
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
4 0 obj << /Type /Page /Parent 5 0 R /Contents 9 0 R >> endobj
|
||||||
|
5 0 obj << /Kids [4 0 R ] /Count 1 /Type /Pages /MediaBox [ 0 0 180 20 ] >> endobj
|
||||||
|
3 0 obj << /Pages 5 0 R /Type /Catalog >> endobj
|
||||||
|
trailer
|
||||||
|
<< /Root 3 0 R >>
|
||||||
|
%%EOF
|
||||||
|
`
|
||||||
|
|
||||||
|
export const TermsReviewingPDF = createExample(TestedComponent, {
|
||||||
|
knownExchanges: [{
|
||||||
|
currency: 'USD',
|
||||||
|
exchangeBaseUrl: 'exchange.demo.taler.net',
|
||||||
|
paytoUris: ['asd'],
|
||||||
|
},{
|
||||||
|
currency: 'USD',
|
||||||
|
exchangeBaseUrl: 'exchange.test.taler.net',
|
||||||
|
paytoUris: ['asd'],
|
||||||
|
}],
|
||||||
|
details: {
|
||||||
|
exchangeInfo: {
|
||||||
|
baseUrl: 'exchange.demo.taler.net'
|
||||||
|
} as ExchangeRecord,
|
||||||
|
withdrawFee: {
|
||||||
|
currency: 'USD',
|
||||||
|
fraction: 0,
|
||||||
|
value: 0
|
||||||
|
},
|
||||||
|
} as ExchangeWithdrawDetails,
|
||||||
|
amount: {
|
||||||
|
currency: 'USD',
|
||||||
|
value: 2,
|
||||||
|
fraction: 10000000
|
||||||
|
},
|
||||||
|
|
||||||
|
onSwitchExchange: async () => { },
|
||||||
|
terms: {
|
||||||
|
value: {
|
||||||
|
type: 'pdf',
|
||||||
|
location: new URL(`data:text/html;base64,${Buffer.from(termsPdf).toString('base64')}`),
|
||||||
|
},
|
||||||
|
status: 'new'
|
||||||
|
},
|
||||||
|
reviewing: true
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
export const TermsReviewingXML = createExample(TestedComponent, {
|
||||||
knownExchanges: [{
|
knownExchanges: [{
|
||||||
currency: 'USD',
|
currency: 'USD',
|
||||||
exchangeBaseUrl: 'exchange.demo.taler.net',
|
exchangeBaseUrl: 'exchange.demo.taler.net',
|
||||||
@ -454,7 +980,7 @@ export const WithdrawNewTermsReviewingXML = createExample(TestedComponent, {
|
|||||||
reviewing: true
|
reviewing: true
|
||||||
})
|
})
|
||||||
|
|
||||||
export const WithdrawNewTermsAcceptedXML = createExample(TestedComponent, {
|
export const NewTermsAccepted = createExample(TestedComponent, {
|
||||||
knownExchanges: [{
|
knownExchanges: [{
|
||||||
currency: 'USD',
|
currency: 'USD',
|
||||||
exchangeBaseUrl: 'exchange.demo.taler.net',
|
exchangeBaseUrl: 'exchange.demo.taler.net',
|
||||||
@ -487,10 +1013,10 @@ export const WithdrawNewTermsAcceptedXML = createExample(TestedComponent, {
|
|||||||
},
|
},
|
||||||
status: 'new'
|
status: 'new'
|
||||||
},
|
},
|
||||||
accepted: true
|
reviewed: true
|
||||||
})
|
})
|
||||||
|
|
||||||
export const WithdrawNewTermsShowAfterAcceptedXML = createExample(TestedComponent, {
|
export const TermsShowAgainXML = createExample(TestedComponent, {
|
||||||
knownExchanges: [{
|
knownExchanges: [{
|
||||||
currency: 'USD',
|
currency: 'USD',
|
||||||
exchangeBaseUrl: 'exchange.demo.taler.net',
|
exchangeBaseUrl: 'exchange.demo.taler.net',
|
||||||
@ -528,7 +1054,7 @@ export const WithdrawNewTermsShowAfterAcceptedXML = createExample(TestedComponen
|
|||||||
reviewing: true,
|
reviewing: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const WithdrawChangedTermsXML = createExample(TestedComponent, {
|
export const TermsChanged = createExample(TestedComponent, {
|
||||||
knownExchanges: [{
|
knownExchanges: [{
|
||||||
currency: 'USD',
|
currency: 'USD',
|
||||||
exchangeBaseUrl: 'exchange.demo.taler.net',
|
exchangeBaseUrl: 'exchange.demo.taler.net',
|
||||||
@ -564,7 +1090,7 @@ export const WithdrawChangedTermsXML = createExample(TestedComponent, {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export const WithdrawNotFoundTermsXML = createExample(TestedComponent, {
|
export const TermsNotFound = createExample(TestedComponent, {
|
||||||
knownExchanges: [{
|
knownExchanges: [{
|
||||||
currency: 'USD',
|
currency: 'USD',
|
||||||
exchangeBaseUrl: 'exchange.demo.taler.net',
|
exchangeBaseUrl: 'exchange.demo.taler.net',
|
||||||
@ -596,7 +1122,7 @@ export const WithdrawNotFoundTermsXML = createExample(TestedComponent, {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export const WithdrawAcceptedTermsXML = createExample(TestedComponent, {
|
export const TermsAlreadyAccepted = createExample(TestedComponent, {
|
||||||
knownExchanges: [{
|
knownExchanges: [{
|
||||||
currency: 'USD',
|
currency: 'USD',
|
||||||
exchangeBaseUrl: 'exchange.demo.taler.net',
|
exchangeBaseUrl: 'exchange.demo.taler.net',
|
||||||
@ -629,7 +1155,7 @@ export const WithdrawAcceptedTermsXML = createExample(TestedComponent, {
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
export const WithdrawAcceptedTermsWithoutFee = createExample(TestedComponent, {
|
export const WithoutFee = createExample(TestedComponent, {
|
||||||
knownExchanges: [{
|
knownExchanges: [{
|
||||||
currency: 'USD',
|
currency: 'USD',
|
||||||
exchangeBaseUrl: 'exchange.demo.taler.net',
|
exchangeBaseUrl: 'exchange.demo.taler.net',
|
||||||
|
@ -49,7 +49,7 @@ export interface ViewProps {
|
|||||||
onReview: (b: boolean) => void;
|
onReview: (b: boolean) => void;
|
||||||
onAccept: (b: boolean) => void;
|
onAccept: (b: boolean) => void;
|
||||||
reviewing: boolean;
|
reviewing: boolean;
|
||||||
accepted: boolean;
|
reviewed: boolean;
|
||||||
confirmed: boolean;
|
confirmed: boolean;
|
||||||
terms: {
|
terms: {
|
||||||
value?: TermsDocument;
|
value?: TermsDocument;
|
||||||
@ -61,7 +61,7 @@ export interface ViewProps {
|
|||||||
|
|
||||||
type TermsStatus = 'new' | 'accepted' | 'changed' | 'notfound';
|
type TermsStatus = 'new' | 'accepted' | 'changed' | 'notfound';
|
||||||
|
|
||||||
type TermsDocument = TermsDocumentXml | TermsDocumentHtml;
|
type TermsDocument = TermsDocumentXml | TermsDocumentHtml | TermsDocumentPlain | TermsDocumentJson | TermsDocumentPdf;
|
||||||
|
|
||||||
interface TermsDocumentXml {
|
interface TermsDocumentXml {
|
||||||
type: 'xml',
|
type: 'xml',
|
||||||
@ -70,7 +70,22 @@ interface TermsDocumentXml {
|
|||||||
|
|
||||||
interface TermsDocumentHtml {
|
interface TermsDocumentHtml {
|
||||||
type: 'html',
|
type: 'html',
|
||||||
href: string,
|
href: URL,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TermsDocumentPlain {
|
||||||
|
type: 'plain',
|
||||||
|
content: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TermsDocumentJson {
|
||||||
|
type: 'json',
|
||||||
|
data: any,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TermsDocumentPdf {
|
||||||
|
type: 'pdf',
|
||||||
|
location: URL,
|
||||||
}
|
}
|
||||||
|
|
||||||
function amountToString(text: AmountJson) {
|
function amountToString(text: AmountJson) {
|
||||||
@ -79,7 +94,7 @@ function amountToString(text: AmountJson) {
|
|||||||
return `${amount} ${aj.currency}`
|
return `${amount} ${aj.currency}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function View({ details, knownExchanges, amount, onWithdraw, onSwitchExchange, terms, reviewing, onReview, onAccept, accepted, confirmed }: ViewProps) {
|
export function View({ details, knownExchanges, amount, onWithdraw, onSwitchExchange, terms, reviewing, onReview, onAccept, reviewed, confirmed }: ViewProps) {
|
||||||
const needsReview = terms.status === 'changed' || terms.status === 'new'
|
const needsReview = terms.status === 'changed' || terms.status === 'new'
|
||||||
|
|
||||||
const [switchingExchange, setSwitchingExchange] = useState<string | undefined>(undefined)
|
const [switchingExchange, setSwitchingExchange] = useState<string | undefined>(undefined)
|
||||||
@ -105,9 +120,6 @@ export function View({ details, knownExchanges, amount, onWithdraw, onSwitchExch
|
|||||||
<div>
|
<div>
|
||||||
<SelectList label="Known exchanges" list={exchanges} name="" onChange={onSwitchExchange} />
|
<SelectList label="Known exchanges" list={exchanges} name="" onChange={onSwitchExchange} />
|
||||||
</div>
|
</div>
|
||||||
<p>
|
|
||||||
This is the list of known exchanges
|
|
||||||
</p>
|
|
||||||
<LinkSuccess upperCased onClick={() => onSwitchExchange(switchingExchange)}>
|
<LinkSuccess upperCased onClick={() => onSwitchExchange(switchingExchange)}>
|
||||||
{i18n.str`Confirm exchange selection`}
|
{i18n.str`Confirm exchange selection`}
|
||||||
</LinkSuccess>
|
</LinkSuccess>
|
||||||
@ -118,7 +130,7 @@ export function View({ details, knownExchanges, amount, onWithdraw, onSwitchExch
|
|||||||
|
|
||||||
</section>
|
</section>
|
||||||
}
|
}
|
||||||
{!reviewing && accepted &&
|
{!reviewing && reviewed &&
|
||||||
<section>
|
<section>
|
||||||
<LinkSuccess
|
<LinkSuccess
|
||||||
upperCased
|
upperCased
|
||||||
@ -130,11 +142,24 @@ export function View({ details, knownExchanges, amount, onWithdraw, onSwitchExch
|
|||||||
}
|
}
|
||||||
{reviewing &&
|
{reviewing &&
|
||||||
<section>
|
<section>
|
||||||
<TermsOfService>
|
{terms.status !== 'accepted' && terms.value && terms.value.type === 'xml' &&
|
||||||
{terms.status !== 'accepted' && terms.value && terms.value.type === 'xml' && <ExchangeXmlTos doc={terms.value.document} />}
|
<TermsOfService>
|
||||||
</TermsOfService>
|
<ExchangeXmlTos doc={terms.value.document} />
|
||||||
|
</TermsOfService>
|
||||||
|
}
|
||||||
|
{terms.status !== 'accepted' && terms.value && terms.value.type === 'plain' &&
|
||||||
|
<div style={{ textAlign: 'left' }}>
|
||||||
|
<pre>{terms.value.content}</pre>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
{terms.status !== 'accepted' && terms.value && terms.value.type === 'html' &&
|
||||||
|
<iframe src={terms.value.href.toString()} />
|
||||||
|
}
|
||||||
|
{terms.status !== 'accepted' && terms.value && terms.value.type === 'pdf' &&
|
||||||
|
<a href={terms.value.location.toString()} download="tos.pdf" >Download Terms of Service</a>
|
||||||
|
}
|
||||||
</section>}
|
</section>}
|
||||||
{reviewing && accepted &&
|
{reviewing && reviewed &&
|
||||||
<section>
|
<section>
|
||||||
<LinkSuccess
|
<LinkSuccess
|
||||||
upperCased
|
upperCased
|
||||||
@ -144,14 +169,14 @@ export function View({ details, knownExchanges, amount, onWithdraw, onSwitchExch
|
|||||||
</LinkSuccess>
|
</LinkSuccess>
|
||||||
</section>
|
</section>
|
||||||
}
|
}
|
||||||
{(reviewing || accepted) &&
|
{(reviewing || reviewed) &&
|
||||||
<section>
|
<section>
|
||||||
<CheckboxOutlined
|
<CheckboxOutlined
|
||||||
name="terms"
|
name="terms"
|
||||||
enabled={accepted}
|
enabled={reviewed}
|
||||||
label={i18n.str`I accept the exchange terms of service`}
|
label={i18n.str`I accept the exchange terms of service`}
|
||||||
onToggle={() => {
|
onToggle={() => {
|
||||||
onAccept(!accepted)
|
onAccept(!reviewed)
|
||||||
onReview(false)
|
onReview(false)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -162,7 +187,7 @@ export function View({ details, knownExchanges, amount, onWithdraw, onSwitchExch
|
|||||||
* Main action section
|
* Main action section
|
||||||
*/}
|
*/}
|
||||||
<section>
|
<section>
|
||||||
{terms.status === 'new' && !accepted && !reviewing &&
|
{terms.status === 'new' && !reviewed && !reviewing &&
|
||||||
<ButtonSuccess
|
<ButtonSuccess
|
||||||
upperCased
|
upperCased
|
||||||
disabled={!details.exchangeInfo.baseUrl}
|
disabled={!details.exchangeInfo.baseUrl}
|
||||||
@ -171,7 +196,7 @@ export function View({ details, knownExchanges, amount, onWithdraw, onSwitchExch
|
|||||||
{i18n.str`Review exchange terms of service`}
|
{i18n.str`Review exchange terms of service`}
|
||||||
</ButtonSuccess>
|
</ButtonSuccess>
|
||||||
}
|
}
|
||||||
{terms.status === 'changed' && !accepted &&
|
{terms.status === 'changed' && !reviewed && !reviewing &&
|
||||||
<ButtonWarning
|
<ButtonWarning
|
||||||
upperCased
|
upperCased
|
||||||
disabled={!details.exchangeInfo.baseUrl}
|
disabled={!details.exchangeInfo.baseUrl}
|
||||||
@ -180,7 +205,7 @@ export function View({ details, knownExchanges, amount, onWithdraw, onSwitchExch
|
|||||||
{i18n.str`Review new version of terms of service`}
|
{i18n.str`Review new version of terms of service`}
|
||||||
</ButtonWarning>
|
</ButtonWarning>
|
||||||
}
|
}
|
||||||
{(terms.status === 'accepted' || (needsReview && accepted)) &&
|
{(terms.status === 'accepted' || (needsReview && reviewed)) &&
|
||||||
<ButtonSuccess
|
<ButtonSuccess
|
||||||
upperCased
|
upperCased
|
||||||
disabled={!details.exchangeInfo.baseUrl || confirmed}
|
disabled={!details.exchangeInfo.baseUrl || confirmed}
|
||||||
@ -204,7 +229,7 @@ export function WithdrawPageWithParsedURI({ uri, uriInfo }: { uri: string, uriIn
|
|||||||
const [errorAccepting, setErrorAccepting] = useState<string | undefined>(undefined)
|
const [errorAccepting, setErrorAccepting] = useState<string | undefined>(undefined)
|
||||||
|
|
||||||
const [reviewing, setReviewing] = useState<boolean>(false)
|
const [reviewing, setReviewing] = useState<boolean>(false)
|
||||||
const [accepted, setAccepted] = useState<boolean>(false)
|
const [reviewed, setReviewed] = useState<boolean>(false)
|
||||||
const [confirmed, setConfirmed] = useState<boolean>(false)
|
const [confirmed, setConfirmed] = useState<boolean>(false)
|
||||||
|
|
||||||
const knownExchangesHook = useAsyncAsHook(() => listExchanges())
|
const knownExchangesHook = useAsyncAsHook(() => listExchanges())
|
||||||
@ -219,7 +244,7 @@ export function WithdrawPageWithParsedURI({ uri, uriInfo }: { uri: string, uriIn
|
|||||||
return getExchangeWithdrawalInfo({
|
return getExchangeWithdrawalInfo({
|
||||||
exchangeBaseUrl: exchange,
|
exchangeBaseUrl: exchange,
|
||||||
amount: withdrawAmount,
|
amount: withdrawAmount,
|
||||||
tosAcceptedFormat: ['text/json', 'text/xml', 'text/pdf']
|
tosAcceptedFormat: ['text/xml']
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -235,7 +260,7 @@ export function WithdrawPageWithParsedURI({ uri, uriInfo }: { uri: string, uriIn
|
|||||||
const onAccept = async (): Promise<void> => {
|
const onAccept = async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
await setExchangeTosAccepted(details.exchangeInfo.baseUrl, details.tosRequested?.tosEtag)
|
await setExchangeTosAccepted(details.exchangeInfo.baseUrl, details.tosRequested?.tosEtag)
|
||||||
setAccepted(true)
|
setReviewed(true)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Error) {
|
if (e instanceof Error) {
|
||||||
setErrorAccepting(e.message)
|
setErrorAccepting(e.message)
|
||||||
@ -257,18 +282,7 @@ export function WithdrawPageWithParsedURI({ uri, uriInfo }: { uri: string, uriIn
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let termsContent: TermsDocument | undefined = undefined;
|
const termsContent: TermsDocument | undefined = !details.tosRequested ? undefined : parseTermsOfServiceContent(details.tosRequested.tosContentType, details.tosRequested.tosText);
|
||||||
if (details.tosRequested) {
|
|
||||||
if (details.tosRequested.tosContentType === 'text/xml') {
|
|
||||||
try {
|
|
||||||
const document = new DOMParser().parseFromString(details.tosRequested.tosText, "text/xml")
|
|
||||||
termsContent = { type: 'xml', document }
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e)
|
|
||||||
debugger;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const status: TermsStatus = !termsContent ? 'notfound' : (
|
const status: TermsStatus = !termsContent ? 'notfound' : (
|
||||||
!details.exchangeDetails.termsOfServiceAcceptedEtag ? 'new' : (
|
!details.exchangeDetails.termsOfServiceAcceptedEtag ? 'new' : (
|
||||||
@ -285,7 +299,7 @@ export function WithdrawPageWithParsedURI({ uri, uriInfo }: { uri: string, uriIn
|
|||||||
onSwitchExchange={setCustomExchange}
|
onSwitchExchange={setCustomExchange}
|
||||||
knownExchanges={knownExchanges}
|
knownExchanges={knownExchanges}
|
||||||
confirmed={confirmed}
|
confirmed={confirmed}
|
||||||
accepted={accepted} onAccept={onAccept}
|
reviewed={reviewed} onAccept={onAccept}
|
||||||
reviewing={reviewing} onReview={setReviewing}
|
reviewing={reviewing} onReview={setReviewing}
|
||||||
// terms={[]}
|
// terms={[]}
|
||||||
/>
|
/>
|
||||||
@ -307,3 +321,48 @@ export function WithdrawPage({ talerWithdrawUri }: Props): JSX.Element {
|
|||||||
return <WithdrawPageWithParsedURI uri={talerWithdrawUri} uriInfo={uriInfoHook.response} />
|
return <WithdrawPageWithParsedURI uri={talerWithdrawUri} uriInfo={uriInfoHook.response} />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseTermsOfServiceContent(type: string, text: string): TermsDocument | undefined {
|
||||||
|
if (type === 'text/xml') {
|
||||||
|
try {
|
||||||
|
const document = new DOMParser().parseFromString(text, "text/xml")
|
||||||
|
return { type: 'xml', document }
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
debugger;
|
||||||
|
}
|
||||||
|
} else if (type === 'text/html') {
|
||||||
|
try {
|
||||||
|
const href = new URL(text)
|
||||||
|
return { type: 'html', href }
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
debugger;
|
||||||
|
}
|
||||||
|
} else if (type === 'text/json') {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(text)
|
||||||
|
return { type: 'json', data }
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
debugger;
|
||||||
|
}
|
||||||
|
} else if (type === 'text/pdf') {
|
||||||
|
try {
|
||||||
|
const location = new URL(text)
|
||||||
|
return { type: 'pdf', location }
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
debugger;
|
||||||
|
}
|
||||||
|
} else if (type === 'text/plain') {
|
||||||
|
try {
|
||||||
|
const content = text
|
||||||
|
return { type: 'plain', content }
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
debugger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -25,10 +25,7 @@ export function useTalerActionURL(): [string | undefined, (s: boolean) => void]
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function check(): Promise<void> {
|
async function check(): Promise<void> {
|
||||||
const talerUri = await findTalerUriInActiveTab();
|
const talerUri = await findTalerUriInActiveTab();
|
||||||
if (talerUri) {
|
setTalerActionUrl(talerUri)
|
||||||
const actionUrl = actionForTalerUri(talerUri);
|
|
||||||
setTalerActionUrl(actionUrl);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
check();
|
check();
|
||||||
}, []);
|
}, []);
|
||||||
@ -36,49 +33,6 @@ export function useTalerActionURL(): [string | undefined, (s: boolean) => void]
|
|||||||
return [url, setDismissed];
|
return [url, setDismissed];
|
||||||
}
|
}
|
||||||
|
|
||||||
function actionForTalerUri(talerUri: string): string | undefined {
|
|
||||||
const uriType = classifyTalerUri(talerUri);
|
|
||||||
switch (uriType) {
|
|
||||||
case TalerUriType.TalerWithdraw:
|
|
||||||
return makeExtensionUrlWithParams("static/wallet.html#/withdraw", {
|
|
||||||
talerWithdrawUri: talerUri,
|
|
||||||
});
|
|
||||||
case TalerUriType.TalerPay:
|
|
||||||
return makeExtensionUrlWithParams("static/wallet.html#/pay", {
|
|
||||||
talerPayUri: talerUri,
|
|
||||||
});
|
|
||||||
case TalerUriType.TalerTip:
|
|
||||||
return makeExtensionUrlWithParams("static/wallet.html#/tip", {
|
|
||||||
talerTipUri: talerUri,
|
|
||||||
});
|
|
||||||
case TalerUriType.TalerRefund:
|
|
||||||
return makeExtensionUrlWithParams("static/wallet.html#/refund", {
|
|
||||||
talerRefundUri: talerUri,
|
|
||||||
});
|
|
||||||
case TalerUriType.TalerNotifyReserve:
|
|
||||||
// FIXME: implement
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.warn(
|
|
||||||
"Response with HTTP 402 has Taler header, but header value is not a taler:// URI.",
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeExtensionUrlWithParams(
|
|
||||||
url: string,
|
|
||||||
params?: { [name: string]: string | undefined },
|
|
||||||
): string {
|
|
||||||
const innerUrl = new URL(chrome.extension.getURL("/" + url));
|
|
||||||
if (params) {
|
|
||||||
const hParams = Object.keys(params).map(k => `${k}=${params[k]}`).join('&')
|
|
||||||
innerUrl.hash = innerUrl.hash + '?' + hParams
|
|
||||||
}
|
|
||||||
return innerUrl.href;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function findTalerUriInActiveTab(): Promise<string | undefined> {
|
async function findTalerUriInActiveTab(): Promise<string | undefined> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
chrome.tabs.executeScript(
|
chrome.tabs.executeScript(
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
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 { createExample } from '../test-utils';
|
||||||
|
import { TalerActionFound as TestedComponent } from './TalerActionFound';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'popup/TalerActionFound',
|
||||||
|
component: TestedComponent,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const PayAction = createExample(TestedComponent, {
|
||||||
|
url: 'taler://pay/something'
|
||||||
|
});
|
||||||
|
|
||||||
|
export const WithdrawalAction = createExample(TestedComponent, {
|
||||||
|
url: 'taler://withdraw/something'
|
||||||
|
});
|
||||||
|
|
||||||
|
export const TipAction = createExample(TestedComponent, {
|
||||||
|
url: 'taler://tip/something'
|
||||||
|
});
|
||||||
|
|
||||||
|
export const NotifyAction = createExample(TestedComponent, {
|
||||||
|
url: 'taler://notify-reserve/something'
|
||||||
|
});
|
||||||
|
|
||||||
|
export const RefundAction = createExample(TestedComponent, {
|
||||||
|
url: 'taler://refund/something'
|
||||||
|
});
|
||||||
|
|
||||||
|
export const InvalidAction = createExample(TestedComponent, {
|
||||||
|
url: 'taler://something/asd'
|
||||||
|
});
|
@ -0,0 +1,98 @@
|
|||||||
|
import { classifyTalerUri, TalerUriType } from "@gnu-taler/taler-util";
|
||||||
|
import { ButtonPrimary, ButtonSuccess, PopupBox } from "../components/styled/index";
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
url: string;
|
||||||
|
onDismiss: (s: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TalerActionFound({ url, onDismiss }: Props) {
|
||||||
|
const uriType = classifyTalerUri(url);
|
||||||
|
return <PopupBox>
|
||||||
|
<section>
|
||||||
|
<h1>Taler Action </h1>
|
||||||
|
{uriType === TalerUriType.TalerPay && <div>
|
||||||
|
<p>This page has pay action.</p>
|
||||||
|
<ButtonSuccess onClick={() => { chrome.tabs.create({ "url": actionForTalerUri(uriType, url) }); }}>
|
||||||
|
Open pay page
|
||||||
|
</ButtonSuccess>
|
||||||
|
</div>}
|
||||||
|
{uriType === TalerUriType.TalerWithdraw && <div>
|
||||||
|
<p>This page has a withdrawal action.</p>
|
||||||
|
<ButtonSuccess onClick={() => { chrome.tabs.create({ "url": actionForTalerUri(uriType, url) }); }}>
|
||||||
|
Open withdraw page
|
||||||
|
</ButtonSuccess>
|
||||||
|
</div>}
|
||||||
|
{uriType === TalerUriType.TalerTip && <div>
|
||||||
|
<p>This page has a tip action.</p>
|
||||||
|
<ButtonSuccess onClick={() => { chrome.tabs.create({ "url": actionForTalerUri(uriType, url) }); }}>
|
||||||
|
Open tip page
|
||||||
|
</ButtonSuccess>
|
||||||
|
</div>}
|
||||||
|
{uriType === TalerUriType.TalerNotifyReserve && <div>
|
||||||
|
<p>This page has a notify reserve action.</p>
|
||||||
|
<ButtonSuccess onClick={() => { chrome.tabs.create({ "url": actionForTalerUri(uriType, url) }); }}>
|
||||||
|
Notify
|
||||||
|
</ButtonSuccess>
|
||||||
|
</div>}
|
||||||
|
{uriType === TalerUriType.TalerRefund && <div>
|
||||||
|
<p>This page has a refund action.</p>
|
||||||
|
<ButtonSuccess onClick={() => { chrome.tabs.create({ "url": actionForTalerUri(uriType, url) }); }}>
|
||||||
|
Open refund page
|
||||||
|
</ButtonSuccess>
|
||||||
|
</div>}
|
||||||
|
{uriType === TalerUriType.Unknown && <div>
|
||||||
|
<p>This page has a malformed taler uri.</p>
|
||||||
|
<p>{url}</p>
|
||||||
|
</div>}
|
||||||
|
|
||||||
|
</section>
|
||||||
|
<footer>
|
||||||
|
<div />
|
||||||
|
<ButtonPrimary onClick={() => onDismiss(true)}> Dismiss </ButtonPrimary>
|
||||||
|
</footer>
|
||||||
|
</PopupBox>;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function actionForTalerUri(uriType: TalerUriType, talerUri: string): string | undefined {
|
||||||
|
switch (uriType) {
|
||||||
|
case TalerUriType.TalerWithdraw:
|
||||||
|
return makeExtensionUrlWithParams("static/wallet.html#/withdraw", {
|
||||||
|
talerWithdrawUri: talerUri,
|
||||||
|
});
|
||||||
|
case TalerUriType.TalerPay:
|
||||||
|
return makeExtensionUrlWithParams("static/wallet.html#/pay", {
|
||||||
|
talerPayUri: talerUri,
|
||||||
|
});
|
||||||
|
case TalerUriType.TalerTip:
|
||||||
|
return makeExtensionUrlWithParams("static/wallet.html#/tip", {
|
||||||
|
talerTipUri: talerUri,
|
||||||
|
});
|
||||||
|
case TalerUriType.TalerRefund:
|
||||||
|
return makeExtensionUrlWithParams("static/wallet.html#/refund", {
|
||||||
|
talerRefundUri: talerUri,
|
||||||
|
});
|
||||||
|
case TalerUriType.TalerNotifyReserve:
|
||||||
|
// FIXME: implement
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.warn(
|
||||||
|
"Response with HTTP 402 has Taler header, but header value is not a taler:// URI.",
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeExtensionUrlWithParams(
|
||||||
|
url: string,
|
||||||
|
params?: { [name: string]: string | undefined },
|
||||||
|
): string {
|
||||||
|
const innerUrl = new URL(chrome.extension.getURL("/" + url));
|
||||||
|
if (params) {
|
||||||
|
const hParams = Object.keys(params).map(k => `${k}=${params[k]}`).join('&')
|
||||||
|
innerUrl.hash = innerUrl.hash + '?' + hParams
|
||||||
|
}
|
||||||
|
return innerUrl.href;
|
||||||
|
}
|
@ -38,6 +38,7 @@ import {
|
|||||||
import { ProviderAddPage } from "./popup/ProviderAddPage";
|
import { ProviderAddPage } from "./popup/ProviderAddPage";
|
||||||
import { ProviderDetailPage } from "./popup/ProviderDetailPage";
|
import { ProviderDetailPage } from "./popup/ProviderDetailPage";
|
||||||
import { SettingsPage } from "./popup/Settings";
|
import { SettingsPage } from "./popup/Settings";
|
||||||
|
import { TalerActionFound } from "./popup/TalerActionFound";
|
||||||
|
|
||||||
function main(): void {
|
function main(): void {
|
||||||
try {
|
try {
|
||||||
@ -62,32 +63,16 @@ if (document.readyState === "loading") {
|
|||||||
main();
|
main();
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
|
||||||
url: string;
|
|
||||||
onDismiss: (s: boolean) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
function TalerActionFound({ url, onDismiss }: Props) {
|
|
||||||
return <div style={{ padding: "1em", width: 400 }}>
|
|
||||||
<h1>Taler Action </h1>
|
|
||||||
<p>This page has a Taler action.</p>
|
|
||||||
<p>
|
|
||||||
<button onClick={() => { chrome.tabs.create({ "url": url }); }}>
|
|
||||||
Open
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<button onClick={() => onDismiss(true)}> Dismiss </button>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function Application() {
|
function Application() {
|
||||||
const [talerActionUrl, setDismissed] = useTalerActionURL()
|
const [talerActionUrl, setDismissed] = useTalerActionURL()
|
||||||
|
|
||||||
if (talerActionUrl) {
|
if (talerActionUrl) {
|
||||||
return <TalerActionFound url={talerActionUrl} onDismiss={setDismissed} />
|
return <div>
|
||||||
|
<WalletNavBar />
|
||||||
|
<div style={{ width: 400, height: 290 }}>
|
||||||
|
<TalerActionFound url={talerActionUrl} onDismiss={setDismissed} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -21,6 +21,8 @@ import { CreateManualWithdraw } from "./CreateManualWithdraw";
|
|||||||
import * as wxApi from '../wxApi'
|
import * as wxApi from '../wxApi'
|
||||||
import { AcceptManualWithdrawalResult, AmountJson, Amounts } from "@gnu-taler/taler-util";
|
import { AcceptManualWithdrawalResult, AmountJson, Amounts } from "@gnu-taler/taler-util";
|
||||||
import { ReserveCreated } from "./ReserveCreated.js";
|
import { ReserveCreated } from "./ReserveCreated.js";
|
||||||
|
import { route } from 'preact-router';
|
||||||
|
import { Pages } from "../NavigationBar.js";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
||||||
@ -58,7 +60,9 @@ export function ManualWithdrawPage({ }: Props): VNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
return <ReserveCreated reservePub={success.reservePub} paytos={success.exchangePaytoUris} onBack={() => {}}/>
|
return <ReserveCreated reservePub={success.reservePub} paytos={success.exchangePaytoUris} onBack={() => {
|
||||||
|
route(Pages.balance)
|
||||||
|
}}/>
|
||||||
}
|
}
|
||||||
|
|
||||||
return <CreateManualWithdraw
|
return <CreateManualWithdraw
|
||||||
|
@ -41,3 +41,13 @@ export const OneChecked = createExample(TestedComponent, {
|
|||||||
setDeviceName: () => Promise.resolve(),
|
setDeviceName: () => Promise.resolve(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const WithOneExchange = createExample(TestedComponent, {
|
||||||
|
deviceName: 'this-is-the-device-name',
|
||||||
|
permissionsEnabled: true,
|
||||||
|
setDeviceName: () => Promise.resolve(),
|
||||||
|
knownExchanges: [{
|
||||||
|
currency: 'USD',
|
||||||
|
exchangeBaseUrl: 'http://exchange.taler',
|
||||||
|
paytoUris: ['payto://x-taler-bank/bank.rpi.sebasjm.com/exchangeminator']
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
@ -81,15 +81,14 @@ export function SettingsView({ knownExchanges, lang, changeLang, deviceName, set
|
|||||||
{!knownExchanges || !knownExchanges.length ? <div>
|
{!knownExchanges || !knownExchanges.length ? <div>
|
||||||
No exchange yet!
|
No exchange yet!
|
||||||
</div> :
|
</div> :
|
||||||
<dl>
|
<table>
|
||||||
{knownExchanges.map(e => <Fragment>
|
{knownExchanges.map(e => <tr>
|
||||||
<dt>{e.currency}</dt>
|
<td>{e.currency}</td>
|
||||||
<dd>{e.exchangeBaseUrl}</dd>
|
<td><a href={e.exchangeBaseUrl}>{e.exchangeBaseUrl}</a></td>
|
||||||
<dd>{e.paytoUris}</dd>
|
</tr>)}
|
||||||
</Fragment>)}
|
</table>
|
||||||
</dl>
|
|
||||||
}
|
}
|
||||||
<ButtonPrimary>add exchange</ButtonPrimary>
|
|
||||||
<h2><i18n.Translate>Permissions</i18n.Translate></h2>
|
<h2><i18n.Translate>Permissions</i18n.Translate></h2>
|
||||||
<Checkbox label="Automatically open wallet based on page content"
|
<Checkbox label="Automatically open wallet based on page content"
|
||||||
name="perm"
|
name="perm"
|
||||||
|
@ -2,8 +2,32 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="/static/style/pure.css" />
|
<style>
|
||||||
<link rel="stylesheet" type="text/css" href="/static/style/popup.css" />
|
html {
|
||||||
|
font-family: sans-serif; /* 1 */
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style>
|
||||||
|
html {
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #f8faf7;
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
<link rel="stylesheet" type="text/css" href="/dist/popupEntryPoint.css" />
|
<link rel="stylesheet" type="text/css" href="/dist/popupEntryPoint.css" />
|
||||||
<link rel="icon" href="/static/img/icon.png" />
|
<link rel="icon" href="/static/img/icon.png" />
|
||||||
<script src="/dist/popupEntryPoint.js"></script>
|
<script src="/dist/popupEntryPoint.js"></script>
|
||||||
|
Loading…
Reference in New Issue
Block a user