-
Notifications
You must be signed in to change notification settings - Fork 84
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add new collection selector modal
- Loading branch information
1 parent
3d0f94d
commit 066c597
Showing
23 changed files
with
429 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 9 additions & 2 deletions
11
src/components/Modals/CreateCollectionModal/CreateCollectionModal.container.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 7 additions & 3 deletions
10
src/components/Modals/CreateCollectionModal/CreateCollectionModal.types.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,22 @@ | ||
import { Dispatch } from 'redux' | ||
import { ModalProps } from 'decentraland-dapps/dist/providers/ModalProvider/ModalProvider.types' | ||
import { SaveCollectionRequestAction, saveCollectionRequest } from 'modules/collection/actions' | ||
import { OpenModalAction } from 'decentraland-dapps/dist/modules/modal' | ||
|
||
export type Props = ModalProps & { | ||
address?: string | ||
isLoading: boolean | ||
onSubmit: typeof saveCollectionRequest | ||
onBack: () => void | ||
isLinkedWearablesV2Enabled: boolean | ||
error: string | null | ||
} | ||
|
||
export type State = { | ||
collectionName: string | ||
} | ||
|
||
export type MapStateProps = Pick<Props, 'address' | 'isLoading' | 'error'> | ||
export type MapDispatchProps = Pick<Props, 'onSubmit'> | ||
export type MapDispatch = Dispatch<SaveCollectionRequestAction> | ||
export type MapStateProps = Pick<Props, 'address' | 'isLoading' | 'error' | 'isLinkedWearablesV2Enabled'> | ||
export type MapDispatchProps = Pick<Props, 'onSubmit' | 'onBack'> | ||
export type OwnProps = Pick<Props, 'metadata' | 'onClose' | 'name'> | ||
export type MapDispatch = Dispatch<SaveCollectionRequestAction | OpenModalAction> |
24 changes: 24 additions & 0 deletions
24
...omponents/Modals/CreateCollectionSelectorModal/CreateCollectionSelectorModal.container.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { connect } from 'react-redux' | ||
import { openModal } from 'decentraland-dapps/dist/modules/modal' | ||
import { isLoadingThirdParties, isThirdPartyManager } from 'modules/thirdParty/selectors' | ||
import { MapDispatchProps, MapDispatch, OwnProps, MapStateProps } from './CreateCollectionSelectorModal.types' | ||
import { CreateCollectionSelectorModal } from './CreateCollectionSelectorModal' | ||
import { RootState } from 'modules/common/types' | ||
|
||
const mapState = (state: RootState): MapStateProps => ({ | ||
isThirdPartyManager: isThirdPartyManager(state), | ||
isLoadingThirdParties: isLoadingThirdParties(state) | ||
}) | ||
|
||
const mapDispatch = (dispatch: MapDispatch, ownProps: OwnProps): MapDispatchProps => ({ | ||
onCreateCollection: () => { | ||
ownProps.onClose() | ||
dispatch(openModal('CreateCollectionModal')) | ||
}, | ||
onCreateLinkedWearablesCollection: () => { | ||
ownProps.onClose() | ||
dispatch(openModal('CreateLinkedWearablesCollectionModal')) | ||
} | ||
}) | ||
|
||
export default connect(mapState, mapDispatch)(CreateCollectionSelectorModal) |
58 changes: 58 additions & 0 deletions
58
src/components/Modals/CreateCollectionSelectorModal/CreateCollectionSelectorModal.module.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
.modalContent { | ||
display: flex; | ||
flex-direction: row; | ||
gap: 16px; | ||
} | ||
|
||
.collectionSelection { | ||
position: relative; | ||
flex: 1 1 0px; | ||
display: flex; | ||
flex-direction: column; | ||
align-items: center; | ||
padding: 33px; | ||
background-color: #2e2c33; | ||
border-radius: 8px; | ||
} | ||
|
||
.collectionSelection .disabled { | ||
width: 100%; | ||
height: 100%; | ||
border-radius: 8px; | ||
position: absolute; | ||
top: 0; | ||
left: 0; | ||
opacity: 0.3; | ||
background-color: black; | ||
} | ||
|
||
.collectionSelection img { | ||
width: 133px; | ||
height: 133px; | ||
} | ||
|
||
.collectionSelection .content { | ||
display: flex; | ||
flex-direction: column; | ||
flex-grow: 1; | ||
} | ||
|
||
.collectionSelection .content .text { | ||
text-align: center; | ||
margin-top: 32px; | ||
} | ||
|
||
.collectionSelection .actions { | ||
display: flex; | ||
flex-direction: column; | ||
justify-content: space-between; | ||
align-items: center; | ||
gap: 15px; | ||
margin-top: 24px; | ||
} | ||
|
||
.collectionSelection .actions a { | ||
font-size: 14px; | ||
text-transform: uppercase; | ||
z-index: 2; | ||
} |
98 changes: 98 additions & 0 deletions
98
src/components/Modals/CreateCollectionSelectorModal/CreateCollectionSelectorModal.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import { renderWithProviders } from 'specs/utils' | ||
import { CreateCollectionSelectorModal } from './CreateCollectionSelectorModal' | ||
import { Props } from './CreateCollectionSelectorModal.types' | ||
import { CREATE_BUTTON_TEST_ID, DISABLED_DATA_TEST_ID } from './constants' | ||
import userEvent from '@testing-library/user-event' | ||
|
||
export function renderWorldContributorTab(props: Partial<Props>) { | ||
return renderWithProviders( | ||
<CreateCollectionSelectorModal | ||
onCreateCollection={jest.fn()} | ||
onCreateLinkedWearablesCollection={jest.fn()} | ||
metadata={{}} | ||
name="aName" | ||
onClose={jest.fn()} | ||
isLoadingThirdParties={false} | ||
isThirdPartyManager={false} | ||
{...props} | ||
/> | ||
) | ||
} | ||
|
||
describe('when clicking on the create collection button', () => { | ||
let renderedComponent: ReturnType<typeof renderWorldContributorTab> | ||
let onCreateCollection: jest.Mock | ||
let onCreateLinkedWearablesCollection: jest.Mock | ||
|
||
beforeEach(() => { | ||
onCreateCollection = jest.fn() | ||
onCreateLinkedWearablesCollection = jest.fn() | ||
renderedComponent = renderWorldContributorTab({ | ||
onCreateCollection, | ||
onCreateLinkedWearablesCollection, | ||
isThirdPartyManager: true | ||
}) | ||
}) | ||
|
||
describe('and the button belongs to the classic collections', () => { | ||
let createButton: HTMLElement | ||
beforeEach(() => { | ||
createButton = renderedComponent.getAllByTestId(CREATE_BUTTON_TEST_ID)[0] | ||
userEvent.click(createButton) | ||
}) | ||
|
||
it('should call the the onCreateCollection prop method', () => { | ||
expect(onCreateCollection).toHaveBeenCalled() | ||
}) | ||
}) | ||
|
||
describe('and the button belongs to the linked collections', () => { | ||
beforeEach(() => { | ||
const createButton = renderedComponent.getAllByTestId(CREATE_BUTTON_TEST_ID)[1] | ||
userEvent.click(createButton) | ||
}) | ||
|
||
it('should call the onCreateLinkedWearablesCollection method prop', () => { | ||
expect(onCreateLinkedWearablesCollection).toHaveBeenCalled() | ||
}) | ||
}) | ||
}) | ||
|
||
describe('and the linked collections are being loaded', () => { | ||
let renderedComponent: ReturnType<typeof renderWorldContributorTab> | ||
beforeEach(() => { | ||
renderedComponent = renderWorldContributorTab({ isLoadingThirdParties: true }) | ||
}) | ||
|
||
it('should show the disabled overlay for the linked collections', () => { | ||
const disabledOverlay = renderedComponent.getByTestId(DISABLED_DATA_TEST_ID) | ||
expect(disabledOverlay).toBeInTheDocument() | ||
}) | ||
|
||
it('should disable the create button for the linked collections', () => { | ||
const createButton = renderedComponent.getAllByTestId(CREATE_BUTTON_TEST_ID)[1] | ||
expect(createButton).toBeDisabled() | ||
}) | ||
|
||
it('should set the button as loading', () => { | ||
const createButton = renderedComponent.getAllByTestId(CREATE_BUTTON_TEST_ID)[1] | ||
expect(createButton).toHaveClass('loading') | ||
}) | ||
}) | ||
|
||
describe('and the user is not a third party manager', () => { | ||
let renderedComponent: ReturnType<typeof renderWorldContributorTab> | ||
beforeEach(() => { | ||
renderedComponent = renderWorldContributorTab({ isThirdPartyManager: false }) | ||
}) | ||
|
||
it('should show the disabled overlay for the linked collections', () => { | ||
const disabledOverlay = renderedComponent.getByTestId(DISABLED_DATA_TEST_ID) | ||
expect(disabledOverlay).toBeInTheDocument() | ||
}) | ||
|
||
it('should disable the create button for the linked collections', () => { | ||
const createButton = renderedComponent.getAllByTestId(CREATE_BUTTON_TEST_ID)[1] | ||
expect(createButton).toBeDisabled() | ||
}) | ||
}) |
85 changes: 85 additions & 0 deletions
85
src/components/Modals/CreateCollectionSelectorModal/CreateCollectionSelectorModal.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import { Button, ModalContent, ModalNavigation } from 'decentraland-ui' | ||
import classNames from 'classnames' | ||
import Modal from 'decentraland-dapps/dist/containers/Modal' | ||
import { t } from 'decentraland-dapps/dist/modules/translation' | ||
import { config } from 'config' | ||
import ethereumSvg from '../../../icons/ethereum.svg' | ||
import polygonSvg from '../../../icons/polygon.svg' | ||
import { Props } from './CreateCollectionSelectorModal.types' | ||
import styles from './CreateCollectionSelectorModal.module.css' | ||
import { CREATE_BUTTON_TEST_ID, DISABLED_DATA_TEST_ID } from './constants' | ||
|
||
const CollectionSelection = ({ | ||
image, | ||
title, | ||
subtitle, | ||
disabled, | ||
isLoading, | ||
onCreate, | ||
learnMoreUrl | ||
}: { | ||
image: string | ||
title: string | ||
subtitle: string | ||
disabled?: boolean | ||
isLoading?: boolean | ||
learnMoreUrl: string | ||
onCreate: () => void | ||
}) => { | ||
return ( | ||
<div className={classNames(styles.collectionSelection)}> | ||
{disabled && <div data-testid={DISABLED_DATA_TEST_ID} className={styles.disabled}></div>} | ||
<img src={image} alt={title} /> | ||
<div className={styles.content}> | ||
<div className={styles.text}> | ||
<h2>{title}</h2> | ||
<p>{subtitle}</p> | ||
</div> | ||
</div> | ||
<div className={styles.actions}> | ||
<Button data-testid={CREATE_BUTTON_TEST_ID} primary disabled={disabled} loading={isLoading} onClick={onCreate}> | ||
{t('create_collection_selector_modal.actions.create')} | ||
</Button> | ||
<a href={learnMoreUrl}>{t('create_collection_selector_modal.actions.learn_more')}</a> | ||
</div> | ||
</div> | ||
) | ||
} | ||
const COLLECTIONS_LEARN_MORE_URL = `${config.get('DOCS_URL')}/creator/wearables-and-emotes/manage-collections/creating-collection/` | ||
const LINKED_COLLECTIONS_LEARN_MORE_URL = `${config.get('DOCS_URL')}/creator/wearables/linked-wearables/` | ||
|
||
export const CreateCollectionSelectorModal = (props: Props) => { | ||
const { onClose, onCreateCollection, onCreateLinkedWearablesCollection, name, isThirdPartyManager, isLoadingThirdParties } = props | ||
|
||
return ( | ||
<Modal name={name} onClose={onClose} size="small"> | ||
<ModalNavigation | ||
title={t('create_collection_selector_modal.title')} | ||
subtitle={t('create_collection_selector_modal.subtitle')} | ||
onClose={onClose} | ||
/> | ||
<ModalContent> | ||
<div className={styles.modalContent}> | ||
<CollectionSelection | ||
// Temporary image for the collections | ||
image={ethereumSvg} | ||
title={t('create_collection_selector_modal.collection.title')} | ||
subtitle={t('create_collection_selector_modal.collection.subtitle')} | ||
onCreate={onCreateCollection} | ||
learnMoreUrl={COLLECTIONS_LEARN_MORE_URL} | ||
/> | ||
<CollectionSelection | ||
// Temporary image for the linked wearables collections | ||
image={polygonSvg} | ||
title={t('create_collection_selector_modal.linked_collection.title')} | ||
subtitle={t('create_collection_selector_modal.linked_collection.subtitle')} | ||
onCreate={onCreateLinkedWearablesCollection} | ||
isLoading={isLoadingThirdParties} | ||
disabled={!isThirdPartyManager || isLoadingThirdParties} | ||
learnMoreUrl={LINKED_COLLECTIONS_LEARN_MORE_URL} | ||
/> | ||
</div> | ||
</ModalContent> | ||
</Modal> | ||
) | ||
} |
Oops, something went wrong.