diff --git a/package-lock.json b/package-lock.json index e438b89f..261e701b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13430,7 +13430,7 @@ }, "node_modules/terraso-backend": { "version": "0.1.0", - "resolved": "git+ssh://git@github.com/techmatters/terraso-backend.git#1371c39d38d5525fd1de5059718bd572ec51a4a0" + "resolved": "git+ssh://git@github.com/techmatters/terraso-backend.git#b2eca72cb149b7f234864857ddbf20b1b5e3b165" }, "node_modules/test-exclude": { "version": "6.0.0", diff --git a/src/constants.ts b/src/constants.ts index 64a2f157..f84019fc 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -16,11 +16,9 @@ */ import { DepthInterval } from 'terraso-client-shared/graphqlSchema/graphql'; +import { SoilPitMethod } from 'terraso-client-shared/soilId/soilIdTypes'; -export const DEPTH_INTERVAL_PRESETS: Record< - 'LANDPKS' | 'NRCS', - DepthInterval[] -> = { +export const DEPTH_INTERVAL_PRESETS = { LANDPKS: [ { start: 0, end: 10 }, { start: 10, end: 20 }, @@ -37,4 +35,10 @@ export const DEPTH_INTERVAL_PRESETS: Record< { start: 60, end: 100 }, { start: 100, end: 200 }, ], -}; +} as const satisfies Record<'LANDPKS' | 'NRCS', readonly DepthInterval[]>; + +export const DEFAULT_ENABLED_SOIL_PIT_METHODS = [ + 'soilTexture', + 'soilStructure', + 'soilColor', +] as const satisfies readonly SoilPitMethod[]; diff --git a/src/selectors.test.ts b/src/selectors.test.ts index 475f9080..a81db1c2 100644 --- a/src/selectors.test.ts +++ b/src/selectors.test.ts @@ -20,7 +20,10 @@ import { initialState as accountInitialState, User, } from 'terraso-client-shared/account/accountSlice'; -import { DEPTH_INTERVAL_PRESETS } from 'terraso-client-shared/constants'; +import { + DEFAULT_ENABLED_SOIL_PIT_METHODS, + DEPTH_INTERVAL_PRESETS, +} from 'terraso-client-shared/constants'; import { DepthInterval, ProjectPrivacy, @@ -178,6 +181,13 @@ const generateSiteInterval = ( soilTextureEnabled: false, carbonatesEnabled: false, ...(label !== undefined ? { label } : { label: '' }), + ...DEFAULT_ENABLED_SOIL_PIT_METHODS.reduce( + (x, method) => ({ + ...x, + [methodEnabled(method)]: true, + }), + {}, + ), ...(defaults || {}), }); @@ -189,9 +199,14 @@ const projectToSiteInterval = ( depthInterval: interval.depthInterval, label: interval.label, ...(Object.fromEntries( - soilPitMethods.map(method => [ + soilPitMethods.map((method: SoilPitMethod) => [ methodEnabled(method), - projectSettings ? projectSettings[methodRequired(method)] : false, + projectSettings + ? projectSettings[methodRequired(method)] + : false || + (DEFAULT_ENABLED_SOIL_PIT_METHODS as readonly string[]).includes( + method, + ), ]), ) as Record<`${SoilPitMethod}Enabled`, boolean>), }; @@ -439,13 +454,18 @@ test('select predefined project selector with custom preset', () => { ); expect(aggregatedIntervals).toStrictEqual([ - { mutable: true, interval: siteDepthIntervals[0] }, + { + mutable: true, + interval: siteDepthIntervals[0], + backendIntervalExists: true, + }, { mutable: false, interval: projectToSiteInterval( projectDepthIntervals[0], projectSettings[project.id], ), + backendIntervalExists: false, }, { mutable: false, @@ -453,8 +473,13 @@ test('select predefined project selector with custom preset', () => { projectDepthIntervals[1], projectSettings[project.id], ), + backendIntervalExists: false, + }, + { + mutable: true, + interval: siteDepthIntervals[2], + backendIntervalExists: true, }, - { mutable: true, interval: siteDepthIntervals[2] }, ]); }); @@ -499,7 +524,12 @@ test('overlapping site intervals get the project values of the preset interval', { mutable: false, interval: { ...siteDepthIntervals[0], carbonatesEnabled: true }, + backendIntervalExists: true, + }, + { + mutable: false, + interval: siteDepthIntervals[1], + backendIntervalExists: true, }, - { mutable: false, interval: siteDepthIntervals[1] }, ]); }); diff --git a/src/selectors.ts b/src/selectors.ts index c9498489..26f5e9f6 100644 --- a/src/selectors.ts +++ b/src/selectors.ts @@ -17,7 +17,10 @@ import { createSelector } from '@reduxjs/toolkit'; import { User } from 'terraso-client-shared/account/accountSlice'; -import { DEPTH_INTERVAL_PRESETS } from 'terraso-client-shared/constants'; +import { + DEFAULT_ENABLED_SOIL_PIT_METHODS, + DEPTH_INTERVAL_PRESETS, +} from 'terraso-client-shared/constants'; import { DepthInterval, UserRole, @@ -259,17 +262,24 @@ export const makeSoilDepth = ( const methodsEnabled = Object.fromEntries( soilPitMethods.map(method => [ methodEnabled(method), - soilSettings ? soilSettings[methodRequired(method)] : false, + soilSettings + ? soilSettings[methodRequired(method)] + : false || + (DEFAULT_ENABLED_SOIL_PIT_METHODS as readonly string[]).includes( + method, + ), ]), ) as Record<`${SoilPitMethod}Enabled`, boolean>; return { ...depthInterval, ...methodsEnabled }; }; export type AggregatedInterval = { - // can this interval be deleted + can its bounds be updated? + /* can this interval be deleted + can its bounds be updated? */ mutable: boolean; - // if label missing, label should not be assigned to this interval + /* if label missing, label should not be assigned to this interval */ interval: SoilDataDepthInterval; + /* there is an existing backend interval that matches this one */ + backendIntervalExists: boolean; }; const matchIntervals = ( @@ -289,7 +299,11 @@ const matchIntervals = ( if (i === sortedPresets.length) { // no more preset intervals, and we know B_j doesn't overlap with any A // so B_j can be added - intervals.push({ mutable: true, interval: sortedSoilDepth[j] }); + intervals.push({ + mutable: true, + interval: sortedSoilDepth[j], + backendIntervalExists: true, + }); j++; continue; } @@ -299,12 +313,17 @@ const matchIntervals = ( const B_j = sortedSoilDepth[j]; if (B_j.depthInterval.end <= A_i.depthInterval.start) { // B doesn't overlap with A_i-1, and not with A_i, so it can be added - intervals.push({ mutable: true, interval: B_j }); + intervals.push({ + mutable: true, + interval: B_j, + backendIntervalExists: true, + }); } else if (sameDepth(A_i)(B_j)) { // if they are the same depth, B_j contains soil info for A_i intervals.push({ mutable: false, interval: B_j, + backendIntervalExists: true, }); presetCovered = true; } else if (!checkOverlap(A_i)(B_j)) { @@ -319,6 +338,7 @@ const matchIntervals = ( intervals.push({ mutable: false, interval: makeSoilDepth(A_i, soilSettings), + backendIntervalExists: false, }); } i++;