mirror of
https://github.com/MAGICGrants/campaign-site.git
synced 2026-01-08 20:08:05 -05:00
Replace with another favicon if you make your own logo for the fund, but I recommend using the MAGIC logo in the meantime until you come up with one instead of the OpenSats logo
245 lines
6.7 KiB
TypeScript
245 lines
6.7 KiB
TypeScript
import { faMonero } from '@fortawesome/free-brands-svg-icons'
|
|
import { faCreditCard } from '@fortawesome/free-solid-svg-icons'
|
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
import { useEffect, useRef, useState } from 'react'
|
|
import { MAX_AMOUNT } from '../config'
|
|
import { fetchPostJSON } from '../utils/api-helpers'
|
|
import Spinner from './Spinner'
|
|
|
|
type DonationStepsProps = {
|
|
projectNamePretty: string
|
|
projectSlug: string
|
|
}
|
|
const DonationSteps: React.FC<DonationStepsProps> = ({
|
|
projectNamePretty,
|
|
projectSlug,
|
|
}) => {
|
|
const [name, setName] = useState('')
|
|
const [email, setEmail] = useState('')
|
|
|
|
const [deductible, setDeductible] = useState('no')
|
|
const [amount, setAmount] = useState('')
|
|
|
|
const [readyToPay, setReadyToPay] = useState(false)
|
|
|
|
const [btcPayLoading, setBtcpayLoading] = useState(false)
|
|
const [fiatLoading, setFiatLoading] = useState(false)
|
|
|
|
const formRef = useRef<HTMLFormElement | null>(null)
|
|
|
|
const radioHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
setDeductible(event.target.value)
|
|
}
|
|
|
|
function handleFiatAmountClick(e: React.MouseEvent, value: string) {
|
|
e.preventDefault()
|
|
setAmount(value)
|
|
}
|
|
|
|
useEffect(() => {
|
|
if (amount && typeof parseInt(amount) === 'number') {
|
|
if (deductible === 'no' || (name && email)) {
|
|
setReadyToPay(true)
|
|
} else {
|
|
setReadyToPay(false)
|
|
}
|
|
} else {
|
|
setReadyToPay(false)
|
|
}
|
|
}, [deductible, amount, email, name])
|
|
|
|
async function handleBtcPay() {
|
|
const validity = formRef.current?.checkValidity()
|
|
if (!validity) {
|
|
return
|
|
}
|
|
setBtcpayLoading(true)
|
|
try {
|
|
const payload = {
|
|
amount,
|
|
project_slug: projectSlug,
|
|
project_name: projectNamePretty
|
|
}
|
|
|
|
if (email) {
|
|
Object.assign(payload, { email })
|
|
}
|
|
|
|
if (name) {
|
|
Object.assign(payload, { name })
|
|
}
|
|
|
|
console.log(payload)
|
|
const data = await fetchPostJSON('/api/btcpay', payload)
|
|
if (data.checkoutLink) {
|
|
window.location.assign(data.checkoutLink)
|
|
} else if (data.message) {
|
|
throw new Error(data.message)
|
|
} else {
|
|
console.log({ data })
|
|
throw new Error('Something went wrong with BtcPay Server checkout.')
|
|
}
|
|
} catch (e) {
|
|
console.error(e)
|
|
}
|
|
setBtcpayLoading(false)
|
|
}
|
|
|
|
async function handleFiat() {
|
|
const validity = formRef.current?.checkValidity()
|
|
if (!validity) {
|
|
return
|
|
}
|
|
setFiatLoading(true)
|
|
try {
|
|
const data = await fetchPostJSON('/api/stripe_checkout', {
|
|
amount,
|
|
project_slug: projectSlug,
|
|
project_name: projectNamePretty,
|
|
email,
|
|
name,
|
|
})
|
|
console.log({ data })
|
|
if (data.url) {
|
|
window.location.assign(data.url)
|
|
} else {
|
|
throw new Error('Something went wrong with Stripe checkout.')
|
|
}
|
|
} catch (e) {
|
|
console.error(e)
|
|
}
|
|
setFiatLoading(false)
|
|
}
|
|
|
|
return (
|
|
<form
|
|
ref={formRef}
|
|
className="flex flex-col gap-4"
|
|
onSubmit={(e) => e.preventDefault()}
|
|
>
|
|
<section className="flex flex-col gap-1">
|
|
<h3>Do you want this donation to be tax deductible (USA only)?</h3>
|
|
<div className="flex space-x-4 pb-4">
|
|
<label>
|
|
<input
|
|
type="radio"
|
|
id="no"
|
|
name="deductible"
|
|
value="no"
|
|
onChange={radioHandler}
|
|
defaultChecked={true}
|
|
/>
|
|
No
|
|
</label>
|
|
<label>
|
|
<input
|
|
type="radio"
|
|
id="yes"
|
|
value="yes"
|
|
name="deductible"
|
|
onChange={radioHandler}
|
|
/>
|
|
Yes
|
|
</label>
|
|
</div>
|
|
|
|
<h3>
|
|
Name{' '}
|
|
<span className="text-subtle">
|
|
{deductible === 'yes' ? '(required)' : '(optional)'}
|
|
</span>
|
|
</h3>
|
|
<input
|
|
type="text"
|
|
placeholder={'MAGIC Monero Fund'}
|
|
required={deductible === 'yes'}
|
|
onChange={(e) => setName(e.target.value)}
|
|
className="mb-4"
|
|
></input>
|
|
<h3>
|
|
Email{' '}
|
|
<span className="text-subtle">
|
|
{deductible === 'yes' ? '(required)' : '(optional)'}
|
|
</span>
|
|
</h3>
|
|
<input
|
|
type="email"
|
|
placeholder={`MoneroFund@MagicGrants.org`}
|
|
required={deductible === 'yes'}
|
|
onChange={(e) => setEmail(e.target.value)}
|
|
></input>
|
|
</section>
|
|
|
|
<section>
|
|
<div className="flex justify-between items-center">
|
|
<h3>How much would you like to donate?</h3>
|
|
</div>
|
|
<div className="sm:flex-row flex flex-col gap-2 py-2" role="group">
|
|
{[50, 100, 250, 500].map((value, index) => (
|
|
<button
|
|
key={index}
|
|
className="group"
|
|
onClick={(e) => handleFiatAmountClick(e, value.toString())}
|
|
>
|
|
${value}
|
|
</button>
|
|
))}
|
|
<div className="relative flex w-full">
|
|
<div className="flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none">
|
|
{/* <FontAwesomeIcon icon={faDollarSign} className="w-5 h-5 text-black" /> */}
|
|
<span className="w-5 h-5 font-mono text-xl mb-2">{'$'}</span>
|
|
</div>
|
|
<input
|
|
required
|
|
type="number"
|
|
id="amount"
|
|
value={amount}
|
|
onChange={(e) => {
|
|
setAmount(e.target.value)
|
|
}}
|
|
className="!pl-10 w-full"
|
|
placeholder="Or enter custom amount"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<div className="flex flex-wrap items-center gap-4">
|
|
<button
|
|
name="btcpay"
|
|
onClick={handleBtcPay}
|
|
className="pay"
|
|
disabled={!readyToPay || btcPayLoading}
|
|
>
|
|
{btcPayLoading ? (
|
|
<Spinner />
|
|
) : (
|
|
<FontAwesomeIcon
|
|
icon={faMonero}
|
|
className="color-me-monero h-8 w-8"
|
|
/>
|
|
)}
|
|
<span className="whitespace-nowrap">Donate with Monero or Bitcoin</span>
|
|
</button>
|
|
<button
|
|
name="stripe"
|
|
onClick={handleFiat}
|
|
className="pay"
|
|
disabled={!readyToPay || fiatLoading}
|
|
>
|
|
{fiatLoading ? (
|
|
<Spinner />
|
|
) : (
|
|
<FontAwesomeIcon
|
|
icon={faCreditCard}
|
|
className="color-me-monero h-8 w-8"
|
|
/>
|
|
)}
|
|
<span className="whitespace-nowrap">Donate with fiat</span>
|
|
</button>
|
|
</div>
|
|
</form>
|
|
)
|
|
}
|
|
|
|
export default DonationSteps
|