diff --git a/src/hooks/useSearchParamsState.ts b/src/hooks/useSearchParamsState.ts new file mode 100644 index 0000000000..0ad36b1663 --- /dev/null +++ b/src/hooks/useSearchParamsState.ts @@ -0,0 +1,34 @@ +import * as React from "react"; +import { useSearchParams } from "react-router-dom"; + +export function useSearchParamsState( + searchName: string, + defaultValue: T, + parser: (search: string) => T = (v: string) => v as T): [T, React.Dispatch>] { + + const [searchParams, setSearchParams] = useSearchParams(); + const [state, setState] = React.useState(() => { + const param = searchParams.get(searchName); + return param === null ? defaultValue : parser(param) + }); + + const updateState = React.useCallback( + (update: T) => { + setState(prev => { + const nextVal = typeof update === 'function' ? update(prev) : update; + + if (nextVal === prev) { + return prev + } + + setSearchParams((prevSearch) => { + prevSearch.set(searchName, nextVal); + return prevSearch; + }); + return nextVal + }) + }, + [setSearchParams], + ); + return [state, updateState] +} diff --git a/src/i18n/common.json b/src/i18n/common.json index 1c4651670e..6f749fb0e3 100644 --- a/src/i18n/common.json +++ b/src/i18n/common.json @@ -71,6 +71,7 @@ "view": "View", "edit": "Edit", "remaining": "Remaining: {{count}}", + "remaining_other": "Remaining: >100", "hide_images": "Hide images (faster loading)", "display_images": "Display images", "annotations": "Annotations", @@ -325,7 +326,7 @@ "invalid_image": "Invalid image", "pictures": { "picture_date": "Photo uploaded", - "selected_as_nutrients": "Selected as nutriment image ✅", + "selected_as_nutrients": "Selected as nutriment image ✅", "not_selected_as_nutrients": "Not selected as nutriment ❌" }, "instructions": { @@ -334,7 +335,7 @@ "chose_between_empty_and_partially_filled": "You can chose between products for which OpenFoodFacts (OFF) has no data about the nutrients. Or product with partially filled nutrient table.", "picture_date_is_display": "The date of the picture is displayed on top of it. Allowing you to check if it's a recent one.", "nutriments_from_off_are_displayed": "You can display data that are already present in the OFF database. They will appear under the inputs:", - "green_for_same": "With <1>green for those matching with the input value.", + "green_for_same": "With <1>green for those matching with the input value.", "orange_for_empty": "With <1>orange for those with empty input value.", "red_for_different": "With <1>red for those with different input value.", "indicate_not_provided_value": "Empty inputs are ignored. If fibers are not present in the table, you can put \"-\" to specify the value is not available.", @@ -394,4 +395,4 @@ "subtitle": "Download" } } -} +} \ No newline at end of file diff --git a/src/i18n/en.json b/src/i18n/en.json index 1c4651670e..6f749fb0e3 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -71,6 +71,7 @@ "view": "View", "edit": "Edit", "remaining": "Remaining: {{count}}", + "remaining_other": "Remaining: >100", "hide_images": "Hide images (faster loading)", "display_images": "Display images", "annotations": "Annotations", @@ -325,7 +326,7 @@ "invalid_image": "Invalid image", "pictures": { "picture_date": "Photo uploaded", - "selected_as_nutrients": "Selected as nutriment image ✅", + "selected_as_nutrients": "Selected as nutriment image ✅", "not_selected_as_nutrients": "Not selected as nutriment ❌" }, "instructions": { @@ -334,7 +335,7 @@ "chose_between_empty_and_partially_filled": "You can chose between products for which OpenFoodFacts (OFF) has no data about the nutrients. Or product with partially filled nutrient table.", "picture_date_is_display": "The date of the picture is displayed on top of it. Allowing you to check if it's a recent one.", "nutriments_from_off_are_displayed": "You can display data that are already present in the OFF database. They will appear under the inputs:", - "green_for_same": "With <1>green for those matching with the input value.", + "green_for_same": "With <1>green for those matching with the input value.", "orange_for_empty": "With <1>orange for those with empty input value.", "red_for_different": "With <1>red for those with different input value.", "indicate_not_provided_value": "Empty inputs are ignored. If fibers are not present in the table, you can put \"-\" to specify the value is not available.", @@ -394,4 +395,4 @@ "subtitle": "Download" } } -} +} \ No newline at end of file diff --git a/src/pages/nutrition/NutrimentCell.tsx b/src/pages/nutrition/NutrimentCell.tsx index b0d21af667..59e0efbdcb 100644 --- a/src/pages/nutrition/NutrimentCell.tsx +++ b/src/pages/nutrition/NutrimentCell.tsx @@ -66,9 +66,6 @@ function getLegendColor(productValue, value, productUnit, unit) { return 'green' } return 'red' - - // Should never reach that part. - return undefined; } export const NutrimentCell = (props: NutrimentCellProps) => { diff --git a/src/pages/nutrition/index.tsx b/src/pages/nutrition/index.tsx index 72f40370cd..199e1baa92 100644 --- a/src/pages/nutrition/index.tsx +++ b/src/pages/nutrition/index.tsx @@ -26,11 +26,13 @@ import Instructions from "./Instructions"; import useNutrimentTranslations from "./useNutrimentTranslations"; import { useCountry } from "../../contexts/CountryProvider"; import { useTranslation } from "react-i18next"; +import { useSearchParamsState } from "../../hooks/useSearchParamsState"; export default function Nutrition() { const { t } = useTranslation(); - const [partiallyFilled, setPartiallyFilled] = React.useState(false); - const [displayOFFValue, setDisplayOFFValue] = React.useState(false); + const [partiallyFilled, setPartiallyFilled] = useSearchParamsState('partiallyFilled', false, Boolean); + const [displayOFFValue, setDisplayOFFValue] = useSearchParamsState('displayValue', false, Boolean); + const handlePartiallyFilled = (_, checked) => { setPartiallyFilled(checked); setDisplayOFFValue(checked); diff --git a/src/pages/nutrition/useRobotoffPredictions.ts b/src/pages/nutrition/useRobotoffPredictions.ts index 10888a05e2..3bc0726df3 100644 --- a/src/pages/nutrition/useRobotoffPredictions.ts +++ b/src/pages/nutrition/useRobotoffPredictions.ts @@ -103,7 +103,7 @@ export function useRobotoffPredictions(partiallyFilled: boolean) { const nextItem = React.useCallback(() => { setInsightIndex((p) => p + 1); - setCount((p) => p - 1); + setCount((p) => p === 100 ? p : p - 1); }, []); const insight = insights.data[insightIndex];