Skip to content

Commit 667bf68

Browse files
feat: Add disable Third Party (#3153)
* feat: Add disable Third Party * fix: Tests
1 parent 06268da commit 667bf68

29 files changed

+556
-51
lines changed

src/components/ActivityPage/Transaction/Transaction.tsx

+18
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
RECLAIM_NAME_SUCCESS,
3636
CLAIM_NAME_TRANSACTION_SUBMITTED
3737
} from 'modules/ens/actions'
38+
import { DISABLE_THIRD_PARTY_SUCCESS } from 'modules/thirdParty/actions'
3839
import { getSaleAddress, getTotalAmountOfMintedItems } from 'modules/collection/utils'
3940
import { isEnoughClaimMana } from 'modules/ens/utils'
4041
import { includes } from 'lib/address'
@@ -212,6 +213,23 @@ const Transaction = (props: Props) => {
212213
/>
213214
)
214215
}
216+
case DISABLE_THIRD_PARTY_SUCCESS: {
217+
const { thirdPartyId, thirdPartyName } = tx.payload
218+
return (
219+
<TransactionDetail
220+
thirdPartyId={thirdPartyId}
221+
text={
222+
<T
223+
id="transaction.disable_third_party"
224+
values={{
225+
name: thirdPartyName
226+
}}
227+
/>
228+
}
229+
tx={tx}
230+
/>
231+
)
232+
}
215233
case PUBLISH_COLLECTION_SUCCESS:
216234
case APPROVE_COLLECTION_SUCCESS:
217235
case REJECT_COLLECTION_SUCCESS:

src/components/ActivityPage/Transaction/TransactionDetail/TransactionDetail.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { Atlas } from 'components/Atlas'
99
import CollectionImage from 'components/CollectionImage'
1010
import ItemImage from 'components/ItemImage'
1111
import Profile from 'components/Profile'
12+
import { ThirdPartyImage } from 'components/ThirdPartyImage'
1213
import { ENSImage } from '../ENSImage'
1314
import { Props } from './TransactionDetail.types'
1415
import './TransactionDetail.css'
@@ -22,7 +23,7 @@ const getHref = (tx: Transaction) => {
2223
}
2324

2425
const Image = (props: Props) => {
25-
const { selection, address, collectionId, item, subdomain, slotsToyBuy } = props
26+
const { selection, address, collectionId, item, subdomain, slotsToyBuy, thirdPartyId } = props
2627

2728
const set = useMemo(() => new Set((selection || []).map(coord => coordsToId(coord.x, coord.y))), [selection])
2829
const selectedStrokeLayer: Layer = useCallback((x, y) => (set.has(coordsToId(x, y)) ? { color: '#ff0044', scale: 1.4 } : null), [set])
@@ -41,6 +42,8 @@ const Image = (props: Props) => {
4142
return <ENSImage subdomain={subdomain} isSmall />
4243
} else if (slotsToyBuy) {
4344
return <div className="slot-image" />
45+
} else if (thirdPartyId) {
46+
return <ThirdPartyImage thirdPartyId={thirdPartyId} />
4447
} else {
4548
return null
4649
}

src/components/ActivityPage/Transaction/TransactionDetail/TransactionDetail.types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export type Props = {
99
item?: Item
1010
subdomain?: string
1111
slotsToyBuy?: number
12+
thirdPartyId?: string
1213
text: React.ReactNode
1314
tx: Transaction
1415
}

src/components/CollectionsPage/CollectionsPage.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ export default function CollectionsPage(props: Props) {
213213
<Field
214214
placeholder={t('itemdrawer.search_items')}
215215
className="collections-search-field"
216-
input={{ icon: 'search', iconPosition: 'left' }}
216+
input={{ icon: 'search' }}
217217
onChange={handleSearchChange}
218218
icon={<UIIcon name="search" className="searchIcon" />}
219219
iconPosition="left"

src/components/ItemEditorPage/TopPanel/RejectionModal/RejectionModal.container.ts

+11-5
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,25 @@ import { rejectCollectionRequest, REJECT_COLLECTION_REQUEST } from 'modules/coll
55
import { getLoading as getLoadingCollection, hasPendingCurationTransaction } from 'modules/collection/selectors'
66
import { getLoading as getLoadingCuration } from 'modules/curations/collectionCuration/selectors'
77
import { rejectCollectionCurationRequest, REJECT_COLLECTION_CURATION_REQUEST } from 'modules/curations/collectionCuration/actions'
8-
import { MapStateProps, MapDispatchProps, MapDispatch } from './RejectionModal.types'
8+
import { hasPendingDisableThirdPartyTransaction, isDisablingThirdParty } from 'modules/thirdParty/selectors'
9+
import { disableThirdPartyRequest } from 'modules/thirdParty/actions'
10+
import { MapStateProps, MapDispatchProps, MapDispatch, OwnProps } from './RejectionModal.types'
911
import RejectionModal from './RejectionModal'
1012

11-
const mapState = (state: RootState): MapStateProps => ({
13+
const mapState = (state: RootState, ownProps: OwnProps): MapStateProps => ({
1214
isLoading:
1315
isLoadingType(getLoadingCollection(state), REJECT_COLLECTION_REQUEST) ||
14-
isLoadingType(getLoadingCuration(state), REJECT_COLLECTION_CURATION_REQUEST),
15-
hasPendingTransaction: hasPendingCurationTransaction(state)
16+
isLoadingType(getLoadingCuration(state), REJECT_COLLECTION_CURATION_REQUEST) ||
17+
isDisablingThirdParty(state),
18+
hasPendingTransaction:
19+
hasPendingCurationTransaction(state) ||
20+
Boolean(ownProps.thirdParty && hasPendingDisableThirdPartyTransaction(state, ownProps.thirdParty.id))
1621
})
1722

1823
const mapDispatch = (dispatch: MapDispatch): MapDispatchProps => ({
1924
onReject: collection => dispatch(rejectCollectionRequest(collection)),
20-
onRejectCuration: collection => dispatch(rejectCollectionCurationRequest(collection))
25+
onRejectCuration: collection => dispatch(rejectCollectionCurationRequest(collection)),
26+
onDisableThirdParty: (id: string) => dispatch(disableThirdPartyRequest(id))
2127
})
2228

2329
export default connect(mapState, mapDispatch)(RejectionModal)

src/components/ItemEditorPage/TopPanel/RejectionModal/RejectionModal.tsx

+17-5
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ const RejectionModal = ({
1616
open,
1717
type,
1818
isLoading,
19+
thirdParty,
1920
hasPendingTransaction,
21+
onDisableThirdParty,
2022
collection,
2123
curation,
2224
onReject,
@@ -29,6 +31,8 @@ const RejectionModal = ({
2931
return i18nBase + '.disable_collection'
3032
case RejectionType.REJECT_CURATION:
3133
return i18nBase + '.reject_curation'
34+
case RejectionType.DISABLE_THIRD_PARTY:
35+
return i18nBase + '.disable_third_party'
3236
default:
3337
return ''
3438
}
@@ -42,21 +46,27 @@ const RejectionModal = ({
4246
case RejectionType.REJECT_CURATION:
4347
onRejectCuration(curation!.collectionId)
4448
break
49+
case RejectionType.DISABLE_THIRD_PARTY:
50+
if (thirdParty) {
51+
onDisableThirdParty(thirdParty.id)
52+
}
53+
break
4554
default:
4655
}
4756
}
4857

49-
const shouldShowVeredict =
58+
const shouldShowVerdict =
5059
(type === RejectionType.DISABLE_COLLECTION && !collection.isApproved) ||
60+
(type === RejectionType.DISABLE_THIRD_PARTY && !thirdParty?.isApproved) ||
5161
(type === RejectionType.REJECT_COLLECTION && !collection.isApproved) ||
5262
(type === RejectionType.REJECT_CURATION && curation?.status === CurationStatus.REJECTED)
5363

5464
return (
5565
<Modal size="tiny" className="RejectionModal" open={open}>
5666
{hasPendingTransaction ? (
5767
<PendingTransaction i18nKey={i18nKey} />
58-
) : shouldShowVeredict ? (
59-
<Veredict link={collection.forumLink} onClose={onClose} />
68+
) : shouldShowVerdict ? (
69+
<Verdict link={collection.forumLink} onClose={onClose} />
6070
) : (
6171
<Confirmation i18nKey={i18nKey} isLoading={isLoading} onClose={onClose} onConfirm={handleReview} />
6272
)}
@@ -82,7 +92,7 @@ const PendingTransaction = ({ i18nKey }: { i18nKey: string }) => (
8292
</>
8393
)
8494

85-
const Veredict = ({ link, onClose }: { link?: string; onClose: () => void }) => (
95+
const Verdict = ({ link, onClose }: { link?: string; onClose: () => void }) => (
8696
<>
8797
<Modal.Header>{t(i18nBase + '.veredict_explanation')}</Modal.Header>
8898
<Modal.Content>{t(i18nBase + '.go_to_forum')}</Modal.Content>
@@ -119,7 +129,9 @@ const Confirmation = ({
119129
<NetworkButton primary onClick={onConfirm} disabled={isLoading} loading={isLoading} network={Network.MATIC}>
120130
{t(`${i18nKey}.action`)}
121131
</NetworkButton>
122-
<Button onClick={onClose}>{t('global.cancel')}</Button>
132+
<Button disabled={isLoading} onClick={onClose}>
133+
{t('global.cancel')}
134+
</Button>
123135
</Modal.Actions>
124136
</>
125137
)

src/components/ItemEditorPage/TopPanel/RejectionModal/RejectionModal.types.ts

+11-4
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@ import { InitiateApprovalFlowAction, rejectCollectionRequest, RejectCollectionRe
33
import { Collection } from 'modules/collection/types'
44
import { rejectCollectionCurationRequest, RejectCollectionCurationRequestAction } from 'modules/curations/collectionCuration/actions'
55
import { CollectionCuration } from 'modules/curations/collectionCuration/types'
6+
import { disableThirdPartyRequest, DisableThirdPartyRequestAction } from 'modules/thirdParty/actions'
7+
import { ThirdParty } from 'modules/thirdParty/types'
68

79
export enum RejectionType {
810
REJECT_COLLECTION = 'REJECT_COLLECTION',
911
REJECT_CURATION = 'REJECT_CURATION',
10-
DISABLE_COLLECTION = 'DISABLE_COLLECTION'
12+
DISABLE_COLLECTION = 'DISABLE_COLLECTION',
13+
DISABLE_THIRD_PARTY = 'DISABLE_THIRD_PARTY'
1114
}
1215

1316
export type Props = {
@@ -17,12 +20,16 @@ export type Props = {
1720
hasPendingTransaction: boolean
1821
collection: Collection
1922
curation: CollectionCuration | null
23+
thirdParty: ThirdParty | null
2024
onReject: typeof rejectCollectionRequest
25+
onDisableThirdParty: (...args: Parameters<typeof disableThirdPartyRequest>) => unknown
2126
onRejectCuration: typeof rejectCollectionCurationRequest
2227
onClose: () => void
2328
}
2429

2530
export type MapStateProps = Pick<Props, 'isLoading' | 'hasPendingTransaction'>
26-
export type MapDispatchProps = Pick<Props, 'onReject' | 'onRejectCuration'>
27-
export type MapDispatch = Dispatch<RejectCollectionRequestAction | RejectCollectionCurationRequestAction | InitiateApprovalFlowAction>
28-
export type OwnProps = Pick<Props, 'open' | 'type' | 'collection' | 'curation'>
31+
export type MapDispatchProps = Pick<Props, 'onReject' | 'onRejectCuration' | 'onDisableThirdParty'>
32+
export type MapDispatch = Dispatch<
33+
RejectCollectionRequestAction | RejectCollectionCurationRequestAction | InitiateApprovalFlowAction | DisableThirdPartyRequestAction
34+
>
35+
export type OwnProps = Pick<Props, 'open' | 'type' | 'collection' | 'curation' | 'thirdParty'>

src/components/ItemEditorPage/TopPanel/TopPanel.container.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,17 @@ import { isWalletCommitteeMember } from 'modules/committee/selectors'
66
import { getSelectedCollectionId, isReviewing } from 'modules/location/selectors'
77
import { setCollectionCurationAssigneeRequest } from 'modules/curations/collectionCuration/actions'
88
import { FETCH_COLLECTION_REQUEST, initiateApprovalFlow, initiateTPApprovalFlow } from 'modules/collection/actions'
9-
import { MapStateProps, MapDispatchProps, MapDispatch } from './TopPanel.types'
10-
import TopPanel from './TopPanel'
119
import { isLoadingType } from 'decentraland-dapps/dist/modules/loading/selectors'
1210
import { getCollection } from 'modules/collection/selectors'
1311
import { FETCH_ITEM_CURATIONS_REQUEST } from 'modules/curations/itemCuration/actions'
1412
import { FETCH_COLLECTION_ITEMS_REQUEST } from 'modules/item/actions'
1513
import { getCollectionItems, getLoading as getLoadingItems, getPaginationData } from 'modules/item/selectors'
1614
import { getCuration } from 'modules/curations/collectionCuration/selectors'
1715
import { getItemCurations, getLoading as getLoadingItemCurations } from 'modules/curations/itemCuration/selectors'
16+
import { getCollectionThirdParty } from 'modules/thirdParty/selectors'
17+
import { isTPCollection } from 'modules/collection/utils'
18+
import { MapStateProps, MapDispatchProps, MapDispatch } from './TopPanel.types'
19+
import TopPanel from './TopPanel'
1820

1921
const mapState = (state: RootState): MapStateProps => {
2022
const selectedCollectionId = getSelectedCollectionId(state)
@@ -23,12 +25,15 @@ const mapState = (state: RootState): MapStateProps => {
2325
const itemCurations = collection ? getItemCurations(state, collection.id) : []
2426
const curation = selectedCollectionId ? getCuration(state, selectedCollectionId) : null
2527
const itemsPaginationData = selectedCollectionId ? getPaginationData(state, selectedCollectionId) : undefined
28+
const thirdParty = collection && isTPCollection(collection) ? getCollectionThirdParty(state, collection) : null
29+
2630
return {
2731
address: getAddress(state),
2832
items,
2933
totalItems: itemsPaginationData?.total || null,
3034
collection,
3135
itemCurations,
36+
thirdParty,
3237
curation,
3338
chainId: getChainId(state),
3439
isConnected: isConnected(state),

src/components/ItemEditorPage/TopPanel/TopPanel.tsx

+14-10
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export default class TopPanel extends React.PureComponent<Props, State> {
3535
setShowRejectionModal = (showRejectionModal: RejectionType | null) => this.setState({ showRejectionModal })
3636

3737
renderPage = (collection: Collection) => {
38-
const { items, itemCurations, curation, totalItems } = this.props
38+
const { items, itemCurations, curation, totalItems, thirdParty } = this.props
3939
const { showRejectionModal, showApproveConfirmModal } = this.state
4040
const { chainId } = this.props
4141
const type = getCollectionType(collection)
@@ -71,6 +71,7 @@ export default class TopPanel extends React.PureComponent<Props, State> {
7171
open={true}
7272
collection={collection}
7373
curation={curation}
74+
thirdParty={thirdParty}
7475
onClose={() => this.setShowRejectionModal(null)}
7576
/>
7677
)}
@@ -87,7 +88,7 @@ export default class TopPanel extends React.PureComponent<Props, State> {
8788
}
8889

8990
renderButton = (type: ButtonType, collection: Collection, curation: CollectionCuration | null) => {
90-
const { address, onInitiateApprovalFlow, onInitiateTPApprovalFlow, reviewedItems, totalItems } = this.props
91+
const { address, thirdParty, onInitiateApprovalFlow, onInitiateTPApprovalFlow, reviewedItems, totalItems } = this.props
9192

9293
const onClickMap = {
9394
[ButtonType.APPROVE]: () =>
@@ -97,7 +98,8 @@ export default class TopPanel extends React.PureComponent<Props, State> {
9798
? onInitiateTPApprovalFlow(collection)
9899
: onInitiateApprovalFlow(collection),
99100
[ButtonType.ENABLE]: () => onInitiateApprovalFlow(collection),
100-
[ButtonType.DISABLE]: () => this.setShowRejectionModal(RejectionType.DISABLE_COLLECTION),
101+
[ButtonType.DISABLE]: () =>
102+
this.setShowRejectionModal(thirdParty ? RejectionType.DISABLE_THIRD_PARTY : RejectionType.DISABLE_COLLECTION),
101103
[ButtonType.REJECT]: () => {
102104
if (curation?.status === CurationStatus.PENDING) {
103105
this.setShowRejectionModal(RejectionType.REJECT_CURATION)
@@ -147,18 +149,20 @@ export default class TopPanel extends React.PureComponent<Props, State> {
147149
}
148150

149151
renderTPButtons = (collection: Collection, collectionCuration: CollectionCuration | null, itemCurations: ItemCuration[] | null) => {
150-
const { reviewedItems, totalItems } = this.props
151-
const shouldShowApproveButton = itemCurations?.some(itemCuration => itemCuration.status === CurationStatus.PENDING)
152+
const { reviewedItems, totalItems, thirdParty } = this.props
153+
const areCurationsPending = itemCurations?.some(itemCuration => itemCuration.status === CurationStatus.PENDING)
152154
return (
153155
<>
154156
<Header sub>
155-
{t('item_editor.top_panel.reviewed_counter', { count: reviewedItems.length, threshold: getTPThresholdToReview(totalItems!) })}
157+
{areCurationsPending
158+
? t('item_editor.top_panel.reviewed_counter', { count: reviewedItems.length, threshold: getTPThresholdToReview(totalItems!) })
159+
: t('item_editor.top_panel.not_enough_items_to_curate_more')}
156160
{reviewedItems.length >= getTPThresholdToReview(totalItems!) ? <Icon name="check circle" /> : null}
157161
</Header>
158-
{shouldShowApproveButton ? this.renderButton(ButtonType.APPROVE, collection, collectionCuration) : null}
159-
{this.renderButton(ButtonType.REJECT, collection, collectionCuration)}
160-
{/* TODO: the disable button from below is not the same as the original disable one, it will be implemented once the sagas are ready */}
161-
{/* {this.renderButton(ButtonType.DISABLE, collection, collectionCuration)} */}
162+
{areCurationsPending && this.renderButton(ButtonType.APPROVE, collection, collectionCuration)}
163+
{areCurationsPending && this.renderButton(ButtonType.REJECT, collection, collectionCuration)}
164+
{!areCurationsPending && thirdParty?.isApproved && this.renderButton(ButtonType.DISABLE, collection, null)}
165+
{/* TODO: Add when enabling is possible {!areCurationsPending && !thirdParty?.isApproved && thirdParty?.root && this.renderButton(ButtonType.ENABLE, collection, null)} */}
162166
</>
163167
)
164168
}

src/components/ItemEditorPage/TopPanel/TopPanel.types.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,18 @@ import {
1212
setCollectionCurationAssigneeRequest,
1313
SetCollectionCurationAssigneeRequestAction
1414
} from 'modules/curations/collectionCuration/actions'
15-
import { RejectionType } from './RejectionModal/RejectionModal.types'
1615
import { Collection } from 'modules/collection/types'
1716
import { CollectionCuration } from 'modules/curations/collectionCuration/types'
1817
import { ItemCuration } from 'modules/curations/itemCuration/types'
18+
import { ThirdParty } from 'modules/thirdParty/types'
19+
import { RejectionType } from './RejectionModal/RejectionModal.types'
1920

2021
export type Props = {
2122
items: Item[]
2223
collection: Collection | null
2324
curation: CollectionCuration | null
2425
itemCurations: ItemCuration[] | null
26+
thirdParty: ThirdParty | null
2527
isLoading: boolean
2628
reviewedItems: Item[]
2729
totalItems: number | null
@@ -57,6 +59,7 @@ export type MapStateProps = Pick<
5759
| 'collection'
5860
| 'curation'
5961
| 'itemCurations'
62+
| 'thirdParty'
6063
| 'isLoading'
6164
| 'address'
6265
| 'chainId'

src/components/ThirdPartyCollectionDetailPage/ThirdPartyCollectionDetailPage.module.css

-5
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,3 @@
211211
margin: auto;
212212
margin-bottom: 20px;
213213
}
214-
215-
.thirdPartyLogo {
216-
width: 48px;
217-
height: 48px;
218-
}

src/components/ThirdPartyCollectionDetailPage/ThirdPartyCollectionDetailPage.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ import {
1010
Loader,
1111
Dropdown,
1212
DropdownProps,
13-
InfoTooltip,
14-
Blockie
13+
InfoTooltip
1514
} from 'decentraland-ui'
1615
import { t } from 'decentraland-dapps/dist/modules/translation/utils'
1716
import { getArrayOfPagesFromTotal } from 'lib/api/pagination'
@@ -24,6 +23,7 @@ import LoggedInDetailPage from 'components/LoggedInDetailPage'
2423
import CollectionProvider from 'components/CollectionProvider'
2524
import NotFound from 'components/NotFound'
2625
import BuilderIcon from 'components/Icon'
26+
import { ThirdPartyImage } from 'components/ThirdPartyImage'
2727
import Back from 'components/Back'
2828
import { shorten } from 'lib/address'
2929
import { CopyToClipboard } from 'components/CopyToClipboard'
@@ -198,7 +198,7 @@ export default function ThirdPartyCollectionDetailPage({
198198
<Back absolute onClick={handleGoBack} />
199199
<div className={styles.content}>
200200
<div className={styles.title}>
201-
<Blockie className={styles.thirdPartyLogo} seed={thirdParty.id} size={8} scale={8} shape="circle" />
201+
<ThirdPartyImage thirdPartyId={thirdParty.id} />
202202
<Header size="large" className={styles.name} onClick={handleEditName}>
203203
{collection.name}
204204
</Header>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.main {
2+
width: 48px;
3+
height: 48px;
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Blockie } from 'decentraland-ui'
2+
import classNames from 'classnames'
3+
import styles from './ThirdPartyImage.module.css'
4+
import { Props } from './ThirdPartyImage.types'
5+
6+
export const ThirdPartyImage = (props: Props) => {
7+
const { thirdPartyId, className, shape } = props
8+
return <Blockie className={classNames(styles.main, className)} seed={thirdPartyId} size={8} scale={8} shape={shape ?? 'circle'} />
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export type Props = {
2+
className?: string
3+
thirdPartyId: string
4+
shape?: 'circle' | 'square'
5+
}
+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './ThirdPartyImage'
2+
export * from './ThirdPartyImage.types'

0 commit comments

Comments
 (0)