diff --git a/src/App.js b/src/App.js index 2c2d9b4c6..b3348fc29 100644 --- a/src/App.js +++ b/src/App.js @@ -4,25 +4,7 @@ import { createTheme, ThemeProvider } from "@mui/material/styles"; import { Routes, Route, useLocation } from "react-router-dom"; import { useMatomo } from "@jonkoops/matomo-tracker-react"; import axios from "axios"; -import { - EcoScorePage, - LogoAnnotationPage, - LogoSearchPage, - LogoUpdatePage, - LogoDeepSearch, - ProductLogoAnnotationPage, - SettingsPage, - QuestionsPage, - InsightsPage, - NotFoundPage, - Home, - Nutrition, - FlaggedImages, - ShouldLoggedinPage, - PackagingPage, - LogoQuestionValidator, - DashBoard, -} from "./pages"; + import ResponsiveAppBar from "./components/ResponsiveAppBar"; import DevModeContext from "./contexts/devMode"; import { @@ -36,6 +18,33 @@ import LoginContext from "./contexts/login"; import off from "./off"; import { IS_DEVELOPMENT_MODE } from "./const"; import ColorModeContext from "./contexts/colorMode"; +import { CircularProgress } from "@mui/material"; + +const EcoScorePage = React.lazy(() => import("./pages/eco-score")); +const LogoAnnotationPage = React.lazy(() => + import("./pages/logos/LogoAnnotation") +); +const LogoSearchPage = React.lazy(() => import("./pages/logos/LogoSearch")); +const LogoUpdatePage = React.lazy(() => import("./pages/logos/LogoUpdate")); +const LogoDeepSearch = React.lazy(() => import("./pages/logos/LogoDeepSearch")); +const ProductLogoAnnotationPage = React.lazy(() => + import("./pages/logos/ProductLogoAnnotations") +); +const SettingsPage = React.lazy(() => import("./pages/settings")); +const QuestionsPage = React.lazy(() => import("./pages/questions")); +const InsightsPage = React.lazy(() => import("./pages/insights")); +const NotFoundPage = React.lazy(() => import("./pages/not-found")); +const Home = React.lazy(() => import("./pages/home")); +const Nutrition = React.lazy(() => import("./pages/nutrition")); +const FlaggedImages = React.lazy(() => import("./pages/flaggedImages")); +const ShouldLoggedinPage = React.lazy(() => + import("./pages/shouldLoggedinPage") +); +const PackagingPage = React.lazy(() => import("./pages/packaging")); +const LogoQuestionValidator = React.lazy(() => + import("./pages/logosValidator/LogoQuestionValidator") +); +const DashBoard = React.lazy(() => import("./pages/logosValidator/DashBoard")); // OFF colors const latte = "#F6F3F0"; @@ -212,117 +221,123 @@ export default function App() { const theme = createTheme(getToken(mode)); return ( - - - - - - - - } /> - } /> - - ) : ( - - ) - } - /> - - ) : ( - - ) - } - /> - - ) : ( - - ) - } - /> - - ) : ( - - ) - } - /> - - ) : ( - - ) - } - /> + }> + + + + + + + + } /> + } /> + + ) : ( + + ) + } + /> + + ) : ( + + ) + } + /> + + ) : ( + + ) + } + /> + + ) : ( + + ) + } + /> + + ) : ( + + ) + } + /> - } /> - } /> - } /> - } /> - } /> - } /> - - ) : ( - - ) - } - /> - {/* To delete in 2024 */} - } /> - } /> + } /> + } /> + } /> + } /> + } /> + } /> + + ) : ( + + ) + } + /> + {/* To delete in 2024 */} + } /> + } /> - : - } - /> - {showFlaggedImage && ( - } /> - )} + + ) : ( + + ) + } + /> + {showFlaggedImage && ( + } /> + )} - - ) : ( - - ) - } - /> - - - - - + + ) : ( + + ) + } + /> + + + + + + ); } diff --git a/src/components/Opportunities.tsx b/src/components/Opportunities.tsx index d45b568e4..23d319ce8 100644 --- a/src/components/Opportunities.tsx +++ b/src/components/Opportunities.tsx @@ -8,6 +8,7 @@ import CardContent from "@mui/material/CardContent"; import Box from "@mui/material/Box"; import Skeleton from "@mui/material/Skeleton"; import Button from "@mui/material/Button"; +import { CircularProgress } from "@mui/material"; import robotoff from "../robotoff"; import off from "../off"; @@ -28,40 +29,44 @@ const OpportunityCard = (props) => { })}`; return ( + }> + + + + {name} + + {questionNumber.toLocaleString()} + + + + + + ); +}; + +const CardSkeleton = () => ( + }> - - - {name} - - {questionNumber.toLocaleString()} - - - + + + + - ); -}; - -const CardSkeleton = () => ( - - - - - - + ); const useTranslation = (toTranslate) => { @@ -105,7 +110,7 @@ const Opportunities = (props) => { .getUnansweredValues({ type, campaign, country, page, count: pageSize }) .then(({ data }) => { if (isValid) { - setRemainingQuestions((prev) => [...prev, ...data.questions]); + setRemainingQuestions((prev) => [...prev, ...data?.questions]); setIsLoading(false); } }) @@ -124,49 +129,51 @@ const Opportunities = (props) => { const lang = getLang(); return ( - - - {type} - - - {remainingQuestions.map(([value, questionNumber]) => { - const name = - translation[value]?.name?.[lang] ?? - translation[value]?.name?.en ?? - value; - return ( - - ); - })} - {isLoading && - [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, - ].map((id) => )} - + {remainingQuestions.map(([value, questionNumber]) => { + const name = + translation[value]?.name?.[lang] ?? + translation[value]?.name?.en ?? + value; + return ( + + ); + })} + {isLoading && + [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, + ].map((id) => )} + + - + ); }; diff --git a/src/pages/eco-score/index.jsx b/src/pages/eco-score/index.jsx index b9a060d97..f8de761c6 100644 --- a/src/pages/eco-score/index.jsx +++ b/src/pages/eco-score/index.jsx @@ -12,6 +12,7 @@ import Opportunities from "../../components/Opportunities"; import { DEFAULT_FILTER_STATE } from "../../components/QuestionFilter/const"; import { useTranslation } from "react-i18next"; import { capitaliseName } from "../../utils"; +import { CircularProgress } from "@mui/material"; const ecoScoreCards = [ { @@ -168,49 +169,51 @@ export default function EcoScore() { const [selectedCountry, setSelectedCountry] = React.useState(countryNames[0]); return ( - - {t("eco-score.description")} - }> + - {ecoScoreCards.map((props) => ( - - - - ))} - + {t("eco-score.description")} + + {ecoScoreCards.map((props) => ( + + + + ))} + - - { - setSelectedCountry(event.target.value); - }} - sx={{ width: 200 }} - > - {countryNames.map((country) => ( - - {capitaliseName(country)} - - ))} - + + { + setSelectedCountry(event.target.value); + }} + sx={{ width: 200 }} + > + {countryNames.map((country) => ( + + {capitaliseName(country)} + + ))} + - - + + + ); } diff --git a/src/pages/flaggedImages/index.jsx b/src/pages/flaggedImages/index.jsx index 020f5b24e..63d60972e 100644 --- a/src/pages/flaggedImages/index.jsx +++ b/src/pages/flaggedImages/index.jsx @@ -30,54 +30,58 @@ export default function FlaggedImages() { return

{t(`flagged_images.loading`)}

; } return ( - - - {t("flagged_images.title")} - - {data.map(({ code, imgid }) => ( - - - - - - ))} -
- - {code} - - - - - { - axios.delete( - `https://amathjourney.com/api/off-annotation/flag-image/${code}`, - { - mode: "no-cors", - data: { - imgid, - }, - } - ); - setData((prev) => - prev.filter( - (line) => line.code !== code || line.imgid !== imgid - ) - ); - }} - > - - -
+ + + + {t("flagged_images.title")} + + {data.map(({ code, imgid }) => ( + + + + + + ))} +
+ + {code} + + + + + { + axios.delete( + `https://amathjourney.com/api/off-annotation/flag-image/${code}`, + { + mode: "no-cors", + data: { + imgid, + }, + } + ); + setData((prev) => + prev.filter( + (line) => line.code !== code || line.imgid !== imgid + ) + ); + }} + > + + +
+
-
+ ); } diff --git a/src/pages/home/index.jsx b/src/pages/home/index.jsx index 83de3e07b..db73386db 100644 --- a/src/pages/home/index.jsx +++ b/src/pages/home/index.jsx @@ -17,6 +17,7 @@ import UserData from "./UserData"; import { localFavorites } from "../../localeStorageManager"; import LoginContext from "../../contexts/login"; +import { CircularProgress } from "@mui/material"; const Home = () => { const theme = useTheme(); @@ -32,7 +33,7 @@ const Home = () => { const handleOpen = () => setOpen(true); const handleClose = () => setOpen(false); return ( - <> + }> { - + ); }; diff --git a/src/pages/insights/index.jsx b/src/pages/insights/index.jsx index cd5f49c9e..21b11a9bc 100644 --- a/src/pages/insights/index.jsx +++ b/src/pages/insights/index.jsx @@ -1,4 +1,4 @@ -import { Divider, Stack } from "@mui/material"; +import { CircularProgress, Divider, Stack } from "@mui/material"; import * as React from "react"; import Typography from "@mui/material/Typography"; @@ -25,19 +25,21 @@ export default function Insights() { ); return ( - - {t("insights.insights")} - - -
- }> + + {t("insights.insights")} + -
-
+ +
+ +
+ + ); } diff --git a/src/pages/logos/LogoAnnotation.jsx b/src/pages/logos/LogoAnnotation.jsx index e4ff1abe4..2b27bf322 100644 --- a/src/pages/logos/LogoAnnotation.jsx +++ b/src/pages/logos/LogoAnnotation.jsx @@ -266,131 +266,133 @@ export default function LogoAnnotation() { } return ( - - - {t("logos.annotations")} - - {t("logos.task_description")} - - {/* Selection buttons */} - - + }> + + + {t("logos.annotations")} + + {t("logos.task_description")} + + {/* Selection buttons */} + + + + + {t("logos.refresh")} + +
+ + + + + {logoState.isLoading && ( + + + + )} + {/* Logos to select */} + + - - {t("logos.refresh")} - -
+ + + - - - - {logoState.isLoading && ( - - - )} - {/* Logos to select */} - - - - - - + { + const logoIds = selectedLogos.map((l) => l.id); + + setLogoState((prevState) => ({ + ...prevState, + logos: prevState.logos.map((logo) => { + if (!logoIds.includes(logo.id)) { + return logo; + } + return { + ...logo, + selected: false, + annotation_type: annotation.type, + annotation_value: annotation.value, + }; + }), + })); + }} + /> + - - { - const logoIds = selectedLogos.map((l) => l.id); - - setLogoState((prevState) => ({ - ...prevState, - logos: prevState.logos.map((logo) => { - if (!logoIds.includes(logo.id)) { - return logo; - } - return { - ...logo, - selected: false, - annotation_type: annotation.type, - annotation_value: annotation.value, - }; - }), - })); - }} - /> - - + ); } diff --git a/src/pages/logos/LogoDeepSearch.jsx b/src/pages/logos/LogoDeepSearch.jsx index ee5567c8d..4144329e1 100644 --- a/src/pages/logos/LogoDeepSearch.jsx +++ b/src/pages/logos/LogoDeepSearch.jsx @@ -299,112 +299,115 @@ export default function LogoSearch() { }; return ( - - - Logo search - - - Select a logo you want to look for, and let's go to catch them all. For - every logo you annotate, we will fetch it's neighbors such that you - might never stop to annotate. (Press Shift to select range of logos) - - - - {/* {isLoading && } */} + }> + + + Logo search + + + Select a logo you want to look for, and let's go to catch them all. + For every logo you annotate, we will fetch it's neighbors such that + you might never stop to annotate. (Press Shift to select range of + logos) + + + + {/* {isLoading && } */} - - Reference logos (logo already annotated with this value) - + + Reference logos (logo already annotated with this value) + - {isLoadingAnnotatedLogos ? ( - - ) : annotatedLogos == null || annotatedLogos.length === 0 ? ( - - ) : ( + {isLoadingAnnotatedLogos ? ( + + ) : annotatedLogos == null || annotatedLogos.length === 0 ? ( + + ) : ( + + )} + + + + + + Remaining to annotate + + + + + + {isLoadingToAnnotateLogos && } - )} - - - - - Remaining to annotate - - - + + + + + + - - {isLoadingToAnnotateLogos && } - - - - - - - - - - + ); } diff --git a/src/pages/logos/LogoUpdate.jsx b/src/pages/logos/LogoUpdate.jsx index db646342c..369f96cad 100644 --- a/src/pages/logos/LogoUpdate.jsx +++ b/src/pages/logos/LogoUpdate.jsx @@ -24,6 +24,7 @@ import { useTranslation } from "react-i18next"; // Only for testing purpose import { sleep } from "../../utils"; +import { CircularProgress } from "@mui/material"; const getImageURL = (logo) => offService.getImageUrl(logo.image.source_image); @@ -201,5 +202,9 @@ export default function LogoUpdate() { }; }, [logoId]); - return ; + return ( + }> + + + ); } diff --git a/src/pages/logos/ProductLogoAnnotations.jsx b/src/pages/logos/ProductLogoAnnotations.jsx index e6c1f46d8..95544b79a 100644 --- a/src/pages/logos/ProductLogoAnnotations.jsx +++ b/src/pages/logos/ProductLogoAnnotations.jsx @@ -16,6 +16,7 @@ import { logoTypeOptions } from "../../components/LogoSearchForm"; import robotoff from "../../robotoff"; import off from "../../off"; import useUrlParams from "../../hooks/useUrlParams"; +import { CircularProgress } from "@mui/material"; const PRODUCT_PAGE_SIZE = 2; @@ -211,7 +212,7 @@ export default function AnnotateLogosFromProducts() { }, []); return ( -
+ }> } -
+ ); } diff --git a/src/pages/logosValidator/DashBoard.tsx b/src/pages/logosValidator/DashBoard.tsx index aae4f0cfd..60ecf703c 100644 --- a/src/pages/logosValidator/DashBoard.tsx +++ b/src/pages/logosValidator/DashBoard.tsx @@ -75,34 +75,36 @@ export default function VerticalTabs() { }; return ( - - + + + {DASHBOARD.map(({ tag, title }, index) => ( + + ))} + {DASHBOARD.map(({ tag, title }, index) => ( - + ))} - - {DASHBOARD.map(({ tag, title }, index) => ( - - ))} - +
+ ); } diff --git a/src/pages/logosValidator/LogoQuestionValidator.jsx b/src/pages/logosValidator/LogoQuestionValidator.jsx index abc3b2812..b05b18d76 100644 --- a/src/pages/logosValidator/LogoQuestionValidator.jsx +++ b/src/pages/logosValidator/LogoQuestionValidator.jsx @@ -31,6 +31,7 @@ import off from "../../off"; import useUrlParams from "../../hooks/useUrlParams"; import { LOGOS } from "./dashboardDefinition"; +import { CircularProgress } from "@mui/material"; const fetchData = async (insightId) => { const response = await robotoff.insightDetail(insightId); @@ -447,8 +448,10 @@ function LogoQuestionValidator() { export default function WrappedLogoQuestionValidator() { return ( - - - + }> + + + + ); } diff --git a/src/pages/not-found/index.jsx b/src/pages/not-found/index.jsx index 4f763d8d2..ad5447ee8 100644 --- a/src/pages/not-found/index.jsx +++ b/src/pages/not-found/index.jsx @@ -8,23 +8,25 @@ export default function Insights() { const { t } = useTranslation(); return ( - - - {t("notfound.nopage")} - - {t("notfound.redirect1")}{" "} - - {t("notfound.redirect2")} - - - + + + + {t("notfound.nopage")} + + {t("notfound.redirect1")}{" "} + + {t("notfound.redirect2")} + + + + ); } diff --git a/src/pages/nutrition/index.jsx b/src/pages/nutrition/index.jsx index eb1d1b8b4..4589747e5 100644 --- a/src/pages/nutrition/index.jsx +++ b/src/pages/nutrition/index.jsx @@ -29,30 +29,32 @@ export default function Nutrition() { } return ( - - - nutr.display)} - setNutriments={setNutriments} - onchangeHandler={onchangeHandler} - deleteItem={deleteItem} - /> - + + + + nutr.display)} + setNutriments={setNutriments} + onchangeHandler={onchangeHandler} + deleteItem={deleteItem} + /> + + ); } diff --git a/src/pages/packaging/index.tsx b/src/pages/packaging/index.tsx index 8c15db025..aa74c2183 100644 --- a/src/pages/packaging/index.tsx +++ b/src/pages/packaging/index.tsx @@ -27,6 +27,7 @@ import { getImagesUrls } from "../questions/utils"; import offService from "../../off"; import { useTranslation } from "react-i18next"; import useUrlParams from "../../hooks/useUrlParams"; +import { CircularProgress } from "@mui/material"; const formatData = (innerRows) => { const packagings = innerRows @@ -95,7 +96,7 @@ const Page = () => { return

Loading...

; } return ( - <> + }> {getImagesUrls(product.images, product.code).map((src) => ( { {t("questions.edit")} - + ); }; diff --git a/src/pages/questions/index.jsx b/src/pages/questions/index.jsx index 7faa4a468..89198f3b3 100644 --- a/src/pages/questions/index.jsx +++ b/src/pages/questions/index.jsx @@ -19,6 +19,7 @@ import store, { nextPageSelector, } from "./store"; import { Provider, useDispatch, useSelector } from "react-redux"; +import { CircularProgress } from "@mui/material"; function QuestionsConsumer() { const dispatch = useDispatch(); @@ -68,8 +69,10 @@ function QuestionsConsumer() { export default function Questions() { return ( - - - + }> + + + + ); } diff --git a/src/pages/settings/index.jsx b/src/pages/settings/index.jsx index ec82fd918..ad783f190 100644 --- a/src/pages/settings/index.jsx +++ b/src/pages/settings/index.jsx @@ -20,6 +20,7 @@ import DevModeContext from "../../contexts/devMode"; import ColorModeContext from "../../contexts/colorMode"; import { localSettings, localSettingsKeys } from "../../localeStorageManager"; import FooterWithLinks from "../../components/Footer"; +import { CircularProgress } from "@mui/material"; export default function Settings() { const { t, i18n } = useTranslation(); @@ -51,7 +52,7 @@ export default function Settings() { }; return ( - <> + }> {t("settings.settings")} @@ -133,6 +134,6 @@ export default function Settings() { - + ); } diff --git a/src/pages/shouldLoggedinPage/index.js b/src/pages/shouldLoggedinPage/index.js index 67b5f241a..e0569ea4a 100644 --- a/src/pages/shouldLoggedinPage/index.js +++ b/src/pages/shouldLoggedinPage/index.js @@ -1,12 +1,15 @@ +import * as React from "react"; import Typography from "@mui/material/Typography"; import Box from "@mui/material/Box"; const ShouldLoggedinPage = () => ( - - - Restricted page - - Advanced games are restricted to connected users - + + + + Restricted page + + Advanced games are restricted to connected users + + ); export default ShouldLoggedinPage;