Search
Search

Transaction: 2NmgsFU...4xDb

Receiver
Status
Succeeded
Transaction Fee
0.01573 
Deposit Value
<0.00001 
Gas Used
157 Tgas
Attached Gas
300 Tgas
Created
May 22, 2024 at 7:34:58pm
Hash
2NmgsFUZPrK6GGCqxM5Ae8UP29kz1PEKsNqBpPWu4xDb

Actions

Called method: 'set' in contract: social.near
Arguments:
{ "data": { "old.potlock.near": { "widget": { "Components.DonorsTrx": { "": "const { allDonations, filter } = props;\nconst [currentPage, setCurrentPage] = useState(1);\nconst perPage = 30; // need to be less than 50\nuseEffect(() => {\n setCurrentPage(1);\n}, [filter]);\nconst nearLogo =\n \"https://ipfs.near.social/ipfs/bafkreicdcpxua47eddhzjplmrs23mdjt63czowfsa2jnw4krkt532pa2ha\";\nconst { getTimePassed, _address, reverseArr } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n);\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2rem;\n width: 100%;\n .transcation {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-size: 14px;\n .header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px;\n gap: 1rem;\n background: #f6f5f3;\n color: #292929;\n div {\n width: 100px;\n display: flex;\n justify-content: center;\n align-items: center;\n font-weight: 600;\n }\n }\n .address {\n width: 143px !important;\n }\n }\n @media only screen and (max-width: 768px) {\n .transcation {\n font-size: 12px;\n .header {\n padding: 10px 0;\n div {\n width: 80px !important;\n }\n }\n .address {\n width: 80px !important;\n justify-content: center;\n .profile-image {\n display: none !important;\n }\n }\n }\n }\n @media only screen and (max-width: 480px) {\n .transcation {\n font-size: 9px;\n }\n }\n`;\nconst TrRow = styled.div`\n display: flex;\n width: 100%;\n justify-content: space-between;\n gap: 1rem;\n padding: 20px 10px;\n > div,\n > span {\n width: 100px;\n display: flex;\n justify-content: center;\n align-items: center;\n }\n .price {\n display: flex;\n gap: 1rem;\n align-items: center;\n img {\n width: 1.5rem;\n }\n }\n .address {\n color: #292929;\n display: flex;\n align-items: center;\n justify-content: flex-start;\n border-radius: 2px;\n transition: all 200ms;\n .profile-image {\n width: 2rem;\n height: 2rem;\n margin-right: 1rem;\n }\n }\n @media only screen and (max-width: 768px) {\n padding: 10px 0;\n > div,\n > span {\n width: 80px;\n }\n .price {\n gap: 8px;\n img {\n width: 1.25rem;\n }\n }\n .address .profile-image {\n width: 1.5rem;\n height: 1.5rem;\n margin-right: 0.5rem;\n }\n }\n @media only screen and (max-width: 480px) {\n .price img {\n width: 1rem;\n }\n }\n`;\nconst NoResult = styled.div`\n font-size: 2rem;\n text-align: center;\n`;\nconst ProfileImg = ({ address }) => (\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{ accountId: address, style: {} }}\n />\n);\nconst NEAR_DECEMIALS = 24;\nconst calcNetDonationAmount = (amount, decimals) =>\n Big(amount).div(Big(`1e${decimals}`));\nreturn allDonations.length ? (\n <Container>\n <div className=\"transcation\">\n <div className=\"header\">\n <div className=\"address\">Donor</div>\n <div className=\"address\">Project</div>\n <div>Amount</div>\n <div>Date</div>\n </div>\n {reverseArr(allDonations)\n .slice((currentPage - 1) * perPage, currentPage * perPage)\n .map((donation) => {\n const {\n donor_id,\n recipient_id,\n donated_at_ms,\n donated_at,\n project_id,\n ft_id,\n total_amount,\n } = donation;\n const projectId = recipient_id || project_id;\n const isNear = ft_id === \"near\";\n const frMetaDate = !isNear\n ? Near.view(ft_id, \"ft_metadata\", {})\n : null;\n const assetIcon = isNear ? nearLogo : frMetaDate.icon;\n const decimals = isNear ? NEAR_DECEMIALS : frMetaDate.decimals;\n console.log(\"decimals\", decimals);\n return (\n <TrRow>\n <a\n href={props.hrefWithParams(\n `?tab=profile&accountId=${donor_id}`\n )}\n className=\"address\"\n target=\"_blank\"\n >\n <ProfileImg address={donor_id} />\n {_address(donor_id)}\n </a>\n <a\n href={props.hrefWithParams(\n `?tab=project&projectId=${projectId}`\n )}\n className=\"address\"\n target=\"_blank\"\n >\n <ProfileImg address={projectId} />\n {_address(projectId)}\n </a>\n <div className=\"price\">\n <img src={assetIcon} alt={ft_id} />\n {decimals\n ? calcNetDonationAmount(total_amount, decimals).toFixed(2)\n : \"-\"}\n </div>\n <div>{getTimePassed(donated_at_ms || donated_at)} ago</div>\n </TrRow>\n );\n })}\n </div>\n <Widget\n src={\"old.potlock.near/widget/Components.Pagination\"}\n props={{\n onPageChange: (page) => {\n setCurrentPage(page);\n },\n data: allDonations,\n currentPage,\n perPage: perPage,\n bgColor: \"#292929\",\n }}\n />\n </Container>\n) : (\n <NoResult>No Donations</NoResult>\n);\n" }, "ModalDonation.Banners": { "": "const AlertBanner = styled.div`\n display: flex;\n padding: 0.75rem 1rem;\n color: #ed464f;\n gap: 1rem;\n align-items: center;\n border: 1px solid #f4b37d;\n border-radius: 6px;\n background: #fef6ee;\n margin-top: 1.5rem;\n div {\n font-weight: 500;\n }\n .icon {\n width: 22px;\n }\n`;\nconst NadabotBanner = styled.div`\n display: flex;\n align-items: center;\n padding: 0.75rem 1rem;\n border: 1px solid #f4b37d;\n border-radius: 6px;\n background: #fef6ee;\n flex-wrap: wrap;\n margin-top: 1.5rem;\n .label {\n display: flex;\n align-items: center;\n font-weight: 500;\n gap: 1rem;\n img {\n width: 24px;\n height: 24px;\n }\n }\n .verify {\n color: #dd3345;\n font-weight: 500;\n margin-left: auto;\n &:hover {\n text-decoration: none;\n }\n }\n @media only screen and (max-width: 480px) {\n flex-direction: column;\n align-items: flex-start;\n gap: 0px;\n .labe {\n align-items: flex-start;\n }\n .verify {\n margin-left: 40px;\n }\n }\n`;\nconst VerifyInfoWrapper = styled.div`\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 1rem;\n border-radius: 6px;\n border: 1px solid #ecc113;\n background: #fbf9c6;\n box-shadow: 0px 2px 1px 1px rgba(255, 255, 255, 0.8) inset,\n 0px -2px 4px 0px rgba(15, 15, 15, 0.15) inset;\n font-size: 14px;\n color: #3f2209;\n margin-top: 1.5rem;\n .icon {\n width: 17px;\n display: flex;\n height: fit-content;\n svg {\n width: 100%;\n }\n }\n .text {\n flex: 1;\n line-height: 150%;\n }\n a {\n font-weight: 500;\n color: #dd3345;\n :hover {\n text-decoration: none;\n }\n }\n @media only screen and (max-width: 480px) {\n flex-wrap: wrap;\n a {\n width: 100%;\n text-align: center;\n }\n }\n`;\nconst NADA_BOT_ICON =\n \"bafkreicojpp23dmf7hakbt67eah4ba52dx3reekdccaupoggzzlhdkroyi\";\nconst Alert = ({ error }) => (\n <AlertBanner>\n <div className=\"icon\">\n <svg viewBox=\"0 0 22 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M11 4.49L18.53 17.5H3.47L11 4.49ZM11 0.5L0 19.5H22L11 0.5ZM12 14.5H10V16.5H12V14.5ZM12 8.5H10V12.5H12V8.5Z\"\n fill=\"#F6767A\"\n />\n </svg>\n </div>\n <div>{error}</div>\n </AlertBanner>\n);\nconst Nadabot = () => (\n <NadabotBanner>\n <div className=\"label\">\n <img\n src={`https://ipfs.near.social/ipfs/${NADA_BOT_ICON}`}\n alt=\"nadabot\"\n />\n You need to be verified to donate.\n </div>\n <a href=\"https://app.nada.bot/\" target=\"_blank\" className=\"verify\">\n Verify to donate\n </a>\n </NadabotBanner>\n);\nconst VerifyInfo = () => (\n <VerifyInfoWrapper>\n <div className=\"icon\">\n <svg\n width=\"18\"\n height=\"16\"\n viewBox=\"0 0 18 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M0.75 15.125H17.25L9 0.875L0.75 15.125ZM9.75 12.875H8.25V11.375H9.75V12.875ZM9.75 9.875H8.25V6.875H9.75V9.875Z\"\n fill=\"#ECC113\"\n />\n </svg>\n </div>\n <div className=\"text\">\n Your contribution won't be matched unless verified as human before the\n matching round ends.\n </div>\n <a href=\"https://app.nada.bot/\" target=\"_blank\">\n Verify you’re human\n </a>\n </VerifyInfoWrapper>\n);\nreturn {\n Alert,\n Nadabot,\n VerifyInfo,\n};\n" }, "ModalDonation.ConfirmDirect": { "": "const { NADABOT_HUMAN_METHOD, DONATION_CONTRACT_ID } = VM.require(\n \"old.potlock.near/widget/constants\"\n) || {\n NADABOT_HUMAN_METHOD: \"\",\n DONATION_CONTRACT_ID: \"\",\n};\nconst { nearToUsd } = VM.require(\"old.potlock.near/widget/utils\");\nlet DonateSDK =\n VM.require(\"old.potlock.near/widget/SDK.donate\") ||\n (() => ({\n getConfig: () => {},\n asyncGetDonationsForDonor: () => {},\n }));\nDonateSDK = DonateSDK({ env: props.env });\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getConfig: () => {},\n asyncGetDonationsForDonor: () => {},\n};\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n padding: 1.5rem 2rem;\n`;\nconst Label = styled.div`\n font-weight: 500;\n margin-bottom: 4px;\n`;\nconst Amout = styled.div`\n display: flex;\n align-items: center;\n gap: 0.5rem;\n span {\n font-weight: 600;\n }\n div {\n font-weight: 600;\n font-size: 1rem;\n }\n .usd-amount {\n color: #7b7b7b;\n }\n img,\n svg {\n width: 20px;\n }\n`;\nconst SvgIcon = styled.svg`\n width: 16px;\n`;\nconst NoteWrapper = styled.div`\n display: flex;\n cursor: pointer;\n align-items: center;\n gap: 8px;\n svg {\n width: 14px;\n }\n div {\n font-weight: 500;\n }\n`;\nconst FeesRemoval = styled.div`\n display: flex;\n flex-direction: column;\n gap: 1rem;\n .check {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n }\n .label {\n margin-right: 4px;\n margin-left: 8px;\n }\n .address {\n font-weight: 600;\n gap: 4px;\n display: flex;\n align-items: center;\n color: #292929;\n transition: all 300ms;\n &:hover {\n color: #dd3345;\n text-decoration: none;\n }\n }\n .profile-image {\n width: 17px;\n height: 17px;\n display: flex !important;\n }\n @media only screen and (max-width: 480px) {\n .address {\n margin-left: 34px;\n width: 100%;\n }\n }\n`;\nconst Button = styled.div`\n display: flex;\n margin-top: 2rem;\n margin-bottom: 0.5rem;\n button {\n padding: 12px 16px;\n width: 100%;\n font-weight: 500;\n }\n`;\nconst NearIcon = (props) => (\n <SvgIcon\n {...props}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <g clip-path=\"url(#clip0_454_78)\">\n <circle cx=\"8\" cy=\"8\" r=\"7.25\" stroke=\"#292929\" stroke-width=\"1.5\" />\n <path\n d=\"M11.1477 4C10.851 4 10.5763 4.15333 10.421 4.406L8.74866 6.88867C8.72453 6.92441 8.71422 6.96772 8.71967 7.01051C8.72511 7.05329 8.74594 7.09264 8.77826 7.1212C8.81057 7.14976 8.85218 7.1656 8.89531 7.16574C8.93844 7.16589 8.98015 7.15034 9.01266 7.122L10.6587 5.69467C10.6683 5.68598 10.6802 5.68028 10.6931 5.67828C10.7059 5.67628 10.719 5.67806 10.7308 5.6834C10.7426 5.68875 10.7526 5.69742 10.7596 5.70836C10.7665 5.7193 10.7702 5.73203 10.77 5.745V10.215C10.77 10.2287 10.7658 10.2421 10.7579 10.2534C10.7501 10.2646 10.7389 10.2732 10.726 10.2778C10.7131 10.2825 10.6991 10.2831 10.6858 10.2795C10.6726 10.2758 10.6608 10.2682 10.652 10.2577L5.67667 4.30167C5.59667 4.20709 5.49701 4.1311 5.38463 4.079C5.27226 4.0269 5.14987 3.99994 5.026 4H4.85233C4.62628 4 4.40949 4.0898 4.24964 4.24964C4.0898 4.40949 4 4.62628 4 4.85233V11.1477C4 11.3333 4.06061 11.5139 4.17263 11.6619C4.28465 11.81 4.44194 11.9174 4.6206 11.9679C4.79926 12.0184 4.98952 12.0091 5.16245 11.9416C5.33538 11.874 5.48152 11.7519 5.57867 11.5937L7.251 9.111C7.27513 9.07525 7.28544 9.03194 7.27999 8.98916C7.27455 8.94637 7.25372 8.90703 7.22141 8.87846C7.18909 8.8499 7.14748 8.83407 7.10435 8.83392C7.06122 8.83377 7.01951 8.84932 6.987 8.87766L5.341 10.3053C5.33134 10.3139 5.31939 10.3195 5.3066 10.3215C5.29381 10.3234 5.28074 10.3216 5.26898 10.3162C5.25721 10.3108 5.24726 10.3021 5.24034 10.2912C5.23342 10.2803 5.22983 10.2676 5.23 10.2547V5.784C5.22997 5.77027 5.23418 5.75687 5.24206 5.74563C5.24993 5.73438 5.26109 5.72584 5.274 5.72117C5.28691 5.71651 5.30094 5.71594 5.31419 5.71955C5.32743 5.72315 5.33924 5.73076 5.348 5.74133L10.3227 11.698C10.4847 11.8893 10.7227 11.9997 10.9733 12H11.147C11.373 12.0001 11.5898 11.9104 11.7498 11.7507C11.9097 11.591 11.9997 11.3744 12 11.1483V4.85233C11.9999 4.62631 11.9101 4.40956 11.7503 4.24974C11.5904 4.08992 11.3737 4.00009 11.1477 4Z\"\n fill=\"#292929\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_454_78\">\n <rect width=\"16\" height=\"16\" fill=\"white\" />\n </clipPath>\n </defs>\n </SvgIcon>\n);\nconst ProfileImg = ({ accountId }) => (\n <Widget\n src={\"old.potlock.near/widget/Project.ProfileImage\"}\n props={{\n accountId,\n style: {},\n }}\n />\n);\nconst CheckBox = ({ id, checked, onClick }) => (\n <Widget\n src={\"old.potlock.near/widget/Inputs.Checkbox\"}\n props={{\n id,\n checked,\n onClick,\n }}\n />\n);\nconst getFeesBasisPoints = (\n protocolConfig,\n potDetail,\n donationContractConfig\n) => {\n if (protocolConfig) {\n return [\n protocolConfig.account_id,\n protocolConfig.basis_points,\n potDetail.referral_fee_public_round_basis_points,\n ];\n } else if (donationContractConfig) {\n return [\n donationContractConfig.protocol_fee_recipient_account,\n donationContractConfig.protocol_fee_basis_points,\n donationContractConfig.referral_fee_basis_points,\n ];\n } else {\n return [\"\", 0, 0];\n }\n};\nconst pollForDonationSuccess = ({\n projectId: donatedProject,\n afterTs,\n accountId,\n openDonationSuccessModal,\n isPotDonation,\n}) => {\n // poll for updates\n // TODO: update this to also poll Pot contract\n const pollIntervalMs = 1000;\n // const totalPollTimeMs = 60000; // consider adding in to make sure interval doesn't run indefinitely\n const pollId = setInterval(() => {\n (isPotDonation ? PotSDK : DonateSDK)\n .asyncGetDonationsForDonor(accountId)\n .then((donations) => {\n for (const donation of donations) {\n const { recipient_id, project_id, donated_at_ms, donated_at } =\n donation; // donation contract uses recipient_id, pot contract uses project_id; donation contract uses donated_at_ms, pot contract uses donated_at\n if (\n ((project_id || recipient_id) === donatedProject &&\n (donated_at_ms || donated_at) > afterTs) ||\n donated_at > afterTs\n ) {\n // display success message\n clearInterval(pollId);\n openDonationSuccessModal({\n projectId: donation,\n });\n }\n }\n });\n }, pollIntervalMs);\n};\nconst ConfirmDirect = (props) => {\n const {\n selectedDenomination,\n bypassProtocolFee,\n bypassChefFee,\n donationNote,\n donationNoteError,\n addNote,\n updateState,\n selectedRound,\n projectId,\n referrerId,\n accountId,\n amount,\n openDonationSuccessModal,\n donationType,\n } = props;\n // Get protcol, referral & chef Fee\n const potDetail = PotSDK.getConfig(selectedRound);\n const protocolConfigContractId = potDetail\n ? potDetail.protocol_config_provider.split(\":\")[0]\n : \"\";\n const protocolConfigViewMethodName = potDetail\n ? potDetail.protocol_config_provider.split(\":\")[1]\n : \"\";\n const protocolConfig =\n protocolConfigContractId && protocolConfigViewMethodName\n ? Near.view(protocolConfigContractId, protocolConfigViewMethodName, {})\n : null;\n const donationContractConfig = !potDetail\n ? DonateSDK.getConfig() || {}\n : null;\n const [\n protocolFeeRecipientAccount,\n protocolFeeBasisPoints,\n referralFeeBasisPoints,\n ] = getFeesBasisPoints(protocolConfig, potDetail, donationContractConfig);\n const chefFeeBasisPoints =\n donationType === \"pot\" ? potDetail?.chef_fee_basis_points : \"\";\n const storageBalanceBounds = Near.view(\n selectedDenomination.id,\n \"storage_balance_bounds\",\n {}\n );\n const storageBalanceProtocolFeeRecipient = Near.view(\n selectedDenomination.id,\n \"storage_balance_of\",\n { account_id: protocolFeeRecipientAccount }\n );\n const storageBalanceReferrer = referrerId\n ? Near.view(selectedDenomination.id, \"storage_balance_of\", {\n account_id: referrerId,\n })\n : null;\n const storageBalanceDonationContract = Near.view(\n selectedDenomination.id,\n \"storage_balance_of\",\n {\n account_id: DONATION_CONTRACT_ID,\n }\n );\n const handleDonate = () => {\n const donationAmountIndivisible = Big(amount).mul(\n new Big(10).pow(selectedDenomination.decimals)\n );\n const args = {\n referrer_id: referrerId,\n bypass_protocol_fee: bypassProtocolFee,\n message: donationNote,\n ...(bypassChefFee ? { custom_chef_fee_basis_points: 0 } : {}),\n };\n const potId = selectedRound || null;\n const isPotDonation = potId && donationType === \"pot\";\n const now = Date.now();\n const successArgs = {\n projectId,\n afterTs: now,\n accountId,\n openDonationSuccessModal,\n isPotDonation,\n };\n if (isPotDonation) {\n args.project_id = projectId;\n if (bypassChefFee) {\n args.custom_chef_fee_basis_points = 0;\n }\n } else {\n args.recipient_id = projectId;\n }\n // FT WORKFLOW:\n // 1. SEND DEPOSIT TO DONATION CONTRACT\n /// 2. CALL FT CONTRACT:\n /// - check for storage balance for all accounts (protocol fee recipient, referrer, project, donation contract)\n const transactions = [];\n const isFtDonation = selectedDenomination.text !== \"NEAR\";\n if (isFtDonation) {\n const ftId = selectedDenomination.id;\n // add storage deposit transaction\n let requiredDepositFloat = 0.012; // base amount for donation storage\n requiredDepositFloat += 0.0001 * args.message.length; // add 0.0001 NEAR per character in message\n transactions.push({\n contractName: DONATION_CONTRACT_ID,\n methodName: \"storage_deposit\",\n args: {},\n deposit: Big(requiredDepositFloat).mul(Big(10).pow(24)),\n gas: \"100000000000000\",\n });\n const { min, max } = storageBalanceBounds;\n const storageMaxBig = Big(max);\n // check storage balance for each account\n if (\n !args.bypass_protocol_fee &&\n (!storageBalanceProtocolFeeRecipient ||\n Big(storageBalanceProtocolFeeRecipient.total).lt(storageMaxBig))\n ) {\n transactions.push({\n contractName: ftId,\n methodName: \"storage_deposit\",\n args: { account_id: protocolFeeRecipientAccount },\n deposit: storageMaxBig.minus(\n Big(storageBalanceProtocolFeeRecipient || 0)\n ),\n gas: \"100000000000000\",\n });\n }\n // referrer\n if (\n referrerId &&\n (!storageBalanceReferrer ||\n Big(storageBalanceReferrer.total).lt(storageMaxBig))\n ) {\n transactions.push({\n contractName: ftId,\n methodName: \"storage_deposit\",\n args: { account_id: referrerId },\n deposit: storageMaxBig.minus(Big(storageBalanceReferrer || 0)),\n gas: \"100000000000000\",\n });\n }\n // donation contract\n if (\n !storageBalanceDonationContract ||\n Big(storageBalanceDonationContract.total).lt(storageMaxBig)\n ) {\n transactions.push({\n contractName: ftId,\n methodName: \"storage_deposit\",\n args: { account_id: DONATION_CONTRACT_ID },\n deposit: storageMaxBig.minus(\n Big(storageBalanceDonationContract || 0)\n ),\n gas: \"100000000000000\",\n });\n }\n // project (can't do this till this point)\n Near.asyncView(ftId, \"storage_balance_of\", {\n account_id: projectId,\n }).then((balance) => {\n if (!balance || Big(balance.total).lt(storageMaxBig)) {\n transactions.push({\n contractName: ftId,\n methodName: \"storage_deposit\",\n args: { account_id: projectId },\n deposit: storageMaxBig.minus(Big(balance || 0)),\n gas: \"100000000000000\",\n });\n }\n // add donation transaction\n transactions.push({\n contractName: ftId,\n methodName: \"ft_transfer_call\",\n args: {\n receiver_id: DONATION_CONTRACT_ID,\n amount: donationAmountIndivisible.toFixed(0),\n msg: JSON.stringify({\n recipient_id: projectId,\n referrer_id: referrerId || null,\n bypass_protocol_fee: bypassProtocolFee,\n message: args.message,\n }),\n },\n deposit: \"1\",\n gas: \"300000000000000\",\n });\n Near.call(transactions);\n // NB: we won't get here if user used a web wallet, as it will redirect to the wallet\n // <-------- EXTENSION WALLET HANDLING -------->\n pollForDonationSuccess(successArgs);\n });\n } else {\n transactions.push({\n contractName: isPotDonation ? potId : DONATION_CONTRACT_ID,\n methodName: \"donate\",\n args,\n deposit: donationAmountIndivisible.toFixed(0),\n gas: \"300000000000000\",\n });\n Near.call(transactions);\n // NB: we won't get here if user used a web wallet, as it will redirect to the wallet\n // <-------- EXTENSION WALLET HANDLING -------->\n pollForDonationSuccess(successArgs);\n }\n };\n return (\n <Container>\n <div>\n <Label>Total amount</Label>\n <Amout>\n <div>\n {selectedDenomination.icon ? (\n <img src={selectedDenomination.icon} />\n ) : (\n <NearIcon />\n )}\n </div>\n <div>\n {amount} <span>{selectedDenomination.text}</span>\n </div>\n {nearToUsd && selectedDenomination.text === \"NEAR\" && (\n <div className=\"usd-amount\">\n ~${(nearToUsd * amount).toFixed(2)}\n </div>\n )}\n </Amout>\n </div>\n <div>\n <Widget\n src={\"old.potlock.near/widget/Cart.BreakdownSummary\"}\n props={{\n ...props,\n referrerId,\n protocolFeeBasisPoints,\n referralFeeBasisPoints,\n bypassChefFee,\n chef: potDetail?.chef,\n chefFeeBasisPoints,\n totalAmount: amount,\n bypassProtocolFee: bypassProtocolFee,\n ftIcon: selectedDenomination.icon,\n }}\n />\n </div>\n <FeesRemoval>\n <div className=\"check\">\n <CheckBox\n id=\"bypassProtocolFeeSelector\"\n checked={bypassProtocolFee}\n onClick={(e) => {\n updateState({ bypassProtocolFee: e.target.checked });\n }}\n />\n <div className=\"label\">\n Remove {protocolFeeBasisPoints / 100 || \"-\"}% protocol fee\n </div>\n <a\n href={`https://near.social/mob.near/widget/ProfilePage?accountId=${protocolFeeRecipientAccount}`}\n className=\"address\"\n target=\"_blank\"\n >\n <ProfileImg accountId={protocolFeeRecipientAccount} />\n {protocolFeeRecipientAccount}\n </a>\n </div>\n {potDetail?.chef && chefFeeBasisPoints > 0 && (\n <div className=\"check\">\n <CheckBox\n id=\"bypassChefFeeSelector\"\n checked={bypassChefFee}\n onClick={(e) => {\n updateState({ bypassChefFee: e.target.checked });\n }}\n />\n <div className=\"label\">\n {\" \"}\n Remove {chefFeeBasisPoints / 100 || \"-\"}% chef fee\n </div>\n <a\n href={`https://near.social/mob.near/widget/ProfilePage?accountId=${potDetail?.chef}`}\n className=\"address\"\n target=\"_blank\"\n >\n <ProfileImg accountId={potDetail?.chef} />\n {potDetail?.chef}\n </a>\n </div>\n )}\n </FeesRemoval>\n {addNote ? (\n <Widget\n src={\"old.potlock.near/widget/Inputs.TextArea\"}\n props={{\n label: \"Note\",\n inputRows: 2,\n inputStyle: {\n background: \"#FAFAFA\",\n },\n placeholder: `Add an optional note for the project (max ${MAX_NOTE_LENGTH} characters)`,\n value: donationNote,\n onChange: (donationNote) => updateState({ donationNote }),\n validate: () => {\n if (donationNote.length > MAX_NOTE_LENGTH) {\n updateState({\n donationNoteError: `Note must be less than ${MAX_NOTE_LENGTH} characters`,\n });\n return;\n }\n updateState({ donationNoteError: \"\" });\n },\n error: donationNoteError,\n }}\n />\n ) : (\n <NoteWrapper onClick={() => updateState({ addNote: true })}>\n <svg\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M0.249054 13.7509H3.06155L11.3566 5.4559L8.54405 2.6434L0.249054 10.9384V13.7509ZM1.74905 11.5609L8.54405 4.7659L9.23405 5.4559L2.43905 12.2509H1.74905V11.5609Z\"\n fill=\"#7B7B7B\"\n />\n <path\n d=\"M11.7766 0.468398C11.4841 0.175898 11.0116 0.175898 10.7191 0.468398L9.34655 1.8409L12.1591 4.6534L13.5316 3.2809C13.8241 2.9884 13.8241 2.5159 13.5316 2.2234L11.7766 0.468398Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n <div>Add Note</div>\n </NoteWrapper>\n )}\n <Button>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: \"Confirm donation\",\n onClick: handleDonate,\n }}\n />\n </Button>\n </Container>\n );\n};\nreturn {\n ConfirmDirect,\n};\n" }, "Pots.FundModal": { "": "const { isMatchingPoolModalOpen, onClose, potDetail, referrerId, potId } =\n props;\nconst {\n protocol_config_provider,\n chef_fee_basis_points,\n chef,\n base_currency,\n min_matching_pool_donation_amount,\n referral_fee_matching_pool_basis_points,\n} = potDetail;\nState.init({\n matchingPoolDonationAmountNear: \"\",\n matchingPoolDonationAmountNearError: \"\",\n matchingPoolDonationMessage: \"\",\n matchingPoolDonationMessageError: \"\",\n bypassProtocolFee: false,\n bypassChefFee: false,\n fundAsDao: false,\n daoAddress: \"\",\n daoAddressError: \"\",\n daoPolicy: {},\n});\nconst {\n matchingPoolDonationAmountNear,\n matchingPoolDonationAmountNearError,\n matchingPoolDonationMessage,\n matchingPoolDonationMessageError,\n bypassProtocolFee,\n bypassChefFee,\n fundAsDao,\n daoAddress,\n daoAddressError,\n} = state;\nconst { yoctosToNear, doesUserHaveDaoFunctionCallProposalPermissions } =\n VM.require(\"old.potlock.near/widget/utils\") || {\n yoctosToNear: () => \"\",\n doesUserHaveDaoFunctionCallProposalPermissions: () => \"\",\n };\nconst { _address } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n) || {\n _address: () => \"\",\n};\nconst { MAX_DONATION_MESSAGE_LENGTH, SUPPORTED_FTS, ONE_TGAS } = VM.require(\n \"old.potlock.near/widget/constants\"\n) || {\n ONE_TGAS: 0,\n MAX_DONATION_MESSAGE_LENGTH: 0,\n SUPPORTED_FTS: {},\n};\nBig.PE = 100;\nconst FIFTY_TGAS = \"50000000000000\";\nconst THREE_HUNDRED_TGAS = \"300000000000000\";\nconst MIN_DAO_PROPOSAL_DEPOSIT_FALLBACK = \"100000000000000000000000\"; // 0.1N\nconst protocolConfigContractId = protocol_config_provider.split(\":\")[0];\nconst protocolConfigViewMethodName = protocol_config_provider.split(\":\")[1];\nconst protocolConfig = Near.view(\n protocolConfigContractId,\n protocolConfigViewMethodName,\n {}\n);\nconst protocolFeeRecipientProfile = Social.getr(\n `${protocolConfig?.account_id}/profile`\n);\nconst chefProfile = Social.getr(`${chef}/profile`);\nconst chefFeeAmountNear = bypassChefFee\n ? 0\n : (matchingPoolDonationAmountNear * potDetail?.chef_fee_basis_points) /\n 10_000 || 0;\nconst protocolFeeAmountNear = bypassProtocolFee\n ? 0\n : (matchingPoolDonationAmountNear * protocolConfig?.basis_points) / 10_000 ||\n 0;\nconst referrerFeeAmountNear = referrerId\n ? (matchingPoolDonationAmountNear * referral_fee_matching_pool_basis_points) /\n 10_000 || 0\n : 0;\nconst handleMatchingPoolDonation = () => {\n const args = {\n message: matchingPoolDonationMessage,\n matching_pool: true,\n referrer_id: referrerId || null,\n bypass_protocol_fee: bypassProtocolFee,\n };\n if (state.bypassChefFee) {\n args.custom_chef_fee_basis_points = 0;\n }\n const amountFloat = parseFloat(matchingPoolDonationAmountNear || 0);\n if (!amountFloat) {\n State.update({ matchingPoolDonationAmountNearError: \"Invalid amount\" });\n return;\n }\n const amountIndivisible =\n SUPPORTED_FTS[base_currency.toUpperCase()].toIndivisible(amountFloat);\n const transactions = [\n {\n contractName: potId,\n methodName: \"donate\",\n deposit: amountIndivisible,\n args,\n gas: ONE_TGAS.mul(100),\n },\n ];\n // if it is a DAO, we need to convert transactions to DAO function call proposals\n if (state.fundAsDao) {\n const clonedTransactions = JSON.parse(JSON.stringify(transactions));\n transactions = clonedTransactions.map((tx) => {\n const action = {\n method_name: tx.methodName,\n gas: FIFTY_TGAS,\n deposit: tx.deposit ? tx.deposit.toString() : \"0\",\n args: Buffer.from(JSON.stringify(tx.args), \"utf-8\").toString(\"base64\"),\n };\n return {\n ...tx,\n contractName: state.daoAddress,\n methodName: \"add_proposal\",\n args: {\n proposal: {\n description: `Contribute to matching pool for ${potDetail.pot_name} pot (${potId}) on Potlock`,\n kind: {\n FunctionCall: {\n receiver_id: tx.contractName,\n actions: [action],\n },\n },\n },\n },\n deposit:\n state.daoPolicy.proposal_bond || MIN_DAO_PROPOSAL_DEPOSIT_FALLBACK,\n gas: THREE_HUNDRED_TGAS,\n };\n });\n }\n Near.call(transactions);\n // NB: we won't get here if user used a web wallet, as it will redirect to the wallet\n // <---- EXTENSION WALLET HANDLING ----> // TODO: implement\n};\nconst ModalTitle = styled.div`\n color: #525252;\n font-size: 16px;\n font-weight: 400;\n line-height: 20px;\n word-wrap: break-word;\n margin: 8px 0px;\n`;\nconst Row = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-start;\n`;\nconst UserChipLink = styled.a`\n display: flex;\n flex-direction: row;\n margin: 0px 4px;\n margin-left: auto;\n padding: 2px 12px;\n gap: 4px;\n border-radius: 32px;\n background: #ebebeb;\n &:hover {\n text-decoration: none;\n }\n`;\nconst TextBold = styled.div`\n color: #292929;\n font-size: 12px;\n font-weight: 600;\n line-height: 20px;\n word-wrap: break-word;\n text-align: center;\n`;\nconst FeeText = styled.div`\n color: #292929;\n font-size: 14px;\n font-weight: 400;\n line-height: 20px;\n word-wrap: break-word;\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n`;\nconst Label = styled.label`\n width: 100%;\n font-size: 12px;\n line-height: 16px;\n word-wrap: break-word;\n color: #2e2e2e;\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n`;\nconsole.log(protocolFeeRecipientProfile);\nreturn (\n <Widget\n src={\"old.potlock.near/widget/Components.Modal\"}\n props={{\n ...props,\n isModalOpen: isMatchingPoolModalOpen,\n onClose,\n children: (\n <>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Checkbox\"}\n props={{\n id: \"fundAsDaoSelector\",\n label: \"Fund as DAO\",\n checked: fundAsDao,\n onClick: (e) => {\n State.update({ fundAsDao: e.target.checked });\n },\n }}\n />\n {fundAsDao && (\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n inputStyle: {\n background: \"#FAFAFA\",\n },\n placeholder: \"Enter DAO address\",\n value: daoAddress,\n onChange: (daoAddress) =>\n State.update({\n daoAddress: daoAddress.trim().toLowerCase(),\n }),\n validate: () => {\n Near.asyncView(daoAddress, \"get_policy\", {})\n .then((policy) => {\n if (!policy) {\n State.update({\n daoAddressError: \"Invalid DAO address\",\n });\n }\n if (\n !doesUserHaveDaoFunctionCallProposalPermissions(\n context.accountId,\n policy\n )\n ) {\n State.update({\n daoAddressError:\n \"Your account does not have permission to create proposals\",\n });\n } else {\n State.update({\n daoAddressError: \"\",\n daoPolicy: policy,\n });\n }\n })\n .catch((e) => {\n State.update({ daoAddressError: \"Invalid DAO address\" });\n });\n },\n error: daoAddressError,\n }}\n />\n )}\n <ModalTitle>\n Enter matching pool contribution amount in NEAR\n {[\"0\", \"1\"].includes(min_matching_pool_donation_amount)\n ? \"(no minimum)\"\n : `(Min. ${yoctosToNear(min_matching_pool_donation_amount)})`}\n </ModalTitle>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n inputStyle: {\n background: \"#FAFAFA\",\n },\n placeholder: \"Enter amount here in NEAR\",\n value: matchingPoolDonationAmountNear,\n onChange: (matchingPoolDonationAmountNear) =>\n State.update({\n matchingPoolDonationAmountNear,\n }),\n validate: () => {\n // TODO: add validation logic here\n State.update({ matchingPoolDonationAmountNearError: \"\" });\n },\n error: matchingPoolDonationAmountNearError,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Inputs.TextArea\"}\n props={{\n noLabel: true,\n inputRows: 5,\n inputStyle: {\n background: \"#FAFAFA\",\n },\n placeholder: \"Enter an optional message\",\n value: matchingPoolDonationMessage,\n onChange: (matchingPoolDonationMessage) =>\n State.update({ matchingPoolDonationMessage }),\n validate: () => {\n if (\n matchingPoolDonationMessage.length >\n MAX_DONATION_MESSAGE_LENGTH\n ) {\n State.update({\n matchingPoolDonationMessageError: `Message must be less than ${MAX_DONATION_MESSAGE_LENGTH} characters`,\n });\n return;\n }\n State.update({ matchingPoolDonationMessageError: \"\" });\n },\n error: matchingPoolDonationMessageError,\n }}\n />\n <Row>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Checkbox\"}\n props={{\n id: \"bypassProtocolFeeSelector\",\n checked: bypassProtocolFee,\n onClick: (e) => {\n State.update({ bypassProtocolFee: e.target.checked });\n },\n }}\n />\n <Label htmlFor=\"bypassProtocolFeeSelector\">\n Bypass {protocolConfig?.basis_points / 100 || \"-\"}% protocol fee\n to{\" \"}\n <UserChipLink\n href={`https://near.social/mob.near/widget/ProfilePage?accountId=${protocolConfig?.account_id}`}\n target=\"_blank\"\n >\n <Widget\n src={\"old.potlock.near/widget/Project.ProfileImage\"}\n props={{\n ...props,\n accountId: protocolConfig?.account_id,\n style: {\n height: \"12px\",\n width: \"12px\",\n },\n }}\n />\n <TextBold>\n {_address(\n protocolFeeRecipientProfile?.name ||\n protocolConfig?.account_id\n )}\n </TextBold>\n </UserChipLink>\n </Label>\n </Row>\n {chef && chef_fee_basis_points > 0 && (\n <Row style={{ marginTop: \"6px\" }}>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Checkbox\"}\n props={{\n id: \"bypassChefFeeSelector\",\n checked: bypassChefFee,\n onClick: (e) => {\n State.update({ bypassChefFee: e.target.checked });\n },\n }}\n />\n <Label htmlFor=\"bypassChefFeeSelector\">\n Bypass {chef_fee_basis_points / 100 || \"-\"}% chef fee to\n <UserChipLink\n href={`https://near.social/mob.near/widget/ProfilePage?accountId=${chef}`}\n target=\"_blank\"\n >\n <Widget\n src={\"old.potlock.near/widget/Project.ProfileImage\"}\n props={{\n ...props,\n accountId: chef,\n style: {\n height: \"12px\",\n width: \"12px\",\n },\n }}\n />\n <TextBold>{chefProfile?.name || chef}</TextBold>\n </UserChipLink>\n </Label>\n </Row>\n )}\n <Row style={{ marginTop: \"12px\" }}>\n <FeeText>Protocol fee: {protocolFeeAmountNear} NEAR</FeeText>\n </Row>\n {chef && chef_fee_basis_points > 0 && (\n <Row style={{ marginTop: \"12px\" }}>\n <FeeText>Chef fee: {chefFeeAmountNear} NEAR</FeeText>\n </Row>\n )}\n <Row style={{ marginTop: \"6px\" }}>\n {referrerId && (\n <FeeText>\n Referrer fee (to {referrerId}): {referrerFeeAmountNear} NEAR\n </FeeText>\n )}\n </Row>\n <Row style={{ marginTop: \"6px\" }}>\n <FeeText>\n Net donation amount:{\" \"}\n {matchingPoolDonationAmountNear -\n protocolFeeAmountNear -\n chefFeeAmountNear -\n referrerFeeAmountNear}{\" \"}\n NEAR\n </FeeText>\n </Row>\n <Row style={{ justifyContent: \"flex-end\", marginTop: \"12px\" }}>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n disabled:\n daoAddressError ||\n !matchingPoolDonationAmountNear ||\n !!matchingPoolDonationAmountNearError ||\n !parseFloat(matchingPoolDonationAmountNear),\n text: `${\n fundAsDao ? \"Create proposal to contribute \" : \"Contribute\"\n }${\n matchingPoolDonationAmountNear\n ? ` ${matchingPoolDonationAmountNear} ${base_currency.toUpperCase()}`\n : \"\"\n } to matching pool`,\n onClick: handleMatchingPoolDonation,\n }}\n />\n </Row>\n </>\n ),\n }}\n />\n);\n" }, "Cart.Modal": { "": "const { getCartItemCount, getCart, removeItemsFromCart } = VM.require(\n \"old.potlock.near/widget/SDK.cart\"\n) ?? {\n getCartItemCount: () => 0,\n getCart: () => {},\n removeItemsFromCart: () => {},\n};\nconst { href } = VM.require(\"devs.near/widget/lib.url\") || {\n href: () => {},\n};\nconst navHeightPx = 110;\nconst navHeightPxMobile = 96;\nconst cart = getCart();\nconst numCartItems = getCartItemCount();\nconst ModalOverlay = styled.div`\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(255, 255, 255, 0.3);\n backdrop-filter: blur(4px);\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n align-items: flex-end;\n padding-top: ${navHeightPx * 0.8 + 50}px;\n padding-right: 32px;\n z-index: 1000;\n @media screen and (max-width: 768px) {\n padding-right: 8px;\n }\n`;\nconst ModalContainer = styled.div`\n width: 383px;\n border-radius: 12px;\n box-shadow: 0px 0px 0px 1px rgba(41, 41, 41, 0.1),\n 0px 8px 12px -4px rgba(41, 41, 41, 0.1),\n 0px 20px 32px -10px rgba(41, 41, 41, 0.1),\n 0px 32px 44px -16px rgba(41, 41, 41, 0.1);\n padding: 24px 0px;\n background: white;\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n align-items: flex-start;\n position: relative;\n max-height: 80vh;\n max-width: 90vw;\n overflow-y: scroll;\n`;\nconst ModalHeader = styled.div`\n width: 100%;\n // height: 100%;\n padding: 24px 24px 8px 24px;\n justify-content: space-between;\n align-items: flex-start;\n display: inline-flex;\n // background: pink;\n border-bottom: 1px #dbdbdb solid;\n position: relative;\n`;\nconst ModalHeaderText = styled.div`\n text-align: center;\n color: #2e2e2e;\n font-size: 14px;\n font-family: \"Mona Sans\", sans-serif;\n font-weight: 600;\n line-height: 16px;\n word-wrap: break-word;\n`;\nconst NoProjectsText = styled.div`\n text-align: center;\n color: #2e2e2e;\n font-size: 16px;\n font-weight: 500;\n margin-top: 24px;\n width: 100%;\n`;\nconst ButtonContainer = styled.div`\n display: flex;\n flex-direction: column;\n width: 100%;\n padding: 24px 24px 0 24px;\n`;\nconst Ear = styled.div`\n width: 16px;\n height: 16px;\n transform: rotate(45deg);\n transform-origin: 0 0;\n background: white;\n position: absolute;\n top: -11px;\n right: 32px;\n z-index: 1000;\n`;\nconst CartModal = ({ Trigger }) => {\n Trigger = Trigger ?? (() => <></>);\n return (\n <Widget\n src={\"devs.near/widget/Modal\"}\n props={{\n Trigger: Trigger,\n ModalOverlay: ModalOverlay,\n ModalContainer: ModalContainer,\n Content: () => (\n <>\n <ModalHeader>\n <ModalHeaderText>Donation cart</ModalHeaderText>\n <ModalHeaderText>\n {numCartItems}{\" \"}\n <span style={{ fontWeight: 400, color: \"#7B7B7B\" }}>\n {numCartItems === 1 ? \"project\" : \"projects\"}\n </span>\n </ModalHeaderText>\n </ModalHeader>\n {numCartItems === 0 ? (\n <NoProjectsText>Your cart is empty! 💸</NoProjectsText>\n ) : (\n (Object.keys(cart) ?? []).map((projectId) => {\n return (\n <Widget\n src={\"old.potlock.near/widget/Cart.CartModalItem\"}\n props={{\n ...props,\n projectId,\n removeProjectsFromCart: (projectIds) => {\n removeItemsFromCart({ id: projectIds });\n if (numCartItems === 1) {\n setIsModalOpen(false);\n }\n },\n }}\n />\n );\n })\n )}\n <ButtonContainer>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: \"Proceed to donate\",\n disabled: numCartItems === 0,\n href: href({\n widgetSrc: \"old.potlock.near/widget/Index\",\n params: { tab: \"cart\", referrerId: props.referrerId },\n }),\n style: {\n width: \"100%\",\n marginBottom: \"16px\",\n },\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: numCartItems === 0 ? \"primary\" : \"secondary\",\n text: \"Continue shopping\",\n onClick: () => setIsModalOpen(false),\n style: {\n width: \"100%\",\n },\n }}\n />\n </ButtonContainer>\n <Ear />\n </>\n ),\n }}\n />\n );\n};\nreturn { CartModal };\n" }, "Pots.FlagSuccessModal": { "": "const Container = styled.div`\n padding: 16px 32px 40px;\n svg {\n display: block;\n cursor: pointer;\n width: 14px;\n transition: all 300ms ease-in-out;\n margin: 5px 0;\n margin-left: auto;\n &:hover {\n rotate: 90deg;\n }\n }\n .title {\n margin-bottom: 1rem;\n font-size: 16px;\n color: #7b7b7b;\n font-weight: 600;\n span {\n font-weight: 600;\n color: #292929;\n }\n }\n .reason {\n font-size: 14px;\n color: #7b7b7b;\n }\n`;\nconst { onClose, successFlag } = props;\nreturn (\n <Widget\n src={\"old.potlock.near/widget/Components.Modal\"}\n props={{\n ...props,\n onClose: (e) => {\n e.stopPropagation();\n },\n contentStyle: {\n padding: \"0px\",\n },\n children: (\n <Container>\n <svg\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n onClick={onClose}\n >\n <path\n d=\"M14 1.41L12.59 0L7 5.59L1.41 0L0 1.41L5.59 7L0 12.59L1.41 14L7 8.41L12.59 14L14 12.59L8.41 7L14 1.41Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n <div className=\"title\">\n <span> {successFlag.address} </span> has been flagged\n </div>\n <div className=\"reason\">{successFlag.reason}</div>\n </Container>\n ),\n }}\n />\n);\n" }, "Components.Donors": { "": "const { calcNetDonationAmount, filterByDate } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n);\nlet PotFactorySDK =\n VM.require(\"old.potlock.near/widget/SDK.potfactory\") ||\n (() => ({\n getPots: () => {},\n }));\nPotFactorySDK = PotFactorySDK({ env: props.env });\nconst pots = PotFactorySDK.getPots();\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n asyncGetMatchingPoolDonations: () => {},\n};\nlet DonateSDK =\n VM.require(\"old.potlock.near/widget/SDK.donate\") ||\n (() => ({\n asyncGetDonations: () => {},\n }));\nDonateSDK = DonateSDK({ env: props.env });\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n .leaderboard {\n width: 100%;\n h1 {\n font-size: 2.5rem;\n font-weight: 600;\n margin-top: 20px;\n }\n .cards {\n display: flex;\n gap: 3rem;\n margin-top: 2rem;\n margin-bottom: 5rem;\n > div {\n width: 30%;\n display: flex;\n }\n .top {\n width: 40%;\n scale: 1.05;\n }\n @media only screen and (max-width: 670px) {\n flex-direction: column;\n justify-content: center;\n > div {\n width: 100%;\n display: flex;\n }\n .top {\n order: -1;\n scale: 1;\n width: 100%;\n }\n }\n }\n }\n`;\nconst Tabs = styled.div`\n display: flex;\n justify-content: space-between;\n flex-wrap: wrap;\n align-items: center;\n gap: 2rem;\n font-size: 14px;\n margin-bottom: 24px;\n .menu-item {\n font-weight: 600;\n display: flex;\n width: 100%;\n justify-content: space-between;\n gap: 20px;\n }\n .selected {\n gap: 10px;\n .label {\n text-transform: uppercase;\n color: #7b7b7b;\n }\n .count {\n color: #dd3345;\n }\n }\n .select {\n width: fit-content;\n }\n`;\nconst LoadingWrapper = styled.div`\n font-size: 1.5rem;\n margin-top: 1rem;\n`;\nconst Filter = styled.div`\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n .option {\n padding: 0.8em 1em;\n border-radius: 8px;\n color: #292929;\n box-shadow: 0px -1px 0px 0px #dbdbdb inset, 0px 0px 0px 0.5px #dbdbdb;\n transition: all 300ms ease-in-out;\n cursor: pointer;\n &.active,\n :hover {\n background: #292929;\n color: white;\n }\n }\n @media only screen and (max-width: 480px) {\n font-size: 10px;\n }\n`;\nconst Loading = () => <LoadingWrapper>Loading...</LoadingWrapper>;\nconst [index, setIndex] = useState(0);\nconst [currentTab, setTab] = useState(\"leaderboard\");\nconst [title, setTitle] = useState(\"\");\nconst [filter, setFilter] = useState(\"\");\nconst [allDonationsFetched, setAllDonationsFetched] = useState(false);\nconst [donationsByPage, setDonationsByPage] = useState({});\nconst [sponsorsByPage, setSponsorsByPage] = useState({});\nconst [fetchDonationsError, setFetchDonationsError] = useState(\"\");\nconst limit = 900;\nconst cachedDonationsValidityPeriod = 1000 * 60 * 5; // 5 minutes\nconst getSponsorshipDonations = (potId) => {\n return PotSDK.asyncGetMatchingPoolDonations(potId).then((donations) => {\n if (sponsorsByPage[potId]) return \"\";\n setSponsorsByPage((prevSponsorsByPage) => {\n Storage.set(\"sponsorsByPage\", {\n val: { ...prevSponsorsByPage, [potId]: donations },\n ts: Date.now(),\n });\n return { ...prevSponsorsByPage, [potId]: donations };\n });\n });\n};\n// Get Sponsorship Donations\nif (pots && !sponsorsByPage[pots[pots.length - 1].id]) {\n const cachedSponsors = Storage.get(\"sponsorsByPage\");\n if (\n cachedSponsors &&\n cachedSponsors.ts > Date.now() - cachedDonationsValidityPeriod\n ) {\n console.log(\"using cached sponsors\");\n setSponsorsByPage(cachedSponsors.val);\n } else if (cachedSponsors !== null) {\n pots.forEach((pot) => {\n getSponsorshipDonations(pot.id, potDetail);\n });\n }\n}\nconst sponsors = useMemo(() => {\n if (!sponsorsByPage[pots[pots.length - 1].id]) return [];\n let sponsors = Object.values(sponsorsByPage).flat();\n sponsors = sponsors.filter((donation) => filterByDate(filter, donation));\n sponsors = sponsors.reduce((accumulator, currentDonation) => {\n accumulator[currentDonation.donor_id] = {\n amount:\n (accumulator[currentDonation.donor_id].amount || 0) +\n calcNetDonationAmount(currentDonation),\n ...currentDonation,\n };\n return accumulator;\n }, {});\n sponsors = Object.values(sponsors).sort((a, b) => b.amount - a.amount);\n return sponsors;\n}, [sponsorsByPage, filter]);\nif (!allDonationsFetched && !donationsByPage[index]) {\n // first, try to get from cache\n const cacheKey = `donationsByPage-${index}-${limit}`;\n const cachedDonations = Storage.get(cacheKey);\n if (\n cachedDonations &&\n cachedDonations.ts > Date.now() - cachedDonationsValidityPeriod\n ) {\n console.log(\"using cached donations for page \", index);\n setDonationsByPage({ ...donationsByPage, [index]: cachedDonations.val });\n if (cachedDonations.val.length === limit) {\n setIndex(index + 1);\n } else {\n setAllDonationsFetched(true);\n }\n } else if (cachedDonations !== null) {\n // null means it's loading (async)\n console.log(\"fetching donations for page\", index);\n const startTime = Date.now();\n DonateSDK.asyncGetDonations(limit * index, limit)\n .then((donationsPart) => {\n const endTime = Date.now();\n console.log(\n \"fetched donations for index\",\n index,\n \"in\",\n endTime - startTime,\n \"ms\"\n );\n // cache the result\n Storage.set(cacheKey, { val: donationsPart, ts: Date.now() });\n setDonationsByPage({ ...donationsByPage, [index]: donationsPart });\n if (donationsPart.length === limit) {\n setIndex(index + 1);\n } else {\n setAllDonationsFetched(true);\n }\n })\n .catch((e) => {\n setFetchDonationsError(e);\n });\n }\n}\nconst [allDonations, totalsByDonor, sortedDonations] = useMemo(() => {\n if (!allDonationsFetched) return [[], {}, []];\n let donations = Object.values(donationsByPage).flat();\n donations = donations.filter((donation) => filterByDate(filter, donation));\n const totalsByDonor = donations.reduce((accumulator, currentDonation) => {\n accumulator[currentDonation.donor_id] = {\n amount:\n (accumulator[currentDonation.donor_id].amount || 0) +\n (currentDonation.ft_id === \"near\"\n ? calcNetDonationAmount(currentDonation)\n : 0),\n ...currentDonation,\n };\n return accumulator;\n }, {});\n const sortedDonations = Object.values(totalsByDonor).sort(\n (a, b) => b.amount - a.amount\n );\n return [donations, totalsByDonor, sortedDonations];\n}, [donationsByPage, allDonationsFetched, filter]);\nconst leaderboard = [\n {\n rank: \"#2\",\n id: sortedDonations[1].donor_id,\n amount: sortedDonations[1].amount,\n },\n {\n rank: (\n <img\n src=\"https://ipfs.near.social/ipfs/bafkreicjk6oy6465ps32owoomppfkvimbjlnhbaldvf6ujuyhkjas6ghjq\"\n alt=\"top\"\n />\n ),\n id: sortedDonations[0].donor_id,\n className: \"top\",\n amount: sortedDonations[0].amount,\n },\n {\n rank: \"#3\",\n id: sortedDonations[2].donor_id,\n amount: sortedDonations[2].amount,\n },\n];\nconst filterOptions = [\n { text: \"All Time\", value: \"all\" },\n { text: \"1Y\", value: \"year\" },\n { text: \"1M\", value: \"month\" },\n { text: \"1W\", value: \"week\" },\n { text: \"24H\", value: \"day\" },\n];\nconst MenuItem = ({ count, children, className }) => (\n <div className={`menu-item ${className || \"\"}`}>\n <div className=\"label\">{children}</div>\n <div className=\"count\">{count}</div>\n </div>\n);\nconst tabs = [\n {\n label: \"Donor Leaderboard\",\n val: \"leaderboard\",\n count: sortedDonations.length,\n },\n {\n label: \"Sponsors Leaderboard\",\n val: \"sponsors\",\n count: sponsors.length,\n },\n {\n label: \"Donor Feed\",\n val: \"feed\",\n count: allDonations.length,\n },\n];\nconst options = [\n { tab: \"feed\", src: \"Components.DonorsTrx\" },\n { tab: \"leaderboard\", src: \"Components.DonorsLeaderboard\" },\n { tab: \"sponsors\", src: \"Components.DonorsLeaderboard\" },\n];\nconst sortList = tabs.map((tab) => ({\n label: (\n <MenuItem key={tab.val} count={tab.count}>\n {tab.label}\n </MenuItem>\n ),\n val: tab,\n}));\nreturn (\n <Container>\n {fetchDonationsError ? (\n <div>\n <h1>Error fetching donations</h1>\n <p>{fetchDonationsError}</p>\n </div>\n ) : !allDonationsFetched ? (\n <Loading />\n ) : (\n <>\n <div className=\"leaderboard\">\n <h1>Donors Leaderboard</h1>\n <Widget\n src={\"old.potlock.near/widget/Components.DonorsCards\"}\n props={{ ...props, sponsors, sortedDonations, currentTab }}\n />\n </div>\n <Tabs>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Dropdown\"}\n props={{\n sortVal: title,\n title: (\n <MenuItem className=\"selected\" count={tabs[0].count}>\n {tabs[0].val}{\" \"}\n </MenuItem>\n ),\n sortList: sortList,\n FilterMenuCustomStyle: `left:0; right:auto;`,\n handleSortChange: ({ val: option }) => {\n setTitle(\n <MenuItem className=\"selected\" count={option.count}>\n {option.val}\n </MenuItem>\n );\n setTab(option.val);\n },\n }}\n />\n <Filter>\n {filterOptions.map((option) => (\n <div\n className={`option ${filter === option.value ? \"active\" : \"\"}`}\n key={option.value}\n onClick={() => setFilter(option.value)}\n >\n {option.text}\n </div>\n ))}\n </Filter>\n </Tabs>\n <Widget\n src={`old.potlock.near/widget/${\n options.find((option) => option.tab == currentTab).src\n }`}\n props={{\n ...props,\n allDonations: allDonations,\n filter,\n sponsors,\n sortedDonations,\n currentTab,\n }}\n />\n </>\n )}\n </Container>\n);\n" }, "Pots.Card": { "": "const { potId } = props;\nconst { daysUntil, yoctosToNear, yoctosToUsd } = VM.require(\n \"old.potlock.near/widget/utils\"\n) || {\n daysUntil: () => \"\",\n yoctosToNear: () => \"\",\n yoctosToUsd: () => \"\",\n};\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getConfig: () => {},\n};\nconst potConfig = PotSDK.getConfig(potId);\nconst MAX_DESCRIPTION_LENGTH = 100;\nconst MAX_TITLE_LENGTH = 36;\nconst Card = styled.a`\n display: flex;\n flex-direction: column;\n min-width: 320px;\n min-height: 300px;\n border-radius: 8px;\n background: white;\n box-shadow: 0px -2px 0px 0px #464646 inset, 0px 0px 0px 1px #464646;\n padding-bottom: 5px;\n height: 100%;\n &:hover {\n text-decoration: none;\n cursor: pointer;\n }\n`;\nconst CardSection = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n gap: 16px;\n padding: 32px;\n width: 100%;\n height: 100%;\n`;\nconst Title = styled.div`\n color: #292929;\n font-size: 22px;\n font-weight: 600;\n line-height: 28px;\n word-wrap: break-word;\n > div {\n font-weight: inherit;\n display: flex;\n align-items: baseline;\n }\n .usd-amount {\n font-size: 14px;\n font-weight: 400;\n margin-left: 0.25rem;\n }\n .text {\n font-size: 14px;\n color: #7b7b7b;\n margin-left: 0.5rem;\n }\n`;\nconst Description = styled.div`\n color: #525252;\n font-size: 16px;\n font-weight: 400;\n line-height: 28px;\n word-wrap: break-word;\n a {\n color: rgb(123, 123, 123);\n }\n`;\nconst Subtitle = styled.span`\n color: #7b7b7b;\n font-size: 14px;\n font-weight: 600;\n line-height: 20px;\n word-wrap: break-word;\n`;\nif (!potConfig)\n return (\n <Card style={{ justifyContent: \"center\", alignItems: \"center\" }}>\n {potConfig == null ? (\n <div class=\"spinner-border text-secondary\" role=\"status\" />\n ) : (\n <div>Pot {potId} not found.</div>\n )}\n </Card>\n );\nconst {\n pot_name,\n pot_description,\n base_currency,\n public_donations_count,\n matching_pool_balance,\n application_start_ms,\n application_end_ms,\n public_round_start_ms,\n public_round_end_ms,\n cooldown_end_ms,\n all_paid_out,\n} = potConfig;\n// const totalAmount =\n// props.SUPPORTED_FTS[base_currency.toUpperCase()].fromIndivisible(total_public_donations);\nconst description = !pot_description\n ? \"No description\"\n : pot_description.length > MAX_DESCRIPTION_LENGTH\n ? `${pot_description.slice(0, MAX_DESCRIPTION_LENGTH)}...`\n : pot_description;\nconst title = !pot_name\n ? \"No title\"\n : pot_name.length > MAX_TITLE_LENGTH\n ? `${pot_name.slice(0, MAX_TITLE_LENGTH)}...`\n : pot_name;\nconst now = Date.now();\nconst applicationNotStarted = now < application_start_ms;\nconst applicationOpen = now >= application_start_ms && now < application_end_ms;\nconst publicRoundNotStarted = now < public_round_start_ms;\nconst publicRoundOpen =\n now >= public_round_start_ms && now < public_round_end_ms;\nconst cooldownPending =\n public_round_end_ms && now >= public_round_end_ms && !cooldown_end_ms;\nconst cooldownOpen = now >= public_round_end_ms && now < cooldown_end_ms;\nconst payoutsPending =\n cooldown_end_ms && now >= cooldown_end_ms && !all_paid_out;\nconst payoutsCompleted = all_paid_out;\nconst amountNear = yoctosToNear(matching_pool_balance, true);\nconst amountUsd = yoctosToUsd(matching_pool_balance);\nconst tags = [\n /* Application's has not started tag */\n {\n backgroundColor: \"#EFFEFA\",\n borderColor: \"#33DDCB\",\n textColor: \"#023131\",\n text: \"Sponsorship Open\",\n textStyle: { fontWeight: 500, marginLeft: \"8px\" },\n preElementsProps: {\n colorOuter: \"#CAFDF3\",\n colorInner: \"#33DDCB\",\n animate: true,\n },\n visibility: now < application_start_ms,\n },\n /* Application tag */\n {\n backgroundColor: \"#EFFEFA\",\n borderColor: \"#33DDCB\",\n textColor: \"#023131\",\n text: daysUntil(application_end_ms) + \" left to apply\",\n textStyle: { fontWeight: 500, marginLeft: \"8px\" },\n preElementsProps: {\n colorOuter: \"#CAFDF3\",\n colorInner: \"#33DDCB\",\n animate: true,\n },\n visibility: applicationOpen,\n },\n /* Matching round open tag */\n {\n backgroundColor: \"#F7FDE8\",\n borderColor: \"#9ADD33\",\n textColor: \"#192C07\",\n text: daysUntil(public_round_end_ms) + \" left to donate\",\n textStyle: { fontWeight: 500, marginLeft: \"8px\" },\n preElementsProps: {\n colorOuter: \"#D7F5A1\",\n colorInner: \"#9ADD33\",\n animate: true,\n },\n visibility: publicRoundOpen,\n },\n /* Cooldown pending tag */\n {\n backgroundColor: \"#F5F3FF\",\n borderColor: \"#A68AFB\",\n textColor: \"#2E0F66\",\n text: \"Cooldown pending\",\n textStyle: { fontWeight: 500, marginLeft: \"8px\" },\n preElementsProps: {\n colorOuter: \"#EDE9FE\",\n colorInner: \"#A68AFB\",\n animate: true,\n },\n visibility: cooldownPending,\n },\n /* Matching round cooldown tag */\n {\n backgroundColor: \"#F5F3FF\",\n borderColor: \"#A68AFB\",\n textColor: \"#2E0F66\",\n text: \"Challenge period\",\n textStyle: { fontWeight: 500, marginLeft: \"8px\" },\n preElementsProps: {\n colorOuter: \"#EDE9FE\",\n colorInner: \"#A68AFB\",\n animate: true,\n },\n visibility: cooldownOpen,\n },\n /* Payouts pending tag */\n {\n backgroundColor: \"#F7FDE8\",\n borderColor: \"#9ADD33\",\n textColor: \"#192C07\",\n text: \"Payouts pending\",\n preElementsProps: {\n colorOuter: \"#D7F5A1\",\n colorInner: \"#9ADD33\",\n animate: true,\n },\n textStyle: { fontWeight: 500, marginLeft: \"8px\" },\n visibility: payoutsPending,\n },\n /* Matching round closed tag */\n {\n backgroundColor: \"#464646\",\n borderColor: \"#292929\",\n textColor: \"#FFF\",\n text: \"Payouts completed\",\n preElementsProps: {\n colorOuter: \"#656565\",\n colorInner: \"#A6A6A6\",\n animate: false,\n },\n textStyle: { fontWeight: 500, marginLeft: \"8px\" },\n visibility: payoutsCompleted,\n },\n];\nconst Tag = (props) => (\n <Widget\n src={\"old.potlock.near/widget/Pots.Tag\"}\n props={{\n ...props,\n ...(props.preElementsProps\n ? {\n preElements: (\n <Widget\n src={\"old.potlock.near/widget/Components.Indicator\"}\n props={props.preElementsProps}\n />\n ),\n }\n : {}),\n }}\n />\n);\nreturn (\n <Card\n href={props.hrefWithParams(`?tab=pot&potId=${potId}`)}\n data-testid={applicationOpen ? \"active-pot\" : \"inactive-pot\"}\n >\n <CardSection>\n <Title>{title}</Title>\n <Description>\n <Markdown text={description} />\n </Description>\n </CardSection>\n <CardSection\n style={{\n background: \"#F6F5F3\",\n borderTop: \"1px #7B7B7B solid\",\n marginTop: \"auto\",\n height: \"fit-content\",\n }}\n >\n <Title>\n <div>\n {amountNear}\n {amountUsd && <span className=\"usd-amount\">{amountUsd}</span>}\n <span className=\"text\">in pot</span>\n </div>\n </Title>\n {tags.map((tag) =>\n tag.visibility ? <Tag {...tag} key={tag.text} /> : \"\"\n )}\n </CardSection>\n </Card>\n);\n" }, "Components.Banner": { "": "let PotFactorySDK =\n VM.require(\"old.potlock.near/widget/SDK.potfactory\") ||\n (() => ({\n getPots: () => {},\n }));\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n asyncGetConfig: () => {},\n};\nconst [activeRounds, setActiveRounds] = useState([]);\nPotFactorySDK = PotFactorySDK({ env: props.env });\nconst pots = PotFactorySDK.getPots();\nconst now = Date.now();\nuseEffect(() => {\n if (pots) {\n pots.forEach((pot) => {\n PotSDK.asyncGetConfig(pot.id)\n .then((potConfig) => {\n const { public_round_start_ms, public_round_end_ms } = potConfig;\n if (public_round_start_ms < now && public_round_end_ms > now) {\n setActiveRounds((prevActiveRounds) => [\n ...prevActiveRounds,\n {\n ...potConfig,\n pot_id: pot.id,\n },\n ]);\n }\n })\n .catch((e) => {\n console.error(\"error getting pot detail: \", e);\n });\n });\n }\n}, [pots]);\nconst Wrapper = styled.div`\n height: ${(props) => (props.active ? \"48px\" : \"0px !important\")};\n @media screen and (max-width: 768px) {\n height: 36px;\n }\n`;\nconst Container = styled.div`\n width: 100%;\n height: ${(props) => (props.active ? \"48px\" : \"0px !important\")};\n bottom: 0;\n left: 0;\n position: fixed;\n z-index: 999;\n background: #7fc41e;\n color: white;\n display: flex;\n justify-content: center;\n align-items: center;\n overflow: hidden;\n .text {\n font-size: 22px;\n font-weight: 500;\n letter-spacing: 0.015em;\n text-transform: uppercase;\n display: flex;\n gap: 1rem;\n .link {\n display: flex;\n align-items: center;\n font-weight: 600;\n gap: 4px;\n color: white;\n text-decoration: underline;\n transition: transform 300ms ease-in-out;\n img {\n transition: rotate 300ms ease-in-out;\n height: 1em;\n width: fit-content;\n }\n :hover {\n transform: translateX(4px);\n img {\n rotate: 45deg;\n }\n }\n }\n }\n @media screen and (max-width: 992px) {\n .text {\n font-size: 1rem;\n }\n }\n @media screen and (max-width: 768px) {\n height: 36px;\n .text {\n font-size: 12px;\n gap: 0.5rem;\n }\n }\n`;\nconst isSingleRound = activeRounds.length === 1;\nconst limit = isSingleRound ? 20 : 10;\nconst potName =\n activeRounds[0].pot_name.length > limit\n ? activeRounds[0].pot_name.slice(0, limit).trim() + \"...\"\n : activeRounds[0].pot_name;\nconst textForOneRound = `${potName} round is live`;\nconst textForMultipleRounds = `Pot round is live for ${potName} and +${\n activeRounds.length - 1\n} More`;\nreturn (\n <Wrapper active={!!activeRounds.length}>\n <Container active={!!activeRounds.length}>\n <div className=\"text\">\n {isSingleRound ? textForOneRound : textForMultipleRounds}\n <a\n href={props.hrefWithParams(\n isSingleRound\n ? `?tab=pot&potId=${activeRounds[0].pot_id}`\n : `?tab=pots`\n )}\n className=\"link\"\n >\n {isSingleRound ? \"Donate\" : \"Check Now\"}\n <img\n src=\"https://ipfs.near.social/ipfs/bafkreigots5l4o5d3a4zksfimch3gvqw7ezb2quundmjwml33abo5atgwi\"\n alt=\"arrow\"\n />\n </a>\n </div>\n </Container>\n </Wrapper>\n);\n" }, "Components.Indicator": { "": "const Outer = styled.div`\n display: flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background-color: ${props.colorOuter};\n @keyframes beacon {\n 0%,\n 100% {\n transform: scale(1);\n }\n 50% {\n transform: scale(1.3);\n }\n }\n ${props.animate &&\n `\n animation: beacon 1.5s infinite;\n `}\n`;\nconst Inner = styled.div`\n width: 10px;\n height: 10px;\n border-radius: 50%;\n background-color: ${props.colorInner};\n`;\nreturn (\n <Outer>\n <Inner />\n </Outer>\n);\n" }, "Inputs.Text": { "": "const label = props.label ?? \"\";\nconst placeholder = props.placeholder ?? \"\";\nconst value = props.value ?? \"\";\nconst onChange = props.onChange ?? (() => {});\nconst onBlur = props.onBlur ?? (() => {});\nconst validate = props.validate ?? (() => {});\nconst error = props.error ?? \"\";\nconst Container = styled.div`\n display: flex;\n // flex: 1;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n padding: 0px;\n gap: 0.45em;\n width: 100%;\n`;\nconst Label = styled.label`\n font-weight: 500;\n font-size: 14px;\n line-height: 16px;\n word-wrap: break-word;\n color: #2e2e2e;\n`;\nconst Error = styled.span`\n display: inline-block;\n font-style: normal;\n font-weight: 400;\n font-size: 0.75em;\n line-height: 1.25em;\n color: #ff4d4f;\n height: 0;\n overflow: hidden;\n transition: height 0.3s ease-in-out;\n &.show {\n height: 1.25em;\n }\n`;\nconst InputContainer = styled.div`\n display: flex;\n flex-direction: row;\n width: 100%;\n background: #ffffff;\n border: 1px solid #d0d5dd;\n box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);\n border-radius: 4px;\n`;\nconst InputPrefix = styled.div`\n display: flex;\n justify-content: center;\n align-items: center;\n height: 100%;\n text-align: center;\n padding: 14px 16px;\n border-right: 1px #f0f0f0 solid;\n color: #7b7b7b;\n font-size: 16px;\n font-weight: 400;\n`;\nconst Input = styled.input`\n border: none;\n display: flex;\n flex-direction: row;\n align-items: center;\n padding: 0.5em 0.75em;\n gap: 0.5em;\n color: #101828;\n width: 100%;\n border-radius: 4px;\n`;\nconst PercentageSign = styled.span`\n display: flex;\n align-items: center;\n padding: 0 0.75em;\n color: #7b7b7b;\n font-size: 16px;\n font-weight: 400;\n`;\nreturn (\n <Container>\n {label && <Label>{label}</Label>}\n <InputContainer>\n {props.preInputChildren && props.preInputChildren}\n <Input\n type=\"text\"\n placeholder={placeholder}\n value={value}\n onChange={({ target: { value } }) => onChange(value)}\n onBlur={(value) => {\n validate();\n if (onBlur) onBlur(value);\n }}\n disabled={!!props.disabled}\n onKeyDown={props.handleKeyPress ?? null}\n style={props.inputStyles || {}}\n name={props.name}\n />\n {props.percent && <PercentageSign>%</PercentageSign>}\n {props.postInputChildren && props.postInputChildren}\n </InputContainer>\n <Error className={error ? \"show\" : \"\"}>{error}</Error>\n </Container>\n);\n" }, "Inputs.Dropdown": { "": "const {\n sortList,\n sortVal,\n title,\n handleSortChange,\n FilterMenuCustomStyle,\n showCount,\n} = props;\nconst [openFilter, setOpenFilter] = useState(false);\nconst FilterButton = styled.div`\n white-space: nowrap;\n display: flex;\n cursor: pointer;\n gap: 12px;\n align-items: center;\n font-size: 14px;\n font-weight: 500;\n line-height: 20px;\n border: 1px solid #292929;\n padding: 0.5rem 1rem;\n border-radius: 6px;\n color: #292929;\n * {\n font-weight: 500;\n }\n`;\nconst FilterIcon = styled.div`\n display: flex;\n width: 16px;\n height: 16px;\n align-items: center;\n justify-content: center;\n`;\nconst FilterMenu = styled.div`\n position: absolute;\n background: #fff;\n top: 140%;\n right: 0;\n padding: 8px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n border-radius: 6px;\n border: 1px solid rgba(41, 41, 41, 0.36);\n box-shadow: 0px 12px 20px -4px rgba(123, 123, 123, 0.32),\n 0px 4px 8px -3px rgba(123, 123, 123, 0.2),\n 0px 0px 2px 0px rgba(123, 123, 123, 0.36);\n z-index: 3;\n ${FilterMenuCustomStyle || \"\"}\n`;\nconst FilterItem = styled.div`\n cursor: pointer;\n padding: 8px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 12px;\n white-space: nowrap;\n transition: all 300ms ease-in-out;\n &:hover {\n color: #fff;\n background: #292929;\n border-radius: 6px;\n .count {\n color: #fff;\n }\n }\n .count {\n color: #7b7b7b;\n }\n`;\nconst Screen = styled.div`\n position: fixed;\n width: 100%;\n height: 100%;\n left: 0;\n top: 0;\n`;\nreturn (\n <>\n {openFilter && <Screen onClick={() => setOpenFilter(false)} />}\n <div\n style={{ position: \"relative\" }}\n onClick={() => setOpenFilter(!openFilter)}\n >\n <FilterButton style={props.buttonStyle || {}}>\n {sortVal || title}\n <FilterIcon>\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M8 3.88667L10.1133 6L11.0533 5.06L8 2L4.94 5.06L5.88667 6L8 3.88667ZM8 12.1133L5.88667 10L4.94667 10.94L8 14L11.06 10.94L10.1133 10L8 12.1133Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n </FilterIcon>\n </FilterButton>\n {openFilter && (\n <FilterMenu\n onClick={(e) => e.stopPropagation()}\n style={props.menuStyle || {}}\n >\n {sortList.map((option) => (\n <FilterItem\n key={option.val}\n onClick={() => {\n setOpenFilter(false);\n handleSortChange(option);\n }}\n >\n {option.label}{\" \"}\n <div className=\"count\">{showCount ? option.count : \"\"}</div>\n </FilterItem>\n ))}\n </FilterMenu>\n )}\n </div>\n </>\n);\n" }, "Pots.TimeLeft": { "": "const { daysLeft } = props;\nconst [timeLeft, setTimeLeft] = useState(\"-\");\nfunction formatTimeLeft(targetTimestamp) {\n // Calculate time remaining\n const now = new Date().getTime();\n const timeRemaining = targetTimestamp - now;\n // Check if time remaining is negative (target time already passed)\n if (timeRemaining <= 0) {\n return \"Time's up!\";\n }\n // Calculate days, hours, minutes, and seconds\n const days = Math.floor(timeRemaining / (1000 * 60 * 60 * 24));\n const hours = Math.floor(\n (timeRemaining % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)\n );\n const minutes = Math.floor((timeRemaining % (1000 * 60 * 60)) / (1000 * 60));\n const seconds = Math.floor((timeRemaining % (1000 * 60)) / 1000);\n // Construct formatted time string\n const formattedTime = `${days ? days + \"d\" : \"\"} ${\n hours ? hours + \"h\" : \"\"\n } ${minutes ? minutes + \"m\" : \"\"} ${seconds ? seconds + \"s\" : \"\"}`;\n return formattedTime.trim(); // Remove trailing space\n}\nuseEffect(() => {\n const intervelId = setInterval(() => {\n const time = formatTimeLeft(daysLeft);\n setTimeLeft(time);\n if (now > daysLeft) {\n clearInterval(intervelId);\n }\n }, 1000);\n}, []);\nreturn timeLeft;\n" }, "Components.AccountsStack": { "": "const { accountIds, maxDisplayCount, sendToBack } = props;\nconst MAX_DISPLAY_COUNT = maxDisplayCount || 5;\nconst StackContainer = styled.div`\n width: 200px;\n height: 30px;\n margin-bottom: 16px;\n display: flex;\n flex-direction: row;\n @media screen and (max-width: 768px) {\n margin-left: 36px;\n }\n`;\nconst MoreAccountsContainer = styled.div`\n width: 28px;\n height: 28px;\n border: 2px solid white;\n border-radius: 50%;\n background: #dd3345;\n position: relative;\n display: flex;\n justify-content: center;\n align-items: center;\n z-index: ${accountIds.length + 1};\n margin-right: -8px;\n`;\nconst MoreAccountsText = styled.div`\n color: white;\n font-size: 12px;\n font-weight: 600;\n text-align: center;\n`;\nconst accounts = useMemo(\n () => accountIds.slice(0, MAX_DISPLAY_COUNT),\n [accountIds]\n);\nreturn (\n <StackContainer>\n {accountIds.length > MAX_DISPLAY_COUNT && (\n <MoreAccountsContainer>\n <MoreAccountsText>{MAX_DISPLAY_COUNT}+</MoreAccountsText>\n </MoreAccountsContainer>\n )}\n {accounts.map((accountId, idx) => {\n return (\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{\n accountId,\n style: {\n width: \"28px\",\n height: \"28px\",\n zIndex: sendToBack ? 0 : accountIds.length - idx,\n margin: \"0 -8px 0 0\",\n border: \"2px solid white\",\n borderRadius: \"50%\",\n background: \"white\",\n },\n className: \"mb-2\",\n imageClassName: \"rounded-circle w-100 h-100 d-block\",\n thumbnail: false,\n tooltip: true,\n }}\n />\n );\n })}\n </StackContainer>\n);\n" }, "Components.Nav": { "": "const navHeightPx = 110;\nconst navHeightPxMobile = 96;\nconst Nav = styled.div`\n // commenting out stickiness for now\n // position: fixed;\n // top: 0;\n // left: 0;\n width: 100%;\n display: flex;\n padding: 0 40px;\n justify-content: start;\n align-items: center;\n align-self: stretch;\n height: ${navHeightPx}px;\n background: #ffffff;\n z-index: 1000;\n // background: pink;\n @media screen and (max-width: 768px) {\n // display: none;\n padding: 24px 8px 24px 16px;\n height: ${navHeightPxMobile}px;\n }\n @media screen and (max-width: 480px) {\n padding: 24px 8px 24px 0px;\n }\n & > a {\n width: 10rem;\n }\n`;\nconst NavLeft = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n // background: green;\n`;\nconst NavRight = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n`;\nconst NavRightMobile = styled.div`\n display: none;\n @media screen and (max-width: 768px) {\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-end;\n gap: 16px;\n padding-right: 16px;\n }\n`;\nconst NavLogo = styled(\"Link\")`\n display: flex;\n gap: 7px;\n align-items: baseline;\n text-align: center;\n color: #2e2e2e;\n font-size: 23.95px;\n font-weight: 700;\n line-height: 23.95px;\n word-wrap: break-word;\n margin-right: 48px;\n text-decoration: none;\n @media screen and (max-width: 480px) {\n font-size: 20px;\n margin-right: 1rem;\n }\n :hover {\n text-decoration: none;\n }\n img {\n height: 1em;\n }\n`;\nconst NavTabs = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n @media screen and (max-width: 768px) {\n display: none;\n }\n`;\nconst NavTab = styled(\"Link\")`\n cursor: ${(props) => (props.disabled ? \"not-allowed\" : \"pointer\")};\n color: ${(props) => (props.selected ? \"#2E2E2E\" : \"#7B7B7B\")};\n font-size: 14px;\n font-weight: ${(props) => (props.selected ? 500 : 400)};\n line-height: 16px;\n word-wrap: break-word;\n text-decoration: none;\n position: relative;\n :not(:last-child) {\n margin-right: 32px;\n }\n :hover {\n text-decoration: none;\n }\n`;\nconst Banner = styled.div`\n width: 100%;\n // max-height: 50px;\n background: #dd3345;\n // background: rgb(6 10 15);\n display: flex;\n flex-direction: row;\n justify-content: center;\n align-items: center;\n padding: 8px 0;\n // border-bottom: 2px rgb(96, 100, 102) solid;\n`;\nconst BannerText = styled.div`\n text-align: center;\n color: white;\n font-size: 16px;\n font-weight: 600;\n margin-left: 8px;\n @media screen and (max-width: 768px) {\n font-size: 12px;\n margin-left: 4px;\n }\n`;\nconst BannerLinkContainer = styled.a`\n display: flex;\n cursor: pointer;\n text-align: center;\n font-weight: bold;\n color: white;\n font-size: 14px;\n line-height: 21px;\n margin-left: 16px;\n gap: 8px;\n &:hover {\n text-decoration: none;\n }\n @media screen and (max-width: 768px) {\n font-size: 12px;\n margin-left: 8px;\n gap: 4px;\n }\n`;\nconst BannerLinkSvg = styled.svg`\n width: 20px;\n height: 20px;\n fill: none;\n transition: transform 0.2s ease;\n &:hover {\n transform: rotate(45deg);\n }\n @media screen and (max-width: 768px) {\n width: 16px;\n height: 16px;\n }\n`;\nconst BannerAlertSvg = styled.svg`\n width: 18px;\n @media screen and (max-width: 768px) {\n width: 14px;\n }\n`;\nconst NavMenu = styled.div`\n display: none;\n background: white;\n padding: 24px;\n width: 100%;\n gap: 16px;\n @media screen and (max-width: 768px) {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n align-items: flex-start;\n }\n`;\nconst NavMenuItem = styled.a`\n color: ${(props) => (props.selected ? \"#2E2E2E\" : \"#7B7B7B\")};\n font-size: 14px;\n font-weight: ${(props) => (props.selected ? 500 : 400)};\n line-height: 20px;\n word-wrap: break-word;\n cursor: pointer;\n`;\nconst tabOptions = [\n { text: \"Projects\", link: \"projects\", disabled: false },\n { text: \"Feed\", link: \"feed\", disabled: false },\n {\n text: \"Pots\",\n link: \"pots\",\n disabled: false,\n },\n { text: \"Donors\", link: \"donors\", disabled: false },\n // { text: \"Feedback\", href: \"https://potlock.org/feedback\", newTab: true, disabled: false },\n];\nconst [isNavMenuOpen, setIsNavMenuOpen] = useState(false);\nreturn (\n <>\n {false && (\n <Banner>\n <BannerAlertSvg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"white\"\n aria-hidden=\"true\"\n // width=\"18px\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z\"\n ></path>\n </BannerAlertSvg>\n <BannerText>This app is in beta. It has not been audited.</BannerText>\n <BannerLinkContainer\n href=\"https://docs.potlock.io/general-information/beta-phase\"\n target=\"_blank\"\n >\n <span>Learn more</span>\n <BannerLinkSvg\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"w-[18px] group-hover:rotate-[45deg] transition-all\"\n >\n <path\n d=\"M11.6652 6.77894C11.0834 6.78279 10.5015 6.78574 9.91929 6.78777C9.06125 6.78766 8.20376 6.79135 7.34566 6.78145C6.762 6.77478 6.29535 6.33298 6.30266 5.81732C6.31009 5.32123 6.77706 4.88706 7.32973 4.89083C9.53277 4.89897 11.7351 4.91291 13.9368 4.93265C14.6025 4.93925 14.9748 5.32235 14.9826 6.0022C15.0022 8.19227 15.0157 10.3823 15.0231 12.5723C15.0251 13.2043 14.6477 13.6102 14.0912 13.6135C13.5527 13.6152 13.1403 13.1552 13.1372 12.5298C13.1307 11.2364 13.133 9.9431 13.1287 8.64975C13.1284 8.51553 13.113 8.38013 13.0963 8.12137L12.7089 8.50873C10.6829 10.5347 8.64711 12.5508 6.63972 14.5954C6.22161 15.0212 5.62148 14.9861 5.28149 14.6461C4.88466 14.2493 4.90002 13.7158 5.32463 13.2846C7.35705 11.2478 9.39203 9.21284 11.4295 7.17969L11.7105 6.89876L11.6652 6.77894Z\"\n fill=\"currentColor\"\n ></path>\n </BannerLinkSvg>\n </BannerLinkContainer>\n </Banner>\n )}\n <Nav>\n <NavLeft>\n <NavLogo href={props.hrefWithParams(`?tab=projects`)}>\n <img\n src=\"https://ipfs.near.social/ipfs/bafkreiafms2jag3gjbypfceafz2uvs66o25qc7m6u6hkxfyrzfoeyvj7ru\"\n alt=\"logo\"\n />\n POTLOCK\n </NavLogo>\n </NavLeft>\n <NavRight>\n <NavTabs>\n {(tabOptions ?? []).map((tab) => {\n return (\n <NavTab\n href={tab.href ?? props.hrefWithParams(`?tab=${tab.link}`)}\n disabled={tab.disabled}\n target={tab.newTab ? \"_blank\" : \"\"}\n onClick={(e) => {\n if (tab.disabled) e.preventDefault();\n }}\n selected={props.tab === tab.link}\n >\n {tab.text}\n </NavTab>\n );\n })}\n <Widget src={\"old.potlock.near/widget/Cart.NavItem\"} props={props} />\n </NavTabs>\n </NavRight>\n <NavRightMobile>\n <Widget src={\"old.potlock.near/widget/Cart.NavItem\"} props={props} />\n <NavTab onClick={() => setIsNavMenuOpen(!isNavMenuOpen)}>\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n >\n <path\n d=\"M3 18H21V16H3V18ZM3 13H21V11H3V13ZM3 6V8H21V6H3Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n </NavTab>\n </NavRightMobile>\n </Nav>\n {isNavMenuOpen && (\n <NavMenu>\n {tabOptions.map((tab) => {\n return (\n <NavMenuItem\n href={props.hrefWithParams(`?tab=${tab.link}`)}\n disabled={tab.disabled}\n onClick={(e) => {\n if (tab.disabled) e.preventDefault();\n }}\n selected={props.tab === tab.link}\n >\n {tab.text}\n {tab.disabled && \" (Coming Soon)\"}\n </NavMenuItem>\n );\n })}\n </NavMenu>\n )}\n </>\n);\n" }, "Inputs.Date": { "": "const label = props.label ?? \"\";\nconst placeholder = props.placeholder ?? \"\";\nconst value = props.value ?? \"\";\nconst onChange = props.onChange ?? (() => {});\nconst validate = props.validate ?? (() => {});\nconst error = props.error ?? \"\";\nconst Container = styled.div`\n display: flex;\n // flex: 1;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n padding: 0px;\n gap: 0.45em;\n width: 100%;\n`;\nconst Label = styled.label`\n font-weight: 500;\n font-size: 14px;\n line-height: 16px;\n word-wrap: break-word;\n color: #2e2e2e;\n`;\nconst Error = styled.span`\n display: inline-block;\n font-style: normal;\n font-weight: 400;\n font-size: 0.75em;\n line-height: 1.25em;\n color: #ff4d4f;\n height: 0;\n overflow: hidden;\n transition: height 0.3s ease-in-out;\n &.show {\n height: 1.25em;\n }\n`;\nconst InputContainer = styled.div`\n display: flex;\n flex-direction: row;\n width: 100%;\n background: #ffffff;\n border: 1px solid #d0d5dd;\n box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);\n border-radius: 4px;\n`;\nconst InputPrefix = styled.div`\n display: flex;\n justify-content: center;\n align-items: center;\n height: 100%;\n text-align: center;\n padding: 14px 16px;\n border-right: 1px #f0f0f0 solid;\n color: #7b7b7b;\n font-size: 16px;\n font-weight: 400;\n`;\nconst Input = styled.input`\n border: none;\n display: flex;\n flex-direction: row;\n align-items: center;\n padding: 0.5em 0.75em;\n gap: 0.5em;\n color: #101828;\n width: 100%;\n border-radius: 4px;\n`;\nreturn (\n <Container>\n {label && <Label>{label}</Label>}\n <InputContainer>\n {/* {props.prefixText && <InputPrefix>{props.prefixText}</InputPrefix>} */}\n {/* {props.prefixElement && props.prefixElement} */}\n {props.preInputChildren && props.preInputChildren}\n <Input\n type={props.selectTime ? \"datetime-local\" : \"date\"}\n placeholder={placeholder}\n value={value}\n onChange={({ target: { value } }) => onChange(value)}\n onBlur={() => validate()}\n disabled={!!props.disabled}\n onKeyDown={props.handleKeyPress ?? null}\n style={props.inputStyles || {}}\n />\n {props.postInputChildren && props.postInputChildren}\n </InputContainer>\n <Error className={error ? \"show\" : \"\"}>{error}</Error>\n </Container>\n);\n" }, "Components.DonorsLeaderboard": { "": "const { sponsors, sortedDonations, filter, currentTab, tab } = props;\nconst donations = currentTab === \"sponsors\" ? sponsors : sortedDonations;\nconst isInPot = tab === \"pot\";\nconst { nearToUsd } = VM.require(\"old.potlock.near/widget/utils\") || {\n nearToUsd: 1,\n};\nconst [currentPage, setCurrentPage] = useState(1);\nconst perPage = 30; // need to be less than 50\nuseEffect(() => {\n setCurrentPage(1);\n}, [filter]);\nconst nearLogo =\n \"https://ipfs.near.social/ipfs/bafkreicdcpxua47eddhzjplmrs23mdjt63czowfsa2jnw4krkt532pa2ha\";\nconst { getTimePassed, _address, calcNetDonationAmount, reverseArr } =\n VM.require(\"old.potlock.near/widget/Components.DonorsUtils\");\nconst Container = styled.div`\n width: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2rem;\n .transcation {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-size: 14px;\n .header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px;\n gap: 1rem;\n background: #f6f5f3;\n color: #292929;\n div {\n width: 130px;\n display: flex;\n justify-content: center;\n align-items: center;\n font-weight: 600;\n }\n }\n .address {\n width: 190px !important;\n margin-right: auto;\n justify-content: start !important;\n }\n .rank {\n width: 80px !important;\n }\n }\n @media only screen and (max-width: 768px) {\n .transcation {\n font-size: 12px;\n .header {\n padding: 10px 0;\n div {\n width: 80px;\n }\n }\n }\n }\n @media only screen and (max-width: 480px) {\n .transcation {\n font-size: 9px;\n .address {\n width: 120px !important;\n }\n }\n }\n`;\nconst TrRow = styled.div`\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n gap: 1rem;\n padding: 20px 10px;\n > div,\n > span {\n width: 130px;\n display: flex;\n justify-content: center;\n align-items: center;\n }\n .price {\n display: flex;\n gap: 1rem;\n align-items: center;\n img {\n width: 1.5rem;\n }\n }\n .address {\n color: #292929;\n display: flex;\n align-items: center;\n justify-content: flex-start;\n border-radius: 2px;\n transition: all 200ms;\n .profile-image {\n width: 2rem;\n height: 2rem;\n margin-right: 1rem;\n }\n }\n @media only screen and (max-width: 768px) {\n padding: 10px 0;\n > div,\n > span {\n width: 80px;\n }\n .price {\n gap: 8px;\n img {\n width: 1.25rem;\n }\n }\n .address .profile-image {\n width: 1.5rem;\n height: 1.5rem;\n margin-right: 0.5rem;\n }\n }\n @media only screen and (max-width: 480px) {\n .price img {\n width: 1rem;\n }\n }\n`;\nconst NoResult = styled.div`\n font-size: 2rem;\n text-align: center;\n`;\nconst totalDonations = 0;\ndonations.forEach((donation) => {\n totalDonations += donation.amount;\n});\nconst ProfileImg = ({ donor_id }) => (\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{ accountId: donor_id, style: {} }}\n />\n);\nreturn donations.length ? (\n <Container>\n <div className=\"transcation\">\n <div className=\"header\">\n <div className=\"rank\">Rank</div>\n <div className=\"address\">Donor</div>\n <div>Amount</div>\n {isInPot && <div>Percentage</div>}\n {nearToUsd && !isInPot && <div>Amount (USD)</div>}\n </div>\n {donations\n .slice((currentPage - 1) * perPage, currentPage * perPage)\n .map((donation, idx) => {\n const { donor_id, amount, percentage_share } = donation;\n return (\n <TrRow>\n <div className=\"rank\">\n #{idx + 1 + (currentPage - 1) * perPage}\n </div>\n <a\n href={props.hrefWithParams(\n `?tab=profile&accountId=${donor_id}`\n )}\n className=\"address\"\n target=\"_blank\"\n >\n <ProfileImg donor_id={donor_id} />\n {_address(donor_id, 15)}\n </a>\n <div className=\"price\">\n <img src={nearLogo} alt=\"NEAR\" />\n {amount.toFixed(2).replace(/[.,]00$/, \"\")}\n </div>\n {isInPot && <div>{percentage_share}%</div>}\n {nearToUsd && !isInPot && (\n <div>~${(amount * nearToUsd).toFixed(2)}</div>\n )}\n </TrRow>\n );\n })}\n </div>\n <Widget\n src={\"old.potlock.near/widget/Components.Pagination\"}\n props={{\n onPageChange: (page) => {\n setCurrentPage(page);\n },\n data: donations,\n currentPage,\n perPage: perPage,\n bgColor: \"#292929\",\n }}\n />\n </Container>\n) : (\n <NoResult>No Donations</NoResult>\n);\n" }, "Inputs.FilterDropdown": { "": "const Container = styled.div`\n display: flex;\n position: relative;\n flex-direction: column;\n align-items: flex-end;\n font-size: 14px;\n`;\nconst Label = styled.div`\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n cursor: pointer;\n width: fit-content;\n padding: 0.5rem 1rem;\n border-radius: 6px;\n border: 1px solid #7b7b7b;\n &.active {\n color: #fff;\n background: #292929;\n }\n`;\nconst Menu = styled.div`\n position: absolute;\n top: calc(100% + 0.5rem);\n right: 0;\n transition: all 300ms ease-in-out;\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n border-radius: 8px;\n padding: 1rem;\n background: #fff;\n width: 500px;\n box-shadow: 0px 0px 0px 1px rgba(123, 123, 123, 0.09),\n 0px 3px 3px -1px rgba(123, 123, 123, 0.16),\n 0px 9px 9px -3px rgba(123, 123, 123, 0.1),\n 0px 17px 14px -5px rgba(123, 123, 123, 0.08);\n opacity: 0;\n visibility: hidden;\n transform: translateY(100px);\n z-index: 1;\n &.active {\n opacity: 1;\n visibility: visible;\n transform: translateY(0);\n }\n .title {\n width: 100%;\n &:not(:first-of-type) {\n margin-top: 2rem;\n }\n }\n .option {\n display: flex;\n align-items: center;\n gap: 10px;\n border-radius: 8px;\n border: 1px solid #dbdbdb;\n padding: 8px 12px;\n cursor: pointer;\n transition: all 300ms ease-in-out;\n svg {\n display: none;\n width: 14px;\n }\n :hover {\n border: 1px solid #f4b37d;\n background: #fef6ee;\n color: #ea6a25;\n }\n &.selected {\n border: 1px solid #f4b37d;\n background: #fef6ee;\n color: #ea6a25;\n svg {\n display: block;\n }\n }\n }\n @media only screen and (max-width: 768px) {\n width: 200px !important;\n left: 0;\n right: auto;\n }\n`;\nconst Count = styled.div`\n font-weight: 600;\n font-size: 12px;\n display: flex;\n line-height: 1;\n width: 18px;\n height: 18px;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n background: #ebebeb;\n &.active {\n background: #464646;\n color: #f6f5f3;\n }\n`;\nconst Screen = styled.div`\n position: fixed;\n width: 100%;\n height: 100%;\n left: 0;\n top: 0;\n`;\nconst { onClick, menuClass, label, multipleOptions, defaultSelected } = props;\nconst labelIcon = props.labelIcon ?? \"center\";\nconst options = props.options ?? {};\nconst [toggleMenu, setToggleMenu] = useState(false);\nconst [selected, setSelected] = useState(defaultSelected || {});\nconst icons = {\n center: (\n <svg\n width=\"18\"\n height=\"12\"\n viewBox=\"0 0 18 12\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M7 12H11V10H7V12ZM0 0V2H18V0H0ZM3 7H15V5H3V7Z\" fill=\"#7B7B7B\" />\n </svg>\n ),\n right: (\n <svg\n width=\"18\"\n height=\"12\"\n viewBox=\"0 0 18 12\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M0 12H6V10H0V12ZM0 0V2H18V0H0ZM0 7H12V5H0V7Z\" fill=\"#7B7B7B\" />\n </svg>\n ),\n};\nfunction findIndexWithAll(listOfLists, target) {\n for (let i = 0; i < listOfLists.length; i++) {\n const indexInList = listOfLists[i].indexOf(target);\n if (indexInList !== -1) {\n return { listIndex: i, itemIndex: indexInList };\n }\n }\n return { listIndex: -1, itemIndex: -1 }; // Not found\n}\nconst handleSelect = ({ val, type, label }) => {\n let selectedUpdated = { ...selected };\n const selectedList = selected[type] || [];\n if (!multipleOptions) {\n selectedUpdated = { val, label };\n } else if (selectedList.includes(val)) {\n selectedUpdated[type] = selectedList.filter((item) => item !== val);\n } else {\n selectedUpdated[type] = [...selectedList, val];\n }\n const { listIndex, itemIndex } = findIndexWithAll(\n Object.values(selectedUpdated),\n \"all\"\n );\n const types = Object.keys(selectedUpdated);\n // remove filters if all is selected\n if (val === \"all\") {\n selectedUpdated = {\n [type]: [val],\n };\n }\n // remove all if another filter is selected\n else if (listIndex !== -1) {\n selectedUpdated[types[listIndex]].splice(itemIndex, 1);\n }\n setSelected(selectedUpdated);\n onClick(selectedUpdated);\n setToggleMenu(false);\n};\nconst count = Object.values(selected).reduce(\n (total, list) => total + list.length,\n 0\n);\nreturn (\n <Container>\n {toggleMenu && <Screen onClick={() => setToggleMenu(false)} />}\n <Label\n className={toggleMenu ? \"active\" : \"\"}\n onClick={() => setToggleMenu(!toggleMenu)}\n >\n {label || \"Filter\"}\n {multipleOptions && (\n <Count className={toggleMenu ? \"active\" : \"\"}>{count}</Count>\n )}\n {icons[labelIcon]}\n </Label>\n <Menu className={`${toggleMenu ? \"active\" : \"\"} ${menuClass ?? \"\"}`}>\n {Object.keys(options)?.map((menuLabel) => (\n <>\n <div className=\"title\">\n Filter by {menuLabel.includes(\"no label\") ? \"\" : menuLabel}\n </div>\n {(options[menuLabel] || [])?.map(({ label, val }) => (\n <div\n className={`option ${\n multipleOptions &&\n (selected[menuLabel] || [])?.includes(val) &&\n \"selected\"\n }`}\n key={val}\n onClick={() => handleSelect({ label, val, type: menuLabel })}\n >\n <svg\n viewBox=\"0 0 14 12\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M4.59625 8.90631L1.46875 5.77881L0.403748 6.83631L4.59625 11.0288L13.5962 2.02881L12.5387 0.971313L4.59625 8.90631Z\"\n fill=\"#F4B37D\"\n />\n </svg>\n {label}\n </div>\n ))}\n </>\n ))}\n </Menu>\n </Container>\n);\n" }, "Components.ui.Button": { "": "const { Volunteer } = VM.require(\n \"old.potlock.near/widget/Components.Icons\"\n) || {\n Volunteer: () => <></>,\n};\nconst StyledButton = styled.button`\n all: unset;\n width: 120px;\n height: 22px;\n border-radius: 6px;\n padding: 9px 16px 9px 12px;\n justify-content: center;\n align-items: center;\n display: inline-flex;\n gap: 8px;\n font-size: 14px;\n font-weight: 500;\n // font-family: \"Mona Sans\", sans-serif;\n line-height: 22px;\n text-align: center;\n font-feature-settings: \"ss01\" on, \"salt\" on;\n /* Mona sans/Text sm/14px:Medium */\n font-size: 14px;\n font-style: normal;\n font-weight: 500;\n line-height: 22px; /* 157.143% */\n flex-shrink: 0;\n transition: all 200ms cubic-bezier(0.17, 0.67, 0.83, 0.67);\n flex-direction: ${(props) => {\n if (props.direction === \"right\") {\n return \"row\";\n } else if (props.direction === \"left\") {\n return \"row-reverse\";\n }\n }};\n svg path {\n fill: ${(props) => {\n switch (props.variant) {\n case \"outline\":\n return \"rgba(123, 123, 123, 1)\";\n case \"tonal\":\n return \"#656565\";\n case \"standard\":\n return \"#FFFFFF\";\n case \"primary\":\n return \"#FFFFFF\";\n case \"brand-outline\":\n return \"hsla(358, 88%, 71%, 1)\";\n }\n }};\n }\n background: ${(props) => {\n switch (props.variant) {\n case \"outline\":\n return \"var(--button-outline-bg, Neutral/White)\";\n case \"tonal\":\n return \"var(--button-tonal-bg,#FEF6EE) \";\n case \"standard\":\n return \"var(--button-standard-bg, #3D3D3D)\";\n case \"primary\":\n return \"var(--button-primary-bg, #DD3345)\";\n case \"brand-outline\":\n return \"hsla(0, 0%, 100%, 0.01)\";\n }\n }};\n color: ${(props) => {\n switch (props.variant) {\n case \"outline\":\n return \"var(--button-outline-color, #292929)\";\n case \"tonal\":\n return \"var(--button-tonal-color,#292929) \";\n case \"standard\":\n return \"var(--button-standard-color, #FFFFFF)\";\n case \"primary\":\n return \"var(--button-primary-color, #FFFFFF)\";\n case \"brand-outline\":\n return \"hsla(354, 71%, 53%, 1)\";\n }\n }};\n box-shadow: ${(props) => {\n switch (props.variant) {\n case \"outline\":\n return \"0px 0px 0px 1px rgba(0, 0, 0, 0.22) inset, 0px -1px 0px 0px rgba(15, 15, 15, 0.15) inset, 0px 1px 2px -0.5px rgba(5, 5, 5, 0.08);\";\n case \"tonal\":\n return \"0px 0px 0px 1px rgba(0, 0, 0, 0.84) inset, 0px 1px 1px 1px #FFF inset, 0px 0px 0px 2px #FFF inset, 0px 1.5px 0px 0px rgba(0, 0, 0, 0.84);\";\n case \"standard\":\n return \"0px 0px 0px 1px rgba(0, 0, 0, 0.84) inset, 0px 1px 1px 1px rgba(166, 166, 166, 0.40) inset, 0px 0px 0px 2px rgba(166, 166, 166, 0.40) inset, 0px 1px 2px 0px rgba(15, 15, 15, 0.15), 0px 1px 3px -1px rgba(5, 5, 5, 0.08);\";\n case \"primary\":\n return \"0px 0px 0px 1px rgba(0, 0, 0, 0.84) inset, 0px 1px 1px 1px rgba(246, 118, 122, 0.50) inset, 0px 0px 0px 2px rgba(246, 118, 122, 0.50) inset, 0px 1.5px 0px 0px rgba(0, 0, 0, 0.84);\";\n case \"brand-outline\":\n return \"0px 0px 0px 1px rgba(243, 78, 95, 0.78) inset, 0px -1px 0px 0px rgba(73, 8, 19, 0.50) inset, 0px 1px 2px -0.5px rgba(73, 8, 19, 0.20);\";\n }\n }};\n &:hover:not(:disabled) {\n transform: ${(props) => {\n switch (props.variant) {\n case \"primary\":\n case \"tonal\":\n return \"translateY(1px)\";\n }\n }};\n box-shadow: ${(props) => {\n switch (props.variant) {\n case \"primary\":\n return \" 0px 0px 0px 1px rgba(0, 0, 0, 0.84) inset, 0px 1px 1px 1px #ED464F inset;\";\n case \"outline\":\n return \" 0px 0px 0px 1px rgba(0, 0, 0, 0.22) inset, 0px -1px 0px 0px rgba(15, 15, 15, 0.15) inset, 0px 1px 2px -0.5px rgba(5, 5, 5, 0.08);\";\n case \"standard\":\n return \" 0px 0px 0px 1px rgba(0, 0, 0, 0.84) inset, 0px 1px 1px 1px rgba(166, 166, 166, 0.40) inset, 0px 0px 0px 2px rgba(166, 166, 166, 0.40) inset, 0px 1px 2px 0px rgba(15, 15, 15, 0.15), 0px 1px 3px -1px rgba(5, 5, 5, 0.08);\";\n case \"tonal\":\n return \"0px 0px 0px 1px rgba(0, 0, 0, 0.84) inset, 0px 1px 1px 1px #FFF inset;\";\n case \"brand-outline\":\n return \"0px 0px 0px 1px rgba(243, 78, 95, 0.78) inset, 0px -1px 0px 0px rgba(73, 8, 19, 0.50) inset, 0px 1px 2px -0.5px rgba(73, 8, 19, 0.20);\";\n }\n }};\n background: ${(props) => {\n switch (props.variant) {\n case \"primary\":\n return \" #DD3345\";\n case \"outline\":\n return \"Neutral/50\";\n case \"standard\":\n return \" #525252\";\n case \"tonal\":\n return \"0px 0px 0px 1px rgba(0, 0, 0, 0.84) inset, 0px 1px 1px 1px #FFF inset;\";\n case \"brand-outline\":\n return \"#FEF3F2\";\n }\n }};\n }\n &:focus:not(:disabled) {\n box-shadow: ${(props) => {\n switch (props.variant) {\n case \"outline\":\n return \"0px 0px 0px 1px rgba(0, 0, 0, 0.22) inset, 0px -1px 0px 0px rgba(15, 15, 15, 0.15) inset, 0px 1px 2px -0.5px rgba(5, 5, 5, 0.08), 0px 0px 0px 2px #FFF, 0px 0px 0px 4px rgba(0, 0, 0, 0.84);\";\n case \"primary\":\n return \"0px 0px 0px 1px rgba(0, 0, 0, 0.84) inset, 0px 0px 0px 2px #FFF, 0px 0px 0px 4px rgba(0, 0, 0, 0.84);\";\n case \"standard\":\n return \"0px 0px 0px 1px rgba(0, 0, 0, 0.84) inset, 0px 1px 1px 1px rgba(166, 166, 166, 0.30) inset, 0px 0px 0px 2px rgba(166, 166, 166, 0.30) inset, 0px 0px 0px 2px #FFF, 0px 0px 0px 4px rgba(0, 0, 0, 0.84);\";\n case \"tonal\":\n return \"0px 0px 0px 1px rgba(0, 0, 0, 0.84) inset, 0px 0px 0px 2px #FFF, 0px 0px 0px 4px rgba(0, 0, 0, 0.84);\";\n case \"brand-outline\":\n return \"0px 0px 0px 1px rgba(243, 78, 95, 0.78) inset, 0px -1px 0px 0px rgba(73, 8, 19, 0.50) inset, 0px 1px 2px -0.5px rgba(5, 5, 5, 0.08), 0px 0px 0px 2px #FFF, 0px 0px 0px 4px rgba(0, 0, 0, 0.84);\";\n }\n }};\n }\n &:disabled {\n color: ${(props) => {\n switch (props.variant) {\n case \"outline\":\n return \"hsla(0, 0%, 78%, 1)\"; // Adjust color value\n case \"standard\":\n return \"hsla(0, 0%, 65%, 1)\"; // Use CSS variable for color or specify a fallback\n default:\n return \"inherit\"; // Fallback to default color\n }\n }};\n box-shadow: ${(props) => {\n switch (props.variant) {\n case \"outline\":\n return \"0px 0px 0px 1px rgba(15, 15, 15, 0.15) inset;\"; // Adjust box-shadow value\n case \"standard\":\n return \"0px 0px 0px 1px rgba(15, 15, 15, 0.15) inset;\"; // Adjust box-shadow value\n default:\n return \"none\"; // No box-shadow for other variants\n }\n }};\n background: ${(props) => {\n switch (props.variant) {\n case \"outline\":\n return \"var(--button-outline-bg-disabled, #fff)\"; // Use CSS variable for background or specify a fallback\n case \"standard\":\n return \"var(--button-standard-bg-disabled, #EBEBEB)\"; // Use CSS variable for background or specify a fallback\n default:\n return \"inherit\"; // Fallback to default background\n }\n }};\n }\n`;\nconst TipOnPotlock = ({ direction, variant, onClick, href, ...restProps }) => {\n if (href) {\n return (\n <Link href={href}>\n <StyledButton\n direction={direction ?? \"right\"}\n onClick={onClick}\n {...restProps}\n variant={variant ?? \"primary\"}\n >\n <Volunteer />\n Tip on Potlock\n </StyledButton>\n </Link>\n );\n }\n return (\n <StyledButton\n direction={direction ?? \"right\"}\n onClick={onClick}\n {...restProps}\n variant={variant ?? \"primary\"}\n >\n <Volunteer />\n Tip on Potlock\n </StyledButton>\n );\n};\nconst Button = ({\n direction,\n disabled,\n children,\n onClick,\n href,\n ...restProps\n}) => {\n if (href) {\n return (\n <link to={href}>\n <StyledButton\n direction={direction ?? \"right\"}\n onClick={onClick}\n disabled={disabled}\n {...restProps}\n >\n {children}\n </StyledButton>\n </link>\n );\n }\n return (\n <StyledButton\n direction={direction ?? \"right\"}\n onClick={onClick}\n disabled={disabled}\n {...restProps}\n >\n {children}\n </StyledButton>\n );\n};\nreturn { Button, TipOnPotlock };\n" }, "Pots.PoolAllocationTable": { "": "const { potId, env, hrefWithParams, allDonations, potDetail } = props;\nconst {\n base_currency,\n total_public_donations,\n matching_pool_balance,\n public_donations_count,\n} = potDetail;\nconst { NADA_BOT_URL, SUPPORTED_FTS } = VM.require(\n \"old.potlock.near/widget/constants\"\n) || {\n NADA_BOT_URL: \"\",\n SUPPORTED_FTS: {},\n};\nconst { _address } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n) || {\n _address: (address) => address,\n};\nconst {\n calculatePayouts,\n nearToUsdWithFallback,\n yoctosToUsdWithFallback,\n formatWithCommas,\n nearToUsd,\n} = VM.require(\"old.potlock.near/widget/utils\") || {\n nearToUsdWithFallback: () => \"\",\n yoctosToUsdWithFallback: () => \"\",\n calculatePayouts: () => {},\n getFlaggedAccounts: () => {},\n formatWithCommas: () => \"\",\n nearToUsd: 1,\n};\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n asyncGetDonationsForDonor: () => {},\n asyncGetApprovedApplications: () => {},\n getMatchingPoolDonations: () => {},\n};\nconst [projectsId, setProjectsId] = useState(null);\nconst [projectsDonations, setProjectsDonations] = useState({});\nconst [usdToggle, setUsdToggle] = useState(false);\nconst [allPayouts, setAllPayouts] = useState(null);\nconst [flaggedAddresses, setFlaggedAddresses] = useState(null);\nif (!projectsId) {\n PotSDK.asyncGetApprovedApplications(potId).then((projects) => {\n setProjectsId(projects);\n });\n}\nlet sponsorshipDonations = PotSDK.getMatchingPoolDonations(potId);\nif (sponsorshipDonations)\n sponsorshipDonations.sort((a, b) => b.net_amount - a.net_amount);\nconst lastProject = projectsId[projectsId.length - 1].project_id;\nconst calcUniqueDonors = (donations) => {\n // Get the count of unique donors\n const uniqueDonorIds = new Set();\n // Iterate through each object and collect unique donor_id values\n donations.forEach((project) => {\n project.donations.forEach((donation) => {\n uniqueDonorIds.add(donation.donor_id);\n });\n });\n // Get the number of unique donor_id values\n return uniqueDonorIds.size;\n};\nconst calcMatchedAmount = (donations) => {\n const total = Big(0);\n donations.forEach((donation) => {\n total = total.plus(Big(donation.net_amount));\n });\n const amount = SUPPORTED_FTS[base_currency.toUpperCase()].fromIndivisible(\n total.toString()\n );\n return amount;\n};\nconst uniqueDonorIds = allDonations\n ? new Set(allDonations.map((donation) => donation.donor_id))\n : new Set([]);\nconst donorsCount = uniqueDonorIds.size;\nif (!flaggedAddresses) {\n PotSDK.getFlaggedAccounts(potDetail, potId)\n .then((data) => {\n const listOfFlagged = [];\n data.forEach((adminFlaggedAcc) => {\n const addresses = Object.keys(adminFlaggedAcc.potFlaggedAcc);\n listOfFlagged.push(...addresses);\n });\n setFlaggedAddresses(listOfFlagged);\n })\n .catch((err) => console.log(\"error getting the flagged accounts \", err));\n}\nconst sortAndSetPayouts = (payouts) => {\n payouts.sort((a, b) => {\n // sort by matching pool allocation, highest to lowest\n return b.matchingAmount - a.matchingAmount;\n });\n setAllPayouts(payouts.slice(0, 5));\n};\nif (!allPayouts && allDonations?.length > 0 && flaggedAddresses) {\n let allPayouts = [];\n if (potDetail.payouts.length) {\n allPayouts = potDetail.payouts.map((payout) => {\n const { project_id, amount } = payout;\n return {\n projectId: project_id,\n matchingAmount: amount,\n };\n });\n sortAndSetPayouts(allPayouts);\n } else {\n calculatePayouts(\n allDonations,\n matching_pool_balance,\n flaggedAddresses\n ).then((calculatedPayouts) => {\n allPayouts = Object.entries(calculatedPayouts).map(\n ([projectId, { matchingAmount }]) => {\n return {\n projectId,\n matchingAmount,\n };\n }\n );\n sortAndSetPayouts(allPayouts);\n });\n }\n}\nconst ProfileImg = ({ profile }) => (\n <Widget src=\"mob.near/widget/ProfileImage\" props={{ profile, style: {} }} />\n);\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n width: 100%;\n border-radius: 12px;\n border-top: 1px solid #292929;\n border-right: 1px solid #292929;\n border-bottom: 2px solid #292929;\n border-left: 1px solid #292929;\n overflow: hidden;\n .header {\n font-size: 18px;\n font-weight: 600;\n background: #fef6ee;\n padding: 1rem;\n span {\n color: #ee8949;\n }\n }\n .sort {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.5rem 1rem;\n font-size: 11px;\n background: #fef6ee;\n .title {\n font-weight: 500;\n letter-spacing: 0.44px;\n text-transform: uppercase;\n }\n .sort-btn {\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n cursor: pointer;\n }\n }\n`;\nconst Row = styled.div`\n display: flex;\n align-items: center;\n font-size: 14px;\n padding: 1rem;\n gap: 8px;\n border-bottom: 1px solid #c7c7c7;\n &:last-of-type {\n border-bottom: none;\n }\n .address {\n display: flex;\n text-decoration: none;\n align-items: center;\n font-weight: 600;\n gap: 8px;\n margin-left: 24px;\n flex: 1;\n color: #292929;\n transition: color 200ms ease-in;\n :hover {\n color: #dd3345;\n }\n }\n .profile-image {\n width: 18px;\n height: 18px;\n }\n`;\nconst publicRoundStarted = projectsTotalDonations.length > 0;\nconst Table = ({ donations, totalAmount, totalUniqueDonors, title }) => (\n <Container>\n <div className=\"header\">\n {totalAmount}\n <span>raised from</span>\n {totalUniqueDonors}\n <span>{allPayouts?.length > 0 ? \"donors\" : \"sponsors\"}</span>\n </div>\n <div className=\"sort\">\n <div className=\"title\">Top {title} </div>\n <div\n className=\"sort-btn\"\n style={{\n cursor: nearToUsd ? \"pointer\" : \"default\",\n }}\n onClick={() => (nearToUsd ? setUsdToggle(!usdToggle) : \"\")}\n >\n {nearToUsd && (\n <svg\n width=\"12\"\n height=\"14\"\n viewBox=\"0 0 12 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M9 10.7575V5.5H7.5V10.7575H5.25L8.25 13.75L11.25 10.7575H9ZM3.75 0.25L0.75 3.2425H3V8.5H4.5V3.2425H6.75L3.75 0.25ZM9 10.7575V5.5H7.5V10.7575H5.25L8.25 13.75L11.25 10.7575H9ZM3.75 0.25L0.75 3.2425H3V8.5H4.5V3.2425H6.75L3.75 0.25Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n )}\n {usdToggle ? \"USD\" : \"NEAR\"}\n </div>\n </div>\n {donations.map(\n ({ projectId, donor_id, matchingAmount, net_amount }, idx) => {\n const id = donor_id || projectId;\n const nearAmount = formatWithCommas(\n SUPPORTED_FTS[base_currency.toUpperCase()].fromIndivisible(\n net_amount || matchingAmount\n )\n );\n const profile = Social.getr(`${id}/profile`);\n const matchedAmout = usdToggle\n ? yoctosToUsdWithFallback(matchingAmount || net_amount, true)\n : nearAmount;\n const url = projectId\n ? `?tab=project&projectId=${projectId}`\n : `?tab=profile&accountId=${donor_id}`;\n return (\n <Row>\n <div>#{idx + 1}</div>\n <a className=\"address\" href={hrefWithParams(url)}>\n <ProfileImg profile={profile} />\n {_address(profile.name || id, 15)}\n </a>\n <div>\n {matchedAmout} {usdToggle ? \" \" : \"N\"}\n </div>\n </Row>\n );\n }\n )}\n </Container>\n);\nreturn allPayouts?.length > 0 ? (\n <Table\n title=\"matching pool allocations\"\n totalAmount={yoctosToUsdWithFallback(total_public_donations, true)}\n totalUniqueDonors={donorsCount}\n donations={allPayouts}\n />\n) : sponsorshipDonations.length > 0 ? (\n <Table\n title=\"sponsors\"\n totalAmount={nearToUsdWithFallback(calcMatchedAmount(sponsorshipDonations))}\n totalUniqueDonors={\n new Set(sponsorshipDonations.map((obj) => obj.donor_id)).size\n }\n donations={sponsorshipDonations.slice(0, 5)}\n />\n) : (\n \"\"\n);\n" }, "Cart.AddToCart": { "": "const { handleCallback, item, text } = props;\nconst { addItemsToCart, removeItemsFromCart, itemExistsInCart } = VM.require(\n \"old.potlock.near/widget/SDK.cart\"\n) ?? {\n addItemsToCart: () => {},\n removeItemsFromCart: () => {},\n itemExistsInCart: () => false,\n};\nconst existsInCart = itemExistsInCart(item);\nreturn (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"tertiary\",\n text: text || (existsInCart ? \"Remove from cart\" : \"Add to cart\"),\n style: { padding: \"12px 16px\" },\n disabled: props.disabled ?? false,\n onClick: () => {\n if (existsInCart) {\n removeItemsFromCart([item]);\n } else {\n // item.ft = \"NEAR\";\n addItemsToCart([item]);\n }\n if (handleCallback) {\n handleCallback();\n }\n },\n }}\n />\n);\n" }, "Cart.CheckoutItem": { "": "const { basisPointsToPercent } = VM.require(\n \"old.potlock.near/widget/utils\"\n) || {\n basisPointsToPercent: () => 0,\n};\nconst { SUPPORTED_FTS } = VM.require(\"old.potlock.near/widget/constants\") || {\n SUPPORTED_FTS: {},\n};\nconst { removeItemsFromCart, updateItemInCart } = VM.require(\n \"old.potlock.near/widget/SDK.cart\"\n) || {\n removeItemsFromCart: () => {},\n updateItemInCart: () => {},\n};\nconst { cartItem, checked, handleCheckboxClick } = props;\nconst projectId = cartItem?.id;\nconst isPotDonation = cartItem?.potId;\nconst profile =\n props.profile || Social.get(`${projectId}/profile/**`, \"final\") || {};\nconst IPFS_BASE_URL = \"https://nftstorage.link/ipfs/\";\nconst CHEVRON_DOWN_URL =\n IPFS_BASE_URL + \"bafkreiabkwyfxq6pcc2db7u4ldweld5xcjesylfuhocnfz7y3n6jw7dptm\";\nconst CHEVRON_UP_URL =\n IPFS_BASE_URL + \"bafkreibdm7w6zox4znipjqlmxr66wsjjpqq4dguswo7evvrmzlnss3c3vi\";\nconst ItemContainer = styled.div`\n display: flex;\n flex-direction: row;\n max-width: 800px;\n background: white;\n // background: pink;\n border: 1px solid #dbdbdb;\n box-shadow: 0px -2px 0px #dbdbdb inset;\n border-radius: 6px;\n justify-content: flex-start;\n align-items: flex-start;\n`;\nconst ItemLeft = styled.div`\n height: 100%;\n padding: 24px 16px;\n // background: green;\n`;\nconst ItemRight = styled.div`\n display: flex;\n flex-direction: row;\n padding: 24px 24px 24px 16px;\n width: 100%;\n // background: yellow;\n border-left: 1px solid #dbdbdb;\n`;\nconst ImageContainer = styled.div`\n display: flex;\n flex-direction: row;\n gap: 32px;\n`;\nconst DetailsContainer = styled.div`\n display: flex;\n flex-direction: column;\n width: 100%;\n overflow: hidden;\n`;\nconst Title = styled.a`\n color: #2e2e2e;\n font-size: 16px;\n line-height: 24px;\n font-weight: 600;\n word-wrap: break-word;\n`;\nconst Description = styled.div`\n color: #2e2e2e;\n font-size: 16px;\n line-height: 24px;\n font-weight: 400;\n word-wrap: break-word;\n overflow-wrap: break-word;\n margin: 16px 0px 24px 0px;\n`;\nconst FtIcon = styled.img`\n width: 20px;\n height: 20px;\n`;\nconst Row = styled.div`\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n`;\nconst Icon = styled.svg`\n width: 20px;\n height: 20px;\n`;\nconst NearIcon = (props) => (\n <Icon\n {...props}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n id=\"near-logo\"\n >\n <rect width=\"24\" height=\"24\" rx=\"12\" fill=\"#CECECE\" />\n <path\n d=\"M15.616 6.61333L13.1121 10.3333C12.939 10.5867 13.2719 10.8933 13.5117 10.68L15.9756 8.53333C16.0422 8.48 16.1354 8.52 16.1354 8.61333V15.32C16.1354 15.4133 16.0155 15.4533 15.9623 15.3867L8.50388 6.45333C8.26415 6.16 7.91787 6 7.53163 6H7.26526C6.5727 6 6 6.57333 6 7.28V16.72C6 17.4267 6.5727 18 7.27858 18C7.71809 18 8.13097 17.7733 8.3707 17.3867L10.8746 13.6667C11.0477 13.4133 10.7148 13.1067 10.475 13.32L8.0111 15.4533C7.94451 15.5067 7.85128 15.4667 7.85128 15.3733V8.68C7.85128 8.58667 7.97114 8.54667 8.02442 8.61333L15.4828 17.5467C15.7225 17.84 16.0821 18 16.4551 18H16.7214C17.4273 18 18 17.4267 18 16.72V7.28C18 6.57333 17.4273 6 16.7214 6C16.2686 6 15.8557 6.22667 15.616 6.61333Z\"\n fill=\"black\"\n />\n </Icon>\n);\nconst [itemAmount, setItemAmount] = useState(cartItem?.amount);\nconst [itemToken, setItemToken] = useState(cartItem?.token);\nState.init({\n ftBalances: null,\n denominationOptions: [\n {\n text: \"NEAR\",\n value: \"NEAR\",\n selected: itemToken.text === \"NEAR\",\n decimals: 24,\n },\n ],\n});\n// * REMOVING FTs FROM CHECKOUT FOR NOW *\n// const ftBalancesRes = useCache(\n// () =>\n// asyncFetch(\n// `https://near-mainnet.api.pagoda.co/eapi/v1/accounts/${context.accountId}/balances/FT`,\n// {\n// headers: {\n// \"Content-Type\": \"application/json\",\n// \"x-api-key\": \"dce81322-81b0-491d-8880-9cfef4c2b3c2\",\n// },\n// }\n// )\n// .then((res) => res.body)\n// .catch((e) => console.log(\"error fetching ft balances: \", e)),\n// `ft-balances-${context.accountId}`\n// );\n// console.log(\"ftBalancesRes: \", ftBalancesRes);\n// console.log(\"state in CheckoutItem: \", state);\n// * REMOVING FTs FROM CHECKOUT FOR NOW *\n// useEffect(() => {\n// if (context.accountId && !isPotDonation && ftBalancesRes && !state.ftBalances) {\n// State.update({\n// ftBalances: ftBalancesRes.balances,\n// denominationOptions: state.denominationOptions.concat(\n// ftBalancesRes.balances\n// .map(({ amount, contract_account_id, metadata }) => ({\n// amount,\n// id: contract_account_id,\n// text: metadata.symbol,\n// value: metadata.symbol,\n// icon: metadata.icon,\n// decimals: metadata.decimals,\n// selected: false,\n// }))\n// .filter((option) => option.text.length < 10)\n// ),\n// });\n// }\n// }, [context.accountId, state.ftBalances, ftBalancesRes, isPotDonation]);\nreturn (\n <ItemContainer>\n <ItemLeft>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Checkbox\"}\n props={{\n id: \"selector-\" + projectId,\n checked,\n onClick: handleCheckboxClick,\n }}\n />\n </ItemLeft>\n <ItemRight>\n <ImageContainer>\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{\n accountId: projectId,\n style: {\n width: \"40px\",\n height: \"40px\",\n border: \"none\",\n marginRight: \"24px\",\n },\n className: \"mb-2\",\n imageClassName: \"rounded-circle w-100 h-100 d-block\",\n thumbnail: false,\n }}\n />\n </ImageContainer>\n <DetailsContainer>\n <Row>\n <Title\n href={props.hrefWithParams(`?tab=project&projectId=${projectId}`)}\n >\n {profile.name ?? \"\"}\n </Title>\n <Widget\n src={\"old.potlock.near/widget/Pots.Tag\"}\n props={{\n ...props,\n backgroundColor: isPotDonation ? \"#FEF6EE\" : \"#F6F5F3\",\n borderColor: isPotDonation\n ? \"rgba(219, 82, 27, 0.36)\"\n : \"#DBDBDB\",\n textColor: isPotDonation ? \"#EA6A25\" : \"#292929\",\n text: isPotDonation\n ? cartItem.potDetail\n ? cartItem.potDetail.pot_name\n : \"-\"\n : \"Direct Donation\",\n }}\n />\n </Row>\n <Description>{profile.description ?? \"\"}</Description>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"Amount\",\n placeholder: \"0\",\n value: itemAmount,\n onChange: (amount) => {\n amount = amount.replace(/[^\\d.]/g, \"\"); // remove all non-numeric characters except for decimal\n if (amount === \".\") amount = \"0.\";\n setItemAmount(amount);\n },\n onBlur: (e) => {\n updateItemInCart({\n ...cartItem,\n amount: e.target.value,\n });\n },\n inputStyles: {\n textAlign: \"right\",\n borderRadius: \"0px 4px 4px 0px\",\n },\n preInputChildren: (\n <Widget\n src={\"old.potlock.near/widget/Inputs.Select\"}\n props={{\n noLabel: true,\n placeholder: \"\",\n options: state.denominationOptions,\n value: { text: itemToken.text, value: itemToken.value },\n onChange: ({ text, value }) => {\n const token = state.denominationOptions.find(\n (option) => option.text === text\n );\n setItemToken(token);\n setItemAmount(undefined);\n updateCartItem({\n ...cartItem,\n token: token,\n amount: undefined,\n });\n },\n containerStyles: {\n width: \"auto\",\n },\n inputStyles: {\n border: \"none\",\n borderRight: \"1px #F0F0F0 solid\",\n boxShadow: \"none\",\n borderRadius: \"4px 0px 0px 4px\",\n width: \"auto\",\n padding: \"12px 16px\",\n boxShadow: \"0px -2px 0px rgba(93, 93, 93, 0.24) inset\",\n },\n iconLeft:\n itemToken.text == \"NEAR\" ? (\n <NearIcon />\n ) : (\n <FtIcon src={itemToken.icon} />\n ),\n }}\n />\n ),\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Cart.BreakdownSummary\"}\n props={{\n ...props,\n ftIcon: itemToken.icon,\n referrerId,\n totalAmount: itemAmount,\n bypassProtocolFee: false, // TODO: allow user to choose\n containerStyle: { marginTop: \"16px\" },\n }}\n />\n </DetailsContainer>\n </ItemRight>\n </ItemContainer>\n);\n" }, "Pots.Home": { "": "let PotFactorySDK =\n VM.require(\"old.potlock.near/widget/SDK.potfactory\") ||\n (() => ({\n getContractId: () => {},\n getConfig: () => {},\n asyncGetPots: () => {},\n canUserDeployPot: () => {},\n }));\nconst [pots, setPots] = useState(null);\nconst [inProgressRounds, setInProgressRounds] = useState([]);\nconst [filteredRounds, setFilteredRounds] = useState([]);\nconst [completedRounds, setCompletedRounds] = useState([]);\nconst [filterSelcted, setFilterSelected] = useState([]);\nconst [sortBy, setSortBy] = useState(\"\");\nPotFactorySDK = PotFactorySDK({ env: props.env });\nconst potFactoryContractId = PotFactorySDK.getContractId();\nconst potFactoryConfig = PotFactorySDK.getConfig();\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n asyncGetConfig: () => {},\n};\nconst currentDate = Date.now();\nconst filters = {\n application_not_started: (round) => currentDate < round.application_start_ms,\n application_open: (round) =>\n currentDate > round.application_start_ms &&\n currentDate < round.application_end_ms,\n application_closed: (round) => currentDate > round.application_end_ms,\n round_end: (round) => currentDate > round.public_round_end_ms,\n round_open: (round) =>\n currentDate > round.public_round_start_ms &&\n currentDate < round.public_round_end_ms,\n cooldown: (round) =>\n currentDate > round.public_round_end_ms &&\n currentDate < round.cooldown_end_ms,\n completed: (round) => round.all_paid_out,\n};\nconst filterBy = {\n \"no-label\": [\n {\n label: \"Application open\",\n val: \"application_open\",\n },\n {\n label: \"Matching round open\",\n val: \"round_open\",\n },\n {\n label: \"Application closed\",\n val: \"application_closed\",\n },\n {\n label: \"Challenge period\",\n val: \"cooldown\",\n },\n ],\n};\nconst sortOptions = {\n \"no-label\": [\n {\n label: \"Most to least in pot\",\n val: \"least_pots\",\n },\n {\n label: \"Least to most in pot\",\n val: \"most_pots\",\n },\n {\n label: \"Most to least donations\",\n val: \"most_donations\",\n },\n {\n label: \"Least to most donations\",\n val: \"least_donations\",\n },\n ],\n};\nif (!pots) {\n PotFactorySDK.asyncGetPots().then((pots) => {\n pots.forEach(({ id }) => {\n PotSDK.asyncGetConfig(id).then((potConfig) =>\n setPots((prevPot) => ({\n ...prevPot,\n [id]: { ...potConfig, id },\n }))\n );\n });\n });\n}\nconst compareFunction = (pots) => {\n const potsSort = {\n active: {\n check: filters.round_open,\n time: \"public_round_end_ms\",\n items: [],\n },\n cooldown: {\n check: filters.cooldown,\n time: \"cooldown_end_ms\",\n items: [],\n },\n application: {\n check: filters.application_open,\n time: \"application_end_ms\",\n items: [],\n },\n not_started: {\n check: filters.application_not_started,\n time: \"application_start_ms\",\n items: [],\n },\n rest: {\n check: (round) => true,\n time: \"application_start_ms\",\n items: [],\n },\n };\n // sort pots(round status)\n const listOfPots = {};\n const states = Object.keys(potsSort);\n pots.forEach((pot) => {\n Object.keys(potsSort).some((type) => {\n const { check, items } = potsSort[type];\n if (check(pot)) {\n potsSort[type].items = [...items, pot];\n return true;\n }\n });\n });\n // sort pots(time left)\n const inProgressPots = [];\n Object.values(potsSort).forEach(({ items, time }) => {\n items.sort((a, b) => a[time] - b[time]);\n inProgressPots.push(...items);\n });\n return inProgressPots;\n};\nuseEffect(() => {\n if (pots) {\n const potsVal = Object.values(pots);\n const completed = [];\n let inprogress = [];\n potsVal.forEach((round) => {\n if (filters.completed(round)) {\n completed.push(round);\n } else {\n inprogress.push(round);\n }\n });\n inprogress = compareFunction(inprogress);\n setFilteredRounds(inprogress);\n setInProgressRounds(inprogress);\n setCompletedRounds(completed);\n }\n}, [pots]);\nconst canDeploy = PotFactorySDK.canUserDeployPot(context.accountId);\nconst Title = styled.div`\n margin-bottom: 1rem;\n display: flex;\n align-items: center;\n gap: 1rem;\n font-size: 18px;\n font-weight: 600;\n .span {\n font-weight: 600;\n }\n`;\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding-bottom: 48px;\n .content {\n display: flex;\n flex-direction: column;\n width: 100%;\n padding: 0 64px;\n margin-top: 3rem;\n }\n .header {\n display: flex;\n align-items: center;\n margin-bottom: 1rem;\n .filters {\n gap: 1rem;\n display: flex;\n align-items: center;\n .sort {\n width: 286px;\n flex-direction: column;\n padding: 0.5rem;\n gap: 0;\n .title {\n display: none;\n }\n .option {\n border: none;\n width: 100%;\n padding: 0.5rem;\n }\n }\n }\n }\n @media only screen and (max-width: 768px) {\n .content {\n padding: 0 20px;\n }\n .header {\n flex-direction: column;\n align-items: flex-start;\n gap: 1rem;\n }\n }\n`;\nconst Line = styled.div`\n height: 1px;\n width: 100%;\n background: #c7c7c7;\n margin: 3rem 0;\n`;\nif (!potFactoryConfig) {\n return <div class=\"spinner-border text-secondary\" role=\"status\" />;\n}\nconst handleFilter = (selected) => {\n const selectedList = Object.values(selected)[0];\n if (selectedList.length === 0) {\n return setFilteredRounds(inProgressRounds);\n }\n const filteredRounds = [...inProgressRounds].filter((round) =>\n selectedList.some((key) => {\n return filters[key](round) === true;\n })\n );\n setFilteredRounds(filteredRounds);\n};\nconst handleSort = ({ val }) => {\n const sortedRounds = filteredRounds;\n switch (val) {\n case \"least_pots\":\n sortedRounds.sort(\n (a, b) => Big(b.matching_pool_balance) - Big(a.matching_pool_balance)\n );\n break;\n case \"most_pots\":\n sortedRounds.sort(\n (a, b) => Big(a.matching_pool_balance) - Big(b.matching_pool_balance)\n );\n break;\n case \"most_donations\":\n sortedRounds.sort(\n (a, b) => Big(b.total_public_donations) - Big(a.total_public_donations)\n );\n break;\n case \"least_donations\":\n sortedRounds.sort(\n (a, b) => Big(a.total_public_donations) - Big(b.total_public_donations)\n );\n break;\n }\n setFilteredRounds(sortedRounds);\n setSortBy(val);\n};\nreturn (\n <Container>\n <Widget\n src={\"old.potlock.near/widget/Pots.HomeBanner\"}\n props={{\n ...props,\n canDeploy,\n }}\n />\n <div className=\"content\">\n <div className=\"header\">\n <Title\n style={{\n marginRight: \"auto\",\n marginBottom: 0,\n }}\n >\n Active Pots <span>{filteredRounds.length}</span>\n </Title>\n <div className=\"filters\">\n <Widget\n src={\"old.potlock.near/widget/Inputs.FilterDropdown\"}\n props={{\n ...props,\n options: filterBy,\n onClick: handleFilter,\n multipleOptions: true,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Inputs.FilterDropdown\"}\n props={{\n ...props,\n label: \"Sort\",\n labelIcon: \"right\",\n options: sortOptions,\n onClick: handleSort,\n menuClass: \"sort\",\n }}\n />\n </div>\n </div>\n {filteredRounds.length === 0 && <div>No pots</div>}\n <Widget\n src={\"old.potlock.near/widget/Project.ListSection\"}\n props={{\n ...props,\n items: filteredRounds,\n renderItem: (pot) => (\n <Widget\n src={\"old.potlock.near/widget/Pots.Card\"}\n props={{\n ...props,\n potId: pot.id,\n }}\n />\n ),\n maxCols: 3,\n responsive: [\n {\n breakpoint: 1114,\n items: 2,\n },\n {\n breakpoint: 768,\n items: 1,\n },\n ],\n }}\n />\n <Line />\n <Title>\n Completed Pots <span>{completedRounds.length}</span>\n </Title>\n <Widget\n src={\"old.potlock.near/widget/Project.ListSection\"}\n props={{\n ...props,\n items: completedRounds,\n renderItem: (pot) => (\n <Widget\n src={\"old.potlock.near/widget/Pots.Card\"}\n props={{\n ...props,\n potId: pot.id,\n }}\n />\n ),\n maxCols: 3,\n responsive: [\n {\n breakpoint: 1114,\n items: 2,\n },\n {\n breakpoint: 768,\n items: 1,\n },\n ],\n }}\n />\n </div>\n </Container>\n);\n" }, "Pots.HeaderStatus": { "": "const { potDetail } = props;\nconst [mobileMenuActive, setMobileMenuActive] = useState(false);\nconst {\n application_start_ms,\n application_end_ms,\n public_round_start_ms,\n public_round_end_ms,\n cooldown_end_ms,\n all_paid_out,\n} = potDetail;\nconst now = Date.now();\nconst stats = [\n {\n label: \"Applications round\",\n daysLeft: application_end_ms,\n started: now >= application_start_ms,\n completed: now > application_end_ms,\n progress:\n now > application_end_ms\n ? 1\n : (now - application_start_ms) /\n (application_end_ms - application_start_ms),\n },\n {\n label: \"Matching round\",\n daysLeft: public_round_end_ms,\n started: now >= public_round_start_ms,\n completed: now > public_round_end_ms,\n progress:\n now > public_round_end_ms\n ? 1\n : (now - public_round_start_ms) /\n (public_round_end_ms - public_round_start_ms),\n },\n {\n label: \"Challenge period\",\n daysLeft: cooldown_end_ms,\n started: now >= public_round_end_ms,\n completed: now > cooldown_end_ms && !!cooldown_end_ms,\n progress:\n now > cooldown_end_ms && !!cooldown_end_ms\n ? 1\n : (cooldown_end_ms - now) / (public_round_end_ms - cooldown_end_ms),\n },\n {\n label: \"Payouts completed\",\n daysLeft: null,\n started: null,\n completed: all_paid_out,\n progress: all_paid_out ? 1 : 0,\n },\n];\nconst ProgressBar = ({ progress, completed, started }) => (\n <ProgressBarWrapper>\n <svg viewBox=\"0 0 160 160\" className=\"circle\">\n <circle\n r=\"70\"\n cx=\"80\"\n cy=\"80\"\n fill=\"transparent\"\n stroke={completed ? \"#629D13\" : started ? \"#000000\" : \"#C7C7C7\"}\n strokeWidth=\"12px\"\n ></circle>\n <circle\n r=\"70\"\n cx=\"80\"\n cy=\"80\"\n fill=\"transparent\"\n stroke=\"#C7C7C7\"\n strokeWidth=\"12px\"\n strokeDasharray=\"439.6px\"\n strokeDashoffset={439.6 * progress + \"px\"}\n ></circle>\n </svg>\n <svg\n className=\"check\"\n viewBox=\"0 0 12 9\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M3.72667 7.05333L0.946667 4.27333L0 5.21333L3.72667 8.94L11.7267 0.94L10.7867 0L3.72667 7.05333Z\"\n style={{\n fill: completed ? \"#629D13\" : started ? \"#7B7B7B\" : \"#C7C7C7\",\n }}\n />\n </svg>\n </ProgressBarWrapper>\n);\nconst getIndexOfActive = () => {\n let index;\n stats.forEach((state, idx) => {\n if (state.started && !state.completed) {\n index = idx;\n }\n });\n if (index === null) return 3;\n return index;\n};\nconst containerHeight = 181;\nconst showActiveState = getIndexOfActive() * (containerHeight / 4);\nconst Wrapper = styled.div`\n border-top: 1px solid rgb(199 199 199 / 50%);\n border-bottom: 1px solid rgb(199 199 199 / 50%);\n position: relative;\n display: flex;\n align-items: center;\n margin-top: -1px;\n pointer-events: none;\n .spread-indicator {\n height: auto;\n width: 12px;\n transition: all 300ms ease-in-out;\n display: none;\n }\n @media only screen and (max-width: 1100px) {\n pointer-events: all;\n cursor: pointer;\n .spread-indicator {\n display: block;\n }\n }\n`;\nconst Container = styled.div`\n display: flex;\n width: 100%;\n justify-content: center;\n transition: all 300ms ease-in-out;\n .mobile-selected {\n display: flex;\n justify-content: space-between;\n gap: 1rem;\n margin: 1rem 0;\n transition: all 300ms ease-in-out;\n }\n @media only screen and (max-width: 1100px) {\n justify-content: left;\n height: ${containerHeight / 4}px;\n overflow: hidden;\n .mobile-selected {\n margin: 10px 0;\n transform: translateY(${-showActiveState}px);\n flex-direction: column;\n }\n }\n`;\nconst State = styled.div`\n display: flex;\n align-items: center;\n position: relative;\n gap: 1rem;\n font-size: 14px;\n white-space: nowrap;\n color: ${(props) => (props.active ? \"#000\" : \"#7b7b7b\")};\n span {\n font-weight: 600;\n color: #dd3345;\n }\n`;\nconst Loader = styled.div`\n position: relative;\n background: #dbdbdb;\n border-radius: 1px;\n height: 4px;\n width: 130px;\n @media only screen and (max-width: 1400px) {\n width: 90px;\n }\n @media only screen and (max-width: 1100px) {\n height: 40px;\n width: 4px;\n position: absolute;\n left: 10px;\n z-index: 0;\n top: 50%;\n }\n`;\nconst ProgressBarWrapper = styled.div`\n position: relative;\n display: flex;\n .circle {\n width: 24px;\n height: 24px;\n transform: rotate(-90deg);\n }\n .check {\n width: 12px;\n position: absolute;\n transform: translate(-50%, -50%);\n top: 50%;\n left: 50%;\n }\n @media only screen and (max-width: 1100px) {\n z-index: 1;\n background: white;\n padding: 2px 0;\n }\n`;\nreturn (\n <Wrapper onClick={() => setMobileMenuActive(!mobileMenuActive)}>\n <Container\n style={\n mobileMenuActive\n ? {\n height: containerHeight + \"px\",\n }\n : {}\n }\n >\n <div\n className=\"mobile-selected\"\n style={\n mobileMenuActive\n ? {\n transform: \"translateY(0px)\",\n }\n : {}\n }\n >\n {stats.map(({ label, daysLeft, progress, started, completed }, idx) => {\n return (\n <State active={completed || started} key={timeLeft}>\n <ProgressBar\n progress={progress}\n started={started}\n completed={completed}\n />\n <div>\n {label}\n {!daysLeft && started && <span>pending </span>}\n {started && !completed && daysLeft && (\n <span>\n ends in\n <Widget\n src={\"old.potlock.near/widget/Pots.TimeLeft\"}\n props={{\n daysLeft,\n }}\n />\n </span>\n )}\n {idx === 0 && !started && \" hasn’t started\"}\n </div>\n <Loader\n style={{\n background: completed ? \"#629D13\" : \"#dbdbdb\",\n display: idx === 3 ? \"none\" : \"flex\",\n }}\n />\n </State>\n );\n })}\n </div>\n </Container>\n <svg\n className=\"spread-indicator\"\n style={{\n rotate: mobileMenuActive ? \"180deg\" : \"0deg\",\n }}\n viewBox=\"0 0 12 8\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M10.59 0.294922L6 4.87492L1.41 0.294922L0 1.70492L6 7.70492L12 1.70492L10.59 0.294922Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n </Wrapper>\n);\n" }, "Pots.Header": { "": "const {\n potDetail,\n setApplicationModalOpen,\n potId,\n applicationSuccess,\n registrationApproved,\n registryStatus,\n hrefWithParams,\n nav,\n referrerId,\n allDonations,\n} = props;\nconst {\n admins,\n chef,\n owner,\n pot_name,\n pot_description,\n registry_provider,\n matching_pool_balance,\n public_round_end_ms,\n public_round_start_ms,\n application_start_ms,\n application_end_ms,\n cooldown_end_ms,\n all_paid_out,\n} = potDetail;\nconst [isMatchingPoolModalOpen, setIsMatchingPoolModalOpen] = useState(false);\nconst [isModalDonationOpen, setIsModalDonationOpen] = useState(false);\nconst [successfulDonation, setSuccessfulDonation] = useState(null);\nconst [showChallengePayoutsModal, setShowChallengePayoutsModal] =\n useState(false);\nconst [projects, setProjects] = useState(null);\nconst [flaggedAddresses, setFlaggedAddresses] = useState(null);\nconst { IPFS_BASE_URL } = VM.require(\"old.potlock.near/widget/constants\") || {\n IPFS_BASE_URL: \"\",\n};\nconst NADABOT_ICON_URL =\n IPFS_BASE_URL + \"bafkreiecgkoybmplo4o542fphclxrhh4nlof5uit3lkzyv4eo2qymrpsru\";\nconst projectNotRegistered = registryStatus === null;\nconst userIsAdminOrGreater =\n admins.includes(context.accountId) || owner === context.accountId;\nconst userIsChefOrGreater = userIsAdminOrGreater || chef === context.accountId;\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getApplicationByProjectId: () => {},\n asyncGetApprovedApplications: () => {},\n adminProcessPayouts: () => {},\n};\nconst existingApplication = PotSDK.getApplicationByProjectId(\n potId,\n context.accountId\n);\nuseEffect(() => {\n if (!projects) {\n PotSDK.asyncGetApprovedApplications(potId).then((projects) => {\n setProjects(projects);\n });\n }\n}, []);\nconst applicationExists = existingApplication || applicationSuccess;\nconst now = Date.now();\nconst publicRoundOpen =\n now >= public_round_start_ms && now < public_round_end_ms;\nconst publicRoundEnded = now > public_round_end_ms;\nconst applicationOpen = now >= application_start_ms && now < application_end_ms;\nconst canApply = applicationOpen && !applicationExists && !userIsChefOrGreater;\nconst canPayoutsBeSet =\n userIsChefOrGreater && !all_paid_out && publicRoundEnded;\nconst canPayoutsBeProcessed =\n userIsAdminOrGreater && now >= cooldown_end_ms && !all_paid_out;\nconst { NADA_BOT_URL } = VM.require(\"old.potlock.near/widget/constants\") || {\n NADA_BOT_URL: \"\",\n};\nconst { yoctosToNear, yoctosToUsdWithFallback, nearToUsd, calculatePayouts } =\n VM.require(\"old.potlock.near/widget/utils\") || {\n calculatePayouts: () => {},\n yoctosToNear: () => \"\",\n nearToUsd: 1,\n yoctosToUsdWithFallback: () => \"\",\n };\nconst potLink = `https://bos.potlock.io/?tab=pot&potId=${potId}${\n context.accountId && `&referrerId=${context.accountId}`\n}`;\nconst Container = styled.div`\n display: flex;\n flex-wrap: wrap;\n gap: 2rem;\n padding: 64px 4rem 80px;\n .pool-table {\n max-width: 514px;\n width: 100%;\n }\n @media only screen and (max-width: 1068px) {\n flex-direction: column;\n .pool-table {\n margin: auto;\n }\n }\n @media only screen and (max-width: 768px) {\n padding: 3rem 0;\n .pool-table {\n max-width: 100%;\n }\n }\n`;\nconst Header = styled.div`\n display: flex;\n flex-direction: column;\n gap: 24px;\n flex: 1;\n`;\nconst Title = styled.div`\n font-size: 40px;\n font-weight: 500;\n font-family: \"Lora\";\n`;\nconst Description = styled.div`\n max-width: 498px;\n line-height: 1.5em;\n a {\n color: #7b7b7b;\n font-weight: 600;\n }\n`;\nconst Fund = styled.div`\n display: flex;\n flex-direction: column;\n gap: 8px;\n > div {\n display: flex;\n gap: 8px;\n align-items: baseline;\n div {\n font-weight: 600;\n }\n }\n .near-price {\n font-size: 24px;\n }\n`;\nconst ButtonsWrapper = styled.div`\n display: flex;\n flex-wrap: wrap;\n gap: 2rem;\n a,\n button {\n width: 180px;\n padding: 16px;\n }\n @media only screen and (max-width: 480px) {\n flex-direction: column;\n gap: 1rem;\n a,\n button {\n width: 100%;\n }\n }\n`;\nconst Referral = styled.div`\n font-size: 14px;\n gap: 12px;\n display: flex;\n align-items: center;\n`;\nconst payoutsChallenges = PotSDK.getPayoutsChallenges(potId);\nif (!flaggedAddresses) {\n PotSDK.getFlaggedAccounts(potDetail, potId)\n .then((data) => {\n const listOfFlagged = [];\n data.forEach((adminFlaggedAcc) => {\n const addresses = Object.keys(adminFlaggedAcc.potFlaggedAcc);\n listOfFlagged.push(...addresses);\n });\n setFlaggedAddresses(listOfFlagged);\n })\n .catch((err) => console.log(\"error getting the flagged accounts \", err));\n}\nconst handleSetPayouts = () => {\n if (allDonations && flaggedAddresses !== null) {\n calculatePayouts(\n allDonations,\n matching_pool_balance,\n flaggedAddresses\n ).then((calculatedPayouts) => {\n const payouts = Object.entries(calculatedPayouts)\n .map(([projectId, { matchingAmount }]) => ({\n project_id: projectId,\n amount: matchingAmount,\n }))\n .filter((payout) => payout.amount !== \"0\");\n PotSDK.chefSetPayouts(potId, payouts);\n });\n } else {\n console.log(\"error fetching donations or flagged addresses\");\n }\n};\nconst handleProcessPayouts = () => {\n PotSDK.adminProcessPayouts(potId);\n // NB: we won't get here if user used a web wallet, as it will redirect to the wallet\n // <---- EXTENSION WALLET HANDLING ----> // TODO: implement\n};\nconst existingChallengeForUser = (payoutsChallenges || []).find(\n (challenge) => challenge.challenger_id === context.accountId\n);\nconst canDonate = context.accountId && projects.length > 0;\nreturn (\n <Container>\n <Header>\n <Title>{pot_name}</Title>\n <Description>\n <Markdown text={pot_description} />\n </Description>\n <Fund>\n <div className=\"label\">Matching Funds Available:</div>\n <div>\n <div className=\"near-price\">\n {yoctosToNear(matching_pool_balance, true)}\n </div>\n {nearToUsd && (\n <div lassName=\"usd-price\">\n {\" \"}\n {yoctosToUsdWithFallback(matching_pool_balance, true)}\n </div>\n )}\n </div>\n </Fund>\n <ButtonsWrapper>\n {publicRoundOpen && context.accountId && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: canDonate ? \"Donate\" : \"Verify to Donate\",\n href: canDonate ? null : NADA_BOT_URL,\n onClick: canDonate\n ? () => {\n setIsModalDonationOpen(true);\n }\n : null,\n target: canDonate ? \"_self\" : \"_blank\",\n iconSrc: canDonate ? null : NADABOT_ICON_URL,\n }}\n />\n )}\n {now < public_round_end_ms && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"secondary\",\n text: \"Fund matching pool\",\n onClick: () => setIsMatchingPoolModalOpen(true),\n }}\n />\n )}\n {applicationOpen && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type:\n registrationApproved || projectNotRegistered\n ? \"primary\"\n : \"tertiary\",\n text:\n registryStatus && !registrationApproved\n ? `Project Registration ${registryStatus}`\n : \"Apply to pot\",\n style: { marginRight: \"24px\" },\n disabled: registryStatus && !registrationApproved,\n onClick: () => setApplicationModalOpen(true),\n }}\n />\n )}\n {now > public_round_end_ms && now < cooldown_end_ms && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"secondary\",\n existingChallengeForUser,\n text: existingChallengeForUser\n ? \"Update challenge\"\n : \"Challenge payouts\",\n onClick: () => setShowChallengePayoutsModal(true),\n }}\n />\n )}\n {canPayoutsBeSet && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n ...props,\n text: \"Set Payouts\",\n onClick: handleSetPayouts,\n }}\n />\n )}\n {canPayoutsBeProcessed && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n ...props,\n type: \"primary\",\n text: \"Process Payouts\",\n onClick: handleProcessPayouts,\n }}\n />\n )}\n </ButtonsWrapper>\n <Referral>\n <Widget\n src={\"old.potlock.near/widget/Project.CopyIcon\"}\n props={{\n textToCopy: potLink,\n }}\n />\n Earn referral fees\n </Referral>\n </Header>\n <div className=\"pool-table\">\n <Widget\n src={\"old.potlock.near/widget/Pots.PoolAllocationTable\"}\n props={props}\n />\n </div>\n <Widget\n src={\"old.potlock.near/widget/Pots.FundModal\"}\n props={{\n ...props,\n isMatchingPoolModalOpen,\n onClose: () => setIsMatchingPoolModalOpen(false),\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Pots.ChallengeModal\"}\n props={{\n ...props,\n showChallengePayoutsModal,\n onCancel: () => setShowChallengePayoutsModal(false),\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/ModalDonation.Main\"}\n loading={\"\"}\n props={{\n ...props,\n isModalOpen: isModalDonationOpen,\n onClose: () => setIsModalDonationOpen(false),\n potId,\n potDetail,\n projects,\n referrerId,\n multiple: true,\n openDonationModalSuccess: (donation) => {\n setIsModalDonationOpen(false);\n setSuccessfulDonation(donation);\n },\n }}\n />\n {successfulDonation && (\n <Widget\n src={\"old.potlock.near/widget/Project.ModalSuccess\"}\n props={{\n ...props,\n successfulDonation: successfulDonation,\n isModalOpen: successfulDonation != null,\n onClose: () => setSuccessfulDonation(null),\n }}\n />\n )}\n </Container>\n);\n" }, "Components.DonorsCards": { "": "const { sponsors, sortedDonations, currentTab } = props;\nconst donations = currentTab === \"sponsors\" ? sponsors : sortedDonations;\nconst { nearToUsdWithFallback } = VM.require(\n \"old.potlock.near/widget/utils\"\n) || {\n nearToUsdWithFallback: () => \"\",\n};\nconst { _address } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n);\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n box-shadow: 0px 2px 4px #00000081;\n width: 100%;\n position: relative;\n padding-bottom: 1rem;\n font-size: 14px;\n .name {\n font-weight: bold;\n color: var(--primary-color);\n }\n .description {\n color: #b3b3b3;\n }\n .tag {\n position: absolute;\n right: 4px;\n top: 4px;\n background: white;\n border-radius: 2px;\n width: 2rem;\n height: 2rem;\n display: flex;\n align-items: center;\n justify-content: center;\n img {\n width: 18px;\n height: auto;\n }\n }\n .background {\n height: 100px;\n width: 100%;\n }\n .profile {\n position: relative;\n transform: translateY(-50%);\n width: 4rem;\n height: 4rem;\n border-radius: 50%;\n }\n .amount {\n margin-top: 1rem;\n border: 1px solid #b3b3b3;\n padding: 4px;\n border-radius: 4px;\n }\n`;\nconst Card = ({ donor }) => {\n const { id, rank, className, amount } = donor;\n const profile = Social.getr(`${id}/profile`);\n return (\n <div key={donation} className={className || \"\"}>\n <Container>\n {profile === null ? (\n <div class=\"spinner-border text-secondary\" role=\"status\" />\n ) : (\n <>\n <Widget\n src=\"mob.near/widget/Image\"\n props={{\n image: profile.backgroundImage,\n className: \"background\",\n alt: profile.name,\n fallbackUrl:\n \"https://ipfs.near.social/ipfs/bafkreidla73cknxbeovrhgb2blax2j2qgcgcn6ibluzza3buq2mbkoqs2e\",\n }}\n />\n <div className=\"tag\">{rank}</div>\n <Widget\n src=\"mob.near/widget/Image\"\n props={{\n image: profile.image,\n className: \"profile\",\n alt: profile.name,\n fallbackUrl:\n \"https://ipfs.near.social/ipfs/bafkreiccpup6f2kihv7bhlkfi4omttbjpawnsns667gti7jbhqvdnj4vsm\",\n }}\n />\n <a\n href={props.hrefWithParams(`?tab=profile&accountId=${id}`)}\n className=\"name\"\n target=\"_blank\"\n >\n {_address(profile.name ? profile.name : id)}\n </a>\n <div className=\"description\">\n {profile.description ? _address(profile.description, 20) : \"-\"}\n </div>\n <div className=\"amount\">\n {nearToUsdWithFallback(amount)} Donated\n </div>\n </>\n )}\n </Container>\n </div>\n );\n};\nconst leaderboard = [\n {\n rank: \"#2\",\n id: donations[1].donor_id,\n amount: donations[1].amount,\n },\n {\n rank: (\n <img\n src=\"https://ipfs.near.social/ipfs/bafkreicjk6oy6465ps32owoomppfkvimbjlnhbaldvf6ujuyhkjas6ghjq\"\n alt=\"top\"\n />\n ),\n id: donations[0].donor_id,\n className: \"top\",\n amount: donations[0].amount,\n },\n {\n rank: \"#3\",\n id: donations[2].donor_id,\n amount: donations[2].amount,\n },\n];\nreturn (\n <div className=\"cards\">\n {leaderboard.map((donor) => (donor.id ? <Card donor={donor} /> : \"\"))}\n </div>\n);\n" }, "Components.InfoSegment": { "": "const title = props.title;\nconst description = props.description;\nconst icon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M10.0001 13.3327V9.99935M10.0001 6.66602H10.0084M18.3334 9.99935C18.3334 14.6017 14.6025 18.3327 10.0001 18.3327C5.39771 18.3327 1.66675 14.6017 1.66675 9.99935C1.66675 5.39698 5.39771 1.66602 10.0001 1.66602C14.6025 1.66602 18.3334 5.39698 18.3334 9.99935Z\"\n stroke=\"#475467\"\n stroke-width=\"1.66667\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n);\nconst Container = styled.div`\n box-sizing: border-box;\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n padding: 1em;\n gap: 0.75em;\n background: #fcfcfd;\n border: 1px solid #d0d5dd;\n border-radius: 4px;\n width: 100%;\n`;\nconst Text = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n padding: 0px;\n gap: 0.75em;\n`;\nconst Heading = styled.div`\n font-style: normal;\n font-weight: 600;\n font-size: 0.95em;\n line-height: 1.25em;\n color: #344054;\n`;\nconst Description = styled.p`\n font-style: normal;\n font-weight: 400;\n font-size: 0.95em;\n line-height: 1.25em;\n color: #475467;\n white-space: wrap;\n margin: 0px;\n`;\nreturn (\n <Container>\n {icon}\n <Text>\n <Heading>{title}</Heading>\n <Description>{description}</Description>\n </Text>\n </Container>\n);\n" }, "Pots.DonationsTable": { "": "const Container = styled.div`\n display: flex;\n flex-direction: column;\n width: 100%;\n margin-top: 24px;\n padding-bottom: 1rem;\n border-radius: 6px;\n border: 1px solid #7b7b7b;\n align-items: center;\n gap: 2rem;\n .transcation {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-size: 14px;\n }\n .header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.5rem 1rem;\n gap: 2rem;\n color: #292929;\n border-bottom: 1px solid rgba(199, 199, 199, 0.5);\n div {\n width: 100px;\n display: flex;\n justify-content: center;\n align-items: center;\n font-weight: 600;\n &.sort {\n cursor: pointer;\n gap: 8px;\n svg {\n transition: rotate 300ms;\n }\n }\n }\n .price {\n width: 70px;\n margin-right: 5rem;\n }\n }\n .address {\n /* width: 143px !important; */\n flex: 1;\n justify-content: flex-start !important;\n }\n @media only screen and (max-width: 992px) {\n .header .price {\n margin-right: 0;\n }\n }\n @media only screen and (max-width: 768px) {\n .header {\n display: none;\n }\n }\n`;\nconst SearchBarContainer = styled.div`\n display: flex;\n align-items: center;\n gap: 1rem;\n width: 100%;\n font-size: 14px;\n background: #f6f5f3;\n padding: 0.5rem 1rem;\n @media only screen and (max-width: 780px) {\n gap: 0.5rem;\n }\n`;\nconst SearchBar = styled.input`\n background: none;\n width: 100%;\n outline: none;\n border: none;\n &:focus {\n outline: none;\n border: none;\n }\n`;\nconst SearchIcon = styled.div`\n display: flex;\n width: 24px;\n height: 24px;\n align-items: center;\n justify-content: center;\n`;\nconst TrRow = styled.div`\n display: flex;\n width: 100%;\n justify-content: space-between;\n gap: 2rem;\n padding: 1rem;\n border-top: 1px solid rgb(199 199 199 / 50%);\n > div {\n width: 100px;\n display: flex;\n justify-content: center;\n align-items: center;\n }\n .price {\n display: flex;\n gap: 1rem;\n align-items: center;\n font-weight: 600;\n width: 74px;\n margin-right: 5rem;\n justify-content: flex-start;\n span {\n display: none;\n }\n img {\n width: 1.125rem;\n }\n }\n .address {\n position: relative;\n color: #292929;\n display: flex;\n align-items: center;\n justify-content: flex-start;\n border-radius: 2px;\n transition: all 200ms;\n font-weight: 600;\n .profile-image {\n width: 1.5rem;\n height: 1.5rem;\n margin-right: 1rem;\n }\n :hover {\n text-decoration: none;\n .flag {\n opacity: 1;\n pointer-events: all;\n }\n }\n }\n .project-mobile-view {\n position: relative;\n width: fit-content;\n color: #7b7b7b;\n border-radius: 14px;\n padding: 4px 6px;\n border: 1px solid var(--Neutral-200, #dbdbdb);\n background: var(--Neutral-100, #ebebeb);\n cursor: pointer;\n display: none;\n align-items: center;\n gap: 0.5rem;\n margin-left: 4px;\n .profile-image {\n width: 1.125rem;\n height: 1.125rem;\n display: flex !important;\n }\n .flag {\n left: -50%;\n .tip-icon {\n padding-left: 50%;\n }\n }\n :hover {\n text-decoration: none;\n .flag {\n opacity: 1;\n pointer-events: all;\n }\n }\n @media only screen and (max-width: 768px) {\n display: flex;\n }\n }\n .date span {\n display: none;\n }\n @media only screen and (max-width: 992px) {\n .price {\n margin-right: 0;\n }\n }\n @media only screen and (max-width: 768px) {\n flex-wrap: wrap;\n .project {\n display: none !important;\n }\n .price {\n min-width: 120px;\n gap: 8px;\n width: fit-content;\n justify-content: flex-start;\n span {\n display: inline-block;\n }\n }\n .date {\n width: 100%;\n justify-content: start;\n gap: 4px;\n span {\n display: inline;\n }\n }\n .address .profile-image {\n margin-right: 0.5rem;\n }\n }\n`;\nconst Flag = styled.div`\n display: flex;\n align-content: center;\n gap: 12px;\n margin-left: auto;\n opacity: 0;\n pointer-events: none;\n font-weight: 500;\n transition: 300ms ease-in-out;\n @media only screen and (max-width: 992px) {\n opacity: 1;\n div {\n display: none;\n }\n }\n @media only screen and (max-width: 768px) {\n margin-left: 0.5rem;\n }\n`;\nconst FlagTooltipWrapper = styled.div`\n position: absolute;\n display: flex;\n flex-direction: column;\n opacity: 0;\n pointer-events: none;\n transition: all 300ms ease 0s;\n top: 100%;\n background: white;\n z-index: 1;\n box-shadow: 0px 0px 1px 0px rgba(41, 41, 41, 0.74),\n 0px 3px 3px 0px rgba(123, 123, 123, 0.12),\n 0px 6px 6px 0px rgba(123, 123, 123, 0.12);\n border-radius: 4px;\n padding: 1rem;\n max-width: 550px;\n width: max-content;\n margin-top: 8px;\n cursor: default;\n .content {\n display: flex;\n gap: 1rem;\n .content-info {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n }\n .profile-image {\n width: 1.5rem;\n height: 1.5rem;\n margin-right: 0;\n }\n .title {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n .role {\n font-weight: 600;\n color: #7b7b7b;\n }\n .dot {\n width: 5px;\n height: 5px;\n background: #7b7b7b;\n border-radius: 50%;\n }\n .admin {\n font-weight: 600;\n display: flex;\n gap: 4px;\n }\n .text {\n color: #7b7b7b;\n }\n .flaged {\n color: #ed464f;\n font-weight: 600;\n &:hover {\n text-decoration: none;\n }\n }\n }\n .tip-icon {\n display: flex;\n z-index: 1;\n position: absolute;\n top: 0;\n height: 8px;\n transform: translateY(-100%);\n width: 100%;\n justify-content: flex-start;\n left: 0;\n padding-left: 2.5rem;\n svg {\n stroke: rgb(41 41 41 / 21%);\n }\n }\n @media only screen and (max-width: 768px) {\n width: 300px;\n padding: 0.5rem;\n font-size: 12px;\n .content .profile-image {\n display: none !important;\n }\n }\n`;\nconst accountId = context.accountId;\nconst FlagBtn = ({ isFlagged, isProject, address }) =>\n isFlagged && accountId === isFlagged.flaggedBy ? (\n <Flag className=\"flag\" onClick={(e) => handleFlag(e, address, isFlagged)}>\n <svg\n width=\"16\"\n height=\"18\"\n viewBox=\"0 0 16 18\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M7.86 2.5L8.26 4.5H13.5V10.5H10.14L9.74 8.5H2.5V2.5H7.86ZM9.5 0.5H0.5V17.5H2.5V10.5H8.1L8.5 12.5H15.5V2.5H9.9L9.5 0.5Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n <div>Unflag {isProject ? \"project\" : \"donor\"}</div>\n </Flag>\n ) : (\n <Flag className=\"flag\" onClick={(e) => handleFlag(e, address, isFlagged)}>\n <svg\n width=\"16\"\n height=\"18\"\n viewBox=\"0 0 16 18\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M7.86 2.5L8.26 4.5H13.5V10.5H10.14L9.74 8.5H2.5V2.5H7.86ZM9.5 0.5H0.5V17.5H2.5V10.5H8.1L8.5 12.5H15.5V2.5H9.9L9.5 0.5Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n <div>Flag {isProject ? \"project\" : \"donor\"}</div>\n </Flag>\n );\nconst Arrow = (props) => (\n <svg\n {...props}\n style={{ rotate: !props.active ? \"0deg\" : \"180deg\" }}\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M0 6L1.0575 7.0575L5.25 2.8725V12H6.75V2.8725L10.935 7.065L12 6L6 0L0 6Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n);\nconst ProfileImg = ({ address }) => (\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{ accountId: address, style: {} }}\n />\n);\nconst FlagTooltip = ({ flag, href, address }) => (\n <FlagTooltipWrapper className=\"flag\" onClick={(e) => e.preventDefault()}>\n <div className=\"tip-icon\">\n <svg\n width=\"12\"\n height=\"8\"\n viewBox=\"0 0 12 8\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 5.24537e-07L-2.54292e-07 8L12 8L6 5.24537e-07Z\"\n fill=\"white\"\n />\n </svg>\n </div>\n <div className=\"content\">\n <ProfileImg address={flag.flaggedBy} />\n <div className=\"content-info\">\n <div className=\"title\">\n <div className=\"role\">{flag.role}</div>\n <div className=\"dot\" />\n <div className=\"admin\">\n {_address(flag.flaggedBy)} has flagged\n <a\n href={href}\n className=\"flaged\"\n target=\"_blank\"\n onClick={(e) => e.stopPropagation()}\n >\n {_address(address)}\n </a>\n </div>\n </div>\n <div className=\"text\">{flag.potFlaggedAcc[address]}</div>\n </div>\n </div>\n </FlagTooltipWrapper>\n);\nconst AddressItem = ({ href, address, isFlagged, isProject, className }) => (\n <a\n href={href}\n className={className}\n target=\"_blank\"\n onClick={(e) => {\n isFlagged ? e.preventDefault() : null;\n }}\n >\n <ProfileImg address={address} />\n <div\n style={{\n color: isFlagged ? \"#ed464f\" : \"#292929\",\n fontWeight: \"600\",\n }}\n >\n {_address(address)}\n </div>\n {isFlagged && (\n <FlagTooltip flag={isFlagged} href={href} address={address} />\n )}\n {hasAuthority && (\n <FlagBtn\n isProject={isProject}\n className=\"flag\"\n address={address}\n isFlagged={isFlagged}\n />\n )}\n </a>\n);\nconst { getTimePassed, _address, calcNetDonationAmount } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n);\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getFlaggedAccounts: () => {},\n};\nconst {\n filteredDonations,\n filter,\n handleSearch,\n sortDonation,\n currentFilter,\n hrefWithParams,\n potDetail,\n potId,\n} = props;\nconst { admins, owner, chef, all_paid_out } = potDetail;\nconst nearLogo =\n \"https://ipfs.near.social/ipfs/bafkreicdcpxua47eddhzjplmrs23mdjt63czowfsa2jnw4krkt532pa2ha\";\nconst [currentPage, setCurrentPage] = useState(1);\nconst [flagAddress, setFlagAddress] = useState(null);\nconst [successFlag, setSuccessFlag] = useState(null);\nconst [updateFlaggedAddresses, setUpdateFlaggedAddresses] = useState(false);\nconst [flaggedAddresses, setFlaggedAddresses] = useState([]);\nconst perPage = 30; // need to be less than 50\nuseEffect(() => {\n setCurrentPage(1);\n}, [filter]);\nuseEffect(() => {\n PotSDK.getFlaggedAccounts(potDetail, potId)\n .then((data) => setFlaggedAddresses(data))\n .catch((err) => console.log(\"error getting the flagged accounts \", err));\n}, [successFlag, updateFlaggedAddresses]);\nconst handleFlag = (e, address, isFlagged) => {\n e.preventDefault();\n if (isFlagged) {\n // remove flagged account\n // get latest pLBlacklistedAccounts updates\n Near.asyncView(\"social.near\", \"get\", {\n keys: [`${accountId}/profile/**`],\n }).then((profileData) => {\n const profile = profileData[accountId].profile;\n const pLBlacklistedAccounts = JSON.parse(\n profile.pLBlacklistedAccounts || \"{}\"\n );\n const potFlaggedAcc = pLBlacklistedAccounts[potId] || {};\n delete potFlaggedAcc[address];\n const socialArgs = {\n data: {\n [accountId]: {\n profile: {\n pLBlacklistedAccounts: JSON.stringify({\n ...pLBlacklistedAccounts,\n [potId]: {\n ...potFlaggedAcc,\n },\n }),\n },\n },\n },\n };\n const depositFloat = JSON.stringify(socialArgs).length * 0.00015;\n const socialTransaction = {\n contractName: \"social.near\",\n methodName: \"set\",\n args: socialArgs,\n deposit: Big(depositFloat).mul(Big(10).pow(24)),\n };\n Near.call(socialTransaction);\n // update flaggedAddresses\n // TODO: check if it is successful before the update\n setTimeout(() => {\n setUpdateFlaggedAddresses(!updateFlaggedAddresses);\n }, 3000);\n });\n } else {\n // open flagModal\n setFlagAddress(address);\n }\n};\nconst potAdmins = [owner, chef, ...admins];\nconst hasAuthority = potAdmins.includes(accountId) && !all_paid_out;\nconst checkIfIsFlagged = (address) =>\n flaggedAddresses.find((obj) => obj.potFlaggedAcc[address]);\nreturn (\n <Container>\n <div className=\"transcation\">\n <div className=\"header\">\n <div\n className=\"address\"\n onClick={() => {\n setSuccessFlag({\n address: \"re.near\",\n reason: \"test tEST Tetset\",\n });\n }}\n >\n Donor\n </div>\n <div className=\"address\">Project</div>\n <div className=\"sort price\" onClick={() => sortDonation(\"price\")}>\n Amount\n {currentFilter === \"price\" && <Arrow active={filter.price} />}\n </div>\n <div className=\"sort\" onClick={() => sortDonation(\"date\")}>\n Date\n {currentFilter === \"date\" && <Arrow active={!filter.date} />}\n </div>\n </div>\n <SearchBarContainer>\n <SearchIcon>\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M15.7549 14.2549H14.9649L14.6849 13.9849C15.6649 12.8449 16.2549 11.3649 16.2549 9.75488C16.2549 6.16488 13.3449 3.25488 9.75488 3.25488C6.16488 3.25488 3.25488 6.16488 3.25488 9.75488C3.25488 13.3449 6.16488 16.2549 9.75488 16.2549C11.3649 16.2549 12.8449 15.6649 13.9849 14.6849L14.2549 14.9649V15.7549L19.2549 20.7449L20.7449 19.2549L15.7549 14.2549ZM9.75488 14.2549C7.26488 14.2549 5.25488 12.2449 5.25488 9.75488C5.25488 7.26488 7.26488 5.25488 9.75488 5.25488C12.2449 5.25488 14.2549 7.26488 14.2549 9.75488C14.2549 12.2449 12.2449 14.2549 9.75488 14.2549Z\"\n fill=\"#C7C7C7\"\n />\n </svg>\n </SearchIcon>\n <SearchBar placeholder=\"Search donations\" onChange={handleSearch} />\n </SearchBarContainer>\n {filteredDonations.length > 0 ? (\n filteredDonations\n .slice((currentPage - 1) * perPage, currentPage * perPage)\n .map((donation) => {\n const {\n donor_id,\n recipient_id,\n donated_at_ms,\n donated_at,\n project_id,\n } = donation;\n const projectId = recipient_id || project_id;\n const isDonorFlagged = checkIfIsFlagged(donor_id);\n const isProjectFlagged = checkIfIsFlagged(projectId);\n const projectHref = hrefWithParams(\n `?tab=project&projectId=${projectId}`\n );\n const profileHref = hrefWithParams(\n `?tab=profile&accountId=${donor_id}`\n );\n return (\n <TrRow>\n {/* Donor */}\n <AddressItem\n address={donor_id}\n isFlagged={isDonorFlagged}\n href={profileHref}\n isProject={false}\n className=\"address\"\n />\n {/* Project */}\n <AddressItem\n address={projectId}\n isFlagged={isProjectFlagged}\n href={projectHref}\n isProject={true}\n className=\"address project\"\n />\n <div className=\"price\">\n <span>Donated</span>\n <img src={nearLogo} alt=\"NEAR\" />\n {calcNetDonationAmount(donation).toFixed(2)}\n </div>\n <div className=\"date\">\n {getTimePassed(donated_at_ms || donated_at)} ago{\" \"}\n <span> to </span>\n <AddressItem\n address={projectId}\n isFlagged={isProjectFlagged}\n href={projectHref}\n isProject={true}\n className=\"project-mobile-view\"\n />\n </div>\n </TrRow>\n );\n })\n ) : (\n <TrRow>No donations</TrRow>\n )}\n </div>\n <Widget\n src={\"old.potlock.near/widget/Components.Pagination\"}\n props={{\n onPageChange: (page) => {\n setCurrentPage(page);\n },\n data: filteredDonations,\n currentPage,\n perPage: perPage,\n bgColor: \"#292929\",\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Pots.FlagModal\"}\n props={{\n ...props,\n flagAddress: flagAddress,\n isModalOpen: flagAddress != null,\n setSuccessFlag,\n onClose: () => setFlagAddress(null),\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Pots.FlagSuccessModal\"}\n props={{\n ...props,\n successFlag: successFlag,\n isModalOpen: successFlag != null,\n onClose: () => setSuccessFlag(null),\n }}\n />\n </Container>\n);\n" }, "Pots.FlaggedAccounts": { "": "const PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getFlaggedAccounts: () => {},\n};\nconst Line = styled.div`\n width: 100%;\n height: 1px;\n background: #c7c7c7;\n margin: 3rem 0;\n`;\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n width: 100%;\n`;\nconst Title = styled.div`\n font-size: 18px;\n display: flex;\n align-items: center;\n gap: 1.5rem;\n width: fit-content;\n cursor: pointer;\n margin-bottom: 1.5rem;\n div:first-of-type {\n font-weight: 600;\n }\n svg {\n rotate: 180deg;\n transition: all 300ms ease-in-out;\n }\n`;\nconst Table = styled.div`\n display: flex;\n flex-direction: column;\n width: 100%;\n border-radius: 6px;\n border: 1px solid #7b7b7b;\n transition: max-height 400ms ease-in-out;\n overflow: hidden;\n overflow-y: scroll;\n max-height: 1000px;\n opacity: 1;\n &.hidden {\n opacity: 0;\n max-height: 0;\n }\n`;\nconst Flag = styled.div`\n display: flex;\n padding: 1rem;\n border-bottom: 1px solid #c7c7c7;\n font-size: 14px;\n &:last-of-type {\n border-bottom: none;\n }\n .profile-image {\n width: 1.5rem;\n height: 1.5rem;\n margin-right: 0.5rem;\n }\n .content {\n display: flex;\n flex-direction: column;\n }\n .header {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.5rem;\n }\n .id {\n font-weight: 600;\n color: #292929;\n a {\n transition: 200ms;\n font-weight: 600;\n color: #292929;\n :hover {\n text-decoration: none;\n color: #dd3345;\n }\n }\n }\n .flagged-account {\n color: #ed464f;\n font-weight: 600;\n :hover {\n text-decoration: none;\n }\n }\n .role {\n color: #656565;\n font-weight: 600;\n }\n .reason {\n color: #656565;\n margin-top: 0.5rem;\n margin-bottom: 1rem;\n padding-left: 2.5rem;\n background: white;\n }\n .dot {\n background: #656565;\n width: 5px;\n height: 5px;\n border-radius: 50%;\n }\n @media only screen and (max-width: 480px) {\n .profile-image {\n margin-right: 0;\n }\n .reason {\n padding-left: 2rem;\n }\n }\n`;\nconst ProfileImg = ({ address }) => (\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{ accountId: address, style: {} }}\n />\n);\nconst { potId, hrefWithParams, potDetail } = props;\nconst [flaggedAddresses, setFlaggedAddresses] = useState(null);\nconst [toggleView, setToggleView] = useState(null);\nif (!flaggedAddresses) {\n PotSDK.getFlaggedAccounts(potDetail, potId)\n .then((data) => {\n const listOfFlagged = [];\n data.forEach((adminFlaggedAcc) => {\n const addresses = Object.keys(adminFlaggedAcc.potFlaggedAcc);\n addresses.forEach((address) => {\n listOfFlagged.push({\n address: address,\n reason: adminFlaggedAcc.potFlaggedAcc[address],\n flaggedBy: adminFlaggedAcc.flaggedBy,\n role: adminFlaggedAcc.role,\n });\n });\n });\n setFlaggedAddresses(listOfFlagged);\n })\n .catch((err) => console.log(\"error getting the flagged accounts \", err));\n}\nreturn !flaggedAddresses ? (\n \"Loading...\"\n) : flaggedAddresses.length === 0 ? (\n \"\"\n) : (\n <>\n <Container>\n <Title onClick={() => setToggleView(!toggleView)}>\n <div>Flagged Accounts</div>\n <div>{flaggedAddresses?.length}</div>\n <svg\n width=\"12\"\n height=\"8\"\n viewBox=\"0 0 12 8\"\n style={{\n rotate: toggleView ? \"0deg\" : \"180deg\",\n }}\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 0.294922L0 6.29492L1.41 7.70492L6 3.12492L10.59 7.70492L12 6.29492L6 0.294922Z\"\n fill=\"#151A23\"\n />\n </svg>\n </Title>\n <Table className={`${!toggleView ? \"hidden\" : \"\"}`}>\n {flaggedAddresses.map(({ role, flaggedBy, address, reason }) => (\n <Flag key={flaggedBy}>\n {/* <div className=\"vertical-line\" /> */}\n <div className=\"content\">\n <div className=\"header\">\n <ProfileImg address={flaggedBy} />\n <div className=\"role\">{role}</div>\n <div className=\"dot\" />\n <div className=\"id\">\n <a\n href={hrefWithParams(`?tab=profile&accountId=${flaggedBy}`)}\n target=\"_blank\"\n >\n {flaggedBy}{\" \"}\n </a>\n has flagged\n </div>\n <a\n className=\"flagged-account\"\n href={hrefWithParams(`?tab=profile&accountId=${address}`)}\n target=\"_blank\"\n >\n {address}\n </a>\n </div>\n <div className=\"reason\">{reason}</div>\n </div>\n </Flag>\n ))}\n </Table>\n </Container>\n <Line />\n </>\n);\n" }, "Components.Icons.Volunteer": { "": "const Volunteer = () => {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 18 18\"\n fill=\"none\"\n >\n <path\n d=\"M12.375 9.5625C14.6925 7.455 16.875 5.4825 16.875 3.7875C16.875 2.4 15.7875 1.3125 14.4 1.3125C13.62 1.3125 12.8625 1.68 12.375 2.25C11.88 1.68 11.13 1.3125 10.35 1.3125C8.9625 1.3125 7.875 2.4 7.875 3.7875C7.875 5.4825 10.0575 7.455 12.375 9.5625ZM10.35 2.8125C10.68 2.8125 11.0175 2.97 11.235 3.225L12.375 4.5675L13.515 3.225C13.7325 2.97 14.07 2.8125 14.4 2.8125C14.955 2.8125 15.375 3.2325 15.375 3.7875C15.375 4.6275 13.845 6.165 12.375 7.53C10.905 6.165 9.375 4.62 9.375 3.7875C9.375 3.2325 9.795 2.8125 10.35 2.8125Z\"\n fill=\"#DBDBDB\"\n />\n <path\n d=\"M14.625 11.8125H13.125C13.125 10.9125 12.5625 10.1025 11.7225 9.7875L7.1025 8.0625H1.125V16.3125H5.625V15.2325L10.875 16.6875L16.875 14.8125V14.0625C16.875 12.8175 15.87 11.8125 14.625 11.8125ZM2.625 14.8125V9.5625H4.125V14.8125H2.625ZM10.8525 15.12L5.625 13.6725V9.5625H6.8325L11.1975 11.19C11.4525 11.2875 11.625 11.535 11.625 11.8125C11.625 11.8125 10.1325 11.775 9.9 11.7L8.115 11.1075L7.6425 12.5325L9.4275 13.125C9.81 13.2525 10.2075 13.32 10.6125 13.32H14.625C14.9175 13.32 15.18 13.4925 15.3 13.74L10.8525 15.12Z\"\n fill=\"#DBDBDB\"\n />\n </svg>\n );\n};\nreturn { Volunteer };\n" }, "Components.NavOptions": { "": "const { navOptions } = props;\nconst getSelectedNavOption = () => {\n const navOption = navOptions.find((option) => option.id == props.nav);\n return navOption ?? navOptions[0];\n};\nconst NavOptionsContainer = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n gap: 8px;\n width: 100%;\n margin-bottom: 32px;\n`;\nconst NavOptionContainer = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n`;\nconst NavOption = styled.a`\n font-size: 14px;\n padding: 8px 16px;\n font-weight: ${(props) => (props.selected ? 600 : 400)};\n color: ${(props) => (props.selected ? \"#DD3345\" : \"#7B7B7B\")};\n cursor: ${(props) => (props.disabled ? \"not-allowed\" : \"pointer\")};\n &:hover {\n text-decoration: none;\n }\n`;\nreturn (\n <NavOptionsContainer>\n {navOptions.map((option) => {\n const selected = option.id == getSelectedNavOption().id;\n return option.disabled ? (\n <NavOption selected={selected} disabled={option.disabled}>\n {option.label}\n </NavOption>\n ) : !option.label ? (\n \"\"\n ) : (\n <NavOptionContainer>\n {selected && (\n <div\n style={{\n width: 2,\n height: 16,\n background: \"#DD3345\",\n borderRadius: 2,\n }}\n />\n )}\n <NavOption\n selected={selected}\n disabled={option.disabled}\n href={option.href}\n >\n {option.label}\n </NavOption>\n </NavOptionContainer>\n );\n })}\n </NavOptionsContainer>\n);\n" }, "Pots.HomeBannerBackground": { "": "const svgContent = `\n<svg width=\"1320\" height=\"332\" viewBox=\"0 0 1320 332\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<rect width=\"1320\" height=\"1\" fill=\"#FEF6EE\"/>\n<mask id=\"mask0_11854_22101\" style=\"mask-type:alpha\" maskUnits=\"userSpaceOnUse\" x=\"-60\" y=\"-486\" width=\"1440\" height=\"1024\">\n<rect x=\"-60\" y=\"-486\" width=\"1440\" height=\"1024\" fill=\"url(#paint0_radial_11854_22101)\"/>\n</mask>\n<g mask=\"url(#mask0_11854_22101)\">\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M358.131 1057C1475.87 1039 934.083 337 1942 337L1885.87 304C877.952 304 1419.74 1006 302 1024L358.131 1057Z\" fill=\"#FEF6EE\"/>\n<path d=\"M358.131 1057C1475.87 1039 934.083 337 1942 337L1885.87 304C877.952 304 1419.74 1006 302 1024L358.131 1057Z\" stroke=\"#FCE9D5\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M316.097 1021C1433.15 1003 891.698 301 1899 301L1842.9 268C835.601 268 1377.06 970 260 988L316.097 1021Z\" fill=\"#FEF6EE\"/>\n<path d=\"M316.097 1021C1433.15 1003 891.698 301 1899 301L1842.9 268C835.601 268 1377.06 970 260 988L316.097 1021Z\" stroke=\"#FCE9D5\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M262.097 985C1379.15 967 837.698 265 1845 265L1788.9 232C781.601 232 1323.06 934 206 952L262.097 985Z\" fill=\"#F8D3B0\"/>\n<path d=\"M262.097 985C1379.15 967 837.698 265 1845 265L1788.9 232C781.601 232 1323.06 934 206 952L262.097 985Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M218.131 949C1335.87 931 794.083 229 1802 229L1745.87 196C737.952 196 1279.74 898 162 916L218.131 949Z\" fill=\"#F8D3B0\"/>\n<path d=\"M218.131 949C1335.87 931 794.083 229 1802 229L1745.87 196C737.952 196 1279.74 898 162 916L218.131 949Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M161.097 914C1278.15 896 736.698 194 1744 194L1687.9 161C680.601 161 1222.06 863 105 881L161.097 914Z\" fill=\"#F8D3B0\"/>\n<path d=\"M161.097 914C1278.15 896 736.698 194 1744 194L1687.9 161C680.601 161 1222.06 863 105 881L161.097 914Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M104.131 878C1221.87 860 680.083 158 1688 158L1631.87 125C623.952 125 1165.74 827 48 845L104.131 878Z\" fill=\"#F8D3B0\"/>\n<path d=\"M104.131 878C1221.87 860 680.083 158 1688 158L1631.87 125C623.952 125 1165.74 827 48 845L104.131 878Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M49.0967 841C1166.15 823 624.698 121 1632 121L1575.9 88C568.601 88 1110.06 790 -7 808L49.0967 841Z\" fill=\"#F8D3B0\"/>\n<path d=\"M49.0967 841C1166.15 823 624.698 121 1632 121L1575.9 88C568.601 88 1110.06 790 -7 808L49.0967 841Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.2\">\n<path d=\"M-7.86905 805C1109.87 787 568.083 85 1576 85L1519.87 52C511.952 52 1053.74 754 -64 772L-7.86905 805Z\" fill=\"#F8D3B0\"/>\n<path d=\"M-7.86905 805C1109.87 787 568.083 85 1576 85L1519.87 52C511.952 52 1053.74 754 -64 772L-7.86905 805Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.2\">\n<path d=\"M-63.9375 770C1052.44 752 511.312 50 1518 50L1461.94 17C455.25 17 996.375 719 -120 737L-63.9375 770Z\" fill=\"#F8D3B0\"/>\n<path d=\"M-63.9375 770C1052.44 752 511.312 50 1518 50L1461.94 17C455.25 17 996.375 719 -120 737L-63.9375 770Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.2\">\n<path d=\"M-119.903 733C997.153 715 455.698 13 1463 13L1406.9 -20C399.601 -20 941.057 682 -176 700L-119.903 733Z\" fill=\"#F8D3B0\"/>\n<path d=\"M-119.903 733C997.153 715 455.698 13 1463 13L1406.9 -20C399.601 -20 941.057 682 -176 700L-119.903 733Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M-423.903 588C693.153 570 151.698 -132 1159 -132L1102.9 -165C95.6012 -165 637.057 537 -480 555L-423.903 588Z\" fill=\"#FEF6EE\"/>\n<path d=\"M-423.903 588C693.153 570 151.698 -132 1159 -132L1102.9 -165C95.6012 -165 637.057 537 -480 555L-423.903 588Z\" stroke=\"#FCE9D5\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M-460.869 565C656.869 547 115.083 -155 1123 -155L1066.87 -188C58.9524 -188 600.738 514 -517 532L-460.869 565Z\" fill=\"#FEF6EE\"/>\n<path d=\"M-460.869 565C656.869 547 115.083 -155 1123 -155L1066.87 -188C58.9524 -188 600.738 514 -517 532L-460.869 565Z\" stroke=\"#FCE9D5\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M-514.903 529C602.153 511 60.6979 -191 1068 -191L1011.9 -224C4.6012 -224 546.057 478 -571 496L-514.903 529Z\" fill=\"#FEF6EE\"/>\n<path d=\"M-514.903 529C602.153 511 60.6979 -191 1068 -191L1011.9 -224C4.6012 -224 546.057 478 -571 496L-514.903 529Z\" stroke=\"#FCE9D5\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M-568.903 493C548.153 475 6.69794 -227 1014 -227L957.903 -260C-49.3988 -260 492.057 442 -625 460L-568.903 493Z\" fill=\"#F8D3B0\"/>\n<path d=\"M-568.903 493C548.153 475 6.69794 -227 1014 -227L957.903 -260C-49.3988 -260 492.057 442 -625 460L-568.903 493Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M-625.869 457C491.869 439 -49.9167 -263 958 -263L901.869 -296C-106.048 -296 435.738 406 -682 424L-625.869 457Z\" fill=\"#F8D3B0\"/>\n<path d=\"M-625.869 457C491.869 439 -49.9167 -263 958 -263L901.869 -296C-106.048 -296 435.738 406 -682 424L-625.869 457Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M-682.903 422C434.153 404 -107.302 -298 900 -298L843.903 -331C-163.399 -331 378.057 371 -739 389L-682.903 422Z\" fill=\"#F8D3B0\"/>\n<path d=\"M-682.903 422C434.153 404 -107.302 -298 900 -298L843.903 -331C-163.399 -331 378.057 371 -739 389L-682.903 422Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M-739.869 386C377.869 368 -163.917 -334 844 -334L787.869 -367C-220.048 -367 321.738 335 -796 353L-739.869 386Z\" fill=\"#F8D3B0\"/>\n<path d=\"M-739.869 386C377.869 368 -163.917 -334 844 -334L787.869 -367C-220.048 -367 321.738 335 -796 353L-739.869 386Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M-794.903 349C322.153 331 -219.302 -371 788 -371L731.903 -404C-275.399 -404 266.057 298 -851 316L-794.903 349Z\" fill=\"#F8D3B0\"/>\n<path d=\"M-794.903 349C322.153 331 -219.302 -371 788 -371L731.903 -404C-275.399 -404 266.057 298 -851 316L-794.903 349Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.2\">\n<path d=\"M-851.869 313C265.869 295 -275.917 -407 732 -407L675.869 -440C-332.048 -440 209.738 262 -908 280L-851.869 313Z\" fill=\"#F8D3B0\"/>\n<path d=\"M-851.869 313C265.869 295 -275.917 -407 732 -407L675.869 -440C-332.048 -440 209.738 262 -908 280L-851.869 313Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.2\">\n<path d=\"M-907.938 278C208.438 260 -332.688 -442 674 -442L617.938 -475C-388.75 -475 152.375 227 -964 245L-907.938 278Z\" fill=\"#F8D3B0\"/>\n<path d=\"M-907.938 278C208.438 260 -332.688 -442 674 -442L617.938 -475C-388.75 -475 152.375 227 -964 245L-907.938 278Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.2\">\n<path d=\"M-963.903 241C153.153 223 -388.302 -479 619 -479L562.903 -512C-444.399 -512 97.0565 190 -1020 208L-963.903 241Z\" fill=\"#F8D3B0\"/>\n<path d=\"M-963.903 241C153.153 223 -388.302 -479 619 -479L562.903 -512C-444.399 -512 97.0565 190 -1020 208L-963.903 241Z\" stroke=\"#F4B37D\"/>\n</g>\n</g>\n<defs>\n<radialGradient id=\"paint0_radial_11854_22101\" cx=\"0\" cy=\"0\" r=\"1\" gradientUnits=\"userSpaceOnUse\" gradientTransform=\"translate(660 -158.5) rotate(90) scale(724.5 1018.83)\">\n<stop stop-color=\"#FCE9D5\"/>\n<stop offset=\"0.855072\" stop-color=\"#FEF6EE\" stop-opacity=\"0\"/>\n</radialGradient>\n</defs>\n</svg>\n`;\nconst HomeBannerStyle = {\n backgroundImage: `url(\"data:image/svg+xml;charset=utf-8,${encodeURIComponent(\n svgContent\n )}\")`,\n backgroundSize: \"cover\",\n backgroundRepeat: \"no-repeat\",\n backgroundColor: \"#FEF6EE\",\n};\nreturn {\n HomeBannerStyle,\n};\n" }, "Components.Button": { "": "const getButtonBackground = () => {\n if (props.type === \"primary\") {\n if (props.disabled) {\n return \"#e5e5e5\";\n }\n return \"#dd3345\";\n } else if (props.type === \"secondary\") {\n // TODO: handle disabled\n return \"#FEF6EE\";\n } else if (props.type === \"tertiary\") {\n return \"white\";\n }\n};\nconst getButtonTextColor = () => {\n if (props.type === \"primary\") {\n if (props.disabled) {\n return \"darkgrey\";\n }\n return \"white\";\n } else if (props.type === \"secondary\") {\n return \"#2E2E2E\";\n }\n};\nconst tag = props.href ? \"a\" : \"button\";\nconst Button = styled[tag]`\n flex-direction: row;\n justify-content: center;\n align-items: center;\n padding: 16px 24px;\n background: ${getButtonBackground()};\n overflow: hidden;\n box-shadow: 0px -2.700000047683716px 0px #4a4a4a inset;\n border-radius: 6px;\n border: 1px solid #4a4a4a;\n gap: 8px;\n display: inline-flex;\n text-align: center;\n color: ${getButtonTextColor()};\n font-size: 14px;\n line-height: 16px;\n font-weight: 600;\n &:hover {\n text-decoration: none;\n cursor: ${props.disabled ? \"not-allowed\" : \"pointer\"};\n }\n`;\nconst Icon = styled.img`\n width: 20px;\n height: 20px;\n object-fit: contain;\n`;\nreturn (\n <Button\n onClick={(e) => {\n if (props.disabled || !props.onClick) return;\n if (props.stopPropagation) e.stopPropagation();\n e.preventDefault();\n props.onClick(e);\n }}\n href={props.href}\n style={{ ...props.style }}\n target={props.target}\n >\n {props.iconSrc && <Icon src={props.iconSrc} />}\n {props.text}\n </Button>\n);\n" }, "Cart.Checkout": { "": "const donationContractId = \"donate.potlock.near\";\nconst IPFS_BASE_URL = \"https://nftstorage.link/ipfs/\";\n// const TRASH_ICON_URL =\n// IPFS_BASE_URL + \"bafkreifuvrxly3wuy4xdmavmdeb2o47nv6pzxwz3xmy6zvkxv76e55lj3y\";\nconst { getCart, getCartItemCount, removeItemsFromCart } = VM.require(\n \"old.potlock.near/widget/SDK.cart\"\n) || {\n getCart: () => {},\n getCartItemCount: () => 0,\n removeItemsFromCart: () => {},\n};\nconst numCartItems = getCartItemCount();\nconst cart = getCart();\nconst DEFAULT_GATEWAY = \"https://bos.potlock.org/\";\nconst POTLOCK_TWITTER_ACCOUNT_ID = \"PotLock_\";\nconst DEFAULT_SHARE_HASHTAGS = [\"BOS\", \"PublicGoods\", \"Donations\"];\nconst [projectId, setProjectId] = useState(\"\");\nconst Container = styled.div`\n background: #fafafa;\n display: flex;\n flex-direction: row;\n height: 100%;\n min-height: 100vh;\n @media screen and (max-width: 768px) {\n flex-direction: column;\n }\n`;\nconst SuccessContainer = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n // justify-content: center;\n width: 100%;\n padding: 24px;\n gap: 24px;\n`;\n// const ButtonsContainer = styled.div`\n// display: flex;\n// flex-direction: row;\n// gap: 24px;\n// width: 50%;\n// align-items: center;\n// justify-content: center;\n// `;\nconst ColumnLeft = styled.div`\n display: flex;\n flex-direction: column;\n // background: #fafafa;\n width: 55%;\n // background: pink;\n padding: 48px 40px 48px 64px;\n gap: 48px;\n @media screen and (max-width: 768px) {\n width: 100%;\n padding: 24px 16px 24px 16px;\n }\n`;\nconst ColumnRight = styled.div`\n // background: yellow;\n flex: 1;\n padding: 152px 148px 152px 84px;\n border-left: 1px #c7c7c7 solid;\n @media screen and (max-width: 768px) {\n padding: 24px 16px 24px 16px;\n border-left: none;\n border-top: 1px #c7c7c7 solid;\n }\n`;\nconst Title = styled.div`\n color: #2e2e2e;\n font-size: 48px;\n font-family: Lora;\n font-weight: 500;\n line-height: 56px;\n word-wrap: break-word;\n text-align: center;\n`;\nconst Icon = styled.svg`\n width: 1rem;\n height: 1rem;\n path {\n transition: 300ms;\n }\n`;\nconst ActionsContainer = styled.div`\n width: 100%;\n padding: 16px;\n background: white;\n border: 1px solid #dbdbdb;\n box-shadow: 0px -2px 0px #dbdbdb inset;\n border-radius: 6px;\n overflow: hidden;\n justify-content: flex-start;\n align-items: center;\n display: inline-flex;\n gap: 24px;\n`;\nconst InnerContainer = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n gap: 6px;\n :hover path {\n fill: #dd3345;\n }\n`;\nconst SubTitle = styled.div`\n color: #2e2e2e;\n font-weight: 600;\n font-size: 14px;\n`;\nconst TxLink = styled.a`\n color: #2e2e2e;\n cursor: pointer;\n &:hover {\n text-decoration: none;\n }\n`;\nState.init({\n selectedProjectIds: [],\n masterSelectorSelected: false,\n successfulDonationRecipientId: null,\n successfulDonationsRecipientProfiles: null,\n});\nconst allSelected =\n state.selectedProjectIds.length !== 0 &&\n state.selectedProjectIds.length === numCartItems;\nif (props.transactionHashes && !state.successfulDonationsRecipientProfiles) {\n // handles the case where the user is redirected from the wallet after a successful donation\n const transactionHashes = props.transactionHashes.split(\",\");\n for (let i = 0; i < transactionHashes.length; i++) {\n const txHash = transactionHashes[i];\n const body = JSON.stringify({\n jsonrpc: \"2.0\",\n id: \"dontcare\",\n method: \"tx\",\n params: [txHash, context.accountId],\n });\n const res = fetch(\"https://rpc.mainnet.near.org\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body,\n });\n if (res.ok) {\n const methodName =\n res.body.result.transaction.actions[0].FunctionCall.method_name;\n const successVal = res.body.result.status?.SuccessValue;\n const result = JSON.parse(\n Buffer.from(successVal, \"base64\").toString(\"utf-8\")\n ); // atob not working\n const args = JSON.parse(\n Buffer.from(\n res.body.result.transaction.actions[0].FunctionCall.args,\n \"base64\"\n ).toString(\"utf-8\")\n );\n const recipientId =\n methodName === \"donate\"\n ? result.recipient_id\n : methodName === \"ft_transfer_call\"\n ? JSON.parse(args.msg).recipient_id\n : \"\";\n if (recipientId) {\n Near.asyncView(\"social.near\", \"get\", {\n keys: [`${recipientId}/profile/**`],\n }).then((socialData) => {\n State.update({\n successfulDonationsRecipientProfiles: {\n ...state.successfulDonationsRecipientProfiles,\n [recipientId]: socialData[recipientId][\"profile\"],\n },\n });\n });\n }\n }\n }\n}\nuseEffect(() => {\n // handles extension wallet case, where user is not redirected (therefore no props.transactionHashes)\n if (\n state.successfulDonationRecipientId &&\n !state.successfulDonationsRecipientProfiles\n ) {\n Near.asyncView(\"social.near\", \"get\", {\n keys: [`${state.successfulDonationRecipientId}/profile/**`],\n }).then((socialData) => {\n State.update({\n successfulDonationsRecipientProfiles: {\n // don't spread the existing state, as it may be null\n [state.successfulDonationRecipientId]:\n socialData[state.successfulDonationRecipientId][\"profile\"],\n },\n });\n });\n }\n}, [\n state.successfulDonationRecipientId,\n state.successfulDonationsRecipientProfiles,\n]);\nconst twitterIntent = useMemo(() => {\n if (!state.successfulDonationsRecipientProfiles) return;\n const recipientIds = Object.keys(state.successfulDonationsRecipientProfiles);\n const twitterIntentBase = \"https://twitter.com/intent/tweet?text=\";\n // if more than one recipient, share the Explore Projects page; otherwise, share the project page\n let url =\n DEFAULT_GATEWAY +\n `old.potlock.near/widget/Index?referrerId=${context.accountId}`;\n if (recipientIds.length === 1) {\n url = url + `&tab=project&projectId=${recipientIds[0]}`;\n } else {\n url = url + `&tab=projects`;\n }\n // Initialize an empty array to hold the recipient profiles along with their identifiers\n const recipientProfiles = [];\n // Iterate over each entry in the successfulDonationsRecipientProfiles object\n for (const [recipientId, profile] of Object.entries(\n state.successfulDonationsRecipientProfiles\n )) {\n // Determine the identifier to use: Twitter handle, name, or recipient ID\n const identifier = profile.linktree?.twitter\n ? `@${profile.linktree.twitter}`\n : profile.name\n ? profile.name\n : recipientId;\n // Add the profile and its identifier to the array\n recipientProfiles.push({\n identifier,\n hasTwitter: !!profile.linktree?.twitter,\n });\n }\n // Sort the recipientProfiles array to put ones with Twitter handles first\n recipientProfiles.sort((a, b) => {\n if (a.hasTwitter && !b.hasTwitter) return -1;\n if (!a.hasTwitter && b.hasTwitter) return 1;\n return 0;\n });\n // Extract the identifiers from the sorted array\n const sortedIdentifiers = recipientProfiles.map(\n (profile) => profile.identifier\n );\n // Join the sorted recipient identifiers with \" & \" to create a single string\n const recipientsText = sortedIdentifiers.join(\" & \");\n let text = `I just donated to ${recipientsText} on @${POTLOCK_TWITTER_ACCOUNT_ID}! Support public goods at `;\n text = encodeURIComponent(text);\n url = encodeURIComponent(url);\n return (\n twitterIntentBase +\n text +\n `&url=${url}` +\n `&hashtags=${DEFAULT_SHARE_HASHTAGS.join(\",\")}`\n );\n}, [state.successfulDonationsRecipientProfiles]);\nreturn (\n // <div>\n <Container>\n {props.transactionHashes || state.successfulDonationRecipientId ? (\n <SuccessContainer>\n <Title>Thanks for donating!</Title>\n {twitterIntent && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n href: twitterIntent,\n target: \"_blank\",\n type: \"primary\",\n text: \"Share to Twitter\",\n disabled: !twitterIntent,\n style: {\n width: \"300px\",\n },\n }}\n />\n )}\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n href: props.hrefWithParams(`?tab=projects`),\n type: twitterIntent ? \"secondary\" : \"primary\",\n text: \"Explore projects\",\n style: {\n width: \"300px\",\n },\n }}\n />\n {/* {twitterIntent && props.checkoutSuccessTxHash ? (\n <TxLink\n target=\"_blank\"\n href={`https://nearblocks.io/txns/${props.checkoutSuccessTxHash}`}\n >\n View transaction\n </TxLink>\n ) : (\n props.checkoutSuccessTxHash && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n href: `https://nearblocks.io/txns/${props.checkoutSuccessTxHash}`,\n target: \"_blank\",\n type: \"secondary\",\n text: \"View transaction\",\n disabled: !props.checkoutSuccessTxHash,\n style: {\n width: \"300px\",\n },\n }}\n />\n )\n )} */}\n </SuccessContainer>\n ) : (\n <>\n <ColumnLeft>\n <Title>Donation Cart</Title>\n <ActionsContainer>\n <InnerContainer>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Checkbox\"}\n props={{\n id: \"masterSelector\",\n disabled: numCartItems === 0,\n checked: state.masterSelectorSelected,\n onClick: (e) => {\n // if allSelected, then deselect all\n // if not allSelected, then select all\n const selectedProjectIds = Object.keys(cart).filter((_) => {\n if (allSelected) {\n return false;\n }\n return true;\n });\n State.update({\n selectedProjectIds,\n masterSelectorSelected: !allSelected,\n });\n },\n }}\n />\n <SubTitle>Select all</SubTitle>\n </InnerContainer>\n <InnerContainer\n style={{ cursor: \"pointer\" }}\n onClick={() => {\n // doesn't do anything if nothing selected\n if (state.selectedProjectIds.length === 0) return;\n // delete selected projects\n removeItemsFromCart(\n state.selectedProjectIds.map((id) => ({ id }))\n );\n // uncheck box\n State.update({\n selectedProjectIds: [],\n masterSelectorSelected: false,\n });\n }}\n >\n <Icon\n viewBox=\"0 0 12 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M2.5 14C2.0875 14 1.73437 13.8531 1.44062 13.5594C1.14687 13.2656 1 12.9125 1 12.5V2.5H0V1H4V0H8V1H12V2.5H11V12.491C11 12.9137 10.8531 13.2708 10.5594 13.5625C10.2656 13.8542 9.9125 14 9.5 14H2.5ZM9.5 2.5H2.5V12.5H9.5V2.5ZM4 11H5.5V4H4V11ZM6.5 11H8V4H6.5V11Z\"\n fill=\"#7B7B7B\"\n />\n </Icon>\n <SubTitle>Delete</SubTitle>\n </InnerContainer>\n </ActionsContainer>\n {numCartItems === 0 ? (\n <div>No items in cart</div>\n ) : (\n Object.keys(cart).map((projectId) => {\n // setProjectId(projectId); // wtf is this?? commenting out\n const checked = state.selectedProjectIds.includes(projectId);\n return (\n <Widget\n src={\"old.potlock.near/widget/Cart.CheckoutItem\"}\n props={{\n ...props,\n cartItem: cart[projectId],\n checked,\n handleCheckboxClick: (e) => {\n // if selected, then deselect\n // else, select\n let selectedProjectIds = state.selectedProjectIds;\n if (checked) {\n selectedProjectIds = selectedProjectIds.filter(\n (id) => id !== projectId\n );\n } else {\n selectedProjectIds.push(projectId);\n }\n const updatedState = {\n selectedProjectIds,\n };\n if (\n selectedProjectIds.length !== 0 &&\n selectedProjectIds.length !== numCartItems\n ) {\n updatedState.masterSelectorSelected = false;\n }\n State.update(updatedState);\n },\n }}\n />\n );\n })\n )}\n </ColumnLeft>\n <ColumnRight>\n <Widget\n src={\"old.potlock.near/widget/Cart.CheckoutBreakdown\"}\n props={{\n ...props,\n projectId: projectId,\n updateSuccessfulDonationRecipientId: (recipientId) =>\n State.update({ successfulDonationRecipientId: recipientId }),\n }}\n />\n </ColumnRight>\n </>\n )}\n </Container>\n // </div>\n);\n" }, "Pots.Detail": { "": "const { potId } = props;\nconst { doesUserHaveDaoFunctionCallProposalPermissions } = VM.require(\n \"old.potlock.near/widget/utils\"\n) || { doesUserHaveDaoFunctionCallProposalPermissions: () => \"\" };\nconst {\n ONE_TGAS,\n SUPPORTED_FTS: { NEAR },\n} = VM.require(\"old.potlock.near/widget/constants\") || {\n ONE_TGAS: 0,\n SUPPORTED_FTS: {},\n};\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getConfig: () => {},\n asyncGetApplications: () => {},\n asyncGetPublicRoundDonations: () => {},\n};\nconst potDetail = PotSDK.getConfig(potId);\nconst MAX_APPLICATION_MESSAGE_LENGTH = 1000;\nBig.PE = 100;\nconst FIFTY_TGAS = \"50000000000000\";\nconst THREE_HUNDRED_TGAS = \"300000000000000\";\nconst MIN_PROPOSAL_DEPOSIT_FALLBACK = \"100000000000000000000000\"; // 0.1N\nconst Wrapper = styled.div``;\nconst SidebarContainer = styled.div`\n width: 25%;\n // width: 500px;\n @media screen and (max-width: 768px) {\n display: none;\n }\n`;\nconst Container = styled.div`\n padding: 0px 68px;\n @media screen and (max-width: 768px) {\n flex-direction: column;\n width: 100%;\n padding: 0;\n }\n`;\nconst ContainerInner = styled.div`\n display: flex;\n flex-direction: column;\n padding: 68px 0px;\n`;\nconst BodyContainer = styled.div`\n margin-top: 52px;\n padding: 0 4rem;\n flex: 1;\n width: 100%;\n @media screen and (max-width: 768px) {\n padding: 0;\n }\n`;\nconst Divider = styled.div`\n height: 1px;\n width: 100%;\n background-color: #292929;\n`;\nconst ModalTitle = styled.div`\n color: #525252;\n font-size: 16px;\n font-weight: 400;\n line-height: 20px;\n word-wrap: break-word;\n margin-bottom: 8px;\n`;\nconst Row = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n`;\nState.init({\n isApplicationModalOpen: false,\n applicationMessage: \"\",\n applicationMessageError: \"\",\n applicationSuccess: false,\n isDao: false,\n daoAddress: \"\",\n daoAddressError: \"\",\n daoPolicy: null,\n registryStatus: null,\n});\n// if (state.sybilRequirementMet === null) {\n// if (potDetail.sybil_wrapper_provider) {\n// const [contractId, methodName] = potDetail.sybil_wrapper_provider.split(\":\");\n// Near.asyncView(contractId, methodName, { account_id: context.accountId })\n// .then((result) => {\n// State.update({ sybilRequirementMet: result });\n// })\n// .catch((e) => {\n// State.update({ sybilRequirementMet: false });\n// });\n// } else {\n// State.update({ sybilRequirementMet: true });\n// }\n// }\nconst noPot = potDetail === undefined;\nconst loading = potDetail === null;\nif (loading) return <div class=\"spinner-border text-secondary\" role=\"status\" />;\nif (noPot) return \"No pot found\";\nconst now = Date.now();\nconst applicationNotStarted = now < potDetail.application_start_ms;\nconst applicationOpen =\n now >= potDetail.application_start_ms && now < potDetail.application_end_ms;\nconst publicRoundOpen =\n now >= potDetail.public_round_start_ms && now < potDetail.public_round_end_ms;\nconst publicRoundClosed = now >= potDetail.public_round_end_ms;\nconst payoutsPending = publicRoundClosed && !potDetail.cooldown_end_ms;\n// these will be passed down to child components\nprops.navOptions = [\n {\n label: \"Projects\",\n id: \"projects\",\n disabled: false,\n source: \"old.potlock.near/widget/Pots.Projects\",\n href: props.hrefWithParams(`?tab=pot&potId=${potId}&nav=projects`),\n },\n {\n label: \"Applications\",\n id: \"applications\",\n disabled: false,\n source: \"old.potlock.near/widget/Pots.Applications\",\n href: props.hrefWithParams(`?tab=pot&potId=${potId}&nav=applications`),\n },\n {\n label: \"Donations\",\n id: \"donations\",\n disabled: false,\n source: \"old.potlock.near/widget/Pots.Donations\",\n href: props.hrefWithParams(`?tab=pot&potId=${potId}&nav=donations`),\n },\n {\n label: \"Sponsors\",\n id: \"sponsors\",\n disabled: false,\n source: \"old.potlock.near/widget/Pots.Sponsors\",\n href: props.hrefWithParams(`?tab=pot&potId=${potId}&nav=sponsors`),\n },\n {\n label: \"Payouts\",\n id: \"payouts\",\n disabled: now < potDetail.public_round_start_ms, // TODO: ADD BACK IN\n source: \"old.potlock.near/widget/Pots.Payouts\",\n href: props.hrefWithParams(`?tab=pot&potId=${potId}&nav=payouts`),\n },\n {\n label: \"Settings\",\n id: \"settings\",\n disabled: false,\n source: \"old.potlock.near/widget/Pots.Settings\",\n href: props.hrefWithParams(`?tab=pot&potId=${potId}&nav=settings`),\n },\n];\nif (!props.nav) {\n let nav;\n applicationNotStarted\n ? (nav = \"sponsors\")\n : applicationOpen\n ? (nav = \"applications\")\n : publicRoundOpen\n ? (nav = \"projects\")\n : !payoutsPending\n ? (nav = \"donations\")\n : (nav = \"payouts\");\n props.nav = nav;\n} // default to home tab\n// const imageHeightPx = 120;\n// const profileImageTranslateYPx = 220;\nconst handleSendApplication = () => {\n const args = {\n message: state.applicationMessage,\n };\n let deposit = NEAR.toIndivisible(\"0.01\");\n const extraDeposit = Big(state.applicationMessage.length * 0.0001).mul(\n Big(10).pow(24)\n );\n deposit = deposit.plus(extraDeposit);\n const transactions = [\n {\n contractName: potId,\n methodName: \"apply\",\n deposit,\n args,\n gas: ONE_TGAS.mul(100),\n },\n ];\n // if it is a DAO, we need to convert transactions to DAO function call proposals\n if (state.isDao) {\n const clonedTransactions = JSON.parse(JSON.stringify(transactions));\n transactions = clonedTransactions.map((tx) => {\n const action = {\n method_name: tx.methodName,\n gas: FIFTY_TGAS,\n deposit: tx.deposit ? tx.deposit.toString() : \"0\",\n args: Buffer.from(JSON.stringify(tx.args), \"utf-8\").toString(\"base64\"),\n };\n return {\n ...tx,\n contractName: state.daoAddress,\n methodName: \"add_proposal\",\n args: {\n proposal: {\n description: `Application to PotLock pot: ${potDetail.pot_name} (${potId})`,\n kind: {\n FunctionCall: {\n receiver_id: tx.contractName,\n actions: [action],\n },\n },\n },\n },\n deposit: state.daoPolicy.proposal_bond || MIN_PROPOSAL_DEPOSIT_FALLBACK,\n gas: THREE_HUNDRED_TGAS,\n };\n });\n }\n Near.call(transactions);\n // NB: we won't get here if user used a web wallet, as it will redirect to the wallet\n // <---- EXTENSION WALLET HANDLING ---->\n // poll for updates\n const pollIntervalMs = 1000;\n // const totalPollTimeMs = 60000; // consider adding in to make sure interval doesn't run indefinitely\n const pollId = setInterval(() => {\n PotSDK.asyncGetApplications(potId).then((applications) => {\n const application = applications.find(\n (application) =>\n application.project_id ===\n (state.isDao ? state.daoAddress : context.accountId)\n );\n if (application) {\n clearInterval(pollId);\n State.update({ applicationSuccess: true });\n }\n });\n }, pollIntervalMs);\n};\nconst verifyIsOnRegistry = (address) => {\n Near.asyncView(\"lists.potlock.near\", \"get_registrations_for_registrant\", {\n registrant_id: address,\n }).then((registrations) => {\n const registration = registrations.find(\n (registration) => registration.list_id === 1 // potlock registry list id\n );\n if (registration) {\n State.update({ registryStatus: registration.status });\n }\n });\n};\nuseEffect(() => {\n if (!state.isDao) {\n verifyIsOnRegistry(context.accountId || \"\");\n }\n}, []);\n// const registryRequirementMet = state.isOnRegistry || !potDetail.registry_provider;\nconst registrationApproved = state.registryStatus === \"Approved\";\nconst registrationNotApproved =\n state.registryStatus && state.registryStatus !== \"Approved\";\nconst registrationApprovedOrNoRegistryProvider =\n registrationApproved || !potDetail?.registry_provider;\nconst isError = state.applicationMessageError || state.daoAddressError;\n// Get total public donations\nconst allDonationsPaginated = useCache(() => {\n const limit = 480; // number of donations to fetch per req\n const donationsCount = potDetail.public_donations_count;\n const paginations = [\n ...Array(\n parseInt(donationsCount / limit) + (donationsCount % limit > 0 ? 1 : 0)\n ).keys(),\n ];\n try {\n const allDonations = paginations.map((index) =>\n PotSDK.asyncGetPublicRoundDonations(potId, {\n from_index: index * limit,\n limit: limit,\n })\n );\n return Promise.all(allDonations);\n } catch (error) {\n console.error(\n `error getting public donations from ${index} to ${index * limit}`,\n error\n );\n }\n}, \"pot-public-donations\");\nconst allDonations = allDonationsPaginated\n ? allDonationsPaginated.flat()\n : null;\nreturn (\n <Wrapper>\n <Widget\n src={\"old.potlock.near/widget/Pots.HeaderStatus\"}\n props={{\n ...props,\n potDetail: potDetail,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Pots.Header\"}\n props={{\n ...props,\n potDetail: potDetail,\n setApplicationModalOpen: (isOpen) =>\n State.update({ isApplicationModalOpen: isOpen }),\n applicationSuccess: state.applicationSuccess,\n registrationApproved,\n allDonations,\n registryStatus: state.registryStatus,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Profile.Tabs\"}\n props={{\n ...props,\n }}\n />\n <BodyContainer>\n <Widget\n src={props.navOptions.find((option) => option.id == props.nav).source}\n props={{\n ...props,\n potDetail: potDetail,\n allDonations,\n }}\n />\n </BodyContainer>\n <Widget\n src={\"old.potlock.near/widget/Components.Modal\"}\n props={{\n ...props,\n isModalOpen: state.isApplicationModalOpen,\n onClose: () => State.update({ isApplicationModalOpen: false }),\n children: (\n <>\n <ModalTitle>\n Application message <span style={{ color: \"#DD3345\" }}>*</span>\n </ModalTitle>\n <Widget\n src={\"old.potlock.near/widget/Inputs.TextArea\"}\n props={{\n noLabel: true,\n inputRows: 5,\n inputStyle: {\n background: \"#FAFAFA\",\n },\n placeholder: \"Your application message here...\",\n value: state.applicationMessage,\n onChange: (applicationMessage) =>\n State.update({ applicationMessage }),\n validate: () => {\n if (\n state.applicationMessage.length >\n MAX_APPLICATION_MESSAGE_LENGTH\n ) {\n State.update({\n applicationMessageError: `Application message must be less than ${MAX_APPLICATION_MESSAGE_LENGTH} characters`,\n });\n return;\n }\n State.update({ applicationMessageError: \"\" });\n },\n error: state.applicationMessageError,\n }}\n />\n <Row style={{ margin: \"12px 0px\" }}>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Checkbox\"}\n props={{\n id: \"isDaoSelector\",\n checked: state.isDao,\n onClick: (e) => {\n State.update({\n isDao: e.target.checked,\n });\n if (!e.target.checked) {\n // check current account ID against registry\n verifyIsOnRegistry(context.accountId);\n }\n },\n label: \"I'm applying as a DAO\",\n }}\n />\n </Row>\n {state.isDao && (\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"DAO address *\",\n placeholder: \"E.g. mydao.sputnikdao.near\",\n value: state.daoAddress,\n onChange: (daoAddress) =>\n State.update({ daoAddress, daoAddressError: \"\" }),\n validate: () => {\n // **CALLED ON BLUR**\n Near.asyncView(state.daoAddress, \"get_policy\", {})\n .then((policy) => {\n const hasPermissions = !policy\n ? false\n : doesUserHaveDaoFunctionCallProposalPermissions(\n context.accountId,\n policy\n );\n State.update({\n daoAddressError: hasPermissions\n ? \"\"\n : \"You don't have required permissions to submit proposals to this DAO.\",\n daoPolicy: policy,\n });\n // check registry\n verifyIsOnRegistry(state.daoAddress);\n })\n .catch((e) => {\n State.update({\n daoAddressError: \"Invalid DAO address\",\n });\n });\n },\n error: state.daoAddressError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n )}\n <Row style={{ justifyContent: \"flex-end\", marginTop: \"12px\" }}>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n // text: registrationApprovedOrNoRegistryProvider\n // ? state.isDao\n // ? \"Propose to Send Application\"\n // : \"Send application\"\n // : \"Register to apply\",\n text: state.isDao\n ? \"Propose to Send Application\"\n : registrationApprovedOrNoRegistryProvider\n ? \"Send application\"\n : \"Register to apply\",\n onClick:\n state.isDao || registrationApprovedOrNoRegistryProvider\n ? handleSendApplication\n : null,\n disabled: isError,\n href:\n state.isDao || registrationApprovedOrNoRegistryProvider\n ? null\n : props.hrefWithParams(`?tab=createproject`),\n target:\n state.isDao || registrationApprovedOrNoRegistryProvider\n ? \"_self\"\n : \"_blank\",\n }}\n />\n </Row>\n </>\n ),\n }}\n />\n </Wrapper>\n);\n" }, "ModalDonation.ConfirmPot": { "": "const { NADABOT_HUMAN_METHOD, DONATION_CONTRACT_ID } = VM.require(\n \"old.potlock.near/widget/constants\"\n) || {\n NADABOT_HUMAN_METHOD: \"\",\n DONATION_CONTRACT_ID: \"\",\n};\nconst { nearToUsd } = VM.require(\"old.potlock.near/widget/utils\");\nlet DonateSDK =\n VM.require(\"old.potlock.near/widget/SDK.donate\") ||\n (() => ({\n getConfig: () => {},\n asyncGetDonationsForDonor: () => {},\n }));\nDonateSDK = DonateSDK({ env: props.env });\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getConfig: () => {},\n asyncGetDonationsForDonor: () => {},\n};\nconst { _address } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n) || {\n _address: (address) => address,\n};\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n padding: 1.5rem 2rem;\n gap: 1.5rem;\n @media only screen and (max-width: 480px) {\n padding: 1.5rem 1.125rem;\n }\n`;\nconst ContentScrollable = styled.div`\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n overflow-y: scroll;\n height: 450px;\n`;\nconst Label = styled.div`\n font-weight: 500;\n margin-bottom: 4px;\n`;\nconst Amout = styled.div`\n display: flex;\n align-items: center;\n gap: 0.5rem;\n cursor: pointer;\n span {\n font-weight: 600;\n }\n div {\n font-weight: 600;\n font-size: 1rem;\n }\n .usd-amount {\n color: #7b7b7b;\n }\n .toggle-icon {\n width: 8px;\n display: flex;\n margin-left: auto;\n overflow: hidden;\n svg {\n width: 100%;\n transition: all 300ms ease-in-out;\n }\n }\n img,\n svg {\n width: 20px;\n }\n`;\nconst SvgIcon = styled.svg`\n width: 16px;\n`;\nconst FeesRemoval = styled.div`\n display: flex;\n flex-direction: column;\n gap: 1rem;\n .check {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n }\n .label {\n margin-right: 4px;\n margin-left: 8px;\n }\n .address {\n font-weight: 600;\n gap: 4px;\n display: flex;\n align-items: center;\n color: #292929;\n transition: all 300ms;\n &:hover {\n color: #dd3345;\n text-decoration: none;\n }\n }\n .profile-image {\n width: 17px;\n height: 17px;\n display: flex !important;\n }\n @media only screen and (max-width: 480px) {\n .address {\n margin-left: 34px;\n width: 100%;\n }\n }\n`;\nconst Button = styled.div`\n display: flex;\n margin-top: 4rem;\n margin-bottom: 0.5rem;\n button {\n padding: 12px 16px;\n width: 100%;\n font-weight: 500;\n }\n @media only screen and (max-width: 480px) {\n margin-top: 2rem;\n }\n`;\nconst Projects = styled.div`\n padding: 8px 0;\n display: flex;\n flex-direction: column;\n border-radius: 8px;\n border: 1px solid #ebebeb;\n background: rgba(235, 235, 235, 0.24);\n transition: all 300ms ease-in-out;\n &.hidden {\n max-height: 0;\n overflow: hidden;\n opacity: 0;\n }\n .project {\n display: flex;\n align-items: center;\n gap: 1rem;\n padding: 0.5rem 1rem;\n transition: 300ms ease-in-out;\n }\n .profile-image {\n width: 40px;\n height: 40px;\n box-shadow: 0px 0px 1px 0px #a6a6a6 inset;\n border-radius: 50%;\n }\n .info {\n display: flex;\n flex-direction: column;\n .name {\n font-weight: 600;\n }\n .address {\n color: #7b7b7b;\n transition: all 300ms;\n &:hover {\n text-decoration: none;\n color: #dd3345;\n }\n }\n }\n`;\nconst ProjectAmount = styled.div`\n margin-left: auto;\n display: flex;\n gap: 1rem;\n align-items: center;\n div {\n font-weight: 600;\n }\n svg {\n width: 16px;\n }\n`;\nconst NearIcon = (props) => (\n <SvgIcon\n {...props}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <g clip-path=\"url(#clip0_454_78)\">\n <circle cx=\"8\" cy=\"8\" r=\"7.25\" stroke=\"#292929\" stroke-width=\"1.5\" />\n <path\n d=\"M11.1477 4C10.851 4 10.5763 4.15333 10.421 4.406L8.74866 6.88867C8.72453 6.92441 8.71422 6.96772 8.71967 7.01051C8.72511 7.05329 8.74594 7.09264 8.77826 7.1212C8.81057 7.14976 8.85218 7.1656 8.89531 7.16574C8.93844 7.16589 8.98015 7.15034 9.01266 7.122L10.6587 5.69467C10.6683 5.68598 10.6802 5.68028 10.6931 5.67828C10.7059 5.67628 10.719 5.67806 10.7308 5.6834C10.7426 5.68875 10.7526 5.69742 10.7596 5.70836C10.7665 5.7193 10.7702 5.73203 10.77 5.745V10.215C10.77 10.2287 10.7658 10.2421 10.7579 10.2534C10.7501 10.2646 10.7389 10.2732 10.726 10.2778C10.7131 10.2825 10.6991 10.2831 10.6858 10.2795C10.6726 10.2758 10.6608 10.2682 10.652 10.2577L5.67667 4.30167C5.59667 4.20709 5.49701 4.1311 5.38463 4.079C5.27226 4.0269 5.14987 3.99994 5.026 4H4.85233C4.62628 4 4.40949 4.0898 4.24964 4.24964C4.0898 4.40949 4 4.62628 4 4.85233V11.1477C4 11.3333 4.06061 11.5139 4.17263 11.6619C4.28465 11.81 4.44194 11.9174 4.6206 11.9679C4.79926 12.0184 4.98952 12.0091 5.16245 11.9416C5.33538 11.874 5.48152 11.7519 5.57867 11.5937L7.251 9.111C7.27513 9.07525 7.28544 9.03194 7.27999 8.98916C7.27455 8.94637 7.25372 8.90703 7.22141 8.87846C7.18909 8.8499 7.14748 8.83407 7.10435 8.83392C7.06122 8.83377 7.01951 8.84932 6.987 8.87766L5.341 10.3053C5.33134 10.3139 5.31939 10.3195 5.3066 10.3215C5.29381 10.3234 5.28074 10.3216 5.26898 10.3162C5.25721 10.3108 5.24726 10.3021 5.24034 10.2912C5.23342 10.2803 5.22983 10.2676 5.23 10.2547V5.784C5.22997 5.77027 5.23418 5.75687 5.24206 5.74563C5.24993 5.73438 5.26109 5.72584 5.274 5.72117C5.28691 5.71651 5.30094 5.71594 5.31419 5.71955C5.32743 5.72315 5.33924 5.73076 5.348 5.74133L10.3227 11.698C10.4847 11.8893 10.7227 11.9997 10.9733 12H11.147C11.373 12.0001 11.5898 11.9104 11.7498 11.7507C11.9097 11.591 11.9997 11.3744 12 11.1483V4.85233C11.9999 4.62631 11.9101 4.40956 11.7503 4.24974C11.5904 4.08992 11.3737 4.00009 11.1477 4Z\"\n fill=\"#292929\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_454_78\">\n <rect width=\"16\" height=\"16\" fill=\"white\" />\n </clipPath>\n </defs>\n </SvgIcon>\n);\nconst ProfileImg = ({ accountId, profile }) => (\n <Widget\n src={\"old.potlock.near/widget/Project.ProfileImage\"}\n props={{\n accountId,\n profile,\n style: {},\n }}\n />\n);\nconst CheckBox = ({ id, checked, onClick }) => (\n <Widget\n src={\"old.potlock.near/widget/Inputs.Checkbox\"}\n props={{\n id,\n checked,\n onClick,\n }}\n />\n);\nconst getFeesBasisPoints = (protocolConfig, potDetail) => {\n if (protocolConfig) {\n return [\n protocolConfig.account_id,\n protocolConfig.basis_points,\n potDetail.referral_fee_public_round_basis_points,\n ];\n } else {\n return [\"\", 0, 0];\n }\n};\nconst pollForDonationSuccess = ({\n projectIds,\n afterTs,\n accountId,\n openDonationSuccessModal,\n potId,\n}) => {\n // poll for updates\n const pollIntervalMs = 1000;\n // const totalPollTimeMs = 60000; // consider adding in to make sure interval doesn't run indefinitely\n const pollId = setInterval(() => {\n PotSDK.asyncGetDonationsForDonor(potId, accountId)\n .then((alldonations) => {\n const donations = {};\n for (const donation of alldonations) {\n const { project_id, donated_at_ms, donated_at } = donation;\n if (\n projectIds.includes(project_id) &&\n (donated_at_ms || donated_at) > afterTs\n ) {\n donations[project_id] = { ...donation, potId };\n }\n }\n if (Object.keys(donations).length === projectIds.length) {\n // display success message\n clearInterval(pollId);\n openDonationSuccessModal(donations);\n }\n })\n .catch((err) => {\n console.log(err);\n });\n }, pollIntervalMs);\n};\nconst ConfirmPot = (props) => {\n const {\n selectedDenomination,\n bypassProtocolFee,\n bypassChefFee,\n updateState,\n potDetail,\n potId,\n referrerId,\n accountId,\n amount,\n openDonationSuccessModal,\n selectedProjects,\n donationType,\n hrefWithParams,\n toggleAmount,\n } = props;\n const protocolConfigContractId =\n potDetail.protocol_config_provider.split(\":\")[0];\n const protocolConfigViewMethodName =\n potDetail.protocol_config_provider.split(\":\")[1];\n const protocolConfig =\n protocolConfigContractId && protocolConfigViewMethodName\n ? Near.view(protocolConfigContractId, protocolConfigViewMethodName, {})\n : null;\n const [\n protocolFeeRecipientAccount,\n protocolFeeBasisPoints,\n referralFeeBasisPoints,\n ] = getFeesBasisPoints(protocolConfig, potDetail);\n const chefFeeBasisPoints = potDetail?.chef_fee_basis_points;\n const donationAmountIndivisible = (num) =>\n Big(num).mul(new Big(10).pow(selectedDenomination.decimals));\n const projectAmount =\n parseFloat(amount) / Object.keys(selectedProjects).length;\n const autoProjectAmount = donationAmountIndivisible(projectAmount);\n const handleDonate = () => {\n const now = Date.now();\n const successArgs = {\n projectIds: Object.keys(selectedProjects),\n afterTs: now,\n accountId,\n openDonationSuccessModal,\n amount,\n potId,\n };\n const transactions = [];\n Object.keys(selectedProjects).forEach((project) => {\n let amount = 0;\n if (donationType === \"auto\") {\n amount = autoProjectAmount;\n } else {\n amount = donationAmountIndivisible(selectedProjects[project]);\n }\n if (amount) {\n transactions.push({\n contractName: potId,\n methodName: \"donate\",\n args: {\n referrer_id: referrerId,\n project_id: project,\n bypass_protocol_fee: bypassProtocolFee,\n ...(bypassChefFee ? { custom_chef_fee_basis_points: 0 } : {}),\n },\n deposit: amount.toFixed(0),\n gas: \"300000000000000\",\n });\n }\n });\n Near.call(transactions);\n pollForDonationSuccess(successArgs);\n };\n return (\n <Container>\n <ContentScrollable>\n <div>\n <Label>Total amount</Label>\n <Amout\n onClick={() =>\n updateState({\n toggleAmount: !toggleAmount,\n })\n }\n >\n <div>\n {selectedDenomination.icon ? (\n <img src={selectedDenomination.icon} />\n ) : (\n <NearIcon />\n )}\n </div>\n <div>\n {amount} <span>{selectedDenomination.text}</span>\n </div>\n {nearToUsd && (\n <div className=\"usd-amount\">\n ~${(nearToUsd * amount).toFixed(2)}\n </div>\n )}\n <div className=\"toggle-icon\">\n <svg\n viewBox=\"0 0 8 12\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style={{\n rotate: !toggleAmount ? \"\" : \"90deg\",\n }}\n >\n <path\n d=\"M1.70501 0L0.295013 1.41L4.87501 6L0.295013 10.59L1.70501 12L7.70501 6L1.70501 0Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n </div>\n </Amout>\n </div>\n <Projects className={`${!toggleAmount ? \"hidden\" : \"\"}`}>\n {Object.keys(selectedProjects).map((project_id) => {\n const profile = Social.getr(`${project_id}/profile`);\n return selectedProjects[project_id] > 0 ||\n donationType === \"auto\" ? (\n <div className={`project`} key={project_id}>\n <ProfileImg profile={profile} />\n <div className=\"info\">\n {profile?.name && (\n <div className=\"name\">{_address(profile?.name, 20)}</div>\n )}\n <a\n className=\"address\"\n href={hrefWithParams(\n `?tab=project&projectId=${project_id}`\n )}\n target=\"_blank\"\n >\n {_address(project_id, 20)}\n </a>\n </div>\n <ProjectAmount>\n <div>\n {\" \"}\n {donationType === \"auto\"\n ? projectAmount < 0.01\n ? \"<0.01\"\n : projectAmount.toFixed(2)\n : selectedProjects[project_id]}{\" \"}\n </div>\n <NearIcon />\n </ProjectAmount>\n </div>\n ) : (\n \"\"\n );\n })}\n </Projects>\n <Widget\n src={\"old.potlock.near/widget/Cart.BreakdownSummary\"}\n props={{\n ...props,\n referrerId,\n protocolFeeBasisPoints,\n referralFeeBasisPoints,\n bypassChefFee,\n chef: potDetail?.chef,\n chefFeeBasisPoints,\n totalAmount: amount,\n bypassProtocolFee: bypassProtocolFee,\n ftIcon: selectedDenomination.icon,\n }}\n />\n <FeesRemoval>\n <div className=\"check\">\n <CheckBox\n id=\"bypassProtocolFeeSelector\"\n checked={bypassProtocolFee}\n onClick={(e) => {\n updateState({ bypassProtocolFee: e.target.checked });\n }}\n />\n <div className=\"label\">\n Remove {protocolFeeBasisPoints / 100 || \"-\"}% protocol fee\n </div>\n <a\n href={`https://near.social/mob.near/widget/ProfilePage?accountId=${protocolFeeRecipientAccount}`}\n className=\"address\"\n target=\"_blank\"\n >\n <ProfileImg accountId={protocolFeeRecipientAccount} />\n {protocolFeeRecipientAccount}\n </a>\n </div>\n {potDetail?.chef && chefFeeBasisPoints > 0 && (\n <div className=\"check\">\n <CheckBox\n id=\"bypassChefFeeSelector\"\n checked={bypassChefFee}\n onClick={(e) => {\n updateState({ bypassChefFee: e.target.checked });\n }}\n />\n <div className=\"label\">\n {\" \"}\n Remove {chefFeeBasisPoints / 100 || \"-\"}% chef fee\n </div>\n <a\n href={`https://near.social/mob.near/widget/ProfilePage?accountId=${potDetail?.chef}`}\n className=\"address\"\n target=\"_blank\"\n >\n <ProfileImg accountId={potDetail?.chef} />\n {potDetail?.chef}\n </a>\n </div>\n )}\n </FeesRemoval>\n </ContentScrollable>\n <Button>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: \"Confirm donation\",\n onClick: handleDonate,\n }}\n />\n </Button>\n </Container>\n );\n};\nreturn {\n ConfirmPot,\n};\n" }, "Components.ModalMultiAccount": { "": "const {\n isModalOpen,\n onClose,\n titleText,\n descriptionText,\n unitText,\n inputValue,\n onInputChange,\n handleAddAccount,\n handleRemoveAccount,\n accountError,\n accountIds,\n} = props;\nconst IPFS_BASE_URL = \"https://nftstorage.link/ipfs/\";\n// const ADD_ACCOUNTS_ICON_URL =\n// IPFS_BASE_URL + \"bafkreig6c7m2z2lupreu2br4pm3xx575mv6uvmuy2qkij4kzzfpt7tipcq\";\n// const CLOSE_ICON_URL =\n// IPFS_BASE_URL + \"bafkreifyg2vvmdjpbhkylnhye5es3vgpsivhigkjvtv2o4pzsae2z4vi5i\";\nconst ModalHeader = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n margin-bottom: 24px;\n`;\nconst ModalHeaderLeft = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-start;\n`;\nconst IconContainer = styled.div`\n width: 40px;\n height: 40px;\n background: #f0f0f0;\n border-radius: 50%;\n display: flex;\n justify-content: center;\n align-items: center;\n margin-right: 16px;\n`;\nconst Icon = styled.svg`\n width: 20px;\n height: 20px;\n cursor: ${(props) => (props.cursor ? props.cursor : \"default\")};\n transition: 300ms ease-in-out;\n :hover {\n ${(props) => props.hover || \"\"}\n }\n`;\nconst ModalTitle = styled.div`\n font-color: #2e2e2e;\n font-size: 16px;\n font-weight: 600;\n`;\nconst ModalDescription = styled.p`\n font-color: #2e2e2e;\n font-size: 16px;\n font-weight: 400;\n`;\nconst Space = styled.div`\n height: ${(props) => props.height}px;\n`;\nconst MembersCount = styled.span`\n color: #2e2e2e;\n font-weight: 600;\n`;\nconst MembersText = styled.div`\n color: #7b7b7b;\n font-size: 12px;\n font-weight: 400;\n`;\nreturn (\n <Widget\n src={\"old.potlock.near/widget/Components.Modal\"}\n props={{\n isModalOpen,\n onClose,\n children: (\n <>\n <ModalHeader>\n <ModalHeaderLeft>\n <IconContainer>\n <Icon\n viewBox=\"0 0 24 12\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M16.24 7.65C15.07 7.13 13.63 6.75 12 6.75C10.37 6.75 8.93 7.14 7.76 7.65C6.68 8.13 6 9.21 6 10.39V12H18V10.39C18 9.21 17.32 8.13 16.24 7.65ZM8.07 10C8.16 9.77 8.34 9.58 8.56 9.48C9.66 8.99 10.82 8.75 11.99 8.75C13.17 8.75 14.32 9 15.42 9.48C15.65 9.58 15.82 9.77 15.91 10H8.07Z\"\n fill=\"#151A23\"\n />\n <path\n d=\"M1.22 8.58C0.48 8.9 0 9.62 0 10.43V12H4.5V10.39C4.5 9.56 4.73 8.78 5.13 8.1C4.76 8.04 4.39 8 4 8C3.01 8 2.07 8.21 1.22 8.58Z\"\n fill=\"#151A23\"\n />\n <path\n d=\"M22.78 8.58C21.93 8.21 20.99 8 20 8C19.61 8 19.24 8.04 18.87 8.1C19.27 8.78 19.5 9.56 19.5 10.39V12H24V10.43C24 9.62 23.52 8.9 22.78 8.58Z\"\n fill=\"#151A23\"\n />\n <path\n d=\"M12 6C13.66 6 15 4.66 15 3C15 1.34 13.66 0 12 0C10.34 0 9 1.34 9 3C9 4.66 10.34 6 12 6ZM12 2C12.55 2 13 2.45 13 3C13 3.55 12.55 4 12 4C11.45 4 11 3.55 11 3C11 2.45 11.45 2 12 2Z\"\n fill=\"#151A23\"\n />\n <path\n d=\"M3.9999 2.49687L1.49677 5L3.9999 7.50313L6.50303 5L3.9999 2.49687Z\"\n fill=\"#151A23\"\n />\n <path d=\"M20 3L17.5 7H22.5L20 3Z\" fill=\"#151A23\" />\n </Icon>\n </IconContainer>\n <ModalTitle>{titleText}</ModalTitle>\n </ModalHeaderLeft>\n <Icon\n cursor={\"pointer\"}\n hover={`\n rotate: 180deg;\n `}\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n onClick={onClose}\n >\n <path\n d=\"M14 1.41L12.59 0L7 5.59L1.41 0L0 1.41L5.59 7L0 12.59L1.41 14L7 8.41L12.59 14L14 12.59L8.41 7L14 1.41Z\"\n fill=\"#7B7B7B\"\n />\n </Icon>\n </ModalHeader>\n <ModalDescription>{descriptionText}</ModalDescription>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n placeholder: \"NEAR account ID\",\n value: inputValue,\n onChange: onInputChange,\n postInputChildren: (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: \"Add\",\n onClick: handleAddAccount,\n style: { borderRadius: `0px 4px 4px 0px` },\n submit: true,\n }}\n />\n ),\n handleKeyPress: (e) => {\n if (e.key === \"Enter\") {\n handleAddAccount();\n }\n },\n error: accountError,\n }}\n />\n <Space height={24} />\n <MembersText>\n <MembersCount>{accountIds.length} </MembersCount>\n {accountIds.length == 1 ? unitText : `${unitText}s`}\n </MembersText>\n <Widget\n src={\"old.potlock.near/widget/Components.AccountsList\"}\n props={{\n accountIds,\n allowRemove: true,\n handleRemoveAccount,\n }}\n />\n </>\n ),\n }}\n />\n);\n" }, "Cart.CartModalItem": { "": "const profile = Social.getr(`${props.projectId}/profile`);\nconst IPFS_BASE_URL = \"https://nftstorage.link/ipfs/\";\n// const TRASH_ICON_URL =\n// IPFS_BASE_URL + \"bafkreifuvrxly3wuy4xdmavmdeb2o47nv6pzxwz3xmy6zvkxv76e55lj3y\";\nconst TrashContainer = styled.div`\n position: absolute;\n top: 0;\n right: 0;\n width: 32px;\n height: 32px;\n opacity: 0;\n transition: opacity 0.3s ease;\n display: flex;\n align-items: flex-start;\n justify-content: flex-end;\n cursor: pointer;\n`;\nconst TrashIcon = styled.svg`\n width: 20px;\n height: 20px;\n path {\n transition: 300ms;\n }\n :hover path {\n fill: #dd3345;\n }\n`;\nconst ItemContainer = styled.div`\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n justify-content: center;\n padding: 24px;\n border-bottom: 1px #dbdbdb solid;\n &:hover ${TrashContainer} {\n opacity: 1;\n }\n`;\nconst ProjectDetails = styled.div`\n display: flex;\n flex-direction: column;\n position: relative;\n`;\nconst Text = styled.div`\n color: #2e2e2e;\n font-size: 16px;\n line-height: 24px;\n word-wrap: break-word;\n max-width: 270px;\n`;\nconst MAX_DESCRIPTION_LENGTH = 120;\nif (!profile) return \"\";\nreturn (\n <ItemContainer>\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{\n accountId: props.projectId,\n style: {\n width: \"40px\",\n height: \"40px\",\n border: \"none\",\n marginRight: \"24px\",\n },\n className: \"mb-2\",\n imageClassName: \"rounded-circle w-100 h-100 d-block\",\n thumbnail: false,\n }}\n />\n <ProjectDetails>\n <Text style={{ fontWeight: 600 }}>{profile.name}</Text>\n <Text>\n {profile.description.length > MAX_DESCRIPTION_LENGTH\n ? profile.description.slice(0, MAX_DESCRIPTION_LENGTH) + \"...\"\n : profile.description}\n </Text>\n <TrashContainer\n onClick={() => props.removeProjectsFromCart([props.projectId])}\n >\n <TrashIcon\n viewBox=\"0 0 12 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M2.5 14C2.0875 14 1.73437 13.8531 1.44062 13.5594C1.14687 13.2656 1 12.9125 1 12.5V2.5H0V1H4V0H8V1H12V2.5H11V12.491C11 12.9137 10.8531 13.2708 10.5594 13.5625C10.2656 13.8542 9.9125 14 9.5 14H2.5ZM9.5 2.5H2.5V12.5H9.5V2.5ZM4 11H5.5V4H4V11ZM6.5 11H8V4H6.5V11Z\"\n fill=\"#7B7B7B\"\n />\n </TrashIcon>\n </TrashContainer>\n </ProjectDetails>\n </ItemContainer>\n);\n" }, "Pots.Donations": { "": "// get donations\nconst {\n potId,\n allDonations,\n potDetail: { base_currency },\n} = props;\nconst { SUPPORTED_FTS } = VM.require(\"old.potlock.near/widget/constants\") || {\n SUPPORTED_FTS: {},\n};\nconst { getTimePassed, _address } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n) || {\n getTimePassed: () => \"\",\n _address: (address) => address,\n};\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getPublicRoundDonations: () => {},\n};\nState.init({\n filteredDonations: [],\n currentFilter: \"date\",\n filter: {\n date: false, // false === ascending\n price: false, // false === ascending\n },\n});\nconst { filteredDonations, currentFilter, filter } = state;\nuseEffect(() => {\n if (allDonations && filteredDonations.length === 0) {\n const sortedDonations = [...allDonations].reverse();\n State.update({ filteredDonations: sortedDonations });\n }\n}, [allDonations]);\nif (!allDonations)\n return <div class=\"spinner-border text-secondary\" role=\"status\" />;\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n @media screen and (min-width: 375px) and (max-width: 768px) {\n width: 99%;\n }\n @media screen and (max-width: 390px) {\n width: 98%;\n }\n`;\nconst OuterTextContainer = styled.div`\n display: flex;\n flex-direction: row;\n gap: 1.5rem;\n align-items: center;\n @media screen and (max-width: 768px) {\n padding-right: 10px;\n }\n`;\nconst OuterText = styled.div`\n font-size: 18px;\n font-weight: 600;\n`;\nconst DonationsCount = styled.div`\n font-size: 16px;\n`;\nconst TableContainer = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n border: 0.5px rgba(41, 41, 41, 0.5) solid;\n box-shadow: 0px 4px 12px -4px rgba(82, 82, 82, 0.2);\n border-radius: 2px;\n width: 100%;\n overflow-x: auto;\n flex-wrap: nowrap;\n`;\nconst Sort = styled.div`\n display: none;\n justify-content: space-between;\n width: 100%;\n margin-top: 1.5rem;\n div {\n display: flex;\n align-items: center;\n font-weight: 500;\n cursor: pointer;\n gap: 8px;\n color: #7b7b7b;\n &.active {\n color: #292929;\n }\n svg {\n transition: rotate 300ms;\n }\n }\n @media screen and (max-width: 768px) {\n display: flex;\n }\n`;\nconst Arrow = (props) => (\n <svg\n {...props}\n style={{ rotate: !props.active ? \"0deg\" : \"180deg\" }}\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M0 6L1.0575 7.0575L5.25 2.8725V12H6.75V2.8725L10.935 7.065L12 6L6 0L0 6Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n);\nconst searchDonations = (searchTerm) => {\n // filter donations that match the search term (donor_id, project_id)\n const filteredDonations = allDonations.filter((donation) => {\n const { donor_id, project_id } = donation;\n const searchFields = [donor_id, project_id];\n return searchFields.some((field) =>\n field.toLowerCase().includes(searchTerm.toLowerCase())\n );\n });\n return filteredDonations;\n};\nconst sortDonation = (type) => {\n const sort = !filter[type];\n State.update({ currentFilter: type, filter: { ...filter, [type]: sort } });\n if (type === \"price\") {\n const sortedDonations = filteredDonations.sort((a, b) =>\n sort ? b.total_amount - a.total_amount : a.total_amount - b.total_amount\n );\n State.update({ filteredDonations: sortedDonations });\n } else if (type === \"date\") {\n const sortedDonations = filteredDonations.sort((a, b) => {\n return sort ? b.donated_at - a.donated_at : a.donated_at - b.donated_at;\n });\n State.update({ filteredDonations: sortedDonations });\n }\n};\nconst handleSearch = ({ target: { value } }) => {\n const filteredDonations = searchDonations(value);\n State.update({ filteredDonations });\n};\nconst ProfileImg = (address) => (\n <Widget\n src={\"old.potlock.near/widget/Project.ProfileImage\"}\n props={{\n ...props,\n accountId: address,\n style: {},\n }}\n />\n);\nreturn (\n <Container>\n <OuterTextContainer>\n <OuterText>All donations</OuterText>\n <DonationsCount>{allDonations.length}</DonationsCount>\n </OuterTextContainer>\n <Sort>\n <div\n className={`${currentFilter === \"date\" ? \"active\" : \"\"}`}\n onClick={() => sortDonation(\"date\")}\n >\n Sort Date {currentFilter === \"date\" && <Arrow active={!filter.date} />}\n </div>\n <div\n onClick={() => sortDonation(\"price\")}\n className={`${currentFilter === \"price\" ? \"active\" : \"\"}`}\n >\n Sort Amount{\" \"}\n {currentFilter === \"price\" && <Arrow active={filter.price} />}\n </div>\n </Sort>\n <Widget\n src={\"old.potlock.near/widget/Pots.DonationsTable\"}\n props={{\n ...props,\n filteredDonations,\n filter,\n currentFilter,\n handleSearch,\n sortDonation,\n }}\n />\n </Container>\n);\n" }, "Pots.PayoutsChallenges": { "": "const { potId, hrefWithParams } = props;\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getPayoutsChallenges: () => {},\n adminUpdatePayoutsChallenge: () => {},\n isUserPotAdminOrGreater: () => false,\n};\nconst { getTimePassed } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n) || {\n getTimePassed: () => \"\",\n};\nconst payoutsChallenges = PotSDK.getPayoutsChallenges(potId); // TODO: ADD THIS BACK IN\nconst userIsAdminOrGreater = PotSDK.isUserPotAdminOrGreater(\n potId,\n context.accountId\n); // TODO: ADD THIS BACK IN\nState.init({\n adminModalChallengerId: \"\",\n challengeAdminNotes: \"\",\n challengeAdminNotesError: \"\",\n resolveChallenge: false,\n toggleChallenges: false,\n});\nconst {\n adminModalChallengerId,\n challengeAdminNotes,\n challengeAdminNotesError,\n resolveChallenge,\n toggleChallenges,\n} = state;\nconst MAX_CHALLENGE_TEXT_LENGTH = 1000;\nconst handleAdminUpdateChallenge = () => {\n PotSDK.adminUpdatePayoutsChallenge(\n potId,\n adminModalChallengerId,\n challengeAdminNotes,\n resolveChallenge\n );\n State.update({\n adminModalChallengerId: \"\",\n challengeAdminNotes: \"\",\n challengeAdminNotesError: \"\",\n resolveChallenge: false,\n });\n};\nconst handleCancelAdminUpdateChallenge = () => {\n State.update({\n adminModalChallengerId: \"\",\n challengeAdminNotes: \"\",\n challengeAdminNotesError: \"\",\n resolveChallenge: false,\n });\n};\nconst Line = styled.div`\n width: 100%;\n height: 1px;\n background: #c7c7c7;\n margin: 3rem 0;\n`;\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n`;\nconst Title = styled.div`\n font-size: 18px;\n display: flex;\n align-items: center;\n gap: 1.5rem;\n width: fit-content;\n cursor: pointer;\n margin-bottom: 1.5rem;\n div:first-of-type {\n font-weight: 600;\n }\n svg {\n rotate: 180deg;\n transition: all 300ms ease-in-out;\n }\n`;\nconst Table = styled.div`\n display: flex;\n flex-direction: column;\n width: 100%;\n border-radius: 6px;\n border: 1px solid #7b7b7b;\n transition: max-height 400ms ease-in-out;\n overflow: hidden;\n max-height: 1000px;\n opacity: 1;\n &.hidden {\n opacity: 0;\n max-height: 0;\n }\n`;\nconst Challenge = styled.div`\n display: flex;\n padding: 1rem;\n border-bottom: 1px solid #c7c7c7;\n font-size: 14px;\n &:last-of-type {\n border-bottom: none;\n }\n .vertical-line {\n height: 100%;\n background: #c7c7c7;\n width: 1px;\n transform: translateX(0.75rem);\n z-index: -1;\n }\n .profile-image {\n width: 1.5rem;\n height: 1.5rem;\n margin-right: 0.5rem;\n }\n .admin-icon {\n margin-right: 0.75rem;\n svg {\n width: 1.5rem;\n height: 1.5rem;\n }\n }\n .content {\n display: flex;\n flex-direction: column;\n }\n .header {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.5rem;\n }\n .id {\n font-weight: 600;\n color: #292929;\n transition: 200ms;\n :hover {\n text-decoration: none;\n color: #dd3345;\n }\n }\n .title {\n font-weight: 600;\n color: #8b5af8;\n }\n .reason {\n color: #7b7b7b;\n margin-top: 0.5rem;\n margin-bottom: 1rem;\n padding-left: 2.5rem;\n background: white;\n }\n .admin-header {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n }\n .dot {\n background: #7b7b7b;\n width: 5px;\n height: 5px;\n border-radius: 50%;\n }\n .resolved-state {\n font-weight: 600;\n }\n .resolve-btn {\n cursor: pointer;\n background: none;\n border: none;\n }\n @media only screen and (max-width: 480px) {\n .profile-image {\n margin-right: 0;\n }\n .admin-icon {\n margin-right: 0.25rem;\n }\n .reason {\n padding-left: 2rem;\n }\n .date {\n width: 100%;\n margin-top: -0.5rem;\n padding-left: 2rem;\n }\n }\n`;\nconst ModalHeader = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-start;\n background: white;\n padding: 24px 24px 12px 24px;\n border-top-left-radius: 6px;\n border-top-right-radius: 6px;\n font-weight: 500;\n`;\nconst ModalBody = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n padding: 24px;\n border-top: 1px #f0f0f0 solid;\n background: #fafafa;\n gap: 8px;\n`;\nconst ModalFooter = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-end;\n background: #fafafa;\n padding: 12px 24px 24px 24px;\n border-bottom-left-radius: 6px;\n border-bottom-right-radius: 6px;\n gap: 24px;\n width: 100%;\n`;\nconst HeaderItemText = styled.div`\n color: #292929;\n font-size: 14px;\n font-weight: 600;\n line-height: 24px;\n word-wrap: break-word;\n`;\nconst AdminSVG = () => (\n <div className=\"admin-icon\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <mask id=\"path-1-inside-1_10044_14103\" fill=\"white\">\n <path d=\"M0 12C0 5.37258 5.37258 0 12 0C18.6274 0 24 5.37258 24 12C24 18.6274 18.6274 24 12 24C5.37258 24 0 18.6274 0 12Z\" />\n </mask>\n <path\n d=\"M0 12C0 5.37258 5.37258 0 12 0C18.6274 0 24 5.37258 24 12C24 18.6274 18.6274 24 12 24C5.37258 24 0 18.6274 0 12Z\"\n fill=\"#656565\"\n />\n <path\n d=\"M-0.666667 12C-0.666667 5.00439 5.00439 -0.666667 12 -0.666667C18.9956 -0.666667 24.6667 5.00439 24.6667 12H23.3333C23.3333 5.74077 18.2592 0.666667 12 0.666667C5.74077 0.666667 0.666667 5.74077 0.666667 12H-0.666667ZM24.6667 12.6667C24.6667 19.6623 18.9956 25.3333 12 25.3333C5.00439 25.3333 -0.666667 19.6623 -0.666667 12.6667L0.666667 12C0.666667 17.891 5.74077 22.6667 12 22.6667C18.2592 22.6667 23.3333 17.891 23.3333 12L24.6667 12.6667ZM12 25.3333C5.00439 25.3333 -0.666667 19.6623 -0.666667 12.6667V12C-0.666667 5.00439 5.00439 -0.666667 12 -0.666667V0.666667C5.74077 0.666667 0.666667 5.74077 0.666667 12C0.666667 17.891 5.74077 22.6667 12 22.6667V25.3333ZM12 -0.666667C18.9956 -0.666667 24.6667 5.00439 24.6667 12V12.6667C24.6667 19.6623 18.9956 25.3333 12 25.3333V22.6667C18.2592 22.6667 23.3333 17.891 23.3333 12C23.3333 5.74077 18.2592 0.666667 12 0.666667V-0.666667Z\"\n fill=\"#292929\"\n mask=\"url(#path-1-inside-1_10044_14103)\"\n />\n <path\n d=\"M9.20029 12.7527L11.087 10.866L6.40695 6.19268C5.36695 7.23268 5.36695 8.91935 6.40695 9.96601L9.20029 12.7527ZM13.7203 11.546C14.7403 12.0193 16.1736 11.686 17.2336 10.626C18.507 9.35268 18.7536 7.52601 17.7736 6.54601C16.8003 5.57268 14.9736 5.81268 13.6936 7.08601C12.6336 8.14601 12.3003 9.57935 12.7736 10.5993L6.26695 17.106L7.20695 18.046L11.8003 13.466L16.387 18.0527L17.327 17.1127L12.7403 12.526L13.7203 11.546Z\"\n fill=\"white\"\n />\n </svg>\n </div>\n);\nconst ProfileImg = ({ address }) => (\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{ accountId: address, style: {} }}\n />\n);\nconsole.log(\"payoutsChallenges\", payoutsChallenges);\nreturn !payoutsChallenges ? (\n \"Loading...\"\n) : payoutsChallenges.length === 0 ? (\n \"\"\n) : (\n <>\n <Container>\n <Title\n onClick={() =>\n State.update({\n toggleChallenges: !toggleChallenges,\n })\n }\n >\n <div>Payout Challenges</div>\n <div>{payoutsChallenges?.length}</div>\n <svg\n width=\"12\"\n height=\"8\"\n viewBox=\"0 0 12 8\"\n style={{\n rotate: toggleChallenges ? \"0deg\" : \"180deg\",\n }}\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 0.294922L0 6.29492L1.41 7.70492L6 3.12492L10.59 7.70492L12 6.29492L6 0.294922Z\"\n fill=\"#151A23\"\n />\n </svg>\n </Title>\n <Table className={`${!toggleChallenges ? \"hidden\" : \"\"}`}>\n {payoutsChallenges.map(\n ({ challenger_id, admin_notes, created_at, reason, resolved }) => (\n <Challenge key={challenger_id}>\n {/* <div className=\"vertical-line\" /> */}\n <div className=\"content\">\n <div className=\"header\">\n <ProfileImg address={challenger_id} />\n <a\n className=\"id\"\n href={hrefWithParams(\n `?tab=profile&accountId=${challenger_id}`\n )}\n >\n {challenger_id}\n </a>\n <div className=\"title\">Challenged payout</div>\n <div className=\"date\"> {getTimePassed(created_at)}</div>\n </div>\n <div className=\"reason\">{reason}</div>\n <div className=\"admin-header\">\n <AdminSVG />\n <div\n className=\"resolved-state\"\n style={{\n color: resolved ? \"#4a7714\" : \"#C7C7C7\",\n }}\n >\n {resolved ? \"Resolved\" : \"Unresolved\"}\n </div>\n {resolved ? (\n <>\n <div className=\"dot\" />\n <div>1 Response</div>\n </>\n ) : userIsAdminOrGreater ? (\n <>\n <div className=\"dot\" />\n <button\n className=\"resolve-btn\"\n onClick={() =>\n State.update({\n adminModalChallengerId: challenger_id,\n })\n }\n >\n Reply\n </button>\n </>\n ) : (\n \"\"\n )}\n </div>\n <div className=\"reason\">{admin_notes}</div>\n </div>\n </Challenge>\n )\n )}\n </Table>\n {/* Admin update challenge modal */}\n <Widget\n src={\"old.potlock.near/widget/Components.Modal\"}\n props={{\n isModalOpen: adminModalChallengerId,\n onClose: handleCancelAdminUpdateChallenge,\n contentStyle: {\n padding: \"0px\",\n },\n children: (\n <>\n <ModalHeader>\n Update Challenge from {adminModalChallengerId}\n </ModalHeader>\n <ModalBody>\n <HeaderItemText>Challenge Reason:</HeaderItemText>\n <div>\n {\n payoutsChallenges.find(\n (challenge) =>\n challenge.challenger_id === adminModalChallengerId\n ).reason\n }\n </div>\n <Widget\n src={\"old.potlock.near/widget/Inputs.TextArea\"}\n props={{\n noLabel: true,\n inputRows: 5,\n inputStyle: {\n background: \"#FAFAFA\",\n },\n placeholder: \"Respond to the challenge here\",\n value: challengeAdminNotes,\n onChange: (challengeAdminNotes) =>\n State.update({ challengeAdminNotes }),\n validate: () => {\n if (\n challengeAdminNotes.length > MAX_CHALLENGE_TEXT_LENGTH\n ) {\n State.update({\n challengeAdminNotesError: `Notes must be less than ${MAX_CHALLENGE_TEXT_LENGTH} characters`,\n });\n return;\n }\n State.update({ challengeAdminNotesError: \"\" });\n },\n error: challengeAdminNotesError,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Inputs.Checkbox\"}\n props={{\n // id: \"registrationSelector\",\n label: \"Resolve this challenge?\",\n checked: resolveChallenge,\n onClick: (e) => {\n State.update({\n resolveChallenge: e.target.checked,\n });\n },\n }}\n />\n </ModalBody>\n <ModalFooter>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"tertiary\",\n text: \"Cancel\",\n onClick: handleCancelAdminUpdateChallenge,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: \"Submit\",\n disabled:\n !challengeAdminNotes || !!challengeAdminNotesError,\n onClick: handleAdminUpdateChallenge,\n }}\n />\n </ModalFooter>\n </>\n ),\n }}\n />\n </Container>\n <Line />\n </>\n);\n" }, "Cart.NavItem": { "": "const { getCartItemCount } = VM.require(\"old.potlock.near/widget/SDK.cart\") ?? {\n getCartItemCount: () => 0,\n};\nconst { CartModal } = VM.require(\"old.potlock.near/widget/Cart.Modal\") ?? {\n CartModal: () => <></>,\n};\nconst navHeightPx = 110;\nconst navHeightPxMobile = 96;\nconst numCartItems = getCartItemCount();\nconst CartButton = styled.div`\n padding: ${numCartItems > 0 ? \"8px 8px 8px 16px\" : \"8px 16px\"};\n background: #2e2e2e;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n`;\nconst CartText = styled.div`\n color: white;\n font-size: 14px;\n font-weight: 600;\n line-height: 20px;\n word-wrap: break-word;\n text-align: center;\n`;\nconst CartCountContainer = styled.div`\n display: flex;\n flex-direction: row;\n justify-content: center;\n align-items: center;\n background: #f86b3f;\n border-radius: 50%;\n // padding: 0 4px;\n width: 18px;\n height: 18px;\n margin-left: 8px;\n`;\nreturn (\n <CartModal\n Trigger={({ openModal }) => (\n <CartButton onClick={() => openModal()}>\n <CartText>Cart</CartText>\n {numCartItems > 0 && (\n <CartCountContainer>\n <CartText style={{ fontSize: \"12px\" }}>{numCartItems}</CartText>\n </CartCountContainer>\n )}\n </CartButton>\n )}\n />\n);\n" }, "Pots.UNUSED.ModalSybil": { "": "const { isModalOpen, onClose } = props;\nconst { NADA_BOT_URL } = VM.require(\"old.potlock.near/widget/constants\") || {\n NADA_BOT_URL: \"\",\n};\nconst IPFS_BASE_URL = \"https://nftstorage.link/ipfs/\";\nconst CLOSE_ICON_URL =\n IPFS_BASE_URL + \"bafkreifyg2vvmdjpbhkylnhye5es3vgpsivhigkjvtv2o4pzsae2z4vi5i\";\nconst ERROR_ICON_URL =\n IPFS_BASE_URL + \"bafkreicqarojxk6jhdtsk2scfsmnigqpxjfgar6om4wlhn5xmqbbu74u5i\";\nconst IMAGE_URL =\n IPFS_BASE_URL + \"bafkreidwashbfmlr7qo2yoqcfdsqi4ouisgt6h6jwxymz53v2f7hhoy75a\";\nconst ModalHeader = styled.div`\n width: 100%;\n padding: 10px 20px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n background: #f6f5f3;\n`;\nconst ModalHeaderText = styled.div`\n font-size: 17px;\n font-weight: 600;\n line-height: 24px;\n color: #292929;\n`;\nconst Icon = styled.img`\n width: 24px;\n height: 24px;\n`;\nconst ModalContent = styled.div`\n padding: 16px 20px 32px 20px;\n display: flex;\n flex-direction: column;\n gap: 24px;\n align-items: center;\n justify-content: center;\n`;\nconst Row = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n`;\nconst ContentHeaderText = styled.div`\n margin-left: 24px;\n font-size: 32px;\n font-weight: 400;\n line-height: 40px;\n color: #525252;\n font-family: \"Lora\";\n`;\nconst ContentDescriptionText = styled.div`\n font-size: 16px;\n font-weight: 400;\n line-height: 28px;\n`;\nconst ErrorSpan = styled.span`\n color: #dd3345;\n`;\nconst BoldSpan = styled.span`\n font-weight: 600;\n`;\nconst Image = styled.img`\n width: 100px;\n max-height: 245px;\n margin: 0px 32px;\n`;\nreturn (\n <Widget\n src={\"old.potlock.near/widget/Components.Modal\"}\n props={{\n ...props,\n isModalOpen,\n onClose,\n children: (\n <>\n <ModalHeader>\n <div></div>\n <ModalHeaderText>Verify Via Nada.bot</ModalHeaderText>\n <Icon cursor={\"pointer\"} src={CLOSE_ICON_URL} onClick={onClose} />\n </ModalHeader>\n <ModalContent>\n <Row>\n <Icon\n style={{ width: \"35px\", height: \"35px\" }}\n src={ERROR_ICON_URL}\n />\n <ContentHeaderText>\n You Are <ErrorSpan>Not verified</ErrorSpan>\n </ContentHeaderText>\n </Row>\n <Row>\n <ContentDescriptionText>\n To donate to a project via this pot, you need to get verified\n from <BoldSpan>Nada.bot</BoldSpan>\n </ContentDescriptionText>\n </Row>\n <Image src={IMAGE_URL} />\n <Row style={{ alignItems: \"flex-end\" }}>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n href: NADA_BOT_URL,\n target: \"_blank\",\n type: \"primary\",\n text: \"Get Verified Now\",\n // style: {\n // width: \"300px\",\n // },\n }}\n />\n </Row>\n </ModalContent>\n </>\n ),\n }}\n />\n);\n" }, "ModalDonation.Main": { "": "const Container = styled.div`\n display: flex;\n flex-direction: column;\n border-radius: 12px;\n background: #fff;\n font-size: 14px;\n box-shadow: 0px 0px 0px 1px rgba(41, 41, 41, 0.1),\n 0px 8px 12px -4px rgba(41, 41, 41, 0.1),\n 0px 20px 32px -10px rgba(41, 41, 41, 0.1),\n 0px 32px 44px -16px rgba(41, 41, 41, 0.1);\n overflow: hidden;\n border-radius: 6px;\n @media only screen and (max-width: 480px) {\n top: 0;\n border-radius: 0;\n position: fixed;\n left: 0;\n width: 100vw;\n height: 100vh;\n overflow-y: scroll;\n display: flex;\n z-index: 1000;\n }\n`;\nconst Banner = styled.div`\n position: relative;\n display: flex;\n flex-direction: column;\n padding: 1.5rem 2rem;\n gap: 0.5rem;\n overflow: hidden;\n background: #dd3345;\n color: white;\n font-size: 22px;\n .left-pattern {\n position: absolute;\n left: 0;\n top: 0;\n width: 30%;\n transform: translate(-10%, -10%) scaleX(-1);\n pointer-events: none;\n }\n .right-pattern {\n position: absolute;\n right: 0;\n top: 0;\n width: 30%;\n transform: translate(10%, -10%);\n pointer-events: none;\n }\n @media only screen and (max-width: 480px) {\n padding: 1.125rem;\n }\n`;\nconst BannerBg = (props) => (\n <svg\n {...props}\n viewBox=\"0 0 145 152\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <rect\n x=\"157.654\"\n y=\"-37\"\n width=\"20\"\n height=\"161.118\"\n rx=\"10\"\n transform=\"rotate(45 157.654 -37)\"\n fill=\"white\"\n fill-opacity=\"0.08\"\n />\n <rect\n x=\"189.654\"\n y=\"-37\"\n width=\"20\"\n height=\"245.972\"\n rx=\"10\"\n transform=\"rotate(45 189.654 -37)\"\n fill=\"white\"\n fill-opacity=\"0.08\"\n />\n <rect\n x=\"221.654\"\n y=\"-37\"\n width=\"20\"\n height=\"164.654\"\n rx=\"10\"\n transform=\"rotate(45 221.654 -37)\"\n fill=\"white\"\n fill-opacity=\"0.08\"\n />\n <rect\n x=\"125.654\"\n y=\"-37\"\n width=\"20\"\n height=\"177.702\"\n rx=\"10\"\n transform=\"rotate(45 125.654 -37)\"\n fill=\"white\"\n fill-opacity=\"0.08\"\n />\n <rect\n x=\"93.6543\"\n y=\"-37\"\n width=\"20\"\n height=\"78.4889\"\n rx=\"10\"\n transform=\"rotate(45 93.6543 -37)\"\n fill=\"white\"\n fill-opacity=\"0.08\"\n />\n </svg>\n);\nconst HeaderIcons = styled.div`\n display: flex;\n align-items: center;\n justify-content: space-between;\n svg {\n width: 14px;\n cursor: pointer;\n transition: all 300ms ease-in-out;\n }\n .close-icon {\n margin-left: auto;\n &:hover {\n rotate: 90deg;\n }\n }\n div {\n cursor: pointer;\n display: flex;\n }\n .back-arrow:hover svg {\n transform: translateX(-10px);\n }\n`;\nconst DENOMINATION_OPTIONS = [{ text: \"NEAR\", value: \"NEAR\", decimals: 24 }];\nconst {\n projectId,\n referrerId,\n potId,\n onClose,\n NADABOT_CONTRACT_ID,\n POT,\n multiple,\n potDetail,\n} = props;\nconst DEFAULT_DONATION_AMOUNT = \"1\";\nconst accountId = context.accountId;\nconst initialState = {\n amount: \"\",\n donationType: multiple ? \"auto\" : \"direct\",\n showBreakdown: false,\n bypassProtocolFee: false,\n bypassChefFee: false,\n addNote: false,\n donationNote: \"\",\n donationNoteError: \"\",\n allPots: null,\n intervalId: null,\n ftBalances: null,\n selectedDenomination: DENOMINATION_OPTIONS[0],\n denominationOptions: DENOMINATION_OPTIONS,\n selectedRound: \"\",\n currentPage: multiple ? \"formPot\" : \"form\",\n selectedProjects: {},\n toggleAmount: true,\n};\nState.init(initialState);\nconst {\n amount,\n denomination,\n donationType,\n showBreakdownm,\n bypassProtocolFee,\n bypassChefFee,\n addNote,\n donationNote,\n donationNoteError,\n allPots,\n intervalId,\n nearBalance,\n ftBalances,\n denominationOptions,\n selectedDenomination,\n selectedRound,\n currentPage,\n} = state;\nconst [activeRounds, setActiveRounds] = useState(null);\nconst profile = Social.getr(`${projectId}/profile`);\nconst profileName = profile?.name || projectId;\nconst MAX_NOTE_LENGTH = 60;\nconst {\n DONATION_CONTRACT_ID,\n NADABOT_HUMAN_METHOD,\n NADA_BOT_URL,\n SUPPORTED_FTS,\n} = VM.require(\"old.potlock.near/widget/constants\") || {\n DONATION_CONTRACT_ID: \"\",\n NADABOT_HUMAN_METHOD: \"\",\n NADA_BOT_URL: \"\",\n SUPPORTED_FTS: {},\n};\nlet ListsSDK =\n VM.require(\"old.potlock.near/widget/SDK.lists\") ||\n (() => ({\n getRegistrations: () => {},\n }));\nListsSDK = ListsSDK({ env: props.env });\nlet DonateSDK =\n VM.require(\"old.potlock.near/widget/SDK.donate\") ||\n (() => ({\n getConfig: () => {},\n asyncGetDonationsForDonor: () => {},\n }));\nDonateSDK = DonateSDK({ env: props.env });\nlet PotFactorySDK =\n VM.require(\"old.potlock.near/widget/SDK.potfactory\") ||\n (() => ({\n getPots: () => {},\n }));\nPotFactorySDK = PotFactorySDK({ env: props.env });\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getConfig: () => {},\n asyncGetConfig: () => {},\n getApprovedApplications: () => {},\n asyncGetApplicationByProjectId: () => {},\n asyncGetDonationsForDonor: () => {},\n isRoundActive: () => {},\n};\nconst { nearToUsd, formatWithCommas } = VM.require(\n \"old.potlock.near/widget/utils\"\n) || {\n nearToUsd: 1,\n formatWithCommas: () => {},\n};\nconst { addItemsToCart, clearCart } = VM.require(\n \"old.potlock.near/widget/SDK.cart\"\n) || {\n addItemsToCart: () => {},\n clearCart: () => {},\n};\nconst { FormDirect } = VM.require(\n \"old.potlock.near/widget/ModalDonation.Form\"\n) || {\n FormDirect: () => {},\n};\nconst { FormPot } = VM.require(\n \"old.potlock.near/widget/ModalDonation.FormPot\"\n) || {\n FormPot: () => {},\n};\nconst { ConfirmDirect } = VM.require(\n \"old.potlock.near/widget/ModalDonation.ConfirmDirect\"\n) || {\n ConfirmDirect: () => {},\n};\nconst { ConfirmPot } = VM.require(\n \"old.potlock.near/widget/ModalDonation.ConfirmPot\"\n) || {\n ConfirmPot: () => {},\n};\nconst pages = {\n form: FormDirect,\n formPot: FormPot,\n confirm: ConfirmDirect,\n confirmPot: ConfirmPot,\n};\nconst ActivePageComponent = pages[currentPage];\n// get all active pots\nconst pots = useCache(\n () =>\n // get all pots\n PotFactorySDK.asyncGetPots()\n .then((pots) => {\n const activePots = pots.map((pot) =>\n // if active\n PotSDK.isRoundActive(pot.id)\n // check if project had applied\n .then((isActive) => isActive && pot.id)\n .catch((e) => {\n console.error(\n \"error checking active round for pot: \" + pot.id,\n e\n );\n })\n );\n return Promise.all(activePots);\n })\n .catch((e) => {\n console.error(\"error getting pots: \", e);\n }),\n \"active-pots\"\n);\nuseEffect(() => {\n if (potId && !activeRounds) {\n setActiveRounds([potId]);\n State.update({\n selectedRound: potId,\n donationType: multiple ? \"auto\" : \"pot\",\n });\n } else if (!activeRounds?.length && projectId) {\n if (!pots) setActiveRounds([]);\n (pots ?? []).forEach((pot, idx) => {\n if (pot) {\n PotSDK.asyncGetApplicationByProjectId(pot, projectId)\n .then((application) => {\n if (application.status === \"Approved\") {\n setActiveRounds((prev) => {\n const prevRounds = prev || [];\n if (!prevRounds.includes(pot)) {\n return [...prevRounds, pot];\n }\n });\n if (!selectedRound)\n State.update({\n selectedRound: pot,\n });\n } else if (pots.length - 1 === idx && !activeRounds) {\n setActiveRounds((prev) => [...(prev || [])]);\n }\n })\n .catch((err) => {\n console.log(err);\n setActiveRounds((prev) => [...(prev || [])]);\n });\n }\n });\n }\n}, [pots]);\n// Get Ft Balances\nuseEffect(() => {\n if (!ftBalances && !potId) {\n asyncFetch(\n `https://near-mainnet.api.pagoda.co/eapi/v1/accounts/${accountId}/balances/FT`,\n {\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": \"dce81322-81b0-491d-8880-9cfef4c2b3c2\",\n },\n }\n )\n .then((ftBalancesRes) => {\n if (ftBalancesRes) {\n const ftBalances = ftBalancesRes.body.balances;\n State.update({\n ftBalances: ftBalances,\n denominationOptions: DENOMINATION_OPTIONS.concat(\n ftBalances\n .map(({ amount, contract_account_id, metadata }) => ({\n amount,\n id: contract_account_id,\n text: metadata.symbol,\n value: metadata.symbol,\n icon: metadata.icon,\n decimals: metadata.decimals,\n }))\n .filter((option) => option.text.length < 10)\n ),\n });\n }\n })\n .catch((err) => console.log(\"fetching Ft balances faild\"));\n }\n}, [ftBalances]);\nconst nearBalanceRes = fetch(\n `https://near-mainnet.api.pagoda.co/eapi/v1/accounts/${accountId}/balances/NEAR`,\n {\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": \"dce81322-81b0-491d-8880-9cfef4c2b3c2\",\n },\n }\n);\nconst ftBalance = useMemo(() => {\n if (selectedDenomination.text === \"NEAR\") {\n const nearBalance = nearBalanceRes?.body?.balance;\n return nearBalance\n ? parseFloat(Big(nearBalance.amount).div(Big(10).pow(24)).toFixed(2))\n : null;\n }\n const balance = denominationOptions.find(\n // this is where we need the details\n (option) => option.text === selectedDenomination.text\n );\n return balance\n ? parseFloat(\n Big(balance.amount).div(Big(10).pow(balance.decimals)).toFixed(2)\n )\n : null;\n}, [selectedDenomination, ftBalances, nearBalanceRes]);\nreturn (\n <Widget\n src={\"old.potlock.near/widget/Components.Modal\"}\n props={{\n ...props,\n onClose: (e) => {\n e.stopPropagation();\n },\n contentStyle: {\n padding: \"0px\",\n },\n children: (\n <Container>\n <div>\n <Banner>\n <BannerBg className=\"left-pattern\" />\n <BannerBg className=\"right-pattern\" />\n <HeaderIcons>\n {![\"form\", \"formPot\"].includes(currentPage) && (\n <div\n className=\"back-arrow\"\n onClick={() =>\n State.update({\n currentPage: multiple ? \"formPot\" : \"form\",\n })\n }\n >\n <svg\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M16 7H3.83L9.42 1.41L8 0L0 8L8 16L9.41 14.59L3.83 9H16V7Z\"\n fill=\"#FCCFCF\"\n />\n </svg>\n </div>\n )}\n <svg\n onClick={() => onClose()}\n className=\"close-icon\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M14 1.41L12.59 0L7 5.59L1.41 0L0 1.41L5.59 7L0 12.59L1.41 14L7 8.41L12.59 14L14 12.59L8.41 7L14 1.41Z\"\n fill=\"#FCCFCF\"\n />\n </svg>\n </HeaderIcons>\n {[\"confirmPot\", \"confirm\"].includes(currentPage) ? (\n <div> Confirm donation</div>\n ) : currentPage === \"formPot\" ? (\n <div>Donate to Projects in {potDetail?.pot_name}</div>\n ) : (\n <div> Donate to {profileName}</div>\n )}\n </Banner>\n </div>\n <ActivePageComponent\n {...props}\n {...state}\n accountId={accountId}\n updateState={State.update}\n ftBalance={ftBalance}\n activeRounds={activeRounds}\n DENOMINATION_OPTION={DENOMINATION_OPTIONS}\n />\n </Container>\n ),\n }}\n />\n);\n" }, "Pots.FlagModal": { "": "const BannerBg = (props) => (\n <svg\n {...props}\n viewBox=\"0 0 145 152\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <rect\n x=\"157.654\"\n y=\"-37\"\n width=\"20\"\n height=\"161.118\"\n rx=\"10\"\n transform=\"rotate(45 157.654 -37)\"\n fill=\"white\"\n fill-opacity=\"0.08\"\n />\n <rect\n x=\"189.654\"\n y=\"-37\"\n width=\"20\"\n height=\"245.972\"\n rx=\"10\"\n transform=\"rotate(45 189.654 -37)\"\n fill=\"white\"\n fill-opacity=\"0.08\"\n />\n <rect\n x=\"221.654\"\n y=\"-37\"\n width=\"20\"\n height=\"164.654\"\n rx=\"10\"\n transform=\"rotate(45 221.654 -37)\"\n fill=\"white\"\n fill-opacity=\"0.08\"\n />\n <rect\n x=\"125.654\"\n y=\"-37\"\n width=\"20\"\n height=\"177.702\"\n rx=\"10\"\n transform=\"rotate(45 125.654 -37)\"\n fill=\"white\"\n fill-opacity=\"0.08\"\n />\n <rect\n x=\"93.6543\"\n y=\"-37\"\n width=\"20\"\n height=\"78.4889\"\n rx=\"10\"\n transform=\"rotate(45 93.6543 -37)\"\n fill=\"white\"\n fill-opacity=\"0.08\"\n />\n </svg>\n);\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n border-radius: 12px;\n background: #fff;\n font-size: 14px;\n box-shadow: 0px 0px 0px 1px rgba(41, 41, 41, 0.1),\n 0px 8px 12px -4px rgba(41, 41, 41, 0.1),\n 0px 20px 32px -10px rgba(41, 41, 41, 0.1),\n 0px 32px 44px -16px rgba(41, 41, 41, 0.1);\n overflow: hidden;\n border-radius: 6px;\n`;\nconst Banner = styled.div`\n position: relative;\n display: flex;\n flex-direction: column;\n padding: 1.5rem 2rem;\n gap: 0.5rem;\n overflow: hidden;\n background: #dd3345;\n color: white;\n font-size: 22px;\n .left-pattern {\n position: absolute;\n left: 0;\n top: 0;\n width: 30%;\n transform: translate(-10%, -10%) scaleX(-1);\n pointer-events: none;\n }\n .right-pattern {\n position: absolute;\n right: 0;\n top: 0;\n width: 30%;\n transform: translate(10%, -10%);\n pointer-events: none;\n }\n @media only screen and (max-width: 480px) {\n padding: 1.125rem;\n }\n`;\nconst HeaderIcons = styled.div`\n display: flex;\n align-items: center;\n justify-content: space-between;\n svg {\n width: 14px;\n cursor: pointer;\n transition: all 300ms ease-in-out;\n }\n .close-icon {\n margin-left: auto;\n &:hover {\n rotate: 90deg;\n }\n }\n div {\n cursor: pointer;\n display: flex;\n }\n`;\nconst Content = styled.div`\n display: flex;\n flex-direction: column;\n padding: 1.5rem 2rem;\n gap: 1.5rem;\n @media only screen and (max-width: 480px) {\n padding: 1.125rem;\n }\n`;\nconst Label = styled.div`\n font-weight: 500;\n margin-bottom: 0.5rem;\n`;\nconst Limit = styled.div`\n color: #7b7b7b;\n text-align: right;\n`;\nconst InfoCard = styled.div`\n display: flex;\n align-items: center;\n gap: 1rem;\n padding: 0.75rem 1rem;\n width: 100%;\n border-radius: 6px;\n border: 1px solid #ebebeb;\n background: #f6f5f3;\n`;\nconst ButtonsWrapper = styled.div`\n display: grid;\n gap: 1.5rem;\n grid-template-columns: repeat(2, 1fr);\n button {\n font-weight: 500;\n }\n .cancel {\n border: none;\n background: none;\n color: #dd3345;\n }\n`;\nconst MAX_REASON_LENGTH = 250;\nconst accountId = context.accountId;\nconst [reason, setReason] = useState(\"\");\nconst [reasonErr, setReasonErr] = useState(\"\");\nconst { onClose, flagAddress, potId, setSuccessFlag } = props;\nconst onCancel = () => {\n onClose();\n setReason(\"\");\n};\nconst fetchSocialProfile = () => {\n return Near.asyncView(\"social.near\", \"get\", {\n keys: [`${accountId}/profile/**`],\n });\n};\nconst handleSuccess = () => {\n const flsgSuccess = setInterval(() => {\n fetchSocialProfile().then((profileData) => {\n const profile = profileData[accountId].profile;\n const pLBlacklistedAccounts = JSON.parse(\n profile.pLBlacklistedAccounts || \"{}\"\n );\n const potFlaggedAcc = pLBlacklistedAccounts[potId] || {};\n if (potFlaggedAcc[flagAddress]) {\n setSuccessFlag({\n account: flagAddress,\n reason,\n });\n onCancel();\n clearInterval(flsgSuccess);\n }\n });\n }, 1000);\n // Clear the interval after 30 seconds\n setTimeout(() => {\n onCancel();\n clearInterval(flsgSuccess);\n }, 60000);\n};\nconst handleFlag = () => {\n fetchSocialProfile().then((profileData) => {\n const profile = profileData[accountId].profile;\n const pLBlacklistedAccounts = JSON.parse(\n profile.pLBlacklistedAccounts || \"{}\"\n );\n const potFlaggedAcc = pLBlacklistedAccounts[potId] || {};\n const socialArgs = {\n data: {\n [accountId]: {\n profile: {\n pLBlacklistedAccounts: JSON.stringify({\n ...pLBlacklistedAccounts,\n [potId]: {\n ...potFlaggedAcc,\n [flagAddress]: reason,\n },\n }),\n },\n },\n },\n };\n const socialTransaction = {\n contractName: \"social.near\",\n methodName: \"set\",\n args: socialArgs,\n };\n Near.asyncView(\"social.near\", \"get_account\", {\n account_id: accountId,\n }).then((account) => {\n let depositFloat = JSON.stringify(socialArgs).length * 0.00015;\n if (!account) {\n depositFloat += 0.1;\n }\n socialTransaction.deposit = Big(depositFloat).mul(Big(10).pow(24));\n Near.call(socialTransaction);\n handleSuccess();\n });\n });\n};\nreturn (\n <Widget\n src={\"old.potlock.near/widget/Components.Modal\"}\n props={{\n ...props,\n onCancel: (e) => {\n e.stopPropagation();\n },\n contentStyle: {\n padding: \"0px\",\n },\n children: (\n <Container>\n <div>\n <Banner>\n <BannerBg className=\"left-pattern\" />\n <BannerBg className=\"right-pattern\" />\n <HeaderIcons>\n <svg\n onClick={() => onCancel()}\n className=\"close-icon\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M14 1.41L12.59 0L7 5.59L1.41 0L0 1.41L5.59 7L0 12.59L1.41 14L7 8.41L12.59 14L14 12.59L8.41 7L14 1.41Z\"\n fill=\"#FCCFCF\"\n />\n </svg>\n </HeaderIcons>\n Flag {flagAddress}\n </Banner>\n </div>\n <Content>\n <div>\n <Widget\n src={\"old.potlock.near/widget/Inputs.TextArea\"}\n props={{\n label: \"Reason\",\n inputRows: 4,\n inputStyle: {\n background: \"#FAFAFA\",\n },\n placeholder: `Type description`,\n value: reason,\n onChange: (reason) => setReason(reason),\n validate: () => {\n if (reason.length > MAX_REASON_LENGTH) {\n setReasonErr(\n `Reason must be less than ${MAX_REASON_LENGTH} characters`\n );\n return;\n }\n setReasonErr(\"\");\n },\n error: reasonErr,\n }}\n />\n <Limit>\n {reason.length}/{MAX_REASON_LENGTH}\n </Limit>\n </div>\n <InfoCard>\n <div>\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M9 5H11V7H9V5ZM9 9H11V15H9V9ZM10 0C4.48 0 0 4.48 0 10C0 15.52 4.48 20 10 20C15.52 20 20 15.52 20 10C20 4.48 15.52 0 10 0ZM10 18C5.59 18 2 14.41 2 10C2 5.59 5.59 2 10 2C14.41 2 18 5.59 18 10C18 14.41 14.41 18 10 18Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n </div>\n <div>\n Flagging this account will remove their donations when\n calculating payouts for this pot\n </div>\n </InfoCard>\n <ButtonsWrapper>\n <button className=\"cancel\" onClick={onCancel}>\n Cancel\n </button>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: \"Confirm\",\n disabled: !reason || reasonErr,\n onClick: handleFlag,\n }}\n />\n </ButtonsWrapper>\n </Content>\n </Container>\n ),\n }}\n />\n);\n" }, "Inputs.Checkbox": { "": "const Container = styled.div`\n display: flex;\n gap: 8px;\n flex-direction: row;\n align-items: center;\n`;\nconst CheckBox = styled.input`\n width: 18px;\n height: 18px;\n padding: 0px;\n appearance: checkbox;\n cursor: pointer;\n // TODO: update background color when selected\n`;\nconst Label = styled.label``;\nconst Error = styled.span`\n display: inline-block;\n font-style: normal;\n font-weight: 400;\n font-size: 0.75em;\n line-height: 1.25em;\n color: #ff4d4f;\n height: 0;\n overflow: hidden;\n transition: height 0.3s ease-in-out;\n &.show {\n height: 1.25em;\n }\n`;\nconst { id, disabled, checked, onClick } = props;\nconst containerStyle = props.containerStyle ?? {};\nconst checkBoxStyle = props.checkBoxStyle ?? {};\nconst labelStyle = props.labelStyle ?? {};\nconst error = props.error ?? \"\";\nreturn (\n <Container style={containerStyle}>\n <CheckBox\n type=\"checkbox\"\n style={checkBoxStyle}\n id={id}\n disabled={disabled}\n checked={checked}\n onClick={onClick}\n />\n {props.label && (\n <Label for={id} style={labelStyle}>\n {props.label}\n </Label>\n )}\n <Error className={error ? \"show\" : \"\"}>{error}</Error>\n </Container>\n);\n" }, "Components.Header": { "": "const headerTitleFontSizePx = 88;\nconst HeaderContainer = styled.div`\n width: 100%;\n // background: #fffaf4;\n // background: white;\n padding: 80px 64px;\n @media (max-width: 768px) {\n padding: 36px 24px;\n }\n`;\nconst HeaderContent = styled.div`\n display: flex;\n flex-direction: column;\n align-items: ${props.centered ? \"center\" : \"flex-start\"};\n`;\nconst HeaderTitle = styled.div`\n color: #2e2e2e;\n font-size: ${headerTitleFontSizePx}px;\n font-weight: 500;\n word-wrap: break-word;\n position: relative;\n text-align: center;\n z-index: 1;\n position: relative;\n font-family: \"Lora\";\n @media (max-width: 768px) {\n font-size: 48px;\n }\n`;\nconst HeaderDescription = styled.div`\n color: #2e2e2e;\n font-size: 32px;\n font-weight: 400;\n word-wrap: break-word;\n max-width: 866px;\n text-align: ${props.centered ? \"center\" : \"flex-start\"};\n margin-top: 32px;\n @media (max-width: 768px) {\n font-size: 24px;\n text-align: center;\n }\n`;\nconst ButtonsContainer = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n gap: 32px;\n margin-top: 32px;\n`;\nconst Underline = styled.div`\n position: absolute;\n top: ${headerTitleFontSizePx - 40}px;\n left: -40px;\n z-index: -1;\n @media (max-width: 768px) {\n top: 30px;\n left: -30px;\n }\n`;\nconst containerStyle = props.containerStyle ?? {};\nconst showStats = !props.tab || props.tab == \"projects\";\nreturn (\n <HeaderContainer style={containerStyle}>\n <HeaderContent>\n <HeaderTitle>\n {props.title1}\n <Underline>\n <svg\n width=\"340\"\n height=\"42\"\n viewBox=\"0 0 340 42\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M7.29967 39C-14.0566 35.9491 49.9788 32.436 71.4774 30.6444C151.734 23.9564 232.915 20.5161 312.9 15\"\n stroke=\"#DD3345\"\n stroke-width=\"5\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M31.2997 27C9.94337 23.9491 73.9788 20.436 95.4774 18.6444C175.734 11.9564 256.915 8.51608 336.9 3\"\n stroke=\"#DD3345\"\n stroke-width=\"5\"\n stroke-linecap=\"round\"\n />\n </svg>\n </Underline>\n </HeaderTitle>\n {props.title2 && <HeaderTitle>{props.title2}</HeaderTitle>}\n <HeaderDescription>{props.description}</HeaderDescription>\n </HeaderContent>\n {props.children && props.children}\n <ButtonsContainer>\n {props.buttonPrimary && props.buttonPrimary}\n {props.buttonSecondary && props.buttonSecondary}\n </ButtonsContainer>\n {showStats && (\n <Widget\n src={\"old.potlock.near/widget/Project.DonationStats\"}\n props={{ ...props }}\n />\n )}\n </HeaderContainer>\n);\n" }, "Pots.ChallengeModal": { "": "const { showChallengePayoutsModal, onCancel, existingChallengeForUser } = props;\nconst ModalHeader = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-start;\n background: white;\n padding: 24px 24px 12px 24px;\n border-top-left-radius: 6px;\n border-top-right-radius: 6px;\n font-weight: 500;\n`;\nconst ModalBody = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n padding: 24px;\n border-top: 1px #f0f0f0 solid;\n background: #fafafa;\n gap: 8px;\n`;\nconst ModalFooter = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-end;\n background: #fafafa;\n padding: 12px 24px 24px 24px;\n border-bottom-left-radius: 6px;\n border-bottom-right-radius: 6px;\n gap: 24px;\n width: 100%;\n`;\nState.init({\n challengeReason: \"\",\n challengeReasonError: \"\",\n});\nuseEffect(() => {\n if (existingChallengeForUser?.reason) {\n State.update({\n challengeReason: existingChallengeForUser?.reason,\n });\n }\n}, [existingChallengeForUser]);\nconst { challengeReason, challengeReasonError } = state;\nconst handleCancelChallenge = () => {\n onCancel();\n State.update({ challengeReason: \"\", challengeReasonError: \"\" });\n};\nconst handleSubmitChallenge = () => {\n PotSDK.challengePayouts(potId, challengeReason);\n onClose();\n};\nconst MAX_CHALLENGE_TEXT_LENGTH = 1000;\nreturn (\n <Widget\n src={\"old.potlock.near/widget/Components.Modal\"}\n props={{\n isModalOpen: showChallengePayoutsModal,\n onClose: handleCancelChallenge,\n contentStyle: {\n padding: \"0px\",\n },\n children: (\n <>\n <ModalHeader>Challenge Payouts</ModalHeader>\n <ModalBody>\n <div>Explain the reason for your challenge</div>\n <Widget\n src={\"old.potlock.near/widget/Inputs.TextArea\"}\n props={{\n noLabel: true,\n inputRows: 5,\n inputStyle: {\n background: \"#FAFAFA\",\n },\n placeholder: \"Type the reason for your challenge here\",\n value: challengeReason,\n onChange: (challengeReason) =>\n State.update({ challengeReason }),\n validate: () => {\n if (challengeReason.length > MAX_CHALLENGE_TEXT_LENGTH) {\n State.update({\n challengeReasonError: `Challenge reason must be less than ${MAX_CHALLENGE_TEXT_LENGTH} characters`,\n });\n return;\n }\n State.update({ challengeReasonError: \"\" });\n },\n error: challengeReasonError,\n }}\n />\n </ModalBody>\n <ModalFooter>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"tertiary\",\n text: \"Cancel\",\n onClick: handleCancelChallenge,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: \"Submit Challenge\",\n disabled: !challengeReason || !!challengeReasonError,\n onClick: handleSubmitChallenge,\n }}\n />\n </ModalFooter>\n </>\n ),\n }}\n />\n);\n" }, "Components.Loading": { "": "return <div class=\"spinner-border text-secondary\" role=\"status\" />;\n" }, "Pots.HomeBanner": { "": "const { canDeploy, hrefWithParams } = props;\nconst { HomeBannerStyle } = VM.require(\n \"old.potlock.near/widget/Pots.HomeBannerBackground\"\n) || {\n HomeBannerStyle: {},\n};\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n position: relative;\n width: 100%;\n justify-content: center;\n min-height: 400px;\n overflow: hidden;\n .background {\n position: absolute;\n pointer-events: none;\n height: 100%;\n left: 0;\n top: 0;\n }\n .content {\n position: relative;\n z-index: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n padding: 64px;\n }\n .sub-title {\n letter-spacing: 1.12px;\n font-weight: 500;\n font-size: 14px;\n margin-top: 0;\n margin-bottom: 24px;\n text-transform: uppercase;\n }\n .title {\n letter-spacing: -0.4px;\n font-weight: 500;\n font-size: 40px;\n font-family: \"Lora\";\n margin: 0;\n }\n .btns {\n display: flex;\n align-items: center;\n gap: 2rem;\n margin-top: 40px;\n a {\n padding: 12px 16px;\n width: 180px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: 500;\n border-radius: 6px;\n box-shadow: 0px -2px 0px 0px #464646 inset, 0px 0px 0px 1px #464646;\n text-decoration: none;\n color: #292929;\n transition: all 300ms;\n &:first-of-type {\n color: white;\n background: #dd3345;\n &:hover {\n }\n }\n &:hover {\n background: #292929;\n color: white;\n }\n }\n }\n @media only screen and (max-width: 768px) {\n .content {\n padding: 64px 20px;\n }\n .title {\n font-size: 36px;\n }\n .btns {\n flex-direction: column;\n gap: 1rem;\n margin-top: 24px;\n }\n .line-break {\n display: none;\n }\n }\n @media only screen and (max-width: 480px) {\n .btns a {\n width: 100%;\n padding: 12px 0;\n }\n }\n`;\nreturn (\n <Container\n style={{\n ...HomeBannerStyle,\n }}\n >\n <div className=\"content\">\n <h3 className=\"sub-title\">Explore Pots</h3>\n <h1 className=\"title\">\n Donate to Matching Rounds <br className=\"line-break\" /> to Get Your\n Contributions Amplified.\n </h1>\n <div className=\"btns\">\n {canDeploy && <a href={hrefWithParams(`?tab=deploypot`)}>Deploy Pot</a>}\n <a href=\"https://wtfisqf.com\" target=\"_blank\">\n Learn More\n </a>\n </div>\n </div>\n </Container>\n);\n" }, "Pots.Payouts": { "": "// get donations\nconst { potId, potDetail, allDonations } = props;\n// potDetail.cooldown_end_ms = 1710105146000; // TODO: remove this line\nconst { SUPPORTED_FTS } = VM.require(\"old.potlock.near/widget/constants\") || {\n SUPPORTED_FTS: {},\n};\nconst { calculatePayouts, yoctosToNear } = VM.require(\n \"old.potlock.near/widget/utils\"\n) || {\n calculatePayouts: () => {},\n yoctosToNear: () => \"\",\n};\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n isUserPotAdminOrGreater: () => {},\n getPayoutsChallenges: () => {},\n challengePayouts: () => {},\n adminUpdatePayoutsChallenge: () => {},\n getFlaggedAccounts: () => {},\n};\nconst userIsAdminOrGreater = PotSDK.isUserPotAdminOrGreater(\n potId,\n context.accountId\n); // TODO: ADD THIS BACK IN\n// const userIsAdminOrGreater = true; // TODO: REMOVE THIS LINE\nconst IPFS_BASE_URL = \"https://nftstorage.link/ipfs/\";\n// const ALERT_ICON_URL =\n// IPFS_BASE_URL + \"bafkreicqarojxk6jhdtsk2scfsmnigqpxjfgar6om4wlhn5xmqbbu74u5i\";\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n @media screen and (min-width: 375px) and (max-width: 768px) {\n width: 99%;\n }\n @media screen and (max-width: 390px) {\n width: 98%;\n }\n`;\nconst OuterTextContainer = styled.div`\n display: flex;\n flex-direction: row;\n gap: 10px;\n @media screen and (max-width: 768px) {\n padding-right: 10px;\n }\n`;\nconst OuterText = styled.div`\n color: #7b7b7b;\n font-size: 14px;\n font-weight: 500;\n text-transform: uppercase;\n line-height: 24px;\n letter-spacing: 1.12px;\n word-wrap: break-word;\n`;\nconst Count = styled.div`\n color: #dd3345;\n font-size: 14px;\n font-weight: 600;\n line-height: 24px;\n`;\nconst TableContainer = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n border-radius: 6px;\n border: 1px solid #7b7b7b;\n width: 100%;\n overflow-x: auto;\n flex-wrap: nowrap;\n`;\nconst Header = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n gap: 2rem;\n padding: 0.5rem 1rem;\n border-bottom: 1px solid rgba(199, 199, 199, 0.5);\n @media only screen and (max-width: 768px) {\n display: none;\n }\n`;\nconst HeaderItem = styled.div`\n display: flex;\n flex-direction: row;\n align-items: space-between;\n justify-content: flex-start;\n justify-content: space-between;\n width: 110px;\n justify-content: right;\n &.project {\n flex: 1;\n justify-content: left;\n }\n @media only screen and (max-width: 768px) {\n display: none;\n &.project {\n display: flex;\n }\n }\n`;\nconst HeaderItemText = styled.div`\n color: #292929;\n font-size: 14px;\n font-weight: 600;\n line-height: 24px;\n word-wrap: break-word;\n`;\nconst MobileAmount = styled.div`\n width: 100%;\n margin-left: 2rem;\n display: none;\n max-height: 0px;\n overflow: hidden;\n transition: all 200ms;\n span {\n font-weight: 600;\n }\n @media screen and (max-width: 768px) {\n order: 2;\n display: block;\n }\n`;\nconst Row = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n padding: 1rem;\n gap: 2rem;\n border-top: 1px solid rgba(199, 199, 199, 0.5);\n position: relative;\n .toggle-check {\n cursor: pointer;\n position: absolute;\n left: 0;\n top: 0;\n height: 100%;\n width: 100%;\n opacity: 0;\n display: none;\n }\n .toggle-check:checked ~ svg {\n rotate: 0deg;\n }\n .toggle-check:checked + ${MobileAmount} {\n max-height: 100px;\n }\n @media screen and (max-width: 768px) {\n flex-wrap: wrap;\n gap: 0.5rem;\n .toggle-check {\n display: block;\n }\n }\n`;\nconst RowItem = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-start;\n width: 110px;\n justify-content: right;\n &:hover {\n text-decoration: none;\n }\n &.project {\n flex: 1;\n display: flex;\n gap: 1rem;\n justify-content: left;\n transition: 200ms;\n a {\n color: #292929;\n font-weight: 600;\n transition: 200ms;\n &:hover {\n color: #dd3345;\n text-decoration: none;\n }\n }\n }\n @media screen and (max-width: 768px) {\n &.project {\n gap: 0.5rem;\n }\n &.donors,\n &.amount {\n display: none;\n }\n }\n`;\nconst RowText = styled.div`\n color: #292929;\n font-size: 14px;\n font-weight: 600;\n word-wrap: break-word;\n span {\n color: #7b7b7b;\n font-weight: 600;\n display: none;\n }\n @media screen and (max-width: 768px) {\n span {\n display: inline;\n }\n &:last-of-type {\n display: flex;\n gap: 4px;\n }\n }\n`;\nconst SearchBarContainer = styled.div`\n display: flex;\n align-items: center;\n gap: 16px;\n width: 100%;\n background: #f6f5f3;\n padding: 0.5rem 1rem;\n @media only screen and (max-width: 768px) {\n gap: 8px;\n }\n`;\nconst SearchBar = styled.input`\n background: none;\n width: 100%;\n outline: none;\n border: none;\n &:focus {\n outline: none;\n border: none;\n }\n`;\nconst SearchIcon = styled.div`\n display: flex;\n width: 24px;\n height: 24px;\n align-items: center;\n justify-content: center;\n`;\nconst InfoContainer = styled.div`\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 8px;\n border: 1px solid #f4b37d;\n border-radius: 6px;\n background: #fef6ee;\n gap: 1rem;\n margin-left: auto;\n margin-bottom: 1.5rem;\n`;\nconst WarningText = styled.div`\n text-align: center;\n color: #dd3345;\n font-weight: 500;\n font-size: 14px;\n`;\nconst AlertSvg = styled.svg`\n width: 18px;\n @media screen and (max-width: 768px) {\n width: 1rem;\n }\n`;\nState.init({\n allPayouts: null,\n filteredPayouts: null,\n showChallengePayoutsModal: false,\n flaggedAddresses: null,\n});\nconst {\n allPayouts,\n filteredPayouts,\n showChallengePayoutsModal,\n flaggedAddresses,\n} = state;\nif (!flaggedAddresses) {\n PotSDK.getFlaggedAccounts(potDetail, potId)\n .then((data) => {\n const listOfFlagged = [];\n data.forEach((adminFlaggedAcc) => {\n const addresses = Object.keys(adminFlaggedAcc.potFlaggedAcc);\n listOfFlagged.push(...addresses);\n });\n State.update({ flaggedAddresses: listOfFlagged });\n })\n .catch((err) => console.log(\"error getting the flagged accounts \", err));\n}\nif (!allPayouts && allDonations && potDetail && flaggedAddresses) {\n calculatePayouts(\n allDonations,\n potDetail.matching_pool_balance,\n flaggedAddresses\n ).then((calculatedPayouts) => {\n console.log(\"calculated payouts: \", calculatedPayouts);\n if (potDetail.payouts.length) {\n // handle these payouts, which don't contain all the info needed\n // pot payouts contain id, project_id, amount & paid_at\n // 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\n const synthesizedPayouts = potDetail.payouts.map((payout) => {\n const { project_id, amount } = payout;\n const { totalAmount, donorCount } = calculatedPayouts[project_id];\n return {\n projectId: project_id,\n totalAmount,\n matchingAmount: amount,\n donorCount,\n };\n });\n State.update({\n allPayouts: synthesizedPayouts,\n filteredPayouts: synthesizedPayouts,\n });\n } else {\n // calculate estimated payouts\n const allPayouts = Object.entries(calculatedPayouts).map(\n ([projectId, { totalAmount, matchingAmount, donorCount }]) => {\n return {\n projectId,\n totalAmount,\n matchingAmount,\n donorCount,\n };\n }\n ); // TODO: refactor to use PotsSDK (note that this is duplicated in Pots/Projects.jsx)\n allPayouts.sort((a, b) => {\n // sort by matching pool allocation, highest to lowest\n return b.matchingAmount - a.matchingAmount;\n });\n State.update({ allPayouts, filteredPayouts: allPayouts });\n }\n });\n}\nconst columns = [\n \"Project\",\n \"Total Raised\",\n \"Total Unique Donors\",\n \"Matching Pool Allocation\",\n];\nconst { base_currency } = potDetail;\nconst searchPayouts = (searchTerm) => {\n // filter payouts that match the search term (donor_id, project_id)\n const filteredPayouts = allPayouts.filter((payout) => {\n const { projectId } = payout;\n const searchFields = [projectId];\n return searchFields.some((field) =>\n field.toLowerCase().includes(searchTerm.toLowerCase())\n );\n });\n filteredPayouts.sort((a, b) => {\n // sort by matching pool allocation, highest to lowest\n return b.matchingAmount - a.matchingAmount;\n });\n return filteredPayouts;\n};\nconst MAX_ACCOUNT_ID_DISPLAY_LENGTH = 10;\nconst ProfileImage = ({ projectId }) => (\n <Widget\n src={\"old.potlock.near/widget/Project.ProfileImage\"}\n props={{\n ...props,\n accountId: projectId,\n style: {\n height: \"24px\",\n width: \"24px\",\n },\n }}\n />\n);\nconst Arrow = styled.svg`\n width: 12px;\n rotate: 180deg;\n transition: all 200ms;\n display: none;\n @media screen and (max-width: 768px) {\n display: block;\n }\n`;\nconst ArrowDown = (props) => (\n <Arrow\n {...props}\n viewBox=\"0 0 12 8\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 0.294983L0 6.29498L1.41 7.70498L6 3.12498L10.59 7.70498L12 6.29498L6 0.294983Z\"\n fill=\"#7B7B7B\"\n />\n </Arrow>\n);\nreturn (\n <Container>\n <Widget\n src={\"old.potlock.near/widget/Pots.FlaggedAccounts\"}\n props={props}\n />\n <Widget\n src={\"old.potlock.near/widget/Pots.PayoutsChallenges\"}\n props={props}\n />\n {!potDetail.all_paid_out && (\n <InfoContainer>\n <AlertSvg\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M7.25 4.25H8.75V5.75H7.25V4.25ZM7.25 7.25H8.75V11.75H7.25V7.25ZM8 0.5C3.86 0.5 0.5 3.86 0.5 8C0.5 12.14 3.86 15.5 8 15.5C12.14 15.5 15.5 12.14 15.5 8C15.5 3.86 12.14 0.5 8 0.5ZM8 14C4.6925 14 2 11.3075 2 8C2 4.6925 4.6925 2 8 2C11.3075 2 14 4.6925 14 8C14 11.3075 11.3075 14 8 14Z\"\n fill=\"#EE8949\"\n />\n </AlertSvg>\n <WarningText>\n {potDetail.cooldown_end_ms\n ? \"These payouts have been set on the contract but have not been paid out yet.\"\n : \"These payouts are estimated amounts only and have not been set on the contract yet.\"}\n </WarningText>\n </InfoContainer>\n )}\n <TableContainer>\n <Header>\n <HeaderItem className=\"project\">\n <HeaderItemText>Project</HeaderItemText>\n </HeaderItem>\n <HeaderItem>\n <HeaderItemText>Total Raised</HeaderItemText>\n </HeaderItem>\n <HeaderItem>\n <HeaderItemText>Unique Donors</HeaderItemText>\n </HeaderItem>\n <HeaderItem>\n <HeaderItemText>Pool Allocation</HeaderItemText>\n </HeaderItem>\n </Header>\n <SearchBarContainer>\n <SearchIcon>\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M15.7549 14.2549H14.9649L14.6849 13.9849C15.6649 12.8449 16.2549 11.3649 16.2549 9.75488C16.2549 6.16488 13.3449 3.25488 9.75488 3.25488C6.16488 3.25488 3.25488 6.16488 3.25488 9.75488C3.25488 13.3449 6.16488 16.2549 9.75488 16.2549C11.3649 16.2549 12.8449 15.6649 13.9849 14.6849L14.2549 14.9649V15.7549L19.2549 20.7449L20.7449 19.2549L15.7549 14.2549ZM9.75488 14.2549C7.26488 14.2549 5.25488 12.2449 5.25488 9.75488C5.25488 7.26488 7.26488 5.25488 9.75488 5.25488C12.2449 5.25488 14.2549 7.26488 14.2549 9.75488C14.2549 12.2449 12.2449 14.2549 9.75488 14.2549Z\"\n fill=\"#C7C7C7\"\n />\n </svg>\n </SearchIcon>\n <SearchBar\n placeholder=\"Search payouts\"\n onChange={({ target: { value } }) => {\n const filteredPayouts = searchPayouts(value);\n State.update({ filteredPayouts });\n }}\n />\n </SearchBarContainer>\n {!filteredPayouts ? (\n <div>Loading</div>\n ) : filteredPayouts.length === 0 ? (\n <Row style={{ padding: \"12px\" }}>No payouts to display</Row>\n ) : (\n filteredPayouts.map((payout, index) => {\n const { projectId, donorCount, matchingAmount, totalAmount } = payout;\n return (\n <Row key={index}>\n <RowItem className=\"project\">\n <ProfileImage projectId={projectId} />\n <a\n href={`?tab=project&projectId=${projectId}`}\n target={\"_blank\"}\n >\n {projectId.length > MAX_ACCOUNT_ID_DISPLAY_LENGTH\n ? projectId.slice(0, MAX_ACCOUNT_ID_DISPLAY_LENGTH) + \"...\"\n : projectId}\n </a>\n </RowItem>\n {/* Total Raised */}\n <RowItem className=\"amount\">\n <RowText>{yoctosToNear(totalAmount, true)}</RowText>\n </RowItem>\n <input type=\"checkbox\" className=\"toggle-check\" />\n <MobileAmount>\n <span>{yoctosToNear(totalAmount, true)}</span> raised from\n <span>{donorCount}</span> unique donors\n </MobileAmount>\n {/* Total Unique Donors */}\n <RowItem className=\"donors\">\n <RowText>{donorCount}</RowText>\n </RowItem>\n {/* Matching Pool Allocation */}\n <RowItem>\n <RowText>\n {yoctosToNear(matchingAmount, true)} <span>Allocated</span>\n </RowText>\n </RowItem>\n <ArrowDown />\n </Row>\n );\n })\n )}\n </TableContainer>\n </Container>\n);\n" }, "Components.Feed": { "": "let ListsSDK =\n VM.require(\"old.potlock.near/widget/SDK.lists\") ||\n (() => ({\n getRegistrations: () => {},\n }));\nListsSDK = ListsSDK({ env: props.env });\nconst registrations = ListsSDK.getRegistrations() || [];\nconst registrantIds = registrations\n .filter((reg) => reg.status === \"Approved\")\n .map((reg) => reg.registrant_id);\nconst Container = styled.div`\n padding: 24px 64px;\n @media screen and (max-width: 768px) {\n padding: 24px 16px;\n }\n`;\nreturn (\n <Container>\n <Widget\n key=\"feed\"\n src={\"old.potlock.near/widget/Profile.Feed\"}\n props={{ accounts: registrantIds }}\n />\n </Container>\n);\n" }, "Pots.ConfigForm": { "": "const { potDetail, potId, NADABOT_CONTRACT_ID } = props;\nconst { validateNearAddress } = VM.require(\"old.potlock.near/widget/utils\") || {\n validateNearAddress: () => \"\",\n};\nconst {\n NADABOT_HUMAN_METHOD,\n ONE_TGAS,\n SUPPORTED_FTS: { NEAR },\n} = VM.require(\"old.potlock.near/widget/constants\") || {\n NADABOT_HUMAN_METHOD: \"\",\n ONE_TGAS: 0,\n SUPPORTED_FTS: {},\n};\nlet PotFactorySDK =\n VM.require(\"old.potlock.near/widget/SDK.potfactory\") ||\n (() => ({\n getContractId: () => {},\n getProtocolConfig: () => {},\n asyncGetPots: () => {},\n }));\nPotFactorySDK = PotFactorySDK({ env: props.env });\nconst potFactoryContractId = PotFactorySDK.getContractId();\nconst protocolConfig = PotFactorySDK.getProtocolConfig();\n// console.log(\"props in config form: \", props);\nlet ListsSDK =\n VM.require(\"old.potlock.near/widget/SDK.lists\") ||\n (() => ({\n getContractId: () => \"\",\n }));\nListsSDK = ListsSDK({ env: props.env });\nconst DEFAULT_REGISTRY_PROVIDER = `${ListsSDK.getContractId()}:is_registered`;\nconst DEFAULT_SYBIL_WRAPPER_PROVIDER = `${NADABOT_CONTRACT_ID}:${NADABOT_HUMAN_METHOD}`;\nconst CURRENT_SOURCE_CODE_VERSION = \"0.1.0\";\nconst SOURCE_CODE_LINK = \"https://github.com/PotLock/core\"; // for use in contract source metadata\nconst POT_CODE_LINK = \"https://github.com/PotLock/core/tree/main/contracts/pot\"; // for directing user to view source code for Pot\nconst IPFS_BASE_URL = \"https://nftstorage.link/ipfs/\";\n// const ADD_ADMINS_ICON_URL =\n// IPFS_BASE_URL + \"bafkreig6c7m2z2lupreu2br4pm3xx575mv6uvmuy2qkij4kzzfpt7tipcq\";\n// const CLOSE_ICON_URL =\n// IPFS_BASE_URL + \"bafkreifyg2vvmdjpbhkylnhye5es3vgpsivhigkjvtv2o4pzsae2z4vi5i\";\nconst DEFAULT_PROFILE_IMAGE_URL =\n IPFS_BASE_URL + \"bafkreifel4bfm6hxmklcsqjilk3bhvi3acf2rxqepcgglluhginbttkyqm\";\nconst MAX_POT_NAME_LENGTH = 64;\nconst MAX_POT_DESCRIPTION_LENGTH = 256;\nconst MAX_MAX_PROJECTS = 100;\nconst MAX_REFERRAL_FEE_MATCHING_POOL_BASIS_POINTS = 1000; // 10%\nconst MAX_REFERRAL_FEE_PUBLIC_ROUND_BASIS_POINTS = 1000; // 10%\nconst MAX_CHEF_FEE_BASIS_POINTS = 1000; // 10%\nconst getImageUrlFromSocialImage = (image) => {\n if (image.url) {\n return image.url;\n } else if (image.ipfs_cid) {\n return IPFS_BASE_URL + image.ipfs_cid;\n }\n};\nBig.PE = 100;\nconst FormBody = styled.div`\n display: flex;\n flex-direction: column;\n padding: 32px 0px;\n width: 100%;\n @media screen and (max-width: 880px) {\n padding: 10px 10px;\n }\n`;\nconst FormDivider = styled.div`\n height: 2px;\n width: 100%;\n background-color: #ebebeb;\n @media screen and (max-width: 768px) {\n display: none;\n }\n`;\nconst FormSectionContainer = styled.div`\n display: flex;\n flex-direction: row;\n margin: 48px 0;\n @media screen and (max-width: 768px) {\n flex-direction: column;\n gap: 32px;\n }\n`;\nconst FormSectionLeftDiv = styled.div`\n // flex: 1;\n width: 30%;\n display: flex;\n flex-direction: column;\n // background-color: yellow;\n gap: 16px;\n @media screen and (max-width: 768px) {\n width: 100%;\n }\n`;\nconst FormSectionRightDiv = styled.div`\n width: 70%;\n display: flex;\n flex-direction: column;\n gap: 26px;\n @media screen and (max-width: 768px) {\n width: 100%;\n }\n`;\nconst FormSectionTitle = styled.div`\n color: #2e2e2e;\n font-size: 16;\n font-weight: 600;\n word-wrap: break-word;\n`;\nconst FormSectionDescription = styled.div`\n color: #2e2e2e;\n font-size: 16;\n font-weight: 400;\n word-wrap: break-word;\n`;\nconst Row = styled.div`\n display: flex;\n flex-direction: row;\n gap: 24px;\n align-items: end;\n justify-content: flex-start;\n @media screen and (max-width: 768px) {\n flex-direction: column;\n align-items: flex-start;\n }\n`;\nconst Checkbox = styled.div`\n display: flex;\n @media screen and (max-width: 768px) {\n flex-direction: row;\n }\n`;\nconst Label = styled.label`\n font-weight: 500;\n font-size: 14px;\n line-height: 16px;\n word-wrap: break-word;\n color: #2e2e2e;\n`;\nconst isUpdate = !!potDetail;\nconst convertToUTCTimestamp = (localDateTime) => {\n if (!localDateTime) {\n return;\n }\n return new Date(localDateTime).getTime();\n};\nconst formatTimestampForDateTimeLocal = (timestamp) => {\n const date = new Date(timestamp);\n const year = date.getFullYear();\n const month = (date.getMonth() + 1).toString().padStart(2, \"0\"); // months are 0-indexed\n const day = date.getDate().toString().padStart(2, \"0\");\n const hours = date.getHours().toString().padStart(2, \"0\");\n const minutes = date.getMinutes().toString().padStart(2, \"0\");\n return `${year}-${month}-${day}T${hours}:${minutes}`;\n};\n// console.log(\"potDetail: \", potDetail);\nState.init({\n owner: isUpdate ? potDetail.owner : context.accountId,\n ownerError: \"\",\n admin: \"\",\n admins: isUpdate ? potDetail.admins.map((accountId) => ({ accountId })) : [],\n adminsError: \"\",\n isAdminsModalOpen: false,\n name: isUpdate ? potDetail.pot_name : \"\",\n nameError: \"\",\n customHandle: isUpdate ? potId.split(`.${potFactoryContractId}`)[0] : \"\",\n customHandleError: \"\",\n description: isUpdate ? potDetail.pot_description : \"\",\n descriptionError: \"\",\n // referrerFeeMatchingPoolPercent * 100: isUpdate\n // ? potDetail.referral_fee_matching_pool_basis_points\n // : \"\",\n // referrerFeeMatchingPoolPercent * 100Error: \"\",\n referrerFeeMatchingPoolPercent: isUpdate\n ? potDetail.referral_fee_matching_pool_basis_points / 100\n : \"\",\n referrerFeeMatchingPoolPercentError: \"\",\n referrerFeePublicRoundPercent: isUpdate\n ? potDetail.referral_fee_public_round_basis_points / 100\n : \"\",\n referrerFeePublicRoundPercentError: \"\",\n protocolFeeBasisPoints: isUpdate ? potDetail.protocol_fee_basis_points : \"\",\n protocolFeeBasisPointsError: \"\",\n applicationStartDate: isUpdate\n ? formatTimestampForDateTimeLocal(potDetail.application_start_ms)\n : \"\",\n applicationStartDateError: \"\",\n applicationEndDate: isUpdate\n ? formatTimestampForDateTimeLocal(potDetail.application_end_ms)\n : \"\",\n applicationEndDateError: \"\",\n matchingRoundStartDate: isUpdate\n ? formatTimestampForDateTimeLocal(potDetail.public_round_start_ms)\n : \"\",\n matchingRoundStartDateError: \"\",\n matchingRoundEndDate: isUpdate\n ? formatTimestampForDateTimeLocal(potDetail.public_round_end_ms)\n : \"\",\n matchingRoundEndDateError: \"\",\n chef: isUpdate ? potDetail.chef : \"\",\n chefError: \"\",\n chefFeePercent: isUpdate ? potDetail.chef_fee_basis_points / 100 : \"\",\n chefFeePercentError: \"\",\n maxProjects: isUpdate ? potDetail.max_projects : \"\",\n maxProjectsError: \"\",\n baseCurrency: isUpdate ? potDetail.base_currency : \"\",\n baseCurrencyError: \"\",\n minMatchingPoolDonationAmount: NEAR.fromIndivisible(\n isUpdate ? potDetail.min_matching_pool_donation_amount : \"1\"\n ),\n minMatchingPoolDonationAmountError: \"\",\n useNadabotSybil: isUpdate\n ? potDetail.sybil_wrapper_provider == DEFAULT_SYBIL_WRAPPER_PROVIDER\n : true,\n usePotlockRegistry: isUpdate\n ? potDetail.registry_provider == DEFAULT_REGISTRY_PROVIDER\n : true,\n latestSourceCodeCommitHash: \"\",\n deploymentSuccess: false,\n});\nif (!isUpdate && !state.latestSourceCodeCommitHash) {\n const res = fetch(\"https://api.github.com/repos/PotLock/core/commits\");\n if (res.ok && res.body.length > 0) {\n State.update({\n latestSourceCodeCommitHash: res.body[0].sha,\n });\n }\n}\nconst getPotDetailArgsFromState = () => {\n const args = {\n owner: state.owner,\n admins: state.admins\n .filter((admin) => !admin.remove)\n .map((admin) => admin.accountId),\n chef: state.chef || null,\n pot_name: state.name,\n pot_description: state.description,\n max_projects: parseInt(state.maxProjects) || null,\n application_start_ms: convertToUTCTimestamp(state.applicationStartDate),\n application_end_ms: convertToUTCTimestamp(state.applicationEndDate),\n public_round_start_ms: convertToUTCTimestamp(state.matchingRoundStartDate),\n public_round_end_ms: convertToUTCTimestamp(state.matchingRoundEndDate),\n min_matching_pool_donation_amount: NEAR.toIndivisible(\n state.minMatchingPoolDonationAmount\n ).toString(),\n registry_provider: state.usePotlockRegistry\n ? DEFAULT_REGISTRY_PROVIDER\n : null,\n sybil_wrapper_provider: state.useNadabotSybil\n ? DEFAULT_SYBIL_WRAPPER_PROVIDER\n : null,\n custom_sybil_checks: null, // not necessary to include null values but doing so for clarity\n custom_min_threshold_score: null, // not necessary to include null values but doing so for clarity\n referral_fee_matching_pool_basis_points: parseInt(\n (state.referrerFeeMatchingPoolPercent * 100).toFixed(0)\n ),\n referral_fee_public_round_basis_points: parseInt(\n (state.referrerFeePublicRoundPercent * 100).toFixed(0)\n ),\n chef_fee_basis_points: parseInt((state.chefFeePercent * 100).toFixed(0)),\n source_metadata: isUpdate\n ? null\n : {\n // TODO: think about the best way to handle this so that it keeps up to date with the latest source code\n version: CURRENT_SOURCE_CODE_VERSION,\n commit_hash: state.latestSourceCodeCommitHash,\n link: SOURCE_CODE_LINK,\n },\n };\n return args;\n};\n// console.log(\"state; \", state);\nconst canDeploy = useMemo(() => {\n if (\n !state.owner ||\n state.ownerError ||\n !state.name ||\n state.nameError ||\n !state.description ||\n state.descriptionError ||\n !state.referrerFeeMatchingPoolPercent ||\n state.referrerFeeMatchingPoolPercentError ||\n !state.applicationStartDate ||\n state.applicationStartDateError ||\n !state.applicationEndDate ||\n state.applicationEndDateError ||\n !state.matchingRoundStartDate ||\n state.matchingRoundStartDateError ||\n !state.matchingRoundEndDate ||\n state.matchingRoundEndDateError ||\n !state.chef ||\n state.chefError ||\n !state.chefFeePercent ||\n state.chefFeePercentError ||\n !state.maxProjects ||\n state.maxProjectsError\n ) {\n return false;\n }\n return true;\n}, [state]);\nconst handleDeploy = () => {\n // create deploy pot args\n const deployArgs = getPotDetailArgsFromState();\n console.log(\"deployArgs: \", deployArgs);\n Near.asyncView(potFactoryContractId, \"calculate_min_deployment_deposit\", {\n args: deployArgs,\n }).then((amount) => {\n // console.log(\"amount: \", amount);\n const amountYoctos = Big(amount).plus(Big(\"20000000000000000000000\")); // add extra 0.02 NEAR as buffer\n const args = { pot_args: deployArgs };\n if (state.customHandle) {\n args.pot_handle = state.customHandle;\n }\n const transactions = [\n {\n contractName: potFactoryContractId,\n methodName: \"deploy_pot\",\n deposit: amountYoctos,\n args,\n gas: ONE_TGAS.mul(300),\n },\n ];\n const now = Date.now();\n Near.call(transactions);\n // NB: we won't get here if user used a web wallet, as it will redirect to the wallet\n // <---- EXTENSION WALLET HANDLING ---->\n // poll for updates\n const pollIntervalMs = 1000;\n // const totalPollTimeMs = 60000; // consider adding in to make sure interval doesn't run indefinitely\n const pollId = setInterval(() => {\n PotFactorySDK.asyncGetPots().then((pots) => {\n // console.log(\"pots: \", pots);\n const pot = pots.find(\n (pot) =>\n pot.deployed_by === context.accountId && pot.deployed_at_ms > now\n );\n if (pot) {\n clearInterval(pollId);\n State.update({ deploymentSuccess: true });\n }\n });\n }, pollIntervalMs);\n });\n};\nconst handleUpdate = () => {\n // create update pot args\n const updateArgs = getPotDetailArgsFromState();\n // console.log(\"updateArgs: \", updateArgs);\n const depositFloat = JSON.stringify(updateArgs).length * 0.00003;\n const deposit = Big(depositFloat).mul(Big(10).pow(24));\n const transactions = [\n {\n contractName: potId,\n methodName: \"admin_dangerously_set_pot_config\",\n deposit: Big(0.1).mul(Big(10).pow(24)),\n deposit,\n args: { update_args: updateArgs },\n gas: ONE_TGAS.mul(100),\n },\n ];\n Near.call(transactions);\n // NB: we won't get here if user used a web wallet, as it will redirect to the wallet\n // <---- EXTENSION WALLET HANDLING ---->\n // TODO: IMPLEMENT\n};\n// console.log(\"state: \", state);\nconst validateAndUpdatePercentages = (percent, stateKey, errorKey, maxVal) => {\n // TODO: move this to separate component for percentage input that accepts \"basisPoints\" bool parameter\n const updates = {\n [errorKey]: \"\",\n };\n if (!percent) {\n updates[stateKey] = \"0\";\n } else {\n const split = percent.split(\".\");\n if (split.length > 2) {\n return;\n }\n if (split.length === 2 && split[1].length > 2) {\n return;\n }\n // if it ends with a period and this is the only period in the string, set on state\n if (percent.endsWith(\".\") && percent.indexOf(\".\") === percent.length - 1) {\n State.update({\n [stateKey]: percent,\n });\n return;\n }\n // otherwise, parse into a float\n const percentFloat = parseFloat(percent);\n if (percentFloat) {\n updates[stateKey] = percentFloat.toString();\n if (percentFloat > maxVal) {\n updates[errorKey] = `Maximum ${maxVal}%`;\n }\n }\n }\n State.update(updates);\n};\nconst handleAddAdmin = () => {\n let isValid = validateNearAddress(state.admin);\n if (!isValid) {\n State.update({\n adminsError: \"Invalid NEAR account ID\",\n });\n return;\n }\n if (\n !state.admins.find(\n (admin) => admin.accountId == state.admin && !admin.remove\n )\n ) {\n // TODO: if already in state.admins with remove = true, set remove = false\n // get data from social.near\n // const profileImageUrl = DEFAULT_PROFILE_IMAGE_URL;\n const newAdmin = {\n accountId: state.admin.toLowerCase(),\n // imageUrl: profileImageUrl,\n };\n const admins = [...state.admins, newAdmin];\n // console.log(\"admins: \", admins);\n State.update({\n admins,\n admin: \"\",\n adminsError: \"\",\n });\n }\n};\nconst handleRemoveAdmin = (accountId) => {\n State.update({\n admins: state.admins.map((admin) => {\n if (admin.accountId == accountId) {\n return { ...admin, remove: true };\n }\n return admin;\n }),\n });\n};\nconst userIsOwner = context.accountId === potDetail.owner;\nconst userIsAdmin = isUpdate && potDetail.admins.includes(context.accountId);\nconst isAdminOrGreater = userIsOwner || userIsAdmin;\nconst FormSectionLeft = (title, description) => {\n return (\n <FormSectionLeftDiv>\n <FormSectionTitle>{title}</FormSectionTitle>\n <FormSectionDescription>{description}</FormSectionDescription>\n </FormSectionLeftDiv>\n );\n};\nreturn (\n <FormBody>\n <FormSectionContainer>\n {FormSectionLeft(\"Pot details\", \"\")}\n <FormSectionRightDiv>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"Owner *\",\n placeholder: `E.g. ${context.accountId}`,\n value: state.owner,\n onChange: (owner) => State.update({ owner, ownerError: \"\" }),\n validate: () => {\n // **CALLED ON BLUR**\n const valid = validateNearAddress(state.owner);\n State.update({\n ownerError: valid ? \"\" : \"Invalid NEAR account ID\",\n });\n },\n error: state.ownerError,\n disabled: isUpdate ? !userIsOwner : true,\n }}\n />\n {/* <props.ToDo>ADD ADMINS multi-entry</props.ToDo> */}\n <Label>Admins</Label>\n <Widget\n src={\"old.potlock.near/widget/Components.AccountsList\"}\n props={{\n accountIds: state.admins\n .filter((account) => !account.remove)\n .map((account) => account.accountId),\n allowRemove: isUpdate ? userIsOwner : true,\n handleRemoveAccount: handleRemoveAdmin,\n }}\n />\n {(!isUpdate || userIsOwner) && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"tertiary\",\n text: \"Add admins\",\n style: { width: \"fit-content\" },\n onClick: () => State.update({ isAdminsModalOpen: true }),\n }}\n />\n )}\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"Name *\",\n placeholder: \"E.g. DeFi Center\",\n value: state.name,\n onChange: (name) => State.update({ name, nameError: \"\" }),\n validate: () => {\n // **CALLED ON BLUR**\n const valid = state.name.length <= MAX_POT_NAME_LENGTH;\n State.update({\n nameError: valid\n ? \"\"\n : `Name must be ${MAX_POT_NAME_LENGTH} characters or less`,\n });\n },\n error: state.nameError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"Custom handle (optional - will slugify name by default)\",\n placeholder: \"e.g. my-pot-handle\",\n value: state.customHandle,\n onChange: (customHandle) =>\n State.update({ customHandle, customHandleError: \"\" }),\n validate: () => {\n // **CALLED ON BLUR**\n const suffix = `.${potFactoryContractId}`;\n const fullAddress = `${state.customHandle}${suffix}`;\n let customHandleError = \"\";\n if (fullAddress.length > 64) {\n customHandleError = `Handle must be ${\n 64 - suffix.length\n } characters or less`;\n } else {\n const valid = validateNearAddress(fullAddress);\n customHandleError = valid\n ? \"\"\n : `Invalid handle (can only contain lowercase alphanumeric symbols + _ or -)`;\n }\n State.update({\n customHandleError,\n });\n },\n error: state.customHandleError,\n disabled: isUpdate,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Inputs.TextArea\"}\n props={{\n label: \"Description\",\n placeholder: \"Type description\",\n value: state.description,\n onChange: (description) => State.update({ description }),\n validate: () => {\n // **CALLED ON BLUR**\n const valid =\n state.description.length <= MAX_POT_DESCRIPTION_LENGTH;\n State.update({\n descriptionError: valid\n ? \"\"\n : `Description must be ${MAX_POT_DESCRIPTION_LENGTH} characters or less`,\n });\n },\n error: state.descriptionError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n <Row>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"Referrer fee % (matching pool)\",\n placeholder: \"0\",\n percent: true,\n value: state.referrerFeeMatchingPoolPercent,\n onChange: (percent) => {\n validateAndUpdatePercentages(\n percent,\n \"referrerFeeMatchingPoolPercent\",\n \"referrerFeeMatchingPoolPercentError\",\n MAX_REFERRAL_FEE_MATCHING_POOL_BASIS_POINTS / 100\n );\n },\n validate: () => {\n // **CALLED ON BLUR**\n },\n error: state.referrerFeeMatchingPoolPercentError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"Referrer fee % (public round)\",\n placeholder: \"0\",\n percent: true,\n value: state.referrerFeePublicRoundPercent,\n onChange: (percent) => {\n validateAndUpdatePercentages(\n percent,\n \"referrerFeePublicRoundPercent\",\n \"referrerFeePublicRoundPercentError\",\n MAX_REFERRAL_FEE_PUBLIC_ROUND_BASIS_POINTS / 100\n );\n },\n validate: () => {\n // **CALLED ON BLUR**\n },\n error: state.referrerFeeMatchingPoolPercentError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"Protocol fee %\",\n value: protocolConfig ? protocolConfig.basis_points / 100 : \"-\",\n disabled: true,\n percent: true,\n }}\n />\n </Row>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Date\"}\n props={{\n label: \"Application start date\",\n // placeholder: \"0\", // TODO: possibly add this back in\n selectTime: true,\n value: state.applicationStartDate,\n onChange: (date) => {\n State.update({ applicationStartDate: date });\n },\n validate: () => {\n // **CALLED ON BLUR**\n // must be after now & before application end date\n // const now = Date.now();\n const now = new Date().getTime();\n const applicationStartDate = new Date(\n state.applicationStartDate\n ).getTime();\n const applicationEndDate = new Date(\n state.applicationEndDate\n ).getTime();\n const valid =\n applicationStartDate > now &&\n (!applicationEndDate ||\n applicationStartDate < applicationEndDate);\n State.update({\n applicationStartDateError: valid\n ? \"\"\n : \"Invalid application start date\",\n });\n },\n error: state.applicationStartDateError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Inputs.Date\"}\n props={{\n label: \"Application end date\",\n // placeholder: \"0\", // TODO: possibly add this back in\n selectTime: true,\n value: state.applicationEndDate,\n onChange: (date) => State.update({ applicationEndDate: date }),\n validate: () => {\n // **CALLED ON BLUR**\n // must be before matching round start date\n const valid =\n (!state.matchingRoundStartDate ||\n state.applicationEndDate < state.matchingRoundStartDate) &&\n (!state.applicationStartDate ||\n state.applicationEndDate > state.applicationStartDate);\n State.update({\n applicationEndDateError: valid\n ? \"\"\n : \"Invalid application end date\",\n });\n },\n error: state.applicationEndDateError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Inputs.Date\"}\n props={{\n label: \"Matching round start date\",\n selectTime: true,\n value: state.matchingRoundStartDate,\n onChange: (date) => State.update({ matchingRoundStartDate: date }),\n validate: () => {\n // **CALLED ON BLUR**\n // must be after application end and before matching round end\n const valid =\n (!state.applicationEndDate ||\n state.matchingRoundStartDate > state.applicationEndDate) &&\n (!state.matchingRoundEndDate ||\n state.matchingRoundStartDate < state.matchingRoundEndDate);\n State.update({\n matchingRoundStartDateError: valid\n ? \"\"\n : \"Invalid round start date\",\n });\n },\n error: state.matchingRoundStartDateError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Inputs.Date\"}\n props={{\n label: \"Matching round end date\",\n // placeholder: \"0\", // TODO: possibly add this back in\n selectTime: true,\n value: state.matchingRoundEndDate,\n onChange: (date) => State.update({ matchingRoundEndDate: date }),\n validate: () => {\n // **CALLED ON BLUR**\n // must be after matching round start\n const valid =\n !state.matchingRoundStartDate ||\n state.matchingRoundEndDate > state.matchingRoundStartDate;\n State.update({\n matchingRoundEndDateError: valid\n ? \"\"\n : \"Invalid round end date\",\n });\n },\n error: state.matchingRoundEndDateError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n <Row>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"Optional: Min matching pool donation amount (in NEAR)\",\n placeholder: \"0\",\n value: state.minMatchingPoolDonationAmount,\n onChange: (amountNear) => {\n State.update({ minMatchingPoolDonationAmount: amountNear });\n },\n validate: () => {\n // **CALLED ON BLUR**\n },\n error: state.referrerFeeMatchingPoolPercentError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n </Row>\n </FormSectionRightDiv>\n </FormSectionContainer>\n {/* <FormDivider /> */}\n <FormSectionContainer>\n {FormSectionLeft(\"Chef details\", \"\")}\n <FormSectionRightDiv>\n <Row>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"Assign chef\",\n placeholder: \"E.g. user.near\",\n value: state.chef,\n onChange: (chef) => State.update({ chef }),\n validate: () => {\n // **CALLED ON BLUR**\n const valid = validateNearAddress(state.chef);\n State.update({\n chefError: valid ? \"\" : \"Invalid NEAR account ID\",\n });\n },\n error: state.chefError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"Chef fee %\",\n placeholder: \"0\",\n percent: true,\n value: state.chefFeePercent,\n onChange: (percent) => {\n validateAndUpdatePercentages(\n percent,\n \"chefFeePercent\",\n \"chefFeePercentError\",\n MAX_CHEF_FEE_BASIS_POINTS / 100\n );\n },\n validate: () => {\n // **CALLED ON BLUR**\n },\n error: state.chefFeePercentError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n </Row>\n </FormSectionRightDiv>\n </FormSectionContainer>\n {/* <FormDivider /> */}\n <FormSectionContainer>\n {FormSectionLeft(\"Application details\", \"\")}\n <FormSectionRightDiv>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"Max. approved projects\",\n placeholder: \"e.g. 20\",\n value: state.maxProjects,\n onChange: (maxProjects) => State.update({ maxProjects }),\n validate: () => {\n // **CALLED ON BLUR**\n const valid = parseInt(state.maxProjects) <= MAX_MAX_PROJECTS;\n State.update({\n maxProjectsError: valid ? \"\" : `Maximum ${MAX_MAX_PROJECTS}`,\n });\n },\n error: state.maxProjectsError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n </FormSectionRightDiv>\n </FormSectionContainer>\n <FormSectionContainer>\n {FormSectionLeft(\"Project Registration\", \"\")}\n <FormSectionRightDiv>\n <Row>\n <Checkbox>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Checkbox\"}\n props={{\n id: \"registrationSelector\",\n checked: state.usePotlockRegistry,\n onClick: (e) => {\n State.update({\n usePotlockRegistry: e.target.checked,\n });\n },\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n <Label htmlFor=\"sybilSelector\">\n Require approval on PotLock registry (recommended)\n </Label>\n </Checkbox>\n </Row>\n </FormSectionRightDiv>\n </FormSectionContainer>\n <FormSectionContainer>\n {FormSectionLeft(\"Donor Sybil Resistance\", \"\")}\n <FormSectionRightDiv>\n <Row>\n <Checkbox>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Checkbox\"}\n props={{\n id: \"sybilSelector\",\n checked: state.useNadabotSybil,\n onClick: (e) => {\n State.update({\n useNadabotSybil: e.target.checked,\n });\n },\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n <Label htmlFor=\"sybilSelector\">\n 🤖 nada.bot human verification (recommended)\n </Label>\n </Checkbox>\n </Row>\n <Row style={{ justifyContent: \"flex-end\", marginTop: \"36px\" }}>\n {!isUpdate && isAdminOrGreater && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"tertiary\",\n text: \"Cancel\",\n style: props.style || {},\n onClick: () => {\n // TODO: handle click\n },\n }}\n />\n )}\n {((isUpdate && isAdminOrGreater) || !isUpdate) && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: isUpdate ? \"Save changes\" : \"Deploy\",\n style: props.style || {},\n onClick: isUpdate ? handleUpdate : handleDeploy,\n // disabled: !canDeploy,\n }}\n />\n )}\n </Row>\n </FormSectionRightDiv>\n </FormSectionContainer>\n <Widget\n src={\"old.potlock.near/widget/Components.ModalMultiAccount\"}\n props={{\n ...props,\n isModalOpen: state.isAdminsModalOpen,\n onClose: () => State.update({ isAdminsModalOpen: false }),\n titleText: \"Add admins\",\n descriptionText: \"Add NEAR account IDs for your admins.\",\n inputValue: state.admin,\n onInputChange: (admin) => {\n State.update({ admin, adminsError: \"\" });\n },\n handleAddAccount: handleAddAdmin,\n handleRemoveAccount: handleRemoveAdmin,\n accountError: state.adminsError,\n accountIds: state.admins.map((admin) => admin.accountId),\n unitText: \"admin\",\n }}\n />\n </FormBody>\n);\n" }, "Pots.Deploy": { "": "const { canDeploy, hrefWithParams } = props;\nconst { HomeBannerStyle } = VM.require(\n \"old.potlock.near/widget/Pots.HomeBannerBackground\"\n) || {\n HomeBannerStyle: {},\n};\nconst POT_CODE_LINK = \"https://github.com/PotLock/core/tree/main/contracts/pot\"; // for directing user to view source code for Pot\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n > div:last-of-type {\n padding: 0px 175px;\n }\n @media only screen and (max-width: 992px) {\n > div:last-of-type {\n padding: 0px 20px;\n }\n }\n`;\nconst SuccessContainer = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n gap: 24px;\n`;\nconst HeaderTitle = styled.div`\n color: #292929;\n font-size: 60px;\n font-weight: 400;\n line-height: 72px;\n word-wrap: break-word;\n font-family: Lora;\n`;\nconst HeaderContainer = styled.div`\n display: flex;\n flex-direction: column;\n position: relative;\n width: 100%;\n justify-content: center;\n min-height: 400px;\n overflow: hidden;\n .background {\n position: absolute;\n pointer-events: none;\n height: 100%;\n left: 0;\n top: 0;\n }\n .content {\n position: relative;\n z-index: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n padding: 64px 175px;\n }\n .sub-title {\n letter-spacing: 1.12px;\n font-weight: 500;\n font-size: 14px;\n margin-top: 0;\n margin-bottom: 24px;\n text-transform: uppercase;\n }\n .title {\n letter-spacing: -0.4px;\n font-weight: 500;\n font-size: 40px;\n font-family: \"Lora\";\n margin: 0;\n }\n .info {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n margin-top: 24px;\n > svg {\n height: 1em;\n }\n }\n @media only screen and (max-width: 992px) {\n .content {\n padding: 64px 20px;\n }\n .title {\n font-size: 36px;\n }\n .btns {\n flex-direction: column;\n gap: 1rem;\n margin-top: 24px;\n }\n .line-break {\n display: none;\n }\n }\n @media only screen and (max-width: 480px) {\n .btns a {\n width: 100%;\n padding: 12px 0;\n }\n }\n`;\nreturn props.deploymentSuccess || state.deploymentSuccess ? (\n <SuccessContainer>\n <HeaderTitle>Deployment Successful!</HeaderTitle>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: \"View all pots\",\n style: props.style || {},\n href: props.hrefWithParams(`?tab=pots`),\n }}\n />\n </SuccessContainer>\n) : (\n <Container>\n <HeaderContainer\n style={{\n ...HomeBannerStyle,\n }}\n >\n <div className=\"content\">\n <h3 className=\"sub-title\">Deploy pot</h3>\n <h1 className=\"title\">\n Deploy a Quadratic <br className=\"line-break\" />\n Funding Round\n </h1>\n <div className=\"info\">\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6.3335 3.66732H7.66683V5.00065H6.3335V3.66732ZM6.3335 6.33398H7.66683V10.334H6.3335V6.33398ZM7.00016 0.333984C3.32016 0.333984 0.333496 3.32065 0.333496 7.00065C0.333496 10.6807 3.32016 13.6673 7.00016 13.6673C10.6802 13.6673 13.6668 10.6807 13.6668 7.00065C13.6668 3.32065 10.6802 0.333984 7.00016 0.333984ZM7.00016 12.334C4.06016 12.334 1.66683 9.94065 1.66683 7.00065C1.66683 4.06065 4.06016 1.66732 7.00016 1.66732C9.94016 1.66732 12.3335 4.06065 12.3335 7.00065C12.3335 9.94065 9.94016 12.334 7.00016 12.334Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n <div>Know More about Quadratic Funding</div>\n </div>\n </div>\n </HeaderContainer>\n <Widget\n src={\"old.potlock.near/widget/Pots.ConfigForm\"}\n props={{\n ...props,\n }}\n />\n </Container>\n);\n" }, "Components.Attribution": { "": "const Attribution = styled.div`\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-top: 100px;\n margin-bottom: 1rem;\n width: 100%;\n div {\n font-size: 11px;\n color: #7b7b7b;\n }\n svg {\n width: 20px;\n }\n @media only screen and (max-width: 480px) {\n margin-top: 86px;\n }\n`;\nreturn (\n <Attribution>\n <div>\n USD prices powered by{\" \"}\n <a href=\"https://www.coingecko.com/\" target=\"_blank\">\n CoinGecko{\" \"}\n </a>\n </div>\n </Attribution>\n);\n" }, "Cart.CheckoutBreakdown": { "": "const { yoctosToNear } = VM.require(\"old.potlock.near/widget/utils\") || {\n yoctosToNear: () => \"\",\n};\nconst { SUPPORTED_FTS } = VM.require(\"old.potlock.near/widget/constants\") || {\n SUPPORTED_FTS: {},\n};\nconst { getCart, clearCart } = VM.require(\n \"old.potlock.near/widget/SDK.cart\"\n) || {\n getCart: () => {},\n clearCart: () => {},\n};\nconst cart = getCart();\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n asyncGetDonationsForDonor: () => {},\n};\nlet DonateSDK =\n VM.require(\"old.potlock.near/widget/SDK.donate\") ||\n (() => ({\n asyncGetDonationsForDonor: () => {},\n getContractId: () => \"\",\n }));\nDonateSDK = DonateSDK({ env: props.env });\nconst DONATION_CONTRACT_ID = DonateSDK.getContractId();\nconst IPFS_BASE_URL = \"https://nftstorage.link/ipfs/\";\nBig.PE = 100;\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n gap: 24px;\n margin-top: 20px;\n width: 380px;\n // background: white;\n @media screen and (max-width: 768px) {\n width: 100%;\n margin-bottom: 50px;\n }\n`;\nconst Title = styled.div`\n color: #2e2e2e;\n font-size: 24px;\n font-weight: 600;\n line-height: 32px;\n word-wrap: break-word;\n`;\nconst CurrencyHeader = styled.div`\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 8px;\n border-radius: 5px;\n background: #f0f0f0;\n`;\nconst CurrencyHeaderText = styled.div`\n color: #7b7b7b;\n font-size: 12px;\n font-weight: 400;\n line-height: 14px;\n word-wrap: break-word;\n`;\nconst BreakdownItemContainer = styled.div`\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 8px;\n`;\nconst BreakdownItemLeft = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-start;\n width: 50%;\n gap: 8px;\n`;\nconst BreakdownItemRight = styled.div`\n display: flex;\n flex: 1;\n flex-direction: row;\n align-items: center;\n justify-content: flex-end;\n`;\nconst BreakdownItemText = styled.div`\n color: #2e2e2e;\n font-size: 14px;\n font-weight: 400;\n line-height: 16px;\n word-wrap: break-word;\n`;\nconst CurrencyIcon = styled.img`\n width: 20px;\n height: 20px;\n`;\nconst TotalContainer = styled.div`\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 8px;\n border-top: 1px #7b7b7b solid;\n`;\nconst TotalText = styled.div`\n color: #2e2e2e;\n font-size: 14px;\n font-weight: 600;\n line-height: 20px;\n word-wrap: break-word;\n`;\nconst ErrorText = styled.div`\n color: #dd3345;\n font-size: 14px;\n font-weight: 400;\n line-height: 20px;\n word-wrap: break-word;\n width: 100%;\n text-align: center;\n`;\nconst MIN_REQUIRED_DONATION_AMOUNT_PER_PROJECT = 0.1;\nconst [tokens, amountsByFt, totalAmount, donationTooSmall] = useMemo(() => {\n const tokens = {};\n const amountsByFt = {};\n let donationTooSmall = false;\n Object.entries(cart || {}).forEach(([projectId, { token, amount }]) => {\n const ft = token.text;\n if (!amountsByFt[ft]) amountsByFt[ft] = 0;\n amountsByFt[ft] += parseFloat(amount || 0);\n if (amountsByFt[ft] < MIN_REQUIRED_DONATION_AMOUNT_PER_PROJECT)\n donationTooSmall = true;\n tokens[ft] = token;\n });\n const totalAmount = Object.values(amountsByFt).reduce(\n (acc, amount) => acc + amount,\n 0\n );\n return [tokens, amountsByFt, totalAmount, donationTooSmall];\n}, [props]);\n// console.log(\"amountsByFt: \", amountsByFt);\n// console.log(\"tokens: \", tokens);\nconst handleDonate = () => {\n const transactions = [];\n let potIdContained;\n Object.entries(cart).forEach(\n ([projectId, { token, amount, referrerId, note, potId }]) => {\n const isFtDonation = token.text != \"NEAR\";\n const amountIndivisible = Big(parseFloat(amount)).mul(\n Big(10).pow(isFtDonation ? token.decimals : 24)\n );\n const args = {};\n if (isFtDonation) {\n args.receiver_id = DONATION_CONTRACT_ID;\n args.amount = amountIndivisible.toString();\n args.memo = JSON.stringify({\n recipient_id: projectId,\n referrer_id: referrerId || null,\n bypass_protocol_fee: false,\n message: note || null,\n });\n } else {\n // pot & generic contract args\n args.project_id = projectId;\n args.referrer_id = referrerId;\n args.message = note;\n // donation contract args\n args.recipient_id = projectId;\n // other\n potIdContained = potId;\n }\n transactions.push({\n contractName: isFtDonation ? token.id : potId ?? DONATION_CONTRACT_ID,\n methodName: isFtDonation ? \"ft_transfer_call\" : \"donate\",\n args,\n deposit: isFtDonation ? \"1\" : amountIndivisible.toString(),\n gas: \"300000000000000\",\n });\n }\n );\n // if cart contains a non-NEAR token, add storage_deposit to beginning of transactions\n // for each non-NEAR donation: 0.008 base amount for donation storage + 0.0001 NEAR per character in message\n if (Object.keys(amountsByFt).some((ft) => ft !== \"NEAR\")) {\n const requiredDepositFloat = transactions.reduce(\n (acc, { methodName, args }) => {\n if (methodName === \"donate\") return acc;\n const baseAmount = 0.008;\n const argsAmount = (args.message.length || 0) * 0.0001;\n return acc + baseAmount + argsAmount;\n },\n 0\n );\n transactions.unshift({\n contractName: DONATION_CONTRACT_ID,\n methodName: \"storage_deposit\",\n args: {},\n deposit: Big(requiredDepositFloat).mul(Big(10).pow(24)),\n gas: \"100000000000000\",\n });\n }\n const now = Date.now();\n Near.call(transactions);\n // NB: we won't get here if user used a web wallet, as it will redirect to the wallet\n // <-------- EXTENSION WALLET HANDLING -------->\n // poll for updates\n // TODO: update this to also poll Pot contract\n const pollIntervalMs = 1000;\n // const totalPollTimeMs = 60000; // consider adding in to make sure interval doesn't run indefinitely\n const pollId = setInterval(() => {\n (potIdContained\n ? PotSDK.asyncGetDonationsForDonor(potIdContained, context.accountId)\n : DonateSDK.asyncGetDonationsForDonor(context.accountId)\n ).then((donations) => {\n // for each project, there should be a matching donation that occurred since now()\n const foundDonations = [];\n // go through donations, add to foundDonations list\n for (const donation of donations) {\n const {\n recipient_id,\n project_id,\n donated_at_ms,\n donated_at,\n total_amount,\n } = donation;\n const matchingCartItem = cart[project_id || recipient_id];\n if (matchingCartItem && (donated_at_ms > now || donated_at > now)) {\n foundDonations.push(donation);\n }\n }\n if (foundDonations.length) {\n // donations found\n // display success message & clear cart\n clearInterval(pollId);\n props.updateSuccessfulDonationRecipientId(\n foundDonations[0].recipient_id\n );\n clearCart();\n }\n });\n }, pollIntervalMs);\n};\n// console.log(\"props\", props);\n// console.log(\"supported fts: \", SUPPORTED_FTS);\n// console.log(\"props.cart: \", props.cart);\n// console.log(\"props.projectId: \", props.projectId);\nreturn (\n <Container>\n <Title>Breakdown summary</Title>\n <CurrencyHeader>\n <CurrencyHeaderText>Currency</CurrencyHeaderText>\n <CurrencyHeaderText>Amount</CurrencyHeaderText>\n </CurrencyHeader>\n {Object.entries(amountsByFt).map(([ft, amount]) => {\n const amountFloat = parseFloat(amount || 0);\n return (\n <BreakdownItemContainer>\n <BreakdownItemLeft>\n {ft == \"NEAR\" ? (\n <CurrencyIcon src={SUPPORTED_FTS.NEAR.iconUrl} />\n ) : (\n <CurrencyIcon src={tokens[ft].icon} />\n )}\n <BreakdownItemText>{tokens[ft].text}</BreakdownItemText>\n </BreakdownItemLeft>\n <BreakdownItemRight>\n <BreakdownItemText>{amountFloat.toFixed(2)}</BreakdownItemText>\n </BreakdownItemRight>\n </BreakdownItemContainer>\n );\n })}\n {Object.keys(amountsByFt).length <= 1 &&\n amountsByFt.NEAR && ( // only show total if NEAR is the only currency being donated (otherwise it is inaccurate and confusing)\n <TotalContainer>\n <TotalText>Total</TotalText>\n <TotalText>{totalAmount.toFixed(2)}</TotalText>\n </TotalContainer>\n )}\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: `Process Donation`,\n disabled:\n !Object.keys(cart).length || donationTooSmall || !context.accountId,\n onClick: handleDonate,\n style: {\n width: \"100%\",\n },\n }}\n />\n {donationTooSmall && (\n <ErrorText>\n Minimum required donation per project is{\" \"}\n {MIN_REQUIRED_DONATION_AMOUNT_PER_PROJECT} N\n </ErrorText>\n )}\n {!context.accountId && <ErrorText>Please sign in to donate</ErrorText>}\n </Container>\n);\n" }, "Pots.Sponsors": { "": "// get donations\nconst { potId, potDetail } = props;\nconst { SUPPORTED_FTS } = VM.require(\"old.potlock.near/widget/constants\") || {\n SUPPORTED_FTS: {},\n};\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getMatchingPoolDonations: () => {},\n};\nlet sponsorshipDonations = PotSDK.getMatchingPoolDonations(potId);\nconst { NEAR } = SUPPORTED_FTS;\nState.init({\n sponsorshipDonations: null,\n});\nif (sponsorshipDonations && !state.sponsorshipDonations) {\n // accumulate donations for each address\n sponsorshipDonations = sponsorshipDonations.reduce(\n (accumulator, currentDonation) => {\n accumulator[currentDonation.donor_id] = {\n amount:\n parseFloat(accumulator[currentDonation.donor_id].amount || 0) +\n parseFloat(\n SUPPORTED_FTS.NEAR.fromIndivisible(currentDonation.net_amount)\n ),\n ...currentDonation,\n };\n return accumulator;\n },\n {}\n );\n // add % share of total to each donation\n const total = SUPPORTED_FTS.NEAR.fromIndivisible(\n potDetail.matching_pool_balance\n );\n sponsorshipDonations = Object.values(sponsorshipDonations).sort(\n (a, b) => b.amount - a.amount\n );\n sponsorshipDonations = sponsorshipDonations.map((donation) => {\n return {\n ...donation,\n percentage_share: ((donation.amount / total) * 100)\n .toFixed(2)\n .replace(/[.,]00$/, \"\"),\n };\n });\n State.update({ sponsorshipDonations });\n}\nif (!state.sponsorshipDonations)\n return <div class=\"spinner-border text-secondary\" role=\"status\" />;\nconst columns = [\"Rank\", \"Donor\", \"Amount\", \"Percentage\"];\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 24px;\n width: 100%;\n @media screen and (min-width: 375px) and (max-width: 768px) {\n width: 99%;\n }\n @media screen and (max-width: 390px) {\n width: 98%;\n }\n`;\nconst TableContainer = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n margin-top: 35px;\n padding-bottom: 1rem;\n`;\nconst { base_currency } = potDetail;\nconst maxRowItemLength = 14;\nreturn (\n <Container>\n <Widget\n src={\"old.potlock.near/widget/Pots.SponsorsBoard\"}\n props={{\n ...props,\n donations: state.sponsorshipDonations.slice(0, 6),\n base_currency: base_currency,\n }}\n />\n <TableContainer>\n <Widget\n src={\"old.potlock.near/widget/Pots.SponsorsTable\"}\n props={{\n ...props,\n sponsors: state.sponsorshipDonations,\n }}\n />\n </TableContainer>\n </Container>\n);\n" }, "Pots.SponsorsTable": { "": "const { sponsors, filter, tab, hrefWithParams } = props;\nconst isInPot = tab === \"pot\";\nconst { nearToUsd } = VM.require(\"old.potlock.near/widget/utils\") || {\n nearToUsd: 1,\n};\nconst [currentPage, setCurrentPage] = useState(1);\nconst perPage = 30; // need to be less than 50\nuseEffect(() => {\n setCurrentPage(1);\n}, [filter]);\nconst nearLogo =\n \"https://ipfs.near.social/ipfs/bafkreicdcpxua47eddhzjplmrs23mdjt63czowfsa2jnw4krkt532pa2ha\";\nconst { getTimePassed, _address, calcNetDonationAmount, reverseArr } =\n VM.require(\"old.potlock.near/widget/Components.DonorsUtils\");\nconst Container = styled.div`\n width: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2rem;\n border-radius: 6px;\n border: 1px solid #7b7b7b;\n overflow: hidden;\n .transcation {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-size: 14px;\n .header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.5rem 1rem;\n gap: 1rem;\n color: #7b7b7b;\n div {\n display: flex;\n align-items: center;\n font-weight: 600;\n &:last-of-type {\n justify-content: flex-end;\n }\n }\n }\n .address {\n width: 190px;\n margin-right: auto;\n justify-content: start !important;\n }\n .rank {\n width: 40px;\n margin-right: 2rem;\n justify-content: center;\n }\n }\n @media only screen and (max-width: 768px) {\n .transcation {\n font-size: 12px;\n .header {\n padding: 0.5rem;\n }\n .rank {\n margin-right: 0;\n width: 30px;\n }\n }\n }\n @media only screen and (max-width: 480px) {\n .transcation .address {\n width: 135px;\n flex: 1;\n }\n }\n`;\nconst TrRow = styled.div`\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n gap: 1rem;\n padding: 1rem;\n border-top: 1px solid #c7c7c7;\n > div {\n display: flex;\n align-items: center;\n }\n .address {\n color: #292929;\n font-weight: 600;\n display: flex;\n align-items: center;\n justify-content: flex-start;\n border-radius: 2px;\n transition: all 200ms;\n .profile-image {\n width: 1.5rem;\n height: 1.5rem;\n margin-right: 1rem;\n }\n }\n .sponsors-amount {\n justify-content: flex-end;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 1rem;\n }\n @media only screen and (max-width: 768px) {\n padding: 1rem 0.5rem;\n }\n`;\nconst Percentage = styled.div`\n background: #ebebeb;\n box-shadow: 0px -1px 0px 0px #dbdbdb inset, 0px 0px 0px 0.5px #dbdbdb;\n border-radius: 4px;\n padding: 2px 4px;\n min-width: 60px;\n text-align: right;\n`;\nconst NoResult = styled.div`\n font-size: 1.125rem;\n text-align: center;\n`;\nconst totalDonations = 0;\nsponsors.forEach((donation) => {\n totalDonations += donation.amount;\n});\nconst ProfileImg = ({ donor_id }) => (\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{ accountId: donor_id, style: {} }}\n />\n);\nreturn sponsors.length ? (\n <Container>\n <div className=\"transcation\">\n <div className=\"header\">\n <div className=\"rank\">Rank</div>\n <div className=\"address\">Donor</div>\n <div>Amount</div>\n {nearToUsd && !isInPot && <div>Amount (USD)</div>}\n </div>\n {sponsors\n .slice((currentPage - 1) * perPage, currentPage * perPage)\n .map((donation, idx) => {\n const { donor_id, amount, percentage_share } = donation;\n return (\n <TrRow>\n <div className=\"rank\">\n #{idx + 1 + (currentPage - 1) * perPage}\n </div>\n <a\n href={hrefWithParams(`?tab=profile&accountId=${donor_id}`)}\n className=\"address\"\n target=\"_blank\"\n >\n <ProfileImg donor_id={donor_id} />\n <OverlayTrigger\n placement=\"top\"\n overlay={<Tooltip>{donor_id}</Tooltip>}\n >\n <div> {_address(donor_id, 15)}</div>\n </OverlayTrigger>\n </a>\n <div className=\"sponsors-amount\">\n {amount.toFixed(2).replace(/[.,]00$/, \"\")}N{\" \"}\n <Percentage>\n {percentage_share === \"0\" ? \"<0.01\" : percentage_share}%\n </Percentage>{\" \"}\n </div>\n </TrRow>\n );\n })}\n </div>\n <Widget\n src={\"old.potlock.near/widget/Components.Pagination\"}\n props={{\n onPageChange: (page) => {\n setCurrentPage(page);\n },\n data: sponsors,\n currentPage,\n perPage: perPage,\n bgColor: \"#292929\",\n }}\n />\n </Container>\n) : (\n <NoResult>No Sponsors</NoResult>\n);\n" }, "ModalDonation.FormPot": { "": "const { NADABOT_HUMAN_METHOD } = VM.require(\n \"old.potlock.near/widget/constants\"\n) || {\n NADABOT_HUMAN_METHOD: \"\",\n};\nconst { VerifyInfo } = VM.require(\n `old.potlock.near/widget/ModalDonation.Banners`\n) || {\n VerifyInfo: () => {},\n Alert: () => {},\n};\nconst { nearToUsd } = VM.require(\"old.potlock.near/widget/utils\");\nconst { Checks } = VM.require(\n \"old.potlock.near/widget/ModalDonation.Checks\"\n) || {\n Checks: () => {},\n};\nconst { AmountInput } = VM.require(\n \"old.potlock.near/widget/ModalDonation.AmountInput\"\n) || {\n AmountInput: () => {},\n};\nconst { _address } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n) || {\n _address: (address) => address,\n};\nconst { Alert } = VM.require(\n \"old.potlock.near/widget/ModalDonation.Banners\"\n) || {\n Alert: () => {},\n};\nconst Form = styled.div`\n display: flex;\n flex-direction: column;\n padding: 1.5rem 0;\n`;\nconst Content = styled.div`\n display: flex;\n flex-direction: column;\n padding: 0 2rem;\n @media only screen and (max-width: 480px) {\n padding: 0 1.125rem;\n }\n`;\nconst Label = styled.div`\n font-weight: 500;\n margin-bottom: 0.5rem;\n margin-top: 0.5rem;\n`;\nconst CurrentBalance = styled.div`\n display: flex;\n margin-top: 0.5rem;\n gap: 0.5rem;\n flex-wrap: wrap;\n justify-content: flex-end;\n .amount-alert {\n color: #e54141;\n }\n .balance {\n display: flex;\n gap: 0.5rem;\n div:last-of-type {\n color: #7b7b7b;\n }\n }\n`;\nconst TotalAmount = styled.div`\n display: flex;\n gap: 0.5rem;\n align-items: center;\n margin-left: auto;\n .label {\n color: #7b7b7b;\n }\n .amount {\n font-weight: 600;\n .usd {\n color: #7b7b7b;\n }\n }\n @media only screen and (max-width: 480px) {\n width: 100%;\n justify-content: space-between;\n }\n`;\nconst Projects = styled.div`\n padding: 8px 0;\n border-top: 1px solid #ebebeb;\n margin-top: 1.5rem;\n display: flex;\n flex-direction: column;\n height: 238px;\n overflow-y: scroll;\n .project {\n display: flex;\n align-items: center;\n gap: 1rem;\n cursor: pointer;\n padding: 0.5rem 2rem;\n transition: 300ms ease-in-out;\n &:hover,\n &.selected {\n background: rgba(235, 235, 235, 0.24);\n .check {\n border-color: #dd3345;\n svg {\n display: block;\n }\n }\n }\n }\n .profile-image {\n width: 40px;\n height: 40px;\n box-shadow: 0px 0px 1px 0px #a6a6a6 inset;\n border-radius: 50%;\n }\n .info {\n display: flex;\n flex-direction: column;\n .name {\n font-weight: 600;\n }\n .address {\n color: #7b7b7b;\n transition: all 300ms;\n &:hover {\n text-decoration: none;\n color: #dd3345;\n }\n }\n }\n .check {\n margin-left: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n border: 2px solid #c7c7c7;\n border-radius: 50%;\n svg {\n display: none;\n width: 12px;\n }\n &.selected {\n border-color: #dd3345;\n svg {\n display: block;\n }\n }\n }\n @media only screen and (max-width: 480px) {\n .project {\n padding: 0.5rem 1.125rem;\n }\n }\n`;\nconst ProjectAmount = styled.div`\n margin-left: auto;\n position: relative;\n display: flex;\n border-radius: 6px;\n background: rgb(246, 245, 243);\n box-shadow: rgb(255, 255, 255) 0px 1px 0px 0px,\n rgba(41, 41, 41, 0.1) 0px 0px 4px 0px,\n rgba(41, 41, 41, 0.1) 0px 2px 4px -1px inset,\n rgba(41, 41, 41, 0.1) 0px 8px 16px -4px inset;\n input {\n padding: 10px 16px;\n padding-right: 46px;\n text-align: right;\n width: 120px;\n background: transparent;\n border: none;\n }\n svg {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n right: 1rem;\n width: 16px;\n }\n`;\nconst Button = styled.div`\n display: flex;\n margin-top: 4rem;\n margin-bottom: 0.5rem;\n padding: 0 2rem;\n button {\n padding: 12px 16px;\n width: 100%;\n font-weight: 500;\n }\n @media only screen and (max-width: 480px) {\n margin-top: 2rem;\n }\n`;\nconst ProfileImg = ({ profile }) => (\n <Widget\n src={\"old.potlock.near/widget/Project.ProfileImage\"}\n props={{\n profile,\n style: {},\n }}\n />\n);\nconst donationTypes = [\n {\n label: \"Auto\",\n info: \"(allocate funds evenly across multiple projects)\",\n val: \"auto\",\n disabled: false,\n },\n {\n label: \"Manual\",\n info: \"(manually specify amount for each project)\",\n val: \"manual\",\n disabled: false,\n },\n];\nconst isEmpty = (obj) => {\n return Object.keys(obj).length === 0;\n};\nconst FormPot = (props) => {\n const {\n amount,\n amountError,\n DENOMINATION_OPTION,\n updateState,\n selectedDenomination,\n donationType,\n ftBalance,\n hrefWithParams,\n selectedProjects,\n NADABOT_CONTRACT_ID,\n } = props;\n const projects = props.projects ?? [];\n const projectHegiht = 58;\n const projectsContaienrHegiht =\n projects.length > 4 ? 234 : projectHegiht * projects.length;\n const HandleAmoutChange = (amount) => {\n amount = amount.replace(/[^\\d.]/g, \"\"); // remove all non-numeric characters except for decimal\n if (amount === \".\") amount = \"0.\";\n updateState({ amount, amountError: \"\" });\n // error if amount is greater than balance\n if (amount > ftBalance) {\n updateState({\n amountError:\n \"You don’t have enough balance to complete this transaction.\",\n });\n } else if (parseFloat(amount) < 0.1) {\n updateState({ amountError: \"Minimum donation is 0.1 NEAR\" });\n }\n };\n const handleAddProject = (project) => {\n const updatedProjects = selectedProjects;\n if (selectedProjects[project] === \"\") {\n delete updatedProjects[project];\n } else {\n updatedProjects[project] = \"\";\n }\n updateState({\n selectedProjects: updatedProjects,\n });\n };\n const totalAmountAllocated = 0;\n Object.values(selectedProjects).forEach(\n (amount) => (totalAmountAllocated += parseFloat(amount || 0))\n );\n totalAmountAllocated = totalAmountAllocated.toFixed(1);\n const handleProjectAmount = (project, amount) => {\n amount = amount.replace(/[^\\d.]/g, \"\"); // remove all non-numeric characters except for decimal\n if (amount === \".\") amount = \"0.\";\n const updatedProjects = selectedProjects;\n updatedProjects[project] = amount;\n const totalAmount = 0;\n Object.values(updatedProjects).forEach(\n (amount) => (totalAmount += parseFloat(amount))\n );\n if (totalAmount > ftBalance && ftBalance !== null) {\n updateState({\n amountError:\n \"You don’t have enough balance to complete this transaction.\",\n });\n } else if (parseFloat(amount) < 0.1 && parseFloat(amount) !== 0) {\n updateState({ amountError: \"Minimum donation is 0.1 NEAR\" });\n } else {\n updateState({ amountError: \"\" });\n }\n updateState({\n selectedProjects: updatedProjects,\n });\n };\n const isUserHumanVerified = Near.view(\n NADABOT_CONTRACT_ID,\n NADABOT_HUMAN_METHOD,\n {\n account_id: accountId,\n }\n );\n const needsToVerify = isUserHumanVerified === false;\n return (\n <Form>\n <Content>\n <Label>How do you want to allocate funds?</Label>\n <Checks\n options={donationTypes}\n value={donationType}\n onClick={(val) => {\n console.log(\"donationType\", val);\n updateState({\n selectedProjects: {},\n donationType: val,\n });\n }}\n />\n {donationType === \"auto\" && (\n <>\n <Label\n style={{\n marginTop: \"1.5rem\",\n }}\n >\n Amount\n </Label>\n <AmountInput\n value={amount}\n donationType={donationType}\n HandleAmoutChange={HandleAmoutChange}\n updateState={updateState}\n denominationOptions={DENOMINATION_OPTION}\n selectedDenomination={selectedDenomination}\n />\n </>\n )}\n <CurrentBalance>\n {ftBalance && (\n <div className=\"balance\">\n <div>\n {ftBalance} <span> {selectedDenomination.text} </span>\n </div>\n <div>available</div>\n </div>\n )}\n {donationType === \"manual\" && (\n <TotalAmount>\n <div className=\"label\">Total amount allocated</div>\n <div className=\"amount\">\n {totalAmountAllocated}\n <span>NEAR</span>\n {nearToUsd && (\n <span className=\"usd\">\n ~$\n {nearToUsd}\n </span>\n )}\n </div>\n </TotalAmount>\n )}\n </CurrentBalance>\n {amountError && <Alert error={amountError} />}\n {needsToVerify && <VerifyInfo />}\n </Content>\n <Projects style={{ height: projectsContaienrHegiht + \"px\" }}>\n {projects.map(({ project_id }) => {\n const profile = Social.getr(`${project_id}/profile`);\n return (\n <div\n className={`project ${\n selectedProjects[project_id] === \"\" ? \"selected\" : \"\"\n }`}\n style={{\n cursor: donationType == \"auto\" ? \"pointer\" : \"default\",\n }}\n key={project_id}\n onClick={() =>\n donationType == \"auto\" ? handleAddProject(project_id) : {}\n }\n >\n <ProfileImg profile={profile} />\n <div className=\"info\">\n {profile?.name && (\n <div className=\"name\">{_address(profile?.name, 20)}</div>\n )}\n <a\n className=\"address\"\n href={hrefWithParams(`?tab=project&projectId=${project_id}`)}\n target=\"_blank\"\n >\n {_address(project_id, 20)}\n </a>\n </div>\n {donationType === \"manual\" ? (\n <ProjectAmount>\n <input\n className=\"amount\"\n type=\"text\"\n placeholder=\"0.00\"\n onChange={(e) =>\n handleProjectAmount(project_id, e.target.value)\n }\n />\n <svg\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <g clip-path=\"url(#clip0_454_78)\">\n <circle\n cx=\"8\"\n cy=\"8\"\n r=\"7.25\"\n stroke=\"#292929\"\n stroke-width=\"1.5\"\n />\n <path\n d=\"M11.1477 4C10.851 4 10.5763 4.15333 10.421 4.406L8.74866 6.88867C8.72453 6.92441 8.71422 6.96772 8.71967 7.01051C8.72511 7.05329 8.74594 7.09264 8.77826 7.1212C8.81057 7.14976 8.85218 7.1656 8.89531 7.16574C8.93844 7.16589 8.98015 7.15034 9.01266 7.122L10.6587 5.69467C10.6683 5.68598 10.6802 5.68028 10.6931 5.67828C10.7059 5.67628 10.719 5.67806 10.7308 5.6834C10.7426 5.68875 10.7526 5.69742 10.7596 5.70836C10.7665 5.7193 10.7702 5.73203 10.77 5.745V10.215C10.77 10.2287 10.7658 10.2421 10.7579 10.2534C10.7501 10.2646 10.7389 10.2732 10.726 10.2778C10.7131 10.2825 10.6991 10.2831 10.6858 10.2795C10.6726 10.2758 10.6608 10.2682 10.652 10.2577L5.67667 4.30167C5.59667 4.20709 5.49701 4.1311 5.38463 4.079C5.27226 4.0269 5.14987 3.99994 5.026 4H4.85233C4.62628 4 4.40949 4.0898 4.24964 4.24964C4.0898 4.40949 4 4.62628 4 4.85233V11.1477C4 11.3333 4.06061 11.5139 4.17263 11.6619C4.28465 11.81 4.44194 11.9174 4.6206 11.9679C4.79926 12.0184 4.98952 12.0091 5.16245 11.9416C5.33538 11.874 5.48152 11.7519 5.57867 11.5937L7.251 9.111C7.27513 9.07525 7.28544 9.03194 7.27999 8.98916C7.27455 8.94637 7.25372 8.90703 7.22141 8.87846C7.18909 8.8499 7.14748 8.83407 7.10435 8.83392C7.06122 8.83377 7.01951 8.84932 6.987 8.87766L5.341 10.3053C5.33134 10.3139 5.31939 10.3195 5.3066 10.3215C5.29381 10.3234 5.28074 10.3216 5.26898 10.3162C5.25721 10.3108 5.24726 10.3021 5.24034 10.2912C5.23342 10.2803 5.22983 10.2676 5.23 10.2547V5.784C5.22997 5.77027 5.23418 5.75687 5.24206 5.74563C5.24993 5.73438 5.26109 5.72584 5.274 5.72117C5.28691 5.71651 5.30094 5.71594 5.31419 5.71955C5.32743 5.72315 5.33924 5.73076 5.348 5.74133L10.3227 11.698C10.4847 11.8893 10.7227 11.9997 10.9733 12H11.147C11.373 12.0001 11.5898 11.9104 11.7498 11.7507C11.9097 11.591 11.9997 11.3744 12 11.1483V4.85233C11.9999 4.62631 11.9101 4.40956 11.7503 4.24974C11.5904 4.08992 11.3737 4.00009 11.1477 4Z\"\n fill=\"#292929\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_454_78\">\n <rect width=\"16\" height=\"16\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n </ProjectAmount>\n ) : (\n <div className=\"check\">\n <svg\n viewBox=\"0 0 12 10\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <g clip-path=\"url(#clip0_468_92)\">\n <path\n d=\"M1 5.1618L4 8.16197L11.1621 1\"\n stroke=\"#DD3345\"\n stroke-width=\"2\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_468_92\">\n <rect width=\"12\" height=\"10\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n </div>\n )}\n </div>\n );\n })}\n </Projects>\n <Button>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n disabled:\n isEmpty(selectedProjects) ||\n (donationType === \"auto\"\n ? amountError || parseFloat(amount) === 0 || !amount\n : totalAmountAllocated > ftBalance ||\n amountError ||\n parseFloat(totalAmountAllocated) === 0),\n text: \"Proceed to donate\",\n onClick: () => {\n if (donationType === \"auto\")\n updateState({ currentPage: \"confirmPot\" });\n else {\n updateState({\n currentPage: \"confirmPot\",\n amount: totalAmountAllocated,\n });\n }\n },\n }}\n />\n </Button>\n </Form>\n );\n};\nreturn {\n FormPot,\n};\n" }, "Pots.ButtonVerifyToDonate": { "": "return (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n ...props,\n type: \"primary\",\n text: \"Verify to Donate\",\n style: props.style || {},\n href: props.href,\n target: \"_blank\",\n }}\n />\n);\n" }, "ModalDonation.Form": { "": "const { NADABOT_HUMAN_METHOD } = VM.require(\n \"old.potlock.near/widget/constants\"\n) || {\n NADABOT_HUMAN_METHOD: \"\",\n};\nconst { AmountInput } = VM.require(\n \"old.potlock.near/widget/ModalDonation.AmountInput\"\n) || {\n AmountInput: () => {},\n};\nconst { Checks } = VM.require(\n \"old.potlock.near/widget/ModalDonation.Checks\"\n) || {\n Checks: () => {},\n};\nconst { VerifyInfo, Alert } = VM.require(\n \"old.potlock.near/widget/ModalDonation.Banners\"\n) || {\n VerifyInfo: () => {},\n Alert: () => {},\n};\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getConfig: () => {},\n};\nconst Form = styled.div`\n display: flex;\n flex-direction: column;\n padding: 1.5rem 2rem;\n @media only screen and (max-width: 480px) {\n padding: 1.5rem 1.125rem;\n }\n`;\nconst Label = styled.div`\n font-weight: 500;\n margin-bottom: 0.5rem;\n margin-top: 0.5rem;\n`;\nconst Button = styled.div`\n display: flex;\n margin-top: 4rem;\n margin-bottom: 0.5rem;\n button {\n padding: 12px 16px;\n width: 100%;\n font-weight: 500;\n }\n @media only screen and (max-width: 480px) {\n margin-top: 2rem;\n }\n`;\nconst CurrentBalance = styled.div`\n display: flex;\n margin-top: 0.5rem;\n gap: 0.5rem;\n justify-content: flex-end;\n .amount-alert {\n color: #e54141;\n }\n .balance {\n display: flex;\n gap: 0.5rem;\n div:last-of-type {\n color: #7b7b7b;\n }\n }\n`;\nconst PotWrapper = styled.div`\n display: flex;\n flex-direction: column;\n margin-top: 1.5rem;\n`;\nconst PotSelector = styled.div`\n display: flex;\n > div:last-of-type {\n width: 100%;\n }\n`;\nconst Pot = styled.div`\n border-radius: 6px;\n border: 1px solid #dbdbdb;\n border-bottom-width: 2px;\n background: #fff;\n padding: 0.75rem 1rem;\n`;\nconst SelectPot = ({ selectedRound, activeRoundsOptions, updateState }) => (\n <PotSelector>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Dropdown\"}\n props={{\n sortVal: activeRoundsOptions\n ? activeRoundsOptions[selectedRound].label\n : \"\",\n showCount: false,\n sortList: Object.values(activeRoundsOptions),\n buttonStyle: {\n border: \"1px solid #dbdbdb\",\n padding: \"0.75rem 1rem\",\n borderBottomWidth: \"2px\",\n borderRadius: \"6px\",\n justifyContent: \"space-between\",\n },\n menuStyle: {\n top: \"120%\",\n },\n FilterMenuCustomStyle: `left:0; right:auto;`,\n handleSortChange: ({ val }) => {\n updateState({\n selectedRound: val,\n });\n },\n }}\n />\n </PotSelector>\n);\nconst FormDirect = (props) => {\n const {\n projectId,\n profile,\n amount,\n amountError,\n denominationOptions,\n updateState,\n selectedDenomination,\n donationType,\n ftBalance,\n activeRounds,\n NADABOT_CONTRACT_ID,\n accountId,\n } = props;\n const isUserHumanVerified = Near.view(\n NADABOT_CONTRACT_ID,\n NADABOT_HUMAN_METHOD,\n {\n account_id: accountId,\n }\n );\n const needsToVerify = isUserHumanVerified === false && donationType === \"pot\";\n const donationTypes = [\n {\n label: \"Direct donation\",\n val: \"direct\",\n disabled: false,\n },\n {\n label: \"Quadratically matched donation\",\n val: \"pot\",\n disabled: !activeRounds || activeRounds.length === 0,\n disabledText: \"(no pots available)\",\n },\n ];\n const activeRoundsOptions = {};\n (activeRounds || []).forEach((round) => {\n activeRoundsOptions[round] = {\n label: PotSDK.getConfig(round)?.pot_name || round,\n val: round,\n };\n });\n const isFtDonation = selectedDenomination.text !== \"NEAR\";\n const HandleAmoutChange = (amount) => {\n amount = amount.replace(/[^\\d.]/g, \"\"); // remove all non-numeric characters except for decimal\n if (amount === \".\") amount = \"0.\";\n updateState({ amount, amountError: \"\" });\n // error if amount is greater than balance\n if (amount > ftBalance && ftBalance !== null) {\n updateState({\n amountError:\n \"You don’t have enough balance to complete this transaction.\",\n });\n } else if (!isFtDonation && parseFloat(amount) < 0.1) {\n updateState({ amountError: \"Minimum donation is 0.1 NEAR\" });\n }\n };\n const isLoading =\n donationType === \"pot\"\n ? isUserHumanVerified === null || activeRounds === null\n : false;\n return projectId ? (\n profile === null ? (\n <Widget src={\"old.potlock.near/widget/Components.Loading\"} />\n ) : (\n <Form>\n <Label>How do you want to donate?</Label>\n <Checks\n options={donationTypes}\n value={donationType}\n onClick={(val) =>\n updateState({\n donationType: val,\n })\n }\n />\n {donationType === \"pot\" && (\n <PotWrapper>\n <Label>Select Pot</Label>\n <SelectPot {...props} activeRoundsOptions={activeRoundsOptions} />\n </PotWrapper>\n )}\n <Label\n style={{\n marginTop: \"1.5rem\",\n }}\n >\n Amount\n </Label>\n <AmountInput\n value={amount}\n donationType={donationType}\n HandleAmoutChange={HandleAmoutChange}\n updateState={updateState}\n denominationOptions={denominationOptions}\n selectedDenomination={selectedDenomination}\n />\n {ftBalance && (\n <CurrentBalance>\n <div className=\"balance\">\n <div>\n {ftBalance} <span> {selectedDenomination.text} </span>\n </div>\n <div>available</div>\n </div>\n </CurrentBalance>\n )}\n {amountError && <Alert error={amountError} />}\n {needsToVerify && <VerifyInfo />}\n <Button>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n disabled: amountError || !amount,\n text: isLoading ? \"Loading...\" : \"Proceed to donate\",\n onClick: () => updateState({ currentPage: \"confirm\" }),\n }}\n />\n </Button>\n </Form>\n )\n ) : (\n \"\"\n );\n};\nreturn {\n FormDirect,\n};\n" }, "Components.ProjectCard": { "": "const { id, review_notes, status, totalAmount } = props;\nconst { getTagsFromSocialProfileData } = VM.require(\n \"old.potlock.near/widget/utils\"\n) || {\n getTagsFromSocialProfileData: () => [],\n};\nconst IPFS_BASE_URL = \"https://ipfs.near.social/ipfs/\";\nconst cardData = Social.getr(`${id}/profile`);\nlet DonateSDK =\n VM.require(\"old.potlock.near/widget/SDK.donate\") ||\n (() => ({\n getDonationsForRecipient: () => {},\n }));\nDonateSDK = DonateSDK({ env: props.env });\nconst donationsForProject = DonateSDK.getDonationsForRecipient(id);\nconst Card = styled.a`\n display: flex;\n flex-direction: column;\n width: 408px;\n border-radius: 2px;\n background: white;\n box-shadow: 0px -2px 0px #dbdbdb inset;\n border: 1px solid #292929;\n &:hover {\n text-decoration: none;\n cursor: pointer;\n }\n @media screen and (max-width: 768px) {\n width: 340px;\n }\n min-height: 429px;\n margin-left: auto;\n margin-right: auto;\n height: max-content;\n overflow: hidden;\n`;\nconst CardBody = styled.div`\n position: relative;\n padding: 24px;\n display: flex;\n flex-direction: column;\n gap: 16px;\n flex-grow: 1;\n`;\nconst CardImage = styled.img`\n height: 150px;\n min-height: 150px;\n width: 100%;\n object-fit: cover;\n`;\nconst CardTitle = styled.div`\n color: #292929;\n font-size: 17px;\n font-style: normal;\n font-weight: 600;\n line-height: 24px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n`;\nconst CardDescription = styled.div`\n color: #292929;\n font-size: 17px;\n font-style: normal;\n font-weight: 400;\n line-height: 28px;\n flex-grow: 1;\n`;\nconst CardTag = styled.div`\n color: #292929;\n width: max-content;\n white-space: nowrap;\n padding: 8px;\n border-radius: 4px;\n box-shadow: 0px -1px 0px 0px #c7c7c7 inset, 0px 0px 0px 0.5px #c7c7c7;\n border: 1px solid #c7c7c7;\n font-size: 14px;\n font-style: normal;\n font-weight: 400;\n line-height: 20px;\n`;\nconst CardTagContainer = styled.div`\n display: flex;\n gap: 12px;\n flex-wrap: wrap;\n`;\nconst CardAvatar = styled.img`\n position: absolute;\n top: -20px;\n left: 24px;\n border-radius: 100%;\n width: 40px;\n height: 40px;\n border: 3px solid #fff;\n`;\nconst CardFooter = styled.div`\n border-top: 1px solid #000;\n padding: 16px 24px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n`;\nconst TotalDonate = styled.div`\n color: #292929;\n font-size: 17px;\n font-style: normal;\n font-weight: 600;\n line-height: 24px;\n`;\nconst DonationButton = styled.button`\n padding: 12px 16px;\n font-size: 14px;\n font-style: normal;\n font-weight: 500;\n line-height: 20px;\n background: #fef6ee;\n border-radius: 6px;\n border: none;\n box-shadow: 0px -2px 0px 0px #464646 inset, 0px 0px 0px 1px #464646;\n &:hover {\n background: #dd3345;\n color: #fff;\n }\n`;\nconst AddToCartButton = styled.button`\n border: none;\n background: none;\n color: #dd3345;\n text-decoration: none;\n &:hover {\n text-decoration: underline;\n }\n padding: 12px 16px;\n`;\nconst ButtonGroup = styled.div`\n display: flex;\n gap: 10px;\n align-items: center;\n`;\nconst getCategory = (category) => {\n switch (category) {\n case \"social-impact\":\n return \"Social Impact\";\n case \"non-profit\":\n return \"Non Profit\";\n case \"climate\":\n return \"Climate\";\n case \"public-good\":\n return \"Public Good\";\n case \"de-sci\":\n return \"Desci\";\n case \"open-source\":\n return \"Open Source\";\n case \"community\":\n return \"Community\";\n case \"education\":\n return \"Education\";\n }\n};\nconst projectUrl = props.hrefWithParams(`?tab=project&projectId=${id}`);\nconst tags = getTagsFromSocialProfileData(cardData);\nreturn (\n <>\n <Card href={projectUrl}>\n <CardImage\n src={\n cardData &&\n cardData?.backgroundImage &&\n cardData?.backgroundImage?.ipfs_cid\n ? `${IPFS_BASE_URL}${cardData.backgroundImage.ipfs_cid}`\n : \"https://ipfs.near.social/ipfs/bafkreih4i6kftb34wpdzcuvgafozxz6tk6u4f5kcr2gwvtvxikvwriteci\"\n }\n alt=\"background\"\n />\n <CardBody>\n <CardAvatar\n src={\n cardData && cardData?.image && cardData?.image?.ipfs_cid\n ? `${IPFS_BASE_URL}${cardData.image.ipfs_cid}`\n : \"https://ipfs.near.social/ipfs/bafkreih4i6kftb34wpdzcuvgafozxz6tk6u4f5kcr2gwvtvxikvwriteci\"\n }\n alt=\"avatar\"\n />\n <CardTitle>{cardData?.name}</CardTitle>\n <CardDescription>\n {cardData && cardData?.description.length > 60\n ? cardData.description.slice(0, 70) + \"...\"\n : cardData.description}\n </CardDescription>\n <CardTagContainer>\n {tags.map((tag) => (\n <CardTag key={tag}>{tag}</CardTag>\n ))}\n </CardTagContainer>\n </CardBody>\n <CardFooter>\n <TotalDonate>\n ${totalAmount(donationsForProject)}{\" \"}\n <span style={{ fontWeight: 400 }}>Raised</span>\n </TotalDonate>\n <ButtonGroup>\n <AddToCartButton\n onClick={(e) => {\n e.preventDefault();\n if (existsInCart) {\n props.removeProjectsFromCart([props.id]);\n } else {\n props.addProjectsToCart([\n {\n id: props.id,\n amount: \"1\",\n ft: \"NEAR\",\n referrerId: props.referrerId,\n },\n ]);\n if (props.showModal) {\n props.setIsCartModalOpen(true);\n }\n }\n }}\n >\n Add to cart\n </AddToCartButton>\n <DonationButton\n onClick={(e) => {\n e.preventDefault();\n props.openDonateToProjectModal(props.id);\n }}\n >\n Donate\n </DonationButton>\n </ButtonGroup>\n </CardFooter>\n </Card>\n </>\n);\n" }, "Components.NewHero": { "": "const Container = styled.div`\n display: flex;\n flex-direction: column;\n`;\nconst HeroContainer = styled.div`\n display: flex;\n flex-direction: column;\n position: relative;\n width: 100%;\n justify-content: center;\n border: 1px solid #f8d3b0;\n border-radius: 12px;\n overflow: hidden;\n .background {\n position: absolute;\n pointer-events: none;\n left: 0px;\n width: 100%;\n top: 0px;\n min-height: 600px;\n }\n .content {\n position: relative;\n z-index: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n padding: 64px 40px;\n }\n .sub-title {\n color: #dd3345;\n font-weight: 600;\n font-size: 16px;\n margin-top: 0;\n margin-bottom: 12px;\n }\n .title {\n letter-spacing: -0.4px;\n font-weight: 500;\n font-size: 40px;\n font-family: \"Lora\";\n margin: 0;\n }\n .btns {\n display: flex;\n align-items: center;\n gap: 2rem;\n margin-top: 40px;\n font-size: 14px;\n a,\n button {\n padding: 12px 16px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: 500;\n border-radius: 6px;\n box-shadow: 0px 0px 0px 1px #292929, 0px -2px 0px 0px #292929 inset;\n border: none;\n text-decoration: none;\n color: #292929;\n transition: all 300ms;\n &:hover {\n background: #292929;\n color: white;\n }\n }\n button {\n color: white;\n background: #dd3345;\n &:hover {\n }\n }\n }\n @media only screen and (max-width: 768px) {\n .content {\n padding: 48px 20px;\n }\n .title {\n font-size: 36px;\n }\n .btns {\n flex-direction: column;\n gap: 1rem;\n margin-top: 24px;\n }\n .line-break {\n display: none;\n }\n }\n @media only screen and (max-width: 480px) {\n .btns a,\n button {\n width: 100%;\n padding: 12px 0;\n }\n }\n`;\nconst Line = styled.div`\n width: 100%;\n height: 1px;\n background: #ebebeb;\n margin-top: 1rem;\n`;\nconst { HomeBannerStyle } = VM.require(\n \"old.potlock.near/widget/Pots.HomeBannerBackground\"\n) || {\n HomeBannerStyle: {},\n};\nconst { DonationStats } = VM.require(\n \"old.potlock.near/widget/Project.DonationStats\"\n) || {\n DonationStats: () => {},\n};\nconst NewHero = ({ isRegisteredProject, accountId, donateRandomly }) => {\n return (\n <Container>\n <HeroContainer\n style={{\n ...HomeBannerStyle,\n }}\n >\n <div className=\"content\">\n <h3 className=\"sub-title\">Transforming Funding for Public Goods</h3>\n <h1 className=\"title\">\n Discover impact projects, donate directly, &{\" \"}\n <br className=\"line-break\" /> participate in funding rounds.\n </h1>\n <div className=\"btns\">\n <button onClick={donateRandomly} className=\"donate-btn\">\n Donate Randomly\n </button>\n <a\n href={\n isRegisteredProject\n ? `?tab=project&projectId=${accountId}`\n : \"?tab=createproject\"\n }\n >\n {isRegisteredProject\n ? \"View Your Project\"\n : \"Register Your Project\"}\n </a>\n </div>\n </div>\n </HeroContainer>\n <DonationStats />\n <Line />\n </Container>\n );\n};\nreturn {\n NewHero,\n};\n" }, "Inputs.Select": { "": "const label = props.label ?? \"Label\";\nconst noLabel = props.noLabel ?? false;\nconst placeholder = props.placeholder ?? \"Select an option\";\nconst value = props.value ?? \"\";\nconst options = props.options ?? [];\nconst onChange = props.onChange ?? (() => {});\nconst validate = props.validate ?? (() => {});\nconst error = props.error ?? \"\";\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n padding: 0px;\n gap: 0.45em;\n width: 100%;\n`;\nconst Label = styled.label`\n font-weight: 500;\n font-size: 14px;\n line-height: 16px;\n word-wrap: break-word;\n color: #2e2e2e;\n`;\nconst Error = styled.span`\n display: inline-block;\n font-style: normal;\n font-weight: 400;\n font-size: 0.75em;\n line-height: 1.25em;\n color: #ff4d4f;\n height: 0;\n overflow: hidden;\n transition: height 0.3s ease-in-out;\n &.show {\n height: 1.25em;\n }\n`;\nconst Input = styled.div`\n box-sizing: border-box;\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n padding: 0.5em 0.75em;\n gap: 10px;\n background: #ffffff;\n border: 1px solid #d0d5dd;\n // box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);\n boxshadow: 0px -2px 0px rgba(93, 93, 93, 0.24) inset;\n border-radius: 4px;\n color: #101828;\n width: 100%;\n`;\nconst Placeholder = styled.span`\n color: #a0a3a8;\n`;\nconst scaleOut = styled.keyframes`\n from {\n transform: scaleY(0);\n }\n to {\n transform: scaleY(1);\n }\n`;\nconst Content = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n padding: 0;\n gap: 0.5em;\n width: 100%;\n border: 1px solid #d0d5dd;\n border-radius: 4px;\n background: #ffffff;\n z-index: 3 !important;\n /* &[data-state=\"open\"] { */\n /* animation: ${scaleOut} 0.2s ease-in-out; */\n /* } */\n /**/\n /* &[data-state=\"closed\"] { */\n /* animation: ${scaleOut} 0.2s ease-in-out reverse; */\n /* } */\n`;\nconst Viewport = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n padding: 0;\n width: 100%;\n`;\nconst Item = styled.button`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n padding: 0.5em 0.75em;\n gap: 0.5em;\n width: 100%;\n cursor: pointer;\n background: transparent;\n border: none;\n transition: background 0.2s ease-in-out;\n &:nth-child(n + 1) {\n border-top: 1px solid #d0d5dd;\n }\n &:hover {\n background: #d0d5dd;\n boder: none;\n }\n &:focus {\n outline: none;\n }\n`;\nreturn (\n <Container style={props.containerStyles || {}}>\n {noLabel ? <></> : <Label>{label}</Label>}\n <Select.Root\n value={value?.value}\n onValueChange={(value) =>\n onChange(options.find((option) => option.value === value))\n }\n >\n <Select.Trigger asChild={true}>\n <Input style={props.inputStyles || {}}>\n {props.iconLeft && props.iconLeft}\n <Select.Value\n aria-label={value.value}\n placeholder={<Placeholder>{placeholder}</Placeholder>}\n />\n <Select.Icon>\n <svg\n width=\"12\"\n height=\"8\"\n viewBox=\"0 0 12 8\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M10.59 0.295044L6 4.87504L1.41 0.295044L0 1.70504L6 7.70504L12 1.70504L10.59 0.295044Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n </Select.Icon>\n </Input>\n </Select.Trigger>\n <Select.Content asChild={true}>\n <Content>\n <Select.Viewport asChild={true}>\n <Viewport>\n {options.map(({ text, value }) => (\n <Select.Item value={value} asChild={true}>\n <Item>\n <Select.ItemText>{text}</Select.ItemText>\n <Select.ItemIndicator>\n <svg\n width=\"15\"\n height=\"15\"\n viewBox=\"0 0 15 15\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M11.4669 3.72684C11.7558 3.91574 11.8369 4.30308 11.648 4.59198L7.39799 11.092C7.29783 11.2452 7.13556 11.3467 6.95402 11.3699C6.77247 11.3931 6.58989 11.3355 6.45446 11.2124L3.70446 8.71241C3.44905 8.48022 3.43023 8.08494 3.66242 7.82953C3.89461 7.57412 4.28989 7.55529 4.5453 7.78749L6.75292 9.79441L10.6018 3.90792C10.7907 3.61902 11.178 3.53795 11.4669 3.72684Z\"\n fill=\"currentColor\"\n fill-rule=\"evenodd\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </Select.ItemIndicator>\n </Item>\n </Select.Item>\n ))}\n </Viewport>\n </Select.Viewport>\n </Content>\n </Select.Content>\n </Select.Root>\n </Container>\n);\n" }, "Pots.Projects": { "": "const PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getApprovedApplications: () => {},\n getPublicRoundDonations: () => {},\n getFlaggedAccounts: () => {},\n};\n// Card Skeleton - Loading fallback\nconst loadingSkeleton = styled.keyframes`\n 0% {\n opacity: 1;\n }\n 50% {\n opacity: 0.4;\n }\n 100% {\n opacity: 1;\n }\n`;\nconst CardSkeletonContainer = styled.div`\n display: flex;\n flex-direction: column;\n height: 447px;\n width: 100%;\n max-width: 400px;\n border-radius: 12px;\n background: white;\n box-shadow: 0px -2px 0px #dbdbdb inset;\n border: 1px solid #dbdbdb;\n margin-left: auto;\n margin-right: auto;\n overflow: hidden;\n animation-name: ${loadingSkeleton};\n animation-duration: 1s;\n animation-iteration-count: infinite;\n`;\nconst HeaderSkeleton = styled.div`\n display: block;\n width: 100%;\n height: 168px;\n background: #eee;\n`;\nconst ProfileImageSkeleton = styled.div`\n background: #e0e0e0;\n margin-left: 32px;\n transform: translateY(148px);\n width: 40px;\n height: 40px;\n position: absolute;\n border-radius: 999px;\n`;\nconst TitleSkeleton = styled.div`\n width: 120px;\n height: 24px;\n background: #eee;\n margin-left: 24px;\n margin-top: 24px;\n`;\nconst DescriptionSkeleton = styled.div`\n width: 83%;\n height: 48px;\n background: #eee;\n margin-left: 24px;\n margin-top: 24px;\n`;\nconst TagSkeleton = styled.div`\n background: #eee;\n border-radius: 4px;\n height: 34px;\n width: 110px;\n margin: 24px;\n`;\nconst FooterItemSkeleton = styled.div`\n width: 150px;\n height: 40px;\n background: #eee;\n @media screen and (max-width: 390px) {\n width: 100px;\n }\n`;\nconst DonationsInfoContainerSkeleton = styled.div`\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 16px 24px;\n width: 100%;\n border-top: 1px #f0f0f0 solid;\n`;\nconst DonationsInfoItemSkeleton = styled.div`\n display: flex;\n flex-direction: row;\n gap: 8px;\n align-items: center;\n`;\nconst CardSkeleton = () => (\n <CardSkeletonContainer>\n <HeaderSkeleton />\n <ProfileImageSkeleton />\n <TitleSkeleton />\n <DescriptionSkeleton />\n <TagSkeleton />\n <DonationsInfoContainerSkeleton>\n <DonationsInfoItemSkeleton>\n <FooterItemSkeleton />\n </DonationsInfoItemSkeleton>\n <DonationsInfoItemSkeleton>\n <FooterItemSkeleton />\n </DonationsInfoItemSkeleton>\n </DonationsInfoContainerSkeleton>\n </CardSkeletonContainer>\n);\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n`;\nconst Title = styled.div`\n font-size: 18px;\n display: flex;\n align-items: center;\n gap: 1.5rem;\n width: fit-content;\n margin-bottom: 1.5rem;\n div:first-of-type {\n font-weight: 600;\n }\n`;\nconst SearchBar = styled.div`\n display: flex;\n position: relative;\n width: 100%;\n border-radius: 6px;\n border: 0.5px solid #292929;\n margin-bottom: 0.5rem;\n svg {\n position: absolute;\n left: 1rem;\n top: 50%;\n transform: translateY(-50%);\n }\n input {\n font-size: 14px;\n background: transparent;\n width: 100%;\n height: 100%;\n padding: 12px 16px 12px 3rem;\n border: none;\n outline: none;\n }\n @media only screen and (max-width: 768px) {\n svg {\n left: 1rem;\n }\n input {\n padding: 8px 24px 8px 54px;\n }\n }\n`;\nconst [searchTerm, setSearchTerm] = useState(\"\");\nconst [filteredProjects, setFilteredProjects] = useState([]);\nconst [projects, setProjects] = useState(null);\nconst [flaggedAddresses, setFlaggedAddresses] = useState(null);\nconst [payouts, setPayouts] = useState(null);\n// get projects\nconst { potId, potDetail, allDonations } = props;\nconst {\n calculatePayouts,\n getTagsFromSocialProfileData,\n getTeamMembersFromSocialProfileData,\n} = VM.require(\"old.potlock.near/widget/utils\") || {\n calculatePayouts: () => {},\n getFlaggedAccounts: () => {},\n getTagsFromSocialProfileData: () => [],\n getTeamMembersFromSocialProfileData: () => [],\n};\nif (!projects) {\n PotSDK.asyncGetApprovedApplications(potId).then((projects) => {\n setProjects(projects);\n setFilteredProjects(projects);\n });\n}\nif (!projects)\n return <div class=\"spinner-border text-secondary\" role=\"status\" />;\nconst {\n public_round_start_ms,\n public_round_end_ms,\n referral_fee_public_round_basis_points,\n} = potDetail;\nconst now = Date.now();\nconst publicRoundOpen =\n now >= public_round_start_ms && now < public_round_end_ms;\nif (!flaggedAddresses) {\n PotSDK.getFlaggedAccounts(potDetail, potId)\n .then((data) => {\n const listOfFlagged = [];\n data.forEach((adminFlaggedAcc) => {\n const addresses = Object.keys(adminFlaggedAcc.potFlaggedAcc);\n listOfFlagged.push(...addresses);\n });\n setFlaggedAddresses(listOfFlagged);\n })\n .catch((err) => console.log(\"error getting the flagged accounts \", err));\n}\nif (!payouts) {\n if (allDonations.length && flaggedAddresses)\n calculatePayouts(\n allDonations,\n potDetail.matching_pool_balance,\n flaggedAddresses\n )\n .then((payouts) => {\n setPayouts(payouts ?? []);\n })\n .catch((err) => {\n console.log(\"error while calculating payouts \", err);\n setPayouts([]);\n });\n}\nconst searchByWords = (searchTerm) => {\n if (projects.length) {\n searchTerm = searchTerm.toLowerCase().trim();\n setSearchTerm(searchTerm);\n const updatedProjects = projects.filter((project) => {\n const profile = Social.getr(`${id}/profile`);\n const fields = [\n project.project_id,\n project.status,\n profile.description,\n profile.name,\n getTagsFromSocialProfileData(profile).join(\" \"),\n getTeamMembersFromSocialProfileData(profile).join(\" \"),\n ];\n return fields.some((item) =>\n (item || \"\").toLowerCase().includes(searchTerm.toLowerCase())\n );\n });\n setFilteredProjects(updatedProjects);\n }\n};\nreturn (\n <Container>\n <Title>\n <div>Projects</div>\n <div>{filteredProjects?.length}</div>\n </Title>\n <SearchBar>\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M9.81641 8.69141H9.22391L9.01391 8.48891C9.74891 7.63391 10.1914 6.52391 10.1914 5.31641C10.1914 2.62391 8.00891 0.441406 5.31641 0.441406C2.62391 0.441406 0.441406 2.62391 0.441406 5.31641C0.441406 8.00891 2.62391 10.1914 5.31641 10.1914C6.52391 10.1914 7.63391 9.74891 8.48891 9.01391L8.69141 9.22391V9.81641L12.4414 13.5589L13.5589 12.4414L9.81641 8.69141ZM5.31641 8.69141C3.44891 8.69141 1.94141 7.18391 1.94141 5.31641C1.94141 3.44891 3.44891 1.94141 5.31641 1.94141C7.18391 1.94141 8.69141 3.44891 8.69141 5.31641C8.69141 7.18391 7.18391 8.69141 5.31641 8.69141Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n <input\n type=\"text\"\n placeholder=\"Search projects\"\n onChange={(e) => searchByWords(e.target.value)}\n className=\"search-input\"\n />\n </SearchBar>\n <Widget\n src={\"old.potlock.near/widget/Project.ListSection\"}\n props={{\n ...props,\n shouldShuffle: true,\n maxCols: 3,\n items: filteredProjects,\n responsive: [\n {\n breakpoint: 1200,\n items: 2,\n },\n {\n breakpoint: 870,\n items: 1,\n },\n ],\n renderItem: (project) => {\n return (\n <Widget\n src={\"old.potlock.near/widget/Project.Card\"}\n loading={<CardSkeleton />}\n props={{\n ...props,\n potDetail,\n projects,\n projectId: project.project_id,\n allowDonate:\n publicRoundOpen && project.project_id !== context.accountId,\n potRferralFeeBasisPoints:\n referral_fee_public_round_basis_points,\n payoutDetails: payouts[project.project_id] || {\n donorCount: 0,\n matchingAmount: \"0\",\n totalAmount: \"0\",\n },\n }}\n />\n );\n },\n }}\n />\n </Container>\n);\n" }, "Pots.SponsorsBoard": { "": "const { donations, base_currency, hrefWithParams } = props;\nconst sponsorsLeaderboard = [\n donations.slice(1, 3),\n donations.slice(0, 1),\n donations.slice(3, 5),\n].filter((subList) => subList.length > 0);\nconst { _address } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n) || {\n _address: () => \"\",\n};\nconst { SUPPORTED_FTS } = VM.require(\"old.potlock.near/widget/constants\") || {\n SUPPORTED_FTS: {},\n};\nconst Container = styled.div`\n display: flex;\n gap: 2rem;\n min-height: 430px;\n width: 100%;\n .col {\n display: flex;\n flex-direction: column;\n gap: 2rem;\n }\n .item {\n position: relative;\n display: flex;\n justify-content: center;\n gap: 1rem;\n flex-direction: column;\n border-radius: 12px;\n background: #fef6ee;\n height: 50%;\n padding: 24px;\n font-size: 14px;\n &.first {\n box-shadow: 0px 1px 2px -1px rgba(0, 0, 0, 0.08),\n 0px 1px 1px -1px rgba(0, 0, 0, 0.12);\n border: 2px solid #dd3345;\n align-items: center;\n text-align: center;\n height: 100%;\n .profile-image {\n width: 64px;\n height: 64px;\n }\n .footer {\n flex-direction: column;\n gap: 1rem;\n }\n .amount {\n font-size: 32px;\n font-family: \"Lora\";\n }\n }\n .profile-image {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n @media only screen and (max-width: 480px) {\n width: 40px;\n height: 40px;\n }\n }\n .name {\n white-space: nowrap;\n font-weight: 600;\n color: #292929;\n transition: all 300ms;\n font-size: 1rem;\n :hover {\n color: #dd3345;\n text-decoration: none;\n }\n }\n .footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n }\n .amount {\n font-size: 22px;\n font-weight: 600;\n }\n .percentage {\n font-size: 1rem;\n background: #f8d3b0;\n padding: 4px 8px;\n border-radius: 4px;\n font-weight: 600;\n height: fit-content;\n }\n }\n @media only screen and (max-width: 960px) {\n gap: 1rem;\n flex-direction: column;\n .col {\n gap: 1rem;\n }\n .col:nth-child(2) {\n order: -1;\n }\n }\n`;\nconst ProfileImg = ({ profile }) => (\n <Widget\n src=\"mob.near/widget/Image\"\n props={{\n image: profile.image,\n style: {},\n className: \"profile-image\",\n alt: profile.name,\n fallbackUrl:\n \"https://ipfs.near.social/ipfs/bafkreidla73cknxbeovrhgb2blax2j2qgcgcn6ibluzza3buq2mbkoqs2e\",\n }}\n />\n);\nconst Sponsor = ({\n donation: { amount, donor_id, percentage_share },\n colIdx,\n}) => {\n const profile = props.profile ?? Social.getr(`${donor_id}/profile`);\n return (\n <div className={`item ${colIdx === 2 && \"first\"}`}>\n <ProfileImg profile={profile} />\n <a\n href={hrefWithParams(`?tab=profile&accountId=${donor_id}`)}\n target=\"_blank\"\n className=\"name\"\n >\n {_address(profile.name || donor_id, 15)}\n </a>\n <div>{_address(profile.description, colIdx === 2 ? 120 : 35)}</div>\n <div className=\"footer\">\n <div className=\"amount\">{amount} NEAR</div>\n <div className=\"percentage\">{percentage_share}%</div>\n </div>\n </div>\n );\n};\nreturn (\n <Container>\n {sponsorsLeaderboard.map((donationsCol, colIdx) => (\n <div className=\"col\">\n {donationsCol.map((donation, idx) => (\n <Sponsor donation={donation} colIdx={colIdx + 1} idx={idx + 1} />\n ))}\n </div>\n ))}\n </Container>\n);\n" }, "Inputs.TextArea": { "": "const label = props.label ?? \"Label\";\nconst placeholder = props.placeholder ?? \"Placeholder\";\nconst value = props.value ?? \"\";\nconst onChange = props.onChange ?? (() => {});\nconst validate = props.validate ?? (() => {});\nconst error = props.error ?? \"\";\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n padding: 0px;\n gap: 0.45em;\n width: 100%;\n`;\nconst Label = styled.label`\n font-weight: 500;\n font-size: 14px;\n line-height: 16px;\n word-wrap: break-word;\n color: #2e2e2e;\n`;\nconst Error = styled.span`\n display: inline-block;\n font-style: normal;\n font-weight: 400;\n font-size: 0.75em;\n line-height: 1.25em;\n color: #ff4d4f;\n height: 0;\n overflow: hidden;\n transition: height 0.3s ease-in-out;\n &.show {\n height: 1.25em;\n }\n`;\nconst Input = styled.textarea`\n box-sizing: border-box;\n display: flex;\n flex-direction: row;\n align-items: center;\n padding: 0.5em 0.75em;\n width: 100%;\n gap: 0.5em;\n background: #ffffff;\n border: 1px solid #d0d5dd;\n box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);\n border-radius: 4px;\n`;\nreturn (\n <Container style={props.containerStyle ?? {}}>\n {!props.noLabel && <Label style={props.labelStyle ?? {}}>{label}</Label>}\n <Input\n placeholder={placeholder}\n value={value}\n onChange={({ target: { value } }) => onChange(value)}\n onBlur={() => validate()}\n rows={props.inputRows ?? 5}\n style={props.inputStyle ?? {}}\n disabled={!!props.disabled}\n />\n <Error style={props.errorStyle ?? {}} className={error ? \"show\" : \"\"}>\n {error}\n </Error>\n </Container>\n);\n" }, "Pots.Settings": { "": "// get settings\nconst { potDetail, potId, env, hrefWithParams } = props;\nconst [editSettings, setEditSettings] = useState(false);\nconst {\n SUPPORTED_FTS: { NEAR },\n} = VM.require(\"old.potlock.near/widget/constants\") || {\n SUPPORTED_FTS: {\n NEAR: {},\n },\n};\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n isUserPotAdminOrGreater: () => {},\n};\nconst { _address } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n) || {\n _address: (address) => address,\n};\nlet PotFactorySDK =\n VM.require(\"old.potlock.near/widget/SDK.potfactory\") ||\n (() => ({\n getContractId: () => {},\n }));\nPotFactorySDK = PotFactorySDK({ env });\nconst potFactoryContractId = PotFactorySDK.getContractId();\nconst userIsAdminOrGreater = PotSDK.isUserPotAdminOrGreater(\n potId,\n context.accountId\n);\nconst formatTimestampForDateTimeLocal = (timestamp) => {\n const date = new Date(timestamp);\n const year = date.getFullYear();\n const month = (date.getMonth() + 1).toString().padStart(2, \"0\"); // months are 0-indexed\n const day = date.getDate().toString().padStart(2, \"0\");\n const hours = date.getHours().toString().padStart(2, \"0\");\n const minutes = date.getMinutes().toString().padStart(2, \"0\");\n return `${year}-${month}-${day}T${hours}:${minutes}`;\n};\nconst {\n owner,\n chef,\n admins,\n pot_name,\n pot_description,\n max_projects,\n application_start_ms,\n application_end_ms,\n public_round_start_ms,\n public_round_end_ms,\n sybil_wrapper_provider,\n referral_fee_matching_pool_basis_points,\n referral_fee_public_round_basis_points,\n chef_fee_basis_points,\n min_matching_pool_donation_amount,\n registry_provider,\n} = potDetail;\nconst fields = [\n {\n label: \"Name\",\n val: pot_name,\n },\n {\n label: \"Custom handle\",\n val: potId.split(`.${potFactoryContractId}`)[0],\n },\n {\n label: \"Description\",\n val: pot_description,\n },\n {\n label: \"Referrer fee % (matching pool)\",\n val: referral_fee_matching_pool_basis_points / 100 + \"%\",\n },\n {\n label: \"Referrer fee % (public round)\",\n val: referral_fee_public_round_basis_points / 100 + \"%\",\n },\n {\n label: \"Application date\",\n val: `${formatTimestampForDateTimeLocal(\n application_start_ms\n )} - ${formatTimestampForDateTimeLocal(application_end_ms)}`,\n },\n {\n label: \"Matching round date\",\n val: `${formatTimestampForDateTimeLocal(\n public_round_start_ms\n )} - ${formatTimestampForDateTimeLocal(public_round_end_ms)}`,\n },\n {\n label: \"Min matching pool donation\",\n val: NEAR.fromIndivisible(min_matching_pool_donation_amount),\n },\n {\n label: \"Chef fee\",\n val: chef_fee_basis_points / 100 + \"%\",\n },\n {\n label: \"Assigned Chef\",\n val: chef,\n },\n {\n label: \"Max. approved projects\",\n val: max_projects,\n },\n {\n label: \"Registry Provider\",\n val: registry_provider,\n },\n {\n label: \"Donor Sybil Resistance\",\n val: sybil_wrapper_provider ? \"🤖 nada.bot human verified\" : \"none\",\n },\n];\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n width: 100%;\n`;\nconst Title = styled.div`\n font-weight: 600;\n font-size: 22px;\n`;\nconst PrviewContainer = styled.div`\n display: flex;\n flex-direction: column;\n max-width: 922px;\n`;\nconst AdminsWrapper = styled.div`\n position: absolute;\n display: flex;\n flex-direction: column;\n opacity: 0;\n pointer-events: none;\n padding-top: 5px;\n transition: all 300ms;\n top: 100%;\n .list {\n background: white;\n color: #292929;\n border-radius: 4px;\n overflow: hidden;\n box-shadow: 0px 0px 1px 0px rgba(41, 41, 41, 0.74),\n 0px 3px 3px 0px rgba(123, 123, 123, 0.12),\n 0px 6px 6px 0px rgba(123, 123, 123, 0.12);\n a {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 12px 16px;\n color: #292929;\n transition: 300ms;\n .profile-image {\n width: 24px;\n height: 24px;\n box-shadow: 0px 0px 1px 0px #a6a6a6 inset;\n border: 2px solid #f8d3b0;\n border-radius: 50%;\n }\n &:hover {\n background: #292929;\n text-decoration: none;\n color: white;\n }\n }\n }\n .tip-icon {\n display: flex;\n justify-content: center;\n z-index: 1;\n svg {\n stroke: rgb(41 41 41 / 21%);\n }\n }\n`;\nconst Admins = styled.div`\n display: flex;\n font-size: 11px;\n gap: 2rem;\n .owner {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 0.5rem;\n .address {\n display: flex;\n gap: 0.5rem;\n align-items: center;\n div {\n font-size: 14px;\n font-weight: 500;\n }\n .profile-image {\n width: 24px;\n height: 24px;\n border-radius: 50%;\n }\n }\n }\n .admins {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 0.5rem;\n .avaters {\n display: flex;\n gap: 0.5rem;\n }\n .profile-image {\n width: 24px;\n height: 24px;\n }\n .icons-tolltip {\n position: relative;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: white;\n border-radius: 50%;\n border: 2px solid #f8d3b0;\n background: #b8182d;\n &:hover {\n ${AdminsWrapper} {\n opacity: 1;\n pointer-events: all;\n }\n }\n }\n }\n .edit {\n display: flex;\n gap: 0.5rem;\n color: #dd3345;\n align-items: center;\n cursor: pointer;\n margin-left: auto;\n }\n @media only screen and (max-width: 768px) {\n flex-wrap: wrap;\n .edit {\n width: 100%;\n }\n }\n`;\nconst Detail = styled.div`\n display: flex;\n flex-direction: column;\n gap: 1rem;\n border-radius: 12px;\n border: 1px solid #c7c7c7;\n padding: 3rem;\n margin-top: 1.5rem;\n .row-field {\n display: flex;\n align-items: center;\n gap: 2rem;\n font-size: 14px;\n }\n .label {\n font-weight: 500;\n max-width: 238px;\n width: 100%;\n text-align: left;\n }\n .input {\n color: #7b7b7b;\n }\n @media only screen and (max-width: 768px) {\n padding: 1rem;\n gap: 1.5rem;\n .row-field {\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n }\n }\n`;\nconst ProfileImage = ({ address }) => (\n <Widget\n src={\"old.potlock.near/widget/Project.ProfileImage\"}\n props={{\n ...props,\n accountId: address,\n style: {},\n }}\n />\n);\nconst AdminsTooltip = () => (\n <AdminsWrapper>\n <div className=\"tip-icon\">\n <svg\n width=\"12\"\n height=\"8\"\n viewBox=\"0 0 12 8\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 5.24537e-07L-2.54292e-07 8L12 8L6 5.24537e-07Z\"\n fill=\"white\"\n />\n </svg>\n </div>\n <div className=\"list\">\n {admins.slice(0, admins.length).map((admin) => (\n <a\n href={hrefWithParams(`?tab=profile&accountId=${admin}`)}\n target=\"_blank\"\n >\n <ProfileImage address={admin} />\n <div>{admin}</div>\n </a>\n ))}\n </div>\n </AdminsWrapper>\n);\nreturn editSettings ? (\n <Container>\n <Title>Edit Pot settings</Title>\n <Widget\n src={\"old.potlock.near/widget/Pots.ConfigForm\"}\n props={{\n ...props,\n }}\n />\n </Container>\n) : (\n <PrviewContainer>\n <Admins>\n <div className=\"owner\">\n <div>Owner</div>\n <div className=\"address\">\n <ProfileImage address={owner} />\n <div>{_address(owner, 15)}</div>\n </div>\n </div>\n {admins.length > 0 && (\n <div className=\"admins\">\n <div>Admins</div>\n <div className=\"avaters\">\n {admins.slice(0, 4).map((admin, idx) => (\n <OverlayTrigger\n placement=\"bottom\"\n overlay={<Tooltip id={`tooltip-${idx}`}>{admin}</Tooltip>}\n key={admin}\n >\n <a\n href={hrefWithParams(`?tab=profile&accountId=${admin}`)}\n target=\"_blank\"\n >\n <ProfileImage address={admin} />\n </a>\n </OverlayTrigger>\n ))}\n {admins.length > 4 && (\n <div className=\"icons-tolltip\">\n +{admins.length - 4}\n <AdminsTooltip />\n </div>\n )}\n </div>\n </div>\n )}\n {userIsAdminOrGreater && (\n <div className=\"edit\" onClick={() => setEditSettings(true)}>\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M0.25 13.7501H3.0625L11.3575 5.45508L8.545 2.64258L0.25 10.9376V13.7501ZM1.75 11.5601L8.545 4.76508L9.235 5.45508L2.44 12.2501H1.75V11.5601Z\"\n fill=\"#DD3345\"\n />\n <path\n d=\"M11.7777 0.469375C11.4852 0.176875 11.0127 0.176875 10.7202 0.469375L9.34766 1.84187L12.1602 4.65438L13.5327 3.28187C13.8252 2.98937 13.8252 2.51688 13.5327 2.22438L11.7777 0.469375Z\"\n fill=\"#DD3345\"\n />\n </svg>\n Edit Pot\n </div>\n )}\n </Admins>\n <Detail>\n {fields.map((field) => (\n <div className=\"row-field\" key={field.label}>\n <div className=\"label\">{field.label}</div>\n <div className=\"input\">{field.val}</div>\n </div>\n ))}\n </Detail>\n </PrviewContainer>\n);\n" }, "Components.Modal": { "": "const ModalOverlay = styled.div`\n position: fixed;\n padding: 0 10px;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n // background: rgba(0, 0, 0, 0.2);\n backdrop-filter: blur(5px);\n display: flex;\n justify-content: center;\n align-items: center;\n // padding-top: 30vh;\n z-index: 1000;\n`;\nconst ModalContent = styled.div`\n width: 100%;\n max-width: 600px;\n padding: 24px 24px 18px 24px;\n background: white;\n display: flex;\n flex-direction: column;\n border-radius: 12px;\n overflow: hidden;\n box-shadow: 0px 0px 0px 1px rgba(41, 41, 41, 0.1),\n 0px 8px 12px -4px rgba(41, 41, 41, 0.1),\n 0px 20px 32px -10px rgba(41, 41, 41, 0.1),\n 0px 32px 44px -16px rgba(41, 41, 41, 0.1);\n`;\nconst overlayStyle = props.overlayStyle || {};\nconst contentStyle = props.contentStyle || {};\nState.init({\n isModalOpen: false,\n});\nconst Modal = ({ isOpen, onClose, children }) => {\n if (!isOpen) return \"\";\n return (\n <ModalOverlay onClick={onClose} style={overlayStyle}>\n <ModalContent onClick={(e) => e.stopPropagation()} style={contentStyle}>\n {children}\n </ModalContent>\n </ModalOverlay>\n );\n};\nreturn (\n <Modal\n isOpen={\n props.hasOwnProperty(\"isModalOpen\")\n ? props.isModalOpen\n : state.isModalOpen\n }\n onClose={\n props.hasOwnProperty(\"onClose\")\n ? props.onClose\n : () => State.update({ isModalOpen: false })\n }\n >\n {props.children}\n </Modal>\n);\n" }, "Components.Icons": { "": "const { Volunteer } = VM.require(\n \"old.potlock.near/widget/Components.Icons.Volunteer\"\n);\nconst { Component } = VM.require(\n \"old.potlock.near/widget/Components.Icons.Component\"\n);\nreturn {\n Volunteer,\n Component,\n};\n" }, "Cart.BreakdownSummary": { "": "const {\n referrerId,\n totalAmount,\n bypassProtocolFee,\n recipientId,\n potRferralFeeBasisPoints,\n ftIcon,\n bypassChefFee,\n chef,\n chefFeeBasisPoints,\n} = props;\nconst { basisPointsToPercent } = VM.require(\n \"old.potlock.near/widget/utils\"\n) || {\n basisPointsToPercent: () => 0,\n};\nconst { SUPPORTED_FTS } = VM.require(\"old.potlock.near/widget/constants\") || {\n SUPPORTED_FTS: {},\n};\nlet DonateSDK =\n VM.require(\"old.potlock.near/widget/SDK.donate\") ||\n (() => ({\n getConfig: () => {},\n }));\nDonateSDK = DonateSDK({ env: props.env });\nconst donationContractConfig = DonateSDK.getConfig();\nconst IPFS_BASE_URL = \"https://nftstorage.link/ipfs/\";\nconst CHEVRON_DOWN_URL =\n IPFS_BASE_URL + \"bafkreiabkwyfxq6pcc2db7u4ldweld5xcjesylfuhocnfz7y3n6jw7dptm\";\nconst CHEVRON_UP_URL =\n IPFS_BASE_URL + \"bafkreibdm7w6zox4znipjqlmxr66wsjjpqq4dguswo7evvrmzlnss3c3vi\";\nconst SvgIcon = styled.svg`\n width: 16px;\n height: 16px;\n`;\nconst BreakdownSummary = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n .breakdown-details {\n display: flex;\n flex-direction: column;\n width: 100%;\n margin-top: 8px;\n gap: 12px;\n border: 1px #dbdbdb solid;\n border-radius: 8px;\n transition: all 300ms ease-in-out;\n &.hidden {\n visibility: hidden;\n height: 0;\n opacity: 0;\n transform: translateY(100px);\n }\n }\n`;\nconst Header = styled.div`\n display: flex;\n flex-direction: row;\n justify-content: flex-start;\n align-items: center;\n width: 100%;\n`;\nconst BreakdownTitle = styled.div`\n color: #2e2e2e;\n font-size: 14px;\n font-weight: 500;\n word-wrap: break-word;\n`;\nconst ChevronIcon = styled.svg`\n width: 1rem;\n height: 1rem;\n margin-left: 8px;\n transition: all 300ms ease-in-out;\n`;\nconst BreakdownDetails = styled.div`\n display: flex;\n flex-direction: column;\n width: 100%;\n margin-top: 8px;\n gap: 12px;\n padding: 16px;\n border-radius: 8px;\n border: 1px #dbdbdb solid;\n background: #fafafa;\n transition: all 300ms ease-in-out;\n`;\nconst BreakdownItem = styled.div`\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 0 16px;\n gap: 16px;\n :first-of-type {\n padding-top: 1rem;\n }\n :last-of-type {\n padding-bottom: 1rem;\n }\n`;\nconst BreakdownItemLeft = styled.div`\n color: #7b7b7b;\n font-size: 14px;\n font-weight: 400;\n word-wrap: break-word;\n`;\nconst BreakdownItemRight = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n font-weight: 500;\n gap: 8px;\n`;\nconst BreakdownAmount = styled.div`\n color: #2e2e2e;\n font-size: 14px;\n line-height: 20px;\n font-weight: 500;\n word-wrap: break-word;\n`;\nconst Icon = styled.img`\n width: 16px;\n height: 16px;\n`;\nconst NearIcon = (props) => (\n <SvgIcon\n {...props}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <g clip-path=\"url(#clip0_454_78)\">\n <circle cx=\"8\" cy=\"8\" r=\"7.25\" stroke=\"#292929\" stroke-width=\"1.5\" />\n <path\n d=\"M11.1477 4C10.851 4 10.5763 4.15333 10.421 4.406L8.74866 6.88867C8.72453 6.92441 8.71422 6.96772 8.71967 7.01051C8.72511 7.05329 8.74594 7.09264 8.77826 7.1212C8.81057 7.14976 8.85218 7.1656 8.89531 7.16574C8.93844 7.16589 8.98015 7.15034 9.01266 7.122L10.6587 5.69467C10.6683 5.68598 10.6802 5.68028 10.6931 5.67828C10.7059 5.67628 10.719 5.67806 10.7308 5.6834C10.7426 5.68875 10.7526 5.69742 10.7596 5.70836C10.7665 5.7193 10.7702 5.73203 10.77 5.745V10.215C10.77 10.2287 10.7658 10.2421 10.7579 10.2534C10.7501 10.2646 10.7389 10.2732 10.726 10.2778C10.7131 10.2825 10.6991 10.2831 10.6858 10.2795C10.6726 10.2758 10.6608 10.2682 10.652 10.2577L5.67667 4.30167C5.59667 4.20709 5.49701 4.1311 5.38463 4.079C5.27226 4.0269 5.14987 3.99994 5.026 4H4.85233C4.62628 4 4.40949 4.0898 4.24964 4.24964C4.0898 4.40949 4 4.62628 4 4.85233V11.1477C4 11.3333 4.06061 11.5139 4.17263 11.6619C4.28465 11.81 4.44194 11.9174 4.6206 11.9679C4.79926 12.0184 4.98952 12.0091 5.16245 11.9416C5.33538 11.874 5.48152 11.7519 5.57867 11.5937L7.251 9.111C7.27513 9.07525 7.28544 9.03194 7.27999 8.98916C7.27455 8.94637 7.25372 8.90703 7.22141 8.87846C7.18909 8.8499 7.14748 8.83407 7.10435 8.83392C7.06122 8.83377 7.01951 8.84932 6.987 8.87766L5.341 10.3053C5.33134 10.3139 5.31939 10.3195 5.3066 10.3215C5.29381 10.3234 5.28074 10.3216 5.26898 10.3162C5.25721 10.3108 5.24726 10.3021 5.24034 10.2912C5.23342 10.2803 5.22983 10.2676 5.23 10.2547V5.784C5.22997 5.77027 5.23418 5.75687 5.24206 5.74563C5.24993 5.73438 5.26109 5.72584 5.274 5.72117C5.28691 5.71651 5.30094 5.71594 5.31419 5.71955C5.32743 5.72315 5.33924 5.73076 5.348 5.74133L10.3227 11.698C10.4847 11.8893 10.7227 11.9997 10.9733 12H11.147C11.373 12.0001 11.5898 11.9104 11.7498 11.7507C11.9097 11.591 11.9997 11.3744 12 11.1483V4.85233C11.9999 4.62631 11.9101 4.40956 11.7503 4.24974C11.5904 4.08992 11.3737 4.00009 11.1477 4Z\"\n fill=\"#292929\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_454_78\">\n <rect width=\"16\" height=\"16\" fill=\"white\" />\n </clipPath>\n </defs>\n </SvgIcon>\n);\nState.init({\n showBreakdown: true,\n});\nif (!donationContractConfig) return \"\";\nconst {\n protocol_fee_basis_points,\n referral_fee_basis_points,\n protocol_fee_recipient_account: protocolFeeRecipientAccount,\n} = donationContractConfig;\nconst protocolFeeBasisPoints =\n props.protocolFeeBasisPoints ?? protocol_fee_basis_points;\nconst referralFeeBasisPoints =\n potRferralFeeBasisPoints || props.referralFeeBasisPoints;\nconst TOTAL_BASIS_POINTS = 10_000;\nlet projectAllocationBasisPoints =\n TOTAL_BASIS_POINTS -\n (bypassProtocolFee || !protocolFeeBasisPoints ? 0 : protocolFeeBasisPoints) -\n (bypassChefFee || !chefFeeBasisPoints ? 0 : chefFeeBasisPoints);\nif (referrerId) {\n projectAllocationBasisPoints -= referralFeeBasisPoints;\n}\nconst projectAllocationPercent = basisPointsToPercent(\n projectAllocationBasisPoints\n);\nconst projectAllocationAmount =\n (parseFloat(totalAmount) * projectAllocationBasisPoints) / TOTAL_BASIS_POINTS;\nconst protocolFeePercent = basisPointsToPercent(protocolFeeBasisPoints);\nconst protocolFeeAmount =\n (parseFloat(totalAmount) * protocolFeeBasisPoints) / TOTAL_BASIS_POINTS;\nconst referrerFeePercent = basisPointsToPercent(referralFeeBasisPoints);\nconst referrerFeeAmount =\n (parseFloat(totalAmount) * referralFeeBasisPoints) / TOTAL_BASIS_POINTS;\nconst chefFeePercent = basisPointsToPercent(chefFeeBasisPoints);\nconst chefFeeAmount =\n (parseFloat(totalAmount) * chefFeeBasisPoints) / TOTAL_BASIS_POINTS;\nconst fees = [\n {\n label: \"Protocol fee\",\n percentage: protocolFeePercent,\n amount: protocolFeeAmount,\n show: !bypassProtocolFee,\n },\n {\n label: \"Referrer fee\",\n percentage: referrerFeePercent,\n amount: referrerFeeAmount,\n show: referrerId,\n },\n {\n label: \"Chef fee\",\n percentage: chefFeePercent,\n amount: chefFeeAmount,\n show: !bypassChefFee && chefFeeBasisPoints,\n },\n {\n label: \"On-Chain Storage\",\n percentage: \"\",\n amount: \"<0.01\",\n show: true,\n },\n {\n label: \"Project allocation\",\n percentage: projectAllocationPercent,\n amount: projectAllocationAmount,\n show: true,\n },\n];\nreturn (\n <BreakdownSummary\n style={props.containerStyle || {}}\n // onClick={() => State.update({ showBreakdown: !state.showBreakdown })}\n >\n <Header style={props.headerStyle || {}}>\n <BreakdownTitle> Breakdown</BreakdownTitle>\n </Header>\n <div\n className={`breakdown-details ${!state.showBreakdown ? \"hidden\" : \"\"}`}\n active={state.showBreakdown}\n >\n {fees.map(({ show, amount, label, percentage }) => {\n return show ? (\n <BreakdownItem key={label}>\n <BreakdownItemLeft>\n {label} {percentage ? `(${percentage}%)` : \"\"}{\" \"}\n </BreakdownItemLeft>\n <BreakdownItemRight>\n <BreakdownAmount>\n {typeof amount === \"string\" ? amount : amount}\n </BreakdownAmount>\n {ftIcon ? <Icon src={ftIcon} alt=\"ft-icon\" /> : <NearIcon />}\n </BreakdownItemRight>\n </BreakdownItem>\n ) : (\n \"\"\n );\n })}\n </div>\n </BreakdownSummary>\n);\n" }, "Components.Icons.Component": { "": "const Component = () => {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"17\"\n height=\"16\"\n viewBox=\"0 0 17 16\"\n fill=\"none\"\n >\n <path\n fill-rule=\"evenodd\"\n clip-rule=\"evenodd\"\n d=\"M6.35199 1H10.6497C10.7929 1 10.903 1 10.9987 1.01042C11.4235 1.05593 11.8181 1.25185 12.1111 1.56281C12.4042 1.87376 12.5764 2.27925 12.5966 2.70605C12.9787 2.82125 13.3143 3.05502 13.5547 3.37354C13.7952 3.69207 13.928 4.07882 13.9341 4.47786C14.3255 4.59507 14.6634 4.78065 14.9395 5.07888C15.3641 5.53795 15.4956 6.10251 15.5008 6.76279C15.5054 7.39768 15.3927 8.19991 15.2521 9.19554L14.9656 11.2233C14.8562 12.002 14.767 12.635 14.6283 13.1305C14.4831 13.6495 14.2688 14.076 13.8729 14.4042C13.4796 14.7298 13.0134 14.8698 12.4625 14.9362C11.9292 15 11.2585 15 10.4244 15H6.57729C5.7425 15 5.0718 15 4.53915 14.9362C3.98761 14.8698 3.52138 14.7298 3.12808 14.4042C2.73217 14.076 2.51794 13.6488 2.37273 13.1305C2.23403 12.635 2.14482 12.002 2.03478 11.2226L1.74892 9.19554C1.60892 8.19926 1.49496 7.39768 1.50017 6.76279C1.50538 6.10251 1.63692 5.53795 2.06147 5.07888C2.33757 4.78065 2.67487 4.59572 3.06622 4.47786C3.07249 4.07885 3.20552 3.69218 3.44608 3.37378C3.68664 3.05538 4.02224 2.82175 4.40436 2.7067C4.42446 2.27979 4.59659 1.87414 4.88965 1.56305C5.1827 1.25196 5.57736 1.05595 6.00231 1.01042C6.09803 1 6.20808 1 6.35068 1M4.0651 4.3066C4.66808 4.25581 5.4065 4.25581 6.29664 4.25581H10.7037C11.5932 4.25581 12.3316 4.25581 12.9352 4.3066C12.8902 4.10719 12.7786 3.92906 12.6188 3.80148C12.459 3.67391 12.2606 3.6045 12.0562 3.60465H4.94482C4.5092 3.60465 4.15561 3.9107 4.0664 4.3066M10.8951 1.98195C11.2533 2.01972 11.5365 2.2867 11.6062 2.62791H5.39608C5.43063 2.45861 5.51815 2.3047 5.64599 2.18845C5.77383 2.0722 5.93534 1.99965 6.10715 1.9813C6.14361 1.9774 6.19571 1.97674 6.37868 1.97674H10.623C10.8053 1.97674 10.8574 1.9774 10.8945 1.9813M2.77906 5.74177C2.97636 5.52884 3.27264 5.38754 3.84892 5.3107C4.43561 5.23256 5.22157 5.23191 6.33375 5.23191H10.6679C11.7801 5.23191 12.566 5.23321 13.1527 5.3107C13.729 5.38754 14.0253 5.52884 14.2226 5.74177C14.4153 5.95014 14.5202 6.2334 14.5241 6.76995C14.528 7.32344 14.4264 8.05274 14.2792 9.09851L14.0038 11.052C13.8879 11.8731 13.8071 12.4409 13.688 12.8668C13.5727 13.277 13.4379 13.4952 13.2498 13.6508C13.059 13.8097 12.8024 13.9113 12.3459 13.966C11.8778 14.022 11.2663 14.0226 10.3925 14.0226H6.6092C5.73533 14.0226 5.12389 14.022 4.65571 13.966C4.19989 13.9106 3.94268 13.8097 3.75189 13.6514C3.56371 13.4952 3.42892 13.2764 3.31366 12.8668C3.1945 12.4409 3.11375 11.8731 2.99785 11.052L2.7224 9.09851C2.57524 8.0534 2.47366 7.32344 2.47757 6.76995C2.48147 6.2334 2.58631 5.94949 2.77906 5.74177Z\"\n fill=\"white\"\n />\n </svg>\n );\n};\nreturn { Component };\n" }, "Components.Pagination": { "": "const { onPageChange, data, currentPage, perPage, customSyle, bgColor } = props;\nconst siblingCount = props.siblingCount ?? 1;\nconst showArrows = props.showArrows ?? false;\nconst totalCount = data?.length;\nconst range = (start, end) => {\n let length = end - start + 1;\n return Array.from({ length }, (_, idx) => idx + start);\n};\nconst usePagination = ({ totalCount, perPage, siblingCount, currentPage }) => {\n const paginationRange = useMemo(() => {\n const totalPageCount = Math.ceil(totalCount / perPage);\n const totalPageNumbers = siblingCount + 3;\n if (totalPageNumbers >= totalPageCount || totalPageCount < 6) {\n return range(1, totalPageCount);\n }\n const leftSiblingIndex = Math.max(currentPage - siblingCount, 1);\n const rightSiblingIndex = Math.min(\n currentPage + siblingCount,\n totalPageCount\n );\n const shouldShowLeftDots = leftSiblingIndex > 2;\n const shouldShowRightDots = rightSiblingIndex <= totalPageCount - 3;\n const firstPageIndex = 1;\n const lastPageIndex = totalPageCount;\n if (!shouldShowLeftDots && shouldShowRightDots) {\n let leftItemCount = 3 + siblingCount;\n let leftRange = range(1, leftItemCount);\n return [...leftRange, DOTS, totalPageCount];\n }\n if (shouldShowLeftDots && !shouldShowRightDots) {\n let rightItemCount = 3 + 2 * siblingCount;\n let rightRange = range(\n totalPageCount - rightItemCount + 1,\n totalPageCount\n );\n return [firstPageIndex, DOTS, ...rightRange];\n }\n if (shouldShowLeftDots && shouldShowRightDots) {\n let middleRange = range(leftSiblingIndex, rightSiblingIndex);\n return [firstPageIndex, DOTS, ...middleRange, DOTS, lastPageIndex];\n }\n if (!shouldShowLeftDots && !shouldShowRightDots) {\n return range(1, totalPageCount);\n }\n }, [totalCount, perPage, siblingCount, currentPage]);\n return paginationRange;\n};\nconst paginationRange = usePagination({\n currentPage,\n totalCount,\n siblingCount,\n perPage,\n});\nif (currentPage === 0 || paginationRange.length < 2) {\n return \"\";\n}\nconst onNext = () => {\n onPageChange(currentPage + 1);\n};\nconst onPrevious = () => {\n onPageChange(currentPage - 1);\n};\nlet lastPage = paginationRange[paginationRange.length - 1];\nconst Container = styled.div`\n display: flex;\n gap: 1rem;\n justify-content: center;\n list-style-type: none;\n ${customSyle || \"\"}\n li {\n display: flex;\n align-items: center;\n justify-content: center;\n &.disabled {\n pointer-events: none;\n .arrow::before {\n border-right: 0.12em solid rgba(0, 0, 0, 0.43);\n border-top: 0.12em solid rgba(0, 0, 0, 0.43);\n }\n &:hover {\n cursor: default;\n }\n }\n }\n .pagination-item {\n border: 1px solid transparent;\n background: ${bgColor};\n border-radius: 2px;\n padding: 10px;\n font-size: 12px;\n color: white;\n cursor: pointer;\n transition: all 300ms;\n &.dots:hover {\n cursor: default;\n opacity: 1;\n }\n &:hover {\n opacity: 0.75;\n }\n &.selected {\n background: white;\n cursor: default;\n color: ${bgColor};\n border-color: ${bgColor};\n }\n }\n .arrow {\n cursor: pointer;\n &::before {\n position: relative;\n content: \"\";\n display: inline-block;\n width: 0.4em;\n height: 0.4em;\n border-right: 0.12em solid rgba(0, 0, 0, 0.87);\n border-top: 0.12em solid rgba(0, 0, 0, 0.87);\n }\n &.left {\n transform: rotate(-135deg) translate(-50%);\n }\n &.right {\n transform: rotate(45deg);\n }\n }\n`;\nreturn (\n <Container>\n {showArrows && (\n <li\n className={`${currentPage === 1 ? \"disabled\" : \"\"}`}\n onClick={onPrevious}\n >\n <div className=\"arrow left\" />\n </li>\n )}\n {paginationRange?.length > 0 &&\n paginationRange.map((pageNumber) => {\n if (pageNumber === DOTS) {\n return <li className=\"pagination-item dots\">&#8230;</li>;\n }\n return (\n <li\n className={`pagination-item ${\n pageNumber === currentPage ? \"selected\" : \"\"\n }`}\n onClick={() => onPageChange(pageNumber)}\n >\n {pageNumber}\n </li>\n );\n })}\n {showArrows && (\n <li\n className={`${currentPage === lastPage ? \"disabled\" : \"\"}`}\n onClick={onNext}\n >\n <div className=\"arrow right\" />\n </li>\n )}\n </Container>\n);\n" }, "Pots.Applications": { "": "// get applications\nconst { potId, potDetail, hrefWithParams } = props;\nconst { daysAgo } = VM.require(\"old.potlock.near/widget/utils\") || {\n daysAgo: () => \"\",\n};\nconst {\n ONE_TGAS,\n SUPPORTED_FTS: { NEAR },\n} = VM.require(\"old.potlock.near/widget/constants\") || {\n ONE_TGAS: 0,\n SUPPORTED_FTS: {},\n};\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getApplications: () => {},\n};\nconst { getTimePassed, _address } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n) || {\n _address: (address) => address,\n};\nconst MAX_APPLICATION_MESSAGE_LENGTH = 1000;\nconst applications = PotSDK.getApplications(potId);\nconst getApplicationCount = (sortVal) => {\n if (!applications) return;\n return applications?.filter((application) => {\n if (sortVal === \"All\") return true;\n return application.status === sortVal;\n })?.length;\n};\nconst APPLICATIONS_FILTERS = {\n ALL: {\n label: \"All applications\",\n val: \"ALL\",\n count: getApplicationCount(\"All\"),\n },\n PENDING: {\n label: \"Pending applications\",\n val: \"PENDING\",\n count: getApplicationCount(\"Pending\"),\n },\n APPROVED: {\n label: \"Approved applications\",\n val: \"APPROVED\",\n count: getApplicationCount(\"Approved\"),\n },\n REJECTED: {\n label: \"Rejected applications\",\n val: \"REJECTED\",\n count: getApplicationCount(\"Rejected\"),\n },\n};\nconst APPLICATIONS_FILTERS_TAGS = {\n Pending: {\n label: \"Pending\",\n borderColor: \"#C7C7C7\",\n color: \"#292929\",\n background: \"#F6F5F3\",\n icon: (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M8 0.5C3.86 0.5 0.5 3.86 0.5 8C0.5 12.14 3.86 15.5 8 15.5C12.14 15.5 15.5 12.14 15.5 8C15.5 3.86 12.14 0.5 8 0.5ZM8 14C4.685 14 2 11.315 2 8C2 4.685 4.685 2 8 2C11.315 2 14 4.685 14 8C14 11.315 11.315 14 8 14Z\"\n fill=\"#7B7B7B\"\n />\n <path\n d=\"M4.25 9.125C4.87132 9.125 5.375 8.62132 5.375 8C5.375 7.37868 4.87132 6.875 4.25 6.875C3.62868 6.875 3.125 7.37868 3.125 8C3.125 8.62132 3.62868 9.125 4.25 9.125Z\"\n fill=\"#7B7B7B\"\n />\n <path\n d=\"M8 9.125C8.62132 9.125 9.125 8.62132 9.125 8C9.125 7.37868 8.62132 6.875 8 6.875C7.37868 6.875 6.875 7.37868 6.875 8C6.875 8.62132 7.37868 9.125 8 9.125Z\"\n fill=\"#7B7B7B\"\n />\n <path\n d=\"M11.75 9.125C12.3713 9.125 12.875 8.62132 12.875 8C12.875 7.37868 12.3713 6.875 11.75 6.875C11.1287 6.875 10.625 7.37868 10.625 8C10.625 8.62132 11.1287 9.125 11.75 9.125Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n ),\n },\n Approved: {\n label: \"Approved\",\n color: \"#192C07\",\n borderColor: \"#9ADD33\",\n background: \"#F7FDE8\",\n icon: (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M8 0.5C3.86 0.5 0.5 3.86 0.5 8C0.5 12.14 3.86 15.5 8 15.5C12.14 15.5 15.5 12.14 15.5 8C15.5 3.86 12.14 0.5 8 0.5ZM8 14C4.6925 14 2 11.3075 2 8C2 4.6925 4.6925 2 8 2C11.3075 2 14 4.6925 14 8C14 11.3075 11.3075 14 8 14ZM11.4425 4.685L6.5 9.6275L4.5575 7.6925L3.5 8.75L6.5 11.75L12.5 5.75L11.4425 4.685Z\"\n fill=\"#629D13\"\n />\n </svg>\n ),\n },\n Rejected: {\n label: \"Rejected\",\n borderColor: \"#FAA7A8\",\n color: \"#490813\",\n background: \"#FEF3F2\",\n icon: (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M8 0.5C3.86 0.5 0.5 3.86 0.5 8C0.5 12.14 3.86 15.5 8 15.5C12.14 15.5 15.5 12.14 15.5 8C15.5 3.86 12.14 0.5 8 0.5ZM2 8C2 4.685 4.685 2 8 2C9.3875 2 10.6625 2.4725 11.675 3.2675L3.2675 11.675C2.4725 10.6625 2 9.3875 2 8ZM8 14C6.6125 14 5.3375 13.5275 4.325 12.7325L12.7325 4.325C13.5275 5.3375 14 6.6125 14 8C14 11.315 11.315 14 8 14Z\"\n fill=\"#ED464F\"\n />\n </svg>\n ),\n },\n};\nState.init({\n isModalOpen: false,\n newStatus: \"\",\n projectId: \"\",\n reviewMessage: \"\",\n searchTerm: \"\",\n allApplications: null,\n filteredApplications: [],\n filterVal: \"ALL\",\n});\nconst {\n isModalOpen,\n newStatus,\n projectId,\n reviewMessage,\n searchTerm,\n allApplications,\n filteredApplications,\n filterVal,\n} = state;\nif (applications && !allApplications) {\n applications.reverse();\n State.update({\n filteredApplications: applications,\n allApplications: applications,\n });\n}\nif (!allApplications)\n return <div class=\"spinner-border text-secondary\" role=\"status\" />;\nconst { owner, admins, chef } = potDetail;\nconst isChefOrGreater =\n context.accountId === chef ||\n admins.includes(context.accountId) ||\n context.accountId === owner;\nconst handleApproveApplication = (projectId) => {\n State.update({ isModalOpen: true, newStatus: \"Approved\", projectId });\n};\nconst handleRejectApplication = (projectId) => {\n State.update({ isModalOpen: true, newStatus: \"Rejected\", projectId });\n};\nconst handleCancel = () => {\n State.update({\n isModalOpen: false,\n newStatus: \"\",\n projectId: \"\",\n reviewMessage: \"\",\n });\n};\nconst handleSubmit = () => {\n const args = {\n project_id: projectId,\n status: newStatus,\n notes: reviewMessage,\n };\n const transactions = [\n {\n contractName: potId,\n methodName: \"chef_set_application_status\",\n deposit: NEAR.toIndivisible(0.01),\n args,\n gas: ONE_TGAS.mul(100),\n },\n ];\n Near.call(transactions);\n // NB: we won't get here if user used a web wallet, as it will redirect to the wallet\n // <---- TODO: IMPLEMENT EXTENSION WALLET HANDLING ---->\n};\nconst searchApplications = (searchTerm) => {\n // filter applications that match the search term (message, project_id, review_notes or status)\n const filteredApplications = allApplications?.filter((application) => {\n const { message, project_id, review_notes, status } = application;\n const searchFields = [message, project_id, review_notes, status];\n return searchFields.some((field) =>\n field.toLowerCase().includes(searchTerm.toLowerCase().trim())\n );\n });\n return filteredApplications;\n};\nconst sortApplications = (key) => {\n if (key === \"ALL\") {\n return searchApplications(searchTerm);\n }\n const filtered = allApplications?.filter((application) => {\n return application.status === APPLICATIONS_FILTERS[key].label.split(\" \")[0];\n });\n return filtered;\n};\nconst handleSort = (key) => {\n const sorted = sortApplications(key);\n State.update({ filteredApplications: sorted, filterVal: key });\n};\nconst ProfileImg = ({ profile }) => (\n <Widget src=\"mob.near/widget/ProfileImage\" props={{ profile, style: {} }} />\n);\nconst Container = styled.div`\n display: flex;\n gap: 2rem;\n .dropdown {\n display: none;\n }\n @media only screen and (max-width: 768px) {\n flex-direction: column;\n gap: 1.5rem;\n .dropdown {\n display: flex;\n }\n }\n`;\nconst Filter = styled.div`\n display: grid;\n width: 286px;\n border-radius: 6px;\n padding: 8px 0;\n border: 1px solid var(--Neutral-500, #7b7b7b);\n height: fit-content;\n .item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 0.5rem 1rem;\n font-size: 14px;\n cursor: pointer;\n svg {\n opacity: 0;\n transition: all 300ms ease;\n }\n &.active {\n svg {\n opacity: 1;\n }\n }\n &:hover {\n svg {\n opacity: 1;\n }\n }\n }\n .count {\n color: #7b7b7b;\n margin-left: auto;\n }\n @media only screen and (max-width: 768px) {\n display: none;\n }\n`;\nconst Applications = styled.div`\n border-radius: 6px;\n border: 1px solid #7b7b7b;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n max-width: 711px;\n width: 100%;\n`;\nconst SearchBar = styled.div`\n display: flex;\n position: relative;\n svg {\n position: absolute;\n left: 1.5rem;\n top: 50%;\n transform: translateY(-50%);\n }\n input {\n font-size: 14px;\n background: #f6f5f3;\n width: 100%;\n height: 100%;\n padding: 8px 24px 8px 60px;\n border: none;\n outline: none;\n }\n @media only screen and (max-width: 768px) {\n svg {\n left: 1rem;\n }\n input {\n padding: 8px 24px 8px 54px;\n }\n }\n`;\nconst ApplicationRow = styled.div`\n display: flex;\n flex-direction: column;\n padding: 1.5rem;\n font-size: 14px;\n position: relative;\n border-top: 1px solid #c7c7c7;\n .header {\n display: flex;\n gap: 1rem;\n justify-content: space-between;\n position: relative;\n align-items: center;\n }\n .header-info {\n display: flex;\n gap: 8px;\n align-items: center;\n cursor: auto;\n }\n .profile-image {\n margin-right: 8px;\n width: 24px;\n height: 24px;\n }\n .name {\n color: #292929;\n font-weight: 600;\n }\n .address {\n color: #7b7b7b;\n font-weight: 600;\n cursor: pointer;\n transition: all 300ms;\n position: relative;\n z-index: 2;\n &:hover {\n color: #292929;\n }\n }\n .content {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n overflow: hidden;\n transition: all 300ms ease-in-out;\n max-height: 0;\n .message {\n padding-top: 1rem;\n }\n .notes {\n display: flex;\n flex-direction: column;\n gap: 8px;\n .title {\n color: #7b7b7b;\n }\n }\n button {\n width: fit-content;\n }\n }\n .arrow {\n rotate: 180deg;\n transition: all 300ms;\n }\n .toggle-check {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 67px;\n z-index: 1;\n opacity: 0;\n cursor: pointer;\n }\n .toggle-check:checked + .header .arrow {\n rotate: 0deg;\n }\n .toggle-check:checked + .header + .content {\n max-height: 100%;\n }\n @media only screen and (max-width: 768px) {\n padding: 1rem;\n .header-info {\n flex-wrap: wrap;\n gap: 0px;\n }\n .name {\n margin: 0 8px;\n }\n .date {\n line-height: 1;\n width: 100%;\n margin-left: 2.5rem;\n }\n }\n`;\nconst Dot = styled.div`\n width: 6px;\n height: 6px;\n background: #7b7b7b;\n border-radius: 50%;\n @media only screen and (max-width: 768px) {\n display: none;\n }\n`;\nconst Status = styled.div`\n display: flex;\n padding: 6px 12px;\n gap: 8px;\n align-items: center;\n border-width: 1px;\n border-style: solid;\n border-radius: 4px;\n margin-left: auto;\n div {\n font-weight: 500;\n }\n svg {\n width: 1rem;\n }\n @media only screen and (max-width: 768px) {\n padding: 6px;\n div {\n display: none;\n }\n svg {\n width: 16px;\n }\n }\n`;\nconst ModalHeader = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-start;\n background: white;\n padding: 24px 24px 12px 24px;\n border-top-left-radius: 6px;\n border-top-right-radius: 6px;\n font-weight: 500;\n`;\nconst ModalBody = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n padding: 24px;\n border-top: 1px #f0f0f0 solid;\n background: #fafafa;\n gap: 8px;\n`;\nconst ModalFooter = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-end;\n background: #fafafa;\n padding: 12px 24px 24px 24px;\n border-bottom-left-radius: 6px;\n border-bottom-right-radius: 6px;\n gap: 24px;\n width: 100%;\n`;\nconst DropdownLabel = styled.div`\n display: flex;\n gap: 10px;\n align-items: center;\n .label {\n font-weight: 500;\n }\n .count {\n display: flex;\n width: ${({ digit }) => 24 + (digit - 1) * 6}px;\n height: ${({ digit }) => 24 + (digit - 1) * 6}px;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n background: #ebebeb;\n }\n`;\nreturn (\n <Container>\n <div className=\"dropdown\">\n <Widget\n src={\"old.potlock.near/widget/Inputs.Dropdown\"}\n props={{\n sortVal: (\n <DropdownLabel\n digit={APPLICATIONS_FILTERS[filterVal].count.toString().length}\n >\n <div className=\"label\">\n {APPLICATIONS_FILTERS[filterVal].label}\n </div>\n <div className=\"count\">\n {APPLICATIONS_FILTERS[filterVal].count}\n </div>\n </DropdownLabel>\n ),\n showCount: true,\n sortList: Object.values(APPLICATIONS_FILTERS),\n FilterMenuCustomStyle: `left:0; right:auto;`,\n handleSortChange: ({ val }) => {\n handleSort(val);\n },\n }}\n />\n </div>\n <Filter>\n {Object.keys(APPLICATIONS_FILTERS).map((key) => (\n <div\n key={key}\n className={`item ${filterVal === key ? \"active\" : \"\"}`}\n onClick={() => handleSort(key)}\n >\n <svg\n width=\"14\"\n height=\"12\"\n viewBox=\"0 0 14 12\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M4.59631 8.9057L1.46881 5.7782L0.403809 6.8357L4.59631 11.0282L13.5963 2.0282L12.5388 0.970703L4.59631 8.9057Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n <div> {APPLICATIONS_FILTERS[key].label}</div>\n <div className=\"count\">{APPLICATIONS_FILTERS[key].count}</div>\n </div>\n ))}\n </Filter>\n <Applications>\n <SearchBar>\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M9.81641 8.69141H9.22391L9.01391 8.48891C9.74891 7.63391 10.1914 6.52391 10.1914 5.31641C10.1914 2.62391 8.00891 0.441406 5.31641 0.441406C2.62391 0.441406 0.441406 2.62391 0.441406 5.31641C0.441406 8.00891 2.62391 10.1914 5.31641 10.1914C6.52391 10.1914 7.63391 9.74891 8.48891 9.01391L8.69141 9.22391V9.81641L12.4414 13.5589L13.5589 12.4414L9.81641 8.69141ZM5.31641 8.69141C3.44891 8.69141 1.94141 7.18391 1.94141 5.31641C1.94141 3.44891 3.44891 1.94141 5.31641 1.94141C7.18391 1.94141 8.69141 3.44891 8.69141 5.31641C8.69141 7.18391 7.18391 8.69141 5.31641 8.69141Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n <input\n type=\"text\"\n placeholder=\"Search applications\"\n className=\"search-input\"\n onChange={(e) => {\n const results = searchApplications(e.target.value);\n State.update({\n searchTerm: e.target.value,\n filteredApplications: results,\n });\n }}\n />\n </SearchBar>\n {filteredApplications.length ? (\n filteredApplications.map(\n ({ project_id, status, message, review_notes, submitted_at }) => {\n const { borderColor, color, icon, label, background } =\n APPLICATIONS_FILTERS_TAGS[status];\n const profile = Social.getr(`${project_id}/profile`);\n return (\n <ApplicationRow key={project_id}>\n <input type=\"checkbox\" className=\"toggle-check\" />\n <div className=\"header\">\n <div className=\"header-info\">\n <ProfileImg profile={profile} />\n {profile?.name && (\n <div className=\"name\">{_address(profile?.name, 10)}</div>\n )}\n <OverlayTrigger\n placement=\"top\"\n overlay={<Tooltip>{project_id}</Tooltip>}\n >\n <a\n className=\"address\"\n href={hrefWithParams(\n `?tab=project&projectId=${project_id}`\n )}\n target=\"_blank\"\n >\n {_address(project_id, 10)}\n </a>\n </OverlayTrigger>\n <Dot />\n <div className=\"date\">{daysAgo(submitted_at)}</div>\n </div>\n <Status\n style={{\n borderColor,\n color,\n background,\n }}\n >\n <div>{label}</div>\n {icon}\n </Status>\n <svg\n width=\"12\"\n height=\"8\"\n viewBox=\"0 0 12 8\"\n fill=\"none\"\n className=\"arrow\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 0.294922L0 6.29492L1.41 7.70492L6 3.12492L10.59 7.70492L12 6.29492L6 0.294922Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n </div>\n <div className=\"content\">\n <div className=\"message\">{message}</div>\n {review_notes && (\n <div className=\"notes\">\n <div className=\"title\">Admin notes:</div>\n <div>{review_notes}</div>\n </div>\n )}\n {isChefOrGreater && (\n <>\n {status !== \"Approved\" && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"secondary\",\n text: \"Approve\",\n onClick: () => handleApproveApplication(project_id),\n }}\n />\n )}\n {status !== \"Rejected\" && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: \"Reject\",\n onClick: () => handleRejectApplication(project_id),\n }}\n />\n )}\n </>\n )}\n </div>\n </ApplicationRow>\n );\n }\n )\n ) : (\n <div style={{ padding: \"1rem\" }}>No applications to display</div>\n )}\n </Applications>\n <Widget\n src={\"old.potlock.near/widget/Components.Modal\"}\n props={{\n ...props,\n isModalOpen,\n onClose: () =>\n State.update({ isModalOpen: false, newStatus: \"\", projectId: \"\" }),\n contentStyle: {\n padding: \"0px\",\n },\n children: (\n <>\n <ModalHeader>\n {newStatus === \"Approved\"\n ? \"Approve \"\n : newStatus === \"Rejected\"\n ? \"Reject \"\n : \"\"}\n application from {projectId}\n </ModalHeader>\n <ModalBody>\n <div>Leave a note *</div>\n <Widget\n src={\"old.potlock.near/widget/Inputs.TextArea\"}\n props={{\n noLabel: true,\n inputRows: 5,\n inputStyle: {\n background: \"#FAFAFA\",\n },\n placeholder: \"Type notes here\",\n value: reviewMessage,\n onChange: (reviewMessage) => State.update({ reviewMessage }),\n validate: () => {\n if (reviewMessage.length > MAX_APPLICATION_MESSAGE_LENGTH) {\n State.update({\n reviewMessageError: `Application message must be less than ${MAX_APPLICATION_MESSAGE_LENGTH} characters`,\n });\n return;\n }\n State.update({ reviewMessageError: \"\" });\n },\n error: reviewMessageError,\n }}\n />\n </ModalBody>\n <ModalFooter>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"tertiary\",\n text: \"Cancel\",\n onClick: handleCancel,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: \"Submit\",\n disabled: !reviewMessage || !!reviewMessageError,\n onClick: handleSubmit,\n }}\n />\n </ModalFooter>\n </>\n ),\n }}\n />\n </Container>\n);\n" }, "Components.DonorsUtils": { "": "// Get the current date in the local time zone\nconst currentDate = new Date();\n// Calculate the time zone offset in milliseconds\nlet localTimeZoneOffsetMinutes = currentDate.getTimezoneOffset();\nlocalTimeZoneOffsetMinutes = localTimeZoneOffsetMinutes * 60 * 1000;\nconst oneDayTime = 24 * 60 * 60 * 1000;\nconst currentTimestamp = new Date().getTime();\nconst yesterday = currentTimestamp - oneDayTime;\nconst lastWeek = currentTimestamp - oneDayTime * 7;\nconst lastMonth = currentTimestamp - oneDayTime * 30;\nconst lastYear = currentTimestamp - oneDayTime * 365;\nconst getTimePassed = (timestamp, abbreviate) => {\n // Calculate the difference in milliseconds\n const timePassed = currentTimestamp - timestamp;\n // Convert milliseconds to seconds, minutes, hours, etc.\n const secondsPassed = Math.floor(timePassed / 1000);\n const minutesPassed = Math.floor(secondsPassed / 60);\n const hoursPassed = Math.floor(minutesPassed / 60);\n const daysPassed = Math.floor(hoursPassed / 24);\n let time = 0;\n // Display the time passed conditionally\n if (daysPassed > 0) {\n time = !abbreviate\n ? `${daysPassed} day${daysPassed === 1 ? \"\" : \"s\"}`\n : `${daysPassed}d`;\n } else if (hoursPassed > 0) {\n time = !abbreviate\n ? `${hoursPassed} hour${hoursPassed === 1 ? \"\" : \"s\"}`\n : `${hoursPassed}h`;\n } else if (minutesPassed > 0) {\n time = !abbreviate\n ? `${minutesPassed} minute${minutesPassed === 1 ? \"\" : \"s\"}`\n : `${minutesPassed}m`;\n } else {\n time = !abbreviate\n ? `${secondsPassed} second${secondsPassed === 1 ? \"\" : \"s\"}`\n : `${secondsPassed}s`;\n }\n return time;\n};\nconst _address = (address, max) => {\n const limit = max || 10;\n if (address.length > limit) return address.slice(0, limit) + \"...\";\n else return address;\n};\nconst reverseArr = (input) => {\n var ret = new Array();\n for (var i = input.length - 1; i >= 0; i--) {\n ret.push(input[i]);\n }\n return ret;\n};\nconst calcNetDonationAmount = (donation) => {\n const lastDonationAmount = Big(\n donation.total_amount -\n (donation.referrer_fee || 0) -\n (donation.protocol_fee || 0)\n ).div(Big(1e24));\n return parseFloat(lastDonationAmount);\n};\nconst filterByDate = (filter, donation) => {\n const donateAt = donation.donated_at_ms || donation.donated_at;\n switch (filter) {\n case \"day\":\n if (donateAt > yesterday) return true;\n return false;\n case \"week\":\n if (donateAt > lastWeek) return true;\n return false;\n case \"month\":\n if (donateAt > lastMonth) return true;\n return false;\n case \"year\":\n if (donateAt > lastYear) return true;\n return false;\n case \"all\":\n return true;\n default:\n return true;\n }\n};\nreturn {\n getTimePassed,\n filterByDate,\n _address,\n reverseArr,\n calcNetDonationAmount,\n};\n" }, "ModalDonation.AmountInput": { "": "const { nearToUsd } = VM.require(\"old.potlock.near/widget/utils\");\nconst SvgIcon = styled.svg`\n width: 16px;\n`;\nconst NearIcon = (props) => (\n <SvgIcon\n {...props}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <g clip-path=\"url(#clip0_454_78)\">\n <circle cx=\"8\" cy=\"8\" r=\"7.25\" stroke=\"#292929\" stroke-width=\"1.5\" />\n <path\n d=\"M11.1477 4C10.851 4 10.5763 4.15333 10.421 4.406L8.74866 6.88867C8.72453 6.92441 8.71422 6.96772 8.71967 7.01051C8.72511 7.05329 8.74594 7.09264 8.77826 7.1212C8.81057 7.14976 8.85218 7.1656 8.89531 7.16574C8.93844 7.16589 8.98015 7.15034 9.01266 7.122L10.6587 5.69467C10.6683 5.68598 10.6802 5.68028 10.6931 5.67828C10.7059 5.67628 10.719 5.67806 10.7308 5.6834C10.7426 5.68875 10.7526 5.69742 10.7596 5.70836C10.7665 5.7193 10.7702 5.73203 10.77 5.745V10.215C10.77 10.2287 10.7658 10.2421 10.7579 10.2534C10.7501 10.2646 10.7389 10.2732 10.726 10.2778C10.7131 10.2825 10.6991 10.2831 10.6858 10.2795C10.6726 10.2758 10.6608 10.2682 10.652 10.2577L5.67667 4.30167C5.59667 4.20709 5.49701 4.1311 5.38463 4.079C5.27226 4.0269 5.14987 3.99994 5.026 4H4.85233C4.62628 4 4.40949 4.0898 4.24964 4.24964C4.0898 4.40949 4 4.62628 4 4.85233V11.1477C4 11.3333 4.06061 11.5139 4.17263 11.6619C4.28465 11.81 4.44194 11.9174 4.6206 11.9679C4.79926 12.0184 4.98952 12.0091 5.16245 11.9416C5.33538 11.874 5.48152 11.7519 5.57867 11.5937L7.251 9.111C7.27513 9.07525 7.28544 9.03194 7.27999 8.98916C7.27455 8.94637 7.25372 8.90703 7.22141 8.87846C7.18909 8.8499 7.14748 8.83407 7.10435 8.83392C7.06122 8.83377 7.01951 8.84932 6.987 8.87766L5.341 10.3053C5.33134 10.3139 5.31939 10.3195 5.3066 10.3215C5.29381 10.3234 5.28074 10.3216 5.26898 10.3162C5.25721 10.3108 5.24726 10.3021 5.24034 10.2912C5.23342 10.2803 5.22983 10.2676 5.23 10.2547V5.784C5.22997 5.77027 5.23418 5.75687 5.24206 5.74563C5.24993 5.73438 5.26109 5.72584 5.274 5.72117C5.28691 5.71651 5.30094 5.71594 5.31419 5.71955C5.32743 5.72315 5.33924 5.73076 5.348 5.74133L10.3227 11.698C10.4847 11.8893 10.7227 11.9997 10.9733 12H11.147C11.373 12.0001 11.5898 11.9104 11.7498 11.7507C11.9097 11.591 11.9997 11.3744 12 11.1483V4.85233C11.9999 4.62631 11.9101 4.40956 11.7503 4.24974C11.5904 4.08992 11.3737 4.00009 11.1477 4Z\"\n fill=\"#292929\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_454_78\">\n <rect width=\"16\" height=\"16\" fill=\"white\" />\n </clipPath>\n </defs>\n </SvgIcon>\n);\nconst Container = styled.div`\n position: relative;\n display: flex;\n border-radius: 6px;\n border: 1px solid #dbdbdb;\n border-bottom: 2px solid #dbdbdb;\n background: #fff;\n input {\n padding: 0.75rem 1rem;\n flex: 1;\n background: transparent;\n border: none;\n border-radius: 0;\n &:focus {\n box-shadow: none;\n }\n }\n .usd-amount {\n padding-right: 12px;\n color: #7b7b7b;\n display: flex;\n align-items: center;\n border-right: 1px solid #dbdbdb;\n }\n`;\nconst DropdownWrapper = styled.div`\n display: flex;\n span {\n font-weight: 500;\n }\n`;\nconst PotDenominatio = styled.div`\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 0 1rem;\n .text {\n font-weight: 500;\n }\n`;\nconst Dropdown = ({\n selectedDenomination,\n denominationOptions,\n updateState,\n}) => (\n <DropdownWrapper>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Select\"}\n props={{\n noLabel: true,\n placeholder: \"\",\n options: denominationOptions,\n value: {\n text: selectedDenomination.text,\n value: selectedDenomination.value,\n },\n onChange: ({ value }) => {\n updateState({\n selectedDenomination: denominationOptions.find(\n (option) => option.value === value\n ),\n });\n },\n containerStyles: {\n width: \"auto\",\n },\n inputStyles: {\n border: \"none\",\n boxShadow: \"none\",\n width: \"auto\",\n padding: \"12px 16px\",\n height: \"100%\",\n color: \"#292929\",\n },\n iconLeft: selectedDenomination.icon ? (\n <img\n src={selectedDenomination.icon}\n style={{ height: \"16px\", width: \"16px\" }}\n />\n ) : (\n <NearIcon />\n ),\n }}\n />\n </DropdownWrapper>\n);\nconst AmountInput = (props) => {\n const {\n value,\n HandleAmoutChange,\n donationType,\n denominationOptions,\n selectedDenomination,\n } = props;\n return (\n <Container>\n <input\n type=\"text\"\n value={value}\n placeholder=\"0\"\n onChange={(e) => HandleAmoutChange(e.target.value)}\n name=\"amount\"\n />\n <div className=\"usd-amount\">\n {\" \"}\n {nearToUsd && selectedDenomination.value === \"NEAR\"\n ? `~$ ${(nearToUsd * value).toFixed(2)}`\n : \"\"}\n </div>\n {donationType === \"pot\" || denominationOptions.length === 1 ? (\n <PotDenominatio>\n <NearIcon />\n <div className=\"text\">{denominationOptions[0].text}</div>\n </PotDenominatio>\n ) : (\n <Dropdown {...props} />\n )}\n </Container>\n );\n};\nreturn { AmountInput };\n" }, "Pots.Tag": { "": "const { backgroundColor, borderColor, textColor, text } = props;\nconst textStyle = props.textStyle || {};\nconst TagContainer = styled.div`\n display: flex;\n justify-content: center;\n align-items: center;\n background-color: ${backgroundColor || \"#ffffff\"};\n border: 1px solid ${borderColor || \"#000000\"};\n box-shadow: 0px -0.699999988079071px 0px ${borderColor} inset;\n // width: 100%;\n // height: 100%;\n text-align: center;\n padding: 6px 8px;\n border-radius: 4px;\n`;\nconst TagText = styled.span`\n color: ${textColor || \"#000000\"};\n font-size: 14px;\n`;\nreturn (\n <TagContainer>\n {props.preElements}\n <TagText style={textStyle}>{text}</TagText>\n </TagContainer>\n);\n" }, "ModalDonation.Checks": { "": "const Container = styled.div`\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n > div {\n display: flex;\n border-radius: 8px;\n align-items: center;\n gap: 0.5rem;\n padding: 1rem;\n cursor: pointer;\n border: 1px solid #dbdbdb;\n color: #7b7b7b;\n background: white;\n transition: all 300ms;\n .text {\n flex: 1;\n font-weight: 500;\n }\n &.active {\n box-shadow: 0px 0px 1.4px 2px #fee6e5;\n color: #dd3345;\n border-color: #dd3345;\n span {\n color: #7b7b7b;\n }\n }\n &.disabled {\n pointer-events: none;\n color: #a6a6a6;\n background: #f6f5f3;\n span {\n color: #a6a6a6;\n }\n }\n }\n`;\nconst CheckBox = styled.div`\n width: 20px;\n height: 20px;\n border: 2px solid #d9d9d9;\n display: flex;\n border-radius: 50%;\n div {\n width: 10px;\n height: 10px;\n background: transparent;\n border-radius: 50%;\n margin: auto;\n }\n &.active {\n border-color: #dd3345;\n div {\n background: #dd3345;\n }\n }\n`;\nconst Checks = ({ options, value, onClick }) => {\n return (\n <Container>\n {options.map((option) => (\n <div\n key={option.val}\n onClick={() => onClick(option.val)}\n className={`${value === option.val ? \"active\" : \"\"} ${\n option.disabled ? \"disabled\" : \"\"\n }`}\n >\n <CheckBox className={`${value === option.val ? \"active\" : \"\"}`}>\n <div></div>\n </CheckBox>\n <div className=\"text\">\n {option.label} {option.info && <span> {option.info} </span>}\n {option.disabled && <span> {option.disabledText} </span>}\n </div>\n </div>\n ))}\n </Container>\n );\n};\nreturn { Checks };\n" }, "Inputs.SelectMultiple": { "": "const { label, options, onChange, placeholder, selected } = props;\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n padding: 0px;\n gap: 0.45em;\n width: 100%;\n`;\nconst Label = styled.label`\n font-style: normal;\n // font-weight: 600;\n font-size: 0.95em;\n line-height: 1.25em;\n color: #344054;\n`;\nreturn (\n <Container>\n {label && <Label>{label}</Label>}\n <Typeahead\n options={options}\n multiple\n onChange={onChange}\n placeholder={placeholder}\n selected={selected}\n />\n </Container>\n);\n" }, "Components.AccountsList": { "": "const { accountIds, allowRemove, handleRemoveAccount } = props;\nconst MembersListItem = styled.div`\n padding: 16px 0px;\n border-top: 1px #f0f0f0 solid;\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n`;\nconst MembersListItemLeft = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-start;\n gap: 16px;\n`;\nconst MembersListItemText = styled.div`\n font-size: 16px;\n font-weight: 400;\n color: #2e2e2e;\n`;\nconst RemoveMember = styled.a`\n color: #2e2e2e;\n font-size: 14px;\n font-weight: 600;\n visibility: hidden;\n cursor: pointer;\n opacity: 0;\n transition: opacity 0.2s ease-in-out;\n &:hover {\n text-decoration: none;\n }\n ${MembersListItem}:hover & {\n visibility: visible;\n opacity: 1;\n }\n`;\nreturn (\n <>\n {accountIds.map((accountId) => {\n return (\n <MembersListItem>\n <MembersListItemLeft>\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{\n accountId,\n style: {\n width: \"40px\",\n height: \"40px\",\n margin: \"0 -8px 0 0\",\n borderRadius: \"50%\",\n background: \"white\",\n },\n imageClassName: \"rounded-circle w-100 h-100 d-block\",\n thumbnail: false,\n tooltip: true,\n }}\n />\n <MembersListItemText>@{accountId}</MembersListItemText>\n </MembersListItemLeft>\n {allowRemove && (\n <RemoveMember onClick={() => handleRemoveAccount(accountId)}>\n Remove\n </RemoveMember>\n )}\n </MembersListItem>\n );\n })}\n </>\n);\n" } } } } }

Transaction Execution Plan

Convert Transaction To Receipt
Gas Burned:
1 Tgas
Tokens Burned:
0.00014 
Receipt:
Predecessor ID:
Receiver ID:
Gas Burned:
155 Tgas
Tokens Burned:
0.01559 
Called method: 'set' in contract: social.near
Arguments:
{ "data": { "old.potlock.near": { "widget": { "Components.DonorsTrx": { "": "const { allDonations, filter } = props;\nconst [currentPage, setCurrentPage] = useState(1);\nconst perPage = 30; // need to be less than 50\nuseEffect(() => {\n setCurrentPage(1);\n}, [filter]);\nconst nearLogo =\n \"https://ipfs.near.social/ipfs/bafkreicdcpxua47eddhzjplmrs23mdjt63czowfsa2jnw4krkt532pa2ha\";\nconst { getTimePassed, _address, reverseArr } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n);\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2rem;\n width: 100%;\n .transcation {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-size: 14px;\n .header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px;\n gap: 1rem;\n background: #f6f5f3;\n color: #292929;\n div {\n width: 100px;\n display: flex;\n justify-content: center;\n align-items: center;\n font-weight: 600;\n }\n }\n .address {\n width: 143px !important;\n }\n }\n @media only screen and (max-width: 768px) {\n .transcation {\n font-size: 12px;\n .header {\n padding: 10px 0;\n div {\n width: 80px !important;\n }\n }\n .address {\n width: 80px !important;\n justify-content: center;\n .profile-image {\n display: none !important;\n }\n }\n }\n }\n @media only screen and (max-width: 480px) {\n .transcation {\n font-size: 9px;\n }\n }\n`;\nconst TrRow = styled.div`\n display: flex;\n width: 100%;\n justify-content: space-between;\n gap: 1rem;\n padding: 20px 10px;\n > div,\n > span {\n width: 100px;\n display: flex;\n justify-content: center;\n align-items: center;\n }\n .price {\n display: flex;\n gap: 1rem;\n align-items: center;\n img {\n width: 1.5rem;\n }\n }\n .address {\n color: #292929;\n display: flex;\n align-items: center;\n justify-content: flex-start;\n border-radius: 2px;\n transition: all 200ms;\n .profile-image {\n width: 2rem;\n height: 2rem;\n margin-right: 1rem;\n }\n }\n @media only screen and (max-width: 768px) {\n padding: 10px 0;\n > div,\n > span {\n width: 80px;\n }\n .price {\n gap: 8px;\n img {\n width: 1.25rem;\n }\n }\n .address .profile-image {\n width: 1.5rem;\n height: 1.5rem;\n margin-right: 0.5rem;\n }\n }\n @media only screen and (max-width: 480px) {\n .price img {\n width: 1rem;\n }\n }\n`;\nconst NoResult = styled.div`\n font-size: 2rem;\n text-align: center;\n`;\nconst ProfileImg = ({ address }) => (\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{ accountId: address, style: {} }}\n />\n);\nconst NEAR_DECEMIALS = 24;\nconst calcNetDonationAmount = (amount, decimals) =>\n Big(amount).div(Big(`1e${decimals}`));\nreturn allDonations.length ? (\n <Container>\n <div className=\"transcation\">\n <div className=\"header\">\n <div className=\"address\">Donor</div>\n <div className=\"address\">Project</div>\n <div>Amount</div>\n <div>Date</div>\n </div>\n {reverseArr(allDonations)\n .slice((currentPage - 1) * perPage, currentPage * perPage)\n .map((donation) => {\n const {\n donor_id,\n recipient_id,\n donated_at_ms,\n donated_at,\n project_id,\n ft_id,\n total_amount,\n } = donation;\n const projectId = recipient_id || project_id;\n const isNear = ft_id === \"near\";\n const frMetaDate = !isNear\n ? Near.view(ft_id, \"ft_metadata\", {})\n : null;\n const assetIcon = isNear ? nearLogo : frMetaDate.icon;\n const decimals = isNear ? NEAR_DECEMIALS : frMetaDate.decimals;\n console.log(\"decimals\", decimals);\n return (\n <TrRow>\n <a\n href={props.hrefWithParams(\n `?tab=profile&accountId=${donor_id}`\n )}\n className=\"address\"\n target=\"_blank\"\n >\n <ProfileImg address={donor_id} />\n {_address(donor_id)}\n </a>\n <a\n href={props.hrefWithParams(\n `?tab=project&projectId=${projectId}`\n )}\n className=\"address\"\n target=\"_blank\"\n >\n <ProfileImg address={projectId} />\n {_address(projectId)}\n </a>\n <div className=\"price\">\n <img src={assetIcon} alt={ft_id} />\n {decimals\n ? calcNetDonationAmount(total_amount, decimals).toFixed(2)\n : \"-\"}\n </div>\n <div>{getTimePassed(donated_at_ms || donated_at)} ago</div>\n </TrRow>\n );\n })}\n </div>\n <Widget\n src={\"old.potlock.near/widget/Components.Pagination\"}\n props={{\n onPageChange: (page) => {\n setCurrentPage(page);\n },\n data: allDonations,\n currentPage,\n perPage: perPage,\n bgColor: \"#292929\",\n }}\n />\n </Container>\n) : (\n <NoResult>No Donations</NoResult>\n);\n" }, "ModalDonation.Banners": { "": "const AlertBanner = styled.div`\n display: flex;\n padding: 0.75rem 1rem;\n color: #ed464f;\n gap: 1rem;\n align-items: center;\n border: 1px solid #f4b37d;\n border-radius: 6px;\n background: #fef6ee;\n margin-top: 1.5rem;\n div {\n font-weight: 500;\n }\n .icon {\n width: 22px;\n }\n`;\nconst NadabotBanner = styled.div`\n display: flex;\n align-items: center;\n padding: 0.75rem 1rem;\n border: 1px solid #f4b37d;\n border-radius: 6px;\n background: #fef6ee;\n flex-wrap: wrap;\n margin-top: 1.5rem;\n .label {\n display: flex;\n align-items: center;\n font-weight: 500;\n gap: 1rem;\n img {\n width: 24px;\n height: 24px;\n }\n }\n .verify {\n color: #dd3345;\n font-weight: 500;\n margin-left: auto;\n &:hover {\n text-decoration: none;\n }\n }\n @media only screen and (max-width: 480px) {\n flex-direction: column;\n align-items: flex-start;\n gap: 0px;\n .labe {\n align-items: flex-start;\n }\n .verify {\n margin-left: 40px;\n }\n }\n`;\nconst VerifyInfoWrapper = styled.div`\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 1rem;\n border-radius: 6px;\n border: 1px solid #ecc113;\n background: #fbf9c6;\n box-shadow: 0px 2px 1px 1px rgba(255, 255, 255, 0.8) inset,\n 0px -2px 4px 0px rgba(15, 15, 15, 0.15) inset;\n font-size: 14px;\n color: #3f2209;\n margin-top: 1.5rem;\n .icon {\n width: 17px;\n display: flex;\n height: fit-content;\n svg {\n width: 100%;\n }\n }\n .text {\n flex: 1;\n line-height: 150%;\n }\n a {\n font-weight: 500;\n color: #dd3345;\n :hover {\n text-decoration: none;\n }\n }\n @media only screen and (max-width: 480px) {\n flex-wrap: wrap;\n a {\n width: 100%;\n text-align: center;\n }\n }\n`;\nconst NADA_BOT_ICON =\n \"bafkreicojpp23dmf7hakbt67eah4ba52dx3reekdccaupoggzzlhdkroyi\";\nconst Alert = ({ error }) => (\n <AlertBanner>\n <div className=\"icon\">\n <svg viewBox=\"0 0 22 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M11 4.49L18.53 17.5H3.47L11 4.49ZM11 0.5L0 19.5H22L11 0.5ZM12 14.5H10V16.5H12V14.5ZM12 8.5H10V12.5H12V8.5Z\"\n fill=\"#F6767A\"\n />\n </svg>\n </div>\n <div>{error}</div>\n </AlertBanner>\n);\nconst Nadabot = () => (\n <NadabotBanner>\n <div className=\"label\">\n <img\n src={`https://ipfs.near.social/ipfs/${NADA_BOT_ICON}`}\n alt=\"nadabot\"\n />\n You need to be verified to donate.\n </div>\n <a href=\"https://app.nada.bot/\" target=\"_blank\" className=\"verify\">\n Verify to donate\n </a>\n </NadabotBanner>\n);\nconst VerifyInfo = () => (\n <VerifyInfoWrapper>\n <div className=\"icon\">\n <svg\n width=\"18\"\n height=\"16\"\n viewBox=\"0 0 18 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M0.75 15.125H17.25L9 0.875L0.75 15.125ZM9.75 12.875H8.25V11.375H9.75V12.875ZM9.75 9.875H8.25V6.875H9.75V9.875Z\"\n fill=\"#ECC113\"\n />\n </svg>\n </div>\n <div className=\"text\">\n Your contribution won't be matched unless verified as human before the\n matching round ends.\n </div>\n <a href=\"https://app.nada.bot/\" target=\"_blank\">\n Verify you’re human\n </a>\n </VerifyInfoWrapper>\n);\nreturn {\n Alert,\n Nadabot,\n VerifyInfo,\n};\n" }, "ModalDonation.ConfirmDirect": { "": "const { NADABOT_HUMAN_METHOD, DONATION_CONTRACT_ID } = VM.require(\n \"old.potlock.near/widget/constants\"\n) || {\n NADABOT_HUMAN_METHOD: \"\",\n DONATION_CONTRACT_ID: \"\",\n};\nconst { nearToUsd } = VM.require(\"old.potlock.near/widget/utils\");\nlet DonateSDK =\n VM.require(\"old.potlock.near/widget/SDK.donate\") ||\n (() => ({\n getConfig: () => {},\n asyncGetDonationsForDonor: () => {},\n }));\nDonateSDK = DonateSDK({ env: props.env });\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getConfig: () => {},\n asyncGetDonationsForDonor: () => {},\n};\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n padding: 1.5rem 2rem;\n`;\nconst Label = styled.div`\n font-weight: 500;\n margin-bottom: 4px;\n`;\nconst Amout = styled.div`\n display: flex;\n align-items: center;\n gap: 0.5rem;\n span {\n font-weight: 600;\n }\n div {\n font-weight: 600;\n font-size: 1rem;\n }\n .usd-amount {\n color: #7b7b7b;\n }\n img,\n svg {\n width: 20px;\n }\n`;\nconst SvgIcon = styled.svg`\n width: 16px;\n`;\nconst NoteWrapper = styled.div`\n display: flex;\n cursor: pointer;\n align-items: center;\n gap: 8px;\n svg {\n width: 14px;\n }\n div {\n font-weight: 500;\n }\n`;\nconst FeesRemoval = styled.div`\n display: flex;\n flex-direction: column;\n gap: 1rem;\n .check {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n }\n .label {\n margin-right: 4px;\n margin-left: 8px;\n }\n .address {\n font-weight: 600;\n gap: 4px;\n display: flex;\n align-items: center;\n color: #292929;\n transition: all 300ms;\n &:hover {\n color: #dd3345;\n text-decoration: none;\n }\n }\n .profile-image {\n width: 17px;\n height: 17px;\n display: flex !important;\n }\n @media only screen and (max-width: 480px) {\n .address {\n margin-left: 34px;\n width: 100%;\n }\n }\n`;\nconst Button = styled.div`\n display: flex;\n margin-top: 2rem;\n margin-bottom: 0.5rem;\n button {\n padding: 12px 16px;\n width: 100%;\n font-weight: 500;\n }\n`;\nconst NearIcon = (props) => (\n <SvgIcon\n {...props}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <g clip-path=\"url(#clip0_454_78)\">\n <circle cx=\"8\" cy=\"8\" r=\"7.25\" stroke=\"#292929\" stroke-width=\"1.5\" />\n <path\n d=\"M11.1477 4C10.851 4 10.5763 4.15333 10.421 4.406L8.74866 6.88867C8.72453 6.92441 8.71422 6.96772 8.71967 7.01051C8.72511 7.05329 8.74594 7.09264 8.77826 7.1212C8.81057 7.14976 8.85218 7.1656 8.89531 7.16574C8.93844 7.16589 8.98015 7.15034 9.01266 7.122L10.6587 5.69467C10.6683 5.68598 10.6802 5.68028 10.6931 5.67828C10.7059 5.67628 10.719 5.67806 10.7308 5.6834C10.7426 5.68875 10.7526 5.69742 10.7596 5.70836C10.7665 5.7193 10.7702 5.73203 10.77 5.745V10.215C10.77 10.2287 10.7658 10.2421 10.7579 10.2534C10.7501 10.2646 10.7389 10.2732 10.726 10.2778C10.7131 10.2825 10.6991 10.2831 10.6858 10.2795C10.6726 10.2758 10.6608 10.2682 10.652 10.2577L5.67667 4.30167C5.59667 4.20709 5.49701 4.1311 5.38463 4.079C5.27226 4.0269 5.14987 3.99994 5.026 4H4.85233C4.62628 4 4.40949 4.0898 4.24964 4.24964C4.0898 4.40949 4 4.62628 4 4.85233V11.1477C4 11.3333 4.06061 11.5139 4.17263 11.6619C4.28465 11.81 4.44194 11.9174 4.6206 11.9679C4.79926 12.0184 4.98952 12.0091 5.16245 11.9416C5.33538 11.874 5.48152 11.7519 5.57867 11.5937L7.251 9.111C7.27513 9.07525 7.28544 9.03194 7.27999 8.98916C7.27455 8.94637 7.25372 8.90703 7.22141 8.87846C7.18909 8.8499 7.14748 8.83407 7.10435 8.83392C7.06122 8.83377 7.01951 8.84932 6.987 8.87766L5.341 10.3053C5.33134 10.3139 5.31939 10.3195 5.3066 10.3215C5.29381 10.3234 5.28074 10.3216 5.26898 10.3162C5.25721 10.3108 5.24726 10.3021 5.24034 10.2912C5.23342 10.2803 5.22983 10.2676 5.23 10.2547V5.784C5.22997 5.77027 5.23418 5.75687 5.24206 5.74563C5.24993 5.73438 5.26109 5.72584 5.274 5.72117C5.28691 5.71651 5.30094 5.71594 5.31419 5.71955C5.32743 5.72315 5.33924 5.73076 5.348 5.74133L10.3227 11.698C10.4847 11.8893 10.7227 11.9997 10.9733 12H11.147C11.373 12.0001 11.5898 11.9104 11.7498 11.7507C11.9097 11.591 11.9997 11.3744 12 11.1483V4.85233C11.9999 4.62631 11.9101 4.40956 11.7503 4.24974C11.5904 4.08992 11.3737 4.00009 11.1477 4Z\"\n fill=\"#292929\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_454_78\">\n <rect width=\"16\" height=\"16\" fill=\"white\" />\n </clipPath>\n </defs>\n </SvgIcon>\n);\nconst ProfileImg = ({ accountId }) => (\n <Widget\n src={\"old.potlock.near/widget/Project.ProfileImage\"}\n props={{\n accountId,\n style: {},\n }}\n />\n);\nconst CheckBox = ({ id, checked, onClick }) => (\n <Widget\n src={\"old.potlock.near/widget/Inputs.Checkbox\"}\n props={{\n id,\n checked,\n onClick,\n }}\n />\n);\nconst getFeesBasisPoints = (\n protocolConfig,\n potDetail,\n donationContractConfig\n) => {\n if (protocolConfig) {\n return [\n protocolConfig.account_id,\n protocolConfig.basis_points,\n potDetail.referral_fee_public_round_basis_points,\n ];\n } else if (donationContractConfig) {\n return [\n donationContractConfig.protocol_fee_recipient_account,\n donationContractConfig.protocol_fee_basis_points,\n donationContractConfig.referral_fee_basis_points,\n ];\n } else {\n return [\"\", 0, 0];\n }\n};\nconst pollForDonationSuccess = ({\n projectId: donatedProject,\n afterTs,\n accountId,\n openDonationSuccessModal,\n isPotDonation,\n}) => {\n // poll for updates\n // TODO: update this to also poll Pot contract\n const pollIntervalMs = 1000;\n // const totalPollTimeMs = 60000; // consider adding in to make sure interval doesn't run indefinitely\n const pollId = setInterval(() => {\n (isPotDonation ? PotSDK : DonateSDK)\n .asyncGetDonationsForDonor(accountId)\n .then((donations) => {\n for (const donation of donations) {\n const { recipient_id, project_id, donated_at_ms, donated_at } =\n donation; // donation contract uses recipient_id, pot contract uses project_id; donation contract uses donated_at_ms, pot contract uses donated_at\n if (\n ((project_id || recipient_id) === donatedProject &&\n (donated_at_ms || donated_at) > afterTs) ||\n donated_at > afterTs\n ) {\n // display success message\n clearInterval(pollId);\n openDonationSuccessModal({\n projectId: donation,\n });\n }\n }\n });\n }, pollIntervalMs);\n};\nconst ConfirmDirect = (props) => {\n const {\n selectedDenomination,\n bypassProtocolFee,\n bypassChefFee,\n donationNote,\n donationNoteError,\n addNote,\n updateState,\n selectedRound,\n projectId,\n referrerId,\n accountId,\n amount,\n openDonationSuccessModal,\n donationType,\n } = props;\n // Get protcol, referral & chef Fee\n const potDetail = PotSDK.getConfig(selectedRound);\n const protocolConfigContractId = potDetail\n ? potDetail.protocol_config_provider.split(\":\")[0]\n : \"\";\n const protocolConfigViewMethodName = potDetail\n ? potDetail.protocol_config_provider.split(\":\")[1]\n : \"\";\n const protocolConfig =\n protocolConfigContractId && protocolConfigViewMethodName\n ? Near.view(protocolConfigContractId, protocolConfigViewMethodName, {})\n : null;\n const donationContractConfig = !potDetail\n ? DonateSDK.getConfig() || {}\n : null;\n const [\n protocolFeeRecipientAccount,\n protocolFeeBasisPoints,\n referralFeeBasisPoints,\n ] = getFeesBasisPoints(protocolConfig, potDetail, donationContractConfig);\n const chefFeeBasisPoints =\n donationType === \"pot\" ? potDetail?.chef_fee_basis_points : \"\";\n const storageBalanceBounds = Near.view(\n selectedDenomination.id,\n \"storage_balance_bounds\",\n {}\n );\n const storageBalanceProtocolFeeRecipient = Near.view(\n selectedDenomination.id,\n \"storage_balance_of\",\n { account_id: protocolFeeRecipientAccount }\n );\n const storageBalanceReferrer = referrerId\n ? Near.view(selectedDenomination.id, \"storage_balance_of\", {\n account_id: referrerId,\n })\n : null;\n const storageBalanceDonationContract = Near.view(\n selectedDenomination.id,\n \"storage_balance_of\",\n {\n account_id: DONATION_CONTRACT_ID,\n }\n );\n const handleDonate = () => {\n const donationAmountIndivisible = Big(amount).mul(\n new Big(10).pow(selectedDenomination.decimals)\n );\n const args = {\n referrer_id: referrerId,\n bypass_protocol_fee: bypassProtocolFee,\n message: donationNote,\n ...(bypassChefFee ? { custom_chef_fee_basis_points: 0 } : {}),\n };\n const potId = selectedRound || null;\n const isPotDonation = potId && donationType === \"pot\";\n const now = Date.now();\n const successArgs = {\n projectId,\n afterTs: now,\n accountId,\n openDonationSuccessModal,\n isPotDonation,\n };\n if (isPotDonation) {\n args.project_id = projectId;\n if (bypassChefFee) {\n args.custom_chef_fee_basis_points = 0;\n }\n } else {\n args.recipient_id = projectId;\n }\n // FT WORKFLOW:\n // 1. SEND DEPOSIT TO DONATION CONTRACT\n /// 2. CALL FT CONTRACT:\n /// - check for storage balance for all accounts (protocol fee recipient, referrer, project, donation contract)\n const transactions = [];\n const isFtDonation = selectedDenomination.text !== \"NEAR\";\n if (isFtDonation) {\n const ftId = selectedDenomination.id;\n // add storage deposit transaction\n let requiredDepositFloat = 0.012; // base amount for donation storage\n requiredDepositFloat += 0.0001 * args.message.length; // add 0.0001 NEAR per character in message\n transactions.push({\n contractName: DONATION_CONTRACT_ID,\n methodName: \"storage_deposit\",\n args: {},\n deposit: Big(requiredDepositFloat).mul(Big(10).pow(24)),\n gas: \"100000000000000\",\n });\n const { min, max } = storageBalanceBounds;\n const storageMaxBig = Big(max);\n // check storage balance for each account\n if (\n !args.bypass_protocol_fee &&\n (!storageBalanceProtocolFeeRecipient ||\n Big(storageBalanceProtocolFeeRecipient.total).lt(storageMaxBig))\n ) {\n transactions.push({\n contractName: ftId,\n methodName: \"storage_deposit\",\n args: { account_id: protocolFeeRecipientAccount },\n deposit: storageMaxBig.minus(\n Big(storageBalanceProtocolFeeRecipient || 0)\n ),\n gas: \"100000000000000\",\n });\n }\n // referrer\n if (\n referrerId &&\n (!storageBalanceReferrer ||\n Big(storageBalanceReferrer.total).lt(storageMaxBig))\n ) {\n transactions.push({\n contractName: ftId,\n methodName: \"storage_deposit\",\n args: { account_id: referrerId },\n deposit: storageMaxBig.minus(Big(storageBalanceReferrer || 0)),\n gas: \"100000000000000\",\n });\n }\n // donation contract\n if (\n !storageBalanceDonationContract ||\n Big(storageBalanceDonationContract.total).lt(storageMaxBig)\n ) {\n transactions.push({\n contractName: ftId,\n methodName: \"storage_deposit\",\n args: { account_id: DONATION_CONTRACT_ID },\n deposit: storageMaxBig.minus(\n Big(storageBalanceDonationContract || 0)\n ),\n gas: \"100000000000000\",\n });\n }\n // project (can't do this till this point)\n Near.asyncView(ftId, \"storage_balance_of\", {\n account_id: projectId,\n }).then((balance) => {\n if (!balance || Big(balance.total).lt(storageMaxBig)) {\n transactions.push({\n contractName: ftId,\n methodName: \"storage_deposit\",\n args: { account_id: projectId },\n deposit: storageMaxBig.minus(Big(balance || 0)),\n gas: \"100000000000000\",\n });\n }\n // add donation transaction\n transactions.push({\n contractName: ftId,\n methodName: \"ft_transfer_call\",\n args: {\n receiver_id: DONATION_CONTRACT_ID,\n amount: donationAmountIndivisible.toFixed(0),\n msg: JSON.stringify({\n recipient_id: projectId,\n referrer_id: referrerId || null,\n bypass_protocol_fee: bypassProtocolFee,\n message: args.message,\n }),\n },\n deposit: \"1\",\n gas: \"300000000000000\",\n });\n Near.call(transactions);\n // NB: we won't get here if user used a web wallet, as it will redirect to the wallet\n // <-------- EXTENSION WALLET HANDLING -------->\n pollForDonationSuccess(successArgs);\n });\n } else {\n transactions.push({\n contractName: isPotDonation ? potId : DONATION_CONTRACT_ID,\n methodName: \"donate\",\n args,\n deposit: donationAmountIndivisible.toFixed(0),\n gas: \"300000000000000\",\n });\n Near.call(transactions);\n // NB: we won't get here if user used a web wallet, as it will redirect to the wallet\n // <-------- EXTENSION WALLET HANDLING -------->\n pollForDonationSuccess(successArgs);\n }\n };\n return (\n <Container>\n <div>\n <Label>Total amount</Label>\n <Amout>\n <div>\n {selectedDenomination.icon ? (\n <img src={selectedDenomination.icon} />\n ) : (\n <NearIcon />\n )}\n </div>\n <div>\n {amount} <span>{selectedDenomination.text}</span>\n </div>\n {nearToUsd && selectedDenomination.text === \"NEAR\" && (\n <div className=\"usd-amount\">\n ~${(nearToUsd * amount).toFixed(2)}\n </div>\n )}\n </Amout>\n </div>\n <div>\n <Widget\n src={\"old.potlock.near/widget/Cart.BreakdownSummary\"}\n props={{\n ...props,\n referrerId,\n protocolFeeBasisPoints,\n referralFeeBasisPoints,\n bypassChefFee,\n chef: potDetail?.chef,\n chefFeeBasisPoints,\n totalAmount: amount,\n bypassProtocolFee: bypassProtocolFee,\n ftIcon: selectedDenomination.icon,\n }}\n />\n </div>\n <FeesRemoval>\n <div className=\"check\">\n <CheckBox\n id=\"bypassProtocolFeeSelector\"\n checked={bypassProtocolFee}\n onClick={(e) => {\n updateState({ bypassProtocolFee: e.target.checked });\n }}\n />\n <div className=\"label\">\n Remove {protocolFeeBasisPoints / 100 || \"-\"}% protocol fee\n </div>\n <a\n href={`https://near.social/mob.near/widget/ProfilePage?accountId=${protocolFeeRecipientAccount}`}\n className=\"address\"\n target=\"_blank\"\n >\n <ProfileImg accountId={protocolFeeRecipientAccount} />\n {protocolFeeRecipientAccount}\n </a>\n </div>\n {potDetail?.chef && chefFeeBasisPoints > 0 && (\n <div className=\"check\">\n <CheckBox\n id=\"bypassChefFeeSelector\"\n checked={bypassChefFee}\n onClick={(e) => {\n updateState({ bypassChefFee: e.target.checked });\n }}\n />\n <div className=\"label\">\n {\" \"}\n Remove {chefFeeBasisPoints / 100 || \"-\"}% chef fee\n </div>\n <a\n href={`https://near.social/mob.near/widget/ProfilePage?accountId=${potDetail?.chef}`}\n className=\"address\"\n target=\"_blank\"\n >\n <ProfileImg accountId={potDetail?.chef} />\n {potDetail?.chef}\n </a>\n </div>\n )}\n </FeesRemoval>\n {addNote ? (\n <Widget\n src={\"old.potlock.near/widget/Inputs.TextArea\"}\n props={{\n label: \"Note\",\n inputRows: 2,\n inputStyle: {\n background: \"#FAFAFA\",\n },\n placeholder: `Add an optional note for the project (max ${MAX_NOTE_LENGTH} characters)`,\n value: donationNote,\n onChange: (donationNote) => updateState({ donationNote }),\n validate: () => {\n if (donationNote.length > MAX_NOTE_LENGTH) {\n updateState({\n donationNoteError: `Note must be less than ${MAX_NOTE_LENGTH} characters`,\n });\n return;\n }\n updateState({ donationNoteError: \"\" });\n },\n error: donationNoteError,\n }}\n />\n ) : (\n <NoteWrapper onClick={() => updateState({ addNote: true })}>\n <svg\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M0.249054 13.7509H3.06155L11.3566 5.4559L8.54405 2.6434L0.249054 10.9384V13.7509ZM1.74905 11.5609L8.54405 4.7659L9.23405 5.4559L2.43905 12.2509H1.74905V11.5609Z\"\n fill=\"#7B7B7B\"\n />\n <path\n d=\"M11.7766 0.468398C11.4841 0.175898 11.0116 0.175898 10.7191 0.468398L9.34655 1.8409L12.1591 4.6534L13.5316 3.2809C13.8241 2.9884 13.8241 2.5159 13.5316 2.2234L11.7766 0.468398Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n <div>Add Note</div>\n </NoteWrapper>\n )}\n <Button>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: \"Confirm donation\",\n onClick: handleDonate,\n }}\n />\n </Button>\n </Container>\n );\n};\nreturn {\n ConfirmDirect,\n};\n" }, "Pots.FundModal": { "": "const { isMatchingPoolModalOpen, onClose, potDetail, referrerId, potId } =\n props;\nconst {\n protocol_config_provider,\n chef_fee_basis_points,\n chef,\n base_currency,\n min_matching_pool_donation_amount,\n referral_fee_matching_pool_basis_points,\n} = potDetail;\nState.init({\n matchingPoolDonationAmountNear: \"\",\n matchingPoolDonationAmountNearError: \"\",\n matchingPoolDonationMessage: \"\",\n matchingPoolDonationMessageError: \"\",\n bypassProtocolFee: false,\n bypassChefFee: false,\n fundAsDao: false,\n daoAddress: \"\",\n daoAddressError: \"\",\n daoPolicy: {},\n});\nconst {\n matchingPoolDonationAmountNear,\n matchingPoolDonationAmountNearError,\n matchingPoolDonationMessage,\n matchingPoolDonationMessageError,\n bypassProtocolFee,\n bypassChefFee,\n fundAsDao,\n daoAddress,\n daoAddressError,\n} = state;\nconst { yoctosToNear, doesUserHaveDaoFunctionCallProposalPermissions } =\n VM.require(\"old.potlock.near/widget/utils\") || {\n yoctosToNear: () => \"\",\n doesUserHaveDaoFunctionCallProposalPermissions: () => \"\",\n };\nconst { _address } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n) || {\n _address: () => \"\",\n};\nconst { MAX_DONATION_MESSAGE_LENGTH, SUPPORTED_FTS, ONE_TGAS } = VM.require(\n \"old.potlock.near/widget/constants\"\n) || {\n ONE_TGAS: 0,\n MAX_DONATION_MESSAGE_LENGTH: 0,\n SUPPORTED_FTS: {},\n};\nBig.PE = 100;\nconst FIFTY_TGAS = \"50000000000000\";\nconst THREE_HUNDRED_TGAS = \"300000000000000\";\nconst MIN_DAO_PROPOSAL_DEPOSIT_FALLBACK = \"100000000000000000000000\"; // 0.1N\nconst protocolConfigContractId = protocol_config_provider.split(\":\")[0];\nconst protocolConfigViewMethodName = protocol_config_provider.split(\":\")[1];\nconst protocolConfig = Near.view(\n protocolConfigContractId,\n protocolConfigViewMethodName,\n {}\n);\nconst protocolFeeRecipientProfile = Social.getr(\n `${protocolConfig?.account_id}/profile`\n);\nconst chefProfile = Social.getr(`${chef}/profile`);\nconst chefFeeAmountNear = bypassChefFee\n ? 0\n : (matchingPoolDonationAmountNear * potDetail?.chef_fee_basis_points) /\n 10_000 || 0;\nconst protocolFeeAmountNear = bypassProtocolFee\n ? 0\n : (matchingPoolDonationAmountNear * protocolConfig?.basis_points) / 10_000 ||\n 0;\nconst referrerFeeAmountNear = referrerId\n ? (matchingPoolDonationAmountNear * referral_fee_matching_pool_basis_points) /\n 10_000 || 0\n : 0;\nconst handleMatchingPoolDonation = () => {\n const args = {\n message: matchingPoolDonationMessage,\n matching_pool: true,\n referrer_id: referrerId || null,\n bypass_protocol_fee: bypassProtocolFee,\n };\n if (state.bypassChefFee) {\n args.custom_chef_fee_basis_points = 0;\n }\n const amountFloat = parseFloat(matchingPoolDonationAmountNear || 0);\n if (!amountFloat) {\n State.update({ matchingPoolDonationAmountNearError: \"Invalid amount\" });\n return;\n }\n const amountIndivisible =\n SUPPORTED_FTS[base_currency.toUpperCase()].toIndivisible(amountFloat);\n const transactions = [\n {\n contractName: potId,\n methodName: \"donate\",\n deposit: amountIndivisible,\n args,\n gas: ONE_TGAS.mul(100),\n },\n ];\n // if it is a DAO, we need to convert transactions to DAO function call proposals\n if (state.fundAsDao) {\n const clonedTransactions = JSON.parse(JSON.stringify(transactions));\n transactions = clonedTransactions.map((tx) => {\n const action = {\n method_name: tx.methodName,\n gas: FIFTY_TGAS,\n deposit: tx.deposit ? tx.deposit.toString() : \"0\",\n args: Buffer.from(JSON.stringify(tx.args), \"utf-8\").toString(\"base64\"),\n };\n return {\n ...tx,\n contractName: state.daoAddress,\n methodName: \"add_proposal\",\n args: {\n proposal: {\n description: `Contribute to matching pool for ${potDetail.pot_name} pot (${potId}) on Potlock`,\n kind: {\n FunctionCall: {\n receiver_id: tx.contractName,\n actions: [action],\n },\n },\n },\n },\n deposit:\n state.daoPolicy.proposal_bond || MIN_DAO_PROPOSAL_DEPOSIT_FALLBACK,\n gas: THREE_HUNDRED_TGAS,\n };\n });\n }\n Near.call(transactions);\n // NB: we won't get here if user used a web wallet, as it will redirect to the wallet\n // <---- EXTENSION WALLET HANDLING ----> // TODO: implement\n};\nconst ModalTitle = styled.div`\n color: #525252;\n font-size: 16px;\n font-weight: 400;\n line-height: 20px;\n word-wrap: break-word;\n margin: 8px 0px;\n`;\nconst Row = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-start;\n`;\nconst UserChipLink = styled.a`\n display: flex;\n flex-direction: row;\n margin: 0px 4px;\n margin-left: auto;\n padding: 2px 12px;\n gap: 4px;\n border-radius: 32px;\n background: #ebebeb;\n &:hover {\n text-decoration: none;\n }\n`;\nconst TextBold = styled.div`\n color: #292929;\n font-size: 12px;\n font-weight: 600;\n line-height: 20px;\n word-wrap: break-word;\n text-align: center;\n`;\nconst FeeText = styled.div`\n color: #292929;\n font-size: 14px;\n font-weight: 400;\n line-height: 20px;\n word-wrap: break-word;\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n`;\nconst Label = styled.label`\n width: 100%;\n font-size: 12px;\n line-height: 16px;\n word-wrap: break-word;\n color: #2e2e2e;\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n`;\nconsole.log(protocolFeeRecipientProfile);\nreturn (\n <Widget\n src={\"old.potlock.near/widget/Components.Modal\"}\n props={{\n ...props,\n isModalOpen: isMatchingPoolModalOpen,\n onClose,\n children: (\n <>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Checkbox\"}\n props={{\n id: \"fundAsDaoSelector\",\n label: \"Fund as DAO\",\n checked: fundAsDao,\n onClick: (e) => {\n State.update({ fundAsDao: e.target.checked });\n },\n }}\n />\n {fundAsDao && (\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n inputStyle: {\n background: \"#FAFAFA\",\n },\n placeholder: \"Enter DAO address\",\n value: daoAddress,\n onChange: (daoAddress) =>\n State.update({\n daoAddress: daoAddress.trim().toLowerCase(),\n }),\n validate: () => {\n Near.asyncView(daoAddress, \"get_policy\", {})\n .then((policy) => {\n if (!policy) {\n State.update({\n daoAddressError: \"Invalid DAO address\",\n });\n }\n if (\n !doesUserHaveDaoFunctionCallProposalPermissions(\n context.accountId,\n policy\n )\n ) {\n State.update({\n daoAddressError:\n \"Your account does not have permission to create proposals\",\n });\n } else {\n State.update({\n daoAddressError: \"\",\n daoPolicy: policy,\n });\n }\n })\n .catch((e) => {\n State.update({ daoAddressError: \"Invalid DAO address\" });\n });\n },\n error: daoAddressError,\n }}\n />\n )}\n <ModalTitle>\n Enter matching pool contribution amount in NEAR\n {[\"0\", \"1\"].includes(min_matching_pool_donation_amount)\n ? \"(no minimum)\"\n : `(Min. ${yoctosToNear(min_matching_pool_donation_amount)})`}\n </ModalTitle>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n inputStyle: {\n background: \"#FAFAFA\",\n },\n placeholder: \"Enter amount here in NEAR\",\n value: matchingPoolDonationAmountNear,\n onChange: (matchingPoolDonationAmountNear) =>\n State.update({\n matchingPoolDonationAmountNear,\n }),\n validate: () => {\n // TODO: add validation logic here\n State.update({ matchingPoolDonationAmountNearError: \"\" });\n },\n error: matchingPoolDonationAmountNearError,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Inputs.TextArea\"}\n props={{\n noLabel: true,\n inputRows: 5,\n inputStyle: {\n background: \"#FAFAFA\",\n },\n placeholder: \"Enter an optional message\",\n value: matchingPoolDonationMessage,\n onChange: (matchingPoolDonationMessage) =>\n State.update({ matchingPoolDonationMessage }),\n validate: () => {\n if (\n matchingPoolDonationMessage.length >\n MAX_DONATION_MESSAGE_LENGTH\n ) {\n State.update({\n matchingPoolDonationMessageError: `Message must be less than ${MAX_DONATION_MESSAGE_LENGTH} characters`,\n });\n return;\n }\n State.update({ matchingPoolDonationMessageError: \"\" });\n },\n error: matchingPoolDonationMessageError,\n }}\n />\n <Row>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Checkbox\"}\n props={{\n id: \"bypassProtocolFeeSelector\",\n checked: bypassProtocolFee,\n onClick: (e) => {\n State.update({ bypassProtocolFee: e.target.checked });\n },\n }}\n />\n <Label htmlFor=\"bypassProtocolFeeSelector\">\n Bypass {protocolConfig?.basis_points / 100 || \"-\"}% protocol fee\n to{\" \"}\n <UserChipLink\n href={`https://near.social/mob.near/widget/ProfilePage?accountId=${protocolConfig?.account_id}`}\n target=\"_blank\"\n >\n <Widget\n src={\"old.potlock.near/widget/Project.ProfileImage\"}\n props={{\n ...props,\n accountId: protocolConfig?.account_id,\n style: {\n height: \"12px\",\n width: \"12px\",\n },\n }}\n />\n <TextBold>\n {_address(\n protocolFeeRecipientProfile?.name ||\n protocolConfig?.account_id\n )}\n </TextBold>\n </UserChipLink>\n </Label>\n </Row>\n {chef && chef_fee_basis_points > 0 && (\n <Row style={{ marginTop: \"6px\" }}>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Checkbox\"}\n props={{\n id: \"bypassChefFeeSelector\",\n checked: bypassChefFee,\n onClick: (e) => {\n State.update({ bypassChefFee: e.target.checked });\n },\n }}\n />\n <Label htmlFor=\"bypassChefFeeSelector\">\n Bypass {chef_fee_basis_points / 100 || \"-\"}% chef fee to\n <UserChipLink\n href={`https://near.social/mob.near/widget/ProfilePage?accountId=${chef}`}\n target=\"_blank\"\n >\n <Widget\n src={\"old.potlock.near/widget/Project.ProfileImage\"}\n props={{\n ...props,\n accountId: chef,\n style: {\n height: \"12px\",\n width: \"12px\",\n },\n }}\n />\n <TextBold>{chefProfile?.name || chef}</TextBold>\n </UserChipLink>\n </Label>\n </Row>\n )}\n <Row style={{ marginTop: \"12px\" }}>\n <FeeText>Protocol fee: {protocolFeeAmountNear} NEAR</FeeText>\n </Row>\n {chef && chef_fee_basis_points > 0 && (\n <Row style={{ marginTop: \"12px\" }}>\n <FeeText>Chef fee: {chefFeeAmountNear} NEAR</FeeText>\n </Row>\n )}\n <Row style={{ marginTop: \"6px\" }}>\n {referrerId && (\n <FeeText>\n Referrer fee (to {referrerId}): {referrerFeeAmountNear} NEAR\n </FeeText>\n )}\n </Row>\n <Row style={{ marginTop: \"6px\" }}>\n <FeeText>\n Net donation amount:{\" \"}\n {matchingPoolDonationAmountNear -\n protocolFeeAmountNear -\n chefFeeAmountNear -\n referrerFeeAmountNear}{\" \"}\n NEAR\n </FeeText>\n </Row>\n <Row style={{ justifyContent: \"flex-end\", marginTop: \"12px\" }}>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n disabled:\n daoAddressError ||\n !matchingPoolDonationAmountNear ||\n !!matchingPoolDonationAmountNearError ||\n !parseFloat(matchingPoolDonationAmountNear),\n text: `${\n fundAsDao ? \"Create proposal to contribute \" : \"Contribute\"\n }${\n matchingPoolDonationAmountNear\n ? ` ${matchingPoolDonationAmountNear} ${base_currency.toUpperCase()}`\n : \"\"\n } to matching pool`,\n onClick: handleMatchingPoolDonation,\n }}\n />\n </Row>\n </>\n ),\n }}\n />\n);\n" }, "Cart.Modal": { "": "const { getCartItemCount, getCart, removeItemsFromCart } = VM.require(\n \"old.potlock.near/widget/SDK.cart\"\n) ?? {\n getCartItemCount: () => 0,\n getCart: () => {},\n removeItemsFromCart: () => {},\n};\nconst { href } = VM.require(\"devs.near/widget/lib.url\") || {\n href: () => {},\n};\nconst navHeightPx = 110;\nconst navHeightPxMobile = 96;\nconst cart = getCart();\nconst numCartItems = getCartItemCount();\nconst ModalOverlay = styled.div`\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(255, 255, 255, 0.3);\n backdrop-filter: blur(4px);\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n align-items: flex-end;\n padding-top: ${navHeightPx * 0.8 + 50}px;\n padding-right: 32px;\n z-index: 1000;\n @media screen and (max-width: 768px) {\n padding-right: 8px;\n }\n`;\nconst ModalContainer = styled.div`\n width: 383px;\n border-radius: 12px;\n box-shadow: 0px 0px 0px 1px rgba(41, 41, 41, 0.1),\n 0px 8px 12px -4px rgba(41, 41, 41, 0.1),\n 0px 20px 32px -10px rgba(41, 41, 41, 0.1),\n 0px 32px 44px -16px rgba(41, 41, 41, 0.1);\n padding: 24px 0px;\n background: white;\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n align-items: flex-start;\n position: relative;\n max-height: 80vh;\n max-width: 90vw;\n overflow-y: scroll;\n`;\nconst ModalHeader = styled.div`\n width: 100%;\n // height: 100%;\n padding: 24px 24px 8px 24px;\n justify-content: space-between;\n align-items: flex-start;\n display: inline-flex;\n // background: pink;\n border-bottom: 1px #dbdbdb solid;\n position: relative;\n`;\nconst ModalHeaderText = styled.div`\n text-align: center;\n color: #2e2e2e;\n font-size: 14px;\n font-family: \"Mona Sans\", sans-serif;\n font-weight: 600;\n line-height: 16px;\n word-wrap: break-word;\n`;\nconst NoProjectsText = styled.div`\n text-align: center;\n color: #2e2e2e;\n font-size: 16px;\n font-weight: 500;\n margin-top: 24px;\n width: 100%;\n`;\nconst ButtonContainer = styled.div`\n display: flex;\n flex-direction: column;\n width: 100%;\n padding: 24px 24px 0 24px;\n`;\nconst Ear = styled.div`\n width: 16px;\n height: 16px;\n transform: rotate(45deg);\n transform-origin: 0 0;\n background: white;\n position: absolute;\n top: -11px;\n right: 32px;\n z-index: 1000;\n`;\nconst CartModal = ({ Trigger }) => {\n Trigger = Trigger ?? (() => <></>);\n return (\n <Widget\n src={\"devs.near/widget/Modal\"}\n props={{\n Trigger: Trigger,\n ModalOverlay: ModalOverlay,\n ModalContainer: ModalContainer,\n Content: () => (\n <>\n <ModalHeader>\n <ModalHeaderText>Donation cart</ModalHeaderText>\n <ModalHeaderText>\n {numCartItems}{\" \"}\n <span style={{ fontWeight: 400, color: \"#7B7B7B\" }}>\n {numCartItems === 1 ? \"project\" : \"projects\"}\n </span>\n </ModalHeaderText>\n </ModalHeader>\n {numCartItems === 0 ? (\n <NoProjectsText>Your cart is empty! 💸</NoProjectsText>\n ) : (\n (Object.keys(cart) ?? []).map((projectId) => {\n return (\n <Widget\n src={\"old.potlock.near/widget/Cart.CartModalItem\"}\n props={{\n ...props,\n projectId,\n removeProjectsFromCart: (projectIds) => {\n removeItemsFromCart({ id: projectIds });\n if (numCartItems === 1) {\n setIsModalOpen(false);\n }\n },\n }}\n />\n );\n })\n )}\n <ButtonContainer>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: \"Proceed to donate\",\n disabled: numCartItems === 0,\n href: href({\n widgetSrc: \"old.potlock.near/widget/Index\",\n params: { tab: \"cart\", referrerId: props.referrerId },\n }),\n style: {\n width: \"100%\",\n marginBottom: \"16px\",\n },\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: numCartItems === 0 ? \"primary\" : \"secondary\",\n text: \"Continue shopping\",\n onClick: () => setIsModalOpen(false),\n style: {\n width: \"100%\",\n },\n }}\n />\n </ButtonContainer>\n <Ear />\n </>\n ),\n }}\n />\n );\n};\nreturn { CartModal };\n" }, "Pots.FlagSuccessModal": { "": "const Container = styled.div`\n padding: 16px 32px 40px;\n svg {\n display: block;\n cursor: pointer;\n width: 14px;\n transition: all 300ms ease-in-out;\n margin: 5px 0;\n margin-left: auto;\n &:hover {\n rotate: 90deg;\n }\n }\n .title {\n margin-bottom: 1rem;\n font-size: 16px;\n color: #7b7b7b;\n font-weight: 600;\n span {\n font-weight: 600;\n color: #292929;\n }\n }\n .reason {\n font-size: 14px;\n color: #7b7b7b;\n }\n`;\nconst { onClose, successFlag } = props;\nreturn (\n <Widget\n src={\"old.potlock.near/widget/Components.Modal\"}\n props={{\n ...props,\n onClose: (e) => {\n e.stopPropagation();\n },\n contentStyle: {\n padding: \"0px\",\n },\n children: (\n <Container>\n <svg\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n onClick={onClose}\n >\n <path\n d=\"M14 1.41L12.59 0L7 5.59L1.41 0L0 1.41L5.59 7L0 12.59L1.41 14L7 8.41L12.59 14L14 12.59L8.41 7L14 1.41Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n <div className=\"title\">\n <span> {successFlag.address} </span> has been flagged\n </div>\n <div className=\"reason\">{successFlag.reason}</div>\n </Container>\n ),\n }}\n />\n);\n" }, "Components.Donors": { "": "const { calcNetDonationAmount, filterByDate } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n);\nlet PotFactorySDK =\n VM.require(\"old.potlock.near/widget/SDK.potfactory\") ||\n (() => ({\n getPots: () => {},\n }));\nPotFactorySDK = PotFactorySDK({ env: props.env });\nconst pots = PotFactorySDK.getPots();\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n asyncGetMatchingPoolDonations: () => {},\n};\nlet DonateSDK =\n VM.require(\"old.potlock.near/widget/SDK.donate\") ||\n (() => ({\n asyncGetDonations: () => {},\n }));\nDonateSDK = DonateSDK({ env: props.env });\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n .leaderboard {\n width: 100%;\n h1 {\n font-size: 2.5rem;\n font-weight: 600;\n margin-top: 20px;\n }\n .cards {\n display: flex;\n gap: 3rem;\n margin-top: 2rem;\n margin-bottom: 5rem;\n > div {\n width: 30%;\n display: flex;\n }\n .top {\n width: 40%;\n scale: 1.05;\n }\n @media only screen and (max-width: 670px) {\n flex-direction: column;\n justify-content: center;\n > div {\n width: 100%;\n display: flex;\n }\n .top {\n order: -1;\n scale: 1;\n width: 100%;\n }\n }\n }\n }\n`;\nconst Tabs = styled.div`\n display: flex;\n justify-content: space-between;\n flex-wrap: wrap;\n align-items: center;\n gap: 2rem;\n font-size: 14px;\n margin-bottom: 24px;\n .menu-item {\n font-weight: 600;\n display: flex;\n width: 100%;\n justify-content: space-between;\n gap: 20px;\n }\n .selected {\n gap: 10px;\n .label {\n text-transform: uppercase;\n color: #7b7b7b;\n }\n .count {\n color: #dd3345;\n }\n }\n .select {\n width: fit-content;\n }\n`;\nconst LoadingWrapper = styled.div`\n font-size: 1.5rem;\n margin-top: 1rem;\n`;\nconst Filter = styled.div`\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n .option {\n padding: 0.8em 1em;\n border-radius: 8px;\n color: #292929;\n box-shadow: 0px -1px 0px 0px #dbdbdb inset, 0px 0px 0px 0.5px #dbdbdb;\n transition: all 300ms ease-in-out;\n cursor: pointer;\n &.active,\n :hover {\n background: #292929;\n color: white;\n }\n }\n @media only screen and (max-width: 480px) {\n font-size: 10px;\n }\n`;\nconst Loading = () => <LoadingWrapper>Loading...</LoadingWrapper>;\nconst [index, setIndex] = useState(0);\nconst [currentTab, setTab] = useState(\"leaderboard\");\nconst [title, setTitle] = useState(\"\");\nconst [filter, setFilter] = useState(\"\");\nconst [allDonationsFetched, setAllDonationsFetched] = useState(false);\nconst [donationsByPage, setDonationsByPage] = useState({});\nconst [sponsorsByPage, setSponsorsByPage] = useState({});\nconst [fetchDonationsError, setFetchDonationsError] = useState(\"\");\nconst limit = 900;\nconst cachedDonationsValidityPeriod = 1000 * 60 * 5; // 5 minutes\nconst getSponsorshipDonations = (potId) => {\n return PotSDK.asyncGetMatchingPoolDonations(potId).then((donations) => {\n if (sponsorsByPage[potId]) return \"\";\n setSponsorsByPage((prevSponsorsByPage) => {\n Storage.set(\"sponsorsByPage\", {\n val: { ...prevSponsorsByPage, [potId]: donations },\n ts: Date.now(),\n });\n return { ...prevSponsorsByPage, [potId]: donations };\n });\n });\n};\n// Get Sponsorship Donations\nif (pots && !sponsorsByPage[pots[pots.length - 1].id]) {\n const cachedSponsors = Storage.get(\"sponsorsByPage\");\n if (\n cachedSponsors &&\n cachedSponsors.ts > Date.now() - cachedDonationsValidityPeriod\n ) {\n console.log(\"using cached sponsors\");\n setSponsorsByPage(cachedSponsors.val);\n } else if (cachedSponsors !== null) {\n pots.forEach((pot) => {\n getSponsorshipDonations(pot.id, potDetail);\n });\n }\n}\nconst sponsors = useMemo(() => {\n if (!sponsorsByPage[pots[pots.length - 1].id]) return [];\n let sponsors = Object.values(sponsorsByPage).flat();\n sponsors = sponsors.filter((donation) => filterByDate(filter, donation));\n sponsors = sponsors.reduce((accumulator, currentDonation) => {\n accumulator[currentDonation.donor_id] = {\n amount:\n (accumulator[currentDonation.donor_id].amount || 0) +\n calcNetDonationAmount(currentDonation),\n ...currentDonation,\n };\n return accumulator;\n }, {});\n sponsors = Object.values(sponsors).sort((a, b) => b.amount - a.amount);\n return sponsors;\n}, [sponsorsByPage, filter]);\nif (!allDonationsFetched && !donationsByPage[index]) {\n // first, try to get from cache\n const cacheKey = `donationsByPage-${index}-${limit}`;\n const cachedDonations = Storage.get(cacheKey);\n if (\n cachedDonations &&\n cachedDonations.ts > Date.now() - cachedDonationsValidityPeriod\n ) {\n console.log(\"using cached donations for page \", index);\n setDonationsByPage({ ...donationsByPage, [index]: cachedDonations.val });\n if (cachedDonations.val.length === limit) {\n setIndex(index + 1);\n } else {\n setAllDonationsFetched(true);\n }\n } else if (cachedDonations !== null) {\n // null means it's loading (async)\n console.log(\"fetching donations for page\", index);\n const startTime = Date.now();\n DonateSDK.asyncGetDonations(limit * index, limit)\n .then((donationsPart) => {\n const endTime = Date.now();\n console.log(\n \"fetched donations for index\",\n index,\n \"in\",\n endTime - startTime,\n \"ms\"\n );\n // cache the result\n Storage.set(cacheKey, { val: donationsPart, ts: Date.now() });\n setDonationsByPage({ ...donationsByPage, [index]: donationsPart });\n if (donationsPart.length === limit) {\n setIndex(index + 1);\n } else {\n setAllDonationsFetched(true);\n }\n })\n .catch((e) => {\n setFetchDonationsError(e);\n });\n }\n}\nconst [allDonations, totalsByDonor, sortedDonations] = useMemo(() => {\n if (!allDonationsFetched) return [[], {}, []];\n let donations = Object.values(donationsByPage).flat();\n donations = donations.filter((donation) => filterByDate(filter, donation));\n const totalsByDonor = donations.reduce((accumulator, currentDonation) => {\n accumulator[currentDonation.donor_id] = {\n amount:\n (accumulator[currentDonation.donor_id].amount || 0) +\n (currentDonation.ft_id === \"near\"\n ? calcNetDonationAmount(currentDonation)\n : 0),\n ...currentDonation,\n };\n return accumulator;\n }, {});\n const sortedDonations = Object.values(totalsByDonor).sort(\n (a, b) => b.amount - a.amount\n );\n return [donations, totalsByDonor, sortedDonations];\n}, [donationsByPage, allDonationsFetched, filter]);\nconst leaderboard = [\n {\n rank: \"#2\",\n id: sortedDonations[1].donor_id,\n amount: sortedDonations[1].amount,\n },\n {\n rank: (\n <img\n src=\"https://ipfs.near.social/ipfs/bafkreicjk6oy6465ps32owoomppfkvimbjlnhbaldvf6ujuyhkjas6ghjq\"\n alt=\"top\"\n />\n ),\n id: sortedDonations[0].donor_id,\n className: \"top\",\n amount: sortedDonations[0].amount,\n },\n {\n rank: \"#3\",\n id: sortedDonations[2].donor_id,\n amount: sortedDonations[2].amount,\n },\n];\nconst filterOptions = [\n { text: \"All Time\", value: \"all\" },\n { text: \"1Y\", value: \"year\" },\n { text: \"1M\", value: \"month\" },\n { text: \"1W\", value: \"week\" },\n { text: \"24H\", value: \"day\" },\n];\nconst MenuItem = ({ count, children, className }) => (\n <div className={`menu-item ${className || \"\"}`}>\n <div className=\"label\">{children}</div>\n <div className=\"count\">{count}</div>\n </div>\n);\nconst tabs = [\n {\n label: \"Donor Leaderboard\",\n val: \"leaderboard\",\n count: sortedDonations.length,\n },\n {\n label: \"Sponsors Leaderboard\",\n val: \"sponsors\",\n count: sponsors.length,\n },\n {\n label: \"Donor Feed\",\n val: \"feed\",\n count: allDonations.length,\n },\n];\nconst options = [\n { tab: \"feed\", src: \"Components.DonorsTrx\" },\n { tab: \"leaderboard\", src: \"Components.DonorsLeaderboard\" },\n { tab: \"sponsors\", src: \"Components.DonorsLeaderboard\" },\n];\nconst sortList = tabs.map((tab) => ({\n label: (\n <MenuItem key={tab.val} count={tab.count}>\n {tab.label}\n </MenuItem>\n ),\n val: tab,\n}));\nreturn (\n <Container>\n {fetchDonationsError ? (\n <div>\n <h1>Error fetching donations</h1>\n <p>{fetchDonationsError}</p>\n </div>\n ) : !allDonationsFetched ? (\n <Loading />\n ) : (\n <>\n <div className=\"leaderboard\">\n <h1>Donors Leaderboard</h1>\n <Widget\n src={\"old.potlock.near/widget/Components.DonorsCards\"}\n props={{ ...props, sponsors, sortedDonations, currentTab }}\n />\n </div>\n <Tabs>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Dropdown\"}\n props={{\n sortVal: title,\n title: (\n <MenuItem className=\"selected\" count={tabs[0].count}>\n {tabs[0].val}{\" \"}\n </MenuItem>\n ),\n sortList: sortList,\n FilterMenuCustomStyle: `left:0; right:auto;`,\n handleSortChange: ({ val: option }) => {\n setTitle(\n <MenuItem className=\"selected\" count={option.count}>\n {option.val}\n </MenuItem>\n );\n setTab(option.val);\n },\n }}\n />\n <Filter>\n {filterOptions.map((option) => (\n <div\n className={`option ${filter === option.value ? \"active\" : \"\"}`}\n key={option.value}\n onClick={() => setFilter(option.value)}\n >\n {option.text}\n </div>\n ))}\n </Filter>\n </Tabs>\n <Widget\n src={`old.potlock.near/widget/${\n options.find((option) => option.tab == currentTab).src\n }`}\n props={{\n ...props,\n allDonations: allDonations,\n filter,\n sponsors,\n sortedDonations,\n currentTab,\n }}\n />\n </>\n )}\n </Container>\n);\n" }, "Pots.Card": { "": "const { potId } = props;\nconst { daysUntil, yoctosToNear, yoctosToUsd } = VM.require(\n \"old.potlock.near/widget/utils\"\n) || {\n daysUntil: () => \"\",\n yoctosToNear: () => \"\",\n yoctosToUsd: () => \"\",\n};\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getConfig: () => {},\n};\nconst potConfig = PotSDK.getConfig(potId);\nconst MAX_DESCRIPTION_LENGTH = 100;\nconst MAX_TITLE_LENGTH = 36;\nconst Card = styled.a`\n display: flex;\n flex-direction: column;\n min-width: 320px;\n min-height: 300px;\n border-radius: 8px;\n background: white;\n box-shadow: 0px -2px 0px 0px #464646 inset, 0px 0px 0px 1px #464646;\n padding-bottom: 5px;\n height: 100%;\n &:hover {\n text-decoration: none;\n cursor: pointer;\n }\n`;\nconst CardSection = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n gap: 16px;\n padding: 32px;\n width: 100%;\n height: 100%;\n`;\nconst Title = styled.div`\n color: #292929;\n font-size: 22px;\n font-weight: 600;\n line-height: 28px;\n word-wrap: break-word;\n > div {\n font-weight: inherit;\n display: flex;\n align-items: baseline;\n }\n .usd-amount {\n font-size: 14px;\n font-weight: 400;\n margin-left: 0.25rem;\n }\n .text {\n font-size: 14px;\n color: #7b7b7b;\n margin-left: 0.5rem;\n }\n`;\nconst Description = styled.div`\n color: #525252;\n font-size: 16px;\n font-weight: 400;\n line-height: 28px;\n word-wrap: break-word;\n a {\n color: rgb(123, 123, 123);\n }\n`;\nconst Subtitle = styled.span`\n color: #7b7b7b;\n font-size: 14px;\n font-weight: 600;\n line-height: 20px;\n word-wrap: break-word;\n`;\nif (!potConfig)\n return (\n <Card style={{ justifyContent: \"center\", alignItems: \"center\" }}>\n {potConfig == null ? (\n <div class=\"spinner-border text-secondary\" role=\"status\" />\n ) : (\n <div>Pot {potId} not found.</div>\n )}\n </Card>\n );\nconst {\n pot_name,\n pot_description,\n base_currency,\n public_donations_count,\n matching_pool_balance,\n application_start_ms,\n application_end_ms,\n public_round_start_ms,\n public_round_end_ms,\n cooldown_end_ms,\n all_paid_out,\n} = potConfig;\n// const totalAmount =\n// props.SUPPORTED_FTS[base_currency.toUpperCase()].fromIndivisible(total_public_donations);\nconst description = !pot_description\n ? \"No description\"\n : pot_description.length > MAX_DESCRIPTION_LENGTH\n ? `${pot_description.slice(0, MAX_DESCRIPTION_LENGTH)}...`\n : pot_description;\nconst title = !pot_name\n ? \"No title\"\n : pot_name.length > MAX_TITLE_LENGTH\n ? `${pot_name.slice(0, MAX_TITLE_LENGTH)}...`\n : pot_name;\nconst now = Date.now();\nconst applicationNotStarted = now < application_start_ms;\nconst applicationOpen = now >= application_start_ms && now < application_end_ms;\nconst publicRoundNotStarted = now < public_round_start_ms;\nconst publicRoundOpen =\n now >= public_round_start_ms && now < public_round_end_ms;\nconst cooldownPending =\n public_round_end_ms && now >= public_round_end_ms && !cooldown_end_ms;\nconst cooldownOpen = now >= public_round_end_ms && now < cooldown_end_ms;\nconst payoutsPending =\n cooldown_end_ms && now >= cooldown_end_ms && !all_paid_out;\nconst payoutsCompleted = all_paid_out;\nconst amountNear = yoctosToNear(matching_pool_balance, true);\nconst amountUsd = yoctosToUsd(matching_pool_balance);\nconst tags = [\n /* Application's has not started tag */\n {\n backgroundColor: \"#EFFEFA\",\n borderColor: \"#33DDCB\",\n textColor: \"#023131\",\n text: \"Sponsorship Open\",\n textStyle: { fontWeight: 500, marginLeft: \"8px\" },\n preElementsProps: {\n colorOuter: \"#CAFDF3\",\n colorInner: \"#33DDCB\",\n animate: true,\n },\n visibility: now < application_start_ms,\n },\n /* Application tag */\n {\n backgroundColor: \"#EFFEFA\",\n borderColor: \"#33DDCB\",\n textColor: \"#023131\",\n text: daysUntil(application_end_ms) + \" left to apply\",\n textStyle: { fontWeight: 500, marginLeft: \"8px\" },\n preElementsProps: {\n colorOuter: \"#CAFDF3\",\n colorInner: \"#33DDCB\",\n animate: true,\n },\n visibility: applicationOpen,\n },\n /* Matching round open tag */\n {\n backgroundColor: \"#F7FDE8\",\n borderColor: \"#9ADD33\",\n textColor: \"#192C07\",\n text: daysUntil(public_round_end_ms) + \" left to donate\",\n textStyle: { fontWeight: 500, marginLeft: \"8px\" },\n preElementsProps: {\n colorOuter: \"#D7F5A1\",\n colorInner: \"#9ADD33\",\n animate: true,\n },\n visibility: publicRoundOpen,\n },\n /* Cooldown pending tag */\n {\n backgroundColor: \"#F5F3FF\",\n borderColor: \"#A68AFB\",\n textColor: \"#2E0F66\",\n text: \"Cooldown pending\",\n textStyle: { fontWeight: 500, marginLeft: \"8px\" },\n preElementsProps: {\n colorOuter: \"#EDE9FE\",\n colorInner: \"#A68AFB\",\n animate: true,\n },\n visibility: cooldownPending,\n },\n /* Matching round cooldown tag */\n {\n backgroundColor: \"#F5F3FF\",\n borderColor: \"#A68AFB\",\n textColor: \"#2E0F66\",\n text: \"Challenge period\",\n textStyle: { fontWeight: 500, marginLeft: \"8px\" },\n preElementsProps: {\n colorOuter: \"#EDE9FE\",\n colorInner: \"#A68AFB\",\n animate: true,\n },\n visibility: cooldownOpen,\n },\n /* Payouts pending tag */\n {\n backgroundColor: \"#F7FDE8\",\n borderColor: \"#9ADD33\",\n textColor: \"#192C07\",\n text: \"Payouts pending\",\n preElementsProps: {\n colorOuter: \"#D7F5A1\",\n colorInner: \"#9ADD33\",\n animate: true,\n },\n textStyle: { fontWeight: 500, marginLeft: \"8px\" },\n visibility: payoutsPending,\n },\n /* Matching round closed tag */\n {\n backgroundColor: \"#464646\",\n borderColor: \"#292929\",\n textColor: \"#FFF\",\n text: \"Payouts completed\",\n preElementsProps: {\n colorOuter: \"#656565\",\n colorInner: \"#A6A6A6\",\n animate: false,\n },\n textStyle: { fontWeight: 500, marginLeft: \"8px\" },\n visibility: payoutsCompleted,\n },\n];\nconst Tag = (props) => (\n <Widget\n src={\"old.potlock.near/widget/Pots.Tag\"}\n props={{\n ...props,\n ...(props.preElementsProps\n ? {\n preElements: (\n <Widget\n src={\"old.potlock.near/widget/Components.Indicator\"}\n props={props.preElementsProps}\n />\n ),\n }\n : {}),\n }}\n />\n);\nreturn (\n <Card\n href={props.hrefWithParams(`?tab=pot&potId=${potId}`)}\n data-testid={applicationOpen ? \"active-pot\" : \"inactive-pot\"}\n >\n <CardSection>\n <Title>{title}</Title>\n <Description>\n <Markdown text={description} />\n </Description>\n </CardSection>\n <CardSection\n style={{\n background: \"#F6F5F3\",\n borderTop: \"1px #7B7B7B solid\",\n marginTop: \"auto\",\n height: \"fit-content\",\n }}\n >\n <Title>\n <div>\n {amountNear}\n {amountUsd && <span className=\"usd-amount\">{amountUsd}</span>}\n <span className=\"text\">in pot</span>\n </div>\n </Title>\n {tags.map((tag) =>\n tag.visibility ? <Tag {...tag} key={tag.text} /> : \"\"\n )}\n </CardSection>\n </Card>\n);\n" }, "Components.Banner": { "": "let PotFactorySDK =\n VM.require(\"old.potlock.near/widget/SDK.potfactory\") ||\n (() => ({\n getPots: () => {},\n }));\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n asyncGetConfig: () => {},\n};\nconst [activeRounds, setActiveRounds] = useState([]);\nPotFactorySDK = PotFactorySDK({ env: props.env });\nconst pots = PotFactorySDK.getPots();\nconst now = Date.now();\nuseEffect(() => {\n if (pots) {\n pots.forEach((pot) => {\n PotSDK.asyncGetConfig(pot.id)\n .then((potConfig) => {\n const { public_round_start_ms, public_round_end_ms } = potConfig;\n if (public_round_start_ms < now && public_round_end_ms > now) {\n setActiveRounds((prevActiveRounds) => [\n ...prevActiveRounds,\n {\n ...potConfig,\n pot_id: pot.id,\n },\n ]);\n }\n })\n .catch((e) => {\n console.error(\"error getting pot detail: \", e);\n });\n });\n }\n}, [pots]);\nconst Wrapper = styled.div`\n height: ${(props) => (props.active ? \"48px\" : \"0px !important\")};\n @media screen and (max-width: 768px) {\n height: 36px;\n }\n`;\nconst Container = styled.div`\n width: 100%;\n height: ${(props) => (props.active ? \"48px\" : \"0px !important\")};\n bottom: 0;\n left: 0;\n position: fixed;\n z-index: 999;\n background: #7fc41e;\n color: white;\n display: flex;\n justify-content: center;\n align-items: center;\n overflow: hidden;\n .text {\n font-size: 22px;\n font-weight: 500;\n letter-spacing: 0.015em;\n text-transform: uppercase;\n display: flex;\n gap: 1rem;\n .link {\n display: flex;\n align-items: center;\n font-weight: 600;\n gap: 4px;\n color: white;\n text-decoration: underline;\n transition: transform 300ms ease-in-out;\n img {\n transition: rotate 300ms ease-in-out;\n height: 1em;\n width: fit-content;\n }\n :hover {\n transform: translateX(4px);\n img {\n rotate: 45deg;\n }\n }\n }\n }\n @media screen and (max-width: 992px) {\n .text {\n font-size: 1rem;\n }\n }\n @media screen and (max-width: 768px) {\n height: 36px;\n .text {\n font-size: 12px;\n gap: 0.5rem;\n }\n }\n`;\nconst isSingleRound = activeRounds.length === 1;\nconst limit = isSingleRound ? 20 : 10;\nconst potName =\n activeRounds[0].pot_name.length > limit\n ? activeRounds[0].pot_name.slice(0, limit).trim() + \"...\"\n : activeRounds[0].pot_name;\nconst textForOneRound = `${potName} round is live`;\nconst textForMultipleRounds = `Pot round is live for ${potName} and +${\n activeRounds.length - 1\n} More`;\nreturn (\n <Wrapper active={!!activeRounds.length}>\n <Container active={!!activeRounds.length}>\n <div className=\"text\">\n {isSingleRound ? textForOneRound : textForMultipleRounds}\n <a\n href={props.hrefWithParams(\n isSingleRound\n ? `?tab=pot&potId=${activeRounds[0].pot_id}`\n : `?tab=pots`\n )}\n className=\"link\"\n >\n {isSingleRound ? \"Donate\" : \"Check Now\"}\n <img\n src=\"https://ipfs.near.social/ipfs/bafkreigots5l4o5d3a4zksfimch3gvqw7ezb2quundmjwml33abo5atgwi\"\n alt=\"arrow\"\n />\n </a>\n </div>\n </Container>\n </Wrapper>\n);\n" }, "Components.Indicator": { "": "const Outer = styled.div`\n display: flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background-color: ${props.colorOuter};\n @keyframes beacon {\n 0%,\n 100% {\n transform: scale(1);\n }\n 50% {\n transform: scale(1.3);\n }\n }\n ${props.animate &&\n `\n animation: beacon 1.5s infinite;\n `}\n`;\nconst Inner = styled.div`\n width: 10px;\n height: 10px;\n border-radius: 50%;\n background-color: ${props.colorInner};\n`;\nreturn (\n <Outer>\n <Inner />\n </Outer>\n);\n" }, "Inputs.Text": { "": "const label = props.label ?? \"\";\nconst placeholder = props.placeholder ?? \"\";\nconst value = props.value ?? \"\";\nconst onChange = props.onChange ?? (() => {});\nconst onBlur = props.onBlur ?? (() => {});\nconst validate = props.validate ?? (() => {});\nconst error = props.error ?? \"\";\nconst Container = styled.div`\n display: flex;\n // flex: 1;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n padding: 0px;\n gap: 0.45em;\n width: 100%;\n`;\nconst Label = styled.label`\n font-weight: 500;\n font-size: 14px;\n line-height: 16px;\n word-wrap: break-word;\n color: #2e2e2e;\n`;\nconst Error = styled.span`\n display: inline-block;\n font-style: normal;\n font-weight: 400;\n font-size: 0.75em;\n line-height: 1.25em;\n color: #ff4d4f;\n height: 0;\n overflow: hidden;\n transition: height 0.3s ease-in-out;\n &.show {\n height: 1.25em;\n }\n`;\nconst InputContainer = styled.div`\n display: flex;\n flex-direction: row;\n width: 100%;\n background: #ffffff;\n border: 1px solid #d0d5dd;\n box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);\n border-radius: 4px;\n`;\nconst InputPrefix = styled.div`\n display: flex;\n justify-content: center;\n align-items: center;\n height: 100%;\n text-align: center;\n padding: 14px 16px;\n border-right: 1px #f0f0f0 solid;\n color: #7b7b7b;\n font-size: 16px;\n font-weight: 400;\n`;\nconst Input = styled.input`\n border: none;\n display: flex;\n flex-direction: row;\n align-items: center;\n padding: 0.5em 0.75em;\n gap: 0.5em;\n color: #101828;\n width: 100%;\n border-radius: 4px;\n`;\nconst PercentageSign = styled.span`\n display: flex;\n align-items: center;\n padding: 0 0.75em;\n color: #7b7b7b;\n font-size: 16px;\n font-weight: 400;\n`;\nreturn (\n <Container>\n {label && <Label>{label}</Label>}\n <InputContainer>\n {props.preInputChildren && props.preInputChildren}\n <Input\n type=\"text\"\n placeholder={placeholder}\n value={value}\n onChange={({ target: { value } }) => onChange(value)}\n onBlur={(value) => {\n validate();\n if (onBlur) onBlur(value);\n }}\n disabled={!!props.disabled}\n onKeyDown={props.handleKeyPress ?? null}\n style={props.inputStyles || {}}\n name={props.name}\n />\n {props.percent && <PercentageSign>%</PercentageSign>}\n {props.postInputChildren && props.postInputChildren}\n </InputContainer>\n <Error className={error ? \"show\" : \"\"}>{error}</Error>\n </Container>\n);\n" }, "Inputs.Dropdown": { "": "const {\n sortList,\n sortVal,\n title,\n handleSortChange,\n FilterMenuCustomStyle,\n showCount,\n} = props;\nconst [openFilter, setOpenFilter] = useState(false);\nconst FilterButton = styled.div`\n white-space: nowrap;\n display: flex;\n cursor: pointer;\n gap: 12px;\n align-items: center;\n font-size: 14px;\n font-weight: 500;\n line-height: 20px;\n border: 1px solid #292929;\n padding: 0.5rem 1rem;\n border-radius: 6px;\n color: #292929;\n * {\n font-weight: 500;\n }\n`;\nconst FilterIcon = styled.div`\n display: flex;\n width: 16px;\n height: 16px;\n align-items: center;\n justify-content: center;\n`;\nconst FilterMenu = styled.div`\n position: absolute;\n background: #fff;\n top: 140%;\n right: 0;\n padding: 8px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n border-radius: 6px;\n border: 1px solid rgba(41, 41, 41, 0.36);\n box-shadow: 0px 12px 20px -4px rgba(123, 123, 123, 0.32),\n 0px 4px 8px -3px rgba(123, 123, 123, 0.2),\n 0px 0px 2px 0px rgba(123, 123, 123, 0.36);\n z-index: 3;\n ${FilterMenuCustomStyle || \"\"}\n`;\nconst FilterItem = styled.div`\n cursor: pointer;\n padding: 8px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 12px;\n white-space: nowrap;\n transition: all 300ms ease-in-out;\n &:hover {\n color: #fff;\n background: #292929;\n border-radius: 6px;\n .count {\n color: #fff;\n }\n }\n .count {\n color: #7b7b7b;\n }\n`;\nconst Screen = styled.div`\n position: fixed;\n width: 100%;\n height: 100%;\n left: 0;\n top: 0;\n`;\nreturn (\n <>\n {openFilter && <Screen onClick={() => setOpenFilter(false)} />}\n <div\n style={{ position: \"relative\" }}\n onClick={() => setOpenFilter(!openFilter)}\n >\n <FilterButton style={props.buttonStyle || {}}>\n {sortVal || title}\n <FilterIcon>\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M8 3.88667L10.1133 6L11.0533 5.06L8 2L4.94 5.06L5.88667 6L8 3.88667ZM8 12.1133L5.88667 10L4.94667 10.94L8 14L11.06 10.94L10.1133 10L8 12.1133Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n </FilterIcon>\n </FilterButton>\n {openFilter && (\n <FilterMenu\n onClick={(e) => e.stopPropagation()}\n style={props.menuStyle || {}}\n >\n {sortList.map((option) => (\n <FilterItem\n key={option.val}\n onClick={() => {\n setOpenFilter(false);\n handleSortChange(option);\n }}\n >\n {option.label}{\" \"}\n <div className=\"count\">{showCount ? option.count : \"\"}</div>\n </FilterItem>\n ))}\n </FilterMenu>\n )}\n </div>\n </>\n);\n" }, "Pots.TimeLeft": { "": "const { daysLeft } = props;\nconst [timeLeft, setTimeLeft] = useState(\"-\");\nfunction formatTimeLeft(targetTimestamp) {\n // Calculate time remaining\n const now = new Date().getTime();\n const timeRemaining = targetTimestamp - now;\n // Check if time remaining is negative (target time already passed)\n if (timeRemaining <= 0) {\n return \"Time's up!\";\n }\n // Calculate days, hours, minutes, and seconds\n const days = Math.floor(timeRemaining / (1000 * 60 * 60 * 24));\n const hours = Math.floor(\n (timeRemaining % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)\n );\n const minutes = Math.floor((timeRemaining % (1000 * 60 * 60)) / (1000 * 60));\n const seconds = Math.floor((timeRemaining % (1000 * 60)) / 1000);\n // Construct formatted time string\n const formattedTime = `${days ? days + \"d\" : \"\"} ${\n hours ? hours + \"h\" : \"\"\n } ${minutes ? minutes + \"m\" : \"\"} ${seconds ? seconds + \"s\" : \"\"}`;\n return formattedTime.trim(); // Remove trailing space\n}\nuseEffect(() => {\n const intervelId = setInterval(() => {\n const time = formatTimeLeft(daysLeft);\n setTimeLeft(time);\n if (now > daysLeft) {\n clearInterval(intervelId);\n }\n }, 1000);\n}, []);\nreturn timeLeft;\n" }, "Components.AccountsStack": { "": "const { accountIds, maxDisplayCount, sendToBack } = props;\nconst MAX_DISPLAY_COUNT = maxDisplayCount || 5;\nconst StackContainer = styled.div`\n width: 200px;\n height: 30px;\n margin-bottom: 16px;\n display: flex;\n flex-direction: row;\n @media screen and (max-width: 768px) {\n margin-left: 36px;\n }\n`;\nconst MoreAccountsContainer = styled.div`\n width: 28px;\n height: 28px;\n border: 2px solid white;\n border-radius: 50%;\n background: #dd3345;\n position: relative;\n display: flex;\n justify-content: center;\n align-items: center;\n z-index: ${accountIds.length + 1};\n margin-right: -8px;\n`;\nconst MoreAccountsText = styled.div`\n color: white;\n font-size: 12px;\n font-weight: 600;\n text-align: center;\n`;\nconst accounts = useMemo(\n () => accountIds.slice(0, MAX_DISPLAY_COUNT),\n [accountIds]\n);\nreturn (\n <StackContainer>\n {accountIds.length > MAX_DISPLAY_COUNT && (\n <MoreAccountsContainer>\n <MoreAccountsText>{MAX_DISPLAY_COUNT}+</MoreAccountsText>\n </MoreAccountsContainer>\n )}\n {accounts.map((accountId, idx) => {\n return (\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{\n accountId,\n style: {\n width: \"28px\",\n height: \"28px\",\n zIndex: sendToBack ? 0 : accountIds.length - idx,\n margin: \"0 -8px 0 0\",\n border: \"2px solid white\",\n borderRadius: \"50%\",\n background: \"white\",\n },\n className: \"mb-2\",\n imageClassName: \"rounded-circle w-100 h-100 d-block\",\n thumbnail: false,\n tooltip: true,\n }}\n />\n );\n })}\n </StackContainer>\n);\n" }, "Components.Nav": { "": "const navHeightPx = 110;\nconst navHeightPxMobile = 96;\nconst Nav = styled.div`\n // commenting out stickiness for now\n // position: fixed;\n // top: 0;\n // left: 0;\n width: 100%;\n display: flex;\n padding: 0 40px;\n justify-content: start;\n align-items: center;\n align-self: stretch;\n height: ${navHeightPx}px;\n background: #ffffff;\n z-index: 1000;\n // background: pink;\n @media screen and (max-width: 768px) {\n // display: none;\n padding: 24px 8px 24px 16px;\n height: ${navHeightPxMobile}px;\n }\n @media screen and (max-width: 480px) {\n padding: 24px 8px 24px 0px;\n }\n & > a {\n width: 10rem;\n }\n`;\nconst NavLeft = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n // background: green;\n`;\nconst NavRight = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n`;\nconst NavRightMobile = styled.div`\n display: none;\n @media screen and (max-width: 768px) {\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-end;\n gap: 16px;\n padding-right: 16px;\n }\n`;\nconst NavLogo = styled(\"Link\")`\n display: flex;\n gap: 7px;\n align-items: baseline;\n text-align: center;\n color: #2e2e2e;\n font-size: 23.95px;\n font-weight: 700;\n line-height: 23.95px;\n word-wrap: break-word;\n margin-right: 48px;\n text-decoration: none;\n @media screen and (max-width: 480px) {\n font-size: 20px;\n margin-right: 1rem;\n }\n :hover {\n text-decoration: none;\n }\n img {\n height: 1em;\n }\n`;\nconst NavTabs = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n @media screen and (max-width: 768px) {\n display: none;\n }\n`;\nconst NavTab = styled(\"Link\")`\n cursor: ${(props) => (props.disabled ? \"not-allowed\" : \"pointer\")};\n color: ${(props) => (props.selected ? \"#2E2E2E\" : \"#7B7B7B\")};\n font-size: 14px;\n font-weight: ${(props) => (props.selected ? 500 : 400)};\n line-height: 16px;\n word-wrap: break-word;\n text-decoration: none;\n position: relative;\n :not(:last-child) {\n margin-right: 32px;\n }\n :hover {\n text-decoration: none;\n }\n`;\nconst Banner = styled.div`\n width: 100%;\n // max-height: 50px;\n background: #dd3345;\n // background: rgb(6 10 15);\n display: flex;\n flex-direction: row;\n justify-content: center;\n align-items: center;\n padding: 8px 0;\n // border-bottom: 2px rgb(96, 100, 102) solid;\n`;\nconst BannerText = styled.div`\n text-align: center;\n color: white;\n font-size: 16px;\n font-weight: 600;\n margin-left: 8px;\n @media screen and (max-width: 768px) {\n font-size: 12px;\n margin-left: 4px;\n }\n`;\nconst BannerLinkContainer = styled.a`\n display: flex;\n cursor: pointer;\n text-align: center;\n font-weight: bold;\n color: white;\n font-size: 14px;\n line-height: 21px;\n margin-left: 16px;\n gap: 8px;\n &:hover {\n text-decoration: none;\n }\n @media screen and (max-width: 768px) {\n font-size: 12px;\n margin-left: 8px;\n gap: 4px;\n }\n`;\nconst BannerLinkSvg = styled.svg`\n width: 20px;\n height: 20px;\n fill: none;\n transition: transform 0.2s ease;\n &:hover {\n transform: rotate(45deg);\n }\n @media screen and (max-width: 768px) {\n width: 16px;\n height: 16px;\n }\n`;\nconst BannerAlertSvg = styled.svg`\n width: 18px;\n @media screen and (max-width: 768px) {\n width: 14px;\n }\n`;\nconst NavMenu = styled.div`\n display: none;\n background: white;\n padding: 24px;\n width: 100%;\n gap: 16px;\n @media screen and (max-width: 768px) {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n align-items: flex-start;\n }\n`;\nconst NavMenuItem = styled.a`\n color: ${(props) => (props.selected ? \"#2E2E2E\" : \"#7B7B7B\")};\n font-size: 14px;\n font-weight: ${(props) => (props.selected ? 500 : 400)};\n line-height: 20px;\n word-wrap: break-word;\n cursor: pointer;\n`;\nconst tabOptions = [\n { text: \"Projects\", link: \"projects\", disabled: false },\n { text: \"Feed\", link: \"feed\", disabled: false },\n {\n text: \"Pots\",\n link: \"pots\",\n disabled: false,\n },\n { text: \"Donors\", link: \"donors\", disabled: false },\n // { text: \"Feedback\", href: \"https://potlock.org/feedback\", newTab: true, disabled: false },\n];\nconst [isNavMenuOpen, setIsNavMenuOpen] = useState(false);\nreturn (\n <>\n {false && (\n <Banner>\n <BannerAlertSvg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"white\"\n aria-hidden=\"true\"\n // width=\"18px\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z\"\n ></path>\n </BannerAlertSvg>\n <BannerText>This app is in beta. It has not been audited.</BannerText>\n <BannerLinkContainer\n href=\"https://docs.potlock.io/general-information/beta-phase\"\n target=\"_blank\"\n >\n <span>Learn more</span>\n <BannerLinkSvg\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"w-[18px] group-hover:rotate-[45deg] transition-all\"\n >\n <path\n d=\"M11.6652 6.77894C11.0834 6.78279 10.5015 6.78574 9.91929 6.78777C9.06125 6.78766 8.20376 6.79135 7.34566 6.78145C6.762 6.77478 6.29535 6.33298 6.30266 5.81732C6.31009 5.32123 6.77706 4.88706 7.32973 4.89083C9.53277 4.89897 11.7351 4.91291 13.9368 4.93265C14.6025 4.93925 14.9748 5.32235 14.9826 6.0022C15.0022 8.19227 15.0157 10.3823 15.0231 12.5723C15.0251 13.2043 14.6477 13.6102 14.0912 13.6135C13.5527 13.6152 13.1403 13.1552 13.1372 12.5298C13.1307 11.2364 13.133 9.9431 13.1287 8.64975C13.1284 8.51553 13.113 8.38013 13.0963 8.12137L12.7089 8.50873C10.6829 10.5347 8.64711 12.5508 6.63972 14.5954C6.22161 15.0212 5.62148 14.9861 5.28149 14.6461C4.88466 14.2493 4.90002 13.7158 5.32463 13.2846C7.35705 11.2478 9.39203 9.21284 11.4295 7.17969L11.7105 6.89876L11.6652 6.77894Z\"\n fill=\"currentColor\"\n ></path>\n </BannerLinkSvg>\n </BannerLinkContainer>\n </Banner>\n )}\n <Nav>\n <NavLeft>\n <NavLogo href={props.hrefWithParams(`?tab=projects`)}>\n <img\n src=\"https://ipfs.near.social/ipfs/bafkreiafms2jag3gjbypfceafz2uvs66o25qc7m6u6hkxfyrzfoeyvj7ru\"\n alt=\"logo\"\n />\n POTLOCK\n </NavLogo>\n </NavLeft>\n <NavRight>\n <NavTabs>\n {(tabOptions ?? []).map((tab) => {\n return (\n <NavTab\n href={tab.href ?? props.hrefWithParams(`?tab=${tab.link}`)}\n disabled={tab.disabled}\n target={tab.newTab ? \"_blank\" : \"\"}\n onClick={(e) => {\n if (tab.disabled) e.preventDefault();\n }}\n selected={props.tab === tab.link}\n >\n {tab.text}\n </NavTab>\n );\n })}\n <Widget src={\"old.potlock.near/widget/Cart.NavItem\"} props={props} />\n </NavTabs>\n </NavRight>\n <NavRightMobile>\n <Widget src={\"old.potlock.near/widget/Cart.NavItem\"} props={props} />\n <NavTab onClick={() => setIsNavMenuOpen(!isNavMenuOpen)}>\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n >\n <path\n d=\"M3 18H21V16H3V18ZM3 13H21V11H3V13ZM3 6V8H21V6H3Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n </NavTab>\n </NavRightMobile>\n </Nav>\n {isNavMenuOpen && (\n <NavMenu>\n {tabOptions.map((tab) => {\n return (\n <NavMenuItem\n href={props.hrefWithParams(`?tab=${tab.link}`)}\n disabled={tab.disabled}\n onClick={(e) => {\n if (tab.disabled) e.preventDefault();\n }}\n selected={props.tab === tab.link}\n >\n {tab.text}\n {tab.disabled && \" (Coming Soon)\"}\n </NavMenuItem>\n );\n })}\n </NavMenu>\n )}\n </>\n);\n" }, "Inputs.Date": { "": "const label = props.label ?? \"\";\nconst placeholder = props.placeholder ?? \"\";\nconst value = props.value ?? \"\";\nconst onChange = props.onChange ?? (() => {});\nconst validate = props.validate ?? (() => {});\nconst error = props.error ?? \"\";\nconst Container = styled.div`\n display: flex;\n // flex: 1;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n padding: 0px;\n gap: 0.45em;\n width: 100%;\n`;\nconst Label = styled.label`\n font-weight: 500;\n font-size: 14px;\n line-height: 16px;\n word-wrap: break-word;\n color: #2e2e2e;\n`;\nconst Error = styled.span`\n display: inline-block;\n font-style: normal;\n font-weight: 400;\n font-size: 0.75em;\n line-height: 1.25em;\n color: #ff4d4f;\n height: 0;\n overflow: hidden;\n transition: height 0.3s ease-in-out;\n &.show {\n height: 1.25em;\n }\n`;\nconst InputContainer = styled.div`\n display: flex;\n flex-direction: row;\n width: 100%;\n background: #ffffff;\n border: 1px solid #d0d5dd;\n box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);\n border-radius: 4px;\n`;\nconst InputPrefix = styled.div`\n display: flex;\n justify-content: center;\n align-items: center;\n height: 100%;\n text-align: center;\n padding: 14px 16px;\n border-right: 1px #f0f0f0 solid;\n color: #7b7b7b;\n font-size: 16px;\n font-weight: 400;\n`;\nconst Input = styled.input`\n border: none;\n display: flex;\n flex-direction: row;\n align-items: center;\n padding: 0.5em 0.75em;\n gap: 0.5em;\n color: #101828;\n width: 100%;\n border-radius: 4px;\n`;\nreturn (\n <Container>\n {label && <Label>{label}</Label>}\n <InputContainer>\n {/* {props.prefixText && <InputPrefix>{props.prefixText}</InputPrefix>} */}\n {/* {props.prefixElement && props.prefixElement} */}\n {props.preInputChildren && props.preInputChildren}\n <Input\n type={props.selectTime ? \"datetime-local\" : \"date\"}\n placeholder={placeholder}\n value={value}\n onChange={({ target: { value } }) => onChange(value)}\n onBlur={() => validate()}\n disabled={!!props.disabled}\n onKeyDown={props.handleKeyPress ?? null}\n style={props.inputStyles || {}}\n />\n {props.postInputChildren && props.postInputChildren}\n </InputContainer>\n <Error className={error ? \"show\" : \"\"}>{error}</Error>\n </Container>\n);\n" }, "Components.DonorsLeaderboard": { "": "const { sponsors, sortedDonations, filter, currentTab, tab } = props;\nconst donations = currentTab === \"sponsors\" ? sponsors : sortedDonations;\nconst isInPot = tab === \"pot\";\nconst { nearToUsd } = VM.require(\"old.potlock.near/widget/utils\") || {\n nearToUsd: 1,\n};\nconst [currentPage, setCurrentPage] = useState(1);\nconst perPage = 30; // need to be less than 50\nuseEffect(() => {\n setCurrentPage(1);\n}, [filter]);\nconst nearLogo =\n \"https://ipfs.near.social/ipfs/bafkreicdcpxua47eddhzjplmrs23mdjt63czowfsa2jnw4krkt532pa2ha\";\nconst { getTimePassed, _address, calcNetDonationAmount, reverseArr } =\n VM.require(\"old.potlock.near/widget/Components.DonorsUtils\");\nconst Container = styled.div`\n width: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2rem;\n .transcation {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-size: 14px;\n .header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px;\n gap: 1rem;\n background: #f6f5f3;\n color: #292929;\n div {\n width: 130px;\n display: flex;\n justify-content: center;\n align-items: center;\n font-weight: 600;\n }\n }\n .address {\n width: 190px !important;\n margin-right: auto;\n justify-content: start !important;\n }\n .rank {\n width: 80px !important;\n }\n }\n @media only screen and (max-width: 768px) {\n .transcation {\n font-size: 12px;\n .header {\n padding: 10px 0;\n div {\n width: 80px;\n }\n }\n }\n }\n @media only screen and (max-width: 480px) {\n .transcation {\n font-size: 9px;\n .address {\n width: 120px !important;\n }\n }\n }\n`;\nconst TrRow = styled.div`\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n gap: 1rem;\n padding: 20px 10px;\n > div,\n > span {\n width: 130px;\n display: flex;\n justify-content: center;\n align-items: center;\n }\n .price {\n display: flex;\n gap: 1rem;\n align-items: center;\n img {\n width: 1.5rem;\n }\n }\n .address {\n color: #292929;\n display: flex;\n align-items: center;\n justify-content: flex-start;\n border-radius: 2px;\n transition: all 200ms;\n .profile-image {\n width: 2rem;\n height: 2rem;\n margin-right: 1rem;\n }\n }\n @media only screen and (max-width: 768px) {\n padding: 10px 0;\n > div,\n > span {\n width: 80px;\n }\n .price {\n gap: 8px;\n img {\n width: 1.25rem;\n }\n }\n .address .profile-image {\n width: 1.5rem;\n height: 1.5rem;\n margin-right: 0.5rem;\n }\n }\n @media only screen and (max-width: 480px) {\n .price img {\n width: 1rem;\n }\n }\n`;\nconst NoResult = styled.div`\n font-size: 2rem;\n text-align: center;\n`;\nconst totalDonations = 0;\ndonations.forEach((donation) => {\n totalDonations += donation.amount;\n});\nconst ProfileImg = ({ donor_id }) => (\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{ accountId: donor_id, style: {} }}\n />\n);\nreturn donations.length ? (\n <Container>\n <div className=\"transcation\">\n <div className=\"header\">\n <div className=\"rank\">Rank</div>\n <div className=\"address\">Donor</div>\n <div>Amount</div>\n {isInPot && <div>Percentage</div>}\n {nearToUsd && !isInPot && <div>Amount (USD)</div>}\n </div>\n {donations\n .slice((currentPage - 1) * perPage, currentPage * perPage)\n .map((donation, idx) => {\n const { donor_id, amount, percentage_share } = donation;\n return (\n <TrRow>\n <div className=\"rank\">\n #{idx + 1 + (currentPage - 1) * perPage}\n </div>\n <a\n href={props.hrefWithParams(\n `?tab=profile&accountId=${donor_id}`\n )}\n className=\"address\"\n target=\"_blank\"\n >\n <ProfileImg donor_id={donor_id} />\n {_address(donor_id, 15)}\n </a>\n <div className=\"price\">\n <img src={nearLogo} alt=\"NEAR\" />\n {amount.toFixed(2).replace(/[.,]00$/, \"\")}\n </div>\n {isInPot && <div>{percentage_share}%</div>}\n {nearToUsd && !isInPot && (\n <div>~${(amount * nearToUsd).toFixed(2)}</div>\n )}\n </TrRow>\n );\n })}\n </div>\n <Widget\n src={\"old.potlock.near/widget/Components.Pagination\"}\n props={{\n onPageChange: (page) => {\n setCurrentPage(page);\n },\n data: donations,\n currentPage,\n perPage: perPage,\n bgColor: \"#292929\",\n }}\n />\n </Container>\n) : (\n <NoResult>No Donations</NoResult>\n);\n" }, "Inputs.FilterDropdown": { "": "const Container = styled.div`\n display: flex;\n position: relative;\n flex-direction: column;\n align-items: flex-end;\n font-size: 14px;\n`;\nconst Label = styled.div`\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n cursor: pointer;\n width: fit-content;\n padding: 0.5rem 1rem;\n border-radius: 6px;\n border: 1px solid #7b7b7b;\n &.active {\n color: #fff;\n background: #292929;\n }\n`;\nconst Menu = styled.div`\n position: absolute;\n top: calc(100% + 0.5rem);\n right: 0;\n transition: all 300ms ease-in-out;\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n border-radius: 8px;\n padding: 1rem;\n background: #fff;\n width: 500px;\n box-shadow: 0px 0px 0px 1px rgba(123, 123, 123, 0.09),\n 0px 3px 3px -1px rgba(123, 123, 123, 0.16),\n 0px 9px 9px -3px rgba(123, 123, 123, 0.1),\n 0px 17px 14px -5px rgba(123, 123, 123, 0.08);\n opacity: 0;\n visibility: hidden;\n transform: translateY(100px);\n z-index: 1;\n &.active {\n opacity: 1;\n visibility: visible;\n transform: translateY(0);\n }\n .title {\n width: 100%;\n &:not(:first-of-type) {\n margin-top: 2rem;\n }\n }\n .option {\n display: flex;\n align-items: center;\n gap: 10px;\n border-radius: 8px;\n border: 1px solid #dbdbdb;\n padding: 8px 12px;\n cursor: pointer;\n transition: all 300ms ease-in-out;\n svg {\n display: none;\n width: 14px;\n }\n :hover {\n border: 1px solid #f4b37d;\n background: #fef6ee;\n color: #ea6a25;\n }\n &.selected {\n border: 1px solid #f4b37d;\n background: #fef6ee;\n color: #ea6a25;\n svg {\n display: block;\n }\n }\n }\n @media only screen and (max-width: 768px) {\n width: 200px !important;\n left: 0;\n right: auto;\n }\n`;\nconst Count = styled.div`\n font-weight: 600;\n font-size: 12px;\n display: flex;\n line-height: 1;\n width: 18px;\n height: 18px;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n background: #ebebeb;\n &.active {\n background: #464646;\n color: #f6f5f3;\n }\n`;\nconst Screen = styled.div`\n position: fixed;\n width: 100%;\n height: 100%;\n left: 0;\n top: 0;\n`;\nconst { onClick, menuClass, label, multipleOptions, defaultSelected } = props;\nconst labelIcon = props.labelIcon ?? \"center\";\nconst options = props.options ?? {};\nconst [toggleMenu, setToggleMenu] = useState(false);\nconst [selected, setSelected] = useState(defaultSelected || {});\nconst icons = {\n center: (\n <svg\n width=\"18\"\n height=\"12\"\n viewBox=\"0 0 18 12\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M7 12H11V10H7V12ZM0 0V2H18V0H0ZM3 7H15V5H3V7Z\" fill=\"#7B7B7B\" />\n </svg>\n ),\n right: (\n <svg\n width=\"18\"\n height=\"12\"\n viewBox=\"0 0 18 12\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M0 12H6V10H0V12ZM0 0V2H18V0H0ZM0 7H12V5H0V7Z\" fill=\"#7B7B7B\" />\n </svg>\n ),\n};\nfunction findIndexWithAll(listOfLists, target) {\n for (let i = 0; i < listOfLists.length; i++) {\n const indexInList = listOfLists[i].indexOf(target);\n if (indexInList !== -1) {\n return { listIndex: i, itemIndex: indexInList };\n }\n }\n return { listIndex: -1, itemIndex: -1 }; // Not found\n}\nconst handleSelect = ({ val, type, label }) => {\n let selectedUpdated = { ...selected };\n const selectedList = selected[type] || [];\n if (!multipleOptions) {\n selectedUpdated = { val, label };\n } else if (selectedList.includes(val)) {\n selectedUpdated[type] = selectedList.filter((item) => item !== val);\n } else {\n selectedUpdated[type] = [...selectedList, val];\n }\n const { listIndex, itemIndex } = findIndexWithAll(\n Object.values(selectedUpdated),\n \"all\"\n );\n const types = Object.keys(selectedUpdated);\n // remove filters if all is selected\n if (val === \"all\") {\n selectedUpdated = {\n [type]: [val],\n };\n }\n // remove all if another filter is selected\n else if (listIndex !== -1) {\n selectedUpdated[types[listIndex]].splice(itemIndex, 1);\n }\n setSelected(selectedUpdated);\n onClick(selectedUpdated);\n setToggleMenu(false);\n};\nconst count = Object.values(selected).reduce(\n (total, list) => total + list.length,\n 0\n);\nreturn (\n <Container>\n {toggleMenu && <Screen onClick={() => setToggleMenu(false)} />}\n <Label\n className={toggleMenu ? \"active\" : \"\"}\n onClick={() => setToggleMenu(!toggleMenu)}\n >\n {label || \"Filter\"}\n {multipleOptions && (\n <Count className={toggleMenu ? \"active\" : \"\"}>{count}</Count>\n )}\n {icons[labelIcon]}\n </Label>\n <Menu className={`${toggleMenu ? \"active\" : \"\"} ${menuClass ?? \"\"}`}>\n {Object.keys(options)?.map((menuLabel) => (\n <>\n <div className=\"title\">\n Filter by {menuLabel.includes(\"no label\") ? \"\" : menuLabel}\n </div>\n {(options[menuLabel] || [])?.map(({ label, val }) => (\n <div\n className={`option ${\n multipleOptions &&\n (selected[menuLabel] || [])?.includes(val) &&\n \"selected\"\n }`}\n key={val}\n onClick={() => handleSelect({ label, val, type: menuLabel })}\n >\n <svg\n viewBox=\"0 0 14 12\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M4.59625 8.90631L1.46875 5.77881L0.403748 6.83631L4.59625 11.0288L13.5962 2.02881L12.5387 0.971313L4.59625 8.90631Z\"\n fill=\"#F4B37D\"\n />\n </svg>\n {label}\n </div>\n ))}\n </>\n ))}\n </Menu>\n </Container>\n);\n" }, "Components.ui.Button": { "": "const { Volunteer } = VM.require(\n \"old.potlock.near/widget/Components.Icons\"\n) || {\n Volunteer: () => <></>,\n};\nconst StyledButton = styled.button`\n all: unset;\n width: 120px;\n height: 22px;\n border-radius: 6px;\n padding: 9px 16px 9px 12px;\n justify-content: center;\n align-items: center;\n display: inline-flex;\n gap: 8px;\n font-size: 14px;\n font-weight: 500;\n // font-family: \"Mona Sans\", sans-serif;\n line-height: 22px;\n text-align: center;\n font-feature-settings: \"ss01\" on, \"salt\" on;\n /* Mona sans/Text sm/14px:Medium */\n font-size: 14px;\n font-style: normal;\n font-weight: 500;\n line-height: 22px; /* 157.143% */\n flex-shrink: 0;\n transition: all 200ms cubic-bezier(0.17, 0.67, 0.83, 0.67);\n flex-direction: ${(props) => {\n if (props.direction === \"right\") {\n return \"row\";\n } else if (props.direction === \"left\") {\n return \"row-reverse\";\n }\n }};\n svg path {\n fill: ${(props) => {\n switch (props.variant) {\n case \"outline\":\n return \"rgba(123, 123, 123, 1)\";\n case \"tonal\":\n return \"#656565\";\n case \"standard\":\n return \"#FFFFFF\";\n case \"primary\":\n return \"#FFFFFF\";\n case \"brand-outline\":\n return \"hsla(358, 88%, 71%, 1)\";\n }\n }};\n }\n background: ${(props) => {\n switch (props.variant) {\n case \"outline\":\n return \"var(--button-outline-bg, Neutral/White)\";\n case \"tonal\":\n return \"var(--button-tonal-bg,#FEF6EE) \";\n case \"standard\":\n return \"var(--button-standard-bg, #3D3D3D)\";\n case \"primary\":\n return \"var(--button-primary-bg, #DD3345)\";\n case \"brand-outline\":\n return \"hsla(0, 0%, 100%, 0.01)\";\n }\n }};\n color: ${(props) => {\n switch (props.variant) {\n case \"outline\":\n return \"var(--button-outline-color, #292929)\";\n case \"tonal\":\n return \"var(--button-tonal-color,#292929) \";\n case \"standard\":\n return \"var(--button-standard-color, #FFFFFF)\";\n case \"primary\":\n return \"var(--button-primary-color, #FFFFFF)\";\n case \"brand-outline\":\n return \"hsla(354, 71%, 53%, 1)\";\n }\n }};\n box-shadow: ${(props) => {\n switch (props.variant) {\n case \"outline\":\n return \"0px 0px 0px 1px rgba(0, 0, 0, 0.22) inset, 0px -1px 0px 0px rgba(15, 15, 15, 0.15) inset, 0px 1px 2px -0.5px rgba(5, 5, 5, 0.08);\";\n case \"tonal\":\n return \"0px 0px 0px 1px rgba(0, 0, 0, 0.84) inset, 0px 1px 1px 1px #FFF inset, 0px 0px 0px 2px #FFF inset, 0px 1.5px 0px 0px rgba(0, 0, 0, 0.84);\";\n case \"standard\":\n return \"0px 0px 0px 1px rgba(0, 0, 0, 0.84) inset, 0px 1px 1px 1px rgba(166, 166, 166, 0.40) inset, 0px 0px 0px 2px rgba(166, 166, 166, 0.40) inset, 0px 1px 2px 0px rgba(15, 15, 15, 0.15), 0px 1px 3px -1px rgba(5, 5, 5, 0.08);\";\n case \"primary\":\n return \"0px 0px 0px 1px rgba(0, 0, 0, 0.84) inset, 0px 1px 1px 1px rgba(246, 118, 122, 0.50) inset, 0px 0px 0px 2px rgba(246, 118, 122, 0.50) inset, 0px 1.5px 0px 0px rgba(0, 0, 0, 0.84);\";\n case \"brand-outline\":\n return \"0px 0px 0px 1px rgba(243, 78, 95, 0.78) inset, 0px -1px 0px 0px rgba(73, 8, 19, 0.50) inset, 0px 1px 2px -0.5px rgba(73, 8, 19, 0.20);\";\n }\n }};\n &:hover:not(:disabled) {\n transform: ${(props) => {\n switch (props.variant) {\n case \"primary\":\n case \"tonal\":\n return \"translateY(1px)\";\n }\n }};\n box-shadow: ${(props) => {\n switch (props.variant) {\n case \"primary\":\n return \" 0px 0px 0px 1px rgba(0, 0, 0, 0.84) inset, 0px 1px 1px 1px #ED464F inset;\";\n case \"outline\":\n return \" 0px 0px 0px 1px rgba(0, 0, 0, 0.22) inset, 0px -1px 0px 0px rgba(15, 15, 15, 0.15) inset, 0px 1px 2px -0.5px rgba(5, 5, 5, 0.08);\";\n case \"standard\":\n return \" 0px 0px 0px 1px rgba(0, 0, 0, 0.84) inset, 0px 1px 1px 1px rgba(166, 166, 166, 0.40) inset, 0px 0px 0px 2px rgba(166, 166, 166, 0.40) inset, 0px 1px 2px 0px rgba(15, 15, 15, 0.15), 0px 1px 3px -1px rgba(5, 5, 5, 0.08);\";\n case \"tonal\":\n return \"0px 0px 0px 1px rgba(0, 0, 0, 0.84) inset, 0px 1px 1px 1px #FFF inset;\";\n case \"brand-outline\":\n return \"0px 0px 0px 1px rgba(243, 78, 95, 0.78) inset, 0px -1px 0px 0px rgba(73, 8, 19, 0.50) inset, 0px 1px 2px -0.5px rgba(73, 8, 19, 0.20);\";\n }\n }};\n background: ${(props) => {\n switch (props.variant) {\n case \"primary\":\n return \" #DD3345\";\n case \"outline\":\n return \"Neutral/50\";\n case \"standard\":\n return \" #525252\";\n case \"tonal\":\n return \"0px 0px 0px 1px rgba(0, 0, 0, 0.84) inset, 0px 1px 1px 1px #FFF inset;\";\n case \"brand-outline\":\n return \"#FEF3F2\";\n }\n }};\n }\n &:focus:not(:disabled) {\n box-shadow: ${(props) => {\n switch (props.variant) {\n case \"outline\":\n return \"0px 0px 0px 1px rgba(0, 0, 0, 0.22) inset, 0px -1px 0px 0px rgba(15, 15, 15, 0.15) inset, 0px 1px 2px -0.5px rgba(5, 5, 5, 0.08), 0px 0px 0px 2px #FFF, 0px 0px 0px 4px rgba(0, 0, 0, 0.84);\";\n case \"primary\":\n return \"0px 0px 0px 1px rgba(0, 0, 0, 0.84) inset, 0px 0px 0px 2px #FFF, 0px 0px 0px 4px rgba(0, 0, 0, 0.84);\";\n case \"standard\":\n return \"0px 0px 0px 1px rgba(0, 0, 0, 0.84) inset, 0px 1px 1px 1px rgba(166, 166, 166, 0.30) inset, 0px 0px 0px 2px rgba(166, 166, 166, 0.30) inset, 0px 0px 0px 2px #FFF, 0px 0px 0px 4px rgba(0, 0, 0, 0.84);\";\n case \"tonal\":\n return \"0px 0px 0px 1px rgba(0, 0, 0, 0.84) inset, 0px 0px 0px 2px #FFF, 0px 0px 0px 4px rgba(0, 0, 0, 0.84);\";\n case \"brand-outline\":\n return \"0px 0px 0px 1px rgba(243, 78, 95, 0.78) inset, 0px -1px 0px 0px rgba(73, 8, 19, 0.50) inset, 0px 1px 2px -0.5px rgba(5, 5, 5, 0.08), 0px 0px 0px 2px #FFF, 0px 0px 0px 4px rgba(0, 0, 0, 0.84);\";\n }\n }};\n }\n &:disabled {\n color: ${(props) => {\n switch (props.variant) {\n case \"outline\":\n return \"hsla(0, 0%, 78%, 1)\"; // Adjust color value\n case \"standard\":\n return \"hsla(0, 0%, 65%, 1)\"; // Use CSS variable for color or specify a fallback\n default:\n return \"inherit\"; // Fallback to default color\n }\n }};\n box-shadow: ${(props) => {\n switch (props.variant) {\n case \"outline\":\n return \"0px 0px 0px 1px rgba(15, 15, 15, 0.15) inset;\"; // Adjust box-shadow value\n case \"standard\":\n return \"0px 0px 0px 1px rgba(15, 15, 15, 0.15) inset;\"; // Adjust box-shadow value\n default:\n return \"none\"; // No box-shadow for other variants\n }\n }};\n background: ${(props) => {\n switch (props.variant) {\n case \"outline\":\n return \"var(--button-outline-bg-disabled, #fff)\"; // Use CSS variable for background or specify a fallback\n case \"standard\":\n return \"var(--button-standard-bg-disabled, #EBEBEB)\"; // Use CSS variable for background or specify a fallback\n default:\n return \"inherit\"; // Fallback to default background\n }\n }};\n }\n`;\nconst TipOnPotlock = ({ direction, variant, onClick, href, ...restProps }) => {\n if (href) {\n return (\n <Link href={href}>\n <StyledButton\n direction={direction ?? \"right\"}\n onClick={onClick}\n {...restProps}\n variant={variant ?? \"primary\"}\n >\n <Volunteer />\n Tip on Potlock\n </StyledButton>\n </Link>\n );\n }\n return (\n <StyledButton\n direction={direction ?? \"right\"}\n onClick={onClick}\n {...restProps}\n variant={variant ?? \"primary\"}\n >\n <Volunteer />\n Tip on Potlock\n </StyledButton>\n );\n};\nconst Button = ({\n direction,\n disabled,\n children,\n onClick,\n href,\n ...restProps\n}) => {\n if (href) {\n return (\n <link to={href}>\n <StyledButton\n direction={direction ?? \"right\"}\n onClick={onClick}\n disabled={disabled}\n {...restProps}\n >\n {children}\n </StyledButton>\n </link>\n );\n }\n return (\n <StyledButton\n direction={direction ?? \"right\"}\n onClick={onClick}\n disabled={disabled}\n {...restProps}\n >\n {children}\n </StyledButton>\n );\n};\nreturn { Button, TipOnPotlock };\n" }, "Pots.PoolAllocationTable": { "": "const { potId, env, hrefWithParams, allDonations, potDetail } = props;\nconst {\n base_currency,\n total_public_donations,\n matching_pool_balance,\n public_donations_count,\n} = potDetail;\nconst { NADA_BOT_URL, SUPPORTED_FTS } = VM.require(\n \"old.potlock.near/widget/constants\"\n) || {\n NADA_BOT_URL: \"\",\n SUPPORTED_FTS: {},\n};\nconst { _address } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n) || {\n _address: (address) => address,\n};\nconst {\n calculatePayouts,\n nearToUsdWithFallback,\n yoctosToUsdWithFallback,\n formatWithCommas,\n nearToUsd,\n} = VM.require(\"old.potlock.near/widget/utils\") || {\n nearToUsdWithFallback: () => \"\",\n yoctosToUsdWithFallback: () => \"\",\n calculatePayouts: () => {},\n getFlaggedAccounts: () => {},\n formatWithCommas: () => \"\",\n nearToUsd: 1,\n};\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n asyncGetDonationsForDonor: () => {},\n asyncGetApprovedApplications: () => {},\n getMatchingPoolDonations: () => {},\n};\nconst [projectsId, setProjectsId] = useState(null);\nconst [projectsDonations, setProjectsDonations] = useState({});\nconst [usdToggle, setUsdToggle] = useState(false);\nconst [allPayouts, setAllPayouts] = useState(null);\nconst [flaggedAddresses, setFlaggedAddresses] = useState(null);\nif (!projectsId) {\n PotSDK.asyncGetApprovedApplications(potId).then((projects) => {\n setProjectsId(projects);\n });\n}\nlet sponsorshipDonations = PotSDK.getMatchingPoolDonations(potId);\nif (sponsorshipDonations)\n sponsorshipDonations.sort((a, b) => b.net_amount - a.net_amount);\nconst lastProject = projectsId[projectsId.length - 1].project_id;\nconst calcUniqueDonors = (donations) => {\n // Get the count of unique donors\n const uniqueDonorIds = new Set();\n // Iterate through each object and collect unique donor_id values\n donations.forEach((project) => {\n project.donations.forEach((donation) => {\n uniqueDonorIds.add(donation.donor_id);\n });\n });\n // Get the number of unique donor_id values\n return uniqueDonorIds.size;\n};\nconst calcMatchedAmount = (donations) => {\n const total = Big(0);\n donations.forEach((donation) => {\n total = total.plus(Big(donation.net_amount));\n });\n const amount = SUPPORTED_FTS[base_currency.toUpperCase()].fromIndivisible(\n total.toString()\n );\n return amount;\n};\nconst uniqueDonorIds = allDonations\n ? new Set(allDonations.map((donation) => donation.donor_id))\n : new Set([]);\nconst donorsCount = uniqueDonorIds.size;\nif (!flaggedAddresses) {\n PotSDK.getFlaggedAccounts(potDetail, potId)\n .then((data) => {\n const listOfFlagged = [];\n data.forEach((adminFlaggedAcc) => {\n const addresses = Object.keys(adminFlaggedAcc.potFlaggedAcc);\n listOfFlagged.push(...addresses);\n });\n setFlaggedAddresses(listOfFlagged);\n })\n .catch((err) => console.log(\"error getting the flagged accounts \", err));\n}\nconst sortAndSetPayouts = (payouts) => {\n payouts.sort((a, b) => {\n // sort by matching pool allocation, highest to lowest\n return b.matchingAmount - a.matchingAmount;\n });\n setAllPayouts(payouts.slice(0, 5));\n};\nif (!allPayouts && allDonations?.length > 0 && flaggedAddresses) {\n let allPayouts = [];\n if (potDetail.payouts.length) {\n allPayouts = potDetail.payouts.map((payout) => {\n const { project_id, amount } = payout;\n return {\n projectId: project_id,\n matchingAmount: amount,\n };\n });\n sortAndSetPayouts(allPayouts);\n } else {\n calculatePayouts(\n allDonations,\n matching_pool_balance,\n flaggedAddresses\n ).then((calculatedPayouts) => {\n allPayouts = Object.entries(calculatedPayouts).map(\n ([projectId, { matchingAmount }]) => {\n return {\n projectId,\n matchingAmount,\n };\n }\n );\n sortAndSetPayouts(allPayouts);\n });\n }\n}\nconst ProfileImg = ({ profile }) => (\n <Widget src=\"mob.near/widget/ProfileImage\" props={{ profile, style: {} }} />\n);\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n width: 100%;\n border-radius: 12px;\n border-top: 1px solid #292929;\n border-right: 1px solid #292929;\n border-bottom: 2px solid #292929;\n border-left: 1px solid #292929;\n overflow: hidden;\n .header {\n font-size: 18px;\n font-weight: 600;\n background: #fef6ee;\n padding: 1rem;\n span {\n color: #ee8949;\n }\n }\n .sort {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.5rem 1rem;\n font-size: 11px;\n background: #fef6ee;\n .title {\n font-weight: 500;\n letter-spacing: 0.44px;\n text-transform: uppercase;\n }\n .sort-btn {\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n cursor: pointer;\n }\n }\n`;\nconst Row = styled.div`\n display: flex;\n align-items: center;\n font-size: 14px;\n padding: 1rem;\n gap: 8px;\n border-bottom: 1px solid #c7c7c7;\n &:last-of-type {\n border-bottom: none;\n }\n .address {\n display: flex;\n text-decoration: none;\n align-items: center;\n font-weight: 600;\n gap: 8px;\n margin-left: 24px;\n flex: 1;\n color: #292929;\n transition: color 200ms ease-in;\n :hover {\n color: #dd3345;\n }\n }\n .profile-image {\n width: 18px;\n height: 18px;\n }\n`;\nconst publicRoundStarted = projectsTotalDonations.length > 0;\nconst Table = ({ donations, totalAmount, totalUniqueDonors, title }) => (\n <Container>\n <div className=\"header\">\n {totalAmount}\n <span>raised from</span>\n {totalUniqueDonors}\n <span>{allPayouts?.length > 0 ? \"donors\" : \"sponsors\"}</span>\n </div>\n <div className=\"sort\">\n <div className=\"title\">Top {title} </div>\n <div\n className=\"sort-btn\"\n style={{\n cursor: nearToUsd ? \"pointer\" : \"default\",\n }}\n onClick={() => (nearToUsd ? setUsdToggle(!usdToggle) : \"\")}\n >\n {nearToUsd && (\n <svg\n width=\"12\"\n height=\"14\"\n viewBox=\"0 0 12 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M9 10.7575V5.5H7.5V10.7575H5.25L8.25 13.75L11.25 10.7575H9ZM3.75 0.25L0.75 3.2425H3V8.5H4.5V3.2425H6.75L3.75 0.25ZM9 10.7575V5.5H7.5V10.7575H5.25L8.25 13.75L11.25 10.7575H9ZM3.75 0.25L0.75 3.2425H3V8.5H4.5V3.2425H6.75L3.75 0.25Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n )}\n {usdToggle ? \"USD\" : \"NEAR\"}\n </div>\n </div>\n {donations.map(\n ({ projectId, donor_id, matchingAmount, net_amount }, idx) => {\n const id = donor_id || projectId;\n const nearAmount = formatWithCommas(\n SUPPORTED_FTS[base_currency.toUpperCase()].fromIndivisible(\n net_amount || matchingAmount\n )\n );\n const profile = Social.getr(`${id}/profile`);\n const matchedAmout = usdToggle\n ? yoctosToUsdWithFallback(matchingAmount || net_amount, true)\n : nearAmount;\n const url = projectId\n ? `?tab=project&projectId=${projectId}`\n : `?tab=profile&accountId=${donor_id}`;\n return (\n <Row>\n <div>#{idx + 1}</div>\n <a className=\"address\" href={hrefWithParams(url)}>\n <ProfileImg profile={profile} />\n {_address(profile.name || id, 15)}\n </a>\n <div>\n {matchedAmout} {usdToggle ? \" \" : \"N\"}\n </div>\n </Row>\n );\n }\n )}\n </Container>\n);\nreturn allPayouts?.length > 0 ? (\n <Table\n title=\"matching pool allocations\"\n totalAmount={yoctosToUsdWithFallback(total_public_donations, true)}\n totalUniqueDonors={donorsCount}\n donations={allPayouts}\n />\n) : sponsorshipDonations.length > 0 ? (\n <Table\n title=\"sponsors\"\n totalAmount={nearToUsdWithFallback(calcMatchedAmount(sponsorshipDonations))}\n totalUniqueDonors={\n new Set(sponsorshipDonations.map((obj) => obj.donor_id)).size\n }\n donations={sponsorshipDonations.slice(0, 5)}\n />\n) : (\n \"\"\n);\n" }, "Cart.AddToCart": { "": "const { handleCallback, item, text } = props;\nconst { addItemsToCart, removeItemsFromCart, itemExistsInCart } = VM.require(\n \"old.potlock.near/widget/SDK.cart\"\n) ?? {\n addItemsToCart: () => {},\n removeItemsFromCart: () => {},\n itemExistsInCart: () => false,\n};\nconst existsInCart = itemExistsInCart(item);\nreturn (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"tertiary\",\n text: text || (existsInCart ? \"Remove from cart\" : \"Add to cart\"),\n style: { padding: \"12px 16px\" },\n disabled: props.disabled ?? false,\n onClick: () => {\n if (existsInCart) {\n removeItemsFromCart([item]);\n } else {\n // item.ft = \"NEAR\";\n addItemsToCart([item]);\n }\n if (handleCallback) {\n handleCallback();\n }\n },\n }}\n />\n);\n" }, "Cart.CheckoutItem": { "": "const { basisPointsToPercent } = VM.require(\n \"old.potlock.near/widget/utils\"\n) || {\n basisPointsToPercent: () => 0,\n};\nconst { SUPPORTED_FTS } = VM.require(\"old.potlock.near/widget/constants\") || {\n SUPPORTED_FTS: {},\n};\nconst { removeItemsFromCart, updateItemInCart } = VM.require(\n \"old.potlock.near/widget/SDK.cart\"\n) || {\n removeItemsFromCart: () => {},\n updateItemInCart: () => {},\n};\nconst { cartItem, checked, handleCheckboxClick } = props;\nconst projectId = cartItem?.id;\nconst isPotDonation = cartItem?.potId;\nconst profile =\n props.profile || Social.get(`${projectId}/profile/**`, \"final\") || {};\nconst IPFS_BASE_URL = \"https://nftstorage.link/ipfs/\";\nconst CHEVRON_DOWN_URL =\n IPFS_BASE_URL + \"bafkreiabkwyfxq6pcc2db7u4ldweld5xcjesylfuhocnfz7y3n6jw7dptm\";\nconst CHEVRON_UP_URL =\n IPFS_BASE_URL + \"bafkreibdm7w6zox4znipjqlmxr66wsjjpqq4dguswo7evvrmzlnss3c3vi\";\nconst ItemContainer = styled.div`\n display: flex;\n flex-direction: row;\n max-width: 800px;\n background: white;\n // background: pink;\n border: 1px solid #dbdbdb;\n box-shadow: 0px -2px 0px #dbdbdb inset;\n border-radius: 6px;\n justify-content: flex-start;\n align-items: flex-start;\n`;\nconst ItemLeft = styled.div`\n height: 100%;\n padding: 24px 16px;\n // background: green;\n`;\nconst ItemRight = styled.div`\n display: flex;\n flex-direction: row;\n padding: 24px 24px 24px 16px;\n width: 100%;\n // background: yellow;\n border-left: 1px solid #dbdbdb;\n`;\nconst ImageContainer = styled.div`\n display: flex;\n flex-direction: row;\n gap: 32px;\n`;\nconst DetailsContainer = styled.div`\n display: flex;\n flex-direction: column;\n width: 100%;\n overflow: hidden;\n`;\nconst Title = styled.a`\n color: #2e2e2e;\n font-size: 16px;\n line-height: 24px;\n font-weight: 600;\n word-wrap: break-word;\n`;\nconst Description = styled.div`\n color: #2e2e2e;\n font-size: 16px;\n line-height: 24px;\n font-weight: 400;\n word-wrap: break-word;\n overflow-wrap: break-word;\n margin: 16px 0px 24px 0px;\n`;\nconst FtIcon = styled.img`\n width: 20px;\n height: 20px;\n`;\nconst Row = styled.div`\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n`;\nconst Icon = styled.svg`\n width: 20px;\n height: 20px;\n`;\nconst NearIcon = (props) => (\n <Icon\n {...props}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n id=\"near-logo\"\n >\n <rect width=\"24\" height=\"24\" rx=\"12\" fill=\"#CECECE\" />\n <path\n d=\"M15.616 6.61333L13.1121 10.3333C12.939 10.5867 13.2719 10.8933 13.5117 10.68L15.9756 8.53333C16.0422 8.48 16.1354 8.52 16.1354 8.61333V15.32C16.1354 15.4133 16.0155 15.4533 15.9623 15.3867L8.50388 6.45333C8.26415 6.16 7.91787 6 7.53163 6H7.26526C6.5727 6 6 6.57333 6 7.28V16.72C6 17.4267 6.5727 18 7.27858 18C7.71809 18 8.13097 17.7733 8.3707 17.3867L10.8746 13.6667C11.0477 13.4133 10.7148 13.1067 10.475 13.32L8.0111 15.4533C7.94451 15.5067 7.85128 15.4667 7.85128 15.3733V8.68C7.85128 8.58667 7.97114 8.54667 8.02442 8.61333L15.4828 17.5467C15.7225 17.84 16.0821 18 16.4551 18H16.7214C17.4273 18 18 17.4267 18 16.72V7.28C18 6.57333 17.4273 6 16.7214 6C16.2686 6 15.8557 6.22667 15.616 6.61333Z\"\n fill=\"black\"\n />\n </Icon>\n);\nconst [itemAmount, setItemAmount] = useState(cartItem?.amount);\nconst [itemToken, setItemToken] = useState(cartItem?.token);\nState.init({\n ftBalances: null,\n denominationOptions: [\n {\n text: \"NEAR\",\n value: \"NEAR\",\n selected: itemToken.text === \"NEAR\",\n decimals: 24,\n },\n ],\n});\n// * REMOVING FTs FROM CHECKOUT FOR NOW *\n// const ftBalancesRes = useCache(\n// () =>\n// asyncFetch(\n// `https://near-mainnet.api.pagoda.co/eapi/v1/accounts/${context.accountId}/balances/FT`,\n// {\n// headers: {\n// \"Content-Type\": \"application/json\",\n// \"x-api-key\": \"dce81322-81b0-491d-8880-9cfef4c2b3c2\",\n// },\n// }\n// )\n// .then((res) => res.body)\n// .catch((e) => console.log(\"error fetching ft balances: \", e)),\n// `ft-balances-${context.accountId}`\n// );\n// console.log(\"ftBalancesRes: \", ftBalancesRes);\n// console.log(\"state in CheckoutItem: \", state);\n// * REMOVING FTs FROM CHECKOUT FOR NOW *\n// useEffect(() => {\n// if (context.accountId && !isPotDonation && ftBalancesRes && !state.ftBalances) {\n// State.update({\n// ftBalances: ftBalancesRes.balances,\n// denominationOptions: state.denominationOptions.concat(\n// ftBalancesRes.balances\n// .map(({ amount, contract_account_id, metadata }) => ({\n// amount,\n// id: contract_account_id,\n// text: metadata.symbol,\n// value: metadata.symbol,\n// icon: metadata.icon,\n// decimals: metadata.decimals,\n// selected: false,\n// }))\n// .filter((option) => option.text.length < 10)\n// ),\n// });\n// }\n// }, [context.accountId, state.ftBalances, ftBalancesRes, isPotDonation]);\nreturn (\n <ItemContainer>\n <ItemLeft>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Checkbox\"}\n props={{\n id: \"selector-\" + projectId,\n checked,\n onClick: handleCheckboxClick,\n }}\n />\n </ItemLeft>\n <ItemRight>\n <ImageContainer>\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{\n accountId: projectId,\n style: {\n width: \"40px\",\n height: \"40px\",\n border: \"none\",\n marginRight: \"24px\",\n },\n className: \"mb-2\",\n imageClassName: \"rounded-circle w-100 h-100 d-block\",\n thumbnail: false,\n }}\n />\n </ImageContainer>\n <DetailsContainer>\n <Row>\n <Title\n href={props.hrefWithParams(`?tab=project&projectId=${projectId}`)}\n >\n {profile.name ?? \"\"}\n </Title>\n <Widget\n src={\"old.potlock.near/widget/Pots.Tag\"}\n props={{\n ...props,\n backgroundColor: isPotDonation ? \"#FEF6EE\" : \"#F6F5F3\",\n borderColor: isPotDonation\n ? \"rgba(219, 82, 27, 0.36)\"\n : \"#DBDBDB\",\n textColor: isPotDonation ? \"#EA6A25\" : \"#292929\",\n text: isPotDonation\n ? cartItem.potDetail\n ? cartItem.potDetail.pot_name\n : \"-\"\n : \"Direct Donation\",\n }}\n />\n </Row>\n <Description>{profile.description ?? \"\"}</Description>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"Amount\",\n placeholder: \"0\",\n value: itemAmount,\n onChange: (amount) => {\n amount = amount.replace(/[^\\d.]/g, \"\"); // remove all non-numeric characters except for decimal\n if (amount === \".\") amount = \"0.\";\n setItemAmount(amount);\n },\n onBlur: (e) => {\n updateItemInCart({\n ...cartItem,\n amount: e.target.value,\n });\n },\n inputStyles: {\n textAlign: \"right\",\n borderRadius: \"0px 4px 4px 0px\",\n },\n preInputChildren: (\n <Widget\n src={\"old.potlock.near/widget/Inputs.Select\"}\n props={{\n noLabel: true,\n placeholder: \"\",\n options: state.denominationOptions,\n value: { text: itemToken.text, value: itemToken.value },\n onChange: ({ text, value }) => {\n const token = state.denominationOptions.find(\n (option) => option.text === text\n );\n setItemToken(token);\n setItemAmount(undefined);\n updateCartItem({\n ...cartItem,\n token: token,\n amount: undefined,\n });\n },\n containerStyles: {\n width: \"auto\",\n },\n inputStyles: {\n border: \"none\",\n borderRight: \"1px #F0F0F0 solid\",\n boxShadow: \"none\",\n borderRadius: \"4px 0px 0px 4px\",\n width: \"auto\",\n padding: \"12px 16px\",\n boxShadow: \"0px -2px 0px rgba(93, 93, 93, 0.24) inset\",\n },\n iconLeft:\n itemToken.text == \"NEAR\" ? (\n <NearIcon />\n ) : (\n <FtIcon src={itemToken.icon} />\n ),\n }}\n />\n ),\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Cart.BreakdownSummary\"}\n props={{\n ...props,\n ftIcon: itemToken.icon,\n referrerId,\n totalAmount: itemAmount,\n bypassProtocolFee: false, // TODO: allow user to choose\n containerStyle: { marginTop: \"16px\" },\n }}\n />\n </DetailsContainer>\n </ItemRight>\n </ItemContainer>\n);\n" }, "Pots.Home": { "": "let PotFactorySDK =\n VM.require(\"old.potlock.near/widget/SDK.potfactory\") ||\n (() => ({\n getContractId: () => {},\n getConfig: () => {},\n asyncGetPots: () => {},\n canUserDeployPot: () => {},\n }));\nconst [pots, setPots] = useState(null);\nconst [inProgressRounds, setInProgressRounds] = useState([]);\nconst [filteredRounds, setFilteredRounds] = useState([]);\nconst [completedRounds, setCompletedRounds] = useState([]);\nconst [filterSelcted, setFilterSelected] = useState([]);\nconst [sortBy, setSortBy] = useState(\"\");\nPotFactorySDK = PotFactorySDK({ env: props.env });\nconst potFactoryContractId = PotFactorySDK.getContractId();\nconst potFactoryConfig = PotFactorySDK.getConfig();\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n asyncGetConfig: () => {},\n};\nconst currentDate = Date.now();\nconst filters = {\n application_not_started: (round) => currentDate < round.application_start_ms,\n application_open: (round) =>\n currentDate > round.application_start_ms &&\n currentDate < round.application_end_ms,\n application_closed: (round) => currentDate > round.application_end_ms,\n round_end: (round) => currentDate > round.public_round_end_ms,\n round_open: (round) =>\n currentDate > round.public_round_start_ms &&\n currentDate < round.public_round_end_ms,\n cooldown: (round) =>\n currentDate > round.public_round_end_ms &&\n currentDate < round.cooldown_end_ms,\n completed: (round) => round.all_paid_out,\n};\nconst filterBy = {\n \"no-label\": [\n {\n label: \"Application open\",\n val: \"application_open\",\n },\n {\n label: \"Matching round open\",\n val: \"round_open\",\n },\n {\n label: \"Application closed\",\n val: \"application_closed\",\n },\n {\n label: \"Challenge period\",\n val: \"cooldown\",\n },\n ],\n};\nconst sortOptions = {\n \"no-label\": [\n {\n label: \"Most to least in pot\",\n val: \"least_pots\",\n },\n {\n label: \"Least to most in pot\",\n val: \"most_pots\",\n },\n {\n label: \"Most to least donations\",\n val: \"most_donations\",\n },\n {\n label: \"Least to most donations\",\n val: \"least_donations\",\n },\n ],\n};\nif (!pots) {\n PotFactorySDK.asyncGetPots().then((pots) => {\n pots.forEach(({ id }) => {\n PotSDK.asyncGetConfig(id).then((potConfig) =>\n setPots((prevPot) => ({\n ...prevPot,\n [id]: { ...potConfig, id },\n }))\n );\n });\n });\n}\nconst compareFunction = (pots) => {\n const potsSort = {\n active: {\n check: filters.round_open,\n time: \"public_round_end_ms\",\n items: [],\n },\n cooldown: {\n check: filters.cooldown,\n time: \"cooldown_end_ms\",\n items: [],\n },\n application: {\n check: filters.application_open,\n time: \"application_end_ms\",\n items: [],\n },\n not_started: {\n check: filters.application_not_started,\n time: \"application_start_ms\",\n items: [],\n },\n rest: {\n check: (round) => true,\n time: \"application_start_ms\",\n items: [],\n },\n };\n // sort pots(round status)\n const listOfPots = {};\n const states = Object.keys(potsSort);\n pots.forEach((pot) => {\n Object.keys(potsSort).some((type) => {\n const { check, items } = potsSort[type];\n if (check(pot)) {\n potsSort[type].items = [...items, pot];\n return true;\n }\n });\n });\n // sort pots(time left)\n const inProgressPots = [];\n Object.values(potsSort).forEach(({ items, time }) => {\n items.sort((a, b) => a[time] - b[time]);\n inProgressPots.push(...items);\n });\n return inProgressPots;\n};\nuseEffect(() => {\n if (pots) {\n const potsVal = Object.values(pots);\n const completed = [];\n let inprogress = [];\n potsVal.forEach((round) => {\n if (filters.completed(round)) {\n completed.push(round);\n } else {\n inprogress.push(round);\n }\n });\n inprogress = compareFunction(inprogress);\n setFilteredRounds(inprogress);\n setInProgressRounds(inprogress);\n setCompletedRounds(completed);\n }\n}, [pots]);\nconst canDeploy = PotFactorySDK.canUserDeployPot(context.accountId);\nconst Title = styled.div`\n margin-bottom: 1rem;\n display: flex;\n align-items: center;\n gap: 1rem;\n font-size: 18px;\n font-weight: 600;\n .span {\n font-weight: 600;\n }\n`;\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding-bottom: 48px;\n .content {\n display: flex;\n flex-direction: column;\n width: 100%;\n padding: 0 64px;\n margin-top: 3rem;\n }\n .header {\n display: flex;\n align-items: center;\n margin-bottom: 1rem;\n .filters {\n gap: 1rem;\n display: flex;\n align-items: center;\n .sort {\n width: 286px;\n flex-direction: column;\n padding: 0.5rem;\n gap: 0;\n .title {\n display: none;\n }\n .option {\n border: none;\n width: 100%;\n padding: 0.5rem;\n }\n }\n }\n }\n @media only screen and (max-width: 768px) {\n .content {\n padding: 0 20px;\n }\n .header {\n flex-direction: column;\n align-items: flex-start;\n gap: 1rem;\n }\n }\n`;\nconst Line = styled.div`\n height: 1px;\n width: 100%;\n background: #c7c7c7;\n margin: 3rem 0;\n`;\nif (!potFactoryConfig) {\n return <div class=\"spinner-border text-secondary\" role=\"status\" />;\n}\nconst handleFilter = (selected) => {\n const selectedList = Object.values(selected)[0];\n if (selectedList.length === 0) {\n return setFilteredRounds(inProgressRounds);\n }\n const filteredRounds = [...inProgressRounds].filter((round) =>\n selectedList.some((key) => {\n return filters[key](round) === true;\n })\n );\n setFilteredRounds(filteredRounds);\n};\nconst handleSort = ({ val }) => {\n const sortedRounds = filteredRounds;\n switch (val) {\n case \"least_pots\":\n sortedRounds.sort(\n (a, b) => Big(b.matching_pool_balance) - Big(a.matching_pool_balance)\n );\n break;\n case \"most_pots\":\n sortedRounds.sort(\n (a, b) => Big(a.matching_pool_balance) - Big(b.matching_pool_balance)\n );\n break;\n case \"most_donations\":\n sortedRounds.sort(\n (a, b) => Big(b.total_public_donations) - Big(a.total_public_donations)\n );\n break;\n case \"least_donations\":\n sortedRounds.sort(\n (a, b) => Big(a.total_public_donations) - Big(b.total_public_donations)\n );\n break;\n }\n setFilteredRounds(sortedRounds);\n setSortBy(val);\n};\nreturn (\n <Container>\n <Widget\n src={\"old.potlock.near/widget/Pots.HomeBanner\"}\n props={{\n ...props,\n canDeploy,\n }}\n />\n <div className=\"content\">\n <div className=\"header\">\n <Title\n style={{\n marginRight: \"auto\",\n marginBottom: 0,\n }}\n >\n Active Pots <span>{filteredRounds.length}</span>\n </Title>\n <div className=\"filters\">\n <Widget\n src={\"old.potlock.near/widget/Inputs.FilterDropdown\"}\n props={{\n ...props,\n options: filterBy,\n onClick: handleFilter,\n multipleOptions: true,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Inputs.FilterDropdown\"}\n props={{\n ...props,\n label: \"Sort\",\n labelIcon: \"right\",\n options: sortOptions,\n onClick: handleSort,\n menuClass: \"sort\",\n }}\n />\n </div>\n </div>\n {filteredRounds.length === 0 && <div>No pots</div>}\n <Widget\n src={\"old.potlock.near/widget/Project.ListSection\"}\n props={{\n ...props,\n items: filteredRounds,\n renderItem: (pot) => (\n <Widget\n src={\"old.potlock.near/widget/Pots.Card\"}\n props={{\n ...props,\n potId: pot.id,\n }}\n />\n ),\n maxCols: 3,\n responsive: [\n {\n breakpoint: 1114,\n items: 2,\n },\n {\n breakpoint: 768,\n items: 1,\n },\n ],\n }}\n />\n <Line />\n <Title>\n Completed Pots <span>{completedRounds.length}</span>\n </Title>\n <Widget\n src={\"old.potlock.near/widget/Project.ListSection\"}\n props={{\n ...props,\n items: completedRounds,\n renderItem: (pot) => (\n <Widget\n src={\"old.potlock.near/widget/Pots.Card\"}\n props={{\n ...props,\n potId: pot.id,\n }}\n />\n ),\n maxCols: 3,\n responsive: [\n {\n breakpoint: 1114,\n items: 2,\n },\n {\n breakpoint: 768,\n items: 1,\n },\n ],\n }}\n />\n </div>\n </Container>\n);\n" }, "Pots.HeaderStatus": { "": "const { potDetail } = props;\nconst [mobileMenuActive, setMobileMenuActive] = useState(false);\nconst {\n application_start_ms,\n application_end_ms,\n public_round_start_ms,\n public_round_end_ms,\n cooldown_end_ms,\n all_paid_out,\n} = potDetail;\nconst now = Date.now();\nconst stats = [\n {\n label: \"Applications round\",\n daysLeft: application_end_ms,\n started: now >= application_start_ms,\n completed: now > application_end_ms,\n progress:\n now > application_end_ms\n ? 1\n : (now - application_start_ms) /\n (application_end_ms - application_start_ms),\n },\n {\n label: \"Matching round\",\n daysLeft: public_round_end_ms,\n started: now >= public_round_start_ms,\n completed: now > public_round_end_ms,\n progress:\n now > public_round_end_ms\n ? 1\n : (now - public_round_start_ms) /\n (public_round_end_ms - public_round_start_ms),\n },\n {\n label: \"Challenge period\",\n daysLeft: cooldown_end_ms,\n started: now >= public_round_end_ms,\n completed: now > cooldown_end_ms && !!cooldown_end_ms,\n progress:\n now > cooldown_end_ms && !!cooldown_end_ms\n ? 1\n : (cooldown_end_ms - now) / (public_round_end_ms - cooldown_end_ms),\n },\n {\n label: \"Payouts completed\",\n daysLeft: null,\n started: null,\n completed: all_paid_out,\n progress: all_paid_out ? 1 : 0,\n },\n];\nconst ProgressBar = ({ progress, completed, started }) => (\n <ProgressBarWrapper>\n <svg viewBox=\"0 0 160 160\" className=\"circle\">\n <circle\n r=\"70\"\n cx=\"80\"\n cy=\"80\"\n fill=\"transparent\"\n stroke={completed ? \"#629D13\" : started ? \"#000000\" : \"#C7C7C7\"}\n strokeWidth=\"12px\"\n ></circle>\n <circle\n r=\"70\"\n cx=\"80\"\n cy=\"80\"\n fill=\"transparent\"\n stroke=\"#C7C7C7\"\n strokeWidth=\"12px\"\n strokeDasharray=\"439.6px\"\n strokeDashoffset={439.6 * progress + \"px\"}\n ></circle>\n </svg>\n <svg\n className=\"check\"\n viewBox=\"0 0 12 9\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M3.72667 7.05333L0.946667 4.27333L0 5.21333L3.72667 8.94L11.7267 0.94L10.7867 0L3.72667 7.05333Z\"\n style={{\n fill: completed ? \"#629D13\" : started ? \"#7B7B7B\" : \"#C7C7C7\",\n }}\n />\n </svg>\n </ProgressBarWrapper>\n);\nconst getIndexOfActive = () => {\n let index;\n stats.forEach((state, idx) => {\n if (state.started && !state.completed) {\n index = idx;\n }\n });\n if (index === null) return 3;\n return index;\n};\nconst containerHeight = 181;\nconst showActiveState = getIndexOfActive() * (containerHeight / 4);\nconst Wrapper = styled.div`\n border-top: 1px solid rgb(199 199 199 / 50%);\n border-bottom: 1px solid rgb(199 199 199 / 50%);\n position: relative;\n display: flex;\n align-items: center;\n margin-top: -1px;\n pointer-events: none;\n .spread-indicator {\n height: auto;\n width: 12px;\n transition: all 300ms ease-in-out;\n display: none;\n }\n @media only screen and (max-width: 1100px) {\n pointer-events: all;\n cursor: pointer;\n .spread-indicator {\n display: block;\n }\n }\n`;\nconst Container = styled.div`\n display: flex;\n width: 100%;\n justify-content: center;\n transition: all 300ms ease-in-out;\n .mobile-selected {\n display: flex;\n justify-content: space-between;\n gap: 1rem;\n margin: 1rem 0;\n transition: all 300ms ease-in-out;\n }\n @media only screen and (max-width: 1100px) {\n justify-content: left;\n height: ${containerHeight / 4}px;\n overflow: hidden;\n .mobile-selected {\n margin: 10px 0;\n transform: translateY(${-showActiveState}px);\n flex-direction: column;\n }\n }\n`;\nconst State = styled.div`\n display: flex;\n align-items: center;\n position: relative;\n gap: 1rem;\n font-size: 14px;\n white-space: nowrap;\n color: ${(props) => (props.active ? \"#000\" : \"#7b7b7b\")};\n span {\n font-weight: 600;\n color: #dd3345;\n }\n`;\nconst Loader = styled.div`\n position: relative;\n background: #dbdbdb;\n border-radius: 1px;\n height: 4px;\n width: 130px;\n @media only screen and (max-width: 1400px) {\n width: 90px;\n }\n @media only screen and (max-width: 1100px) {\n height: 40px;\n width: 4px;\n position: absolute;\n left: 10px;\n z-index: 0;\n top: 50%;\n }\n`;\nconst ProgressBarWrapper = styled.div`\n position: relative;\n display: flex;\n .circle {\n width: 24px;\n height: 24px;\n transform: rotate(-90deg);\n }\n .check {\n width: 12px;\n position: absolute;\n transform: translate(-50%, -50%);\n top: 50%;\n left: 50%;\n }\n @media only screen and (max-width: 1100px) {\n z-index: 1;\n background: white;\n padding: 2px 0;\n }\n`;\nreturn (\n <Wrapper onClick={() => setMobileMenuActive(!mobileMenuActive)}>\n <Container\n style={\n mobileMenuActive\n ? {\n height: containerHeight + \"px\",\n }\n : {}\n }\n >\n <div\n className=\"mobile-selected\"\n style={\n mobileMenuActive\n ? {\n transform: \"translateY(0px)\",\n }\n : {}\n }\n >\n {stats.map(({ label, daysLeft, progress, started, completed }, idx) => {\n return (\n <State active={completed || started} key={timeLeft}>\n <ProgressBar\n progress={progress}\n started={started}\n completed={completed}\n />\n <div>\n {label}\n {!daysLeft && started && <span>pending </span>}\n {started && !completed && daysLeft && (\n <span>\n ends in\n <Widget\n src={\"old.potlock.near/widget/Pots.TimeLeft\"}\n props={{\n daysLeft,\n }}\n />\n </span>\n )}\n {idx === 0 && !started && \" hasn’t started\"}\n </div>\n <Loader\n style={{\n background: completed ? \"#629D13\" : \"#dbdbdb\",\n display: idx === 3 ? \"none\" : \"flex\",\n }}\n />\n </State>\n );\n })}\n </div>\n </Container>\n <svg\n className=\"spread-indicator\"\n style={{\n rotate: mobileMenuActive ? \"180deg\" : \"0deg\",\n }}\n viewBox=\"0 0 12 8\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M10.59 0.294922L6 4.87492L1.41 0.294922L0 1.70492L6 7.70492L12 1.70492L10.59 0.294922Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n </Wrapper>\n);\n" }, "Pots.Header": { "": "const {\n potDetail,\n setApplicationModalOpen,\n potId,\n applicationSuccess,\n registrationApproved,\n registryStatus,\n hrefWithParams,\n nav,\n referrerId,\n allDonations,\n} = props;\nconst {\n admins,\n chef,\n owner,\n pot_name,\n pot_description,\n registry_provider,\n matching_pool_balance,\n public_round_end_ms,\n public_round_start_ms,\n application_start_ms,\n application_end_ms,\n cooldown_end_ms,\n all_paid_out,\n} = potDetail;\nconst [isMatchingPoolModalOpen, setIsMatchingPoolModalOpen] = useState(false);\nconst [isModalDonationOpen, setIsModalDonationOpen] = useState(false);\nconst [successfulDonation, setSuccessfulDonation] = useState(null);\nconst [showChallengePayoutsModal, setShowChallengePayoutsModal] =\n useState(false);\nconst [projects, setProjects] = useState(null);\nconst [flaggedAddresses, setFlaggedAddresses] = useState(null);\nconst { IPFS_BASE_URL } = VM.require(\"old.potlock.near/widget/constants\") || {\n IPFS_BASE_URL: \"\",\n};\nconst NADABOT_ICON_URL =\n IPFS_BASE_URL + \"bafkreiecgkoybmplo4o542fphclxrhh4nlof5uit3lkzyv4eo2qymrpsru\";\nconst projectNotRegistered = registryStatus === null;\nconst userIsAdminOrGreater =\n admins.includes(context.accountId) || owner === context.accountId;\nconst userIsChefOrGreater = userIsAdminOrGreater || chef === context.accountId;\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getApplicationByProjectId: () => {},\n asyncGetApprovedApplications: () => {},\n adminProcessPayouts: () => {},\n};\nconst existingApplication = PotSDK.getApplicationByProjectId(\n potId,\n context.accountId\n);\nuseEffect(() => {\n if (!projects) {\n PotSDK.asyncGetApprovedApplications(potId).then((projects) => {\n setProjects(projects);\n });\n }\n}, []);\nconst applicationExists = existingApplication || applicationSuccess;\nconst now = Date.now();\nconst publicRoundOpen =\n now >= public_round_start_ms && now < public_round_end_ms;\nconst publicRoundEnded = now > public_round_end_ms;\nconst applicationOpen = now >= application_start_ms && now < application_end_ms;\nconst canApply = applicationOpen && !applicationExists && !userIsChefOrGreater;\nconst canPayoutsBeSet =\n userIsChefOrGreater && !all_paid_out && publicRoundEnded;\nconst canPayoutsBeProcessed =\n userIsAdminOrGreater && now >= cooldown_end_ms && !all_paid_out;\nconst { NADA_BOT_URL } = VM.require(\"old.potlock.near/widget/constants\") || {\n NADA_BOT_URL: \"\",\n};\nconst { yoctosToNear, yoctosToUsdWithFallback, nearToUsd, calculatePayouts } =\n VM.require(\"old.potlock.near/widget/utils\") || {\n calculatePayouts: () => {},\n yoctosToNear: () => \"\",\n nearToUsd: 1,\n yoctosToUsdWithFallback: () => \"\",\n };\nconst potLink = `https://bos.potlock.io/?tab=pot&potId=${potId}${\n context.accountId && `&referrerId=${context.accountId}`\n}`;\nconst Container = styled.div`\n display: flex;\n flex-wrap: wrap;\n gap: 2rem;\n padding: 64px 4rem 80px;\n .pool-table {\n max-width: 514px;\n width: 100%;\n }\n @media only screen and (max-width: 1068px) {\n flex-direction: column;\n .pool-table {\n margin: auto;\n }\n }\n @media only screen and (max-width: 768px) {\n padding: 3rem 0;\n .pool-table {\n max-width: 100%;\n }\n }\n`;\nconst Header = styled.div`\n display: flex;\n flex-direction: column;\n gap: 24px;\n flex: 1;\n`;\nconst Title = styled.div`\n font-size: 40px;\n font-weight: 500;\n font-family: \"Lora\";\n`;\nconst Description = styled.div`\n max-width: 498px;\n line-height: 1.5em;\n a {\n color: #7b7b7b;\n font-weight: 600;\n }\n`;\nconst Fund = styled.div`\n display: flex;\n flex-direction: column;\n gap: 8px;\n > div {\n display: flex;\n gap: 8px;\n align-items: baseline;\n div {\n font-weight: 600;\n }\n }\n .near-price {\n font-size: 24px;\n }\n`;\nconst ButtonsWrapper = styled.div`\n display: flex;\n flex-wrap: wrap;\n gap: 2rem;\n a,\n button {\n width: 180px;\n padding: 16px;\n }\n @media only screen and (max-width: 480px) {\n flex-direction: column;\n gap: 1rem;\n a,\n button {\n width: 100%;\n }\n }\n`;\nconst Referral = styled.div`\n font-size: 14px;\n gap: 12px;\n display: flex;\n align-items: center;\n`;\nconst payoutsChallenges = PotSDK.getPayoutsChallenges(potId);\nif (!flaggedAddresses) {\n PotSDK.getFlaggedAccounts(potDetail, potId)\n .then((data) => {\n const listOfFlagged = [];\n data.forEach((adminFlaggedAcc) => {\n const addresses = Object.keys(adminFlaggedAcc.potFlaggedAcc);\n listOfFlagged.push(...addresses);\n });\n setFlaggedAddresses(listOfFlagged);\n })\n .catch((err) => console.log(\"error getting the flagged accounts \", err));\n}\nconst handleSetPayouts = () => {\n if (allDonations && flaggedAddresses !== null) {\n calculatePayouts(\n allDonations,\n matching_pool_balance,\n flaggedAddresses\n ).then((calculatedPayouts) => {\n const payouts = Object.entries(calculatedPayouts)\n .map(([projectId, { matchingAmount }]) => ({\n project_id: projectId,\n amount: matchingAmount,\n }))\n .filter((payout) => payout.amount !== \"0\");\n PotSDK.chefSetPayouts(potId, payouts);\n });\n } else {\n console.log(\"error fetching donations or flagged addresses\");\n }\n};\nconst handleProcessPayouts = () => {\n PotSDK.adminProcessPayouts(potId);\n // NB: we won't get here if user used a web wallet, as it will redirect to the wallet\n // <---- EXTENSION WALLET HANDLING ----> // TODO: implement\n};\nconst existingChallengeForUser = (payoutsChallenges || []).find(\n (challenge) => challenge.challenger_id === context.accountId\n);\nconst canDonate = context.accountId && projects.length > 0;\nreturn (\n <Container>\n <Header>\n <Title>{pot_name}</Title>\n <Description>\n <Markdown text={pot_description} />\n </Description>\n <Fund>\n <div className=\"label\">Matching Funds Available:</div>\n <div>\n <div className=\"near-price\">\n {yoctosToNear(matching_pool_balance, true)}\n </div>\n {nearToUsd && (\n <div lassName=\"usd-price\">\n {\" \"}\n {yoctosToUsdWithFallback(matching_pool_balance, true)}\n </div>\n )}\n </div>\n </Fund>\n <ButtonsWrapper>\n {publicRoundOpen && context.accountId && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: canDonate ? \"Donate\" : \"Verify to Donate\",\n href: canDonate ? null : NADA_BOT_URL,\n onClick: canDonate\n ? () => {\n setIsModalDonationOpen(true);\n }\n : null,\n target: canDonate ? \"_self\" : \"_blank\",\n iconSrc: canDonate ? null : NADABOT_ICON_URL,\n }}\n />\n )}\n {now < public_round_end_ms && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"secondary\",\n text: \"Fund matching pool\",\n onClick: () => setIsMatchingPoolModalOpen(true),\n }}\n />\n )}\n {applicationOpen && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type:\n registrationApproved || projectNotRegistered\n ? \"primary\"\n : \"tertiary\",\n text:\n registryStatus && !registrationApproved\n ? `Project Registration ${registryStatus}`\n : \"Apply to pot\",\n style: { marginRight: \"24px\" },\n disabled: registryStatus && !registrationApproved,\n onClick: () => setApplicationModalOpen(true),\n }}\n />\n )}\n {now > public_round_end_ms && now < cooldown_end_ms && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"secondary\",\n existingChallengeForUser,\n text: existingChallengeForUser\n ? \"Update challenge\"\n : \"Challenge payouts\",\n onClick: () => setShowChallengePayoutsModal(true),\n }}\n />\n )}\n {canPayoutsBeSet && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n ...props,\n text: \"Set Payouts\",\n onClick: handleSetPayouts,\n }}\n />\n )}\n {canPayoutsBeProcessed && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n ...props,\n type: \"primary\",\n text: \"Process Payouts\",\n onClick: handleProcessPayouts,\n }}\n />\n )}\n </ButtonsWrapper>\n <Referral>\n <Widget\n src={\"old.potlock.near/widget/Project.CopyIcon\"}\n props={{\n textToCopy: potLink,\n }}\n />\n Earn referral fees\n </Referral>\n </Header>\n <div className=\"pool-table\">\n <Widget\n src={\"old.potlock.near/widget/Pots.PoolAllocationTable\"}\n props={props}\n />\n </div>\n <Widget\n src={\"old.potlock.near/widget/Pots.FundModal\"}\n props={{\n ...props,\n isMatchingPoolModalOpen,\n onClose: () => setIsMatchingPoolModalOpen(false),\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Pots.ChallengeModal\"}\n props={{\n ...props,\n showChallengePayoutsModal,\n onCancel: () => setShowChallengePayoutsModal(false),\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/ModalDonation.Main\"}\n loading={\"\"}\n props={{\n ...props,\n isModalOpen: isModalDonationOpen,\n onClose: () => setIsModalDonationOpen(false),\n potId,\n potDetail,\n projects,\n referrerId,\n multiple: true,\n openDonationModalSuccess: (donation) => {\n setIsModalDonationOpen(false);\n setSuccessfulDonation(donation);\n },\n }}\n />\n {successfulDonation && (\n <Widget\n src={\"old.potlock.near/widget/Project.ModalSuccess\"}\n props={{\n ...props,\n successfulDonation: successfulDonation,\n isModalOpen: successfulDonation != null,\n onClose: () => setSuccessfulDonation(null),\n }}\n />\n )}\n </Container>\n);\n" }, "Components.DonorsCards": { "": "const { sponsors, sortedDonations, currentTab } = props;\nconst donations = currentTab === \"sponsors\" ? sponsors : sortedDonations;\nconst { nearToUsdWithFallback } = VM.require(\n \"old.potlock.near/widget/utils\"\n) || {\n nearToUsdWithFallback: () => \"\",\n};\nconst { _address } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n);\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n box-shadow: 0px 2px 4px #00000081;\n width: 100%;\n position: relative;\n padding-bottom: 1rem;\n font-size: 14px;\n .name {\n font-weight: bold;\n color: var(--primary-color);\n }\n .description {\n color: #b3b3b3;\n }\n .tag {\n position: absolute;\n right: 4px;\n top: 4px;\n background: white;\n border-radius: 2px;\n width: 2rem;\n height: 2rem;\n display: flex;\n align-items: center;\n justify-content: center;\n img {\n width: 18px;\n height: auto;\n }\n }\n .background {\n height: 100px;\n width: 100%;\n }\n .profile {\n position: relative;\n transform: translateY(-50%);\n width: 4rem;\n height: 4rem;\n border-radius: 50%;\n }\n .amount {\n margin-top: 1rem;\n border: 1px solid #b3b3b3;\n padding: 4px;\n border-radius: 4px;\n }\n`;\nconst Card = ({ donor }) => {\n const { id, rank, className, amount } = donor;\n const profile = Social.getr(`${id}/profile`);\n return (\n <div key={donation} className={className || \"\"}>\n <Container>\n {profile === null ? (\n <div class=\"spinner-border text-secondary\" role=\"status\" />\n ) : (\n <>\n <Widget\n src=\"mob.near/widget/Image\"\n props={{\n image: profile.backgroundImage,\n className: \"background\",\n alt: profile.name,\n fallbackUrl:\n \"https://ipfs.near.social/ipfs/bafkreidla73cknxbeovrhgb2blax2j2qgcgcn6ibluzza3buq2mbkoqs2e\",\n }}\n />\n <div className=\"tag\">{rank}</div>\n <Widget\n src=\"mob.near/widget/Image\"\n props={{\n image: profile.image,\n className: \"profile\",\n alt: profile.name,\n fallbackUrl:\n \"https://ipfs.near.social/ipfs/bafkreiccpup6f2kihv7bhlkfi4omttbjpawnsns667gti7jbhqvdnj4vsm\",\n }}\n />\n <a\n href={props.hrefWithParams(`?tab=profile&accountId=${id}`)}\n className=\"name\"\n target=\"_blank\"\n >\n {_address(profile.name ? profile.name : id)}\n </a>\n <div className=\"description\">\n {profile.description ? _address(profile.description, 20) : \"-\"}\n </div>\n <div className=\"amount\">\n {nearToUsdWithFallback(amount)} Donated\n </div>\n </>\n )}\n </Container>\n </div>\n );\n};\nconst leaderboard = [\n {\n rank: \"#2\",\n id: donations[1].donor_id,\n amount: donations[1].amount,\n },\n {\n rank: (\n <img\n src=\"https://ipfs.near.social/ipfs/bafkreicjk6oy6465ps32owoomppfkvimbjlnhbaldvf6ujuyhkjas6ghjq\"\n alt=\"top\"\n />\n ),\n id: donations[0].donor_id,\n className: \"top\",\n amount: donations[0].amount,\n },\n {\n rank: \"#3\",\n id: donations[2].donor_id,\n amount: donations[2].amount,\n },\n];\nreturn (\n <div className=\"cards\">\n {leaderboard.map((donor) => (donor.id ? <Card donor={donor} /> : \"\"))}\n </div>\n);\n" }, "Components.InfoSegment": { "": "const title = props.title;\nconst description = props.description;\nconst icon = (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M10.0001 13.3327V9.99935M10.0001 6.66602H10.0084M18.3334 9.99935C18.3334 14.6017 14.6025 18.3327 10.0001 18.3327C5.39771 18.3327 1.66675 14.6017 1.66675 9.99935C1.66675 5.39698 5.39771 1.66602 10.0001 1.66602C14.6025 1.66602 18.3334 5.39698 18.3334 9.99935Z\"\n stroke=\"#475467\"\n stroke-width=\"1.66667\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n);\nconst Container = styled.div`\n box-sizing: border-box;\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n padding: 1em;\n gap: 0.75em;\n background: #fcfcfd;\n border: 1px solid #d0d5dd;\n border-radius: 4px;\n width: 100%;\n`;\nconst Text = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n padding: 0px;\n gap: 0.75em;\n`;\nconst Heading = styled.div`\n font-style: normal;\n font-weight: 600;\n font-size: 0.95em;\n line-height: 1.25em;\n color: #344054;\n`;\nconst Description = styled.p`\n font-style: normal;\n font-weight: 400;\n font-size: 0.95em;\n line-height: 1.25em;\n color: #475467;\n white-space: wrap;\n margin: 0px;\n`;\nreturn (\n <Container>\n {icon}\n <Text>\n <Heading>{title}</Heading>\n <Description>{description}</Description>\n </Text>\n </Container>\n);\n" }, "Pots.DonationsTable": { "": "const Container = styled.div`\n display: flex;\n flex-direction: column;\n width: 100%;\n margin-top: 24px;\n padding-bottom: 1rem;\n border-radius: 6px;\n border: 1px solid #7b7b7b;\n align-items: center;\n gap: 2rem;\n .transcation {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-size: 14px;\n }\n .header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.5rem 1rem;\n gap: 2rem;\n color: #292929;\n border-bottom: 1px solid rgba(199, 199, 199, 0.5);\n div {\n width: 100px;\n display: flex;\n justify-content: center;\n align-items: center;\n font-weight: 600;\n &.sort {\n cursor: pointer;\n gap: 8px;\n svg {\n transition: rotate 300ms;\n }\n }\n }\n .price {\n width: 70px;\n margin-right: 5rem;\n }\n }\n .address {\n /* width: 143px !important; */\n flex: 1;\n justify-content: flex-start !important;\n }\n @media only screen and (max-width: 992px) {\n .header .price {\n margin-right: 0;\n }\n }\n @media only screen and (max-width: 768px) {\n .header {\n display: none;\n }\n }\n`;\nconst SearchBarContainer = styled.div`\n display: flex;\n align-items: center;\n gap: 1rem;\n width: 100%;\n font-size: 14px;\n background: #f6f5f3;\n padding: 0.5rem 1rem;\n @media only screen and (max-width: 780px) {\n gap: 0.5rem;\n }\n`;\nconst SearchBar = styled.input`\n background: none;\n width: 100%;\n outline: none;\n border: none;\n &:focus {\n outline: none;\n border: none;\n }\n`;\nconst SearchIcon = styled.div`\n display: flex;\n width: 24px;\n height: 24px;\n align-items: center;\n justify-content: center;\n`;\nconst TrRow = styled.div`\n display: flex;\n width: 100%;\n justify-content: space-between;\n gap: 2rem;\n padding: 1rem;\n border-top: 1px solid rgb(199 199 199 / 50%);\n > div {\n width: 100px;\n display: flex;\n justify-content: center;\n align-items: center;\n }\n .price {\n display: flex;\n gap: 1rem;\n align-items: center;\n font-weight: 600;\n width: 74px;\n margin-right: 5rem;\n justify-content: flex-start;\n span {\n display: none;\n }\n img {\n width: 1.125rem;\n }\n }\n .address {\n position: relative;\n color: #292929;\n display: flex;\n align-items: center;\n justify-content: flex-start;\n border-radius: 2px;\n transition: all 200ms;\n font-weight: 600;\n .profile-image {\n width: 1.5rem;\n height: 1.5rem;\n margin-right: 1rem;\n }\n :hover {\n text-decoration: none;\n .flag {\n opacity: 1;\n pointer-events: all;\n }\n }\n }\n .project-mobile-view {\n position: relative;\n width: fit-content;\n color: #7b7b7b;\n border-radius: 14px;\n padding: 4px 6px;\n border: 1px solid var(--Neutral-200, #dbdbdb);\n background: var(--Neutral-100, #ebebeb);\n cursor: pointer;\n display: none;\n align-items: center;\n gap: 0.5rem;\n margin-left: 4px;\n .profile-image {\n width: 1.125rem;\n height: 1.125rem;\n display: flex !important;\n }\n .flag {\n left: -50%;\n .tip-icon {\n padding-left: 50%;\n }\n }\n :hover {\n text-decoration: none;\n .flag {\n opacity: 1;\n pointer-events: all;\n }\n }\n @media only screen and (max-width: 768px) {\n display: flex;\n }\n }\n .date span {\n display: none;\n }\n @media only screen and (max-width: 992px) {\n .price {\n margin-right: 0;\n }\n }\n @media only screen and (max-width: 768px) {\n flex-wrap: wrap;\n .project {\n display: none !important;\n }\n .price {\n min-width: 120px;\n gap: 8px;\n width: fit-content;\n justify-content: flex-start;\n span {\n display: inline-block;\n }\n }\n .date {\n width: 100%;\n justify-content: start;\n gap: 4px;\n span {\n display: inline;\n }\n }\n .address .profile-image {\n margin-right: 0.5rem;\n }\n }\n`;\nconst Flag = styled.div`\n display: flex;\n align-content: center;\n gap: 12px;\n margin-left: auto;\n opacity: 0;\n pointer-events: none;\n font-weight: 500;\n transition: 300ms ease-in-out;\n @media only screen and (max-width: 992px) {\n opacity: 1;\n div {\n display: none;\n }\n }\n @media only screen and (max-width: 768px) {\n margin-left: 0.5rem;\n }\n`;\nconst FlagTooltipWrapper = styled.div`\n position: absolute;\n display: flex;\n flex-direction: column;\n opacity: 0;\n pointer-events: none;\n transition: all 300ms ease 0s;\n top: 100%;\n background: white;\n z-index: 1;\n box-shadow: 0px 0px 1px 0px rgba(41, 41, 41, 0.74),\n 0px 3px 3px 0px rgba(123, 123, 123, 0.12),\n 0px 6px 6px 0px rgba(123, 123, 123, 0.12);\n border-radius: 4px;\n padding: 1rem;\n max-width: 550px;\n width: max-content;\n margin-top: 8px;\n cursor: default;\n .content {\n display: flex;\n gap: 1rem;\n .content-info {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n }\n .profile-image {\n width: 1.5rem;\n height: 1.5rem;\n margin-right: 0;\n }\n .title {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n .role {\n font-weight: 600;\n color: #7b7b7b;\n }\n .dot {\n width: 5px;\n height: 5px;\n background: #7b7b7b;\n border-radius: 50%;\n }\n .admin {\n font-weight: 600;\n display: flex;\n gap: 4px;\n }\n .text {\n color: #7b7b7b;\n }\n .flaged {\n color: #ed464f;\n font-weight: 600;\n &:hover {\n text-decoration: none;\n }\n }\n }\n .tip-icon {\n display: flex;\n z-index: 1;\n position: absolute;\n top: 0;\n height: 8px;\n transform: translateY(-100%);\n width: 100%;\n justify-content: flex-start;\n left: 0;\n padding-left: 2.5rem;\n svg {\n stroke: rgb(41 41 41 / 21%);\n }\n }\n @media only screen and (max-width: 768px) {\n width: 300px;\n padding: 0.5rem;\n font-size: 12px;\n .content .profile-image {\n display: none !important;\n }\n }\n`;\nconst accountId = context.accountId;\nconst FlagBtn = ({ isFlagged, isProject, address }) =>\n isFlagged && accountId === isFlagged.flaggedBy ? (\n <Flag className=\"flag\" onClick={(e) => handleFlag(e, address, isFlagged)}>\n <svg\n width=\"16\"\n height=\"18\"\n viewBox=\"0 0 16 18\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M7.86 2.5L8.26 4.5H13.5V10.5H10.14L9.74 8.5H2.5V2.5H7.86ZM9.5 0.5H0.5V17.5H2.5V10.5H8.1L8.5 12.5H15.5V2.5H9.9L9.5 0.5Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n <div>Unflag {isProject ? \"project\" : \"donor\"}</div>\n </Flag>\n ) : (\n <Flag className=\"flag\" onClick={(e) => handleFlag(e, address, isFlagged)}>\n <svg\n width=\"16\"\n height=\"18\"\n viewBox=\"0 0 16 18\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M7.86 2.5L8.26 4.5H13.5V10.5H10.14L9.74 8.5H2.5V2.5H7.86ZM9.5 0.5H0.5V17.5H2.5V10.5H8.1L8.5 12.5H15.5V2.5H9.9L9.5 0.5Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n <div>Flag {isProject ? \"project\" : \"donor\"}</div>\n </Flag>\n );\nconst Arrow = (props) => (\n <svg\n {...props}\n style={{ rotate: !props.active ? \"0deg\" : \"180deg\" }}\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M0 6L1.0575 7.0575L5.25 2.8725V12H6.75V2.8725L10.935 7.065L12 6L6 0L0 6Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n);\nconst ProfileImg = ({ address }) => (\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{ accountId: address, style: {} }}\n />\n);\nconst FlagTooltip = ({ flag, href, address }) => (\n <FlagTooltipWrapper className=\"flag\" onClick={(e) => e.preventDefault()}>\n <div className=\"tip-icon\">\n <svg\n width=\"12\"\n height=\"8\"\n viewBox=\"0 0 12 8\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 5.24537e-07L-2.54292e-07 8L12 8L6 5.24537e-07Z\"\n fill=\"white\"\n />\n </svg>\n </div>\n <div className=\"content\">\n <ProfileImg address={flag.flaggedBy} />\n <div className=\"content-info\">\n <div className=\"title\">\n <div className=\"role\">{flag.role}</div>\n <div className=\"dot\" />\n <div className=\"admin\">\n {_address(flag.flaggedBy)} has flagged\n <a\n href={href}\n className=\"flaged\"\n target=\"_blank\"\n onClick={(e) => e.stopPropagation()}\n >\n {_address(address)}\n </a>\n </div>\n </div>\n <div className=\"text\">{flag.potFlaggedAcc[address]}</div>\n </div>\n </div>\n </FlagTooltipWrapper>\n);\nconst AddressItem = ({ href, address, isFlagged, isProject, className }) => (\n <a\n href={href}\n className={className}\n target=\"_blank\"\n onClick={(e) => {\n isFlagged ? e.preventDefault() : null;\n }}\n >\n <ProfileImg address={address} />\n <div\n style={{\n color: isFlagged ? \"#ed464f\" : \"#292929\",\n fontWeight: \"600\",\n }}\n >\n {_address(address)}\n </div>\n {isFlagged && (\n <FlagTooltip flag={isFlagged} href={href} address={address} />\n )}\n {hasAuthority && (\n <FlagBtn\n isProject={isProject}\n className=\"flag\"\n address={address}\n isFlagged={isFlagged}\n />\n )}\n </a>\n);\nconst { getTimePassed, _address, calcNetDonationAmount } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n);\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getFlaggedAccounts: () => {},\n};\nconst {\n filteredDonations,\n filter,\n handleSearch,\n sortDonation,\n currentFilter,\n hrefWithParams,\n potDetail,\n potId,\n} = props;\nconst { admins, owner, chef, all_paid_out } = potDetail;\nconst nearLogo =\n \"https://ipfs.near.social/ipfs/bafkreicdcpxua47eddhzjplmrs23mdjt63czowfsa2jnw4krkt532pa2ha\";\nconst [currentPage, setCurrentPage] = useState(1);\nconst [flagAddress, setFlagAddress] = useState(null);\nconst [successFlag, setSuccessFlag] = useState(null);\nconst [updateFlaggedAddresses, setUpdateFlaggedAddresses] = useState(false);\nconst [flaggedAddresses, setFlaggedAddresses] = useState([]);\nconst perPage = 30; // need to be less than 50\nuseEffect(() => {\n setCurrentPage(1);\n}, [filter]);\nuseEffect(() => {\n PotSDK.getFlaggedAccounts(potDetail, potId)\n .then((data) => setFlaggedAddresses(data))\n .catch((err) => console.log(\"error getting the flagged accounts \", err));\n}, [successFlag, updateFlaggedAddresses]);\nconst handleFlag = (e, address, isFlagged) => {\n e.preventDefault();\n if (isFlagged) {\n // remove flagged account\n // get latest pLBlacklistedAccounts updates\n Near.asyncView(\"social.near\", \"get\", {\n keys: [`${accountId}/profile/**`],\n }).then((profileData) => {\n const profile = profileData[accountId].profile;\n const pLBlacklistedAccounts = JSON.parse(\n profile.pLBlacklistedAccounts || \"{}\"\n );\n const potFlaggedAcc = pLBlacklistedAccounts[potId] || {};\n delete potFlaggedAcc[address];\n const socialArgs = {\n data: {\n [accountId]: {\n profile: {\n pLBlacklistedAccounts: JSON.stringify({\n ...pLBlacklistedAccounts,\n [potId]: {\n ...potFlaggedAcc,\n },\n }),\n },\n },\n },\n };\n const depositFloat = JSON.stringify(socialArgs).length * 0.00015;\n const socialTransaction = {\n contractName: \"social.near\",\n methodName: \"set\",\n args: socialArgs,\n deposit: Big(depositFloat).mul(Big(10).pow(24)),\n };\n Near.call(socialTransaction);\n // update flaggedAddresses\n // TODO: check if it is successful before the update\n setTimeout(() => {\n setUpdateFlaggedAddresses(!updateFlaggedAddresses);\n }, 3000);\n });\n } else {\n // open flagModal\n setFlagAddress(address);\n }\n};\nconst potAdmins = [owner, chef, ...admins];\nconst hasAuthority = potAdmins.includes(accountId) && !all_paid_out;\nconst checkIfIsFlagged = (address) =>\n flaggedAddresses.find((obj) => obj.potFlaggedAcc[address]);\nreturn (\n <Container>\n <div className=\"transcation\">\n <div className=\"header\">\n <div\n className=\"address\"\n onClick={() => {\n setSuccessFlag({\n address: \"re.near\",\n reason: \"test tEST Tetset\",\n });\n }}\n >\n Donor\n </div>\n <div className=\"address\">Project</div>\n <div className=\"sort price\" onClick={() => sortDonation(\"price\")}>\n Amount\n {currentFilter === \"price\" && <Arrow active={filter.price} />}\n </div>\n <div className=\"sort\" onClick={() => sortDonation(\"date\")}>\n Date\n {currentFilter === \"date\" && <Arrow active={!filter.date} />}\n </div>\n </div>\n <SearchBarContainer>\n <SearchIcon>\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M15.7549 14.2549H14.9649L14.6849 13.9849C15.6649 12.8449 16.2549 11.3649 16.2549 9.75488C16.2549 6.16488 13.3449 3.25488 9.75488 3.25488C6.16488 3.25488 3.25488 6.16488 3.25488 9.75488C3.25488 13.3449 6.16488 16.2549 9.75488 16.2549C11.3649 16.2549 12.8449 15.6649 13.9849 14.6849L14.2549 14.9649V15.7549L19.2549 20.7449L20.7449 19.2549L15.7549 14.2549ZM9.75488 14.2549C7.26488 14.2549 5.25488 12.2449 5.25488 9.75488C5.25488 7.26488 7.26488 5.25488 9.75488 5.25488C12.2449 5.25488 14.2549 7.26488 14.2549 9.75488C14.2549 12.2449 12.2449 14.2549 9.75488 14.2549Z\"\n fill=\"#C7C7C7\"\n />\n </svg>\n </SearchIcon>\n <SearchBar placeholder=\"Search donations\" onChange={handleSearch} />\n </SearchBarContainer>\n {filteredDonations.length > 0 ? (\n filteredDonations\n .slice((currentPage - 1) * perPage, currentPage * perPage)\n .map((donation) => {\n const {\n donor_id,\n recipient_id,\n donated_at_ms,\n donated_at,\n project_id,\n } = donation;\n const projectId = recipient_id || project_id;\n const isDonorFlagged = checkIfIsFlagged(donor_id);\n const isProjectFlagged = checkIfIsFlagged(projectId);\n const projectHref = hrefWithParams(\n `?tab=project&projectId=${projectId}`\n );\n const profileHref = hrefWithParams(\n `?tab=profile&accountId=${donor_id}`\n );\n return (\n <TrRow>\n {/* Donor */}\n <AddressItem\n address={donor_id}\n isFlagged={isDonorFlagged}\n href={profileHref}\n isProject={false}\n className=\"address\"\n />\n {/* Project */}\n <AddressItem\n address={projectId}\n isFlagged={isProjectFlagged}\n href={projectHref}\n isProject={true}\n className=\"address project\"\n />\n <div className=\"price\">\n <span>Donated</span>\n <img src={nearLogo} alt=\"NEAR\" />\n {calcNetDonationAmount(donation).toFixed(2)}\n </div>\n <div className=\"date\">\n {getTimePassed(donated_at_ms || donated_at)} ago{\" \"}\n <span> to </span>\n <AddressItem\n address={projectId}\n isFlagged={isProjectFlagged}\n href={projectHref}\n isProject={true}\n className=\"project-mobile-view\"\n />\n </div>\n </TrRow>\n );\n })\n ) : (\n <TrRow>No donations</TrRow>\n )}\n </div>\n <Widget\n src={\"old.potlock.near/widget/Components.Pagination\"}\n props={{\n onPageChange: (page) => {\n setCurrentPage(page);\n },\n data: filteredDonations,\n currentPage,\n perPage: perPage,\n bgColor: \"#292929\",\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Pots.FlagModal\"}\n props={{\n ...props,\n flagAddress: flagAddress,\n isModalOpen: flagAddress != null,\n setSuccessFlag,\n onClose: () => setFlagAddress(null),\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Pots.FlagSuccessModal\"}\n props={{\n ...props,\n successFlag: successFlag,\n isModalOpen: successFlag != null,\n onClose: () => setSuccessFlag(null),\n }}\n />\n </Container>\n);\n" }, "Pots.FlaggedAccounts": { "": "const PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getFlaggedAccounts: () => {},\n};\nconst Line = styled.div`\n width: 100%;\n height: 1px;\n background: #c7c7c7;\n margin: 3rem 0;\n`;\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n width: 100%;\n`;\nconst Title = styled.div`\n font-size: 18px;\n display: flex;\n align-items: center;\n gap: 1.5rem;\n width: fit-content;\n cursor: pointer;\n margin-bottom: 1.5rem;\n div:first-of-type {\n font-weight: 600;\n }\n svg {\n rotate: 180deg;\n transition: all 300ms ease-in-out;\n }\n`;\nconst Table = styled.div`\n display: flex;\n flex-direction: column;\n width: 100%;\n border-radius: 6px;\n border: 1px solid #7b7b7b;\n transition: max-height 400ms ease-in-out;\n overflow: hidden;\n overflow-y: scroll;\n max-height: 1000px;\n opacity: 1;\n &.hidden {\n opacity: 0;\n max-height: 0;\n }\n`;\nconst Flag = styled.div`\n display: flex;\n padding: 1rem;\n border-bottom: 1px solid #c7c7c7;\n font-size: 14px;\n &:last-of-type {\n border-bottom: none;\n }\n .profile-image {\n width: 1.5rem;\n height: 1.5rem;\n margin-right: 0.5rem;\n }\n .content {\n display: flex;\n flex-direction: column;\n }\n .header {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.5rem;\n }\n .id {\n font-weight: 600;\n color: #292929;\n a {\n transition: 200ms;\n font-weight: 600;\n color: #292929;\n :hover {\n text-decoration: none;\n color: #dd3345;\n }\n }\n }\n .flagged-account {\n color: #ed464f;\n font-weight: 600;\n :hover {\n text-decoration: none;\n }\n }\n .role {\n color: #656565;\n font-weight: 600;\n }\n .reason {\n color: #656565;\n margin-top: 0.5rem;\n margin-bottom: 1rem;\n padding-left: 2.5rem;\n background: white;\n }\n .dot {\n background: #656565;\n width: 5px;\n height: 5px;\n border-radius: 50%;\n }\n @media only screen and (max-width: 480px) {\n .profile-image {\n margin-right: 0;\n }\n .reason {\n padding-left: 2rem;\n }\n }\n`;\nconst ProfileImg = ({ address }) => (\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{ accountId: address, style: {} }}\n />\n);\nconst { potId, hrefWithParams, potDetail } = props;\nconst [flaggedAddresses, setFlaggedAddresses] = useState(null);\nconst [toggleView, setToggleView] = useState(null);\nif (!flaggedAddresses) {\n PotSDK.getFlaggedAccounts(potDetail, potId)\n .then((data) => {\n const listOfFlagged = [];\n data.forEach((adminFlaggedAcc) => {\n const addresses = Object.keys(adminFlaggedAcc.potFlaggedAcc);\n addresses.forEach((address) => {\n listOfFlagged.push({\n address: address,\n reason: adminFlaggedAcc.potFlaggedAcc[address],\n flaggedBy: adminFlaggedAcc.flaggedBy,\n role: adminFlaggedAcc.role,\n });\n });\n });\n setFlaggedAddresses(listOfFlagged);\n })\n .catch((err) => console.log(\"error getting the flagged accounts \", err));\n}\nreturn !flaggedAddresses ? (\n \"Loading...\"\n) : flaggedAddresses.length === 0 ? (\n \"\"\n) : (\n <>\n <Container>\n <Title onClick={() => setToggleView(!toggleView)}>\n <div>Flagged Accounts</div>\n <div>{flaggedAddresses?.length}</div>\n <svg\n width=\"12\"\n height=\"8\"\n viewBox=\"0 0 12 8\"\n style={{\n rotate: toggleView ? \"0deg\" : \"180deg\",\n }}\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 0.294922L0 6.29492L1.41 7.70492L6 3.12492L10.59 7.70492L12 6.29492L6 0.294922Z\"\n fill=\"#151A23\"\n />\n </svg>\n </Title>\n <Table className={`${!toggleView ? \"hidden\" : \"\"}`}>\n {flaggedAddresses.map(({ role, flaggedBy, address, reason }) => (\n <Flag key={flaggedBy}>\n {/* <div className=\"vertical-line\" /> */}\n <div className=\"content\">\n <div className=\"header\">\n <ProfileImg address={flaggedBy} />\n <div className=\"role\">{role}</div>\n <div className=\"dot\" />\n <div className=\"id\">\n <a\n href={hrefWithParams(`?tab=profile&accountId=${flaggedBy}`)}\n target=\"_blank\"\n >\n {flaggedBy}{\" \"}\n </a>\n has flagged\n </div>\n <a\n className=\"flagged-account\"\n href={hrefWithParams(`?tab=profile&accountId=${address}`)}\n target=\"_blank\"\n >\n {address}\n </a>\n </div>\n <div className=\"reason\">{reason}</div>\n </div>\n </Flag>\n ))}\n </Table>\n </Container>\n <Line />\n </>\n);\n" }, "Components.Icons.Volunteer": { "": "const Volunteer = () => {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 18 18\"\n fill=\"none\"\n >\n <path\n d=\"M12.375 9.5625C14.6925 7.455 16.875 5.4825 16.875 3.7875C16.875 2.4 15.7875 1.3125 14.4 1.3125C13.62 1.3125 12.8625 1.68 12.375 2.25C11.88 1.68 11.13 1.3125 10.35 1.3125C8.9625 1.3125 7.875 2.4 7.875 3.7875C7.875 5.4825 10.0575 7.455 12.375 9.5625ZM10.35 2.8125C10.68 2.8125 11.0175 2.97 11.235 3.225L12.375 4.5675L13.515 3.225C13.7325 2.97 14.07 2.8125 14.4 2.8125C14.955 2.8125 15.375 3.2325 15.375 3.7875C15.375 4.6275 13.845 6.165 12.375 7.53C10.905 6.165 9.375 4.62 9.375 3.7875C9.375 3.2325 9.795 2.8125 10.35 2.8125Z\"\n fill=\"#DBDBDB\"\n />\n <path\n d=\"M14.625 11.8125H13.125C13.125 10.9125 12.5625 10.1025 11.7225 9.7875L7.1025 8.0625H1.125V16.3125H5.625V15.2325L10.875 16.6875L16.875 14.8125V14.0625C16.875 12.8175 15.87 11.8125 14.625 11.8125ZM2.625 14.8125V9.5625H4.125V14.8125H2.625ZM10.8525 15.12L5.625 13.6725V9.5625H6.8325L11.1975 11.19C11.4525 11.2875 11.625 11.535 11.625 11.8125C11.625 11.8125 10.1325 11.775 9.9 11.7L8.115 11.1075L7.6425 12.5325L9.4275 13.125C9.81 13.2525 10.2075 13.32 10.6125 13.32H14.625C14.9175 13.32 15.18 13.4925 15.3 13.74L10.8525 15.12Z\"\n fill=\"#DBDBDB\"\n />\n </svg>\n );\n};\nreturn { Volunteer };\n" }, "Components.NavOptions": { "": "const { navOptions } = props;\nconst getSelectedNavOption = () => {\n const navOption = navOptions.find((option) => option.id == props.nav);\n return navOption ?? navOptions[0];\n};\nconst NavOptionsContainer = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n gap: 8px;\n width: 100%;\n margin-bottom: 32px;\n`;\nconst NavOptionContainer = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n`;\nconst NavOption = styled.a`\n font-size: 14px;\n padding: 8px 16px;\n font-weight: ${(props) => (props.selected ? 600 : 400)};\n color: ${(props) => (props.selected ? \"#DD3345\" : \"#7B7B7B\")};\n cursor: ${(props) => (props.disabled ? \"not-allowed\" : \"pointer\")};\n &:hover {\n text-decoration: none;\n }\n`;\nreturn (\n <NavOptionsContainer>\n {navOptions.map((option) => {\n const selected = option.id == getSelectedNavOption().id;\n return option.disabled ? (\n <NavOption selected={selected} disabled={option.disabled}>\n {option.label}\n </NavOption>\n ) : !option.label ? (\n \"\"\n ) : (\n <NavOptionContainer>\n {selected && (\n <div\n style={{\n width: 2,\n height: 16,\n background: \"#DD3345\",\n borderRadius: 2,\n }}\n />\n )}\n <NavOption\n selected={selected}\n disabled={option.disabled}\n href={option.href}\n >\n {option.label}\n </NavOption>\n </NavOptionContainer>\n );\n })}\n </NavOptionsContainer>\n);\n" }, "Pots.HomeBannerBackground": { "": "const svgContent = `\n<svg width=\"1320\" height=\"332\" viewBox=\"0 0 1320 332\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<rect width=\"1320\" height=\"1\" fill=\"#FEF6EE\"/>\n<mask id=\"mask0_11854_22101\" style=\"mask-type:alpha\" maskUnits=\"userSpaceOnUse\" x=\"-60\" y=\"-486\" width=\"1440\" height=\"1024\">\n<rect x=\"-60\" y=\"-486\" width=\"1440\" height=\"1024\" fill=\"url(#paint0_radial_11854_22101)\"/>\n</mask>\n<g mask=\"url(#mask0_11854_22101)\">\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M358.131 1057C1475.87 1039 934.083 337 1942 337L1885.87 304C877.952 304 1419.74 1006 302 1024L358.131 1057Z\" fill=\"#FEF6EE\"/>\n<path d=\"M358.131 1057C1475.87 1039 934.083 337 1942 337L1885.87 304C877.952 304 1419.74 1006 302 1024L358.131 1057Z\" stroke=\"#FCE9D5\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M316.097 1021C1433.15 1003 891.698 301 1899 301L1842.9 268C835.601 268 1377.06 970 260 988L316.097 1021Z\" fill=\"#FEF6EE\"/>\n<path d=\"M316.097 1021C1433.15 1003 891.698 301 1899 301L1842.9 268C835.601 268 1377.06 970 260 988L316.097 1021Z\" stroke=\"#FCE9D5\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M262.097 985C1379.15 967 837.698 265 1845 265L1788.9 232C781.601 232 1323.06 934 206 952L262.097 985Z\" fill=\"#F8D3B0\"/>\n<path d=\"M262.097 985C1379.15 967 837.698 265 1845 265L1788.9 232C781.601 232 1323.06 934 206 952L262.097 985Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M218.131 949C1335.87 931 794.083 229 1802 229L1745.87 196C737.952 196 1279.74 898 162 916L218.131 949Z\" fill=\"#F8D3B0\"/>\n<path d=\"M218.131 949C1335.87 931 794.083 229 1802 229L1745.87 196C737.952 196 1279.74 898 162 916L218.131 949Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M161.097 914C1278.15 896 736.698 194 1744 194L1687.9 161C680.601 161 1222.06 863 105 881L161.097 914Z\" fill=\"#F8D3B0\"/>\n<path d=\"M161.097 914C1278.15 896 736.698 194 1744 194L1687.9 161C680.601 161 1222.06 863 105 881L161.097 914Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M104.131 878C1221.87 860 680.083 158 1688 158L1631.87 125C623.952 125 1165.74 827 48 845L104.131 878Z\" fill=\"#F8D3B0\"/>\n<path d=\"M104.131 878C1221.87 860 680.083 158 1688 158L1631.87 125C623.952 125 1165.74 827 48 845L104.131 878Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M49.0967 841C1166.15 823 624.698 121 1632 121L1575.9 88C568.601 88 1110.06 790 -7 808L49.0967 841Z\" fill=\"#F8D3B0\"/>\n<path d=\"M49.0967 841C1166.15 823 624.698 121 1632 121L1575.9 88C568.601 88 1110.06 790 -7 808L49.0967 841Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.2\">\n<path d=\"M-7.86905 805C1109.87 787 568.083 85 1576 85L1519.87 52C511.952 52 1053.74 754 -64 772L-7.86905 805Z\" fill=\"#F8D3B0\"/>\n<path d=\"M-7.86905 805C1109.87 787 568.083 85 1576 85L1519.87 52C511.952 52 1053.74 754 -64 772L-7.86905 805Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.2\">\n<path d=\"M-63.9375 770C1052.44 752 511.312 50 1518 50L1461.94 17C455.25 17 996.375 719 -120 737L-63.9375 770Z\" fill=\"#F8D3B0\"/>\n<path d=\"M-63.9375 770C1052.44 752 511.312 50 1518 50L1461.94 17C455.25 17 996.375 719 -120 737L-63.9375 770Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.2\">\n<path d=\"M-119.903 733C997.153 715 455.698 13 1463 13L1406.9 -20C399.601 -20 941.057 682 -176 700L-119.903 733Z\" fill=\"#F8D3B0\"/>\n<path d=\"M-119.903 733C997.153 715 455.698 13 1463 13L1406.9 -20C399.601 -20 941.057 682 -176 700L-119.903 733Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M-423.903 588C693.153 570 151.698 -132 1159 -132L1102.9 -165C95.6012 -165 637.057 537 -480 555L-423.903 588Z\" fill=\"#FEF6EE\"/>\n<path d=\"M-423.903 588C693.153 570 151.698 -132 1159 -132L1102.9 -165C95.6012 -165 637.057 537 -480 555L-423.903 588Z\" stroke=\"#FCE9D5\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M-460.869 565C656.869 547 115.083 -155 1123 -155L1066.87 -188C58.9524 -188 600.738 514 -517 532L-460.869 565Z\" fill=\"#FEF6EE\"/>\n<path d=\"M-460.869 565C656.869 547 115.083 -155 1123 -155L1066.87 -188C58.9524 -188 600.738 514 -517 532L-460.869 565Z\" stroke=\"#FCE9D5\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M-514.903 529C602.153 511 60.6979 -191 1068 -191L1011.9 -224C4.6012 -224 546.057 478 -571 496L-514.903 529Z\" fill=\"#FEF6EE\"/>\n<path d=\"M-514.903 529C602.153 511 60.6979 -191 1068 -191L1011.9 -224C4.6012 -224 546.057 478 -571 496L-514.903 529Z\" stroke=\"#FCE9D5\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M-568.903 493C548.153 475 6.69794 -227 1014 -227L957.903 -260C-49.3988 -260 492.057 442 -625 460L-568.903 493Z\" fill=\"#F8D3B0\"/>\n<path d=\"M-568.903 493C548.153 475 6.69794 -227 1014 -227L957.903 -260C-49.3988 -260 492.057 442 -625 460L-568.903 493Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M-625.869 457C491.869 439 -49.9167 -263 958 -263L901.869 -296C-106.048 -296 435.738 406 -682 424L-625.869 457Z\" fill=\"#F8D3B0\"/>\n<path d=\"M-625.869 457C491.869 439 -49.9167 -263 958 -263L901.869 -296C-106.048 -296 435.738 406 -682 424L-625.869 457Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M-682.903 422C434.153 404 -107.302 -298 900 -298L843.903 -331C-163.399 -331 378.057 371 -739 389L-682.903 422Z\" fill=\"#F8D3B0\"/>\n<path d=\"M-682.903 422C434.153 404 -107.302 -298 900 -298L843.903 -331C-163.399 -331 378.057 371 -739 389L-682.903 422Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M-739.869 386C377.869 368 -163.917 -334 844 -334L787.869 -367C-220.048 -367 321.738 335 -796 353L-739.869 386Z\" fill=\"#F8D3B0\"/>\n<path d=\"M-739.869 386C377.869 368 -163.917 -334 844 -334L787.869 -367C-220.048 -367 321.738 335 -796 353L-739.869 386Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.3\">\n<path d=\"M-794.903 349C322.153 331 -219.302 -371 788 -371L731.903 -404C-275.399 -404 266.057 298 -851 316L-794.903 349Z\" fill=\"#F8D3B0\"/>\n<path d=\"M-794.903 349C322.153 331 -219.302 -371 788 -371L731.903 -404C-275.399 -404 266.057 298 -851 316L-794.903 349Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.2\">\n<path d=\"M-851.869 313C265.869 295 -275.917 -407 732 -407L675.869 -440C-332.048 -440 209.738 262 -908 280L-851.869 313Z\" fill=\"#F8D3B0\"/>\n<path d=\"M-851.869 313C265.869 295 -275.917 -407 732 -407L675.869 -440C-332.048 -440 209.738 262 -908 280L-851.869 313Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.2\">\n<path d=\"M-907.938 278C208.438 260 -332.688 -442 674 -442L617.938 -475C-388.75 -475 152.375 227 -964 245L-907.938 278Z\" fill=\"#F8D3B0\"/>\n<path d=\"M-907.938 278C208.438 260 -332.688 -442 674 -442L617.938 -475C-388.75 -475 152.375 227 -964 245L-907.938 278Z\" stroke=\"#F4B37D\"/>\n</g>\n<g style=\"mix-blend-mode:multiply\" opacity=\"0.2\">\n<path d=\"M-963.903 241C153.153 223 -388.302 -479 619 -479L562.903 -512C-444.399 -512 97.0565 190 -1020 208L-963.903 241Z\" fill=\"#F8D3B0\"/>\n<path d=\"M-963.903 241C153.153 223 -388.302 -479 619 -479L562.903 -512C-444.399 -512 97.0565 190 -1020 208L-963.903 241Z\" stroke=\"#F4B37D\"/>\n</g>\n</g>\n<defs>\n<radialGradient id=\"paint0_radial_11854_22101\" cx=\"0\" cy=\"0\" r=\"1\" gradientUnits=\"userSpaceOnUse\" gradientTransform=\"translate(660 -158.5) rotate(90) scale(724.5 1018.83)\">\n<stop stop-color=\"#FCE9D5\"/>\n<stop offset=\"0.855072\" stop-color=\"#FEF6EE\" stop-opacity=\"0\"/>\n</radialGradient>\n</defs>\n</svg>\n`;\nconst HomeBannerStyle = {\n backgroundImage: `url(\"data:image/svg+xml;charset=utf-8,${encodeURIComponent(\n svgContent\n )}\")`,\n backgroundSize: \"cover\",\n backgroundRepeat: \"no-repeat\",\n backgroundColor: \"#FEF6EE\",\n};\nreturn {\n HomeBannerStyle,\n};\n" }, "Components.Button": { "": "const getButtonBackground = () => {\n if (props.type === \"primary\") {\n if (props.disabled) {\n return \"#e5e5e5\";\n }\n return \"#dd3345\";\n } else if (props.type === \"secondary\") {\n // TODO: handle disabled\n return \"#FEF6EE\";\n } else if (props.type === \"tertiary\") {\n return \"white\";\n }\n};\nconst getButtonTextColor = () => {\n if (props.type === \"primary\") {\n if (props.disabled) {\n return \"darkgrey\";\n }\n return \"white\";\n } else if (props.type === \"secondary\") {\n return \"#2E2E2E\";\n }\n};\nconst tag = props.href ? \"a\" : \"button\";\nconst Button = styled[tag]`\n flex-direction: row;\n justify-content: center;\n align-items: center;\n padding: 16px 24px;\n background: ${getButtonBackground()};\n overflow: hidden;\n box-shadow: 0px -2.700000047683716px 0px #4a4a4a inset;\n border-radius: 6px;\n border: 1px solid #4a4a4a;\n gap: 8px;\n display: inline-flex;\n text-align: center;\n color: ${getButtonTextColor()};\n font-size: 14px;\n line-height: 16px;\n font-weight: 600;\n &:hover {\n text-decoration: none;\n cursor: ${props.disabled ? \"not-allowed\" : \"pointer\"};\n }\n`;\nconst Icon = styled.img`\n width: 20px;\n height: 20px;\n object-fit: contain;\n`;\nreturn (\n <Button\n onClick={(e) => {\n if (props.disabled || !props.onClick) return;\n if (props.stopPropagation) e.stopPropagation();\n e.preventDefault();\n props.onClick(e);\n }}\n href={props.href}\n style={{ ...props.style }}\n target={props.target}\n >\n {props.iconSrc && <Icon src={props.iconSrc} />}\n {props.text}\n </Button>\n);\n" }, "Cart.Checkout": { "": "const donationContractId = \"donate.potlock.near\";\nconst IPFS_BASE_URL = \"https://nftstorage.link/ipfs/\";\n// const TRASH_ICON_URL =\n// IPFS_BASE_URL + \"bafkreifuvrxly3wuy4xdmavmdeb2o47nv6pzxwz3xmy6zvkxv76e55lj3y\";\nconst { getCart, getCartItemCount, removeItemsFromCart } = VM.require(\n \"old.potlock.near/widget/SDK.cart\"\n) || {\n getCart: () => {},\n getCartItemCount: () => 0,\n removeItemsFromCart: () => {},\n};\nconst numCartItems = getCartItemCount();\nconst cart = getCart();\nconst DEFAULT_GATEWAY = \"https://bos.potlock.org/\";\nconst POTLOCK_TWITTER_ACCOUNT_ID = \"PotLock_\";\nconst DEFAULT_SHARE_HASHTAGS = [\"BOS\", \"PublicGoods\", \"Donations\"];\nconst [projectId, setProjectId] = useState(\"\");\nconst Container = styled.div`\n background: #fafafa;\n display: flex;\n flex-direction: row;\n height: 100%;\n min-height: 100vh;\n @media screen and (max-width: 768px) {\n flex-direction: column;\n }\n`;\nconst SuccessContainer = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n // justify-content: center;\n width: 100%;\n padding: 24px;\n gap: 24px;\n`;\n// const ButtonsContainer = styled.div`\n// display: flex;\n// flex-direction: row;\n// gap: 24px;\n// width: 50%;\n// align-items: center;\n// justify-content: center;\n// `;\nconst ColumnLeft = styled.div`\n display: flex;\n flex-direction: column;\n // background: #fafafa;\n width: 55%;\n // background: pink;\n padding: 48px 40px 48px 64px;\n gap: 48px;\n @media screen and (max-width: 768px) {\n width: 100%;\n padding: 24px 16px 24px 16px;\n }\n`;\nconst ColumnRight = styled.div`\n // background: yellow;\n flex: 1;\n padding: 152px 148px 152px 84px;\n border-left: 1px #c7c7c7 solid;\n @media screen and (max-width: 768px) {\n padding: 24px 16px 24px 16px;\n border-left: none;\n border-top: 1px #c7c7c7 solid;\n }\n`;\nconst Title = styled.div`\n color: #2e2e2e;\n font-size: 48px;\n font-family: Lora;\n font-weight: 500;\n line-height: 56px;\n word-wrap: break-word;\n text-align: center;\n`;\nconst Icon = styled.svg`\n width: 1rem;\n height: 1rem;\n path {\n transition: 300ms;\n }\n`;\nconst ActionsContainer = styled.div`\n width: 100%;\n padding: 16px;\n background: white;\n border: 1px solid #dbdbdb;\n box-shadow: 0px -2px 0px #dbdbdb inset;\n border-radius: 6px;\n overflow: hidden;\n justify-content: flex-start;\n align-items: center;\n display: inline-flex;\n gap: 24px;\n`;\nconst InnerContainer = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n gap: 6px;\n :hover path {\n fill: #dd3345;\n }\n`;\nconst SubTitle = styled.div`\n color: #2e2e2e;\n font-weight: 600;\n font-size: 14px;\n`;\nconst TxLink = styled.a`\n color: #2e2e2e;\n cursor: pointer;\n &:hover {\n text-decoration: none;\n }\n`;\nState.init({\n selectedProjectIds: [],\n masterSelectorSelected: false,\n successfulDonationRecipientId: null,\n successfulDonationsRecipientProfiles: null,\n});\nconst allSelected =\n state.selectedProjectIds.length !== 0 &&\n state.selectedProjectIds.length === numCartItems;\nif (props.transactionHashes && !state.successfulDonationsRecipientProfiles) {\n // handles the case where the user is redirected from the wallet after a successful donation\n const transactionHashes = props.transactionHashes.split(\",\");\n for (let i = 0; i < transactionHashes.length; i++) {\n const txHash = transactionHashes[i];\n const body = JSON.stringify({\n jsonrpc: \"2.0\",\n id: \"dontcare\",\n method: \"tx\",\n params: [txHash, context.accountId],\n });\n const res = fetch(\"https://rpc.mainnet.near.org\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body,\n });\n if (res.ok) {\n const methodName =\n res.body.result.transaction.actions[0].FunctionCall.method_name;\n const successVal = res.body.result.status?.SuccessValue;\n const result = JSON.parse(\n Buffer.from(successVal, \"base64\").toString(\"utf-8\")\n ); // atob not working\n const args = JSON.parse(\n Buffer.from(\n res.body.result.transaction.actions[0].FunctionCall.args,\n \"base64\"\n ).toString(\"utf-8\")\n );\n const recipientId =\n methodName === \"donate\"\n ? result.recipient_id\n : methodName === \"ft_transfer_call\"\n ? JSON.parse(args.msg).recipient_id\n : \"\";\n if (recipientId) {\n Near.asyncView(\"social.near\", \"get\", {\n keys: [`${recipientId}/profile/**`],\n }).then((socialData) => {\n State.update({\n successfulDonationsRecipientProfiles: {\n ...state.successfulDonationsRecipientProfiles,\n [recipientId]: socialData[recipientId][\"profile\"],\n },\n });\n });\n }\n }\n }\n}\nuseEffect(() => {\n // handles extension wallet case, where user is not redirected (therefore no props.transactionHashes)\n if (\n state.successfulDonationRecipientId &&\n !state.successfulDonationsRecipientProfiles\n ) {\n Near.asyncView(\"social.near\", \"get\", {\n keys: [`${state.successfulDonationRecipientId}/profile/**`],\n }).then((socialData) => {\n State.update({\n successfulDonationsRecipientProfiles: {\n // don't spread the existing state, as it may be null\n [state.successfulDonationRecipientId]:\n socialData[state.successfulDonationRecipientId][\"profile\"],\n },\n });\n });\n }\n}, [\n state.successfulDonationRecipientId,\n state.successfulDonationsRecipientProfiles,\n]);\nconst twitterIntent = useMemo(() => {\n if (!state.successfulDonationsRecipientProfiles) return;\n const recipientIds = Object.keys(state.successfulDonationsRecipientProfiles);\n const twitterIntentBase = \"https://twitter.com/intent/tweet?text=\";\n // if more than one recipient, share the Explore Projects page; otherwise, share the project page\n let url =\n DEFAULT_GATEWAY +\n `old.potlock.near/widget/Index?referrerId=${context.accountId}`;\n if (recipientIds.length === 1) {\n url = url + `&tab=project&projectId=${recipientIds[0]}`;\n } else {\n url = url + `&tab=projects`;\n }\n // Initialize an empty array to hold the recipient profiles along with their identifiers\n const recipientProfiles = [];\n // Iterate over each entry in the successfulDonationsRecipientProfiles object\n for (const [recipientId, profile] of Object.entries(\n state.successfulDonationsRecipientProfiles\n )) {\n // Determine the identifier to use: Twitter handle, name, or recipient ID\n const identifier = profile.linktree?.twitter\n ? `@${profile.linktree.twitter}`\n : profile.name\n ? profile.name\n : recipientId;\n // Add the profile and its identifier to the array\n recipientProfiles.push({\n identifier,\n hasTwitter: !!profile.linktree?.twitter,\n });\n }\n // Sort the recipientProfiles array to put ones with Twitter handles first\n recipientProfiles.sort((a, b) => {\n if (a.hasTwitter && !b.hasTwitter) return -1;\n if (!a.hasTwitter && b.hasTwitter) return 1;\n return 0;\n });\n // Extract the identifiers from the sorted array\n const sortedIdentifiers = recipientProfiles.map(\n (profile) => profile.identifier\n );\n // Join the sorted recipient identifiers with \" & \" to create a single string\n const recipientsText = sortedIdentifiers.join(\" & \");\n let text = `I just donated to ${recipientsText} on @${POTLOCK_TWITTER_ACCOUNT_ID}! Support public goods at `;\n text = encodeURIComponent(text);\n url = encodeURIComponent(url);\n return (\n twitterIntentBase +\n text +\n `&url=${url}` +\n `&hashtags=${DEFAULT_SHARE_HASHTAGS.join(\",\")}`\n );\n}, [state.successfulDonationsRecipientProfiles]);\nreturn (\n // <div>\n <Container>\n {props.transactionHashes || state.successfulDonationRecipientId ? (\n <SuccessContainer>\n <Title>Thanks for donating!</Title>\n {twitterIntent && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n href: twitterIntent,\n target: \"_blank\",\n type: \"primary\",\n text: \"Share to Twitter\",\n disabled: !twitterIntent,\n style: {\n width: \"300px\",\n },\n }}\n />\n )}\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n href: props.hrefWithParams(`?tab=projects`),\n type: twitterIntent ? \"secondary\" : \"primary\",\n text: \"Explore projects\",\n style: {\n width: \"300px\",\n },\n }}\n />\n {/* {twitterIntent && props.checkoutSuccessTxHash ? (\n <TxLink\n target=\"_blank\"\n href={`https://nearblocks.io/txns/${props.checkoutSuccessTxHash}`}\n >\n View transaction\n </TxLink>\n ) : (\n props.checkoutSuccessTxHash && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n href: `https://nearblocks.io/txns/${props.checkoutSuccessTxHash}`,\n target: \"_blank\",\n type: \"secondary\",\n text: \"View transaction\",\n disabled: !props.checkoutSuccessTxHash,\n style: {\n width: \"300px\",\n },\n }}\n />\n )\n )} */}\n </SuccessContainer>\n ) : (\n <>\n <ColumnLeft>\n <Title>Donation Cart</Title>\n <ActionsContainer>\n <InnerContainer>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Checkbox\"}\n props={{\n id: \"masterSelector\",\n disabled: numCartItems === 0,\n checked: state.masterSelectorSelected,\n onClick: (e) => {\n // if allSelected, then deselect all\n // if not allSelected, then select all\n const selectedProjectIds = Object.keys(cart).filter((_) => {\n if (allSelected) {\n return false;\n }\n return true;\n });\n State.update({\n selectedProjectIds,\n masterSelectorSelected: !allSelected,\n });\n },\n }}\n />\n <SubTitle>Select all</SubTitle>\n </InnerContainer>\n <InnerContainer\n style={{ cursor: \"pointer\" }}\n onClick={() => {\n // doesn't do anything if nothing selected\n if (state.selectedProjectIds.length === 0) return;\n // delete selected projects\n removeItemsFromCart(\n state.selectedProjectIds.map((id) => ({ id }))\n );\n // uncheck box\n State.update({\n selectedProjectIds: [],\n masterSelectorSelected: false,\n });\n }}\n >\n <Icon\n viewBox=\"0 0 12 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M2.5 14C2.0875 14 1.73437 13.8531 1.44062 13.5594C1.14687 13.2656 1 12.9125 1 12.5V2.5H0V1H4V0H8V1H12V2.5H11V12.491C11 12.9137 10.8531 13.2708 10.5594 13.5625C10.2656 13.8542 9.9125 14 9.5 14H2.5ZM9.5 2.5H2.5V12.5H9.5V2.5ZM4 11H5.5V4H4V11ZM6.5 11H8V4H6.5V11Z\"\n fill=\"#7B7B7B\"\n />\n </Icon>\n <SubTitle>Delete</SubTitle>\n </InnerContainer>\n </ActionsContainer>\n {numCartItems === 0 ? (\n <div>No items in cart</div>\n ) : (\n Object.keys(cart).map((projectId) => {\n // setProjectId(projectId); // wtf is this?? commenting out\n const checked = state.selectedProjectIds.includes(projectId);\n return (\n <Widget\n src={\"old.potlock.near/widget/Cart.CheckoutItem\"}\n props={{\n ...props,\n cartItem: cart[projectId],\n checked,\n handleCheckboxClick: (e) => {\n // if selected, then deselect\n // else, select\n let selectedProjectIds = state.selectedProjectIds;\n if (checked) {\n selectedProjectIds = selectedProjectIds.filter(\n (id) => id !== projectId\n );\n } else {\n selectedProjectIds.push(projectId);\n }\n const updatedState = {\n selectedProjectIds,\n };\n if (\n selectedProjectIds.length !== 0 &&\n selectedProjectIds.length !== numCartItems\n ) {\n updatedState.masterSelectorSelected = false;\n }\n State.update(updatedState);\n },\n }}\n />\n );\n })\n )}\n </ColumnLeft>\n <ColumnRight>\n <Widget\n src={\"old.potlock.near/widget/Cart.CheckoutBreakdown\"}\n props={{\n ...props,\n projectId: projectId,\n updateSuccessfulDonationRecipientId: (recipientId) =>\n State.update({ successfulDonationRecipientId: recipientId }),\n }}\n />\n </ColumnRight>\n </>\n )}\n </Container>\n // </div>\n);\n" }, "Pots.Detail": { "": "const { potId } = props;\nconst { doesUserHaveDaoFunctionCallProposalPermissions } = VM.require(\n \"old.potlock.near/widget/utils\"\n) || { doesUserHaveDaoFunctionCallProposalPermissions: () => \"\" };\nconst {\n ONE_TGAS,\n SUPPORTED_FTS: { NEAR },\n} = VM.require(\"old.potlock.near/widget/constants\") || {\n ONE_TGAS: 0,\n SUPPORTED_FTS: {},\n};\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getConfig: () => {},\n asyncGetApplications: () => {},\n asyncGetPublicRoundDonations: () => {},\n};\nconst potDetail = PotSDK.getConfig(potId);\nconst MAX_APPLICATION_MESSAGE_LENGTH = 1000;\nBig.PE = 100;\nconst FIFTY_TGAS = \"50000000000000\";\nconst THREE_HUNDRED_TGAS = \"300000000000000\";\nconst MIN_PROPOSAL_DEPOSIT_FALLBACK = \"100000000000000000000000\"; // 0.1N\nconst Wrapper = styled.div``;\nconst SidebarContainer = styled.div`\n width: 25%;\n // width: 500px;\n @media screen and (max-width: 768px) {\n display: none;\n }\n`;\nconst Container = styled.div`\n padding: 0px 68px;\n @media screen and (max-width: 768px) {\n flex-direction: column;\n width: 100%;\n padding: 0;\n }\n`;\nconst ContainerInner = styled.div`\n display: flex;\n flex-direction: column;\n padding: 68px 0px;\n`;\nconst BodyContainer = styled.div`\n margin-top: 52px;\n padding: 0 4rem;\n flex: 1;\n width: 100%;\n @media screen and (max-width: 768px) {\n padding: 0;\n }\n`;\nconst Divider = styled.div`\n height: 1px;\n width: 100%;\n background-color: #292929;\n`;\nconst ModalTitle = styled.div`\n color: #525252;\n font-size: 16px;\n font-weight: 400;\n line-height: 20px;\n word-wrap: break-word;\n margin-bottom: 8px;\n`;\nconst Row = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n`;\nState.init({\n isApplicationModalOpen: false,\n applicationMessage: \"\",\n applicationMessageError: \"\",\n applicationSuccess: false,\n isDao: false,\n daoAddress: \"\",\n daoAddressError: \"\",\n daoPolicy: null,\n registryStatus: null,\n});\n// if (state.sybilRequirementMet === null) {\n// if (potDetail.sybil_wrapper_provider) {\n// const [contractId, methodName] = potDetail.sybil_wrapper_provider.split(\":\");\n// Near.asyncView(contractId, methodName, { account_id: context.accountId })\n// .then((result) => {\n// State.update({ sybilRequirementMet: result });\n// })\n// .catch((e) => {\n// State.update({ sybilRequirementMet: false });\n// });\n// } else {\n// State.update({ sybilRequirementMet: true });\n// }\n// }\nconst noPot = potDetail === undefined;\nconst loading = potDetail === null;\nif (loading) return <div class=\"spinner-border text-secondary\" role=\"status\" />;\nif (noPot) return \"No pot found\";\nconst now = Date.now();\nconst applicationNotStarted = now < potDetail.application_start_ms;\nconst applicationOpen =\n now >= potDetail.application_start_ms && now < potDetail.application_end_ms;\nconst publicRoundOpen =\n now >= potDetail.public_round_start_ms && now < potDetail.public_round_end_ms;\nconst publicRoundClosed = now >= potDetail.public_round_end_ms;\nconst payoutsPending = publicRoundClosed && !potDetail.cooldown_end_ms;\n// these will be passed down to child components\nprops.navOptions = [\n {\n label: \"Projects\",\n id: \"projects\",\n disabled: false,\n source: \"old.potlock.near/widget/Pots.Projects\",\n href: props.hrefWithParams(`?tab=pot&potId=${potId}&nav=projects`),\n },\n {\n label: \"Applications\",\n id: \"applications\",\n disabled: false,\n source: \"old.potlock.near/widget/Pots.Applications\",\n href: props.hrefWithParams(`?tab=pot&potId=${potId}&nav=applications`),\n },\n {\n label: \"Donations\",\n id: \"donations\",\n disabled: false,\n source: \"old.potlock.near/widget/Pots.Donations\",\n href: props.hrefWithParams(`?tab=pot&potId=${potId}&nav=donations`),\n },\n {\n label: \"Sponsors\",\n id: \"sponsors\",\n disabled: false,\n source: \"old.potlock.near/widget/Pots.Sponsors\",\n href: props.hrefWithParams(`?tab=pot&potId=${potId}&nav=sponsors`),\n },\n {\n label: \"Payouts\",\n id: \"payouts\",\n disabled: now < potDetail.public_round_start_ms, // TODO: ADD BACK IN\n source: \"old.potlock.near/widget/Pots.Payouts\",\n href: props.hrefWithParams(`?tab=pot&potId=${potId}&nav=payouts`),\n },\n {\n label: \"Settings\",\n id: \"settings\",\n disabled: false,\n source: \"old.potlock.near/widget/Pots.Settings\",\n href: props.hrefWithParams(`?tab=pot&potId=${potId}&nav=settings`),\n },\n];\nif (!props.nav) {\n let nav;\n applicationNotStarted\n ? (nav = \"sponsors\")\n : applicationOpen\n ? (nav = \"applications\")\n : publicRoundOpen\n ? (nav = \"projects\")\n : !payoutsPending\n ? (nav = \"donations\")\n : (nav = \"payouts\");\n props.nav = nav;\n} // default to home tab\n// const imageHeightPx = 120;\n// const profileImageTranslateYPx = 220;\nconst handleSendApplication = () => {\n const args = {\n message: state.applicationMessage,\n };\n let deposit = NEAR.toIndivisible(\"0.01\");\n const extraDeposit = Big(state.applicationMessage.length * 0.0001).mul(\n Big(10).pow(24)\n );\n deposit = deposit.plus(extraDeposit);\n const transactions = [\n {\n contractName: potId,\n methodName: \"apply\",\n deposit,\n args,\n gas: ONE_TGAS.mul(100),\n },\n ];\n // if it is a DAO, we need to convert transactions to DAO function call proposals\n if (state.isDao) {\n const clonedTransactions = JSON.parse(JSON.stringify(transactions));\n transactions = clonedTransactions.map((tx) => {\n const action = {\n method_name: tx.methodName,\n gas: FIFTY_TGAS,\n deposit: tx.deposit ? tx.deposit.toString() : \"0\",\n args: Buffer.from(JSON.stringify(tx.args), \"utf-8\").toString(\"base64\"),\n };\n return {\n ...tx,\n contractName: state.daoAddress,\n methodName: \"add_proposal\",\n args: {\n proposal: {\n description: `Application to PotLock pot: ${potDetail.pot_name} (${potId})`,\n kind: {\n FunctionCall: {\n receiver_id: tx.contractName,\n actions: [action],\n },\n },\n },\n },\n deposit: state.daoPolicy.proposal_bond || MIN_PROPOSAL_DEPOSIT_FALLBACK,\n gas: THREE_HUNDRED_TGAS,\n };\n });\n }\n Near.call(transactions);\n // NB: we won't get here if user used a web wallet, as it will redirect to the wallet\n // <---- EXTENSION WALLET HANDLING ---->\n // poll for updates\n const pollIntervalMs = 1000;\n // const totalPollTimeMs = 60000; // consider adding in to make sure interval doesn't run indefinitely\n const pollId = setInterval(() => {\n PotSDK.asyncGetApplications(potId).then((applications) => {\n const application = applications.find(\n (application) =>\n application.project_id ===\n (state.isDao ? state.daoAddress : context.accountId)\n );\n if (application) {\n clearInterval(pollId);\n State.update({ applicationSuccess: true });\n }\n });\n }, pollIntervalMs);\n};\nconst verifyIsOnRegistry = (address) => {\n Near.asyncView(\"lists.potlock.near\", \"get_registrations_for_registrant\", {\n registrant_id: address,\n }).then((registrations) => {\n const registration = registrations.find(\n (registration) => registration.list_id === 1 // potlock registry list id\n );\n if (registration) {\n State.update({ registryStatus: registration.status });\n }\n });\n};\nuseEffect(() => {\n if (!state.isDao) {\n verifyIsOnRegistry(context.accountId || \"\");\n }\n}, []);\n// const registryRequirementMet = state.isOnRegistry || !potDetail.registry_provider;\nconst registrationApproved = state.registryStatus === \"Approved\";\nconst registrationNotApproved =\n state.registryStatus && state.registryStatus !== \"Approved\";\nconst registrationApprovedOrNoRegistryProvider =\n registrationApproved || !potDetail?.registry_provider;\nconst isError = state.applicationMessageError || state.daoAddressError;\n// Get total public donations\nconst allDonationsPaginated = useCache(() => {\n const limit = 480; // number of donations to fetch per req\n const donationsCount = potDetail.public_donations_count;\n const paginations = [\n ...Array(\n parseInt(donationsCount / limit) + (donationsCount % limit > 0 ? 1 : 0)\n ).keys(),\n ];\n try {\n const allDonations = paginations.map((index) =>\n PotSDK.asyncGetPublicRoundDonations(potId, {\n from_index: index * limit,\n limit: limit,\n })\n );\n return Promise.all(allDonations);\n } catch (error) {\n console.error(\n `error getting public donations from ${index} to ${index * limit}`,\n error\n );\n }\n}, \"pot-public-donations\");\nconst allDonations = allDonationsPaginated\n ? allDonationsPaginated.flat()\n : null;\nreturn (\n <Wrapper>\n <Widget\n src={\"old.potlock.near/widget/Pots.HeaderStatus\"}\n props={{\n ...props,\n potDetail: potDetail,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Pots.Header\"}\n props={{\n ...props,\n potDetail: potDetail,\n setApplicationModalOpen: (isOpen) =>\n State.update({ isApplicationModalOpen: isOpen }),\n applicationSuccess: state.applicationSuccess,\n registrationApproved,\n allDonations,\n registryStatus: state.registryStatus,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Profile.Tabs\"}\n props={{\n ...props,\n }}\n />\n <BodyContainer>\n <Widget\n src={props.navOptions.find((option) => option.id == props.nav).source}\n props={{\n ...props,\n potDetail: potDetail,\n allDonations,\n }}\n />\n </BodyContainer>\n <Widget\n src={\"old.potlock.near/widget/Components.Modal\"}\n props={{\n ...props,\n isModalOpen: state.isApplicationModalOpen,\n onClose: () => State.update({ isApplicationModalOpen: false }),\n children: (\n <>\n <ModalTitle>\n Application message <span style={{ color: \"#DD3345\" }}>*</span>\n </ModalTitle>\n <Widget\n src={\"old.potlock.near/widget/Inputs.TextArea\"}\n props={{\n noLabel: true,\n inputRows: 5,\n inputStyle: {\n background: \"#FAFAFA\",\n },\n placeholder: \"Your application message here...\",\n value: state.applicationMessage,\n onChange: (applicationMessage) =>\n State.update({ applicationMessage }),\n validate: () => {\n if (\n state.applicationMessage.length >\n MAX_APPLICATION_MESSAGE_LENGTH\n ) {\n State.update({\n applicationMessageError: `Application message must be less than ${MAX_APPLICATION_MESSAGE_LENGTH} characters`,\n });\n return;\n }\n State.update({ applicationMessageError: \"\" });\n },\n error: state.applicationMessageError,\n }}\n />\n <Row style={{ margin: \"12px 0px\" }}>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Checkbox\"}\n props={{\n id: \"isDaoSelector\",\n checked: state.isDao,\n onClick: (e) => {\n State.update({\n isDao: e.target.checked,\n });\n if (!e.target.checked) {\n // check current account ID against registry\n verifyIsOnRegistry(context.accountId);\n }\n },\n label: \"I'm applying as a DAO\",\n }}\n />\n </Row>\n {state.isDao && (\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"DAO address *\",\n placeholder: \"E.g. mydao.sputnikdao.near\",\n value: state.daoAddress,\n onChange: (daoAddress) =>\n State.update({ daoAddress, daoAddressError: \"\" }),\n validate: () => {\n // **CALLED ON BLUR**\n Near.asyncView(state.daoAddress, \"get_policy\", {})\n .then((policy) => {\n const hasPermissions = !policy\n ? false\n : doesUserHaveDaoFunctionCallProposalPermissions(\n context.accountId,\n policy\n );\n State.update({\n daoAddressError: hasPermissions\n ? \"\"\n : \"You don't have required permissions to submit proposals to this DAO.\",\n daoPolicy: policy,\n });\n // check registry\n verifyIsOnRegistry(state.daoAddress);\n })\n .catch((e) => {\n State.update({\n daoAddressError: \"Invalid DAO address\",\n });\n });\n },\n error: state.daoAddressError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n )}\n <Row style={{ justifyContent: \"flex-end\", marginTop: \"12px\" }}>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n // text: registrationApprovedOrNoRegistryProvider\n // ? state.isDao\n // ? \"Propose to Send Application\"\n // : \"Send application\"\n // : \"Register to apply\",\n text: state.isDao\n ? \"Propose to Send Application\"\n : registrationApprovedOrNoRegistryProvider\n ? \"Send application\"\n : \"Register to apply\",\n onClick:\n state.isDao || registrationApprovedOrNoRegistryProvider\n ? handleSendApplication\n : null,\n disabled: isError,\n href:\n state.isDao || registrationApprovedOrNoRegistryProvider\n ? null\n : props.hrefWithParams(`?tab=createproject`),\n target:\n state.isDao || registrationApprovedOrNoRegistryProvider\n ? \"_self\"\n : \"_blank\",\n }}\n />\n </Row>\n </>\n ),\n }}\n />\n </Wrapper>\n);\n" }, "ModalDonation.ConfirmPot": { "": "const { NADABOT_HUMAN_METHOD, DONATION_CONTRACT_ID } = VM.require(\n \"old.potlock.near/widget/constants\"\n) || {\n NADABOT_HUMAN_METHOD: \"\",\n DONATION_CONTRACT_ID: \"\",\n};\nconst { nearToUsd } = VM.require(\"old.potlock.near/widget/utils\");\nlet DonateSDK =\n VM.require(\"old.potlock.near/widget/SDK.donate\") ||\n (() => ({\n getConfig: () => {},\n asyncGetDonationsForDonor: () => {},\n }));\nDonateSDK = DonateSDK({ env: props.env });\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getConfig: () => {},\n asyncGetDonationsForDonor: () => {},\n};\nconst { _address } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n) || {\n _address: (address) => address,\n};\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n padding: 1.5rem 2rem;\n gap: 1.5rem;\n @media only screen and (max-width: 480px) {\n padding: 1.5rem 1.125rem;\n }\n`;\nconst ContentScrollable = styled.div`\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n overflow-y: scroll;\n height: 450px;\n`;\nconst Label = styled.div`\n font-weight: 500;\n margin-bottom: 4px;\n`;\nconst Amout = styled.div`\n display: flex;\n align-items: center;\n gap: 0.5rem;\n cursor: pointer;\n span {\n font-weight: 600;\n }\n div {\n font-weight: 600;\n font-size: 1rem;\n }\n .usd-amount {\n color: #7b7b7b;\n }\n .toggle-icon {\n width: 8px;\n display: flex;\n margin-left: auto;\n overflow: hidden;\n svg {\n width: 100%;\n transition: all 300ms ease-in-out;\n }\n }\n img,\n svg {\n width: 20px;\n }\n`;\nconst SvgIcon = styled.svg`\n width: 16px;\n`;\nconst FeesRemoval = styled.div`\n display: flex;\n flex-direction: column;\n gap: 1rem;\n .check {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n }\n .label {\n margin-right: 4px;\n margin-left: 8px;\n }\n .address {\n font-weight: 600;\n gap: 4px;\n display: flex;\n align-items: center;\n color: #292929;\n transition: all 300ms;\n &:hover {\n color: #dd3345;\n text-decoration: none;\n }\n }\n .profile-image {\n width: 17px;\n height: 17px;\n display: flex !important;\n }\n @media only screen and (max-width: 480px) {\n .address {\n margin-left: 34px;\n width: 100%;\n }\n }\n`;\nconst Button = styled.div`\n display: flex;\n margin-top: 4rem;\n margin-bottom: 0.5rem;\n button {\n padding: 12px 16px;\n width: 100%;\n font-weight: 500;\n }\n @media only screen and (max-width: 480px) {\n margin-top: 2rem;\n }\n`;\nconst Projects = styled.div`\n padding: 8px 0;\n display: flex;\n flex-direction: column;\n border-radius: 8px;\n border: 1px solid #ebebeb;\n background: rgba(235, 235, 235, 0.24);\n transition: all 300ms ease-in-out;\n &.hidden {\n max-height: 0;\n overflow: hidden;\n opacity: 0;\n }\n .project {\n display: flex;\n align-items: center;\n gap: 1rem;\n padding: 0.5rem 1rem;\n transition: 300ms ease-in-out;\n }\n .profile-image {\n width: 40px;\n height: 40px;\n box-shadow: 0px 0px 1px 0px #a6a6a6 inset;\n border-radius: 50%;\n }\n .info {\n display: flex;\n flex-direction: column;\n .name {\n font-weight: 600;\n }\n .address {\n color: #7b7b7b;\n transition: all 300ms;\n &:hover {\n text-decoration: none;\n color: #dd3345;\n }\n }\n }\n`;\nconst ProjectAmount = styled.div`\n margin-left: auto;\n display: flex;\n gap: 1rem;\n align-items: center;\n div {\n font-weight: 600;\n }\n svg {\n width: 16px;\n }\n`;\nconst NearIcon = (props) => (\n <SvgIcon\n {...props}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <g clip-path=\"url(#clip0_454_78)\">\n <circle cx=\"8\" cy=\"8\" r=\"7.25\" stroke=\"#292929\" stroke-width=\"1.5\" />\n <path\n d=\"M11.1477 4C10.851 4 10.5763 4.15333 10.421 4.406L8.74866 6.88867C8.72453 6.92441 8.71422 6.96772 8.71967 7.01051C8.72511 7.05329 8.74594 7.09264 8.77826 7.1212C8.81057 7.14976 8.85218 7.1656 8.89531 7.16574C8.93844 7.16589 8.98015 7.15034 9.01266 7.122L10.6587 5.69467C10.6683 5.68598 10.6802 5.68028 10.6931 5.67828C10.7059 5.67628 10.719 5.67806 10.7308 5.6834C10.7426 5.68875 10.7526 5.69742 10.7596 5.70836C10.7665 5.7193 10.7702 5.73203 10.77 5.745V10.215C10.77 10.2287 10.7658 10.2421 10.7579 10.2534C10.7501 10.2646 10.7389 10.2732 10.726 10.2778C10.7131 10.2825 10.6991 10.2831 10.6858 10.2795C10.6726 10.2758 10.6608 10.2682 10.652 10.2577L5.67667 4.30167C5.59667 4.20709 5.49701 4.1311 5.38463 4.079C5.27226 4.0269 5.14987 3.99994 5.026 4H4.85233C4.62628 4 4.40949 4.0898 4.24964 4.24964C4.0898 4.40949 4 4.62628 4 4.85233V11.1477C4 11.3333 4.06061 11.5139 4.17263 11.6619C4.28465 11.81 4.44194 11.9174 4.6206 11.9679C4.79926 12.0184 4.98952 12.0091 5.16245 11.9416C5.33538 11.874 5.48152 11.7519 5.57867 11.5937L7.251 9.111C7.27513 9.07525 7.28544 9.03194 7.27999 8.98916C7.27455 8.94637 7.25372 8.90703 7.22141 8.87846C7.18909 8.8499 7.14748 8.83407 7.10435 8.83392C7.06122 8.83377 7.01951 8.84932 6.987 8.87766L5.341 10.3053C5.33134 10.3139 5.31939 10.3195 5.3066 10.3215C5.29381 10.3234 5.28074 10.3216 5.26898 10.3162C5.25721 10.3108 5.24726 10.3021 5.24034 10.2912C5.23342 10.2803 5.22983 10.2676 5.23 10.2547V5.784C5.22997 5.77027 5.23418 5.75687 5.24206 5.74563C5.24993 5.73438 5.26109 5.72584 5.274 5.72117C5.28691 5.71651 5.30094 5.71594 5.31419 5.71955C5.32743 5.72315 5.33924 5.73076 5.348 5.74133L10.3227 11.698C10.4847 11.8893 10.7227 11.9997 10.9733 12H11.147C11.373 12.0001 11.5898 11.9104 11.7498 11.7507C11.9097 11.591 11.9997 11.3744 12 11.1483V4.85233C11.9999 4.62631 11.9101 4.40956 11.7503 4.24974C11.5904 4.08992 11.3737 4.00009 11.1477 4Z\"\n fill=\"#292929\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_454_78\">\n <rect width=\"16\" height=\"16\" fill=\"white\" />\n </clipPath>\n </defs>\n </SvgIcon>\n);\nconst ProfileImg = ({ accountId, profile }) => (\n <Widget\n src={\"old.potlock.near/widget/Project.ProfileImage\"}\n props={{\n accountId,\n profile,\n style: {},\n }}\n />\n);\nconst CheckBox = ({ id, checked, onClick }) => (\n <Widget\n src={\"old.potlock.near/widget/Inputs.Checkbox\"}\n props={{\n id,\n checked,\n onClick,\n }}\n />\n);\nconst getFeesBasisPoints = (protocolConfig, potDetail) => {\n if (protocolConfig) {\n return [\n protocolConfig.account_id,\n protocolConfig.basis_points,\n potDetail.referral_fee_public_round_basis_points,\n ];\n } else {\n return [\"\", 0, 0];\n }\n};\nconst pollForDonationSuccess = ({\n projectIds,\n afterTs,\n accountId,\n openDonationSuccessModal,\n potId,\n}) => {\n // poll for updates\n const pollIntervalMs = 1000;\n // const totalPollTimeMs = 60000; // consider adding in to make sure interval doesn't run indefinitely\n const pollId = setInterval(() => {\n PotSDK.asyncGetDonationsForDonor(potId, accountId)\n .then((alldonations) => {\n const donations = {};\n for (const donation of alldonations) {\n const { project_id, donated_at_ms, donated_at } = donation;\n if (\n projectIds.includes(project_id) &&\n (donated_at_ms || donated_at) > afterTs\n ) {\n donations[project_id] = { ...donation, potId };\n }\n }\n if (Object.keys(donations).length === projectIds.length) {\n // display success message\n clearInterval(pollId);\n openDonationSuccessModal(donations);\n }\n })\n .catch((err) => {\n console.log(err);\n });\n }, pollIntervalMs);\n};\nconst ConfirmPot = (props) => {\n const {\n selectedDenomination,\n bypassProtocolFee,\n bypassChefFee,\n updateState,\n potDetail,\n potId,\n referrerId,\n accountId,\n amount,\n openDonationSuccessModal,\n selectedProjects,\n donationType,\n hrefWithParams,\n toggleAmount,\n } = props;\n const protocolConfigContractId =\n potDetail.protocol_config_provider.split(\":\")[0];\n const protocolConfigViewMethodName =\n potDetail.protocol_config_provider.split(\":\")[1];\n const protocolConfig =\n protocolConfigContractId && protocolConfigViewMethodName\n ? Near.view(protocolConfigContractId, protocolConfigViewMethodName, {})\n : null;\n const [\n protocolFeeRecipientAccount,\n protocolFeeBasisPoints,\n referralFeeBasisPoints,\n ] = getFeesBasisPoints(protocolConfig, potDetail);\n const chefFeeBasisPoints = potDetail?.chef_fee_basis_points;\n const donationAmountIndivisible = (num) =>\n Big(num).mul(new Big(10).pow(selectedDenomination.decimals));\n const projectAmount =\n parseFloat(amount) / Object.keys(selectedProjects).length;\n const autoProjectAmount = donationAmountIndivisible(projectAmount);\n const handleDonate = () => {\n const now = Date.now();\n const successArgs = {\n projectIds: Object.keys(selectedProjects),\n afterTs: now,\n accountId,\n openDonationSuccessModal,\n amount,\n potId,\n };\n const transactions = [];\n Object.keys(selectedProjects).forEach((project) => {\n let amount = 0;\n if (donationType === \"auto\") {\n amount = autoProjectAmount;\n } else {\n amount = donationAmountIndivisible(selectedProjects[project]);\n }\n if (amount) {\n transactions.push({\n contractName: potId,\n methodName: \"donate\",\n args: {\n referrer_id: referrerId,\n project_id: project,\n bypass_protocol_fee: bypassProtocolFee,\n ...(bypassChefFee ? { custom_chef_fee_basis_points: 0 } : {}),\n },\n deposit: amount.toFixed(0),\n gas: \"300000000000000\",\n });\n }\n });\n Near.call(transactions);\n pollForDonationSuccess(successArgs);\n };\n return (\n <Container>\n <ContentScrollable>\n <div>\n <Label>Total amount</Label>\n <Amout\n onClick={() =>\n updateState({\n toggleAmount: !toggleAmount,\n })\n }\n >\n <div>\n {selectedDenomination.icon ? (\n <img src={selectedDenomination.icon} />\n ) : (\n <NearIcon />\n )}\n </div>\n <div>\n {amount} <span>{selectedDenomination.text}</span>\n </div>\n {nearToUsd && (\n <div className=\"usd-amount\">\n ~${(nearToUsd * amount).toFixed(2)}\n </div>\n )}\n <div className=\"toggle-icon\">\n <svg\n viewBox=\"0 0 8 12\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style={{\n rotate: !toggleAmount ? \"\" : \"90deg\",\n }}\n >\n <path\n d=\"M1.70501 0L0.295013 1.41L4.87501 6L0.295013 10.59L1.70501 12L7.70501 6L1.70501 0Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n </div>\n </Amout>\n </div>\n <Projects className={`${!toggleAmount ? \"hidden\" : \"\"}`}>\n {Object.keys(selectedProjects).map((project_id) => {\n const profile = Social.getr(`${project_id}/profile`);\n return selectedProjects[project_id] > 0 ||\n donationType === \"auto\" ? (\n <div className={`project`} key={project_id}>\n <ProfileImg profile={profile} />\n <div className=\"info\">\n {profile?.name && (\n <div className=\"name\">{_address(profile?.name, 20)}</div>\n )}\n <a\n className=\"address\"\n href={hrefWithParams(\n `?tab=project&projectId=${project_id}`\n )}\n target=\"_blank\"\n >\n {_address(project_id, 20)}\n </a>\n </div>\n <ProjectAmount>\n <div>\n {\" \"}\n {donationType === \"auto\"\n ? projectAmount < 0.01\n ? \"<0.01\"\n : projectAmount.toFixed(2)\n : selectedProjects[project_id]}{\" \"}\n </div>\n <NearIcon />\n </ProjectAmount>\n </div>\n ) : (\n \"\"\n );\n })}\n </Projects>\n <Widget\n src={\"old.potlock.near/widget/Cart.BreakdownSummary\"}\n props={{\n ...props,\n referrerId,\n protocolFeeBasisPoints,\n referralFeeBasisPoints,\n bypassChefFee,\n chef: potDetail?.chef,\n chefFeeBasisPoints,\n totalAmount: amount,\n bypassProtocolFee: bypassProtocolFee,\n ftIcon: selectedDenomination.icon,\n }}\n />\n <FeesRemoval>\n <div className=\"check\">\n <CheckBox\n id=\"bypassProtocolFeeSelector\"\n checked={bypassProtocolFee}\n onClick={(e) => {\n updateState({ bypassProtocolFee: e.target.checked });\n }}\n />\n <div className=\"label\">\n Remove {protocolFeeBasisPoints / 100 || \"-\"}% protocol fee\n </div>\n <a\n href={`https://near.social/mob.near/widget/ProfilePage?accountId=${protocolFeeRecipientAccount}`}\n className=\"address\"\n target=\"_blank\"\n >\n <ProfileImg accountId={protocolFeeRecipientAccount} />\n {protocolFeeRecipientAccount}\n </a>\n </div>\n {potDetail?.chef && chefFeeBasisPoints > 0 && (\n <div className=\"check\">\n <CheckBox\n id=\"bypassChefFeeSelector\"\n checked={bypassChefFee}\n onClick={(e) => {\n updateState({ bypassChefFee: e.target.checked });\n }}\n />\n <div className=\"label\">\n {\" \"}\n Remove {chefFeeBasisPoints / 100 || \"-\"}% chef fee\n </div>\n <a\n href={`https://near.social/mob.near/widget/ProfilePage?accountId=${potDetail?.chef}`}\n className=\"address\"\n target=\"_blank\"\n >\n <ProfileImg accountId={potDetail?.chef} />\n {potDetail?.chef}\n </a>\n </div>\n )}\n </FeesRemoval>\n </ContentScrollable>\n <Button>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: \"Confirm donation\",\n onClick: handleDonate,\n }}\n />\n </Button>\n </Container>\n );\n};\nreturn {\n ConfirmPot,\n};\n" }, "Components.ModalMultiAccount": { "": "const {\n isModalOpen,\n onClose,\n titleText,\n descriptionText,\n unitText,\n inputValue,\n onInputChange,\n handleAddAccount,\n handleRemoveAccount,\n accountError,\n accountIds,\n} = props;\nconst IPFS_BASE_URL = \"https://nftstorage.link/ipfs/\";\n// const ADD_ACCOUNTS_ICON_URL =\n// IPFS_BASE_URL + \"bafkreig6c7m2z2lupreu2br4pm3xx575mv6uvmuy2qkij4kzzfpt7tipcq\";\n// const CLOSE_ICON_URL =\n// IPFS_BASE_URL + \"bafkreifyg2vvmdjpbhkylnhye5es3vgpsivhigkjvtv2o4pzsae2z4vi5i\";\nconst ModalHeader = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n margin-bottom: 24px;\n`;\nconst ModalHeaderLeft = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-start;\n`;\nconst IconContainer = styled.div`\n width: 40px;\n height: 40px;\n background: #f0f0f0;\n border-radius: 50%;\n display: flex;\n justify-content: center;\n align-items: center;\n margin-right: 16px;\n`;\nconst Icon = styled.svg`\n width: 20px;\n height: 20px;\n cursor: ${(props) => (props.cursor ? props.cursor : \"default\")};\n transition: 300ms ease-in-out;\n :hover {\n ${(props) => props.hover || \"\"}\n }\n`;\nconst ModalTitle = styled.div`\n font-color: #2e2e2e;\n font-size: 16px;\n font-weight: 600;\n`;\nconst ModalDescription = styled.p`\n font-color: #2e2e2e;\n font-size: 16px;\n font-weight: 400;\n`;\nconst Space = styled.div`\n height: ${(props) => props.height}px;\n`;\nconst MembersCount = styled.span`\n color: #2e2e2e;\n font-weight: 600;\n`;\nconst MembersText = styled.div`\n color: #7b7b7b;\n font-size: 12px;\n font-weight: 400;\n`;\nreturn (\n <Widget\n src={\"old.potlock.near/widget/Components.Modal\"}\n props={{\n isModalOpen,\n onClose,\n children: (\n <>\n <ModalHeader>\n <ModalHeaderLeft>\n <IconContainer>\n <Icon\n viewBox=\"0 0 24 12\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M16.24 7.65C15.07 7.13 13.63 6.75 12 6.75C10.37 6.75 8.93 7.14 7.76 7.65C6.68 8.13 6 9.21 6 10.39V12H18V10.39C18 9.21 17.32 8.13 16.24 7.65ZM8.07 10C8.16 9.77 8.34 9.58 8.56 9.48C9.66 8.99 10.82 8.75 11.99 8.75C13.17 8.75 14.32 9 15.42 9.48C15.65 9.58 15.82 9.77 15.91 10H8.07Z\"\n fill=\"#151A23\"\n />\n <path\n d=\"M1.22 8.58C0.48 8.9 0 9.62 0 10.43V12H4.5V10.39C4.5 9.56 4.73 8.78 5.13 8.1C4.76 8.04 4.39 8 4 8C3.01 8 2.07 8.21 1.22 8.58Z\"\n fill=\"#151A23\"\n />\n <path\n d=\"M22.78 8.58C21.93 8.21 20.99 8 20 8C19.61 8 19.24 8.04 18.87 8.1C19.27 8.78 19.5 9.56 19.5 10.39V12H24V10.43C24 9.62 23.52 8.9 22.78 8.58Z\"\n fill=\"#151A23\"\n />\n <path\n d=\"M12 6C13.66 6 15 4.66 15 3C15 1.34 13.66 0 12 0C10.34 0 9 1.34 9 3C9 4.66 10.34 6 12 6ZM12 2C12.55 2 13 2.45 13 3C13 3.55 12.55 4 12 4C11.45 4 11 3.55 11 3C11 2.45 11.45 2 12 2Z\"\n fill=\"#151A23\"\n />\n <path\n d=\"M3.9999 2.49687L1.49677 5L3.9999 7.50313L6.50303 5L3.9999 2.49687Z\"\n fill=\"#151A23\"\n />\n <path d=\"M20 3L17.5 7H22.5L20 3Z\" fill=\"#151A23\" />\n </Icon>\n </IconContainer>\n <ModalTitle>{titleText}</ModalTitle>\n </ModalHeaderLeft>\n <Icon\n cursor={\"pointer\"}\n hover={`\n rotate: 180deg;\n `}\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n onClick={onClose}\n >\n <path\n d=\"M14 1.41L12.59 0L7 5.59L1.41 0L0 1.41L5.59 7L0 12.59L1.41 14L7 8.41L12.59 14L14 12.59L8.41 7L14 1.41Z\"\n fill=\"#7B7B7B\"\n />\n </Icon>\n </ModalHeader>\n <ModalDescription>{descriptionText}</ModalDescription>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n placeholder: \"NEAR account ID\",\n value: inputValue,\n onChange: onInputChange,\n postInputChildren: (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: \"Add\",\n onClick: handleAddAccount,\n style: { borderRadius: `0px 4px 4px 0px` },\n submit: true,\n }}\n />\n ),\n handleKeyPress: (e) => {\n if (e.key === \"Enter\") {\n handleAddAccount();\n }\n },\n error: accountError,\n }}\n />\n <Space height={24} />\n <MembersText>\n <MembersCount>{accountIds.length} </MembersCount>\n {accountIds.length == 1 ? unitText : `${unitText}s`}\n </MembersText>\n <Widget\n src={\"old.potlock.near/widget/Components.AccountsList\"}\n props={{\n accountIds,\n allowRemove: true,\n handleRemoveAccount,\n }}\n />\n </>\n ),\n }}\n />\n);\n" }, "Cart.CartModalItem": { "": "const profile = Social.getr(`${props.projectId}/profile`);\nconst IPFS_BASE_URL = \"https://nftstorage.link/ipfs/\";\n// const TRASH_ICON_URL =\n// IPFS_BASE_URL + \"bafkreifuvrxly3wuy4xdmavmdeb2o47nv6pzxwz3xmy6zvkxv76e55lj3y\";\nconst TrashContainer = styled.div`\n position: absolute;\n top: 0;\n right: 0;\n width: 32px;\n height: 32px;\n opacity: 0;\n transition: opacity 0.3s ease;\n display: flex;\n align-items: flex-start;\n justify-content: flex-end;\n cursor: pointer;\n`;\nconst TrashIcon = styled.svg`\n width: 20px;\n height: 20px;\n path {\n transition: 300ms;\n }\n :hover path {\n fill: #dd3345;\n }\n`;\nconst ItemContainer = styled.div`\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n justify-content: center;\n padding: 24px;\n border-bottom: 1px #dbdbdb solid;\n &:hover ${TrashContainer} {\n opacity: 1;\n }\n`;\nconst ProjectDetails = styled.div`\n display: flex;\n flex-direction: column;\n position: relative;\n`;\nconst Text = styled.div`\n color: #2e2e2e;\n font-size: 16px;\n line-height: 24px;\n word-wrap: break-word;\n max-width: 270px;\n`;\nconst MAX_DESCRIPTION_LENGTH = 120;\nif (!profile) return \"\";\nreturn (\n <ItemContainer>\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{\n accountId: props.projectId,\n style: {\n width: \"40px\",\n height: \"40px\",\n border: \"none\",\n marginRight: \"24px\",\n },\n className: \"mb-2\",\n imageClassName: \"rounded-circle w-100 h-100 d-block\",\n thumbnail: false,\n }}\n />\n <ProjectDetails>\n <Text style={{ fontWeight: 600 }}>{profile.name}</Text>\n <Text>\n {profile.description.length > MAX_DESCRIPTION_LENGTH\n ? profile.description.slice(0, MAX_DESCRIPTION_LENGTH) + \"...\"\n : profile.description}\n </Text>\n <TrashContainer\n onClick={() => props.removeProjectsFromCart([props.projectId])}\n >\n <TrashIcon\n viewBox=\"0 0 12 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M2.5 14C2.0875 14 1.73437 13.8531 1.44062 13.5594C1.14687 13.2656 1 12.9125 1 12.5V2.5H0V1H4V0H8V1H12V2.5H11V12.491C11 12.9137 10.8531 13.2708 10.5594 13.5625C10.2656 13.8542 9.9125 14 9.5 14H2.5ZM9.5 2.5H2.5V12.5H9.5V2.5ZM4 11H5.5V4H4V11ZM6.5 11H8V4H6.5V11Z\"\n fill=\"#7B7B7B\"\n />\n </TrashIcon>\n </TrashContainer>\n </ProjectDetails>\n </ItemContainer>\n);\n" }, "Pots.Donations": { "": "// get donations\nconst {\n potId,\n allDonations,\n potDetail: { base_currency },\n} = props;\nconst { SUPPORTED_FTS } = VM.require(\"old.potlock.near/widget/constants\") || {\n SUPPORTED_FTS: {},\n};\nconst { getTimePassed, _address } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n) || {\n getTimePassed: () => \"\",\n _address: (address) => address,\n};\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getPublicRoundDonations: () => {},\n};\nState.init({\n filteredDonations: [],\n currentFilter: \"date\",\n filter: {\n date: false, // false === ascending\n price: false, // false === ascending\n },\n});\nconst { filteredDonations, currentFilter, filter } = state;\nuseEffect(() => {\n if (allDonations && filteredDonations.length === 0) {\n const sortedDonations = [...allDonations].reverse();\n State.update({ filteredDonations: sortedDonations });\n }\n}, [allDonations]);\nif (!allDonations)\n return <div class=\"spinner-border text-secondary\" role=\"status\" />;\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n @media screen and (min-width: 375px) and (max-width: 768px) {\n width: 99%;\n }\n @media screen and (max-width: 390px) {\n width: 98%;\n }\n`;\nconst OuterTextContainer = styled.div`\n display: flex;\n flex-direction: row;\n gap: 1.5rem;\n align-items: center;\n @media screen and (max-width: 768px) {\n padding-right: 10px;\n }\n`;\nconst OuterText = styled.div`\n font-size: 18px;\n font-weight: 600;\n`;\nconst DonationsCount = styled.div`\n font-size: 16px;\n`;\nconst TableContainer = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n border: 0.5px rgba(41, 41, 41, 0.5) solid;\n box-shadow: 0px 4px 12px -4px rgba(82, 82, 82, 0.2);\n border-radius: 2px;\n width: 100%;\n overflow-x: auto;\n flex-wrap: nowrap;\n`;\nconst Sort = styled.div`\n display: none;\n justify-content: space-between;\n width: 100%;\n margin-top: 1.5rem;\n div {\n display: flex;\n align-items: center;\n font-weight: 500;\n cursor: pointer;\n gap: 8px;\n color: #7b7b7b;\n &.active {\n color: #292929;\n }\n svg {\n transition: rotate 300ms;\n }\n }\n @media screen and (max-width: 768px) {\n display: flex;\n }\n`;\nconst Arrow = (props) => (\n <svg\n {...props}\n style={{ rotate: !props.active ? \"0deg\" : \"180deg\" }}\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M0 6L1.0575 7.0575L5.25 2.8725V12H6.75V2.8725L10.935 7.065L12 6L6 0L0 6Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n);\nconst searchDonations = (searchTerm) => {\n // filter donations that match the search term (donor_id, project_id)\n const filteredDonations = allDonations.filter((donation) => {\n const { donor_id, project_id } = donation;\n const searchFields = [donor_id, project_id];\n return searchFields.some((field) =>\n field.toLowerCase().includes(searchTerm.toLowerCase())\n );\n });\n return filteredDonations;\n};\nconst sortDonation = (type) => {\n const sort = !filter[type];\n State.update({ currentFilter: type, filter: { ...filter, [type]: sort } });\n if (type === \"price\") {\n const sortedDonations = filteredDonations.sort((a, b) =>\n sort ? b.total_amount - a.total_amount : a.total_amount - b.total_amount\n );\n State.update({ filteredDonations: sortedDonations });\n } else if (type === \"date\") {\n const sortedDonations = filteredDonations.sort((a, b) => {\n return sort ? b.donated_at - a.donated_at : a.donated_at - b.donated_at;\n });\n State.update({ filteredDonations: sortedDonations });\n }\n};\nconst handleSearch = ({ target: { value } }) => {\n const filteredDonations = searchDonations(value);\n State.update({ filteredDonations });\n};\nconst ProfileImg = (address) => (\n <Widget\n src={\"old.potlock.near/widget/Project.ProfileImage\"}\n props={{\n ...props,\n accountId: address,\n style: {},\n }}\n />\n);\nreturn (\n <Container>\n <OuterTextContainer>\n <OuterText>All donations</OuterText>\n <DonationsCount>{allDonations.length}</DonationsCount>\n </OuterTextContainer>\n <Sort>\n <div\n className={`${currentFilter === \"date\" ? \"active\" : \"\"}`}\n onClick={() => sortDonation(\"date\")}\n >\n Sort Date {currentFilter === \"date\" && <Arrow active={!filter.date} />}\n </div>\n <div\n onClick={() => sortDonation(\"price\")}\n className={`${currentFilter === \"price\" ? \"active\" : \"\"}`}\n >\n Sort Amount{\" \"}\n {currentFilter === \"price\" && <Arrow active={filter.price} />}\n </div>\n </Sort>\n <Widget\n src={\"old.potlock.near/widget/Pots.DonationsTable\"}\n props={{\n ...props,\n filteredDonations,\n filter,\n currentFilter,\n handleSearch,\n sortDonation,\n }}\n />\n </Container>\n);\n" }, "Pots.PayoutsChallenges": { "": "const { potId, hrefWithParams } = props;\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getPayoutsChallenges: () => {},\n adminUpdatePayoutsChallenge: () => {},\n isUserPotAdminOrGreater: () => false,\n};\nconst { getTimePassed } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n) || {\n getTimePassed: () => \"\",\n};\nconst payoutsChallenges = PotSDK.getPayoutsChallenges(potId); // TODO: ADD THIS BACK IN\nconst userIsAdminOrGreater = PotSDK.isUserPotAdminOrGreater(\n potId,\n context.accountId\n); // TODO: ADD THIS BACK IN\nState.init({\n adminModalChallengerId: \"\",\n challengeAdminNotes: \"\",\n challengeAdminNotesError: \"\",\n resolveChallenge: false,\n toggleChallenges: false,\n});\nconst {\n adminModalChallengerId,\n challengeAdminNotes,\n challengeAdminNotesError,\n resolveChallenge,\n toggleChallenges,\n} = state;\nconst MAX_CHALLENGE_TEXT_LENGTH = 1000;\nconst handleAdminUpdateChallenge = () => {\n PotSDK.adminUpdatePayoutsChallenge(\n potId,\n adminModalChallengerId,\n challengeAdminNotes,\n resolveChallenge\n );\n State.update({\n adminModalChallengerId: \"\",\n challengeAdminNotes: \"\",\n challengeAdminNotesError: \"\",\n resolveChallenge: false,\n });\n};\nconst handleCancelAdminUpdateChallenge = () => {\n State.update({\n adminModalChallengerId: \"\",\n challengeAdminNotes: \"\",\n challengeAdminNotesError: \"\",\n resolveChallenge: false,\n });\n};\nconst Line = styled.div`\n width: 100%;\n height: 1px;\n background: #c7c7c7;\n margin: 3rem 0;\n`;\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n`;\nconst Title = styled.div`\n font-size: 18px;\n display: flex;\n align-items: center;\n gap: 1.5rem;\n width: fit-content;\n cursor: pointer;\n margin-bottom: 1.5rem;\n div:first-of-type {\n font-weight: 600;\n }\n svg {\n rotate: 180deg;\n transition: all 300ms ease-in-out;\n }\n`;\nconst Table = styled.div`\n display: flex;\n flex-direction: column;\n width: 100%;\n border-radius: 6px;\n border: 1px solid #7b7b7b;\n transition: max-height 400ms ease-in-out;\n overflow: hidden;\n max-height: 1000px;\n opacity: 1;\n &.hidden {\n opacity: 0;\n max-height: 0;\n }\n`;\nconst Challenge = styled.div`\n display: flex;\n padding: 1rem;\n border-bottom: 1px solid #c7c7c7;\n font-size: 14px;\n &:last-of-type {\n border-bottom: none;\n }\n .vertical-line {\n height: 100%;\n background: #c7c7c7;\n width: 1px;\n transform: translateX(0.75rem);\n z-index: -1;\n }\n .profile-image {\n width: 1.5rem;\n height: 1.5rem;\n margin-right: 0.5rem;\n }\n .admin-icon {\n margin-right: 0.75rem;\n svg {\n width: 1.5rem;\n height: 1.5rem;\n }\n }\n .content {\n display: flex;\n flex-direction: column;\n }\n .header {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.5rem;\n }\n .id {\n font-weight: 600;\n color: #292929;\n transition: 200ms;\n :hover {\n text-decoration: none;\n color: #dd3345;\n }\n }\n .title {\n font-weight: 600;\n color: #8b5af8;\n }\n .reason {\n color: #7b7b7b;\n margin-top: 0.5rem;\n margin-bottom: 1rem;\n padding-left: 2.5rem;\n background: white;\n }\n .admin-header {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n }\n .dot {\n background: #7b7b7b;\n width: 5px;\n height: 5px;\n border-radius: 50%;\n }\n .resolved-state {\n font-weight: 600;\n }\n .resolve-btn {\n cursor: pointer;\n background: none;\n border: none;\n }\n @media only screen and (max-width: 480px) {\n .profile-image {\n margin-right: 0;\n }\n .admin-icon {\n margin-right: 0.25rem;\n }\n .reason {\n padding-left: 2rem;\n }\n .date {\n width: 100%;\n margin-top: -0.5rem;\n padding-left: 2rem;\n }\n }\n`;\nconst ModalHeader = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-start;\n background: white;\n padding: 24px 24px 12px 24px;\n border-top-left-radius: 6px;\n border-top-right-radius: 6px;\n font-weight: 500;\n`;\nconst ModalBody = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n padding: 24px;\n border-top: 1px #f0f0f0 solid;\n background: #fafafa;\n gap: 8px;\n`;\nconst ModalFooter = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-end;\n background: #fafafa;\n padding: 12px 24px 24px 24px;\n border-bottom-left-radius: 6px;\n border-bottom-right-radius: 6px;\n gap: 24px;\n width: 100%;\n`;\nconst HeaderItemText = styled.div`\n color: #292929;\n font-size: 14px;\n font-weight: 600;\n line-height: 24px;\n word-wrap: break-word;\n`;\nconst AdminSVG = () => (\n <div className=\"admin-icon\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <mask id=\"path-1-inside-1_10044_14103\" fill=\"white\">\n <path d=\"M0 12C0 5.37258 5.37258 0 12 0C18.6274 0 24 5.37258 24 12C24 18.6274 18.6274 24 12 24C5.37258 24 0 18.6274 0 12Z\" />\n </mask>\n <path\n d=\"M0 12C0 5.37258 5.37258 0 12 0C18.6274 0 24 5.37258 24 12C24 18.6274 18.6274 24 12 24C5.37258 24 0 18.6274 0 12Z\"\n fill=\"#656565\"\n />\n <path\n d=\"M-0.666667 12C-0.666667 5.00439 5.00439 -0.666667 12 -0.666667C18.9956 -0.666667 24.6667 5.00439 24.6667 12H23.3333C23.3333 5.74077 18.2592 0.666667 12 0.666667C5.74077 0.666667 0.666667 5.74077 0.666667 12H-0.666667ZM24.6667 12.6667C24.6667 19.6623 18.9956 25.3333 12 25.3333C5.00439 25.3333 -0.666667 19.6623 -0.666667 12.6667L0.666667 12C0.666667 17.891 5.74077 22.6667 12 22.6667C18.2592 22.6667 23.3333 17.891 23.3333 12L24.6667 12.6667ZM12 25.3333C5.00439 25.3333 -0.666667 19.6623 -0.666667 12.6667V12C-0.666667 5.00439 5.00439 -0.666667 12 -0.666667V0.666667C5.74077 0.666667 0.666667 5.74077 0.666667 12C0.666667 17.891 5.74077 22.6667 12 22.6667V25.3333ZM12 -0.666667C18.9956 -0.666667 24.6667 5.00439 24.6667 12V12.6667C24.6667 19.6623 18.9956 25.3333 12 25.3333V22.6667C18.2592 22.6667 23.3333 17.891 23.3333 12C23.3333 5.74077 18.2592 0.666667 12 0.666667V-0.666667Z\"\n fill=\"#292929\"\n mask=\"url(#path-1-inside-1_10044_14103)\"\n />\n <path\n d=\"M9.20029 12.7527L11.087 10.866L6.40695 6.19268C5.36695 7.23268 5.36695 8.91935 6.40695 9.96601L9.20029 12.7527ZM13.7203 11.546C14.7403 12.0193 16.1736 11.686 17.2336 10.626C18.507 9.35268 18.7536 7.52601 17.7736 6.54601C16.8003 5.57268 14.9736 5.81268 13.6936 7.08601C12.6336 8.14601 12.3003 9.57935 12.7736 10.5993L6.26695 17.106L7.20695 18.046L11.8003 13.466L16.387 18.0527L17.327 17.1127L12.7403 12.526L13.7203 11.546Z\"\n fill=\"white\"\n />\n </svg>\n </div>\n);\nconst ProfileImg = ({ address }) => (\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{ accountId: address, style: {} }}\n />\n);\nconsole.log(\"payoutsChallenges\", payoutsChallenges);\nreturn !payoutsChallenges ? (\n \"Loading...\"\n) : payoutsChallenges.length === 0 ? (\n \"\"\n) : (\n <>\n <Container>\n <Title\n onClick={() =>\n State.update({\n toggleChallenges: !toggleChallenges,\n })\n }\n >\n <div>Payout Challenges</div>\n <div>{payoutsChallenges?.length}</div>\n <svg\n width=\"12\"\n height=\"8\"\n viewBox=\"0 0 12 8\"\n style={{\n rotate: toggleChallenges ? \"0deg\" : \"180deg\",\n }}\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 0.294922L0 6.29492L1.41 7.70492L6 3.12492L10.59 7.70492L12 6.29492L6 0.294922Z\"\n fill=\"#151A23\"\n />\n </svg>\n </Title>\n <Table className={`${!toggleChallenges ? \"hidden\" : \"\"}`}>\n {payoutsChallenges.map(\n ({ challenger_id, admin_notes, created_at, reason, resolved }) => (\n <Challenge key={challenger_id}>\n {/* <div className=\"vertical-line\" /> */}\n <div className=\"content\">\n <div className=\"header\">\n <ProfileImg address={challenger_id} />\n <a\n className=\"id\"\n href={hrefWithParams(\n `?tab=profile&accountId=${challenger_id}`\n )}\n >\n {challenger_id}\n </a>\n <div className=\"title\">Challenged payout</div>\n <div className=\"date\"> {getTimePassed(created_at)}</div>\n </div>\n <div className=\"reason\">{reason}</div>\n <div className=\"admin-header\">\n <AdminSVG />\n <div\n className=\"resolved-state\"\n style={{\n color: resolved ? \"#4a7714\" : \"#C7C7C7\",\n }}\n >\n {resolved ? \"Resolved\" : \"Unresolved\"}\n </div>\n {resolved ? (\n <>\n <div className=\"dot\" />\n <div>1 Response</div>\n </>\n ) : userIsAdminOrGreater ? (\n <>\n <div className=\"dot\" />\n <button\n className=\"resolve-btn\"\n onClick={() =>\n State.update({\n adminModalChallengerId: challenger_id,\n })\n }\n >\n Reply\n </button>\n </>\n ) : (\n \"\"\n )}\n </div>\n <div className=\"reason\">{admin_notes}</div>\n </div>\n </Challenge>\n )\n )}\n </Table>\n {/* Admin update challenge modal */}\n <Widget\n src={\"old.potlock.near/widget/Components.Modal\"}\n props={{\n isModalOpen: adminModalChallengerId,\n onClose: handleCancelAdminUpdateChallenge,\n contentStyle: {\n padding: \"0px\",\n },\n children: (\n <>\n <ModalHeader>\n Update Challenge from {adminModalChallengerId}\n </ModalHeader>\n <ModalBody>\n <HeaderItemText>Challenge Reason:</HeaderItemText>\n <div>\n {\n payoutsChallenges.find(\n (challenge) =>\n challenge.challenger_id === adminModalChallengerId\n ).reason\n }\n </div>\n <Widget\n src={\"old.potlock.near/widget/Inputs.TextArea\"}\n props={{\n noLabel: true,\n inputRows: 5,\n inputStyle: {\n background: \"#FAFAFA\",\n },\n placeholder: \"Respond to the challenge here\",\n value: challengeAdminNotes,\n onChange: (challengeAdminNotes) =>\n State.update({ challengeAdminNotes }),\n validate: () => {\n if (\n challengeAdminNotes.length > MAX_CHALLENGE_TEXT_LENGTH\n ) {\n State.update({\n challengeAdminNotesError: `Notes must be less than ${MAX_CHALLENGE_TEXT_LENGTH} characters`,\n });\n return;\n }\n State.update({ challengeAdminNotesError: \"\" });\n },\n error: challengeAdminNotesError,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Inputs.Checkbox\"}\n props={{\n // id: \"registrationSelector\",\n label: \"Resolve this challenge?\",\n checked: resolveChallenge,\n onClick: (e) => {\n State.update({\n resolveChallenge: e.target.checked,\n });\n },\n }}\n />\n </ModalBody>\n <ModalFooter>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"tertiary\",\n text: \"Cancel\",\n onClick: handleCancelAdminUpdateChallenge,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: \"Submit\",\n disabled:\n !challengeAdminNotes || !!challengeAdminNotesError,\n onClick: handleAdminUpdateChallenge,\n }}\n />\n </ModalFooter>\n </>\n ),\n }}\n />\n </Container>\n <Line />\n </>\n);\n" }, "Cart.NavItem": { "": "const { getCartItemCount } = VM.require(\"old.potlock.near/widget/SDK.cart\") ?? {\n getCartItemCount: () => 0,\n};\nconst { CartModal } = VM.require(\"old.potlock.near/widget/Cart.Modal\") ?? {\n CartModal: () => <></>,\n};\nconst navHeightPx = 110;\nconst navHeightPxMobile = 96;\nconst numCartItems = getCartItemCount();\nconst CartButton = styled.div`\n padding: ${numCartItems > 0 ? \"8px 8px 8px 16px\" : \"8px 16px\"};\n background: #2e2e2e;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n`;\nconst CartText = styled.div`\n color: white;\n font-size: 14px;\n font-weight: 600;\n line-height: 20px;\n word-wrap: break-word;\n text-align: center;\n`;\nconst CartCountContainer = styled.div`\n display: flex;\n flex-direction: row;\n justify-content: center;\n align-items: center;\n background: #f86b3f;\n border-radius: 50%;\n // padding: 0 4px;\n width: 18px;\n height: 18px;\n margin-left: 8px;\n`;\nreturn (\n <CartModal\n Trigger={({ openModal }) => (\n <CartButton onClick={() => openModal()}>\n <CartText>Cart</CartText>\n {numCartItems > 0 && (\n <CartCountContainer>\n <CartText style={{ fontSize: \"12px\" }}>{numCartItems}</CartText>\n </CartCountContainer>\n )}\n </CartButton>\n )}\n />\n);\n" }, "Pots.UNUSED.ModalSybil": { "": "const { isModalOpen, onClose } = props;\nconst { NADA_BOT_URL } = VM.require(\"old.potlock.near/widget/constants\") || {\n NADA_BOT_URL: \"\",\n};\nconst IPFS_BASE_URL = \"https://nftstorage.link/ipfs/\";\nconst CLOSE_ICON_URL =\n IPFS_BASE_URL + \"bafkreifyg2vvmdjpbhkylnhye5es3vgpsivhigkjvtv2o4pzsae2z4vi5i\";\nconst ERROR_ICON_URL =\n IPFS_BASE_URL + \"bafkreicqarojxk6jhdtsk2scfsmnigqpxjfgar6om4wlhn5xmqbbu74u5i\";\nconst IMAGE_URL =\n IPFS_BASE_URL + \"bafkreidwashbfmlr7qo2yoqcfdsqi4ouisgt6h6jwxymz53v2f7hhoy75a\";\nconst ModalHeader = styled.div`\n width: 100%;\n padding: 10px 20px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n background: #f6f5f3;\n`;\nconst ModalHeaderText = styled.div`\n font-size: 17px;\n font-weight: 600;\n line-height: 24px;\n color: #292929;\n`;\nconst Icon = styled.img`\n width: 24px;\n height: 24px;\n`;\nconst ModalContent = styled.div`\n padding: 16px 20px 32px 20px;\n display: flex;\n flex-direction: column;\n gap: 24px;\n align-items: center;\n justify-content: center;\n`;\nconst Row = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n`;\nconst ContentHeaderText = styled.div`\n margin-left: 24px;\n font-size: 32px;\n font-weight: 400;\n line-height: 40px;\n color: #525252;\n font-family: \"Lora\";\n`;\nconst ContentDescriptionText = styled.div`\n font-size: 16px;\n font-weight: 400;\n line-height: 28px;\n`;\nconst ErrorSpan = styled.span`\n color: #dd3345;\n`;\nconst BoldSpan = styled.span`\n font-weight: 600;\n`;\nconst Image = styled.img`\n width: 100px;\n max-height: 245px;\n margin: 0px 32px;\n`;\nreturn (\n <Widget\n src={\"old.potlock.near/widget/Components.Modal\"}\n props={{\n ...props,\n isModalOpen,\n onClose,\n children: (\n <>\n <ModalHeader>\n <div></div>\n <ModalHeaderText>Verify Via Nada.bot</ModalHeaderText>\n <Icon cursor={\"pointer\"} src={CLOSE_ICON_URL} onClick={onClose} />\n </ModalHeader>\n <ModalContent>\n <Row>\n <Icon\n style={{ width: \"35px\", height: \"35px\" }}\n src={ERROR_ICON_URL}\n />\n <ContentHeaderText>\n You Are <ErrorSpan>Not verified</ErrorSpan>\n </ContentHeaderText>\n </Row>\n <Row>\n <ContentDescriptionText>\n To donate to a project via this pot, you need to get verified\n from <BoldSpan>Nada.bot</BoldSpan>\n </ContentDescriptionText>\n </Row>\n <Image src={IMAGE_URL} />\n <Row style={{ alignItems: \"flex-end\" }}>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n href: NADA_BOT_URL,\n target: \"_blank\",\n type: \"primary\",\n text: \"Get Verified Now\",\n // style: {\n // width: \"300px\",\n // },\n }}\n />\n </Row>\n </ModalContent>\n </>\n ),\n }}\n />\n);\n" }, "ModalDonation.Main": { "": "const Container = styled.div`\n display: flex;\n flex-direction: column;\n border-radius: 12px;\n background: #fff;\n font-size: 14px;\n box-shadow: 0px 0px 0px 1px rgba(41, 41, 41, 0.1),\n 0px 8px 12px -4px rgba(41, 41, 41, 0.1),\n 0px 20px 32px -10px rgba(41, 41, 41, 0.1),\n 0px 32px 44px -16px rgba(41, 41, 41, 0.1);\n overflow: hidden;\n border-radius: 6px;\n @media only screen and (max-width: 480px) {\n top: 0;\n border-radius: 0;\n position: fixed;\n left: 0;\n width: 100vw;\n height: 100vh;\n overflow-y: scroll;\n display: flex;\n z-index: 1000;\n }\n`;\nconst Banner = styled.div`\n position: relative;\n display: flex;\n flex-direction: column;\n padding: 1.5rem 2rem;\n gap: 0.5rem;\n overflow: hidden;\n background: #dd3345;\n color: white;\n font-size: 22px;\n .left-pattern {\n position: absolute;\n left: 0;\n top: 0;\n width: 30%;\n transform: translate(-10%, -10%) scaleX(-1);\n pointer-events: none;\n }\n .right-pattern {\n position: absolute;\n right: 0;\n top: 0;\n width: 30%;\n transform: translate(10%, -10%);\n pointer-events: none;\n }\n @media only screen and (max-width: 480px) {\n padding: 1.125rem;\n }\n`;\nconst BannerBg = (props) => (\n <svg\n {...props}\n viewBox=\"0 0 145 152\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <rect\n x=\"157.654\"\n y=\"-37\"\n width=\"20\"\n height=\"161.118\"\n rx=\"10\"\n transform=\"rotate(45 157.654 -37)\"\n fill=\"white\"\n fill-opacity=\"0.08\"\n />\n <rect\n x=\"189.654\"\n y=\"-37\"\n width=\"20\"\n height=\"245.972\"\n rx=\"10\"\n transform=\"rotate(45 189.654 -37)\"\n fill=\"white\"\n fill-opacity=\"0.08\"\n />\n <rect\n x=\"221.654\"\n y=\"-37\"\n width=\"20\"\n height=\"164.654\"\n rx=\"10\"\n transform=\"rotate(45 221.654 -37)\"\n fill=\"white\"\n fill-opacity=\"0.08\"\n />\n <rect\n x=\"125.654\"\n y=\"-37\"\n width=\"20\"\n height=\"177.702\"\n rx=\"10\"\n transform=\"rotate(45 125.654 -37)\"\n fill=\"white\"\n fill-opacity=\"0.08\"\n />\n <rect\n x=\"93.6543\"\n y=\"-37\"\n width=\"20\"\n height=\"78.4889\"\n rx=\"10\"\n transform=\"rotate(45 93.6543 -37)\"\n fill=\"white\"\n fill-opacity=\"0.08\"\n />\n </svg>\n);\nconst HeaderIcons = styled.div`\n display: flex;\n align-items: center;\n justify-content: space-between;\n svg {\n width: 14px;\n cursor: pointer;\n transition: all 300ms ease-in-out;\n }\n .close-icon {\n margin-left: auto;\n &:hover {\n rotate: 90deg;\n }\n }\n div {\n cursor: pointer;\n display: flex;\n }\n .back-arrow:hover svg {\n transform: translateX(-10px);\n }\n`;\nconst DENOMINATION_OPTIONS = [{ text: \"NEAR\", value: \"NEAR\", decimals: 24 }];\nconst {\n projectId,\n referrerId,\n potId,\n onClose,\n NADABOT_CONTRACT_ID,\n POT,\n multiple,\n potDetail,\n} = props;\nconst DEFAULT_DONATION_AMOUNT = \"1\";\nconst accountId = context.accountId;\nconst initialState = {\n amount: \"\",\n donationType: multiple ? \"auto\" : \"direct\",\n showBreakdown: false,\n bypassProtocolFee: false,\n bypassChefFee: false,\n addNote: false,\n donationNote: \"\",\n donationNoteError: \"\",\n allPots: null,\n intervalId: null,\n ftBalances: null,\n selectedDenomination: DENOMINATION_OPTIONS[0],\n denominationOptions: DENOMINATION_OPTIONS,\n selectedRound: \"\",\n currentPage: multiple ? \"formPot\" : \"form\",\n selectedProjects: {},\n toggleAmount: true,\n};\nState.init(initialState);\nconst {\n amount,\n denomination,\n donationType,\n showBreakdownm,\n bypassProtocolFee,\n bypassChefFee,\n addNote,\n donationNote,\n donationNoteError,\n allPots,\n intervalId,\n nearBalance,\n ftBalances,\n denominationOptions,\n selectedDenomination,\n selectedRound,\n currentPage,\n} = state;\nconst [activeRounds, setActiveRounds] = useState(null);\nconst profile = Social.getr(`${projectId}/profile`);\nconst profileName = profile?.name || projectId;\nconst MAX_NOTE_LENGTH = 60;\nconst {\n DONATION_CONTRACT_ID,\n NADABOT_HUMAN_METHOD,\n NADA_BOT_URL,\n SUPPORTED_FTS,\n} = VM.require(\"old.potlock.near/widget/constants\") || {\n DONATION_CONTRACT_ID: \"\",\n NADABOT_HUMAN_METHOD: \"\",\n NADA_BOT_URL: \"\",\n SUPPORTED_FTS: {},\n};\nlet ListsSDK =\n VM.require(\"old.potlock.near/widget/SDK.lists\") ||\n (() => ({\n getRegistrations: () => {},\n }));\nListsSDK = ListsSDK({ env: props.env });\nlet DonateSDK =\n VM.require(\"old.potlock.near/widget/SDK.donate\") ||\n (() => ({\n getConfig: () => {},\n asyncGetDonationsForDonor: () => {},\n }));\nDonateSDK = DonateSDK({ env: props.env });\nlet PotFactorySDK =\n VM.require(\"old.potlock.near/widget/SDK.potfactory\") ||\n (() => ({\n getPots: () => {},\n }));\nPotFactorySDK = PotFactorySDK({ env: props.env });\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getConfig: () => {},\n asyncGetConfig: () => {},\n getApprovedApplications: () => {},\n asyncGetApplicationByProjectId: () => {},\n asyncGetDonationsForDonor: () => {},\n isRoundActive: () => {},\n};\nconst { nearToUsd, formatWithCommas } = VM.require(\n \"old.potlock.near/widget/utils\"\n) || {\n nearToUsd: 1,\n formatWithCommas: () => {},\n};\nconst { addItemsToCart, clearCart } = VM.require(\n \"old.potlock.near/widget/SDK.cart\"\n) || {\n addItemsToCart: () => {},\n clearCart: () => {},\n};\nconst { FormDirect } = VM.require(\n \"old.potlock.near/widget/ModalDonation.Form\"\n) || {\n FormDirect: () => {},\n};\nconst { FormPot } = VM.require(\n \"old.potlock.near/widget/ModalDonation.FormPot\"\n) || {\n FormPot: () => {},\n};\nconst { ConfirmDirect } = VM.require(\n \"old.potlock.near/widget/ModalDonation.ConfirmDirect\"\n) || {\n ConfirmDirect: () => {},\n};\nconst { ConfirmPot } = VM.require(\n \"old.potlock.near/widget/ModalDonation.ConfirmPot\"\n) || {\n ConfirmPot: () => {},\n};\nconst pages = {\n form: FormDirect,\n formPot: FormPot,\n confirm: ConfirmDirect,\n confirmPot: ConfirmPot,\n};\nconst ActivePageComponent = pages[currentPage];\n// get all active pots\nconst pots = useCache(\n () =>\n // get all pots\n PotFactorySDK.asyncGetPots()\n .then((pots) => {\n const activePots = pots.map((pot) =>\n // if active\n PotSDK.isRoundActive(pot.id)\n // check if project had applied\n .then((isActive) => isActive && pot.id)\n .catch((e) => {\n console.error(\n \"error checking active round for pot: \" + pot.id,\n e\n );\n })\n );\n return Promise.all(activePots);\n })\n .catch((e) => {\n console.error(\"error getting pots: \", e);\n }),\n \"active-pots\"\n);\nuseEffect(() => {\n if (potId && !activeRounds) {\n setActiveRounds([potId]);\n State.update({\n selectedRound: potId,\n donationType: multiple ? \"auto\" : \"pot\",\n });\n } else if (!activeRounds?.length && projectId) {\n if (!pots) setActiveRounds([]);\n (pots ?? []).forEach((pot, idx) => {\n if (pot) {\n PotSDK.asyncGetApplicationByProjectId(pot, projectId)\n .then((application) => {\n if (application.status === \"Approved\") {\n setActiveRounds((prev) => {\n const prevRounds = prev || [];\n if (!prevRounds.includes(pot)) {\n return [...prevRounds, pot];\n }\n });\n if (!selectedRound)\n State.update({\n selectedRound: pot,\n });\n } else if (pots.length - 1 === idx && !activeRounds) {\n setActiveRounds((prev) => [...(prev || [])]);\n }\n })\n .catch((err) => {\n console.log(err);\n setActiveRounds((prev) => [...(prev || [])]);\n });\n }\n });\n }\n}, [pots]);\n// Get Ft Balances\nuseEffect(() => {\n if (!ftBalances && !potId) {\n asyncFetch(\n `https://near-mainnet.api.pagoda.co/eapi/v1/accounts/${accountId}/balances/FT`,\n {\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": \"dce81322-81b0-491d-8880-9cfef4c2b3c2\",\n },\n }\n )\n .then((ftBalancesRes) => {\n if (ftBalancesRes) {\n const ftBalances = ftBalancesRes.body.balances;\n State.update({\n ftBalances: ftBalances,\n denominationOptions: DENOMINATION_OPTIONS.concat(\n ftBalances\n .map(({ amount, contract_account_id, metadata }) => ({\n amount,\n id: contract_account_id,\n text: metadata.symbol,\n value: metadata.symbol,\n icon: metadata.icon,\n decimals: metadata.decimals,\n }))\n .filter((option) => option.text.length < 10)\n ),\n });\n }\n })\n .catch((err) => console.log(\"fetching Ft balances faild\"));\n }\n}, [ftBalances]);\nconst nearBalanceRes = fetch(\n `https://near-mainnet.api.pagoda.co/eapi/v1/accounts/${accountId}/balances/NEAR`,\n {\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": \"dce81322-81b0-491d-8880-9cfef4c2b3c2\",\n },\n }\n);\nconst ftBalance = useMemo(() => {\n if (selectedDenomination.text === \"NEAR\") {\n const nearBalance = nearBalanceRes?.body?.balance;\n return nearBalance\n ? parseFloat(Big(nearBalance.amount).div(Big(10).pow(24)).toFixed(2))\n : null;\n }\n const balance = denominationOptions.find(\n // this is where we need the details\n (option) => option.text === selectedDenomination.text\n );\n return balance\n ? parseFloat(\n Big(balance.amount).div(Big(10).pow(balance.decimals)).toFixed(2)\n )\n : null;\n}, [selectedDenomination, ftBalances, nearBalanceRes]);\nreturn (\n <Widget\n src={\"old.potlock.near/widget/Components.Modal\"}\n props={{\n ...props,\n onClose: (e) => {\n e.stopPropagation();\n },\n contentStyle: {\n padding: \"0px\",\n },\n children: (\n <Container>\n <div>\n <Banner>\n <BannerBg className=\"left-pattern\" />\n <BannerBg className=\"right-pattern\" />\n <HeaderIcons>\n {![\"form\", \"formPot\"].includes(currentPage) && (\n <div\n className=\"back-arrow\"\n onClick={() =>\n State.update({\n currentPage: multiple ? \"formPot\" : \"form\",\n })\n }\n >\n <svg\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M16 7H3.83L9.42 1.41L8 0L0 8L8 16L9.41 14.59L3.83 9H16V7Z\"\n fill=\"#FCCFCF\"\n />\n </svg>\n </div>\n )}\n <svg\n onClick={() => onClose()}\n className=\"close-icon\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M14 1.41L12.59 0L7 5.59L1.41 0L0 1.41L5.59 7L0 12.59L1.41 14L7 8.41L12.59 14L14 12.59L8.41 7L14 1.41Z\"\n fill=\"#FCCFCF\"\n />\n </svg>\n </HeaderIcons>\n {[\"confirmPot\", \"confirm\"].includes(currentPage) ? (\n <div> Confirm donation</div>\n ) : currentPage === \"formPot\" ? (\n <div>Donate to Projects in {potDetail?.pot_name}</div>\n ) : (\n <div> Donate to {profileName}</div>\n )}\n </Banner>\n </div>\n <ActivePageComponent\n {...props}\n {...state}\n accountId={accountId}\n updateState={State.update}\n ftBalance={ftBalance}\n activeRounds={activeRounds}\n DENOMINATION_OPTION={DENOMINATION_OPTIONS}\n />\n </Container>\n ),\n }}\n />\n);\n" }, "Pots.FlagModal": { "": "const BannerBg = (props) => (\n <svg\n {...props}\n viewBox=\"0 0 145 152\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <rect\n x=\"157.654\"\n y=\"-37\"\n width=\"20\"\n height=\"161.118\"\n rx=\"10\"\n transform=\"rotate(45 157.654 -37)\"\n fill=\"white\"\n fill-opacity=\"0.08\"\n />\n <rect\n x=\"189.654\"\n y=\"-37\"\n width=\"20\"\n height=\"245.972\"\n rx=\"10\"\n transform=\"rotate(45 189.654 -37)\"\n fill=\"white\"\n fill-opacity=\"0.08\"\n />\n <rect\n x=\"221.654\"\n y=\"-37\"\n width=\"20\"\n height=\"164.654\"\n rx=\"10\"\n transform=\"rotate(45 221.654 -37)\"\n fill=\"white\"\n fill-opacity=\"0.08\"\n />\n <rect\n x=\"125.654\"\n y=\"-37\"\n width=\"20\"\n height=\"177.702\"\n rx=\"10\"\n transform=\"rotate(45 125.654 -37)\"\n fill=\"white\"\n fill-opacity=\"0.08\"\n />\n <rect\n x=\"93.6543\"\n y=\"-37\"\n width=\"20\"\n height=\"78.4889\"\n rx=\"10\"\n transform=\"rotate(45 93.6543 -37)\"\n fill=\"white\"\n fill-opacity=\"0.08\"\n />\n </svg>\n);\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n border-radius: 12px;\n background: #fff;\n font-size: 14px;\n box-shadow: 0px 0px 0px 1px rgba(41, 41, 41, 0.1),\n 0px 8px 12px -4px rgba(41, 41, 41, 0.1),\n 0px 20px 32px -10px rgba(41, 41, 41, 0.1),\n 0px 32px 44px -16px rgba(41, 41, 41, 0.1);\n overflow: hidden;\n border-radius: 6px;\n`;\nconst Banner = styled.div`\n position: relative;\n display: flex;\n flex-direction: column;\n padding: 1.5rem 2rem;\n gap: 0.5rem;\n overflow: hidden;\n background: #dd3345;\n color: white;\n font-size: 22px;\n .left-pattern {\n position: absolute;\n left: 0;\n top: 0;\n width: 30%;\n transform: translate(-10%, -10%) scaleX(-1);\n pointer-events: none;\n }\n .right-pattern {\n position: absolute;\n right: 0;\n top: 0;\n width: 30%;\n transform: translate(10%, -10%);\n pointer-events: none;\n }\n @media only screen and (max-width: 480px) {\n padding: 1.125rem;\n }\n`;\nconst HeaderIcons = styled.div`\n display: flex;\n align-items: center;\n justify-content: space-between;\n svg {\n width: 14px;\n cursor: pointer;\n transition: all 300ms ease-in-out;\n }\n .close-icon {\n margin-left: auto;\n &:hover {\n rotate: 90deg;\n }\n }\n div {\n cursor: pointer;\n display: flex;\n }\n`;\nconst Content = styled.div`\n display: flex;\n flex-direction: column;\n padding: 1.5rem 2rem;\n gap: 1.5rem;\n @media only screen and (max-width: 480px) {\n padding: 1.125rem;\n }\n`;\nconst Label = styled.div`\n font-weight: 500;\n margin-bottom: 0.5rem;\n`;\nconst Limit = styled.div`\n color: #7b7b7b;\n text-align: right;\n`;\nconst InfoCard = styled.div`\n display: flex;\n align-items: center;\n gap: 1rem;\n padding: 0.75rem 1rem;\n width: 100%;\n border-radius: 6px;\n border: 1px solid #ebebeb;\n background: #f6f5f3;\n`;\nconst ButtonsWrapper = styled.div`\n display: grid;\n gap: 1.5rem;\n grid-template-columns: repeat(2, 1fr);\n button {\n font-weight: 500;\n }\n .cancel {\n border: none;\n background: none;\n color: #dd3345;\n }\n`;\nconst MAX_REASON_LENGTH = 250;\nconst accountId = context.accountId;\nconst [reason, setReason] = useState(\"\");\nconst [reasonErr, setReasonErr] = useState(\"\");\nconst { onClose, flagAddress, potId, setSuccessFlag } = props;\nconst onCancel = () => {\n onClose();\n setReason(\"\");\n};\nconst fetchSocialProfile = () => {\n return Near.asyncView(\"social.near\", \"get\", {\n keys: [`${accountId}/profile/**`],\n });\n};\nconst handleSuccess = () => {\n const flsgSuccess = setInterval(() => {\n fetchSocialProfile().then((profileData) => {\n const profile = profileData[accountId].profile;\n const pLBlacklistedAccounts = JSON.parse(\n profile.pLBlacklistedAccounts || \"{}\"\n );\n const potFlaggedAcc = pLBlacklistedAccounts[potId] || {};\n if (potFlaggedAcc[flagAddress]) {\n setSuccessFlag({\n account: flagAddress,\n reason,\n });\n onCancel();\n clearInterval(flsgSuccess);\n }\n });\n }, 1000);\n // Clear the interval after 30 seconds\n setTimeout(() => {\n onCancel();\n clearInterval(flsgSuccess);\n }, 60000);\n};\nconst handleFlag = () => {\n fetchSocialProfile().then((profileData) => {\n const profile = profileData[accountId].profile;\n const pLBlacklistedAccounts = JSON.parse(\n profile.pLBlacklistedAccounts || \"{}\"\n );\n const potFlaggedAcc = pLBlacklistedAccounts[potId] || {};\n const socialArgs = {\n data: {\n [accountId]: {\n profile: {\n pLBlacklistedAccounts: JSON.stringify({\n ...pLBlacklistedAccounts,\n [potId]: {\n ...potFlaggedAcc,\n [flagAddress]: reason,\n },\n }),\n },\n },\n },\n };\n const socialTransaction = {\n contractName: \"social.near\",\n methodName: \"set\",\n args: socialArgs,\n };\n Near.asyncView(\"social.near\", \"get_account\", {\n account_id: accountId,\n }).then((account) => {\n let depositFloat = JSON.stringify(socialArgs).length * 0.00015;\n if (!account) {\n depositFloat += 0.1;\n }\n socialTransaction.deposit = Big(depositFloat).mul(Big(10).pow(24));\n Near.call(socialTransaction);\n handleSuccess();\n });\n });\n};\nreturn (\n <Widget\n src={\"old.potlock.near/widget/Components.Modal\"}\n props={{\n ...props,\n onCancel: (e) => {\n e.stopPropagation();\n },\n contentStyle: {\n padding: \"0px\",\n },\n children: (\n <Container>\n <div>\n <Banner>\n <BannerBg className=\"left-pattern\" />\n <BannerBg className=\"right-pattern\" />\n <HeaderIcons>\n <svg\n onClick={() => onCancel()}\n className=\"close-icon\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M14 1.41L12.59 0L7 5.59L1.41 0L0 1.41L5.59 7L0 12.59L1.41 14L7 8.41L12.59 14L14 12.59L8.41 7L14 1.41Z\"\n fill=\"#FCCFCF\"\n />\n </svg>\n </HeaderIcons>\n Flag {flagAddress}\n </Banner>\n </div>\n <Content>\n <div>\n <Widget\n src={\"old.potlock.near/widget/Inputs.TextArea\"}\n props={{\n label: \"Reason\",\n inputRows: 4,\n inputStyle: {\n background: \"#FAFAFA\",\n },\n placeholder: `Type description`,\n value: reason,\n onChange: (reason) => setReason(reason),\n validate: () => {\n if (reason.length > MAX_REASON_LENGTH) {\n setReasonErr(\n `Reason must be less than ${MAX_REASON_LENGTH} characters`\n );\n return;\n }\n setReasonErr(\"\");\n },\n error: reasonErr,\n }}\n />\n <Limit>\n {reason.length}/{MAX_REASON_LENGTH}\n </Limit>\n </div>\n <InfoCard>\n <div>\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M9 5H11V7H9V5ZM9 9H11V15H9V9ZM10 0C4.48 0 0 4.48 0 10C0 15.52 4.48 20 10 20C15.52 20 20 15.52 20 10C20 4.48 15.52 0 10 0ZM10 18C5.59 18 2 14.41 2 10C2 5.59 5.59 2 10 2C14.41 2 18 5.59 18 10C18 14.41 14.41 18 10 18Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n </div>\n <div>\n Flagging this account will remove their donations when\n calculating payouts for this pot\n </div>\n </InfoCard>\n <ButtonsWrapper>\n <button className=\"cancel\" onClick={onCancel}>\n Cancel\n </button>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: \"Confirm\",\n disabled: !reason || reasonErr,\n onClick: handleFlag,\n }}\n />\n </ButtonsWrapper>\n </Content>\n </Container>\n ),\n }}\n />\n);\n" }, "Inputs.Checkbox": { "": "const Container = styled.div`\n display: flex;\n gap: 8px;\n flex-direction: row;\n align-items: center;\n`;\nconst CheckBox = styled.input`\n width: 18px;\n height: 18px;\n padding: 0px;\n appearance: checkbox;\n cursor: pointer;\n // TODO: update background color when selected\n`;\nconst Label = styled.label``;\nconst Error = styled.span`\n display: inline-block;\n font-style: normal;\n font-weight: 400;\n font-size: 0.75em;\n line-height: 1.25em;\n color: #ff4d4f;\n height: 0;\n overflow: hidden;\n transition: height 0.3s ease-in-out;\n &.show {\n height: 1.25em;\n }\n`;\nconst { id, disabled, checked, onClick } = props;\nconst containerStyle = props.containerStyle ?? {};\nconst checkBoxStyle = props.checkBoxStyle ?? {};\nconst labelStyle = props.labelStyle ?? {};\nconst error = props.error ?? \"\";\nreturn (\n <Container style={containerStyle}>\n <CheckBox\n type=\"checkbox\"\n style={checkBoxStyle}\n id={id}\n disabled={disabled}\n checked={checked}\n onClick={onClick}\n />\n {props.label && (\n <Label for={id} style={labelStyle}>\n {props.label}\n </Label>\n )}\n <Error className={error ? \"show\" : \"\"}>{error}</Error>\n </Container>\n);\n" }, "Components.Header": { "": "const headerTitleFontSizePx = 88;\nconst HeaderContainer = styled.div`\n width: 100%;\n // background: #fffaf4;\n // background: white;\n padding: 80px 64px;\n @media (max-width: 768px) {\n padding: 36px 24px;\n }\n`;\nconst HeaderContent = styled.div`\n display: flex;\n flex-direction: column;\n align-items: ${props.centered ? \"center\" : \"flex-start\"};\n`;\nconst HeaderTitle = styled.div`\n color: #2e2e2e;\n font-size: ${headerTitleFontSizePx}px;\n font-weight: 500;\n word-wrap: break-word;\n position: relative;\n text-align: center;\n z-index: 1;\n position: relative;\n font-family: \"Lora\";\n @media (max-width: 768px) {\n font-size: 48px;\n }\n`;\nconst HeaderDescription = styled.div`\n color: #2e2e2e;\n font-size: 32px;\n font-weight: 400;\n word-wrap: break-word;\n max-width: 866px;\n text-align: ${props.centered ? \"center\" : \"flex-start\"};\n margin-top: 32px;\n @media (max-width: 768px) {\n font-size: 24px;\n text-align: center;\n }\n`;\nconst ButtonsContainer = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n gap: 32px;\n margin-top: 32px;\n`;\nconst Underline = styled.div`\n position: absolute;\n top: ${headerTitleFontSizePx - 40}px;\n left: -40px;\n z-index: -1;\n @media (max-width: 768px) {\n top: 30px;\n left: -30px;\n }\n`;\nconst containerStyle = props.containerStyle ?? {};\nconst showStats = !props.tab || props.tab == \"projects\";\nreturn (\n <HeaderContainer style={containerStyle}>\n <HeaderContent>\n <HeaderTitle>\n {props.title1}\n <Underline>\n <svg\n width=\"340\"\n height=\"42\"\n viewBox=\"0 0 340 42\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M7.29967 39C-14.0566 35.9491 49.9788 32.436 71.4774 30.6444C151.734 23.9564 232.915 20.5161 312.9 15\"\n stroke=\"#DD3345\"\n stroke-width=\"5\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M31.2997 27C9.94337 23.9491 73.9788 20.436 95.4774 18.6444C175.734 11.9564 256.915 8.51608 336.9 3\"\n stroke=\"#DD3345\"\n stroke-width=\"5\"\n stroke-linecap=\"round\"\n />\n </svg>\n </Underline>\n </HeaderTitle>\n {props.title2 && <HeaderTitle>{props.title2}</HeaderTitle>}\n <HeaderDescription>{props.description}</HeaderDescription>\n </HeaderContent>\n {props.children && props.children}\n <ButtonsContainer>\n {props.buttonPrimary && props.buttonPrimary}\n {props.buttonSecondary && props.buttonSecondary}\n </ButtonsContainer>\n {showStats && (\n <Widget\n src={\"old.potlock.near/widget/Project.DonationStats\"}\n props={{ ...props }}\n />\n )}\n </HeaderContainer>\n);\n" }, "Pots.ChallengeModal": { "": "const { showChallengePayoutsModal, onCancel, existingChallengeForUser } = props;\nconst ModalHeader = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-start;\n background: white;\n padding: 24px 24px 12px 24px;\n border-top-left-radius: 6px;\n border-top-right-radius: 6px;\n font-weight: 500;\n`;\nconst ModalBody = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n padding: 24px;\n border-top: 1px #f0f0f0 solid;\n background: #fafafa;\n gap: 8px;\n`;\nconst ModalFooter = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-end;\n background: #fafafa;\n padding: 12px 24px 24px 24px;\n border-bottom-left-radius: 6px;\n border-bottom-right-radius: 6px;\n gap: 24px;\n width: 100%;\n`;\nState.init({\n challengeReason: \"\",\n challengeReasonError: \"\",\n});\nuseEffect(() => {\n if (existingChallengeForUser?.reason) {\n State.update({\n challengeReason: existingChallengeForUser?.reason,\n });\n }\n}, [existingChallengeForUser]);\nconst { challengeReason, challengeReasonError } = state;\nconst handleCancelChallenge = () => {\n onCancel();\n State.update({ challengeReason: \"\", challengeReasonError: \"\" });\n};\nconst handleSubmitChallenge = () => {\n PotSDK.challengePayouts(potId, challengeReason);\n onClose();\n};\nconst MAX_CHALLENGE_TEXT_LENGTH = 1000;\nreturn (\n <Widget\n src={\"old.potlock.near/widget/Components.Modal\"}\n props={{\n isModalOpen: showChallengePayoutsModal,\n onClose: handleCancelChallenge,\n contentStyle: {\n padding: \"0px\",\n },\n children: (\n <>\n <ModalHeader>Challenge Payouts</ModalHeader>\n <ModalBody>\n <div>Explain the reason for your challenge</div>\n <Widget\n src={\"old.potlock.near/widget/Inputs.TextArea\"}\n props={{\n noLabel: true,\n inputRows: 5,\n inputStyle: {\n background: \"#FAFAFA\",\n },\n placeholder: \"Type the reason for your challenge here\",\n value: challengeReason,\n onChange: (challengeReason) =>\n State.update({ challengeReason }),\n validate: () => {\n if (challengeReason.length > MAX_CHALLENGE_TEXT_LENGTH) {\n State.update({\n challengeReasonError: `Challenge reason must be less than ${MAX_CHALLENGE_TEXT_LENGTH} characters`,\n });\n return;\n }\n State.update({ challengeReasonError: \"\" });\n },\n error: challengeReasonError,\n }}\n />\n </ModalBody>\n <ModalFooter>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"tertiary\",\n text: \"Cancel\",\n onClick: handleCancelChallenge,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: \"Submit Challenge\",\n disabled: !challengeReason || !!challengeReasonError,\n onClick: handleSubmitChallenge,\n }}\n />\n </ModalFooter>\n </>\n ),\n }}\n />\n);\n" }, "Components.Loading": { "": "return <div class=\"spinner-border text-secondary\" role=\"status\" />;\n" }, "Pots.HomeBanner": { "": "const { canDeploy, hrefWithParams } = props;\nconst { HomeBannerStyle } = VM.require(\n \"old.potlock.near/widget/Pots.HomeBannerBackground\"\n) || {\n HomeBannerStyle: {},\n};\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n position: relative;\n width: 100%;\n justify-content: center;\n min-height: 400px;\n overflow: hidden;\n .background {\n position: absolute;\n pointer-events: none;\n height: 100%;\n left: 0;\n top: 0;\n }\n .content {\n position: relative;\n z-index: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n padding: 64px;\n }\n .sub-title {\n letter-spacing: 1.12px;\n font-weight: 500;\n font-size: 14px;\n margin-top: 0;\n margin-bottom: 24px;\n text-transform: uppercase;\n }\n .title {\n letter-spacing: -0.4px;\n font-weight: 500;\n font-size: 40px;\n font-family: \"Lora\";\n margin: 0;\n }\n .btns {\n display: flex;\n align-items: center;\n gap: 2rem;\n margin-top: 40px;\n a {\n padding: 12px 16px;\n width: 180px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: 500;\n border-radius: 6px;\n box-shadow: 0px -2px 0px 0px #464646 inset, 0px 0px 0px 1px #464646;\n text-decoration: none;\n color: #292929;\n transition: all 300ms;\n &:first-of-type {\n color: white;\n background: #dd3345;\n &:hover {\n }\n }\n &:hover {\n background: #292929;\n color: white;\n }\n }\n }\n @media only screen and (max-width: 768px) {\n .content {\n padding: 64px 20px;\n }\n .title {\n font-size: 36px;\n }\n .btns {\n flex-direction: column;\n gap: 1rem;\n margin-top: 24px;\n }\n .line-break {\n display: none;\n }\n }\n @media only screen and (max-width: 480px) {\n .btns a {\n width: 100%;\n padding: 12px 0;\n }\n }\n`;\nreturn (\n <Container\n style={{\n ...HomeBannerStyle,\n }}\n >\n <div className=\"content\">\n <h3 className=\"sub-title\">Explore Pots</h3>\n <h1 className=\"title\">\n Donate to Matching Rounds <br className=\"line-break\" /> to Get Your\n Contributions Amplified.\n </h1>\n <div className=\"btns\">\n {canDeploy && <a href={hrefWithParams(`?tab=deploypot`)}>Deploy Pot</a>}\n <a href=\"https://wtfisqf.com\" target=\"_blank\">\n Learn More\n </a>\n </div>\n </div>\n </Container>\n);\n" }, "Pots.Payouts": { "": "// get donations\nconst { potId, potDetail, allDonations } = props;\n// potDetail.cooldown_end_ms = 1710105146000; // TODO: remove this line\nconst { SUPPORTED_FTS } = VM.require(\"old.potlock.near/widget/constants\") || {\n SUPPORTED_FTS: {},\n};\nconst { calculatePayouts, yoctosToNear } = VM.require(\n \"old.potlock.near/widget/utils\"\n) || {\n calculatePayouts: () => {},\n yoctosToNear: () => \"\",\n};\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n isUserPotAdminOrGreater: () => {},\n getPayoutsChallenges: () => {},\n challengePayouts: () => {},\n adminUpdatePayoutsChallenge: () => {},\n getFlaggedAccounts: () => {},\n};\nconst userIsAdminOrGreater = PotSDK.isUserPotAdminOrGreater(\n potId,\n context.accountId\n); // TODO: ADD THIS BACK IN\n// const userIsAdminOrGreater = true; // TODO: REMOVE THIS LINE\nconst IPFS_BASE_URL = \"https://nftstorage.link/ipfs/\";\n// const ALERT_ICON_URL =\n// IPFS_BASE_URL + \"bafkreicqarojxk6jhdtsk2scfsmnigqpxjfgar6om4wlhn5xmqbbu74u5i\";\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n @media screen and (min-width: 375px) and (max-width: 768px) {\n width: 99%;\n }\n @media screen and (max-width: 390px) {\n width: 98%;\n }\n`;\nconst OuterTextContainer = styled.div`\n display: flex;\n flex-direction: row;\n gap: 10px;\n @media screen and (max-width: 768px) {\n padding-right: 10px;\n }\n`;\nconst OuterText = styled.div`\n color: #7b7b7b;\n font-size: 14px;\n font-weight: 500;\n text-transform: uppercase;\n line-height: 24px;\n letter-spacing: 1.12px;\n word-wrap: break-word;\n`;\nconst Count = styled.div`\n color: #dd3345;\n font-size: 14px;\n font-weight: 600;\n line-height: 24px;\n`;\nconst TableContainer = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n border-radius: 6px;\n border: 1px solid #7b7b7b;\n width: 100%;\n overflow-x: auto;\n flex-wrap: nowrap;\n`;\nconst Header = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n gap: 2rem;\n padding: 0.5rem 1rem;\n border-bottom: 1px solid rgba(199, 199, 199, 0.5);\n @media only screen and (max-width: 768px) {\n display: none;\n }\n`;\nconst HeaderItem = styled.div`\n display: flex;\n flex-direction: row;\n align-items: space-between;\n justify-content: flex-start;\n justify-content: space-between;\n width: 110px;\n justify-content: right;\n &.project {\n flex: 1;\n justify-content: left;\n }\n @media only screen and (max-width: 768px) {\n display: none;\n &.project {\n display: flex;\n }\n }\n`;\nconst HeaderItemText = styled.div`\n color: #292929;\n font-size: 14px;\n font-weight: 600;\n line-height: 24px;\n word-wrap: break-word;\n`;\nconst MobileAmount = styled.div`\n width: 100%;\n margin-left: 2rem;\n display: none;\n max-height: 0px;\n overflow: hidden;\n transition: all 200ms;\n span {\n font-weight: 600;\n }\n @media screen and (max-width: 768px) {\n order: 2;\n display: block;\n }\n`;\nconst Row = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n padding: 1rem;\n gap: 2rem;\n border-top: 1px solid rgba(199, 199, 199, 0.5);\n position: relative;\n .toggle-check {\n cursor: pointer;\n position: absolute;\n left: 0;\n top: 0;\n height: 100%;\n width: 100%;\n opacity: 0;\n display: none;\n }\n .toggle-check:checked ~ svg {\n rotate: 0deg;\n }\n .toggle-check:checked + ${MobileAmount} {\n max-height: 100px;\n }\n @media screen and (max-width: 768px) {\n flex-wrap: wrap;\n gap: 0.5rem;\n .toggle-check {\n display: block;\n }\n }\n`;\nconst RowItem = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-start;\n width: 110px;\n justify-content: right;\n &:hover {\n text-decoration: none;\n }\n &.project {\n flex: 1;\n display: flex;\n gap: 1rem;\n justify-content: left;\n transition: 200ms;\n a {\n color: #292929;\n font-weight: 600;\n transition: 200ms;\n &:hover {\n color: #dd3345;\n text-decoration: none;\n }\n }\n }\n @media screen and (max-width: 768px) {\n &.project {\n gap: 0.5rem;\n }\n &.donors,\n &.amount {\n display: none;\n }\n }\n`;\nconst RowText = styled.div`\n color: #292929;\n font-size: 14px;\n font-weight: 600;\n word-wrap: break-word;\n span {\n color: #7b7b7b;\n font-weight: 600;\n display: none;\n }\n @media screen and (max-width: 768px) {\n span {\n display: inline;\n }\n &:last-of-type {\n display: flex;\n gap: 4px;\n }\n }\n`;\nconst SearchBarContainer = styled.div`\n display: flex;\n align-items: center;\n gap: 16px;\n width: 100%;\n background: #f6f5f3;\n padding: 0.5rem 1rem;\n @media only screen and (max-width: 768px) {\n gap: 8px;\n }\n`;\nconst SearchBar = styled.input`\n background: none;\n width: 100%;\n outline: none;\n border: none;\n &:focus {\n outline: none;\n border: none;\n }\n`;\nconst SearchIcon = styled.div`\n display: flex;\n width: 24px;\n height: 24px;\n align-items: center;\n justify-content: center;\n`;\nconst InfoContainer = styled.div`\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 8px;\n border: 1px solid #f4b37d;\n border-radius: 6px;\n background: #fef6ee;\n gap: 1rem;\n margin-left: auto;\n margin-bottom: 1.5rem;\n`;\nconst WarningText = styled.div`\n text-align: center;\n color: #dd3345;\n font-weight: 500;\n font-size: 14px;\n`;\nconst AlertSvg = styled.svg`\n width: 18px;\n @media screen and (max-width: 768px) {\n width: 1rem;\n }\n`;\nState.init({\n allPayouts: null,\n filteredPayouts: null,\n showChallengePayoutsModal: false,\n flaggedAddresses: null,\n});\nconst {\n allPayouts,\n filteredPayouts,\n showChallengePayoutsModal,\n flaggedAddresses,\n} = state;\nif (!flaggedAddresses) {\n PotSDK.getFlaggedAccounts(potDetail, potId)\n .then((data) => {\n const listOfFlagged = [];\n data.forEach((adminFlaggedAcc) => {\n const addresses = Object.keys(adminFlaggedAcc.potFlaggedAcc);\n listOfFlagged.push(...addresses);\n });\n State.update({ flaggedAddresses: listOfFlagged });\n })\n .catch((err) => console.log(\"error getting the flagged accounts \", err));\n}\nif (!allPayouts && allDonations && potDetail && flaggedAddresses) {\n calculatePayouts(\n allDonations,\n potDetail.matching_pool_balance,\n flaggedAddresses\n ).then((calculatedPayouts) => {\n console.log(\"calculated payouts: \", calculatedPayouts);\n if (potDetail.payouts.length) {\n // handle these payouts, which don't contain all the info needed\n // pot payouts contain id, project_id, amount & paid_at\n // 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\n const synthesizedPayouts = potDetail.payouts.map((payout) => {\n const { project_id, amount } = payout;\n const { totalAmount, donorCount } = calculatedPayouts[project_id];\n return {\n projectId: project_id,\n totalAmount,\n matchingAmount: amount,\n donorCount,\n };\n });\n State.update({\n allPayouts: synthesizedPayouts,\n filteredPayouts: synthesizedPayouts,\n });\n } else {\n // calculate estimated payouts\n const allPayouts = Object.entries(calculatedPayouts).map(\n ([projectId, { totalAmount, matchingAmount, donorCount }]) => {\n return {\n projectId,\n totalAmount,\n matchingAmount,\n donorCount,\n };\n }\n ); // TODO: refactor to use PotsSDK (note that this is duplicated in Pots/Projects.jsx)\n allPayouts.sort((a, b) => {\n // sort by matching pool allocation, highest to lowest\n return b.matchingAmount - a.matchingAmount;\n });\n State.update({ allPayouts, filteredPayouts: allPayouts });\n }\n });\n}\nconst columns = [\n \"Project\",\n \"Total Raised\",\n \"Total Unique Donors\",\n \"Matching Pool Allocation\",\n];\nconst { base_currency } = potDetail;\nconst searchPayouts = (searchTerm) => {\n // filter payouts that match the search term (donor_id, project_id)\n const filteredPayouts = allPayouts.filter((payout) => {\n const { projectId } = payout;\n const searchFields = [projectId];\n return searchFields.some((field) =>\n field.toLowerCase().includes(searchTerm.toLowerCase())\n );\n });\n filteredPayouts.sort((a, b) => {\n // sort by matching pool allocation, highest to lowest\n return b.matchingAmount - a.matchingAmount;\n });\n return filteredPayouts;\n};\nconst MAX_ACCOUNT_ID_DISPLAY_LENGTH = 10;\nconst ProfileImage = ({ projectId }) => (\n <Widget\n src={\"old.potlock.near/widget/Project.ProfileImage\"}\n props={{\n ...props,\n accountId: projectId,\n style: {\n height: \"24px\",\n width: \"24px\",\n },\n }}\n />\n);\nconst Arrow = styled.svg`\n width: 12px;\n rotate: 180deg;\n transition: all 200ms;\n display: none;\n @media screen and (max-width: 768px) {\n display: block;\n }\n`;\nconst ArrowDown = (props) => (\n <Arrow\n {...props}\n viewBox=\"0 0 12 8\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 0.294983L0 6.29498L1.41 7.70498L6 3.12498L10.59 7.70498L12 6.29498L6 0.294983Z\"\n fill=\"#7B7B7B\"\n />\n </Arrow>\n);\nreturn (\n <Container>\n <Widget\n src={\"old.potlock.near/widget/Pots.FlaggedAccounts\"}\n props={props}\n />\n <Widget\n src={\"old.potlock.near/widget/Pots.PayoutsChallenges\"}\n props={props}\n />\n {!potDetail.all_paid_out && (\n <InfoContainer>\n <AlertSvg\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M7.25 4.25H8.75V5.75H7.25V4.25ZM7.25 7.25H8.75V11.75H7.25V7.25ZM8 0.5C3.86 0.5 0.5 3.86 0.5 8C0.5 12.14 3.86 15.5 8 15.5C12.14 15.5 15.5 12.14 15.5 8C15.5 3.86 12.14 0.5 8 0.5ZM8 14C4.6925 14 2 11.3075 2 8C2 4.6925 4.6925 2 8 2C11.3075 2 14 4.6925 14 8C14 11.3075 11.3075 14 8 14Z\"\n fill=\"#EE8949\"\n />\n </AlertSvg>\n <WarningText>\n {potDetail.cooldown_end_ms\n ? \"These payouts have been set on the contract but have not been paid out yet.\"\n : \"These payouts are estimated amounts only and have not been set on the contract yet.\"}\n </WarningText>\n </InfoContainer>\n )}\n <TableContainer>\n <Header>\n <HeaderItem className=\"project\">\n <HeaderItemText>Project</HeaderItemText>\n </HeaderItem>\n <HeaderItem>\n <HeaderItemText>Total Raised</HeaderItemText>\n </HeaderItem>\n <HeaderItem>\n <HeaderItemText>Unique Donors</HeaderItemText>\n </HeaderItem>\n <HeaderItem>\n <HeaderItemText>Pool Allocation</HeaderItemText>\n </HeaderItem>\n </Header>\n <SearchBarContainer>\n <SearchIcon>\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M15.7549 14.2549H14.9649L14.6849 13.9849C15.6649 12.8449 16.2549 11.3649 16.2549 9.75488C16.2549 6.16488 13.3449 3.25488 9.75488 3.25488C6.16488 3.25488 3.25488 6.16488 3.25488 9.75488C3.25488 13.3449 6.16488 16.2549 9.75488 16.2549C11.3649 16.2549 12.8449 15.6649 13.9849 14.6849L14.2549 14.9649V15.7549L19.2549 20.7449L20.7449 19.2549L15.7549 14.2549ZM9.75488 14.2549C7.26488 14.2549 5.25488 12.2449 5.25488 9.75488C5.25488 7.26488 7.26488 5.25488 9.75488 5.25488C12.2449 5.25488 14.2549 7.26488 14.2549 9.75488C14.2549 12.2449 12.2449 14.2549 9.75488 14.2549Z\"\n fill=\"#C7C7C7\"\n />\n </svg>\n </SearchIcon>\n <SearchBar\n placeholder=\"Search payouts\"\n onChange={({ target: { value } }) => {\n const filteredPayouts = searchPayouts(value);\n State.update({ filteredPayouts });\n }}\n />\n </SearchBarContainer>\n {!filteredPayouts ? (\n <div>Loading</div>\n ) : filteredPayouts.length === 0 ? (\n <Row style={{ padding: \"12px\" }}>No payouts to display</Row>\n ) : (\n filteredPayouts.map((payout, index) => {\n const { projectId, donorCount, matchingAmount, totalAmount } = payout;\n return (\n <Row key={index}>\n <RowItem className=\"project\">\n <ProfileImage projectId={projectId} />\n <a\n href={`?tab=project&projectId=${projectId}`}\n target={\"_blank\"}\n >\n {projectId.length > MAX_ACCOUNT_ID_DISPLAY_LENGTH\n ? projectId.slice(0, MAX_ACCOUNT_ID_DISPLAY_LENGTH) + \"...\"\n : projectId}\n </a>\n </RowItem>\n {/* Total Raised */}\n <RowItem className=\"amount\">\n <RowText>{yoctosToNear(totalAmount, true)}</RowText>\n </RowItem>\n <input type=\"checkbox\" className=\"toggle-check\" />\n <MobileAmount>\n <span>{yoctosToNear(totalAmount, true)}</span> raised from\n <span>{donorCount}</span> unique donors\n </MobileAmount>\n {/* Total Unique Donors */}\n <RowItem className=\"donors\">\n <RowText>{donorCount}</RowText>\n </RowItem>\n {/* Matching Pool Allocation */}\n <RowItem>\n <RowText>\n {yoctosToNear(matchingAmount, true)} <span>Allocated</span>\n </RowText>\n </RowItem>\n <ArrowDown />\n </Row>\n );\n })\n )}\n </TableContainer>\n </Container>\n);\n" }, "Components.Feed": { "": "let ListsSDK =\n VM.require(\"old.potlock.near/widget/SDK.lists\") ||\n (() => ({\n getRegistrations: () => {},\n }));\nListsSDK = ListsSDK({ env: props.env });\nconst registrations = ListsSDK.getRegistrations() || [];\nconst registrantIds = registrations\n .filter((reg) => reg.status === \"Approved\")\n .map((reg) => reg.registrant_id);\nconst Container = styled.div`\n padding: 24px 64px;\n @media screen and (max-width: 768px) {\n padding: 24px 16px;\n }\n`;\nreturn (\n <Container>\n <Widget\n key=\"feed\"\n src={\"old.potlock.near/widget/Profile.Feed\"}\n props={{ accounts: registrantIds }}\n />\n </Container>\n);\n" }, "Pots.ConfigForm": { "": "const { potDetail, potId, NADABOT_CONTRACT_ID } = props;\nconst { validateNearAddress } = VM.require(\"old.potlock.near/widget/utils\") || {\n validateNearAddress: () => \"\",\n};\nconst {\n NADABOT_HUMAN_METHOD,\n ONE_TGAS,\n SUPPORTED_FTS: { NEAR },\n} = VM.require(\"old.potlock.near/widget/constants\") || {\n NADABOT_HUMAN_METHOD: \"\",\n ONE_TGAS: 0,\n SUPPORTED_FTS: {},\n};\nlet PotFactorySDK =\n VM.require(\"old.potlock.near/widget/SDK.potfactory\") ||\n (() => ({\n getContractId: () => {},\n getProtocolConfig: () => {},\n asyncGetPots: () => {},\n }));\nPotFactorySDK = PotFactorySDK({ env: props.env });\nconst potFactoryContractId = PotFactorySDK.getContractId();\nconst protocolConfig = PotFactorySDK.getProtocolConfig();\n// console.log(\"props in config form: \", props);\nlet ListsSDK =\n VM.require(\"old.potlock.near/widget/SDK.lists\") ||\n (() => ({\n getContractId: () => \"\",\n }));\nListsSDK = ListsSDK({ env: props.env });\nconst DEFAULT_REGISTRY_PROVIDER = `${ListsSDK.getContractId()}:is_registered`;\nconst DEFAULT_SYBIL_WRAPPER_PROVIDER = `${NADABOT_CONTRACT_ID}:${NADABOT_HUMAN_METHOD}`;\nconst CURRENT_SOURCE_CODE_VERSION = \"0.1.0\";\nconst SOURCE_CODE_LINK = \"https://github.com/PotLock/core\"; // for use in contract source metadata\nconst POT_CODE_LINK = \"https://github.com/PotLock/core/tree/main/contracts/pot\"; // for directing user to view source code for Pot\nconst IPFS_BASE_URL = \"https://nftstorage.link/ipfs/\";\n// const ADD_ADMINS_ICON_URL =\n// IPFS_BASE_URL + \"bafkreig6c7m2z2lupreu2br4pm3xx575mv6uvmuy2qkij4kzzfpt7tipcq\";\n// const CLOSE_ICON_URL =\n// IPFS_BASE_URL + \"bafkreifyg2vvmdjpbhkylnhye5es3vgpsivhigkjvtv2o4pzsae2z4vi5i\";\nconst DEFAULT_PROFILE_IMAGE_URL =\n IPFS_BASE_URL + \"bafkreifel4bfm6hxmklcsqjilk3bhvi3acf2rxqepcgglluhginbttkyqm\";\nconst MAX_POT_NAME_LENGTH = 64;\nconst MAX_POT_DESCRIPTION_LENGTH = 256;\nconst MAX_MAX_PROJECTS = 100;\nconst MAX_REFERRAL_FEE_MATCHING_POOL_BASIS_POINTS = 1000; // 10%\nconst MAX_REFERRAL_FEE_PUBLIC_ROUND_BASIS_POINTS = 1000; // 10%\nconst MAX_CHEF_FEE_BASIS_POINTS = 1000; // 10%\nconst getImageUrlFromSocialImage = (image) => {\n if (image.url) {\n return image.url;\n } else if (image.ipfs_cid) {\n return IPFS_BASE_URL + image.ipfs_cid;\n }\n};\nBig.PE = 100;\nconst FormBody = styled.div`\n display: flex;\n flex-direction: column;\n padding: 32px 0px;\n width: 100%;\n @media screen and (max-width: 880px) {\n padding: 10px 10px;\n }\n`;\nconst FormDivider = styled.div`\n height: 2px;\n width: 100%;\n background-color: #ebebeb;\n @media screen and (max-width: 768px) {\n display: none;\n }\n`;\nconst FormSectionContainer = styled.div`\n display: flex;\n flex-direction: row;\n margin: 48px 0;\n @media screen and (max-width: 768px) {\n flex-direction: column;\n gap: 32px;\n }\n`;\nconst FormSectionLeftDiv = styled.div`\n // flex: 1;\n width: 30%;\n display: flex;\n flex-direction: column;\n // background-color: yellow;\n gap: 16px;\n @media screen and (max-width: 768px) {\n width: 100%;\n }\n`;\nconst FormSectionRightDiv = styled.div`\n width: 70%;\n display: flex;\n flex-direction: column;\n gap: 26px;\n @media screen and (max-width: 768px) {\n width: 100%;\n }\n`;\nconst FormSectionTitle = styled.div`\n color: #2e2e2e;\n font-size: 16;\n font-weight: 600;\n word-wrap: break-word;\n`;\nconst FormSectionDescription = styled.div`\n color: #2e2e2e;\n font-size: 16;\n font-weight: 400;\n word-wrap: break-word;\n`;\nconst Row = styled.div`\n display: flex;\n flex-direction: row;\n gap: 24px;\n align-items: end;\n justify-content: flex-start;\n @media screen and (max-width: 768px) {\n flex-direction: column;\n align-items: flex-start;\n }\n`;\nconst Checkbox = styled.div`\n display: flex;\n @media screen and (max-width: 768px) {\n flex-direction: row;\n }\n`;\nconst Label = styled.label`\n font-weight: 500;\n font-size: 14px;\n line-height: 16px;\n word-wrap: break-word;\n color: #2e2e2e;\n`;\nconst isUpdate = !!potDetail;\nconst convertToUTCTimestamp = (localDateTime) => {\n if (!localDateTime) {\n return;\n }\n return new Date(localDateTime).getTime();\n};\nconst formatTimestampForDateTimeLocal = (timestamp) => {\n const date = new Date(timestamp);\n const year = date.getFullYear();\n const month = (date.getMonth() + 1).toString().padStart(2, \"0\"); // months are 0-indexed\n const day = date.getDate().toString().padStart(2, \"0\");\n const hours = date.getHours().toString().padStart(2, \"0\");\n const minutes = date.getMinutes().toString().padStart(2, \"0\");\n return `${year}-${month}-${day}T${hours}:${minutes}`;\n};\n// console.log(\"potDetail: \", potDetail);\nState.init({\n owner: isUpdate ? potDetail.owner : context.accountId,\n ownerError: \"\",\n admin: \"\",\n admins: isUpdate ? potDetail.admins.map((accountId) => ({ accountId })) : [],\n adminsError: \"\",\n isAdminsModalOpen: false,\n name: isUpdate ? potDetail.pot_name : \"\",\n nameError: \"\",\n customHandle: isUpdate ? potId.split(`.${potFactoryContractId}`)[0] : \"\",\n customHandleError: \"\",\n description: isUpdate ? potDetail.pot_description : \"\",\n descriptionError: \"\",\n // referrerFeeMatchingPoolPercent * 100: isUpdate\n // ? potDetail.referral_fee_matching_pool_basis_points\n // : \"\",\n // referrerFeeMatchingPoolPercent * 100Error: \"\",\n referrerFeeMatchingPoolPercent: isUpdate\n ? potDetail.referral_fee_matching_pool_basis_points / 100\n : \"\",\n referrerFeeMatchingPoolPercentError: \"\",\n referrerFeePublicRoundPercent: isUpdate\n ? potDetail.referral_fee_public_round_basis_points / 100\n : \"\",\n referrerFeePublicRoundPercentError: \"\",\n protocolFeeBasisPoints: isUpdate ? potDetail.protocol_fee_basis_points : \"\",\n protocolFeeBasisPointsError: \"\",\n applicationStartDate: isUpdate\n ? formatTimestampForDateTimeLocal(potDetail.application_start_ms)\n : \"\",\n applicationStartDateError: \"\",\n applicationEndDate: isUpdate\n ? formatTimestampForDateTimeLocal(potDetail.application_end_ms)\n : \"\",\n applicationEndDateError: \"\",\n matchingRoundStartDate: isUpdate\n ? formatTimestampForDateTimeLocal(potDetail.public_round_start_ms)\n : \"\",\n matchingRoundStartDateError: \"\",\n matchingRoundEndDate: isUpdate\n ? formatTimestampForDateTimeLocal(potDetail.public_round_end_ms)\n : \"\",\n matchingRoundEndDateError: \"\",\n chef: isUpdate ? potDetail.chef : \"\",\n chefError: \"\",\n chefFeePercent: isUpdate ? potDetail.chef_fee_basis_points / 100 : \"\",\n chefFeePercentError: \"\",\n maxProjects: isUpdate ? potDetail.max_projects : \"\",\n maxProjectsError: \"\",\n baseCurrency: isUpdate ? potDetail.base_currency : \"\",\n baseCurrencyError: \"\",\n minMatchingPoolDonationAmount: NEAR.fromIndivisible(\n isUpdate ? potDetail.min_matching_pool_donation_amount : \"1\"\n ),\n minMatchingPoolDonationAmountError: \"\",\n useNadabotSybil: isUpdate\n ? potDetail.sybil_wrapper_provider == DEFAULT_SYBIL_WRAPPER_PROVIDER\n : true,\n usePotlockRegistry: isUpdate\n ? potDetail.registry_provider == DEFAULT_REGISTRY_PROVIDER\n : true,\n latestSourceCodeCommitHash: \"\",\n deploymentSuccess: false,\n});\nif (!isUpdate && !state.latestSourceCodeCommitHash) {\n const res = fetch(\"https://api.github.com/repos/PotLock/core/commits\");\n if (res.ok && res.body.length > 0) {\n State.update({\n latestSourceCodeCommitHash: res.body[0].sha,\n });\n }\n}\nconst getPotDetailArgsFromState = () => {\n const args = {\n owner: state.owner,\n admins: state.admins\n .filter((admin) => !admin.remove)\n .map((admin) => admin.accountId),\n chef: state.chef || null,\n pot_name: state.name,\n pot_description: state.description,\n max_projects: parseInt(state.maxProjects) || null,\n application_start_ms: convertToUTCTimestamp(state.applicationStartDate),\n application_end_ms: convertToUTCTimestamp(state.applicationEndDate),\n public_round_start_ms: convertToUTCTimestamp(state.matchingRoundStartDate),\n public_round_end_ms: convertToUTCTimestamp(state.matchingRoundEndDate),\n min_matching_pool_donation_amount: NEAR.toIndivisible(\n state.minMatchingPoolDonationAmount\n ).toString(),\n registry_provider: state.usePotlockRegistry\n ? DEFAULT_REGISTRY_PROVIDER\n : null,\n sybil_wrapper_provider: state.useNadabotSybil\n ? DEFAULT_SYBIL_WRAPPER_PROVIDER\n : null,\n custom_sybil_checks: null, // not necessary to include null values but doing so for clarity\n custom_min_threshold_score: null, // not necessary to include null values but doing so for clarity\n referral_fee_matching_pool_basis_points: parseInt(\n (state.referrerFeeMatchingPoolPercent * 100).toFixed(0)\n ),\n referral_fee_public_round_basis_points: parseInt(\n (state.referrerFeePublicRoundPercent * 100).toFixed(0)\n ),\n chef_fee_basis_points: parseInt((state.chefFeePercent * 100).toFixed(0)),\n source_metadata: isUpdate\n ? null\n : {\n // TODO: think about the best way to handle this so that it keeps up to date with the latest source code\n version: CURRENT_SOURCE_CODE_VERSION,\n commit_hash: state.latestSourceCodeCommitHash,\n link: SOURCE_CODE_LINK,\n },\n };\n return args;\n};\n// console.log(\"state; \", state);\nconst canDeploy = useMemo(() => {\n if (\n !state.owner ||\n state.ownerError ||\n !state.name ||\n state.nameError ||\n !state.description ||\n state.descriptionError ||\n !state.referrerFeeMatchingPoolPercent ||\n state.referrerFeeMatchingPoolPercentError ||\n !state.applicationStartDate ||\n state.applicationStartDateError ||\n !state.applicationEndDate ||\n state.applicationEndDateError ||\n !state.matchingRoundStartDate ||\n state.matchingRoundStartDateError ||\n !state.matchingRoundEndDate ||\n state.matchingRoundEndDateError ||\n !state.chef ||\n state.chefError ||\n !state.chefFeePercent ||\n state.chefFeePercentError ||\n !state.maxProjects ||\n state.maxProjectsError\n ) {\n return false;\n }\n return true;\n}, [state]);\nconst handleDeploy = () => {\n // create deploy pot args\n const deployArgs = getPotDetailArgsFromState();\n console.log(\"deployArgs: \", deployArgs);\n Near.asyncView(potFactoryContractId, \"calculate_min_deployment_deposit\", {\n args: deployArgs,\n }).then((amount) => {\n // console.log(\"amount: \", amount);\n const amountYoctos = Big(amount).plus(Big(\"20000000000000000000000\")); // add extra 0.02 NEAR as buffer\n const args = { pot_args: deployArgs };\n if (state.customHandle) {\n args.pot_handle = state.customHandle;\n }\n const transactions = [\n {\n contractName: potFactoryContractId,\n methodName: \"deploy_pot\",\n deposit: amountYoctos,\n args,\n gas: ONE_TGAS.mul(300),\n },\n ];\n const now = Date.now();\n Near.call(transactions);\n // NB: we won't get here if user used a web wallet, as it will redirect to the wallet\n // <---- EXTENSION WALLET HANDLING ---->\n // poll for updates\n const pollIntervalMs = 1000;\n // const totalPollTimeMs = 60000; // consider adding in to make sure interval doesn't run indefinitely\n const pollId = setInterval(() => {\n PotFactorySDK.asyncGetPots().then((pots) => {\n // console.log(\"pots: \", pots);\n const pot = pots.find(\n (pot) =>\n pot.deployed_by === context.accountId && pot.deployed_at_ms > now\n );\n if (pot) {\n clearInterval(pollId);\n State.update({ deploymentSuccess: true });\n }\n });\n }, pollIntervalMs);\n });\n};\nconst handleUpdate = () => {\n // create update pot args\n const updateArgs = getPotDetailArgsFromState();\n // console.log(\"updateArgs: \", updateArgs);\n const depositFloat = JSON.stringify(updateArgs).length * 0.00003;\n const deposit = Big(depositFloat).mul(Big(10).pow(24));\n const transactions = [\n {\n contractName: potId,\n methodName: \"admin_dangerously_set_pot_config\",\n deposit: Big(0.1).mul(Big(10).pow(24)),\n deposit,\n args: { update_args: updateArgs },\n gas: ONE_TGAS.mul(100),\n },\n ];\n Near.call(transactions);\n // NB: we won't get here if user used a web wallet, as it will redirect to the wallet\n // <---- EXTENSION WALLET HANDLING ---->\n // TODO: IMPLEMENT\n};\n// console.log(\"state: \", state);\nconst validateAndUpdatePercentages = (percent, stateKey, errorKey, maxVal) => {\n // TODO: move this to separate component for percentage input that accepts \"basisPoints\" bool parameter\n const updates = {\n [errorKey]: \"\",\n };\n if (!percent) {\n updates[stateKey] = \"0\";\n } else {\n const split = percent.split(\".\");\n if (split.length > 2) {\n return;\n }\n if (split.length === 2 && split[1].length > 2) {\n return;\n }\n // if it ends with a period and this is the only period in the string, set on state\n if (percent.endsWith(\".\") && percent.indexOf(\".\") === percent.length - 1) {\n State.update({\n [stateKey]: percent,\n });\n return;\n }\n // otherwise, parse into a float\n const percentFloat = parseFloat(percent);\n if (percentFloat) {\n updates[stateKey] = percentFloat.toString();\n if (percentFloat > maxVal) {\n updates[errorKey] = `Maximum ${maxVal}%`;\n }\n }\n }\n State.update(updates);\n};\nconst handleAddAdmin = () => {\n let isValid = validateNearAddress(state.admin);\n if (!isValid) {\n State.update({\n adminsError: \"Invalid NEAR account ID\",\n });\n return;\n }\n if (\n !state.admins.find(\n (admin) => admin.accountId == state.admin && !admin.remove\n )\n ) {\n // TODO: if already in state.admins with remove = true, set remove = false\n // get data from social.near\n // const profileImageUrl = DEFAULT_PROFILE_IMAGE_URL;\n const newAdmin = {\n accountId: state.admin.toLowerCase(),\n // imageUrl: profileImageUrl,\n };\n const admins = [...state.admins, newAdmin];\n // console.log(\"admins: \", admins);\n State.update({\n admins,\n admin: \"\",\n adminsError: \"\",\n });\n }\n};\nconst handleRemoveAdmin = (accountId) => {\n State.update({\n admins: state.admins.map((admin) => {\n if (admin.accountId == accountId) {\n return { ...admin, remove: true };\n }\n return admin;\n }),\n });\n};\nconst userIsOwner = context.accountId === potDetail.owner;\nconst userIsAdmin = isUpdate && potDetail.admins.includes(context.accountId);\nconst isAdminOrGreater = userIsOwner || userIsAdmin;\nconst FormSectionLeft = (title, description) => {\n return (\n <FormSectionLeftDiv>\n <FormSectionTitle>{title}</FormSectionTitle>\n <FormSectionDescription>{description}</FormSectionDescription>\n </FormSectionLeftDiv>\n );\n};\nreturn (\n <FormBody>\n <FormSectionContainer>\n {FormSectionLeft(\"Pot details\", \"\")}\n <FormSectionRightDiv>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"Owner *\",\n placeholder: `E.g. ${context.accountId}`,\n value: state.owner,\n onChange: (owner) => State.update({ owner, ownerError: \"\" }),\n validate: () => {\n // **CALLED ON BLUR**\n const valid = validateNearAddress(state.owner);\n State.update({\n ownerError: valid ? \"\" : \"Invalid NEAR account ID\",\n });\n },\n error: state.ownerError,\n disabled: isUpdate ? !userIsOwner : true,\n }}\n />\n {/* <props.ToDo>ADD ADMINS multi-entry</props.ToDo> */}\n <Label>Admins</Label>\n <Widget\n src={\"old.potlock.near/widget/Components.AccountsList\"}\n props={{\n accountIds: state.admins\n .filter((account) => !account.remove)\n .map((account) => account.accountId),\n allowRemove: isUpdate ? userIsOwner : true,\n handleRemoveAccount: handleRemoveAdmin,\n }}\n />\n {(!isUpdate || userIsOwner) && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"tertiary\",\n text: \"Add admins\",\n style: { width: \"fit-content\" },\n onClick: () => State.update({ isAdminsModalOpen: true }),\n }}\n />\n )}\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"Name *\",\n placeholder: \"E.g. DeFi Center\",\n value: state.name,\n onChange: (name) => State.update({ name, nameError: \"\" }),\n validate: () => {\n // **CALLED ON BLUR**\n const valid = state.name.length <= MAX_POT_NAME_LENGTH;\n State.update({\n nameError: valid\n ? \"\"\n : `Name must be ${MAX_POT_NAME_LENGTH} characters or less`,\n });\n },\n error: state.nameError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"Custom handle (optional - will slugify name by default)\",\n placeholder: \"e.g. my-pot-handle\",\n value: state.customHandle,\n onChange: (customHandle) =>\n State.update({ customHandle, customHandleError: \"\" }),\n validate: () => {\n // **CALLED ON BLUR**\n const suffix = `.${potFactoryContractId}`;\n const fullAddress = `${state.customHandle}${suffix}`;\n let customHandleError = \"\";\n if (fullAddress.length > 64) {\n customHandleError = `Handle must be ${\n 64 - suffix.length\n } characters or less`;\n } else {\n const valid = validateNearAddress(fullAddress);\n customHandleError = valid\n ? \"\"\n : `Invalid handle (can only contain lowercase alphanumeric symbols + _ or -)`;\n }\n State.update({\n customHandleError,\n });\n },\n error: state.customHandleError,\n disabled: isUpdate,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Inputs.TextArea\"}\n props={{\n label: \"Description\",\n placeholder: \"Type description\",\n value: state.description,\n onChange: (description) => State.update({ description }),\n validate: () => {\n // **CALLED ON BLUR**\n const valid =\n state.description.length <= MAX_POT_DESCRIPTION_LENGTH;\n State.update({\n descriptionError: valid\n ? \"\"\n : `Description must be ${MAX_POT_DESCRIPTION_LENGTH} characters or less`,\n });\n },\n error: state.descriptionError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n <Row>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"Referrer fee % (matching pool)\",\n placeholder: \"0\",\n percent: true,\n value: state.referrerFeeMatchingPoolPercent,\n onChange: (percent) => {\n validateAndUpdatePercentages(\n percent,\n \"referrerFeeMatchingPoolPercent\",\n \"referrerFeeMatchingPoolPercentError\",\n MAX_REFERRAL_FEE_MATCHING_POOL_BASIS_POINTS / 100\n );\n },\n validate: () => {\n // **CALLED ON BLUR**\n },\n error: state.referrerFeeMatchingPoolPercentError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"Referrer fee % (public round)\",\n placeholder: \"0\",\n percent: true,\n value: state.referrerFeePublicRoundPercent,\n onChange: (percent) => {\n validateAndUpdatePercentages(\n percent,\n \"referrerFeePublicRoundPercent\",\n \"referrerFeePublicRoundPercentError\",\n MAX_REFERRAL_FEE_PUBLIC_ROUND_BASIS_POINTS / 100\n );\n },\n validate: () => {\n // **CALLED ON BLUR**\n },\n error: state.referrerFeeMatchingPoolPercentError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"Protocol fee %\",\n value: protocolConfig ? protocolConfig.basis_points / 100 : \"-\",\n disabled: true,\n percent: true,\n }}\n />\n </Row>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Date\"}\n props={{\n label: \"Application start date\",\n // placeholder: \"0\", // TODO: possibly add this back in\n selectTime: true,\n value: state.applicationStartDate,\n onChange: (date) => {\n State.update({ applicationStartDate: date });\n },\n validate: () => {\n // **CALLED ON BLUR**\n // must be after now & before application end date\n // const now = Date.now();\n const now = new Date().getTime();\n const applicationStartDate = new Date(\n state.applicationStartDate\n ).getTime();\n const applicationEndDate = new Date(\n state.applicationEndDate\n ).getTime();\n const valid =\n applicationStartDate > now &&\n (!applicationEndDate ||\n applicationStartDate < applicationEndDate);\n State.update({\n applicationStartDateError: valid\n ? \"\"\n : \"Invalid application start date\",\n });\n },\n error: state.applicationStartDateError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Inputs.Date\"}\n props={{\n label: \"Application end date\",\n // placeholder: \"0\", // TODO: possibly add this back in\n selectTime: true,\n value: state.applicationEndDate,\n onChange: (date) => State.update({ applicationEndDate: date }),\n validate: () => {\n // **CALLED ON BLUR**\n // must be before matching round start date\n const valid =\n (!state.matchingRoundStartDate ||\n state.applicationEndDate < state.matchingRoundStartDate) &&\n (!state.applicationStartDate ||\n state.applicationEndDate > state.applicationStartDate);\n State.update({\n applicationEndDateError: valid\n ? \"\"\n : \"Invalid application end date\",\n });\n },\n error: state.applicationEndDateError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Inputs.Date\"}\n props={{\n label: \"Matching round start date\",\n selectTime: true,\n value: state.matchingRoundStartDate,\n onChange: (date) => State.update({ matchingRoundStartDate: date }),\n validate: () => {\n // **CALLED ON BLUR**\n // must be after application end and before matching round end\n const valid =\n (!state.applicationEndDate ||\n state.matchingRoundStartDate > state.applicationEndDate) &&\n (!state.matchingRoundEndDate ||\n state.matchingRoundStartDate < state.matchingRoundEndDate);\n State.update({\n matchingRoundStartDateError: valid\n ? \"\"\n : \"Invalid round start date\",\n });\n },\n error: state.matchingRoundStartDateError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Inputs.Date\"}\n props={{\n label: \"Matching round end date\",\n // placeholder: \"0\", // TODO: possibly add this back in\n selectTime: true,\n value: state.matchingRoundEndDate,\n onChange: (date) => State.update({ matchingRoundEndDate: date }),\n validate: () => {\n // **CALLED ON BLUR**\n // must be after matching round start\n const valid =\n !state.matchingRoundStartDate ||\n state.matchingRoundEndDate > state.matchingRoundStartDate;\n State.update({\n matchingRoundEndDateError: valid\n ? \"\"\n : \"Invalid round end date\",\n });\n },\n error: state.matchingRoundEndDateError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n <Row>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"Optional: Min matching pool donation amount (in NEAR)\",\n placeholder: \"0\",\n value: state.minMatchingPoolDonationAmount,\n onChange: (amountNear) => {\n State.update({ minMatchingPoolDonationAmount: amountNear });\n },\n validate: () => {\n // **CALLED ON BLUR**\n },\n error: state.referrerFeeMatchingPoolPercentError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n </Row>\n </FormSectionRightDiv>\n </FormSectionContainer>\n {/* <FormDivider /> */}\n <FormSectionContainer>\n {FormSectionLeft(\"Chef details\", \"\")}\n <FormSectionRightDiv>\n <Row>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"Assign chef\",\n placeholder: \"E.g. user.near\",\n value: state.chef,\n onChange: (chef) => State.update({ chef }),\n validate: () => {\n // **CALLED ON BLUR**\n const valid = validateNearAddress(state.chef);\n State.update({\n chefError: valid ? \"\" : \"Invalid NEAR account ID\",\n });\n },\n error: state.chefError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"Chef fee %\",\n placeholder: \"0\",\n percent: true,\n value: state.chefFeePercent,\n onChange: (percent) => {\n validateAndUpdatePercentages(\n percent,\n \"chefFeePercent\",\n \"chefFeePercentError\",\n MAX_CHEF_FEE_BASIS_POINTS / 100\n );\n },\n validate: () => {\n // **CALLED ON BLUR**\n },\n error: state.chefFeePercentError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n </Row>\n </FormSectionRightDiv>\n </FormSectionContainer>\n {/* <FormDivider /> */}\n <FormSectionContainer>\n {FormSectionLeft(\"Application details\", \"\")}\n <FormSectionRightDiv>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Text\"}\n props={{\n label: \"Max. approved projects\",\n placeholder: \"e.g. 20\",\n value: state.maxProjects,\n onChange: (maxProjects) => State.update({ maxProjects }),\n validate: () => {\n // **CALLED ON BLUR**\n const valid = parseInt(state.maxProjects) <= MAX_MAX_PROJECTS;\n State.update({\n maxProjectsError: valid ? \"\" : `Maximum ${MAX_MAX_PROJECTS}`,\n });\n },\n error: state.maxProjectsError,\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n </FormSectionRightDiv>\n </FormSectionContainer>\n <FormSectionContainer>\n {FormSectionLeft(\"Project Registration\", \"\")}\n <FormSectionRightDiv>\n <Row>\n <Checkbox>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Checkbox\"}\n props={{\n id: \"registrationSelector\",\n checked: state.usePotlockRegistry,\n onClick: (e) => {\n State.update({\n usePotlockRegistry: e.target.checked,\n });\n },\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n <Label htmlFor=\"sybilSelector\">\n Require approval on PotLock registry (recommended)\n </Label>\n </Checkbox>\n </Row>\n </FormSectionRightDiv>\n </FormSectionContainer>\n <FormSectionContainer>\n {FormSectionLeft(\"Donor Sybil Resistance\", \"\")}\n <FormSectionRightDiv>\n <Row>\n <Checkbox>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Checkbox\"}\n props={{\n id: \"sybilSelector\",\n checked: state.useNadabotSybil,\n onClick: (e) => {\n State.update({\n useNadabotSybil: e.target.checked,\n });\n },\n disabled: isUpdate ? !isAdminOrGreater : false,\n }}\n />\n <Label htmlFor=\"sybilSelector\">\n 🤖 nada.bot human verification (recommended)\n </Label>\n </Checkbox>\n </Row>\n <Row style={{ justifyContent: \"flex-end\", marginTop: \"36px\" }}>\n {!isUpdate && isAdminOrGreater && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"tertiary\",\n text: \"Cancel\",\n style: props.style || {},\n onClick: () => {\n // TODO: handle click\n },\n }}\n />\n )}\n {((isUpdate && isAdminOrGreater) || !isUpdate) && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: isUpdate ? \"Save changes\" : \"Deploy\",\n style: props.style || {},\n onClick: isUpdate ? handleUpdate : handleDeploy,\n // disabled: !canDeploy,\n }}\n />\n )}\n </Row>\n </FormSectionRightDiv>\n </FormSectionContainer>\n <Widget\n src={\"old.potlock.near/widget/Components.ModalMultiAccount\"}\n props={{\n ...props,\n isModalOpen: state.isAdminsModalOpen,\n onClose: () => State.update({ isAdminsModalOpen: false }),\n titleText: \"Add admins\",\n descriptionText: \"Add NEAR account IDs for your admins.\",\n inputValue: state.admin,\n onInputChange: (admin) => {\n State.update({ admin, adminsError: \"\" });\n },\n handleAddAccount: handleAddAdmin,\n handleRemoveAccount: handleRemoveAdmin,\n accountError: state.adminsError,\n accountIds: state.admins.map((admin) => admin.accountId),\n unitText: \"admin\",\n }}\n />\n </FormBody>\n);\n" }, "Pots.Deploy": { "": "const { canDeploy, hrefWithParams } = props;\nconst { HomeBannerStyle } = VM.require(\n \"old.potlock.near/widget/Pots.HomeBannerBackground\"\n) || {\n HomeBannerStyle: {},\n};\nconst POT_CODE_LINK = \"https://github.com/PotLock/core/tree/main/contracts/pot\"; // for directing user to view source code for Pot\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n > div:last-of-type {\n padding: 0px 175px;\n }\n @media only screen and (max-width: 992px) {\n > div:last-of-type {\n padding: 0px 20px;\n }\n }\n`;\nconst SuccessContainer = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n gap: 24px;\n`;\nconst HeaderTitle = styled.div`\n color: #292929;\n font-size: 60px;\n font-weight: 400;\n line-height: 72px;\n word-wrap: break-word;\n font-family: Lora;\n`;\nconst HeaderContainer = styled.div`\n display: flex;\n flex-direction: column;\n position: relative;\n width: 100%;\n justify-content: center;\n min-height: 400px;\n overflow: hidden;\n .background {\n position: absolute;\n pointer-events: none;\n height: 100%;\n left: 0;\n top: 0;\n }\n .content {\n position: relative;\n z-index: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n padding: 64px 175px;\n }\n .sub-title {\n letter-spacing: 1.12px;\n font-weight: 500;\n font-size: 14px;\n margin-top: 0;\n margin-bottom: 24px;\n text-transform: uppercase;\n }\n .title {\n letter-spacing: -0.4px;\n font-weight: 500;\n font-size: 40px;\n font-family: \"Lora\";\n margin: 0;\n }\n .info {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n margin-top: 24px;\n > svg {\n height: 1em;\n }\n }\n @media only screen and (max-width: 992px) {\n .content {\n padding: 64px 20px;\n }\n .title {\n font-size: 36px;\n }\n .btns {\n flex-direction: column;\n gap: 1rem;\n margin-top: 24px;\n }\n .line-break {\n display: none;\n }\n }\n @media only screen and (max-width: 480px) {\n .btns a {\n width: 100%;\n padding: 12px 0;\n }\n }\n`;\nreturn props.deploymentSuccess || state.deploymentSuccess ? (\n <SuccessContainer>\n <HeaderTitle>Deployment Successful!</HeaderTitle>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: \"View all pots\",\n style: props.style || {},\n href: props.hrefWithParams(`?tab=pots`),\n }}\n />\n </SuccessContainer>\n) : (\n <Container>\n <HeaderContainer\n style={{\n ...HomeBannerStyle,\n }}\n >\n <div className=\"content\">\n <h3 className=\"sub-title\">Deploy pot</h3>\n <h1 className=\"title\">\n Deploy a Quadratic <br className=\"line-break\" />\n Funding Round\n </h1>\n <div className=\"info\">\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6.3335 3.66732H7.66683V5.00065H6.3335V3.66732ZM6.3335 6.33398H7.66683V10.334H6.3335V6.33398ZM7.00016 0.333984C3.32016 0.333984 0.333496 3.32065 0.333496 7.00065C0.333496 10.6807 3.32016 13.6673 7.00016 13.6673C10.6802 13.6673 13.6668 10.6807 13.6668 7.00065C13.6668 3.32065 10.6802 0.333984 7.00016 0.333984ZM7.00016 12.334C4.06016 12.334 1.66683 9.94065 1.66683 7.00065C1.66683 4.06065 4.06016 1.66732 7.00016 1.66732C9.94016 1.66732 12.3335 4.06065 12.3335 7.00065C12.3335 9.94065 9.94016 12.334 7.00016 12.334Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n <div>Know More about Quadratic Funding</div>\n </div>\n </div>\n </HeaderContainer>\n <Widget\n src={\"old.potlock.near/widget/Pots.ConfigForm\"}\n props={{\n ...props,\n }}\n />\n </Container>\n);\n" }, "Components.Attribution": { "": "const Attribution = styled.div`\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-top: 100px;\n margin-bottom: 1rem;\n width: 100%;\n div {\n font-size: 11px;\n color: #7b7b7b;\n }\n svg {\n width: 20px;\n }\n @media only screen and (max-width: 480px) {\n margin-top: 86px;\n }\n`;\nreturn (\n <Attribution>\n <div>\n USD prices powered by{\" \"}\n <a href=\"https://www.coingecko.com/\" target=\"_blank\">\n CoinGecko{\" \"}\n </a>\n </div>\n </Attribution>\n);\n" }, "Cart.CheckoutBreakdown": { "": "const { yoctosToNear } = VM.require(\"old.potlock.near/widget/utils\") || {\n yoctosToNear: () => \"\",\n};\nconst { SUPPORTED_FTS } = VM.require(\"old.potlock.near/widget/constants\") || {\n SUPPORTED_FTS: {},\n};\nconst { getCart, clearCart } = VM.require(\n \"old.potlock.near/widget/SDK.cart\"\n) || {\n getCart: () => {},\n clearCart: () => {},\n};\nconst cart = getCart();\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n asyncGetDonationsForDonor: () => {},\n};\nlet DonateSDK =\n VM.require(\"old.potlock.near/widget/SDK.donate\") ||\n (() => ({\n asyncGetDonationsForDonor: () => {},\n getContractId: () => \"\",\n }));\nDonateSDK = DonateSDK({ env: props.env });\nconst DONATION_CONTRACT_ID = DonateSDK.getContractId();\nconst IPFS_BASE_URL = \"https://nftstorage.link/ipfs/\";\nBig.PE = 100;\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n gap: 24px;\n margin-top: 20px;\n width: 380px;\n // background: white;\n @media screen and (max-width: 768px) {\n width: 100%;\n margin-bottom: 50px;\n }\n`;\nconst Title = styled.div`\n color: #2e2e2e;\n font-size: 24px;\n font-weight: 600;\n line-height: 32px;\n word-wrap: break-word;\n`;\nconst CurrencyHeader = styled.div`\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 8px;\n border-radius: 5px;\n background: #f0f0f0;\n`;\nconst CurrencyHeaderText = styled.div`\n color: #7b7b7b;\n font-size: 12px;\n font-weight: 400;\n line-height: 14px;\n word-wrap: break-word;\n`;\nconst BreakdownItemContainer = styled.div`\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 8px;\n`;\nconst BreakdownItemLeft = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-start;\n width: 50%;\n gap: 8px;\n`;\nconst BreakdownItemRight = styled.div`\n display: flex;\n flex: 1;\n flex-direction: row;\n align-items: center;\n justify-content: flex-end;\n`;\nconst BreakdownItemText = styled.div`\n color: #2e2e2e;\n font-size: 14px;\n font-weight: 400;\n line-height: 16px;\n word-wrap: break-word;\n`;\nconst CurrencyIcon = styled.img`\n width: 20px;\n height: 20px;\n`;\nconst TotalContainer = styled.div`\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 8px;\n border-top: 1px #7b7b7b solid;\n`;\nconst TotalText = styled.div`\n color: #2e2e2e;\n font-size: 14px;\n font-weight: 600;\n line-height: 20px;\n word-wrap: break-word;\n`;\nconst ErrorText = styled.div`\n color: #dd3345;\n font-size: 14px;\n font-weight: 400;\n line-height: 20px;\n word-wrap: break-word;\n width: 100%;\n text-align: center;\n`;\nconst MIN_REQUIRED_DONATION_AMOUNT_PER_PROJECT = 0.1;\nconst [tokens, amountsByFt, totalAmount, donationTooSmall] = useMemo(() => {\n const tokens = {};\n const amountsByFt = {};\n let donationTooSmall = false;\n Object.entries(cart || {}).forEach(([projectId, { token, amount }]) => {\n const ft = token.text;\n if (!amountsByFt[ft]) amountsByFt[ft] = 0;\n amountsByFt[ft] += parseFloat(amount || 0);\n if (amountsByFt[ft] < MIN_REQUIRED_DONATION_AMOUNT_PER_PROJECT)\n donationTooSmall = true;\n tokens[ft] = token;\n });\n const totalAmount = Object.values(amountsByFt).reduce(\n (acc, amount) => acc + amount,\n 0\n );\n return [tokens, amountsByFt, totalAmount, donationTooSmall];\n}, [props]);\n// console.log(\"amountsByFt: \", amountsByFt);\n// console.log(\"tokens: \", tokens);\nconst handleDonate = () => {\n const transactions = [];\n let potIdContained;\n Object.entries(cart).forEach(\n ([projectId, { token, amount, referrerId, note, potId }]) => {\n const isFtDonation = token.text != \"NEAR\";\n const amountIndivisible = Big(parseFloat(amount)).mul(\n Big(10).pow(isFtDonation ? token.decimals : 24)\n );\n const args = {};\n if (isFtDonation) {\n args.receiver_id = DONATION_CONTRACT_ID;\n args.amount = amountIndivisible.toString();\n args.memo = JSON.stringify({\n recipient_id: projectId,\n referrer_id: referrerId || null,\n bypass_protocol_fee: false,\n message: note || null,\n });\n } else {\n // pot & generic contract args\n args.project_id = projectId;\n args.referrer_id = referrerId;\n args.message = note;\n // donation contract args\n args.recipient_id = projectId;\n // other\n potIdContained = potId;\n }\n transactions.push({\n contractName: isFtDonation ? token.id : potId ?? DONATION_CONTRACT_ID,\n methodName: isFtDonation ? \"ft_transfer_call\" : \"donate\",\n args,\n deposit: isFtDonation ? \"1\" : amountIndivisible.toString(),\n gas: \"300000000000000\",\n });\n }\n );\n // if cart contains a non-NEAR token, add storage_deposit to beginning of transactions\n // for each non-NEAR donation: 0.008 base amount for donation storage + 0.0001 NEAR per character in message\n if (Object.keys(amountsByFt).some((ft) => ft !== \"NEAR\")) {\n const requiredDepositFloat = transactions.reduce(\n (acc, { methodName, args }) => {\n if (methodName === \"donate\") return acc;\n const baseAmount = 0.008;\n const argsAmount = (args.message.length || 0) * 0.0001;\n return acc + baseAmount + argsAmount;\n },\n 0\n );\n transactions.unshift({\n contractName: DONATION_CONTRACT_ID,\n methodName: \"storage_deposit\",\n args: {},\n deposit: Big(requiredDepositFloat).mul(Big(10).pow(24)),\n gas: \"100000000000000\",\n });\n }\n const now = Date.now();\n Near.call(transactions);\n // NB: we won't get here if user used a web wallet, as it will redirect to the wallet\n // <-------- EXTENSION WALLET HANDLING -------->\n // poll for updates\n // TODO: update this to also poll Pot contract\n const pollIntervalMs = 1000;\n // const totalPollTimeMs = 60000; // consider adding in to make sure interval doesn't run indefinitely\n const pollId = setInterval(() => {\n (potIdContained\n ? PotSDK.asyncGetDonationsForDonor(potIdContained, context.accountId)\n : DonateSDK.asyncGetDonationsForDonor(context.accountId)\n ).then((donations) => {\n // for each project, there should be a matching donation that occurred since now()\n const foundDonations = [];\n // go through donations, add to foundDonations list\n for (const donation of donations) {\n const {\n recipient_id,\n project_id,\n donated_at_ms,\n donated_at,\n total_amount,\n } = donation;\n const matchingCartItem = cart[project_id || recipient_id];\n if (matchingCartItem && (donated_at_ms > now || donated_at > now)) {\n foundDonations.push(donation);\n }\n }\n if (foundDonations.length) {\n // donations found\n // display success message & clear cart\n clearInterval(pollId);\n props.updateSuccessfulDonationRecipientId(\n foundDonations[0].recipient_id\n );\n clearCart();\n }\n });\n }, pollIntervalMs);\n};\n// console.log(\"props\", props);\n// console.log(\"supported fts: \", SUPPORTED_FTS);\n// console.log(\"props.cart: \", props.cart);\n// console.log(\"props.projectId: \", props.projectId);\nreturn (\n <Container>\n <Title>Breakdown summary</Title>\n <CurrencyHeader>\n <CurrencyHeaderText>Currency</CurrencyHeaderText>\n <CurrencyHeaderText>Amount</CurrencyHeaderText>\n </CurrencyHeader>\n {Object.entries(amountsByFt).map(([ft, amount]) => {\n const amountFloat = parseFloat(amount || 0);\n return (\n <BreakdownItemContainer>\n <BreakdownItemLeft>\n {ft == \"NEAR\" ? (\n <CurrencyIcon src={SUPPORTED_FTS.NEAR.iconUrl} />\n ) : (\n <CurrencyIcon src={tokens[ft].icon} />\n )}\n <BreakdownItemText>{tokens[ft].text}</BreakdownItemText>\n </BreakdownItemLeft>\n <BreakdownItemRight>\n <BreakdownItemText>{amountFloat.toFixed(2)}</BreakdownItemText>\n </BreakdownItemRight>\n </BreakdownItemContainer>\n );\n })}\n {Object.keys(amountsByFt).length <= 1 &&\n amountsByFt.NEAR && ( // only show total if NEAR is the only currency being donated (otherwise it is inaccurate and confusing)\n <TotalContainer>\n <TotalText>Total</TotalText>\n <TotalText>{totalAmount.toFixed(2)}</TotalText>\n </TotalContainer>\n )}\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: `Process Donation`,\n disabled:\n !Object.keys(cart).length || donationTooSmall || !context.accountId,\n onClick: handleDonate,\n style: {\n width: \"100%\",\n },\n }}\n />\n {donationTooSmall && (\n <ErrorText>\n Minimum required donation per project is{\" \"}\n {MIN_REQUIRED_DONATION_AMOUNT_PER_PROJECT} N\n </ErrorText>\n )}\n {!context.accountId && <ErrorText>Please sign in to donate</ErrorText>}\n </Container>\n);\n" }, "Pots.Sponsors": { "": "// get donations\nconst { potId, potDetail } = props;\nconst { SUPPORTED_FTS } = VM.require(\"old.potlock.near/widget/constants\") || {\n SUPPORTED_FTS: {},\n};\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getMatchingPoolDonations: () => {},\n};\nlet sponsorshipDonations = PotSDK.getMatchingPoolDonations(potId);\nconst { NEAR } = SUPPORTED_FTS;\nState.init({\n sponsorshipDonations: null,\n});\nif (sponsorshipDonations && !state.sponsorshipDonations) {\n // accumulate donations for each address\n sponsorshipDonations = sponsorshipDonations.reduce(\n (accumulator, currentDonation) => {\n accumulator[currentDonation.donor_id] = {\n amount:\n parseFloat(accumulator[currentDonation.donor_id].amount || 0) +\n parseFloat(\n SUPPORTED_FTS.NEAR.fromIndivisible(currentDonation.net_amount)\n ),\n ...currentDonation,\n };\n return accumulator;\n },\n {}\n );\n // add % share of total to each donation\n const total = SUPPORTED_FTS.NEAR.fromIndivisible(\n potDetail.matching_pool_balance\n );\n sponsorshipDonations = Object.values(sponsorshipDonations).sort(\n (a, b) => b.amount - a.amount\n );\n sponsorshipDonations = sponsorshipDonations.map((donation) => {\n return {\n ...donation,\n percentage_share: ((donation.amount / total) * 100)\n .toFixed(2)\n .replace(/[.,]00$/, \"\"),\n };\n });\n State.update({ sponsorshipDonations });\n}\nif (!state.sponsorshipDonations)\n return <div class=\"spinner-border text-secondary\" role=\"status\" />;\nconst columns = [\"Rank\", \"Donor\", \"Amount\", \"Percentage\"];\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 24px;\n width: 100%;\n @media screen and (min-width: 375px) and (max-width: 768px) {\n width: 99%;\n }\n @media screen and (max-width: 390px) {\n width: 98%;\n }\n`;\nconst TableContainer = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n margin-top: 35px;\n padding-bottom: 1rem;\n`;\nconst { base_currency } = potDetail;\nconst maxRowItemLength = 14;\nreturn (\n <Container>\n <Widget\n src={\"old.potlock.near/widget/Pots.SponsorsBoard\"}\n props={{\n ...props,\n donations: state.sponsorshipDonations.slice(0, 6),\n base_currency: base_currency,\n }}\n />\n <TableContainer>\n <Widget\n src={\"old.potlock.near/widget/Pots.SponsorsTable\"}\n props={{\n ...props,\n sponsors: state.sponsorshipDonations,\n }}\n />\n </TableContainer>\n </Container>\n);\n" }, "Pots.SponsorsTable": { "": "const { sponsors, filter, tab, hrefWithParams } = props;\nconst isInPot = tab === \"pot\";\nconst { nearToUsd } = VM.require(\"old.potlock.near/widget/utils\") || {\n nearToUsd: 1,\n};\nconst [currentPage, setCurrentPage] = useState(1);\nconst perPage = 30; // need to be less than 50\nuseEffect(() => {\n setCurrentPage(1);\n}, [filter]);\nconst nearLogo =\n \"https://ipfs.near.social/ipfs/bafkreicdcpxua47eddhzjplmrs23mdjt63czowfsa2jnw4krkt532pa2ha\";\nconst { getTimePassed, _address, calcNetDonationAmount, reverseArr } =\n VM.require(\"old.potlock.near/widget/Components.DonorsUtils\");\nconst Container = styled.div`\n width: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2rem;\n border-radius: 6px;\n border: 1px solid #7b7b7b;\n overflow: hidden;\n .transcation {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-size: 14px;\n .header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.5rem 1rem;\n gap: 1rem;\n color: #7b7b7b;\n div {\n display: flex;\n align-items: center;\n font-weight: 600;\n &:last-of-type {\n justify-content: flex-end;\n }\n }\n }\n .address {\n width: 190px;\n margin-right: auto;\n justify-content: start !important;\n }\n .rank {\n width: 40px;\n margin-right: 2rem;\n justify-content: center;\n }\n }\n @media only screen and (max-width: 768px) {\n .transcation {\n font-size: 12px;\n .header {\n padding: 0.5rem;\n }\n .rank {\n margin-right: 0;\n width: 30px;\n }\n }\n }\n @media only screen and (max-width: 480px) {\n .transcation .address {\n width: 135px;\n flex: 1;\n }\n }\n`;\nconst TrRow = styled.div`\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n gap: 1rem;\n padding: 1rem;\n border-top: 1px solid #c7c7c7;\n > div {\n display: flex;\n align-items: center;\n }\n .address {\n color: #292929;\n font-weight: 600;\n display: flex;\n align-items: center;\n justify-content: flex-start;\n border-radius: 2px;\n transition: all 200ms;\n .profile-image {\n width: 1.5rem;\n height: 1.5rem;\n margin-right: 1rem;\n }\n }\n .sponsors-amount {\n justify-content: flex-end;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 1rem;\n }\n @media only screen and (max-width: 768px) {\n padding: 1rem 0.5rem;\n }\n`;\nconst Percentage = styled.div`\n background: #ebebeb;\n box-shadow: 0px -1px 0px 0px #dbdbdb inset, 0px 0px 0px 0.5px #dbdbdb;\n border-radius: 4px;\n padding: 2px 4px;\n min-width: 60px;\n text-align: right;\n`;\nconst NoResult = styled.div`\n font-size: 1.125rem;\n text-align: center;\n`;\nconst totalDonations = 0;\nsponsors.forEach((donation) => {\n totalDonations += donation.amount;\n});\nconst ProfileImg = ({ donor_id }) => (\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{ accountId: donor_id, style: {} }}\n />\n);\nreturn sponsors.length ? (\n <Container>\n <div className=\"transcation\">\n <div className=\"header\">\n <div className=\"rank\">Rank</div>\n <div className=\"address\">Donor</div>\n <div>Amount</div>\n {nearToUsd && !isInPot && <div>Amount (USD)</div>}\n </div>\n {sponsors\n .slice((currentPage - 1) * perPage, currentPage * perPage)\n .map((donation, idx) => {\n const { donor_id, amount, percentage_share } = donation;\n return (\n <TrRow>\n <div className=\"rank\">\n #{idx + 1 + (currentPage - 1) * perPage}\n </div>\n <a\n href={hrefWithParams(`?tab=profile&accountId=${donor_id}`)}\n className=\"address\"\n target=\"_blank\"\n >\n <ProfileImg donor_id={donor_id} />\n <OverlayTrigger\n placement=\"top\"\n overlay={<Tooltip>{donor_id}</Tooltip>}\n >\n <div> {_address(donor_id, 15)}</div>\n </OverlayTrigger>\n </a>\n <div className=\"sponsors-amount\">\n {amount.toFixed(2).replace(/[.,]00$/, \"\")}N{\" \"}\n <Percentage>\n {percentage_share === \"0\" ? \"<0.01\" : percentage_share}%\n </Percentage>{\" \"}\n </div>\n </TrRow>\n );\n })}\n </div>\n <Widget\n src={\"old.potlock.near/widget/Components.Pagination\"}\n props={{\n onPageChange: (page) => {\n setCurrentPage(page);\n },\n data: sponsors,\n currentPage,\n perPage: perPage,\n bgColor: \"#292929\",\n }}\n />\n </Container>\n) : (\n <NoResult>No Sponsors</NoResult>\n);\n" }, "ModalDonation.FormPot": { "": "const { NADABOT_HUMAN_METHOD } = VM.require(\n \"old.potlock.near/widget/constants\"\n) || {\n NADABOT_HUMAN_METHOD: \"\",\n};\nconst { VerifyInfo } = VM.require(\n `old.potlock.near/widget/ModalDonation.Banners`\n) || {\n VerifyInfo: () => {},\n Alert: () => {},\n};\nconst { nearToUsd } = VM.require(\"old.potlock.near/widget/utils\");\nconst { Checks } = VM.require(\n \"old.potlock.near/widget/ModalDonation.Checks\"\n) || {\n Checks: () => {},\n};\nconst { AmountInput } = VM.require(\n \"old.potlock.near/widget/ModalDonation.AmountInput\"\n) || {\n AmountInput: () => {},\n};\nconst { _address } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n) || {\n _address: (address) => address,\n};\nconst { Alert } = VM.require(\n \"old.potlock.near/widget/ModalDonation.Banners\"\n) || {\n Alert: () => {},\n};\nconst Form = styled.div`\n display: flex;\n flex-direction: column;\n padding: 1.5rem 0;\n`;\nconst Content = styled.div`\n display: flex;\n flex-direction: column;\n padding: 0 2rem;\n @media only screen and (max-width: 480px) {\n padding: 0 1.125rem;\n }\n`;\nconst Label = styled.div`\n font-weight: 500;\n margin-bottom: 0.5rem;\n margin-top: 0.5rem;\n`;\nconst CurrentBalance = styled.div`\n display: flex;\n margin-top: 0.5rem;\n gap: 0.5rem;\n flex-wrap: wrap;\n justify-content: flex-end;\n .amount-alert {\n color: #e54141;\n }\n .balance {\n display: flex;\n gap: 0.5rem;\n div:last-of-type {\n color: #7b7b7b;\n }\n }\n`;\nconst TotalAmount = styled.div`\n display: flex;\n gap: 0.5rem;\n align-items: center;\n margin-left: auto;\n .label {\n color: #7b7b7b;\n }\n .amount {\n font-weight: 600;\n .usd {\n color: #7b7b7b;\n }\n }\n @media only screen and (max-width: 480px) {\n width: 100%;\n justify-content: space-between;\n }\n`;\nconst Projects = styled.div`\n padding: 8px 0;\n border-top: 1px solid #ebebeb;\n margin-top: 1.5rem;\n display: flex;\n flex-direction: column;\n height: 238px;\n overflow-y: scroll;\n .project {\n display: flex;\n align-items: center;\n gap: 1rem;\n cursor: pointer;\n padding: 0.5rem 2rem;\n transition: 300ms ease-in-out;\n &:hover,\n &.selected {\n background: rgba(235, 235, 235, 0.24);\n .check {\n border-color: #dd3345;\n svg {\n display: block;\n }\n }\n }\n }\n .profile-image {\n width: 40px;\n height: 40px;\n box-shadow: 0px 0px 1px 0px #a6a6a6 inset;\n border-radius: 50%;\n }\n .info {\n display: flex;\n flex-direction: column;\n .name {\n font-weight: 600;\n }\n .address {\n color: #7b7b7b;\n transition: all 300ms;\n &:hover {\n text-decoration: none;\n color: #dd3345;\n }\n }\n }\n .check {\n margin-left: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n border: 2px solid #c7c7c7;\n border-radius: 50%;\n svg {\n display: none;\n width: 12px;\n }\n &.selected {\n border-color: #dd3345;\n svg {\n display: block;\n }\n }\n }\n @media only screen and (max-width: 480px) {\n .project {\n padding: 0.5rem 1.125rem;\n }\n }\n`;\nconst ProjectAmount = styled.div`\n margin-left: auto;\n position: relative;\n display: flex;\n border-radius: 6px;\n background: rgb(246, 245, 243);\n box-shadow: rgb(255, 255, 255) 0px 1px 0px 0px,\n rgba(41, 41, 41, 0.1) 0px 0px 4px 0px,\n rgba(41, 41, 41, 0.1) 0px 2px 4px -1px inset,\n rgba(41, 41, 41, 0.1) 0px 8px 16px -4px inset;\n input {\n padding: 10px 16px;\n padding-right: 46px;\n text-align: right;\n width: 120px;\n background: transparent;\n border: none;\n }\n svg {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n right: 1rem;\n width: 16px;\n }\n`;\nconst Button = styled.div`\n display: flex;\n margin-top: 4rem;\n margin-bottom: 0.5rem;\n padding: 0 2rem;\n button {\n padding: 12px 16px;\n width: 100%;\n font-weight: 500;\n }\n @media only screen and (max-width: 480px) {\n margin-top: 2rem;\n }\n`;\nconst ProfileImg = ({ profile }) => (\n <Widget\n src={\"old.potlock.near/widget/Project.ProfileImage\"}\n props={{\n profile,\n style: {},\n }}\n />\n);\nconst donationTypes = [\n {\n label: \"Auto\",\n info: \"(allocate funds evenly across multiple projects)\",\n val: \"auto\",\n disabled: false,\n },\n {\n label: \"Manual\",\n info: \"(manually specify amount for each project)\",\n val: \"manual\",\n disabled: false,\n },\n];\nconst isEmpty = (obj) => {\n return Object.keys(obj).length === 0;\n};\nconst FormPot = (props) => {\n const {\n amount,\n amountError,\n DENOMINATION_OPTION,\n updateState,\n selectedDenomination,\n donationType,\n ftBalance,\n hrefWithParams,\n selectedProjects,\n NADABOT_CONTRACT_ID,\n } = props;\n const projects = props.projects ?? [];\n const projectHegiht = 58;\n const projectsContaienrHegiht =\n projects.length > 4 ? 234 : projectHegiht * projects.length;\n const HandleAmoutChange = (amount) => {\n amount = amount.replace(/[^\\d.]/g, \"\"); // remove all non-numeric characters except for decimal\n if (amount === \".\") amount = \"0.\";\n updateState({ amount, amountError: \"\" });\n // error if amount is greater than balance\n if (amount > ftBalance) {\n updateState({\n amountError:\n \"You don’t have enough balance to complete this transaction.\",\n });\n } else if (parseFloat(amount) < 0.1) {\n updateState({ amountError: \"Minimum donation is 0.1 NEAR\" });\n }\n };\n const handleAddProject = (project) => {\n const updatedProjects = selectedProjects;\n if (selectedProjects[project] === \"\") {\n delete updatedProjects[project];\n } else {\n updatedProjects[project] = \"\";\n }\n updateState({\n selectedProjects: updatedProjects,\n });\n };\n const totalAmountAllocated = 0;\n Object.values(selectedProjects).forEach(\n (amount) => (totalAmountAllocated += parseFloat(amount || 0))\n );\n totalAmountAllocated = totalAmountAllocated.toFixed(1);\n const handleProjectAmount = (project, amount) => {\n amount = amount.replace(/[^\\d.]/g, \"\"); // remove all non-numeric characters except for decimal\n if (amount === \".\") amount = \"0.\";\n const updatedProjects = selectedProjects;\n updatedProjects[project] = amount;\n const totalAmount = 0;\n Object.values(updatedProjects).forEach(\n (amount) => (totalAmount += parseFloat(amount))\n );\n if (totalAmount > ftBalance && ftBalance !== null) {\n updateState({\n amountError:\n \"You don’t have enough balance to complete this transaction.\",\n });\n } else if (parseFloat(amount) < 0.1 && parseFloat(amount) !== 0) {\n updateState({ amountError: \"Minimum donation is 0.1 NEAR\" });\n } else {\n updateState({ amountError: \"\" });\n }\n updateState({\n selectedProjects: updatedProjects,\n });\n };\n const isUserHumanVerified = Near.view(\n NADABOT_CONTRACT_ID,\n NADABOT_HUMAN_METHOD,\n {\n account_id: accountId,\n }\n );\n const needsToVerify = isUserHumanVerified === false;\n return (\n <Form>\n <Content>\n <Label>How do you want to allocate funds?</Label>\n <Checks\n options={donationTypes}\n value={donationType}\n onClick={(val) => {\n console.log(\"donationType\", val);\n updateState({\n selectedProjects: {},\n donationType: val,\n });\n }}\n />\n {donationType === \"auto\" && (\n <>\n <Label\n style={{\n marginTop: \"1.5rem\",\n }}\n >\n Amount\n </Label>\n <AmountInput\n value={amount}\n donationType={donationType}\n HandleAmoutChange={HandleAmoutChange}\n updateState={updateState}\n denominationOptions={DENOMINATION_OPTION}\n selectedDenomination={selectedDenomination}\n />\n </>\n )}\n <CurrentBalance>\n {ftBalance && (\n <div className=\"balance\">\n <div>\n {ftBalance} <span> {selectedDenomination.text} </span>\n </div>\n <div>available</div>\n </div>\n )}\n {donationType === \"manual\" && (\n <TotalAmount>\n <div className=\"label\">Total amount allocated</div>\n <div className=\"amount\">\n {totalAmountAllocated}\n <span>NEAR</span>\n {nearToUsd && (\n <span className=\"usd\">\n ~$\n {nearToUsd}\n </span>\n )}\n </div>\n </TotalAmount>\n )}\n </CurrentBalance>\n {amountError && <Alert error={amountError} />}\n {needsToVerify && <VerifyInfo />}\n </Content>\n <Projects style={{ height: projectsContaienrHegiht + \"px\" }}>\n {projects.map(({ project_id }) => {\n const profile = Social.getr(`${project_id}/profile`);\n return (\n <div\n className={`project ${\n selectedProjects[project_id] === \"\" ? \"selected\" : \"\"\n }`}\n style={{\n cursor: donationType == \"auto\" ? \"pointer\" : \"default\",\n }}\n key={project_id}\n onClick={() =>\n donationType == \"auto\" ? handleAddProject(project_id) : {}\n }\n >\n <ProfileImg profile={profile} />\n <div className=\"info\">\n {profile?.name && (\n <div className=\"name\">{_address(profile?.name, 20)}</div>\n )}\n <a\n className=\"address\"\n href={hrefWithParams(`?tab=project&projectId=${project_id}`)}\n target=\"_blank\"\n >\n {_address(project_id, 20)}\n </a>\n </div>\n {donationType === \"manual\" ? (\n <ProjectAmount>\n <input\n className=\"amount\"\n type=\"text\"\n placeholder=\"0.00\"\n onChange={(e) =>\n handleProjectAmount(project_id, e.target.value)\n }\n />\n <svg\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <g clip-path=\"url(#clip0_454_78)\">\n <circle\n cx=\"8\"\n cy=\"8\"\n r=\"7.25\"\n stroke=\"#292929\"\n stroke-width=\"1.5\"\n />\n <path\n d=\"M11.1477 4C10.851 4 10.5763 4.15333 10.421 4.406L8.74866 6.88867C8.72453 6.92441 8.71422 6.96772 8.71967 7.01051C8.72511 7.05329 8.74594 7.09264 8.77826 7.1212C8.81057 7.14976 8.85218 7.1656 8.89531 7.16574C8.93844 7.16589 8.98015 7.15034 9.01266 7.122L10.6587 5.69467C10.6683 5.68598 10.6802 5.68028 10.6931 5.67828C10.7059 5.67628 10.719 5.67806 10.7308 5.6834C10.7426 5.68875 10.7526 5.69742 10.7596 5.70836C10.7665 5.7193 10.7702 5.73203 10.77 5.745V10.215C10.77 10.2287 10.7658 10.2421 10.7579 10.2534C10.7501 10.2646 10.7389 10.2732 10.726 10.2778C10.7131 10.2825 10.6991 10.2831 10.6858 10.2795C10.6726 10.2758 10.6608 10.2682 10.652 10.2577L5.67667 4.30167C5.59667 4.20709 5.49701 4.1311 5.38463 4.079C5.27226 4.0269 5.14987 3.99994 5.026 4H4.85233C4.62628 4 4.40949 4.0898 4.24964 4.24964C4.0898 4.40949 4 4.62628 4 4.85233V11.1477C4 11.3333 4.06061 11.5139 4.17263 11.6619C4.28465 11.81 4.44194 11.9174 4.6206 11.9679C4.79926 12.0184 4.98952 12.0091 5.16245 11.9416C5.33538 11.874 5.48152 11.7519 5.57867 11.5937L7.251 9.111C7.27513 9.07525 7.28544 9.03194 7.27999 8.98916C7.27455 8.94637 7.25372 8.90703 7.22141 8.87846C7.18909 8.8499 7.14748 8.83407 7.10435 8.83392C7.06122 8.83377 7.01951 8.84932 6.987 8.87766L5.341 10.3053C5.33134 10.3139 5.31939 10.3195 5.3066 10.3215C5.29381 10.3234 5.28074 10.3216 5.26898 10.3162C5.25721 10.3108 5.24726 10.3021 5.24034 10.2912C5.23342 10.2803 5.22983 10.2676 5.23 10.2547V5.784C5.22997 5.77027 5.23418 5.75687 5.24206 5.74563C5.24993 5.73438 5.26109 5.72584 5.274 5.72117C5.28691 5.71651 5.30094 5.71594 5.31419 5.71955C5.32743 5.72315 5.33924 5.73076 5.348 5.74133L10.3227 11.698C10.4847 11.8893 10.7227 11.9997 10.9733 12H11.147C11.373 12.0001 11.5898 11.9104 11.7498 11.7507C11.9097 11.591 11.9997 11.3744 12 11.1483V4.85233C11.9999 4.62631 11.9101 4.40956 11.7503 4.24974C11.5904 4.08992 11.3737 4.00009 11.1477 4Z\"\n fill=\"#292929\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_454_78\">\n <rect width=\"16\" height=\"16\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n </ProjectAmount>\n ) : (\n <div className=\"check\">\n <svg\n viewBox=\"0 0 12 10\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <g clip-path=\"url(#clip0_468_92)\">\n <path\n d=\"M1 5.1618L4 8.16197L11.1621 1\"\n stroke=\"#DD3345\"\n stroke-width=\"2\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_468_92\">\n <rect width=\"12\" height=\"10\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n </div>\n )}\n </div>\n );\n })}\n </Projects>\n <Button>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n disabled:\n isEmpty(selectedProjects) ||\n (donationType === \"auto\"\n ? amountError || parseFloat(amount) === 0 || !amount\n : totalAmountAllocated > ftBalance ||\n amountError ||\n parseFloat(totalAmountAllocated) === 0),\n text: \"Proceed to donate\",\n onClick: () => {\n if (donationType === \"auto\")\n updateState({ currentPage: \"confirmPot\" });\n else {\n updateState({\n currentPage: \"confirmPot\",\n amount: totalAmountAllocated,\n });\n }\n },\n }}\n />\n </Button>\n </Form>\n );\n};\nreturn {\n FormPot,\n};\n" }, "Pots.ButtonVerifyToDonate": { "": "return (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n ...props,\n type: \"primary\",\n text: \"Verify to Donate\",\n style: props.style || {},\n href: props.href,\n target: \"_blank\",\n }}\n />\n);\n" }, "ModalDonation.Form": { "": "const { NADABOT_HUMAN_METHOD } = VM.require(\n \"old.potlock.near/widget/constants\"\n) || {\n NADABOT_HUMAN_METHOD: \"\",\n};\nconst { AmountInput } = VM.require(\n \"old.potlock.near/widget/ModalDonation.AmountInput\"\n) || {\n AmountInput: () => {},\n};\nconst { Checks } = VM.require(\n \"old.potlock.near/widget/ModalDonation.Checks\"\n) || {\n Checks: () => {},\n};\nconst { VerifyInfo, Alert } = VM.require(\n \"old.potlock.near/widget/ModalDonation.Banners\"\n) || {\n VerifyInfo: () => {},\n Alert: () => {},\n};\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getConfig: () => {},\n};\nconst Form = styled.div`\n display: flex;\n flex-direction: column;\n padding: 1.5rem 2rem;\n @media only screen and (max-width: 480px) {\n padding: 1.5rem 1.125rem;\n }\n`;\nconst Label = styled.div`\n font-weight: 500;\n margin-bottom: 0.5rem;\n margin-top: 0.5rem;\n`;\nconst Button = styled.div`\n display: flex;\n margin-top: 4rem;\n margin-bottom: 0.5rem;\n button {\n padding: 12px 16px;\n width: 100%;\n font-weight: 500;\n }\n @media only screen and (max-width: 480px) {\n margin-top: 2rem;\n }\n`;\nconst CurrentBalance = styled.div`\n display: flex;\n margin-top: 0.5rem;\n gap: 0.5rem;\n justify-content: flex-end;\n .amount-alert {\n color: #e54141;\n }\n .balance {\n display: flex;\n gap: 0.5rem;\n div:last-of-type {\n color: #7b7b7b;\n }\n }\n`;\nconst PotWrapper = styled.div`\n display: flex;\n flex-direction: column;\n margin-top: 1.5rem;\n`;\nconst PotSelector = styled.div`\n display: flex;\n > div:last-of-type {\n width: 100%;\n }\n`;\nconst Pot = styled.div`\n border-radius: 6px;\n border: 1px solid #dbdbdb;\n border-bottom-width: 2px;\n background: #fff;\n padding: 0.75rem 1rem;\n`;\nconst SelectPot = ({ selectedRound, activeRoundsOptions, updateState }) => (\n <PotSelector>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Dropdown\"}\n props={{\n sortVal: activeRoundsOptions\n ? activeRoundsOptions[selectedRound].label\n : \"\",\n showCount: false,\n sortList: Object.values(activeRoundsOptions),\n buttonStyle: {\n border: \"1px solid #dbdbdb\",\n padding: \"0.75rem 1rem\",\n borderBottomWidth: \"2px\",\n borderRadius: \"6px\",\n justifyContent: \"space-between\",\n },\n menuStyle: {\n top: \"120%\",\n },\n FilterMenuCustomStyle: `left:0; right:auto;`,\n handleSortChange: ({ val }) => {\n updateState({\n selectedRound: val,\n });\n },\n }}\n />\n </PotSelector>\n);\nconst FormDirect = (props) => {\n const {\n projectId,\n profile,\n amount,\n amountError,\n denominationOptions,\n updateState,\n selectedDenomination,\n donationType,\n ftBalance,\n activeRounds,\n NADABOT_CONTRACT_ID,\n accountId,\n } = props;\n const isUserHumanVerified = Near.view(\n NADABOT_CONTRACT_ID,\n NADABOT_HUMAN_METHOD,\n {\n account_id: accountId,\n }\n );\n const needsToVerify = isUserHumanVerified === false && donationType === \"pot\";\n const donationTypes = [\n {\n label: \"Direct donation\",\n val: \"direct\",\n disabled: false,\n },\n {\n label: \"Quadratically matched donation\",\n val: \"pot\",\n disabled: !activeRounds || activeRounds.length === 0,\n disabledText: \"(no pots available)\",\n },\n ];\n const activeRoundsOptions = {};\n (activeRounds || []).forEach((round) => {\n activeRoundsOptions[round] = {\n label: PotSDK.getConfig(round)?.pot_name || round,\n val: round,\n };\n });\n const isFtDonation = selectedDenomination.text !== \"NEAR\";\n const HandleAmoutChange = (amount) => {\n amount = amount.replace(/[^\\d.]/g, \"\"); // remove all non-numeric characters except for decimal\n if (amount === \".\") amount = \"0.\";\n updateState({ amount, amountError: \"\" });\n // error if amount is greater than balance\n if (amount > ftBalance && ftBalance !== null) {\n updateState({\n amountError:\n \"You don’t have enough balance to complete this transaction.\",\n });\n } else if (!isFtDonation && parseFloat(amount) < 0.1) {\n updateState({ amountError: \"Minimum donation is 0.1 NEAR\" });\n }\n };\n const isLoading =\n donationType === \"pot\"\n ? isUserHumanVerified === null || activeRounds === null\n : false;\n return projectId ? (\n profile === null ? (\n <Widget src={\"old.potlock.near/widget/Components.Loading\"} />\n ) : (\n <Form>\n <Label>How do you want to donate?</Label>\n <Checks\n options={donationTypes}\n value={donationType}\n onClick={(val) =>\n updateState({\n donationType: val,\n })\n }\n />\n {donationType === \"pot\" && (\n <PotWrapper>\n <Label>Select Pot</Label>\n <SelectPot {...props} activeRoundsOptions={activeRoundsOptions} />\n </PotWrapper>\n )}\n <Label\n style={{\n marginTop: \"1.5rem\",\n }}\n >\n Amount\n </Label>\n <AmountInput\n value={amount}\n donationType={donationType}\n HandleAmoutChange={HandleAmoutChange}\n updateState={updateState}\n denominationOptions={denominationOptions}\n selectedDenomination={selectedDenomination}\n />\n {ftBalance && (\n <CurrentBalance>\n <div className=\"balance\">\n <div>\n {ftBalance} <span> {selectedDenomination.text} </span>\n </div>\n <div>available</div>\n </div>\n </CurrentBalance>\n )}\n {amountError && <Alert error={amountError} />}\n {needsToVerify && <VerifyInfo />}\n <Button>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n disabled: amountError || !amount,\n text: isLoading ? \"Loading...\" : \"Proceed to donate\",\n onClick: () => updateState({ currentPage: \"confirm\" }),\n }}\n />\n </Button>\n </Form>\n )\n ) : (\n \"\"\n );\n};\nreturn {\n FormDirect,\n};\n" }, "Components.ProjectCard": { "": "const { id, review_notes, status, totalAmount } = props;\nconst { getTagsFromSocialProfileData } = VM.require(\n \"old.potlock.near/widget/utils\"\n) || {\n getTagsFromSocialProfileData: () => [],\n};\nconst IPFS_BASE_URL = \"https://ipfs.near.social/ipfs/\";\nconst cardData = Social.getr(`${id}/profile`);\nlet DonateSDK =\n VM.require(\"old.potlock.near/widget/SDK.donate\") ||\n (() => ({\n getDonationsForRecipient: () => {},\n }));\nDonateSDK = DonateSDK({ env: props.env });\nconst donationsForProject = DonateSDK.getDonationsForRecipient(id);\nconst Card = styled.a`\n display: flex;\n flex-direction: column;\n width: 408px;\n border-radius: 2px;\n background: white;\n box-shadow: 0px -2px 0px #dbdbdb inset;\n border: 1px solid #292929;\n &:hover {\n text-decoration: none;\n cursor: pointer;\n }\n @media screen and (max-width: 768px) {\n width: 340px;\n }\n min-height: 429px;\n margin-left: auto;\n margin-right: auto;\n height: max-content;\n overflow: hidden;\n`;\nconst CardBody = styled.div`\n position: relative;\n padding: 24px;\n display: flex;\n flex-direction: column;\n gap: 16px;\n flex-grow: 1;\n`;\nconst CardImage = styled.img`\n height: 150px;\n min-height: 150px;\n width: 100%;\n object-fit: cover;\n`;\nconst CardTitle = styled.div`\n color: #292929;\n font-size: 17px;\n font-style: normal;\n font-weight: 600;\n line-height: 24px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n`;\nconst CardDescription = styled.div`\n color: #292929;\n font-size: 17px;\n font-style: normal;\n font-weight: 400;\n line-height: 28px;\n flex-grow: 1;\n`;\nconst CardTag = styled.div`\n color: #292929;\n width: max-content;\n white-space: nowrap;\n padding: 8px;\n border-radius: 4px;\n box-shadow: 0px -1px 0px 0px #c7c7c7 inset, 0px 0px 0px 0.5px #c7c7c7;\n border: 1px solid #c7c7c7;\n font-size: 14px;\n font-style: normal;\n font-weight: 400;\n line-height: 20px;\n`;\nconst CardTagContainer = styled.div`\n display: flex;\n gap: 12px;\n flex-wrap: wrap;\n`;\nconst CardAvatar = styled.img`\n position: absolute;\n top: -20px;\n left: 24px;\n border-radius: 100%;\n width: 40px;\n height: 40px;\n border: 3px solid #fff;\n`;\nconst CardFooter = styled.div`\n border-top: 1px solid #000;\n padding: 16px 24px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n`;\nconst TotalDonate = styled.div`\n color: #292929;\n font-size: 17px;\n font-style: normal;\n font-weight: 600;\n line-height: 24px;\n`;\nconst DonationButton = styled.button`\n padding: 12px 16px;\n font-size: 14px;\n font-style: normal;\n font-weight: 500;\n line-height: 20px;\n background: #fef6ee;\n border-radius: 6px;\n border: none;\n box-shadow: 0px -2px 0px 0px #464646 inset, 0px 0px 0px 1px #464646;\n &:hover {\n background: #dd3345;\n color: #fff;\n }\n`;\nconst AddToCartButton = styled.button`\n border: none;\n background: none;\n color: #dd3345;\n text-decoration: none;\n &:hover {\n text-decoration: underline;\n }\n padding: 12px 16px;\n`;\nconst ButtonGroup = styled.div`\n display: flex;\n gap: 10px;\n align-items: center;\n`;\nconst getCategory = (category) => {\n switch (category) {\n case \"social-impact\":\n return \"Social Impact\";\n case \"non-profit\":\n return \"Non Profit\";\n case \"climate\":\n return \"Climate\";\n case \"public-good\":\n return \"Public Good\";\n case \"de-sci\":\n return \"Desci\";\n case \"open-source\":\n return \"Open Source\";\n case \"community\":\n return \"Community\";\n case \"education\":\n return \"Education\";\n }\n};\nconst projectUrl = props.hrefWithParams(`?tab=project&projectId=${id}`);\nconst tags = getTagsFromSocialProfileData(cardData);\nreturn (\n <>\n <Card href={projectUrl}>\n <CardImage\n src={\n cardData &&\n cardData?.backgroundImage &&\n cardData?.backgroundImage?.ipfs_cid\n ? `${IPFS_BASE_URL}${cardData.backgroundImage.ipfs_cid}`\n : \"https://ipfs.near.social/ipfs/bafkreih4i6kftb34wpdzcuvgafozxz6tk6u4f5kcr2gwvtvxikvwriteci\"\n }\n alt=\"background\"\n />\n <CardBody>\n <CardAvatar\n src={\n cardData && cardData?.image && cardData?.image?.ipfs_cid\n ? `${IPFS_BASE_URL}${cardData.image.ipfs_cid}`\n : \"https://ipfs.near.social/ipfs/bafkreih4i6kftb34wpdzcuvgafozxz6tk6u4f5kcr2gwvtvxikvwriteci\"\n }\n alt=\"avatar\"\n />\n <CardTitle>{cardData?.name}</CardTitle>\n <CardDescription>\n {cardData && cardData?.description.length > 60\n ? cardData.description.slice(0, 70) + \"...\"\n : cardData.description}\n </CardDescription>\n <CardTagContainer>\n {tags.map((tag) => (\n <CardTag key={tag}>{tag}</CardTag>\n ))}\n </CardTagContainer>\n </CardBody>\n <CardFooter>\n <TotalDonate>\n ${totalAmount(donationsForProject)}{\" \"}\n <span style={{ fontWeight: 400 }}>Raised</span>\n </TotalDonate>\n <ButtonGroup>\n <AddToCartButton\n onClick={(e) => {\n e.preventDefault();\n if (existsInCart) {\n props.removeProjectsFromCart([props.id]);\n } else {\n props.addProjectsToCart([\n {\n id: props.id,\n amount: \"1\",\n ft: \"NEAR\",\n referrerId: props.referrerId,\n },\n ]);\n if (props.showModal) {\n props.setIsCartModalOpen(true);\n }\n }\n }}\n >\n Add to cart\n </AddToCartButton>\n <DonationButton\n onClick={(e) => {\n e.preventDefault();\n props.openDonateToProjectModal(props.id);\n }}\n >\n Donate\n </DonationButton>\n </ButtonGroup>\n </CardFooter>\n </Card>\n </>\n);\n" }, "Components.NewHero": { "": "const Container = styled.div`\n display: flex;\n flex-direction: column;\n`;\nconst HeroContainer = styled.div`\n display: flex;\n flex-direction: column;\n position: relative;\n width: 100%;\n justify-content: center;\n border: 1px solid #f8d3b0;\n border-radius: 12px;\n overflow: hidden;\n .background {\n position: absolute;\n pointer-events: none;\n left: 0px;\n width: 100%;\n top: 0px;\n min-height: 600px;\n }\n .content {\n position: relative;\n z-index: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n padding: 64px 40px;\n }\n .sub-title {\n color: #dd3345;\n font-weight: 600;\n font-size: 16px;\n margin-top: 0;\n margin-bottom: 12px;\n }\n .title {\n letter-spacing: -0.4px;\n font-weight: 500;\n font-size: 40px;\n font-family: \"Lora\";\n margin: 0;\n }\n .btns {\n display: flex;\n align-items: center;\n gap: 2rem;\n margin-top: 40px;\n font-size: 14px;\n a,\n button {\n padding: 12px 16px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: 500;\n border-radius: 6px;\n box-shadow: 0px 0px 0px 1px #292929, 0px -2px 0px 0px #292929 inset;\n border: none;\n text-decoration: none;\n color: #292929;\n transition: all 300ms;\n &:hover {\n background: #292929;\n color: white;\n }\n }\n button {\n color: white;\n background: #dd3345;\n &:hover {\n }\n }\n }\n @media only screen and (max-width: 768px) {\n .content {\n padding: 48px 20px;\n }\n .title {\n font-size: 36px;\n }\n .btns {\n flex-direction: column;\n gap: 1rem;\n margin-top: 24px;\n }\n .line-break {\n display: none;\n }\n }\n @media only screen and (max-width: 480px) {\n .btns a,\n button {\n width: 100%;\n padding: 12px 0;\n }\n }\n`;\nconst Line = styled.div`\n width: 100%;\n height: 1px;\n background: #ebebeb;\n margin-top: 1rem;\n`;\nconst { HomeBannerStyle } = VM.require(\n \"old.potlock.near/widget/Pots.HomeBannerBackground\"\n) || {\n HomeBannerStyle: {},\n};\nconst { DonationStats } = VM.require(\n \"old.potlock.near/widget/Project.DonationStats\"\n) || {\n DonationStats: () => {},\n};\nconst NewHero = ({ isRegisteredProject, accountId, donateRandomly }) => {\n return (\n <Container>\n <HeroContainer\n style={{\n ...HomeBannerStyle,\n }}\n >\n <div className=\"content\">\n <h3 className=\"sub-title\">Transforming Funding for Public Goods</h3>\n <h1 className=\"title\">\n Discover impact projects, donate directly, &{\" \"}\n <br className=\"line-break\" /> participate in funding rounds.\n </h1>\n <div className=\"btns\">\n <button onClick={donateRandomly} className=\"donate-btn\">\n Donate Randomly\n </button>\n <a\n href={\n isRegisteredProject\n ? `?tab=project&projectId=${accountId}`\n : \"?tab=createproject\"\n }\n >\n {isRegisteredProject\n ? \"View Your Project\"\n : \"Register Your Project\"}\n </a>\n </div>\n </div>\n </HeroContainer>\n <DonationStats />\n <Line />\n </Container>\n );\n};\nreturn {\n NewHero,\n};\n" }, "Inputs.Select": { "": "const label = props.label ?? \"Label\";\nconst noLabel = props.noLabel ?? false;\nconst placeholder = props.placeholder ?? \"Select an option\";\nconst value = props.value ?? \"\";\nconst options = props.options ?? [];\nconst onChange = props.onChange ?? (() => {});\nconst validate = props.validate ?? (() => {});\nconst error = props.error ?? \"\";\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n padding: 0px;\n gap: 0.45em;\n width: 100%;\n`;\nconst Label = styled.label`\n font-weight: 500;\n font-size: 14px;\n line-height: 16px;\n word-wrap: break-word;\n color: #2e2e2e;\n`;\nconst Error = styled.span`\n display: inline-block;\n font-style: normal;\n font-weight: 400;\n font-size: 0.75em;\n line-height: 1.25em;\n color: #ff4d4f;\n height: 0;\n overflow: hidden;\n transition: height 0.3s ease-in-out;\n &.show {\n height: 1.25em;\n }\n`;\nconst Input = styled.div`\n box-sizing: border-box;\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n padding: 0.5em 0.75em;\n gap: 10px;\n background: #ffffff;\n border: 1px solid #d0d5dd;\n // box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);\n boxshadow: 0px -2px 0px rgba(93, 93, 93, 0.24) inset;\n border-radius: 4px;\n color: #101828;\n width: 100%;\n`;\nconst Placeholder = styled.span`\n color: #a0a3a8;\n`;\nconst scaleOut = styled.keyframes`\n from {\n transform: scaleY(0);\n }\n to {\n transform: scaleY(1);\n }\n`;\nconst Content = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n padding: 0;\n gap: 0.5em;\n width: 100%;\n border: 1px solid #d0d5dd;\n border-radius: 4px;\n background: #ffffff;\n z-index: 3 !important;\n /* &[data-state=\"open\"] { */\n /* animation: ${scaleOut} 0.2s ease-in-out; */\n /* } */\n /**/\n /* &[data-state=\"closed\"] { */\n /* animation: ${scaleOut} 0.2s ease-in-out reverse; */\n /* } */\n`;\nconst Viewport = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n padding: 0;\n width: 100%;\n`;\nconst Item = styled.button`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n padding: 0.5em 0.75em;\n gap: 0.5em;\n width: 100%;\n cursor: pointer;\n background: transparent;\n border: none;\n transition: background 0.2s ease-in-out;\n &:nth-child(n + 1) {\n border-top: 1px solid #d0d5dd;\n }\n &:hover {\n background: #d0d5dd;\n boder: none;\n }\n &:focus {\n outline: none;\n }\n`;\nreturn (\n <Container style={props.containerStyles || {}}>\n {noLabel ? <></> : <Label>{label}</Label>}\n <Select.Root\n value={value?.value}\n onValueChange={(value) =>\n onChange(options.find((option) => option.value === value))\n }\n >\n <Select.Trigger asChild={true}>\n <Input style={props.inputStyles || {}}>\n {props.iconLeft && props.iconLeft}\n <Select.Value\n aria-label={value.value}\n placeholder={<Placeholder>{placeholder}</Placeholder>}\n />\n <Select.Icon>\n <svg\n width=\"12\"\n height=\"8\"\n viewBox=\"0 0 12 8\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M10.59 0.295044L6 4.87504L1.41 0.295044L0 1.70504L6 7.70504L12 1.70504L10.59 0.295044Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n </Select.Icon>\n </Input>\n </Select.Trigger>\n <Select.Content asChild={true}>\n <Content>\n <Select.Viewport asChild={true}>\n <Viewport>\n {options.map(({ text, value }) => (\n <Select.Item value={value} asChild={true}>\n <Item>\n <Select.ItemText>{text}</Select.ItemText>\n <Select.ItemIndicator>\n <svg\n width=\"15\"\n height=\"15\"\n viewBox=\"0 0 15 15\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M11.4669 3.72684C11.7558 3.91574 11.8369 4.30308 11.648 4.59198L7.39799 11.092C7.29783 11.2452 7.13556 11.3467 6.95402 11.3699C6.77247 11.3931 6.58989 11.3355 6.45446 11.2124L3.70446 8.71241C3.44905 8.48022 3.43023 8.08494 3.66242 7.82953C3.89461 7.57412 4.28989 7.55529 4.5453 7.78749L6.75292 9.79441L10.6018 3.90792C10.7907 3.61902 11.178 3.53795 11.4669 3.72684Z\"\n fill=\"currentColor\"\n fill-rule=\"evenodd\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </Select.ItemIndicator>\n </Item>\n </Select.Item>\n ))}\n </Viewport>\n </Select.Viewport>\n </Content>\n </Select.Content>\n </Select.Root>\n </Container>\n);\n" }, "Pots.Projects": { "": "const PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getApprovedApplications: () => {},\n getPublicRoundDonations: () => {},\n getFlaggedAccounts: () => {},\n};\n// Card Skeleton - Loading fallback\nconst loadingSkeleton = styled.keyframes`\n 0% {\n opacity: 1;\n }\n 50% {\n opacity: 0.4;\n }\n 100% {\n opacity: 1;\n }\n`;\nconst CardSkeletonContainer = styled.div`\n display: flex;\n flex-direction: column;\n height: 447px;\n width: 100%;\n max-width: 400px;\n border-radius: 12px;\n background: white;\n box-shadow: 0px -2px 0px #dbdbdb inset;\n border: 1px solid #dbdbdb;\n margin-left: auto;\n margin-right: auto;\n overflow: hidden;\n animation-name: ${loadingSkeleton};\n animation-duration: 1s;\n animation-iteration-count: infinite;\n`;\nconst HeaderSkeleton = styled.div`\n display: block;\n width: 100%;\n height: 168px;\n background: #eee;\n`;\nconst ProfileImageSkeleton = styled.div`\n background: #e0e0e0;\n margin-left: 32px;\n transform: translateY(148px);\n width: 40px;\n height: 40px;\n position: absolute;\n border-radius: 999px;\n`;\nconst TitleSkeleton = styled.div`\n width: 120px;\n height: 24px;\n background: #eee;\n margin-left: 24px;\n margin-top: 24px;\n`;\nconst DescriptionSkeleton = styled.div`\n width: 83%;\n height: 48px;\n background: #eee;\n margin-left: 24px;\n margin-top: 24px;\n`;\nconst TagSkeleton = styled.div`\n background: #eee;\n border-radius: 4px;\n height: 34px;\n width: 110px;\n margin: 24px;\n`;\nconst FooterItemSkeleton = styled.div`\n width: 150px;\n height: 40px;\n background: #eee;\n @media screen and (max-width: 390px) {\n width: 100px;\n }\n`;\nconst DonationsInfoContainerSkeleton = styled.div`\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 16px 24px;\n width: 100%;\n border-top: 1px #f0f0f0 solid;\n`;\nconst DonationsInfoItemSkeleton = styled.div`\n display: flex;\n flex-direction: row;\n gap: 8px;\n align-items: center;\n`;\nconst CardSkeleton = () => (\n <CardSkeletonContainer>\n <HeaderSkeleton />\n <ProfileImageSkeleton />\n <TitleSkeleton />\n <DescriptionSkeleton />\n <TagSkeleton />\n <DonationsInfoContainerSkeleton>\n <DonationsInfoItemSkeleton>\n <FooterItemSkeleton />\n </DonationsInfoItemSkeleton>\n <DonationsInfoItemSkeleton>\n <FooterItemSkeleton />\n </DonationsInfoItemSkeleton>\n </DonationsInfoContainerSkeleton>\n </CardSkeletonContainer>\n);\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n`;\nconst Title = styled.div`\n font-size: 18px;\n display: flex;\n align-items: center;\n gap: 1.5rem;\n width: fit-content;\n margin-bottom: 1.5rem;\n div:first-of-type {\n font-weight: 600;\n }\n`;\nconst SearchBar = styled.div`\n display: flex;\n position: relative;\n width: 100%;\n border-radius: 6px;\n border: 0.5px solid #292929;\n margin-bottom: 0.5rem;\n svg {\n position: absolute;\n left: 1rem;\n top: 50%;\n transform: translateY(-50%);\n }\n input {\n font-size: 14px;\n background: transparent;\n width: 100%;\n height: 100%;\n padding: 12px 16px 12px 3rem;\n border: none;\n outline: none;\n }\n @media only screen and (max-width: 768px) {\n svg {\n left: 1rem;\n }\n input {\n padding: 8px 24px 8px 54px;\n }\n }\n`;\nconst [searchTerm, setSearchTerm] = useState(\"\");\nconst [filteredProjects, setFilteredProjects] = useState([]);\nconst [projects, setProjects] = useState(null);\nconst [flaggedAddresses, setFlaggedAddresses] = useState(null);\nconst [payouts, setPayouts] = useState(null);\n// get projects\nconst { potId, potDetail, allDonations } = props;\nconst {\n calculatePayouts,\n getTagsFromSocialProfileData,\n getTeamMembersFromSocialProfileData,\n} = VM.require(\"old.potlock.near/widget/utils\") || {\n calculatePayouts: () => {},\n getFlaggedAccounts: () => {},\n getTagsFromSocialProfileData: () => [],\n getTeamMembersFromSocialProfileData: () => [],\n};\nif (!projects) {\n PotSDK.asyncGetApprovedApplications(potId).then((projects) => {\n setProjects(projects);\n setFilteredProjects(projects);\n });\n}\nif (!projects)\n return <div class=\"spinner-border text-secondary\" role=\"status\" />;\nconst {\n public_round_start_ms,\n public_round_end_ms,\n referral_fee_public_round_basis_points,\n} = potDetail;\nconst now = Date.now();\nconst publicRoundOpen =\n now >= public_round_start_ms && now < public_round_end_ms;\nif (!flaggedAddresses) {\n PotSDK.getFlaggedAccounts(potDetail, potId)\n .then((data) => {\n const listOfFlagged = [];\n data.forEach((adminFlaggedAcc) => {\n const addresses = Object.keys(adminFlaggedAcc.potFlaggedAcc);\n listOfFlagged.push(...addresses);\n });\n setFlaggedAddresses(listOfFlagged);\n })\n .catch((err) => console.log(\"error getting the flagged accounts \", err));\n}\nif (!payouts) {\n if (allDonations.length && flaggedAddresses)\n calculatePayouts(\n allDonations,\n potDetail.matching_pool_balance,\n flaggedAddresses\n )\n .then((payouts) => {\n setPayouts(payouts ?? []);\n })\n .catch((err) => {\n console.log(\"error while calculating payouts \", err);\n setPayouts([]);\n });\n}\nconst searchByWords = (searchTerm) => {\n if (projects.length) {\n searchTerm = searchTerm.toLowerCase().trim();\n setSearchTerm(searchTerm);\n const updatedProjects = projects.filter((project) => {\n const profile = Social.getr(`${id}/profile`);\n const fields = [\n project.project_id,\n project.status,\n profile.description,\n profile.name,\n getTagsFromSocialProfileData(profile).join(\" \"),\n getTeamMembersFromSocialProfileData(profile).join(\" \"),\n ];\n return fields.some((item) =>\n (item || \"\").toLowerCase().includes(searchTerm.toLowerCase())\n );\n });\n setFilteredProjects(updatedProjects);\n }\n};\nreturn (\n <Container>\n <Title>\n <div>Projects</div>\n <div>{filteredProjects?.length}</div>\n </Title>\n <SearchBar>\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M9.81641 8.69141H9.22391L9.01391 8.48891C9.74891 7.63391 10.1914 6.52391 10.1914 5.31641C10.1914 2.62391 8.00891 0.441406 5.31641 0.441406C2.62391 0.441406 0.441406 2.62391 0.441406 5.31641C0.441406 8.00891 2.62391 10.1914 5.31641 10.1914C6.52391 10.1914 7.63391 9.74891 8.48891 9.01391L8.69141 9.22391V9.81641L12.4414 13.5589L13.5589 12.4414L9.81641 8.69141ZM5.31641 8.69141C3.44891 8.69141 1.94141 7.18391 1.94141 5.31641C1.94141 3.44891 3.44891 1.94141 5.31641 1.94141C7.18391 1.94141 8.69141 3.44891 8.69141 5.31641C8.69141 7.18391 7.18391 8.69141 5.31641 8.69141Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n <input\n type=\"text\"\n placeholder=\"Search projects\"\n onChange={(e) => searchByWords(e.target.value)}\n className=\"search-input\"\n />\n </SearchBar>\n <Widget\n src={\"old.potlock.near/widget/Project.ListSection\"}\n props={{\n ...props,\n shouldShuffle: true,\n maxCols: 3,\n items: filteredProjects,\n responsive: [\n {\n breakpoint: 1200,\n items: 2,\n },\n {\n breakpoint: 870,\n items: 1,\n },\n ],\n renderItem: (project) => {\n return (\n <Widget\n src={\"old.potlock.near/widget/Project.Card\"}\n loading={<CardSkeleton />}\n props={{\n ...props,\n potDetail,\n projects,\n projectId: project.project_id,\n allowDonate:\n publicRoundOpen && project.project_id !== context.accountId,\n potRferralFeeBasisPoints:\n referral_fee_public_round_basis_points,\n payoutDetails: payouts[project.project_id] || {\n donorCount: 0,\n matchingAmount: \"0\",\n totalAmount: \"0\",\n },\n }}\n />\n );\n },\n }}\n />\n </Container>\n);\n" }, "Pots.SponsorsBoard": { "": "const { donations, base_currency, hrefWithParams } = props;\nconst sponsorsLeaderboard = [\n donations.slice(1, 3),\n donations.slice(0, 1),\n donations.slice(3, 5),\n].filter((subList) => subList.length > 0);\nconst { _address } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n) || {\n _address: () => \"\",\n};\nconst { SUPPORTED_FTS } = VM.require(\"old.potlock.near/widget/constants\") || {\n SUPPORTED_FTS: {},\n};\nconst Container = styled.div`\n display: flex;\n gap: 2rem;\n min-height: 430px;\n width: 100%;\n .col {\n display: flex;\n flex-direction: column;\n gap: 2rem;\n }\n .item {\n position: relative;\n display: flex;\n justify-content: center;\n gap: 1rem;\n flex-direction: column;\n border-radius: 12px;\n background: #fef6ee;\n height: 50%;\n padding: 24px;\n font-size: 14px;\n &.first {\n box-shadow: 0px 1px 2px -1px rgba(0, 0, 0, 0.08),\n 0px 1px 1px -1px rgba(0, 0, 0, 0.12);\n border: 2px solid #dd3345;\n align-items: center;\n text-align: center;\n height: 100%;\n .profile-image {\n width: 64px;\n height: 64px;\n }\n .footer {\n flex-direction: column;\n gap: 1rem;\n }\n .amount {\n font-size: 32px;\n font-family: \"Lora\";\n }\n }\n .profile-image {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n @media only screen and (max-width: 480px) {\n width: 40px;\n height: 40px;\n }\n }\n .name {\n white-space: nowrap;\n font-weight: 600;\n color: #292929;\n transition: all 300ms;\n font-size: 1rem;\n :hover {\n color: #dd3345;\n text-decoration: none;\n }\n }\n .footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n }\n .amount {\n font-size: 22px;\n font-weight: 600;\n }\n .percentage {\n font-size: 1rem;\n background: #f8d3b0;\n padding: 4px 8px;\n border-radius: 4px;\n font-weight: 600;\n height: fit-content;\n }\n }\n @media only screen and (max-width: 960px) {\n gap: 1rem;\n flex-direction: column;\n .col {\n gap: 1rem;\n }\n .col:nth-child(2) {\n order: -1;\n }\n }\n`;\nconst ProfileImg = ({ profile }) => (\n <Widget\n src=\"mob.near/widget/Image\"\n props={{\n image: profile.image,\n style: {},\n className: \"profile-image\",\n alt: profile.name,\n fallbackUrl:\n \"https://ipfs.near.social/ipfs/bafkreidla73cknxbeovrhgb2blax2j2qgcgcn6ibluzza3buq2mbkoqs2e\",\n }}\n />\n);\nconst Sponsor = ({\n donation: { amount, donor_id, percentage_share },\n colIdx,\n}) => {\n const profile = props.profile ?? Social.getr(`${donor_id}/profile`);\n return (\n <div className={`item ${colIdx === 2 && \"first\"}`}>\n <ProfileImg profile={profile} />\n <a\n href={hrefWithParams(`?tab=profile&accountId=${donor_id}`)}\n target=\"_blank\"\n className=\"name\"\n >\n {_address(profile.name || donor_id, 15)}\n </a>\n <div>{_address(profile.description, colIdx === 2 ? 120 : 35)}</div>\n <div className=\"footer\">\n <div className=\"amount\">{amount} NEAR</div>\n <div className=\"percentage\">{percentage_share}%</div>\n </div>\n </div>\n );\n};\nreturn (\n <Container>\n {sponsorsLeaderboard.map((donationsCol, colIdx) => (\n <div className=\"col\">\n {donationsCol.map((donation, idx) => (\n <Sponsor donation={donation} colIdx={colIdx + 1} idx={idx + 1} />\n ))}\n </div>\n ))}\n </Container>\n);\n" }, "Inputs.TextArea": { "": "const label = props.label ?? \"Label\";\nconst placeholder = props.placeholder ?? \"Placeholder\";\nconst value = props.value ?? \"\";\nconst onChange = props.onChange ?? (() => {});\nconst validate = props.validate ?? (() => {});\nconst error = props.error ?? \"\";\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n padding: 0px;\n gap: 0.45em;\n width: 100%;\n`;\nconst Label = styled.label`\n font-weight: 500;\n font-size: 14px;\n line-height: 16px;\n word-wrap: break-word;\n color: #2e2e2e;\n`;\nconst Error = styled.span`\n display: inline-block;\n font-style: normal;\n font-weight: 400;\n font-size: 0.75em;\n line-height: 1.25em;\n color: #ff4d4f;\n height: 0;\n overflow: hidden;\n transition: height 0.3s ease-in-out;\n &.show {\n height: 1.25em;\n }\n`;\nconst Input = styled.textarea`\n box-sizing: border-box;\n display: flex;\n flex-direction: row;\n align-items: center;\n padding: 0.5em 0.75em;\n width: 100%;\n gap: 0.5em;\n background: #ffffff;\n border: 1px solid #d0d5dd;\n box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);\n border-radius: 4px;\n`;\nreturn (\n <Container style={props.containerStyle ?? {}}>\n {!props.noLabel && <Label style={props.labelStyle ?? {}}>{label}</Label>}\n <Input\n placeholder={placeholder}\n value={value}\n onChange={({ target: { value } }) => onChange(value)}\n onBlur={() => validate()}\n rows={props.inputRows ?? 5}\n style={props.inputStyle ?? {}}\n disabled={!!props.disabled}\n />\n <Error style={props.errorStyle ?? {}} className={error ? \"show\" : \"\"}>\n {error}\n </Error>\n </Container>\n);\n" }, "Pots.Settings": { "": "// get settings\nconst { potDetail, potId, env, hrefWithParams } = props;\nconst [editSettings, setEditSettings] = useState(false);\nconst {\n SUPPORTED_FTS: { NEAR },\n} = VM.require(\"old.potlock.near/widget/constants\") || {\n SUPPORTED_FTS: {\n NEAR: {},\n },\n};\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n isUserPotAdminOrGreater: () => {},\n};\nconst { _address } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n) || {\n _address: (address) => address,\n};\nlet PotFactorySDK =\n VM.require(\"old.potlock.near/widget/SDK.potfactory\") ||\n (() => ({\n getContractId: () => {},\n }));\nPotFactorySDK = PotFactorySDK({ env });\nconst potFactoryContractId = PotFactorySDK.getContractId();\nconst userIsAdminOrGreater = PotSDK.isUserPotAdminOrGreater(\n potId,\n context.accountId\n);\nconst formatTimestampForDateTimeLocal = (timestamp) => {\n const date = new Date(timestamp);\n const year = date.getFullYear();\n const month = (date.getMonth() + 1).toString().padStart(2, \"0\"); // months are 0-indexed\n const day = date.getDate().toString().padStart(2, \"0\");\n const hours = date.getHours().toString().padStart(2, \"0\");\n const minutes = date.getMinutes().toString().padStart(2, \"0\");\n return `${year}-${month}-${day}T${hours}:${minutes}`;\n};\nconst {\n owner,\n chef,\n admins,\n pot_name,\n pot_description,\n max_projects,\n application_start_ms,\n application_end_ms,\n public_round_start_ms,\n public_round_end_ms,\n sybil_wrapper_provider,\n referral_fee_matching_pool_basis_points,\n referral_fee_public_round_basis_points,\n chef_fee_basis_points,\n min_matching_pool_donation_amount,\n registry_provider,\n} = potDetail;\nconst fields = [\n {\n label: \"Name\",\n val: pot_name,\n },\n {\n label: \"Custom handle\",\n val: potId.split(`.${potFactoryContractId}`)[0],\n },\n {\n label: \"Description\",\n val: pot_description,\n },\n {\n label: \"Referrer fee % (matching pool)\",\n val: referral_fee_matching_pool_basis_points / 100 + \"%\",\n },\n {\n label: \"Referrer fee % (public round)\",\n val: referral_fee_public_round_basis_points / 100 + \"%\",\n },\n {\n label: \"Application date\",\n val: `${formatTimestampForDateTimeLocal(\n application_start_ms\n )} - ${formatTimestampForDateTimeLocal(application_end_ms)}`,\n },\n {\n label: \"Matching round date\",\n val: `${formatTimestampForDateTimeLocal(\n public_round_start_ms\n )} - ${formatTimestampForDateTimeLocal(public_round_end_ms)}`,\n },\n {\n label: \"Min matching pool donation\",\n val: NEAR.fromIndivisible(min_matching_pool_donation_amount),\n },\n {\n label: \"Chef fee\",\n val: chef_fee_basis_points / 100 + \"%\",\n },\n {\n label: \"Assigned Chef\",\n val: chef,\n },\n {\n label: \"Max. approved projects\",\n val: max_projects,\n },\n {\n label: \"Registry Provider\",\n val: registry_provider,\n },\n {\n label: \"Donor Sybil Resistance\",\n val: sybil_wrapper_provider ? \"🤖 nada.bot human verified\" : \"none\",\n },\n];\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n width: 100%;\n`;\nconst Title = styled.div`\n font-weight: 600;\n font-size: 22px;\n`;\nconst PrviewContainer = styled.div`\n display: flex;\n flex-direction: column;\n max-width: 922px;\n`;\nconst AdminsWrapper = styled.div`\n position: absolute;\n display: flex;\n flex-direction: column;\n opacity: 0;\n pointer-events: none;\n padding-top: 5px;\n transition: all 300ms;\n top: 100%;\n .list {\n background: white;\n color: #292929;\n border-radius: 4px;\n overflow: hidden;\n box-shadow: 0px 0px 1px 0px rgba(41, 41, 41, 0.74),\n 0px 3px 3px 0px rgba(123, 123, 123, 0.12),\n 0px 6px 6px 0px rgba(123, 123, 123, 0.12);\n a {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 12px 16px;\n color: #292929;\n transition: 300ms;\n .profile-image {\n width: 24px;\n height: 24px;\n box-shadow: 0px 0px 1px 0px #a6a6a6 inset;\n border: 2px solid #f8d3b0;\n border-radius: 50%;\n }\n &:hover {\n background: #292929;\n text-decoration: none;\n color: white;\n }\n }\n }\n .tip-icon {\n display: flex;\n justify-content: center;\n z-index: 1;\n svg {\n stroke: rgb(41 41 41 / 21%);\n }\n }\n`;\nconst Admins = styled.div`\n display: flex;\n font-size: 11px;\n gap: 2rem;\n .owner {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 0.5rem;\n .address {\n display: flex;\n gap: 0.5rem;\n align-items: center;\n div {\n font-size: 14px;\n font-weight: 500;\n }\n .profile-image {\n width: 24px;\n height: 24px;\n border-radius: 50%;\n }\n }\n }\n .admins {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 0.5rem;\n .avaters {\n display: flex;\n gap: 0.5rem;\n }\n .profile-image {\n width: 24px;\n height: 24px;\n }\n .icons-tolltip {\n position: relative;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: white;\n border-radius: 50%;\n border: 2px solid #f8d3b0;\n background: #b8182d;\n &:hover {\n ${AdminsWrapper} {\n opacity: 1;\n pointer-events: all;\n }\n }\n }\n }\n .edit {\n display: flex;\n gap: 0.5rem;\n color: #dd3345;\n align-items: center;\n cursor: pointer;\n margin-left: auto;\n }\n @media only screen and (max-width: 768px) {\n flex-wrap: wrap;\n .edit {\n width: 100%;\n }\n }\n`;\nconst Detail = styled.div`\n display: flex;\n flex-direction: column;\n gap: 1rem;\n border-radius: 12px;\n border: 1px solid #c7c7c7;\n padding: 3rem;\n margin-top: 1.5rem;\n .row-field {\n display: flex;\n align-items: center;\n gap: 2rem;\n font-size: 14px;\n }\n .label {\n font-weight: 500;\n max-width: 238px;\n width: 100%;\n text-align: left;\n }\n .input {\n color: #7b7b7b;\n }\n @media only screen and (max-width: 768px) {\n padding: 1rem;\n gap: 1.5rem;\n .row-field {\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n }\n }\n`;\nconst ProfileImage = ({ address }) => (\n <Widget\n src={\"old.potlock.near/widget/Project.ProfileImage\"}\n props={{\n ...props,\n accountId: address,\n style: {},\n }}\n />\n);\nconst AdminsTooltip = () => (\n <AdminsWrapper>\n <div className=\"tip-icon\">\n <svg\n width=\"12\"\n height=\"8\"\n viewBox=\"0 0 12 8\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 5.24537e-07L-2.54292e-07 8L12 8L6 5.24537e-07Z\"\n fill=\"white\"\n />\n </svg>\n </div>\n <div className=\"list\">\n {admins.slice(0, admins.length).map((admin) => (\n <a\n href={hrefWithParams(`?tab=profile&accountId=${admin}`)}\n target=\"_blank\"\n >\n <ProfileImage address={admin} />\n <div>{admin}</div>\n </a>\n ))}\n </div>\n </AdminsWrapper>\n);\nreturn editSettings ? (\n <Container>\n <Title>Edit Pot settings</Title>\n <Widget\n src={\"old.potlock.near/widget/Pots.ConfigForm\"}\n props={{\n ...props,\n }}\n />\n </Container>\n) : (\n <PrviewContainer>\n <Admins>\n <div className=\"owner\">\n <div>Owner</div>\n <div className=\"address\">\n <ProfileImage address={owner} />\n <div>{_address(owner, 15)}</div>\n </div>\n </div>\n {admins.length > 0 && (\n <div className=\"admins\">\n <div>Admins</div>\n <div className=\"avaters\">\n {admins.slice(0, 4).map((admin, idx) => (\n <OverlayTrigger\n placement=\"bottom\"\n overlay={<Tooltip id={`tooltip-${idx}`}>{admin}</Tooltip>}\n key={admin}\n >\n <a\n href={hrefWithParams(`?tab=profile&accountId=${admin}`)}\n target=\"_blank\"\n >\n <ProfileImage address={admin} />\n </a>\n </OverlayTrigger>\n ))}\n {admins.length > 4 && (\n <div className=\"icons-tolltip\">\n +{admins.length - 4}\n <AdminsTooltip />\n </div>\n )}\n </div>\n </div>\n )}\n {userIsAdminOrGreater && (\n <div className=\"edit\" onClick={() => setEditSettings(true)}>\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M0.25 13.7501H3.0625L11.3575 5.45508L8.545 2.64258L0.25 10.9376V13.7501ZM1.75 11.5601L8.545 4.76508L9.235 5.45508L2.44 12.2501H1.75V11.5601Z\"\n fill=\"#DD3345\"\n />\n <path\n d=\"M11.7777 0.469375C11.4852 0.176875 11.0127 0.176875 10.7202 0.469375L9.34766 1.84187L12.1602 4.65438L13.5327 3.28187C13.8252 2.98937 13.8252 2.51688 13.5327 2.22438L11.7777 0.469375Z\"\n fill=\"#DD3345\"\n />\n </svg>\n Edit Pot\n </div>\n )}\n </Admins>\n <Detail>\n {fields.map((field) => (\n <div className=\"row-field\" key={field.label}>\n <div className=\"label\">{field.label}</div>\n <div className=\"input\">{field.val}</div>\n </div>\n ))}\n </Detail>\n </PrviewContainer>\n);\n" }, "Components.Modal": { "": "const ModalOverlay = styled.div`\n position: fixed;\n padding: 0 10px;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n // background: rgba(0, 0, 0, 0.2);\n backdrop-filter: blur(5px);\n display: flex;\n justify-content: center;\n align-items: center;\n // padding-top: 30vh;\n z-index: 1000;\n`;\nconst ModalContent = styled.div`\n width: 100%;\n max-width: 600px;\n padding: 24px 24px 18px 24px;\n background: white;\n display: flex;\n flex-direction: column;\n border-radius: 12px;\n overflow: hidden;\n box-shadow: 0px 0px 0px 1px rgba(41, 41, 41, 0.1),\n 0px 8px 12px -4px rgba(41, 41, 41, 0.1),\n 0px 20px 32px -10px rgba(41, 41, 41, 0.1),\n 0px 32px 44px -16px rgba(41, 41, 41, 0.1);\n`;\nconst overlayStyle = props.overlayStyle || {};\nconst contentStyle = props.contentStyle || {};\nState.init({\n isModalOpen: false,\n});\nconst Modal = ({ isOpen, onClose, children }) => {\n if (!isOpen) return \"\";\n return (\n <ModalOverlay onClick={onClose} style={overlayStyle}>\n <ModalContent onClick={(e) => e.stopPropagation()} style={contentStyle}>\n {children}\n </ModalContent>\n </ModalOverlay>\n );\n};\nreturn (\n <Modal\n isOpen={\n props.hasOwnProperty(\"isModalOpen\")\n ? props.isModalOpen\n : state.isModalOpen\n }\n onClose={\n props.hasOwnProperty(\"onClose\")\n ? props.onClose\n : () => State.update({ isModalOpen: false })\n }\n >\n {props.children}\n </Modal>\n);\n" }, "Components.Icons": { "": "const { Volunteer } = VM.require(\n \"old.potlock.near/widget/Components.Icons.Volunteer\"\n);\nconst { Component } = VM.require(\n \"old.potlock.near/widget/Components.Icons.Component\"\n);\nreturn {\n Volunteer,\n Component,\n};\n" }, "Cart.BreakdownSummary": { "": "const {\n referrerId,\n totalAmount,\n bypassProtocolFee,\n recipientId,\n potRferralFeeBasisPoints,\n ftIcon,\n bypassChefFee,\n chef,\n chefFeeBasisPoints,\n} = props;\nconst { basisPointsToPercent } = VM.require(\n \"old.potlock.near/widget/utils\"\n) || {\n basisPointsToPercent: () => 0,\n};\nconst { SUPPORTED_FTS } = VM.require(\"old.potlock.near/widget/constants\") || {\n SUPPORTED_FTS: {},\n};\nlet DonateSDK =\n VM.require(\"old.potlock.near/widget/SDK.donate\") ||\n (() => ({\n getConfig: () => {},\n }));\nDonateSDK = DonateSDK({ env: props.env });\nconst donationContractConfig = DonateSDK.getConfig();\nconst IPFS_BASE_URL = \"https://nftstorage.link/ipfs/\";\nconst CHEVRON_DOWN_URL =\n IPFS_BASE_URL + \"bafkreiabkwyfxq6pcc2db7u4ldweld5xcjesylfuhocnfz7y3n6jw7dptm\";\nconst CHEVRON_UP_URL =\n IPFS_BASE_URL + \"bafkreibdm7w6zox4znipjqlmxr66wsjjpqq4dguswo7evvrmzlnss3c3vi\";\nconst SvgIcon = styled.svg`\n width: 16px;\n height: 16px;\n`;\nconst BreakdownSummary = styled.div`\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n .breakdown-details {\n display: flex;\n flex-direction: column;\n width: 100%;\n margin-top: 8px;\n gap: 12px;\n border: 1px #dbdbdb solid;\n border-radius: 8px;\n transition: all 300ms ease-in-out;\n &.hidden {\n visibility: hidden;\n height: 0;\n opacity: 0;\n transform: translateY(100px);\n }\n }\n`;\nconst Header = styled.div`\n display: flex;\n flex-direction: row;\n justify-content: flex-start;\n align-items: center;\n width: 100%;\n`;\nconst BreakdownTitle = styled.div`\n color: #2e2e2e;\n font-size: 14px;\n font-weight: 500;\n word-wrap: break-word;\n`;\nconst ChevronIcon = styled.svg`\n width: 1rem;\n height: 1rem;\n margin-left: 8px;\n transition: all 300ms ease-in-out;\n`;\nconst BreakdownDetails = styled.div`\n display: flex;\n flex-direction: column;\n width: 100%;\n margin-top: 8px;\n gap: 12px;\n padding: 16px;\n border-radius: 8px;\n border: 1px #dbdbdb solid;\n background: #fafafa;\n transition: all 300ms ease-in-out;\n`;\nconst BreakdownItem = styled.div`\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 0 16px;\n gap: 16px;\n :first-of-type {\n padding-top: 1rem;\n }\n :last-of-type {\n padding-bottom: 1rem;\n }\n`;\nconst BreakdownItemLeft = styled.div`\n color: #7b7b7b;\n font-size: 14px;\n font-weight: 400;\n word-wrap: break-word;\n`;\nconst BreakdownItemRight = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n font-weight: 500;\n gap: 8px;\n`;\nconst BreakdownAmount = styled.div`\n color: #2e2e2e;\n font-size: 14px;\n line-height: 20px;\n font-weight: 500;\n word-wrap: break-word;\n`;\nconst Icon = styled.img`\n width: 16px;\n height: 16px;\n`;\nconst NearIcon = (props) => (\n <SvgIcon\n {...props}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <g clip-path=\"url(#clip0_454_78)\">\n <circle cx=\"8\" cy=\"8\" r=\"7.25\" stroke=\"#292929\" stroke-width=\"1.5\" />\n <path\n d=\"M11.1477 4C10.851 4 10.5763 4.15333 10.421 4.406L8.74866 6.88867C8.72453 6.92441 8.71422 6.96772 8.71967 7.01051C8.72511 7.05329 8.74594 7.09264 8.77826 7.1212C8.81057 7.14976 8.85218 7.1656 8.89531 7.16574C8.93844 7.16589 8.98015 7.15034 9.01266 7.122L10.6587 5.69467C10.6683 5.68598 10.6802 5.68028 10.6931 5.67828C10.7059 5.67628 10.719 5.67806 10.7308 5.6834C10.7426 5.68875 10.7526 5.69742 10.7596 5.70836C10.7665 5.7193 10.7702 5.73203 10.77 5.745V10.215C10.77 10.2287 10.7658 10.2421 10.7579 10.2534C10.7501 10.2646 10.7389 10.2732 10.726 10.2778C10.7131 10.2825 10.6991 10.2831 10.6858 10.2795C10.6726 10.2758 10.6608 10.2682 10.652 10.2577L5.67667 4.30167C5.59667 4.20709 5.49701 4.1311 5.38463 4.079C5.27226 4.0269 5.14987 3.99994 5.026 4H4.85233C4.62628 4 4.40949 4.0898 4.24964 4.24964C4.0898 4.40949 4 4.62628 4 4.85233V11.1477C4 11.3333 4.06061 11.5139 4.17263 11.6619C4.28465 11.81 4.44194 11.9174 4.6206 11.9679C4.79926 12.0184 4.98952 12.0091 5.16245 11.9416C5.33538 11.874 5.48152 11.7519 5.57867 11.5937L7.251 9.111C7.27513 9.07525 7.28544 9.03194 7.27999 8.98916C7.27455 8.94637 7.25372 8.90703 7.22141 8.87846C7.18909 8.8499 7.14748 8.83407 7.10435 8.83392C7.06122 8.83377 7.01951 8.84932 6.987 8.87766L5.341 10.3053C5.33134 10.3139 5.31939 10.3195 5.3066 10.3215C5.29381 10.3234 5.28074 10.3216 5.26898 10.3162C5.25721 10.3108 5.24726 10.3021 5.24034 10.2912C5.23342 10.2803 5.22983 10.2676 5.23 10.2547V5.784C5.22997 5.77027 5.23418 5.75687 5.24206 5.74563C5.24993 5.73438 5.26109 5.72584 5.274 5.72117C5.28691 5.71651 5.30094 5.71594 5.31419 5.71955C5.32743 5.72315 5.33924 5.73076 5.348 5.74133L10.3227 11.698C10.4847 11.8893 10.7227 11.9997 10.9733 12H11.147C11.373 12.0001 11.5898 11.9104 11.7498 11.7507C11.9097 11.591 11.9997 11.3744 12 11.1483V4.85233C11.9999 4.62631 11.9101 4.40956 11.7503 4.24974C11.5904 4.08992 11.3737 4.00009 11.1477 4Z\"\n fill=\"#292929\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_454_78\">\n <rect width=\"16\" height=\"16\" fill=\"white\" />\n </clipPath>\n </defs>\n </SvgIcon>\n);\nState.init({\n showBreakdown: true,\n});\nif (!donationContractConfig) return \"\";\nconst {\n protocol_fee_basis_points,\n referral_fee_basis_points,\n protocol_fee_recipient_account: protocolFeeRecipientAccount,\n} = donationContractConfig;\nconst protocolFeeBasisPoints =\n props.protocolFeeBasisPoints ?? protocol_fee_basis_points;\nconst referralFeeBasisPoints =\n potRferralFeeBasisPoints || props.referralFeeBasisPoints;\nconst TOTAL_BASIS_POINTS = 10_000;\nlet projectAllocationBasisPoints =\n TOTAL_BASIS_POINTS -\n (bypassProtocolFee || !protocolFeeBasisPoints ? 0 : protocolFeeBasisPoints) -\n (bypassChefFee || !chefFeeBasisPoints ? 0 : chefFeeBasisPoints);\nif (referrerId) {\n projectAllocationBasisPoints -= referralFeeBasisPoints;\n}\nconst projectAllocationPercent = basisPointsToPercent(\n projectAllocationBasisPoints\n);\nconst projectAllocationAmount =\n (parseFloat(totalAmount) * projectAllocationBasisPoints) / TOTAL_BASIS_POINTS;\nconst protocolFeePercent = basisPointsToPercent(protocolFeeBasisPoints);\nconst protocolFeeAmount =\n (parseFloat(totalAmount) * protocolFeeBasisPoints) / TOTAL_BASIS_POINTS;\nconst referrerFeePercent = basisPointsToPercent(referralFeeBasisPoints);\nconst referrerFeeAmount =\n (parseFloat(totalAmount) * referralFeeBasisPoints) / TOTAL_BASIS_POINTS;\nconst chefFeePercent = basisPointsToPercent(chefFeeBasisPoints);\nconst chefFeeAmount =\n (parseFloat(totalAmount) * chefFeeBasisPoints) / TOTAL_BASIS_POINTS;\nconst fees = [\n {\n label: \"Protocol fee\",\n percentage: protocolFeePercent,\n amount: protocolFeeAmount,\n show: !bypassProtocolFee,\n },\n {\n label: \"Referrer fee\",\n percentage: referrerFeePercent,\n amount: referrerFeeAmount,\n show: referrerId,\n },\n {\n label: \"Chef fee\",\n percentage: chefFeePercent,\n amount: chefFeeAmount,\n show: !bypassChefFee && chefFeeBasisPoints,\n },\n {\n label: \"On-Chain Storage\",\n percentage: \"\",\n amount: \"<0.01\",\n show: true,\n },\n {\n label: \"Project allocation\",\n percentage: projectAllocationPercent,\n amount: projectAllocationAmount,\n show: true,\n },\n];\nreturn (\n <BreakdownSummary\n style={props.containerStyle || {}}\n // onClick={() => State.update({ showBreakdown: !state.showBreakdown })}\n >\n <Header style={props.headerStyle || {}}>\n <BreakdownTitle> Breakdown</BreakdownTitle>\n </Header>\n <div\n className={`breakdown-details ${!state.showBreakdown ? \"hidden\" : \"\"}`}\n active={state.showBreakdown}\n >\n {fees.map(({ show, amount, label, percentage }) => {\n return show ? (\n <BreakdownItem key={label}>\n <BreakdownItemLeft>\n {label} {percentage ? `(${percentage}%)` : \"\"}{\" \"}\n </BreakdownItemLeft>\n <BreakdownItemRight>\n <BreakdownAmount>\n {typeof amount === \"string\" ? amount : amount}\n </BreakdownAmount>\n {ftIcon ? <Icon src={ftIcon} alt=\"ft-icon\" /> : <NearIcon />}\n </BreakdownItemRight>\n </BreakdownItem>\n ) : (\n \"\"\n );\n })}\n </div>\n </BreakdownSummary>\n);\n" }, "Components.Icons.Component": { "": "const Component = () => {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"17\"\n height=\"16\"\n viewBox=\"0 0 17 16\"\n fill=\"none\"\n >\n <path\n fill-rule=\"evenodd\"\n clip-rule=\"evenodd\"\n d=\"M6.35199 1H10.6497C10.7929 1 10.903 1 10.9987 1.01042C11.4235 1.05593 11.8181 1.25185 12.1111 1.56281C12.4042 1.87376 12.5764 2.27925 12.5966 2.70605C12.9787 2.82125 13.3143 3.05502 13.5547 3.37354C13.7952 3.69207 13.928 4.07882 13.9341 4.47786C14.3255 4.59507 14.6634 4.78065 14.9395 5.07888C15.3641 5.53795 15.4956 6.10251 15.5008 6.76279C15.5054 7.39768 15.3927 8.19991 15.2521 9.19554L14.9656 11.2233C14.8562 12.002 14.767 12.635 14.6283 13.1305C14.4831 13.6495 14.2688 14.076 13.8729 14.4042C13.4796 14.7298 13.0134 14.8698 12.4625 14.9362C11.9292 15 11.2585 15 10.4244 15H6.57729C5.7425 15 5.0718 15 4.53915 14.9362C3.98761 14.8698 3.52138 14.7298 3.12808 14.4042C2.73217 14.076 2.51794 13.6488 2.37273 13.1305C2.23403 12.635 2.14482 12.002 2.03478 11.2226L1.74892 9.19554C1.60892 8.19926 1.49496 7.39768 1.50017 6.76279C1.50538 6.10251 1.63692 5.53795 2.06147 5.07888C2.33757 4.78065 2.67487 4.59572 3.06622 4.47786C3.07249 4.07885 3.20552 3.69218 3.44608 3.37378C3.68664 3.05538 4.02224 2.82175 4.40436 2.7067C4.42446 2.27979 4.59659 1.87414 4.88965 1.56305C5.1827 1.25196 5.57736 1.05595 6.00231 1.01042C6.09803 1 6.20808 1 6.35068 1M4.0651 4.3066C4.66808 4.25581 5.4065 4.25581 6.29664 4.25581H10.7037C11.5932 4.25581 12.3316 4.25581 12.9352 4.3066C12.8902 4.10719 12.7786 3.92906 12.6188 3.80148C12.459 3.67391 12.2606 3.6045 12.0562 3.60465H4.94482C4.5092 3.60465 4.15561 3.9107 4.0664 4.3066M10.8951 1.98195C11.2533 2.01972 11.5365 2.2867 11.6062 2.62791H5.39608C5.43063 2.45861 5.51815 2.3047 5.64599 2.18845C5.77383 2.0722 5.93534 1.99965 6.10715 1.9813C6.14361 1.9774 6.19571 1.97674 6.37868 1.97674H10.623C10.8053 1.97674 10.8574 1.9774 10.8945 1.9813M2.77906 5.74177C2.97636 5.52884 3.27264 5.38754 3.84892 5.3107C4.43561 5.23256 5.22157 5.23191 6.33375 5.23191H10.6679C11.7801 5.23191 12.566 5.23321 13.1527 5.3107C13.729 5.38754 14.0253 5.52884 14.2226 5.74177C14.4153 5.95014 14.5202 6.2334 14.5241 6.76995C14.528 7.32344 14.4264 8.05274 14.2792 9.09851L14.0038 11.052C13.8879 11.8731 13.8071 12.4409 13.688 12.8668C13.5727 13.277 13.4379 13.4952 13.2498 13.6508C13.059 13.8097 12.8024 13.9113 12.3459 13.966C11.8778 14.022 11.2663 14.0226 10.3925 14.0226H6.6092C5.73533 14.0226 5.12389 14.022 4.65571 13.966C4.19989 13.9106 3.94268 13.8097 3.75189 13.6514C3.56371 13.4952 3.42892 13.2764 3.31366 12.8668C3.1945 12.4409 3.11375 11.8731 2.99785 11.052L2.7224 9.09851C2.57524 8.0534 2.47366 7.32344 2.47757 6.76995C2.48147 6.2334 2.58631 5.94949 2.77906 5.74177Z\"\n fill=\"white\"\n />\n </svg>\n );\n};\nreturn { Component };\n" }, "Components.Pagination": { "": "const { onPageChange, data, currentPage, perPage, customSyle, bgColor } = props;\nconst siblingCount = props.siblingCount ?? 1;\nconst showArrows = props.showArrows ?? false;\nconst totalCount = data?.length;\nconst range = (start, end) => {\n let length = end - start + 1;\n return Array.from({ length }, (_, idx) => idx + start);\n};\nconst usePagination = ({ totalCount, perPage, siblingCount, currentPage }) => {\n const paginationRange = useMemo(() => {\n const totalPageCount = Math.ceil(totalCount / perPage);\n const totalPageNumbers = siblingCount + 3;\n if (totalPageNumbers >= totalPageCount || totalPageCount < 6) {\n return range(1, totalPageCount);\n }\n const leftSiblingIndex = Math.max(currentPage - siblingCount, 1);\n const rightSiblingIndex = Math.min(\n currentPage + siblingCount,\n totalPageCount\n );\n const shouldShowLeftDots = leftSiblingIndex > 2;\n const shouldShowRightDots = rightSiblingIndex <= totalPageCount - 3;\n const firstPageIndex = 1;\n const lastPageIndex = totalPageCount;\n if (!shouldShowLeftDots && shouldShowRightDots) {\n let leftItemCount = 3 + siblingCount;\n let leftRange = range(1, leftItemCount);\n return [...leftRange, DOTS, totalPageCount];\n }\n if (shouldShowLeftDots && !shouldShowRightDots) {\n let rightItemCount = 3 + 2 * siblingCount;\n let rightRange = range(\n totalPageCount - rightItemCount + 1,\n totalPageCount\n );\n return [firstPageIndex, DOTS, ...rightRange];\n }\n if (shouldShowLeftDots && shouldShowRightDots) {\n let middleRange = range(leftSiblingIndex, rightSiblingIndex);\n return [firstPageIndex, DOTS, ...middleRange, DOTS, lastPageIndex];\n }\n if (!shouldShowLeftDots && !shouldShowRightDots) {\n return range(1, totalPageCount);\n }\n }, [totalCount, perPage, siblingCount, currentPage]);\n return paginationRange;\n};\nconst paginationRange = usePagination({\n currentPage,\n totalCount,\n siblingCount,\n perPage,\n});\nif (currentPage === 0 || paginationRange.length < 2) {\n return \"\";\n}\nconst onNext = () => {\n onPageChange(currentPage + 1);\n};\nconst onPrevious = () => {\n onPageChange(currentPage - 1);\n};\nlet lastPage = paginationRange[paginationRange.length - 1];\nconst Container = styled.div`\n display: flex;\n gap: 1rem;\n justify-content: center;\n list-style-type: none;\n ${customSyle || \"\"}\n li {\n display: flex;\n align-items: center;\n justify-content: center;\n &.disabled {\n pointer-events: none;\n .arrow::before {\n border-right: 0.12em solid rgba(0, 0, 0, 0.43);\n border-top: 0.12em solid rgba(0, 0, 0, 0.43);\n }\n &:hover {\n cursor: default;\n }\n }\n }\n .pagination-item {\n border: 1px solid transparent;\n background: ${bgColor};\n border-radius: 2px;\n padding: 10px;\n font-size: 12px;\n color: white;\n cursor: pointer;\n transition: all 300ms;\n &.dots:hover {\n cursor: default;\n opacity: 1;\n }\n &:hover {\n opacity: 0.75;\n }\n &.selected {\n background: white;\n cursor: default;\n color: ${bgColor};\n border-color: ${bgColor};\n }\n }\n .arrow {\n cursor: pointer;\n &::before {\n position: relative;\n content: \"\";\n display: inline-block;\n width: 0.4em;\n height: 0.4em;\n border-right: 0.12em solid rgba(0, 0, 0, 0.87);\n border-top: 0.12em solid rgba(0, 0, 0, 0.87);\n }\n &.left {\n transform: rotate(-135deg) translate(-50%);\n }\n &.right {\n transform: rotate(45deg);\n }\n }\n`;\nreturn (\n <Container>\n {showArrows && (\n <li\n className={`${currentPage === 1 ? \"disabled\" : \"\"}`}\n onClick={onPrevious}\n >\n <div className=\"arrow left\" />\n </li>\n )}\n {paginationRange?.length > 0 &&\n paginationRange.map((pageNumber) => {\n if (pageNumber === DOTS) {\n return <li className=\"pagination-item dots\">&#8230;</li>;\n }\n return (\n <li\n className={`pagination-item ${\n pageNumber === currentPage ? \"selected\" : \"\"\n }`}\n onClick={() => onPageChange(pageNumber)}\n >\n {pageNumber}\n </li>\n );\n })}\n {showArrows && (\n <li\n className={`${currentPage === lastPage ? \"disabled\" : \"\"}`}\n onClick={onNext}\n >\n <div className=\"arrow right\" />\n </li>\n )}\n </Container>\n);\n" }, "Pots.Applications": { "": "// get applications\nconst { potId, potDetail, hrefWithParams } = props;\nconst { daysAgo } = VM.require(\"old.potlock.near/widget/utils\") || {\n daysAgo: () => \"\",\n};\nconst {\n ONE_TGAS,\n SUPPORTED_FTS: { NEAR },\n} = VM.require(\"old.potlock.near/widget/constants\") || {\n ONE_TGAS: 0,\n SUPPORTED_FTS: {},\n};\nconst PotSDK = VM.require(\"old.potlock.near/widget/SDK.pot\") || {\n getApplications: () => {},\n};\nconst { getTimePassed, _address } = VM.require(\n \"old.potlock.near/widget/Components.DonorsUtils\"\n) || {\n _address: (address) => address,\n};\nconst MAX_APPLICATION_MESSAGE_LENGTH = 1000;\nconst applications = PotSDK.getApplications(potId);\nconst getApplicationCount = (sortVal) => {\n if (!applications) return;\n return applications?.filter((application) => {\n if (sortVal === \"All\") return true;\n return application.status === sortVal;\n })?.length;\n};\nconst APPLICATIONS_FILTERS = {\n ALL: {\n label: \"All applications\",\n val: \"ALL\",\n count: getApplicationCount(\"All\"),\n },\n PENDING: {\n label: \"Pending applications\",\n val: \"PENDING\",\n count: getApplicationCount(\"Pending\"),\n },\n APPROVED: {\n label: \"Approved applications\",\n val: \"APPROVED\",\n count: getApplicationCount(\"Approved\"),\n },\n REJECTED: {\n label: \"Rejected applications\",\n val: \"REJECTED\",\n count: getApplicationCount(\"Rejected\"),\n },\n};\nconst APPLICATIONS_FILTERS_TAGS = {\n Pending: {\n label: \"Pending\",\n borderColor: \"#C7C7C7\",\n color: \"#292929\",\n background: \"#F6F5F3\",\n icon: (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M8 0.5C3.86 0.5 0.5 3.86 0.5 8C0.5 12.14 3.86 15.5 8 15.5C12.14 15.5 15.5 12.14 15.5 8C15.5 3.86 12.14 0.5 8 0.5ZM8 14C4.685 14 2 11.315 2 8C2 4.685 4.685 2 8 2C11.315 2 14 4.685 14 8C14 11.315 11.315 14 8 14Z\"\n fill=\"#7B7B7B\"\n />\n <path\n d=\"M4.25 9.125C4.87132 9.125 5.375 8.62132 5.375 8C5.375 7.37868 4.87132 6.875 4.25 6.875C3.62868 6.875 3.125 7.37868 3.125 8C3.125 8.62132 3.62868 9.125 4.25 9.125Z\"\n fill=\"#7B7B7B\"\n />\n <path\n d=\"M8 9.125C8.62132 9.125 9.125 8.62132 9.125 8C9.125 7.37868 8.62132 6.875 8 6.875C7.37868 6.875 6.875 7.37868 6.875 8C6.875 8.62132 7.37868 9.125 8 9.125Z\"\n fill=\"#7B7B7B\"\n />\n <path\n d=\"M11.75 9.125C12.3713 9.125 12.875 8.62132 12.875 8C12.875 7.37868 12.3713 6.875 11.75 6.875C11.1287 6.875 10.625 7.37868 10.625 8C10.625 8.62132 11.1287 9.125 11.75 9.125Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n ),\n },\n Approved: {\n label: \"Approved\",\n color: \"#192C07\",\n borderColor: \"#9ADD33\",\n background: \"#F7FDE8\",\n icon: (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M8 0.5C3.86 0.5 0.5 3.86 0.5 8C0.5 12.14 3.86 15.5 8 15.5C12.14 15.5 15.5 12.14 15.5 8C15.5 3.86 12.14 0.5 8 0.5ZM8 14C4.6925 14 2 11.3075 2 8C2 4.6925 4.6925 2 8 2C11.3075 2 14 4.6925 14 8C14 11.3075 11.3075 14 8 14ZM11.4425 4.685L6.5 9.6275L4.5575 7.6925L3.5 8.75L6.5 11.75L12.5 5.75L11.4425 4.685Z\"\n fill=\"#629D13\"\n />\n </svg>\n ),\n },\n Rejected: {\n label: \"Rejected\",\n borderColor: \"#FAA7A8\",\n color: \"#490813\",\n background: \"#FEF3F2\",\n icon: (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M8 0.5C3.86 0.5 0.5 3.86 0.5 8C0.5 12.14 3.86 15.5 8 15.5C12.14 15.5 15.5 12.14 15.5 8C15.5 3.86 12.14 0.5 8 0.5ZM2 8C2 4.685 4.685 2 8 2C9.3875 2 10.6625 2.4725 11.675 3.2675L3.2675 11.675C2.4725 10.6625 2 9.3875 2 8ZM8 14C6.6125 14 5.3375 13.5275 4.325 12.7325L12.7325 4.325C13.5275 5.3375 14 6.6125 14 8C14 11.315 11.315 14 8 14Z\"\n fill=\"#ED464F\"\n />\n </svg>\n ),\n },\n};\nState.init({\n isModalOpen: false,\n newStatus: \"\",\n projectId: \"\",\n reviewMessage: \"\",\n searchTerm: \"\",\n allApplications: null,\n filteredApplications: [],\n filterVal: \"ALL\",\n});\nconst {\n isModalOpen,\n newStatus,\n projectId,\n reviewMessage,\n searchTerm,\n allApplications,\n filteredApplications,\n filterVal,\n} = state;\nif (applications && !allApplications) {\n applications.reverse();\n State.update({\n filteredApplications: applications,\n allApplications: applications,\n });\n}\nif (!allApplications)\n return <div class=\"spinner-border text-secondary\" role=\"status\" />;\nconst { owner, admins, chef } = potDetail;\nconst isChefOrGreater =\n context.accountId === chef ||\n admins.includes(context.accountId) ||\n context.accountId === owner;\nconst handleApproveApplication = (projectId) => {\n State.update({ isModalOpen: true, newStatus: \"Approved\", projectId });\n};\nconst handleRejectApplication = (projectId) => {\n State.update({ isModalOpen: true, newStatus: \"Rejected\", projectId });\n};\nconst handleCancel = () => {\n State.update({\n isModalOpen: false,\n newStatus: \"\",\n projectId: \"\",\n reviewMessage: \"\",\n });\n};\nconst handleSubmit = () => {\n const args = {\n project_id: projectId,\n status: newStatus,\n notes: reviewMessage,\n };\n const transactions = [\n {\n contractName: potId,\n methodName: \"chef_set_application_status\",\n deposit: NEAR.toIndivisible(0.01),\n args,\n gas: ONE_TGAS.mul(100),\n },\n ];\n Near.call(transactions);\n // NB: we won't get here if user used a web wallet, as it will redirect to the wallet\n // <---- TODO: IMPLEMENT EXTENSION WALLET HANDLING ---->\n};\nconst searchApplications = (searchTerm) => {\n // filter applications that match the search term (message, project_id, review_notes or status)\n const filteredApplications = allApplications?.filter((application) => {\n const { message, project_id, review_notes, status } = application;\n const searchFields = [message, project_id, review_notes, status];\n return searchFields.some((field) =>\n field.toLowerCase().includes(searchTerm.toLowerCase().trim())\n );\n });\n return filteredApplications;\n};\nconst sortApplications = (key) => {\n if (key === \"ALL\") {\n return searchApplications(searchTerm);\n }\n const filtered = allApplications?.filter((application) => {\n return application.status === APPLICATIONS_FILTERS[key].label.split(\" \")[0];\n });\n return filtered;\n};\nconst handleSort = (key) => {\n const sorted = sortApplications(key);\n State.update({ filteredApplications: sorted, filterVal: key });\n};\nconst ProfileImg = ({ profile }) => (\n <Widget src=\"mob.near/widget/ProfileImage\" props={{ profile, style: {} }} />\n);\nconst Container = styled.div`\n display: flex;\n gap: 2rem;\n .dropdown {\n display: none;\n }\n @media only screen and (max-width: 768px) {\n flex-direction: column;\n gap: 1.5rem;\n .dropdown {\n display: flex;\n }\n }\n`;\nconst Filter = styled.div`\n display: grid;\n width: 286px;\n border-radius: 6px;\n padding: 8px 0;\n border: 1px solid var(--Neutral-500, #7b7b7b);\n height: fit-content;\n .item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 0.5rem 1rem;\n font-size: 14px;\n cursor: pointer;\n svg {\n opacity: 0;\n transition: all 300ms ease;\n }\n &.active {\n svg {\n opacity: 1;\n }\n }\n &:hover {\n svg {\n opacity: 1;\n }\n }\n }\n .count {\n color: #7b7b7b;\n margin-left: auto;\n }\n @media only screen and (max-width: 768px) {\n display: none;\n }\n`;\nconst Applications = styled.div`\n border-radius: 6px;\n border: 1px solid #7b7b7b;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n max-width: 711px;\n width: 100%;\n`;\nconst SearchBar = styled.div`\n display: flex;\n position: relative;\n svg {\n position: absolute;\n left: 1.5rem;\n top: 50%;\n transform: translateY(-50%);\n }\n input {\n font-size: 14px;\n background: #f6f5f3;\n width: 100%;\n height: 100%;\n padding: 8px 24px 8px 60px;\n border: none;\n outline: none;\n }\n @media only screen and (max-width: 768px) {\n svg {\n left: 1rem;\n }\n input {\n padding: 8px 24px 8px 54px;\n }\n }\n`;\nconst ApplicationRow = styled.div`\n display: flex;\n flex-direction: column;\n padding: 1.5rem;\n font-size: 14px;\n position: relative;\n border-top: 1px solid #c7c7c7;\n .header {\n display: flex;\n gap: 1rem;\n justify-content: space-between;\n position: relative;\n align-items: center;\n }\n .header-info {\n display: flex;\n gap: 8px;\n align-items: center;\n cursor: auto;\n }\n .profile-image {\n margin-right: 8px;\n width: 24px;\n height: 24px;\n }\n .name {\n color: #292929;\n font-weight: 600;\n }\n .address {\n color: #7b7b7b;\n font-weight: 600;\n cursor: pointer;\n transition: all 300ms;\n position: relative;\n z-index: 2;\n &:hover {\n color: #292929;\n }\n }\n .content {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n overflow: hidden;\n transition: all 300ms ease-in-out;\n max-height: 0;\n .message {\n padding-top: 1rem;\n }\n .notes {\n display: flex;\n flex-direction: column;\n gap: 8px;\n .title {\n color: #7b7b7b;\n }\n }\n button {\n width: fit-content;\n }\n }\n .arrow {\n rotate: 180deg;\n transition: all 300ms;\n }\n .toggle-check {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 67px;\n z-index: 1;\n opacity: 0;\n cursor: pointer;\n }\n .toggle-check:checked + .header .arrow {\n rotate: 0deg;\n }\n .toggle-check:checked + .header + .content {\n max-height: 100%;\n }\n @media only screen and (max-width: 768px) {\n padding: 1rem;\n .header-info {\n flex-wrap: wrap;\n gap: 0px;\n }\n .name {\n margin: 0 8px;\n }\n .date {\n line-height: 1;\n width: 100%;\n margin-left: 2.5rem;\n }\n }\n`;\nconst Dot = styled.div`\n width: 6px;\n height: 6px;\n background: #7b7b7b;\n border-radius: 50%;\n @media only screen and (max-width: 768px) {\n display: none;\n }\n`;\nconst Status = styled.div`\n display: flex;\n padding: 6px 12px;\n gap: 8px;\n align-items: center;\n border-width: 1px;\n border-style: solid;\n border-radius: 4px;\n margin-left: auto;\n div {\n font-weight: 500;\n }\n svg {\n width: 1rem;\n }\n @media only screen and (max-width: 768px) {\n padding: 6px;\n div {\n display: none;\n }\n svg {\n width: 16px;\n }\n }\n`;\nconst ModalHeader = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-start;\n background: white;\n padding: 24px 24px 12px 24px;\n border-top-left-radius: 6px;\n border-top-right-radius: 6px;\n font-weight: 500;\n`;\nconst ModalBody = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n padding: 24px;\n border-top: 1px #f0f0f0 solid;\n background: #fafafa;\n gap: 8px;\n`;\nconst ModalFooter = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-end;\n background: #fafafa;\n padding: 12px 24px 24px 24px;\n border-bottom-left-radius: 6px;\n border-bottom-right-radius: 6px;\n gap: 24px;\n width: 100%;\n`;\nconst DropdownLabel = styled.div`\n display: flex;\n gap: 10px;\n align-items: center;\n .label {\n font-weight: 500;\n }\n .count {\n display: flex;\n width: ${({ digit }) => 24 + (digit - 1) * 6}px;\n height: ${({ digit }) => 24 + (digit - 1) * 6}px;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n background: #ebebeb;\n }\n`;\nreturn (\n <Container>\n <div className=\"dropdown\">\n <Widget\n src={\"old.potlock.near/widget/Inputs.Dropdown\"}\n props={{\n sortVal: (\n <DropdownLabel\n digit={APPLICATIONS_FILTERS[filterVal].count.toString().length}\n >\n <div className=\"label\">\n {APPLICATIONS_FILTERS[filterVal].label}\n </div>\n <div className=\"count\">\n {APPLICATIONS_FILTERS[filterVal].count}\n </div>\n </DropdownLabel>\n ),\n showCount: true,\n sortList: Object.values(APPLICATIONS_FILTERS),\n FilterMenuCustomStyle: `left:0; right:auto;`,\n handleSortChange: ({ val }) => {\n handleSort(val);\n },\n }}\n />\n </div>\n <Filter>\n {Object.keys(APPLICATIONS_FILTERS).map((key) => (\n <div\n key={key}\n className={`item ${filterVal === key ? \"active\" : \"\"}`}\n onClick={() => handleSort(key)}\n >\n <svg\n width=\"14\"\n height=\"12\"\n viewBox=\"0 0 14 12\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M4.59631 8.9057L1.46881 5.7782L0.403809 6.8357L4.59631 11.0282L13.5963 2.0282L12.5388 0.970703L4.59631 8.9057Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n <div> {APPLICATIONS_FILTERS[key].label}</div>\n <div className=\"count\">{APPLICATIONS_FILTERS[key].count}</div>\n </div>\n ))}\n </Filter>\n <Applications>\n <SearchBar>\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M9.81641 8.69141H9.22391L9.01391 8.48891C9.74891 7.63391 10.1914 6.52391 10.1914 5.31641C10.1914 2.62391 8.00891 0.441406 5.31641 0.441406C2.62391 0.441406 0.441406 2.62391 0.441406 5.31641C0.441406 8.00891 2.62391 10.1914 5.31641 10.1914C6.52391 10.1914 7.63391 9.74891 8.48891 9.01391L8.69141 9.22391V9.81641L12.4414 13.5589L13.5589 12.4414L9.81641 8.69141ZM5.31641 8.69141C3.44891 8.69141 1.94141 7.18391 1.94141 5.31641C1.94141 3.44891 3.44891 1.94141 5.31641 1.94141C7.18391 1.94141 8.69141 3.44891 8.69141 5.31641C8.69141 7.18391 7.18391 8.69141 5.31641 8.69141Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n <input\n type=\"text\"\n placeholder=\"Search applications\"\n className=\"search-input\"\n onChange={(e) => {\n const results = searchApplications(e.target.value);\n State.update({\n searchTerm: e.target.value,\n filteredApplications: results,\n });\n }}\n />\n </SearchBar>\n {filteredApplications.length ? (\n filteredApplications.map(\n ({ project_id, status, message, review_notes, submitted_at }) => {\n const { borderColor, color, icon, label, background } =\n APPLICATIONS_FILTERS_TAGS[status];\n const profile = Social.getr(`${project_id}/profile`);\n return (\n <ApplicationRow key={project_id}>\n <input type=\"checkbox\" className=\"toggle-check\" />\n <div className=\"header\">\n <div className=\"header-info\">\n <ProfileImg profile={profile} />\n {profile?.name && (\n <div className=\"name\">{_address(profile?.name, 10)}</div>\n )}\n <OverlayTrigger\n placement=\"top\"\n overlay={<Tooltip>{project_id}</Tooltip>}\n >\n <a\n className=\"address\"\n href={hrefWithParams(\n `?tab=project&projectId=${project_id}`\n )}\n target=\"_blank\"\n >\n {_address(project_id, 10)}\n </a>\n </OverlayTrigger>\n <Dot />\n <div className=\"date\">{daysAgo(submitted_at)}</div>\n </div>\n <Status\n style={{\n borderColor,\n color,\n background,\n }}\n >\n <div>{label}</div>\n {icon}\n </Status>\n <svg\n width=\"12\"\n height=\"8\"\n viewBox=\"0 0 12 8\"\n fill=\"none\"\n className=\"arrow\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 0.294922L0 6.29492L1.41 7.70492L6 3.12492L10.59 7.70492L12 6.29492L6 0.294922Z\"\n fill=\"#7B7B7B\"\n />\n </svg>\n </div>\n <div className=\"content\">\n <div className=\"message\">{message}</div>\n {review_notes && (\n <div className=\"notes\">\n <div className=\"title\">Admin notes:</div>\n <div>{review_notes}</div>\n </div>\n )}\n {isChefOrGreater && (\n <>\n {status !== \"Approved\" && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"secondary\",\n text: \"Approve\",\n onClick: () => handleApproveApplication(project_id),\n }}\n />\n )}\n {status !== \"Rejected\" && (\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: \"Reject\",\n onClick: () => handleRejectApplication(project_id),\n }}\n />\n )}\n </>\n )}\n </div>\n </ApplicationRow>\n );\n }\n )\n ) : (\n <div style={{ padding: \"1rem\" }}>No applications to display</div>\n )}\n </Applications>\n <Widget\n src={\"old.potlock.near/widget/Components.Modal\"}\n props={{\n ...props,\n isModalOpen,\n onClose: () =>\n State.update({ isModalOpen: false, newStatus: \"\", projectId: \"\" }),\n contentStyle: {\n padding: \"0px\",\n },\n children: (\n <>\n <ModalHeader>\n {newStatus === \"Approved\"\n ? \"Approve \"\n : newStatus === \"Rejected\"\n ? \"Reject \"\n : \"\"}\n application from {projectId}\n </ModalHeader>\n <ModalBody>\n <div>Leave a note *</div>\n <Widget\n src={\"old.potlock.near/widget/Inputs.TextArea\"}\n props={{\n noLabel: true,\n inputRows: 5,\n inputStyle: {\n background: \"#FAFAFA\",\n },\n placeholder: \"Type notes here\",\n value: reviewMessage,\n onChange: (reviewMessage) => State.update({ reviewMessage }),\n validate: () => {\n if (reviewMessage.length > MAX_APPLICATION_MESSAGE_LENGTH) {\n State.update({\n reviewMessageError: `Application message must be less than ${MAX_APPLICATION_MESSAGE_LENGTH} characters`,\n });\n return;\n }\n State.update({ reviewMessageError: \"\" });\n },\n error: reviewMessageError,\n }}\n />\n </ModalBody>\n <ModalFooter>\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"tertiary\",\n text: \"Cancel\",\n onClick: handleCancel,\n }}\n />\n <Widget\n src={\"old.potlock.near/widget/Components.Button\"}\n props={{\n type: \"primary\",\n text: \"Submit\",\n disabled: !reviewMessage || !!reviewMessageError,\n onClick: handleSubmit,\n }}\n />\n </ModalFooter>\n </>\n ),\n }}\n />\n </Container>\n);\n" }, "Components.DonorsUtils": { "": "// Get the current date in the local time zone\nconst currentDate = new Date();\n// Calculate the time zone offset in milliseconds\nlet localTimeZoneOffsetMinutes = currentDate.getTimezoneOffset();\nlocalTimeZoneOffsetMinutes = localTimeZoneOffsetMinutes * 60 * 1000;\nconst oneDayTime = 24 * 60 * 60 * 1000;\nconst currentTimestamp = new Date().getTime();\nconst yesterday = currentTimestamp - oneDayTime;\nconst lastWeek = currentTimestamp - oneDayTime * 7;\nconst lastMonth = currentTimestamp - oneDayTime * 30;\nconst lastYear = currentTimestamp - oneDayTime * 365;\nconst getTimePassed = (timestamp, abbreviate) => {\n // Calculate the difference in milliseconds\n const timePassed = currentTimestamp - timestamp;\n // Convert milliseconds to seconds, minutes, hours, etc.\n const secondsPassed = Math.floor(timePassed / 1000);\n const minutesPassed = Math.floor(secondsPassed / 60);\n const hoursPassed = Math.floor(minutesPassed / 60);\n const daysPassed = Math.floor(hoursPassed / 24);\n let time = 0;\n // Display the time passed conditionally\n if (daysPassed > 0) {\n time = !abbreviate\n ? `${daysPassed} day${daysPassed === 1 ? \"\" : \"s\"}`\n : `${daysPassed}d`;\n } else if (hoursPassed > 0) {\n time = !abbreviate\n ? `${hoursPassed} hour${hoursPassed === 1 ? \"\" : \"s\"}`\n : `${hoursPassed}h`;\n } else if (minutesPassed > 0) {\n time = !abbreviate\n ? `${minutesPassed} minute${minutesPassed === 1 ? \"\" : \"s\"}`\n : `${minutesPassed}m`;\n } else {\n time = !abbreviate\n ? `${secondsPassed} second${secondsPassed === 1 ? \"\" : \"s\"}`\n : `${secondsPassed}s`;\n }\n return time;\n};\nconst _address = (address, max) => {\n const limit = max || 10;\n if (address.length > limit) return address.slice(0, limit) + \"...\";\n else return address;\n};\nconst reverseArr = (input) => {\n var ret = new Array();\n for (var i = input.length - 1; i >= 0; i--) {\n ret.push(input[i]);\n }\n return ret;\n};\nconst calcNetDonationAmount = (donation) => {\n const lastDonationAmount = Big(\n donation.total_amount -\n (donation.referrer_fee || 0) -\n (donation.protocol_fee || 0)\n ).div(Big(1e24));\n return parseFloat(lastDonationAmount);\n};\nconst filterByDate = (filter, donation) => {\n const donateAt = donation.donated_at_ms || donation.donated_at;\n switch (filter) {\n case \"day\":\n if (donateAt > yesterday) return true;\n return false;\n case \"week\":\n if (donateAt > lastWeek) return true;\n return false;\n case \"month\":\n if (donateAt > lastMonth) return true;\n return false;\n case \"year\":\n if (donateAt > lastYear) return true;\n return false;\n case \"all\":\n return true;\n default:\n return true;\n }\n};\nreturn {\n getTimePassed,\n filterByDate,\n _address,\n reverseArr,\n calcNetDonationAmount,\n};\n" }, "ModalDonation.AmountInput": { "": "const { nearToUsd } = VM.require(\"old.potlock.near/widget/utils\");\nconst SvgIcon = styled.svg`\n width: 16px;\n`;\nconst NearIcon = (props) => (\n <SvgIcon\n {...props}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <g clip-path=\"url(#clip0_454_78)\">\n <circle cx=\"8\" cy=\"8\" r=\"7.25\" stroke=\"#292929\" stroke-width=\"1.5\" />\n <path\n d=\"M11.1477 4C10.851 4 10.5763 4.15333 10.421 4.406L8.74866 6.88867C8.72453 6.92441 8.71422 6.96772 8.71967 7.01051C8.72511 7.05329 8.74594 7.09264 8.77826 7.1212C8.81057 7.14976 8.85218 7.1656 8.89531 7.16574C8.93844 7.16589 8.98015 7.15034 9.01266 7.122L10.6587 5.69467C10.6683 5.68598 10.6802 5.68028 10.6931 5.67828C10.7059 5.67628 10.719 5.67806 10.7308 5.6834C10.7426 5.68875 10.7526 5.69742 10.7596 5.70836C10.7665 5.7193 10.7702 5.73203 10.77 5.745V10.215C10.77 10.2287 10.7658 10.2421 10.7579 10.2534C10.7501 10.2646 10.7389 10.2732 10.726 10.2778C10.7131 10.2825 10.6991 10.2831 10.6858 10.2795C10.6726 10.2758 10.6608 10.2682 10.652 10.2577L5.67667 4.30167C5.59667 4.20709 5.49701 4.1311 5.38463 4.079C5.27226 4.0269 5.14987 3.99994 5.026 4H4.85233C4.62628 4 4.40949 4.0898 4.24964 4.24964C4.0898 4.40949 4 4.62628 4 4.85233V11.1477C4 11.3333 4.06061 11.5139 4.17263 11.6619C4.28465 11.81 4.44194 11.9174 4.6206 11.9679C4.79926 12.0184 4.98952 12.0091 5.16245 11.9416C5.33538 11.874 5.48152 11.7519 5.57867 11.5937L7.251 9.111C7.27513 9.07525 7.28544 9.03194 7.27999 8.98916C7.27455 8.94637 7.25372 8.90703 7.22141 8.87846C7.18909 8.8499 7.14748 8.83407 7.10435 8.83392C7.06122 8.83377 7.01951 8.84932 6.987 8.87766L5.341 10.3053C5.33134 10.3139 5.31939 10.3195 5.3066 10.3215C5.29381 10.3234 5.28074 10.3216 5.26898 10.3162C5.25721 10.3108 5.24726 10.3021 5.24034 10.2912C5.23342 10.2803 5.22983 10.2676 5.23 10.2547V5.784C5.22997 5.77027 5.23418 5.75687 5.24206 5.74563C5.24993 5.73438 5.26109 5.72584 5.274 5.72117C5.28691 5.71651 5.30094 5.71594 5.31419 5.71955C5.32743 5.72315 5.33924 5.73076 5.348 5.74133L10.3227 11.698C10.4847 11.8893 10.7227 11.9997 10.9733 12H11.147C11.373 12.0001 11.5898 11.9104 11.7498 11.7507C11.9097 11.591 11.9997 11.3744 12 11.1483V4.85233C11.9999 4.62631 11.9101 4.40956 11.7503 4.24974C11.5904 4.08992 11.3737 4.00009 11.1477 4Z\"\n fill=\"#292929\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_454_78\">\n <rect width=\"16\" height=\"16\" fill=\"white\" />\n </clipPath>\n </defs>\n </SvgIcon>\n);\nconst Container = styled.div`\n position: relative;\n display: flex;\n border-radius: 6px;\n border: 1px solid #dbdbdb;\n border-bottom: 2px solid #dbdbdb;\n background: #fff;\n input {\n padding: 0.75rem 1rem;\n flex: 1;\n background: transparent;\n border: none;\n border-radius: 0;\n &:focus {\n box-shadow: none;\n }\n }\n .usd-amount {\n padding-right: 12px;\n color: #7b7b7b;\n display: flex;\n align-items: center;\n border-right: 1px solid #dbdbdb;\n }\n`;\nconst DropdownWrapper = styled.div`\n display: flex;\n span {\n font-weight: 500;\n }\n`;\nconst PotDenominatio = styled.div`\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 0 1rem;\n .text {\n font-weight: 500;\n }\n`;\nconst Dropdown = ({\n selectedDenomination,\n denominationOptions,\n updateState,\n}) => (\n <DropdownWrapper>\n <Widget\n src={\"old.potlock.near/widget/Inputs.Select\"}\n props={{\n noLabel: true,\n placeholder: \"\",\n options: denominationOptions,\n value: {\n text: selectedDenomination.text,\n value: selectedDenomination.value,\n },\n onChange: ({ value }) => {\n updateState({\n selectedDenomination: denominationOptions.find(\n (option) => option.value === value\n ),\n });\n },\n containerStyles: {\n width: \"auto\",\n },\n inputStyles: {\n border: \"none\",\n boxShadow: \"none\",\n width: \"auto\",\n padding: \"12px 16px\",\n height: \"100%\",\n color: \"#292929\",\n },\n iconLeft: selectedDenomination.icon ? (\n <img\n src={selectedDenomination.icon}\n style={{ height: \"16px\", width: \"16px\" }}\n />\n ) : (\n <NearIcon />\n ),\n }}\n />\n </DropdownWrapper>\n);\nconst AmountInput = (props) => {\n const {\n value,\n HandleAmoutChange,\n donationType,\n denominationOptions,\n selectedDenomination,\n } = props;\n return (\n <Container>\n <input\n type=\"text\"\n value={value}\n placeholder=\"0\"\n onChange={(e) => HandleAmoutChange(e.target.value)}\n name=\"amount\"\n />\n <div className=\"usd-amount\">\n {\" \"}\n {nearToUsd && selectedDenomination.value === \"NEAR\"\n ? `~$ ${(nearToUsd * value).toFixed(2)}`\n : \"\"}\n </div>\n {donationType === \"pot\" || denominationOptions.length === 1 ? (\n <PotDenominatio>\n <NearIcon />\n <div className=\"text\">{denominationOptions[0].text}</div>\n </PotDenominatio>\n ) : (\n <Dropdown {...props} />\n )}\n </Container>\n );\n};\nreturn { AmountInput };\n" }, "Pots.Tag": { "": "const { backgroundColor, borderColor, textColor, text } = props;\nconst textStyle = props.textStyle || {};\nconst TagContainer = styled.div`\n display: flex;\n justify-content: center;\n align-items: center;\n background-color: ${backgroundColor || \"#ffffff\"};\n border: 1px solid ${borderColor || \"#000000\"};\n box-shadow: 0px -0.699999988079071px 0px ${borderColor} inset;\n // width: 100%;\n // height: 100%;\n text-align: center;\n padding: 6px 8px;\n border-radius: 4px;\n`;\nconst TagText = styled.span`\n color: ${textColor || \"#000000\"};\n font-size: 14px;\n`;\nreturn (\n <TagContainer>\n {props.preElements}\n <TagText style={textStyle}>{text}</TagText>\n </TagContainer>\n);\n" }, "ModalDonation.Checks": { "": "const Container = styled.div`\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n > div {\n display: flex;\n border-radius: 8px;\n align-items: center;\n gap: 0.5rem;\n padding: 1rem;\n cursor: pointer;\n border: 1px solid #dbdbdb;\n color: #7b7b7b;\n background: white;\n transition: all 300ms;\n .text {\n flex: 1;\n font-weight: 500;\n }\n &.active {\n box-shadow: 0px 0px 1.4px 2px #fee6e5;\n color: #dd3345;\n border-color: #dd3345;\n span {\n color: #7b7b7b;\n }\n }\n &.disabled {\n pointer-events: none;\n color: #a6a6a6;\n background: #f6f5f3;\n span {\n color: #a6a6a6;\n }\n }\n }\n`;\nconst CheckBox = styled.div`\n width: 20px;\n height: 20px;\n border: 2px solid #d9d9d9;\n display: flex;\n border-radius: 50%;\n div {\n width: 10px;\n height: 10px;\n background: transparent;\n border-radius: 50%;\n margin: auto;\n }\n &.active {\n border-color: #dd3345;\n div {\n background: #dd3345;\n }\n }\n`;\nconst Checks = ({ options, value, onClick }) => {\n return (\n <Container>\n {options.map((option) => (\n <div\n key={option.val}\n onClick={() => onClick(option.val)}\n className={`${value === option.val ? \"active\" : \"\"} ${\n option.disabled ? \"disabled\" : \"\"\n }`}\n >\n <CheckBox className={`${value === option.val ? \"active\" : \"\"}`}>\n <div></div>\n </CheckBox>\n <div className=\"text\">\n {option.label} {option.info && <span> {option.info} </span>}\n {option.disabled && <span> {option.disabledText} </span>}\n </div>\n </div>\n ))}\n </Container>\n );\n};\nreturn { Checks };\n" }, "Inputs.SelectMultiple": { "": "const { label, options, onChange, placeholder, selected } = props;\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n padding: 0px;\n gap: 0.45em;\n width: 100%;\n`;\nconst Label = styled.label`\n font-style: normal;\n // font-weight: 600;\n font-size: 0.95em;\n line-height: 1.25em;\n color: #344054;\n`;\nreturn (\n <Container>\n {label && <Label>{label}</Label>}\n <Typeahead\n options={options}\n multiple\n onChange={onChange}\n placeholder={placeholder}\n selected={selected}\n />\n </Container>\n);\n" }, "Components.AccountsList": { "": "const { accountIds, allowRemove, handleRemoveAccount } = props;\nconst MembersListItem = styled.div`\n padding: 16px 0px;\n border-top: 1px #f0f0f0 solid;\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n`;\nconst MembersListItemLeft = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: flex-start;\n gap: 16px;\n`;\nconst MembersListItemText = styled.div`\n font-size: 16px;\n font-weight: 400;\n color: #2e2e2e;\n`;\nconst RemoveMember = styled.a`\n color: #2e2e2e;\n font-size: 14px;\n font-weight: 600;\n visibility: hidden;\n cursor: pointer;\n opacity: 0;\n transition: opacity 0.2s ease-in-out;\n &:hover {\n text-decoration: none;\n }\n ${MembersListItem}:hover & {\n visibility: visible;\n opacity: 1;\n }\n`;\nreturn (\n <>\n {accountIds.map((accountId) => {\n return (\n <MembersListItem>\n <MembersListItemLeft>\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{\n accountId,\n style: {\n width: \"40px\",\n height: \"40px\",\n margin: \"0 -8px 0 0\",\n borderRadius: \"50%\",\n background: \"white\",\n },\n imageClassName: \"rounded-circle w-100 h-100 d-block\",\n thumbnail: false,\n tooltip: true,\n }}\n />\n <MembersListItemText>@{accountId}</MembersListItemText>\n </MembersListItemLeft>\n {allowRemove && (\n <RemoveMember onClick={() => handleRemoveAccount(accountId)}>\n Remove\n </RemoveMember>\n )}\n </MembersListItem>\n );\n })}\n </>\n);\n" } } } } }
Result:
{ "block_height": "119511215" }
No logs
Receipt:
Predecessor ID:
Receiver ID:
Gas Burned:
223 Ggas
Tokens Burned:
0 
Transferred 0.17317  to old.potlock.near
Empty result
No logs