Skip to content

Commit

Permalink
fix (and reworkit a little bit) the Layout Grid (#1018)
Browse files Browse the repository at this point in the history
  • Loading branch information
nicoecheza authored Oct 14, 2024
1 parent c201492 commit aeb6a17
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 213 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { areConnected } from '@dcl/ecs'
import { useCallback, useState } from 'react'
import { useCallback, useMemo, useState } from 'react'
import { AiOutlineInfoCircle as InfoIcon } from 'react-icons/ai'

import { Dropdown } from '../../../ui'
Expand All @@ -9,16 +9,17 @@ import { Grid, Props as GridProps } from './Grid'

import {
coordToStr,
getCoordinates,
getMinMaxFromOrderedCoords,
getOption,
getLayoutInfo,
stringifyGridError,
getLayoutInfoFromString,
strToCoord,
transformCoordsToString,
getEnabledCoords,
hasCoord
hasCoord,
getGridInfo,
isCoord,
generateGridFrom
} from './utils'
import { getAxisLengths } from './Grid/utils'
import { ModeAdvanced } from './ModeAdvanced'
Expand All @@ -30,59 +31,35 @@ import './Layout.css'
type Coords = GridProps['coords'][0]

function Layout({ value, onChange }: Props) {
const currentLayout = getLayoutInfo(value.parcels)
const coordinates = getCoordinates(currentLayout.min, currentLayout.max)

const [grid, setGrid] = useState<Coords[]>(coordinates)
const [disabled, setDisabled] = useState(new Set<string>())
const { grid: _grid } = useMemo(() => getGridInfo(value.parcels), [value.parcels])
const [grid, setGrid] = useState(_grid)
const [mode, setMode] = useState<Mode>(Mode.GRID)
const [base, setBase] = useState(value.base)

const [gridMin, gridMax] = getMinMaxFromOrderedCoords(grid)
const axisLengths = getAxisLengths(grid)
const enabledCoords = getEnabledCoords(grid, disabled)
const [gridMin, gridMax] = useMemo(() => getMinMaxFromOrderedCoords(grid), [grid])
const axisLengths = useMemo(() => getAxisLengths(grid), [grid])
const enabledCoords = useMemo(() => getEnabledCoords(grid), [grid])
const numberOfCoords = enabledCoords.length

const handleGridChange = (type: keyof Coords) => (e: React.ChangeEvent<HTMLSelectElement>) => {
// this should also work for negative parcels...
const num = Number(e.target.value)
const grixMaxAxis = gridMax[type]
const axisLength = axisLengths[type]
const diff = Math.abs(axisLength - num)
const value = num > axisLength ? grixMaxAxis + diff : grixMaxAxis - diff
const newMax: Coords = { ...gridMax, [type]: value }
return setGrid(getCoordinates(gridMin, newMax))
}

const isTileDisabled = useCallback(
(coord: Coords) => {
const str = coordToStr(coord)
return disabled.has(str)
const handleGridChange = useCallback(
(type: keyof Coords) => (e: React.ChangeEvent<HTMLSelectElement>) => {
const num = Number(e.target.value)
const axisLength = axisLengths[type]
const diff = Math.abs(axisLength - num)
const value = num > axisLength ? gridMax[type] + diff : gridMax[type] - diff
const newMax: Coords = { ...gridMax, [type]: value }
setGrid(generateGridFrom(grid, gridMin, newMax))
},
[grid, disabled]
[grid, gridMin, gridMax, axisLengths]
)

// const isTileDisconnected = useCallback((coord: Coords) => {}, [grid, disabled])
const isTileDisabled = useCallback((coord: Coords) => !hasCoord(enabledCoords, coord), [enabledCoords])

const isBaseTile = useCallback(
(coord: Coords) => {
return coord.x === base.x && coord.y === base.y
},
[base]
)
const isBaseTile = useCallback((coord: Coords) => coord.x === base.x && coord.y === base.y, [base])

const handleTileClick = useCallback(
(coord: Coords) => {
const str = coordToStr(coord)
if (disabled.has(str)) {
disabled.delete(str)
} else {
disabled.add(str)
}
setDisabled(new Set(disabled))
},
[grid, disabled]
)
const handleTileClick = useCallback((coord: Coords) => {
setGrid((prevGrid) => prevGrid.map(($) => (isCoord($, coord) ? { ...$, disabled: !$.disabled } : $)))
}, [])

const handleAdvancedConfirm = useCallback(
(value: ModeAdvancedValue) => {
Expand All @@ -91,46 +68,35 @@ function Layout({ value, onChange }: Props) {
x: length.x > MAX_AXIS_PARCELS ? min.x + Math.min(MAX_AXIS_PARCELS, max.x) : max.x,
y: length.y > MAX_AXIS_PARCELS ? min.y + Math.min(MAX_AXIS_PARCELS, max.y) : max.y
}
const parcels = getCoordinates(min, clampMax)
const base = strToCoord(value.base) || min
setGrid(parcels)
setBase(base)
setGrid(generateGridFrom(grid, min, clampMax))
setBase(strToCoord(value.base) || min)
},
[grid, base, disabled]
[grid]
)

const applyCurrentState = useCallback(() => {
onChange({ parcels: enabledCoords, base })
}, [grid, base, disabled])
}, [enabledCoords, base])

const handleModeChange = useCallback(
(mode: Mode) => () => {
setMode(mode)
},
[mode]
)
const handleModeChange = useCallback((mode: Mode) => () => setMode(mode), [])

const getGridError = useCallback((): GridError | null => {
const gridError = useMemo((): GridError | null => {
if (numberOfCoords <= 0) return GridError.NUMBER_OF_PARCELS
if (!areConnected(enabledCoords)) return GridError.NOT_CONNECTED
if (!hasCoord(enabledCoords, base)) return GridError.MISSING_BASE_PARCEL
return null
}, [grid, base, disabled])
}, [numberOfCoords, enabledCoords, base])

const getTitle = useCallback(() => {
const title = useMemo(() => {
if (mode === Mode.ADVANCED) return 'Set Coordinates'
return `${numberOfCoords} Parcel${numberOfCoords === 1 ? '' : 's'}`
}, [grid, mode, disabled])
}, [numberOfCoords, mode])

const getInstruction = useCallback(() => {
const instruction = useMemo(() => {
if (mode === Mode.ADVANCED) return 'Type in the layout coordinates you want to deploy'
return 'Click individual tiles to exclude/include them from the layout'
}, [mode])

const title = getTitle()
const instruction = getInstruction()
const gridError = getGridError()

return (
<div className="SceneLayout">
<div className="display">
Expand All @@ -151,7 +117,7 @@ function Layout({ value, onChange }: Props) {
{mode === Mode.ADVANCED ? (
<ModeAdvanced
value={{
coords: transformCoordsToString(grid, disabled),
coords: transformCoordsToString(enabledCoords),
base: coordToStr(base)
}}
disabled={!!gridError}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import { MAX_AXIS_PARCELS, TILE_OPTIONS } from './types'
import {
getLayoutInfo,
generateCoordinatesBetweenPoints,
getLayoutInfoFromString,
getCoordinatesBetweenPoints,
getCoordinatesInGridOrder,
getOption,
getMinMaxFromOrderedCoords,
coordToStr,
transformCoordsToString
transformCoordsToString,
getGridInfo
} from './utils'

describe('getLayoutInfo', () => {
it('returns correct parcel info', () => {
describe('getGridInfo', () => {
it('returns correct grid info', () => {
const parcels = [
{ x: 0, y: 0 },
{ x: 0, y: 1 },
Expand All @@ -22,9 +21,14 @@ describe('getLayoutInfo', () => {
min: { x: 0, y: 0 },
max: { x: 1, y: 1 },
length: { x: 1, y: 1 },
parcels: parcels
grid: [
{ x: 0, y: 1, disabled: false },
{ x: 1, y: 1, disabled: false },
{ x: 0, y: 0, disabled: false },
{ x: 1, y: 0, disabled: false }
]
}
expect(getLayoutInfo(parcels)).toEqual(expected)
expect(getGridInfo(parcels)).toEqual(expected)
})
})

Expand All @@ -35,51 +39,33 @@ describe('getLayoutInfoFromString', () => {
min: { x: 0, y: 0 },
max: { x: 1, y: 1 },
length: { x: 1, y: 1 },
parcels: [
{ x: 0, y: 0 },
{ x: 0, y: 1 },
{ x: 1, y: 0 },
{ x: 1, y: 1 }
grid: [
{ x: 0, y: 1, disabled: false },
{ x: 1, y: 1, disabled: false },
{ x: 0, y: 0, disabled: false },
{ x: 1, y: 0, disabled: false }
]
}
expect(getLayoutInfoFromString(parcelsString)).toEqual(expected)
})
})

describe('getCoordinatesBetweenPoints', () => {
it('returns correct coordinates between two points', () => {
describe('generateCoordinatesBetweenPoints', () => {
it('returns correct coordinates between two points sorted in grid order', () => {
const pointA = { x: 0, y: 0 }
const pointB = { x: 2, y: 2 }
const expected = [
{ x: 0, y: 0 },
{ x: 0, y: 1 },
{ x: 0, y: 2 },
{ x: 1, y: 0 },
{ x: 1, y: 1 },
{ x: 1, y: 2 },
{ x: 2, y: 0 },
{ x: 2, y: 1 },
{ x: 2, y: 2 }
]
expect(getCoordinatesBetweenPoints(pointA, pointB)).toEqual(expected)
})
})

describe('getCoordinatesInGridOrder', () => {
it('returns coordinates sorted in grid order', () => {
const unsorted = [
{ x: 0, y: 0 },
{ x: 0, y: 1 },
{ x: 1, y: 0 },
{ x: 1, y: 1 }
]
const expected = [
{ x: 2, y: 2 },
{ x: 0, y: 1 },
{ x: 1, y: 1 },
{ x: 2, y: 1 },
{ x: 0, y: 0 },
{ x: 1, y: 0 }
{ x: 1, y: 0 },
{ x: 2, y: 0 }
]
expect(getCoordinatesInGridOrder(unsorted)).toEqual(expected)
expect(generateCoordinatesBetweenPoints(pointA, pointB)).toEqual(expected)
})
})

Expand Down Expand Up @@ -185,38 +171,14 @@ describe('transformCoordsToString', () => {
{ x: 1, y: 1 },
{ x: 2, y: 2 }
]
const disabledCoords = new Set<string>()
const expected = '0,0 1,1 2,2'
expect(transformCoordsToString(coords, disabledCoords)).toEqual(expected)
})

it('filters disabled coordinates', () => {
const coords = [
{ x: 0, y: 0 },
{ x: 1, y: 1 },
{ x: 2, y: 2 }
]
const disabledCoords = new Set(['1,1'])
const expected = '0,0 2,2'
expect(transformCoordsToString(coords, disabledCoords)).toEqual(expected)
expect(transformCoordsToString(coords)).toEqual(expected)
})

it('returns empty string for empty coordinates array', () => {
const coords = []
const disabledCoords = new Set<string>()
const expected = ''
expect(transformCoordsToString(coords, disabledCoords)).toEqual(expected)
})

it('returns empty string for all coordinates disabled', () => {
const coords = [
{ x: 0, y: 0 },
{ x: 1, y: 1 },
{ x: 2, y: 2 }
]
const disabledCoords = new Set(['0,0', '1,1', '2,2'])
const expected = ''
expect(transformCoordsToString(coords, disabledCoords)).toEqual(expected)
expect(transformCoordsToString(coords)).toEqual(expected)
})

it('handles coordinates with negative values', () => {
Expand All @@ -225,19 +187,17 @@ describe('transformCoordsToString', () => {
{ x: 0, y: 0 },
{ x: 1, y: 1 }
]
const disabledCoords = new Set(['-1,-1'])
const expected = '0,0 1,1'
expect(transformCoordsToString(coords, disabledCoords)).toEqual(expected)
const expected = '-1,-1 0,0 1,1'
expect(transformCoordsToString(coords)).toEqual(expected)
})

it('handles large coordinate values', () => {
const coords = [
{ x: 1000000, y: 1000000 },
{ x: 2000000, y: 2000000 }
]
const disabledCoords = new Set<string>()
const expected = '1000000,1000000 2000000,2000000'
expect(transformCoordsToString(coords, disabledCoords)).toEqual(expected)
expect(transformCoordsToString(coords)).toEqual(expected)
})
})

Expand Down
Loading

0 comments on commit aeb6a17

Please sign in to comment.