diff --git a/package.json b/package.json index c6d34e1..e908812 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "react-dom": "^18.3.1", "react-dropzone": "^14.2.3", "react-infinite-scroller": "^1.2.5", + "react-minimal-pie-chart": "^9.1.0", "react-toastify": "^10.0.5", "superjson": "^2.2.1", "supports-color": "8.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 36c0f82..31d884f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -80,6 +80,9 @@ importers: react-infinite-scroller: specifier: ^1.2.5 version: 1.2.6(react@18.3.1) + react-minimal-pie-chart: + specifier: ^9.1.0 + version: 9.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-toastify: specifier: ^10.0.5 version: 10.0.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -6793,6 +6796,12 @@ packages: react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + react-minimal-pie-chart@9.1.0: + resolution: {integrity: sha512-JziZXZT0aw+9X+rGSpQwbSG7t3ypsyhzJNpiTUGfVeCqr70YIPbHE5Us3RsCsNRlVHbeLGrp/ibVuzUJT6Gcvw==} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 || ^19 + react-dom: ^16.8.0 || ^17 || ^18 || ^19 + react-native-webview@11.26.1: resolution: {integrity: sha512-hC7BkxOpf+z0UKhxFSFTPAM4shQzYmZHoELa6/8a/MspcjEP7ukYKpuSUTLDywQditT8yI9idfcKvfZDKQExGw==} peerDependencies: @@ -7465,6 +7474,10 @@ packages: svg-parser@2.0.4: resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==} + svg-partial-circle@1.0.0: + resolution: {integrity: sha512-jDWgNzrlpsGo9A7/tdjCy6+1RzeeANYV1a3JtNYC/0ZXI3U+3VMucuNv7JuKti9VVBdyNxNO1CZs/k0xS1lUFA==} + engines: {node: '>=6'} + svgo@3.3.2: resolution: {integrity: sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==} engines: {node: '>=14.0.0'} @@ -17357,6 +17370,12 @@ snapshots: react-is@18.3.1: {} + react-minimal-pie-chart@9.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + svg-partial-circle: 1.0.0 + react-native-webview@11.26.1(react-native@0.76.0(@babel/core@7.24.6(supports-color@8.1.1))(@babel/preset-env@7.24.6(@babel/core@7.24.6(supports-color@8.1.1))(supports-color@8.1.1))(@types/react@18.3.3)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)(supports-color@8.1.1)(utf-8-validate@5.0.10))(react@18.3.1): dependencies: escape-string-regexp: 2.0.0 @@ -18171,6 +18190,8 @@ snapshots: svg-parser@2.0.4: {} + svg-partial-circle@1.0.0: {} + svgo@3.3.2: dependencies: '@trysound/sax': 0.2.0 diff --git a/src/components/bounty/BountyClaims.tsx b/src/components/bounty/BountyClaims.tsx index 13fe04f..db6f730 100644 --- a/src/components/bounty/BountyClaims.tsx +++ b/src/components/bounty/BountyClaims.tsx @@ -56,16 +56,6 @@ export default function BountyClaims({ bountyId }: { bountyId: string }) { } ); - const { data: bounty } = trpc.bounty.useQuery( - { - id: Number(bountyId), - chainId: chain.id, - }, - { - enabled: !!bountyId, - } - ); - if (!claims) { return
No claims
; } @@ -91,7 +81,6 @@ export default function BountyClaims({ bountyId }: { bountyId: string }) { claim.accepted); @@ -50,7 +48,7 @@ export default function ClaimList({
- {isMultiplayer &&

other claims

} + {votingClaim &&

other claims

} {claims .filter((claim) => claim.id !== votingClaim?.id) .map((claim) => ( diff --git a/src/components/bounty/Voting.tsx b/src/components/bounty/Voting.tsx index 5df8ccf..5d57e5f 100644 --- a/src/components/bounty/Voting.tsx +++ b/src/components/bounty/Voting.tsx @@ -1,4 +1,4 @@ -import { PieChart } from '@mui/x-charts/PieChart'; +import { PieChart } from 'react-minimal-pie-chart'; import React from 'react'; import { toast } from 'react-toastify'; import { formatEther } from 'viem'; @@ -8,6 +8,18 @@ import { bountyVotingTracker } from '@/utils/web3'; import { useAccount, useSwitchChain, useWriteContract } from 'wagmi'; import abi from '@/constant/abi/abi'; import { useMutation, useQuery } from '@tanstack/react-query'; +import { trpc } from '@/trpc/client'; + +function formatDeadline(date: Date) { + return date.toLocaleString('en-US', { + month: 'numeric', + day: 'numeric', + year: 'numeric', + hour: 'numeric', + minute: 'numeric', + hour12: true, + }); +} export default function Voting({ bountyId, @@ -26,6 +38,23 @@ export default function Voting({ queryFn: () => bountyVotingTracker({ id: bountyId, chainName: chain.slug }), }); + const bounty = trpc.bounty.useQuery({ + id: Number(bountyId), + chainId: chain.id, + }); + + const bountyContibutors = trpc.participations.useQuery({ + chainId: chain.id, + bountyId: Number(bountyId), + }); + + const isBountyContributor = bountyContibutors.data?.some( + (contributor) => + contributor.user_address.toLowerCase() == account.address?.toLowerCase() + ); + const isVotingInProgress = + parseInt(voting.data?.deadline ?? '0') * 1000 > Date.now(); + const voteMutation = useMutation({ mutationFn: async ({ vote, @@ -84,33 +113,66 @@ export default function Voting({ }, }); - const isVotingInProgress = - parseInt(voting.data?.deadline ?? '0') * 1000 > Date.now(); - return (
{voting.data ? ( - <> +
+
+ {isAcceptedBounty ? 'Voting closed' : 'Voting in progress'} +
{ + return !dataEntry.value ? ( + '' + ) : ( + + + {Math.round(dataEntry.percentage)}% + + + {dataEntry.title} + + + ); + }} + labelStyle={() => ({ + fontSize: '3px', + fontWeight: 'bold', + })} + animate />
@@ -125,68 +187,71 @@ export default function Voting({ }`}
- {isVotingInProgress ? ( - <> - - - - ) : ( - !isAcceptedBounty && ( - - ) - )} + {isVotingInProgress + ? isBountyContributor && ( +
+
what is your vote?
+
+ + +
+
+ ) + : !isAcceptedBounty && ( + + )}
{!isAcceptedBounty && (
Deadline:{' '} - {new Date( - parseInt(voting.data.deadline ?? '0') * 1000 - ).toLocaleString()} + {formatDeadline( + new Date(parseInt(voting.data.deadline ?? '0') * 1000) + )}
)} - +
) : ( -
Loading voting data...
+
Loading voting data...
)}
);