Skip to content

Commit

Permalink
feat: add names world deploy (#3106)
Browse files Browse the repository at this point in the history
  • Loading branch information
meelrossi committed May 24, 2024
1 parent 3610087 commit 35c6e9a
Show file tree
Hide file tree
Showing 16 changed files with 261 additions and 34 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import { connect } from 'react-redux'
import { push, replace } from 'connected-react-router'
import { RootState } from 'modules/common/types'
import { fetchContributableNamesRequest } from 'modules/ens/actions'
import { getCurrentProject } from 'modules/project/selectors'
import { getENSByWallet, getExternalNamesForConnectedWallet } from 'modules/ens/selectors'
import { getIsWorldContributorEnabled } from 'modules/features/selectors'
import {
getNamesListWithDeploymentPermissions,
getENSByWallet,
getExternalNamesForConnectedWallet,
isLoading as isLoadingENS
} from 'modules/ens/selectors'
import { deployToWorldRequest } from 'modules/deployment/actions'
import { getCurrentMetrics, getCurrentScene } from 'modules/scene/selectors'
import { recordMediaRequest } from 'modules/media/actions'
Expand All @@ -16,13 +23,15 @@ const mapState = (state: RootState): MapStateProps => {
return {
ensList: getENSByWallet(state),
externalNames: getExternalNamesForConnectedWallet(state),
contributableNames: getNamesListWithDeploymentPermissions(state),
project: getCurrentProject(state) as Project,
scene: getCurrentScene(state),
metrics: getCurrentMetrics(state),
deployments: getDeploymentsByWorlds(state),
deploymentProgress: getUploadProgress(state),
error: getError(state),
isLoading: isLoading(state)
isLoading: isLoading(state) || isLoadingENS(state),
isWorldContributorEnabled: getIsWorldContributorEnabled(state)
}
}

Expand All @@ -32,7 +41,8 @@ const mapDispatch = (dispatch: MapDispatch): MapDispatchProps => ({
},
onRecord: () => dispatch(recordMediaRequest()),
onNavigate: path => dispatch(push(path)),
onReplace: (path, locationState) => dispatch(replace(path, locationState))
onReplace: (path, locationState) => dispatch(replace(path, locationState)),
onFetchContributableNames: () => dispatch(fetchContributableNamesRequest())
})

export default connect(mapState, mapDispatch)(DeployToWorld)
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,17 @@
background-repeat: no-repeat;
background-image: url('../../../../images/scene-error.svg');
}

.contributableName {
display: flex;
gap: 8px;
}

.contributableNameOwner {
font-size: 12px;
color: #9b9b9b;
}

.contributableNameOwner :global(.avatar .name) {
font-weight: bold;
}
48 changes: 43 additions & 5 deletions src/components/Modals/DeployModal/DeployToWorld/DeployToWorld.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import dclImage from './images/dcl.svg'
import ensImage from './images/ens.svg'
import styles from './DeployToWorld.module.css'
import { ModelMetrics } from 'modules/models/types'
import { ENS } from 'modules/ens/types'
import Profile from 'components/Profile'

const EXPLORER_URL = config.get('EXPLORER_URL', '')
const WORLDS_CONTENT_SERVER_URL = config.get('WORLDS_CONTENT_SERVER', '')
Expand All @@ -36,11 +38,14 @@ export default function DeployToWorld({
isLoading,
error,
claimedName,
contributableNames,
isWorldContributorEnabled,
onPublish,
onRecord,
onNavigate,
onClose,
onBack
onBack,
onFetchContributableNames
}: Props) {
const analytics = getAnalytics()

Expand Down Expand Up @@ -88,6 +93,12 @@ export default function DeployToWorld({
}
}, [claimedName, analytics])

useEffect(() => {
if (isWorldContributorEnabled) {
onFetchContributableNames()
}
}, [onFetchContributableNames, isWorldContributorEnabled])

const handlePublish = useCallback(() => {
if (world) {
onPublish(project.id, world)
Expand Down Expand Up @@ -178,21 +189,48 @@ export default function DeployToWorld({
)

const worldOptions = useMemo(() => {
const names = nameType === NameType.DCL ? ensList : externalNames
const options: DropdownItemProps[] = names.map(ens => ({ text: ens.name, value: ens.subdomain }))
let availableNames: ENS[]
let availableContributableNames: ENS[]

if (nameType === NameType.DCL) {
availableNames = ensList
availableContributableNames = contributableNames.filter(ens => ens.subdomain.includes('.dcl.eth'))
} else {
availableNames = externalNames
availableContributableNames = contributableNames.filter(ens => !ens.subdomain.includes('.dcl.eth'))
}

const options: DropdownItemProps[] = [
...availableNames.map(ens => ({ text: ens.name, value: ens.subdomain })),
...(isWorldContributorEnabled
? availableContributableNames.map(ens => ({
text: (
<span className={styles.contributableName}>
{ens.name}
{ens.nftOwnerAddress && (
<span className={styles.contributableNameOwner}>
owned by <Profile address={ens.nftOwnerAddress} />
</span>
)}
</span>
),
value: ens.subdomain
}))
: [])
]

options.push({
text: (
<span>
<DCLIcon name="add" />
{nameType === NameType.DCL ? t('deployment_modal.deploy_world.claim_name') : t('deployment_modal.deploy_world.claim_name_ens')}
{nameType !== NameType.ENS ? t('deployment_modal.deploy_world.claim_name') : t('deployment_modal.deploy_world.claim_name_ens')}
</span>
),
value: CLAIM_NAME_OPTION
})

return options
}, [nameType, ensList, externalNames])
}, [nameType, ensList, externalNames, contributableNames])

const getShareInTwitterUrl = () => {
const url = encodeURIComponent(getExplorerUrl)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { SceneMetrics } from '@dcl/inspector/dist/redux/scene-metrics/types'
import { deployToWorldRequest, DeployToWorldRequestAction } from 'modules/deployment/actions'
import { recordMediaRequest, RecordMediaRequestAction } from 'modules/media/actions'
import { ENS } from 'modules/ens/types'
import { FetchExternalNamesRequestAction } from 'modules/ens/actions'
import { FetchContributableNamesRequestAction, FetchExternalNamesRequestAction } from 'modules/ens/actions'
import { Project } from 'modules/project/types'
import { ModelMetrics } from 'modules/models/types'
import { DeploymentState } from 'modules/deployment/reducer'
Expand All @@ -22,24 +22,41 @@ export type Props = {
externalNames: ENS[]
deployments: Record<string, Deployment>
deploymentProgress: DeploymentState['progress']
contributableNames: ENS[]
error: string | null
isLoading: boolean
claimedName: string | null
isWorldContributorEnabled: boolean
onClose: () => void
onBack: () => void
onPublish: typeof deployToWorldRequest
onRecord: typeof recordMediaRequest
onNavigate: (path: string) => void
onReplace: (path: string, locationState?: DeployToWorldLocationStateProps) => void
onFetchContributableNames: () => void
}

export type MapStateProps = Pick<
Props,
'ensList' | 'externalNames' | 'project' | 'metrics' | 'deployments' | 'deploymentProgress' | 'error' | 'isLoading' | 'scene'
| 'ensList'
| 'externalNames'
| 'project'
| 'metrics'
| 'deployments'
| 'deploymentProgress'
| 'error'
| 'isLoading'
| 'scene'
| 'contributableNames'
| 'isWorldContributorEnabled'
>
export type MapDispatchProps = Pick<Props, 'onPublish' | 'onNavigate' | 'onRecord' | 'onReplace'>
export type MapDispatchProps = Pick<Props, 'onPublish' | 'onNavigate' | 'onRecord' | 'onReplace' | 'onFetchContributableNames'>
export type MapDispatch = Dispatch<
DeployToWorldRequestAction | CallHistoryMethodAction | RecordMediaRequestAction | FetchExternalNamesRequestAction
| DeployToWorldRequestAction
| CallHistoryMethodAction
| RecordMediaRequestAction
| FetchExternalNamesRequestAction
| FetchContributableNamesRequestAction
>

export enum DeployToWorldView {
Expand All @@ -57,5 +74,6 @@ export type DeployToWorldModalMetadata = DeployModalMetadata & {

export enum NameType {
DCL,
ENS
ENS,
CONTRIBUTE
}
2 changes: 1 addition & 1 deletion src/components/WorldListPage/WorldUrl/WorldUrl.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Icon } from 'decentraland-ui'
import classNames from 'classnames'
import { t } from 'decentraland-dapps/dist/modules/translation'
import CopyToClipboard from 'components/CopyToClipboard/CopyToClipboard'
import { getExplorerUrl, isWorldDeployed } from '../utils'
import { Props } from './WorldUrl.types'
import styles from './WorldUrl.module.css'
import classNames from 'classnames'

export default function WorldUrl({ ens, deploymentsByWorlds }: Props) {
const url = getExplorerUrl(ens.subdomain)
Expand Down
30 changes: 28 additions & 2 deletions src/modules/deployment/selectors.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,22 +47,48 @@ describe('when getting deployments by worlds', () => {
'zoro.eth': {
subdomain: 'zoro.eth'
}
},
contributableNames: {
'test.dcl.eth': {
subdomain: 'test.dcl.eth',
worldStatus: {
healthy: true,
scene: {
entityId: 'testDclEthEntity',
baseUrl: 'https://abaseUrl'
}
}
},
'test2.eth': {
subdomain: 'test2.eth',
worldStatus: {
healthy: true,
scene: {
entityId: 'test2EthEntity',
baseUrl: 'https://abaseUrl'
}
}
}
}
},
deployment: {
data: {
deployMyWorldId: { id: 'deployMyWorldId' },
deployMyWorld2Id: { id: 'deployMyWorld2Id' },
deployMyWorld3Id: { id: 'deployMyWorld3Id' },
deployMyWorld4Id: { id: 'deployMyWorld4Id' }
deployMyWorld4Id: { id: 'deployMyWorld4Id' },
testDclEthEntity: { id: 'testDclEthEntity' },
test2EthEntity: { id: 'test2EthEntity' }
}
}
} as unknown as RootState

expect(getDeploymentsByWorlds(state)).toEqual({
'my-world.dcl.eth': { id: 'deployMyWorldId' },
'my-world2.dcl.eth': { id: 'deployMyWorld2Id' },
'luffy.eth': { id: 'deployMyWorld3Id' }
'luffy.eth': { id: 'deployMyWorld3Id' },
'test.dcl.eth': { id: 'testDclEthEntity' },
'test2.eth': { id: 'test2EthEntity' }
})
})
})
10 changes: 6 additions & 4 deletions src/modules/deployment/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { getCurrentProject, getUserProjects } from 'modules/project/selectors'
import { Project } from 'modules/project/types'
import { getLandTiles, getDeploymentsByCoord } from 'modules/land/selectors'
import { LandTile } from 'modules/land/types'
import { getENSList, getExternalNamesList } from 'modules/ens/selectors'
import { getContributableNamesList, getENSList, getExternalNamesList } from 'modules/ens/selectors'
import { ENS, WorldStatus } from 'modules/ens/types'
import { idToCoords, coordsToId, emptyColorByRole } from 'modules/land/utils'
import { DeploymentState } from './reducer'
Expand Down Expand Up @@ -119,15 +119,17 @@ export const getEmptyTiles = createSelector<RootState, Record<string, Deployment
}
)

export const getDeploymentsByWorlds = createSelector<RootState, DeploymentState['data'], ENS[], ENS[], Record<string, Deployment>>(
export const getDeploymentsByWorlds = createSelector<RootState, DeploymentState['data'], ENS[], ENS[], ENS[], Record<string, Deployment>>(
getData,
getENSList,
getExternalNamesList,
(deployments, ensList, externalNamesList) => {
getContributableNamesList,
(deployments, ensList, externalNamesList, contributableNamesList) => {
const out: Record<string, Deployment> = {}
const dclNameWorlds = ensList.filter(ens => !!ens.worldStatus)
const externalNameWorlds = externalNamesList.filter(ens => !!ens.worldStatus)
const worlds = [...dclNameWorlds, ...externalNameWorlds]
const contributableNamesWorlds = contributableNamesList.filter(ens => !!ens.worldStatus)
const worlds = [...dclNameWorlds, ...externalNameWorlds, ...contributableNamesWorlds]

for (const world of worlds) {
out[world.subdomain] = deployments[(world.worldStatus as WorldStatus).scene.entityId]
Expand Down
3 changes: 2 additions & 1 deletion src/modules/ens/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ export const FETCH_ENS_WORLD_STATUS_SUCCESS = '[Success] Fetch ENS World Status'
export const FETCH_ENS_WORLD_STATUS_FAILURE = '[Failure] Fetch ENS World Status'

export const fetchENSWorldStatusRequest = (subdomain: string) => action(FETCH_ENS_WORLD_STATUS_REQUEST, { subdomain })
export const fetchENSWorldStatusSuccess = (ens: ENS) => action(FETCH_ENS_WORLD_STATUS_SUCCESS, { ens })
export const fetchENSWorldStatusSuccess = (ens: ENS, isContributableName = false) =>
action(FETCH_ENS_WORLD_STATUS_SUCCESS, { ens, isContributableName })
export const fetchENSWorldStatusFailure = (error: ENSError) => action(FETCH_ENS_WORLD_STATUS_FAILURE, { error })

export type FetchENSWorldStatusRequestAction = ReturnType<typeof fetchENSWorldStatusRequest>
Expand Down
15 changes: 12 additions & 3 deletions src/modules/ens/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,20 @@ export function ensReducer(state: ENSState = INITIAL_STATE, action: ENSReducerAc
}
}
case FETCH_ENS_WORLD_STATUS_SUCCESS: {
const { ens } = action.payload
const { ens, isContributableName } = action.payload

let update: Pick<ENSState, 'data'> | Pick<ENSState, 'externalNames'>
let update: Pick<ENSState, 'data'> | Pick<ENSState, 'externalNames'> | Pick<ENSState, 'contributableNames'>

if (isExternalName(ens.subdomain)) {
if (isContributableName) {
update = {
contributableNames: {
...state.contributableNames,
[ens.subdomain]: {
...ens
}
}
}
} else if (isExternalName(ens.subdomain)) {
update = {
externalNames: {
...state.externalNames,
Expand Down
5 changes: 4 additions & 1 deletion src/modules/ens/sagas.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import {
} from './actions'
import { ensSaga } from './sagas'
import { ContributableDomain, ENS, ENSError, ENSOrigin, WorldStatus } from './types'
import { getENSBySubdomain, getExternalNames } from './selectors'
import { getContributableNamesList, getENSBySubdomain, getExternalNames } from './selectors'
import { addWorldStatusToEachENS } from './utils'
import { Authorization } from 'lib/api/auth'
import { marketplace } from 'lib/api/marketplace'
Expand Down Expand Up @@ -170,6 +170,7 @@ describe('when handling the fetch ens world status request', () => {
await expectSaga(ensSaga, builderClient, ensApi, worldsAPIContent)
.provide([
[select(getENSBySubdomain, subdomain), getENSBySubdomainResult],
[select(getContributableNamesList), []],
[call([worldsAPIContent, 'fetchWorld'], subdomain), fetchWorldsResult]
])
.put(
Expand Down Expand Up @@ -210,6 +211,7 @@ describe('when handling the fetch ens world status request', () => {
await expectSaga(ensSaga, builderClient, ensApi, worldsAPIContent)
.provide([
[select(getExternalNames), getExternalNamesResult],
[select(getContributableNamesList), []],
[call([worldsAPIContent, 'fetchWorld'], subdomain), fetchWorldsResult]
])
.put(
Expand Down Expand Up @@ -240,6 +242,7 @@ describe('when handling the fetch ens world status request', () => {
await expectSaga(ensSaga, builderClient, ensApi, worldsAPIContent)
.provide([
[select(getExternalNames), getExternalNamesResult],
[select(getContributableNamesList), []],
[call([worldsAPIContent, 'fetchWorld'], subdomain), fetchWorldsResult]
])
.put(
Expand Down
Loading

0 comments on commit 35c6e9a

Please sign in to comment.