From 3709b4d93ca6977873c46c81abb460c9f9afbf2f Mon Sep 17 00:00:00 2001 From: MTG2000 Date: Sat, 21 May 2022 16:21:28 +0300 Subject: [PATCH] feat: enable voting in other components --- functions/graphql/types/vote.js | 1 + src/Components/VoteButton/VoteButton.tsx | 12 +- .../PostCard/BountyCard/BountyCard.tsx | 2 +- .../PostCard/QuestionCard/QuestionCard.tsx | 2 +- .../PostCard/StoryCard/StoryCard.tsx | 11 +- .../Components/TrendingCard/TrendingCard.tsx | 4 +- .../Posts/pages/FeedPage/FeedPage.tsx | 4 +- .../PopularTopicsFilter.tsx | 2 +- .../Components/PostActions/PostActions.tsx | 61 +++++-- .../pages/PostDetailsPage/PostDetailsPage.tsx | 3 +- .../pages/ProjectPage/VoteCard/VoteCard.tsx | 25 +-- src/styles/index.scss | 2 +- src/utils/hooks/useVote/useVote.tsx | 159 ++++++++++-------- 13 files changed, 172 insertions(+), 116 deletions(-) diff --git a/functions/graphql/types/vote.js b/functions/graphql/types/vote.js index 7503662..c7b074f 100644 --- a/functions/graphql/types/vote.js +++ b/functions/graphql/types/vote.js @@ -133,6 +133,7 @@ const voteMutation = extendType({ const { item_id, item_type, amount_in_sat } = args; const lightning_address = (await getLightningAddress(item_id, item_type)) ?? BOLT_FUN_LIGHTNING_ADDRESS; const pr = await getPaymetRequestForItem(lightning_address, args.amount_in_sat); + console.log(pr); const invoice = parsePaymentRequest({ request: pr }); // #TODO remove votes rows that get added but not confirmed after some time diff --git a/src/Components/VoteButton/VoteButton.tsx b/src/Components/VoteButton/VoteButton.tsx index d9e7d57..99ea2c7 100644 --- a/src/Components/VoteButton/VoteButton.tsx +++ b/src/Components/VoteButton/VoteButton.tsx @@ -19,8 +19,8 @@ interface Particle { } type Props = { - initVotes: number, - onVote?: (Vote: number) => void, + votes: number, + onVote?: (amount: number, config: Partial<{ onSetteled: () => void }>) => void, fillType?: 'leftRight' | 'upDown' | "background" | 'radial', direction?: 'horizontal' | 'vertical' disableCounter?: boolean @@ -30,7 +30,7 @@ type Props = { } & Omit, 'children'> export default function VoteButton({ - initVotes, + votes, onVote = () => { }, fillType = 'leftRight', direction = 'horizontal', @@ -56,9 +56,9 @@ export default function VoteButton({ const resetCounterOnRelease = resetCounterOnReleaseProp; const doVote = useDebouncedCallback(() => { - onVote(voteCntRef.current); + const amount = voteCntRef.current; + onVote(amount, { onSetteled: () => setVoteCnt(v => v - amount) }); voteCntRef.current = 0; - console.log("VOTED"); }, [], 2000) @@ -192,7 +192,7 @@ export default function VoteButton({ {numberFormatter(initVotes + voteCnt)} + /> {numberFormatter(votes + voteCnt)} {increments.map(increment =>
- +
{bounty.applicants_count} Applicants
diff --git a/src/features/Posts/Components/PostCard/QuestionCard/QuestionCard.tsx b/src/features/Posts/Components/PostCard/QuestionCard/QuestionCard.tsx index ffa5d0a..ddb3955 100644 --- a/src/features/Posts/Components/PostCard/QuestionCard/QuestionCard.tsx +++ b/src/features/Posts/Components/PostCard/QuestionCard/QuestionCard.tsx @@ -52,7 +52,7 @@ export default function QuestionCard({ question }: Props) {
- +
{question.answers_count} Answers
diff --git a/src/features/Posts/Components/PostCard/StoryCard/StoryCard.tsx b/src/features/Posts/Components/PostCard/StoryCard/StoryCard.tsx index 890b3e6..d29e2f8 100644 --- a/src/features/Posts/Components/PostCard/StoryCard/StoryCard.tsx +++ b/src/features/Posts/Components/PostCard/StoryCard/StoryCard.tsx @@ -1,9 +1,10 @@ -import VotesCount from "src/Components/VotesCount/VotesCount" import { Story } from "src/features/Posts/types" import Header from "../Header/Header" import { BiComment } from 'react-icons/bi' import { Link } from "react-router-dom" import VoteButton from "src/Components/VoteButton/VoteButton" +import { useVote } from "src/utils/hooks" +import { Vote_Item_Type } from 'src/graphql'; export type StoryCardType = Pick @@ -33,7 +40,7 @@ export default function StoryCard({ story }: Props) {
- +
{story.comments_count} Comments
diff --git a/src/features/Posts/Components/TrendingCard/TrendingCard.tsx b/src/features/Posts/Components/TrendingCard/TrendingCard.tsx index 14b0e68..b8c7074 100644 --- a/src/features/Posts/Components/TrendingCard/TrendingCard.tsx +++ b/src/features/Posts/Components/TrendingCard/TrendingCard.tsx @@ -13,7 +13,7 @@ export default function TrendingCard() { return (

Trending on BOLT.FUN

-
    +
      { trendingPosts.loading ? Array(4).fill(0).map((_, idx) =>
    • @@ -24,7 +24,7 @@ export default function TrendingCard() { ) : trendingPosts.data?.getTrendingPosts.map(post => { - return + return
    • {post.title}

      diff --git a/src/features/Posts/pages/FeedPage/FeedPage.tsx b/src/features/Posts/pages/FeedPage/FeedPage.tsx index 14d006c..130f72f 100644 --- a/src/features/Posts/pages/FeedPage/FeedPage.tsx +++ b/src/features/Posts/pages/FeedPage/FeedPage.tsx @@ -43,10 +43,10 @@ export default function FeedPage() { maxHeight: `calc(100vh - ${navHeight}px - 16px)`, overflowY: "scroll", }}> - -
      +
      */} diff --git a/src/features/Posts/pages/FeedPage/PopularTopicsFilter/PopularTopicsFilter.tsx b/src/features/Posts/pages/FeedPage/PopularTopicsFilter/PopularTopicsFilter.tsx index 3716c8c..1189759 100644 --- a/src/features/Posts/pages/FeedPage/PopularTopicsFilter/PopularTopicsFilter.tsx +++ b/src/features/Posts/pages/FeedPage/PopularTopicsFilter/PopularTopicsFilter.tsx @@ -52,7 +52,7 @@ export default function PopularTopicsFilter({ filterChanged }: Props) { > - +
    • ) diff --git a/src/features/Posts/pages/PostDetailsPage/Components/PostActions/PostActions.tsx b/src/features/Posts/pages/PostDetailsPage/Components/PostActions/PostActions.tsx index a0096b9..a522f5e 100644 --- a/src/features/Posts/pages/PostDetailsPage/Components/PostActions/PostActions.tsx +++ b/src/features/Posts/pages/PostDetailsPage/Components/PostActions/PostActions.tsx @@ -1,33 +1,62 @@ import { BsBookmark } from "react-icons/bs" +import { FiArrowLeft } from "react-icons/fi" import { MdIosShare } from "react-icons/md" +import { useNavigate } from "react-router-dom" import VoteButton from "src/Components/VoteButton/VoteButton" +import { Post } from "src/features/Posts/types" +import { Vote_Item_Type } from "src/graphql" +import { useVote } from "src/utils/hooks" interface Props { - votes_count: number + post: Pick } -export default function PostActions(props: Props) { +export default function PostActions({ post }: Props) { const actions = [ - { - icon: BsBookmark, - value: 27 - }, { icon: MdIosShare, - value: 72 + value: '--' }, - ] + ]; + + const navigate = useNavigate(); + + const { vote } = useVote({ + itemId: post.id, + itemType: Vote_Item_Type[post.__typename!] + }); return ( -
        - - {actions.map((action, idx) =>
      • + + {/*
          +
        • - - {action.value} -
        • )} -
        + +
      • +
      */} +
        + {actions.map((action, idx) =>
      • + + {action.value} +
      • )} + +
      +
) } diff --git a/src/features/Posts/pages/PostDetailsPage/PostDetailsPage.tsx b/src/features/Posts/pages/PostDetailsPage/PostDetailsPage.tsx index 65e9854..51e8af2 100644 --- a/src/features/Posts/pages/PostDetailsPage/PostDetailsPage.tsx +++ b/src/features/Posts/pages/PostDetailsPage/PostDetailsPage.tsx @@ -19,7 +19,6 @@ export default function PostDetailsPage() { type: type as any }, skip: isNaN(Number(id)), - }) const { navHeight } = useAppSelector((state) => ({ @@ -44,7 +43,7 @@ export default function PostDetailsPage() { top: `${navHeight + 16}px`, maxHeight: `calc(100vh - ${navHeight}px - 16px)`, }}> - +
diff --git a/src/features/Projects/pages/ProjectPage/VoteCard/VoteCard.tsx b/src/features/Projects/pages/ProjectPage/VoteCard/VoteCard.tsx index c625ffa..569779c 100644 --- a/src/features/Projects/pages/ProjectPage/VoteCard/VoteCard.tsx +++ b/src/features/Projects/pages/ProjectPage/VoteCard/VoteCard.tsx @@ -28,16 +28,8 @@ export default function VoteCard({ onClose, direction, projectId, initVotes, ... const [selectedOption, setSelectedOption] = useState(10); const [voteAmount, setVoteAmount] = useState(initVotes ?? 10); const { vote, paymentStatus } = useVote({ - onSuccess: () => { - setTimeout(() => { - onClose?.(); - }, 4000); - }, - onError: () => { - setTimeout(() => { - onClose?.(); - }, 4000); - } + itemId: projectId, + itemType: Vote_Item_Type.Project }) @@ -54,7 +46,18 @@ export default function VoteCard({ onClose, direction, projectId, initVotes, ... const requestPayment = (e: FormEvent) => { e.preventDefault(); - vote({ variables: { "amountInSat": voteAmount, "itemId": projectId!, itemType: Vote_Item_Type.Project } }); + vote(voteAmount, { + onSuccess: () => { + setTimeout(() => { + onClose?.(); + }, 4000); + }, + onError: () => { + setTimeout(() => { + onClose?.(); + }, 4000); + } + }); } return ( diff --git a/src/styles/index.scss b/src/styles/index.scss index 0cfdffb..5550ae9 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -7,7 +7,7 @@ $screen-xs-min: 320px; body { overflow-x: hidden; - /* background-color: #F8FAFC; */ + background-color: #f8fafc; } .page-container { diff --git a/src/utils/hooks/useVote/useVote.tsx b/src/utils/hooks/useVote/useVote.tsx index e3cdc7c..f5808bf 100644 --- a/src/utils/hooks/useVote/useVote.tsx +++ b/src/utils/hooks/useVote/useVote.tsx @@ -1,7 +1,7 @@ import { gql } from '@apollo/client'; -import { useState } from 'react'; -import { useConfirmVoteMutation, useVoteMutation } from 'src/graphql'; +import { useCallback, useState } from 'react'; +import { useConfirmVoteMutation, useVoteMutation, Vote_Item_Type } from 'src/graphql'; import { Wallet_Service } from 'src/services'; export enum PaymentStatus { @@ -15,80 +15,97 @@ export enum PaymentStatus { } -export const useVote = ({ onSuccess, onError }: { - onSuccess?: () => void - onError?: (error: any) => void +export const useVote = ({ itemId, itemType }: { + itemType: Vote_Item_Type, + itemId: number }) => { const [paymentStatus, setPaymentStatus] = useState(PaymentStatus.DEFAULT); + const [voteMutaion] = useVoteMutation(); + const [confirmVote] = useConfirmVoteMutation(); - const [voteMutaion] = useVoteMutation({ - onCompleted: async (votingData) => { - try { - setPaymentStatus(PaymentStatus.AWAITING_PAYMENT); - const webln = await Wallet_Service.getWebln() - const paymentResponse = await webln.sendPayment(votingData.vote.payment_request); - setPaymentStatus(PaymentStatus.PAID); - confirmVote({ - variables: { - paymentRequest: votingData.vote.payment_request, - preimage: paymentResponse.preimage - } - }) - } catch (error) { - console.log(error); - setPaymentStatus(PaymentStatus.NOT_PAID); - } - - }, - onError: (error) => { - console.log(error); - alert("Something wrong happened...") - setPaymentStatus(PaymentStatus.NOT_PAID); - onError?.(error) - } - }); - - const [confirmVote] = useConfirmVoteMutation({ - onCompleted: () => { - setPaymentStatus(PaymentStatus.PAYMENT_CONFIRMED); - onSuccess?.(); - }, - update(cache, { data }) { - try { - const { item_id, item_type, amount_in_sat } = data!.confirmVote; - const { votes_count } = cache.readFragment({ - id: `${item_type}:${item_id}`, - fragment: gql` - fragment My${item_type} on ${item_type} { - votes_count - }` - }) ?? {}; - cache.writeFragment({ - id: `${item_type}:${item_id}`, - fragment: gql` - fragment My${item_type} on ${item_type} { - votes_count - } - `, - data: { - votes_count: votes_count + amount_in_sat - }, - }) - } catch (error) { - - } - }, - - onError: () => { } - - }); - - - const vote = (...params: Parameters) => { + const vote = useCallback((amount: number, config?: Partial<{ + onSuccess: () => void, + onError: (error: any) => void, + onSetteled: () => void + }>) => { setPaymentStatus(PaymentStatus.FETCHING_PAYMENT_DETAILS) - voteMutaion(...params) - } + voteMutaion({ + variables: { + itemId, + itemType, + amountInSat: amount + }, + onCompleted: async (votingData) => { + try { + setPaymentStatus(PaymentStatus.AWAITING_PAYMENT); + const webln = await Wallet_Service.getWebln() + const paymentResponse = await webln.sendPayment(votingData.vote.payment_request); + setPaymentStatus(PaymentStatus.PAID); + + //Confirm Voting payment + confirmVote({ + variables: { + paymentRequest: votingData.vote.payment_request, + preimage: paymentResponse.preimage + }, + onCompleted: () => { + setPaymentStatus(PaymentStatus.PAYMENT_CONFIRMED); + config?.onSuccess?.(); + config?.onSetteled?.() + }, + update(cache, { data }) { + try { + const { item_id, item_type, amount_in_sat } = data!.confirmVote; + const { votes_count } = cache.readFragment({ + id: `${item_type}:${item_id}`, + fragment: gql` + fragment My${item_type} on ${item_type} { + votes_count + }` + }) ?? {}; + cache.writeFragment({ + id: `${item_type}:${item_id}`, + fragment: gql` + fragment My${item_type} on ${item_type} { + votes_count + } + `, + data: { + votes_count: votes_count + amount_in_sat + }, + }) + } catch (error) { + config?.onError?.(error) + } + }, + + onError: (error) => { + config?.onError?.(error); + config?.onSetteled?.(); + } + }) + } catch (error) { + setPaymentStatus(PaymentStatus.CANCELED); + config?.onError?.(error); + config?.onSetteled?.(); + alert("Payment rejected by user") + + } + + }, + onError: (error) => { + console.log(error); + alert("Something wrong happened...") + setPaymentStatus(PaymentStatus.NOT_PAID); + config?.onError?.(error); + config?.onSetteled?.(); + } + }) + }, [confirmVote, itemId, itemType, voteMutaion]); + + + return { paymentStatus, vote