diff --git a/src/components/Create/Create.tsx b/src/components/Create/Create.tsx
index 1741f23c2c..b778396280 100644
--- a/src/components/Create/Create.tsx
+++ b/src/components/Create/Create.tsx
@@ -12,8 +12,8 @@ import { NetworkName } from 'models/networkName'
import Link from 'next/link'
import { useRouter } from 'next/router'
import {
+ AddNftCollectionForm,
FundingCyclesPage,
- NftRewardsPage,
ProjectDetailsPage,
ProjectTokenPage,
ReconfigurationRulesPage,
@@ -124,7 +124,7 @@ export function Create() {
Reward your supporters with custom NFTs.
}
>
-
+
Review & confirm}
destroyOnClose
- onOk={reconfigureFundingCycle}
+ onOk={() => reconfigureFundingCycle()}
okText={Deploy changes}
okButtonProps={{ disabled: !formHasChanges }}
cancelButtonProps={{ hidden: true }}
diff --git a/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/NewEditNftsPage/EditNftsPage.tsx b/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/NewEditNftsPage/EditNftsPage.tsx
new file mode 100644
index 0000000000..ededc40b4d
--- /dev/null
+++ b/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/NewEditNftsPage/EditNftsPage.tsx
@@ -0,0 +1,31 @@
+import Loading from 'components/Loading'
+import { ProjectMetadataContext } from 'contexts/shared/ProjectMetadataContext'
+import { V2V3ProjectContext } from 'contexts/v2v3/Project/V2V3ProjectContext'
+import { useNftDeployerCanReconfigure } from 'hooks/JB721Delegate/contractReader/useNftDeployerCanReconfigure'
+import { useHasNftRewards } from 'hooks/JB721Delegate/useHasNftRewards'
+import { useContext } from 'react'
+import { EditNftsTabs } from '../EditNftsPage/EditNftsTabs'
+import { EnableNftsCard } from './EnableNftsCard'
+import { LaunchNftsPage } from './LaunchNftsPage'
+
+export function EditNftsPage() {
+ const { projectId } = useContext(ProjectMetadataContext)
+ const { projectOwnerAddress } = useContext(V2V3ProjectContext)
+ const { value: hasExistingNfts, loading: hasNftsLoading } = useHasNftRewards()
+
+ const nftDeployerCanReconfigure = useNftDeployerCanReconfigure({
+ projectId,
+ projectOwnerAddress,
+ })
+
+ if (hasNftsLoading) {
+ return
+ }
+ if (hasExistingNfts) {
+ return
+ } else if (!nftDeployerCanReconfigure) {
+ return
+ } else {
+ return
+ }
+}
diff --git a/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/NewEditNftsPage/EnableNftsModal.tsx b/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/NewEditNftsPage/EnableNftsModal.tsx
index fc62ba6cb1..72a316d6e6 100644
--- a/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/NewEditNftsPage/EnableNftsModal.tsx
+++ b/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/NewEditNftsPage/EnableNftsModal.tsx
@@ -43,7 +43,7 @@ export function EnableNftsModal({
confirmLoading={loading}
>
- To add NFTs to your next cycle. You'll need to{' '}
+ To add NFTs to your next cycle, you'll need to{' '}
grant NFT permissions.
{' '}
state.editingV2Project)
- const dispatch = useDispatch()
-
- const editingFundingCycleConfig = useEditingFundingCycleConfig()
- const { reconfigureLoading, reconfigureFundingCycle } =
- useReconfigureFundingCycle({
- editingFundingCycleConfig,
- memo: 'First NFT collection',
- launchedNewNfts: true,
- })
-
- const onNftDeploy = async () => {
- const newRewardTiers =
- editingFundingCycleConfig.editingNftRewards?.rewardTiers
- const collectionName =
- editingFundingCycleConfig.editingNftRewards?.collectionMetadata.name ?? ''
- const collectionDescription =
- editingFundingCycleConfig.editingNftRewards?.collectionMetadata
- .description ?? ''
- const collectionLogoUri = logoUri ?? ''
- const collectionInfoUri =
- editingFundingCycleConfig.editingNftRewards?.collectionMetadata.uri ?? ''
-
- const [rewardTiersCIDs, nftCollectionMetadataUri] = await Promise.all([
- newRewardTiers ? pinNftRewards(newRewardTiers) : [],
- pinNftCollectionMetadata({
- collectionName,
- collectionDescription,
- collectionLogoUri,
- collectionInfoUri,
- }),
- ])
- console.info('rewardTiersCIDs: ', rewardTiersCIDs)
- console.info('nftCollectionMetadataUri: ', nftCollectionMetadataUri)
- dispatch(editingV2ProjectActions.setNftRewardsCIDs(rewardTiersCIDs))
- dispatch(
- editingV2ProjectActions.setNftRewardsCollectionMetadataUri(
- nftCollectionMetadataUri,
- ),
- )
- reconfigureFundingCycle()
- }
-
- return (
-
- Deploy NFT collection
-
- }
- />
- )
-}
diff --git a/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/NewEditNftsPage/LaunchNftsAdvanced.tsx b/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/NewEditNftsPage/LaunchNftsAdvanced.tsx
deleted file mode 100644
index d285afd913..0000000000
--- a/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/NewEditNftsPage/LaunchNftsAdvanced.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import { Trans } from '@lingui/macro'
-import { Form } from 'antd'
-import TooltipLabel from 'components/TooltipLabel'
-import { JuiceSwitch } from 'components/inputs/JuiceSwitch'
-import { AdvancedDropdown } from '../NewEditCyclePage/AdvancedDropdown'
-
-export function LaunchNftsAdvanced() {
- return (
-
- {/* On-chain Governace (simple 2-option Select) */}
- {/* Payment success message */}
-
- Use NFTs for redemption}
- tip={
-
- Contributors will redeem from the project's treasury with
- their NFTs as opposed to standard project tokens.
-
- }
- />
- }
- />
-
- {/* Prevent NFT overspending */}
-
- )
-}
diff --git a/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/NewEditNftsPage/LaunchNftsPage.tsx b/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/NewEditNftsPage/LaunchNftsPage.tsx
new file mode 100644
index 0000000000..ca5c19c30e
--- /dev/null
+++ b/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/NewEditNftsPage/LaunchNftsPage.tsx
@@ -0,0 +1,10 @@
+import { AddNftCollectionForm } from 'components/Create/components'
+import { UploadAndLaunchNftsButton } from './UploadAndLaunchNftsButton'
+
+export function LaunchNftsPage() {
+ return (
+ }
+ />
+ )
+}
diff --git a/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/NewEditNftsPage/NewEditNftsPage.tsx b/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/NewEditNftsPage/NewEditNftsPage.tsx
deleted file mode 100644
index 4bd74ba3f4..0000000000
--- a/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/NewEditNftsPage/NewEditNftsPage.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import Loading from 'components/Loading'
-import { useHasNftRewards } from 'hooks/JB721Delegate/useHasNftRewards'
-import { EditNftsTabs } from '../EditNftsPage/EditNftsTabs'
-import { LaunchNftCollection } from './LaunchNftCollection'
-
-export function NewEditNftsPage() {
- const { value: hasExistingNfts, loading: hasNftsLoading } = useHasNftRewards()
-
- if (hasNftsLoading) {
- return
- }
- if (hasExistingNfts) {
- return
- } else {
- return
- }
-}
diff --git a/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/NewEditNftsPage/UploadAndLaunchNftsButton.tsx b/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/NewEditNftsPage/UploadAndLaunchNftsButton.tsx
new file mode 100644
index 0000000000..3b7f0bab9d
--- /dev/null
+++ b/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/NewEditNftsPage/UploadAndLaunchNftsButton.tsx
@@ -0,0 +1,95 @@
+import { Trans } from '@lingui/macro'
+import { Button } from 'antd'
+import { useState } from 'react'
+import { useAppSelector } from 'redux/hooks/useAppSelector'
+import { pinNftCollectionMetadata, pinNftRewards } from 'utils/nftRewards'
+import {
+ EditingFundingCycleConfig,
+ useEditingFundingCycleConfig,
+} from '../ReconfigureFundingCycleSettingsPage/hooks/useEditingFundingCycleConfig'
+import { useReconfigureFundingCycle } from '../ReconfigureFundingCycleSettingsPage/hooks/useReconfigureFundingCycle'
+
+export function UploadAndLaunchNftsButton({
+ className,
+}: {
+ className?: string
+}) {
+ const [ipfsUploading, setIpfsUploading] = useState(false)
+
+ const {
+ projectMetadata: { logoUri },
+ } = useAppSelector(state => state.editingV2Project)
+
+ const editingFundingCycleConfig = useEditingFundingCycleConfig()
+ const { reconfigureLoading, reconfigureFundingCycle } =
+ useReconfigureFundingCycle({
+ editingFundingCycleConfig,
+ memo: 'First NFT collection',
+ launchedNewNfts: true,
+ })
+
+ const {
+ editingPayoutGroupedSplits,
+ editingReservedTokensGroupedSplits,
+ editingFundingCycleMetadata,
+ editingFundingCycleData,
+ editingFundAccessConstraints,
+ editingNftRewards,
+ editingMustStartAtOrAfter,
+ } = editingFundingCycleConfig
+
+ const uploadNftsToIpfs = async () => {
+ setIpfsUploading(true)
+ const newRewardTiers =
+ editingFundingCycleConfig.editingNftRewards?.rewardTiers
+ const collectionName =
+ editingFundingCycleConfig.editingNftRewards?.collectionMetadata.name ?? ''
+ const collectionDescription =
+ editingFundingCycleConfig.editingNftRewards?.collectionMetadata
+ .description ?? ''
+ const collectionLogoUri = logoUri ?? ''
+ const collectionInfoUri =
+ editingFundingCycleConfig.editingNftRewards?.collectionMetadata.uri ?? ''
+
+ const [rewardTiersCIDs, nftCollectionMetadataUri] = await Promise.all([
+ newRewardTiers ? pinNftRewards(newRewardTiers) : [],
+ pinNftCollectionMetadata({
+ collectionName,
+ collectionDescription,
+ collectionLogoUri,
+ collectionInfoUri,
+ }),
+ ])
+ const latestEditingData: EditingFundingCycleConfig = {
+ editingPayoutGroupedSplits,
+ editingReservedTokensGroupedSplits,
+ editingFundingCycleMetadata,
+ editingFundingCycleData,
+ editingFundAccessConstraints,
+ editingNftRewards: editingNftRewards
+ ? {
+ ...editingNftRewards,
+ collectionMetadata: {
+ ...editingNftRewards.collectionMetadata,
+ uri: nftCollectionMetadataUri,
+ },
+ CIDs: rewardTiersCIDs,
+ }
+ : undefined,
+ editingMustStartAtOrAfter,
+ }
+ reconfigureFundingCycle(latestEditingData)
+ setIpfsUploading(false)
+ }
+
+ return (
+
+ )
+}
diff --git a/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/ReconfigureFundingCycleSettingsPage/hooks/useReconfigureFundingCycle.ts b/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/ReconfigureFundingCycleSettingsPage/hooks/useReconfigureFundingCycle.ts
index 7ee6a2b5c6..d1ced0c89a 100644
--- a/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/ReconfigureFundingCycleSettingsPage/hooks/useReconfigureFundingCycle.ts
+++ b/src/components/v2v3/V2V3Project/V2V3ProjectSettings/pages/ReconfigureFundingCycleSettingsPage/hooks/useReconfigureFundingCycle.ts
@@ -57,10 +57,6 @@ export const useReconfigureFundingCycle = ({
const {
nftRewards: { CIDs: nftRewardsCids },
} = useContext(NftRewardsContext)
- console.info(
- 'TODO REMOVE: editingFundingCycleConfig: ',
- editingFundingCycleConfig,
- )
const [reconfigureTxLoading, setReconfigureTxLoading] =
useState(false)
@@ -69,111 +65,109 @@ export const useReconfigureFundingCycle = ({
const reconfigureV2V3FundingCycleWithNftsTx =
useReconfigureV2V3FundingCycleWithNftsTx()
- const {
- editingPayoutGroupedSplits,
- editingReservedTokensGroupedSplits,
- editingFundingCycleMetadata,
- editingFundingCycleData,
- editingFundAccessConstraints,
- editingNftRewards,
- editingMustStartAtOrAfter,
- } = editingFundingCycleConfig
-
- const reconfigureFundingCycle = useCallback(async () => {
- setReconfigureTxLoading(true)
- if (
- !(
- fundingCycle &&
- editingFundingCycleData &&
- editingFundingCycleMetadata &&
- editingFundAccessConstraints
- )
- ) {
- setReconfigureTxLoading(false)
- throw new Error('Error deploying project.')
- }
-
- // Projects with NFT rewards need useDataSourceForPay to be true for NFT rewards to work
- const fundingCycleMetadata = nftRewardsCids?.length
- ? {
- ...editingFundingCycleMetadata,
- ...NFT_FUNDING_CYCLE_METADATA_OVERRIDES,
- }
- : editingFundingCycleMetadata
-
- const weight = getWeightArgument({
- currentFundingCycleWeight: fundingCycle.weight,
- newFundingCycleWeight: editingFundingCycleData.weight,
- })
-
- const reconfigureFundingCycleData: ReconfigureFundingCycleTxParams = {
- fundingCycleData: {
- ...editingFundingCycleData,
- weight,
- },
- fundingCycleMetadata,
- fundAccessConstraints: editingFundAccessConstraints,
- groupedSplits: [
+ // If given a latestEditingData, will use that. Else, will use redux store
+ const reconfigureFundingCycle = useCallback(
+ async (latestEditingData?: EditingFundingCycleConfig) => {
+ const {
editingPayoutGroupedSplits,
editingReservedTokensGroupedSplits,
- ],
- memo,
- mustStartAtOrAfter: editingMustStartAtOrAfter,
- }
+ editingFundingCycleMetadata,
+ editingFundingCycleData,
+ editingFundAccessConstraints,
+ editingNftRewards,
+ editingMustStartAtOrAfter,
+ } = latestEditingData ?? editingFundingCycleConfig
- const txOpts = {
- async onConfirmed() {
- if (projectId) {
- await revalidateProject({
- pv: PV_V2,
- projectId: String(projectId),
- })
- }
+ setReconfigureTxLoading(true)
+ if (
+ !(
+ fundingCycle &&
+ editingFundingCycleData &&
+ editingFundingCycleMetadata &&
+ editingFundAccessConstraints
+ )
+ ) {
setReconfigureTxLoading(false)
- if (onComplete) {
- onComplete()
- } else {
- reloadWindow()
- }
- },
- }
+ throw new Error('Error deploying project.')
+ }
+
+ // Projects with NFT rewards need useDataSourceForPay to be true for NFT rewards to work
+ const fundingCycleMetadata = nftRewardsCids?.length
+ ? {
+ ...editingFundingCycleMetadata,
+ ...NFT_FUNDING_CYCLE_METADATA_OVERRIDES,
+ }
+ : editingFundingCycleMetadata
- let txSuccessful: boolean
- if (launchedNewNfts && editingNftRewards?.rewardTiers) {
- txSuccessful = await reconfigureV2V3FundingCycleWithNftsTx(
- {
- reconfigureData: reconfigureFundingCycleData,
- tiered721DelegateData: editingNftRewards,
+ const weight = getWeightArgument({
+ currentFundingCycleWeight: fundingCycle.weight,
+ newFundingCycleWeight: editingFundingCycleData.weight,
+ })
+
+ const reconfigureFundingCycleData: ReconfigureFundingCycleTxParams = {
+ fundingCycleData: {
+ ...editingFundingCycleData,
+ weight,
+ },
+ fundingCycleMetadata,
+ fundAccessConstraints: editingFundAccessConstraints,
+ groupedSplits: [
+ editingPayoutGroupedSplits,
+ editingReservedTokensGroupedSplits,
+ ],
+ memo,
+ mustStartAtOrAfter: editingMustStartAtOrAfter,
+ }
+
+ const txOpts = {
+ async onConfirmed() {
+ if (projectId) {
+ await revalidateProject({
+ pv: PV_V2,
+ projectId: String(projectId),
+ })
+ }
+ setReconfigureTxLoading(false)
+ if (onComplete) {
+ onComplete()
+ } else {
+ reloadWindow()
+ }
},
- txOpts,
- )
- } else {
- txSuccessful = await reconfigureV2V3FundingCycleTx(
- reconfigureFundingCycleData,
- txOpts,
- )
- }
+ }
+
+ let txSuccessful: boolean
+ if (launchedNewNfts && editingNftRewards?.rewardTiers) {
+ txSuccessful = await reconfigureV2V3FundingCycleWithNftsTx(
+ {
+ reconfigureData: reconfigureFundingCycleData,
+ tiered721DelegateData: editingNftRewards,
+ },
+ txOpts,
+ )
+ } else {
+ txSuccessful = await reconfigureV2V3FundingCycleTx(
+ reconfigureFundingCycleData,
+ txOpts,
+ )
+ }
- if (!txSuccessful) {
- setReconfigureTxLoading(false)
- }
- }, [
- editingFundingCycleData,
- editingFundingCycleMetadata,
- editingFundAccessConstraints,
- reconfigureV2V3FundingCycleTx,
- reconfigureV2V3FundingCycleWithNftsTx,
- launchedNewNfts,
- editingNftRewards,
- editingPayoutGroupedSplits,
- editingReservedTokensGroupedSplits,
- editingMustStartAtOrAfter,
- nftRewardsCids,
- fundingCycle,
- memo,
- onComplete,
- projectId,
- ])
+ if (!txSuccessful) {
+ setReconfigureTxLoading(false)
+ }
+ },
+ [
+ editingFundingCycleConfig,
+ reconfigureV2V3FundingCycleTx,
+ reconfigureV2V3FundingCycleWithNftsTx,
+ launchedNewNfts,
+ nftRewardsCids,
+ fundingCycle,
+ memo,
+ onComplete,
+ projectId,
+ ],
+ )
return { reconfigureLoading: reconfigureTxLoading, reconfigureFundingCycle }
}
diff --git a/src/locales/messages.pot b/src/locales/messages.pot
index f6b0815014..f3bacdfd41 100644
--- a/src/locales/messages.pot
+++ b/src/locales/messages.pot
@@ -152,9 +152,6 @@ msgstr ""
msgid "Data from current cycle"
msgstr ""
-msgid "Contributors will redeem from the project's treasury with their NFTs as opposed to standard project tokens."
-msgstr ""
-
msgid "You're about to add NFTs to your cycle. You'll need to <0>grant NFT permissions0> before deploying the new cycle"
msgstr ""
@@ -497,9 +494,6 @@ msgstr ""
msgid "Due to your <0>{0}0> contract, edits you make will not take effect until the first cycle to start at least <1>{1}1> from now."
msgstr ""
-msgid "To add NFTs to your next cycle. You'll need to <0>grant NFT permissions0>."
-msgstr ""
-
msgid "Payer issuance rate"
msgstr ""
@@ -1022,6 +1016,9 @@ msgstr ""
msgid "<0><1>Peel1> manages this website — the juicebox.money frontend interface. You can reach out to Peel through the <2>Peel Discord2>.0><3><4>JuiceboxDAO4> builds and governs the Juicebox fundraising protocol and other community resources. You can reach out to JuiceboxDAO through the <5>Juicebox Discord5>.3>"
msgstr ""
+msgid "To add NFTs to your next cycle, you'll need to <0>grant NFT permissions0>."
+msgstr ""
+
msgid "Email address"
msgstr ""
@@ -3578,9 +3575,6 @@ msgstr ""
msgid "Burn your {tokensLabel}. You won't receive ETH in return because this project has no ETH, or is using all of its ETH for payouts."
msgstr ""
-msgid "Use NFTs for redemption"
-msgstr ""
-
msgid "JB vs. Kickstarter"
msgstr ""
diff --git a/src/utils/nftRewards.ts b/src/utils/nftRewards.ts
index 67ee9ce755..d795111266 100644
--- a/src/utils/nftRewards.ts
+++ b/src/utils/nftRewards.ts
@@ -175,6 +175,7 @@ export async function pinNftCollectionMetadata({
: 'https://juicebox.money',
fee_recipient: undefined,
}
+
const res = await pinJson(IPFSNftCollectionMetadata)
return res.Hash
}