Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow users to go back to crypto payment #1859

Merged
merged 54 commits into from
Jan 24, 2022
Merged
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
28aeb22
initial changes
FSM1 Dec 16, 2021
b4b1f21
wire up wallet
FSM1 Dec 16, 2021
c339448
Merge remote-tracking branch 'origin/dev' into feat/crypto-payment-1782
FSM1 Jan 6, 2022
cfbabe9
add circular progress bar label
FSM1 Jan 6, 2022
cb8c861
add currency icons
FSM1 Jan 7, 2022
b421d2d
add copy buttons
FSM1 Jan 7, 2022
db103c4
Merge branch 'dev' into feat/crypto-payment-1782
FSM1 Jan 7, 2022
120505a
lingui extract
actions-user Jan 7, 2022
26ff251
lint and padding
FSM1 Jan 7, 2022
1475b27
Apply suggestions from code review
FSM1 Jan 11, 2022
c66bbda
implement fixes
FSM1 Jan 11, 2022
7649eb7
Merge remote-tracking branch 'origin/dev' into feat/crypto-payment-1782
FSM1 Jan 11, 2022
5d2493f
lingui extract
actions-user Jan 11, 2022
a364094
Update packages/files-ui/src/Components/Modules/Settings/Subscription…
FSM1 Jan 11, 2022
c27ead3
fixes from comments
FSM1 Jan 12, 2022
8907d28
remove unnecessary prop
FSM1 Jan 12, 2022
c2f7a7d
temp daily duration for testing - revert before merge
FSM1 Jan 12, 2022
ace49c3
fix dark mode icon colors
FSM1 Jan 12, 2022
c6cd7ca
update api client to latest
FSM1 Jan 14, 2022
1279178
Merge branch 'dev' into feat/crypto-payment-1782
FSM1 Jan 14, 2022
ec4048c
Apply suggestions from code review
FSM1 Jan 14, 2022
1d29c99
revert conflict marker
FSM1 Jan 14, 2022
c0e680f
Merge branch 'feat/crypto-payment-1782' of https://github.com/ChainSa…
FSM1 Jan 14, 2022
a9da33f
remove max-content width
FSM1 Jan 14, 2022
35ad8ef
wip
Tbaut Jan 14, 2022
cad2595
Merge branch 'feat/crypto-payment-1782' of github.com:ChainSafe/ui-mo…
Tbaut Jan 14, 2022
13347fe
Merge branch 'dev' into feat/crypto-payment-1782
Tbaut Jan 14, 2022
24683f4
be able to get back to crypt
Tbaut Jan 14, 2022
9eb2a16
lingui extract
actions-user Jan 14, 2022
74ddf46
fix mobile width issues
FSM1 Jan 14, 2022
348447e
Revert "fix mobile width issues"
FSM1 Jan 17, 2022
46dfe09
ensure that text doesnt overflow
FSM1 Jan 17, 2022
6599357
fix width
FSM1 Jan 17, 2022
1fd561d
Merge branch 'dev' into feat/crypto-payment-1782
Tbaut Jan 17, 2022
0a8246b
lingui extract
actions-user Jan 17, 2022
1ee200b
Merge branch 'feat/crypto-payment-1782' of github.com:ChainSafe/ui-mo…
Tbaut Jan 18, 2022
2b26abe
fix copy and goback
Tbaut Jan 18, 2022
bf39f72
Merge branch 'mnt/tbaut-crypto-1846' of github.com:ChainSafe/ui-monor…
Tbaut Jan 18, 2022
4e45fe7
mobile view
Tbaut Jan 18, 2022
4b01384
cleanup
Tbaut Jan 18, 2022
362a3bd
fix conflicts
Tbaut Jan 18, 2022
4e28de8
pull the new api-client version and remove type casting
Tbaut Jan 18, 2022
8af3afb
fix lint
Tbaut Jan 18, 2022
27001ed
text button in payment details
tanmoyAtb Jan 18, 2022
276af26
Merge branch 'dev' into mnt/tbaut-crypto-1846
tanmoyAtb Jan 19, 2022
a9c78d9
Merge branch 'dev' of github.com:ChainSafe/ui-monorepo into mnt/tbaut…
Tbaut Jan 20, 2022
e745845
address small comments
Tbaut Jan 20, 2022
1541ea7
additional button with awaiting payment
Tbaut Jan 20, 2022
60f7ccf
Merge branch 'dev' into mnt/tbaut-crypto-1846
FSM1 Jan 21, 2022
97e0301
lingui extract
actions-user Jan 21, 2022
0fc9c80
rework it all
Tbaut Jan 21, 2022
d01a917
merge dev
Tbaut Jan 21, 2022
2d61d51
lingui extract
actions-user Jan 21, 2022
61755d2
Merge branch 'dev' into mnt/tbaut-crypto-1846
FSM1 Jan 24, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/files-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"@babel/core": "^7.12.10",
"@babel/runtime": "^7.0.0",
"@chainsafe/browser-storage-hooks": "^1.0.1",
"@chainsafe/files-api-client": "1.18.25",
"@chainsafe/files-api-client": "1.18.26",
"@chainsafe/web3-context": "1.3.1",
"@emeraldpay/hashicon-react": "^0.5.1",
"@lingui/core": "^3.7.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ const ChangeProductModal = ({ onClose }: IChangeProductModal) => {
? setSlide("downgradeDetails")
: setSlide("planDetails")
}}
onShowCryptoOutstandingPayment={() => setSlide("cryptoPayment")}
plans={plans}
/>
)}
Expand All @@ -134,9 +135,7 @@ const ChangeProductModal = ({ onClose }: IChangeProductModal) => {
<PaymentMethodSelector
selectedProductPrice={selectedPrice}
onClose={onClose}
goBack={() => {
setSlide("planDetails")
}}
goBack={() => setSlide("planDetails")}
onSelectPaymentMethod={(paymentMethod) => {
setSelectedPaymentMethod(paymentMethod)
setSlide("confirmPlan")
Expand All @@ -147,24 +146,15 @@ const ChangeProductModal = ({ onClose }: IChangeProductModal) => {
<ConfirmPlan
plan={selectedPlan}
planPrice={selectedPrice}
goToSelectPlan={() => {
setSlide("select")
}}
goToPaymentMethod={() => {
setSlide("paymentMethod")
}}
goToSelectPlan={() => setSlide("select")}
goToPaymentMethod={() => setSlide("paymentMethod")}
loadingChangeSubscription={isLoadingChangeSubscription}
onChangeSubscription={selectedPaymentMethod === "creditCard" ? handleChangeSubscription : () => setSlide("cryptoPayment")}
isSubscriptionError={isSubscriptionError}
paymentMethod={selectedPaymentMethod}
/>
}
{slide === "cryptoPayment" && selectedPlan && selectedPrice &&
<CryptoPayment
plan={selectedPlan}
planPrice={selectedPrice}
goBack={() => setSlide("confirmPlan")}/>
}
{slide === "cryptoPayment" && <CryptoPayment planPrice={selectedPrice} />}
{slide === "planSuccess" && selectedPlan && selectedPrice && <PlanSuccess
onClose={onClose}
plan={selectedPlan}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"
import { makeStyles, createStyles, debounce } from "@chainsafe/common-theme"
import { CSFTheme } from "../../../../../Themes/types"
import { Product, ProductPrice, UpdateSubscriptionResponse } from "@chainsafe/files-api-client"
import { ProductPrice, InvoiceResponse } from "@chainsafe/files-api-client"
import {
BitcoinIcon,
Button,
Expand All @@ -14,7 +14,7 @@ import {
Typography,
UsdcIcon
} from "@chainsafe/common-components"
import { Trans } from "@lingui/macro"
import { t, Trans } from "@lingui/macro"
import dayjs from "dayjs"
import duration from "dayjs/plugin/duration"
import { useBilling } from "../../../../../Contexts/BillingContext"
Expand Down Expand Up @@ -183,6 +183,7 @@ const useStyles = makeStyles(({ constants, palette, zIndex, animation, breakpoin
}
},
copyRow: {
position: "relative",
cursor: "pointer",
borderRadius: 10,
backgroundColor: "var(--gray4)",
Expand All @@ -203,9 +204,7 @@ const useStyles = makeStyles(({ constants, palette, zIndex, animation, breakpoin
)

interface ICryptoPayment {
plan: Product
planPrice: ProductPrice
goBack: () => void
planPrice?: ProductPrice
}

const iconMap: { [key: string]: React.FC<any> } = {
Expand All @@ -222,43 +221,54 @@ const symbolMap: { [key: string]: string } = {
usdc: "USDC"
}

const CryptoPayment = ({ goBack, planPrice }: ICryptoPayment) => {
const CryptoPayment = ({ planPrice }: ICryptoPayment) => {
const classes = useStyles()
const { selectWallet } = useFilesApi()
const { isReady, network, provider, wallet, tokens, switchNetwork, checkIsReady, ethBalance } = useWeb3()
const { filesApiClient } = useFilesApi()
const { currentSubscription } = useBilling()
const [subResponse, setSubResponse] = useState<UpdateSubscriptionResponse | undefined>()
const { currentSubscription, fetchCurrentSubscription, isPendingInvoice, invoices } = useBilling()
const [cryptoPayment, setCryptoPayment] = useState<InvoiceResponse["crypto"] | undefined>()
const [error, setError] = useState<string | undefined>(undefined)
const [cryptoChargeLoading, setCryptoChargeLoading] = useState(false)
const [transferActive, setTransferActive] = useState(false)
const [timeRemaining, setTimeRemaining] = useState<string | undefined>()
const pageLoadTimestamp = useRef(dayjs().unix())

const [copiedDestinationAddress, setCopiedDestinationAddress] = useState(false)
const [copiedAmount, setCopiedAmount] = useState(false)
const debouncedSwitchCopiedDestinationAddress = debounce(() => setCopiedDestinationAddress(false), 3000)
const debouncedSwitchCopiedAmount = debounce(() => setCopiedAmount(false), 3000)
const pendingCryptoInvoice = useMemo(() =>
isPendingInvoice && invoices?.find((i) => i.payment_method === "crypto" && i.status === "open")
, [invoices, isPendingInvoice])
const currencies = useMemo(() => cryptoPayment?.payment_methods.map(c => c.currency), [cryptoPayment])
const [selectedCurrency, setSelectedCurrency] = useState<string | undefined>(undefined)

useEffect(() => {
if (!currentSubscription) return undefined
if (!currentSubscription || !planPrice || isPendingInvoice) return

setCryptoChargeLoading(true)

filesApiClient.updateSubscription(currentSubscription.id, {
price_id: planPrice.id,
payment_method: "crypto"
}).then((response) => {
setSubResponse(response)
pageLoadTimestamp.current = dayjs().unix()
}).then(() => {
fetchCurrentSubscription()
}).catch((error) => {
console.error(error)
setError(`There was a problem creating a charge ${error}`)
setError(t`There was a problem creating a charge ${error}`)
}).finally(() => setCryptoChargeLoading(false))
}, [currentSubscription, filesApiClient, planPrice.id])
}, [currentSubscription, fetchCurrentSubscription, filesApiClient, isPendingInvoice, planPrice])

const cryptoPayment = useMemo(() => subResponse?.invoice?.crypto, [subResponse])
const currencies = useMemo(() => cryptoPayment?.payment_methods.map(c => c.currency), [cryptoPayment])
const [selectedCurrency, setSelectedCurrency] = useState<string | undefined>(undefined)
useEffect(() => {
if (!pendingCryptoInvoice) return

pendingCryptoInvoice?.uuid && filesApiClient.payInvoice(pendingCryptoInvoice.uuid)
.then(r => {
setCryptoPayment(r.crypto)
pageLoadTimestamp.current = dayjs().unix()
})
.catch(console.error)
}, [filesApiClient, pendingCryptoInvoice])

useEffect(() => {
const timer = setInterval(() => {
Expand All @@ -272,34 +282,31 @@ const CryptoPayment = ({ goBack, planPrice }: ICryptoPayment) => {
}
}, [cryptoPayment])

const selectedPaymentMethod = useMemo(() => {
return cryptoPayment && selectedCurrency
? cryptoPayment.payment_methods.find(p => p.currency === selectedCurrency)
: undefined
}, [cryptoPayment, selectedCurrency])
const selectedPaymentMethod = useMemo(() =>
cryptoPayment && selectedCurrency && cryptoPayment.payment_methods.find(p => p.currency === selectedCurrency)
, [cryptoPayment, selectedCurrency])

const onCopyDestinationAddress = useCallback(() => {
if (selectedPaymentMethod) {
navigator.clipboard.writeText(selectedPaymentMethod.address)
.then(() => {
setCopiedDestinationAddress(true)
debouncedSwitchCopiedDestinationAddress()
}).catch(console.error)
}
if (!selectedPaymentMethod) return

navigator.clipboard.writeText(selectedPaymentMethod.address)
.then(() => {
setCopiedDestinationAddress(true)
debouncedSwitchCopiedDestinationAddress()
}).catch(console.error)
}, [debouncedSwitchCopiedDestinationAddress, selectedPaymentMethod])

const onCopyAmount = useCallback(() => {
if (selectedPaymentMethod) {
navigator.clipboard.writeText(selectedPaymentMethod.amount)
.then(() => {
setCopiedAmount(true)
debouncedSwitchCopiedAmount()
}).catch(console.error)
}
if (!selectedPaymentMethod) return

navigator.clipboard.writeText(selectedPaymentMethod.amount)
.then(() => {
setCopiedAmount(true)
debouncedSwitchCopiedAmount()
}).catch(console.error)
}, [debouncedSwitchCopiedAmount, selectedPaymentMethod])

const isBalanceSufficient = useMemo(() => {
const selectedPaymentMethod = cryptoPayment?.payment_methods.find(p => p.currency === selectedCurrency)
if (selectedCurrency === "bitcoin") {
return false
} else if (selectedCurrency === "ethereum") {
Expand All @@ -308,12 +315,10 @@ const CryptoPayment = ({ goBack, planPrice }: ICryptoPayment) => {
const token = Object.values(tokens).find(t => t.symbol?.toLowerCase() === selectedCurrency)
return token && selectedPaymentMethod && token.balance >= Number(selectedPaymentMethod.amount)
}
}, [tokens, ethBalance, selectedCurrency, cryptoPayment])
}, [selectedCurrency, ethBalance, selectedPaymentMethod, tokens])

const handlePayment = useCallback(async () => {
if (!provider || !selectedCurrency) return
const selectedPaymentMethod = cryptoPayment?.payment_methods.find(p => p.currency === selectedCurrency)
if (!selectedPaymentMethod) return
if (!provider || !selectedCurrency || !selectedPaymentMethod) return

const signer = provider.getSigner()
try {
Expand All @@ -326,7 +331,6 @@ const CryptoPayment = ({ goBack, planPrice }: ICryptoPayment) => {
} else {
const token = Object.values(tokens).find(t => t.symbol?.toLowerCase() === selectedCurrency)
if (!token || !token.transfer) return
// TODO Set loading state here
await (await token.transfer(
selectedPaymentMethod.address,
utils.parseUnits(selectedPaymentMethod.amount, token.decimals)
Expand All @@ -337,7 +341,7 @@ const CryptoPayment = ({ goBack, planPrice }: ICryptoPayment) => {
} finally {
setTransferActive(false)
}
}, [cryptoPayment, provider, selectedCurrency, tokens])
}, [provider, selectedCurrency, selectedPaymentMethod, tokens])

const handleSwitchNetwork = useCallback(async () => {
await switchNetwork(1)
Expand All @@ -363,7 +367,7 @@ const CryptoPayment = ({ goBack, planPrice }: ICryptoPayment) => {
/>
</div>}
</div>
{cryptoChargeLoading && <div className={classes.loadingContainer}>
{(cryptoChargeLoading || (pendingCryptoInvoice && !timeRemaining)) && <div className={classes.loadingContainer}>
Tbaut marked this conversation as resolved.
Show resolved Hide resolved
<Loading type='initial' />
</div>}
{error &&
Expand All @@ -375,13 +379,13 @@ const CryptoPayment = ({ goBack, planPrice }: ICryptoPayment) => {
<Trans>Failed to create a charge</Trans>
</Typography>
}
{cryptoPayment &&
{cryptoPayment && pendingCryptoInvoice &&
<>
<div className={classes.rowBox}>
<Typography>Total</Typography>
<div className={classes.pushRightBox}>
<Typography>
{subResponse?.invoice?.currency?.toUpperCase()} {subResponse?.invoice?.amount}
{pendingCryptoInvoice.currency?.toUpperCase()} {pendingCryptoInvoice.amount}
</Typography>
</div>
</div>
Expand Down Expand Up @@ -459,12 +463,12 @@ const CryptoPayment = ({ goBack, planPrice }: ICryptoPayment) => {
}
<section className={classes.bottomSection}>
<div className={classes.buttons}>
<Button
onClick={() => !selectedCurrency ? goBack() : setSelectedCurrency(undefined)}
{!!selectedCurrency && <Button
onClick={() => setSelectedCurrency(undefined)}
variant="text"
>
<Trans>Go back</Trans>
</Button>
</Button>}
{selectedCurrency && selectedCurrency !== "bitcoin" && !isReady &&
<Button onClick={selectWallet}><Trans>Connect Wallet</Trans></Button>
}
Expand Down
Loading