damus.io

damus.io website
git clone git://jb55.com/damus.io
Log | Files | Refs | README | LICENSE

Step1ProductSelection.tsx (3868B)


      1 import { FormattedMessage, useIntl } from "react-intl";
      2 import { motion } from "framer-motion";
      3 import { useEffect, useRef, useState } from "react";
      4 import { LNCheckout, ProductTemplates } from "./Types";
      5 import { StepHeader } from "./StepHeader";
      6 import { Loader2 } from "lucide-react";
      7 
      8 export interface Step1ProductSelectionProps {
      9   lnCheckout: LNCheckout | null
     10   setLNCheckout: (lnCheckout: LNCheckout) => void
     11   setError: (error: string | null) => void
     12 }
     13 
     14 export function Step1ProductSelection(props: Step1ProductSelectionProps) {
     15   const intl = useIntl()
     16   const [productTemplates, setProductTemplates] = useState<ProductTemplates | null>(null) // The different product options
     17   const isStepDone = props.lnCheckout?.product_template_name != null
     18   
     19   // MARK: - Functions
     20 
     21   const fetchProductTemplates = async () => {
     22     try {
     23       const response = await fetch(process.env.NEXT_PUBLIC_PURPLE_API_BASE_URL + "/products", {
     24         method: 'GET',
     25         headers: {
     26           'Content-Type': 'application/json'
     27         },
     28       })
     29       const data = await response.json()
     30       setProductTemplates(data)
     31     }
     32     catch (e) {
     33       console.error(e)
     34       props.setError("Failed to get product list from our servers, please try again later in a few minutes. If the problem persists, please contact support.")
     35     }
     36   }
     37   
     38   const selectProduct = async (productTemplateName: string) => {
     39     try {
     40       const response = await fetch(process.env.NEXT_PUBLIC_PURPLE_API_BASE_URL + "/ln-checkout", {
     41         method: 'POST',
     42         headers: {
     43           'Content-Type': 'application/json'
     44         },
     45         body: JSON.stringify({ product_template_name: productTemplateName })
     46       })
     47       const data: LNCheckout = await response.json()
     48       props.setLNCheckout(data)
     49     }
     50     catch (e) {
     51       console.error(e)
     52       props.setError("Failed to begin the checkout process. Please wait a few minutes, refresh this page, and try again. If the problem persists, please contact support.")
     53     }
     54   }
     55 
     56   // MARK: - Effects and hooks
     57 
     58   // Load the products and the LN checkout (if there is one) on page load
     59   useEffect(() => {
     60     fetchProductTemplates()
     61   }, [])
     62 
     63   // MARK: - Render
     64 
     65   return (<>
     66     <StepHeader
     67       stepNumber={1}
     68       title={intl.formatMessage({ id: "purple.checkout.step-1", defaultMessage: "Choose your plan" })}
     69       done={isStepDone}
     70       active={true}
     71     />
     72     <div className="mt-3 mb-4 flex gap-2 items-center">
     73       {productTemplates ? Object.entries(productTemplates).map(([name, productTemplate]) => (
     74         <button
     75           key={name}
     76           className={`relative flex flex-col items-center justify-center p-3 pt-4 border rounded-lg ${name == props.lnCheckout?.product_template_name ? "border-green-500" : "border-purple-200/50"} disabled:opacity-50 disabled:cursor-not-allowed`}
     77           onClick={() => selectProduct(name)}
     78           disabled={isStepDone}
     79         >
     80           {productTemplate.special_label && (
     81             <div className="absolute top-0 right-0 -mt-4 -mr-2 bg-gradient-to-r from-damuspink-500 to-damuspink-600 rounded-full p-1 px-3">
     82               <div className="text-white text-xs font-semibold">
     83                 {productTemplate.special_label}
     84               </div>
     85             </div>
     86           )}
     87 
     88           <div className="text-purple-200/50 font-normal text-sm">
     89             {productTemplate.description}
     90           </div>
     91           <div className="mt-1 text-purple-100/90 font-semibold text-lg">
     92             {productTemplate.amount_msat / 1000} sats
     93           </div>
     94         </button>
     95       )) : (
     96         <div className="flex flex-col items-center justify-center">
     97           <div className="text-purple-200/50 font-normal text-sm flex items-center">
     98             <Loader2 className="w-4 h-4 mr-2 animate-spin" />
     99             Loading...
    100           </div>
    101         </div>
    102       )}
    103     </div>
    104   </>)
    105 }