diff --git a/src/App.tsx b/src/App.tsx index 7b79706..8c40b9d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -14,6 +14,7 @@ const HottestPage = React.lazy(() => import("src/features/Projects/pages/Hottest const PostDetailsPage = React.lazy(() => import("./features/Posts/pages/PostDetailsPage/PostDetailsPage")) const CategoryPage = React.lazy(() => import("src/features/Projects/pages/CategoryPage/CategoryPage")) const ExplorePage = React.lazy(() => import("src/features/Projects/pages/ExplorePage")) +const DonatePage = React.lazy(() => import("./features/Donations/pages/DonatePage/DonatePage")) function App() { const { isWalletConnected } = useAppSelector(state => ({ @@ -49,6 +50,7 @@ function App() { } /> } /> } /> + } /> } /> diff --git a/src/features/Donations/components/DonateCard/DonateCard.tsx b/src/features/Donations/components/DonateCard/DonateCard.tsx index 7136729..00f703a 100644 --- a/src/features/Donations/components/DonateCard/DonateCard.tsx +++ b/src/features/Donations/components/DonateCard/DonateCard.tsx @@ -1,8 +1,8 @@ import React, { FormEvent, useState } from 'react'; -import { PaymentStatus, useVote } from 'src/utils/hooks'; +import { PaymentStatus, } from 'src/utils/hooks'; import Confetti from "react-confetti"; import { useWindowSize } from '@react-hookz/web'; -import { Vote_Item_Type } from 'src/graphql'; +import { useDonate } from './useDonate'; const defaultOptions = [ { text: '500', value: 500 }, @@ -12,18 +12,13 @@ const defaultOptions = [ ] - export default function DonateCard() { - const { width, height } = useWindowSize() - + const size = useWindowSize(); const [selectedOption, setSelectedOption] = useState(-1); const [donationAmount, setDonationAmount] = useState(); - const { vote, paymentStatus } = useVote({ - itemId: 123, - itemType: Vote_Item_Type.Project - }) + const { donate, paymentStatus, isLoading } = useDonate() const onChangeInput = (event: React.ChangeEvent) => { setSelectedOption(-1); @@ -38,7 +33,7 @@ export default function DonateCard() { const requestPayment = (e: FormEvent) => { e.preventDefault(); if (donationAmount) - vote(donationAmount, { + donate(donationAmount, { onSuccess: () => { setTimeout(() => { setDonationAmount(undefined); @@ -86,18 +81,20 @@ export default function DonateCard() { {paymentStatus === PaymentStatus.FETCHING_PAYMENT_DETAILS &&

Please wait while we the fetch payment details.

} {paymentStatus === PaymentStatus.NOT_PAID &&

You did not confirm the payment. Please try again.

} + {paymentStatus === PaymentStatus.NETWORK_ERROR &&

A network error happened while fetching data.

} {paymentStatus === PaymentStatus.PAID &&

The invoice was paid! Please wait while we confirm it.

} {paymentStatus === PaymentStatus.AWAITING_PAYMENT &&

Waiting for your payment...

} {paymentStatus === PaymentStatus.PAYMENT_CONFIRMED &&

Thanks for your vote

} - {paymentStatus === PaymentStatus.PAYMENT_CONFIRMED && } + {paymentStatus === PaymentStatus.PAYMENT_CONFIRMED && } + ) } diff --git a/src/features/Donations/components/DonateCard/useDonate.tsx b/src/features/Donations/components/DonateCard/useDonate.tsx new file mode 100644 index 0000000..16b0099 --- /dev/null +++ b/src/features/Donations/components/DonateCard/useDonate.tsx @@ -0,0 +1,76 @@ + +import { useCallback, useState } from 'react'; +import { useConfirmDonationMutation, useDonateMutation } from 'src/graphql'; +import { Wallet_Service } from 'src/services'; +import { PaymentStatus } from 'src/utils/hooks'; + + + +export const useDonate = () => { + + const [paymentStatus, setPaymentStatus] = useState(PaymentStatus.DEFAULT); + const [donateMutation] = useDonateMutation(); + const [confirmDonation] = useConfirmDonationMutation(); + + const donate = useCallback((amount: number, config?: Partial<{ + onSuccess: () => void, + onError: (error: any) => void, + onSetteled: () => void + }>) => { + setPaymentStatus(PaymentStatus.FETCHING_PAYMENT_DETAILS) + donateMutation({ + variables: { + amountInSat: amount + }, + onCompleted: async (donationData) => { + try { + setPaymentStatus(PaymentStatus.AWAITING_PAYMENT); + const webln = await Wallet_Service.getWebln() + const paymentResponse = await webln.sendPayment(donationData.donate.payment_request); + setPaymentStatus(PaymentStatus.PAID); + + //Confirm Voting payment + confirmDonation({ + variables: { + paymentRequest: donationData.donate.payment_request, + preimage: paymentResponse.preimage + }, + onCompleted: () => { + setPaymentStatus(PaymentStatus.PAYMENT_CONFIRMED); + config?.onSuccess?.(); + config?.onSetteled?.() + }, + onError: (error) => { + console.log(error) + setPaymentStatus(PaymentStatus.NETWORK_ERROR); + config?.onError?.(error); + config?.onSetteled?.(); + alert("A network error happened while confirming the payment...") + } + }) + } catch (error) { + setPaymentStatus(PaymentStatus.CANCELED); + config?.onError?.(error); + config?.onSetteled?.(); + alert("Payment rejected by user") + } + + }, + onError: (error) => { + console.log(error); + setPaymentStatus(PaymentStatus.NETWORK_ERROR); + config?.onError?.(error); + config?.onSetteled?.(); + alert("A network error happened...") + } + }) + }, [confirmDonation, donateMutation]); + + const isLoading = paymentStatus !== PaymentStatus.DEFAULT && paymentStatus !== PaymentStatus.PAYMENT_CONFIRMED && paymentStatus !== PaymentStatus.NOT_PAID && paymentStatus !== PaymentStatus.NETWORK_ERROR + + return { + paymentStatus, + donate, + isLoading + } +} \ No newline at end of file diff --git a/src/features/Donations/pages/DonatePage/DonationStats/DonationStats.tsx b/src/features/Donations/pages/DonatePage/DonationStats/DonationStats.tsx index 1b6795a..237cc98 100644 --- a/src/features/Donations/pages/DonatePage/DonationStats/DonationStats.tsx +++ b/src/features/Donations/pages/DonatePage/DonationStats/DonationStats.tsx @@ -20,7 +20,7 @@ export default function DonationStats() { Prizes} - value='2.5k' + value='$2.5k' />

- Donate + Donate

Help fund BOLT🔩FUN, as well as other Makers working on lightning apps through tournaments and prize pools diff --git a/src/features/Donations/pages/DonatePage/Header/styles.module.scss b/src/features/Donations/pages/DonatePage/Header/styles.module.scss index dad6686..41b3dcd 100644 --- a/src/features/Donations/pages/DonatePage/Header/styles.module.scss +++ b/src/features/Donations/pages/DonatePage/Header/styles.module.scss @@ -2,6 +2,7 @@ .header { padding: 56px 0; + min-height: calc(min(1080px, 90vh)); background: #ffecf9; background: linear-gradient(40deg, white -5%, #ffb7d963 74%, #e3faff61 100%); @@ -12,8 +13,4 @@ & > div { grid-area: content; } - - @include gt-md { - padding: 156px 0; - } } diff --git a/src/utils/hooks/index.ts b/src/utils/hooks/index.ts index e58a234..9b81126 100644 --- a/src/utils/hooks/index.ts +++ b/src/utils/hooks/index.ts @@ -6,3 +6,4 @@ export * from "./useReachedBottom"; export * from "./useAutoResizableTextArea"; export * from "./useCopyToClipboard"; export * from "./useVote"; +export * from './useWindowSize' diff --git a/src/utils/hooks/useVote/useVote.tsx b/src/utils/hooks/useVote/useVote.tsx index f5808bf..e5f62b4 100644 --- a/src/utils/hooks/useVote/useVote.tsx +++ b/src/utils/hooks/useVote/useVote.tsx @@ -11,10 +11,13 @@ export enum PaymentStatus { AWAITING_PAYMENT, PAYMENT_CONFIRMED, NOT_PAID, - CANCELED + CANCELED, + NETWORK_ERROR } + + export const useVote = ({ itemId, itemType }: { itemType: Vote_Item_Type, itemId: number @@ -81,8 +84,10 @@ export const useVote = ({ itemId, itemType }: { }, onError: (error) => { + setPaymentStatus(PaymentStatus.NETWORK_ERROR); config?.onError?.(error); config?.onSetteled?.(); + alert("A network error happened while confirming the payment...") } }) } catch (error) { @@ -96,18 +101,20 @@ export const useVote = ({ itemId, itemType }: { }, onError: (error) => { console.log(error); - alert("Something wrong happened...") - setPaymentStatus(PaymentStatus.NOT_PAID); + setPaymentStatus(PaymentStatus.NETWORK_ERROR); config?.onError?.(error); config?.onSetteled?.(); + alert("A network error happened...") } }) }, [confirmVote, itemId, itemType, voteMutaion]); + const isLoading = paymentStatus !== PaymentStatus.DEFAULT && paymentStatus !== PaymentStatus.PAYMENT_CONFIRMED && paymentStatus !== PaymentStatus.NOT_PAID && paymentStatus !== PaymentStatus.NETWORK_ERROR return { paymentStatus, - vote + vote, + isLoading, } } \ No newline at end of file diff --git a/src/utils/hooks/useWindowSize.ts b/src/utils/hooks/useWindowSize.ts new file mode 100644 index 0000000..59df959 --- /dev/null +++ b/src/utils/hooks/useWindowSize.ts @@ -0,0 +1,33 @@ +import { useState, useEffect } from "react"; + +// Define general type for useWindowSize hook, which includes width and height +interface Size { + width: number | undefined; + height: number | undefined; +} +// Hook +export function useWindowSize(): Size { + // Initialize state with undefined width/height so server and client renders match + // Learn more here: https://joshwcomeau.com/react/the-perils-of-rehydration/ + const [windowSize, setWindowSize] = useState({ + width: undefined, + height: undefined, + }); + useEffect(() => { + // Handler to call on window resize + function handleResize() { + // Set window width/height to state + setWindowSize({ + width: window.innerWidth, + height: window.innerHeight, + }); + } + // Add event listener + window.addEventListener("resize", handleResize); + // Call handler right away so state gets updated with initial window size + handleResize(); + // Remove event listener on cleanup + return () => window.removeEventListener("resize", handleResize); + }, []); // Empty array ensures that effect is only run on mount + return windowSize; +} \ No newline at end of file