@terra-js/crypto-payment
Install the library
yarn add @terra-js/crypto-payment
How to use
Initialize
- Call once to init the library globally
import {
setLanguage,
setClientId
} from '@terra-js/crypto-payment';
// call once to init
setLanguage('en');
setClientId('dinogo:web:playstore:0.0.1');
Input
// payment amount must be a valid positive number or a string presenting a valid positive number
// we encourage to use string if you need more accuracy
const PAYMENT_AMOUNT = '15.5'
// orderCode is a string defining the order in your system
const ORDER_CODE = '123456ABCD'
Style A: use PaymentCryptoComponent
import {
PaymentCryptoComponent,
ExposeErrorCode
} from '@terra-js/crypto-payment';
function App() {
return (
<div className="App">
<PaymentCryptoComponent paymentAmount={PAYMENT_AMOUNT} orderCode={ORDER_CODE} onPaymentResult={(result) => {
switch (result.code) {
case ExposeErrorCode.Success:
setResult("Success")
break
case ExposeErrorCode.VerifyTransactionHashFailed:
setResult(`VerifyTransactionHashFailed: ${result.message}`)
break
case ExposeErrorCode.WaitNotificationFailed:
setResult(`WaitNotificationFailed: ${result.message}`)
break
case ExposeErrorCode.UserCloseWaitNotificationPopup:
setResult(`UserCloseWaitNotificationPopup: ${result.message}`);
break;
}
}}/>
</div>
);
}
export default withPaymentCryptoProvider(App);
Style B: use PaymentCryptoButton
& PaymentCryptoModal
separately
import {
PaymentCryptoButton,
PaymentCryptoModal,
ExposeErrorCode
} from '@terra-js/crypto-payment';
function App() {
const [showPaymentCryptoPopup, setShowPaymentCryptoPopup] = useState(false);
return (
<div className="App">
<PaymentCryptoButton
onClickForPayment={() => {
setShowPaymentCryptoPopup(true);
}}
/>
<PaymentCryptoModal
isOpen={showPaymentCryptoPopup}
paymentAmount={PAYMENT_AMOUNT}
orderCode={ORDER_CODE}
onCloseModal={() => {
setShowPaymentCryptoPopup(false);
}}
onPaymentResult={(result) => {
console.log('crypto-payment-modal-result', result);
switch (result.code) {
case ExposeErrorCode.Success:
setResult('Success');
break;
case ExposeErrorCode.VerifyTransactionHashFailed:
setResult(`VerifyTransactionHashFailed: ${result.message}`);
break;
case ExposeErrorCode.WaitNotificationFailed:
setResult(`WaitNotificationFailed: ${result.message}`);
break;
case ExposeErrorCode.UserCloseWaitNotificationPopup:
setResult(`UserCloseWaitNotificationPopup: ${result.message}`);
break;
}
}}
/>
</div>
);
}
export default withPaymentCryptoProvider(App);
Style C: use own button to trigger PaymentCryptoModal
and Disconnect
import {
ExposeErrorCode,
PaymentCryptoModal,
setClientId,
setLanguage,
withPaymentCryptoProvider,
useDisconnectWallet,
PaymentCryptoContext,
Result
} from '@terra-js/crypto-payment';
function App() {
const { walletState } = useContext(PaymentCryptoContext);
const [result, setResult] = useState('');
const [showPaymentCryptoPopup, setShowPaymentCryptoPopup] = useState(false);
const {disconnect} = useDisconnectWallet()
const onClickPayButton = async () => {
setShowPaymentCryptoPopup(true);
};
const handlePaymentResult = (result: Result<void>) => {
switch (result.code) {
case ExposeErrorCode.Success:
setResult('Success');
break;
case ExposeErrorCode.VerifyTransactionHashFailed:
setResult(`VerifyTransactionHashFailed: ${result.message}`);
break;
case ExposeErrorCode.WaitNotificationFailed:
setResult(`WaitNotificationFailed: ${result.message}`);
break;
case ExposeErrorCode.UserCloseWaitNotificationPopup:
setResult(`UserCloseWaitNotificationPopup: ${result.message}`);
break;
}
};
const onDisconnect = () => {
disconnect();
}
return (
<div className='App'>
<header className='App-header'>
<div style={{ display: 'flex', flexDirection: 'column', color: 'black', fontSize: 14 }}>
{walletState.isConnected && (
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
<img
src={walletState.walletIcon}
alt='wallet-icon'
style={{ margin: `12px 0 0 0` }}
width={36}
height={36}
/>
<p style={{ margin: `12px 0 0 0` }}>{walletState.stakeKey ? walletState.stakeKey : walletState.walletAccountAddress}</p>
</div>
)}
</div>
<PaymentCryptoModal
isOpen={showPaymentCryptoPopup}
paymentAmount={PAYMENT_AMOUNT}
orderCode={ORDER_CODE}
onCloseModal={() => {
setShowPaymentCryptoPopup(false);
}}
onPaymentResult={(result) => {
console.log('crypto-payment-modal-result', result);
handlePaymentResult(result);
}}
/>
<div style={{ height: 1, width: 200, backgroundColor: 'gray', margin: 16 }} />
<div className='crypto-pay-button' style={{ height: 55 }} onClick={onClickPayButton}>
<div className='crypto-pay-button-inner' style={{ color: '#1990FF' }}>
Payment
</div>
</div>
<div style={{ height: 1, width: 200, backgroundColor: 'gray', margin: 16 }} />
<div className='crypto-pay-button' style={{ height: 55 }} onClick={onDisconnect}>
<div className='crypto-pay-button-inner' style={{ color: '#1990FF' }}>
Disconnect
</div>
</div>
<div style={{ height: 1, width: 200, backgroundColor: 'gray', margin: 16 }} />
<div style={{ color: 'black' }}>Result: {result}</div>
</header>
</div>
);
}
export default withPaymentCryptoProvider(App);
Handling results
result .code
|
meaning |
---|---|
ExposeErrorCode .Success
|
Everything is success |
ExposeErrorCode .VerifyTransactionHashFailed
|
Transaction sent to network, but no IPNs were fired to your backend. Client should notice user to contact admin to manually confirm the transaction. |
ExposeErrorCode .WaitNotificationFailed
|
Transaction sent to network, IPN will be fired to your backend. Client should instruct user to refresh the order for new state |
ExposeErrorCode .UserCloseWaitNotificationPopup
|
Transaction sent to network, but user waited for so long and close the popup. Client should instruct user to refresh the order for new state |
Utils
getCurrentMetamaskAccount
- Return
undefined
if no accounts detected - return public address of current selected account in
Metamask
import { getCurrentMetamaskAccount } from '@terra-js/crypto-payment';
const address = await getCurrentMetamaskAccount();
listen for account changed
useEffect(() => {
const listener = registerAccountsChanged((account: string) => {
console.log('accountChanged', account);
});
return () => {
listener && unregisterAccountsChanged(listener);
};
}, []);
Import the library's css
Import it at appropriated place:
import '@terra-js/crypto-payment/dist/styles/PaymentCrypto.css';
Specifically for Next-js
- Install following
devDependencies
yarn add -D next-compose-plugins // install a version that should be compatible with your next-js version
yarn add -D next-transpile-modules // install a version that should be compatible with your next-js version
- Add config in
next.config.js
/** @type {import('next').NextConfig} */
const withPlugins = require('next-compose-plugins');
const withTM = require('next-transpile-modules')([
'@terra-js/crypto-payment',
]);
const nextConfig = {
// your config here
}
module.exports = withPlugins([withTM], nextConfig)
Some issues when running app
1. Warning when generating source map For example:
Failed to parse source map from '/path/on/device/AtomicFU.common.kt' file: Error: ENOENT: no such file or directory, open '/path/on/device/AtomicFU.common.kt'
``
This issue may be caused when starting app with react-scripts
command like react-scripts start
(projects are created by react-react-app
).
To fix this, please add GENERATE_SOURCEMAP=false
option to the start/build command. For example:
"start": "GENERATE_SOURCEMAP=false react-scripts start",
"build": "GENERATE_SOURCEMAP=false react-scripts build",