mirror of
https://github.com/MAGICGrants/campaign-site.git
synced 2026-01-09 12:27:59 -05:00
cleanup and real btcpay
This commit is contained in:
@@ -6,9 +6,13 @@ import Pay from "./Pay";
|
||||
|
||||
const DonationSteps = () => {
|
||||
|
||||
const [name, setName] = useState("")
|
||||
const [email, setEmail] = useState("")
|
||||
|
||||
const [deductable, setDeductable] = useState("yes");
|
||||
const [amount, setAmount] = useState("")
|
||||
const [fiat, setFiat] = useState(true)
|
||||
|
||||
const [readyToPay, setReadyToPay] = useState(false);
|
||||
|
||||
const radioHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setDeductable(event.target.value);
|
||||
@@ -19,86 +23,87 @@ const DonationSteps = () => {
|
||||
setAmount(value)
|
||||
}
|
||||
|
||||
function handleSatsAmountClick(e: React.MouseEvent, value: string) {
|
||||
function handleSubmit(e: React.FormEvent<unknown>) {
|
||||
e.preventDefault();
|
||||
setAmount(value)
|
||||
console.log(amount)
|
||||
if (amount) {
|
||||
setReadyToPay(true)
|
||||
}
|
||||
}
|
||||
|
||||
function handleToggleFiat(e: React.MouseEvent) {
|
||||
e.preventDefault();
|
||||
setFiat(!fiat)
|
||||
}
|
||||
|
||||
return (<form className="flex flex-col gap-4">
|
||||
<section className="flex flex-col gap-1">
|
||||
<h3>Do you want this donation as tax deductable?</h3>
|
||||
<div className="flex space-x-4">
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
id="yes"
|
||||
name="deductable"
|
||||
value="yes"
|
||||
onChange={radioHandler}
|
||||
defaultChecked={true}
|
||||
/>
|
||||
Yes
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
id="no"
|
||||
value="no"
|
||||
name="deductable"
|
||||
onChange={radioHandler}
|
||||
/>
|
||||
No
|
||||
</label>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
placeholder={`Name (${deductable === "yes" ? "required" : "optional"
|
||||
})`}
|
||||
required={deductable === "yes"}
|
||||
></input>
|
||||
<input
|
||||
type="text"
|
||||
placeholder={`Email (${deductable === "yes" ? "required" : "optional"
|
||||
})`}
|
||||
required={deductable === "yes"}
|
||||
></input>
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div className="flex justify-between items-center">
|
||||
<h3>How much would you like to donate?</h3>
|
||||
<button className="small" onClick={handleToggleFiat}>Toggle Fiat Mode</button>
|
||||
</div>
|
||||
<div className="md:flex-row flex flex-col gap-2 py-2" role="group">
|
||||
{fiat ? ["50", "100", "250", "500"].map(value =>
|
||||
<button className="group" onClick={(e) => handleFiatAmountClick(e, value)}>${value}</button>
|
||||
) : ["100k", "1m", "5m", "10m"].map(value =>
|
||||
<button className="group" onClick={(e) => handleSatsAmountClick(e, value)}>{value} sats</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">{fiat ? "$" : "₿"}</span>
|
||||
if (readyToPay) {
|
||||
return <Pay amount={parseInt(amount)} />
|
||||
} else {
|
||||
return (
|
||||
<form className="flex flex-col gap-4" onSubmit={handleSubmit}>
|
||||
<section className="flex flex-col gap-1">
|
||||
<h3>Do you want this donation as tax deductable?</h3>
|
||||
<div className="flex space-x-4 pb-4">
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
id="yes"
|
||||
name="deductable"
|
||||
value="yes"
|
||||
onChange={radioHandler}
|
||||
defaultChecked={true}
|
||||
/>
|
||||
Yes
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
id="no"
|
||||
value="no"
|
||||
name="deductable"
|
||||
onChange={radioHandler}
|
||||
/>
|
||||
No
|
||||
</label>
|
||||
</div>
|
||||
<input type="text" id="amount" value={amount} className="!pl-10 w-full" placeholder="Or enter custom amount" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Name <span className="text-subtle">{deductable === "yes" ? "(required)" : "(optional)"}</span></h3>
|
||||
<input
|
||||
type="text"
|
||||
placeholder={"Satoshi Nakamoto"}
|
||||
required={deductable === "yes"}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
className="mb-4"
|
||||
></input>
|
||||
<h3>Email <span className="text-subtle">{deductable === "yes" ? "(required)" : "(optional)"}</span></h3>
|
||||
<input
|
||||
type="text"
|
||||
placeholder={`satoshin@gmx.com`}
|
||||
required={deductable === "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 =>
|
||||
<button className="group" onClick={(e) => handleFiatAmountClick(e, value)}>${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 type="text" id="amount" value={amount} className="!pl-10 w-full" placeholder="Or enter custom amount" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<button className="w-full" type="submit">Make Donation</button>
|
||||
|
||||
</form >
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
<div className="h-4 w-4" />
|
||||
<button className="w-full" type="submit">Make Donation</button>
|
||||
</section>
|
||||
{/* <Pay /> */}
|
||||
</form >
|
||||
)
|
||||
};
|
||||
|
||||
export default DonationSteps;
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
import { useState } from "react";
|
||||
import Pay from "./Pay";
|
||||
|
||||
const DonationSteps = () => {
|
||||
const [step, setStep] = useState(1);
|
||||
|
||||
// STEP 1
|
||||
const [deductable, setDeductable] = useState("yes");
|
||||
|
||||
const radioHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setDeductable(event.target.value);
|
||||
};
|
||||
|
||||
function handleStep1(e: React.FormEvent<HTMLInputElement>) {
|
||||
e.preventDefault();
|
||||
setStep(2);
|
||||
}
|
||||
|
||||
// STEP 2
|
||||
function handleStep2(e: React.FormEvent<HTMLInputElement>) {
|
||||
e.preventDefault();
|
||||
setStep(3);
|
||||
}
|
||||
|
||||
// STEP 3
|
||||
|
||||
switch (step) {
|
||||
case 1:
|
||||
return (
|
||||
<section>
|
||||
<form className="flex flex-col space-y-2" onSubmit={handleStep1}>
|
||||
<h2>Do you want this donation as tax deductable?</h2>
|
||||
<div className="flex space-x-4">
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
id="yes"
|
||||
name="deductable"
|
||||
value="yes"
|
||||
onChange={radioHandler}
|
||||
defaultChecked={true}
|
||||
/>
|
||||
Yes
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
id="no"
|
||||
value="no"
|
||||
name="deductable"
|
||||
onChange={radioHandler}
|
||||
/>
|
||||
No
|
||||
</label>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
placeholder={`Email address (${deductable === "yes" ? "required" : "optional"
|
||||
})`}
|
||||
required={deductable === "yes"}
|
||||
></input>
|
||||
<div className="h-4 w-4" />
|
||||
<div className="justify-end flex space-x-4">
|
||||
<button type="submit">Continue</button>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
);
|
||||
case 2:
|
||||
return (
|
||||
<section>
|
||||
<form className="flex flex-col space-y-2" onSubmit={handleStep2}>
|
||||
<h2>One-time donation amount</h2>
|
||||
<input
|
||||
type="number"
|
||||
placeholder={`0.00`}
|
||||
required={deductable === "yes"}
|
||||
></input>
|
||||
<div className="h-4 w-4" />
|
||||
<div className="justify-end flex space-x-4">
|
||||
<button className="secondary" onClick={() => setStep(1)}>
|
||||
Back
|
||||
</button>
|
||||
<button type="submit">Donate</button>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
);
|
||||
case 3:
|
||||
return <Pay />;
|
||||
// never forget the default case, otherwise VS code would be mad!
|
||||
default:
|
||||
return <p>DEFAULT</p>;
|
||||
}
|
||||
};
|
||||
|
||||
export default DonationSteps;
|
||||
@@ -11,20 +11,19 @@ import PaymentModal from "../components/PaymentModal";
|
||||
|
||||
const Header = () => {
|
||||
return (
|
||||
<header className="bg-white p-4 md:p-8">
|
||||
<div className="flex flex-col lg:flex-row items-start lg:items-center">
|
||||
<header className="bg-white p-4 sm:p-8">
|
||||
<div className="flex flex-col sm:flex-row items-start sm:items-center">
|
||||
<div className="flex items-center w-[200px] py-4 pr-8">
|
||||
<Link href="/" passHref>
|
||||
<Image alt="OpenSats logo" src={logo} className="cursor-pointer" />
|
||||
</Link>
|
||||
</div>
|
||||
<nav>
|
||||
<ul className="flex flex-col md:flex-row gap-4 lg:space-x-4">
|
||||
<ul className="flex flex-col sm:flex-row gap-4">
|
||||
<li><Link href="/projects"><a>Projects</a></Link></li>
|
||||
<li>List Your Project</li>
|
||||
<li><Link href="/faq"><a>FAQ</a></Link></li>
|
||||
<li><Link href="/about"><a>About Us</a></Link></li>
|
||||
<li>Sponsors</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
@@ -17,7 +17,7 @@ const Layout: React.FC = ({ children }) => {
|
||||
<main>{children}</main>
|
||||
<footer className="flex justify-between p-4 md:p-8 bg-light">
|
||||
<div className="flex flex-col">
|
||||
<strong>© OpenSats, 2022</strong>
|
||||
<strong>© Open Sats Initiative, 2022</strong>
|
||||
<Link href="/terms"><a>Terms</a></Link>
|
||||
<Link href="/privacy"><a>Privacy</a></Link>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { faBitcoin } from "@fortawesome/free-brands-svg-icons";
|
||||
import { faCreditCard } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
import useSWR from "swr";
|
||||
import { fetchPostJSON } from "../utils/api-helpers";
|
||||
|
||||
const Pay = ({ amount = 100.0 }) => {
|
||||
// const [stripeUrl, setStripeUrl] = useState("");
|
||||
|
||||
const { data: stripe, error: stripeError } = useSWR(
|
||||
["/api/stripe_checkout", { amount }],
|
||||
fetchPostJSON
|
||||
@@ -18,20 +20,26 @@ const Pay = ({ amount = 100.0 }) => {
|
||||
console.log(btcpayError);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex flex-col space-y-4">
|
||||
{stripe?.url && (
|
||||
<p>
|
||||
<a href={stripe.url}>Pay with card</a>
|
||||
</p>
|
||||
<Link href={stripe.url} passHref={true}>
|
||||
<button className="border-2 border-black bg-white p-8 text-xl text-black hover:text-primary rounded-xl flex justify-start gap-4" role="link">
|
||||
<FontAwesomeIcon icon={faCreditCard} className="text-primary h-8 w-8" />
|
||||
Pay with card
|
||||
</button>
|
||||
</Link>
|
||||
)}
|
||||
{stripeError && <mark>heyo</mark>}
|
||||
<mark>Error: {stripeError?.message}</mark>
|
||||
{stripeError && <mark>{stripeError?.message}</mark>}
|
||||
{/* <mark>Error: {stripeError?.message}</mark> */}
|
||||
{btcpay?.url && (
|
||||
<p>
|
||||
<a href={btcpay.url}>Pay with Bitcoin</a>
|
||||
</p>
|
||||
<Link href={btcpay.url} passHref={true}>
|
||||
<button className="border-2 border-black bg-white p-8 text-xl text-black hover:text-primary rounded-xl flex justify-start gap-4" role="link">
|
||||
<FontAwesomeIcon icon={faBitcoin} className="text-primary h-8 w-8" />
|
||||
Pay with Bitcoin
|
||||
</button>
|
||||
</Link>
|
||||
)}
|
||||
<mark>Error: {btcpayError}</mark>
|
||||
{btcpayError && <mark>{btcpayError?.message}</mark>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { useState } from "react";
|
||||
import ReactModal from "react-modal";
|
||||
import Image from "next/image";
|
||||
import waffledog from "../public/waffledog.jpg";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faC, faClose } from "@fortawesome/free-solid-svg-icons";
|
||||
import DonationSteps from "./DonationSteps";
|
||||
import { faClose } from "@fortawesome/free-solid-svg-icons";
|
||||
import DonationForm from "./DonationForm";
|
||||
|
||||
type ModalProps = {
|
||||
@@ -16,7 +14,7 @@ const PaymentModal: React.FC<ModalProps> = ({ isOpen, onRequestClose }) => {
|
||||
<ReactModal
|
||||
isOpen={isOpen}
|
||||
onRequestClose={onRequestClose}
|
||||
className="p-4 bg-white shadow-xl overflow-y-auto max-h-full rounded-xl w-full m-4"
|
||||
className="p-8 bg-white shadow-xl overflow-y-auto max-h-full sm:rounded-xl w-full sm:m-8"
|
||||
overlayClassName="inset-0 fixed bg-[rgba(0,_0,_0,_0.75)] flex items-center justify-center"
|
||||
appElement={
|
||||
typeof window === "undefined"
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { CURRENCY, MIN_AMOUNT, MAX_AMOUNT } from "../../config";
|
||||
import { fetchPostJSONAuthed } from "../../utils/api-helpers";
|
||||
import { formatAmountForStripe } from "../../utils/stripe-helpers";
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
@@ -18,9 +17,8 @@ export default async function handler(
|
||||
}
|
||||
let data = await fetchPostJSONAuthed(
|
||||
`${process.env
|
||||
.BTCPAY_URL!}stores/9PMMpizLnpWtBeHV5Y9iKLj14Ei5iuVSWxYeSSntnsDU/invoices`,
|
||||
.BTCPAY_URL!}stores/${process.env.BTCPAY_STORE_ID}/invoices`,
|
||||
`token ${process.env.BTCPAY_API_KEY}`,
|
||||
// TODO validate that we aren't fucking with the amount with floating point stuff
|
||||
{ amount, currency: CURRENCY }
|
||||
);
|
||||
|
||||
|
||||
3
pages/apply.tsx
Normal file
3
pages/apply.tsx
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function Apply() {
|
||||
return <h1>apply!</h1>
|
||||
}
|
||||
@@ -28,11 +28,11 @@ const Home: NextPage = () => {
|
||||
Support contributors to Bitcoin and other free and open source
|
||||
projects
|
||||
</h1>
|
||||
<p className="text-textgray">We help you find and support <Link href="/projects">open-source bitcoin projects</Link> - helping create a better tomorrow, today.</p>
|
||||
<button onClick={() => setModalOpen(true)}>
|
||||
Explore Grants
|
||||
<p className="text-textgray">We help you find and support open-source Bitcoin projects - helping create a better tomorrow, today.</p>
|
||||
<button role={"button"} onClick={() => setModalOpen(true)}>
|
||||
Donate to Bitcoin
|
||||
</button>
|
||||
<p>or <a href="#">become a core donor to our General Fund</a></p>
|
||||
<p>Are you an open source contributor? <a href="#">Apply for your project to be listed.</a></p>
|
||||
</div>
|
||||
<div className="flex-1 flex justify-center">
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ button.selected {
|
||||
|
||||
input[type='text'],
|
||||
input[type='number'] {
|
||||
@apply border border-lightgray rounded p-2 invalid:border-red-500 focus:border-black;
|
||||
@apply border border-lightgray rounded p-2 focus:border-black;
|
||||
}
|
||||
|
||||
input[type='radio'] {
|
||||
|
||||
Reference in New Issue
Block a user