import classNames from "classnames";
import { makeStyles } from "@material-ui/core/styles";
import React, { useEffect, useState, useMemo } from "react";
import { getDatabase, ref, get } from "firebase/database";
import Link from "next/link";
import styles from "/styles/jss/nextjs-material-kit/pages/components.js";
import CameraInput from "./CameraInput";
import LocalStorageInput from "./LocalStorageInput";
import Button from "/components/CustomButtons/Button.js";
import Card from "/components/Card/Card.js";
import CardMedia from "@material-ui/core/CardMedia";
import CardBody from "/components/Card/CardBody.js";
import CardFooter from "/components/Card/CardFooter.js";
import GridContainer from "/components/Grid/GridContainer.js";
import GridItem from "/components/Grid/GridItem.js";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import Switch from "@material-ui/core/Switch";
const useStyles = makeStyles(styles);
/**
* The `CameraContent` function in JavaScript fetches food data based on image predictions and displays
* food information along with images.
* @returns The `CameraContent` function is being exported as the default export. It returns JSX
* elements that conditionally render different sections based on the state of the component.
*/
export function CameraContent() {
const classes = useStyles();
const [checkedStates, setCheckedStates] = useState([]);
const [image, setImage] = React.useState(null);
const [predictions, setPredictions] = React.useState(null);
const [foods, setFoods] = useState([]);
const [debouncedSearch, setDebouncedSearch] = useState("");
const database = getDatabase();
useEffect(() => {
const fetchFoods = async () => {
if (debouncedSearch.trim() === "") {
setFoods([]);
return;
}
const foodRef = ref(database, "food/");
try {
const snapshot = await get(foodRef);
if (snapshot.exists()) {
const foodArray = Object.entries(snapshot.val()).map(
([idd, data]) => ({
idd,
...data,
})
);
const filteredFoods = foodArray.filter((food) =>
food.idd.toLowerCase().includes(debouncedSearch.toLowerCase())
);
setFoods(filteredFoods);
setCheckedStates(Array(foodArray.length).fill(false));
} else {
console.log("No data available");
}
} catch (error) {
console.error("Error retrieving data:", error);
}
};
fetchFoods();
}, [debouncedSearch]);
const cachedFoods = useMemo(() => foods, [foods]);
return (
<>
{!image && (
<div style={{ display: "flex", justifyContent: "center", gap: "10px" }}>
<CameraInput onImageCapture={setImage} />{" "}
<LocalStorageInput onImageSelect={setImage} />
</div>
)}
{image && (
<div>
<div
style={{ display: "flex", justifyContent: "center", gap: "25px" }}
>
<img
src={image}
alt="Selected Image"
style={{
maxWidth: "1000px",
maxHeight: "1000px",
width: "auto",
height: "auto",
objectFit: "contain",
}}
/>
</div>
<div
style={{ display: "flex", justifyContent: "center", gap: "25px" }}
>
<Button color="info" onClick={uploadImageAndGetPrediction}>
Get Prediction
</Button>
<Button color="danger" onClick={handleDiscardClick}>
Discard Picture
</Button>
</div>
</div>
)}
{foods.length > 0 && (
<GridContainer justify="left" spacing={4}>
{cachedFoods.map((food, index) => (
<GridItem xs={12} sm={6} md={4} lg={4} key={food.idd}>
<Card style={{ backgroundColor: "#fff9c4" }}>
<CardMedia
align="left"
component="img"
alt="Image cannot be loaded"
width="100"
height="200"
image={
food.category !== "Others"
? `/img/foods/${food.category.toLowerCase()}.jpg`
: "/img/fudpic.jpg"
}
title="Picture of a food"
/>
<CardBody>
<h4 className={food.idd} style={{ fontWeight: "bold" }}>
{food.idd}
</h4>
<p>
Calories:{" "}
{checkedStates[index] ? food.scalories : food.calories}
</p>
<p>Fats: {checkedStates[index] ? food.sfats : food.fats}</p>
<p>
Carbs: {checkedStates[index] ? food.scarbs : food.carbs}
</p>
<p>
Protein:{" "}
{checkedStates[index] ? food.sprotein : food.protein}
</p>
</CardBody>
<CardFooter>
{/* More Info button linking to FoodInfo page */}
<Link href={`/foodinfo?id=${food.id}`}>
<a>More Info</a>
</Link>
</CardFooter>
</Card>
</GridItem>
))}
</GridContainer>
)}
</>
);
}
/**
* The function `handleDiscardClick` logs "Hello" to the console and resets the image and foods state
* variables.
* @returns If the `image` variable is falsy, the function will return early without executing the
* remaining code.
*/
export const handleDiscardClick = () => {
console.log("Hello");
if (!image) return;
setImage(null);
setFoods([]);
};
/**
* The function `fetchFoodInfo` asynchronously retrieves food information based on provided IDs,
* filters the data, and sets states accordingly.
* @param foodIds - Food IDs are unique identifiers for different food items in the database. The
* `fetchFoodInfo` function takes an array of foodIds as a parameter to retrieve information about
* those specific food items from the database.
*/
export const fetchFoodInfo = async (foodIds) => {
console.log("Requested food IDs:", foodIds);
const foodRef = ref(database, "food/");
try {
const snapshot = await get(foodRef);
if (snapshot.exists()) {
const foodArray = Object.entries(snapshot.val()).map(([idd, data]) => ({
idd,
...data,
}));
console.log("Fetched food array:", foodArray);
const filteredFoods = foodArray.filter((food) =>
foodIds.includes(food.id)
);
console.log("Filtered foods:", filteredFoods);
setFoods(filteredFoods);
// Initialize checkedStates with false for each food item
setCheckedStates(filteredFoods.map(() => false));
} else {
console.log("No data available");
}
} catch (error) {
console.error("Error retrieving data:", error);
}
};
/**
* The function `uploadImageAndGetPrediction` fetches an image blob, sends it to a Flask API for
* prediction, processes the prediction result, and fetches additional food information based on the
* prediction.
*/
export const uploadImageAndGetPrediction = async () => {
try {
console.log("Fetching image blob...");
const imageBlob = await fetch(image).then((r) => r.blob());
const formData = new FormData();
formData.append("file", imageBlob, "image.jpg");
console.log("Sending image to Flask API...");
const FLASK_API_URL = "http://127.0.0.1:5000/predict";
const response = await fetch(FLASK_API_URL, {
method: "POST",
body: formData,
});
if (!response.ok) {
throw new Error("Failed to upload image and get prediction");
}
const result = await response.json();
console.log("Prediction received:", result.prediction);
const foodIds = result.prediction;
setPredictions(foodIds);
console.log("Fetching food info...");
await fetchFoodInfo(foodIds);
} catch (error) {
console.error("Error:", error);
}
};