Skip to content

Commit

Permalink
feat: Mapping tokens to wearables (#3138)
Browse files Browse the repository at this point in the history
* feat: Mapping tokens to wearables

* fix: Types and tests

* fix: Types

* fix: Word break
  • Loading branch information
LautaroPetaccio authored Jul 12, 2024
1 parent bb514b1 commit 22fa9b9
Show file tree
Hide file tree
Showing 34 changed files with 394 additions and 92 deletions.
34 changes: 17 additions & 17 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
"dependencies": {
"@babylonjs/core": "^4.2.0",
"@babylonjs/loaders": "^4.2.0",
"@dcl/builder-client": "^4.3.3",
"@dcl/builder-client": "^4.4.0",
"@dcl/builder-templates": "^0.2.0",
"@dcl/content-hash-tree": "^1.1.3",
"@dcl/crypto": "^3.4.5",
"@dcl/hashing": "^3.0.4",
"@dcl/mini-rpc": "^1.0.7",
"@dcl/schemas": "^11.7.0",
"@dcl/schemas": "^11.12.0",
"@dcl/sdk": "7.5.5",
"@dcl/single-sign-on-client": "^0.1.0",
"@dcl/ui-env": "^1.5.0",
Expand Down Expand Up @@ -42,7 +42,7 @@
"decentraland-ecs": "6.12.4-7784644013.commit-f770b3e",
"decentraland-experiments": "^1.0.2",
"decentraland-transactions": "^2.6.1",
"decentraland-ui": "^6.1.1",
"decentraland-ui": "^6.1.2",
"ethers": "^5.6.8",
"file-saver": "^2.0.1",
"graphql": "^15.8.0",
Expand Down Expand Up @@ -158,4 +158,4 @@
"decentraland-ecs": "6.12.4-7784644013.commit-f770b3e",
"decentraland": "3.3.0"
}
}
}
5 changes: 2 additions & 3 deletions src/components/CollectionStatus/CollectionStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ import { t } from 'decentraland-dapps/dist/modules/translation/utils'
import { Popup } from 'decentraland-ui'

import { SyncStatus } from 'modules/item/types'
import { isThirdPartyCollection } from 'modules/collection/utils'
import { Props } from './CollectionStatus.types'
import { getCollectionType } from 'modules/collection/utils'
import { CollectionType } from 'modules/collection/types'
import './CollectionStatus.css'

export default class CollectionStatus extends React.PureComponent<Props> {
render() {
const { status, collection } = this.props
const shouldRenderStatus = status && status !== SyncStatus.UNPUBLISHED && getCollectionType(collection) !== CollectionType.THIRD_PARTY
const shouldRenderStatus = status && status !== SyncStatus.UNPUBLISHED && !isThirdPartyCollection(collection)
return shouldRenderStatus ? (
<Popup
position="top center"
Expand Down
11 changes: 3 additions & 8 deletions src/components/CurationPage/CollectionRow/CollectionRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ import { Icon, Table } from 'decentraland-ui'
import { t } from 'decentraland-dapps/dist/modules/translation/utils'
import { locations } from 'routing/locations'
import { getCollectionCurationState } from 'modules/curations/collectionCuration/utils'
import { getCollectionType } from 'modules/collection/utils'
import { isThirdPartyCollection } from 'modules/collection/utils'
import { CurationStatus } from 'modules/curations/types'
import { CollectionType } from 'modules/collection/types'
import CollectionStatus from 'components/CollectionStatus'
import CollectionImage from 'components/CollectionImage'
import { AssignModalOperationType } from 'components/Modals/EditCurationAssigneeModal/EditCurationAssigneeModal.types'
Expand Down Expand Up @@ -92,14 +91,10 @@ export default function CollectionRow(props: Props) {
</div>
</Table.Cell>
<Table.Cell width={2}>
<div>
{getCollectionType(collection) === CollectionType.THIRD_PARTY
? t('collection_row.type_third_party')
: t('collection_row.type_standard')}
</div>
<div>{isThirdPartyCollection(collection) ? t('collection_row.type_third_party') : t('collection_row.type_standard')}</div>
</Table.Cell>
<Table.Cell width={2}>
<div>{getCollectionType(collection) === CollectionType.THIRD_PARTY ? '-' : <Profile textOnly address={collection.owner} />}</div>
<div>{isThirdPartyCollection(collection) ? '-' : <Profile textOnly address={collection.owner} />}</div>
</Table.Cell>
<Table.Cell width={3}>
<div title={format(createdAtDate, 'd MMMM yyyy HH:mm')}>
Expand Down
8 changes: 3 additions & 5 deletions src/components/ItemEditorPage/LeftPanel/LeftPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as React from 'react'
import { Loader, Tabs } from 'decentraland-ui'
import { t } from 'decentraland-dapps/dist/modules/translation/utils'
import { Collection, CollectionType } from 'modules/collection/types'
import { Collection } from 'modules/collection/types'
import { CurationStatus } from 'modules/curations/types'
import { getCollectionType } from 'modules/collection/utils'
import { isThirdPartyCollection } from 'modules/collection/utils'
import { Item, ItemType } from 'modules/item/types'
import CollectionProvider from 'components/CollectionProvider'
import Header from './Header'
Expand Down Expand Up @@ -125,9 +125,7 @@ export default class LeftPanel extends React.PureComponent<Props, State> {
getItems(collection: Collection | null, collectionItems: Item[]) {
const { selectedCollectionId, orphanItems, isReviewing } = this.props
if (selectedCollectionId && collection) {
return getCollectionType(collection) === CollectionType.THIRD_PARTY && isReviewing
? collectionItems.filter(item => item.isPublished)
: collectionItems
return isThirdPartyCollection(collection) && isReviewing ? collectionItems.filter(item => item.isPublished) : collectionItems
}
return orphanItems
}
Expand Down
17 changes: 17 additions & 0 deletions src/components/MappingEditor/MappingEditor.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.main {
display: flex;
flex-direction: column;
}

.mappings {
display: flex;
flex-direction: column;
}

.main :global(.ui.dropdown > .text > img) {
margin-top: 3px;
}

.mappingType :global(.ui.dropdown .menu > .item > img) {
margin-top: 0px;
}
158 changes: 158 additions & 0 deletions src/components/MappingEditor/MappingEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { SyntheticEvent, useCallback, useMemo } from 'react'
import { DropdownProps, Field, InputOnChangeData, SelectField, TextAreaField, TextAreaProps } from 'decentraland-ui'
import { MappingType, MultipleMapping } from '@dcl/schemas'
import { t } from 'decentraland-dapps/dist/modules/translation'
import allIcon from '../../icons/all.svg'
import multipleIcon from '../../icons/multiple.svg'
import singleIcon from '../../icons/single.svg'
import rangeIcon from '../../icons/range.svg'
import { Props } from './MappingEditor.types'
import styles from './MappingEditor.module.css'

const mappingTypeIcons = {
[MappingType.ANY]: allIcon,
[MappingType.MULTIPLE]: multipleIcon,
[MappingType.SINGLE]: singleIcon,
[MappingType.RANGE]: rangeIcon
}

export const MappingEditor = (props: Props) => {
const { mapping, error, disabled, onChange } = props
const [mappingType, mappingValue] = useMemo(() => {
switch (mapping.type) {
case MappingType.MULTIPLE:
return [MappingType.MULTIPLE, mapping.ids.join(', ')]
case MappingType.SINGLE:
return [MappingType.SINGLE, mapping.id]
case MappingType.RANGE:
return [MappingType.RANGE, `${mapping.from},${mapping.to}`]
case MappingType.ANY:
default:
return [MappingType.ANY, '']
}
}, [mapping])

const mappingTypeOptions = useMemo(
() =>
Object.values(MappingType).map((mapping: MappingType) => ({
value: mapping,
image: mappingTypeIcons[mapping],
text: t(`mapping_editor.mapping_types.${mapping}`)
})),
[]
)

const handleMappingTypeChange = useCallback((_: SyntheticEvent<HTMLElement, Event>, { value }: DropdownProps) => {
const mappingType = value as MappingType
switch (mappingType) {
case MappingType.ANY:
props.onChange({ type: mappingType })
break
case MappingType.MULTIPLE:
props.onChange({ type: mappingType, ids: [] })
break
case MappingType.SINGLE:
props.onChange({ type: mappingType, id: '' })
break
case MappingType.RANGE:
props.onChange({ type: mappingType, to: '', from: '' })
break
}
}, [])

const handleSingleMappingValueChange = useCallback((_: React.ChangeEvent<HTMLInputElement>, data: InputOnChangeData) => {
onChange({ type: MappingType.SINGLE, id: data.value })
}, [])

const handleMultipleMappingValueChange = useCallback((_: React.ChangeEvent<HTMLTextAreaElement>, data: TextAreaProps) => {
const ids =
data.value
?.toString()
.replaceAll(/[^0-9,\s]/g, '')
.split(',')
.map(value => value.trim()) ?? []

onChange({
type: MappingType.MULTIPLE,
ids
})
}, [])

const handleFromMappingValueChange = useCallback(
(_: React.ChangeEvent<HTMLInputElement>, data: InputOnChangeData) => {
onChange({ type: MappingType.RANGE, from: data.value, to: mappingValue.split(',')[1] })
},
[mappingValue]
)

const handleToMappingValueChange = useCallback(
(_: React.ChangeEvent<HTMLInputElement>, data: InputOnChangeData) => {
onChange({ type: MappingType.RANGE, from: mappingValue.split(',')[0], to: data.value })
},
[mappingValue]
)

return (
<div className={styles.main}>
<SelectField
label={t('mapping_editor.mapping_type_label')}
onChange={handleMappingTypeChange}
value={mappingType}
className={styles.mappingType}
options={mappingTypeOptions}
/>{' '}
<div className={styles.mappings}>
{mappingType === MappingType.ANY ? (
<Field label={t('mapping_editor.mapping_value_label')} disabled value={t('mapping_editor.mapping_value_any')} />
) : mappingType === MappingType.SINGLE ? (
<Field
label={t('mapping_editor.mapping_value_label')}
disabled={disabled}
type={mappingType === MappingType.SINGLE ? 'number' : 'text'}
value={mappingValue}
error={!!error}
message={error}
placeholder={'1234567890'}
maxLength={78}
onChange={handleSingleMappingValueChange}
/>
) : mappingType === MappingType.MULTIPLE ? (
<TextAreaField
label={t('mapping_editor.mapping_value_label')}
disabled={disabled}
info={
mappingValue.length === 0 && !error
? t('mapping_editor.mapping_value_multiple_info')
: t('mapping_editor.mapping_value_multiple_amount_info', { count: (mapping as MultipleMapping).ids.length })
}
error={error}
placeholder={'1, 2, 3, 4'}
value={mappingValue}
onChange={handleMultipleMappingValueChange}
/>
) : mappingType === MappingType.RANGE ? (
<>
<Field
label={t('mapping_editor.mapping_value_from_label')}
disabled={disabled}
type="number"
placeholder={'1'}
maxLength={78}
value={mappingValue.split(',')[0]}
onChange={handleFromMappingValueChange}
/>
<Field
label={t('mapping_editor.mapping_value_to_label')}
disabled={disabled}
type="number"
placeholder={'4000'}
maxLength={78}
value={mappingValue.split(',')[1]}
onChange={handleToMappingValueChange}
/>
</>
) : null}
</div>
</div>
)
}
8 changes: 8 additions & 0 deletions src/components/MappingEditor/MappingEditor.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Mapping } from '@dcl/schemas'

export type Props = {
mapping: Mapping
error?: string
disabled?: boolean
onChange: (mapping: Mapping) => void
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,5 @@

.ui.modal.ApprovalFlowModal .error-container .urn {
font-size: 12px;
word-break: break-all;
}
Loading

0 comments on commit 22fa9b9

Please sign in to comment.