From 951548f151c921cd8fcc617da7a1060d3f7d5dd0 Mon Sep 17 00:00:00 2001 From: M-RB3 Date: Wed, 22 May 2024 09:47:42 +0400 Subject: [PATCH 01/18] improving the donation modal & projects loading Co-authored-by: Wenderson Pires --- src/Main.tsx | 6 +- src/SDK/pot.js | 4 +- src/components/Card/Card.tsx | 9 +- src/components/PotCard/styles.ts | 2 +- src/hooks/useModals.tsx | 4 +- .../ModalDonation/AmountInput/AmountInput.tsx | 2 +- .../ModalDonation/ConfirmPot/ConfirmPot.tsx | 8 +- src/modals/ModalDonation/index.tsx | 1 - src/modals/ModalSuccess/ModalSuccess.tsx | 4 +- src/pages/Pot/NavPages/Projects/Projects.tsx | 187 +++++----- src/pages/Pot/NavPages/Projects/styles.ts | 13 + src/pages/Pot/components/Header/Header.tsx | 2 +- .../PoolAllocationTable.tsx | 111 +++++- .../PoolAllocationTable/Table/Table.tsx | 1 - .../Table/TableSkeleton.tsx | 29 ++ .../PoolAllocationTable/Table/styles.ts | 71 ++++ src/pages/Profile/components/Tabs.tsx | 6 +- src/services/getPotData.ts | 337 ++++++++++++++++++ src/types.ts | 51 ++- src/utils/calculatePayouts.ts | 7 +- 20 files changed, 701 insertions(+), 154 deletions(-) create mode 100644 src/pages/Pot/components/PoolAllocationTable/Table/TableSkeleton.tsx create mode 100644 src/services/getPotData.ts diff --git a/src/Main.tsx b/src/Main.tsx index 0e9b6428..4d2aaa67 100644 --- a/src/Main.tsx +++ b/src/Main.tsx @@ -1,9 +1,12 @@ -import { ModulesProvider } from "alem"; +import { ModulesProvider, useParams } from "alem"; import Banner from "./components/Banner/Banner"; import Nav from "./components/Nav/Nav"; +import ModalSuccess from "./modals/ModalSuccess/ModalSuccess"; import Routes from "./routes/Routes"; const Main = () => { + const { transactionHashes } = useParams(); + return ( <> @@ -12,6 +15,7 @@ const Main = () => { + {transactionHashes && } ); }; diff --git a/src/SDK/pot.js b/src/SDK/pot.js index 5ceb71b9..5a624ce8 100644 --- a/src/SDK/pot.js +++ b/src/SDK/pot.js @@ -29,8 +29,8 @@ const PotSDK = { // TODO: paginate return Near.view(potId, "get_matching_pool_donations", {}); }, - asyncGetMatchingPoolDonations: (potId) => { - return Near.asyncView(potId, "get_matching_pool_donations", {}); + asyncGetMatchingPoolDonations: (potId, args) => { + return Near.asyncView(potId, "get_matching_pool_donations", ...(args || {})); }, getPublicRoundDonations: (potId, args) => { return Near.view(potId, "get_public_round_donations", { diff --git a/src/components/Card/Card.tsx b/src/components/Card/Card.tsx index 355a7da3..04059d9c 100644 --- a/src/components/Card/Card.tsx +++ b/src/components/Card/Card.tsx @@ -32,7 +32,6 @@ import { } from "./styles"; const Card = (props: any) => { - const [ready, isReady] = useState(false); const { payoutDetails, allowDonate: _allowDonate } = props; const { potId } = useParams(); @@ -100,13 +99,7 @@ const Card = (props: any) => { const tags = getTagsFromSocialProfileData(profile); - useEffect(() => { - if (profile !== null && !ready) { - isReady(true); - } - }, [profile, donationsForProject, tags]); - - if (!ready) return ; + if (profile === null && totalAmountNear === null) return ; return ( <> diff --git a/src/components/PotCard/styles.ts b/src/components/PotCard/styles.ts index 33989401..93855712 100644 --- a/src/components/PotCard/styles.ts +++ b/src/components/PotCard/styles.ts @@ -1,6 +1,6 @@ import styled from "styled-components"; -export const Card = styled.a` +export const Card = styled("Link")` display: flex; flex-direction: column; min-width: 320px; diff --git a/src/hooks/useModals.tsx b/src/hooks/useModals.tsx index 8081051a..4c1b8126 100644 --- a/src/hooks/useModals.tsx +++ b/src/hooks/useModals.tsx @@ -1,4 +1,3 @@ -import { useParams } from "alem"; import DonationModalProvider from "@app/contexts/DonationModalProvider"; import { useDonationModal } from "@app/hooks/useDonationModal"; import ModalDonation from "../modals/ModalDonation"; @@ -12,12 +11,11 @@ import ModalSuccess from "../modals/ModalSuccess/ModalSuccess"; const useModals = () => { DonationModalProvider(); - const { transactionHashes: _transactionHashes } = useParams(); const { successfulDonation, donationModalProps } = useDonationModal(); return () => ( <> - {(successfulDonation || _transactionHashes) && } + {successfulDonation && } {donationModalProps && } ); diff --git a/src/modals/ModalDonation/AmountInput/AmountInput.tsx b/src/modals/ModalDonation/AmountInput/AmountInput.tsx index a93f69ba..a49add35 100644 --- a/src/modals/ModalDonation/AmountInput/AmountInput.tsx +++ b/src/modals/ModalDonation/AmountInput/AmountInput.tsx @@ -49,7 +49,7 @@ const AmountInput = (props: any) => { ); const { value, amount, HandleAmoutChange, donationType, denominationOptions, selectedDenomination } = props; - const _value = value || amount || 0; + const _value = value || amount || ""; return ( diff --git a/src/modals/ModalDonation/ConfirmPot/ConfirmPot.tsx b/src/modals/ModalDonation/ConfirmPot/ConfirmPot.tsx index d4253fa4..b666aac5 100644 --- a/src/modals/ModalDonation/ConfirmPot/ConfirmPot.tsx +++ b/src/modals/ModalDonation/ConfirmPot/ConfirmPot.tsx @@ -25,7 +25,7 @@ const ConfirmPot = ({ bypassChefFee, updateState, potDetail, - potId, + selectedRound, referrerId, accountId, amount, @@ -62,13 +62,13 @@ const ConfirmPot = ({ const pollIntervalMs = 1000; // const totalPollTimeMs = 60000; // consider adding in to make sure interval doesn't run indefinitely const pollId = setInterval(() => { - PotSDK.asyncGetDonationsForDonor(potId, accountId) + PotSDK.asyncGetDonationsForDonor(selectedRound, accountId) .then((alldonations: any) => { const donations: Record = {}; for (const donation of alldonations) { const { project_id, donated_at_ms, donated_at } = donation; if (projectIds.includes(project_id) && (donated_at_ms || donated_at) > afterTs) { - donations[project_id] = { ...donation, potId }; + donations[project_id] = { ...donation, potId: selectedRound }; } } if (Object.keys(donations).length === projectIds.length) { @@ -128,7 +128,7 @@ const ConfirmPot = ({ if (amount) { transactions.push({ - contractName: potId, + contractName: selectedRound, methodName: "donate", args: { referrer_id: referrerId, diff --git a/src/modals/ModalDonation/index.tsx b/src/modals/ModalDonation/index.tsx index cf515a12..f8f84c42 100644 --- a/src/modals/ModalDonation/index.tsx +++ b/src/modals/ModalDonation/index.tsx @@ -270,7 +270,6 @@ const ModalDonation = () => { {...donationModalProps} {...state} accountId={accountId} - potId={potId} referrerId={referrerId} updateState={State.update} ftBalance={ftBalance} diff --git a/src/modals/ModalSuccess/ModalSuccess.tsx b/src/modals/ModalSuccess/ModalSuccess.tsx index c284c79f..4ba23fce 100644 --- a/src/modals/ModalSuccess/ModalSuccess.tsx +++ b/src/modals/ModalSuccess/ModalSuccess.tsx @@ -48,7 +48,7 @@ const ModalSuccess = () => { }); const onClose = () => { - _setSuccessfulDonation(null); + if (_setSuccessfulDonation) _setSuccessfulDonation(null); const location = getLocation(); delete params.transactionHashes; @@ -135,7 +135,7 @@ const ModalSuccess = () => { : ""; if (recipientId) { - if (methodName === "donate") { + if (methodName === "donate" && (result.project_id || result.recipient_id)) { setSuccessfulDonation((prev: any) => ({ ...prev, [recipientId]: { ...result, potId: receiver_id }, diff --git a/src/pages/Pot/NavPages/Projects/Projects.tsx b/src/pages/Pot/NavPages/Projects/Projects.tsx index d0a275a5..2fcb676c 100644 --- a/src/pages/Pot/NavPages/Projects/Projects.tsx +++ b/src/pages/Pot/NavPages/Projects/Projects.tsx @@ -1,40 +1,50 @@ -import { useState, Social, context, useParams, createDebounce, useEffect } from "alem"; -import PotSDK from "@app/SDK/pot"; +import { useState, Social, context, useParams, createDebounce, useEffect, Storage, promisify } from "alem"; import Card from "@app/components/Card/Card"; -import ListSection from "@app/pages/Projects/components/ListSection"; -import calculatePayouts from "@app/utils/calculatePayouts"; +import { getPotDonations } from "@app/pages/Donor/NavPages/Donations/utils"; +import { getConfig, getDonations, getFlaggedAccounts, getPayout, getPotProjects } from "@app/services/getPotData"; +import { FlaggedAddress, Payout, PotApplication, PotDetail, PotDonation } from "@app/types"; import getTagsFromSocialProfileData from "@app/utils/getTagsFromSocialProfileData"; import getTeamMembersFromSocialProfileData from "@app/utils/getTeamMembersFromSocialProfileData"; -import { Centralized, Container, SearchBar, Title } from "./styles"; +import { Centralized, Container, SearchBar, Title, ProjectsWrapper } from "./styles"; type Props = { potDetail: any; allDonations: any; }; -const Projects = (props: Props) => { - const [filteredProjects, setFilteredProjects] = useState([]); - const [projects, setProjects] = useState(null); - const [flaggedAddresses, setFlaggedAddresses] = useState(null); - const [payouts, setPayouts] = useState(null); +type ProjectsState = { + potDetail: PotDetail | null; + donations: PotDonation[] | null; + filteredProjects: PotApplication[]; + projects: PotApplication[] | null; + flaggedAddresses: FlaggedAddress[] | null; + payouts: Record | null; +}; - // get projects +const Projects = (props: Props) => { const { potId } = useParams(); - const { potDetail, allDonations } = props; - - if (!projects) { - PotSDK.asyncGetApprovedApplications(potId) - .then((projects: any) => { - setProjects(projects); - setFilteredProjects(projects); - }) - .catch((err: any) => { - console.log("error fetching projects ", err); - setProjects([]); - setFilteredProjects([]); - }); - } + const [state, setState] = useState({ + filteredProjects: [], + donations: null, + projects: null, + flaggedAddresses: null, + payouts: null, + potDetail: null, + }); + + // const [projects, setProjects] = useState(null); + // const [filteredProjects, setFilteredProjects] = useState([]); + // const [donations, setDonations] = useState(null); + // const [flaggedAddresses, setFlaggedAddresses] = useState(null); + // const [payouts, setPayouts] = useState | null>(null); + // const [potDetail, setPotDetail] = useState(null); + + const updateState = (newValue: Partial) => { + setState((prevState) => ({ ...prevState, ...newValue })); + }; + + const { filteredProjects, flaggedAddresses, payouts, projects, potDetail, donations } = state; const Loading = () => ( @@ -42,44 +52,50 @@ const Projects = (props: Props) => { ); - if (!projects) return ; - - const { public_round_start_ms, public_round_end_ms, referral_fee_public_round_basis_points } = potDetail; - - const now = Date.now(); - const publicRoundOpen = now >= public_round_start_ms && now < public_round_end_ms; + // get projects + useEffect(() => { + if (!projects) + getPotProjects({ + potId, + updateState, + isApprpved: true, + }); + if (!potDetail) + getConfig({ + potId, + updateState, + }); + }, []); - if (!flaggedAddresses) { - PotSDK.getFlaggedAccounts(potDetail, potId) - .then((data) => { - const listOfFlagged: any = []; - data.forEach((adminFlaggedAcc: any) => { - const addresses = Object.keys(adminFlaggedAcc.potFlaggedAcc); - listOfFlagged.push(...addresses); + useEffect(() => { + if (potDetail) { + if (!flaggedAddresses) + getFlaggedAccounts({ + potId, + potDetail, + type: "list", + updateState, }); - setFlaggedAddresses(listOfFlagged); - }) - .catch((err) => console.log("error getting the flagged accounts ", err)); - } + if (!donations) + getDonations({ + potId, + potDetail, + updateState, + }); + } + }, [potDetail]); useEffect(() => { - if (!payouts) { - if (allDonations.length && flaggedAddresses) - calculatePayouts(allDonations, potDetail.matching_pool_balance, flaggedAddresses) - .then((payouts: any) => { - setPayouts(payouts ?? []); - }) - .catch((err) => { - console.log("error while calculating payouts ", err); - setPayouts([]); - }); - else if (allDonations.length === 0 && flaggedAddresses?.length === 0) { - setPayouts([]); - } - } - }, [allDonations, flaggedAddresses]); + if (potDetail && flaggedAddresses && donations) + getPayout({ allDonations: donations, flaggedAddresses, potDetail, potId, updateState }); + }, [potDetail, flaggedAddresses, donations]); - if (!flaggedAddresses || !payouts) return ; + if (!projects || !potDetail) return ; + + const { public_round_start_ms, public_round_end_ms } = potDetail; + + const now = Date.now(); + const publicRoundOpen = now >= public_round_start_ms && now < public_round_end_ms; const searchByWords = (searchTerm: string) => { if (projects.length) { @@ -96,7 +112,9 @@ const Projects = (props: Props) => { ]; return fields.some((item) => (item || "").toLowerCase().includes(searchTerm.toLowerCase())); }); - setFilteredProjects(updatedProjects); + updateState({ + filteredProjects: updatedProjects, + }); } }; @@ -124,39 +142,24 @@ const Projects = (props: Props) => { /> {filteredProjects.length > 0 ? ( - { - return ( - - ); - }} - /> + + {filteredProjects.map((project: PotApplication) => ( + + ))} + ) : (
No projects
)} diff --git a/src/pages/Pot/NavPages/Projects/styles.ts b/src/pages/Pot/NavPages/Projects/styles.ts index cbc1849f..2666776b 100644 --- a/src/pages/Pot/NavPages/Projects/styles.ts +++ b/src/pages/Pot/NavPages/Projects/styles.ts @@ -49,6 +49,19 @@ export const SearchBar = styled.div` } `; +export const ProjectsWrapper = styled.div` + margin-top: 2rem; + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 1rem; + @media only screen and (max-width: 1024px) { + grid-template-columns: repeat(2, 1fr); + } + @media only screen and (max-width: 768px) { + grid-template-columns: repeat(1, 1fr); + } +`; + export const Centralized = styled.div` display: flex; justify-content: center; diff --git a/src/pages/Pot/components/Header/Header.tsx b/src/pages/Pot/components/Header/Header.tsx index 146ddd5b..4b8d2f17 100644 --- a/src/pages/Pot/components/Header/Header.tsx +++ b/src/pages/Pot/components/Header/Header.tsx @@ -88,7 +88,7 @@ const Header = ({ potDetail, allDonations }: { potDetail: PotDetail; allDonation const successVal = trxs[0].body.result.status?.SuccessValue; const result = JSON.parse(Buffer.from(successVal, "base64").toString("utf-8")); // atob not working - if (methodName === "donate" && receiver_id === potId && result) { + if (methodName === "donate" && receiver_id === potId && result.matching_pool) { setFundDonation({ ...result, potId, diff --git a/src/pages/Pot/components/PoolAllocationTable/PoolAllocationTable.tsx b/src/pages/Pot/components/PoolAllocationTable/PoolAllocationTable.tsx index f6692ef6..68f403bf 100644 --- a/src/pages/Pot/components/PoolAllocationTable/PoolAllocationTable.tsx +++ b/src/pages/Pot/components/PoolAllocationTable/PoolAllocationTable.tsx @@ -1,12 +1,17 @@ -import { useState, useParams, Big } from "alem"; +import { useState, useParams, Big, Social } from "alem"; import PotSDK from "@app/SDK/pot"; +import Image from "@app/components/mob.near/Image"; import constants from "@app/constants"; -import { PotDetail } from "@app/types"; +import { PotDetail, PotDonation } from "@app/types"; import _address from "@app/utils/_address"; import calculatePayouts from "@app/utils/calculatePayouts"; +import formatWithCommas from "@app/utils/formatWithCommas"; +import hrefWithParams from "@app/utils/hrefWithParams"; +import nearToUsd from "@app/utils/nearToUsd"; import nearToUsdWithFallback from "@app/utils/nearToUsdWithFallback"; import yoctosToUsdWithFallback from "@app/utils/yoctosToUsdWithFallback"; -import Table from "./Table/Table"; +import TableSkeleton from "./Table/TableSkeleton"; +import { Container, Row } from "./Table/styles"; type Props = { potDetail: PotDetail; @@ -16,11 +21,13 @@ type Props = { const PoolAllocationTable = ({ potDetail, allDonations }: Props) => { const { SUPPORTED_FTS } = constants; - const { base_currency, total_public_donations, matching_pool_balance, public_donations_count } = potDetail; + const { total_public_donations, matching_pool_balance, public_donations_count } = potDetail; const [projectsId, setProjectsId] = useState(null); const [allPayouts, setAllPayouts] = useState(null); const [flaggedAddresses, setFlaggedAddresses] = useState(null); + const [sponsorshipDonations, setSponsorshipDonations] = useState(null); + const [usdToggle, setUsdToggle] = useState(false); const { potId } = useParams(); @@ -30,9 +37,12 @@ const PoolAllocationTable = ({ potDetail, allDonations }: Props) => { }); } - let sponsorshipDonations = PotSDK.getMatchingPoolDonations(potId); - - if (sponsorshipDonations) sponsorshipDonations.sort((a: any, b: any) => b.net_amount - a.net_amount); + if (potDetail && public_donations_count === 0) { + PotSDK.asyncGetMatchingPoolDonations(potId).then((sponsorshipDonations: PotDonation[]) => { + sponsorshipDonations.sort((a: any, b: any) => b.net_amount - a.net_amount); + setSponsorshipDonations(sponsorshipDonations); + }); + } const calcMatchedAmount = (donations: any) => { if (donations) { @@ -40,7 +50,7 @@ const PoolAllocationTable = ({ potDetail, allDonations }: Props) => { donations?.forEach((donation: any) => { total = total.plus(Big(donation.net_amount)); }); - const amount = SUPPORTED_FTS[base_currency.toUpperCase() || "NEAR"].fromIndivisible(total.toString()); + const amount = SUPPORTED_FTS["NEAR"].fromIndivisible(total.toString()); return amount; } }; @@ -49,7 +59,7 @@ const PoolAllocationTable = ({ potDetail, allDonations }: Props) => { const donorsCount = uniqueDonorIds.size; - if (!flaggedAddresses) { + if (!flaggedAddresses && allDonations) { PotSDK.getFlaggedAccounts(potDetail, potId) .then((data) => { if (data) { @@ -97,17 +107,82 @@ const PoolAllocationTable = ({ potDetail, allDonations }: Props) => { } } - return allPayouts?.length > 0 ? ( - - ) : sponsorshipDonations.length > 0 ? ( + const Table = ({ donations, totalAmount, totalUniqueDonors, title }: any) => { + return ( + +
+ {totalAmount} + raised from + {totalUniqueDonors} + {title === "sponsors" ? "sponsors" : "donors"} +
+
+
Top {title}
+
(nearToUsd ? setUsdToggle(!usdToggle) : "")} + > + {nearToUsd && ( + + + + )} + {usdToggle ? "USD" : "NEAR"} +
+
+ {donations.map(({ projectId, donor_id, matchingAmount, net_amount }: any, idx: number) => { + const id = donor_id || projectId; + const nearAmount = formatWithCommas(SUPPORTED_FTS["NEAR"].fromIndivisible(net_amount || matchingAmount)); + + const profile = Social.getr(`${id}/profile`); + const matchedAmout = usdToggle ? yoctosToUsdWithFallback(matchingAmount || net_amount, true) : nearAmount; + + const url = projectId ? `?tab=project&projectId=${projectId}` : `?tab=profile&accountId=${donor_id}`; + return ( + +
#{idx + 1}
+ + + {_address(profile?.name || id, 15)} + +
+ {matchedAmout} {usdToggle ? " " : "N"} +
+
+ ); + })} +
+ ); + }; + + return public_donations_count > 0 ? ( + allPayouts !== null ? ( +
+ ) : ( + + ) + ) : sponsorshipDonations === null ? ( + + ) : sponsorshipDonations?.length > 0 ? (
obj.donor_id)).size} donations={sponsorshipDonations.slice(0, 5)} /> diff --git a/src/pages/Pot/components/PoolAllocationTable/Table/Table.tsx b/src/pages/Pot/components/PoolAllocationTable/Table/Table.tsx index bf1abbc8..8b7688e0 100644 --- a/src/pages/Pot/components/PoolAllocationTable/Table/Table.tsx +++ b/src/pages/Pot/components/PoolAllocationTable/Table/Table.tsx @@ -1,6 +1,5 @@ import { Social, useState } from "alem"; import Image from "@app/components/mob.near/Image"; -import ProfileImage from "@app/components/mob.near/ProfileImage"; import constants from "@app/constants"; import _address from "@app/utils/_address"; import formatWithCommas from "@app/utils/formatWithCommas"; diff --git a/src/pages/Pot/components/PoolAllocationTable/Table/TableSkeleton.tsx b/src/pages/Pot/components/PoolAllocationTable/Table/TableSkeleton.tsx new file mode 100644 index 00000000..3f40a694 --- /dev/null +++ b/src/pages/Pot/components/PoolAllocationTable/Table/TableSkeleton.tsx @@ -0,0 +1,29 @@ +import { + SkeletonContainer, + SkeletonHeader, + SkeletonRowItem, + SkeletonAddress, + SkeleteonProfile, + SkeletonName, + SkeletonAmount, +} from "./styles"; + +const TableSkeleton = () => { + return ( + + + {new Array(5).fill(0).map((_, idx) => ( + +
#{idx + 1}
+ + + + + +
+ ))} +
+ ); +}; + +export default TableSkeleton; diff --git a/src/pages/Pot/components/PoolAllocationTable/Table/styles.ts b/src/pages/Pot/components/PoolAllocationTable/Table/styles.ts index e4fce641..6063d1e6 100644 --- a/src/pages/Pot/components/PoolAllocationTable/Table/styles.ts +++ b/src/pages/Pot/components/PoolAllocationTable/Table/styles.ts @@ -73,3 +73,74 @@ export const Row = styled.div` display: flex !important; } `; +// skeleton + +const loadingSkeleton = styled.keyframes` + 0% { + opacity: 1; + } + 50% { + opacity: 0.4; + } + 100% { + opacity: 1; + } +`; + +export const SkeletonContainer = styled.div` + display: flex; + flex-direction: column; + height: 360px; + width: 100%; + max-width: 514px; + border-radius: 12px; + border-width: 1px 1px 2px; + border-style: solid; + border-color: rgb(41, 41, 41); + animation-name: ${loadingSkeleton}; + animation-duration: 1s; + animation-iteration-count: infinite; + overflow: hidden; +`; +export const SkeletonHeader = styled.div` + height: 90px; + width: 100%; + background: #eee; +`; + +export const SkeletonRowItem = styled.div` + display: flex; + align-items: center; + width: 100%; + padding: 1rem; + gap: 8px; + border-bottom: 1px solid #c7c7c7; + &:last-of-type { + border-bottom: none; + } +`; + +export const SkeletonAddress = styled.div` + display: flex; + align-items: center; + gap: 8px; + margin-left: 24px; + flex: 1; +`; + +export const SkeleteonProfile = styled.div` + width: 18px; + height: 18px; + border-radius: 50%; + background: #eee; +`; +export const SkeletonName = styled.div` + width: 100px; + height: 14px; + background: #eee; +`; +export const SkeletonAmount = styled.div` + width: 57px; + height: 14px; + background: #eee; +`; diff --git a/src/pages/Profile/components/Tabs.tsx b/src/pages/Profile/components/Tabs.tsx index 6326d847..e1440fed 100644 --- a/src/pages/Profile/components/Tabs.tsx +++ b/src/pages/Profile/components/Tabs.tsx @@ -48,14 +48,16 @@ const Tabs = ({ navOptions, nav }: Props) => { } `; + const Link = styled("Link")``; + return ( {navOptions.map((option: any) => { const selected = option.id == getSelectedNavOption().id; return option.label ? ( - + {option.label} - + ) : ( "" ); diff --git a/src/services/getPotData.ts b/src/services/getPotData.ts new file mode 100644 index 00000000..e23c9adf --- /dev/null +++ b/src/services/getPotData.ts @@ -0,0 +1,337 @@ +import { Storage } from "alem"; +import PotSDK from "@app/SDK/pot"; +import { FlaggedAddress, Payout, PotApplication, PotDetail, PotDonation } from "@app/types"; +import calculatePayouts from "@app/utils/calculatePayouts"; + +type UpdateState = (newValues: Partial) => void; + +type GetPayoutProps = { + potId: string; + allDonations: PotDonation[]; + flaggedAddresses: FlaggedAddress[]; + potDetail: PotDetail; + updateState: UpdateState; +}; + +export type ProjectsState = { + potDetail?: PotDetail; + donations?: PotDonation[]; + filteredProjects?: PotApplication[]; + projects?: PotApplication[] | null; + flaggedAddresses?: FlaggedAddress[] | null; + payouts?: Record | null; +}; + +function isEqual(obj1: any, obj2: any) { + // Check if both are the same reference + if (obj1 === obj2) return true; + + // Check if both are null or undefined + if (obj1 == null || obj2 == null) return false; + + // Check if both are not objects (e.g., numbers, strings, etc.) + if (typeof obj1 !== "object" || typeof obj2 !== "object") return false; + + // Get the keys of both objects + const keys1 = Object.keys(obj1); + const keys2 = Object.keys(obj2); + + // Check if both objects have the same number of keys + if (keys1.length !== keys2.length) return false; + + // Check if all keys and their values are the same + for (const key of keys1) { + if (!keys2.includes(key) || !isEqual(obj1[key], obj2[key])) { + return false; + } + } + + return true; +} + +const getPotData = (potId: string, property: string) => Storage.get(`${potId}-${property}`); + +const setPotData = (potId: string, property: string, value: any) => Storage.set(`${potId}-${property}`, value); + +// Get pot detail +export const getConfig = ({ potId, updateState }: { potId: string; updateState: UpdateState }) => { + const potData = getPotData(potId, "config"); + const potDetail = potData?.potDetail; + + if (potDetail) + updateState({ + potDetail, + }); + + PotSDK.asyncGetConfig(potId) + .then((currentPotDetail: PotDetail) => { + if (isEqual(potDetail, currentPotDetail)) return; + else { + setPotData(potId, "config", currentPotDetail); + updateState({ + potDetail: currentPotDetail, + }); + } + }) + .catch((err: unknown) => { + console.log("error getthing pot config ", err); + }); +}; + +// get pot applications +export function getPotProjects({ + potId, + updateState, + isApprpved, +}: { + potId: string; + updateState: UpdateState; + isApprpved: boolean; +}) { + // get projects from local storage + const potData = getPotData(potId, "projects"); + const savedProject = potData.projects || []; + + if (savedProject) { + // if storage project exist show it + let allProjects = savedProject; + // Check if only approved applications is requested + if (isApprpved) allProjects = allProjects.filter((project: PotApplication) => project.status === "Approved"); + updateState({ + projects: allProjects, + filteredProjects: allProjects, + }); + } + // check the current projects + PotSDK.asyncGetApprovedApplications(potId) + .then((projects: PotApplication[]) => { + if (projects.length === potData.projects?.length) return; + setPotData(potId, "projects", projects); + let allProjects = projects; + if (isApprpved) allProjects = allProjects.filter((project: PotApplication) => project.status === "Approved"); + updateState({ + projects, + filteredProjects: allProjects, + }); + }) + .catch((error: unknown) => { + updateState({ + projects: [], + filteredProjects: [], + }); + }); +} + +// get pot payouts +export const getPayout = ({ potId, allDonations, flaggedAddresses, potDetail, updateState }: GetPayoutProps) => { + const potData = getPotData(potId, "payouts"); + const payouts = potData.payouts; + if (payouts) + updateState({ + payouts, + }); + + if (flaggedAddresses) { + if (potDetail.payouts) { + if (isEqual(potDetail.payouts, payouts)) return; + else { + setPotData(potId, "payouts", payouts); + updateState({ + payouts, + }); + } + } else if (allDonations.length && flaggedAddresses) + calculatePayouts(allDonations, potDetail.matching_pool_balance, flaggedAddresses).then((currentPayouts) => { + if (isEqual(payouts, currentPayouts)) return; + else { + setPotData(potId, "payouts", currentPayouts); + updateState({ + payouts: currentPayouts, + }); + } + }); + else if (allDonations?.length === 0 && flaggedAddresses?.length === 0) { + updateState({ + payouts: {}, + }); + } + } +}; + +// get matched donations +export const asyncGetPublicDonations = (potDetail: PotDetail, potId: string) => { + const limit = 480; // number of donations to fetch per req + + const donationsCount = potDetail.public_donations_count; + const paginations = [...Array(Math.ceil(donationsCount / limit)).keys()]; + + try { + const allDonations = paginations.map((index) => + PotSDK.asyncGetPublicRoundDonations(potId, { + from_index: index * limit, + limit: limit, + }), + ); + + return Promise.all(allDonations); + } catch (error) { + console.error(`error getting public donations`, error); + return Promise.all([]); + } +}; + +export const getDonations = ({ + potId, + potDetail, + updateState, +}: { + potId: string; + potDetail: PotDetail; + updateState: (newValues: Partial) => void; +}) => { + const potData = getPotData(potId, "donations"); + const donations = potData.donations || []; + + if (donations) + updateState({ + donations, + }); + + if (potDetail.public_donations_count !== donations.length) { + asyncGetPublicDonations(potDetail, potId).then((paginatedDonations) => { + const currentDonations = paginatedDonations ? paginatedDonations.flat() : []; + setPotData(potId, "donations", currentDonations); + updateState({ + donations: currentDonations, + }); + }); + } +}; + +const getListOfFlagged = (flaggedAddresses: FlaggedAddress[]) => { + const listOfFlagged: any = []; + flaggedAddresses.forEach((adminFlaggedAcc: any) => { + const addresses = Object.keys(adminFlaggedAcc.potFlaggedAcc); + listOfFlagged.push(...addresses); + }); + return listOfFlagged; +}; + +export const getFlaggedAccounts = ({ + potId, + potDetail, + updateState, + type, +}: { + potId: string; + potDetail: PotDetail; + updateState: (newValues: Partial) => void; + type: "list" | "obj"; +}) => { + const potData = getPotData(potId, "flaggedAccounts"); + let flaggedAddresses = potData.flaggedAddresses || []; + + if (type === "list") { + flaggedAddresses = getListOfFlagged(flaggedAddresses); + } + updateState({ + flaggedAddresses, + }); + + PotSDK.getFlaggedAccounts(potDetail) + .then((data) => { + if (type === "list") { + const liftOfFlagged = getListOfFlagged(data); + if (liftOfFlagged.length === flaggedAddresses.length) return; + else { + setPotData(potId, "flaggedAccounts", data); + updateState({ + flaggedAddresses: data, + }); + } + } else { + const isNotEqual = data.some((adminFlaggedAcc: FlaggedAddress, idx: string) => { + if (adminFlaggedAcc?.potFlaggedAcc?.length === adminFlaggedAcc?.potFlaggedAcc?.length) return false; + else return true; + }); + + if (isNotEqual) { + setPotData(potId, "flaggedAccounts", data); + updateState({ + flaggedAddresses: data, + }); + } + } + }) + .catch((err) => console.log("error getting the flagged accounts ", err)); +}; + +// const allDonations = allDonationsPaginated ? allDonationsPaginated.flat() : null; + +// const potOptions = { +// potDetail: ({ potId }: { potId: string }) => PotSDK.asyncGetConfig(potId), +// projects: ({ potId }: { potId: string }) => PotSDK.asyncGetApprovedApplications(potId), +// sponsorshipDonations: ({ potId }: { potId: string }) => PotSDK.asyncGetMatchingPoolDonations(potId), +// // need potDetail, flaggedAddresses, potDetail +// payout: ({ allDonations, flaggedAddresses, potDetail }: GetPayoutProps) => +// getPayout({ +// allDonations, +// flaggedAddresses, +// potDetail, +// }), +// // need potDetail +// flaggedAddresses: ({ potId, potDetail }: { potId: string; potDetail: PotDetail }) => +// PotSDK.getFlaggedAccounts(potDetail, potId), +// donations: ({ potId, potDetail }: { potId: string; potDetail: PotDetail }) => +// asyncGetPublicDonations(potDetail, potId), +// }; + +// type PotDataOptions = "potDetail" | "payout" | "flaggedAddresses" | "projects" | "donations" | "sponsorshipDonations"; + +// export function getFlaggedAddresses({ +// potId, +// optionsHandler, +// updateState, +// }: { +// potId: string; +// optionsHandler: Record any>; +// updateState: (newValues: Partial) => void; +// }) { +// // get pot Data from local storage +// const potData: ProjectsState = JSON.parse(Storage.get(potId) || "{}"); + +// const potDetail = potData.potDetail; +// const donations = potData.donations; + +// const options = Object.keys(optionsHandler) as PotDataOptions[]; + +// const needsPotDetail = ["payout", "donations", "flaggedAddresses"]; +// const needsAll = "payout"; +// // what is needed before fetching +// let fetchFirst: Record = {}; + +// options.forEach((option) => { +// if (needsPotDetail.includes(option)) fetchFirst["potDetail"] = ""; +// if (needsAll === option) { +// fetchFirst = { +// potDetail: "", +// donations: "", +// flaggedAddresses: "", +// }; +// } +// }); + +// if( +// fetchFirst["potDetail"] && +// ){ +// PotSDK.asyncGetConfig(potId).then((potDetail:PotDetail)=>{ + +// }) +// } + +// const promises = {}; +// const results = {}; +// options.forEach((option) => { +// const result = potOptions[option]({}); +// }); +// } diff --git a/src/types.ts b/src/types.ts index 5f9c2a2b..fc31d0ed 100644 --- a/src/types.ts +++ b/src/types.ts @@ -54,22 +54,6 @@ export type Pot = { deployed_at_ms: number; }; -export type PotDonation = { - id: string; - donor_id: string; - total_amount: string; - net_amount: string; - message: string; - donated_at: number; - project_id: null | string; - referrer_id: null | string; - referrer_fee: null | string; - protocol_fee: string; - matching_pool: boolean; - chef_id: null | string; - chef_fee: null | string; -}; - export type FundDonation = { id: string; donor_id: string; @@ -110,3 +94,38 @@ export type PotApplication = { updated_at: null | string; review_notes: null | string; }; + +export interface PotDonation { + id: string; + donor_id: string; + total_amount: string; + net_amount: string; + message: string; + donated_at: number; + project_id: null | string; + referrer_id: null | string; + referrer_fee: null | string; + protocol_fee: string; + matching_pool: boolean; + chef_id: null | string; + chef_fee: null | string; +} + +export enum PotAdminRoles { + Admin = "admin", + Chef = "chef", + Wwner = "owner", +} + +export type FlaggedAddress = { + flaggedBy: string; + role: PotAdminRoles; + potFlaggedAcc: "string"; +}; + +export interface Payout { + id: string; + project_id: string; + amount: string; + paid_at: number; +} diff --git a/src/utils/calculatePayouts.ts b/src/utils/calculatePayouts.ts index 73b38fa8..da1d2f1e 100644 --- a/src/utils/calculatePayouts.ts +++ b/src/utils/calculatePayouts.ts @@ -1,7 +1,12 @@ import { Big, Near } from "alem"; import constants from "@app/constants"; +import { Payout } from "@app/types"; -const calculatePayouts = (allPotDonations: any, totalMatchingPool: any, blacklistedAccounts: any) => { +const calculatePayouts = ( + allPotDonations: any, + totalMatchingPool: any, + blacklistedAccounts: any, +): Promise> => { const { NADABOT_CONTRACT_ID } = constants; // * QF/CLR logic taken from https://github.com/gitcoinco/quadratic-funding/blob/master/quadratic-funding/clr.py * From d85d7ef218518eb3b7083aca2a076ada303c9241 Mon Sep 17 00:00:00 2001 From: M-RB3 Date: Wed, 22 May 2024 15:25:48 +0400 Subject: [PATCH 02/18] update pot header table and projects --- src/SDK/pot.js | 2 +- src/components/Card/Card.tsx | 10 +- src/pages/Pot/NavPages/Projects/Projects.tsx | 119 +++++---- .../PoolAllocationTable.tsx | 140 +++++------ src/pages/Projects/components/ListSection.tsx | 3 +- src/services/getPotData.ts | 238 ++++++++---------- 6 files changed, 229 insertions(+), 283 deletions(-) diff --git a/src/SDK/pot.js b/src/SDK/pot.js index 5a624ce8..e28d4e87 100644 --- a/src/SDK/pot.js +++ b/src/SDK/pot.js @@ -30,7 +30,7 @@ const PotSDK = { return Near.view(potId, "get_matching_pool_donations", {}); }, asyncGetMatchingPoolDonations: (potId, args) => { - return Near.asyncView(potId, "get_matching_pool_donations", ...(args || {})); + return Near.asyncView(potId, "get_matching_pool_donations", args || {}); }, getPublicRoundDonations: (potId, args) => { return Near.view(potId, "get_public_round_donations", { diff --git a/src/components/Card/Card.tsx b/src/components/Card/Card.tsx index 04059d9c..354d5a6f 100644 --- a/src/components/Card/Card.tsx +++ b/src/components/Card/Card.tsx @@ -32,9 +32,7 @@ import { } from "./styles"; const Card = (props: any) => { - const { payoutDetails, allowDonate: _allowDonate } = props; - const { potId } = useParams(); - + const { payoutDetails, allowDonate: _allowDonate, potId } = props; // Start Modals provider const Modals = useModals(); const { setDonationModalProps } = useDonationModal(); @@ -55,7 +53,7 @@ const Card = (props: any) => { ? DonateSDK.getDonationsForRecipient(projectId) : []; - const totalAmountNear = useMemo(() => { + const getTotalAmountNear = () => { if (payoutDetails) return payoutDetails.totalAmount; if (!donationsForProject) return "0"; let totalDonationAmountNear = new Big(0); @@ -65,7 +63,9 @@ const Card = (props: any) => { } } return totalDonationAmountNear.toString(); - }, [donationsForProject, payoutDetails]); + }; + + const totalAmountNear = getTotalAmountNear(); const getImageSrc = (image: any) => { const defaultImageUrl = "https://ipfs.near.social/ipfs/bafkreih4i6kftb34wpdzcuvgafozxz6tk6u4f5kcr2gwvtvxikvwriteci"; diff --git a/src/pages/Pot/NavPages/Projects/Projects.tsx b/src/pages/Pot/NavPages/Projects/Projects.tsx index 2fcb676c..9fd5f248 100644 --- a/src/pages/Pot/NavPages/Projects/Projects.tsx +++ b/src/pages/Pot/NavPages/Projects/Projects.tsx @@ -1,50 +1,26 @@ -import { useState, Social, context, useParams, createDebounce, useEffect, Storage, promisify } from "alem"; +import { useState, Social, context, useParams, createDebounce, useEffect } from "alem"; import Card from "@app/components/Card/Card"; -import { getPotDonations } from "@app/pages/Donor/NavPages/Donations/utils"; +import ListSection from "@app/pages/Projects/components/ListSection"; import { getConfig, getDonations, getFlaggedAccounts, getPayout, getPotProjects } from "@app/services/getPotData"; import { FlaggedAddress, Payout, PotApplication, PotDetail, PotDonation } from "@app/types"; import getTagsFromSocialProfileData from "@app/utils/getTagsFromSocialProfileData"; import getTeamMembersFromSocialProfileData from "@app/utils/getTeamMembersFromSocialProfileData"; -import { Centralized, Container, SearchBar, Title, ProjectsWrapper } from "./styles"; +import { Centralized, Container, SearchBar, Title } from "./styles"; type Props = { potDetail: any; allDonations: any; }; -type ProjectsState = { - potDetail: PotDetail | null; - donations: PotDonation[] | null; - filteredProjects: PotApplication[]; - projects: PotApplication[] | null; - flaggedAddresses: FlaggedAddress[] | null; - payouts: Record | null; -}; - const Projects = (props: Props) => { const { potId } = useParams(); - const [state, setState] = useState({ - filteredProjects: [], - donations: null, - projects: null, - flaggedAddresses: null, - payouts: null, - potDetail: null, - }); - - // const [projects, setProjects] = useState(null); - // const [filteredProjects, setFilteredProjects] = useState([]); - // const [donations, setDonations] = useState(null); - // const [flaggedAddresses, setFlaggedAddresses] = useState(null); - // const [payouts, setPayouts] = useState | null>(null); - // const [potDetail, setPotDetail] = useState(null); - - const updateState = (newValue: Partial) => { - setState((prevState) => ({ ...prevState, ...newValue })); - }; - - const { filteredProjects, flaggedAddresses, payouts, projects, potDetail, donations } = state; + const [projects, setProjects] = useState(null); + const [filteredProjects, setFilteredProjects] = useState([]); + const [donations, setDonations] = useState(null); + const [flaggedAddresses, setFlaggedAddresses] = useState(null); + const [payouts, setPayouts] = useState | null>(null); + const [potDetail, setPotDetail] = useState(null); const Loading = () => ( @@ -57,13 +33,16 @@ const Projects = (props: Props) => { if (!projects) getPotProjects({ potId, - updateState, + updateState: (projects: PotApplication[]) => { + setFilteredProjects(projects); + setProjects(projects); + }, isApprpved: true, }); if (!potDetail) getConfig({ potId, - updateState, + updateState: setPotDetail, }); }, []); @@ -74,20 +53,28 @@ const Projects = (props: Props) => { potId, potDetail, type: "list", - updateState, + updateState: setFlaggedAddresses, }); if (!donations) getDonations({ potId, potDetail, - updateState, + updateState: setDonations, }); } }, [potDetail]); useEffect(() => { - if (potDetail && flaggedAddresses && donations) - getPayout({ allDonations: donations, flaggedAddresses, potDetail, potId, updateState }); + if (potDetail && flaggedAddresses && donations) { + getPayout({ + allDonations: donations, + flaggedAddresses, + potDetail, + potId, + withTotalAmount: true, + updateState: setPayouts, + }); + } }, [potDetail, flaggedAddresses, donations]); if (!projects || !potDetail) return ; @@ -112,9 +99,7 @@ const Projects = (props: Props) => { ]; return fields.some((item) => (item || "").toLowerCase().includes(searchTerm.toLowerCase())); }); - updateState({ - filteredProjects: updatedProjects, - }); + setFilteredProjects(updatedProjects); } }; @@ -142,24 +127,38 @@ const Projects = (props: Props) => { /> {filteredProjects.length > 0 ? ( - - {filteredProjects.map((project: PotApplication) => ( - - ))} - + { + return ( + + ); + }} + /> ) : (
No projects
)} diff --git a/src/pages/Pot/components/PoolAllocationTable/PoolAllocationTable.tsx b/src/pages/Pot/components/PoolAllocationTable/PoolAllocationTable.tsx index 68f403bf..f10edeb6 100644 --- a/src/pages/Pot/components/PoolAllocationTable/PoolAllocationTable.tsx +++ b/src/pages/Pot/components/PoolAllocationTable/PoolAllocationTable.tsx @@ -1,10 +1,9 @@ -import { useState, useParams, Big, Social } from "alem"; -import PotSDK from "@app/SDK/pot"; +import { useState, useParams, Big, Social, useEffect } from "alem"; import Image from "@app/components/mob.near/Image"; import constants from "@app/constants"; -import { PotDetail, PotDonation } from "@app/types"; +import { getConfig, getDonations, getFlaggedAccounts, getPayout, getSponsorships } from "@app/services/getPotData"; +import { FlaggedAddress, Payout, PotDetail, PotDonation } from "@app/types"; import _address from "@app/utils/_address"; -import calculatePayouts from "@app/utils/calculatePayouts"; import formatWithCommas from "@app/utils/formatWithCommas"; import hrefWithParams from "@app/utils/hrefWithParams"; import nearToUsd from "@app/utils/nearToUsd"; @@ -13,36 +12,65 @@ import yoctosToUsdWithFallback from "@app/utils/yoctosToUsdWithFallback"; import TableSkeleton from "./Table/TableSkeleton"; import { Container, Row } from "./Table/styles"; -type Props = { - potDetail: PotDetail; - allDonations: any; -}; - -const PoolAllocationTable = ({ potDetail, allDonations }: Props) => { +const PoolAllocationTable = () => { const { SUPPORTED_FTS } = constants; - const { total_public_donations, matching_pool_balance, public_donations_count } = potDetail; + const { potId } = useParams(); - const [projectsId, setProjectsId] = useState(null); const [allPayouts, setAllPayouts] = useState(null); - const [flaggedAddresses, setFlaggedAddresses] = useState(null); const [sponsorshipDonations, setSponsorshipDonations] = useState(null); const [usdToggle, setUsdToggle] = useState(false); + const [allDonations, setDonations] = useState(null); + const [flaggedAddresses, setFlaggedAddresses] = useState(null); + const [potDetail, setPotDetail] = useState(null); + + useEffect(() => { + if (!sponsorshipDonations) + getSponsorships({ + potId, + updateState: setSponsorshipDonations, + }); + if (!potDetail) + getConfig({ + potId, + updateState: setPotDetail, + }); + }, []); + + useEffect(() => { + if (potDetail) { + if (!flaggedAddresses) + getFlaggedAccounts({ + potId, + potDetail, + type: "list", + updateState: setFlaggedAddresses, + }); + if (!allDonations) + getDonations({ + potId, + potDetail, + updateState: setDonations, + }); + } + }, [potDetail]); + + useEffect(() => { + if (potDetail && flaggedAddresses && allDonations && !allPayouts) { + getPayout({ + allDonations, + flaggedAddresses, + potDetail, + potId, + withTotalAmount: false, + updateState: setAllPayouts, + }); + } + }, [potDetail, flaggedAddresses, allDonations]); - const { potId } = useParams(); - - if (!projectsId) { - PotSDK.asyncGetApprovedApplications(potId).then((projects: any) => { - setProjectsId(projects); - }); - } + if (potDetail === null || sponsorshipDonations === null) return ""; - if (potDetail && public_donations_count === 0) { - PotSDK.asyncGetMatchingPoolDonations(potId).then((sponsorshipDonations: PotDonation[]) => { - sponsorshipDonations.sort((a: any, b: any) => b.net_amount - a.net_amount); - setSponsorshipDonations(sponsorshipDonations); - }); - } + const { total_public_donations, matching_pool_balance, public_donations_count } = potDetail; const calcMatchedAmount = (donations: any) => { if (donations) { @@ -59,53 +87,7 @@ const PoolAllocationTable = ({ potDetail, allDonations }: Props) => { const donorsCount = uniqueDonorIds.size; - if (!flaggedAddresses && allDonations) { - PotSDK.getFlaggedAccounts(potDetail, potId) - .then((data) => { - if (data) { - const listOfFlagged: any = []; - data?.forEach((adminFlaggedAcc: any) => { - const addresses = Object.keys(adminFlaggedAcc.potFlaggedAcc); - listOfFlagged.push(...addresses); - }); - setFlaggedAddresses(listOfFlagged); - } - }) - .catch((err) => console.log("error getting the flagged accounts ", err)); - } - - const sortAndSetPayouts = (payouts: any) => { - payouts.sort((a: any, b: any) => { - // sort by matching pool allocation, highest to lowest - return b.matchingAmount - a.matchingAmount; - }); - setAllPayouts(payouts.slice(0, 5)); - }; - - if (!allPayouts && allDonations?.length > 0 && flaggedAddresses) { - let allPayouts = []; - - if (potDetail.payouts.length) { - allPayouts = potDetail.payouts.map((payout) => { - const { project_id, amount } = payout; - return { - projectId: project_id, - matchingAmount: amount, - }; - }); - sortAndSetPayouts(allPayouts); - } else { - calculatePayouts(allDonations, matching_pool_balance, flaggedAddresses).then((calculatedPayouts: any) => { - allPayouts = Object.entries(calculatedPayouts).map(([projectId, { matchingAmount }]: any) => { - return { - projectId, - matchingAmount, - }; - }); - sortAndSetPayouts(allPayouts); - }); - } - } + console.log("allPayouts", allPayouts); const Table = ({ donations, totalAmount, totalUniqueDonors, title }: any) => { return ( @@ -136,14 +118,16 @@ const PoolAllocationTable = ({ potDetail, allDonations }: Props) => { {usdToggle ? "USD" : "NEAR"} - {donations.map(({ projectId, donor_id, matchingAmount, net_amount }: any, idx: number) => { - const id = donor_id || projectId; - const nearAmount = formatWithCommas(SUPPORTED_FTS["NEAR"].fromIndivisible(net_amount || matchingAmount)); + {donations.map(({ project_id, donor_id, matchingAmount, net_amount, amount }: any, idx: number) => { + const id = donor_id || project_id; + const nearAmount = formatWithCommas( + SUPPORTED_FTS["NEAR"].fromIndivisible(net_amount || matchingAmount || amount), + ); const profile = Social.getr(`${id}/profile`); const matchedAmout = usdToggle ? yoctosToUsdWithFallback(matchingAmount || net_amount, true) : nearAmount; - const url = projectId ? `?tab=project&projectId=${projectId}` : `?tab=profile&accountId=${donor_id}`; + const url = project_id ? `?tab=project&projectId=${project_id}` : `?tab=profile&accountId=${donor_id}`; return (
#{idx + 1}
@@ -172,7 +156,7 @@ const PoolAllocationTable = ({ potDetail, allDonations }: Props) => { title="matching pool allocations" totalAmount={yoctosToUsdWithFallback(total_public_donations, true)} totalUniqueDonors={donorsCount} - donations={allPayouts} + donations={allPayouts.slice(0, 5)} /> ) : ( diff --git a/src/pages/Projects/components/ListSection.tsx b/src/pages/Projects/components/ListSection.tsx index 69a60f67..6d6789d1 100644 --- a/src/pages/Projects/components/ListSection.tsx +++ b/src/pages/Projects/components/ListSection.tsx @@ -1,5 +1,6 @@ import { VM, props, useMemo } from "alem"; import styled from "styled-components"; +import Feed from "@app/components/devs.near/Feed"; type BreakPoint = { breakpoint: number; @@ -17,8 +18,6 @@ type Props = { const ListSection = ({ shouldShuffle, items, renderItem }: Props) => { const responsive = props.responsive || []; - const { Feed } = VM.require("devs.near/widget/Feed"); - if (!Feed) { return

Loading...

; } diff --git a/src/services/getPotData.ts b/src/services/getPotData.ts index e23c9adf..06b59e4f 100644 --- a/src/services/getPotData.ts +++ b/src/services/getPotData.ts @@ -3,10 +3,12 @@ import PotSDK from "@app/SDK/pot"; import { FlaggedAddress, Payout, PotApplication, PotDetail, PotDonation } from "@app/types"; import calculatePayouts from "@app/utils/calculatePayouts"; -type UpdateState = (newValues: Partial) => void; +// type UpdateState = (newValues: Partial) => void; +type UpdateState = (newValues: any) => void; type GetPayoutProps = { potId: string; + withTotalAmount: boolean; allDonations: PotDonation[]; flaggedAddresses: FlaggedAddress[]; potDetail: PotDetail; @@ -22,6 +24,11 @@ export type ProjectsState = { payouts?: Record | null; }; +type CalculatedPayout = { + project_id: string; + amount: number; +}; + function isEqual(obj1: any, obj2: any) { // Check if both are the same reference if (obj1 === obj2) return true; @@ -49,28 +56,43 @@ 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 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; + } + } + + // If no differences are found, return true + return true; +} + const getPotData = (potId: string, property: string) => Storage.get(`${potId}-${property}`); const setPotData = (potId: string, property: string, value: any) => Storage.set(`${potId}-${property}`, value); // Get pot detail export const getConfig = ({ potId, updateState }: { potId: string; updateState: UpdateState }) => { - const potData = getPotData(potId, "config"); - const potDetail = potData?.potDetail; + const potDetail = getPotData(potId, "config"); - if (potDetail) - updateState({ - potDetail, - }); + if (potDetail) updateState(potDetail); PotSDK.asyncGetConfig(potId) .then((currentPotDetail: PotDetail) => { if (isEqual(potDetail, currentPotDetail)) return; else { setPotData(potId, "config", currentPotDetail); - updateState({ - potDetail: currentPotDetail, - }); + updateState(currentPotDetail); } }) .catch((err: unknown) => { @@ -89,71 +111,75 @@ export function getPotProjects({ isApprpved: boolean; }) { // get projects from local storage - const potData = getPotData(potId, "projects"); - const savedProject = potData.projects || []; + const savedProject = getPotData(potId, "projects") || []; if (savedProject) { // if storage project exist show it let allProjects = savedProject; // Check if only approved applications is requested if (isApprpved) allProjects = allProjects.filter((project: PotApplication) => project.status === "Approved"); - updateState({ - projects: allProjects, - filteredProjects: allProjects, - }); + updateState(allProjects); } // check the current projects - PotSDK.asyncGetApprovedApplications(potId) + PotSDK.asyncGetApplications(potId) .then((projects: PotApplication[]) => { - if (projects.length === potData.projects?.length) return; + if (projects.length === savedProject?.length) return; setPotData(potId, "projects", projects); let allProjects = projects; if (isApprpved) allProjects = allProjects.filter((project: PotApplication) => project.status === "Approved"); - updateState({ - projects, - filteredProjects: allProjects, - }); + updateState(allProjects); }) .catch((error: unknown) => { - updateState({ - projects: [], - filteredProjects: [], - }); + console.log("error fetching pot applications ", error); + + updateState([]); }); } // get pot payouts -export const getPayout = ({ potId, allDonations, flaggedAddresses, potDetail, updateState }: GetPayoutProps) => { - const potData = getPotData(potId, "payouts"); - const payouts = potData.payouts; - if (payouts) - updateState({ - payouts, - }); +export const getPayout = ({ + potId, + allDonations, + flaggedAddresses, + potDetail, + withTotalAmount, // true => return object false=> return false + updateState, +}: GetPayoutProps) => { + const storageKey = withTotalAmount ? "payouts-obj" : "payouts"; + + const payouts = getPotData(potId, storageKey); + + if (payouts) updateState(payouts); if (flaggedAddresses) { - if (potDetail.payouts) { + if (potDetail.payouts && !withTotalAmount) { if (isEqual(potDetail.payouts, payouts)) return; else { - setPotData(potId, "payouts", payouts); - updateState({ - payouts, - }); + const sortedPayouts = potDetail.payouts; + sortedPayouts.sort((a: any, b: any) => b.matchingAmount - a.matchingAmount); + setPotData(potId, storageKey, sortedPayouts); + updateState(sortedPayouts); } } else if (allDonations.length && flaggedAddresses) - calculatePayouts(allDonations, potDetail.matching_pool_balance, flaggedAddresses).then((currentPayouts) => { - if (isEqual(payouts, currentPayouts)) return; + calculatePayouts(allDonations, potDetail.matching_pool_balance, flaggedAddresses).then((calculatedPayouts) => { + const currentPayouts = Object.entries(calculatedPayouts) + .map(([projectId, { matchingAmount, donorCount, totalAmount }]: any) => ({ + project_id: projectId, + amount: matchingAmount, + donorCount, + totalAmount, + })) + .filter((payout) => payout.amount !== "0"); + currentPayouts.sort((a: any, b: any) => b.matchingAmount - a.matchingAmount); + + if (areListsEqual(currentPayouts, payouts)) return; else { - setPotData(potId, "payouts", currentPayouts); - updateState({ - payouts: currentPayouts, - }); + setPotData(potId, storageKey, withTotalAmount ? calculatedPayouts : currentPayouts); + updateState(withTotalAmount ? calculatedPayouts : currentPayouts); } }); else if (allDonations?.length === 0 && flaggedAddresses?.length === 0) { - updateState({ - payouts: {}, - }); + updateState({}); } } }; @@ -187,23 +213,17 @@ export const getDonations = ({ }: { potId: string; potDetail: PotDetail; - updateState: (newValues: Partial) => void; + updateState: UpdateState; }) => { - const potData = getPotData(potId, "donations"); - const donations = potData.donations || []; + const donations = getPotData(potId, "donations") || []; - if (donations) - updateState({ - donations, - }); + if (donations) updateState(donations); if (potDetail.public_donations_count !== donations.length) { asyncGetPublicDonations(potDetail, potId).then((paginatedDonations) => { const currentDonations = paginatedDonations ? paginatedDonations.flat() : []; setPotData(potId, "donations", currentDonations); - updateState({ - donations: currentDonations, - }); + updateState(currentDonations); }); } }; @@ -225,7 +245,7 @@ export const getFlaggedAccounts = ({ }: { potId: string; potDetail: PotDetail; - updateState: (newValues: Partial) => void; + updateState: UpdateState; type: "list" | "obj"; }) => { const potData = getPotData(potId, "flaggedAccounts"); @@ -234,10 +254,7 @@ export const getFlaggedAccounts = ({ if (type === "list") { flaggedAddresses = getListOfFlagged(flaggedAddresses); } - updateState({ - flaggedAddresses, - }); - + updateState(flaggedAddresses); PotSDK.getFlaggedAccounts(potDetail) .then((data) => { if (type === "list") { @@ -245,9 +262,7 @@ export const getFlaggedAccounts = ({ if (liftOfFlagged.length === flaggedAddresses.length) return; else { setPotData(potId, "flaggedAccounts", data); - updateState({ - flaggedAddresses: data, - }); + updateState(data); } } else { const isNotEqual = data.some((adminFlaggedAcc: FlaggedAddress, idx: string) => { @@ -257,81 +272,30 @@ export const getFlaggedAccounts = ({ if (isNotEqual) { setPotData(potId, "flaggedAccounts", data); - updateState({ - flaggedAddresses: data, - }); + updateState(data); } } }) .catch((err) => console.log("error getting the flagged accounts ", err)); }; -// const allDonations = allDonationsPaginated ? allDonationsPaginated.flat() : null; - -// const potOptions = { -// potDetail: ({ potId }: { potId: string }) => PotSDK.asyncGetConfig(potId), -// projects: ({ potId }: { potId: string }) => PotSDK.asyncGetApprovedApplications(potId), -// sponsorshipDonations: ({ potId }: { potId: string }) => PotSDK.asyncGetMatchingPoolDonations(potId), -// // need potDetail, flaggedAddresses, potDetail -// payout: ({ allDonations, flaggedAddresses, potDetail }: GetPayoutProps) => -// getPayout({ -// allDonations, -// flaggedAddresses, -// potDetail, -// }), -// // need potDetail -// flaggedAddresses: ({ potId, potDetail }: { potId: string; potDetail: PotDetail }) => -// PotSDK.getFlaggedAccounts(potDetail, potId), -// donations: ({ potId, potDetail }: { potId: string; potDetail: PotDetail }) => -// asyncGetPublicDonations(potDetail, potId), -// }; - -// type PotDataOptions = "potDetail" | "payout" | "flaggedAddresses" | "projects" | "donations" | "sponsorshipDonations"; - -// export function getFlaggedAddresses({ -// potId, -// optionsHandler, -// updateState, -// }: { -// potId: string; -// optionsHandler: Record any>; -// updateState: (newValues: Partial) => void; -// }) { -// // get pot Data from local storage -// const potData: ProjectsState = JSON.parse(Storage.get(potId) || "{}"); - -// const potDetail = potData.potDetail; -// const donations = potData.donations; - -// const options = Object.keys(optionsHandler) as PotDataOptions[]; - -// const needsPotDetail = ["payout", "donations", "flaggedAddresses"]; -// const needsAll = "payout"; -// // what is needed before fetching -// let fetchFirst: Record = {}; - -// options.forEach((option) => { -// if (needsPotDetail.includes(option)) fetchFirst["potDetail"] = ""; -// if (needsAll === option) { -// fetchFirst = { -// potDetail: "", -// donations: "", -// flaggedAddresses: "", -// }; -// } -// }); - -// if( -// fetchFirst["potDetail"] && -// ){ -// PotSDK.asyncGetConfig(potId).then((potDetail:PotDetail)=>{ - -// }) -// } - -// const promises = {}; -// const results = {}; -// options.forEach((option) => { -// const result = potOptions[option]({}); -// }); -// } +export const getSponsorships = ({ potId, updateState }: { potId: string; updateState: UpdateState }) => { + const sponsors = getPotData(potId, "sponsors"); + console.log("sponsors", sponsors); + + if (sponsors) updateState(sponsors); + + PotSDK.asyncGetMatchingPoolDonations(potId) + .then((sponsorshipDonations: PotDonation[]) => { + sponsorshipDonations.sort((a: any, b: any) => b.net_amount - a.net_amount); + if (sponsors?.length === sponsorshipDonations?.length) return; + else { + updateState(sponsorshipDonations); + setPotData(potId, "sponsors", sponsorshipDonations); + } + }) + .catch((err: unknown) => { + console.log("error fetching sponsors ", err); + updateState([]); + }); +}; From 9dbd6aaa107f7ef121f054aa77858d094c09690e Mon Sep 17 00:00:00 2001 From: M-RB3 Date: Wed, 22 May 2024 15:46:02 +0400 Subject: [PATCH 03/18] update applications --- .../NavPages/Applications/Applications.tsx | 53 +++++++++++++------ .../PoolAllocationTable.tsx | 15 +++--- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/src/pages/Pot/NavPages/Applications/Applications.tsx b/src/pages/Pot/NavPages/Applications/Applications.tsx index 11985433..8fa8064a 100644 --- a/src/pages/Pot/NavPages/Applications/Applications.tsx +++ b/src/pages/Pot/NavPages/Applications/Applications.tsx @@ -1,10 +1,9 @@ import { Social, State, context, state, useParams, Tooltip, OverlayTrigger, useEffect } from "alem"; -import PotSDK from "@app/SDK/pot"; import Button from "@app/components/Button"; import Dropdown from "@app/components/Inputs/Dropdown/Dropdown"; import ToastContainer from "@app/components/ToastNotification/getToastContainer"; import ProfileImage from "@app/components/mob.near/ProfileImage"; -import { PotDetail } from "@app/types"; +import { getConfig, getPotProjects } from "@app/services/getPotData"; import _address from "@app/utils/_address"; import daysAgo from "@app/utils/daysAgo"; import getTransactionsFromHashes from "@app/utils/getTransactionsFromHashes"; @@ -22,12 +21,13 @@ import { Status, } from "./styles"; -const Applications = ({ potDetail }: { potDetail: PotDetail }) => { +const Applications = () => { const accountId = context.accountId; const { potId, transactionHashes } = useParams(); State.init({ newStatus: "", + potDetail: null, projectId: "", searchTerm: "", allApplications: null, @@ -39,27 +39,48 @@ const Applications = ({ potDetail }: { potDetail: PotDetail }) => { }, }); - const { newStatus, projectId, searchTerm, allApplications, filteredApplications, filterVal, toastContent } = state; - - const applications = PotSDK.getApplications(potId); + const { + newStatus, + projectId, + searchTerm, + allApplications, + filteredApplications, + filterVal, + toastContent, + potDetail, + } = state; const getApplicationCount = (sortVal: string) => { - if (!applications) return; - return applications?.filter((application: any) => { + if (!allApplications) return; + return allApplications?.filter((application: any) => { if (sortVal === "All") return true; return application.status === sortVal; })?.length; }; - if (applications && !allApplications) { - applications.reverse(); - State.update({ - filteredApplications: applications, - allApplications: applications, - }); - } + useEffect(() => { + if (!potDetail) + getConfig({ + potId, + updateState: (potDetail) => + State.update({ + potDetail, + }), + }); + if (!allApplications) + getPotProjects({ + potId, + isApprpved: false, + updateState: (applications) => + State.update({ + allApplications: applications, + filteredApplications: applications, + }), + }); + }, []); - if (!allApplications) return
; + if (allApplications === null || potDetail === null) + return
; const { owner, admins, chef } = potDetail; diff --git a/src/pages/Pot/components/PoolAllocationTable/PoolAllocationTable.tsx b/src/pages/Pot/components/PoolAllocationTable/PoolAllocationTable.tsx index f10edeb6..b00d66d7 100644 --- a/src/pages/Pot/components/PoolAllocationTable/PoolAllocationTable.tsx +++ b/src/pages/Pot/components/PoolAllocationTable/PoolAllocationTable.tsx @@ -68,9 +68,9 @@ const PoolAllocationTable = () => { } }, [potDetail, flaggedAddresses, allDonations]); - if (potDetail === null || sponsorshipDonations === null) return ""; + if (potDetail === null) return ; - const { total_public_donations, matching_pool_balance, public_donations_count } = potDetail; + const { total_public_donations, public_donations_count } = potDetail; const calcMatchedAmount = (donations: any) => { if (donations) { @@ -87,8 +87,6 @@ const PoolAllocationTable = () => { const donorsCount = uniqueDonorIds.size; - console.log("allPayouts", allPayouts); - const Table = ({ donations, totalAmount, totalUniqueDonors, title }: any) => { return ( @@ -120,12 +118,13 @@ const PoolAllocationTable = () => {
{donations.map(({ project_id, donor_id, matchingAmount, net_amount, amount }: any, idx: number) => { const id = donor_id || project_id; - const nearAmount = formatWithCommas( - SUPPORTED_FTS["NEAR"].fromIndivisible(net_amount || matchingAmount || amount), - ); + + const generalAmount = net_amount || matchingAmount || amount; + + const nearAmount = formatWithCommas(SUPPORTED_FTS["NEAR"].fromIndivisible(generalAmount)); const profile = Social.getr(`${id}/profile`); - const matchedAmout = usdToggle ? yoctosToUsdWithFallback(matchingAmount || net_amount, true) : nearAmount; + const matchedAmout = usdToggle ? yoctosToUsdWithFallback(generalAmount, true) : nearAmount; const url = project_id ? `?tab=project&projectId=${project_id}` : `?tab=profile&accountId=${donor_id}`; return ( From 8a5cf6f0b2218b358bdc65744da482cf22820100 Mon Sep 17 00:00:00 2001 From: M-RB3 Date: Wed, 22 May 2024 16:17:19 +0400 Subject: [PATCH 04/18] update Donations --- .../Pot/NavPages/Donations/Donations.tsx | 47 +++++++++++++------ src/services/getPotData.ts | 6 +-- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/pages/Pot/NavPages/Donations/Donations.tsx b/src/pages/Pot/NavPages/Donations/Donations.tsx index 1a71c710..d72e58e9 100644 --- a/src/pages/Pot/NavPages/Donations/Donations.tsx +++ b/src/pages/Pot/NavPages/Donations/Donations.tsx @@ -1,21 +1,22 @@ import { State, state, useEffect, useParams } from "alem"; import Arrow from "@app/assets/svgs/Arrow"; -import constants from "@app/constants"; -import { PotDetail } from "@app/types"; +import { getConfig, getDonations } from "@app/services/getPotData"; +import { PotDetail, PotDonation } from "@app/types"; import _address from "@app/utils/_address"; -import getTimePassed from "@app/utils/getTimePassed"; import DonationsTable from "../../components/DonationsTable/DonationsTable"; -import { Container, DonationsCount, OuterText, OuterTextContainer, Sort, TableContainer } from "./styes"; +import { Container, DonationsCount, OuterText, OuterTextContainer, Sort } from "./styes"; type Props = { allDonations: any[]; potDetail: PotDetail; }; -const Donations = (props: Props) => { - const { allDonations, potDetail } = props; +const Donations = () => { + const { potId } = useParams(); State.init({ + potDetail: null, + allDonations: null, filteredDonations: [], currentFilter: "date", filter: { @@ -24,23 +25,39 @@ const Donations = (props: Props) => { }, }); - const { filteredDonations, currentFilter, filter } = state; + const { filteredDonations, currentFilter, filter, potDetail, allDonations } = state; useEffect(() => { - if (allDonations && filteredDonations.length === 0) { - const sortedDonations = [...allDonations].reverse(); - State.update({ filteredDonations: sortedDonations }); - } - }, [allDonations]); - if (!allDonations) return
; + if (!potDetail) + getConfig({ + potId, + updateState: (potDetail) => + State.update({ + potDetail, + }), + }); + if (!allDonations && potDetail) + getDonations({ + potId, + potDetail, + updateState: (allDonations) => + State.update({ + allDonations, + filteredDonations: allDonations, + }), + }); + }, [potDetail]); + + if (allDonations === null && potDetail === null) + return
; const searchDonations = (searchTerm: string) => { // filter donations that match the search term (donor_id, project_id) - const filteredDonations = allDonations.filter((donation) => { + const filteredDonations = allDonations.filter((donation: PotDonation) => { const { donor_id, project_id } = donation; const searchFields = [donor_id, project_id]; - return searchFields.some((field) => field.toLowerCase().includes(searchTerm.toLowerCase())); + return searchFields.some((field) => (field || "").toLowerCase().includes(searchTerm.toLowerCase())); }); return filteredDonations; }; diff --git a/src/services/getPotData.ts b/src/services/getPotData.ts index 06b59e4f..51393386 100644 --- a/src/services/getPotData.ts +++ b/src/services/getPotData.ts @@ -215,13 +215,14 @@ export const getDonations = ({ potDetail: PotDetail; updateState: UpdateState; }) => { - const donations = getPotData(potId, "donations") || []; + const donations = getPotData(potId, "donations"); if (donations) updateState(donations); - if (potDetail.public_donations_count !== donations.length) { + if (potDetail.public_donations_count !== donations?.length) { asyncGetPublicDonations(potDetail, potId).then((paginatedDonations) => { const currentDonations = paginatedDonations ? paginatedDonations.flat() : []; + currentDonations.reverse(); setPotData(potId, "donations", currentDonations); updateState(currentDonations); }); @@ -281,7 +282,6 @@ export const getFlaggedAccounts = ({ export const getSponsorships = ({ potId, updateState }: { potId: string; updateState: UpdateState }) => { const sponsors = getPotData(potId, "sponsors"); - console.log("sponsors", sponsors); if (sponsors) updateState(sponsors); From 7d569c648f04d032176cea18844eb2ad67e934a7 Mon Sep 17 00:00:00 2001 From: M-RB3 Date: Wed, 22 May 2024 16:35:08 +0400 Subject: [PATCH 05/18] update sponsors --- src/pages/Pot/NavPages/Sponsors/Sponsors.tsx | 81 +++++++++++--------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/src/pages/Pot/NavPages/Sponsors/Sponsors.tsx b/src/pages/Pot/NavPages/Sponsors/Sponsors.tsx index 5e7a0e53..566a6e19 100644 --- a/src/pages/Pot/NavPages/Sponsors/Sponsors.tsx +++ b/src/pages/Pot/NavPages/Sponsors/Sponsors.tsx @@ -1,50 +1,59 @@ -import { State, state, useParams } from "alem"; -import PotSDK from "@app/SDK/pot"; -import { PotDetail } from "@app/types"; +import { useEffect, useParams, useState } from "alem"; +import { getConfig, getSponsorships } from "@app/services/getPotData"; +import { PotDetail, PotDonation } from "@app/types"; import SponsorsBoard from "../../components/SponsorsBoard/SponsorsBoard"; import SponsorsTable from "../../components/SponsorsTable/SponsorsTable"; import { Container, TableContainer } from "./styles"; -const Sponsors = ({ potDetail }: { potDetail: PotDetail }) => { +const Sponsors = () => { const { potId } = useParams(); - let sponsorshipDonations = PotSDK.getMatchingPoolDonations(potId); - - State.init({ - sponsorshipDonations: null, - }); - - if (sponsorshipDonations && !state.sponsorshipDonations) { - // accumulate donations for each address - sponsorshipDonations = sponsorshipDonations.reduce((accumulator: any, currentDonation: any) => { - accumulator[currentDonation.donor_id] = { - amount: accumulator[currentDonation.donor_id].amount || 0 + currentDonation.net_amount, - ...currentDonation, - }; - return accumulator; - }, {}); - - // add % share of total to each donation - const total = parseFloat(potDetail.matching_pool_balance); - - sponsorshipDonations = Object.values(sponsorshipDonations).sort((a: any, b: any) => b.amount - a.amount); - sponsorshipDonations = sponsorshipDonations.map((donation: any) => { - return { - ...donation, - percentage_share: ((donation.amount / total) * 100).toFixed(2).replace(/[.,]00$/, ""), - }; - }); - State.update({ sponsorshipDonations }); - } - - if (!state.sponsorshipDonations) return
; + const [sponsorshipDonations, setSponsorshipDonations] = useState(null); + const [potDetail, setPotDetail] = useState(null); + + useEffect(() => { + if (!potDetail) { + getConfig({ + potId, + updateState: setPotDetail, + }); + } + if (!sponsorshipDonations && potDetail) { + getSponsorships({ + potId, + updateState: (donations) => { + let sponsorshipDonations = donations.reduce((accumulator: any, currentDonation: any) => { + accumulator[currentDonation.donor_id] = { + amount: accumulator[currentDonation.donor_id].amount || 0 + currentDonation.net_amount, + ...currentDonation, + }; + return accumulator; + }, {}); + + // add % share of total to each donation + const total = parseFloat(potDetail.matching_pool_balance); + + sponsorshipDonations = Object.values(sponsorshipDonations).sort((a: any, b: any) => b.amount - a.amount); + sponsorshipDonations = sponsorshipDonations.map((donation: any) => { + return { + ...donation, + percentage_share: ((donation.amount / total) * 100).toFixed(2).replace(/[.,]00$/, ""), + }; + }); + setSponsorshipDonations(sponsorshipDonations); + }, + }); + } + }, [potDetail]); + + if (!sponsorshipDonations) return
; return ( - + - + ); From e2facba45eec4cac8b5c6b2093915a8fae0affcc Mon Sep 17 00:00:00 2001 From: M-RB3 Date: Wed, 22 May 2024 18:53:56 +0400 Subject: [PATCH 06/18] finish update flagging --- src/components/Card/Card.tsx | 5 +- src/pages/Pot/NavPages/Payouts/Payouts.tsx | 118 ++++++++---------- src/pages/Pot/NavPages/Projects/Projects.tsx | 10 +- src/pages/Pot/Pot.tsx | 2 +- .../FlaggedAccounts/FlaggedAccounts.tsx | 47 ++++--- src/pages/Pot/components/Header/Header.tsx | 2 +- .../PoolAllocationTable.tsx | 9 +- src/services/getPotData.ts | 70 +++++------ src/types.ts | 11 +- src/utils/calculatePayouts.ts | 4 +- 10 files changed, 141 insertions(+), 137 deletions(-) diff --git a/src/components/Card/Card.tsx b/src/components/Card/Card.tsx index 354d5a6f..4508b9ae 100644 --- a/src/components/Card/Card.tsx +++ b/src/components/Card/Card.tsx @@ -1,4 +1,4 @@ -import { Big, RouteLink, Social, context, useEffect, useMemo, useParams, useState } from "alem"; +import { Big, RouteLink, Social, context } from "alem"; import DonateSDK from "@app/SDK/donate"; import PotSDK from "@app/SDK/pot"; import { useDonationModal } from "@app/hooks/useDonationModal"; @@ -33,6 +33,7 @@ import { const Card = (props: any) => { const { payoutDetails, allowDonate: _allowDonate, potId } = props; + // Start Modals provider const Modals = useModals(); const { setDonationModalProps } = useDonationModal(); @@ -196,7 +197,7 @@ const Card = (props: any) => { {payoutDetails && ( Estimated matched amount - {yoctosToNear(payoutDetails.matchingAmount) || "- N"} + {yoctosToNear(payoutDetails.amount) || "- N"} )} diff --git a/src/pages/Pot/NavPages/Payouts/Payouts.tsx b/src/pages/Pot/NavPages/Payouts/Payouts.tsx index ddb30141..69e1ad7a 100644 --- a/src/pages/Pot/NavPages/Payouts/Payouts.tsx +++ b/src/pages/Pot/NavPages/Payouts/Payouts.tsx @@ -1,9 +1,7 @@ -import { context, useParams, State, state } from "alem"; -import PotSDK from "@app/SDK/pot"; +import { useParams, State, state, useEffect } from "alem"; import ArrowDown from "@app/assets/svgs/ArrowDown"; import ProfileImage from "@app/components/mob.near/ProfileImage"; -import { PotDetail } from "@app/types"; -import calculatePayouts from "@app/utils/calculatePayouts"; +import { getConfig, getDonations, getFlaggedAccounts, getPayout } from "@app/services/getPotData"; import yoctosToNear from "@app/utils/yoctosToNear"; import FlaggedAccounts from "../../components/FlaggedAccounts/FlaggedAccounts"; import PayoutsChallenges from "../../components/PayoutsChallenges/PayoutsChallenges"; @@ -25,67 +23,59 @@ import { WarningText, } from "./styles"; -const Payouts = ({ potDetail, allDonations }: { potDetail: PotDetail; allDonations: any }) => { +const Payouts = () => { const { potId } = useParams(); State.init({ - allPayouts: null, + potDetail: null, + allDonations: null, + allPayouts: null, // array + allPayoutsDetails: null, // obj filteredPayouts: null, flaggedAddresses: null, }); - const { allPayouts, filteredPayouts, flaggedAddresses } = state; + const { allPayouts, filteredPayouts, flaggedAddresses, potDetail, allDonations } = state; - if (!flaggedAddresses) { - PotSDK.getFlaggedAccounts(potDetail, potId) - .then((data) => { - const listOfFlagged: any = []; - data.forEach((adminFlaggedAcc: any) => { - const addresses = Object.keys(adminFlaggedAcc.potFlaggedAcc); - listOfFlagged.push(...addresses); - }); - State.update({ flaggedAddresses: listOfFlagged }); - }) - .catch((err) => console.log("error getting the flagged accounts ", err)); - } + useEffect(() => { + if (!potDetail) + getConfig({ + potId, + updateState: (potDetail) => State.update({ potDetail }), + }); + if (!allDonations && potDetail) + getDonations({ + potDetail, + potId, + updateState: (allDonations) => State.update({ allDonations }), + }); + if (!flaggedAddresses && potDetail) + getFlaggedAccounts({ + potDetail, + potId, + updateState: (flaggedAddresses) => State.update({ flaggedAddresses }), + type: "list", + }); + }, [potDetail]); - if (!allPayouts && allDonations && potDetail && flaggedAddresses) { - calculatePayouts(allDonations, potDetail.matching_pool_balance, flaggedAddresses).then((calculatedPayouts: any) => { - if (potDetail.payouts.length) { - // handle these payouts, which don't contain all the info needed - // pot payouts contain id, project_id, amount & paid_at - // loop through potDetail payouts and synthesize the two sets of payouts, so projectId and matchingAmount are taken from potDetail payouts, and donorCount and totalAmount are taken from calculatedPayouts - const synthesizedPayouts = potDetail.payouts.map((payout) => { - const { project_id, amount } = payout; - const { totalAmount, donorCount } = calculatedPayouts[project_id]; - return { - projectId: project_id, - totalAmount, - matchingAmount: amount, - donorCount, - }; - }); - State.update({ allPayouts: synthesizedPayouts, filteredPayouts: synthesizedPayouts }); - } else { - // calculate estimated payouts - const allPayouts = Object.entries(calculatedPayouts).map( - ([projectId, { totalAmount, matchingAmount, donorCount }]: any) => { - return { - projectId, - totalAmount, - matchingAmount, - donorCount, - }; - }, - ); // TODO: refactor to use PotsSDK (note that this is duplicated in Pots/Projects.jsx) - allPayouts.sort((a, b) => { - // sort by matching pool allocation, highest to lowest - return b.matchingAmount - a.matchingAmount; - }); - State.update({ allPayouts, filteredPayouts: allPayouts }); - } + useEffect(() => { + console.log({ + potDetail, + flaggedAddresses, + allDonations, }); - } + + if (potDetail && flaggedAddresses && allDonations && !allPayouts) { + getPayout({ + allDonations, + flaggedAddresses, + potDetail, + potId, + withTotalAmount: true, + updateState: (payouts) => State.update({ allPayouts: payouts, filteredPayouts: payouts }), + }); + } + }, [potDetail, allDonations, flaggedAddresses]); const searchPayouts = (searchTerm: string) => { // filter payouts that match the search term (donor_id, project_id) @@ -96,7 +86,7 @@ const Payouts = ({ potDetail, allDonations }: { potDetail: PotDetail; allDonatio }); filteredPayouts.sort((a: any, b: any) => { // sort by matching pool allocation, highest to lowest - return b.matchingAmount - a.matchingAmount; + return b.amount - a.amount; }); return filteredPayouts; }; @@ -105,7 +95,7 @@ const Payouts = ({ potDetail, allDonations }: { potDetail: PotDetail; allDonatio return ( - + {!potDetail.all_paid_out && ( @@ -162,7 +152,7 @@ const Payouts = ({ potDetail, allDonations }: { potDetail: PotDetail; allDonatio No payouts to display ) : ( filteredPayouts.map((payout: any, index: number) => { - const { projectId, donorCount, matchingAmount, totalAmount } = payout; + const { project_id, donorCount, amount, totalAmount } = payout; return ( @@ -173,12 +163,12 @@ const Payouts = ({ potDetail, allDonations }: { potDetail: PotDetail; allDonatio width: "24px", }} className="profile-image" - accountId={projectId} + accountId={project_id} /> - - {projectId.length > MAX_ACCOUNT_ID_DISPLAY_LENGTH - ? projectId.slice(0, MAX_ACCOUNT_ID_DISPLAY_LENGTH) + "..." - : projectId} + + {project_id.length > MAX_ACCOUNT_ID_DISPLAY_LENGTH + ? project_id.slice(0, MAX_ACCOUNT_ID_DISPLAY_LENGTH) + "..." + : project_id} {/* Total Raised */} @@ -197,7 +187,7 @@ const Payouts = ({ potDetail, allDonations }: { potDetail: PotDetail; allDonatio {/* Matching Pool Allocation */} - {yoctosToNear(matchingAmount, true)} Allocated + {yoctosToNear(amount, true)} Allocated diff --git a/src/pages/Pot/NavPages/Projects/Projects.tsx b/src/pages/Pot/NavPages/Projects/Projects.tsx index 9fd5f248..c37d9d54 100644 --- a/src/pages/Pot/NavPages/Projects/Projects.tsx +++ b/src/pages/Pot/NavPages/Projects/Projects.tsx @@ -12,14 +12,14 @@ type Props = { allDonations: any; }; -const Projects = (props: Props) => { +const Projects = () => { const { potId } = useParams(); const [projects, setProjects] = useState(null); const [filteredProjects, setFilteredProjects] = useState([]); const [donations, setDonations] = useState(null); const [flaggedAddresses, setFlaggedAddresses] = useState(null); - const [payouts, setPayouts] = useState | null>(null); + const [payouts, setPayouts] = useState(null); const [potDetail, setPotDetail] = useState(null); const Loading = () => ( @@ -65,7 +65,7 @@ const Projects = (props: Props) => { }, [potDetail]); useEffect(() => { - if (potDetail && flaggedAddresses && donations) { + if (potDetail && flaggedAddresses && donations && !payouts) { getPayout({ allDonations: donations, flaggedAddresses, @@ -77,7 +77,7 @@ const Projects = (props: Props) => { } }, [potDetail, flaggedAddresses, donations]); - if (!projects || !potDetail) return ; + if (projects === null || potDetail === null) return ; const { public_round_start_ms, public_round_end_ms } = potDetail; @@ -149,7 +149,7 @@ const Projects = (props: Props) => { projects, projectId: project.project_id, allowDonate: publicRoundOpen && project.project_id !== context.accountId, - payoutDetails: (payouts || {})[project.project_id] || { + payoutDetails: (payouts || []).find((payout: Payout) => payout.project_id === project.project_id) || { donorCount: 0, matchingAmount: "0", totalAmount: "0", diff --git a/src/pages/Pot/Pot.tsx b/src/pages/Pot/Pot.tsx index 9c463f50..072eb5dd 100644 --- a/src/pages/Pot/Pot.tsx +++ b/src/pages/Pot/Pot.tsx @@ -76,7 +76,7 @@ const Pot = () => { return ( - + {/* */}
diff --git a/src/pages/Pot/components/FlaggedAccounts/FlaggedAccounts.tsx b/src/pages/Pot/components/FlaggedAccounts/FlaggedAccounts.tsx index 3f884ecf..ab9786f7 100644 --- a/src/pages/Pot/components/FlaggedAccounts/FlaggedAccounts.tsx +++ b/src/pages/Pot/components/FlaggedAccounts/FlaggedAccounts.tsx @@ -1,36 +1,45 @@ -import { useParams, useState } from "alem"; +import { useEffect, useParams, useState } from "alem"; import PotSDK from "@app/SDK/pot"; import ProfileImage from "@app/components/mob.near/ProfileImage"; +import { getConfig, getFlaggedAccounts } from "@app/services/getPotData"; import { PotDetail } from "@app/types"; import hrefWithParams from "@app/utils/hrefWithParams"; import { Container, Flag, Line, Table, Title } from "./styles"; -const FlaggedAccounts = ({ potDetail }: { potDetail: PotDetail }) => { +const FlaggedAccounts = () => { const { potId } = useParams(); const [flaggedAddresses, setFlaggedAddresses] = useState(null); + const [potDetail, setPotDetail] = useState(null); const [toggleView, setToggleView] = useState(null); - if (!flaggedAddresses) { - PotSDK.getFlaggedAccounts(potDetail, potId) - .then((data) => { - const listOfFlagged: any = []; - data.forEach((adminFlaggedAcc: any) => { - const addresses = Object.keys(adminFlaggedAcc.potFlaggedAcc); - addresses.forEach((address) => { - listOfFlagged.push({ - address: address, - reason: adminFlaggedAcc.potFlaggedAcc[address], - flaggedBy: adminFlaggedAcc.flaggedBy, - role: adminFlaggedAcc.role, + useEffect(() => { + if (!potDetail) getConfig({ potId, updateState: setPotDetail }); + if (!flaggedAddresses && potDetail) + getFlaggedAccounts({ + potId, + potDetail, + type: "obj", + updateState: (data) => { + console.log("data", data); + + const listOfFlagged: any = []; + data.forEach((adminFlaggedAcc: any) => { + const addresses = Object.keys(adminFlaggedAcc.potFlaggedAcc); + addresses.forEach((address) => { + listOfFlagged.push({ + address: address, + reason: adminFlaggedAcc.potFlaggedAcc[address], + flaggedBy: adminFlaggedAcc.flaggedBy, + role: adminFlaggedAcc.role, + }); }); }); - }); - setFlaggedAddresses(listOfFlagged); - }) - .catch((err) => console.log("error getting the flagged accounts ", err)); - } + setFlaggedAddresses(listOfFlagged); + }, + }); + }, [potDetail]); return !flaggedAddresses ? ( "Loading..." diff --git a/src/pages/Pot/components/Header/Header.tsx b/src/pages/Pot/components/Header/Header.tsx index 4b8d2f17..0c84b10a 100644 --- a/src/pages/Pot/components/Header/Header.tsx +++ b/src/pages/Pot/components/Header/Header.tsx @@ -242,7 +242,7 @@ const Header = ({ potDetail, allDonations }: { potDetail: PotDetail; allDonation
- +
{isApplicationModalOpen && ( { } }; - const uniqueDonorIds = allDonations ? new Set(allDonations.map((donation: any) => donation.donor_id)) : new Set([]); - - const donorsCount = uniqueDonorIds.size; + const donorsCount = useMemo(() => { + const uniqueDonorIds = allDonations ? new Set(allDonations.map((donation: any) => donation.donor_id)) : new Set([]); + return uniqueDonorIds.size; + }, [allDonations]); const Table = ({ donations, totalAmount, totalUniqueDonors, title }: any) => { return ( diff --git a/src/services/getPotData.ts b/src/services/getPotData.ts index 51393386..f0667ef1 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 } from "@app/types"; +import { FlaggedAddress, Payout, PotApplication, PotDetail, PotDonation, CalculatedPayout } from "@app/types"; import calculatePayouts from "@app/utils/calculatePayouts"; // type UpdateState = (newValues: Partial) => void; @@ -24,11 +24,6 @@ export type ProjectsState = { payouts?: Record | null; }; -type CalculatedPayout = { - project_id: string; - amount: number; -}; - function isEqual(obj1: any, obj2: any) { // Check if both are the same reference if (obj1 === obj2) return true; @@ -148,6 +143,7 @@ export const getPayout = ({ const storageKey = withTotalAmount ? "payouts-obj" : "payouts"; const payouts = getPotData(potId, storageKey); + console.log("payouts", payouts); if (payouts) updateState(payouts); @@ -156,29 +152,33 @@ export const getPayout = ({ if (isEqual(potDetail.payouts, payouts)) return; else { const sortedPayouts = potDetail.payouts; - sortedPayouts.sort((a: any, b: any) => b.matchingAmount - a.matchingAmount); + sortedPayouts.sort((a: any, b: any) => b.amount - a.amount); setPotData(potId, storageKey, sortedPayouts); updateState(sortedPayouts); } - } else if (allDonations.length && flaggedAddresses) + } else if (allDonations.length && flaggedAddresses) { calculatePayouts(allDonations, potDetail.matching_pool_balance, flaggedAddresses).then((calculatedPayouts) => { - const currentPayouts = Object.entries(calculatedPayouts) - .map(([projectId, { matchingAmount, donorCount, totalAmount }]: any) => ({ - project_id: projectId, - amount: matchingAmount, - donorCount, - totalAmount, - })) - .filter((payout) => payout.amount !== "0"); - currentPayouts.sort((a: any, b: any) => b.matchingAmount - a.matchingAmount); + const currentPayouts = potDetail.payouts + ? potDetail.payouts.map((payout: Payout) => ({ + ...payout, + donorCount: calculatedPayouts[payout.project_id].donorCount, + totalAmount: calculatedPayouts[payout.project_id].totalAmount, + })) + : Object.entries(calculatedPayouts).map(([projectId, { matchingAmount, donorCount, totalAmount }]: any) => ({ + project_id: projectId, + amount: matchingAmount, + donorCount, + totalAmount, + })); + currentPayouts.sort((a: any, b: any) => b.amount - a.amount); if (areListsEqual(currentPayouts, payouts)) return; else { - setPotData(potId, storageKey, withTotalAmount ? calculatedPayouts : currentPayouts); - updateState(withTotalAmount ? calculatedPayouts : currentPayouts); + setPotData(potId, storageKey, currentPayouts); + updateState(currentPayouts); } }); - else if (allDonations?.length === 0 && flaggedAddresses?.length === 0) { + } else if (allDonations?.length === 0 && flaggedAddresses?.length === 0) { updateState({}); } } @@ -249,29 +249,25 @@ export const getFlaggedAccounts = ({ updateState: UpdateState; type: "list" | "obj"; }) => { - const potData = getPotData(potId, "flaggedAccounts"); - let flaggedAddresses = potData.flaggedAddresses || []; + const flaggedAddresses = getPotData(potId, "flaggedAccounts") || []; + + const saveListOfFlagged = getListOfFlagged(flaggedAddresses); if (type === "list") { - flaggedAddresses = getListOfFlagged(flaggedAddresses); + updateState(saveListOfFlagged); + } else { + updateState(flaggedAddresses); } - updateState(flaggedAddresses); - PotSDK.getFlaggedAccounts(potDetail) + + PotSDK.getFlaggedAccounts(potDetail, potId) .then((data) => { - if (type === "list") { - const liftOfFlagged = getListOfFlagged(data); - if (liftOfFlagged.length === flaggedAddresses.length) return; - else { + const liftOfFlagged = getListOfFlagged(data); + + if (liftOfFlagged.length !== saveListOfFlagged.length) { + if (type === "list") { setPotData(potId, "flaggedAccounts", data); updateState(data); - } - } else { - const isNotEqual = data.some((adminFlaggedAcc: FlaggedAddress, idx: string) => { - if (adminFlaggedAcc?.potFlaggedAcc?.length === adminFlaggedAcc?.potFlaggedAcc?.length) return false; - else return true; - }); - - if (isNotEqual) { + } else { setPotData(potId, "flaggedAccounts", data); updateState(data); } diff --git a/src/types.ts b/src/types.ts index fc31d0ed..33286515 100644 --- a/src/types.ts +++ b/src/types.ts @@ -123,9 +123,16 @@ export type FlaggedAddress = { potFlaggedAcc: "string"; }; -export interface Payout { +export type Payout = { id: string; project_id: string; amount: string; paid_at: number; -} +}; + +export type CalculatedPayout = { + project_id: string; + amount: number; + donorCount: number; + totalAmount: string; +}; diff --git a/src/utils/calculatePayouts.ts b/src/utils/calculatePayouts.ts index da1d2f1e..1bf81001 100644 --- a/src/utils/calculatePayouts.ts +++ b/src/utils/calculatePayouts.ts @@ -1,12 +1,12 @@ import { Big, Near } from "alem"; import constants from "@app/constants"; -import { Payout } from "@app/types"; +import { CalculatedPayout } from "@app/types"; const calculatePayouts = ( allPotDonations: any, totalMatchingPool: any, blacklistedAccounts: any, -): Promise> => { +): Promise> => { const { NADABOT_CONTRACT_ID } = constants; // * QF/CLR logic taken from https://github.com/gitcoinco/quadratic-funding/blob/master/quadratic-funding/clr.py * From e1f627352b813d3ac5169ce5ad61349434d613c2 Mon Sep 17 00:00:00 2001 From: M-RB3 Date: Thu, 23 May 2024 12:32:34 +0400 Subject: [PATCH 07/18] update setting --- src/pages/Pot/NavPages/Projects/Projects.tsx | 2 +- src/pages/Pot/NavPages/Settings/Settings.tsx | 20 ++++-- src/services/getPotData.ts | 76 ++++++++++++-------- 3 files changed, 62 insertions(+), 36 deletions(-) diff --git a/src/pages/Pot/NavPages/Projects/Projects.tsx b/src/pages/Pot/NavPages/Projects/Projects.tsx index c37d9d54..cb862fd8 100644 --- a/src/pages/Pot/NavPages/Projects/Projects.tsx +++ b/src/pages/Pot/NavPages/Projects/Projects.tsx @@ -151,7 +151,7 @@ const Projects = () => { allowDonate: publicRoundOpen && project.project_id !== context.accountId, payoutDetails: (payouts || []).find((payout: Payout) => payout.project_id === project.project_id) || { donorCount: 0, - matchingAmount: "0", + amount: "0", totalAmount: "0", }, }} diff --git a/src/pages/Pot/NavPages/Settings/Settings.tsx b/src/pages/Pot/NavPages/Settings/Settings.tsx index cc684af0..cd79ac4d 100644 --- a/src/pages/Pot/NavPages/Settings/Settings.tsx +++ b/src/pages/Pot/NavPages/Settings/Settings.tsx @@ -1,6 +1,7 @@ -import { OverlayTrigger, Tooltip, context, useParams, useState } from "alem"; +import { OverlayTrigger, Tooltip, context, useEffect, useParams, useState } from "alem"; import PotSDK from "@app/SDK/pot"; import ProfileImage from "@app/components/mob.near/ProfileImage"; +import { getConfig } from "@app/services/getPotData"; import { PotDetail } from "@app/types"; import _address from "@app/utils/_address"; import hrefWithParams from "@app/utils/hrefWithParams"; @@ -8,15 +9,26 @@ import ConfigForm from "../ConfigForm/ConfigForm"; import getFields from "./getFields"; import { Admins, AdminsWrapper, Container, Detail, PrviewContainer, Title } from "./styles"; -const Settings = ({ potDetail }: { potDetail: PotDetail }) => { - const { owner, admins } = potDetail; - +const Settings = () => { const { potId } = useParams(); const [editSettings, setEditSettings] = useState(false); + const [potDetail, setPotDetail] = useState(null); const userIsAdminOrGreater = PotSDK.isUserPotAdminOrGreater(potId, context.accountId); + useEffect(() => { + if (!potDetail) + getConfig({ + potId, + updateState: setPotDetail, + }); + }, []); + + if (potDetail === null) return
; + const fields = getFields(potId, potDetail); + const { owner, admins } = potDetail; + const AdminsTooltip = () => (
diff --git a/src/services/getPotData.ts b/src/services/getPotData.ts index f0667ef1..3768ee62 100644 --- a/src/services/getPotData.ts +++ b/src/services/getPotData.ts @@ -142,44 +142,58 @@ export const getPayout = ({ }: GetPayoutProps) => { const storageKey = withTotalAmount ? "payouts-obj" : "payouts"; - const payouts = getPotData(potId, storageKey); - console.log("payouts", payouts); + const flaggedLength = flaggedAddresses.length; + const allDonationsLength = allDonations.length; + + const potData = getPotData(potId, storageKey); + + const payouts = potData?.payouts; + const storedFlaggedLength = potData?.flaggedLength; + const storedAllDonationsLength = potData?.allDonationsLength; + + // limit payment calculations by checking the calculatePayouts params + const isEqualStored = flaggedLength === storedFlaggedLength && storedAllDonationsLength === allDonationsLength; if (payouts) updateState(payouts); - if (flaggedAddresses) { - if (potDetail.payouts && !withTotalAmount) { - if (isEqual(potDetail.payouts, payouts)) return; - else { - const sortedPayouts = potDetail.payouts; - sortedPayouts.sort((a: any, b: any) => b.amount - a.amount); - setPotData(potId, storageKey, sortedPayouts); - updateState(sortedPayouts); - } - } else if (allDonations.length && flaggedAddresses) { + if (!isEqualStored || payouts.length === 0) { + if (potDetail.payouts.length && !withTotalAmount) { + const sortedPayouts = potDetail.payouts; + sortedPayouts.sort((a: any, b: any) => b.amount - a.amount); + setPotData(potId, storageKey, { + payouts: sortedPayouts, + flaggedLength, + allDonationsLength, + }); + updateState(sortedPayouts); + } else if (allDonations?.length === 0 && flaggedAddresses?.length === 0) { + updateState({}); + } else if (allDonations && flaggedAddresses) { calculatePayouts(allDonations, potDetail.matching_pool_balance, flaggedAddresses).then((calculatedPayouts) => { - const currentPayouts = potDetail.payouts - ? potDetail.payouts.map((payout: Payout) => ({ - ...payout, - donorCount: calculatedPayouts[payout.project_id].donorCount, - totalAmount: calculatedPayouts[payout.project_id].totalAmount, - })) - : Object.entries(calculatedPayouts).map(([projectId, { matchingAmount, donorCount, totalAmount }]: any) => ({ - project_id: projectId, - amount: matchingAmount, - donorCount, - totalAmount, - })); + const currentPayouts = + potDetail.payouts.length > 0 + ? potDetail.payouts.map((payout: Payout) => ({ + ...payout, + donorCount: calculatedPayouts[payout.project_id].donorCount, + totalAmount: calculatedPayouts[payout.project_id].totalAmount, + })) + : Object.entries(calculatedPayouts).map( + ([projectId, { matchingAmount, donorCount, totalAmount }]: any) => ({ + project_id: projectId, + amount: matchingAmount, + donorCount, + totalAmount, + }), + ); currentPayouts.sort((a: any, b: any) => b.amount - a.amount); - if (areListsEqual(currentPayouts, payouts)) return; - else { - setPotData(potId, storageKey, currentPayouts); - updateState(currentPayouts); - } + setPotData(potId, storageKey, { + payouts: currentPayouts, + flaggedLength, + allDonationsLength, + }); + updateState(currentPayouts); }); - } else if (allDonations?.length === 0 && flaggedAddresses?.length === 0) { - updateState({}); } } }; From dd86f3ee034ef9c78f9ba3f821979d20a4ba3972 Mon Sep 17 00:00:00 2001 From: M-RB3 Date: Thu, 23 May 2024 13:18:35 +0400 Subject: [PATCH 08/18] update pot header --- .../Pot/NavPages/Donations/Donations.tsx | 5 - src/pages/Pot/NavPages/Projects/Projects.tsx | 5 - src/pages/Pot/Pot.tsx | 32 +---- src/pages/Pot/components/Header/Header.tsx | 123 ++++++++++-------- .../components/HeaderStatus/HeaderStatus.tsx | 14 +- 5 files changed, 83 insertions(+), 96 deletions(-) diff --git a/src/pages/Pot/NavPages/Donations/Donations.tsx b/src/pages/Pot/NavPages/Donations/Donations.tsx index d72e58e9..65b6be41 100644 --- a/src/pages/Pot/NavPages/Donations/Donations.tsx +++ b/src/pages/Pot/NavPages/Donations/Donations.tsx @@ -6,11 +6,6 @@ import _address from "@app/utils/_address"; import DonationsTable from "../../components/DonationsTable/DonationsTable"; import { Container, DonationsCount, OuterText, OuterTextContainer, Sort } from "./styes"; -type Props = { - allDonations: any[]; - potDetail: PotDetail; -}; - const Donations = () => { const { potId } = useParams(); diff --git a/src/pages/Pot/NavPages/Projects/Projects.tsx b/src/pages/Pot/NavPages/Projects/Projects.tsx index cb862fd8..e6e40a84 100644 --- a/src/pages/Pot/NavPages/Projects/Projects.tsx +++ b/src/pages/Pot/NavPages/Projects/Projects.tsx @@ -7,11 +7,6 @@ import getTagsFromSocialProfileData from "@app/utils/getTagsFromSocialProfileDat import getTeamMembersFromSocialProfileData from "@app/utils/getTeamMembersFromSocialProfileData"; import { Centralized, Container, SearchBar, Title } from "./styles"; -type Props = { - potDetail: any; - allDonations: any; -}; - const Projects = () => { const { potId } = useParams(); diff --git a/src/pages/Pot/Pot.tsx b/src/pages/Pot/Pot.tsx index 072eb5dd..64996404 100644 --- a/src/pages/Pot/Pot.tsx +++ b/src/pages/Pot/Pot.tsx @@ -44,30 +44,6 @@ const Pot = () => { // default to home tab } - // Get total public donations - const allDonationsPaginated = useCache(() => { - const limit = 480; // number of donations to fetch per req - - const donationsCount = potDetail.public_donations_count; - const paginations = [...Array(Math.ceil(donationsCount / limit)).keys()]; - - try { - const allDonations = paginations.map((index) => - PotSDK.asyncGetPublicRoundDonations(potId, { - from_index: index * limit, - limit: limit, - }), - ); - - return Promise.all(allDonations); - } catch (error) { - console.error(`error getting public donations`, error); - return Promise.all([]); - } - }, "pot-public-donations"); - - const allDonations = allDonationsPaginated ? allDonationsPaginated.flat() : null; - const options = navOptions(potId || "", potDetail); const SelectedNavComponent = useMemo(() => { @@ -76,14 +52,12 @@ const Pot = () => { return ( - {/* */} -
+ +
- - {SelectedNavComponent && } - + {SelectedNavComponent && } ); }; diff --git a/src/pages/Pot/components/Header/Header.tsx b/src/pages/Pot/components/Header/Header.tsx index 0c84b10a..4d689d9c 100644 --- a/src/pages/Pot/components/Header/Header.tsx +++ b/src/pages/Pot/components/Header/Header.tsx @@ -5,7 +5,8 @@ import constants from "@app/constants"; import { useDonationModal } from "@app/hooks/useDonationModal"; import useModals from "@app/hooks/useModals"; import CopyIcon from "@app/pages/Project/components/CopyIcon"; -import { PotDetail } from "@app/types"; +import { getConfig, getDonations, getFlaggedAccounts, getPotProjects } from "@app/services/getPotData"; +import { PotDetail, PotDonation } from "@app/types"; import calculatePayouts from "@app/utils/calculatePayouts"; import getTransactionsFromHashes from "@app/utils/getTransactionsFromHashes"; import nearToUsd from "@app/utils/nearToUsd"; @@ -18,23 +19,7 @@ import PoolAllocationTable from "../PoolAllocationTable/PoolAllocationTable"; import SuccessFundModal, { ExtendedFundDonation } from "../SuccessFundModal/SuccessFundModal"; import { ButtonsWrapper, Container, Description, Fund, HeaderWrapper, Referral, Title } from "./styles"; -const Header = ({ potDetail, allDonations }: { potDetail: PotDetail; allDonations: any }) => { - const { - admins, - chef, - owner, - pot_name, - pot_description, - matching_pool_balance, - public_round_end_ms, - public_round_start_ms, - application_start_ms, - application_end_ms, - cooldown_end_ms: _cooldown_end_ms, - all_paid_out, - registry_provider, - } = potDetail; - +const Header = () => { const { IPFS_BASE_URL, NADA_BOT_URL } = constants; const { potId, transactionHashes } = useParams(); @@ -55,29 +40,59 @@ const Header = ({ potDetail, allDonations }: { potDetail: PotDetail; allDonation const [isDao, setIsDao] = useState(null); const [applicationSuccess, setApplicationSuccess] = useState(null); const [flaggedAddresses, setFlaggedAddresses] = useState(null); + const [potDetail, setPotDetail] = useState(null); + const [allDonations, setAlldonations] = useState(null); // set fund mathcing pool success const [fundDonation, setFundDonation] = useState(null); - const verifyIsOnRegistry = (address: any) => { - Near.asyncView("lists.potlock.near", "get_registrations_for_registrant", { - registrant_id: address, - }).then((registrations) => { - const registration = registrations.find( - (registration: any) => registration.list_id === 1, // potlock registry list id - ); - if (registration) { - setRegistryStatus(registration.status); - } - }); - }; - useEffect(() => { - if (!isDao) { - verifyIsOnRegistry(context.accountId || ""); + if (!potDetail) + getConfig({ + potId, + updateState: setPotDetail, + }); + if (!projects) + getPotProjects({ + potId, + isApprpved: true, + updateState: setProjects, + }); + if (potDetail && !flaggedAddresses) { + getFlaggedAccounts({ + potId, + potDetail, + type: "list", + updateState: setFlaggedAddresses, + }); } - }, []); + if (!allDonations && potDetail) + getDonations({ + potId, + potDetail, + updateState: setAlldonations, + }); + }, [potDetail]); + + if (potDetail === null) return
; // Handle fund success for web wallet + + const { + admins, + chef, + owner, + pot_name, + pot_description, + matching_pool_balance, + public_round_end_ms, + public_round_start_ms, + application_start_ms, + application_end_ms, + cooldown_end_ms: _cooldown_end_ms, + all_paid_out, + registry_provider, + } = potDetail; + useEffect(() => { if (accountId && transactionHashes) { getTransactionsFromHashes(transactionHashes, accountId).then((trxs) => { @@ -99,20 +114,31 @@ const Header = ({ potDetail, allDonations }: { potDetail: PotDetail; allDonation } }, []); + const verifyIsOnRegistry = (address: any) => { + Near.asyncView("lists.potlock.near", "get_registrations_for_registrant", { + registrant_id: address, + }).then((registrations) => { + const registration = registrations.find( + (registration: any) => registration.list_id === 1, // potlock registry list id + ); + if (registration) { + setRegistryStatus(registration.status); + } + }); + }; + + useEffect(() => { + if (!isDao) { + verifyIsOnRegistry(context.accountId || ""); + } + }, []); + const projectNotRegistered = registryStatus === null; const userIsAdminOrGreater = admins.includes(accountId) || owner === accountId; const userIsChefOrGreater = userIsAdminOrGreater || chef === accountId; const existingApplication = PotSDK.getApplicationByProjectId(potId, context.accountId); - useEffect(() => { - if (!projects) { - PotSDK.asyncGetApprovedApplications(potId).then((projects: any) => { - setProjects(projects); - }); - } - }, []); - const applicationExists = existingApplication || applicationSuccess; const now = Date.now(); @@ -136,19 +162,6 @@ const Header = ({ potDetail, allDonations }: { potDetail: PotDetail; allDonation const payoutsChallenges = PotSDK.getPayoutsChallenges(potId); - if (!flaggedAddresses) { - PotSDK.getFlaggedAccounts(potDetail, potId) - .then((data) => { - const listOfFlagged: any = []; - data.forEach((adminFlaggedAcc: any) => { - const addresses = Object.keys(adminFlaggedAcc.potFlaggedAcc); - listOfFlagged.push(...addresses); - }); - setFlaggedAddresses(listOfFlagged); - }) - .catch((err) => console.log("error getting the flagged accounts ", err)); - } - const handleSetPayouts = () => { if (allDonations && flaggedAddresses !== null) { calculatePayouts(allDonations, matching_pool_balance, flaggedAddresses).then((calculatedPayouts: any) => { diff --git a/src/pages/Pot/components/HeaderStatus/HeaderStatus.tsx b/src/pages/Pot/components/HeaderStatus/HeaderStatus.tsx index ee8c34e9..4399580f 100644 --- a/src/pages/Pot/components/HeaderStatus/HeaderStatus.tsx +++ b/src/pages/Pot/components/HeaderStatus/HeaderStatus.tsx @@ -1,14 +1,24 @@ -import { useState } from "alem"; +import { useEffect, useParams, useState } from "alem"; import styled from "styled-components"; +import { getConfig } from "@app/services/getPotData"; import { PotDetail } from "@app/types"; import TimeLeft from "../TimeLeft"; import ProgressBar from "./ProgressBar"; import statsList from "./statsList"; import { Loader, State, Wrapper } from "./styles"; -const HeaderStatus = ({ potDetail }: { potDetail: PotDetail }) => { +const HeaderStatus = () => { + const { potId } = useParams(); const [mobileMenuActive, setMobileMenuActive] = useState(false); + const [potDetail, setPotDetail] = useState(null); + + useEffect(() => { + if (!potDetail) getConfig({ potId, updateState: setPotDetail }); + }, []); + + if (potDetail === null) return ""; + const stats = statsList(potDetail); const getIndexOfActive = () => { From 26d221de47dca0a6de7b6d03a0269e54dc1c88ab Mon Sep 17 00:00:00 2001 From: M-RB3 Date: Thu, 23 May 2024 13:22:04 +0400 Subject: [PATCH 09/18] set the card back to statefill for now --- src/components/Card/Card.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/Card/Card.tsx b/src/components/Card/Card.tsx index 4508b9ae..a853df4a 100644 --- a/src/components/Card/Card.tsx +++ b/src/components/Card/Card.tsx @@ -1,4 +1,4 @@ -import { Big, RouteLink, Social, context } from "alem"; +import { Big, RouteLink, Social, context, useMemo, useParams } from "alem"; import DonateSDK from "@app/SDK/donate"; import PotSDK from "@app/SDK/pot"; import { useDonationModal } from "@app/hooks/useDonationModal"; @@ -32,7 +32,9 @@ import { } from "./styles"; const Card = (props: any) => { - const { payoutDetails, allowDonate: _allowDonate, potId } = props; + const { potId } = useParams(); + + const { payoutDetails, allowDonate: _allowDonate } = props; // Start Modals provider const Modals = useModals(); @@ -66,7 +68,7 @@ const Card = (props: any) => { return totalDonationAmountNear.toString(); }; - const totalAmountNear = getTotalAmountNear(); + const totalAmountNear = useMemo(getTotalAmountNear, [donationsForProject, payoutDetails]); const getImageSrc = (image: any) => { const defaultImageUrl = "https://ipfs.near.social/ipfs/bafkreih4i6kftb34wpdzcuvgafozxz6tk6u4f5kcr2gwvtvxikvwriteci"; From 8df9a1a2372832a8aee577fcd6e25d79a83e1748 Mon Sep 17 00:00:00 2001 From: M-RB3 Date: Fri, 24 May 2024 01:21:35 +0400 Subject: [PATCH 10/18] fix project success --- src/pages/CreateProject/CreateProject.tsx | 4 ++-- src/pages/CreateProject/components/CreateForm/CreateForm.tsx | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/pages/CreateProject/CreateProject.tsx b/src/pages/CreateProject/CreateProject.tsx index 808b7ce8..57ddd976 100644 --- a/src/pages/CreateProject/CreateProject.tsx +++ b/src/pages/CreateProject/CreateProject.tsx @@ -5,8 +5,8 @@ import Header from "./components/Header/Header"; const CreateProject = () => { const { tab } = useParams(); - const registeration = ListsSDK.getRegistration(null, context.accountId); - const edit = tab === "editproject" || registeration; + // const registeration = ListsSDK.getRegistration(null, context.accountId); + const edit = tab === "editproject"; return ( <> diff --git a/src/pages/CreateProject/components/CreateForm/CreateForm.tsx b/src/pages/CreateProject/components/CreateForm/CreateForm.tsx index 9ed25af3..fb0f90ba 100644 --- a/src/pages/CreateProject/components/CreateForm/CreateForm.tsx +++ b/src/pages/CreateProject/components/CreateForm/CreateForm.tsx @@ -94,9 +94,7 @@ const CreateForm = (props: { edit: boolean }) => { } }, [policy]); - const registeredProject = useMemo(() => { - return ListsSDK.getRegistration(null, state.isDao ? state.daoAddress : context.accountId); - }, [state.isDao, state.daoAddress]); + const registeredProject = ListsSDK.getRegistration(null, state.isDao ? state.daoAddress : context.accountId); const proposals: any = checkDao ? Near.view(state.daoAddress, "get_proposals", { From b5f4a139de2f9265e329757c4aa7216b84a32c24 Mon Sep 17 00:00:00 2001 From: M-RB3 Date: Fri, 24 May 2024 01:45:03 +0400 Subject: [PATCH 11/18] fix double fetch on list sdk --- src/SDK/lists.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/SDK/lists.js b/src/SDK/lists.js index c0c86e16..c2e2875f 100644 --- a/src/SDK/lists.js +++ b/src/SDK/lists.js @@ -34,9 +34,7 @@ const ListsSDK = { const registration = registrations.find( (registration) => registration.list_id === (listId || potlockRegistryListId), ); - return Near.view(_listContractId, "get_registration", { - registration_id: registration.id, - }); + return registration; } }, asyncGetRegistration: (listId, registrantId) => { From 10430e41ebc3eeb382dca72d87434aa371d99551 Mon Sep 17 00:00:00 2001 From: M-RB3 Date: Fri, 24 May 2024 01:45:46 +0400 Subject: [PATCH 12/18] make card stateless --- src/components/Card/ButtonDonation.tsx | 36 +++++++++++++++++ src/components/Card/Card.tsx | 40 +++++-------------- src/components/Card/styles.ts | 26 +----------- .../ModalDonation/AmountInput/AmountInput.tsx | 2 +- .../ConfirmDirect/ConfirmDirect.tsx | 2 +- .../ModalDonation/ConfirmPot/ConfirmPot.tsx | 2 +- src/modals/ModalDonation/FormPot/FormPot.tsx | 2 +- src/{utils => modules}/nearToUsd.ts | 0 .../SuccessfullRegister.tsx | 2 +- .../Donor/NavPages/Donations/Donations.tsx | 2 +- .../DonorsLeaderboard/DonorsLeaderboard.tsx | 2 +- src/pages/Pot/NavPages/Projects/Projects.tsx | 2 +- src/pages/Pot/components/Header/Header.tsx | 2 +- .../PoolAllocationTable.tsx | 2 +- .../PoolAllocationTable/Table/Table.tsx | 2 +- .../SponsorsTable/SponsorsTable.tsx | 2 +- .../PotlockFunding/PotlockFunding.tsx | 2 +- src/utils/nearToUsdWithFallback.ts | 2 +- src/utils/yoctosToUsd.ts | 4 +- src/utils/yoctosToUsdWithFallback.ts | 2 +- 20 files changed, 65 insertions(+), 71 deletions(-) create mode 100644 src/components/Card/ButtonDonation.tsx rename src/{utils => modules}/nearToUsd.ts (100%) diff --git a/src/components/Card/ButtonDonation.tsx b/src/components/Card/ButtonDonation.tsx new file mode 100644 index 00000000..aae5ab5d --- /dev/null +++ b/src/components/Card/ButtonDonation.tsx @@ -0,0 +1,36 @@ +import { context, useEffect } from "alem"; +import { useDonationModal } from "@app/hooks/useDonationModal"; +import useModals from "@app/hooks/useModals"; +import Button from "../Button"; + +const ButtonDonation = ({ allowDonate, projectId }: { allowDonate: boolean; projectId: string }) => { + const Modals = useModals(); + const { setDonationModalProps } = useDonationModal(); + useEffect(() => {}, []); // make the component statefull so it does not break + return ( +
e.preventDefault()} + style={{ + cursor: "default", + color: "#292929", + }} + > + + {allowDonate && context.accountId && ( + + )} +
+ ); +}; + +export default ButtonDonation; diff --git a/src/components/Card/Card.tsx b/src/components/Card/Card.tsx index a853df4a..99d990a0 100644 --- a/src/components/Card/Card.tsx +++ b/src/components/Card/Card.tsx @@ -1,8 +1,6 @@ -import { Big, RouteLink, Social, context, useMemo, useParams } from "alem"; +import { Big, RouteLink, Social, useEffect } from "alem"; import DonateSDK from "@app/SDK/donate"; import PotSDK from "@app/SDK/pot"; -import { useDonationModal } from "@app/hooks/useDonationModal"; -import useModals from "@app/hooks/useModals"; import routesPath from "@app/routes/routesPath"; import _address from "@app/utils/_address"; import getTagsFromSocialProfileData from "@app/utils/getTagsFromSocialProfileData"; @@ -12,6 +10,7 @@ import yoctosToUsdWithFallback from "@app/utils/yoctosToUsdWithFallback"; import CardSkeleton from "../../pages/Projects/components/CardSkeleton"; import Button from "../Button"; import Image from "../mob.near/Image"; +import ButtonDonation from "./ButtonDonation"; import { Amount, AmountDescriptor, @@ -32,17 +31,10 @@ import { } from "./styles"; const Card = (props: any) => { - const { potId } = useParams(); - - const { payoutDetails, allowDonate: _allowDonate } = props; - - // Start Modals provider - const Modals = useModals(); - const { setDonationModalProps } = useDonationModal(); + const { payoutDetails, allowDonate: _allowDonate, potId } = props; const projectId = props.project.registrant_id || props.projectId; const profile = Social.getr(`${projectId}/profile`) as any; - const allowDonate = _allowDonate ?? true; const MAX_DESCRIPTION_LENGTH = 80; @@ -68,7 +60,12 @@ const Card = (props: any) => { return totalDonationAmountNear.toString(); }; - const totalAmountNear = useMemo(getTotalAmountNear, [donationsForProject, payoutDetails]); + const totalAmountNear = getTotalAmountNear(); + // useMemo(getTotalAmountNear, [donationsForProject, payoutDetails]); + // console.log("totalAmountNear", totalAmountNear); + // console.log("profile", profile); + + if (profile === null || totalAmountNear === null) return ; const getImageSrc = (image: any) => { const defaultImageUrl = "https://ipfs.near.social/ipfs/bafkreih4i6kftb34wpdzcuvgafozxz6tk6u4f5kcr2gwvtvxikvwriteci"; @@ -102,11 +99,9 @@ const Card = (props: any) => { const tags = getTagsFromSocialProfileData(profile); - if (profile === null && totalAmountNear === null) return ; - return ( <> - + {/* */} @@ -181,20 +176,7 @@ const Card = (props: any) => { {payoutDetails.donorCount === 1 ? "Donor" : "Donors"} )} - {allowDonate && context.accountId && ( - - )} + {payoutDetails && ( diff --git a/src/components/Card/styles.ts b/src/components/Card/styles.ts index 3cd0fb1c..3d90e69a 100644 --- a/src/components/Card/styles.ts +++ b/src/components/Card/styles.ts @@ -16,7 +16,7 @@ export const CardContainer = styled.div` margin-right: auto; transition: all 300ms; &:hover { - transform: translateY(-1rem); + /* transform: translateY(-1rem); */ } `; @@ -111,30 +111,6 @@ export const DonationsInfoItem = styled.div` align-items: center; `; -export const DonationButton = styled.button` - flex-direction: row; - justify-content: center; - align-items: center; - padding: 16px 24px; - background: #fef6ee; - overflow: hidden; - box-shadow: 0px -2.700000047683716px 0px #4a4a4a inset; - border-radius: 6px; - border: 1px solid #4a4a4a; - gap: 8px; - display: inline-flex; - text-align: center; - color: #2e2e2e; - font-size: 14px; - line-height: 16px; - font-weight: 600; - - &:hover { - text-decoration: none; - cursor: pointer; - } -`; - export const Amount = styled.div` font-size: 17px; font-weight: 600; diff --git a/src/modals/ModalDonation/AmountInput/AmountInput.tsx b/src/modals/ModalDonation/AmountInput/AmountInput.tsx index a49add35..2f966e6a 100644 --- a/src/modals/ModalDonation/AmountInput/AmountInput.tsx +++ b/src/modals/ModalDonation/AmountInput/AmountInput.tsx @@ -1,6 +1,6 @@ import NearIcon from "@app/assets/svgs/near-icon"; import Select from "@app/components/Inputs/Select/Select"; -import nearToUsd from "@app/utils/nearToUsd"; +import nearToUsd from "@app/modules/nearToUsd"; import { Container, DropdownWrapper, PotDenomination } from "./styles"; const AmountInput = (props: any) => { diff --git a/src/modals/ModalDonation/ConfirmDirect/ConfirmDirect.tsx b/src/modals/ModalDonation/ConfirmDirect/ConfirmDirect.tsx index af4227eb..13ce6fdc 100644 --- a/src/modals/ModalDonation/ConfirmDirect/ConfirmDirect.tsx +++ b/src/modals/ModalDonation/ConfirmDirect/ConfirmDirect.tsx @@ -8,8 +8,8 @@ import CheckBox from "@app/components/Inputs/Checkbox/Checkbox"; import TextArea from "@app/components/Inputs/TextArea/TextArea"; import ProfileImage from "@app/components/mob.near/ProfileImage"; import constants from "@app/constants"; +import nearToUsd from "@app/modules/nearToUsd"; import hrefWithParams from "@app/utils/hrefWithParams"; -import nearToUsd from "@app/utils/nearToUsd"; import { Amout, ButtonWrapper, Container, FeesRemoval, Label, NoteWrapper } from "./styles"; const ConfirmDirect = ({ diff --git a/src/modals/ModalDonation/ConfirmPot/ConfirmPot.tsx b/src/modals/ModalDonation/ConfirmPot/ConfirmPot.tsx index b666aac5..71db8b52 100644 --- a/src/modals/ModalDonation/ConfirmPot/ConfirmPot.tsx +++ b/src/modals/ModalDonation/ConfirmPot/ConfirmPot.tsx @@ -5,9 +5,9 @@ import Button from "@app/components/Button"; import BreakdownSummary from "@app/components/Cart/BreakdownSummary/BreakdownSummary"; import CheckBox from "@app/components/Inputs/Checkbox/Checkbox"; import ProfileImage from "@app/components/mob.near/ProfileImage"; +import nearToUsd from "@app/modules/nearToUsd"; import _address from "@app/utils/_address"; import hrefWithParams from "@app/utils/hrefWithParams"; -import nearToUsd from "@app/utils/nearToUsd"; import { Amout, ButtonWrapper, diff --git a/src/modals/ModalDonation/FormPot/FormPot.tsx b/src/modals/ModalDonation/FormPot/FormPot.tsx index 8efeafdd..b418c4d5 100644 --- a/src/modals/ModalDonation/FormPot/FormPot.tsx +++ b/src/modals/ModalDonation/FormPot/FormPot.tsx @@ -2,9 +2,9 @@ import { Near, Social, context } from "alem"; import Button from "@app/components/Button"; import ProfileImage from "@app/components/mob.near/ProfileImage"; import constants from "@app/constants"; +import nearToUsd from "@app/modules/nearToUsd"; import _address from "@app/utils/_address"; import hrefWithParams from "@app/utils/hrefWithParams"; -import nearToUsd from "@app/utils/nearToUsd"; import AmountInput from "../AmountInput/AmountInput"; import Alert from "../Banners/Alert"; import VerifyInfo from "../Banners/VerifyInfo"; diff --git a/src/utils/nearToUsd.ts b/src/modules/nearToUsd.ts similarity index 100% rename from src/utils/nearToUsd.ts rename to src/modules/nearToUsd.ts diff --git a/src/pages/CreateProject/components/SuccessfullRegister/SuccessfullRegister.tsx b/src/pages/CreateProject/components/SuccessfullRegister/SuccessfullRegister.tsx index ac521447..fad04a89 100644 --- a/src/pages/CreateProject/components/SuccessfullRegister/SuccessfullRegister.tsx +++ b/src/pages/CreateProject/components/SuccessfullRegister/SuccessfullRegister.tsx @@ -11,7 +11,7 @@ const SuccessfullRegister = ({ registeredProject }: { registeredProject: any })