Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

prevent missing entries in submission #1114

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/i18n/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@
"validate_serving": "Validate (serving)",
"skip": "Skip",
"invalid_image": "Invalid image",
"missingValues": "It seems that some inputs are empty for nutriments OFF already knows. Either fill those inputs with appropriate value, or put a \"-\" to indicate that the value is not available.",
"pictures": {
"picture_date": "Photo uploaded",
"selected_as_nutrients": "Selected as nutriment image ✅",
Expand Down
1 change: 1 addition & 0 deletions src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@
"validate_serving": "Validate (serving)",
"skip": "Skip",
"invalid_image": "Invalid image",
"missingValues": "It seems that some inputs are empty for nutriments OFF already knows. Either fill those inputs with appropriate value, or put a \"-\" to indicate that the value is not available.",
"pictures": {
"picture_date": "Photo uploaded",
"selected_as_nutrients": "Selected as nutriment image ✅",
Expand Down
38 changes: 34 additions & 4 deletions src/pages/nutrition/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
Checkbox,
FormControlLabel,
Typography,
Alert,
} from "@mui/material";
import Stack from "@mui/material/Stack";
import {
Expand All @@ -26,6 +27,7 @@ import Instructions from "./Instructions";
import useNutrimentTranslations from "./useNutrimentTranslations";
import { useCountry } from "../../contexts/CountryProvider";
import { useTranslation } from "react-i18next";
import { doesNotRemoveData } from "./preventDataLost";

export default function Nutrition() {
const { t } = useTranslation();
Expand Down Expand Up @@ -76,6 +78,32 @@ export default function Nutrition() {
return NUTRIMENTS.filter((item) => !displayedIds.has(item.id));
}, [nutrimentsDisplayed]);

const allOFF100gHaveValues = React.useMemo(() => {
// Every nutriment that has a value in the OFF DB should have a value in database should have a value in the form.
// We ask users to set "-" if the nutrient is not provided on the packaging.
return nutrimentsDisplayed.every(({ id: nutrimentId }) =>
doesNotRemoveData({
nutrimentId,
values,
nutriments: product?.nutriments,
category: "100g",
}),
);
}, [nutrimentsDisplayed, values, product]);

const allOFFServingHaveValues = React.useMemo(() => {
// Every nutriment that has a value in the OFF DB should have a value in database should have a value in the form.
// We ask users to set "-" if the nutrient is not provided on the packaging.
return nutrimentsDisplayed.every(({ id: nutrimentId }) =>
doesNotRemoveData({
nutrimentId,
values,
nutriments: product?.nutriments,
category: "serving",
}),
);
}, [nutrimentsDisplayed, values, product]);

return (
<React.Suspense>
<ErrorBoundary>
Expand Down Expand Up @@ -279,10 +307,8 @@ export default function Nutrition() {
tabIndex={1}
variant="contained"
color="success"
sx={{
ml: 1,
mt: 2,
}}
sx={{ ml: 1, mt: 2 }}
disabled={!allOFF100gHaveValues}
onClick={() => {
postRobotoff({
insightId: insight.id,
Expand All @@ -302,6 +328,7 @@ export default function Nutrition() {
variant="contained"
color="success"
sx={{ ml: 1, mt: 2 }}
disabled={!allOFFServingHaveValues}
onClick={() => {
postRobotoff({
insightId: insight.id,
Expand All @@ -318,6 +345,9 @@ export default function Nutrition() {
</tr>
</tfoot>
</table>
{(!allOFF100gHaveValues || !allOFFServingHaveValues) && (
<Alert severity="info">{t("nutrition.missingValues")}</Alert>
)}
</Box>

<Stack direction="row" justifyContent="center" sx={{ mt: 5 }}>
Expand Down
41 changes: 41 additions & 0 deletions src/pages/nutrition/preventDataLost.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { NutrimentPrediction } from "./insight.types";

function hasValue(v: Pick<NutrimentPrediction, "value" | "unit">) {
return v && v.value !== null && v.value !== undefined && v.value !== "";
}
export function doesNotRemoveData({
nutrimentId,
values,
nutriments,
category,
}: {
nutrimentId: string;
values: Record<string, Pick<NutrimentPrediction, "value" | "unit">>;
nutriments?: any;
category: "serving" | "100g";
}) {
if (nutriments === undefined) {
return true;
}
if (hasValue(values[`${nutrimentId}_${category}`])) {
// The form has value for this nutrient
return true;
}
if (
nutriments?.[`${nutrimentId}_serving`] == null &&
nutriments?.[`${nutrimentId}_100g`] == null
) {
// OFF does not have value for this nutrient.
// We check 100g and serving, to avoid validating empty serving if 100g are defined.
return true;
}

// Exceptions for sodium if we have value for the sodium or the inverse
if (nutrimentId === "sodium" && hasValue(values[`salt_${category}`])) {
return true; // no sodium, but salt
}
if (nutrimentId === "salt" && hasValue(values[`sodium_${category}`])) {
return true; // no salt but sodium
}
return false;
}
Loading