diff --git a/apps/client/src/common/components/view-params-editor/InlineColourPicker.tsx b/apps/client/src/common/components/view-params-editor/InlineColourPicker.tsx index 705d591296..208dc543d4 100644 --- a/apps/client/src/common/components/view-params-editor/InlineColourPicker.tsx +++ b/apps/client/src/common/components/view-params-editor/InlineColourPicker.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import SwatchPicker from '../input/colour-input/SwatchPicker'; @@ -16,10 +16,13 @@ const ensureHex = (value: string) => { return value; }; -export default function InlineColourPicker(props: InlineColourPickerProps) { - const { name, value } = props; +export default function InlineColourPicker({ name, value }: InlineColourPickerProps) { const [colour, setColour] = useState(() => ensureHex(value)); + useEffect(() => { + setColour(ensureHex(value)); + }, [value]); + return (
diff --git a/apps/client/src/common/components/view-params-editor/ParamInput.tsx b/apps/client/src/common/components/view-params-editor/ParamInput.tsx index 8d673665a6..f335d9a2ef 100644 --- a/apps/client/src/common/components/view-params-editor/ParamInput.tsx +++ b/apps/client/src/common/components/view-params-editor/ParamInput.tsx @@ -1,10 +1,10 @@ -import { useState } from 'react'; +import { ComponentProps, useEffect, useState } from 'react'; import { useSearchParams } from 'react-router'; import { isStringBoolean } from '../../../features/viewers/common/viewUtils'; import Checkbox from '../checkbox/Checkbox'; import Input from '../input/input/Input'; -import Select from '../select/Select'; +import Select, { SelectOption } from '../select/Select'; import Switch from '../switch/Switch'; import InlineColourPicker from './InlineColourPicker'; @@ -35,7 +35,7 @@ export default function ParamInput({ paramField }: ParamInputProps) { return No options available; } - return ; + return ; } interface EditFormMultiOptionProps { @@ -83,7 +81,12 @@ function MultiOption({ paramField }: EditFormMultiOptionProps) { const { id, values, defaultValue = [''] } = paramField; const optionFromParams = searchParams.getAll(id); - const [paramState, setParamState] = useState(optionFromParams || defaultValue); + const [paramState, setParamState] = useState(optionFromParams.length ? optionFromParams : defaultValue); + + useEffect(() => { + const params = searchParams.getAll(id); + setParamState(params.length ? params : defaultValue); + }, [searchParams, id, defaultValue]); const toggleValue = (value: string, checked: boolean) => { if (checked) { @@ -129,5 +132,52 @@ interface ControlledSwitchProps { } function ControlledSwitch({ id, initialValue }: ControlledSwitchProps) { const [checked, setChecked] = useState(initialValue); + + // synchronise checked state + useEffect(() => { + setChecked(initialValue); + }, [initialValue]); + return ; } + +interface ControlledSelectProps { + id: string; + initialValue?: string; + options: SelectOption[]; +} +function ControlledSelect({ id, initialValue, options }: ControlledSelectProps) { + const [selected, setSelected] = useState(initialValue); + + // synchronise selected state + useEffect(() => { + setSelected(initialValue); + }, [initialValue]); + + return ( + setValue(event.target.value as T)} + {...inputProps} + /> + ); +} diff --git a/apps/client/src/common/components/view-params-editor/ViewParamPresets.tsx b/apps/client/src/common/components/view-params-editor/ViewParamPresets.tsx new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/client/src/common/components/view-params-editor/ViewParamsEditor.tsx b/apps/client/src/common/components/view-params-editor/ViewParamsEditor.tsx index e771c8bb11..83c5193c9e 100644 --- a/apps/client/src/common/components/view-params-editor/ViewParamsEditor.tsx +++ b/apps/client/src/common/components/view-params-editor/ViewParamsEditor.tsx @@ -1,4 +1,4 @@ -import { FormEvent, memo, useReducer } from 'react'; +import { FormEvent, memo } from 'react'; import { IoClose } from 'react-icons/io5'; import { useSearchParams } from 'react-router'; import { Dialog } from '@base-ui-components/react/dialog'; @@ -12,7 +12,7 @@ import Info from '../info/Info'; import { ViewOption } from './viewParams.types'; import { getURLSearchParamsFromObj } from './viewParams.utils'; import { useViewParamsEditorStore } from './viewParamsEditor.store'; -import { ViewParamsShare } from './ViewParamShare'; +import { ViewParamsPresets } from './ViewParamsPresets'; import ViewParamsSection from './ViewParamsSection'; import style from './ViewParamsEditor.module.scss'; @@ -24,12 +24,9 @@ interface EditFormDrawerProps { export default memo(ViewParamsEditor); function ViewParamsEditor({ target, viewOptions }: EditFormDrawerProps) { - // TODO: can we ensure that the options update when the user loads an alias? const [_, setSearchParams] = useSearchParams(); const { data: viewSettings } = useViewSettings(); const { isOpen, close } = useViewParamsEditorStore(); - // TODO: we dont want this as a permanent option - const forceRender = useReducer((x) => x + 1, 0)[1]; const handleClose = () => { close(); @@ -37,7 +34,6 @@ function ViewParamsEditor({ target, viewOptions }: EditFormDrawerProps) { const resetParams = () => { setSearchParams(); - forceRender(); }; const onParamsFormSubmit = (formEvent: FormEvent) => { @@ -46,7 +42,6 @@ function ViewParamsEditor({ target, viewOptions }: EditFormDrawerProps) { const newParamsObject = Object.fromEntries(new FormData(formEvent.currentTarget)); const newSearchParams = getURLSearchParamsFromObj(newParamsObject, viewOptions); setSearchParams(newSearchParams); - forceRender(); }; return ( @@ -71,7 +66,7 @@ function ViewParamsEditor({ target, viewOptions }: EditFormDrawerProps) { {viewSettings.overrideStyles && ( This view style is being modified by a custom CSS file. )} - +
{viewOptions.map((section) => ( { - setSearchParams(`${preset.search}&alias=${preset.alias}`); + const newSearch = new URLSearchParams(preset.search); + newSearch.set('alias', preset.alias); + setSearchParams(newSearch); }; if (viewPresets.length === 0) { @@ -25,12 +27,12 @@ export function ViewParamsShare({ target }: { target: OntimeView }) { return (
{viewPresets.map((preset) => { - const active = window.location.search.includes(`alias=${preset.alias}`); + const active = searchParams.get('alias') === preset.alias; return (
{preset.alias}