diff --git a/app/hoc/projects.ts b/app/hoc/projects.ts index 8dfad60c75..544846e14d 100644 --- a/app/hoc/projects.ts +++ b/app/hoc/projects.ts @@ -2,6 +2,7 @@ import { QueryClient } from 'react-query'; import { getSession } from 'next-auth/client'; import { dehydrate } from 'react-query/hydration'; + import PROJECTS from 'services/projects'; import { mergeDehydratedState } from './utils'; diff --git a/app/hoc/scenarios.ts b/app/hoc/scenarios.ts new file mode 100644 index 0000000000..5ac0efd09c --- /dev/null +++ b/app/hoc/scenarios.ts @@ -0,0 +1,71 @@ +import { QueryClient } from 'react-query'; + +import { getSession } from 'next-auth/client'; +import { dehydrate } from 'react-query/hydration'; + +import SCENARIOS from 'services/scenarios'; + +import { mergeDehydratedState } from './utils'; + +export function withScenario(getServerSidePropsFunc?: Function) { + return async (context: any) => { + const session = await getSession(context); + + if (!session) { + if (getServerSidePropsFunc) { + const SSPF = await getServerSidePropsFunc(context) || {}; + + return { + props: { + ...SSPF.props, + }, + }; + } + + return { + props: {}, + }; + } + + const { params } = context; + + const { sid } = params; + + const queryClient = new QueryClient(); + + await queryClient.prefetchQuery(['scenarios', sid], () => SCENARIOS.request({ + method: 'GET', + url: `/${sid}`, + headers: { + Authorization: `Bearer ${session.accessToken}`, + }, + }).then((response) => { + return response.data; + })); + + if (getServerSidePropsFunc) { + const SSPF = await getServerSidePropsFunc(context) || {}; + + const { dehydratedState: prevDehydratedState } = SSPF.props; + const currentDehydratedState = JSON.parse(JSON.stringify(dehydrate(queryClient))); + + const newDehydratedState = mergeDehydratedState(prevDehydratedState, currentDehydratedState); + + return { + ...SSPF, + props: { + session, + ...SSPF.props, + dehydratedState: newDehydratedState, + }, + }; + } + + return { + props: { + session, + dehydratedState: JSON.parse(JSON.stringify(dehydrate(queryClient))), + }, + }; + }; +} diff --git a/app/hooks/gap-analysis/index.ts b/app/hooks/gap-analysis/index.ts index 1d55865df7..33b6c9b0ac 100644 --- a/app/hooks/gap-analysis/index.ts +++ b/app/hooks/gap-analysis/index.ts @@ -82,13 +82,13 @@ export function useGapAnalysis(sId, options: UseFeaturesOptionsProps = {}) { return pageData.map((d):AllItemProps => { const { id, - alias, - featureClassName, + name, } = d; + // TODO: use data from API return { id, - name: alias || featureClassName, + name, current: { percent: 0.5, value: 400, diff --git a/app/hooks/map/index.ts b/app/hooks/map/index.ts index b1cc05ac2f..0faee7d711 100644 --- a/app/hooks/map/index.ts +++ b/app/hooks/map/index.ts @@ -240,7 +240,7 @@ export function usePUGridPreviewLayer({ // PUGrid export function usePUGridLayer({ - active, sid, type, subtype, runId, options = {}, cache, + active, sid, type, subtype, options = {}, cache, }: UsePUGridLayer) { const include = useMemo(() => { if (type === 'protected-areas' || type === 'features') return 'protection'; @@ -259,6 +259,7 @@ export function usePUGridLayer({ wdpaThreshold = 0, puIncludedValue, puExcludedValue, + runId, } = options; return { @@ -290,24 +291,28 @@ export function usePUGridLayer({ }, // PROTECTED AREAS - ...(type === 'protected-areas' && subtype === 'protected-areas-percentage') || type === 'features' ? [ - { - type: 'fill', - 'source-layer': 'layer0', - paint: { - 'fill-color': COLORS.wdpa, - 'fill-opacity': [ - 'case', - ['all', - ['has', 'percentageProtected'], - ['>=', ['get', 'percentageProtected'], (wdpaThreshold * 100)], + ...( + type === 'protected-areas' && subtype === 'protected-areas-percentage') + || type === 'features' + || (type === 'analysis' && subtype === 'analysis-preview' + ) ? [ + { + type: 'fill', + 'source-layer': 'layer0', + paint: { + 'fill-color': COLORS.wdpa, + 'fill-opacity': [ + 'case', + ['all', + ['has', 'percentageProtected'], + ['>=', ['get', 'percentageProtected'], (wdpaThreshold)], + ], + 0.5, + 0, ], - 0.5, - 0, - ], + }, }, - }, - ] : [], + ] : [], // ANALYSIS - GAP ANALYSIS ...type === 'analysis' && subtype === 'analysis-gap-analysis' ? [ @@ -419,11 +424,10 @@ export function usePUGridLayer({ }, }, ] : [], - ], }, }; - }, [cache, active, sid, type, subtype, runId, options, include]); + }, [cache, active, sid, type, subtype, options, include]); } // PUGrid diff --git a/app/hooks/map/types.ts b/app/hooks/map/types.ts index 0be360cd7f..221972a35e 100644 --- a/app/hooks/map/types.ts +++ b/app/hooks/map/types.ts @@ -63,6 +63,7 @@ export interface UsePUGridLayer { puAction?: string; puIncludedValue?: string[]; puExcludedValue?: string[]; + runId?: string; }; } @@ -75,5 +76,6 @@ export interface UseLegend { puAction?: string; puIncludedValue?: string[]; puExcludedValue?: string[]; + runId?: string; }; } diff --git a/app/hooks/solutions/index.ts b/app/hooks/solutions/index.ts index 3d8d505d8c..de3e9a6bb0 100644 --- a/app/hooks/solutions/index.ts +++ b/app/hooks/solutions/index.ts @@ -75,7 +75,7 @@ export function useSolutions(sid, options: UseSolutionsOptionsProps = {}) { return { id, - run: runId, + runId, score: scoreValue, cost: costValue, planningUnits, @@ -94,7 +94,7 @@ export function useSolutions(sid, options: UseSolutionsOptionsProps = {}) { export function useSolution(sid, solutionId) { const [session] = useSession(); - const query = useQuery(['scenarios', sid, solutionId], async () => SCENARIOS.request({ + const query = useQuery(['solution-id', sid, solutionId], async () => SCENARIOS.request({ method: 'GET', url: `/${sid}/marxan/solutions/${solutionId}`, headers: { @@ -116,36 +116,23 @@ export function useSolution(sid, solutionId) { }, [query, data?.data]); } -export function useMostDifferentSolutions(sid, options: UseSolutionsOptionsProps = {}) { +export function useMostDifferentSolutions(sid) { const [session] = useSession(); - const { - filters = {}, - } = options; - - const parsedFilters = Object.keys(filters) - .reduce((acc, k) => { - return { - ...acc, - [`filter[${k}]`]: filters[k], - }; - }, {}); - - const query = useQuery(['scenarios', sid], async () => SCENARIOS.request({ + const query = useQuery(['solutions-different', sid], async () => SCENARIOS.request({ method: 'GET', url: `/${sid}/marxan/solutions/most-different`, headers: { Authorization: `Bearer ${session.accessToken}`, }, - params: { - ...parsedFilters, - }, + }).then((response) => { + return response.data; })); const { data } = query; return useMemo(() => { - const parsedData = Array.isArray(data.data.data) ? data.data.data.map((d) => { + const parsedData = Array.isArray(data?.data) ? data.data.map((d) => { const { id, runId, @@ -157,7 +144,7 @@ export function useMostDifferentSolutions(sid, options: UseSolutionsOptionsProps return { id, - run: runId, + runId, score: scoreValue, cost: costValue, planningUnits, @@ -175,7 +162,7 @@ export function useMostDifferentSolutions(sid, options: UseSolutionsOptionsProps export function useBestSolution(sid) { const [session] = useSession(); - const query = useQuery(['scenarios', sid], async () => SCENARIOS.request({ + const query = useQuery(['solutions-best', sid], async () => SCENARIOS.request({ method: 'GET', url: `/${sid}/marxan/solutions/best`, headers: { diff --git a/app/hooks/solutions/mock.ts b/app/hooks/solutions/mock.ts index cb635dcd6d..eabf35448a 100644 --- a/app/hooks/solutions/mock.ts +++ b/app/hooks/solutions/mock.ts @@ -3,7 +3,7 @@ import { Solution } from 'types/project-model'; const ITEMS: Solution[] = [ { id: '1', - run: 1, + runId: 1, score: 5, cost: 100, planningUnits: 10, @@ -11,7 +11,7 @@ const ITEMS: Solution[] = [ }, { id: '2', - run: 2, + runId: 2, score: 10, cost: 10, planningUnits: 1, @@ -19,7 +19,7 @@ const ITEMS: Solution[] = [ }, { id: '3', - run: 3, + runId: 3, score: 3, cost: 13, planningUnits: 3, diff --git a/app/layout/scenarios/edit/features/component.tsx b/app/layout/scenarios/edit/features/component.tsx index 34ef439cae..4566fca739 100644 --- a/app/layout/scenarios/edit/features/component.tsx +++ b/app/layout/scenarios/edit/features/component.tsx @@ -8,7 +8,7 @@ import { useRouter } from 'next/router'; import { getScenarioEditSlice } from 'store/slices/scenarios/edit'; import { motion } from 'framer-motion'; -import { mergeScenarioStatusMetaData, SCENARIO_EDITING_META_DATA_DEFAULT_VALUES } from 'utils/utils-scenarios'; +import { mergeScenarioStatusMetaData } from 'utils/utils-scenarios'; import { useSelectedFeatures } from 'hooks/features'; import { useScenario, useSaveScenario } from 'hooks/scenarios'; @@ -56,7 +56,7 @@ export const ScenariosSidebarEditFeatures: React.FC = () => { const { data = {} } = useProject(pid); const { bbox } = data; + const { + data: scenarioData, + } = useScenario(sid); + const { data: selectedFeaturesData, } = useSelectedFeatures(sid, {}); @@ -59,6 +64,7 @@ export const ScenariosEditMap: React.FC = () => { tab, subtab, cache, + // WDPA wdpaCategories, wdpaThreshold, @@ -101,8 +107,8 @@ export const ScenariosEditMap: React.FC = () => { type: tab, subtype: subtab, options: { - ...wdpaCategories, - wdpaThreshold, + wdpaIucnCategories: tab === 'protected-areas' && subtab === 'protected-areas-preview' ? wdpaCategories.wdpaIucnCategories : scenarioData.wdpaIucnCategories, + wdpaThreshold: tab === 'protected-areas' && subtab === 'protected-areas-percentage' ? wdpaThreshold * 100 : scenarioData.wdpaThreshold, puAction, puIncludedValue: puTmpIncludedValue, puExcludedValue: puTmpExcludedValue, @@ -115,8 +121,8 @@ export const ScenariosEditMap: React.FC = () => { type: tab, subtype: subtab, options: { - ...wdpaCategories, - wdpaThreshold, + wdpaIucnCategories: tab === 'protected-areas' && subtab === 'protected-areas-preview' ? wdpaCategories.wdpaIucnCategories : scenarioData.wdpaIucnCategories, + wdpaThreshold: tab === 'protected-areas' && subtab === 'protected-areas-percentage' ? wdpaThreshold : scenarioData.wdpaThreshold, puAction, puIncludedValue: puTmpIncludedValue, puExcludedValue: puTmpExcludedValue, diff --git a/app/layout/scenarios/edit/run/component.tsx b/app/layout/scenarios/edit/run/component.tsx index 0eb77e708c..761514ae23 100644 --- a/app/layout/scenarios/edit/run/component.tsx +++ b/app/layout/scenarios/edit/run/component.tsx @@ -8,7 +8,6 @@ import { useRouter } from 'next/router'; import cx from 'classnames'; import { usePlausible } from 'next-plausible'; -import { SCENARIO_EDITING_META_DATA_DEFAULT_VALUES } from 'utils/utils-scenarios'; import { useMe } from 'hooks/me'; import { useProject } from 'hooks/projects'; @@ -44,7 +43,7 @@ export const ScenariosRun: React.FC = () => { const { data: scenarioData } = useScenario(sid); const { metadata } = scenarioData || {}; - const { scenarioEditingMetadata = SCENARIO_EDITING_META_DATA_DEFAULT_VALUES } = metadata || {}; + const { scenarioEditingMetadata } = metadata || {}; const saveScenarioMutation = useSaveScenario({ requestConfig: { diff --git a/app/layout/scenarios/edit/run/constants.tsx b/app/layout/scenarios/edit/run/constants.tsx index 1cd3ea54b5..138aacbc34 100644 --- a/app/layout/scenarios/edit/run/constants.tsx +++ b/app/layout/scenarios/edit/run/constants.tsx @@ -694,35 +694,6 @@ export const FIELDS = [ }, ], }, - { - id: 'MISSLEVEL', - label: 'Conservation Feature missing proportion', - description: (

Amount or target below which a Conservation Feature is counted as ‘missing’.This is the proportion of the target a conservation feature must reach in order for it to be reported as met. There are situations where Marxan can get extremely close to the target (e.g. 99% of the desired level) without actually meeting the target. You can specify a level for which you are pragmatically satisfied that the amount of representation is close enough to the target to report it as met. This value should always be high, i.e. greater than or equal to ‘0.95’. If you are setting it lower than ‘0.95’, you should probably think about changing your targets.

), - category: { - id: 'program-control', - label: 'Program control', - }, - default: 1, - required: false, - advanced: true, - input: { - className: 'text-2xl', - min: 0, - max: 1000000, - type: 'number', - step: '1', - }, - validations: [ - { - presence: true, - numericality: { - onlyInteger: true, - greaterThanOrEqualTo: 0, - lessThanOrEqualTo: 1000000, - }, - }, - ], - }, { id: 'RUNMODE', label: 'Run option', diff --git a/app/layout/scenarios/edit/tabs/component.tsx b/app/layout/scenarios/edit/tabs/component.tsx index 241664df04..55ff7557e1 100644 --- a/app/layout/scenarios/edit/tabs/component.tsx +++ b/app/layout/scenarios/edit/tabs/component.tsx @@ -7,7 +7,6 @@ import { useRouter } from 'next/router'; import { getScenarioEditSlice } from 'store/slices/scenarios/edit'; import { motion } from 'framer-motion'; -import { SCENARIO_EDITING_META_DATA_DEFAULT_VALUES } from 'utils/utils-scenarios'; import { useScenario } from 'hooks/scenarios'; @@ -32,7 +31,7 @@ export const ScenariosSidebarTabs: React.FC = () => { const { scenarioEditingMetadata } = metadata || {}; const { status: metaStatus, - } = scenarioEditingMetadata || SCENARIO_EDITING_META_DATA_DEFAULT_VALUES; + } = scenarioEditingMetadata || {}; const scenarioSlice = getScenarioEditSlice(sid); const { setTab, setSubTab } = scenarioSlice.actions; diff --git a/app/layout/scenarios/edit/wdpa/component.tsx b/app/layout/scenarios/edit/wdpa/component.tsx index 9f8e3d4032..5cf1e3b0b5 100644 --- a/app/layout/scenarios/edit/wdpa/component.tsx +++ b/app/layout/scenarios/edit/wdpa/component.tsx @@ -7,7 +7,6 @@ import { useRouter } from 'next/router'; import { getScenarioEditSlice } from 'store/slices/scenarios/edit'; import { motion } from 'framer-motion'; -import { SCENARIO_EDITING_META_DATA_DEFAULT_VALUES } from 'utils/utils-scenarios'; import { useProject } from 'hooks/projects'; import { useScenario } from 'hooks/scenarios'; @@ -45,7 +44,7 @@ export const ScenariosSidebarEditWDPA: React.FC = const { subtab: metaSubtab, - } = scenarioEditingMetadata || SCENARIO_EDITING_META_DATA_DEFAULT_VALUES; + } = scenarioEditingMetadata; const { data: wdpaData } = useWDPACategories({ adminAreaId: projectData?.adminAreaLevel2Id diff --git a/app/layout/scenarios/edit/wdpa/threshold/component.tsx b/app/layout/scenarios/edit/wdpa/threshold/component.tsx index 880c3086e6..42ff09d88e 100644 --- a/app/layout/scenarios/edit/wdpa/threshold/component.tsx +++ b/app/layout/scenarios/edit/wdpa/threshold/component.tsx @@ -154,7 +154,10 @@ export const WDPAThreshold: React.FC = ({ }, [saveScenarioMutation, sid, metadata, onBack]); // Loading - if ((scenarioIsFetching && !scenarioIsFetched) || (wdpaIsFetching && !wdpaIsFetched)) { + if ( + (!!scenarioData && scenarioIsFetching && !scenarioIsFetched) + || (!!wdpaData && wdpaIsFetching && !wdpaIsFetched) + ) { return ( = () => { const { wdpaIucnCategories, wdpaThreshold } = scenarioData || {}; + const { + data: bestSolutionData, + } = useBestSolution(sid); + + const bestSolution = bestSolutionData || {}; + getScenarioSlice(sid); const { tab, subtab, + selectedSolution, } = useSelector((state) => state[`/scenarios/${sid}`]); const minZoom = 2; @@ -74,6 +82,7 @@ export const ScenariosMap: React.FC = () => { wdpaThreshold, puIncludedValue: included, puExcludedValue: excluded, + runId: selectedSolution?.runId || bestSolution?.runId, }, }); @@ -87,6 +96,7 @@ export const ScenariosMap: React.FC = () => { wdpaThreshold, puIncludedValue: included, puExcludedValue: excluded, + runId: selectedSolution?.runId || bestSolution?.runId, }, }); diff --git a/app/layout/scenarios/show/solutions/details/component.tsx b/app/layout/scenarios/show/solutions/details/component.tsx index 9a57c36aa3..8a70076283 100644 --- a/app/layout/scenarios/show/solutions/details/component.tsx +++ b/app/layout/scenarios/show/solutions/details/component.tsx @@ -38,13 +38,13 @@ export const ScenariosSolutionsDetails: React.FC const [frequencyOnMap, onToggleFrequencyOnMap] = useState(false); getScenarioSlice(sid); - const { selectedSolutionId } = useSelector((state) => state[`/scenarios/${sid}`]); + const { selectedSolution } = useSelector((state) => state[`/scenarios/${sid}`]); const { data: selectedSolutionData, isFetching: selectedSolutionisFetching, isFetched: selectedSolutionisFetched, - } = useSolution(sid, selectedSolutionId); + } = useSolution(sid, selectedSolution?.id); const { data: bestSolutionData, @@ -52,10 +52,14 @@ export const ScenariosSolutionsDetails: React.FC isFetched: bestSolutionisFetched, } = useBestSolution(sid); - const isBestSolutionShown = selectedSolutionId === bestSolutionData.id || !selectedSolutionId; + const isBestSolution = selectedSolution + && bestSolutionData + && selectedSolution?.id === bestSolutionData?.id; - const solutionIsLoading = bestSolutionisFetching && !bestSolutionisFetched - && selectedSolutionisFetching && !selectedSolutionisFetched; + const solutionIsLoading = ( + bestSolutionisFetching && !bestSolutionisFetched) + || (selectedSolutionisFetching && !selectedSolutionisFetched + ); const frequencyValues = [ { @@ -157,12 +161,12 @@ export const ScenariosSolutionsDetails: React.FC iconClassName="w-10 h-10 text-primary-500" /> {(selectedSolutionData || bestSolutionData) && ( - + )} diff --git a/app/layout/scenarios/show/solutions/table-form/component.tsx b/app/layout/scenarios/show/solutions/table-form/component.tsx index 62c87ba08e..2295ca562b 100644 --- a/app/layout/scenarios/show/solutions/table-form/component.tsx +++ b/app/layout/scenarios/show/solutions/table-form/component.tsx @@ -39,8 +39,10 @@ export const SolutionsTableForm: React.FC = ({ } = useBestSolution(sid); - const { selectedSolutionId } = useSelector((state) => state[`/scenarios/${sid}`]); - const [selectedSolution, onSelectSolution] = useState(selectedSolutionId || bestSolutionData?.id); + const { selectedSolution } = useSelector((state) => state[`/scenarios/${sid}`]); + const [selectSolution, setSelectSolution] = useState( + selectedSolution?.id || bestSolutionData?.id, + ); const { data, @@ -76,9 +78,9 @@ export const SolutionsTableForm: React.FC = ({ ); const onSave = useCallback(() => { - dispatch(setSelectedSolution(selectedSolution)); + dispatch(setSelectedSolution(selectSolution)); setShowTable(false); - }, [dispatch, selectedSolution, setSelectedSolution, setShowTable]); + }, [dispatch, selectSolution, setSelectedSolution, setShowTable]); return (
@@ -215,8 +217,8 @@ export const SolutionsTableForm: React.FC = ({ onSelectSolution(solution.id)} + selectedSolution={selectSolution} + onSelectSolution={(solution) => setSelectSolution(solution)} /> )} diff --git a/app/layout/scenarios/show/solutions/table/component.tsx b/app/layout/scenarios/show/solutions/table/component.tsx index c0afb40dba..3ebe887813 100644 --- a/app/layout/scenarios/show/solutions/table/component.tsx +++ b/app/layout/scenarios/show/solutions/table/component.tsx @@ -48,7 +48,7 @@ export const SolutionsTable: React.FC = ({ }, { label: 'RUN', - id: 'run', + id: 'runId', }, { label: 'Score', diff --git a/app/layout/solutions/selected/component.tsx b/app/layout/solutions/selected/component.tsx index 57eb4b2e6f..d2ea149e68 100644 --- a/app/layout/solutions/selected/component.tsx +++ b/app/layout/solutions/selected/component.tsx @@ -30,12 +30,14 @@ export const SelectedSolution: React.FC = ({
-
-
-

- {`Run ${runId}`} -

-
+ {runId && ( +
+
+

+ {`Run ${runId}`} +

+
+ )} {best && (

Best solution

diff --git a/app/pages/projects/[pid]/scenarios/[sid]/edit.tsx b/app/pages/projects/[pid]/scenarios/[sid]/edit.tsx index a2888f730d..f308444b37 100644 --- a/app/pages/projects/[pid]/scenarios/[sid]/edit.tsx +++ b/app/pages/projects/[pid]/scenarios/[sid]/edit.tsx @@ -5,11 +5,10 @@ import { useDispatch } from 'react-redux'; import { useRouter } from 'next/router'; import { withProtection, withUser } from 'hoc/auth'; +import { withScenario } from 'hoc/scenarios'; import { getScenarioEditSlice } from 'store/slices/scenarios/edit'; -import { SCENARIO_EDITING_META_DATA_DEFAULT_VALUES } from 'utils/utils-scenarios'; - import { useScenario } from 'hooks/scenarios'; import Header from 'layout/header'; @@ -25,7 +24,7 @@ import SidebarEditWDPA from 'layout/scenarios/edit/wdpa'; import Title from 'layout/title/scenario-title'; import Wrapper from 'layout/wrapper'; -export const getServerSideProps = withProtection(withUser()); +export const getServerSideProps = withProtection(withUser(withScenario())); const EditScenarioPage: React.FC = () => { const { query } = useRouter(); @@ -36,7 +35,7 @@ const EditScenarioPage: React.FC = () => { const { tab: metaTab, subtab: metaSubtab, - } = scenarioEditingMetadata || SCENARIO_EDITING_META_DATA_DEFAULT_VALUES; + } = scenarioEditingMetadata || {}; const scenarioSlice = getScenarioEditSlice(sid); const { setTab, setSubTab } = scenarioSlice.actions; @@ -44,7 +43,7 @@ const EditScenarioPage: React.FC = () => { useEffect(() => { if (metaTab) dispatch(setTab(metaTab)); - if (metaTab) dispatch(setSubTab(metaSubtab)); + if (metaSubtab) dispatch(setSubTab(metaSubtab)); // eslint-disable-next-line react-hooks/exhaustive-deps }, [metaTab, metaSubtab]); diff --git a/app/pages/projects/[pid]/scenarios/[sid]/index.tsx b/app/pages/projects/[pid]/scenarios/[sid]/index.tsx index d2c35d51af..669ee15904 100644 --- a/app/pages/projects/[pid]/scenarios/[sid]/index.tsx +++ b/app/pages/projects/[pid]/scenarios/[sid]/index.tsx @@ -1,12 +1,7 @@ -import React, { useEffect } from 'react'; - -import { useDispatch } from 'react-redux'; - -import { useRouter } from 'next/router'; +import React from 'react'; import { withProtection, withUser } from 'hoc/auth'; - -import { getScenarioSlice } from 'store/slices/scenarios/detail'; +import { withScenario } from 'hoc/scenarios'; import Header from 'layout/header'; import MetaIcons from 'layout/meta-icons'; @@ -21,20 +16,9 @@ import SidebarShowWDPA from 'layout/scenarios/show/wdpa'; import Title from 'layout/title/scenario-title'; import Wrapper from 'layout/wrapper'; -export const getServerSideProps = withProtection(withUser()); +export const getServerSideProps = withProtection(withUser(withScenario())); const ShowScenarioPage: React.FC = () => { - const { query } = useRouter(); - const { sid } = query; - - const scenarioSlice = getScenarioSlice(sid); - const { setTab, setSubTab } = scenarioSlice.actions; - const dispatch = useDispatch(); - - useEffect(() => { - dispatch(setTab('solutions')); - dispatch(setSubTab(null)); - }, [setTab, setSubTab, dispatch]); return ( diff --git a/app/store/slices/scenarios/detail.ts b/app/store/slices/scenarios/detail.ts index d62efe8f7f..025602b0ae 100644 --- a/app/store/slices/scenarios/detail.ts +++ b/app/store/slices/scenarios/detail.ts @@ -1,16 +1,17 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { injectReducer } from 'store'; +import { Solution } from 'types/project-model'; interface ScenarioShowStateProps { tab: string, subtab: string, - selectedSolutionId: string; + selectedSolution: Solution; } const initialState = { tab: 'solutions', subtab: null, - selectedSolutionId: null, + selectedSolution: null, } as ScenarioShowStateProps; export function getScenarioSlice(id) { @@ -24,8 +25,8 @@ export function getScenarioSlice(id) { setSubTab: (state, action: PayloadAction<string>) => { state.subtab = action.payload; }, - setSelectedSolution: (state, action: PayloadAction<string>) => { - state.selectedSolutionId = action.payload; + setSelectedSolution: (state, action: PayloadAction<Solution>) => { + state.selectedSolution = action.payload; }, }, }); diff --git a/app/types/project-model.ts b/app/types/project-model.ts index 66148cc6d5..1619f62c71 100644 --- a/app/types/project-model.ts +++ b/app/types/project-model.ts @@ -31,7 +31,7 @@ export interface Area { export interface Solution { id: string; - run: number; + runId: number; score: number; cost: number; planningUnits: number;