From 76200cec56b733b5286793d9c33720009d95ab16 Mon Sep 17 00:00:00 2001 From: M-RB3 Date: Mon, 27 May 2024 18:18:28 +0400 Subject: [PATCH 1/4] all project cleanup --- src/components/Card/styles.ts | 1 - .../Projects/components/AllProjects/AllProjects.tsx | 11 ----------- 2 files changed, 12 deletions(-) diff --git a/src/components/Card/styles.ts b/src/components/Card/styles.ts index 9e41b00f..8b542763 100644 --- a/src/components/Card/styles.ts +++ b/src/components/Card/styles.ts @@ -7,7 +7,6 @@ export const CardContainer = styled.div` min-height: 405px; width: 100%; height: 100%; - /* overflow: hidden; */ border-radius: 12px; background: white; box-shadow: 0px -2px 0px #dbdbdb inset; diff --git a/src/pages/Projects/components/AllProjects/AllProjects.tsx b/src/pages/Projects/components/AllProjects/AllProjects.tsx index adcdd1be..1602f7f2 100644 --- a/src/pages/Projects/components/AllProjects/AllProjects.tsx +++ b/src/pages/Projects/components/AllProjects/AllProjects.tsx @@ -1,5 +1,4 @@ import { Social, createDebounce, useEffect, useState } from "alem"; -import DonateSDK from "@app/SDK/donate"; import Card from "@app/components/Card/Card"; import FilterDropdown from "@app/components/Inputs/FilterDropdown/FilterDropdown"; import useModals from "@app/hooks/useModals"; @@ -7,7 +6,6 @@ import getProjects from "@app/services/getProjects"; import { Project } from "@app/types"; import getTagsFromSocialProfileData from "@app/utils/getTagsFromSocialProfileData"; import getTeamMembersFromSocialProfileData from "@app/utils/getTeamMembersFromSocialProfileData"; -import yoctosToUsd from "@app/utils/yoctosToUsd"; import ListSection from "../ListSection"; import SearchBar from "../SearchBar/SearchBar"; import { ProjectsContainer, FilterWrapper, Title, Container, Header } from "./styles"; @@ -17,8 +15,6 @@ const AllProjects = () => { const projectsData = getProjects(); const Modals = useModals(); - const [totalDonation, setTotalDonation] = useState(0); - const [totalDonated, setTotalDonated] = useState("0"); const [projects, setProjects] = useState([]); const [filteredProjects, setFilteredProjects] = useState([]); const [sort, setSort] = useState("Sort"); @@ -36,13 +32,6 @@ const AllProjects = () => { return ""; } - const donateConfig: any = DonateSDK.getConfig(); - if (donateConfig && !totalDonated && !totalDonation) { - const lastDonationAmount = yoctosToUsd(donateConfig.net_donations_amount); - setTotalDonated(lastDonationAmount); - setTotalDonation(donateConfig.total_donations_count); - } - const handleSortChange = (sortType: string) => { setSort(sortType); const projects = [...filteredProjects]; From 934dfed97fd2dd2fd2666c4606dc0b12fa958c58 Mon Sep 17 00:00:00 2001 From: M-RB3 Date: Thu, 30 May 2024 14:30:26 +0400 Subject: [PATCH 2/4] finish new payout processing --- src/components/Inputs/Text/Text.tsx | 6 +- src/modals/ModalDonation/Banners/Alert.tsx | 4 +- src/pages/Pot/components/Header/Header.tsx | 14 +- .../components/PayoutsModal/PayoutsModal.tsx | 147 ++++++++++++++++++ .../Pot/components/PayoutsModal/styles.ts | 58 +++++++ src/types.ts | 2 +- 6 files changed, 219 insertions(+), 12 deletions(-) create mode 100644 src/pages/Pot/components/PayoutsModal/PayoutsModal.tsx create mode 100644 src/pages/Pot/components/PayoutsModal/styles.ts diff --git a/src/components/Inputs/Text/Text.tsx b/src/components/Inputs/Text/Text.tsx index 5a63ecdc..10774e41 100644 --- a/src/components/Inputs/Text/Text.tsx +++ b/src/components/Inputs/Text/Text.tsx @@ -10,6 +10,7 @@ type Props = { onBlur?: (value: any) => void; validate?: () => void; error?: string; + defaultValue?: string; preInputChildren?: any; postInputChildren?: any; disabled?: boolean; @@ -22,7 +23,7 @@ type Props = { const Text = (props: Props) => { const label = props.label ?? ""; const placeholder = props.placeholder ?? ""; - const value = props.value ?? ""; + const value = props.value; const onChange = props.onChange ?? (() => {}); const onBlur = props.onBlur ?? (() => {}); const validate = props.validate ?? (() => {}); @@ -35,8 +36,9 @@ const Text = (props: Props) => { {props.preInputChildren && props.preInputChildren} onChange(value)} onBlur={(value) => { validate(); diff --git a/src/modals/ModalDonation/Banners/Alert.tsx b/src/modals/ModalDonation/Banners/Alert.tsx index 0e384225..d047f41d 100644 --- a/src/modals/ModalDonation/Banners/Alert.tsx +++ b/src/modals/ModalDonation/Banners/Alert.tsx @@ -1,7 +1,7 @@ import { AlertBanner } from "./styles"; -const Alert = ({ error }: any) => ( - +const Alert = ({ error, style }: { error: string; style?: React.CSSProperties }) => ( +
{ const [flaggedAddresses, setFlaggedAddresses] = useState(null); const [potDetail, setPotDetail] = useState(null); const [allDonations, setAlldonations] = useState(null); + const [payoutsToProcess, setPayoutsToProcess] = useState(null); // set fund mathcing pool success const [fundDonation, setFundDonation] = useState(null); @@ -165,13 +167,7 @@ const Header = () => { const handleSetPayouts = () => { if (allDonations && flaggedAddresses !== null) { calculatePayouts(allDonations, matching_pool_balance, flaggedAddresses).then((calculatedPayouts: any) => { - const payouts = Object.entries(calculatedPayouts) - .map(([projectId, { matchingAmount }]: any) => ({ - project_id: projectId, - amount: matchingAmount, - })) - .filter((payout) => payout.amount !== "0"); - PotSDK.chefSetPayouts(potId, payouts); + setPayoutsToProcess(calculatedPayouts); }); } else { console.log("error fetching donations or flagged addresses"); @@ -293,6 +289,10 @@ const Header = () => { }} /> )} + {/* Admin process Payout */} + {payoutsToProcess && ( + + )} ); }; diff --git a/src/pages/Pot/components/PayoutsModal/PayoutsModal.tsx b/src/pages/Pot/components/PayoutsModal/PayoutsModal.tsx new file mode 100644 index 00000000..259abef7 --- /dev/null +++ b/src/pages/Pot/components/PayoutsModal/PayoutsModal.tsx @@ -0,0 +1,147 @@ +import { Big, useMemo, useState } from "alem"; +import PotSDK from "@app/SDK/pot"; +import Button from "@app/components/Button"; +import Text from "@app/components/Inputs/Text/Text"; +import Alert from "@app/modals/ModalDonation/Banners/Alert"; +import ModalOverlay from "@app/modals/ModalOverlay"; +import { CalculatedPayout } from "@app/types"; +import _address from "@app/utils/_address"; +import { ButtonWrapper, Container, PayoutItem, PayoutsView, Title, Total, ExitIcon } from "./styles"; + +const PayoutsModal = ({ + originalPayouts, + setPayoutsToProcess, + potId, +}: { + originalPayouts: Record; + setPayoutsToProcess: (payouts: null) => void; + potId: string; +}) => { + const [payouts, setPayouts] = useState(originalPayouts); + const [error, setError] = useState(""); + + const calcNear = (amount: string) => Big(amount).div(Big(10).pow(24)).toNumber().toFixed(2); + const calcYoctos = (amount: string) => new Big(amount).mul(new Big(10).pow(24)).toString(); + + const sumAmount = (payouts: any) => + payouts.reduce( + (acc: any, payout: any) => + Big(acc) + .plus(new Big(payout.matchingAmount || payout.amount)) + .toString(), + 0, + ); + + const originalTotalAmountYoctos = useMemo(() => sumAmount(Object.values(originalPayouts)), [originalPayouts]); + + const originalTotalAmount = calcNear(originalTotalAmountYoctos); + + const [payoutsList, totalAmount, remainder] = useMemo(() => { + const payoutsArr = Object.entries(payouts).map(([projectId, { matchingAmount }]: any) => ({ + project_id: projectId, + amount: calcNear(matchingAmount), + })); + + const totalAmountYoctos = sumAmount(Object.values(payouts)); + + const totalAmount = calcNear(totalAmountYoctos); + + const remainderYoctos = Big(originalTotalAmountYoctos).minus(Big(totalAmountYoctos)).toNumber(); + if (remainderYoctos < 0) setError("The payout's total can not be greater than the original amount."); + else setError(""); + const remainder = calcNear(remainderYoctos.toString()); + + return [payoutsArr, totalAmount, remainder, remainderYoctos]; + }, [payouts]); + + const handleChange = (projectId: string, amount: string) => { + setPayouts({ + ...payouts, + [projectId]: { + ...payouts[projectId], + matchingAmount: calcYoctos(amount), + }, + }); + }; + + const handlePayout = () => { + let payoutsArr = Object.entries(payouts) + .map(([projectId, { matchingAmount }]: any) => ({ + project_id: projectId, + amount: matchingAmount, + })) + .filter((payout) => payout.amount !== "0"); + let yoctos = sumAmount(payoutsArr); + + const remainder = Big(originalTotalAmountYoctos).minus(Big(yoctos)); + + payoutsArr[0].amount = Big(payoutsArr[0].amount).plus(remainder).toString(); + + yoctos = sumAmount(payoutsArr); + + console.log("check if the original amount equal to the new one", Big(yoctos).cmp(Big(originalTotalAmountYoctos))); + + PotSDK.chefSetPayouts(potId, payoutsArr); + }; + + return ( + + + + setPayoutsToProcess(null)} + className="close-icon" + viewBox="0 0 14 14" + fill="none" + xmlns="http://www.w3.org/2000/svg" + > + + + + {potId} + +
Total amount
+
+ {totalAmount} / {originalTotalAmount} N +
+ + +
Remainder
+
{remainder} N
+
+ {error && ( + + )} + + + + + {payoutsList.map(({ project_id, amount }) => ( + +
{_address(project_id, 20)}
+ handleChange(project_id, amount)} + defaultValue={amount} + /> +
+ ))} +
+ + + ); +}; + +export default PayoutsModal; diff --git a/src/pages/Pot/components/PayoutsModal/styles.ts b/src/pages/Pot/components/PayoutsModal/styles.ts new file mode 100644 index 00000000..8d89a805 --- /dev/null +++ b/src/pages/Pot/components/PayoutsModal/styles.ts @@ -0,0 +1,58 @@ +import styled from "styled-components"; + +export const Container = styled.div` + display: flex; + flex-direction: column; + gap: 1rem; + position: relative; + height: 80vh; +`; + +export const Title = styled.div` + font-size: 18px; + font-weight: 500; + overflow-wrap: break-word; +`; + +export const PayoutsView = styled.div` + display: flex; + gap: 0.5rem; + flex-direction: column; + max-height: 100%; + overflow-y: scroll; +`; + +export const PayoutItem = styled.div` + display: flex; + gap: 1rem; + align-items: center; + justify-content: space-between; + .id { + width: 172px; + } +`; + +export const Total = styled.div` + display: flex; + gap: 0.5rem; + .original { + color: #656565; + } + span { + font-weight: 500; + color: var(--Primary-600); + } +`; +export const ButtonWrapper = styled.div` + display: flex; + gap: 1rem; +`; + +export const ExitIcon = styled.div` + display: flex; + justify-content: flex-end; + svg { + cursor: pointer; + width: 18px; + } +`; diff --git a/src/types.ts b/src/types.ts index 33286515..e0d58f91 100644 --- a/src/types.ts +++ b/src/types.ts @@ -132,7 +132,7 @@ export type Payout = { export type CalculatedPayout = { project_id: string; - amount: number; + matchingAmount: string; donorCount: number; totalAmount: string; }; From f6369ae68b1bbcb3a19352ff1146003c5101fc83 Mon Sep 17 00:00:00 2001 From: M-RB3 Date: Thu, 30 May 2024 14:45:24 +0400 Subject: [PATCH 3/4] reduce the maximum donations to fetch per req to 450 --- src/services/getPotData.ts | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/services/getPotData.ts b/src/services/getPotData.ts index 0e25439a..c1a3463d 100644 --- a/src/services/getPotData.ts +++ b/src/services/getPotData.ts @@ -1,6 +1,6 @@ import { Storage } from "alem"; import PotSDK from "@app/SDK/pot"; -import { FlaggedAddress, Payout, PotApplication, PotDetail, PotDonation, CalculatedPayout } from "@app/types"; +import { FlaggedAddress, Payout, PotApplication, PotDetail, PotDonation } from "@app/types"; import calculatePayouts from "@app/utils/calculatePayouts"; // type UpdateState = (newValues: Partial) => void; @@ -51,26 +51,26 @@ function isEqual(obj1: any, obj2: any) { return true; } -function isObjectEqual(obj1: CalculatedPayout, obj2: CalculatedPayout): boolean { - return obj1.project_id === obj2.project_id && obj1.amount === obj2.amount; -} +// function isObjectEqual(obj1: CalculatedPayout, obj2: CalculatedPayout): boolean { +// return obj1.project_id === obj2.project_id && obj1.amount === obj2.amount; +// } -function areListsEqual(list1: CalculatedPayout[], list2: CalculatedPayout[]): boolean { - // Check if both lists have the same length - if (list1.length !== list2.length) { - return false; - } +// function areListsEqual(list1: CalculatedPayout[], list2: CalculatedPayout[]): boolean { +// // Check if both lists have the same length +// if (list1.length !== list2.length) { +// return false; +// } - // Check if all objects in the lists are equal - for (let i = 0; i < list1.length; i++) { - if (!isObjectEqual(list1[i], list2[i])) { - return false; - } - } +// // Check if all objects in the lists are equal +// for (let i = 0; i < list1.length; i++) { +// if (!isObjectEqual(list1[i], list2[i])) { +// return false; +// } +// } - // If no differences are found, return true - return true; -} +// // If no differences are found, return true +// return true; +// } const getPotData = (potId: string, property: string) => Storage.get(`${potId}-${property}`); @@ -200,7 +200,7 @@ export const getPayout = ({ // get matched donations export const asyncGetPublicDonations = (potDetail: PotDetail, potId: string) => { - const limit = 480; // number of donations to fetch per req + const limit = 450; // number of donations to fetch per req const donationsCount = potDetail.public_donations_count; const paginations = [...Array(Math.ceil(donationsCount / limit)).keys()]; From f756fb008992f49c43e3c560045bf429fc4ac451 Mon Sep 17 00:00:00 2001 From: M-RB3 Date: Thu, 30 May 2024 16:30:06 +0400 Subject: [PATCH 4/4] fix pots loading --- src/pages/PotsHome/PotsHome.tsx | 58 +++++++++++++++++---------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/pages/PotsHome/PotsHome.tsx b/src/pages/PotsHome/PotsHome.tsx index 9987f39c..c409168e 100644 --- a/src/pages/PotsHome/PotsHome.tsx +++ b/src/pages/PotsHome/PotsHome.tsx @@ -18,23 +18,18 @@ const PotsHome = () => { // Get all pots config if (!pots) { PotFactorySDK.asyncGetPots().then((pots: Pot[]) => { - pots.forEach(({ id }) => { - PotSDK.asyncGetConfig(id).then((potConfig: PotDetail) => - setPots((prevPot: any) => ({ - ...prevPot, - [id]: { ...potConfig, id }, - })), - ); + const configsPromises = pots.map(({ id }) => PotSDK.asyncGetConfig(id)); + Promise.all(configsPromises).then((configs) => { + const potDetails = configs.map((config: PotDetail, idx: number) => ({ + ...config, + id: pots[idx].id, + })); + setPots(potDetails); }); }); } const compareFunction = (pots: PotDetail[]) => { - // sort pots(round status) - const listOfPots: any = {}; - - const states = Object.keys(potsSort); - pots.forEach((pot) => { Object.keys(potsSort).some((type) => { const { check, items } = potsSort[type]; @@ -139,22 +134,29 @@ const PotsHome = () => { {filteredRounds.length === 0 &&
No pots
} - } - maxCols={3} - responsive={[ - { - breakpoint: 1114, - items: 2, - }, - { - breakpoint: 768, - items: 1, - }, - ]} - /> - + {pots === null ? ( +
+
+
+ ) : filteredRounds.length > 0 ? ( + } + maxCols={3} + responsive={[ + { + breakpoint: 1114, + items: 2, + }, + { + breakpoint: 768, + items: 1, + }, + ]} + /> + ) : ( +
No pots
+ )} Completed Pots <span>{completedRounds.length}</span>