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

Added image upload component and backend call #132

Merged
merged 3 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
57 changes: 57 additions & 0 deletions web/components/BabyBook/ImageUpload.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React, { useContext } from "react";
import { storage } from "../../db/firebase"; // import firebase storage
import { ref, uploadBytesResumable, getDownloadURL } from "firebase/storage";

export const ImageUpload = ({}) => {
const saveFile = async (e: React.ChangeEvent<HTMLInputElement>) => {
const files = e.target.files;
if (!files || files.length === 0) return;

try {
const file = files[0];

const extension = file.name.split(".").pop();
const storageRef = ref(storage, `images/${Date.now()}.${extension}`);

const uploadTask = uploadBytesResumable(storageRef, file);

uploadTask.on(
"state_changed",
(snapshot) => {
const progress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100;
},
(error) => {
console.error("Upload failed:", error);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return an object instead of printing the error or showing an alert so that displaying errors can be handled by the frontend, should be in the form {success: false, error: [error message]}

},
async () => {
const downloadURL = await getDownloadURL(uploadTask.snapshot.ref);
// TODO: Incorporate baby and caregiver context
// https://github.com/GTBitsOfGood/motherhood-beyond-bars/blob/_original/mobile/screens/babybook/SelectPicture.tsx#L28
// TODO: Incorporate caption
const metadata = {
imageURL: downloadURL,
caregiverID: "test-caregiverId",
caption: "test-caption",
babyID: "test-babyId",
};
const response = await fetch("/api/save-image", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(metadata),
});
if (!response.ok) {
const result = await response.json();
alert(result.error || "Error uploading image metadata");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return an object here as well instead of an error

}
}
);
} catch (error) {
console.error("Upload failed:", error);
alert("An error occurred while uploading the image.");
}
};
return <input type="file" onChange={saveFile} />;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The backend and frontend should be separated where the backend endpoint is in a separate file from the frontend so that it can be re-used

};
38 changes: 38 additions & 0 deletions web/pages/api/save-image.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// pages/api/saveImage.js
import { NextApiRequest, NextApiResponse } from "next";
import { db } from "../../db/firebase"; // Firestore database
import { doc, setDoc, Timestamp } from "firebase/firestore";

export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method === "POST") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API isn't needed in this case since Firebase can do client-side database calls, so to speed up code fetching we should call the Firebase functions as endpoints rather than in the API. There are some cases where we need to handle things on the server-side, but we're good in this case

// Extracting the necessary data from the request body
const { imageURL, caregiverID, caption, babyID } = req.body;

try {
// Create a reference to the document in the 'babies' collection and save metadata
const docRef = doc(
db,
"babies",
babyID,
"book",
`${caregiverID}_${Date.now()}`
);
await setDoc(docRef, {
imageUrl: imageURL,
caption: caption,
date: Timestamp.now(),
caregiverId: caregiverID,
});

res.status(200).json({ message: "Image metadata saved successfully" });
} catch (error) {
console.error("Error saving image metadata:", error);
res.status(500).json({ error: "Error saving image metadata" });
}
} else {
res.status(405).json({ message: "Method not allowed" });
}
}
14 changes: 14 additions & 0 deletions web/pages/upload-test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// pages/upload-test.js

import { ImageUpload } from "@components/BabyBook/ImageUpload";

const UploadTestPage = () => {
return (
<div>
<h1>Test Image Upload</h1>
<ImageUpload />
</div>
);
};

export default UploadTestPage;