Skip to content

Commit

Permalink
Play with some taxonomy explorer (openfoodfacts#1084)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexfauquette authored Dec 2, 2024
1 parent 80fca77 commit 737f0f5
Show file tree
Hide file tree
Showing 6 changed files with 327 additions and 15 deletions.
3 changes: 3 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ const IngredientPage = React.lazy(() => import("./pages/ingredients"));
const Brandinator = React.lazy(() => import("./pages/Brandinator"));
const BugPage = React.lazy(() => import("./pages/bug"));

const TaxonomyWalk = React.lazy(() => import("./pages/taxonomyWalk"));

// OFF colors
const latte = "#F6F3F0";
const cappucino = "#EDE0DB";
Expand Down Expand Up @@ -357,6 +359,7 @@ export default function App() {
/>
<Route path="/gala" element={<GalaBoard />} />
<Route path="/bugs" element={<BugPage />} />
<Route path="/taxo-walk" element={<TaxonomyWalk />} />
</Routes>
</DevModeContext.Provider>
</LoginContext.Provider>
Expand Down
21 changes: 6 additions & 15 deletions src/components/TaxonomyAutoSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,28 @@ type TaxonomyAutoSelectProps = Omit<TextFieldProps, "value" | "onChange"> & {
* The taxonly to querry
*/
taxonomy: TaxonomyNames;
onChange: (itemId: string) => void;
onChange: (itemId: string, ctx?: object) => void;
value: string;
/**
* The the id bellow the text field
*/
showKey?: boolean;
lang?: string;
};

const isOptionEqualToValue = (option: string | TaxonomyItem, value: string) =>
(typeof option === "string" ? option : option.text) === value;

export default function TaxonomyAutoSelect(props: TaxonomyAutoSelectProps) {
const { taxonomy, value, onChange, showKey, fullWidth, ...other } = props;
const { taxonomy, value, onChange, showKey, fullWidth, lang, ...other } =
props;
const [inputValue, setInputValue] = React.useState("");
const [selectedValue, setSelectedValue] = React.useState(null);
const [options, setOptions] = React.useState<
readonly (string | TaxonomyItem)[]
>([]);

const language = "en"; //getLang();
const language = lang ?? "en"; //getLang();

const fetch = React.useMemo(
() =>
Expand Down Expand Up @@ -76,9 +78,6 @@ export default function TaxonomyAutoSelect(props: TaxonomyAutoSelectProps) {
};
}, [value, inputValue, fetch]);

const selectedOption = options.find((option) =>
isOptionEqualToValue(option, value),
);
return (
<Autocomplete
getOptionLabel={(option) =>
Expand All @@ -96,9 +95,8 @@ export default function TaxonomyAutoSelect(props: TaxonomyAutoSelectProps) {
isOptionEqualToValue={isOptionEqualToValue}
// noOptionsText="No locations"
onChange={(event: any, newValue: TaxonomyItem | null | string) => {
console.log({ newValue });
if (typeof newValue === "object") {
onChange(newValue.text);
onChange(newValue.text, newValue);
setSelectedValue(newValue);
return;
}
Expand All @@ -108,12 +106,6 @@ export default function TaxonomyAutoSelect(props: TaxonomyAutoSelectProps) {
setInputValue(newInputValue);
}}
onBlur={() => {
console.log("blur");
console.log({
inputValue,
value,
selectedOption,
});
if (
inputValue === value ||
(selectedValue && selectedValue.text === inputValue)
Expand All @@ -128,7 +120,6 @@ export default function TaxonomyAutoSelect(props: TaxonomyAutoSelectProps) {
{...params}
{...other}
onKeyDown={(event) => {
console.log(event.key);
if (event.key === "Enter") {
event.preventDefault();
}
Expand Down
35 changes: 35 additions & 0 deletions src/offTaxonomy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import axios, { AxiosResponse } from "axios";

type TagType = "categories";

export type TaxonomyItem = {
id: string;
text: string;
taxonomy_name: string;
};

export type GetTaxonomyParams = {
/**
* @default "categories"
*/
categories?: TagType;
/**
* @default ["fr", "en"]
*/
languages?: string[];
/**
* The tag
*/
tag: string;
};
export default function getTaxonomy(
params: GetTaxonomyParams,
): Promise<AxiosResponse<{ options?: TaxonomyItem[] }>> {
const { categories = "categories", tag, languages = ["fr", "en"] } = params;

return axios.get(
`https://world.openfoodfacts.org/api/v2/taxonomy?tagtype=${categories}&tags=${tag}&lc=${languages.join(
",",
)}`,
);
}
26 changes: 26 additions & 0 deletions src/pages/taxonomyWalk/Error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import * as React from "react";

export class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}

static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}

componentDidCatch(error, info) {
// Example "componentStack":
// in ComponentThatThrows (created by App)
// in ErrorBoundary (created by App)
// in div (created by App)
// in App
console.log(error, info.componentStack);
}

render() {
return this.props.children;
}
}
111 changes: 111 additions & 0 deletions src/pages/taxonomyWalk/ItemCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import * as React from "react";
import {
Box,
Button,
Card,
CardContent,
List,
ListItem,
Typography,
} from "@mui/material";

export type CategoryType = {
id: string;
children?: string[];
parents?: string[];
name?: { en?: string; fr?: string };
agribalyse_food_code?: { en: string };
ciqual_food_code?: { en: string };
intake24_category_code?: { en: string };
};

export default function CategoryCard(props: {
id: string;
data: CategoryType | "failed" | "loading";
clickChildren?: (id: string) => void;
clickParent?: (id: string) => void;
goTo?: () => void;
hideParent?: boolean;
hideChildren?: boolean;
}) {
const { id: itemId, data, clickParent, hideChildren, goTo } = props;

const [showMore, setShowMore] = React.useState(false);

if (data === "loading") {
return null;
}

if (data === "failed") {
return (
<Card sx={{ border: "solid black 1px", mb: 0.5 }}>
<CardContent>
<Box>
<Typography variant="h5">{itemId}</Typography>
<Typography>No data found</Typography>
</Box>
</CardContent>
</Card>
);
}
const { parents = [], children = [], name, id, ...other } = data;

return (
<Card sx={{ border: "solid black 1px", mb: 0.5 }}>
<CardContent>
<Box>
<Typography variant="h5">
{name ? Object.values(name).join("/") : id}
{!!goTo && <Button onClick={() => goTo()}>Go</Button>}
</Typography>
{showMore && (
<pre style={{ fontSize: 10 }}>{JSON.stringify(other, null, 2)}</pre>
)}
<button onClick={() => setShowMore((p) => !p)}>
{showMore ? "hide data" : "additional info"}
</button>
</Box>
<Box
sx={{
display: "flex",
flexDirection: "row",
borderTop: "solid black 1px",
pt: 1,
mt: 1,
}}
>
<Box sx={{ flexGrow: 1 }}>
<Typography>parents</Typography>
<List>
{parents.map((parentId) => (
<ListItem
key={parentId}
onClick={() => clickParent?.(parentId)}
sx={{ p: 0 }}
>
{parentId}
</ListItem>
))}
</List>
</Box>
<Box sx={{ flexGrow: 1 }}>
<Typography>enfants</Typography>
<List>
{children &&
!hideChildren &&
children.map((childId) => (
<ListItem
key={childId}
onClick={() => clickParent?.(childId)}
sx={{ p: 0 }}
>
{childId}
</ListItem>
))}
</List>
</Box>
</Box>
</CardContent>
</Card>
);
}
Loading

0 comments on commit 737f0f5

Please sign in to comment.