From f852a17df688de8b3f88be22b30221fbfd6d8869 Mon Sep 17 00:00:00 2001 From: Sanaullah Sani Date: Mon, 13 Nov 2023 22:43:15 +0600 Subject: [PATCH] Added no vote list (#256) * moved global css files to _app.tsx * latest fixes * reviewed changes * no confidence vote for both votes added * removed old project page * blocked unauthorized users fron applications and projects * reviewed changes * fixed no confidence vote list * build fixes * removed briefs/id/applications page * refund flow optimization * blocked unauthorized brief owners from applications --- .../Application/BriefOwnerHeader.tsx | 10 +- src/components/ClientView/ClientView.tsx | 2 +- src/components/CopyToClipboardToast.tsx | 43 + .../Dashboard/MyClientBriefsView.tsx | 41 +- src/components/HirePopup.tsx | 31 +- .../Project/ExpandableMilestone.tsx | 520 ---------- src/components/Project/ProjectBalance.tsx | 2 +- .../Project/V2/NoConfidenceVoteBox.tsx | 31 +- .../Project/VotingList/NoConfidenceList.tsx | 6 +- src/components/RefundModal/RefundModal.tsx | 29 +- .../RefundModal/SuccessRefundModal.tsx | 18 +- src/components/ReviewModal/VoteModal.tsx | 24 +- ..._drop_user_data_from_noconfidence_table.ts | 23 + src/lib/queryServices/projectQueries.ts | 28 +- src/pages/api/briefs/[id]/applications.ts | 15 + .../api/project/noConfidenceVote/getVoters.ts | 4 +- .../api/project/noConfidenceVote/index.ts | 16 +- .../[id]/applications/[applicationId].tsx | 27 +- src/pages/briefs/[id]/applications/index.tsx | 142 --- src/pages/briefs/mybriefs.tsx | 1 - src/pages/projects/[id].tsx | 37 +- src/pages/projects/new.tsx | 939 ------------------ src/redux/services/briefService.ts | 4 +- src/redux/services/projectServices.ts | 84 +- 24 files changed, 303 insertions(+), 1774 deletions(-) create mode 100644 src/components/CopyToClipboardToast.tsx delete mode 100644 src/components/Project/ExpandableMilestone.tsx create mode 100644 src/db/migrations/20231109101614_drop_user_data_from_noconfidence_table.ts delete mode 100644 src/pages/briefs/[id]/applications/index.tsx delete mode 100644 src/pages/projects/new.tsx diff --git a/src/components/Application/BriefOwnerHeader.tsx b/src/components/Application/BriefOwnerHeader.tsx index b5d168e2..3c907e94 100644 --- a/src/components/Application/BriefOwnerHeader.tsx +++ b/src/components/Application/BriefOwnerHeader.tsx @@ -69,8 +69,8 @@ const BriefOwnerHeader = (props: BriefOwnerHeaderProps) => { user, } = props; - const [balance, setBalance] = useState(); - const [imbueBalance, setImbueBalance] = useState(); + const [balance, setBalance] = useState(); + const [imbueBalance, setImbueBalance] = useState(); const [loadingWallet, setLoadingWallet] = useState('loading'); const [error, setError] = useState(); @@ -129,13 +129,15 @@ const BriefOwnerHeader = (props: BriefOwnerHeaderProps) => { user?.web3_address, application.id ); + const imbueBalance = await getBalance( Currency.IMBU, user, user?.web3_address ); - setBalance(balance.toLocaleString()); - setImbueBalance(imbueBalance.toLocaleString()); + + setBalance(Number(balance) || 0); + setImbueBalance(Number(imbueBalance) || 0); } catch (error) { setError({ message: error }); } finally { diff --git a/src/components/ClientView/ClientView.tsx b/src/components/ClientView/ClientView.tsx index eeadf523..c3f4cfbb 100644 --- a/src/components/ClientView/ClientView.tsx +++ b/src/components/ClientView/ClientView.tsx @@ -54,7 +54,7 @@ export default function ClientView({ onClick={() => setSwitcher('projects')} className='text-2xl text-black py-5 border-r text-center w-full' > - Projects({briefs?.acceptedBriefs.length}) + Projects({briefs?.acceptedBriefs?.length})

setSwitcher('grants')} diff --git a/src/components/CopyToClipboardToast.tsx b/src/components/CopyToClipboardToast.tsx new file mode 100644 index 00000000..8cb0fde3 --- /dev/null +++ b/src/components/CopyToClipboardToast.tsx @@ -0,0 +1,43 @@ +import { Alert } from '@mui/material'; +import React, { ReactNode, useState } from 'react'; + + +interface CopyToClipboardProps { + link: string; + title: string; + children: ReactNode; + extraClass?: string; +} + +const CopyToClipboardToast = (props: CopyToClipboardProps) => { + const { link, title, children, extraClass } = props; + const [copied, setCopied] = useState(''); + + const copyToClipboard = () => { + const textToCopy = link || ''; + + navigator.clipboard.writeText(textToCopy); + setCopied(title); + + setTimeout(() => { + setCopied(''); + }, 3000); + }; + + return ( +

+
+ {`${copied} Copied to clipboard`} +
+ +
+ {children} +
+
+ ); +}; + +export default CopyToClipboardToast; \ No newline at end of file diff --git a/src/components/Dashboard/MyClientBriefsView.tsx b/src/components/Dashboard/MyClientBriefsView.tsx index 58333c81..b07b7f7f 100644 --- a/src/components/Dashboard/MyClientBriefsView.tsx +++ b/src/components/Dashboard/MyClientBriefsView.tsx @@ -2,6 +2,7 @@ //import ArrowBackIcon from '@mui/icons-material/ArrowBack'; import { useRouter } from 'next/router'; import React, { useEffect, useState } from 'react'; +import { useSelector } from 'react-redux'; import { Freelancer, Project } from '@/model'; import { @@ -9,6 +10,7 @@ import { getUserBriefs, } from '@/redux/services/briefService'; import { getUsersOngoingGrants } from '@/redux/services/projectServices'; +import { RootState } from '@/redux/store/store'; // import OngoingProject from './FreelacerView/OngoingProject/OngoingProject'; // import { ApplicationContainer } from '../Briefs/ApplicationContainer'; @@ -20,12 +22,13 @@ type ClientViewProps = { briefId: string | string[] | undefined; handleMessageBoxClick: (_userId: number, _freelander: Freelancer) => void; redirectToBriefApplications: (_applicationId: string) => void; - user: any; }; const MyClientBriefsView = (props: ClientViewProps) => { - const { user, briefId, handleMessageBoxClick, redirectToBriefApplications } = - props; + const { briefId, handleMessageBoxClick, redirectToBriefApplications } = props; + + const { user, loading } = useSelector((state: RootState) => state.userState); + const [briefs, _setBriefs] = useState(); const [briefApplications, setBriefApplications] = useState([]); @@ -35,25 +38,39 @@ const MyClientBriefsView = (props: ClientViewProps) => { useEffect(() => { const setUserBriefs = async () => { - if (user?.id) _setBriefs(await getUserBriefs(user?.id)); - setOngoingGrants(await getUsersOngoingGrants(user?.web3_address)); + if (!user.id) return router.push('/auth/sign-in') + + _setBriefs(await getUserBriefs(user?.id)); + + if (user?.web3_address) + setOngoingGrants(await getUsersOngoingGrants(user?.web3_address)); }; - setUserBriefs(); - }, [user?.id, user?.web3_address]); + !loading && setUserBriefs(); + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [user.id, user?.web3_address, loading]); useEffect(() => { - const getApplications = async (id: string | number) => { + const getApplications = async () => { + if (!briefId) return + try { setLoadingApplications(true); - setBriefApplications(await getBriefApplications(id)); + const resp = await getBriefApplications(String(briefId)); + + if (resp.status === 501) + return router.push('/dashboard'); + + setBriefApplications(resp); + setLoadingApplications(false); } catch (error) { console.log(error); - } finally { setLoadingApplications(false); } }; - briefId && getApplications(briefId.toString()); - }, [briefId, user?.id]); + + briefId && getApplications(); + }, [briefId, loading, router]); const goBack = () => { router.query.briefId = []; diff --git a/src/components/HirePopup.tsx b/src/components/HirePopup.tsx index cd774b5e..0ef9704d 100644 --- a/src/components/HirePopup.tsx +++ b/src/components/HirePopup.tsx @@ -24,6 +24,7 @@ import { getOffchainEscrowAddress, getOffchainEscrowBalance, mintTokens } from ' import { RootState } from '@/redux/store/store'; import AccountChoice from './AccountChoice'; +import CopyToClipboardToast from './CopyToClipboardToast'; import ErrorScreen from './ErrorScreen'; import SuccessScreen from './SuccessScreen'; import styles from '../styles/modules/hire-modal.module.css'; @@ -74,12 +75,19 @@ export const HirePopup = ({ const updateEscrowInfo = async () => { - const escrowAddress = await getOffchainEscrowAddress(application.id); - setEscrowAddress(escrowAddress); - const allBalances = await getOffchainEscrowBalance(application.id); - const currency = Currency[application.currency_id].toString().toLowerCase(); - const escrowBalance = Number(allBalances[currency]) ?? 0; - setEscrowBalance(escrowBalance); + try { + const escrowAddress = await getOffchainEscrowAddress(application.id); + + if (escrowAddress?.status !== "Failed") + setEscrowAddress(escrowAddress); + + const allBalances = await getOffchainEscrowBalance(application.id); + const currency = Currency[application.currency_id].toString().toLowerCase(); + const escrowBalance = Number(allBalances[currency]) || 0; + setEscrowBalance(escrowBalance); + } catch (error) { + setError({ message: "Failed to load payment info" }) + } }; useEffect(() => { @@ -379,8 +387,15 @@ export const HirePopup = ({

Escrow Address: - - {escrowAddress} + + + {escrowAddress} +

diff --git a/src/components/Project/ExpandableMilestone.tsx b/src/components/Project/ExpandableMilestone.tsx deleted file mode 100644 index 60c7e31f..00000000 --- a/src/components/Project/ExpandableMilestone.tsx +++ /dev/null @@ -1,520 +0,0 @@ -import { Tooltip } from '@mui/material'; -import { WalletAccount } from '@talismn/connect-wallets'; -import Image from 'next/image'; -import { useState } from 'react'; - -import { sendNotification } from '@/utils'; -import { initImbueAPIInfo } from '@/utils/polkadot'; - -import { - ImbueChainPollResult, - Milestone, - OffchainProjectState, - Project, - User, -} from '@/model'; -import ChainService, { ImbueChainEvent } from '@/redux/services/chainService'; -import { - updateFirstPendingMilestone, - updateMilestone, - updateProject, - updateProjectVotingState, -} from '@/redux/services/projectServices'; -import { voteOnMilestone } from '@/redux/services/projectServices'; - -import ProjectStateTag from './ProjectStateTag'; -import AccountChoice from '../AccountChoice'; -import { Dialogue } from '../Dialogue'; - -type ExpandableDropDownsProps = { - milestone: Milestone; - index: number; - modified: Date; - // vote: () => void; - // withdraw: () => void; - setOpenVotingList: (_value: boolean) => void; - setLoading: (_value: boolean) => void; - setSuccess: (_value: boolean) => void; - setSuccessTitle: (_value: string) => void; - setError: (_value: any) => void; - approversPreview: User[]; - firstPendingMilestone: number | undefined; - projectInMilestoneVoting: boolean | undefined; - isApplicant: boolean; - canVote: boolean; - user: User; - projectType: 'grant' | 'brief' | null; - isProjectOwner: boolean; - balance: number; - project: Project; - milestonLoadingTitle: string; - targetUser: User; -}; - -const ExpandableDropDowns = (props: ExpandableDropDownsProps) => { - const { - setLoading, - project, - setSuccess, - setSuccessTitle, - setError, - milestone, - index, - modified, - setOpenVotingList, - approversPreview, - firstPendingMilestone, - projectInMilestoneVoting, - isApplicant, - canVote, - user, - projectType, - isProjectOwner, - balance, - milestonLoadingTitle, - } = props; - - const [expanded, setExpanded] = useState(false); - const [showPolkadotAccounts, setShowPolkadotAccounts] = - useState(false); - const [submittingMilestone, setSubmittingMilestone] = - useState(false); - const [milestoneKeyInView, setMilestoneKeyInView] = useState(0); - const [votingWalletAccount, setVotingWalletAccount] = useState< - WalletAccount | any - >({}); - const [showVotingModal, setShowVotingModal] = useState(false); - const [withdrawMilestone, setWithdrawMilestone] = useState(false); - - // submitting a milestone - const submitMilestone = async (account: WalletAccount) => { - if (!project?.chain_project_id) - return setError({ message: 'No project found' }); - - setLoading(true); - - try { - const imbueApi = await initImbueAPIInfo(); - const chainService = new ChainService(imbueApi, user); - const result = await chainService.submitMilestone( - account, - project.chain_project_id, - milestoneKeyInView - ); - - // eslint-disable-next-line no-constant-condition - while (true) { - if (result.status || result.txError) { - if (result.status) { - const resp = await updateProjectVotingState( - Number(project.id), - true - ); - if (resp) { - await sendNotification( - project.approvers, - 'submit_Milestone.testing', - `A New Milestone has been submitted on project ${project.name}`, - `Milestone Submitted Successfully`, - Number(project.id), - milestone.milestone_index + 1 - ); - setSuccess(true); - setSuccessTitle('Milestone Submitted Successfully'); - } else { - setError({ - message: - 'Server error. Could not update project voting status.', - }); - } - } else if (result.txError) { - setError({ message: result.errorMessage }); - } - break; - } - await new Promise((f) => setTimeout(f, 1000)); - } - } catch (error: any) { - setError({ message: `Internal server error. ${error.message}` }); - } finally { - setLoading(false); - } - }; - - const handleSubmitMilestone = (milestone_index: number) => { - // show polkadot account modal - setShowPolkadotAccounts(true); - // set submitting mile stone to false - setSubmittingMilestone(true); - // setMile stone key in view - setMilestoneKeyInView(milestone_index); - }; - - // voting on a mile stone - const handleVoting = (milestone_index: number) => { - // show polkadot account modal - setShowPolkadotAccounts(true); - // set submitting mile stone to false - setSubmittingMilestone(false); - // setMile stone key in view - setMilestoneKeyInView(milestone_index); - }; - - const handleVoteOnMilestone = async ( - account: WalletAccount, - vote: boolean - ) => { - setLoading(true); - - if (!project?.id || !user.web3_address) return; - - try { - const imbueApi = await initImbueAPIInfo(); - // const userRes: User | any = await utils.getCurrentUser(); - const chainService = new ChainService(imbueApi, user); - - const result = await chainService.voteOnMilestone( - account, - project.chain_project_id, - milestoneKeyInView, - vote - ); - - let pollResult = ImbueChainPollResult.Pending; - - if (!result.txError) { - pollResult = (await chainService.pollChainMessage( - ImbueChainEvent.ApproveMilestone, - account.address - )) as ImbueChainPollResult; - } else { - setError({ message: result.errorMessage }); - } - - // eslint-disable-next-line no-constant-condition - while (true) { - if (pollResult == ImbueChainPollResult.EventFound) { - await updateMilestone(milestone.project_id, milestoneKeyInView, true); - await updateProjectVotingState(Number(project.id), false); - await updateFirstPendingMilestone( - Number(project.id), - Number(project.first_pending_milestone) + 1 - ); - await voteOnMilestone( - user.id, - user.web3_address, - milestoneKeyInView, - vote, - project.id - ); - - setSuccess(true); - - setSuccessTitle( - 'Your vote was successful. This milestone has been completed.' - ); - setLoading(false); - - break; - } else if (result.status) { - await voteOnMilestone( - user.id, - user.web3_address, - milestoneKeyInView, - vote, - project.id - ); - - setSuccess(true); - setSuccessTitle('Your vote was successful.'); - setLoading(false); - break; - } else if (result.txError) { - setError({ message: result.errorMessage }); - setLoading(false); - break; - } else if (pollResult != ImbueChainPollResult.Pending) { - await voteOnMilestone( - user.id, - user.web3_address, - milestoneKeyInView, - vote, - project.id - ); - - setSuccess(true); - setSuccessTitle('Request resolved successfully'); - setLoading(false); - break; - } - await new Promise((f) => setTimeout(f, 1000)); - } - } catch (error) { - setError({ message: 'Could not vote. Please try again later' }); - // eslint-disable-next-line no-console - console.error(error); - setLoading(false); - } - // finally { - // console.log("in finally"); - - // setLoading(false); - // } - }; - - // voting on a mile stone - const handleWithdraw = (milestone_index: number) => { - // set submitting mile stone to true - setWithdrawMilestone(true); - // show polkadot account modal - setShowPolkadotAccounts(true); - // setMile stone key in view - setMilestoneKeyInView(milestone_index); - }; - - // withdrawing funds - const withdraw = async (account: WalletAccount) => { - setLoading(true); - const imbueApi = await initImbueAPIInfo(); - const projectMilestones = project.milestones; - // const user: User | any = await utils.getCurrentUser(); - const chainService = new ChainService(imbueApi, user); - const result = await chainService.withdraw( - account, - project.chain_project_id - ); - - // eslint-disable-next-line no-constant-condition - while (true) { - if (result.status || result.txError) { - if (result.status) { - const haveAllMilestonesBeenApproved = projectMilestones - .map((m: any) => m.is_approved) - .every(Boolean); - - if (haveAllMilestonesBeenApproved) { - project.status_id = OffchainProjectState.Completed; - project.completed = true; - - await updateProject(Number(project?.id), project); - } - setLoading(false); - setSuccess(true); - setSuccessTitle('Withdraw successful'); - } else if (result.txError) { - setLoading(false); - setError({ message: result.errorMessage }); - } - break; - } - await new Promise((f) => setTimeout(f, 1000)); - } - }; - - return ( -

- {showPolkadotAccounts && ( - { - if (submittingMilestone) { - submitMilestone(account); - // } - // else if (raiseVoteOfNoConfidence) { - // refund(account); - } else if (withdrawMilestone) { - withdraw(account); - } else { - setVotingWalletAccount(account); - setShowVotingModal(true); - } - }} - visible={showPolkadotAccounts} - setVisible={setShowPolkadotAccounts} - initiatorAddress={project?.owner} - filterByInitiator - /> - )} - {showVotingModal && ( - setShowVotingModal(false)} - actionList={ - <> -
  • - -
  • -
  • - -
  • - - } - /> - )} - -
    { - setExpanded(!expanded); - }} - className='py-6 flex justify-between w-full items-center max-width-750px:flex-col max-width-750px:flex cursor-pointer' - > -
    -

    - Milestone {index + 1} -

    -

    - {milestone?.name} -

    -
    -
    - {milestonLoadingTitle ? ( -

    - {milestonLoadingTitle} -

    - ) : ( - <> - {milestone?.is_approved ? ( - - ) : milestone?.milestone_index == firstPendingMilestone && - projectInMilestoneVoting ? ( - - ) : ( - - )} - - )} - - dropdownstate -
    -
    - -
    -

    - Percentage of funds to be released{' '} - - {milestone?.percentage_to_unlock}% - -

    -

    - Funding to be released{' '} - - {Number(milestone?.amount)?.toLocaleString?.()} $IMBU - -

    - -

    - {milestone?.description} -

    - - {!milestonLoadingTitle && - !isApplicant && - milestone.milestone_index == firstPendingMilestone && - projectInMilestoneVoting && ( - - - - )} - - {!milestonLoadingTitle && - (isApplicant || (projectType === 'grant' && isProjectOwner)) && - milestone.milestone_index == firstPendingMilestone && - !projectInMilestoneVoting && - !milestone?.is_approved && ( - - - - )} - - {!milestonLoadingTitle && isApplicant && milestone.is_approved && ( - - )} -
    -
    - ); -}; - -export default ExpandableDropDowns; diff --git a/src/components/Project/ProjectBalance.tsx b/src/components/Project/ProjectBalance.tsx index f891b79d..0911e750 100644 --- a/src/components/Project/ProjectBalance.tsx +++ b/src/components/Project/ProjectBalance.tsx @@ -63,7 +63,7 @@ const ProjectBalance = (props: ProjectBalanceType) => { const balance = await getBalance( currency_id, user, - project.currency_id < 100 ? project?.escrow_address : undefined, + project.currency_id < 100 ? project?.escrow_address : undefined, Number(project.id) ); if (!balance && project.status_id !== OffchainProjectState.Completed) { diff --git a/src/components/Project/V2/NoConfidenceVoteBox.tsx b/src/components/Project/V2/NoConfidenceVoteBox.tsx index b0990ff7..dbf92cb1 100644 --- a/src/components/Project/V2/NoConfidenceVoteBox.tsx +++ b/src/components/Project/V2/NoConfidenceVoteBox.tsx @@ -2,7 +2,6 @@ import { Avatar, AvatarGroup, LinearProgress } from '@mui/material'; import { WalletAccount } from '@talismn/connect-wallets'; import React, { useEffect, useState } from 'react'; -import { NoConfidenceVoter } from '@/lib/queryServices/projectQueries'; import { initPolkadotJSAPI } from '@/utils/polkadot'; import VoteModal from '@/components/ReviewModal/VoteModal'; @@ -13,7 +12,7 @@ import ChainService from '@/redux/services/chainService'; type MilestoneVoteBoxProps = { user: User; - noConfidenceVoters: NoConfidenceVoter[]; + noConfidenceVoters: Array; canVote: boolean; isApplicant: boolean; project: Project; @@ -33,6 +32,9 @@ const NoConfidenceBox = (props: MilestoneVoteBoxProps) => { const [votingWalletAccount, setVotingWalletAccount] = useState({}); const [refundOnly, setRefundOnly] = useState(false); + const yesVote = noConfidenceVoters.filter((v) => !v.vote) + const noVote = noConfidenceVoters.filter((v) => v.vote) + const handleVoting = (milestone_index: number) => { // show polkadot account modal setShowPolkadotAccounts(true); @@ -108,16 +110,15 @@ const NoConfidenceBox = (props: MilestoneVoteBoxProps) => { className='mt-auto cursor-pointer' onClick={() => props?.setOpenVotingList(true)} > - { - /* - { - [1, 2, 3].map((v, index) => ( - - )) - } - */} + + { + noVote.map((v, index) => ( + + )) + } +

    - No ({0} votes/ {0}%) + No ({noVote.length} votes/ {(noVote.length / props.approversCount) * 100}%)

    { > { - noConfidenceVoters.map((v, index) => ( + yesVote.map((v, index) => ( )) }

    - ({noConfidenceVoters.length} Votes/ {(noConfidenceVoters.length / props.approversCount) * 100}%) Yes + ({yesVote.length} Votes/ {(yesVote.length / props.approversCount) * 100}%) Yes

    @@ -142,7 +143,7 @@ const NoConfidenceBox = (props: MilestoneVoteBoxProps) => { className='w-[52%] text-imbue-coral rotate-180 before:bg-[#DDDCD6] h-5 rounded-full' color='inherit' variant='determinate' - value={0} + value={(noVote.length / props.approversCount) * 100 || 0} />
    { @@ -151,7 +152,7 @@ const NoConfidenceBox = (props: MilestoneVoteBoxProps) => { ) : "" diff --git a/src/components/Project/VotingList/NoConfidenceList.tsx b/src/components/Project/VotingList/NoConfidenceList.tsx index 09aa0c68..28a2caef 100644 --- a/src/components/Project/VotingList/NoConfidenceList.tsx +++ b/src/components/Project/VotingList/NoConfidenceList.tsx @@ -3,6 +3,8 @@ import Image from 'next/image'; import React, { useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; +import { NoConfidenceVote } from '@/lib/queryServices/projectQueries'; + import freelalncerPic from '@/assets/images/profile-image.png' import { Project, User } from '@/model'; import { getProjectNoConfidenceVoters } from '@/redux/services/projectServices'; @@ -46,7 +48,9 @@ const NoConfidenceList = (props: VotingListProps) => { } }); - setVotes({ yes: voteResp, pending: pending }) + const yes = voteResp.filter((v: NoConfidenceVote) => !v.vote) + const no = voteResp.filter((v: NoConfidenceVote) => v.vote) + setVotes({ yes, no, pending }) // const votersAddressed = voteResp?.map((voter: any) => voter.web3_address) } catch (error) { // eslint-disable-next-line no-console diff --git a/src/components/RefundModal/RefundModal.tsx b/src/components/RefundModal/RefundModal.tsx index 9295be50..41423fd1 100644 --- a/src/components/RefundModal/RefundModal.tsx +++ b/src/components/RefundModal/RefundModal.tsx @@ -7,6 +7,7 @@ interface VotingModalProps { handleRefund: (_vote: boolean) => Promise; handleVote: (_vote: boolean) => Promise; refundOnly: boolean; + undergoingRefund: boolean; } export default function RefundModal({ @@ -14,15 +15,15 @@ export default function RefundModal({ handleRefund, handleVote, setLoading, - refundOnly + refundOnly, + undergoingRefund }: VotingModalProps) { - console.log("🚀 ~ file: RefundModal.tsx:19 ~ refundOnly:", refundOnly) const handleNo = async (): Promise => { setLoading(true) setVisible(false); - - if (refundOnly) { + + if (refundOnly || undergoingRefund) { await handleRefund(true) } else { await handleVote(false); @@ -49,16 +50,20 @@ export default function RefundModal({ and believe strongly that its deliverables is not quantifiable by expected milestones.

    -
    - +
    + { + ((undergoingRefund && refundOnly) || !refundOnly) && ( + + ) + } - ) : ( - - )} - - )} -

    - -

    - Posted {timePosted} -

    - -

    - {isProjectOwner && projectType === 'brief' - ? 'Freelancer hired' - : 'Project Owner'} -

    - -
    -
    - router.push( - isProjectOwner - ? `/freelancers/${targetUser?.username}` - : `/profile/${targetUser?.username}` - ) - } - className='flex items-center' - > - freelaner-icon - -

    - {targetUser?.display_name} -

    -
    - - {targetUser?.id && user?.id && targetUser?.id !== user?.id && ( - - )} - - {showRefundButton && ( - <> - - - - - )} - {projectInVotingOfNoConfidence && ( - - )} -
    - - {project?.approvers && ( - <> -

    - Approvers -

    - - - )} -
    - -
    -
    -
    - {'shieldIcon'} - -
    -

    - Milestone{' '} - {chainLoading && ( - - loading... - - )} - {!chainLoading && ( - - {approvedMilestones?.length}/{project?.milestones?.length} - - )} -

    - {/* mile stone step indicator */} -
    -
    m?.is_approved - )?.length / - project?.milestones?.length) * - 100 - }%`, - }} - className='h-full rounded-xl bg-content-primary absolute' - >
    -
    - {project?.milestones?.map((m: any, i: number) => ( -
    - ))} -
    -
    -
    -
    -
    - -
    -
    - {'dollarSign'} -
    -

    - {Number( - Number(project?.total_cost_without_fee) + - Number(project?.imbue_fee) - )?.toLocaleString()}{' '} - ${Currency[project?.currency_id || 0]} -

    -
    - Budget - Fixed -
    -
    -
    -
    - -
    -
    - {'calenderIcon'} -
    -

    - {timeData[project?.duration_id || 0].label} -

    -
    - Timeline -
    -
    -
    -
    - - {project?.escrow_address && ( -
    -
    - -
    -

    - Wallet Address - setModalOpen(true)} - className='bg-indigo-700 ml-2 h-5 w-5 py-1 px-1.5 cursor-pointer text-xs !text-white rounded-full flex justify-center items-center' - > - ? - -

    -
    - {project?.escrow_address} - -
    -
    -
    -
    - )} - - {project?.chain_project_id && ( -
    -
    - -
    -

    - On-Chain Project ID -

    -
    - {project?.chain_project_id} -
    -
    -
    -
    - )} -
    -
    - {chainLoading && - project?.milestones?.map((item: any) => ( -
    -
    - - - - - - -
    -
    - - - - - - -
    -
    - ))} - - {project?.milestones?.map?.((milestone: Milestone, index: number) => { - return ( - - ); - })} -
    - - -
    - - { - setLoginModal(val); - }} - redirectUrl={`/project/${projectId}/`} - /> - -
    - - -
    -
    - -
    - - -
    -
    - - - - -
    - - -
    -
    - - {/* */} - - - ); -} - -export default Project; diff --git a/src/redux/services/briefService.ts b/src/redux/services/briefService.ts index b651669b..5e75ecb6 100644 --- a/src/redux/services/briefService.ts +++ b/src/redux/services/briefService.ts @@ -167,9 +167,7 @@ export const getBriefApplications = async (brifId: string | number) => { if (resp.ok) { return await resp.json(); } else { - throw new Error( - 'Failed to get all brief applications. status:' + resp.status - ); + return resp } }; diff --git a/src/redux/services/projectServices.ts b/src/redux/services/projectServices.ts index 9a65f0c7..27a3675d 100644 --- a/src/redux/services/projectServices.ts +++ b/src/redux/services/projectServices.ts @@ -103,7 +103,7 @@ export const getMilestoneAttachments = async ( export const completeMilestone = async ( projectId: number, - milestoneIndex: number, + milestoneIndex: number ) => { const resp = await fetch( `${config.apiBase}/project/completeMilestone?projectId=${projectId}&milestoneIndex=${milestoneIndex}`, @@ -316,16 +316,16 @@ export const getProjectNoConfidenceVoters = async ( } }; -export const insertNoConfidenceVoter = async ( +export const insertNoConfidenceVote = async ( projectId: number | string, - voter: User + voteData: { voter: User; vote: boolean } ) => { const resp = await fetch( `${config.apiBase}/project/noConfidenceVote?projectId=${projectId}`, { headers: config.postAPIHeaders, method: 'post', - body: JSON.stringify(voter), + body: JSON.stringify(voteData), } ); @@ -339,9 +339,7 @@ export const insertNoConfidenceVoter = async ( }; // Multichain -export const getProjectBalance = async ( - projectId: number, -) => { +export const getProjectBalance = async (projectId: number) => { try { const resp = await fetch( `${config.apiBase}/payments/${projectId}/balance`, @@ -359,10 +357,7 @@ export const getProjectBalance = async ( } }; - -export const getProjectEscrowAddress = async ( - projectId: number, -) => { +export const getProjectEscrowAddress = async (projectId: number) => { try { const resp = await fetch( `${config.apiBase}/payments/${projectId}/address`, @@ -380,9 +375,7 @@ export const getProjectEscrowAddress = async ( } }; -export const withdrawOffchain = async ( - projectId: number | string, -) => { +export const withdrawOffchain = async (projectId: number | string) => { try { const resp = await fetch( `${config.apiBase}/payments/${projectId}/withdraw`, @@ -415,57 +408,40 @@ export const watchChain = async ( imbueChainEvent: ImbueChainEvent, address: string, projectId: number | string, - milestoneId?: number | string, + milestoneId?: number | string ) => { - const resp = await fetch( - `${config.apiBase}/watch`, - { - headers: config.postAPIHeaders, - method: 'POST', - body: JSON.stringify({ imbueChainEvent, address, projectId, milestoneId }), - } - ); + const resp = await fetch(`${config.apiBase}/watch`, { + headers: config.postAPIHeaders, + method: 'POST', + body: JSON.stringify({ imbueChainEvent, address, projectId, milestoneId }), + }); return await resp.json(); }; - -export const getOffchainEscrowAddress = async ( - projectId: string | number, -) => { - const resp = await fetch( - `${config.apiBase}/payments/${projectId}/address`, - { - headers: config.postAPIHeaders, - method: 'GET', - } - ); +export const getOffchainEscrowAddress = async (projectId: string | number) => { + const resp = await fetch(`${config.apiBase}/payments/${projectId}/address`, { + headers: config.postAPIHeaders, + method: 'GET', + }); return await resp.json(); }; -export const getOffchainEscrowBalance = async ( - projectId: string | number, -) => { - const resp = await fetch( - `${config.apiBase}/payments/${projectId}/balance`, - { - headers: config.postAPIHeaders, - method: 'GET', - } - ); +export const getOffchainEscrowBalance = async (projectId: string | number) => { + const resp = await fetch(`${config.apiBase}/payments/${projectId}/balance`, { + headers: config.postAPIHeaders, + method: 'GET', + }); return await resp.json(); }; export const mintTokens = async ( projectId: string | number, - beneficiary: string, + beneficiary: string ) => { - const resp = await fetch( - `${config.apiBase}/payments/${projectId}/mint`, - { - headers: config.postAPIHeaders, - method: 'POST', - body: JSON.stringify({ beneficiary }), - } - ); + const resp = await fetch(`${config.apiBase}/payments/${projectId}/mint`, { + headers: config.postAPIHeaders, + method: 'POST', + body: JSON.stringify({ beneficiary }), + }); return await resp.json(); -}; \ No newline at end of file +};