├── .env.example ├── .eslintignore ├── .eslintrc.yml ├── .github └── workflows │ └── lint.yml_bkp ├── .gitignore ├── .unimportedrc.json ├── LICENSE.txt ├── README.md ├── codegen.yaml ├── next-env.d.ts ├── next.config.js ├── package-lock.json ├── package.json ├── public ├── Browser Mock.svg ├── chain_assets │ ├── aave.svg │ ├── apwine.svg │ ├── biconomy.svg │ ├── boba.svg │ ├── celo.svg │ ├── celo_token.svg │ ├── cusd.svg │ ├── dai.svg │ ├── dollar.svg │ ├── eth.svg │ ├── flux.svg │ ├── gnosis.svg │ ├── inch.svg │ ├── livepeer.svg │ ├── matic.svg │ ├── metis.svg │ ├── ocean.svg │ ├── perp.svg │ ├── sUSD.svg │ ├── snx.svg │ ├── solana.png │ ├── spruce.svg │ ├── stackos.svg │ ├── telos.svg │ ├── toncoin.svg │ ├── uma.svg │ ├── uniswap.svg │ ├── unlock.svg │ ├── usdc.svg │ ├── weth.svg │ ├── wmatic.svg │ ├── yearn.svg │ └── zkp.svg ├── favicon.ico ├── favicon.png ├── favicon.svg ├── fonts │ └── v2 │ │ └── NueHaas │ │ ├── NHaasGroteskTXPro-55Rg.ttf │ │ ├── NHaasGroteskTXPro-56It.ttf │ │ ├── NHaasGroteskTXPro-65Md.ttf │ │ ├── NHaasGroteskTXPro-66MdIt.ttf │ │ ├── NHaasGroteskTXPro-75Bd.ttf │ │ └── NHaasGroteskTXPro-76BdIt.ttf ├── privacypolicy.html ├── termsofservice.html ├── v2 │ ├── icons │ │ ├── accept.svg │ │ ├── add user.svg │ │ ├── add.svg │ │ ├── alert.svg │ │ ├── arrow left.svg │ │ ├── arrow right.svg │ │ ├── bell.svg │ │ ├── bitcoin.svg │ │ ├── bold_button.svg │ │ ├── calendar-color.svg │ │ ├── calendar.svg │ │ ├── call.svg │ │ ├── celo.svg │ │ ├── celo_safe.svg │ │ ├── chat.svg │ │ ├── check double.svg │ │ ├── checkBox.svg │ │ ├── checkbox circle.svg │ │ ├── chevron right.svg │ │ ├── close.svg │ │ ├── copy.svg │ │ ├── desktop.svg │ │ ├── discord.svg │ │ ├── discover.svg │ │ ├── doc.svg │ │ ├── dot.svg │ │ ├── down.svg │ │ ├── dropdown.svg │ │ ├── embed.svg │ │ ├── error warning.svg │ │ ├── export-download.svg │ │ ├── export.svg │ │ ├── filter.svg │ │ ├── gdrive.svg │ │ ├── group.svg │ │ ├── image add.svg │ │ ├── import.svg │ │ ├── iotex.svg │ │ ├── italics_button.svg │ │ ├── key.svg │ │ ├── link.svg │ │ ├── loader.svg │ │ ├── mail.svg │ │ ├── metamask.svg │ │ ├── multisig.svg │ │ ├── new tab.svg │ │ ├── notVisible.svg │ │ ├── ol_button.svg │ │ ├── openmask.svg │ │ ├── pencil.svg │ │ ├── phantom.svg │ │ ├── phone.svg │ │ ├── pie chart.svg │ │ ├── projectDetails.svg │ │ ├── qb.svg │ │ ├── qr-scan.svg │ │ ├── questbook.svg │ │ ├── question.svg │ │ ├── realms.svg │ │ ├── realms_logo.svg │ │ ├── reject.svg │ │ ├── resubmit.svg │ │ ├── safe.svg │ │ ├── safe_logo.svg │ │ ├── search.svg │ │ ├── settings.svg │ │ ├── share forward.svg │ │ ├── share-box.svg │ │ ├── share.svg │ │ ├── swap.svg │ │ ├── telegram.svg │ │ ├── thumbs up.svg │ │ ├── time.svg │ │ ├── tonkey.svg │ │ ├── twitter.svg │ │ ├── ul_button.svg │ │ ├── underline_button.svg │ │ ├── unhappy.svg │ │ ├── visible.svg │ │ ├── wallet-connect.svg │ │ └── wallet.svg │ └── images │ │ ├── Rectangle 6.svg │ │ ├── banner.png │ │ ├── builders.svg │ │ ├── cover-image.svg │ │ ├── default_profile_picture.png │ │ ├── empty-body.svg │ │ ├── profile-bg.png │ │ ├── qb-discussion.svg │ │ ├── qb-only-logo.svg │ │ ├── reclaim_bg.svg │ │ ├── safeguard.svg │ │ └── tonBanner.png └── workbox-7c2a5a06.js ├── sentry.client.config.ts ├── sentry.properties ├── sentry.server.config.ts ├── src ├── constants │ ├── Networks.tsx │ ├── addresses.ts │ ├── applicantDetailsList.tsx │ ├── chains.ts │ ├── config.json │ ├── safesEndpoints.json │ ├── safesEndpointsTest.json │ ├── safesSupported.json │ ├── seo.tsx │ └── strings.json ├── contexts │ └── safeContext.tsx ├── contracts │ └── abi │ │ ├── ApplicationRegistryAbi.json │ │ ├── ApplicationReviewRegistryAbi.json │ │ ├── CommunicationAbi.json │ │ ├── GrantAbi.json │ │ ├── GrantFactoryAbi.json │ │ ├── ReviewerGuard.json │ │ ├── UtilityRegistryAbi.json │ │ ├── WalletAbi.json │ │ └── WorkspaceRegistryAbi.json ├── generated │ ├── SupportedChainId.ts │ ├── chainInfo.json │ ├── contracts │ │ ├── ApplicationRegistryAbi.ts │ │ ├── ApplicationReviewRegistryAbi.ts │ │ ├── CommunicationAbi.ts │ │ ├── ERC20.ts │ │ ├── ERC20Proxy.ts │ │ ├── GrantAbi.ts │ │ ├── GrantFactoryAbi.ts │ │ ├── ReviewerGuard.ts │ │ ├── UtilityRegistryAbi.ts │ │ ├── WorkspaceRegistryAbi.ts │ │ ├── common.ts │ │ ├── factories │ │ │ ├── ApplicationRegistryAbi__factory.ts │ │ │ ├── ApplicationReviewRegistryAbi__factory.ts │ │ │ ├── CommunicationAbi__factory.ts │ │ │ ├── ERC20Proxy__factory.ts │ │ │ ├── ERC20__factory.ts │ │ │ ├── GrantAbi__factory.ts │ │ │ ├── GrantFactoryAbi__factory.ts │ │ │ ├── ReviewerGuard__factory.ts │ │ │ ├── UtilityRegistryAbi__factory.ts │ │ │ ├── WorkspaceRegistryAbi__factory.ts │ │ │ └── index.ts │ │ └── index.ts │ ├── graphql.ts │ ├── icons.tsx │ └── mutation │ │ ├── addComment.ts │ │ ├── addComments.ts │ │ ├── assignReviewers.ts │ │ ├── batchGrantApplicationUpdate.ts │ │ ├── createBuilder.ts │ │ ├── createBuilderProfile.ts │ │ ├── createInviteLink.ts │ │ ├── createRFP.ts │ │ ├── disburseRewardsFromSafe.ts │ │ ├── editComment.ts │ │ ├── generateToken.ts │ │ ├── index.ts │ │ ├── joinViaInviteLink.ts │ │ ├── reSubmitProposal.ts │ │ ├── reclaimProof.ts │ │ ├── sendDocuSign.ts │ │ ├── setRubrics.ts │ │ ├── submitProposal.ts │ │ ├── submitReviews.ts │ │ ├── updateBuilderProfile.ts │ │ ├── updateGrant.ts │ │ ├── updateMetadataWorkspace.ts │ │ ├── updateWorkspaceMember.ts │ │ ├── verifyToken.ts │ │ └── workspaceUpdateSafe.ts ├── global.d.ts ├── graphql │ ├── apollo.tsx │ └── subgraph.tsx ├── libraries │ ├── data │ │ ├── getAdminPublicKeysQuery.ts │ │ ├── getApplicationDetailsQuery.ts │ │ ├── getBuilderProfileQuery.ts │ │ ├── getGrantManagersWithPublicKeyQuery.ts │ │ ├── getGrantQuery.ts │ │ ├── getMemberPublicKeysQuery.ts │ │ ├── getQBAdminsQuery.ts │ │ ├── getWorkspaceMemberExistsQuery.ts │ │ ├── getWorkspaceMembersPublicKeysQuery.ts │ │ └── getWorkspaceMembersQuery.ts │ ├── graphql │ │ ├── getAdminPublicKeys.graphql │ │ ├── getApplicationDetails.graphql │ │ ├── getBuilderProfile.graphql │ │ ├── getGrant.graphql │ │ ├── getGrantManagersWithPublicKey.graphql │ │ ├── getLatestBlock.graphql │ │ ├── getMemberPublicKeys.graphql │ │ ├── getQBAdmins.graphql │ │ ├── getWorkspaceMemberExists.graphql │ │ ├── getWorkspaceMembers.graphql │ │ └── getWorkspaceMembersPublicKeys.graphql │ ├── hooks │ │ ├── DAOSearchContext.ts │ │ ├── QBAdminsContext.ts │ │ ├── gasless │ │ │ ├── useBiconomy.ts │ │ │ ├── useNetwork.ts │ │ │ └── useQuestbookAccount.ts │ │ ├── useCreateMapping.tsx │ │ ├── useCustomToast.tsx │ │ ├── useFunctionCall.tsx │ │ ├── useLinkYourMultisig.tsx │ │ ├── useMultiChainQuery.ts │ │ ├── useQBContract.ts │ │ ├── useQuery.ts │ │ ├── useSetupProfile.tsx │ │ ├── useUpdateDaoVisibility.ts │ │ └── utils │ │ │ └── useChainId.ts │ ├── logger.ts │ ├── ui │ │ ├── BackButton.tsx │ │ ├── ConfirmationModal.tsx │ │ ├── CopyIcon.tsx │ │ ├── CustomSelect.tsx │ │ ├── FlushedInput.tsx │ │ ├── ImageUpload.tsx │ │ ├── LinkYourMultisigModal │ │ │ ├── DropdownSelect.tsx │ │ │ ├── SafeSelect.tsx │ │ │ ├── VerifySignerErrorState.tsx │ │ │ ├── VerifySignerModal.tsx │ │ │ └── index.tsx │ │ ├── NavBar │ │ │ ├── _components │ │ │ │ ├── AccountDetails.tsx │ │ │ │ ├── BackupWallet.tsx │ │ │ │ ├── CreateNewWallet.tsx │ │ │ │ ├── ImportConfirmationModal.tsx │ │ │ │ ├── IssueWarning.tsx │ │ │ │ ├── NotificationPopover.tsx │ │ │ │ ├── RestoreWallet.tsx │ │ │ │ ├── SignIn.tsx │ │ │ │ ├── UpdateProfileModal.tsx │ │ │ │ ├── googleRecovery.ts │ │ │ │ ├── googleRecoveryTypes.ts │ │ │ │ └── googleRecoveryUtils.ts │ │ │ ├── _utils │ │ │ │ └── constants.ts │ │ │ └── index.tsx │ │ ├── NetworkTransactionFlowStepperModal.tsx │ │ ├── QRCodeModal.tsx │ │ ├── RichTextEditor │ │ │ ├── commentTextEditor.tsx │ │ │ ├── commentTextViewer.tsx │ │ │ ├── loader.tsx │ │ │ ├── textEditor.tsx │ │ │ └── textViewer.tsx │ │ ├── SearchField.tsx │ │ ├── SetupNotificationModal.tsx │ │ └── navbarLayout.tsx │ ├── utils │ │ ├── amplitude.tsx │ │ ├── appCopy.ts │ │ ├── authToken.ts │ │ ├── constants.tsx │ │ ├── contextGenerator.ts │ │ ├── copy.ts │ │ ├── error.ts │ │ ├── formatting.ts │ │ ├── gasless.ts │ │ ├── getSCWAddress.ts │ │ ├── index.ts │ │ ├── invite.ts │ │ ├── ipfs.ts │ │ ├── logger.ts │ │ ├── multisig.ts │ │ ├── pii.ts │ │ ├── reviews.ts │ │ ├── seo.ts │ │ ├── token.ts │ │ ├── types.ts │ │ └── validations.ts │ └── validator │ │ ├── index.ts │ │ ├── schema.yaml │ │ └── utils │ │ └── generateTypes.ts ├── pages │ ├── _app.tsx │ ├── _error.tsx │ ├── dashboard.tsx │ ├── grantees.tsx │ ├── index.tsx │ ├── profile │ │ └── [address].tsx │ ├── proposal_form.tsx │ ├── proposal_recovery.tsx │ ├── request_proposal.tsx │ ├── settings.tsx │ └── setup_profile.tsx ├── screens │ ├── dashboard │ │ ├── ActionList.tsx │ │ ├── Banner.tsx │ │ ├── Body.tsx │ │ ├── Context.tsx │ │ ├── FundBuilderDrawer.tsx │ │ ├── FundBuilderModal.tsx │ │ ├── FundingMethod.tsx │ │ ├── ProposalList.tsx │ │ ├── SafeGuardModal.tsx │ │ ├── SendAnUpdateModal.tsx │ │ ├── SetupProfileModal.tsx │ │ ├── _components │ │ │ ├── ActionList │ │ │ │ ├── MultiSelect │ │ │ │ │ └── index.tsx │ │ │ │ └── SingleSelect │ │ │ │ │ ├── Milestones.tsx │ │ │ │ │ ├── Payouts.tsx │ │ │ │ │ ├── ReviewProposal.tsx │ │ │ │ │ ├── Reviews.tsx │ │ │ │ │ └── index.tsx │ │ │ ├── Body │ │ │ │ ├── Empty.tsx │ │ │ │ ├── MultiSelect │ │ │ │ │ └── index.tsx │ │ │ │ └── SingleSelect │ │ │ │ │ ├── Discussions.tsx │ │ │ │ │ ├── Proposal.tsx │ │ │ │ │ └── index.tsx │ │ │ ├── DashboardInput.tsx │ │ │ ├── FilterTag.tsx │ │ │ ├── FundBuilder │ │ │ │ ├── ConnectWalletButton.tsx │ │ │ │ ├── MilestoneChoose.tsx │ │ │ │ ├── PaidByWallet.tsx │ │ │ │ ├── PayFromChoose.tsx │ │ │ │ ├── PayWithChoose.tsx │ │ │ │ ├── ProposalDetails.tsx │ │ │ │ ├── ToChoose.tsx │ │ │ │ ├── TransactionInitiated.tsx │ │ │ │ └── Verify.tsx │ │ │ ├── HelloSignModal.tsx │ │ │ ├── HeroBanner.tsx │ │ │ ├── ProposalList │ │ │ │ ├── Empty.tsx │ │ │ │ └── ProposalCard.tsx │ │ │ ├── QuickReplyButton.tsx │ │ │ ├── RoleTag.tsx │ │ │ ├── StateTag.tsx │ │ │ └── ThreeColumnSkeleton.tsx │ │ ├── _data │ │ │ ├── getApplicantProposalsQuery.ts │ │ │ ├── getApplicationActionsQuery.ts │ │ │ ├── getBuilderInfoQuery.ts │ │ │ ├── getCommentsQuery.ts │ │ │ ├── getDocuSignTemplates.ts │ │ │ ├── getFundsAllocatedQuery.ts │ │ │ ├── getGrantDetailsForSEOQuery.ts │ │ │ ├── getGrantsQuery.ts │ │ │ ├── getMemberPublicKeysQuery.ts │ │ │ ├── getPayoutQuery.ts │ │ │ ├── getProposalDetailsForSEOQuery.ts │ │ │ ├── getProposalsQuery.ts │ │ │ ├── getSpecificApplicationActionQuery.ts │ │ │ ├── getSpecificProposalCommentsQuery.ts │ │ │ ├── getSpecificProposalQuery.ts │ │ │ └── getSynapsId.ts │ │ ├── _graphql │ │ │ ├── getApplicantProposals.graphql │ │ │ ├── getApplicationActionForProposal.graphql │ │ │ ├── getApplicationActions.graphql │ │ │ ├── getBuilderInfo.graphql │ │ │ ├── getComments.graphql │ │ │ ├── getDocusSignTemplates.graphql │ │ │ ├── getFundTransfers.graphql │ │ │ ├── getFundsAllocated.graphql │ │ │ ├── getGrantDetailsForSEO.graphql │ │ │ ├── getPayouts.graphql │ │ │ ├── getProposalDetailsForSEO.graphql │ │ │ ├── getProposals.graphql │ │ │ ├── getSpecificProposal.graphql │ │ │ ├── getSpecificProposalComments.graphql │ │ │ └── getSynapsId.graphql │ │ ├── _hooks │ │ │ ├── useAddComment.ts │ │ │ ├── useAddComments.ts │ │ │ ├── useAssignReviewers.ts │ │ │ ├── useDocuSign.ts │ │ │ ├── useEditComment.ts │ │ │ ├── usePayout.ts │ │ │ ├── usePhantomWallet.ts │ │ │ ├── useQuickReplies.tsx │ │ │ ├── useSetRubrics.ts │ │ │ ├── useSubmitReview.ts │ │ │ ├── useSynaps.ts │ │ │ └── useTonWallet.ts │ │ ├── _utils │ │ │ ├── constants.ts │ │ │ ├── formatters.ts │ │ │ ├── tonWalletUtils.ts │ │ │ └── types.ts │ │ └── index.tsx │ ├── discover │ │ ├── Context.tsx │ │ ├── FeaturedSections.tsx │ │ ├── Footer.tsx │ │ ├── HeroBanner.tsx │ │ ├── StatsBanner.tsx │ │ ├── _components │ │ │ ├── BuilderModal.tsx │ │ │ ├── ProposalCard.tsx │ │ │ ├── RFPCard.tsx │ │ │ ├── rfpGrid.tsx │ │ │ └── stateButton.tsx │ │ ├── _graphql │ │ │ ├── getAllFundTransfers.graphql │ │ │ ├── getAllGrants.graphql │ │ │ ├── getAllGrantsForMember.graphql │ │ │ ├── getFundsAllocated.graphql │ │ │ ├── getGrantProgramDetails.graphql │ │ │ ├── getProposalNameAndAuthors.graphql │ │ │ ├── getSectionGrants.graphql │ │ │ ├── getSectionSubGrants.graphql │ │ │ ├── getStats.graphql │ │ │ └── getWorkspacesAndBuilderGrants.graphql │ │ ├── _utils │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── data │ │ │ ├── fundsTransfers.ts │ │ │ ├── getAllGrants.ts │ │ │ ├── getAllGrantsForMembers.ts │ │ │ ├── getFundsAllocated.ts │ │ │ ├── getGrantProgramDetails.ts │ │ │ ├── getProposalNameAndAuthors.ts │ │ │ ├── getSectionGrants.ts │ │ │ ├── getSectionSubGrants.ts │ │ │ ├── getStats.ts │ │ │ └── getWorkspaceAndBuilderGrants.ts │ │ ├── hooks │ │ │ └── github.tsx │ │ └── index.tsx │ ├── grantees │ │ ├── Context.tsx │ │ ├── HeroBanner.tsx │ │ ├── _components │ │ │ ├── RFPCard.tsx │ │ │ ├── rfpGrid.tsx │ │ │ └── stateButton.tsx │ │ ├── _graphql │ │ │ └── getSectionGrants.graphql │ │ ├── _utils │ │ │ ├── constants.ts │ │ │ └── types.ts │ │ ├── data │ │ │ └── getSectionGrants.tsx │ │ ├── hooks │ │ │ └── github.tsx │ │ └── index.tsx │ ├── profile │ │ ├── Context.tsx │ │ ├── _components │ │ │ ├── GrantStats.tsx │ │ │ ├── ProfileBanner.tsx │ │ │ ├── ProfileModal.tsx │ │ │ ├── ProofQrModal.tsx │ │ │ ├── ProposalCard.tsx │ │ │ └── stateButton.tsx │ │ ├── _graphql │ │ │ ├── getBuilderInfo.graphql │ │ │ ├── getMyProposals.graphql │ │ │ └── getUserNameAvailability.graphql │ │ ├── _utils │ │ │ ├── constant.ts │ │ │ ├── formatters.ts │ │ │ └── types.ts │ │ ├── data │ │ │ ├── getBuilderInfo.ts │ │ │ ├── getMyProposals.ts │ │ │ └── getUserNameAvailability.ts │ │ ├── hooks │ │ │ ├── checkUsernameAvailablity.tsx │ │ │ └── generateProof.ts │ │ └── index.tsx │ ├── proposal_form │ │ ├── Context.tsx │ │ ├── _components │ │ │ ├── SectionHeader.tsx │ │ │ ├── SectionInput.tsx │ │ │ ├── SectionRichTextEditor.tsx │ │ │ ├── SectionSelect.tsx │ │ │ ├── SelectArray.tsx │ │ │ └── SelectRadioButton.tsx │ │ ├── _data │ │ │ ├── grantDetailsQuery.ts │ │ │ ├── proposalDetailsQuery.ts │ │ │ └── walletAddressCheckerQuery.ts │ │ ├── _graphql │ │ │ ├── grantDetails.graphql │ │ │ ├── proposalDetails.graphql │ │ │ └── walletAddressChecker.graphql │ │ ├── _hooks │ │ │ └── useSubmitProposal.tsx │ │ ├── _utils │ │ │ ├── constants.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ └── index.tsx │ ├── proposal_recovery │ │ ├── _graphql │ │ │ └── getMigrationStatus.graphql │ │ ├── data │ │ │ └── getMigrationStatusQuery.ts │ │ └── index.tsx │ ├── request_proposal │ │ ├── Context.tsx │ │ ├── _components │ │ │ ├── SelectDropdown.tsx │ │ │ └── StepIndicator.tsx │ │ ├── _data │ │ │ ├── getGrantDetailsByIdQuery.ts │ │ │ └── getGrantDetailsQuery.ts │ │ ├── _graphql │ │ │ ├── getGrantDetails.graphql │ │ │ └── getGrantDetailsById.graphql │ │ ├── _hooks │ │ │ ├── useCreateRFP.ts │ │ │ └── useUpdateRFP.ts │ │ ├── _subscreens │ │ │ ├── Payouts.tsx │ │ │ ├── ProposalReview.tsx │ │ │ └── ProposalSubmission.tsx │ │ ├── _utils │ │ │ ├── constants.ts │ │ │ └── types.ts │ │ └── index.tsx │ ├── settings │ │ ├── Context.tsx │ │ ├── WorkspaceMemberCard.tsx │ │ ├── _components │ │ │ ├── AddMemberButton.tsx │ │ │ └── DropdownIcon.tsx │ │ ├── _graphql │ │ │ ├── getWorkspaceDetails.graphql │ │ │ └── getWorkspaceMembersByWorkspaceId.graphql │ │ ├── _hooks │ │ │ └── useUpdateGrantProgram.tsx │ │ ├── _utils │ │ │ └── types.ts │ │ ├── data │ │ │ ├── getWorkspaceDetailsQuery.ts │ │ │ ├── getWorkspaceMembersByWorkspaceIdQuery.ts │ │ │ └── index.ts │ │ └── index.tsx │ └── setup_profile │ │ └── index.tsx ├── theme │ ├── colors.tsx │ ├── components │ │ ├── button.tsx │ │ ├── container.tsx │ │ ├── divider.tsx │ │ ├── header.tsx │ │ ├── input.tsx │ │ ├── link.tsx │ │ ├── progress.tsx │ │ └── text.tsx │ └── index.tsx └── types │ ├── gasless.ts │ ├── gen.d.ts │ └── index.ts ├── styles └── globals.css └── tsconfig.json /.env.example: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_IS_TEST= 2 | NEXT_PUBLIC_INFURA_ID= 3 | CLIENT_ID= 4 | CLIENT_SECRET= 5 | BICO_AUTH_TOKEN= 6 | SOLANA_RPC= 7 | SENTRY_LOG_LEVEL= 8 | SENTRY_AUTH_TOKEN= 9 | API_ENDPOINT= 10 | NOTIF_BOT_USERNAME= 11 | INFURA_IPFS_PROJECT_ID= 12 | INFURA_IPFS_API_KEY= 13 | WALLETCONNECT_PROJECT_ID= 14 | BACKEND_URL= -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | src/generated 3 | src/pages/test.tsx 4 | out 5 | .next 6 | .vscode 7 | public 8 | contracts -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | extends: '@creatoros' 2 | parserOptions: 3 | project: ./tsconfig.json 4 | plugins: 5 | - no-relative-import-paths 6 | - sonarjs 7 | rules: 8 | no-console: 'error' 9 | sonarjs/no-duplicated-branches: 'error' 10 | sonarjs/no-identical-functions: 'error' 11 | sonarjs/no-gratuitous-expressions: 'error' 12 | no-relative-import-paths/no-relative-import-paths: 13 | - error 14 | - rootDir: '' -------------------------------------------------------------------------------- /.github/workflows/lint.yml_bkp: -------------------------------------------------------------------------------- 1 | name: Check PR health 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | check-lint: 7 | runs-on: ubuntu-latest 8 | timeout-minutes: 10 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | 13 | - name: Install Node 14 | uses: actions/setup-node@v1 15 | with: 16 | node-version: 16.x 17 | 18 | - name: Install packages 19 | run: npm i --legacy-peer-deps 20 | 21 | - name: Refresh packages 22 | run: npm run refresh 23 | 24 | - name: Check linting 25 | run: npm run lint 26 | 27 | - name: Check build 28 | run: npm run build 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | /.pnp 6 | .pnp.js 7 | src/.graphclientrc.yml 8 | 9 | # testing 10 | /coverage 11 | /pages/api/ 12 | /pages/test.tsx 13 | tests/ 14 | 15 | # next.js 16 | /.next/ 17 | /out/ 18 | 19 | # production 20 | /build 21 | 22 | # misc 23 | .DS_Store 24 | *.pem 25 | 26 | # debug 27 | npm-debug.log* 28 | yarn-debug.log* 29 | yarn-error.log* 30 | 31 | # local env files 32 | .env 33 | .env.local 34 | .env.development.local 35 | .env.test.local 36 | .env.production.local 37 | 38 | # vercel 39 | .vercel 40 | 41 | # typescript 42 | *.tsbuildinfo 43 | 44 | yarn.lock 45 | 46 | .env 47 | src/pages/test.tsx 48 | test/ 49 | lib 50 | # Sentry 51 | .sentryclirc 52 | 53 | #service worker 54 | sw.js 55 | workbox-588899ac.js -------------------------------------------------------------------------------- /.unimportedrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "aliases": { 3 | "src/*": [ 4 | "./src", 5 | "./src/*" 6 | ], 7 | "entry": [ 8 | "src/pages/**/*.{js,ts,tsx}", 9 | "next.config.js" 10 | ] 11 | }, 12 | "ignoreUnresolved": [ 13 | ".graphclient", 14 | "encoding", 15 | "public/favicon.ico", 16 | "src/types/gen", 17 | "styles/globals.css" 18 | ], 19 | "ignoreUnused": [ 20 | "@apidevtools/json-schema-ref-parser", 21 | "@metamask/eth-sig-util", 22 | "@unstoppabledomains/resolution", 23 | "create-chakra-icons", 24 | "idriss-crypto", 25 | "js-yaml-loader", 26 | "json-schema-to-typescript", 27 | "linkifyjs", 28 | "lottie-react", 29 | "next", 30 | "next-plugin-yaml", 31 | "next-pwa", 32 | "next-transpile-modules", 33 | "openapi-typescript", 34 | "react", 35 | "react-apexcharts", 36 | "react-datepicker", 37 | "react-dom", 38 | "react-image-picker-editor", 39 | "ts-node" 40 | ], 41 | "ignoreUnimported": [ 42 | "src/generated/contracts/ERC20.ts", 43 | "src/generated/contracts/ERC20Proxy.ts", 44 | "src/generated/contracts/factories/ERC20Proxy__factory.ts", 45 | "src/generated/contracts/factories/ERC20__factory.ts", 46 | "src/libraries/validator/utils/generateTypes.ts", 47 | "src/screens/dashboard/_utils/constants.ts", 48 | "src/screens/request_proposal/_utils/constants.ts" 49 | ] 50 | } -------------------------------------------------------------------------------- /codegen.yaml: -------------------------------------------------------------------------------- 1 | schema: 2 | - https://the-graph.questbook.app/subgraphs/name/qb-subgraph-optimism-mainnet 3 | documents: 4 | - src/libraries/graphql/*.graphql 5 | - src/screens/dashboard/_graphql/*.graphql 6 | - src/screens/discover/_graphql/*.graphql 7 | - src/screens/proposal_form/_graphql/*.graphql 8 | - src/screens/profile/_graphql/*.graphql 9 | - src/screens/request_proposal/_graphql/*.graphql 10 | - src/screens/settings/_graphql/*.graphql 11 | overwrite: true 12 | generates: 13 | ./src/generated/graphql.ts: 14 | plugins: 15 | - typescript 16 | - typescript-operations 17 | - typescript-react-apollo 18 | config: 19 | scalars: 20 | BigDecimal: string 21 | BigInt: string 22 | Bytes: string 23 | skipTypename: false 24 | withComponent: false 25 | withHooks: true 26 | withHOC: false 27 | withRefetchFn: true -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /public/chain_assets/biconomy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /public/chain_assets/cusd.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Celo US Dollar Currency Symbol 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /public/chain_assets/dollar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/chain_assets/eth.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /public/chain_assets/flux.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/chain_assets/gnosis.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /public/chain_assets/livepeer.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /public/chain_assets/matic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /public/chain_assets/perp.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /public/chain_assets/solana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/questbook/grants-frontend/e5b3129c808e83b7aa02ef306f21917f36cbd691/public/chain_assets/solana.png -------------------------------------------------------------------------------- /public/chain_assets/spruce.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /public/chain_assets/unlock.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/questbook/grants-frontend/e5b3129c808e83b7aa02ef306f21917f36cbd691/public/favicon.ico -------------------------------------------------------------------------------- /public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/questbook/grants-frontend/e5b3129c808e83b7aa02ef306f21917f36cbd691/public/favicon.png -------------------------------------------------------------------------------- /public/fonts/v2/NueHaas/NHaasGroteskTXPro-55Rg.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/questbook/grants-frontend/e5b3129c808e83b7aa02ef306f21917f36cbd691/public/fonts/v2/NueHaas/NHaasGroteskTXPro-55Rg.ttf -------------------------------------------------------------------------------- /public/fonts/v2/NueHaas/NHaasGroteskTXPro-56It.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/questbook/grants-frontend/e5b3129c808e83b7aa02ef306f21917f36cbd691/public/fonts/v2/NueHaas/NHaasGroteskTXPro-56It.ttf -------------------------------------------------------------------------------- /public/fonts/v2/NueHaas/NHaasGroteskTXPro-65Md.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/questbook/grants-frontend/e5b3129c808e83b7aa02ef306f21917f36cbd691/public/fonts/v2/NueHaas/NHaasGroteskTXPro-65Md.ttf -------------------------------------------------------------------------------- /public/fonts/v2/NueHaas/NHaasGroteskTXPro-66MdIt.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/questbook/grants-frontend/e5b3129c808e83b7aa02ef306f21917f36cbd691/public/fonts/v2/NueHaas/NHaasGroteskTXPro-66MdIt.ttf -------------------------------------------------------------------------------- /public/fonts/v2/NueHaas/NHaasGroteskTXPro-75Bd.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/questbook/grants-frontend/e5b3129c808e83b7aa02ef306f21917f36cbd691/public/fonts/v2/NueHaas/NHaasGroteskTXPro-75Bd.ttf -------------------------------------------------------------------------------- /public/fonts/v2/NueHaas/NHaasGroteskTXPro-76BdIt.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/questbook/grants-frontend/e5b3129c808e83b7aa02ef306f21917f36cbd691/public/fonts/v2/NueHaas/NHaasGroteskTXPro-76BdIt.ttf -------------------------------------------------------------------------------- /public/v2/icons/accept.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/add user.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/alert.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/arrow left.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/arrow right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/bell.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/bitcoin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/bold_button.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /public/v2/icons/calendar-color.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /public/v2/icons/calendar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/call.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/chat.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/check double.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/checkBox.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /public/v2/icons/checkbox circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/chevron right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/copy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /public/v2/icons/desktop.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/discover.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/doc.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /public/v2/icons/dot.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/dropdown.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/embed.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/error warning.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/export-download.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /public/v2/icons/export.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/filter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/gdrive.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /public/v2/icons/group.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/image add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/import.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/italics_button.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /public/v2/icons/key.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/loader.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/mail.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/new tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/ol_button.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /public/v2/icons/pencil.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/phone.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/pie chart.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/qr-scan.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/question.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/reject.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/resubmit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/share forward.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/share-box.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/share.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /public/v2/icons/swap.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/telegram.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/thumbs up.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/time.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/twitter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/ul_button.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /public/v2/icons/underline_button.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /public/v2/icons/visible.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/wallet-connect.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/icons/wallet.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/v2/images/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/questbook/grants-frontend/e5b3129c808e83b7aa02ef306f21917f36cbd691/public/v2/images/banner.png -------------------------------------------------------------------------------- /public/v2/images/builders.svg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/questbook/grants-frontend/e5b3129c808e83b7aa02ef306f21917f36cbd691/public/v2/images/builders.svg -------------------------------------------------------------------------------- /public/v2/images/default_profile_picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/questbook/grants-frontend/e5b3129c808e83b7aa02ef306f21917f36cbd691/public/v2/images/default_profile_picture.png -------------------------------------------------------------------------------- /public/v2/images/profile-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/questbook/grants-frontend/e5b3129c808e83b7aa02ef306f21917f36cbd691/public/v2/images/profile-bg.png -------------------------------------------------------------------------------- /public/v2/images/qb-only-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /public/v2/images/tonBanner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/questbook/grants-frontend/e5b3129c808e83b7aa02ef306f21917f36cbd691/public/v2/images/tonBanner.png -------------------------------------------------------------------------------- /sentry.client.config.ts: -------------------------------------------------------------------------------- 1 | // This file configures the initialization of Sentry on the server. 2 | // The config you add here will be used whenever the server handles a request. 3 | // https://docs.sentry.io/platforms/javascript/guides/nextjs/ 4 | 5 | import { init } from '@sentry/nextjs' 6 | 7 | init({ 8 | dsn: 'https://8fb977f0e4774e1fa01ae8d9e596e9d2@o1425922.ingest.sentry.io/6776175', 9 | // Adjust this value in production, or use tracesSampler for greater control 10 | tracesSampleRate: 1.0, 11 | enabled: process.env.NODE_ENV === 'production', 12 | // ... 13 | // Note: if you want to override the automatic release value, do not set a 14 | // `release` value here - use the environment variable `SENTRY_RELEASE`, so 15 | // that it will also get attached to your source maps 16 | }) -------------------------------------------------------------------------------- /sentry.properties: -------------------------------------------------------------------------------- 1 | defaults.url=https://sentry.io/ 2 | defaults.org=questbook 3 | defaults.project=grants-tool 4 | # cli.executable=../path/to/bin/sentry-cli -------------------------------------------------------------------------------- /sentry.server.config.ts: -------------------------------------------------------------------------------- 1 | export {} -------------------------------------------------------------------------------- /src/constants/Networks.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-restricted-syntax */ 2 | 3 | export enum NetworkType { 4 | EVM = 1, 5 | Solana = 2, 6 | TON = 3, 7 | } 8 | 9 | -------------------------------------------------------------------------------- /src/constants/addresses.ts: -------------------------------------------------------------------------------- 1 | import { CHAIN_INFO } from 'src/constants/chains' 2 | import { AddressMap, QBContract } from 'src/types' 3 | 4 | export const WORKSPACE_REGISTRY_ADDRESS = compileAddresses('workspace') 5 | export const APPLICATION_REGISTRY_ADDRESS = compileAddresses('applications') 6 | export const APPLICATION_REVIEW_REGISTRY_ADDRESS = compileAddresses('reviews') 7 | export const GRANT_FACTORY_ADDRESS = compileAddresses('grantFactory') 8 | export const COMMUNICATION_ADDRESS = compileAddresses('communication') 9 | 10 | function compileAddresses(contract: QBContract) { 11 | return Object.values(CHAIN_INFO).reduce( 12 | (acc, chainInfo) => { 13 | acc[chainInfo.id] = chainInfo.qbContracts[contract] 14 | return acc 15 | }, { } as AddressMap 16 | ) 17 | } -------------------------------------------------------------------------------- /src/constants/applicantDetailsList.tsx: -------------------------------------------------------------------------------- 1 | export default [ 2 | { 3 | title: 'Name', 4 | id: 'applicantName', 5 | inputType: 'short-form', 6 | isRequired: true, 7 | }, 8 | { 9 | title: 'Email', 10 | id: 'applicantEmail', 11 | inputType: 'short-form', 12 | isRequired: true, 13 | pii: true 14 | }, 15 | { 16 | title: 'Telegram', 17 | id: 'applicantTelegram', 18 | inputType: 'short-form', 19 | isRequired: false, 20 | }, 21 | { 22 | title: 'Twitter', 23 | id: 'applicantTwitter', 24 | inputType: 'short-form', 25 | isRequired: false, 26 | }, 27 | { 28 | title: 'Wallet Address', 29 | id: 'applicantAddress', 30 | inputType: 'short-form', 31 | isRequired: true 32 | }, 33 | { 34 | title: 'Team Members', 35 | id: 'teamMembers', 36 | inputType: 'long-form', 37 | isRequired: false, 38 | }, 39 | 40 | { 41 | title: 'Title', 42 | id: 'projectName', 43 | inputType: 'short-form', 44 | isRequired: true, 45 | }, 46 | { 47 | title: 'Project Details', 48 | id: 'projectDetails', 49 | inputType: 'long-form', 50 | isRequired: true, 51 | }, 52 | { 53 | title: 'Funding Ask', 54 | id: 'fundingAsk', 55 | inputType: 'long-form', 56 | isRequired: true, 57 | }, 58 | { 59 | title: 'tl,dr', 60 | id: 'tldr', 61 | inputType: 'short-form', 62 | isRequired: false, 63 | } 64 | ] 65 | -------------------------------------------------------------------------------- /src/constants/chains.ts: -------------------------------------------------------------------------------- 1 | import chainInfo from 'src/generated/chainInfo.json' 2 | import SupportedChainId from 'src/generated/SupportedChainId' 3 | import { ChainInfoMap } from 'src/types' 4 | import 'dotenv/config' 5 | 6 | // by default, we show all test nets 7 | export const SHOW_TEST_NETS = process.env.NEXT_PUBLIC_IS_TEST !== 'false' 8 | export const defaultChainId = process.env.NEXT_PUBLIC_IS_TEST === 'true' 9 | ? SupportedChainId.GOERLI_TESTNET 10 | : SupportedChainId.OPTIMISM_MAINNET 11 | export const CHAIN_INFO = chainInfo as ChainInfoMap 12 | export const USD_ASSET = '0x0000000000000000000000000000000000000001' 13 | export const USD_ICON = '/dollar_icon.svg' 14 | export const SOL_ETH_ASSET = '0x0000000000000000000000000000000000000002' 15 | export const USD_DECIMALS = 0 16 | export const SOL_ETH_DECIMALS = 9 17 | 18 | // when SHOW_TEST_NETS = true, we show every chain 19 | // otherwise only use mainnets 20 | export const ALL_SUPPORTED_CHAIN_IDS: SupportedChainId[] = Object.values(CHAIN_INFO) 21 | .map(({ id }) => id) 22 | // Changed this temporarily to show only the testnet for testing 23 | .filter(id => SHOW_TEST_NETS || !CHAIN_INFO[id].isTestNetwork) 24 | 25 | export { SupportedChainId } 26 | -------------------------------------------------------------------------------- /src/constants/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultDAOImagePath": "/images/default_dao.svg", 3 | "defaultDAOImageHash": "QmeNL8mChbLFJvhx3YnLa6mMKGHiXwgxPVRVWnQxW651dR", 4 | "supportLink": "https://discord.gg/a3SkQX6gnW", 5 | "defaultTokenUploadImagePath": "/images/default_token_upload.svg", 6 | "approvalLink": "https://www.notion.so/Why-Approve-Fund-Disbursal-ed6094e1a1c9410689c9321a0f5dbfae", 7 | "defaultRubricMaximumPoints": 5 8 | } -------------------------------------------------------------------------------- /src/constants/safesEndpoints.json: -------------------------------------------------------------------------------- 1 | { 2 | "1": "https://safe-transaction-mainnet.safe.global/api/", 3 | "40": "https://transaction.safe.telos.net/api/", 4 | "100": "https://safe-transaction.xdai.gnosis.io/api/", 5 | "42161": "https://safe-transaction.arbitrum.gnosis.io/api/", 6 | "43114": "https://safe-transaction.avalanche.gnosis.io/api/", 7 | "1313161554": "https://safe-transaction.aurora.gnosis.io/api/", 8 | "56": "https://safe-transaction-bsc.safe.global/api/", 9 | "246": "https://safe-transaction.ewc.gnosis.io/api/", 10 | "10": "https://safe-transaction.optimism.gnosis.io/api/", 11 | "137": "https://safe-transaction.polygon.gnosis.io/api/", 12 | "42220": "https://transaction-service.gnosis-safe-staging.celo-networks-dev.org/api/" 13 | } 14 | -------------------------------------------------------------------------------- /src/constants/safesEndpointsTest.json: -------------------------------------------------------------------------------- 1 | { 2 | "4": "https://safe-transaction.rinkeby.gnosis.io/api/", 3 | "5": "https://safe-transaction.goerli.gnosis.io/api/", 4 | "73799": "https://safe-transaction.volta.gnosis.io/api/" 5 | } 6 | -------------------------------------------------------------------------------- /src/constants/safesSupported.json: -------------------------------------------------------------------------------- 1 | { 2 | "1": "Ethereum Mainnet", 3 | "40": "Telos", 4 | "100": "Gnosis", 5 | "42161": "Arbitrum One", 6 | "43114": "Avalanche C-Chain", 7 | "1313161554": "Aurora Mainnet", 8 | "56": "Binance Smart Chain", 9 | "246": "Energy Web Chain", 10 | "10": "Optimism", 11 | "137": "Polygon Mainnet", 12 | "42220": "Celo Mainnet", 13 | "4": "Rinkeby", 14 | "5": "Goerli", 15 | "73799": "Energy Web Volta", 16 | "1313161555": "Aurora Testnet" 17 | } 18 | -------------------------------------------------------------------------------- /src/constants/seo.tsx: -------------------------------------------------------------------------------- 1 | const seoConfig = { 2 | title: 'Questbook', 3 | titleTemplate: '%s', 4 | description: 5 | 'Discover Opportunities in Web 3.0 and Earn in Crypto', 6 | // siteUrl: 'https://www.questbook.app/', 7 | siteUrl: 'https://beta.questbook.app/', 8 | twitter: { 9 | handle: '@questbookapp', 10 | site: '@questbookapp', 11 | cardType: 'summary_large_image', 12 | title: 'Questbook Grant', 13 | image: 'https://ipfs.io/ipfs/bafkreif2xxm6kfj3n5gksduce26xjyijhkh6qil7e3pj7yuysjaneh624y', 14 | }, 15 | openGraph: { 16 | type: 'website', 17 | locale: 'en_US', 18 | url: 'https://beta.questbook.app/', 19 | title: 'Questbook', 20 | description: 21 | 'Discover Opportunities in Web 3.0 and Earn in Crypto', 22 | // eslint-disable-next-line camelcase 23 | site_name: 'Questbook', 24 | images: [ 25 | { 26 | url: 'https://ipfs.io/ipfs/bafkreif2xxm6kfj3n5gksduce26xjyijhkh6qil7e3pj7yuysjaneh624y', 27 | width: 1240, 28 | height: 480, 29 | alt: 'Questbook Grant', 30 | }, 31 | { 32 | url: 'https://ipfs.io/ipfs/bafkreif2xxm6kfj3n5gksduce26xjyijhkh6qil7e3pj7yuysjaneh624y', 33 | width: 1012, 34 | height: 506, 35 | alt: 'Questbook Grant', 36 | }, 37 | ], 38 | }, 39 | } 40 | 41 | export default seoConfig 42 | -------------------------------------------------------------------------------- /src/contexts/safeContext.tsx: -------------------------------------------------------------------------------- 1 | import { createContext, ReactNode, useContext, useState } from 'react' 2 | import { EthereumMainnet } from '@questbook/supported-safes/lib/chains/ethereum-mainnet' 3 | import { SolanaMainnet } from '@questbook/supported-safes/lib/chains/solana-mainnet' 4 | import { TonKeyMainnet } from '@questbook/supported-safes/lib/chains/tonkey-mainnet' 5 | export const SafeContext = createContext<{safeObj: EthereumMainnet | SolanaMainnet | TonKeyMainnet| undefined, setSafeObj: (safe: EthereumMainnet | SolanaMainnet | TonKeyMainnet | undefined) => void} | null>(null) 6 | 7 | export const useSafeContext = () => useContext(SafeContext) 8 | 9 | export const SafeProvider = ({ children }: {children: ReactNode}) => { 10 | const [safeObj, setSafeObj] = useState() 11 | return ( 12 | 13 | {children} 14 | 15 | ) 16 | } -------------------------------------------------------------------------------- /src/generated/SupportedChainId.ts: -------------------------------------------------------------------------------- 1 | 2 | enum SupportedChainId { 3 | CELO_MAINNET = 42220, 4 | GOERLI_TESTNET = 5, 5 | OPTIMISM_MAINNET = 10, 6 | POLYGON_MAINNET = 137, 7 | } 8 | 9 | export default SupportedChainId -------------------------------------------------------------------------------- /src/generated/contracts/common.ts: -------------------------------------------------------------------------------- 1 | /* Autogenerated file. Do not edit manually. */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | import type { Listener } from "@ethersproject/providers"; 5 | import type { Event, EventFilter } from "ethers"; 6 | 7 | export interface TypedEvent< 8 | TArgsArray extends Array = any, 9 | TArgsObject = any 10 | > extends Event { 11 | args: TArgsArray & TArgsObject; 12 | } 13 | 14 | export interface TypedEventFilter<_TEvent extends TypedEvent> 15 | extends EventFilter {} 16 | 17 | export interface TypedListener { 18 | (...listenerArg: [...__TypechainArgsArray, TEvent]): void; 19 | } 20 | 21 | type __TypechainArgsArray = T extends TypedEvent ? U : never; 22 | 23 | export interface OnEvent { 24 | ( 25 | eventFilter: TypedEventFilter, 26 | listener: TypedListener 27 | ): TRes; 28 | (eventName: string, listener: Listener): TRes; 29 | } 30 | 31 | export type MinEthersFactory = { 32 | deploy(...a: ARGS[]): Promise; 33 | }; 34 | 35 | export type GetContractTypeFromFactory = F extends MinEthersFactory< 36 | infer C, 37 | any 38 | > 39 | ? C 40 | : never; 41 | 42 | export type GetARGsTypeFromFactory = F extends MinEthersFactory 43 | ? Parameters 44 | : never; 45 | 46 | export type PromiseOrValue = T | Promise; 47 | -------------------------------------------------------------------------------- /src/generated/contracts/factories/index.ts: -------------------------------------------------------------------------------- 1 | /* Autogenerated file. Do not edit manually. */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | export { ApplicationRegistryAbi__factory } from "./ApplicationRegistryAbi__factory"; 5 | export { ApplicationReviewRegistryAbi__factory } from "./ApplicationReviewRegistryAbi__factory"; 6 | export { CommunicationAbi__factory } from "./CommunicationAbi__factory"; 7 | export { GrantAbi__factory } from "./GrantAbi__factory"; 8 | export { GrantFactoryAbi__factory } from "./GrantFactoryAbi__factory"; 9 | export { ReviewerGuard__factory } from "./ReviewerGuard__factory"; 10 | export { UtilityRegistryAbi__factory } from "./UtilityRegistryAbi__factory"; 11 | export { WorkspaceRegistryAbi__factory } from "./WorkspaceRegistryAbi__factory"; 12 | -------------------------------------------------------------------------------- /src/generated/contracts/index.ts: -------------------------------------------------------------------------------- 1 | /* Autogenerated file. Do not edit manually. */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | export type { ApplicationRegistryAbi } from "./ApplicationRegistryAbi"; 5 | export type { ApplicationReviewRegistryAbi } from "./ApplicationReviewRegistryAbi"; 6 | export type { CommunicationAbi } from "./CommunicationAbi"; 7 | export type { GrantAbi } from "./GrantAbi"; 8 | export type { GrantFactoryAbi } from "./GrantFactoryAbi"; 9 | export type { ReviewerGuard } from "./ReviewerGuard"; 10 | export type { UtilityRegistryAbi } from "./UtilityRegistryAbi"; 11 | export type { WorkspaceRegistryAbi } from "./WorkspaceRegistryAbi"; 12 | export * as factories from "./factories"; 13 | export { ApplicationRegistryAbi__factory } from "./factories/ApplicationRegistryAbi__factory"; 14 | export { ApplicationReviewRegistryAbi__factory } from "./factories/ApplicationReviewRegistryAbi__factory"; 15 | export { CommunicationAbi__factory } from "./factories/CommunicationAbi__factory"; 16 | export { GrantAbi__factory } from "./factories/GrantAbi__factory"; 17 | export { GrantFactoryAbi__factory } from "./factories/GrantFactoryAbi__factory"; 18 | export { ReviewerGuard__factory } from "./factories/ReviewerGuard__factory"; 19 | export { UtilityRegistryAbi__factory } from "./factories/UtilityRegistryAbi__factory"; 20 | export { WorkspaceRegistryAbi__factory } from "./factories/WorkspaceRegistryAbi__factory"; 21 | -------------------------------------------------------------------------------- /src/generated/mutation/addComment.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const addCommentMutation = gql`mutation addComment($workspace: String!, $grant: String!, $application: String!, $isPrivate: Boolean!, $comment: JSON!, $sender: String!) { 3 | addComment(workspace: $workspace,grant:$grant ,application: $application,isPrivate:$isPrivate,comment:$comment,sender:$sender){ 4 | record{ 5 | _id 6 | } 7 | recordId 8 | } 9 | }` -------------------------------------------------------------------------------- /src/generated/mutation/addComments.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const addBatchCommentsMutation = gql`mutation addComments($workspace: String!, $grant: String!, $application: [String!]!, $isPrivate: Boolean!, $comments: [JSON!]!) { 3 | addComments(workspace: $workspace,grant:$grant ,application: $application,isPrivate:$isPrivate,comments:$comments){ 4 | record{ 5 | _id 6 | } 7 | recordId 8 | } 9 | }` -------------------------------------------------------------------------------- /src/generated/mutation/assignReviewers.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const assignReviewersMutation = gql`mutation assignReviewers($workspaceId: String!,$applicationId: String!,$grantAddress: String!, $reviewers: [String!]!, $active: [Boolean!]!){ 3 | assignReviewers(workspaceId: $workspaceId, applicationId: $applicationId, grantAddress: $grantAddress, reviewers: $reviewers, active: $active){ 4 | recordId 5 | record{ 6 | _id 7 | } 8 | } 9 | } 10 | ` -------------------------------------------------------------------------------- /src/generated/mutation/batchGrantApplicationUpdate.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const batchGrantApplicationUpdateMutation = gql` 3 | mutation batchUpdateGrantApplication($id: [String!]!, $grant: String!, $workspaceId: String!, $applicantId: [String!], $state: [String!]!, $feedback: [JSON!]!){ 4 | batchUpdateGrantApplication(id: $id, grant: $grant, workspaceId: $workspaceId, applicantId: $applicantId, state: $state, feedback: $feedback){ 5 | recordId 6 | record{ 7 | _id 8 | } 9 | } 10 | } 11 | ` -------------------------------------------------------------------------------- /src/generated/mutation/createBuilder.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const createBuilder = gql`mutation createBuilder($telegram: String!, $github: JSON!, $application: String, $email: String!, $twitter: String, $referral: JSON, $newsletter: Boolean) { 3 | createBuilder(telegram: $telegram, github: $github, application: $application, email: $email, twitter: $twitter, referral: $referral, newsletter: $newsletter) { 4 | recordId 5 | record { 6 | _id 7 | } 8 | } 9 | } 10 | ` -------------------------------------------------------------------------------- /src/generated/mutation/createBuilderProfile.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const createBuilderProfile = gql` 3 | mutation createBuilderProfile($telegram: String, $username: String!, $imageURL: String, $address: String!, $bio: String) { 4 | createProfile(telegram: $telegram, username: $username, imageURL: $imageURL, address: $address, bio: $bio) { 5 | recordId 6 | record { 7 | _id 8 | } 9 | } 10 | } 11 | ` -------------------------------------------------------------------------------- /src/generated/mutation/createInviteLink.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const createInviteLinkMutation = gql` 3 | mutation createInviteLink($w: String!, $r: String!, $k: String!, $createdBy: String!){ 4 | createInviteLink(w: $w, r: $r, k: $k, createdBy: $createdBy){ 5 | recordId 6 | record{ 7 | _id 8 | } 9 | } 10 | }` -------------------------------------------------------------------------------- /src/generated/mutation/disburseRewardsFromSafe.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const DisburseRewardSafeMutation = gql` 3 | mutation disburseRewardsFromSafe($applicationIds: [String!]!, $milestoneIds: [String!]!, $asset: String!, $tokenName: String!, $nonEvmAssetAddress: String!, $amounts: [Float!]!, $transactionHash: String!, $sender: String!, $grant: String!, $to: String! 4 | ) { 5 | disburseRewardsFromSafe( 6 | applicationIds: $applicationIds 7 | milestoneIds: $milestoneIds 8 | asset: $asset 9 | tokenName: $tokenName 10 | nonEvmAssetAddress: $nonEvmAssetAddress 11 | amounts: $amounts 12 | transactionHash: $transactionHash 13 | sender: $sender 14 | grant: $grant 15 | to: $to 16 | ){ 17 | record { 18 | _id 19 | } 20 | } 21 | }` -------------------------------------------------------------------------------- /src/generated/mutation/editComment.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const editCommentMutation = gql`mutation editComment($id: String! $isPrivate: Boolean!, $comment: JSON!) { 3 | editComment(id: $id,isPrivate:$isPrivate,comment:$comment){ 4 | record{ 5 | _id 6 | } 7 | recordId 8 | } 9 | }` -------------------------------------------------------------------------------- /src/generated/mutation/generateToken.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const generateTokenMutation = gql` 3 | mutation generateToken($address: String!){ 4 | generateToken(address: $address){ 5 | recordId 6 | record{ 7 | id: _id 8 | nonce 9 | } 10 | } 11 | } 12 | ` -------------------------------------------------------------------------------- /src/generated/mutation/index.ts: -------------------------------------------------------------------------------- 1 | export { DisburseRewardSafeMutation } from './disburseRewardsFromSafe' 2 | export { submitProposalMutation } from './submitProposal' 3 | export { reSubmitProposalMutation } from './reSubmitProposal' 4 | export { updateGrant } from './updateGrant' 5 | export { assignReviewersMutation } from './assignReviewers' 6 | export { submitReviewsMutation } from './submitReviews' 7 | export { setRubricsMutation } from './setRubrics' 8 | export { updateWorkspaceMemberMutation } from './updateWorkspaceMember' 9 | export { createInviteLinkMutation } from './createInviteLink' 10 | export { joinViaInviteLinkMutation } from './joinViaInviteLink' 11 | export { workspaceUpdateSafeMutation } from './workspaceUpdateSafe' 12 | export { generateTokenMutation } from './generateToken' 13 | export { verifyTokenMutation } from './verifyToken' 14 | export { addBatchCommentsMutation } from './addComments' 15 | export { batchGrantApplicationUpdateMutation } from './batchGrantApplicationUpdate' -------------------------------------------------------------------------------- /src/generated/mutation/joinViaInviteLink.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const joinViaInviteLinkMutation = gql`mutation joinViaInviteLink($id: String!, $members: [String!]!, $roles: [Int!]!, $enabled: [Boolean!]!, $metadataHashes: [JSON!]!, $w: String!, $r: String!, $k: String!){ 3 | joinViaInviteLink(id: $id, members: $members, roles: $roles, enabled: $enabled, metadataHashes: $metadataHashes, w: $w, r: $r, k: $k){ 4 | recordId 5 | record{ 6 | _id 7 | } 8 | } 9 | } 10 | ` -------------------------------------------------------------------------------- /src/generated/mutation/reSubmitProposal.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const reSubmitProposalMutation = gql `mutation updateGrantApplication( 3 | $id: String!, 4 | $grant: String!, 5 | $workspaceId: String!, 6 | $milestoneCount: Int, 7 | $milestones: JSON, 8 | $applicantId: String!, 9 | $applicantPublicKey: String, 10 | $fields:JSON 11 | $pii: JSON 12 | $state: String! 13 | $feedback: JSON 14 | ){ 15 | updateGrantApplication( 16 | id: $id, 17 | grant: $grant, 18 | workspaceId: $workspaceId, 19 | milestoneCount: $milestoneCount, 20 | milestones: $milestones, 21 | applicantId: $applicantId, 22 | applicantPublicKey: $applicantPublicKey, 23 | fields:$fields 24 | pii: $pii 25 | state: $state 26 | feedback: $feedback 27 | ){ 28 | record{ 29 | _id 30 | } 31 | recordId 32 | } 33 | }` -------------------------------------------------------------------------------- /src/generated/mutation/reclaimProof.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const reclaimProof = gql`mutation reclaimProof($type: String!, $address: String!, $proposalId: String, $pubKey: String){ 3 | generateProof(type: $type, address: $address, proposalId: $proposalId, pubKey: $pubKey) { 4 | requestUrl 5 | statusUrl 6 | migrationId 7 | } 8 | }` -------------------------------------------------------------------------------- /src/generated/mutation/sendDocuSign.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const sendDocuSign = gql`mutation sendDocuSign($id: String!, $proposalId: String!, $email: [JSON]!, $templateId: String!, $templateName: String!){ 3 | sendDocuSign(id: $id, proposalId: $proposalId, email: $email, templateId: $templateId, templateName: $templateName){ 4 | recordId 5 | record{ 6 | _id 7 | } 8 | } 9 | }` -------------------------------------------------------------------------------- /src/generated/mutation/setRubrics.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const setRubricsMutation = gql`mutation setRubric($workspaceId: String!, $grantId:String!, $metadataHash:JSON!){ 3 | setRubric(workspaceId: $workspaceId, grantId: $grantId, metadataHash: $metadataHash){ 4 | record{ 5 | _id 6 | } 7 | recordId 8 | } 9 | }` -------------------------------------------------------------------------------- /src/generated/mutation/submitProposal.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const submitProposalMutation = gql`mutation createNewGrantApplication( 3 | $grant: String!, 4 | $workspaceId: String!, 5 | $milestoneCount: Int!, 6 | $milestones: JSON!, 7 | $applicantId: String!, 8 | $applicantPublicKey: String!, 9 | $fields:JSON! 10 | $pii: JSON 11 | ){ 12 | createNewGrantApplication( 13 | grant: $grant, 14 | workspaceId: $workspaceId, 15 | milestoneCount: $milestoneCount, 16 | milestones: $milestones, 17 | applicantId: $applicantId, 18 | applicantPublicKey: $applicantPublicKey, 19 | fields:$fields 20 | pii: $pii 21 | ){ 22 | record{ 23 | _id 24 | } 25 | recordId 26 | } 27 | }` -------------------------------------------------------------------------------- /src/generated/mutation/submitReviews.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const submitReviewsMutation = gql`mutation submitReviews($workspaceId: String!,$applicationId: String!,$grantAddress: String!, $metadata: JSON!, $reviewerAddress: String!){ 3 | submitReviews(workspaceId: $workspaceId, applicationId: $applicationId, grantAddress: $grantAddress, metadata: $metadata, reviewerAddress: $reviewerAddress){ 4 | recordId 5 | record{ 6 | _id 7 | } 8 | } 9 | }` -------------------------------------------------------------------------------- /src/generated/mutation/updateBuilderProfile.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const updateBuilderProfile = gql` 3 | mutation updateBuilderProfile($telegram: String, $imageURL: String, $address: String!, $bio: String) { 4 | updateProfile(telegram: $telegram, imageURL: $imageURL, address: $address, bio: $bio) { 5 | recordId 6 | record { 7 | _id 8 | } 9 | } 10 | } 11 | ` -------------------------------------------------------------------------------- /src/generated/mutation/updateGrant.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client'; 2 | 3 | export const updateGrant = gql` 4 | mutation updateGrant( 5 | $id: String!, 6 | $ownerId: String!, 7 | $title: String!, 8 | $bio: String!, 9 | $about: String!, 10 | $rewardCommitted: String!, 11 | $payoutType: String!, 12 | $link: String, 13 | $reviewType: String!, 14 | $fields: JSON! 15 | $milestones: [String] 16 | $workspace: String!, 17 | $rubrics: JSON 18 | ) { 19 | updateGrant( 20 | id: $id, 21 | ownerId: $ownerId, 22 | title: $title, 23 | bio: $bio, 24 | about: $about, 25 | rewardCommitted: $rewardCommitted, 26 | payoutType: $payoutType, 27 | link: $link, 28 | reviewType: $reviewType, 29 | fields: $fields 30 | milestones: $milestones 31 | workspace: $workspace, 32 | rubrics: $rubrics 33 | ) { 34 | recordId 35 | record { 36 | _id 37 | } 38 | } 39 | } 40 | `; 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/generated/mutation/updateMetadataWorkspace.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const updateMetadataWorkspaceMutation = gql`mutation updateWorkspaceMetadata($id: String!, $metadata: JSON!){ 3 | updateWorkspaceMetadata(id: $id, metadata: $metadata){ 4 | recordId 5 | record{ 6 | _id 7 | } 8 | } 9 | }` -------------------------------------------------------------------------------- /src/generated/mutation/updateWorkspaceMember.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const updateWorkspaceMemberMutation = gql` 3 | mutation updateWorkspaceMember($id: String!, $members: [String!]!, $roles: [Int!]!, $enabled: [Boolean!]!, $metadataHashes: [JSON!]!){ 4 | updateWorkspaceMember(id: $id, members: $members, roles: $roles, enabled: $enabled, metadataHashes: $metadataHashes){ 5 | recordId 6 | record{ 7 | _id 8 | } 9 | } 10 | } 11 | ` -------------------------------------------------------------------------------- /src/generated/mutation/verifyToken.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const verifyTokenMutation = gql` 3 | mutation verifyToken($id: String!, $sign: String!){ 4 | verifyToken(id: $id, sign: $sign){ 5 | accessToken 6 | } 7 | } 8 | ` -------------------------------------------------------------------------------- /src/generated/mutation/workspaceUpdateSafe.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const workspaceUpdateSafeMutation = gql` 3 | mutation workspaceSafeUpdate($id: String!, $longSafeAddress: String!, $safeChainId: String!){ 4 | workspaceSafeUpdate(id: $id, longSafeAddress: $longSafeAddress, safeChainId: $safeChainId){ 5 | recordId 6 | record{ 7 | _id 8 | } 9 | } 10 | } 11 | ` -------------------------------------------------------------------------------- /src/global.d.ts: -------------------------------------------------------------------------------- 1 | declare module '@biconomy/mexa'; 2 | 3 | declare module '*.yaml' { 4 | const src: JSON 5 | export default src 6 | } -------------------------------------------------------------------------------- /src/graphql/apollo.tsx: -------------------------------------------------------------------------------- 1 | import { ApolloClient, DocumentNode, InMemoryCache } from '@apollo/client' 2 | import logger from 'src/libraries/logger' 3 | 4 | 5 | export const ENDPOINT_CLIENT = process.env.BACKEND_URL 6 | 7 | export const client = new ApolloClient({ 8 | uri: ENDPOINT_CLIENT, 9 | cache: new InMemoryCache(), 10 | queryDeduplication: true, 11 | defaultOptions: { 12 | watchQuery: { 13 | fetchPolicy: 'network-only', 14 | }, 15 | query: { 16 | fetchPolicy: 'network-only', 17 | errorPolicy: 'all', 18 | }, 19 | }, 20 | }) 21 | 22 | 23 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 24 | export async function executeMutation(mutation: DocumentNode, variables: any) { 25 | try { 26 | const response = await client.mutate({ 27 | mutation, 28 | variables, 29 | context: { 30 | headers: { 31 | Authorization: `Bearer ${localStorage.getItem('authToken')}`, 32 | 'Content-Type': 'application/json', 33 | }, 34 | }, 35 | }) 36 | const { data, errors } = response 37 | 38 | logger.info({ data, errors }, 'executeMutation') 39 | return data 40 | } catch(e) { 41 | logger.warn(e) 42 | } 43 | } 44 | 45 | export default client 46 | 47 | -------------------------------------------------------------------------------- /src/graphql/subgraph.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | ApolloClient, 3 | HttpLink, InMemoryCache, 4 | } from '@apollo/client' 5 | import { CHAIN_INFO } from 'src/constants/chains' 6 | import { SupportedChainId } from 'src/constants/chains' 7 | import { GetLatestBlockDocument } from 'src/generated/graphql' 8 | import { delay } from 'src/libraries/utils' 9 | 10 | class SubgraphClient { 11 | client: ApolloClient<{ }> 12 | 13 | constructor(chainId: SupportedChainId) { 14 | const link = new HttpLink({ uri: CHAIN_INFO[chainId].subgraphClientUrl }) 15 | const client = new ApolloClient({ 16 | link, 17 | cache: new InMemoryCache(), 18 | }) 19 | this.client = client 20 | this.waitForBlock = this.waitForBlock.bind(this) 21 | } 22 | 23 | async waitForBlock(blockNumber: number) { 24 | let latestBlockNumber = 0 25 | do { 26 | // Schedule a promise that will be ready once 27 | // the next Ethereum block will likely be available. 28 | const response = await this.client.query({ 29 | query: GetLatestBlockDocument, 30 | fetchPolicy: 'network-only', 31 | }) 32 | // eslint-disable-next-line no-underscore-dangle 33 | latestBlockNumber = response.data._meta.block.number 34 | 35 | // waiting for 4 seconds to fetch next block(s) 36 | await delay(4000) 37 | } while(latestBlockNumber < blockNumber) 38 | } 39 | } 40 | 41 | export default SubgraphClient 42 | -------------------------------------------------------------------------------- /src/libraries/data/getAdminPublicKeysQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | 3 | export const getAdminPublicKeysQuery = gql`query getAdminPublicKeys($workspaceId: String!) { 4 | workspace(_id: $workspaceId) { 5 | members:membersFilter(filter: {_operators: {accessLevel: { 6 | ne:"reviewer" 7 | }}, enabled: true}) { 8 | id:_id 9 | actorId 10 | fullName 11 | publicKey 12 | } 13 | } 14 | }` -------------------------------------------------------------------------------- /src/libraries/data/getBuilderProfileQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getBuilderProfileQuery = gql`query getBuilderInfo($wallet: String!){ 3 | getProfile(filter:{ 4 | address:$wallet 5 | }) { 6 | _id 7 | telegram 8 | username 9 | imageURL 10 | address 11 | } 12 | }` -------------------------------------------------------------------------------- /src/libraries/data/getGrantManagersWithPublicKeyQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getGrantManagersWithPublicKeyQuery = gql`query getGrantManagersWithPublicKey($grantID: String!) { 3 | grantManagers(filter: {grant: $grantID}) { 4 | member { 5 | actorId, 6 | publicKey, 7 | enabled 8 | } 9 | } 10 | }` -------------------------------------------------------------------------------- /src/libraries/data/getMemberPublicKeysQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getMemberPublicKeysQuery = gql`query getMemberPublicKeys($workspaceId: String!, $applicationIds: [String!]!) { 3 | workspace(_id: $workspaceId) { 4 | members: membersFilter(filter: { 5 | _operators:{ 6 | accessLevel: { 7 | ne:"reviewer" 8 | } 9 | } 10 | enabled: false 11 | }) { 12 | actorId 13 | publicKey 14 | } 15 | } 16 | grantApplications(filter: { 17 | _operators:{ 18 | _id: { 19 | in: $applicationIds 20 | } 21 | } 22 | }) { 23 | id:_id 24 | applicantId 25 | applicantPublicKey 26 | applicationReviewers { 27 | member(filter: { 28 | enabled: true 29 | }) { 30 | actorId 31 | publicKey 32 | } 33 | } 34 | } 35 | } 36 | ` -------------------------------------------------------------------------------- /src/libraries/data/getQBAdminsQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getQBAdminsQuery = gql`query getQBAdmins { 3 | qbAdmins { 4 | walletAddress 5 | } 6 | } 7 | ` -------------------------------------------------------------------------------- /src/libraries/data/getWorkspaceMemberExistsQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getWorkspaceMemberExistsQuery = gql`query getWorkspaceMemberExists($id: String!) { 3 | workspaceMember(_id: $id) { 4 | id:_id 5 | } 6 | }` -------------------------------------------------------------------------------- /src/libraries/data/getWorkspaceMembersPublicKeysQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getWorkspaceMembersPublicKeysQuery = gql`query getWorkspaceMembersPublicKeys($workspaceId: String!) { 3 | workspaceMembers(filter: { workspace: $workspaceId, enabled: true }) { 4 | actorId 5 | publicKey 6 | } 7 | }` -------------------------------------------------------------------------------- /src/libraries/data/getWorkspaceMembersQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getWorkspaceMembersQuery = gql`query getWorkspaceMembers($actorId: String!) { 3 | workspaceMembers( 4 | filter: { actorId: $actorId, enabled: true } 5 | sort: ADDEDAT_DESC 6 | ) { 7 | id:_id 8 | actorId 9 | enabled 10 | workspace { 11 | id:_id 12 | ownerId 13 | logoIpfsHash 14 | title 15 | supportedNetworks 16 | safe { 17 | id:_id 18 | chainId 19 | address 20 | } 21 | tokens { 22 | address 23 | label 24 | decimal 25 | iconHash 26 | } 27 | safe { 28 | address 29 | chainId 30 | } 31 | members: membersFilter(filter: { enabled: true }) { 32 | id:_id 33 | actorId 34 | publicKey 35 | fullName 36 | email 37 | accessLevel 38 | outstandingReviewIds 39 | lastReviewSubmittedAt 40 | profilePictureIpfsHash 41 | pii { 42 | id:_id 43 | data 44 | } 45 | } 46 | } 47 | } 48 | } 49 | ` -------------------------------------------------------------------------------- /src/libraries/graphql/getAdminPublicKeys.graphql: -------------------------------------------------------------------------------- 1 | query getAdminPublicKeys($workspaceId: String!) { 2 | workspace(_id: $workspaceId) { 3 | members:membersFilter(filter: {_operators: {accessLevel: { 4 | ne:"reviewer" 5 | }}, enabled: true}) { 6 | id:_id 7 | actorId 8 | fullName 9 | publicKey 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/libraries/graphql/getBuilderProfile.graphql: -------------------------------------------------------------------------------- 1 | query getBuilderInfo($wallet: String!){ 2 | getProfile(filter:{ 3 | address:$wallet 4 | }) { 5 | _id 6 | telegram 7 | username 8 | imageURL 9 | } 10 | } -------------------------------------------------------------------------------- /src/libraries/graphql/getGrantManagersWithPublicKey.graphql: -------------------------------------------------------------------------------- 1 | query getGrantManagersWithPublicKey($grantID: String!) { 2 | grantManagers(filter: {grant: $grantID}) { 3 | member { 4 | actorId, 5 | publicKey, 6 | enabled 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /src/libraries/graphql/getLatestBlock.graphql: -------------------------------------------------------------------------------- 1 | query getLatestBlock { 2 | _meta { 3 | block { 4 | number 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /src/libraries/graphql/getMemberPublicKeys.graphql: -------------------------------------------------------------------------------- 1 | query getMemberPublicKeys($workspaceId: String!, $applicationIds: [String!]!) { 2 | workspace(_id: $workspaceId) { 3 | members: membersFilter(filter: { 4 | _operators:{ 5 | accessLevel: { 6 | ne:"reviewer" 7 | } 8 | } 9 | enabled: false 10 | }) { 11 | actorId 12 | publicKey 13 | } 14 | } 15 | grantApplications(filter: { 16 | _operators:{ 17 | _id: { 18 | in: $applicationIds 19 | } 20 | } 21 | }) { 22 | id:_id 23 | applicantId 24 | applicantPublicKey 25 | applicationReviewers { 26 | member(filter: { 27 | enabled: true 28 | }) { 29 | actorId 30 | publicKey 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/libraries/graphql/getQBAdmins.graphql: -------------------------------------------------------------------------------- 1 | query getQBAdmins { 2 | qbAdmins { 3 | walletAddress 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/libraries/graphql/getWorkspaceMemberExists.graphql: -------------------------------------------------------------------------------- 1 | query getWorkspaceMemberExists($id: String!) { 2 | workspaceMember(_id: $id) { 3 | id:_id 4 | } 5 | } -------------------------------------------------------------------------------- /src/libraries/graphql/getWorkspaceMembers.graphql: -------------------------------------------------------------------------------- 1 | query getWorkspaceMembers($actorId: String!) { 2 | workspaceMembers( 3 | filter: { actorId: $actorId, enabled: true } 4 | sort: ADDEDAT_DESC 5 | ) { 6 | id:_id 7 | actorId 8 | enabled 9 | workspace { 10 | id:_id 11 | ownerId 12 | logoIpfsHash 13 | title 14 | supportedNetworks 15 | safe { 16 | id:_id 17 | chainId 18 | address 19 | } 20 | tokens { 21 | address 22 | label 23 | decimal 24 | iconHash 25 | } 26 | safe { 27 | address 28 | chainId 29 | } 30 | members: membersFilter(filter: { enabled: true }) { 31 | id:_id 32 | actorId 33 | publicKey 34 | fullName 35 | email 36 | accessLevel 37 | outstandingReviewIds 38 | lastReviewSubmittedAt 39 | profilePictureIpfsHash 40 | pii { 41 | id:_id 42 | data 43 | } 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/libraries/graphql/getWorkspaceMembersPublicKeys.graphql: -------------------------------------------------------------------------------- 1 | query getWorkspaceMembersPublicKeys($workspaceId: String!) { 2 | workspaceMembers(filter: { workspace: $workspaceId, enabled: true }) { 3 | actorId 4 | publicKey 5 | } 6 | } -------------------------------------------------------------------------------- /src/libraries/hooks/DAOSearchContext.ts: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | import { ContextGenerator } from 'src/libraries/utils/contextGenerator' 3 | 4 | const useDaoSearch = () => { 5 | const [searchString, setSearchString] = useState() 6 | 7 | return { 8 | searchString, 9 | setSearchString, 10 | } 11 | } 12 | 13 | export const { 14 | context: DAOSearchContext, 15 | contextMaker: DAOSearchContextMaker, 16 | } = ContextGenerator(useDaoSearch) 17 | -------------------------------------------------------------------------------- /src/libraries/hooks/QBAdminsContext.ts: -------------------------------------------------------------------------------- 1 | import { useContext, useMemo } from 'react' 2 | import { defaultChainId } from 'src/constants/chains' 3 | import { useGetQbAdminsQuery } from 'src/generated/graphql' 4 | import { ContextGenerator } from 'src/libraries/utils/contextGenerator' 5 | import { ApiClientsContext, WebwalletContext } from 'src/pages/_app' 6 | 7 | const useGetQBAdmins = () => { 8 | const { subgraphClients } = useContext(ApiClientsContext)! 9 | const { webwallet, scwAddress } = useContext(WebwalletContext)! 10 | 11 | const { client } = subgraphClients[defaultChainId] 12 | const { data: adminData, loading, error } = useGetQbAdminsQuery({ client }) 13 | 14 | const isQbAdmin = useMemo(() => { 15 | const scwLower = scwAddress?.toLowerCase() 16 | const webwalletLower = webwallet?.address?.toLowerCase() 17 | 18 | return !!adminData?.qbadmins.find(admin => { 19 | const adminLower = admin.walletAddress.toLowerCase() 20 | return adminLower === scwLower || adminLower === webwalletLower 21 | }) 22 | }, [adminData, scwAddress, webwallet]) 23 | 24 | return { 25 | isQbAdmin, 26 | loading, 27 | error, 28 | qbAdmins: adminData?.qbadmins.map((admin) => admin.walletAddress) || [], 29 | } 30 | } 31 | 32 | export const { 33 | context: QBAdminsContext, 34 | contextMaker: QBAdminsContextMaker, 35 | } = ContextGenerator(useGetQBAdmins) 36 | -------------------------------------------------------------------------------- /src/libraries/hooks/gasless/useBiconomy.ts: -------------------------------------------------------------------------------- 1 | import { useContext, useEffect } from 'react' 2 | import logger from 'src/libraries/utils/logger' 3 | import { BiconomyContext, WebwalletContext } from 'src/pages/_app' 4 | 5 | export const useBiconomy = (props: { chainId?: string }) => { 6 | const { webwallet, scwAddress, nonce } = useContext(WebwalletContext)! 7 | const { biconomyDaoObjs, biconomyWalletClients, loadingBiconomyMap, initiateBiconomy } = useContext(BiconomyContext)! 8 | 9 | useEffect(() => { 10 | if(typeof window === 'undefined') { 11 | return 12 | } 13 | 14 | const chainId = props.chainId 15 | 16 | if(!webwallet || !nonce || !chainId) { 17 | return 18 | } 19 | 20 | initiateBiconomy(chainId) 21 | }, [initiateBiconomy, props.chainId, nonce]) 22 | 23 | useEffect(() => { 24 | logger.info({ biconomyWalletClients, isPresent: biconomyWalletClients?.[props.chainId!], chainId: props.chainId, isPresentInt: biconomyWalletClients?.[parseInt(props.chainId!)] }, 'Biconomy Wallet Client') 25 | }, [biconomyWalletClients]) 26 | 27 | return { 28 | biconomyDaoObj: (!!biconomyDaoObjs && props.chainId) ? biconomyDaoObjs[props.chainId] : undefined, 29 | biconomyWalletClient: (!!biconomyWalletClients && props.chainId) ? biconomyWalletClients[props.chainId] : undefined, 30 | scwAddress: scwAddress, 31 | loading: !!loadingBiconomyMap[props.chainId!], 32 | } 33 | } -------------------------------------------------------------------------------- /src/libraries/hooks/gasless/useNetwork.ts: -------------------------------------------------------------------------------- 1 | 2 | import { useContext, useMemo } from 'react' 3 | import { CHAIN_INFO, defaultChainId } from 'src/constants/chains' 4 | import { WebwalletContext } from 'src/pages/_app' 5 | 6 | export const useNetwork = () => { 7 | const { network, switchNetwork } = useContext(WebwalletContext)! 8 | 9 | const data = useMemo(() => { 10 | if(network && network in CHAIN_INFO) { 11 | return CHAIN_INFO[network] 12 | } 13 | 14 | return CHAIN_INFO[defaultChainId] 15 | }, [network]) 16 | 17 | return { activeChain: network, network, switchNetwork, data } 18 | } 19 | -------------------------------------------------------------------------------- /src/libraries/hooks/gasless/useQuestbookAccount.ts: -------------------------------------------------------------------------------- 1 | import { useContext, useMemo } from 'react' 2 | import { WebwalletContext } from 'src/pages/_app' 3 | 4 | export const useQuestbookAccount = () => { 5 | const { webwallet, scwAddress, setNonce, nonce } = useContext(WebwalletContext)! 6 | 7 | // const [gaslessData, setGaslessData] = useState() 8 | const gaslessData2 = useMemo(() => { 9 | if(scwAddress && nonce && webwallet) { 10 | return { 11 | address: scwAddress, 12 | connector: { 13 | name: 'gasless-webwallet' 14 | } 15 | } 16 | } 17 | 18 | return undefined 19 | }, [webwallet, scwAddress, nonce]) 20 | 21 | return { data: gaslessData2, nonce, setNonce } 22 | } -------------------------------------------------------------------------------- /src/libraries/hooks/useQuery.ts: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | import { DocumentNode } from '@apollo/client' 3 | import { logger } from 'ethers' 4 | import client from 'src/graphql/apollo' 5 | 6 | type UseQueryOptions = { 7 | query: DocumentNode 8 | }; 9 | 10 | 11 | type QueryResult = T | undefined; 12 | export function useQuery({ query }: UseQueryOptions) { 13 | const [results, setResults] = useState>(undefined) 14 | 15 | async function fetchMore(variables?: Partial, reset?: boolean, retries = 2): Promise { 16 | if(reset) { 17 | setResults(undefined) 18 | } 19 | 20 | try { 21 | const { data, error } = await client.query({ 22 | query, 23 | variables, 24 | }) 25 | 26 | if(data) { 27 | setResults(data) 28 | } 29 | 30 | if(error) { 31 | logger.warn(error) 32 | if(retries > 0) { 33 | await fetchMore(variables, reset, retries - 1) 34 | logger.info(`Retrying... Attempts left: ${retries}`) 35 | } 36 | } 37 | 38 | return data 39 | } catch(error) { 40 | if(error && retries > 0) { 41 | logger.info(`Encountered 503 error. Retrying... Attempts left: ${retries}`) 42 | return await fetchMore(variables, reset, retries - 2) 43 | } else { 44 | logger.warn('Retries exhausted or different error encountered.') 45 | return undefined 46 | } 47 | } 48 | } 49 | 50 | return { 51 | results, 52 | fetchMore, 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/libraries/hooks/utils/useChainId.ts: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react' 2 | import { useNetwork } from 'src/libraries/hooks/gasless/useNetwork' 3 | 4 | /** 5 | * Return the chain ID if supported by the app, otherwise return undefined 6 | * @returns the chain ID if supported -- undefined otherwise 7 | */ 8 | export default function useChainId() { 9 | // @TODO-gasless: Change here! 10 | const { data } = useNetwork() 11 | const id = useMemo(() => data.id, [data]) 12 | return id 13 | } 14 | -------------------------------------------------------------------------------- /src/libraries/logger.ts: -------------------------------------------------------------------------------- 1 | import P from 'pino' 2 | 3 | const logger = P() 4 | 5 | const defaultLogLevel = process.env.NODE_ENV === 'production' ? 'silent' : 'debug' 6 | const logLevel = process.env.LOG_LEVEL || defaultLogLevel 7 | logger.level = logLevel 8 | 9 | export default logger -------------------------------------------------------------------------------- /src/libraries/ui/BackButton.tsx: -------------------------------------------------------------------------------- 1 | import { Button, ButtonProps, Text } from '@chakra-ui/react' 2 | import { useRouter } from 'next/router' 3 | import { ArrowLeft } from 'src/generated/icons' 4 | 5 | function BackButton(props: ButtonProps) { 6 | const buildComponent = () => { 7 | return ( 8 | 22 | ) 23 | } 24 | 25 | const router = useRouter() 26 | return buildComponent() 27 | } 28 | 29 | export default BackButton -------------------------------------------------------------------------------- /src/libraries/ui/CopyIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Tooltip } from '@chakra-ui/react' 3 | import copy from 'copy-to-clipboard' 4 | import { Copy } from 'src/generated/icons' 5 | 6 | type Props = { 7 | text: string 8 | } 9 | 10 | function CopyIcon({ text }: Props) { 11 | const defaultTooltip = 'Copy' 12 | const copiedTooltip = 'Copied' 13 | 14 | const [tooltipLabel, setTooltipLabel] = React.useState(defaultTooltip) 15 | 16 | return ( 17 | 18 | { 25 | copy(text) 26 | setTooltipLabel(copiedTooltip) 27 | } 28 | } /> 29 | 30 | 31 | ) 32 | } 33 | 34 | export default CopyIcon 35 | -------------------------------------------------------------------------------- /src/libraries/ui/NavBar/_components/IssueWarning.tsx: -------------------------------------------------------------------------------- 1 | import { FaExclamationCircle } from 'react-icons/fa' 2 | import { Flex, Icon, Text } from '@chakra-ui/react' 3 | 4 | const IssueWarning = () => { 5 | return ( 6 | 14 | 19 | 25 | Due to the ongoing issue with our subgraph node, we have temporarily disabled proposal submissions. Our team is actively working on resolving the problem. We apologize for any inconvenience. 26 | 27 | 28 | ) 29 | } 30 | 31 | export default IssueWarning -------------------------------------------------------------------------------- /src/libraries/ui/NavBar/_components/googleRecoveryTypes.ts: -------------------------------------------------------------------------------- 1 | interface GoogleRecoveryMechanismOptions { 2 | // Basic options 3 | googleClientId: string 4 | folderNameGD: string 5 | fileNameGD: string 6 | 7 | // Options handling multi key case. 8 | // TODO add more options maybe? 9 | allowMultiKeys: boolean 10 | handleExistingKey: 'Error' | 'Overwrite' 11 | } 12 | 13 | export interface Metadata { 14 | name: string 15 | parents: string[] 16 | mimeType: string 17 | } 18 | 19 | export type { GoogleRecoveryMechanismOptions } -------------------------------------------------------------------------------- /src/libraries/ui/NavBar/_utils/constants.ts: -------------------------------------------------------------------------------- 1 | const DOMAIN_CACHE_KEY = 'current-domain' 2 | const ROLE_CACHE = 'role' 3 | 4 | export { DOMAIN_CACHE_KEY, ROLE_CACHE } -------------------------------------------------------------------------------- /src/libraries/ui/QRCodeModal.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import QRCode from 'react-qr-code' 3 | import { Box, Flex, Modal, ModalCloseButton, ModalContent, ModalOverlay, Text } from '@chakra-ui/react' 4 | import { NotificationContext } from 'src/pages/_app' 5 | 6 | function QRCodeModal() { 7 | const buildComponent = () => { 8 | return ( 9 | { 15 | setQrCodeText(undefined) 16 | } 17 | }> 18 | 19 | 20 | 21 | 26 | 29 | Scan QR code with your phone camera 30 | 31 | 32 | 36 | 37 | 38 | 39 | ) 40 | } 41 | 42 | const { qrCodeText, setQrCodeText } = useContext(NotificationContext)! 43 | 44 | return buildComponent() 45 | } 46 | 47 | export default QRCodeModal -------------------------------------------------------------------------------- /src/libraries/ui/RichTextEditor/loader.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Center, CircularProgress } from '@chakra-ui/react' 3 | 4 | interface Props { 5 | size?: string | number 6 | mt?: string | number 7 | } 8 | 9 | function Loader({ size, mt }: Props) { 10 | return ( 11 |
12 | 17 |
18 | ) 19 | } 20 | 21 | Loader.defaultProps = { 22 | size: '32px', 23 | mt: 0, 24 | } 25 | 26 | export default Loader -------------------------------------------------------------------------------- /src/libraries/ui/SearchField.tsx: -------------------------------------------------------------------------------- 1 | import { Input, InputGroup, InputGroupProps, InputLeftElement, InputProps } from '@chakra-ui/react' 2 | import { Search } from 'src/generated/icons' 3 | 4 | function SearchField(props: InputProps & {inputGroupProps?: InputGroupProps}) { 5 | const buildComponent = () => { 6 | return ( 7 | 8 | 11 | 14 | 15 | 16 | 17 | ) 18 | } 19 | 20 | return buildComponent() 21 | } 22 | 23 | export default SearchField -------------------------------------------------------------------------------- /src/libraries/utils/amplitude.tsx: -------------------------------------------------------------------------------- 1 | import { createContext, useEffect, useState } from 'react' 2 | import { init, track } from '@amplitude/analytics-browser' 3 | 4 | const AMPLITUDE_API_KEY = process.env.AMPLITUDE_API_KEY! 5 | 6 | const AmplitudeContext = createContext<{ 7 | trackAmplitudeEvent: (eventName: string, eventProperties: object) => void 8 | }>({ 9 | trackAmplitudeEvent: () => {}, 10 | }) 11 | 12 | const AmplitudeProvider = ({ children }: { children: React.ReactNode }) => { 13 | const [initialized, setInitialized] = useState(false) 14 | 15 | useEffect(() => { 16 | if(!initialized) { 17 | init(AMPLITUDE_API_KEY, undefined, { 18 | defaultTracking: { 19 | sessions: true, 20 | attribution: true, 21 | pageViews: true, 22 | formInteractions: true, 23 | }, 24 | }) 25 | setInitialized(true) 26 | } 27 | }, [initialized]) 28 | 29 | const trackAmplitudeEvent = (eventName: string, eventProperties: object) => { 30 | track(eventName, eventProperties) 31 | } 32 | 33 | return ( 34 | 35 | {children} 36 | 37 | ) 38 | } 39 | 40 | export { 41 | AmplitudeProvider, 42 | AmplitudeContext, 43 | } -------------------------------------------------------------------------------- /src/libraries/utils/authToken.ts: -------------------------------------------------------------------------------- 1 | import { logger } from 'ethers' 2 | import { generateTokenMutation, verifyTokenMutation } from 'src/generated/mutation' 3 | import { executeMutation } from 'src/graphql/apollo' 4 | 5 | export const generateToken = async(address: string) => { 6 | const generate = await executeMutation(generateTokenMutation, { address }) 7 | logger.info(generate.generateToken.record, 'generateToken') 8 | if(!generate?.generateToken?.record) { 9 | throw new Error('Unable to generate token') 10 | } 11 | 12 | 13 | return generate.generateToken.record 14 | } 15 | 16 | export const verifyToken = async(id: string, sign: string) => { 17 | const verify = await executeMutation(verifyTokenMutation, { id, sign }) 18 | if(!verify?.verifyToken?.accessToken) { 19 | throw new Error('Unable to verify token') 20 | } 21 | 22 | return verify.verifyToken.accessToken 23 | } -------------------------------------------------------------------------------- /src/libraries/utils/constants.tsx: -------------------------------------------------------------------------------- 1 | import { Metamask, Openmask, Phantom, WalletConnect } from 'src/generated/icons' 2 | 3 | export const MONTH_MAP: {[key: string]: string} = { 4 | '01': 'Jan', 5 | '02': 'Feb', 6 | '03': 'Mar', 7 | '04': 'Apr', 8 | '05': 'May', 9 | '06': 'Jun', 10 | '07': 'Jul', 11 | '08': 'Aug', 12 | '09': 'Sep', 13 | '10': 'Oct', 14 | '11': 'Nov', 15 | '12': 'Dec', 16 | } 17 | 18 | export const chainNames = new Map([ 19 | ['1', 'Ethereum Mainnet'], 20 | ['5', 'Goerli Testnet'], 21 | ['10', 'Optimism Mainnet'], 22 | ['40', 'Telos Mainnet'], 23 | ['137', 'Polygon Mainnet'], 24 | ['42220', 'Celo Mainnet'], 25 | ['9001', 'Solana'], 26 | ['90001', 'Solana'], 27 | ['900001', 'Solana'], 28 | ]) 29 | 30 | export const availableWallets = [{ 31 | name: 'Metamask', 32 | icon: , 35 | isPopular: true, 36 | id: 'injected', 37 | }, { 38 | name: 'WalletConnect', 39 | icon: , 42 | isPopular: false, 43 | id: 'walletConnect' 44 | }] 45 | 46 | export const solanaWallets = [{ 47 | name: 'Phantom', 48 | icon: , 51 | isPopular: false, 52 | id: 'phantom', 53 | }] 54 | export const tonWallets = [{ 55 | name: 'OpenMask', 56 | icon: , 59 | ispopular:false, 60 | id:'openMask' 61 | }] -------------------------------------------------------------------------------- /src/libraries/utils/contextGenerator.ts: -------------------------------------------------------------------------------- 1 | import { createContext, createElement, ReactNode } from 'react' 2 | 3 | /** 4 | * Makes a context for a store and a component to provide the store 5 | */ 6 | export function ContextGenerator(store: () => T) { 7 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 8 | const context = createContext(undefined as any) 9 | return { 10 | context, 11 | contextMaker: ({ children }: {children: ReactNode}) => { 12 | const value = store() 13 | return createElement(context.Provider, { value }, children) 14 | }, 15 | } 16 | } -------------------------------------------------------------------------------- /src/libraries/utils/getSCWAddress.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from 'ethers' 2 | import ABI from 'src/contracts/abi/WalletAbi.json' 3 | 4 | export const getSCWAddress = async(address: string) => { 5 | try { 6 | const scw = '0x050bca32264195976Fe00BcA566B548413A9E658' 7 | const fetchAddress = async(provider: string, address: string) => { 8 | const providerConfig = new ethers.providers.AlchemyProvider(provider, 'YKJ826SHB7c7rV5dDzcubjX8LzYRVdvn') 9 | const scwContract = new ethers.Contract(scw, ABI, providerConfig) 10 | const result = await scwContract.getAddressForCounterfactualWallet(address, 0) 11 | const check = await scwContract.isWalletExist(result) 12 | return check ? result : false 13 | } 14 | 15 | const optimismAddress = await fetchAddress('optimism', address) 16 | return { doesWalletExist: !!optimismAddress, walletAddress: optimismAddress ? optimismAddress : address } 17 | } catch(e) { 18 | throw new Error(`Error fetching address: ${e}`) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/libraries/utils/index.ts: -------------------------------------------------------------------------------- 1 | export const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)) 2 | 3 | export function getAvatar(initials: boolean, address: string | null | undefined) { 4 | let url = '' 5 | if(!address) { 6 | url = '/v2/images/default_profile_picture.png' 7 | // } else if(initials) { 8 | // address = address.toLowerCase() 9 | // // violet 2, teal 2, orange 2, crimson 2, pink 2 10 | // const colors = ['785EF0', '10AEBA', 'FF7545', 'FF4C4D', 'E281BF'] 11 | // const colorId = address ? address.charCodeAt(0) % 5 : Math.floor(Math.random() * 5) 12 | // const color = colors[colorId] 13 | // url = `https://api.dicebear.com/7.x/identicon/svg?seed=${address}&fontSize=32&backgroundColor=%23${color}` 14 | } else { 15 | address = address.toLowerCase() 16 | url = `https://api.dicebear.com/7.x/identicon/svg?seed=${address}` 17 | } 18 | 19 | return url 20 | 21 | } -------------------------------------------------------------------------------- /src/libraries/utils/logger.ts: -------------------------------------------------------------------------------- 1 | import P from 'pino' 2 | 3 | const logger = P() 4 | 5 | const defaultLogLevel = process.env.NODE_ENV === 'production' ? 'silent' : 'debug' 6 | const logLevel = process.env.LOG_LEVEL || defaultLogLevel 7 | logger.level = logLevel 8 | 9 | export default logger -------------------------------------------------------------------------------- /src/libraries/utils/seo.ts: -------------------------------------------------------------------------------- 1 | import seoConfig from 'src/constants/seo' 2 | 3 | type GetSeoOptions = { 4 | omitOpenGraphImage?: boolean 5 | }; 6 | 7 | function getSeo(options: GetSeoOptions = {}) { 8 | const { omitOpenGraphImage } = options 9 | const { images, ...openGraph } = seoConfig.openGraph 10 | 11 | return { 12 | ...seoConfig, 13 | openGraph: { 14 | ...openGraph, 15 | images: omitOpenGraphImage ? undefined : images, 16 | }, 17 | } 18 | } 19 | 20 | export default getSeo 21 | -------------------------------------------------------------------------------- /src/libraries/utils/token.ts: -------------------------------------------------------------------------------- 1 | import { CHAIN_INFO, SupportedChainId } from 'src/constants/chains' 2 | import { Grant } from 'src/generated/graphql' 3 | import { getUrlForIPFSHash } from 'src/libraries/utils/ipfs' 4 | import { ChainInfo } from 'src/types' 5 | 6 | export function getChainInfo( 7 | grant: { 8 | reward: Pick & { 9 | token?: Pick< 10 | Exclude, 11 | 'iconHash' | 'label' | 'decimal' | 'address' 12 | > | undefined | null 13 | } 14 | }, 15 | chainId: SupportedChainId, 16 | ): ChainInfo['supportedCurrencies'][string] { 17 | // let chainInfo: ChainInfo['supportedCurrencies'][string] 18 | let tokenIcon: string 19 | let chainInfo = 20 | CHAIN_INFO[chainId]?.supportedCurrencies[grant.reward.asset.toLowerCase()] 21 | 22 | if(!chainInfo && grant.reward.token) { 23 | tokenIcon = getUrlForIPFSHash(grant.reward.token.iconHash) 24 | chainInfo = { 25 | address: grant.reward.token.address, 26 | label: grant.reward.token.label, 27 | pair: undefined, 28 | decimals: +grant.reward.token.decimal, 29 | icon: tokenIcon, 30 | } 31 | } else if(!chainInfo && !grant.reward.token) { 32 | chainInfo = { 33 | address: '', 34 | label: 'UNSUP', 35 | decimals: 18, 36 | pair: undefined, 37 | icon: '', 38 | } 39 | } 40 | 41 | return chainInfo 42 | } 43 | -------------------------------------------------------------------------------- /src/libraries/utils/types.ts: -------------------------------------------------------------------------------- 1 | export type PIIForCommentType = { 2 | sender?: string 3 | message?: string 4 | timestamp?: number 5 | role?: string 6 | tag?: string 7 | pii?: {[key: string]: string} 8 | } -------------------------------------------------------------------------------- /src/libraries/validator/utils/generateTypes.ts: -------------------------------------------------------------------------------- 1 | import { readFile, writeFile } from 'fs/promises' 2 | import { load } from 'js-yaml' 3 | import { compile } from 'json-schema-to-typescript' 4 | import path from 'path' 5 | 6 | const GEN_TYPES_FILE = './src/types/gen.d.ts' 7 | 8 | async function main() { 9 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 10 | const schema = await readYaml('src/libraries/validator/schema.yaml') 11 | // console.log('Generating types for schema...', schema) 12 | const result = await compile(schema.Validations, 'Schema', { 13 | maxItems: -1, 14 | $refOptions: { 15 | resolve: { 16 | file: { 17 | read: (file) => { 18 | const parsed = path.parse(file.url) 19 | return schema[parsed.name] 20 | } 21 | } 22 | } 23 | } 24 | }) 25 | await writeFile(GEN_TYPES_FILE, result) 26 | } 27 | 28 | async function readYaml(file: string) { 29 | const yaml = await readFile(file, { encoding: 'utf-8' }) 30 | return load(yaml) as T 31 | } 32 | 33 | main() -------------------------------------------------------------------------------- /src/pages/grantees.tsx: -------------------------------------------------------------------------------- 1 | import _ from 'src/screens/grantees' 2 | export default _ -------------------------------------------------------------------------------- /src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import _ from 'src/screens/discover' 2 | export default _ 3 | -------------------------------------------------------------------------------- /src/pages/profile/[address].tsx: -------------------------------------------------------------------------------- 1 | import { GetServerSidePropsContext } from 'next' 2 | import _ from 'src/screens/profile' 3 | import { ProfileDataType } from 'src/screens/profile/_utils/types' 4 | 5 | export default _ 6 | 7 | export async function getServerSideProps(context: GetServerSidePropsContext) { 8 | const { address } = context.query 9 | 10 | 11 | if(typeof address !== 'string') { 12 | return { 13 | parseError: true 14 | } 15 | } 16 | 17 | let dynamicData: ProfileDataType 18 | 19 | try { 20 | dynamicData = { address } 21 | 22 | } catch(error) { 23 | return { 24 | notFound: true, 25 | } 26 | } 27 | 28 | return { 29 | props: { 30 | dynamicData 31 | }, 32 | } 33 | } -------------------------------------------------------------------------------- /src/pages/proposal_form.tsx: -------------------------------------------------------------------------------- 1 | import _ from 'src/screens/proposal_form' 2 | export default _ -------------------------------------------------------------------------------- /src/pages/proposal_recovery.tsx: -------------------------------------------------------------------------------- 1 | import _ from 'src/screens/proposal_recovery' 2 | export default _ -------------------------------------------------------------------------------- /src/pages/request_proposal.tsx: -------------------------------------------------------------------------------- 1 | import _ from 'src/screens/request_proposal' 2 | export default _ -------------------------------------------------------------------------------- /src/pages/settings.tsx: -------------------------------------------------------------------------------- 1 | import _ from 'src/screens/settings' 2 | export default _ -------------------------------------------------------------------------------- /src/pages/setup_profile.tsx: -------------------------------------------------------------------------------- 1 | import _ from 'src/screens/setup_profile' 2 | export default _ -------------------------------------------------------------------------------- /src/screens/dashboard/ActionList.tsx: -------------------------------------------------------------------------------- 1 | // This renders the action-section, namely Reviews, Milestones and Payouts, that will show up as the third column 2 | 3 | import { useContext } from 'react' 4 | import { Flex } from '@chakra-ui/react' 5 | import MultiSelect from 'src/screens/dashboard/_components/ActionList/MultiSelect' 6 | import SingleSelect from 'src/screens/dashboard/_components/ActionList/SingleSelect' 7 | import { DashboardContext } from 'src/screens/dashboard/Context' 8 | 9 | function ActionList() { 10 | const buildComponent = () => ( 11 | 18 | {selectedProposals.size > 1 ? : } 19 | 20 | 21 | 22 | ) 23 | 24 | const { selectedProposals } = useContext(DashboardContext)! 25 | 26 | return buildComponent() 27 | } 28 | 29 | export default ActionList -------------------------------------------------------------------------------- /src/screens/dashboard/Banner.tsx: -------------------------------------------------------------------------------- 1 | import { Flex, Text } from '@chakra-ui/react' 2 | 3 | function Banner({ message, link, linkText }: { message: string, link?: string, linkText?: string }) { 4 | return ( 5 | 18 | 25 | {message} 26 | 27 | { 28 | link && linkText && ( 29 | window.open(link, '_blank')} 36 | mx={2} 37 | > 38 | {linkText} 39 | 40 | ) 41 | } 42 | 43 | ) 44 | } 45 | 46 | export default Banner 47 | -------------------------------------------------------------------------------- /src/screens/dashboard/Body.tsx: -------------------------------------------------------------------------------- 1 | // This renders the single proposal along with the Discussion section or the aggregated proposals, and shows up as the 2nd column 2 | 3 | import { useContext } from 'react' 4 | import { Flex } from '@chakra-ui/react' 5 | import Empty from 'src/screens/dashboard/_components/Body/Empty' 6 | import MultiSelect from 'src/screens/dashboard/_components/Body/MultiSelect' 7 | import SingleSelect from 'src/screens/dashboard/_components/Body/SingleSelect' 8 | import { DashboardContext } from 'src/screens/dashboard/Context' 9 | 10 | function Body() { 11 | const buildComponent = () => { 12 | return ( 13 | 16 | {selectedProposals.size > 1 ? : selectedProposals.size === 1 ? : } 17 | 18 | ) 19 | } 20 | 21 | const { selectedProposals } = useContext(DashboardContext)! 22 | 23 | return buildComponent() 24 | } 25 | 26 | export default Body -------------------------------------------------------------------------------- /src/screens/dashboard/_components/Body/SingleSelect/index.tsx: -------------------------------------------------------------------------------- 1 | import { Flex, useMediaQuery } from '@chakra-ui/react' 2 | import Discussions from 'src/screens/dashboard/_components/Body/SingleSelect/Discussions' 3 | import Proposal from 'src/screens/dashboard/_components/Body/SingleSelect/Proposal' 4 | import ActionList from 'src/screens/dashboard/ActionList' 5 | 6 | function SingleSelect() { 7 | const buildComponent = () => ( 8 | 12 | 13 | { 14 | isMobile[0] && ( 15 | ) 16 | } 17 | 18 | 19 | ) 20 | const isMobile = useMediaQuery(['(max-width:959px)']) 21 | 22 | return buildComponent() 23 | } 24 | 25 | export default SingleSelect -------------------------------------------------------------------------------- /src/screens/dashboard/_components/DashboardInput.tsx: -------------------------------------------------------------------------------- 1 | import { Input, InputProps } from '@chakra-ui/react' 2 | 3 | function DashboardInput(props: InputProps) { 4 | const buildComponent = () => { 5 | return ( 6 | 14 | ) 15 | } 16 | 17 | return buildComponent() 18 | } 19 | 20 | export default DashboardInput -------------------------------------------------------------------------------- /src/screens/dashboard/_components/FundBuilder/PaidByWallet.tsx: -------------------------------------------------------------------------------- 1 | import { Flex, Text } from '@chakra-ui/react' 2 | 3 | const PaidByWallet = () => { 4 | const buildComponent = () => ( 5 | 10 | 11 | Fund Builder 12 | 13 | 14 | 24 | 25 | 28 | Payouts done to the applicant through TON Wallet 29 | 30 | 31 | 32 | 33 | ) 34 | 35 | return buildComponent() 36 | } 37 | 38 | export default PaidByWallet -------------------------------------------------------------------------------- /src/screens/dashboard/_components/FundBuilder/PayFromChoose.tsx: -------------------------------------------------------------------------------- 1 | import { Flex, Image, Text } from '@chakra-ui/react' 2 | 3 | function PayFromChoose({ selectedMode }: { selectedMode: {logo: string | undefined, value: string | undefined} | undefined}) { 4 | const buildComponent = () => { 5 | return ( 6 | 11 | 14 | Pay From 15 | 16 | 17 | 20 | 24 | {selectedMode?.value} 25 | 26 | 27 | 28 | ) 29 | } 30 | 31 | return buildComponent() 32 | } 33 | 34 | export default PayFromChoose -------------------------------------------------------------------------------- /src/screens/dashboard/_components/RoleTag.tsx: -------------------------------------------------------------------------------- 1 | import { Text } from '@chakra-ui/react' 2 | import { Roles } from 'src/types' 3 | 4 | interface Props { 5 | role: Roles 6 | isBuilder?: boolean 7 | } 8 | 9 | function RoleTag({ role, isBuilder = false }: Props) { 10 | const buildComponent = () => { 11 | return ( 12 | 20 | {role === 'admin' || role === 'reviewer' ? config[role].text : role === 'builder' && isBuilder ? config.builder.text : config.community.text} 21 | 22 | ) 23 | } 24 | 25 | const config = { 26 | admin: { 27 | bg: 'accent.azure', 28 | text: 'Admin' 29 | }, 30 | reviewer: { 31 | bg: 'accent.carrot', 32 | text: 'Reviewer' 33 | }, 34 | builder: { 35 | bg: 'accent.royal', 36 | text: 'Builder' 37 | }, 38 | community: { 39 | bg: 'accent.orchid', 40 | text: 'Community' 41 | } 42 | } 43 | 44 | return buildComponent() 45 | } 46 | 47 | export default RoleTag -------------------------------------------------------------------------------- /src/screens/dashboard/_components/ThreeColumnSkeleton.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import { Flex, Skeleton, SkeletonText } from '@chakra-ui/react' 3 | import { GrantsProgramContext } from 'src/pages/_app' 4 | 5 | function ThreeColumnSkeleton() { 6 | const buildComponent = () => { 7 | return ( 8 | 13 | { 14 | ['25%', '48%', '25%'].map((width, index) => { 15 | return ( 16 | 22 | {loadingComponent()} 23 | 24 | ) 25 | }) 26 | } 27 | 28 | ) 29 | } 30 | 31 | const loadingComponent = () => { 32 | return ( 33 | 39 | 43 | 47 | 48 | ) 49 | } 50 | 51 | const { isLoading } = useContext(GrantsProgramContext)! 52 | 53 | return buildComponent() 54 | } 55 | 56 | export default ThreeColumnSkeleton -------------------------------------------------------------------------------- /src/screens/dashboard/_data/getApplicationActionsQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getApplicationActionsQuery = gql` 3 | query getApplicationActions($grantId: String!) { 4 | grantApplications(filter: { grant: $grantId }) { 5 | id:_id 6 | applicantId 7 | applicantPublicKey 8 | actions { 9 | id:_id 10 | updatedBy 11 | updatedAtS 12 | state 13 | feedback 14 | } 15 | grant { 16 | id:_id 17 | workspace { 18 | members:membersFilter { 19 | actorId 20 | fullName 21 | profilePictureIpfsHash 22 | publicKey 23 | accessLevel 24 | } 25 | supportedNetworks 26 | } 27 | } 28 | } 29 | } 30 | ` -------------------------------------------------------------------------------- /src/screens/dashboard/_data/getBuilderInfoQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getBuilderInfoQuery = gql`query getBuilderInfo($id: String!) { 3 | builder(applicationId: $id) { 4 | telegram 5 | } 6 | }` -------------------------------------------------------------------------------- /src/screens/dashboard/_data/getCommentsQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getCommentsQuery = gql`query getComments($grantId: String!, $first: Int, $skip: Int) { 3 | comments( 4 | limit: $first 5 | skip: $skip 6 | filter: { grant: $grantId } 7 | sort:CREATEDATS_ASC 8 | ) { 9 | id:_id 10 | isPrivate 11 | commentsPublicHash 12 | createdAt 13 | commentsEncryptedData { 14 | id:_id 15 | data 16 | } 17 | workspace { 18 | members: membersFilter(filter: { 19 | enabled: true 20 | }) { 21 | actorId 22 | fullName 23 | profilePictureIpfsHash 24 | publicKey 25 | accessLevel 26 | } 27 | supportedNetworks 28 | } 29 | application { 30 | id:_id 31 | applicantPublicKey 32 | applicantId 33 | } 34 | } 35 | } 36 | ` -------------------------------------------------------------------------------- /src/screens/dashboard/_data/getDocuSignTemplates.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getDocuSignTemplates = gql`mutation getDocuSignTemplates($id: String!){ 3 | getDocuSignTemplates(id: $id){ 4 | templates 5 | } 6 | }` -------------------------------------------------------------------------------- /src/screens/dashboard/_data/getFundsAllocatedQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getFundsAllocatedQuery = gql`query getFundsAllocated($id: String!) { 3 | grantApplications(filter: { 4 | state: "approved", 5 | grant: $id 6 | }, sort: UPDATEDATS_DESC) { 7 | grant { 8 | totalGrantFundingDisbursedUSD 9 | } 10 | milestones { 11 | id: _id 12 | amount 13 | amountPaid 14 | } 15 | } 16 | }` -------------------------------------------------------------------------------- /src/screens/dashboard/_data/getGrantDetailsForSEOQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getGrantDetailsForSEOQuery = gql`query getGrantDetailsForSEO($grantId: String!) { 3 | grant(_id: $grantId) { 4 | id:_id 5 | title 6 | workspace { 7 | id:_id 8 | logoIpfsHash 9 | } 10 | } 11 | } 12 | ` -------------------------------------------------------------------------------- /src/screens/dashboard/_data/getMemberPublicKeysQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getMemberPublicKeysQuery = gql`query getMemberPublicKeys($workspaceId: String!, $applicationIds: [String!]!) { 3 | workspace(_id: $workspaceId) { 4 | members: membersFilter(filter: { 5 | _operators:{ 6 | accessLevel: { 7 | ne:"reviewer" 8 | } 9 | } 10 | enabled: false 11 | }) { 12 | actorId 13 | publicKey 14 | } 15 | } 16 | grantApplications(filter: { 17 | _operators:{ 18 | _id: { 19 | in: $applicationIds 20 | } 21 | } 22 | }) { 23 | id:_id 24 | applicantId 25 | applicantPublicKey 26 | applicationReviewers { 27 | member(filter: { 28 | enabled: true 29 | }) { 30 | actorId 31 | publicKey 32 | } 33 | } 34 | } 35 | } 36 | ` -------------------------------------------------------------------------------- /src/screens/dashboard/_data/getPayoutQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getPayoutQuery = gql`query getPayouts($first: Int, $skip: Int, $proposalID: String!) { 3 | fundTransfers( 4 | limit: $first 5 | skip: $skip 6 | filter: { 7 | application: $proposalID 8 | _operators: { 9 | type: { 10 | in: ["funds_disbursed", "funds_disbursed_from_safe"] 11 | } 12 | } 13 | } 14 | ) { 15 | amount 16 | asset 17 | type 18 | createdAtS 19 | to 20 | transactionHash 21 | status 22 | executionTimestamp 23 | milestone { 24 | id: _id 25 | } 26 | grant { 27 | reward { 28 | id: _id 29 | asset 30 | committed 31 | token { 32 | id: _id 33 | label 34 | address 35 | chainId 36 | iconHash 37 | decimal 38 | } 39 | } 40 | } 41 | } 42 | } 43 | ` -------------------------------------------------------------------------------- /src/screens/dashboard/_data/getProposalDetailsForSEOQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getProposalDetailsForSEOQuery = gql`# This query is used in getServerSideProps for SEO 3 | query getProposalDetailsForSEO($proposalId: String!) { 4 | grantApplication(_id: $proposalId) { 5 | id:_id 6 | title: fieldFilterBySection(filter: { field: "projectName" }) { 7 | values { 8 | value 9 | } 10 | } 11 | grant { 12 | id:_id 13 | title 14 | workspace { 15 | id:_id 16 | logoIpfsHash 17 | } 18 | } 19 | } 20 | } 21 | ` -------------------------------------------------------------------------------- /src/screens/dashboard/_data/getSpecificApplicationActionQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getSpecificApplicationActionQuery = gql`query getApplicationActions($grantId: String!, $proposalId: String!) { 3 | grantApplications(filter: { grant: $grantId, _id:$proposalId }) { 4 | id:_id 5 | applicantId 6 | applicantPublicKey 7 | actions { 8 | id:_id 9 | updatedBy 10 | updatedAtS 11 | state 12 | feedback 13 | } 14 | grant { 15 | id:_id 16 | workspace { 17 | members:membersFilter { 18 | actorId 19 | fullName 20 | profilePictureIpfsHash 21 | publicKey 22 | accessLevel 23 | } 24 | supportedNetworks 25 | } 26 | } 27 | } 28 | } 29 | ` -------------------------------------------------------------------------------- /src/screens/dashboard/_data/getSpecificProposalCommentsQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getSpecificProposalCommentsQuery = gql`query getComments($grantId: String!, $proposalId: String!) { 3 | comments( 4 | filter: { grant: $grantId, application: $proposalId } 5 | sort:CREATEDAT_ASC 6 | ) { 7 | id:_id 8 | isPrivate 9 | commentsPublicHash 10 | createdAt 11 | updatedAt 12 | commentsEncryptedData { 13 | id:_id 14 | data 15 | } 16 | workspace { 17 | members: membersFilter(filter: { 18 | enabled: true 19 | }) { 20 | actorId 21 | fullName 22 | profilePictureIpfsHash 23 | publicKey 24 | accessLevel 25 | } 26 | supportedNetworks 27 | } 28 | application { 29 | id:_id 30 | applicantPublicKey 31 | applicantId 32 | } 33 | } 34 | } 35 | ` -------------------------------------------------------------------------------- /src/screens/dashboard/_data/getSynapsId.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getSynapsId = gql`mutation getSynapseId($id:String!, $type:String!, $proposalId: String!){ 3 | getSynapsId(id: $id, type: $type, proposalId: $proposalId){ 4 | link 5 | } 6 | }` -------------------------------------------------------------------------------- /src/screens/dashboard/_graphql/getApplicationActionForProposal.graphql: -------------------------------------------------------------------------------- 1 | query getApplicationActions($grantId: String!, $proposalId: String!) { 2 | grantApplications(filter: { grant: $grantId, _id:$proposalId }) { 3 | id:_id 4 | applicantId 5 | applicantPublicKey 6 | actions { 7 | id:_id 8 | updatedBy 9 | updatedAtS 10 | state 11 | feedback 12 | } 13 | grant { 14 | id:_id 15 | workspace { 16 | members:membersFilter { 17 | actorId 18 | fullName 19 | profilePictureIpfsHash 20 | publicKey 21 | accessLevel 22 | } 23 | supportedNetworks 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/screens/dashboard/_graphql/getApplicationActions.graphql: -------------------------------------------------------------------------------- 1 | query getApplicationActions($grantId: String!) { 2 | grantApplications(filter: { grant: $grantId }) { 3 | id:_id 4 | applicantId 5 | applicantPublicKey 6 | actions { 7 | id:_id 8 | updatedBy 9 | updatedAtS 10 | state 11 | feedback 12 | } 13 | grant { 14 | id:_id 15 | workspace { 16 | members:membersFilter { 17 | actorId 18 | fullName 19 | profilePictureIpfsHash 20 | publicKey 21 | accessLevel 22 | } 23 | supportedNetworks 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/screens/dashboard/_graphql/getBuilderInfo.graphql: -------------------------------------------------------------------------------- 1 | query getBuilderInfo($id: String!) { 2 | builder(applicationId: $id) { 3 | telegram 4 | } 5 | } -------------------------------------------------------------------------------- /src/screens/dashboard/_graphql/getComments.graphql: -------------------------------------------------------------------------------- 1 | query getComments($grantId: String!, $first: Int, $skip: Int) { 2 | comments( 3 | limit: $first 4 | skip: $skip 5 | filter: { grant: $grantId } 6 | sort:CREATEDAT_ASC 7 | ) { 8 | id:_id 9 | isPrivate 10 | commentsPublicHash 11 | createdAt 12 | commentsEncryptedData { 13 | id:_id 14 | data 15 | } 16 | workspace { 17 | members: membersFilter(filter: { 18 | enabled: true 19 | }) { 20 | actorId 21 | fullName 22 | profilePictureIpfsHash 23 | publicKey 24 | accessLevel 25 | } 26 | supportedNetworks 27 | } 28 | application { 29 | id:_id 30 | applicantPublicKey 31 | applicantId 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/screens/dashboard/_graphql/getDocusSignTemplates.graphql: -------------------------------------------------------------------------------- 1 | mutation getDocuSignTemplates($id: String!){ 2 | getDocuSignTemplates(id: $id){ 3 | templates 4 | } 5 | } -------------------------------------------------------------------------------- /src/screens/dashboard/_graphql/getFundTransfers.graphql: -------------------------------------------------------------------------------- 1 | query getPayouts($first: Int, $skip: Int,$proposalID: String!) { 2 | fundTransfers(limit: $first,skip: $skip,filter: {application: $proposalID, _operators: 3 | { 4 | type: { 5 | in: ["funds_disbursed", "funds_disbursed_from_safe"] 6 | } 7 | }}) { 8 | amount 9 | asset 10 | type 11 | createdAtS 12 | to 13 | transactionHash 14 | status 15 | executionTimestamp 16 | milestone { 17 | id:_id 18 | } 19 | grant { 20 | reward { 21 | id:_id 22 | asset 23 | committed 24 | token { 25 | id:_id 26 | label 27 | address 28 | chainId 29 | iconHash 30 | decimals 31 | } 32 | } 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/screens/dashboard/_graphql/getFundsAllocated.graphql: -------------------------------------------------------------------------------- 1 | query getFundsAllocated($id: String!) { 2 | grantApplications(filter: { 3 | state: "approved", 4 | grant: $id 5 | }, sort: UPDATEDATS_DESC) { 6 | milestones { 7 | id: _id 8 | amount 9 | amountPaid 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/screens/dashboard/_graphql/getGrantDetailsForSEO.graphql: -------------------------------------------------------------------------------- 1 | # This query is used in getServerSideProps for SEO 2 | query getGrantDetailsForSEO($grantId: String!) { 3 | grant(_id: $grantId) { 4 | id:_id 5 | title 6 | workspace { 7 | id:_id 8 | logoIpfsHash 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/screens/dashboard/_graphql/getPayouts.graphql: -------------------------------------------------------------------------------- 1 | query getPayouts($first: Int, $skip: Int, $proposalID: String!) { 2 | fundTransfers(limit: $first, skip: $skip,filter: {application: $proposalID, _operators: { 3 | type: { 4 | in: ["funds_disbursed", "funds_disbursed_from_safe"] 5 | } 6 | } }) { 7 | amount 8 | asset 9 | type 10 | createdAtS 11 | to 12 | transactionHash 13 | status 14 | executionTimestamp 15 | milestone { 16 | id:_id 17 | } 18 | grant { 19 | reward { 20 | id:_id 21 | asset 22 | committed 23 | token { 24 | id:_id 25 | label 26 | address 27 | decimal 28 | chainId 29 | iconHash 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/screens/dashboard/_graphql/getProposalDetailsForSEO.graphql: -------------------------------------------------------------------------------- 1 | # This query is used in getServerSideProps for SEO 2 | query getProposalDetailsForSEO($proposalId: String!) { 3 | grantApplication(_id: $proposalId) { 4 | id:_id 5 | title: fieldFilterBySection(filter: { field: "projectName" }) { 6 | values { 7 | value 8 | } 9 | } 10 | grant { 11 | id:_id 12 | title 13 | workspace { 14 | id:_id 15 | logoIpfsHash 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/screens/dashboard/_graphql/getSpecificProposalComments.graphql: -------------------------------------------------------------------------------- 1 | query getComments($grantId: String!, $proposalId: String!) { 2 | comments( 3 | filter: { grant: $grantId, application: $proposalId } 4 | sort:CREATEDAT_ASC 5 | ) { 6 | id:_id 7 | isPrivate 8 | commentsPublicHash 9 | createdAt 10 | updatedAt 11 | commentsEncryptedData { 12 | id:_id 13 | data 14 | } 15 | workspace { 16 | members: membersFilter(filter: { 17 | enabled: true 18 | }) { 19 | actorId 20 | fullName 21 | profilePictureIpfsHash 22 | publicKey 23 | accessLevel 24 | } 25 | supportedNetworks 26 | } 27 | application { 28 | id:_id 29 | applicantPublicKey 30 | applicantId 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/screens/dashboard/_graphql/getSynapsId.graphql: -------------------------------------------------------------------------------- 1 | mutation getSynapseId($id:String!, $type:String!){ 2 | getSynapsId(id: $id, type: $type){ 3 | link 4 | } 5 | } -------------------------------------------------------------------------------- /src/screens/dashboard/_hooks/useDocuSign.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import { executeMutation } from 'src/graphql/apollo' 3 | import { GrantsProgramContext } from 'src/pages/_app' 4 | import { getDocuSignTemplates } from 'src/screens/dashboard/_data/getDocuSignTemplates' 5 | 6 | function GetDocuSignTemplates() { 7 | 8 | const { grant } = useContext(GrantsProgramContext)! 9 | 10 | 11 | const getHelloSignTemplates = async() => { 12 | const templates = await executeMutation(getDocuSignTemplates, { id: grant?.workspace?.id }) 13 | return templates?.getDocuSignTemplates?.templates 14 | } 15 | 16 | return { getHelloSignTemplates } 17 | } 18 | 19 | export default GetDocuSignTemplates -------------------------------------------------------------------------------- /src/screens/dashboard/_hooks/usePhantomWallet.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react' 2 | import { PhantomProvider, WindowWithSolana } from 'src/types' 3 | 4 | export default function usePhantomWallet() { 5 | const [ phantomWalletAvailable, setPhantomWalletAvailable ] = useState(false) 6 | const [phantomWallet, setPhantomWallet] = useState() 7 | const [phantomWalletConnected, setPhantomWalletConnected] = useState(false) 8 | 9 | useEffect(() => { 10 | if('solana' in window) { 11 | const solWindow = window as WindowWithSolana 12 | if(solWindow?.solana?.isPhantom) { 13 | setPhantomWallet(solWindow.solana) 14 | setPhantomWalletAvailable(true) 15 | } 16 | } 17 | }, []) 18 | 19 | useEffect(() => { 20 | phantomWallet?.on('connect', () => { 21 | // console.log('phantom wallet connected ') 22 | setPhantomWalletConnected(true) 23 | }) 24 | phantomWallet?.on('disconnect', () => { 25 | // console.log('phantom wallet disconnected') 26 | setPhantomWalletConnected(false) 27 | }) 28 | 29 | }, [phantomWallet?.isConnected]) 30 | 31 | return { 32 | phantomWalletAvailable, 33 | phantomWallet, 34 | phantomWalletConnected, 35 | setPhantomWalletConnected } 36 | } -------------------------------------------------------------------------------- /src/screens/dashboard/_hooks/useSynaps.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import { executeMutation } from 'src/graphql/apollo' 3 | import { GrantsProgramContext } from 'src/pages/_app' 4 | import { getSynapsId } from 'src/screens/dashboard/_data/getSynapsId' 5 | 6 | function GetSynapsLink() { 7 | 8 | const { grant } = useContext(GrantsProgramContext)! 9 | 10 | 11 | const getSynapsLink = async(type: 'KYC' | 'KYB', proposalId: String) => { 12 | const synapsId = await executeMutation(getSynapsId, { id: grant?.workspace?.id, type, proposalId }) 13 | return synapsId?.getSynapsId?.link 14 | } 15 | 16 | return { getSynapsLink } 17 | } 18 | 19 | export default GetSynapsLink -------------------------------------------------------------------------------- /src/screens/dashboard/_utils/constants.ts: -------------------------------------------------------------------------------- 1 | const GRANT_CACHE_KEY = 'current-grant' 2 | const GRANT_PII = ['Personal Telegram Handle', 3 | 'Personal WeChat Handle', 4 | 'I confirm that I have studied the Grant Program Guidelines and the Ecosystem Map with the existing solutions on TON (please write \'yes\')', 5 | 'In case my proposal is approved, sign an official grant agreement and abide by its provisions in good faith', 6 | 'Any materials or links which can prove your achievement of building an App in Telegram with >10 thousand daily active users, or >1 million daily active users in any other internet platforms such as WeChat, QQ, Facebook, Google, Line, Kakao, etc. in the past', 7 | 'Education & Working experience & achievements of the founder and/or chief creator of Mini-app'] 8 | 9 | export { GRANT_CACHE_KEY, GRANT_PII } -------------------------------------------------------------------------------- /src/screens/dashboard/_utils/formatters.ts: -------------------------------------------------------------------------------- 1 | import moment from 'moment' 2 | 3 | const formatTime = (timestamp: number, isPayout: boolean = false) => { 4 | const now = Date.now() 5 | if(now - timestamp <= 24 * 60 * 60) { 6 | // Within a day 7 | return `${Math.floor((now - timestamp) / 24)}h` 8 | } else if(now - timestamp <= 7 * 24 * 60 * 60) { 9 | // Within a week 10 | return `${Math.floor((now - timestamp) / 7)}d` 11 | } else { 12 | return isPayout ? moment.unix(timestamp).format('DD MMM, YYYY') : moment.unix(timestamp).format('DD MMM') 13 | } 14 | } 15 | 16 | const formatAmount = (amount: number, symbol?: string): string => { 17 | const defaultSymbol = 'USD' 18 | if(!symbol) { 19 | symbol = defaultSymbol 20 | } 21 | 22 | if(amount >= 1e6) { 23 | return symbol === 'USD' ? `$${(amount / 1e6).toFixed(1)}M` : `${(amount / 1e6).toFixed(1)}M ${symbol}` 24 | } else if(amount >= 1e3) { 25 | return symbol === 'USD' ? `$${(amount / 1e3).toFixed(0)}K` : `${(amount / 1e3).toFixed(0)}K ${symbol}` 26 | } else { 27 | return symbol === 'USD' ? `$${amount}` : `${amount} ${symbol}` 28 | } 29 | } 30 | 31 | 32 | export { formatTime, formatAmount } -------------------------------------------------------------------------------- /src/screens/dashboard/_utils/tonWalletUtils.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | export interface TokenDetailsInterface { 4 | tokenIcon: string 5 | tokenName: string 6 | symbol: string 7 | tokenValueAmount: number 8 | usdValueAmount: number 9 | mintAddress: string 10 | info: { 11 | decimals: number 12 | tokenAddress: string 13 | fiatConversion: number 14 | } 15 | fiatConversion: number 16 | } 17 | const getTokenUSDonDate = async(tokenName: string) => { 18 | const url = `https://api.coingecko.com/api/v3/simple/price?ids=${tokenName}&vs_currencies=usd` 19 | const tokenUsdValue = parseFloat((await axios.get(url)).data[tokenName].usd) 20 | 21 | return tokenUsdValue 22 | } 23 | 24 | const getToken = async() => { 25 | const TONTokenId: string = 'the-open-network' 26 | 27 | // const currentTime = (new Date()).toLocaleDateString().split('/').join('-') 28 | 29 | const tonUsdRate = await getTokenUSDonDate(TONTokenId) 30 | const details: TokenDetailsInterface = { 31 | tokenIcon: '/v2/icons/toncoin.svg', 32 | tokenName: 'TON', 33 | tokenValueAmount: 0, 34 | usdValueAmount: 0, 35 | mintAddress: '0x0000000', 36 | info: { 37 | decimals: 9, 38 | tokenAddress: TONTokenId, 39 | fiatConversion: tonUsdRate 40 | }, 41 | fiatConversion: tonUsdRate, 42 | symbol: 'TON' 43 | } 44 | return details 45 | } 46 | 47 | export default getToken -------------------------------------------------------------------------------- /src/screens/discover/_graphql/getAllFundTransfers.graphql: -------------------------------------------------------------------------------- 1 | query getAllFundsTransfer($first: Int, $skip: Int) { 2 | fundTransfers(limit:$first,skip:$skip) { 3 | grant{ 4 | id:_id 5 | } 6 | amount 7 | type 8 | tokenUSDValue 9 | asset 10 | tokenName 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/screens/discover/_graphql/getAllGrants.graphql: -------------------------------------------------------------------------------- 1 | query GetAllGrants($first: Int, $skip: Int, $searchString: RegExpAsString!) { 2 | grants( 3 | limit: $first 4 | skip: $skip 5 | sort: CREATEDATS_DESC 6 | filter: { 7 | _operators: { 8 | title: { 9 | regex: $searchString 10 | } 11 | } 12 | } 13 | ) { 14 | id:_id 15 | title 16 | applications(limit: 1) { 17 | id: _id 18 | applicantId 19 | state 20 | } 21 | acceptingApplications 22 | fundTransfers { 23 | amount 24 | type 25 | tokenUSDValue 26 | asset 27 | tokenName 28 | } 29 | workspace { 30 | id:_id 31 | title 32 | isVisible 33 | logoIpfsHash 34 | supportedNetworks 35 | members(limit: 1) { 36 | id:_id 37 | actorId 38 | accessLevel 39 | } 40 | safe { 41 | chainId 42 | address 43 | } 44 | } 45 | reward { 46 | committed 47 | id:_id 48 | asset 49 | token { 50 | address 51 | label 52 | decimal 53 | iconHash 54 | } 55 | } 56 | deadlineS 57 | deadline 58 | numberOfApplications 59 | numberOfApplicationsSelected 60 | numberOfApplicationsPending 61 | createdAtS 62 | updatedAtS 63 | totalGrantFundingDisbursedUSD 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/screens/discover/_graphql/getFundsAllocated.graphql: -------------------------------------------------------------------------------- 1 | query getSectionGrants { 2 | sections { 3 | grants(sort: NUMBEROFAPPLICATIONS_DESC) { 4 | _id 5 | applications(filter: { 6 | state: "approved" 7 | }, sort: UPDATEDATS_DESC, limit: 2000) { 8 | milestones { 9 | id: _id 10 | amount 11 | } 12 | } 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/screens/discover/_graphql/getGrantProgramDetails.graphql: -------------------------------------------------------------------------------- 1 | query getGrantProgramDetails($workspaceID: String!) { 2 | grantProgram: grants(filter: {workspace: $workspaceID},sort: CREATEDATS_DESC) { 3 | id: _id 4 | title 5 | workspace { 6 | id: _id 7 | title 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/screens/discover/_graphql/getProposalNameAndAuthors.graphql: -------------------------------------------------------------------------------- 1 | query fetchNamesAndAuthors($ids: [String]!){ 2 | grantApplications(filter: { 3 | _operators: { 4 | _id: { 5 | in: $ids 6 | } 7 | } 8 | }, limit: 1000, sort: UPDATEDATS_DESC ){ 9 | _id 10 | name: fieldFilterBySection( 11 | filter:{ 12 | field: "projectName" 13 | } 14 | ) { 15 | values{ 16 | value 17 | } 18 | } 19 | author:fieldFilterBySection(filter: { 20 | field: "applicantName" 21 | } ){ 22 | values { 23 | value 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/screens/discover/_graphql/getStats.graphql: -------------------------------------------------------------------------------- 1 | query getStats { 2 | stats { 3 | builders 4 | proposals 5 | } 6 | } -------------------------------------------------------------------------------- /src/screens/discover/_utils/index.ts: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * @description Extracts the builder info from the URL 4 | * @param {string} url - The URL to extract the builder info from 5 | */ 6 | export const extractBuilderInfo = (url?: string): boolean => { 7 | let params: URLSearchParams 8 | if(url) { 9 | params = new URL(url).searchParams 10 | } else { 11 | params = new URLSearchParams(window.location.search) 12 | } 13 | 14 | const builderIdStr = params.get('isBuilder') 15 | if(typeof builderIdStr === 'string') { 16 | return true 17 | } 18 | 19 | return false 20 | } -------------------------------------------------------------------------------- /src/screens/discover/data/fundsTransfers.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | import { client } from 'src/graphql/apollo' 3 | import { FundTransfer } from 'src/screens/discover/_utils/types' 4 | 5 | export const QUERY_FUNDSTRANSFERS = gql` 6 | query getAllFundsTransfer($first: Int, $skip: Int) { 7 | fundTransfers(limit:$first,skip:$skip) { 8 | grant{ 9 | id:_id 10 | } 11 | amount 12 | type 13 | tokenUSDValue 14 | asset 15 | tokenName 16 | } 17 | } 18 | ` 19 | 20 | 21 | export async function getAllFundsTransfers(): Promise { 22 | let records: FundTransfer[] = [] 23 | let skip = 0 24 | let allData = false 25 | 26 | try { 27 | while(!allData) { 28 | const { data, error } = await client.query({ 29 | query: QUERY_FUNDSTRANSFERS, 30 | variables: { 31 | skip, 32 | first: 500, 33 | }, 34 | }) 35 | 36 | if(data?.fundTransfers && !error) { 37 | records = records.concat(data.fundTransfers) 38 | skip += 500 39 | 40 | if(data?.fundTransfers.length === 0) { 41 | allData = true 42 | } 43 | } 44 | } 45 | } catch(error) { 46 | } 47 | 48 | return records 49 | } 50 | -------------------------------------------------------------------------------- /src/screens/discover/data/getFundsAllocated.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getFundsAllocated = gql`query getSectionGrants { 3 | sections { 4 | grants(sort: NUMBEROFAPPLICATIONS_DESC) { 5 | _id 6 | applications(filter: { 7 | state: "approved" 8 | }, sort: UPDATEDATS_DESC, limit: 10) { 9 | milestones { 10 | id: _id 11 | amount 12 | } 13 | } 14 | } 15 | } 16 | }` -------------------------------------------------------------------------------- /src/screens/discover/data/getGrantProgramDetails.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | 3 | export const GetGrantProgramDetails = gql` 4 | query getGrantProgramDetails($workspaceID: String!) { 5 | grantProgram: grants(filter: {workspace: $workspaceID},sort: CREATEDATS_DESC) { 6 | id: _id 7 | title 8 | workspace { 9 | id: _id 10 | title 11 | } 12 | } 13 | }` -------------------------------------------------------------------------------- /src/screens/discover/data/getProposalNameAndAuthors.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getProposalNameAndAuthorsQuery = gql` 3 | query fetchNamesAndAuthors($ids: [String]!){ 4 | grantApplications(filter: { 5 | _operators: { 6 | _id: { 7 | in: $ids 8 | } 9 | } 10 | },limit: 1000, sort: UPDATEDATS_DESC){ 11 | _id 12 | name: fieldFilterBySection( 13 | filter:{ 14 | field: "projectName" 15 | } 16 | ) { 17 | values{ 18 | value 19 | } 20 | } 21 | author:fieldFilterBySection(filter: { 22 | field: "applicantName" 23 | } ){ 24 | values { 25 | value 26 | } 27 | } 28 | } 29 | }` -------------------------------------------------------------------------------- /src/screens/discover/data/getSectionSubGrants.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | 3 | 4 | export const getSectionSubGrantsQuery = gql` 5 | query getSectionSubGrants { 6 | grants(sort: NUMBEROFAPPLICATIONS_DESC, filter: { subgrant: true }) { 7 | id:_id 8 | title 9 | applications(filter: { 10 | state: "approved" 11 | }, limit: 2, sort: UPDATEDATS_DESC) { 12 | id: _id 13 | applicantId 14 | state 15 | createdAtS 16 | updatedAtS 17 | milestones { 18 | id: _id 19 | amount 20 | } 21 | } 22 | reward { 23 | id:_id 24 | asset 25 | committed 26 | token { 27 | id:_id 28 | label 29 | address 30 | decimal 31 | chainId 32 | iconHash 33 | } 34 | } 35 | acceptingApplications 36 | workspace { 37 | id:_id 38 | title 39 | isVisible 40 | logoIpfsHash 41 | supportedNetworks 42 | safe { 43 | chainId 44 | address 45 | } 46 | } 47 | link 48 | deadlineS 49 | deadline 50 | numberOfApplications 51 | numberOfApplicationsSelected 52 | numberOfApplicationsPending 53 | createdAtS 54 | updatedAtS 55 | totalGrantFundingDisbursedUSD 56 | } 57 | } 58 | ` -------------------------------------------------------------------------------- /src/screens/discover/data/getStats.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | 3 | export const getStatsQuery = gql`query getStats { 4 | stats { 5 | builders 6 | proposals 7 | } 8 | }` -------------------------------------------------------------------------------- /src/screens/discover/hooks/github.tsx: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { logger } from 'ethers' 3 | 4 | 5 | export const useGithub = async(token: string): 6 | Promise<{ 7 | username: string 8 | repos: number 9 | }> => { 10 | try { 11 | logger.info({ token }, 'useGithub') 12 | const response = await axios.get('https://api.github.com/user', { 13 | headers: { 14 | 'Authorization': `token ${token}` 15 | } 16 | }) 17 | return { 18 | username: response.data.login, 19 | repos: response.data.public_repos 20 | } 21 | } catch(error) { 22 | logger.info({ error }, 'useGithub') 23 | return { 24 | username: '', 25 | repos: 0 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/screens/grantees/HeroBanner.tsx: -------------------------------------------------------------------------------- 1 | import { Flex, Text } from '@chakra-ui/react' 2 | 3 | function StatsBanner() { 4 | const buildComponent = () => { 5 | return ( 6 | 15 | 23 | Grantee List 24 | 25 | 32 | These are all the grantees that have received grants via Questbook from different ecosystems including, Arbitrum, Ton, Compound and more 33 | 34 | 35 | ) 36 | } 37 | 38 | return buildComponent() 39 | } 40 | 41 | export default StatsBanner -------------------------------------------------------------------------------- /src/screens/grantees/_components/rfpGrid.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | import { Button, Grid, GridItem } from '@chakra-ui/react' 3 | import RFPCard from 'src/screens/grantees/_components/RFPCard' 4 | import { RecentProposals } from 'src/screens/grantees/_utils/types' 5 | 6 | type RFPGridProps = { 7 | proposals: RecentProposals 8 | } 9 | 10 | function RFPGrid({ 11 | proposals 12 | }: RFPGridProps) { 13 | const [more, setMore] = useState(6) 14 | 15 | const buildComponent = () => ( 16 | <> 17 | 22 | { 23 | proposals 24 | .slice(0, more) 25 | .map((proposal, index: number) => { 26 | return ( 27 | 29 | 33 | 34 | 35 | ) 36 | }) 37 | } 38 | 39 | { 40 | 41 | more < proposals.length && proposals.length > 6 && ( 42 | 52 | ) 53 | } 54 | 55 | ) 56 | 57 | return buildComponent() 58 | } 59 | 60 | export default RFPGrid -------------------------------------------------------------------------------- /src/screens/grantees/_graphql/getSectionGrants.graphql: -------------------------------------------------------------------------------- 1 | query getSectionGrants { 2 | sections { 3 | grants(sort: NUMBEROFAPPLICATIONS_DESC) { 4 | id: _id 5 | title 6 | workspace { 7 | _id 8 | logoIpfsHash 9 | } 10 | applications(filter: { 11 | state: "approved" 12 | }, sort: UPDATEDATS_DESC, limit: 10) { 13 | id: _id 14 | name: fieldFilterBySection( 15 | filter:{ 16 | field: "projectName" 17 | } 18 | ) { 19 | values{ 20 | value 21 | } 22 | } 23 | author:fieldFilterBySection(filter: { 24 | field: "applicantName" 25 | } ){ 26 | values { 27 | value 28 | } 29 | } 30 | milestones { 31 | id: _id 32 | amount 33 | amountPaid 34 | } 35 | } 36 | } 37 | sectionName 38 | sectionLogoIpfsHash 39 | } 40 | } -------------------------------------------------------------------------------- /src/screens/grantees/_utils/constants.ts: -------------------------------------------------------------------------------- 1 | export const inActiveProposals = [ 2 | '0x318', 3 | '0x273', 4 | '0x26c', 5 | '0x291', 6 | '0x27b', 7 | '0x1de' 8 | ] 9 | 10 | export const completedProposals = [ 11 | '0x36d', 12 | ] -------------------------------------------------------------------------------- /src/screens/grantees/data/getSectionGrants.tsx: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | 3 | 4 | export const getSectionGrantsQuery = gql` 5 | query getSectionGrants { 6 | sections { 7 | grants(sort: NUMBEROFAPPLICATIONS_DESC) { 8 | id: _id 9 | title 10 | workspace { 11 | _id 12 | logoIpfsHash 13 | } 14 | applications(filter: { 15 | state: "approved" 16 | }, sort: UPDATEDATS_DESC, limit: 1000) { 17 | id: _id 18 | name: fieldFilterBySection( 19 | filter:{ 20 | field: "projectName" 21 | } 22 | ) { 23 | values{ 24 | value 25 | } 26 | } 27 | author:fieldFilterBySection(filter: { 28 | field: "applicantName" 29 | } ){ 30 | values { 31 | value 32 | } 33 | } 34 | milestones { 35 | id: _id 36 | amount 37 | amountPaid 38 | } 39 | } 40 | } 41 | sectionName 42 | sectionLogoIpfsHash 43 | } 44 | } 45 | ` -------------------------------------------------------------------------------- /src/screens/grantees/hooks/github.tsx: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { logger } from 'ethers' 3 | 4 | 5 | export const useGithub = async(token: string): 6 | Promise<{ 7 | username: string 8 | repos: number 9 | }> => { 10 | try { 11 | logger.info({ token }, 'useGithub') 12 | const response = await axios.get('https://api.github.com/user', { 13 | headers: { 14 | 'Authorization': `token ${token}` 15 | } 16 | }) 17 | return { 18 | username: response.data.login, 19 | repos: response.data.public_repos 20 | } 21 | } catch(error) { 22 | logger.info({ error }, 'useGithub') 23 | return { 24 | username: '', 25 | repos: 0 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/screens/profile/_graphql/getBuilderInfo.graphql: -------------------------------------------------------------------------------- 1 | query getBuilderInfo($wallet: String!){ 2 | getProfile(filter:{ 3 | address:$wallet 4 | }) { 5 | _id 6 | telegram 7 | github 8 | bio 9 | twitter 10 | username 11 | imageURL 12 | proofs 13 | createdAt 14 | updatedAt 15 | } 16 | } -------------------------------------------------------------------------------- /src/screens/profile/_graphql/getMyProposals.graphql: -------------------------------------------------------------------------------- 1 | query getMyProposals($wallet: String!) { 2 | grantApplications(filter: { applicantId: $wallet }) { 3 | id: _id 4 | name: fieldFilterBySection(filter: { field: "projectName" }) { 5 | values { 6 | value 7 | } 8 | } 9 | grant { 10 | id: _id 11 | title 12 | workspace { 13 | logoIpfsHash 14 | } 15 | } 16 | state 17 | milestones { 18 | id: _id 19 | amount 20 | amountPaid 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/screens/profile/_graphql/getUserNameAvailability.graphql: -------------------------------------------------------------------------------- 1 | query getUsernameAvailablity($username: String!){ 2 | usernameCheck(username: $username) { 3 | isAvailable 4 | } 5 | } -------------------------------------------------------------------------------- /src/screens/profile/_utils/constant.ts: -------------------------------------------------------------------------------- 1 | export const supportedProviders = [ 2 | { 3 | 'name': 'arbitrum', 4 | 'icon': 'QmQfZEDeLroURuySnfKDF1XpwmU94cGULHZwQhaHPYZxiJ', 5 | }, 6 | { 7 | 'name': 'compound', 8 | 'icon': 'QmP2MjriVUqyxNPz2bpDP58Y3iNsTkyHdMo9aBj4to7vvW', 9 | }, 10 | { 11 | 'name': 'axelar', 12 | 'icon': 'QmbS1MwNDNPJt9ve4UYspg1WAqoYam6J6E2kVg24N9Nh3h', 13 | }, 14 | { 15 | 'name': 'polygon', 16 | 'icon': 'QmNfAjH9v44rgQA2aNy6k6iGh7u786r9ca3eXhxB6gk7Hb', 17 | }, 18 | { 19 | 'name': 'ens', 20 | 'icon': 'QmNrd1rxQx5BZzWFWY5ZSaFPhNXyijUSRCTLMVveHpK8LF', 21 | } 22 | ] -------------------------------------------------------------------------------- /src/screens/profile/_utils/formatters.ts: -------------------------------------------------------------------------------- 1 | export const timeAgo = (timestamp: string): String => { 2 | const now = new Date().getTime() 3 | const then = new Date(timestamp).getTime() 4 | const diffInMs = now - then 5 | 6 | const seconds = diffInMs / 1000 7 | const minutes = seconds / 60 8 | const hours = minutes / 60 9 | const days = hours / 24 10 | const weeks = days / 7 11 | const months = days / 30 12 | 13 | if(minutes < 1) { 14 | return `${Math.floor(seconds)} second(s) ago` 15 | } else if(hours < 1) { 16 | return `${Math.floor(minutes)} minute(s) ago` 17 | } else if(days < 1) { 18 | return `${Math.floor(hours)} hour(s) ago` 19 | } else if(days < 7) { 20 | return `${Math.floor(days)} day(s) ago` 21 | } else if(days < 30) { 22 | return `${Math.floor(weeks)} week(s) ago` 23 | } else { 24 | return `${Math.floor(months)} month(s) ago` 25 | } 26 | } -------------------------------------------------------------------------------- /src/screens/profile/data/getBuilderInfo.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | 3 | 4 | export const getBuilderInfo = gql`query getBuilderInfo($wallet: String!){ 5 | getProfile(filter:{ 6 | address:$wallet 7 | }) { 8 | _id 9 | address 10 | telegram 11 | github 12 | bio 13 | twitter 14 | username 15 | imageURL 16 | compound 17 | ens 18 | axelar 19 | polygon 20 | arbitrum 21 | createdAt 22 | updatedAt 23 | } 24 | }` -------------------------------------------------------------------------------- /src/screens/profile/data/getMyProposals.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getMyProposals = gql`query getMyProposals($wallet: String!) { 3 | grantApplications(filter: { applicantId: $wallet }) { 4 | id: _id 5 | name: fieldFilterBySection(filter: { field: "projectName" }) { 6 | values { 7 | value 8 | } 9 | } 10 | grant { 11 | id: _id 12 | title 13 | workspace { 14 | logoIpfsHash 15 | tokens { 16 | _id 17 | chainId 18 | decimal 19 | label 20 | } 21 | } 22 | } 23 | state 24 | milestones { 25 | id: _id 26 | amount 27 | amountPaid 28 | } 29 | } 30 | } 31 | ` -------------------------------------------------------------------------------- /src/screens/profile/data/getUserNameAvailability.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getUserNameAvailability = gql`query getUsernameAvailablity($username: String!){ 3 | usernameCheck(username: $username) { 4 | isAvailable 5 | } 6 | }` -------------------------------------------------------------------------------- /src/screens/profile/hooks/checkUsernameAvailablity.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react' 2 | import { useQuery } from 'src/libraries/hooks/useQuery' 3 | import { getUserNameAvailability } from 'src/screens/profile/data/getUserNameAvailability' 4 | 5 | const useCheckUsernameAvailability = (initialUsername: string = '') => { 6 | const [isUsernameAvailable, setIsUsernameAvailable] = useState(false) 7 | const [username, setUsername] = useState(initialUsername) 8 | 9 | const { fetchMore: fetchUsername } = useQuery({ 10 | query: getUserNameAvailability, 11 | }) 12 | 13 | const checkUsername = async(usernameToCheck: string): Promise => { 14 | const results = await fetchUsername({ 15 | username: usernameToCheck, 16 | }, true) as { usernameCheck: { isAvailable: boolean } } 17 | return results?.usernameCheck?.isAvailable || false 18 | } 19 | 20 | useEffect(() => { 21 | if(username) { 22 | checkUsername(username).then((result: boolean) => { 23 | setIsUsernameAvailable(result) 24 | }) 25 | } else { 26 | setIsUsernameAvailable(false) 27 | } 28 | }, [username]) 29 | 30 | return { isUsernameAvailable, checkUsername, setUsername } 31 | } 32 | 33 | export default useCheckUsernameAvailability -------------------------------------------------------------------------------- /src/screens/profile/hooks/generateProof.ts: -------------------------------------------------------------------------------- 1 | import { reclaimProof } from 'src/generated/mutation/reclaimProof' 2 | import { executeMutation } from 'src/graphql/apollo' 3 | 4 | export const generateProof = async(provider: string, address: string, proposalId?: string, pubKey?: string) => { 5 | try { 6 | const response = await executeMutation(reclaimProof, { type: provider, address, proposalId, pubKey }) 7 | if(response.generateProof) { 8 | return { 9 | requestUrl: response.generateProof.requestUrl, 10 | statusUrl: response.generateProof.statusUrl, 11 | sessionId: response.generateProof.sessionId, 12 | migrationId: response?.generateProof?.migrationId, 13 | error: false 14 | } 15 | } 16 | 17 | return { 18 | requestUrl: '', 19 | statusUrl: '', 20 | sessionId: '', 21 | migrationId: '', 22 | error: true 23 | } 24 | } catch(e) { 25 | return { 26 | requestUrl: '', 27 | statusUrl: '', 28 | sessionId: '', 29 | migrationId: '', 30 | error: true 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/screens/proposal_form/_components/SectionHeader.tsx: -------------------------------------------------------------------------------- 1 | import { Text, TextProps } from '@chakra-ui/react' 2 | 3 | function SectionHeader(props: TextProps) { 4 | const buildComponent = () => { 5 | return ( 6 | 14 | ) 15 | } 16 | 17 | return buildComponent() 18 | } 19 | 20 | export default SectionHeader -------------------------------------------------------------------------------- /src/screens/proposal_form/_components/SectionSelect.tsx: -------------------------------------------------------------------------------- 1 | import { Flex, FlexProps, NumberDecrementStepper, NumberIncrementStepper, NumberInput, NumberInputField, NumberInputProps, NumberInputStepper, Text } from '@chakra-ui/react' 2 | 3 | interface Props extends NumberInputProps { 4 | label: string 5 | flexProps?: FlexProps 6 | } 7 | 8 | function SectionSelect({ label, flexProps, ...props }: Props) { 9 | const buildComponent = () => { 10 | return ( 11 | 16 | 23 | {label} 24 | 25 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | ) 47 | } 48 | 49 | return buildComponent() 50 | } 51 | 52 | export default SectionSelect -------------------------------------------------------------------------------- /src/screens/proposal_form/_data/grantDetailsQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const grantDetailsQuery = gql`query grantDetails($grantId: String!) { 3 | grant(_id: $grantId) { 4 | id:_id 5 | creatorId 6 | title 7 | summary 8 | details 9 | reward { 10 | id:_id 11 | asset 12 | committed 13 | token { 14 | id:_id 15 | label 16 | address 17 | decimal 18 | iconHash 19 | chainId 20 | } 21 | } 22 | startDate 23 | deadline 24 | startDateS 25 | deadlineS 26 | payoutType 27 | reviewType 28 | link 29 | docIpfsHash 30 | acceptingApplications 31 | metadataHash 32 | funding 33 | workspace { 34 | id:_id 35 | title 36 | supportedNetworks 37 | logoIpfsHash 38 | safe { 39 | address 40 | chainId 41 | } 42 | } 43 | fields { 44 | id:_id 45 | title 46 | inputType 47 | possibleValues 48 | isPii 49 | } 50 | milestones 51 | } 52 | }` -------------------------------------------------------------------------------- /src/screens/proposal_form/_data/walletAddressCheckerQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const walletAddressCheckerQuery = gql`query walletAddressChecker($grantId:String!, $walletAddress:String!){ 3 | grantApplications(filter:{grant: $grantId, applicantId: $walletAddress} ) { 4 | id:_id 5 | walletAddress 6 | applicantId 7 | createdAtS 8 | } 9 | }` -------------------------------------------------------------------------------- /src/screens/proposal_form/_graphql/grantDetails.graphql: -------------------------------------------------------------------------------- 1 | query grantDetails($grantId: String!) { 2 | grant(_id: $grantId) { 3 | id:_id 4 | creatorId 5 | title 6 | summary 7 | details 8 | reward { 9 | id:_id 10 | asset 11 | committed 12 | token { 13 | id:_id 14 | label 15 | address 16 | decimal 17 | iconHash 18 | chainId 19 | } 20 | } 21 | startDate 22 | deadline 23 | startDateS 24 | deadlineS 25 | payoutType 26 | reviewType 27 | link 28 | docIpfsHash 29 | acceptingApplications 30 | metadataHash 31 | funding 32 | workspace { 33 | id:_id 34 | title 35 | supportedNetworks 36 | logoIpfsHash 37 | safe { 38 | address 39 | chainId 40 | } 41 | } 42 | fields { 43 | id:_id 44 | title 45 | inputType 46 | possibleValues 47 | isPii 48 | } 49 | milestones 50 | } 51 | } -------------------------------------------------------------------------------- /src/screens/proposal_form/_graphql/walletAddressChecker.graphql: -------------------------------------------------------------------------------- 1 | query walletAddressChecker($grantId:String!, $walletAddress:String!){ 2 | grantApplications(filter:{grant: $grantId, walletAddress: $walletAddress} ) { 3 | id:_id 4 | walletAddress 5 | applicantId 6 | createdAtS 7 | } 8 | } -------------------------------------------------------------------------------- /src/screens/proposal_form/_utils/types.ts: -------------------------------------------------------------------------------- 1 | import { EditorState } from 'draft-js' 2 | import { GrantDetailsQuery, GrantField, ProposalDetailsQuery } from 'src/generated/graphql' 3 | import SupportedChainId from 'src/generated/SupportedChainId' 4 | 5 | export type FormType = 'submit' | 'resubmit' 6 | 7 | export type ProposalFormContextType = { 8 | grant: Grant 9 | proposal: Proposal 10 | chainId: SupportedChainId 11 | form: Form 12 | setForm: (form: Form) => void 13 | type: FormType 14 | error?: string 15 | telegram: string 16 | setTelegram: (telegram: string) => void 17 | twitter: string 18 | setTwitter: (twitter: string) => void 19 | referral: { type: string, value: string } 20 | setReferral: (referral: { type: string, value: string }) => void 21 | newsletter: string 22 | setNewsLetter: (newsletter: string) => void 23 | } 24 | 25 | export type Grant = GrantDetailsQuery['grant'] 26 | export type Proposal = ProposalDetailsQuery['grantApplication'] 27 | 28 | export type FormField = { 29 | id: string 30 | value: string 31 | } & GrantField 32 | 33 | export type MilestoneType = { 34 | index: number 35 | title: string 36 | amount: number 37 | details?: string 38 | deadline?: string 39 | } 40 | 41 | export type Form = { 42 | fields: FormField[] 43 | milestones: MilestoneType[] 44 | members: string[] 45 | details: EditorState 46 | } -------------------------------------------------------------------------------- /src/screens/proposal_recovery/_graphql/getMigrationStatus.graphql: -------------------------------------------------------------------------------- 1 | query migrationStatus($id: MongoID!){ 2 | migration(_id: $id){ 3 | status 4 | } 5 | } -------------------------------------------------------------------------------- /src/screens/proposal_recovery/data/getMigrationStatusQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getMigrationStatusQuery = gql`query migrationStatus($id: MongoID!){ 3 | migration(_id: $id){ 4 | status 5 | } 6 | }` -------------------------------------------------------------------------------- /src/screens/request_proposal/_components/SelectDropdown.tsx: -------------------------------------------------------------------------------- 1 | import { Select, SingleValue, } from 'chakra-react-select' 2 | 3 | interface Props { 4 | options: T[] 5 | value?: SingleValue 6 | onChange: (value: SingleValue) => void 7 | placeholder?: string 8 | } 9 | 10 | function SelectDropdown({ options, placeholder, value, onChange }: Props) { 11 | return ( 12 | 13 | variant='flushed' 14 | options={options} 15 | placeholder={placeholder} 16 | selectedOptionStyle='check' 17 | onChange={onChange} 18 | value={value} 19 | chakraStyles={ 20 | { 21 | container: (provided) => ({ 22 | ...provided, 23 | width: '40%', 24 | fontSize: '96px', 25 | fontWeight: '400', 26 | color: 'black.100' 27 | }), 28 | valueContainer: (provided) => ({ 29 | ...provided, 30 | // fontSize: '16px', 31 | }), 32 | menu: (provided) => ({ 33 | ...provided, 34 | fontSize: '24px', 35 | fontWeight: '400', 36 | }) 37 | } 38 | } 39 | /> 40 | ) 41 | } 42 | 43 | export default SelectDropdown -------------------------------------------------------------------------------- /src/screens/request_proposal/_components/StepIndicator.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import { Container, Flex } from '@chakra-ui/react' 3 | import { WebwalletContext } from 'src/pages/_app' 4 | 5 | function StepIndicator() { 6 | const buildComponent = () => ( 7 | 12 | 0 ? 'accent.azure' : 'gray.200'} 17 | height={1} 18 | maxW='100%' 19 | /> 20 | 1 ? 'accent.azure' : 'gray.200'} 24 | height={1} 25 | /> 26 | 2 ? 'accent.azure' : 'gray.200'} 30 | height={1} 31 | maxW='100%' 32 | /> 33 | 34 | ) 35 | 36 | const { createingProposalStep } = useContext(WebwalletContext)! 37 | 38 | return buildComponent() 39 | } 40 | 41 | export default StepIndicator -------------------------------------------------------------------------------- /src/screens/request_proposal/_data/getGrantDetailsByIdQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getGrantDetailsByIdQuery = gql`query getGrantDetailsById($grantID: String!) { 3 | grant( 4 | _id: $grantID 5 | ) { 6 | id:_id 7 | creatorId 8 | title 9 | summary 10 | details 11 | link 12 | docIpfsHash 13 | payoutType 14 | reviewType 15 | rubric { 16 | id:_id 17 | } 18 | fields { 19 | id:_id 20 | title 21 | inputType 22 | isPii 23 | } 24 | reward { 25 | id:_id 26 | asset 27 | committed 28 | token { 29 | address 30 | label 31 | decimal 32 | iconHash 33 | } 34 | } 35 | startDate 36 | deadline 37 | funding 38 | acceptingApplications 39 | milestones 40 | rubric { 41 | isPrivate 42 | items { 43 | id:_id 44 | title 45 | details 46 | maximumPoints 47 | } 48 | } 49 | } 50 | }` -------------------------------------------------------------------------------- /src/screens/request_proposal/_data/getGrantDetailsQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | export const getGrantDetailsQuery = gql`query grantDetails($grantId: String!) { 3 | grant(_id: $grantId) { 4 | id:_id 5 | creatorId 6 | title 7 | summary 8 | details 9 | reward { 10 | id:_id 11 | asset 12 | committed 13 | token { 14 | id:_id 15 | label 16 | address 17 | decimal 18 | iconHash 19 | chainId 20 | } 21 | } 22 | startDate 23 | deadline 24 | startDateS 25 | deadlineS 26 | payoutType 27 | reviewType 28 | link 29 | docIpfsHash 30 | acceptingApplications 31 | metadataHash 32 | funding 33 | workspace { 34 | id:_id 35 | title 36 | supportedNetworks 37 | logoIpfsHash 38 | safe { 39 | address 40 | chainId 41 | } 42 | } 43 | fields: fields { 44 | id:_id 45 | title 46 | inputType 47 | possibleValues 48 | isPii 49 | } 50 | milestones 51 | } 52 | }` -------------------------------------------------------------------------------- /src/screens/request_proposal/_graphql/getGrantDetails.graphql: -------------------------------------------------------------------------------- 1 | query grantDetails($grantId: String!) { 2 | grant(_id: $grantId) { 3 | id:_id 4 | creatorId 5 | title 6 | summary 7 | details 8 | reward { 9 | id:_id 10 | asset 11 | committed 12 | token { 13 | id:_id 14 | label 15 | address 16 | decimal 17 | iconHash 18 | chainId 19 | } 20 | } 21 | startDate 22 | deadline 23 | startDateS 24 | deadlineS 25 | payoutType 26 | reviewType 27 | link 28 | docIpfsHash 29 | acceptingApplications 30 | metadataHash 31 | funding 32 | workspace { 33 | id:_id 34 | title 35 | supportedNetworks 36 | logoIpfsHash 37 | safe { 38 | address 39 | chainId 40 | } 41 | } 42 | fields: fields { 43 | id:_id 44 | title 45 | inputType 46 | possibleValues 47 | isPii 48 | } 49 | milestones 50 | } 51 | } -------------------------------------------------------------------------------- /src/screens/request_proposal/_graphql/getGrantDetailsById.graphql: -------------------------------------------------------------------------------- 1 | query getGrantDetailsById($grantID: String!) { 2 | grant( 3 | _id: $grantID 4 | ) { 5 | id:_id 6 | creatorId 7 | title 8 | summary 9 | details 10 | link 11 | docIpfsHash 12 | payoutType 13 | reviewType 14 | rubric { 15 | id:_id 16 | } 17 | fields { 18 | id:_id 19 | title 20 | inputType 21 | isPii 22 | } 23 | reward { 24 | id:_id 25 | asset 26 | committed 27 | token { 28 | address 29 | label 30 | decimal 31 | iconHash 32 | } 33 | } 34 | startDate 35 | deadline 36 | funding 37 | acceptingApplications 38 | milestones 39 | rubric { 40 | isPrivate 41 | items { 42 | id:_id 43 | title 44 | details 45 | maximumPoints 46 | } 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /src/screens/request_proposal/_utils/constants.ts: -------------------------------------------------------------------------------- 1 | export const requiredRubrics = ['Team competence', 'Idea Quality', 'Relevance to our ecosystem'] 2 | 3 | // eslint-disable-next-line no-restricted-syntax 4 | export enum PayoutMode { 5 | IN_ONE_GO = 'in one go', 6 | BASED_ON_MILESTONE = 'based on milestone' 7 | } -------------------------------------------------------------------------------- /src/screens/settings/_components/DropdownIcon.tsx: -------------------------------------------------------------------------------- 1 | import { createIcon } from '@chakra-ui/react' 2 | 3 | export const DropdownIcon = createIcon({ 4 | displayName: 'DropdownIcon', 5 | viewBox: '0 0 24 24', 6 | path: ( 7 | 13 | 16 | 17 | ) 18 | 19 | }) -------------------------------------------------------------------------------- /src/screens/settings/_graphql/getWorkspaceDetails.graphql: -------------------------------------------------------------------------------- 1 | query getWorkspaceDetails($workspaceID: String!) { 2 | workspace(_id: $workspaceID) { 3 | id:_id 4 | title 5 | bio 6 | about 7 | logoIpfsHash 8 | coverImageIpfsHash 9 | supportedNetworks 10 | safe { 11 | address 12 | chainId 13 | } 14 | partners { 15 | name 16 | industry 17 | website 18 | partnerImageHash 19 | } 20 | socials { 21 | name 22 | value 23 | } 24 | tokens { 25 | address 26 | label 27 | decimal 28 | iconHash 29 | } 30 | member:membersFilter(filter: { 31 | enabled: true 32 | }) { 33 | id:_id 34 | actorId 35 | publicKey 36 | email 37 | accessLevel 38 | updatedAt 39 | outstandingReviewIds 40 | lastReviewSubmittedAt 41 | enabled 42 | addedBy { 43 | id:_id 44 | actorId 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/screens/settings/_graphql/getWorkspaceMembersByWorkspaceId.graphql: -------------------------------------------------------------------------------- 1 | query getWorkspaceMembersByWorkspaceId( 2 | $workspaceId: String! 3 | $first: Int 4 | $skip: Int 5 | ) { 6 | workspaceMembers( 7 | filter: { workspace: $workspaceId } 8 | limit: $first 9 | skip: $skip 10 | ) { 11 | id:_id 12 | actorId 13 | fullName 14 | profilePictureIpfsHash 15 | accessLevel 16 | addedAt 17 | publicKey 18 | email 19 | enabled 20 | pii { 21 | id:_id 22 | data 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/screens/settings/_utils/types.ts: -------------------------------------------------------------------------------- 1 | import { GetWorkspaceDetailsQuery, GetWorkspaceMembersByWorkspaceIdQuery } from 'src/generated/graphql' 2 | import { MinimalWorkspace } from 'src/types' 3 | 4 | export type SettingsFormContextType = { 5 | workspace: MinimalWorkspace 6 | workspaceMembers: WorkspaceMembers 7 | grantProgramData: GrantProgramForm 8 | setGrantProgramData: (data: GrantProgramForm) => void 9 | safeURL: string 10 | refreshWorkspace: (refresh: boolean) => void 11 | } 12 | 13 | export type Workspace = GetWorkspaceDetailsQuery['workspace'] 14 | export type WorkspaceMembers = GetWorkspaceMembersByWorkspaceIdQuery['workspaceMembers'] 15 | 16 | export type SocialLinks = { 17 | name: string 18 | value: string 19 | } 20 | 21 | export type GrantProgramForm = { 22 | title: string 23 | about: string 24 | bio: string 25 | socials?: SocialLinks[] 26 | logoIpfsHash: string 27 | } -------------------------------------------------------------------------------- /src/screens/settings/data/getWorkspaceDetailsQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | 3 | 4 | export const getWorkspaceDetailsQuery = gql`query getWorkspaceDetails($workspaceID: String!) { 5 | workspace(_id: $workspaceID) { 6 | id:_id 7 | title 8 | bio 9 | about 10 | logoIpfsHash 11 | coverImageIpfsHash 12 | supportedNetworks 13 | safe { 14 | address 15 | chainId 16 | } 17 | partners { 18 | name 19 | industry 20 | website 21 | partnerImageHash 22 | } 23 | socials { 24 | name 25 | value 26 | } 27 | tokens { 28 | address 29 | label 30 | decimal 31 | iconHash 32 | } 33 | member:membersFilter(filter: { 34 | enabled: true 35 | }) { 36 | id:_id 37 | actorId 38 | publicKey 39 | email 40 | accessLevel 41 | updatedAt 42 | outstandingReviewIds 43 | lastReviewSubmittedAt 44 | enabled 45 | addedBy { 46 | id:_id 47 | actorId 48 | } 49 | } 50 | } 51 | } 52 | ` -------------------------------------------------------------------------------- /src/screens/settings/data/getWorkspaceMembersByWorkspaceIdQuery.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | 3 | 4 | export const getWorkspaceMembersByWorkspaceIdQuery = gql` 5 | query getWorkspaceMembersByWorkspaceId( 6 | $workspaceId: String! 7 | $first: Int 8 | $skip: Int 9 | ) { 10 | workspaceMembers( 11 | filter: { workspace: $workspaceId, enabled: true } 12 | limit: $first 13 | skip: $skip 14 | ) { 15 | id:_id 16 | actorId 17 | fullName 18 | profilePictureIpfsHash 19 | accessLevel 20 | addedAt 21 | publicKey 22 | email 23 | enabled 24 | pii { 25 | id:_id 26 | data 27 | } 28 | } 29 | } 30 | ` -------------------------------------------------------------------------------- /src/screens/settings/data/index.ts: -------------------------------------------------------------------------------- 1 | export { getWorkspaceMembersByWorkspaceIdQuery } from './getWorkspaceMembersByWorkspaceIdQuery' 2 | export { getWorkspaceDetailsQuery } from './getWorkspaceDetailsQuery' -------------------------------------------------------------------------------- /src/theme/colors.tsx: -------------------------------------------------------------------------------- 1 | const colors = { 2 | brand: { 3 | green: '#B6F72B', 4 | ivory: '#F8FFF2', 5 | blue: '#C2E7DA', 6 | }, 7 | white: '#FFFFFF', 8 | gray: { 9 | 100: '#F7F5F2', 10 | 200: '#F1EEE8', 11 | 300: '#E7E4DD', 12 | 400: '#C1BDB7', 13 | 500: '#8D8B87', 14 | 600: '#767471' 15 | }, 16 | black: { 17 | 100: '#1D1919', 18 | 200: '#2B2929', 19 | 300: '#53514F' 20 | }, 21 | green:{ 22 | 100: '#5AB711' 23 | }, 24 | accent: { 25 | azure: '#0A84FF', 26 | carrot: '#EF6436', 27 | vivid: '#5C62F5', 28 | orchid: '#DC6ACF', 29 | jeans: '#56C7EC', 30 | royal: '#F2943E', 31 | june: '#BCDB4A', 32 | steel: '#B8C7DF', 33 | columbia: '#C2E7DA', 34 | vodka: '#C4B0EB', 35 | melon: '#F3B2A8', 36 | crayola: '#F4D364', 37 | } 38 | } 39 | 40 | export default colors -------------------------------------------------------------------------------- /src/theme/components/container.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | Container: { 3 | variants: { 4 | 'header-container': { 5 | boxShadow: '0px 4px 20px -8px rgba(9, 17, 18, 0.2)', 6 | display: 'flex', 7 | h: 20, 8 | alignItems: 'center', 9 | }, 10 | }, 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /src/theme/components/divider.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | Divider: { 3 | baseStyle: { 4 | borderColor: '#E8E9E9', 5 | opacity: 1, 6 | }, 7 | variants: { 8 | sidebar: { 9 | background: '#E0E0EC', 10 | height: '1px', 11 | opacity: 0.6, 12 | }, 13 | table: { 14 | background: 'black', 15 | height: '2px', 16 | opacity: 1, 17 | }, 18 | }, 19 | }, 20 | } 21 | -------------------------------------------------------------------------------- /src/theme/components/header.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | Heading: { 3 | variants: { 4 | modal: { 5 | fontFamily: 'Spartan', 6 | fontSize: '28px', 7 | fontWeight: 600, 8 | lineHeight: '40px', 9 | }, 10 | page: { 11 | fontFamily: 'DM Sans', 12 | fontSize: '28px', 13 | fontStyle: 'normal', 14 | fontWeight: 700, 15 | lineHeight: '40px', 16 | letterSpacing: '0px', 17 | }, 18 | applicationHeading: { 19 | color: '#122224', 20 | fontWeight: '700', 21 | fontSize: '16px', 22 | lineSpacing: '0.5px', 23 | lineHeight: '24px', 24 | }, 25 | applicationSubtitle: { 26 | color: '#717A7C', 27 | fontWeight: '400', 28 | fontSize: '16px', 29 | lineSpacing: '0.5px', 30 | lineHeight: '24px', 31 | }, 32 | content: { 33 | fontSize: '2rem', 34 | fontWeight: '500', 35 | lineHeight: '2.5rem', 36 | fontFamily: 'Neue-Haas-Grotesk-Display, sans-serif', 37 | }, 38 | small: { 39 | fontSize: '1.5rem', 40 | fontWeight: '700', 41 | lineHeight: '32px', 42 | fontFamily: 'Neue-Haas-Grotesk-Display, sans-serif', 43 | } 44 | }, 45 | }, 46 | } 47 | -------------------------------------------------------------------------------- /src/theme/components/link.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | Link: { 3 | baseStyle: { 4 | color: 'brand.500', 5 | whiteSpace: 'nowrap', 6 | }, 7 | variants: { 8 | black: { 9 | color: 'black', 10 | fontWeight: 400, 11 | }, 12 | basev2: { 13 | fontWeight: '500', 14 | color: 'black', 15 | }, 16 | }, 17 | }, 18 | } 19 | -------------------------------------------------------------------------------- /src/theme/components/progress.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | Progress: { 3 | baseStyle: { 4 | // @TODO: Not able to modify base theme of progress 5 | borderRadius: '24px', 6 | }, 7 | }, 8 | } 9 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "target": "es5", 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "allowJs": true, 7 | "skipLibCheck": true, 8 | "strict": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "noEmit": true, 11 | "esModuleInterop": true, 12 | "module": "commonjs", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "jsx": "preserve", 17 | "incremental": true, 18 | }, 19 | "include": ["next-env.d.ts", "next.config.js", "sentry.client.config.ts", "sentry.server.config.ts", "src/**/*.ts", "src/**/*.tsx"], 20 | "exclude": ["node_modules"] 21 | } 22 | --------------------------------------------------------------------------------