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 (and reworkit a little bit) the Layout Grid #1018

Merged
merged 1 commit into from
Oct 14, 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,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
Loading