703 lines
20 KiB
JavaScript
703 lines
20 KiB
JavaScript
import { useEffect, useState, useRef, useMemo, useCallback } from 'react';
|
|
import { StyleSheet, View } from 'react-native';
|
|
import { deleteGift, getGiftCard } from '../../../../../db';
|
|
import { parseGiftUrl } from '../../../../functions/gift/encodeDecodeSecret';
|
|
import { useNavigation } from '@react-navigation/native';
|
|
import { decryptMessage } from '../../../../functions/messaging/encodingAndDecodingMessages';
|
|
import { getPublicKey } from 'nostr-tools';
|
|
import { ThemeText } from '../../../../functions/CustomElements';
|
|
import { useGlobalContextProvider } from '../../../../../context-store/context';
|
|
import { useNodeContext } from '../../../../../context-store/nodeContext';
|
|
import displayCorrectDenomination from '../../../../functions/displayCorrectDenomination';
|
|
import CustomButton from '../../../../functions/CustomElements/button';
|
|
import {
|
|
CENTER,
|
|
SIZES,
|
|
STARTING_INDEX_FOR_GIFTS_DERIVE,
|
|
USDB_TOKEN_ID,
|
|
WEBSITE_REGEX,
|
|
} from '../../../../constants';
|
|
import GetThemeColors from '../../../../hooks/themeColors';
|
|
import { INSET_WINDOW_WIDTH } from '../../../../constants/theme';
|
|
import FullLoadingScreen from '../../../../functions/CustomElements/loadingScreen';
|
|
import { useSparkWallet } from '../../../../../context-store/sparkContext';
|
|
import {
|
|
getSparkPaymentFeeEstimate,
|
|
initializeSparkWallet,
|
|
sendSparkPayment,
|
|
sendSparkTokens,
|
|
disposeSparkWallet,
|
|
} from '../../../../functions/spark';
|
|
import { awaitSparkBalance } from '../../../../functions/spark/awaitBalanceChange';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { useKeysContext } from '../../../../../context-store/keys';
|
|
import {
|
|
getGiftByUuid,
|
|
updateGiftLocal,
|
|
} from '../../../../functions/gift/giftsStorage';
|
|
import { transformTxToPaymentObject } from '../../../../functions/spark/transformTxToPayment';
|
|
import { bulkUpdateSparkTransactions } from '../../../../functions/spark/transactions';
|
|
import { updateConfirmAnimation } from '../../../../functions/lottieViewColorTransformer';
|
|
import { useGlobalThemeContext } from '../../../../../context-store/theme';
|
|
import LottieView from 'lottie-react-native';
|
|
import {
|
|
deriveGiftRestoreKey,
|
|
deriveSparkGiftMnemonic,
|
|
} from '../../../../functions/gift/deriveGiftWallet';
|
|
import { dollarsToSats } from '../../../../functions/spark/flashnet';
|
|
import { useFlashnet } from '../../../../../context-store/flashnetContext';
|
|
|
|
const confirmTxAnimation = require('../../../../assets/confirmTxAnimation.json');
|
|
|
|
export default function ClaimGiftScreen({
|
|
url,
|
|
claimType,
|
|
expertMode,
|
|
customGiftIndex,
|
|
}) {
|
|
const { poolInfoRef } = useFlashnet();
|
|
const { accountMnemoinc } = useKeysContext();
|
|
const navigate = useNavigation();
|
|
const { sparkInformation } = useSparkWallet();
|
|
const { masterInfoObject } = useGlobalContextProvider();
|
|
const { fiatStats } = useNodeContext();
|
|
const { backgroundOffset, backgroundColor } = GetThemeColors();
|
|
const [giftDetails, setGiftDetails] = useState({});
|
|
const [isClaiming, setIsClaiming] = useState(false);
|
|
const { t } = useTranslation();
|
|
const { theme, darkModeType } = useGlobalThemeContext();
|
|
const [didClaim, setDidClaim] = useState(false);
|
|
const animationRef = useRef(null);
|
|
const [claimStatus, setClaimStatus] = useState('');
|
|
|
|
// Store the initialization promise and result
|
|
const walletInitPromise = useRef(null);
|
|
const walletInitResult = useRef(null);
|
|
const isClaimingRef = useRef(false);
|
|
const denomination = giftDetails?.denomination || 'BTC';
|
|
|
|
const handleError = useCallback(
|
|
errorMessage => {
|
|
navigate.navigate('ErrorScreen', { errorMessage });
|
|
},
|
|
[navigate],
|
|
);
|
|
|
|
const deriveReclaimGiftSeed = useCallback(async () => {
|
|
if (expertMode) {
|
|
const giftWalletMnemonic = await deriveSparkGiftMnemonic(
|
|
accountMnemoinc,
|
|
STARTING_INDEX_FOR_GIFTS_DERIVE + customGiftIndex,
|
|
);
|
|
return { giftSeed: giftWalletMnemonic.derivedMnemonic };
|
|
}
|
|
|
|
let uuid;
|
|
if (WEBSITE_REGEX.test(url)) {
|
|
const parsedURL = parseGiftUrl(url);
|
|
uuid = parsedURL.giftId;
|
|
} else {
|
|
uuid = url;
|
|
}
|
|
|
|
const savedGift = await getGiftByUuid(uuid);
|
|
|
|
if (!savedGift) {
|
|
throw new Error(t('screens.inAccount.giftPages.claimPage.parseError'));
|
|
}
|
|
|
|
if (Date.now() < savedGift.expireTime) {
|
|
throw new Error(t('screens.inAccount.giftPages.claimPage.notExpired'));
|
|
}
|
|
|
|
const giftSeed = await deriveGiftRestoreKey(
|
|
accountMnemoinc,
|
|
savedGift.giftNum,
|
|
savedGift.createdTime,
|
|
);
|
|
|
|
return {
|
|
...savedGift,
|
|
giftSeed,
|
|
};
|
|
}, [expertMode, url, customGiftIndex, accountMnemoinc, t]);
|
|
|
|
const deriveClaimGiftSeed = useCallback(async () => {
|
|
const parsedURL = parseGiftUrl(url);
|
|
if (!parsedURL) {
|
|
throw new Error(t('screens.inAccount.giftPages.claimPage.parseError'));
|
|
}
|
|
|
|
const retrivedGift = await getGiftCard(parsedURL.giftId);
|
|
|
|
if (!retrivedGift || retrivedGift?.expireTime < Date.now()) {
|
|
throw new Error(
|
|
t('screens.inAccount.giftPages.claimPage.expiredOrClaimed'),
|
|
);
|
|
}
|
|
|
|
const publicKey = getPublicKey(parsedURL.secret);
|
|
const decodedSeed = decryptMessage(
|
|
parsedURL.secret,
|
|
publicKey,
|
|
retrivedGift.encryptedText,
|
|
);
|
|
|
|
if (decodedSeed.split(' ').length < 5) {
|
|
throw new Error(t('screens.inAccount.giftPages.claimPage.noGiftSeed'));
|
|
}
|
|
|
|
return { ...retrivedGift, giftSeed: decodedSeed };
|
|
}, [url, t]);
|
|
|
|
const loadGiftDetails = useCallback(async () => {
|
|
try {
|
|
const details =
|
|
claimType === 'reclaim'
|
|
? await deriveReclaimGiftSeed()
|
|
: await deriveClaimGiftSeed();
|
|
|
|
setGiftDetails(details);
|
|
|
|
// Pre-initialize wallet in background
|
|
walletInitPromise.current = initializeSparkWallet(details.giftSeed)
|
|
.then(result => {
|
|
walletInitResult.current = result;
|
|
return result;
|
|
})
|
|
.catch(err => {
|
|
console.log('Pre-initialization failed:', err);
|
|
walletInitResult.current = null;
|
|
return null;
|
|
});
|
|
} catch (err) {
|
|
console.log('error loading gift details', err);
|
|
navigate.goBack();
|
|
handleError(err.message);
|
|
}
|
|
}, [
|
|
claimType,
|
|
deriveReclaimGiftSeed,
|
|
deriveClaimGiftSeed,
|
|
navigate,
|
|
handleError,
|
|
]);
|
|
|
|
const getBalanceWithStatusRetry = useCallback(
|
|
async (seed, expectedAmount, shouldEnforceAmount = false) => {
|
|
setClaimStatus(
|
|
t('screens.inAccount.giftPages.claimPage.giftBalanceMessage'),
|
|
);
|
|
|
|
const handleBalanceCheck = result => {
|
|
if (!result?.didWork) return false;
|
|
|
|
const bitcoinBalance = Number(result.balance);
|
|
const dollarBalance = Number(
|
|
result.tokensObj?.[USDB_TOKEN_ID]?.balance,
|
|
);
|
|
|
|
// Expert mode has no expected amount — resolve as soon as any funds land.
|
|
if (expectedAmount === undefined) {
|
|
return bitcoinBalance > 0 || dollarBalance > 0;
|
|
}
|
|
|
|
const bitcoinCheck = bitcoinBalance >= expectedAmount * 0.97;
|
|
const dollarCheck =
|
|
dollarBalance >= expectedAmount * Math.pow(10, 6) * 0.97;
|
|
|
|
return denomination === 'BTC' ? bitcoinCheck : dollarCheck;
|
|
};
|
|
|
|
// Immediate read first, then listen for the gift wallet's balance events
|
|
// (up to 60s) instead of fixed-delay polling.
|
|
const result = await awaitSparkBalance({
|
|
mnemonic: seed,
|
|
predicate: handleBalanceCheck,
|
|
});
|
|
|
|
if (
|
|
shouldEnforceAmount &&
|
|
expectedAmount !== undefined &&
|
|
!handleBalanceCheck(result)
|
|
) {
|
|
throw new Error(
|
|
t('screens.inAccount.giftPages.claimPage.balanceMismatchError'),
|
|
);
|
|
}
|
|
|
|
return result;
|
|
},
|
|
[t, expertMode, denomination],
|
|
);
|
|
|
|
const ensureWalletInitialized = useCallback(
|
|
async giftSeed => {
|
|
let initResult = walletInitResult.current;
|
|
|
|
if (walletInitPromise.current && !initResult) {
|
|
initResult = await walletInitPromise.current;
|
|
}
|
|
|
|
if (!initResult) {
|
|
initResult = await initializeSparkWallet(giftSeed, false, {
|
|
maxRetries: 4,
|
|
});
|
|
}
|
|
|
|
if (!initResult) {
|
|
throw new Error(
|
|
t('screens.inAccount.giftPages.claimPage.giftWalletInitError'),
|
|
);
|
|
}
|
|
|
|
return initResult;
|
|
},
|
|
[t],
|
|
);
|
|
|
|
const calculatePaymentAmount = useCallback(
|
|
async (giftSeed, giftAmount) => {
|
|
const walletBalance = await getBalanceWithStatusRetry(
|
|
giftSeed,
|
|
expertMode ? undefined : giftAmount,
|
|
claimType === 'claim',
|
|
);
|
|
|
|
const bitcoinBalance = walletBalance?.didWork
|
|
? Number(walletBalance?.balance)
|
|
: 0;
|
|
const dollarBalance = walletBalance?.didWork
|
|
? Number(walletBalance?.tokensObj?.[USDB_TOKEN_ID]?.balance) || 0
|
|
: 0;
|
|
const dollarGiftAmount = giftAmount * Math.pow(10, 6);
|
|
|
|
let formattedWalletBalance;
|
|
let fees;
|
|
let fromBalance;
|
|
if (expertMode) {
|
|
if (!bitcoinBalance && !dollarBalance) {
|
|
throw new Error(
|
|
t('screens.inAccount.giftPages.claimPage.nobalanceErrorExpert'),
|
|
);
|
|
}
|
|
formattedWalletBalance = bitcoinBalance || dollarBalance;
|
|
fromBalance = bitcoinBalance ? 'BTC' : 'USD';
|
|
fees = await (denomination === 'USD'
|
|
? Promise.resolve(0)
|
|
: getSparkPaymentFeeEstimate(formattedWalletBalance, giftSeed));
|
|
} else {
|
|
formattedWalletBalance = walletBalance?.didWork
|
|
? denomination === 'BTC'
|
|
? bitcoinBalance
|
|
: dollarBalance
|
|
: giftAmount || 0;
|
|
|
|
fees = await (denomination === 'USD'
|
|
? Promise.resolve(
|
|
dollarGiftAmount > formattedWalletBalance
|
|
? dollarGiftAmount - formattedWalletBalance
|
|
: 0,
|
|
)
|
|
: getSparkPaymentFeeEstimate(formattedWalletBalance, giftSeed));
|
|
fromBalance = denomination;
|
|
}
|
|
|
|
const sendingAmount =
|
|
formattedWalletBalance - (fromBalance === 'USD' ? 0 : fees);
|
|
|
|
if (sendingAmount <= 0) {
|
|
if (claimType === 'reclaim' && !expertMode) {
|
|
await deleteGift(giftDetails.uuid);
|
|
await updateGiftLocal(giftDetails.uuid, {
|
|
state: 'Reclaimed',
|
|
});
|
|
}
|
|
|
|
throw new Error(
|
|
expertMode
|
|
? t('screens.inAccount.giftPages.claimPage.nobalanceErrorExpert')
|
|
: t('screens.inAccount.giftPages.claimPage.nobalanceError'),
|
|
);
|
|
}
|
|
const balanceDifference = expertMode
|
|
? 0
|
|
: denomination === 'USD'
|
|
? dollarGiftAmount > formattedWalletBalance
|
|
? dollarGiftAmount - formattedWalletBalance
|
|
: 0
|
|
: giftAmount > formattedWalletBalance
|
|
? giftAmount - formattedWalletBalance
|
|
: 0;
|
|
|
|
const finalFee = fees + balanceDifference;
|
|
|
|
return { sendingAmount, fees: finalFee, fromBalance };
|
|
},
|
|
[
|
|
getBalanceWithStatusRetry,
|
|
expertMode,
|
|
claimType,
|
|
giftDetails.uuid,
|
|
t,
|
|
denomination,
|
|
],
|
|
);
|
|
|
|
// Extract transaction processing logic
|
|
const processTransaction = useCallback(
|
|
async (
|
|
paymentResponse,
|
|
receivingAddress,
|
|
sendingAmount,
|
|
fees,
|
|
paymentDenomination,
|
|
) => {
|
|
const data = paymentResponse.response;
|
|
const formattedToken = paymentDenomination === 'USD' ? USDB_TOKEN_ID : '';
|
|
const fee =
|
|
paymentDenomination === 'USD'
|
|
? dollarsToSats(fees / Math.pow(10, 6), poolInfoRef.currentPriceAInB)
|
|
: fees;
|
|
let tx = {
|
|
id: paymentDenomination === 'USD' ? data : data.id,
|
|
paymentStatus: 'completed',
|
|
paymentType: 'spark',
|
|
accountId: sparkInformation.identityPubKey,
|
|
details: {
|
|
fee: fee,
|
|
totalFee: fee,
|
|
supportFee: fee,
|
|
amount: sendingAmount,
|
|
address: receivingAddress,
|
|
time:
|
|
paymentDenomination === 'USD'
|
|
? new Date().getTime()
|
|
: new Date(data.updatedTime).getTime(),
|
|
direction: 'INCOMING',
|
|
description:
|
|
claimType === 'reclaim'
|
|
? t('screens.inAccount.giftPages.reclaimGiftMessage')
|
|
: giftDetails.description,
|
|
senderIdentityPublicKey:
|
|
paymentDenomination === 'USD' ? '' : data.receiverIdentityPublicKey,
|
|
isLRC20Payment: paymentDenomination === 'USD',
|
|
LRC20Token: formattedToken,
|
|
isGift: true,
|
|
},
|
|
};
|
|
|
|
if (!tx.details.description) {
|
|
tx.details.description = t(
|
|
'screens.inAccount.giftPages.claimPage.defaultDesc',
|
|
);
|
|
}
|
|
|
|
await bulkUpdateSparkTransactions([tx], 'fullUpdate-waitBalance');
|
|
|
|
if (!expertMode) {
|
|
await deleteGift(giftDetails.uuid);
|
|
if (claimType === 'reclaim') {
|
|
await updateGiftLocal(giftDetails.uuid, {
|
|
state: 'Reclaimed',
|
|
});
|
|
}
|
|
}
|
|
},
|
|
[
|
|
claimType,
|
|
giftDetails.description,
|
|
giftDetails.uuid,
|
|
expertMode,
|
|
t,
|
|
accountMnemoinc,
|
|
],
|
|
);
|
|
|
|
const handleClaim = useCallback(async () => {
|
|
if (isClaimingRef.current) return;
|
|
isClaimingRef.current = true;
|
|
setIsClaiming(true);
|
|
|
|
try {
|
|
setClaimStatus(
|
|
t('screens.inAccount.giftPages.claimPage.claimingGiftMessage1'),
|
|
);
|
|
|
|
await ensureWalletInitialized(giftDetails.giftSeed);
|
|
|
|
const receivingAddress = sparkInformation.sparkAddress;
|
|
const { sendingAmount, fees, fromBalance } = await calculatePaymentAmount(
|
|
giftDetails.giftSeed,
|
|
denomination === 'BTC' ? giftDetails.amount : giftDetails.dollarAmount,
|
|
);
|
|
|
|
setClaimStatus(
|
|
t('screens.inAccount.giftPages.claimPage.claimingGiftMessage4'),
|
|
);
|
|
|
|
const paymentResponse = await (fromBalance === 'BTC'
|
|
? sendSparkPayment({
|
|
receiverSparkAddress: receivingAddress,
|
|
amountSats: sendingAmount,
|
|
mnemonic: giftDetails.giftSeed,
|
|
})
|
|
: sendSparkTokens({
|
|
tokenIdentifier: USDB_TOKEN_ID,
|
|
tokenAmount: sendingAmount,
|
|
receiverSparkAddress: receivingAddress,
|
|
mnemonic: giftDetails.giftSeed,
|
|
}));
|
|
|
|
if (!paymentResponse.didWork) {
|
|
throw new Error(
|
|
t('screens.inAccount.giftPages.claimPage.paymentError'),
|
|
);
|
|
}
|
|
|
|
await processTransaction(
|
|
paymentResponse,
|
|
receivingAddress,
|
|
sendingAmount,
|
|
fees,
|
|
fromBalance,
|
|
);
|
|
setDidClaim(true);
|
|
} catch (err) {
|
|
console.log('Error claiming gift:', err);
|
|
navigate.goBack();
|
|
handleError(err.message || 'Failed to claim gift');
|
|
} finally {
|
|
// Tear down the gift wallet session/listeners once the claim is done.
|
|
if (giftDetails.giftSeed) await disposeSparkWallet(giftDetails.giftSeed);
|
|
setIsClaiming(false);
|
|
isClaimingRef.current = false;
|
|
}
|
|
}, [
|
|
giftDetails.giftSeed,
|
|
giftDetails.amount,
|
|
sparkInformation.sparkAddress,
|
|
ensureWalletInitialized,
|
|
calculatePaymentAmount,
|
|
processTransaction,
|
|
navigate,
|
|
handleError,
|
|
denomination,
|
|
t,
|
|
]);
|
|
|
|
useEffect(() => {
|
|
if (!expertMode && !url) return;
|
|
|
|
const isConnected =
|
|
sparkInformation.identityPubKey && sparkInformation.didConnect;
|
|
|
|
if (isConnected) {
|
|
loadGiftDetails();
|
|
}
|
|
}, [
|
|
url,
|
|
sparkInformation.identityPubKey,
|
|
sparkInformation.didConnect,
|
|
expertMode,
|
|
loadGiftDetails,
|
|
]);
|
|
|
|
useEffect(() => {
|
|
if (didClaim) {
|
|
animationRef.current?.play();
|
|
}
|
|
}, [didClaim]);
|
|
|
|
// Cleanup on unmount
|
|
useEffect(() => {
|
|
return () => {
|
|
walletInitPromise.current = null;
|
|
walletInitResult.current = null;
|
|
isClaimingRef.current = false;
|
|
};
|
|
}, []);
|
|
|
|
const confirmAnimation = useMemo(() => {
|
|
return updateConfirmAnimation(
|
|
confirmTxAnimation,
|
|
theme ? (darkModeType ? 'lightsOut' : 'dark') : 'light',
|
|
);
|
|
}, [theme, darkModeType]);
|
|
|
|
const containerBackgroundColor = useMemo(() => {
|
|
return theme && darkModeType ? backgroundColor : backgroundOffset;
|
|
}, [theme, darkModeType, backgroundColor, backgroundOffset]);
|
|
|
|
if (!sparkInformation.identityPubKey || !sparkInformation.didConnect) {
|
|
return (
|
|
<FullLoadingScreen
|
|
text={t('wallet.sendPages.sendPaymentScreen.connectToSparkMessage')}
|
|
/>
|
|
);
|
|
}
|
|
|
|
if (!Object.keys(giftDetails).length) {
|
|
return <FullLoadingScreen showText={false} />;
|
|
}
|
|
|
|
if (didClaim) {
|
|
return (
|
|
<View style={styles.tempClaimMessageContainer}>
|
|
<LottieView
|
|
ref={animationRef}
|
|
source={confirmAnimation}
|
|
loop={false}
|
|
style={styles.lottieView}
|
|
/>
|
|
<ThemeText
|
|
styles={styles.confirmMessage}
|
|
content={t('screens.inAccount.giftPages.claimPage.confirmMessage')}
|
|
/>
|
|
<CustomButton
|
|
actionFunction={navigate.goBack}
|
|
textContent={t('constants.done')}
|
|
/>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
const amountDisplay = expertMode
|
|
? customGiftIndex
|
|
: displayCorrectDenomination({
|
|
amount:
|
|
denomination === 'BTC'
|
|
? giftDetails.amount
|
|
: giftDetails?.dollarAmount,
|
|
masterInfoObject: {
|
|
...masterInfoObject,
|
|
userBalanceDenomination:
|
|
denomination === 'USD'
|
|
? 'fiat'
|
|
: masterInfoObject.userBalanceDenomination,
|
|
},
|
|
fiatStats,
|
|
forceCurrency: denomination === 'USD' ? 'USD' : false,
|
|
convertAmount: denomination !== 'USD',
|
|
});
|
|
|
|
const headerText =
|
|
claimType === 'reclaim'
|
|
? t('screens.inAccount.giftPages.claimPage.reclaimHead')
|
|
: t('screens.inAccount.giftPages.claimPage.claimHead');
|
|
|
|
const amountHeaderText =
|
|
claimType === 'reclaim'
|
|
? expertMode
|
|
? t('screens.inAccount.giftPages.claimPage.reclaimAmountHeadExpert')
|
|
: t('screens.inAccount.giftPages.claimPage.reclaimAmountHead')
|
|
: t('screens.inAccount.giftPages.claimPage.claimAmountHead');
|
|
|
|
const amountDescriptionText = expertMode
|
|
? t('screens.inAccount.giftPages.claimPage.networkFeeWarningExpert')
|
|
: t('screens.inAccount.giftPages.claimPage.networkFeeWarning');
|
|
|
|
const buttonText = isClaiming
|
|
? t('screens.inAccount.giftPages.claimPage.buttonTextClaiming')
|
|
: claimType === 'reclaim'
|
|
? t('screens.inAccount.giftPages.claimPage.reclaimButton')
|
|
: t('screens.inAccount.giftPages.claimPage.claimButton');
|
|
|
|
const loadingText =
|
|
claimStatus ||
|
|
(claimType === 'reclaim'
|
|
? t('screens.inAccount.giftPages.claimPage.reclaimLoading')
|
|
: t('screens.inAccount.giftPages.claimPage.claimLoading'));
|
|
|
|
return (
|
|
<View style={styles.container}>
|
|
<ThemeText styles={styles.header} content={headerText} />
|
|
<View
|
|
style={[styles.border, { backgroundColor: containerBackgroundColor }]}
|
|
/>
|
|
|
|
{isClaiming ? (
|
|
<FullLoadingScreen
|
|
textStyles={styles.claimingMessage}
|
|
text={loadingText}
|
|
/>
|
|
) : (
|
|
<>
|
|
<View
|
|
style={[
|
|
styles.amountContainer,
|
|
{ backgroundColor: containerBackgroundColor },
|
|
]}
|
|
>
|
|
<ThemeText
|
|
styles={styles.amountHeader}
|
|
content={amountHeaderText}
|
|
/>
|
|
<ThemeText styles={styles.amount} content={amountDisplay} />
|
|
<ThemeText
|
|
styles={styles.amountDescription}
|
|
content={amountDescriptionText}
|
|
/>
|
|
</View>
|
|
<CustomButton
|
|
buttonStyles={styles.buttonContainer}
|
|
textContent={buttonText}
|
|
actionFunction={handleClaim}
|
|
/>
|
|
</>
|
|
)}
|
|
</View>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: { flex: 1, width: INSET_WINDOW_WIDTH, ...CENTER },
|
|
header: {
|
|
fontSize: SIZES.xLarge,
|
|
textAlign: 'center',
|
|
fontWeight: 500,
|
|
},
|
|
border: {
|
|
height: 3,
|
|
marginVertical: 20,
|
|
},
|
|
amountContainer: {
|
|
padding: 20,
|
|
borderRadius: 8,
|
|
marginBottom: 10,
|
|
},
|
|
amountHeader: {
|
|
textAlign: 'center',
|
|
},
|
|
amount: {
|
|
textAlign: 'center',
|
|
fontSize: SIZES.xxLarge,
|
|
marginVertical: 10,
|
|
},
|
|
amountDescription: {
|
|
fontSize: SIZES.small,
|
|
textAlign: 'center',
|
|
opacity: 0.6,
|
|
},
|
|
buttonContainer: {
|
|
marginTop: 'auto',
|
|
alignSelf: 'center',
|
|
},
|
|
tempClaimMessageContainer: {
|
|
flex: 1,
|
|
alignItems: 'center',
|
|
width: INSET_WINDOW_WIDTH,
|
|
...CENTER,
|
|
},
|
|
confirmMessage: { textAlign: 'center', marginBottom: 'auto' },
|
|
claimingMessage: {
|
|
textAlign: 'center',
|
|
width: INSET_WINDOW_WIDTH,
|
|
minHeight: 80,
|
|
},
|
|
lottieView: {
|
|
width: 150,
|
|
height: 150,
|
|
},
|
|
});
|