Skip to content

Commit 1a01a82

Browse files
authored
feat: Modal to publish worlds to ENS names (#2903)
1 parent 6e24ec5 commit 1a01a82

File tree

23 files changed

+1170
-36
lines changed

23 files changed

+1170
-36
lines changed

src/components/Modals/DeployModal/DeployModal.container.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,17 @@ import { RootState } from 'modules/common/types'
33
import { getCurrentProject } from 'modules/project/selectors'
44
import { getData as getDeployments } from 'modules/deployment/selectors'
55
import { getActivePoolGroup } from 'modules/poolGroup/selectors'
6+
import { getCurrentScene } from 'modules/scene/selectors'
7+
import { getIsWorldsForEnsOwnersEnabled } from 'modules/features/selectors'
68
import { MapStateProps, OwnProps } from './DeployModal.types'
79
import DeployModal from './DeployModal'
8-
import { getCurrentScene } from 'modules/scene/selectors'
910

1011
const mapState = (state: RootState, ownProps: OwnProps): MapStateProps => ({
1112
deployment: getDeployments(state)[ownProps.metadata.projectId],
1213
currentPoolGroup: getActivePoolGroup(state),
1314
project: getCurrentProject(state),
14-
scene: getCurrentScene(state)
15+
scene: getCurrentScene(state),
16+
isWorldsForEnsOwnersEnabled: getIsWorldsForEnsOwnersEnabled(state)
1517
})
1618

1719
export default connect(mapState)(DeployModal)

src/components/Modals/DeployModal/DeployModal.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Icon from 'components/Icon'
66
import DeployToLand from './DeployToLand'
77
import DeployToPool from './DeployToPool'
88
import DeployToWorld from './DeployToWorld'
9+
import DeployToWorldWorldsForEnsOwners from './DeployToWorld_WorldsForEnsOwnersFeature'
910
import ClearDeployment from './ClearDeployment'
1011
import { Props, State, DeployModalView } from './DeployModal.types'
1112
import './DeployModal.css'
@@ -132,7 +133,7 @@ export default class DeployModal extends React.PureComponent<Props, State> {
132133

133134
render() {
134135
const { view, deploymentId, claimedName } = this.state
135-
const { name, currentPoolGroup, scene } = this.props
136+
const { name, currentPoolGroup, scene, isWorldsForEnsOwnersEnabled } = this.props
136137

137138
if (view === DeployModalView.CLEAR_DEPLOYMENT && deploymentId) {
138139
return <ClearDeployment deploymentId={deploymentId} name={name} onClose={this.handleClose} />
@@ -156,7 +157,11 @@ export default class DeployModal extends React.PureComponent<Props, State> {
156157
}
157158

158159
if (view === DeployModalView.DEPLOY_TO_WORLD) {
159-
return <DeployToWorld claimedName={claimedName} name={name} onClose={this.handleClose} onBack={this.handleBack} />
160+
return isWorldsForEnsOwnersEnabled ? (
161+
<DeployToWorldWorldsForEnsOwners claimedName={claimedName} name={name} onClose={this.handleClose} onBack={this.handleBack} />
162+
) : (
163+
<DeployToWorld claimedName={claimedName} name={name} onClose={this.handleClose} onBack={this.handleBack} />
164+
)
160165
}
161166

162167
return this.renderChoiceForm()

src/components/Modals/DeployModal/DeployModal.types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export type Props = ModalProps & {
1010
currentPoolGroup: PoolGroup | null
1111
project: Project | null
1212
scene: Scene | null
13+
isWorldsForEnsOwnersEnabled: boolean
1314
}
1415

1516
export type State = {
@@ -24,7 +25,7 @@ export type Step = {
2425
}
2526

2627
export type OwnProps = Pick<Props, 'metadata'>
27-
export type MapStateProps = Pick<Props, 'deployment' | 'currentPoolGroup' | 'project' | 'scene'>
28+
export type MapStateProps = Pick<Props, 'deployment' | 'currentPoolGroup' | 'project' | 'scene' | 'isWorldsForEnsOwnersEnabled'>
2829

2930
export enum DeployModalView {
3031
NONE = 'NONE',
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { connect } from 'react-redux'
2+
import { push, replace } from 'connected-react-router'
3+
import { RootState } from 'modules/common/types'
4+
import { getCurrentProject } from 'modules/project/selectors'
5+
import { getENSByWallet, getExternalNamesForConnectedWallet } from 'modules/ens/selectors'
6+
import { fetchExternalNamesRequest } from 'modules/ens/actions'
7+
import { deployToWorldRequest } from 'modules/deployment/actions'
8+
import { getCurrentMetrics } from 'modules/scene/selectors'
9+
import { recordMediaRequest } from 'modules/media/actions'
10+
import { getDeploymentsByWorlds, getProgress as getUploadProgress, getError, isLoading } from 'modules/deployment/selectors'
11+
import { Project } from 'modules/project/types'
12+
import { MapDispatch, MapDispatchProps, MapStateProps } from './DeployToWorld.types'
13+
14+
import DeployToWorld from './DeployToWorld'
15+
16+
const mapState = (state: RootState): MapStateProps => {
17+
return {
18+
ensList: getENSByWallet(state),
19+
externalNames: getExternalNamesForConnectedWallet(state),
20+
project: getCurrentProject(state) as Project,
21+
metrics: getCurrentMetrics(state),
22+
deployments: getDeploymentsByWorlds(state),
23+
deploymentProgress: getUploadProgress(state),
24+
error: getError(state),
25+
isLoading: isLoading(state)
26+
}
27+
}
28+
29+
const mapDispatch = (dispatch: MapDispatch): MapDispatchProps => ({
30+
onPublish: (projectId: string, name: string) => {
31+
return dispatch(deployToWorldRequest(projectId, name))
32+
},
33+
onRecord: () => dispatch(recordMediaRequest()),
34+
onNavigate: path => dispatch(push(path)),
35+
onReplace: (path, locationState) => dispatch(replace(path, locationState)),
36+
onFetchExternalNames: () => dispatch(fetchExternalNamesRequest())
37+
})
38+
39+
export default connect(mapState, mapDispatch)(DeployToWorld)
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
.modalBody {
2+
width: 750px;
3+
padding: 48px;
4+
display: flex;
5+
flex-direction: column;
6+
gap: 32px;
7+
}
8+
9+
.modalNavigation {
10+
display: flex;
11+
justify-content: space-between;
12+
}
13+
14+
.modalNavigation.end {
15+
justify-content: end;
16+
}
17+
18+
.emptyState {
19+
display: flex;
20+
flex-direction: column;
21+
gap: 30px;
22+
}
23+
24+
.emptyState .modalHeader h3 {
25+
font-size: 20px;
26+
line-height: 24px;
27+
}
28+
29+
.modalHeader {
30+
display: flex;
31+
flex-direction: column;
32+
align-items: center;
33+
justify-content: center;
34+
}
35+
36+
.modalHeader h3 {
37+
font-weight: 600;
38+
font-size: 30px;
39+
line-height: 36px;
40+
}
41+
42+
.modalHeader span {
43+
font-weight: 400;
44+
font-size: 18px;
45+
line-height: 22px;
46+
}
47+
48+
.modalBody .actionButton:global(.ui.button) {
49+
height: auto;
50+
width: fit-content;
51+
align-self: flex-end;
52+
}
53+
54+
.modalBodyState {
55+
display: flex;
56+
flex-direction: column;
57+
align-items: center;
58+
}
59+
60+
.modalBodyState .description {
61+
text-align: center;
62+
font-size: 14px;
63+
line-height: 20px;
64+
}
65+
66+
.modalBodyStateActions {
67+
display: flex;
68+
flex-wrap: wrap;
69+
justify-content: center;
70+
}
71+
72+
.modalBodyStateActionButton {
73+
height: 46px !important;
74+
width: 475px !important;
75+
margin: 8px 32px !important;
76+
}
77+
78+
.modalForm {
79+
display: flex;
80+
gap: 36px;
81+
}
82+
83+
.modalFormActions:has(.actionCheckbox):has(.actionButton) {
84+
justify-content: space-between !important;
85+
}
86+
87+
.actionCheckbox {
88+
display: flex;
89+
align-items: center;
90+
}
91+
92+
.actionCheckbox div {
93+
margin-right: 8px;
94+
}
95+
96+
.actionCheckbox :global(.ui.checkbox input[type='checkbox'].hidden) ~ label:hover::before {
97+
border: 2px solid white;
98+
}
99+
100+
.thumbnail {
101+
width: 240px;
102+
height: 190px;
103+
background-size: cover;
104+
background-position: center;
105+
border: 1px solid lightgray;
106+
}
107+
108+
.thumbnailInfo {
109+
float: right;
110+
margin: 3px 7px !important;
111+
filter: invert(84%) sepia(8%) saturate(12%) hue-rotate(24deg) brightness(102%) contrast(89%);
112+
}
113+
114+
.thumbnailInfo:hover {
115+
filter: invert(97%) sepia(97%) saturate(0%) hue-rotate(17deg) brightness(104%) contrast(104%);
116+
}
117+
118+
.metricsList {
119+
margin-top: 4px !important;
120+
}
121+
122+
.metricsList div {
123+
margin-left: 4px;
124+
text-transform: capitalize;
125+
}
126+
127+
.metricsList div::before {
128+
content: '-\00a0';
129+
}
130+
131+
.modalForm .worldDetails {
132+
width: 375px;
133+
}
134+
135+
.nameTypeOption {
136+
display: flex;
137+
gap: 0.5rem;
138+
align-items: center;
139+
}
140+
141+
.modalForm .worldDetailsDescription {
142+
color: var(--text);
143+
font-size: 14px;
144+
margin-bottom: 18px;
145+
overflow-wrap: break-word;
146+
}
147+
148+
.modalForm .worldHasContent {
149+
display: flex;
150+
align-items: center;
151+
background-color: rgba(115, 110, 125, 0.16);
152+
border-radius: 4px;
153+
padding: 6px 8px;
154+
font-size: 12px;
155+
line-height: 16px;
156+
}
157+
158+
.modalForm .worldHasContent :global(.Icon) {
159+
min-width: 24px;
160+
}
161+
162+
.modalForm .worldHasContent div {
163+
margin-right: 13px;
164+
}
165+
166+
.navigationButton {
167+
background: transparent;
168+
border: 0;
169+
cursor: pointer;
170+
}
171+
172+
.navigationButton:disabled {
173+
opacity: 0.4;
174+
cursor: not-allowed;
175+
}
176+
177+
.modalBodyEmptyState .emptyThumbnail {
178+
height: 180px;
179+
width: 180px;
180+
margin-bottom: 10px;
181+
background-position: center;
182+
background-size: contain;
183+
background-repeat: no-repeat;
184+
background-image: url('../../../../images/empty-deploy-to-world.svg');
185+
}
186+
187+
.modalBodySuccessState .description {
188+
font-size: 14px;
189+
margin-bottom: 28px;
190+
}
191+
192+
.modalBodySuccessState .shareUrlFieldInput input {
193+
border: 2px solid var(--text) !important;
194+
padding: 9px 15px !important;
195+
font-size: 15px !important;
196+
}
197+
198+
.modalBodySuccessState .shareUrlFieldInput i {
199+
opacity: 1 !important;
200+
}
201+
202+
.shareUrlField {
203+
width: 432px;
204+
}
205+
206+
.shareUrlField p {
207+
display: none !important;
208+
}
209+
210+
.modalBodySuccessState .successImage {
211+
height: 150px;
212+
width: 150px;
213+
margin-bottom: 10px;
214+
background-position: center;
215+
background-size: contain;
216+
background-repeat: no-repeat;
217+
background-image: url('../../../../images/save-world-success.svg');
218+
}
219+
220+
.failureImage {
221+
height: 150px;
222+
width: 150px;
223+
margin-bottom: 10px;
224+
background-position: center;
225+
background-size: contain;
226+
background-repeat: no-repeat;
227+
background-image: url('../../../../images/scene-error.svg');
228+
}

0 commit comments

Comments
 (0)