Skip to content

Commit

Permalink
Merge pull request #179 from adrianvrj/feat-vote
Browse files Browse the repository at this point in the history
[feat] added voting logic
  • Loading branch information
EmmanuelAR authored Nov 3, 2024
2 parents 3d63c86 + 27b8a48 commit 973a584
Show file tree
Hide file tree
Showing 10 changed files with 183 additions and 75 deletions.
21 changes: 0 additions & 21 deletions frontend/gostarkme-web/app/app/fund/[fundId]/page.tsx

This file was deleted.

26 changes: 26 additions & 0 deletions frontend/gostarkme-web/app/app/fund/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'use client';

import hex2ascii from "@/app/utils";
import Fund from "@/components/modules/Fund/Fund";
import Bounded from "@/components/ui/Bounded";
import Divider from "@/components/ui/Divider";
import { FUND_MANAGER_ADDR } from "@/constants";
import { fundAbi } from "@/contracts/abis/fund";
import { fundManager } from "@/contracts/abis/fundManager";
import { walletStarknetkitLatestAtom } from "@/state/connectedWallet";
import { useAtomValue } from "jotai";
import { useEffect, useState } from "react";
import { Contract } from "starknet";

const FundDetailsPage = () => {

return (
<>
<Bounded className="px-60 text-lg">
<Fund></Fund>
</Bounded>
</>
);
};

export default FundDetailsPage;
36 changes: 21 additions & 15 deletions frontend/gostarkme-web/app/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ import FundCards from "@/components/dashboard/fundCard";
import Footer from "@/components/ui/Footer";
import Navbar from "@/components/ui/Navbar";
import { FUND_MANAGER_ADDR } from "@/constants";
import { fund } from "@/contracts/abis/fund";
import { fundAbi } from "@/contracts/abis/fund";
import { fundManager } from "@/contracts/abis/fundManager";
import { walletStarknetkitLatestAtom } from "@/state/connectedWallet";
import { useAtomValue } from "jotai";
import { useAtom, useAtomValue, useSetAtom } from "jotai";
import React, { useEffect, useState } from "react";
import { byteArray, Contract, InvokeFunctionResponse } from "starknet";
import { navItems } from "@/constants";
import hex2ascii from "../utils";

const Dashboard = () => {

Expand All @@ -19,13 +20,7 @@ const Dashboard = () => {

const [funds, setFunds] = useState<any>([]);

function hex2ascii(hexx: string) {
var hex = hexx.toString();//force conversion
var str = '';
for (var i = 0; i < hex.length; i += 2)
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
return str;
}
const [loading, setLoading] = useState(true);

async function getFunds() {
const id = await fundManagerContract.getCurrentId();
Expand All @@ -34,20 +29,23 @@ const Dashboard = () => {
// GET FUND ADDRESS
let fundaddr = await fundManagerContract.getFund(i);
fundaddr = "0x" + fundaddr.toString(16);
const fundContract = new Contract(fund, fundaddr, wallet?.account);
const fundContract = new Contract(fundAbi, fundaddr, wallet?.account);
// GET FUND NAME
let name = await fundContract.getName();
name = hex2ascii(name.toString(16));
// GET FUND DESCRIPTION
let desc = await fundContract.getReason();
// GET FUND ID
let fund_id = await fundContract.getId();
fundings.push({
type: "Project",
title: name,
description: desc,
fund_id: fund_id.toString(),
});
}
console.log(fundings);
setFunds(fundings);
setLoading(false);
}

useEffect(() => {
Expand All @@ -70,19 +68,27 @@ const Dashboard = () => {
Latest Funds
<span className="ml-2 text-yellow-400">&#x2728;</span>
</h1>
{funds.length !== 0 ? (

{loading && <div className="text-center text-gray-500">
Loading funds ...
</div>}

{funds.length !== 0 && !loading &&
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-6 md:gap-x-[138px] md:gap-y-[84px]">
{funds.map((fund: { type: string; title: string; description: string; }, index: number) => (
{funds.map((fund: { type: string; title: string; description: string; fund_id: string }, index: number) => (
<FundCards key={index} fund={fund} index={index} />
))}
</div>
) : (
}

{funds.length === 0 && !loading &&
<div className="flex justify-center items-center h-64">
<div className="text-center text-gray-500">
There is no fundings to display.
</div>
</div>
)}
}

<Footer></Footer>
</div>
);
Expand Down
11 changes: 11 additions & 0 deletions frontend/gostarkme-web/app/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default function hex2ascii(hexx: string) {
var hex = hexx.toString();//force conversion
var str = '';
for (var i = 0; i < hex.length; i += 2)
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
return str;
}

export function calculatePorcentage(qty: number, goal: number): number {
return (Number(qty) / Number(goal)) * 100;
}
55 changes: 34 additions & 21 deletions frontend/gostarkme-web/components/dashboard/fundCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,56 @@

import { StardustAnimation } from "@/animations/StardustAnimation";
import useComponentSize from "@/hooks/useComponentSize.hook";
import { clickedFundState } from "@/state/nFunds";
import { useSetAtom } from "jotai";
import Link from "next/link";
import React from "react";

interface FundCardProps {
fund: {
type: string;
title: string;
description: string;
fund_id: string
};
index: number;
}

const FundCards = ({ fund, index }: FundCardProps) => {
const [ref, width, height] = useComponentSize();

const setClickedFund = useSetAtom(clickedFundState);

function handleNav() {
setClickedFund(Number(fund.fund_id));
}

return (
<div className="relative" ref={ref}>
<div
key={index}
className="min-w-[30rem] bg-gray-950 shadow-[0px_4px_4px_0px_#00000040] text-white rounded-[10px] py-[32px] md:py-[48px] md:px-[48px] lg:py-[64px] lg:px-[72px] gap-8 md:gap-10 lg:gap-14 flex flex-col items-start justify-between"
>
<div className="flex flex-col items-start justify-between gap-4 md:gap-6">
<p className=" text-sm md:text-base lg:text-lg text-white font-light leading-[22px] md:leading-[25px] lg:leading-[27.6px]">
{fund.type} {fund.type === "Project" ? <span>&#x1f680;</span> : <span>&#x1FAC0;</span>}
</p>
<h1 className="text-lg md:text-lg lg:text-[30px] font-bold">
{fund.title}
</h1>
</div>
<div>
{fund.description !== " " ? (
<p className="text-lg md:text-lg lg:text-[25px] text-white">{fund.description}</p>
) :
(
<p className="text-lg md:text-lg lg:text-[25px] text-white">No description provided</p>
)}
<Link onClick={handleNav} href={"/app/fund"}>
<div
key={index}
className="min-w-[30rem] bg-gray-950 shadow-[0px_4px_4px_0px_#00000040] text-white rounded-[10px] py-[32px] md:py-[48px] md:px-[48px] lg:py-[64px] lg:px-[72px] gap-8 md:gap-10 lg:gap-14 flex flex-col items-start justify-between"
>
<div className="flex flex-col items-start justify-between gap-4 md:gap-6">
<p className=" text-sm md:text-base lg:text-lg text-white font-light leading-[22px] md:leading-[25px] lg:leading-[27.6px]">
{fund.type} {fund.type === "Project" ? <span>&#x1f680;</span> : <span>&#x1FAC0;</span>}
</p>
<h1 className="text-lg md:text-lg lg:text-[30px] font-bold">
{fund.title}
</h1>
</div>
<div>
{fund.description !== " " ? (
<p className="text-lg md:text-lg lg:text-[25px] text-white">{fund.description}</p>
) :
(
<p className="text-lg md:text-lg lg:text-[25px] text-white">No description provided</p>
)}
</div>
<StardustAnimation height={height} width={width} />
</div>
<StardustAnimation height={height} width={width} />
</div>
</Link>
</div>
);
};
Expand Down
64 changes: 54 additions & 10 deletions frontend/gostarkme-web/components/modules/Fund/Fund.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,65 @@
import FundDonate from "./FundDonate";
import starknetlogo from "@/public/icons/starklogo.png";
import { FundVote } from "./FundVote";
import { useState } from "react";
import { useEffect, useState } from "react";
import { FUND_MANAGER_ADDR, upVotesNeeded } from "@/constants";
import Divider from "@/components/ui/Divider";
import hex2ascii from "@/app/utils";
import { fundAbi } from "@/contracts/abis/fund";
import { fundManager } from "@/contracts/abis/fundManager";
import { walletStarknetkitLatestAtom } from "@/state/connectedWallet";
import { useAtomValue } from "jotai";
import { Contract } from "starknet";
import { clickedFundState } from "@/state/nFunds";

interface FundProps {
message: string;
}
const Fund = () => {

const Fund = ({ message }: FundProps) => {
const [type, setType] = useState<string>("donate");
const wallet = useAtomValue(walletStarknetkitLatestAtom);

const [fundManagerContract, _setFundManagerContract] = useState<Contract>(new Contract(fundManager, FUND_MANAGER_ADDR, wallet?.account));

const [fund, setFund] = useState<any>({});

const clickedFund = useAtomValue(clickedFundState);

async function getDetails() {
let addr = await fundManagerContract.getFund(clickedFund);
addr = "0x" + addr.toString(16);
const fundContract = new Contract(fundAbi, addr, wallet?.account);

// GET FUND NAME
let name = await fundContract.getName();
name = hex2ascii(name.toString(16));
// GET FUND DESCRIPTION
let desc = await fundContract.getReason();
if (desc == " ") {
desc = "No description provided";
}
let state = await fundContract.getState();

let currentBalance = await fundContract.getCurrentGoalState();

let goal = await fundContract.getGoal();

let upVotes = await fundContract.getUpVotes();

setFund({ name: name, desc: desc, state: state, currentBalance: currentBalance, goal: goal, upVotes: upVotes, addr: addr });
}

useEffect(() => {
getDetails();
}, []);

return (
<section>
<p className="mb-40">{message}</p>

{type === "donate" ? <FundDonate icon={starknetlogo} /> : <FundVote />}
{/* For Vote, there is no logo, but when you already have it, just pass it through the prop */}
<h2 className="font-bold">{fund.name}</h2>
<Divider />
<p className="mb-40">{fund.desc}</p>
{ Number(fund.state) === 0 && <p>Fund is currently innactive.</p>}
{ Number(fund.state) === 1 && <FundVote upVotes={fund.upVotes} upVotesNeeded={upVotesNeeded} addr={fund.addr}/>}
{ Number(fund.state) === 2 && <FundDonate icon={starknetlogo} />}
{ Number(fund.state) === 3 && <p>Fund is currently closed.</p>}
{ Number(fund.state) === 4 && <p>Fund was already withdrawed.</p>}
</section>
);
};
Expand Down
36 changes: 29 additions & 7 deletions frontend/gostarkme-web/components/modules/Fund/FundVote.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,43 @@
import { calculatePorcentage } from "@/app/utils";
import { Button } from "@/components/ui/Button";
import { LinkButton } from "@/components/ui/LinkButton";
import ProgressBar from "@/components/ui/ProgressBar";
import Image, { StaticImageData } from "next/image";
import { fundAbi } from "@/contracts/abis/fund";
import { walletStarknetkitLatestAtom } from "@/state/connectedWallet";
import { useAtomValue } from "jotai";
import { useState } from "react";
import { Contract, wallet, InvokeFunctionResponse } from "starknet";

interface FundVoteProps {
icon?: StaticImageData;
upVotes: number,
upVotesNeeded: number,
addr: string,
}

export const FundVote = ({ icon }: FundVoteProps) => {
export const FundVote = ({ upVotes, upVotesNeeded, addr }: FundVoteProps) => {

const wallet = useAtomValue(walletStarknetkitLatestAtom);

const progress = calculatePorcentage(upVotes, upVotesNeeded);

function vote() {
const fundContract = new Contract(fundAbi, addr, wallet?.account);
const myCall = fundContract.populate("receiveVote", []);
wallet?.account?.execute(myCall)
.then(async (resp: InvokeFunctionResponse) => {
console.log("increaseBalance txH =", resp.transaction_hash);
})
.catch((e: any) => { console.log("error increase balance =", e) });
}

return (
<div className="flex flex-col">
<ProgressBar progress={34} />
<ProgressBar progress={progress} />
<div className="flex justify-center my-2">
<p className="text-center mx-2">200 / 300 </p>
{/* <Image src={icon || ""} alt="icon" width={24} height={24} /> */}
<p className="text-center mx-2">{upVotes.toString()} / {upVotesNeeded.toString()} </p>
<p>&#127775;</p>
</div>
<LinkButton label="Vote" href="/" />
<Button label="Vote" onClick={vote}></Button>
</div>
);
};
2 changes: 2 additions & 0 deletions frontend/gostarkme-web/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,5 @@ export const navItems = [
{ label: 'My Profile', href: '/app/myprofile' },
{ label: 'My funds', href: '/app/myfunds' }
];

export const upVotesNeeded = 100;
2 changes: 1 addition & 1 deletion frontend/gostarkme-web/contracts/abis/fund.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const fund = [
export const fundAbi = [
{
"type": "impl",
"name": "FundImpl",
Expand Down
5 changes: 5 additions & 0 deletions frontend/gostarkme-web/state/nFunds.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { atomWithReset } from "jotai/utils"

export const clickedFundState = atomWithReset<
Number | null | undefined
>(undefined)

0 comments on commit 973a584

Please sign in to comment.