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: Allow anyone to create a LW collection #3191

Merged
merged 5 commits into from
Sep 25, 2024
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
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
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 { MapDispatchProps, MapDispatch, OwnProps } 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: () => {
Expand All @@ -21,4 +14,4 @@ const mapDispatch = (dispatch: MapDispatch, ownProps: OwnProps): MapDispatchProp
}
})

export default connect(mapState, mapDispatch)(CreateCollectionSelectorModal)
export default connect(undefined, mapDispatch)(CreateCollectionSelectorModal)
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,6 @@
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: 227px;
height: 110px;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
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 { CREATE_BUTTON_TEST_ID } from './constants'
import userEvent from '@testing-library/user-event'

export function renderWorldContributorTab(props: Partial<Props>) {
Expand All @@ -12,8 +12,6 @@ export function renderWorldContributorTab(props: Partial<Props>) {
metadata={{}}
name="aName"
onClose={jest.fn()}
isLoadingThirdParties={false}
isThirdPartyManager={false}
{...props}
/>
)
Expand All @@ -29,8 +27,7 @@ describe('when clicking on the create collection button', () => {
onCreateThirdPartyCollection = jest.fn()
renderedComponent = renderWorldContributorTab({
onCreateCollection,
onCreateThirdPartyCollection,
isThirdPartyManager: true
onCreateThirdPartyCollection
})
})

Expand All @@ -57,42 +54,3 @@ describe('when clicking on the create collection button', () => {
})
})
})

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()
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import collectionsImage from '../../../images/collections.png'
import linkedCollectionsImage from '../../../images/linked-collections.png'
import { Props } from './CreateCollectionSelectorModal.types'
import styles from './CreateCollectionSelectorModal.module.css'
import { CREATE_BUTTON_TEST_ID, DISABLED_DATA_TEST_ID } from './constants'
import { CREATE_BUTTON_TEST_ID } from './constants'

const CollectionSelectionModal = ({
image,
Expand All @@ -28,7 +28,6 @@ const CollectionSelectionModal = ({
}) => {
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}>
Expand All @@ -49,7 +48,7 @@ const COLLECTIONS_LEARN_MORE_URL = `${config.get('DOCS_URL')}/creator/wearables-
const LINKED_COLLECTIONS_LEARN_MORE_URL = `${config.get('DOCS_URL')}/creator/wearables/linked-wearables/`

export const CreateCollectionSelectorModal = (props: Props) => {
const { onClose, onCreateCollection, onCreateThirdPartyCollection, name, isThirdPartyManager, isLoadingThirdParties } = props
const { onClose, onCreateCollection, onCreateThirdPartyCollection, name } = props

return (
<Modal name={name} onClose={onClose} size="large">
Expand All @@ -72,8 +71,6 @@ export const CreateCollectionSelectorModal = (props: Props) => {
title={t('create_collection_selector_modal.linked_collection.title')}
subtitle={t('create_collection_selector_modal.linked_collection.subtitle')}
onCreate={onCreateThirdPartyCollection}
isLoading={isLoadingThirdParties}
disabled={!isThirdPartyManager || isLoadingThirdParties}
learnMoreUrl={LINKED_COLLECTIONS_LEARN_MORE_URL}
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,10 @@ import { OpenModalAction } from 'decentraland-dapps/dist/modules/modal'
import { ModalProps } from 'decentraland-dapps/dist/providers/ModalProvider/ModalProvider.types'

export type Props = ModalProps & {
isThirdPartyManager: boolean
isLoadingThirdParties: boolean
onCreateCollection: () => void
onCreateThirdPartyCollection: () => void
}

export type MapStateProps = Pick<Props, 'isThirdPartyManager' | 'isLoadingThirdParties'>
export type MapDispatchProps = Pick<Props, 'onCreateCollection' | 'onCreateThirdPartyCollection'>
export type OwnProps = Pick<Props, 'metadata' | 'onClose' | 'name'>
export type MapDispatch = Dispatch<OpenModalAction>
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export const DISABLED_DATA_TEST_ID = 'create-collection-selector-modal-disabled'
export const CREATE_BUTTON_TEST_ID = 'create-collection-selector-modal-create-button'
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ export const CreateThirdPartyCollectionModal: FC<Props> = (props: Props) => {
collectionName
})
}
}, [onSubmit, collectionId, collectionName, selectedThirdParty, ownerAddress, analytics])
}, [onSubmit, collectionId, selectedContract, selectedNetwork, collectionName, selectedThirdParty, ownerAddress, analytics])

const isSubmittable =
collectionName &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,20 @@ import { getCollectionItems, getLoading as getLoadingItem, getPaginationData } f
import { FETCH_COLLECTION_ITEMS_REQUEST } from 'modules/item/actions'
import { FETCH_COLLECTIONS_REQUEST, DELETE_COLLECTION_REQUEST } from 'modules/collection/actions'
import { openModal } from 'decentraland-dapps/dist/modules/modal/actions'
import { getCollectionThirdParty, isFetchingAvailableSlots } from 'modules/thirdParty/selectors'
import { fetchThirdPartyAvailableSlotsRequest } from 'modules/thirdParty/actions'
import { getCollectionThirdParty, isFetchingAvailableSlots, isLoadingThirdParties, isLoadingThirdParty } from 'modules/thirdParty/selectors'
import { fetchThirdPartyAvailableSlotsRequest, fetchThirdPartyRequest } from 'modules/thirdParty/actions'
import { isThirdPartyCollection } from 'modules/collection/utils'
import { Collection } from 'modules/collection/types'
import { getIsLinkedWearablesPaymentsEnabled, getIsLinkedWearablesV2Enabled } from 'modules/features/selectors'
import { getLastLocation } from 'modules/ui/location/selector'
import { MapStateProps, MapDispatchProps, MapDispatch } from './ThirdPartyCollectionDetailPage.types'
import CollectionDetailPage from './ThirdPartyCollectionDetailPage'
import { extractThirdPartyId } from 'lib/urn'

const mapState = (state: RootState): MapStateProps => {
const collectionId = getCollectionId(state) || ''
const collection = getCollection(state, collectionId)
const isThirdParty = collection ? isThirdPartyCollection(collection) : false
const totalItems = getPaginationData(state, collectionId)?.total || null
const items = collection ? getCollectionItems(state, collection.id) : []
const paginatedData = (collection && getPaginationData(state, collection.id)) || null
Expand All @@ -40,7 +42,9 @@ const mapState = (state: RootState): MapStateProps => {
isLoading:
isLoadingType(getLoadingCollection(state), FETCH_COLLECTIONS_REQUEST) ||
isLoadingType(getLoadingCollection(state), DELETE_COLLECTION_REQUEST) ||
isLoadingType(getLoadingItem(state), FETCH_COLLECTION_ITEMS_REQUEST),
isLoadingType(getLoadingItem(state), FETCH_COLLECTION_ITEMS_REQUEST) ||
isLoadingThirdParties(state) ||
!!(isThirdParty && collection && isLoadingThirdParty(state, extractThirdPartyId(collection.urn))),
isLoadingAvailableSlots: isFetchingAvailableSlots(state),
lastLocation: getLastLocation(state)
}
Expand All @@ -49,7 +53,8 @@ const mapState = (state: RootState): MapStateProps => {
const mapDispatch = (dispatch: MapDispatch): MapDispatchProps => ({
onNewItem: (collectionId: string) => dispatch(openModal('CreateItemsModal', { collectionId })),
onEditName: (collection: Collection) => dispatch(openModal('EditCollectionNameModal', { collection })),
onFetchAvailableSlots: (thirdPartyId: string) => dispatch(fetchThirdPartyAvailableSlotsRequest(thirdPartyId))
onFetchAvailableSlots: (thirdPartyId: string) => dispatch(fetchThirdPartyAvailableSlotsRequest(thirdPartyId)),
onFetchThirdParty: (thirdPartyId: string) => dispatch(fetchThirdPartyRequest(thirdPartyId))
})

export default connect(mapState, mapDispatch)(CollectionDetailPage)
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@

.editCollectionName {
visibility: hidden;
padding-left: 16px;
}

.header .title .name:hover + .editCollectionName {
Expand All @@ -95,7 +96,7 @@
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
width: calc(100% - 80px);
width: fit-content;
}

.header .title .size {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {
import { t } from 'decentraland-dapps/dist/modules/translation/utils'
import { getArrayOfPagesFromTotal } from 'lib/api/pagination'
import { locations } from 'routing/locations'
import { ItemMappingStatus } from 'lib/api/builder'
import { extractThirdPartyId } from 'lib/urn'
import { isUserManagerOfThirdParty } from 'modules/thirdParty/utils'
import { Item } from 'modules/item/types'
import { ThirdParty } from 'modules/thirdParty/types'
Expand All @@ -35,7 +37,6 @@ import { Props, PAGE_SIZE } from './ThirdPartyCollectionDetailPage.types'
import { CollectionItemHeader } from './CollectionItemHeader'
import { CollectionItemHeaderV2 } from './CollectionItemHeaderV2'
import styles from './ThirdPartyCollectionDetailPage.module.css'
import { ItemMappingStatus } from 'lib/api/builder'

const Info = ({ children, title, info }: { children: React.ReactNode; title: string; info?: string }) => (
<div className={styles.info}>
Expand Down Expand Up @@ -66,6 +67,7 @@ export default function ThirdPartyCollectionDetailPage({
isThirdPartyV2Enabled,
isLinkedWearablesPaymentsEnabled,
onFetchAvailableSlots,
onFetchThirdParty,
onNewItem,
onEditName,
isLoadingAvailableSlots
Expand All @@ -84,6 +86,12 @@ export default function ThirdPartyCollectionDetailPage({
}
}, [thirdParty, isLoadingAvailableSlots, onFetchAvailableSlots])

useEffect(() => {
if (!isLoading && !thirdParty && collection?.urn) {
onFetchThirdParty(extractThirdPartyId(collection.urn))
}
}, [collection?.urn, isLoading, thirdParty])

useEffect(() => {
// update the state if the page query param changes
if (currentPage !== page) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import { Collection } from 'modules/collection/types'
import { ThirdParty } from 'modules/thirdParty/types'
import { FetchItemCurationsRequestAction } from 'modules/curations/itemCuration/actions'
import { ItemCuration } from 'modules/curations/itemCuration/types'
import { fetchThirdPartyAvailableSlotsRequest, FetchThirdPartyAvailableSlotsRequestAction } from 'modules/thirdParty/actions'
import {
fetchThirdPartyAvailableSlotsRequest,
FetchThirdPartyAvailableSlotsRequestAction,
FetchThirdPartyRequestAction
} from 'modules/thirdParty/actions'
import { FetchCollectionItemsRequestAction } from 'modules/item/actions'
import { ItemPaginationData } from 'modules/item/reducer'

Expand All @@ -32,6 +36,7 @@ export type Props = {
isLinkedWearablesPaymentsEnabled: boolean
onNewItem: (collectionId: string) => unknown
onEditName: (collection: Collection) => unknown
onFetchThirdParty: (thirdPartyId: string) => unknown
onFetchAvailableSlots: typeof fetchThirdPartyAvailableSlotsRequest
}

Expand Down Expand Up @@ -60,7 +65,11 @@ export type MapStateProps = Pick<
| 'paginatedData'
| 'lastLocation'
>
export type MapDispatchProps = Pick<Props, 'onNewItem' | 'onEditName' | 'onFetchAvailableSlots'>
export type MapDispatchProps = Pick<Props, 'onNewItem' | 'onEditName' | 'onFetchAvailableSlots' | 'onFetchThirdParty'>
export type MapDispatch = Dispatch<
OpenModalAction | FetchItemCurationsRequestAction | FetchThirdPartyAvailableSlotsRequestAction | FetchCollectionItemsRequestAction
| OpenModalAction
| FetchItemCurationsRequestAction
| FetchThirdPartyAvailableSlotsRequestAction
| FetchCollectionItemsRequestAction
| FetchThirdPartyRequestAction
>
4 changes: 4 additions & 0 deletions src/lib/api/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -996,6 +996,10 @@ export class BuilderAPI extends BaseAPI {
return this.request('get', '/thirdParties', { params: { manager }, retry: retryParams }) as Promise<ThirdParty[]>
}

async fetchThirdParty(id: string): Promise<ThirdParty> {
return this.request('get', `/thirdParties/${id}`) as Promise<ThirdParty>
}

async fetchThirdPartyAvailableSlots(thirdPartyId: string): Promise<number> {
return this.request('get', `/thirdParties/${thirdPartyId}/slots`, { retry: retryParams }) as Promise<number>
}
Expand Down
14 changes: 14 additions & 0 deletions src/modules/thirdParty/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,20 @@ export type FetchThirdPartiesRequestAction = ReturnType<typeof fetchThirdParties
export type FetchThirdPartiesSuccessAction = ReturnType<typeof fetchThirdPartiesSuccess>
export type FetchThirdPartiesFailureAction = ReturnType<typeof fetchThirdPartiesFailure>

// Fetch a single third party

export const FETCH_THIRD_PARTY_REQUEST = '[Request] Fetch Third Party'
export const FETCH_THIRD_PARTY_SUCCESS = '[Success] Fetch Third Party'
export const FETCH_THIRD_PARTY_FAILURE = '[Failure] Fetch Third Party'

export const fetchThirdPartyRequest = (thirdPartyId: ThirdParty['id']) => action(FETCH_THIRD_PARTY_REQUEST, { thirdPartyId })
export const fetchThirdPartySuccess = (thirdParty: ThirdParty) => action(FETCH_THIRD_PARTY_SUCCESS, { thirdParty })
export const fetchThirdPartyFailure = (error: string) => action(FETCH_THIRD_PARTY_FAILURE, { error })

export type FetchThirdPartyRequestAction = ReturnType<typeof fetchThirdPartyRequest>
export type FetchThirdPartySuccessAction = ReturnType<typeof fetchThirdPartySuccess>
export type FetchThirdPartyFailureAction = ReturnType<typeof fetchThirdPartyFailure>

// Fetch Third Party Available Slots

export const FETCH_THIRD_PARTY_AVAILABLE_SLOTS_REQUEST = '[Request] Fetch Third Party Available Slots'
Expand Down
Loading
Loading