cleanup and real btcpay

This commit is contained in:
Paul Miller
2022-04-02 10:14:53 -05:00
parent 46fbaea9b5
commit 00a8172d03
10 changed files with 113 additions and 199 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>
);
};

View File

@@ -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"

View File

@@ -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
View File

@@ -0,0 +1,3 @@
export default function Apply() {
return <h1>apply!</h1>
}

View File

@@ -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">

View File

@@ -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'] {