Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: ensure that project chain is defined at beginning #4577

Merged
merged 3 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/locales/messages.pot
Original file line number Diff line number Diff line change
Expand Up @@ -1904,6 +1904,9 @@ msgstr ""
msgid "The amount of ETH in the wallet that owns this project."
msgstr ""

msgid "A project chain"
msgstr ""

msgid "Get paid in ETH, program your own payouts, token issuance, and redemptions to easily run your treasury completely on-chain — as your community grows, you can update your treasury's rules to grow with it."
msgstr ""

Expand Down
15 changes: 7 additions & 8 deletions src/packages/v4/components/Create/DeployProjectButtonText.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import { NETWORKS } from 'constants/networks'
import { Trans } from '@lingui/macro'
import { useAppSelector } from 'redux/hooks/useAppSelector'
import { NETWORKS } from 'constants/networks'
import useMobile from 'hooks/useMobile'
import { useWallet } from 'hooks/Wallet'
import { useAppSelector } from 'redux/hooks/useAppSelector'

export function DeployProjectButtonText() {
const isMobile = useMobile()
const { isConnected, chain } = useWallet()

const {
projectChainId,
} = useAppSelector(state => state.creatingV2Project)
const { projectChainId } = useAppSelector(state => state.creatingV2Project)

const walletConnectedToWrongChain = chain?.id && projectChainId !== parseInt(chain.id)
const walletConnectedToWrongChain =
chain?.id && projectChainId !== parseInt(chain.id)

if (!isConnected) {
return isMobile ? (
Expand All @@ -30,8 +29,8 @@ export function DeployProjectButtonText() {
)
}

if (chain?.name && !isMobile) {
return <Trans>Deploy project to {NETWORKS[projectChainId]?.label}</Trans>
if (projectChainId && NETWORKS[projectChainId]?.label && !isMobile) {
return <Trans>Deploy project to {NETWORKS[projectChainId].label}</Trans>
}

return <Trans>Deploy project</Trans>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,34 @@
import { DEFAULT_PROJECT_CHAIN_ID, NETWORKS, SupportedChainId } from "constants/networks"
import {
DEFAULT_PROJECT_CHAIN_ID,
NETWORKS,
SupportedChainId,
} from 'constants/networks'

import { JuiceListbox } from "components/inputs/JuiceListbox"
import { JuiceListbox } from 'components/inputs/JuiceListbox'

export const ProjectChainSelect: React.FC<
React.PropsWithChildren<{
value?: SupportedChainId
onChange?: (value: SupportedChainId) => void
}>
> = ({ value, onChange }) => {

const networkOptions = () => Object.entries(NETWORKS).map(
([chainId, networkInfo]) => ({
label: networkInfo.label,
const networkOptions = () =>
Object.entries(NETWORKS).map(([chainId, networkInfo]) => ({
label: networkInfo.label,
value: parseInt(chainId),
})
)
}))

return (
<JuiceListbox
value={{label: NETWORKS[value ?? DEFAULT_PROJECT_CHAIN_ID]?.label, value }}
value={{
label: NETWORKS[value ?? DEFAULT_PROJECT_CHAIN_ID]?.label,
value,
}}
onChange={({ value }) => {
if (!value) return
onChange?.(value)
}}
options={networkOptions()}
/>
)
}
}
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
import { Col, Form, Row } from 'antd'
import { Trans, t } from '@lingui/macro'
import { Col, Form, Row } from 'antd'
import {
V2V3_CURRENCY_ETH,
V2V3_CURRENCY_USD,
} from 'packages/v2v3/utils/currency'
import { inputMustBeEthAddressRule, inputMustExistRule } from 'utils/antdRules'
import { useCallback, useContext, useState } from 'react'
import { inputMustBeEthAddressRule, inputMustExistRule } from 'utils/antdRules'

import { CREATE_FLOW } from 'constants/fathomEvents'
import { RightOutlined } from '@ant-design/icons'
import { Callout } from 'components/Callout/Callout'
import { CreateCollapse } from '../../CreateCollapse/CreateCollapse'
import { EthAddressInput } from 'components/inputs/EthAddressInput'
import { FormImageUploader } from 'components/inputs/FormImageUploader'
import { FormItems } from 'components/formItems'
import { EthAddressInput } from 'components/inputs/EthAddressInput'
import FormattedNumberInput from 'components/inputs/FormattedNumberInput'
import { JuiceInput } from 'components/inputs/JuiceTextInput'
import { FormImageUploader } from 'components/inputs/FormImageUploader'
import { JuiceTextArea } from 'components/inputs/JuiceTextArea'
import Link from 'next/link'
import { OptionalHeader } from '../../OptionalHeader'
import { PageContext } from '../../Wizard/contexts/PageContext'
import { ProjectChainSelect } from './ProjectChainSelect'
import { JuiceInput } from 'components/inputs/JuiceTextInput'
import { RichEditor } from 'components/RichEditor'
import { RightOutlined } from '@ant-design/icons'
import { V2V3CurrencyOption } from 'packages/v2v3/models/currencyOption'
import { Wizard } from '../../Wizard/Wizard'
import { CREATE_FLOW } from 'constants/fathomEvents'
import { constants } from 'ethers'
import { inputIsLengthRule } from 'utils/antdRules/inputIsLengthRule'
import { useWallet } from 'hooks/Wallet'
import { trackFathomGoal } from 'lib/fathom'
import Link from 'next/link'
import { useLockPageRulesWrapper } from 'packages/v2v3/components/Create/hooks/useLockPageRulesWrapper'
import { useProjectDetailsForm } from './hooks/useProjectDetailsForm'
import { V2V3CurrencyOption } from 'packages/v2v3/models/currencyOption'
import { useSetCreateFurthestPageReached } from 'redux/hooks/v2v3/useEditingCreateFurthestPageReached'
import { useWallet } from 'hooks/Wallet'
import { inputIsLengthRule } from 'utils/antdRules/inputIsLengthRule'
import { CreateCollapse } from '../../CreateCollapse/CreateCollapse'
import { OptionalHeader } from '../../OptionalHeader'
import { PageContext } from '../../Wizard/contexts/PageContext'
import { Wizard } from '../../Wizard/Wizard'
import { useProjectDetailsForm } from './hooks/useProjectDetailsForm'
import { ProjectChainSelect } from './ProjectChainSelect'

export const ProjectDetailsPage: React.FC<
React.PropsWithChildren<unknown>
Expand Down Expand Up @@ -75,6 +75,9 @@ export const ProjectDetailsPage: React.FC<
name="projectChainId"
label={t`Project chain`}
required
rules={lockPageRulesWrapper([
inputMustExistRule({ label: t`A project chain` }),
])}
>
<ProjectChainSelect />
</Form.Item>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { DEFAULT_PROJECT_CHAIN_ID, SupportedChainId } from 'constants/networks'
import { useEffect, useMemo } from 'react'
import {
DEFAULT_MUST_START_AT_OR_AFTER,
creatingV2ProjectActions,
} from 'redux/slices/v2v3/creatingV2Project'
import { DEFAULT_PROJECT_CHAIN_ID, SupportedChainId } from 'constants/networks'
import { useEffect, useMemo } from 'react'

import { AmountInputValue } from '../ProjectDetailsPage'
import { Form } from 'antd'
import { useForm } from 'antd/lib/form/Form'
import { useWallet } from 'hooks/Wallet'
import { ProjectTagName } from 'models/project-tags'
import { V2V3CurrencyOption } from 'packages/v2v3/models/currencyOption'
import { V2V3_CURRENCY_USD } from 'packages/v2v3/utils/currency'
import { useAppDispatch } from 'redux/hooks/useAppDispatch'
import { useAppSelector } from 'redux/hooks/useAppSelector'
import { useForm } from 'antd/lib/form/Form'
import { useFormDispatchWatch } from '../../hooks/useFormDispatchWatch'
import { useWallet } from 'hooks/Wallet'
import { AmountInputValue } from '../ProjectDetailsPage'

type ProjectDetailsFormProps = Partial<{
projectName: string
Expand Down Expand Up @@ -43,12 +43,18 @@ type ProjectDetailsFormProps = Partial<{

export const useProjectDetailsForm = () => {
const [form] = useForm<ProjectDetailsFormProps>()
const { projectChainId, projectMetadata, inputProjectOwner, mustStartAtOrAfter } =
useAppSelector(state => state.creatingV2Project)
const {
projectChainId,
projectMetadata,
inputProjectOwner,
mustStartAtOrAfter,
} = useAppSelector(state => state.creatingV2Project)

const { chain } = useWallet()
const { chain } = useWallet()

const defaultChainId = chain?.id ? parseInt(chain.id) : DEFAULT_PROJECT_CHAIN_ID
const defaultChainId = chain?.id
? parseInt(chain.id)
: DEFAULT_PROJECT_CHAIN_ID
const initialValues: ProjectDetailsFormProps = useMemo(
() => ({
projectName: projectMetadata.name,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { Trans, t } from '@lingui/macro'

import EthereumAddress from 'components/EthereumAddress'
import { NETWORKS } from 'constants/networks'
import ProjectLogo from 'components/ProjectLogo'
import { ProjectTagsList } from 'components/ProjectTags/ProjectTagsList'
import { ReviewDescription } from '../ReviewDescription'
import { RichPreview } from 'components/RichPreview/RichPreview'
import { ipfsUriToGatewayUrl } from 'utils/ipfs'
import { useAppSelector } from 'redux/hooks/useAppSelector'
import { useMemo } from 'react'
import { NETWORKS } from 'constants/networks'
import { useWallet } from 'hooks/Wallet'
import React, { useMemo } from 'react'
import { useAppSelector } from 'redux/hooks/useAppSelector'
import { ipfsUriToGatewayUrl } from 'utils/ipfs'
import { wrapNonAnchorsInAnchor } from 'utils/wrapNonAnchorsInAnchor'
import { ReviewDescription } from '../ReviewDescription'

export const ProjectDetailsReview = () => {
const { userAddress } = useWallet()
Expand All @@ -34,13 +34,18 @@ export const ProjectDetailsReview = () => {
inputProjectOwner,
} = useAppSelector(state => state.creatingV2Project)

const youtubeUrl = useMemo(() => {
if (!introVideoUrl) return undefined
const url = new URL(introVideoUrl)
const videoId = url.searchParams.get('v')
if (!videoId) return undefined
return `https://www.youtube.com/embed/${videoId}`
}, [introVideoUrl])
const projectChainName = React.useMemo(
() => (projectChainId ? NETWORKS[projectChainId]?.label : undefined),
[projectChainId],
)

// const youtubeUrl = useMemo(() => {
// if (!introVideoUrl) return undefined
// const url = new URL(introVideoUrl)
// const videoId = url.searchParams.get('v')
// if (!videoId) return undefined
// return `https://www.youtube.com/embed/${videoId}`
// }, [introVideoUrl])

const ownerAddress = inputProjectOwner ?? userAddress

Expand Down Expand Up @@ -68,14 +73,16 @@ export const ProjectDetailsReview = () => {
</div>
}
/>
<ReviewDescription
title={t`Project chain`}
desc={
<div className="overflow-hidden text-ellipsis text-base font-medium">
{NETWORKS[projectChainId]?.label}
</div>
}
/>
{projectChainName && (
<ReviewDescription
title={t`Project chain`}
desc={
<div className="overflow-hidden text-ellipsis text-base font-medium">
{projectChainName}
</div>
}
/>
)}
<ReviewDescription
className="col-span-2"
title={t`Tagline`}
Expand Down Expand Up @@ -160,6 +167,7 @@ export const ProjectDetailsReview = () => {
className="row-span-2"
title={t`Project cover photo`}
desc={
// eslint-disable-next-line @next/next/no-img-element
<img width={144} src={coverImageSrc} alt={`${name} cover photo`} />
}
/>
Expand Down
18 changes: 9 additions & 9 deletions src/redux/slices/v2v3/shared/v2ProjectDefaultState.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
import { BigNumber, constants } from 'ethers'
import { CreateState, ProjectState } from './v2ProjectTypes'
import {
ETH_PAYOUT_SPLIT_GROUP,
RESERVED_TOKEN_SPLIT_GROUP,
} from 'constants/splits'
import { BigNumber, constants } from 'ethers'
import { JB721GovernanceType, JBTiered721Flags } from 'models/nftRewards'
import {
LATEST_METADATA_VERSION,
ProjectMetadata,
} from 'models/projectMetadata'
import {
V2V3_CURRENCY_ETH,
V2V3_CURRENCY_USD,
} from 'packages/v2v3/utils/currency'
import { issuanceRateFrom, redemptionRateFrom } from 'packages/v2v3/utils/math'
import {
SerializedV2V3FundingCycleData,
SerializedV2V3FundingCycleMetadata,
serializeV2V3FundingCycleData,
serializeV2V3FundingCycleMetadata,
} from 'packages/v2v3/utils/serializers'
import {
V2V3_CURRENCY_ETH,
V2V3_CURRENCY_USD,
} from 'packages/v2v3/utils/currency'
import { issuanceRateFrom, redemptionRateFrom } from 'packages/v2v3/utils/math'
import { CreateState, ProjectState } from './v2ProjectTypes'

import { JB721TiersHookFlags } from 'packages/v4/models/nfts'
import { ONE_MILLION } from 'constants/numbers'
import { JB721TiersHookFlags } from 'packages/v4/models/nfts'
import { projectDescriptionTemplate } from 'templates/create/projectDescriptionTemplate'

const DEFAULT_DOMAIN = 'juicebox'
Expand Down Expand Up @@ -119,7 +119,7 @@ const DEFAULT_PROJECT_METADATA_STATE: ProjectMetadata = {
}

const DEFAULT_CREATE_STATE: CreateState = {
projectChainId: 0, // not necessary for v2v3
projectChainId: undefined, // not necessary for v2v3
treasurySelection: 'zero',
reconfigurationRuleSelection: undefined,
fundingCyclesPageSelection: undefined,
Expand Down
14 changes: 7 additions & 7 deletions src/redux/slices/v2v3/shared/v2ProjectTypes.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
import {
ETHPayoutGroupedSplits,
ReservedTokensGroupedSplits,
} from 'packages/v2v3/models/splits'
import {
JB721GovernanceType,
JBTiered721Flags,
NftCollectionMetadata,
NftRewardTier,
} from 'models/nftRewards'
import {
ETHPayoutGroupedSplits,
ReservedTokensGroupedSplits,
} from 'packages/v2v3/models/splits'
import {
SerializedV2V3FundAccessConstraint,
SerializedV2V3FundingCycleData,
SerializedV2V3FundingCycleMetadata,
} from 'packages/v2v3/utils/serializers'

import { SupportedChainId } from 'constants/networks'
import { CreatePage } from 'models/createPage'
import { FundingTargetType } from 'models/fundingTargetType'
import { NftPostPayModalConfig } from 'models/nftPostPayModal'
import { NftPricingContext } from 'packages/v2v3/hooks/JB721Delegate/contractReader/useNftCollectionPricingContext'
import { PayoutsSelection } from 'models/payoutsSelection'
import { ProjectMetadata } from 'models/projectMetadata'
import { ProjectTokensSelection } from 'models/projectTokenSelection'
import { ReconfigurationStrategy } from 'models/reconfigurationStrategy'
import { SupportedChainId } from 'constants/networks'
import { TreasurySelection } from 'models/treasurySelection'
import { NftPricingContext } from 'packages/v2v3/hooks/JB721Delegate/contractReader/useNftCollectionPricingContext'

export type NftRewardsData = {
rewardTiers: NftRewardTier[] | undefined
Expand All @@ -37,7 +37,7 @@ export type NftRewardsData = {

export interface CreateState {
fundingCyclesPageSelection: 'automated' | 'manual' | undefined
projectChainId: SupportedChainId
projectChainId: SupportedChainId | undefined
treasurySelection: TreasurySelection | undefined
fundingTargetSelection: FundingTargetType | undefined
payoutsSelection: PayoutsSelection | undefined
Expand Down
Loading