Skip to content

Commit

Permalink
Merge pull request #3324 from LiteFarmOrg/LF-4309-complete-form-break…
Browse files Browse the repository at this point in the history
…s-when-not-completed-fast-enough-allowing-page-to-time-out-or-something

LF-4309 Complete form breaks when not completed fast enough allowing page to time out or something
  • Loading branch information
Duncan-Brain authored Jul 23, 2024
2 parents b49c6d6 + afe589b commit db2bf63
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 116 deletions.
21 changes: 21 additions & 0 deletions packages/api/src/models/soilAmendmentTaskModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,27 @@ class SoilAmendmentTaskModel extends Model {
return 'task_id';
}

async $beforeUpdate(queryContext) {
await super.$beforeUpdate(queryContext);

if (this.method_id) {
const { key } = await soilAmendmentMethodModel
.query(queryContext.transaction)
.findById(this.method_id)
.select('key')
.first();

if (key !== 'OTHER') {
this.other_application_method = null;
}

if (key !== 'FURROW_HOLE') {
this.furrow_hole_depth = null;
this.furrow_hole_depth_unit = null;
}
}
}

// Optional JSON schema. This is not the database schema! Nothing is generated
// based on this. This is only used for validation. Whenever a model instance
// is created it is checked against this schema. http://json-schema.org/.
Expand Down
5 changes: 5 additions & 0 deletions packages/webapp/src/components/Form/Unit/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ const Unit = ({
hasLeaf,
autoConversion,
onInputChange,
shouldUnregister,
...props
}) => {
const { t } = useTranslation(['translation', 'common']);
Expand Down Expand Up @@ -165,6 +166,7 @@ const Unit = ({
<Controller
control={control}
name={displayUnitName}
shouldUnregister={shouldUnregister}
render={({ field: { onBlur, value, ref } }) => (
<Select
data-cy="unit-select"
Expand Down Expand Up @@ -202,6 +204,7 @@ const Unit = ({
valueAsNumber: true,
max: { value: getMax(), message: t('UNIT.VALID_VALUE') + max },
min: { value: 0, message: t('UNIT.VALID_VALUE') + max },
shouldUnregister,
})}
data-testid={`${testId}-hiddeninput`}
/>
Expand Down Expand Up @@ -283,6 +286,8 @@ Unit.propTypes = {
onBlur: PropTypes.func,
/** testId used for component testing */
'data-testid': PropTypes.string,
/** react hook form shouldUnregister - unmounting input removes value */
shouldUnregister: PropTypes.bool,
};

export default Unit;
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ const SoilAmendmentProductCard = ({
label={t('ADD_TASK.SOIL_AMENDMENT_VIEW.OTHER_PURPOSE')}
name={OTHER_PURPOSE}
disabled={isReadOnly}
hookFormRegister={register(OTHER_PURPOSE)}
hookFormRegister={register(OTHER_PURPOSE, { shouldUnregister: true })}
optional
/>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ const PureSoilAmendmentTask = ({
defaultValue={undefined} // TODO
system={system}
placeholder={t('ADD_TASK.SOIL_AMENDMENT_VIEW.FURROW_HOLE_DEPTH_PLACEHOLDER')}
shouldUnregister={true}
/>
</>
)}
Expand All @@ -191,7 +192,7 @@ const PureSoilAmendmentTask = ({
label={t('ADD_TASK.SOIL_AMENDMENT_VIEW.OTHER_METHOD')}
name={OTHER_APPLICATION_METHOD}
disabled={disabled}
hookFormRegister={register(OTHER_APPLICATION_METHOD)}
hookFormRegister={register(OTHER_APPLICATION_METHOD, { shouldUnregister: true })}
optional
placeholder={t('ADD_TASK.SOIL_AMENDMENT_VIEW.OTHER_METHOD_PLACEHOLDER')}
/>
Expand Down
52 changes: 4 additions & 48 deletions packages/webapp/src/containers/Task/saga.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,7 @@ import {
onLoadingHarvestUseTypeStart,
} from '../harvestUseTypeSlice';
import { managementPlanWithCurrentLocationEntitiesSelector } from './TaskCrops/managementPlansWithLocationSelector';
import {
formatSoilAmendmentTaskToDBStructure,
formatSoilAmendmentProductToDBStructure,
} from '../../util/task';
import { api } from '../../store/api/apiSlice';
import { formatSoilAmendmentProductToDBStructure } from '../../util/task';

const taskTypeEndpoint = [
'cleaning_task',
Expand Down Expand Up @@ -485,20 +481,11 @@ const getIrrigationTaskBody = (data, endpoint, managementPlanWithCurrentLocation
);
};

const getSoilAmendmentTaskBody = (
data,
endpoint,
managementPlanWithCurrentLocationEntities,
{ purposes, methods },
) => {
const getSoilAmendmentTaskBody = (data, endpoint, managementPlanWithCurrentLocationEntities) => {
return {
...getPostTaskBody(data, endpoint, managementPlanWithCurrentLocationEntities),
soil_amendment_task: formatSoilAmendmentTaskToDBStructure(data.soil_amendment_task, {
methods,
}),
soil_amendment_task_products: formatSoilAmendmentProductToDBStructure(
data.soil_amendment_task_products,
{ purposes },
),
};
};
Expand All @@ -519,15 +506,13 @@ const getPostTaskReqBody = (
task_translation_key,
isCustomTask,
managementPlanWithCurrentLocationEntities,
taskTypeSpecificData,
) => {
if (isCustomTask)
return getPostTaskBody(data, endpoint, managementPlanWithCurrentLocationEntities);
return taskTypeGetPostTaskBodyFunctionMap[task_translation_key](
data,
endpoint,
managementPlanWithCurrentLocationEntities,
taskTypeSpecificData,
);
};

Expand All @@ -541,17 +526,6 @@ export function* createTaskSaga({ payload }) {
const { task_translation_key, farm_id: task_farm_id } = yield select(
taskTypeSelector(data.task_type_id),
);
const taskTypeSpecificData = {};
if (task_translation_key === 'SOIL_AMENDMENT_TASK') {
// Access cached data
// https://redux-toolkit.js.org/rtk-query/usage/usage-without-react-hooks#accessing-cached-data--request-status
const purposes = yield select((state) =>
api.endpoints.getSoilAmendmentPurposes.select()(state),
);
taskTypeSpecificData.purposes = purposes.data;
const methods = yield select((state) => api.endpoints.getSoilAmendmentMethods.select()(state));
taskTypeSpecificData.methods = methods.data;
}
const header = getHeader(user_id, farm_id);
const isCustomTask = !!task_farm_id;
const isHarvest = task_translation_key === 'HARVEST_TASK';
Expand All @@ -574,7 +548,6 @@ export function* createTaskSaga({ payload }) {
task_translation_key,
isCustomTask,
managementPlanWithCurrentLocationEntities,
taskTypeSpecificData,
),
header,
);
Expand Down Expand Up @@ -720,18 +693,12 @@ const getCompleteIrrigationTaskBody = (task_translation_key) => (data) => {
);
};

const getCompleteSoilAmendmentTaskBody = (data, taskTypeSpecificData) => {
const soilAmendmentTask = formatSoilAmendmentTaskToDBStructure(
data.soil_amendment_task,
taskTypeSpecificData,
);
const getCompleteSoilAmendmentTaskBody = (data) => {
const soilAmendmentTaskProducts = formatSoilAmendmentProductToDBStructure(
data.soil_amendment_task_products,
taskTypeSpecificData,
);
return {
...data.taskData,
soil_amendment_task: soilAmendmentTask,
soil_amendment_task_products: soilAmendmentTaskProducts,
};
};
Expand All @@ -752,19 +719,8 @@ export function* completeTaskSaga({ payload: { task_id, data, returnPath } }) {
const { task_translation_key, isCustomTaskType } = data;
const header = getHeader(user_id, farm_id);
const endpoint = isCustomTaskType ? 'custom_task' : task_translation_key.toLowerCase();
const taskTypeSpecificData = {};
if (task_translation_key === 'SOIL_AMENDMENT_TASK') {
// Access cached data
// https://redux-toolkit.js.org/rtk-query/usage/usage-without-react-hooks#accessing-cached-data--request-status
const purposes = yield select((state) =>
api.endpoints.getSoilAmendmentPurposes.select()(state),
);
taskTypeSpecificData.purposes = purposes.data;
const methods = yield select((state) => api.endpoints.getSoilAmendmentMethods.select()(state));
taskTypeSpecificData.methods = methods.data;
}
const taskData = taskTypeGetCompleteTaskBodyFunctionMap[task_translation_key]
? taskTypeGetCompleteTaskBodyFunctionMap[task_translation_key](data, taskTypeSpecificData)
? taskTypeGetCompleteTaskBodyFunctionMap[task_translation_key](data)
: data.taskData;

try {
Expand Down
77 changes: 11 additions & 66 deletions packages/webapp/src/util/task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@
* GNU General Public License for more details, see <https://www.gnu.org/licenses/>.
*/

import { SoilAmendmentMethod, SoilAmendmentPurpose } from '../store/api/types';
import { getUnitOptionMap } from './convert-units/getUnitOptionMap';

interface UnitOption {
label: string;
value: string;
Expand Down Expand Up @@ -61,39 +58,29 @@ type FormSoilAmendmentTaskProduct = {
};

type DBSoilAmendmentTask = {
furrow_hole_depth?: number;
furrow_hole_depth_unit?: string;
other_application_method?: string;
[key: string]: any;
};

type FormSoilAmendmentTask = {
furrow_hole_depth?: number;
furrow_hole_depth_unit?: UnitOption;
other_application_method?: string;
[key: string]: any;
};

type DBTask = {
soil_amendment_task_products: DBSoilAmendmentTaskProduct[];
[key: string]: any;
};

type FormTask = {
type FormSoilAmendmentTask = {
soil_amendment_task_products: FormSoilAmendmentTaskProduct[];
[key: string]: any;
};

// Type guard
function isFormSoilAmendmentTask(task: DBTask | FormTask): task is FormTask {
function isFormSoilAmendmentTask(
task: DBSoilAmendmentTask | FormSoilAmendmentTask,
): task is FormSoilAmendmentTask {
return (
task.soil_amendment_task_products?.[0] && 'purposes' in task.soil_amendment_task_products[0]
);
}

export const formatSoilAmendmentTaskToFormStructure = (task: DBTask | FormTask): FormTask => {
export const formatSoilAmendmentTaskToFormStructure = (
task: DBSoilAmendmentTask | FormSoilAmendmentTask,
): FormSoilAmendmentTask => {
if (isFormSoilAmendmentTask(task)) {
return task as FormTask;
return task as FormSoilAmendmentTask;
}

const taskClone = structuredClone(task);
Expand Down Expand Up @@ -138,10 +125,9 @@ export const formatSoilAmendmentTaskToFormStructure = (task: DBTask | FormTask):
const formatPurposeIdsToRelationships = (
purposeIds: number[],
otherPurpose: string | undefined,
otherPurposeId: number,
): PurposeRelationship[] => {
return purposeIds.map((purpose_id) => {
return { purpose_id, other_purpose: purpose_id === otherPurposeId ? otherPurpose : undefined };
return { purpose_id, other_purpose: otherPurpose };
});
};

Expand All @@ -152,15 +138,10 @@ type RemainingFormSATProductKeys = keyof Omit<

export const formatSoilAmendmentProductToDBStructure = (
soilAmendmentTaskProducts: FormSoilAmendmentTaskProduct[] | undefined,
{ purposes }: { purposes: SoilAmendmentPurpose[] },
): DBSoilAmendmentTaskProduct[] | undefined => {
if (!soilAmendmentTaskProducts) {
return undefined;
}
const otherPurposeId = purposes?.find(({ key }) => key === 'OTHER')?.id;
if (!otherPurposeId) {
throw Error('id for OTHER purpose does not exist');
}
return soilAmendmentTaskProducts.map((formTaskProduct) => {
const { purposes: purposeIds, other_purpose, is_weight, ...rest } = formTaskProduct;

Expand All @@ -184,53 +165,17 @@ export const formatSoilAmendmentProductToDBStructure = (
application_rate_volume_unit: !is_weight
? (rest.application_rate_volume_unit as UnitOption)?.value
: undefined,
purpose_relationships: formatPurposeIdsToRelationships(
purposeIds,
other_purpose,
otherPurposeId,
),
purpose_relationships: formatPurposeIdsToRelationships(purposeIds, other_purpose),
};
});
};

export const formatSoilAmendmentTaskToDBStructure = (
soilAmendmentTask: FormSoilAmendmentTask | undefined,
{ methods }: { methods: SoilAmendmentMethod[] },
): DBSoilAmendmentTask | undefined => {
if (!soilAmendmentTask) {
return undefined;
}
const {
method_id,
furrow_hole_depth,
furrow_hole_depth_unit,
other_application_method,
...rest
} = soilAmendmentTask;
const furrowHoleId = methods?.find(({ key }) => key === 'FURROW_HOLE')?.id;
const otherMethodId = methods?.find(({ key }) => key === 'OTHER')?.id;
if (!furrowHoleId) {
throw Error('id for FURROW_HOLE method does not exist');
}
if (!otherMethodId) {
throw Error('id for OTHER method does not exist');
}
return {
...rest,
method_id,
furrow_hole_depth: method_id === furrowHoleId ? furrow_hole_depth : undefined,
furrow_hole_depth_unit: method_id === furrowHoleId ? furrow_hole_depth_unit?.value : undefined,
other_application_method:
soilAmendmentTask.method_id === otherMethodId ? other_application_method : undefined,
};
};

export const formatTaskReadOnlyDefaultValues = (task: {
taskType?: { task_translation_key: string };
[key: string]: any;
}) => {
if (task.taskType?.task_translation_key === 'SOIL_AMENDMENT_TASK') {
return formatSoilAmendmentTaskToFormStructure(task as DBTask);
return formatSoilAmendmentTaskToFormStructure(task as DBSoilAmendmentTask);
}

return structuredClone(task);
Expand Down

0 comments on commit db2bf63

Please sign in to comment.