diff --git a/app/layout/project/sidebar/scenario/grid-setup/features/target-spf/bulk-action-menu/modals/edit/index.tsx b/app/layout/project/sidebar/scenario/grid-setup/features/target-spf/bulk-action-menu/modals/edit/index.tsx index 5a95be5a51..48add96f66 100644 --- a/app/layout/project/sidebar/scenario/grid-setup/features/target-spf/bulk-action-menu/modals/edit/index.tsx +++ b/app/layout/project/sidebar/scenario/grid-setup/features/target-spf/bulk-action-menu/modals/edit/index.tsx @@ -10,14 +10,22 @@ import { useToasts } from 'hooks/toast'; import Button from 'components/button'; import Field from 'components/forms/field'; import Label from 'components/forms/label'; +import Radio from 'components/forms/radio'; import { composeValidators } from 'components/forms/validations'; import { Feature } from 'types/api/feature'; export type FormValues = { target: number; spf: number; + mode: 'all' | 'only-target' | 'only-spf'; }; +const EDITION_MODES = [ + { value: 'all', label: 'Target & SPF' }, + { value: 'only-target', label: 'Target' }, + { value: 'only-spf', label: 'SPF' }, +]; + const INPUT_CLASSES = 'h-10 w-full rounded-md border border-gray-400 px-3 text-gray-900 focus:border-none focus:outline-none focus:ring-1 focus:ring-blue-600'; @@ -75,7 +83,7 @@ const EditModal = ({ const onEditSubmit = useCallback( (values: FormValues) => { - const { target, spf = 1 } = values; + const { target, spf = 1, mode } = values; const data = { status: 'created', @@ -117,14 +125,34 @@ const EditModal = ({ }; } + let newMarxanSettings = sf.marxanSettings; + + if (mode === 'only-target') { + newMarxanSettings = { + ...newMarxanSettings, + prop: target / 100, + }; + } + + if (mode === 'only-spf') { + newMarxanSettings = { + ...newMarxanSettings, + fpf: +spf, + }; + } + + if (mode === 'all') { + newMarxanSettings = { + prop: target / 100, + fpf: +spf, + }; + } + return { featureId, kind, marxanSettings: selectedFeatures.find((f) => f.id === featureId) - ? { - prop: target / 100 || 0.5, - fpf: +spf, - } + ? newMarxanSettings : sf.marxanSettings, }; }), @@ -181,65 +209,90 @@ const EditModal = ({ return ( initialValues={{ + mode: 'all', target: - (selectedFeatures?.length === 1 && selectedFeatures?.[0]?.marxanSettings?.prop) || 50, - spf: (selectedFeatures?.length === 1 && selectedFeatures?.[0]?.marxanSettings?.fpf) || 1, + (selectedFeatures?.length === 1 && selectedFeatures?.[0]?.marxanSettings?.prop) || + undefined, + spf: + (selectedFeatures?.length === 1 && selectedFeatures?.[0]?.marxanSettings?.fpf) || + undefined, }} - ref={formRef} onSubmit={onEditSubmit} render={({ form, handleSubmit }) => { formRef.current = form; + const currentMode = form?.getState()?.values?.mode; + return (

Edit selected features

+
+ {EDITION_MODES.map(({ value, label }) => { + return ( + + {(fprops) => ( +
+ + +
+ )} +
+ ); + })} +
+
- - name="target" - validate={composeValidators([{ presence: true }])} - > - {(fprops) => ( - - - - - - )} - - - - name="spf" - validate={composeValidators([{ presence: true }])} - > - {(fprops) => ( - - - - - - )} - + {['only-target', 'all'].includes(currentMode) && ( + + name="target" + validate={composeValidators([{ presence: true }])} + > + {(fprops) => ( + + + + + + )} + + )} + {['only-spf', 'all'].includes(currentMode) && ( + + name="spf" + validate={composeValidators([{ presence: true }])} + > + {(fprops) => ( + + + + + + )} + + )}
@@ -247,7 +300,12 @@ const EditModal = ({ Cancel -
diff --git a/app/layout/project/sidebar/scenario/grid-setup/features/target-spf/index.tsx b/app/layout/project/sidebar/scenario/grid-setup/features/target-spf/index.tsx index e51764cd5a..e35c3d46b7 100644 --- a/app/layout/project/sidebar/scenario/grid-setup/features/target-spf/index.tsx +++ b/app/layout/project/sidebar/scenario/grid-setup/features/target-spf/index.tsx @@ -24,6 +24,7 @@ import TargetsSPFTable from 'layout/project/sidebar/scenario/grid-setup/features import ActionsMenu from 'layout/project/sidebar/scenario/grid-setup/features/target-spf/targets-spf-table/actions-menu'; import Section from 'layout/section'; import { Feature } from 'types/api/feature'; +import { toFixedWithoutZeros } from 'utils/numbers'; import CLOSE_SVG from 'svgs/ui/close.svg?sprite'; @@ -103,7 +104,7 @@ const TargetAndSPFFeatures = (): JSX.Element => { splitted: true, marxanSettings: { ...splitFeature.marxanSettings, - prop: splitFeature.marxanSettings?.prop * 100, + prop: toFixedWithoutZeros(splitFeature.marxanSettings?.prop * 100), ...(featureValues[`${feature.id}-${splitFeature.name}`]?.target && { prop: featureValues[`${feature.id}-${splitFeature.name}`].target, }), @@ -127,7 +128,7 @@ const TargetAndSPFFeatures = (): JSX.Element => { type: featureMetadata?.tag, marxanSettings: { ...feature.marxanSettings, - prop: feature.marxanSettings?.prop * 100, + prop: toFixedWithoutZeros(feature.marxanSettings?.prop * 100), ...(featureValues[feature.id]?.target && { prop: featureValues[feature.id].target, }), @@ -424,7 +425,7 @@ const TargetAndSPFFeatures = (): JSX.Element => { return { ...acc, [featureId]: { - target: marxanSettings?.prop * 100, + target: toFixedWithoutZeros(marxanSettings?.prop * 100), spf: marxanSettings?.fpf, }, }; diff --git a/app/layout/project/sidebar/scenario/grid-setup/features/target-spf/targets-spf-table/index.tsx b/app/layout/project/sidebar/scenario/grid-setup/features/target-spf/targets-spf-table/index.tsx index c4bdd0a11d..852c8396c1 100644 --- a/app/layout/project/sidebar/scenario/grid-setup/features/target-spf/targets-spf-table/index.tsx +++ b/app/layout/project/sidebar/scenario/grid-setup/features/target-spf/targets-spf-table/index.tsx @@ -57,6 +57,7 @@ const TargetsSPFTable = ({ theme="light" className="block h-4 w-4 checked:bg-blue-500" onChange={onSelectAll} + checked={selectedIds.length === data.length} disabled={noDataCustom} /> diff --git a/app/utils/numbers.ts b/app/utils/numbers.ts new file mode 100644 index 0000000000..8c24eb8cc7 --- /dev/null +++ b/app/utils/numbers.ts @@ -0,0 +1,3 @@ +export function toFixedWithoutZeros(num: number, decimalPlaces = 2): number { + return Number(num.toFixed(decimalPlaces).replace(/\.?0+$/, '')); +}