diff --git a/src/components/Atlas/Atlas.spec.tsx b/src/components/Atlas/Atlas.spec.tsx new file mode 100644 index 00000000..a5bab03f --- /dev/null +++ b/src/components/Atlas/Atlas.spec.tsx @@ -0,0 +1,113 @@ +import { Atlas, AtlasProps, AtlasTile } from './Atlas' + +const OWNED_COLOR = '#3D3A46' +const UNOWNED_COLOR = '#09080A' +const ROAD_COLOR = '#716C7A' + +const buildTile = (tile: Partial = {}): AtlasTile => ({ + x: 0, + y: 0, + type: 9, + owner: '0xowner', + ...tile +}) + +const buildLayer = (tiles: AtlasTile[]) => { + const props = { + tiles: tiles.reduce>((acc, tile) => { + acc[tile.x + ',' + tile.y] = tile + return acc + }, {}) + } as AtlasProps + return new Atlas(props).layer +} + +describe('Atlas.layer', () => { + describe('when the tile is a road', () => { + it('should keep its color and the borders reported by the API', () => { + const layer = buildLayer([buildTile({ type: 7, top: 1, left: 1 })]) + + expect(layer(0, 0)).toEqual({ + color: ROAD_COLOR, + top: true, + left: true, + topLeft: false + }) + }) + }) + + describe('when the tile is a district', () => { + it('should paint it as the LAND it is instead of demarcating it', () => { + const layer = buildLayer([buildTile({ type: 5 })]) + + expect(layer(0, 0)).toEqual({ + color: OWNED_COLOR, + top: false, + left: false, + topLeft: false + }) + }) + + it('should paint an unowned district parcel as unowned LAND', () => { + const layer = buildLayer([ + buildTile({ type: 5, owner: undefined as never }) + ]) + + expect(layer(0, 0)).toHaveProperty('color', UNOWNED_COLOR) + }) + + it('should stitch it to the neighbours that belong to its estate', () => { + const layer = buildLayer([ + buildTile({ + x: 0, + y: 0, + type: 5, + estate_id: '1', + top: 1, + left: 1, + topLeft: 1 + }), + buildTile({ x: 0, y: 1, type: 5, estate_id: '1' }), + buildTile({ x: -1, y: 0, type: 5, estate_id: '2' }), + buildTile({ x: -1, y: 1, type: 5, estate_id: '1' }) + ]) + + expect(layer(0, 0)).toEqual({ + color: OWNED_COLOR, + top: true, + left: false, + topLeft: true + }) + }) + + it('should not stitch a district parcel that does not belong to an estate', () => { + const layer = buildLayer([ + buildTile({ x: 0, y: 0, type: 5, top: 1, left: 1, topLeft: 1 }), + buildTile({ x: 0, y: 1, type: 5 }) + ]) + + expect(layer(0, 0)).toEqual({ + color: OWNED_COLOR, + top: false, + left: false, + topLeft: false + }) + }) + }) + + describe('when the tile is a parcel on sale inside a district', () => { + it('should stitch it to its estate instead of to the district', () => { + const layer = buildLayer([ + buildTile({ x: 0, y: 0, type: 10, estate_id: '1', top: 1, left: 1 }), + buildTile({ x: -1, y: 0, type: 5, estate_id: '2' }) + ]) + + expect(layer(0, 0)).toEqual({ + color: OWNED_COLOR, + top: false, + left: false, + topLeft: false + }) + }) + }) +}) diff --git a/src/components/Atlas/Atlas.tsx b/src/components/Atlas/Atlas.tsx index dc7b696f..f7c27ba1 100644 --- a/src/components/Atlas/Atlas.tsx +++ b/src/components/Atlas/Atlas.tsx @@ -17,6 +17,17 @@ export type AtlasTile = { export { Layer, Coord } +// Legacy tile types served by https://api.decentraland.org/v1/tiles +const DISTRICT_TYPE = 5 +const OWNED_TYPE = 9 +const ON_SALE_TYPE = 10 +const UNOWNED_TYPE = 11 + +const coordsToId = (x: number, y: number) => x + ',' + y + +const isSameEstate = (tile: AtlasTile, other?: AtlasTile) => + !!tile.estate_id && !!other && other.estate_id === tile.estate_id + export type AtlasProps = Omit & { layers?: Layer[] tiles?: Record @@ -32,7 +43,7 @@ const COLOR_BY_TYPE = Object.freeze({ 2: '#ff9990', // my estates 3: '#ff4053', // my estates on sale 4: '#ffbd33', // parcels/estates where I have permissions - 5: '#5054D4', // districts + 5: '#3D3A46', // districts, drawn as owned LAND 6: '#563db8', // contributions 7: '#716C7A', // roads 8: '#70AC76', // plazas @@ -64,6 +75,21 @@ export class Atlas extends React.PureComponent { const id = x + ',' + y if (tiles && id in tiles) { const tile = tiles[id] + // Districts are drawn as the LAND they are, with borders recomputed per + // estate instead of tracing the district outline. Parcels on sale go + // through it too: the ones inside a district are reported as ON_SALE. + // See DAO proposal 9ee1965f-6a96-45f9-bb20-f60baa13607f. + if (tile.type === DISTRICT_TYPE || tile.type === ON_SALE_TYPE) { + return { + color: + tile.type === DISTRICT_TYPE + ? COLOR_BY_TYPE[tile.owner ? OWNED_TYPE : UNOWNED_TYPE] + : COLOR_BY_TYPE[tile.type], + top: isSameEstate(tile, tiles[coordsToId(x, y + 1)]), + left: isSameEstate(tile, tiles[coordsToId(x - 1, y)]), + topLeft: isSameEstate(tile, tiles[coordsToId(x - 1, y + 1)]) + } + } return { color: COLOR_BY_TYPE[tile.type], top: !!tile.top,