- {reviews.map((review) => (
-
-
{review.author}
-
{review.location}
-
- {Array.from({ length: review.rating }).map((_, index) => (
- ★
- ))}
-
-
{review.content}
+ {cafes.map((cafe) => (
+
handleClick(cafe.placeId)}
+ >
+
{cafe.name}
+
{cafe.vicinity}
))}
diff --git a/src/dummy.json b/src/dummy.json
new file mode 100644
index 0000000..bd2b4d8
--- /dev/null
+++ b/src/dummy.json
@@ -0,0 +1,31 @@
+{
+ "test_id": {
+ "cafeId": "ChIJ60vPsg_QD4gRE61MVG65nSs",
+ "content": "Great place for coffee and work!",
+ "category": "Review",
+ "date": "2024-11-07T14:30:00Z",
+ "replies": {
+ "replyId_1": "I agree, the coffee is fantastic!",
+ "replyId_2": "The WiFi is also great for working!"
+ },
+ "uid": "user_1"
+ },
+ "test_id_2": {
+ "cafeId": "ChIJ60vPsg_QD4gRE61MVG65nSs",
+ "content": "Could use more seating during peak hours.",
+ "category": "Suggestion",
+ "date": "2024-11-08T09:00:00Z",
+ "replies": {},
+ "uid": "user_2"
+ },
+ "test_id_3": {
+ "cafeId": "ChIJ60vPsg_QD4gRE61MVG65nSs",
+ "content": "Is the cafe open late on weekends?",
+ "category": "Question",
+ "date": "2024-11-09T11:45:00Z",
+ "replies": {
+ "replyId_1": "Yes, they stay open until 10 PM on Saturdays and Sundays!"
+ },
+ "uid": "user_3"
+ }
+}
\ No newline at end of file
diff --git a/src/pages/CafePage.css b/src/pages/CafePage.css
new file mode 100644
index 0000000..5aa8304
--- /dev/null
+++ b/src/pages/CafePage.css
@@ -0,0 +1,90 @@
+.cafe-page-container {
+ padding: 2rem;
+ font-family: 'Hind Vadodara', sans-serif;
+}
+
+.cafe-header {
+ margin-bottom: 2rem;
+ border-bottom: 1px solid #ddd;
+ padding-bottom: 1rem;
+ text-align: center;
+}
+
+.cafe-header h1 {
+ font-size: 2.5rem;
+ color: #8A3323;
+ margin-bottom: 0.5rem;
+}
+
+.cafe-header p {
+ font-size: 1.2rem;
+}
+
+.posts-section {
+ margin-top: 2rem;
+}
+
+.posts-section h2 {
+ font-size: 1.8rem;
+ margin-bottom: 1rem;
+ color: #8A3323;
+}
+.posts-list {
+ list-style-type: none;
+ padding: 0;
+}
+
+.post-item {
+ padding: 1rem;
+ margin-bottom: 1rem;
+ border: 1px solid #ddd;
+ border-radius: 8px;
+ background-color: #fafafa;
+}
+
+.post-header {
+ margin-bottom: 1rem;
+ font-size: 1rem;
+ color: #555;
+}
+
+.post-header strong {
+ color: #8A3323;
+}
+
+.post-content p {
+ font-size: 1.2rem;
+ color: #333;
+}
+
+.replies-section {
+ margin-top: 1rem;
+ padding-left: 20px;
+ background-color: #f9f9f9;
+ border-left: 3px solid #8A3323;
+}
+
+.replies-section h3 {
+ font-size: 1.5rem;
+ margin-bottom: 1rem;
+}
+
+.reply-item {
+ margin-bottom: 0.8rem;
+ font-size: 1.1rem;
+ color: #333;
+}
+
+.error-message {
+ text-align: center;
+ padding: 2rem;
+ background-color: #ffebee;
+ border: 1px solid #f44336;
+ border-radius: 8px;
+ color: #d32f2f;
+}
+
+.error-message h1,
+.error-message h3 {
+ color: #d32f2f;
+}
diff --git a/src/pages/CafePage.jsx b/src/pages/CafePage.jsx
new file mode 100644
index 0000000..8a2fd53
--- /dev/null
+++ b/src/pages/CafePage.jsx
@@ -0,0 +1,158 @@
+import './CafePage.css';
+import { useParams } from 'react-router-dom';
+import { useState, useEffect } from 'react';
+import { findZipcode } from '../utilities/findZipcode';
+import { findCafes } from '../utilities/findCafes';
+import { useAuthState } from '../utilities/firebase';
+import { findCafePosts, addReplyToPost } from '../utilities/posts';
+import Banner from '../components/Banner';
+
+const CafePage = () => {
+ const { place_id } = useParams();
+ const [user] = useAuthState();
+ const [zipcode, setZipcode] = useState(null);
+ const [cafes, setCafes] = useState([]);
+ const [cafe, setCafe] = useState(null);
+ const [replyMessages, setReplyMessages] = useState({});
+
+ useEffect(() => {
+ if (user && user.email) {
+ const fetchZipCode = async () => {
+ const userZipcode = await findZipcode(user.email);
+ setZipcode(userZipcode);
+ };
+ fetchZipCode();
+ }
+ }, [user]);
+
+ useEffect(() => {
+ if (zipcode) {
+ const fetchCafes = async () => {
+ try {
+ await findCafes(5, zipcode, setCafes);
+ } catch (error) {
+ console.error('Error fetching cafes:', error);
+ setCafes([]);
+ }
+ };
+ fetchCafes();
+ }
+ }, [zipcode]);
+
+ useEffect(() => {
+ if (cafes.length > 0) {
+ const foundCafe = cafes.find((cafe) => cafe.placeId === place_id);
+ setCafe(foundCafe);
+ }
+ }, [cafes, place_id]);
+
+ const [posts, postError] = findCafePosts(cafe?.placeId);
+
+ if (!cafe) {
+ return (
+
+
Cafe not found
+
Sorry, we couldn't find a cafe with the specified ID.
+
+ );
+ }
+
+ const postItems = posts ? Object.entries(posts) : [];
+ const sortedPosts = postItems.sort((a, b) => new Date(b[1].date) - new Date(a[1].date));
+
+ const handleReplyChange = (e, postId) => {
+ setReplyMessages((prev) => ({
+ ...prev,
+ [postId]: e.target.value,
+ }));
+ };
+
+ const handleAddReply = async (postId) => {
+ const replyMessage = replyMessages[postId];
+ if (replyMessage && replyMessage.trim()) {
+ const error = await addReplyToPost(postId, user?.uid, replyMessage);
+ if (error) {
+ console.error('Error adding reply:', error);
+ } else {
+ setReplyMessages((prev) => ({
+ ...prev,
+ [postId]: '',
+ }));
+ }
+ }
+ };
+
+ return (
+
+
+
+
+
{cafe.name}
+
Location: {cafe.vicinity}
+
+
+ {sortedPosts && sortedPosts.length > 0 ? (
+
+
Posts
+
+ {sortedPosts.map(([postKey, post], index) => (
+ -
+
+
Category: {post.category}
+
{new Date(post.date).toLocaleString()}
+
+
+
+ {post.replies && Object.entries(post.replies).length > 0 ? (
+
+
Replies:
+
+ {Object.entries(post.replies).map(([replyId, message], replyIndex) => (
+ -
+
{message}
+
+ ))}
+
+
+ ) : (
+ No replies for this post.
+ )}
+
+ {user ? (
+
+
+ ) : (
+ Please log in to reply.
+ )}
+
+ ))}
+
+
+ ) : (
+
No posts available for this cafe.
+ )}
+ {postError && (
+
+
Error loading posts
+
{postError.message}
+
+ )}
+
+
+ );
+};
+
+export default CafePage;
diff --git a/src/pages/LandingPage.jsx b/src/pages/LandingPage.jsx
new file mode 100644
index 0000000..0ed5ef1
--- /dev/null
+++ b/src/pages/LandingPage.jsx
@@ -0,0 +1,56 @@
+import React from 'react';
+import '../App.css';
+import MapComponent from "../MapComponent";
+import Banner from '../components/Banner';
+import { useAuthState } from '../utilities/firebase';
+import { useState, useEffect } from "react";
+import { findZipcode } from "../utilities/findZipcode";
+import { findCafes } from "../utilities/findCafes";
+
+const LandingPage = () => {
+ const [user] = useAuthState();
+ const [zipcode, setZipcode] = useState(null);
+ const [cafes, setCafes] = useState([]);
+
+ useEffect(() => {
+ const fetchData = async () => {
+ if (user && user.email) {
+ try {
+ const userZipcode = await findZipcode(user.email);
+ setZipcode(userZipcode);
+
+ if (userZipcode) {
+ await findCafes(2, userZipcode, setCafes);
+ }
+ } catch (error) {
+ console.error("Error fetching zipcode or cafes:", error);
+ setZipcode(null);
+ setCafes([]);
+ }
+ }
+ };
+ fetchData();
+ }, [user]);
+
+ useEffect(() => {
+ console.log(cafes);
+ }, [cafes]);
+
+ const cafesMap = [
+ { name: "Cafe Blue", lat: 42.046, lng: -87.688 },
+ { name: "Green Bean Cafe", lat: 42.048, lng: -87.684 },
+ { name: "Java Lounge", lat: 42.044, lng: -87.690 },
+ ];
+
+ return (
+
+
+ {/* Integrate MapComponent with hardcoded data */}
+
+
+
+
+ );
+}
+
+export default LandingPage;
\ No newline at end of file
diff --git a/src/pages/ReviewPostPage.jsx b/src/pages/ReviewPostPage.jsx
new file mode 100644
index 0000000..861853d
--- /dev/null
+++ b/src/pages/ReviewPostPage.jsx
@@ -0,0 +1,157 @@
+import React, { useState, useEffect } from 'react';
+import '../App.css';
+import { useAuthState } from '../utilities/firebase';
+import { findCafes } from '../utilities/findCafes';
+
+const ReviewPostPage = () => {
+ const [reviews, setReviews] = useState([]);
+ const [availability, setAvailability] = useState({});
+ const [newReview, setNewReview] = useState('');
+ const [selectedReview, setSelectedReview] = useState(null);
+ const [replyText, setReplyText] = useState('');
+ const [cafeStatus, setCafeStatus] = useState({ seating: '', outlets: '' });
+ const [address, setAddress] = useState('');
+ const [dist, setDist] = useState('');
+ const [cafes, setCafes] = useState([]);
+ useEffect(() => { }, []);
+
+ const findCafesWrapper = () => {
+ findCafes(dist, address, setCafes);
+ };
+
+ const handleReviewSubmit = () => {
+ if (newReview.trim()) {
+ const review = { id: Date.now(), text: newReview, replies: [] };
+ setReviews((prevReviews) => [...prevReviews, review]);
+ setNewReview('');
+ }
+ };
+
+ const handleReplySubmit = (reviewId) => {
+ if (replyText.trim()) {
+ setReviews((prevReviews) =>
+ prevReviews.map((review) =>
+ review.id === reviewId
+ ? { ...review, replies: [...review.replies, replyText] }
+ : review
+ )
+ );
+ setReplyText('');
+ setSelectedReview(null);
+ }
+ };
+
+ const handleAvailabilityUpdate = (cafeId) => {
+ const timestamp = new Date().toLocaleString();
+ const newUpdate = { timestamp, seating: cafeStatus.seating, outlets: cafeStatus.outlets };
+
+ setAvailability((prevAvailability) => ({
+ ...prevAvailability,
+ [cafeId]: {
+ history: [...(prevAvailability[cafeId]?.history || []), newUpdate],
+ },
+ }));
+ setCafeStatus({ seating: '', outlets: '' });
+ };
+ return (
+
+
+
+
Share a Review
+
setNewReview(e.target.value)}
+ />
+
+
+
+
+
Update Cafe Availability
+
setCafeStatus({ ...cafeStatus, seating: e.target.value })}
+ />
+
setCafeStatus({ ...cafeStatus, outlets: e.target.value })}
+ />
+
+
+
Availability History
+ {availability['cafe-123']?.history?.map((update, index) => (
+
+
+ {update.timestamp}: Seating: {update.seating}, Outlets: {update.outlets}
+
+
+ ))}
+
+
+
+
Cafes Near Me
+
setAddress(e.target.value)}
+ />
+
setDist(e.target.value)}
+ />
+
+
Cafes Near Me
+
+ {cafes.map((cafe, index) => (
+ - {cafe}
+ ))}
+
+
+
+
+ {cafes.map((cafesMap, index) => (
+ -
+ {cafe.name} (Lat: {cafe.lat}, Lng: {cafe.lng})
+
+ ))}
+
+
+
+
+
+ )
+}
+
+export default ReviewPostPage;
\ No newline at end of file
diff --git a/src/pages/ReviewsPage.jsx b/src/pages/ReviewsPage.jsx
index c79993c..f184840 100644
--- a/src/pages/ReviewsPage.jsx
+++ b/src/pages/ReviewsPage.jsx
@@ -1,13 +1,46 @@
+import { useAuthState } from "../utilities/firebase";
+import { useState, useEffect } from "react";
+import { findZipcode } from "../utilities/findZipcode";
+import { findCafes } from "../utilities/findCafes";
import Banner from "../components/Banner";
import CafeList from "../components/CafeList";
const ReviewsPage = () => {
+ const [user] = useAuthState();
+ const [zipcode, setZipcode] = useState(null);
+ const [cafes, setCafes] = useState([]);
+ console.log(user);
+
+ useEffect(() => {
+ const fetchData = async () => {
+ if (user && user.email) {
+ try {
+ const userZipcode = await findZipcode(user.email);
+ setZipcode(userZipcode);
+
+ if (userZipcode) {
+ await findCafes(2, userZipcode, setCafes);
+ }
+ } catch (error) {
+ console.error("Error fetching zipcode or cafes:", error);
+ setZipcode(null);
+ setCafes([]);
+ }
+ }
+ };
+ fetchData();
+ }, [user]);
+
+ useEffect(() => {
+ console.log(cafes);
+ }, [cafes]);
+
return (
-
-
+
+
- )
-}
+ );
+};
-export default ReviewsPage;
\ No newline at end of file
+export default ReviewsPage;
diff --git a/src/utilities/findCafes.jsx b/src/utilities/findCafes.jsx
index 98dea2a..7160390 100644
--- a/src/utilities/findCafes.jsx
+++ b/src/utilities/findCafes.jsx
@@ -15,7 +15,11 @@ export const findCafes = (dist, address, setCafes) => {
},
(results, status) => {
if (status === window.google.maps.places.PlacesServiceStatus.OK) {
- setCafes(results.map((place) => place.name));
+ setCafes(results.map((place) => ({
+ name: place.name,
+ placeId: place.place_id,
+ vicinity: place.vicinity
+ })));
} else {
alert("No cafes found within the specified radius.");
setCafes([]);
diff --git a/src/utilities/findZipcode.jsx b/src/utilities/findZipcode.jsx
index 740ced2..f16b393 100644
--- a/src/utilities/findZipcode.jsx
+++ b/src/utilities/findZipcode.jsx
@@ -41,7 +41,8 @@ const getZipCode = async (placeId) => {
const getUniversity = (email) => {
const domain = email.split('@')[1];
- const university = domain.split('.')[0];
+ console.log(domain);
+ const university = domain.split('.')[1];
return university;
}
diff --git a/src/utilities/firebase.js b/src/utilities/firebase.js
index 4390349..ea1d27d 100644
--- a/src/utilities/firebase.js
+++ b/src/utilities/firebase.js
@@ -27,16 +27,16 @@ const database = getDatabase(app);
export const signInWithGoogle = () => {
signInWithPopup(auth, provider)
- .then(async (result) => {
- console.log('User signed in:', result.user);
- var zipcode = await findZipcode(result.user.email);
- console.log("Zipcode: ", zipcode);
- })
- .catch((error) => {
- console.error('Error signing in with Google:', error);
- });
- };
-
+ .then(async (result) => {
+ console.log('User signed in:', result.user);
+ var zipcode = await findZipcode(result.user.email);
+ console.log("Zipcode: ", zipcode);
+ })
+ .catch((error) => {
+ console.error('Error signing in with Google:', error);
+ });
+};
+
export const firebaseSignOut = () => signOut(auth);
export const useAuthState = () => {
@@ -53,13 +53,13 @@ export const useAuthState = () => {
export const useDbData = (path) => {
const [data, setData] = useState();
const [error, setError] = useState(null);
-
+
useEffect(() => {
const dbRef = ref(database, path);
const unsubscribe = onValue(
- dbRef,
- (snapshot) => setData(snapshot.val()),
- (error) => setError(error)
+ dbRef,
+ (snapshot) => setData(snapshot.val()),
+ (error) => setError(error)
);
return () => unsubscribe();
}, [path]);
@@ -72,9 +72,9 @@ export const useDbUpdate = (path) => {
const updateData = useCallback(
(value) => {
- update(ref(database, path), value)
- .then(() => setResult({ message: "Update successful", timestamp: Date.now() }))
- .catch((error) => setResult({ error, message: error.message }));
+ update(ref(database, path), value)
+ .then(() => setResult({ message: "Update successful", timestamp: Date.now() }))
+ .catch((error) => setResult({ error, message: error.message }));
},
[path]
);
@@ -82,4 +82,14 @@ export const useDbUpdate = (path) => {
return [updateData, result];
};
-export {database};
\ No newline at end of file
+export const handleSignIn = async () => {
+ try {
+ await signInWithGoogle();
+ } catch (error) {
+ console.error('Error signing in:', error);
+ }
+};
+
+export const handleLogout = () => firebaseSignOut();
+
+export { database };
\ No newline at end of file
diff --git a/src/utilities/posts.js b/src/utilities/posts.js
deleted file mode 100644
index d1f47f1..0000000
--- a/src/utilities/posts.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import { useState, useEffect } from 'react';
-import { onValue, query, orderByChild, equalTo, ref } from 'firebase/database';
-import { database } from './firebase';
-
-export const findCafePosts = (cafeId) => {
- const [data, setData] = useState(null);
- const [error, setError] = useState(null);
-
- useEffect(() => {
- if (!cafeId) return
-
- const postsRef = ref(database, `/posts`);
- const postsQuery = query(postsRef, orderByChild('cafeId'), equalTo(cafeId));
-
- const unsubscribe = onValue(
- postsQuery,
- (snapshot) => {
- if (snapshot.exists()) {
- setData(snapshot.val());
- } else {
- setData([]);
- }
- },
- (error) => {
- setError(error);
- }
- );
-
- return () => unsubscribe();
- }, [cafeId]);
-
- return [data, error];
-};
\ No newline at end of file
diff --git a/src/utilities/posts.jsx b/src/utilities/posts.jsx
new file mode 100644
index 0000000..8bd36fe
--- /dev/null
+++ b/src/utilities/posts.jsx
@@ -0,0 +1,62 @@
+import { useState, useEffect } from 'react';
+import { onValue, query, orderByChild, equalTo, ref, get, update } from 'firebase/database';
+import { database } from './firebase';
+
+export const findCafePosts = (cafeId) => {
+ const [data, setData] = useState(null);
+ const [error, setError] = useState(null);
+
+ useEffect(() => {
+ if (!cafeId) return
+
+ const postsRef = ref(database, `/posts`);
+ const postsQuery = query(postsRef, orderByChild('cafeId'), equalTo(cafeId));
+ const unsubscribe = onValue(
+ postsQuery,
+ (snapshot) => {
+ if (snapshot.exists()) {
+ console.log(snapshot.val());
+ setData(snapshot.val());
+ } else {
+ setData([]);
+ }
+ },
+ (error) => {
+ setError(error);
+ }
+ );
+
+ return () => unsubscribe();
+ }, [cafeId]);
+ return [data, error];
+};
+
+export const addReplyToPost = async (postId, userId, replyMessage) => {
+ try {
+ const postRef = ref(database, `/posts/${postId}`);
+ const postSnapshot = await get(postRef);
+ if (!postSnapshot.exists()) {
+ return 'Post not found';
+ }
+
+ const postData = postSnapshot.val();
+ const replies = postData.replies || {};
+ const replyId = `replyId_${Object.keys(replies).length + 1}`;
+
+ const newReply = {
+ [replyId]: replyMessage
+ };
+
+ await update(postRef, {
+ replies: {
+ ...replies,
+ ...newReply
+ }
+ });
+
+ return null;
+ } catch (error) {
+ console.error('Error adding reply:', error);
+ return error.message || 'Error adding reply';
+ }
+};