PurpleCheckout.tsx (4944B)
1 import { useIntl } from "react-intl"; 2 import { useEffect, useState } from "react"; 3 import { useInterval } from 'usehooks-ts' 4 import { Info } from "lucide-react"; 5 import { PurpleLayout } from "../PurpleLayout"; 6 import { AccountInfo } from "@/utils/PurpleUtils"; 7 import { Step1ProductSelection } from "./PurpleCheckoutDetails/Step1ProductSelection"; 8 import { LNCheckout } from "./PurpleCheckoutDetails/Types"; 9 import { Step2UserVerification } from "./PurpleCheckoutDetails/Step2UserVerification"; 10 import { Step3Payment } from "./PurpleCheckoutDetails/Step3Payment"; 11 import { PurpleCheckoutErrorDialog } from "./PurpleCheckoutDetails/ErrorDialog"; 12 import { CheckoutSuccess } from "./PurpleCheckoutDetails/CheckoutSuccess"; 13 14 15 export function PurpleCheckout() { 16 const intl = useIntl() 17 const [lnCheckout, setLNCheckout] = useState<LNCheckout | null>(null) // The checkout object from the server 18 const [error, setError] = useState<string | null>(null) // An error message to display to the user 19 const [selectedAuthMethod, setSelectedAuthMethod] = useState<string | "nostr-dm" | "damus-ios">("nostr-dm") 20 const [existingAccountInfo, setExistingAccountInfo] = useState<AccountInfo | null | undefined>(undefined) // The account info fetched from the server 21 22 // MARK: - Functions 23 24 const refreshLNCheckout = async (id?: string) => { 25 if (!lnCheckout && !id) { 26 return 27 } 28 try { 29 const response = await fetch(process.env.NEXT_PUBLIC_PURPLE_API_BASE_URL + "/ln-checkout/" + (id || lnCheckout?.id), { 30 method: 'GET', 31 headers: { 32 'Content-Type': 'application/json' 33 }, 34 }) 35 const data: LNCheckout = await response.json() 36 setLNCheckout(data) 37 } 38 catch (e) { 39 console.error(e) 40 setError("Failed to get checkout info from our servers, please wait a few minutes and try to refresh this page. If the problem persists, please contact support.") 41 } 42 } 43 44 const pollState = async () => { 45 if (!lnCheckout) { 46 return 47 } 48 if (!lnCheckout.verified_pubkey) { 49 refreshLNCheckout() 50 } 51 } 52 53 // MARK: - Effects and hooks 54 55 // Keep checking the state of things when needed 56 useInterval(pollState, 1000) 57 58 useEffect(() => { 59 // Set the query parameter on the URL to be the lnCheckout ID to avoid losing it on page refresh 60 if (lnCheckout) { 61 const url = new URL(window.location.href) 62 url.searchParams.set("id", lnCheckout.id) 63 window.history.replaceState({}, "", url.toString()) 64 } 65 }, [lnCheckout]) 66 67 // Load the LN checkout (if there is one) on page load 68 useEffect(() => { 69 // Check if there is a lnCheckout ID in the URL query parameters. If so, fetch the lnCheckout 70 const url = new URL(window.location.href) 71 const id = url.searchParams.get("id") 72 if (id) { 73 console.log("Found lnCheckout ID in URL query parameters. Fetching lnCheckout...") 74 refreshLNCheckout(id) 75 } 76 }, []) 77 78 // MARK: - Render 79 80 return (<> 81 <PurpleCheckoutErrorDialog lnCheckout={lnCheckout} error={error} setError={setError} /> 82 83 <PurpleLayout> 84 <h2 className="text-2xl text-left text-purple-200 font-semibold break-keep mb-2"> 85 {intl.formatMessage({ id: "purple.checkout.title", defaultMessage: "Checkout" })} 86 </h2> 87 <div className="text-purple-200/70 text-normal text-left mb-6 font-semibold flex flex-col md:flex-row gap-3 rounded-lg bg-purple-200/10 p-3 items-center md:items-start"> 88 <Info className="w-6 h-6 shrink-0 mt-0 md:mt-1" /> 89 <div className="flex flex-col text-center md:text-left"> 90 <span className="text-normal md:text-lg mb-2"> 91 {intl.formatMessage({ id: "purple.checkout.description", defaultMessage: "New accounts and renewals" })} 92 </span> 93 <span className="text-xs text-purple-200/50"> 94 {intl.formatMessage({ id: "purple.checkout.description-2", defaultMessage: "Use this page to purchase a new account, or to renew an existing one. You will need the latest Damus version to complete the checkout." })} 95 </span> 96 </div> 97 </div> 98 99 <Step1ProductSelection 100 lnCheckout={lnCheckout} 101 setLNCheckout={setLNCheckout} 102 setError={setError} 103 /> 104 105 <Step2UserVerification 106 lnCheckout={lnCheckout} 107 setLNCheckout={setLNCheckout} 108 selectedAuthMethod={selectedAuthMethod} 109 setSelectedAuthMethod={setSelectedAuthMethod} 110 setError={setError} 111 /> 112 113 <Step3Payment 114 lnCheckout={lnCheckout} 115 setLNCheckout={setLNCheckout} 116 setError={setError} 117 successView={<> 118 {lnCheckout && 119 <CheckoutSuccess 120 lnCheckout={lnCheckout} 121 existingAccountInfo={existingAccountInfo} 122 selectedAuthMethod={selectedAuthMethod} 123 setError={setError} 124 /> 125 } 126 </>} 127 /> 128 </PurpleLayout> 129 </>) 130 }